@trieb.work/payload-plugin-backup-mongodb 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +319 -0
- package/dist/backup-dashboard.css +1132 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.js +3 -0
- package/dist/client.js.map +1 -0
- package/dist/collections/BackupSettings.d.ts +6 -0
- package/dist/collections/BackupSettings.js +91 -0
- package/dist/collections/BackupSettings.js.map +1 -0
- package/dist/collections/BackupTasks.d.ts +2 -0
- package/dist/collections/BackupTasks.js +56 -0
- package/dist/collections/BackupTasks.js.map +1 -0
- package/dist/components/BackupDashboard/BackupItemActions.client.d.ts +7 -0
- package/dist/components/BackupDashboard/BackupItemActions.client.js +90 -0
- package/dist/components/BackupDashboard/BackupItemActions.client.js.map +1 -0
- package/dist/components/BackupDashboard/BackupListCollapsible.client.d.ts +16 -0
- package/dist/components/BackupDashboard/BackupListCollapsible.client.js +597 -0
- package/dist/components/BackupDashboard/BackupListCollapsible.client.js.map +1 -0
- package/dist/components/BackupDashboard/BackupSettingsModal.client.d.ts +2 -0
- package/dist/components/BackupDashboard/BackupSettingsModal.client.js +939 -0
- package/dist/components/BackupDashboard/BackupSettingsModal.client.js.map +1 -0
- package/dist/components/BackupDashboard/CollectionBackupPreviewBody.client.d.ts +18 -0
- package/dist/components/BackupDashboard/CollectionBackupPreviewBody.client.js +267 -0
- package/dist/components/BackupDashboard/CollectionBackupPreviewBody.client.js.map +1 -0
- package/dist/components/BackupDashboard/ManualBackupDialog.client.d.ts +1 -0
- package/dist/components/BackupDashboard/ManualBackupDialog.client.js +276 -0
- package/dist/components/BackupDashboard/ManualBackupDialog.client.js.map +1 -0
- package/dist/components/BackupDashboard/RestoreBackupDialog.client.d.ts +6 -0
- package/dist/components/BackupDashboard/RestoreBackupDialog.client.js +551 -0
- package/dist/components/BackupDashboard/RestoreBackupDialog.client.js.map +1 -0
- package/dist/components/BackupDashboard/TaskActionButton.client.d.ts +29 -0
- package/dist/components/BackupDashboard/TaskActionButton.client.js +240 -0
- package/dist/components/BackupDashboard/TaskActionButton.client.js.map +1 -0
- package/dist/components/BackupDashboard/backupDashboardInlineCss.d.ts +1 -0
- package/dist/components/BackupDashboard/backupDashboardInlineCss.js +3 -0
- package/dist/components/BackupDashboard/backupDashboardInlineCss.js.map +1 -0
- package/dist/components/BackupDashboard/index.client.d.ts +8 -0
- package/dist/components/BackupDashboard/index.client.js +9 -0
- package/dist/components/BackupDashboard/index.client.js.map +1 -0
- package/dist/components/BackupDashboard/index.d.ts +8 -0
- package/dist/components/BackupDashboard/index.js +196 -0
- package/dist/components/BackupDashboard/index.js.map +1 -0
- package/dist/core/archive.d.ts +8 -0
- package/dist/core/archive.js +47 -0
- package/dist/core/archive.js.map +1 -0
- package/dist/core/backup.d.ts +41 -0
- package/dist/core/backup.js +188 -0
- package/dist/core/backup.js.map +1 -0
- package/dist/core/backupBlobIO.d.ts +54 -0
- package/dist/core/backupBlobIO.js +179 -0
- package/dist/core/backupBlobIO.js.map +1 -0
- package/dist/core/backupBlobTransfer.d.ts +29 -0
- package/dist/core/backupBlobTransfer.js +85 -0
- package/dist/core/backupBlobTransfer.js.map +1 -0
- package/dist/core/backupSettings.d.ts +35 -0
- package/dist/core/backupSettings.js +95 -0
- package/dist/core/backupSettings.js.map +1 -0
- package/dist/core/backupSourcePreview.d.ts +10 -0
- package/dist/core/backupSourcePreview.js +33 -0
- package/dist/core/backupSourcePreview.js.map +1 -0
- package/dist/core/blobTokenValidate.d.ts +14 -0
- package/dist/core/blobTokenValidate.js +75 -0
- package/dist/core/blobTokenValidate.js.map +1 -0
- package/dist/core/db.d.ts +24 -0
- package/dist/core/db.js +12 -0
- package/dist/core/db.js.map +1 -0
- package/dist/core/restore.d.ts +27 -0
- package/dist/core/restore.js +199 -0
- package/dist/core/restore.js.map +1 -0
- package/dist/core/restorePreview.d.ts +64 -0
- package/dist/core/restorePreview.js +266 -0
- package/dist/core/restorePreview.js.map +1 -0
- package/dist/core/taskProgress.d.ts +26 -0
- package/dist/core/taskProgress.js +73 -0
- package/dist/core/taskProgress.js.map +1 -0
- package/dist/core/vercelBackupCron.d.ts +8 -0
- package/dist/core/vercelBackupCron.js +38 -0
- package/dist/core/vercelBackupCron.js.map +1 -0
- package/dist/endpoints/createBackupEndpoints.d.ts +1 -0
- package/dist/endpoints/createBackupEndpoints.js +3 -0
- package/dist/endpoints/createBackupEndpoints.js.map +1 -0
- package/dist/endpoints/index.d.ts +3 -0
- package/dist/endpoints/index.js +34 -0
- package/dist/endpoints/index.js.map +1 -0
- package/dist/endpoints/paths/admin-backup-download.d.ts +8 -0
- package/dist/endpoints/paths/admin-backup-download.js +72 -0
- package/dist/endpoints/paths/admin-backup-download.js.map +1 -0
- package/dist/endpoints/paths/admin-delete.d.ts +3 -0
- package/dist/endpoints/paths/admin-delete.js +55 -0
- package/dist/endpoints/paths/admin-delete.js.map +1 -0
- package/dist/endpoints/paths/admin-manual.d.ts +3 -0
- package/dist/endpoints/paths/admin-manual.js +61 -0
- package/dist/endpoints/paths/admin-manual.js.map +1 -0
- package/dist/endpoints/paths/admin-preview.d.ts +6 -0
- package/dist/endpoints/paths/admin-preview.js +102 -0
- package/dist/endpoints/paths/admin-preview.js.map +1 -0
- package/dist/endpoints/paths/admin-restore.d.ts +3 -0
- package/dist/endpoints/paths/admin-restore.js +74 -0
- package/dist/endpoints/paths/admin-restore.js.map +1 -0
- package/dist/endpoints/paths/admin-seed.d.ts +3 -0
- package/dist/endpoints/paths/admin-seed.js +47 -0
- package/dist/endpoints/paths/admin-seed.js.map +1 -0
- package/dist/endpoints/paths/admin-settings.d.ts +3 -0
- package/dist/endpoints/paths/admin-settings.js +230 -0
- package/dist/endpoints/paths/admin-settings.js.map +1 -0
- package/dist/endpoints/paths/admin-task.d.ts +3 -0
- package/dist/endpoints/paths/admin-task.js +34 -0
- package/dist/endpoints/paths/admin-task.js.map +1 -0
- package/dist/endpoints/paths/admin-validate-blob-token.d.ts +8 -0
- package/dist/endpoints/paths/admin-validate-blob-token.js +26 -0
- package/dist/endpoints/paths/admin-validate-blob-token.js.map +1 -0
- package/dist/endpoints/paths/cron-list.d.ts +2 -0
- package/dist/endpoints/paths/cron-list.js +33 -0
- package/dist/endpoints/paths/cron-list.js.map +1 -0
- package/dist/endpoints/paths/cron-restore.d.ts +2 -0
- package/dist/endpoints/paths/cron-restore.js +61 -0
- package/dist/endpoints/paths/cron-restore.js.map +1 -0
- package/dist/endpoints/paths/cron-run.d.ts +3 -0
- package/dist/endpoints/paths/cron-run.js +45 -0
- package/dist/endpoints/paths/cron-run.js.map +1 -0
- package/dist/endpoints/shared.d.ts +13 -0
- package/dist/endpoints/shared.js +58 -0
- package/dist/endpoints/shared.js.map +1 -0
- package/dist/exports/client.d.ts +1 -0
- package/dist/exports/client.js +3 -0
- package/dist/exports/client.js.map +1 -0
- package/dist/exports/rsc.d.ts +1 -0
- package/dist/exports/rsc.js +3 -0
- package/dist/exports/rsc.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +3 -0
- package/dist/plugin.js +82 -0
- package/dist/plugin.js.map +1 -0
- package/dist/publicApiPaths.d.ts +19 -0
- package/dist/publicApiPaths.js +20 -0
- package/dist/publicApiPaths.js.map +1 -0
- package/dist/types.d.ts +21 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/backupSelection.d.ts +6 -0
- package/dist/utils/backupSelection.js +16 -0
- package/dist/utils/backupSelection.js.map +1 -0
- package/dist/utils/blobName.d.ts +32 -0
- package/dist/utils/blobName.js +99 -0
- package/dist/utils/blobName.js.map +1 -0
- package/dist/utils/dashboardRoleAccess.d.ts +23 -0
- package/dist/utils/dashboardRoleAccess.js +64 -0
- package/dist/utils/dashboardRoleAccess.js.map +1 -0
- package/dist/utils/dialogBackdrop.d.ts +9 -0
- package/dist/utils/dialogBackdrop.js +17 -0
- package/dist/utils/dialogBackdrop.js.map +1 -0
- package/dist/utils/formatBytes.d.ts +2 -0
- package/dist/utils/formatBytes.js +20 -0
- package/dist/utils/formatBytes.js.map +1 -0
- package/dist/utils/hostname.d.ts +2 -0
- package/dist/utils/hostname.js +17 -0
- package/dist/utils/hostname.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/maskBlobToken.d.ts +11 -0
- package/dist/utils/maskBlobToken.js +42 -0
- package/dist/utils/maskBlobToken.js.map +1 -0
- package/package.json +140 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { BackupTaskProgress } from '../../core/taskProgress';
|
|
2
|
+
export interface TaskActionDangerConfirm {
|
|
3
|
+
body: string;
|
|
4
|
+
cancelLabel?: string;
|
|
5
|
+
confirmLabel?: string;
|
|
6
|
+
title: string;
|
|
7
|
+
/** If true, show a second confirmation dialog before running the request (e.g. lock-out risk). */
|
|
8
|
+
when: () => boolean;
|
|
9
|
+
}
|
|
10
|
+
type TaskActionButtonProps = {
|
|
11
|
+
body?: Record<string, unknown>;
|
|
12
|
+
buttonStyle?: 'error' | 'primary' | 'secondary' | 'subtle';
|
|
13
|
+
className?: string;
|
|
14
|
+
completeLabel?: string;
|
|
15
|
+
/** Extra confirmation dialog (danger) before POST — runs when `when()` returns true on click. */
|
|
16
|
+
dangerConfirm?: TaskActionDangerConfirm;
|
|
17
|
+
endpoint: string;
|
|
18
|
+
/** When true, the idle (not-yet-running) action is disabled — e.g. while a restore preview loads. */
|
|
19
|
+
idleDisabled?: boolean;
|
|
20
|
+
idleLabel: string;
|
|
21
|
+
kind: BackupTaskProgress['kind'];
|
|
22
|
+
/** Invoked once when the task reaches `completed` (after optional `refreshOnComplete`). Not called when `redirectOnComplete` is set. */
|
|
23
|
+
onComplete?: () => void;
|
|
24
|
+
pendingLabel: string;
|
|
25
|
+
redirectOnComplete?: string;
|
|
26
|
+
refreshOnComplete?: boolean;
|
|
27
|
+
};
|
|
28
|
+
export declare const TaskActionButton: React.FC<TaskActionButtonProps>;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { Button, Pill } from '@payloadcms/ui';
|
|
4
|
+
import { useRouter } from 'next/navigation';
|
|
5
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
6
|
+
import { backupPluginPublicApiPaths } from '../../publicApiPaths';
|
|
7
|
+
import { closeNativeDialogOnBackdropPointer } from '../../utils/dialogBackdrop';
|
|
8
|
+
export const TaskActionButton = ({ body, buttonStyle = 'primary', className, completeLabel, dangerConfirm, endpoint, idleDisabled = false, idleLabel, kind, onComplete, pendingLabel, redirectOnComplete, refreshOnComplete = false })=>{
|
|
9
|
+
const router = useRouter();
|
|
10
|
+
const dangerDialogRef = useRef(null);
|
|
11
|
+
const intervalRef = useRef(null);
|
|
12
|
+
/** Avoid firing `onComplete` twice if the polling effect re-runs while status stays `completed`. */ const completeNotifyForTaskIdRef = useRef(null);
|
|
13
|
+
/** Lets the task GET succeed after restore replaces `users` (session becomes invalid). */ const pollSecretRef = useRef(null);
|
|
14
|
+
const [error, setError] = useState(null);
|
|
15
|
+
const [isStarting, setIsStarting] = useState(false);
|
|
16
|
+
const [task, setTask] = useState(null);
|
|
17
|
+
const isBusy = isStarting || task?.status === 'queued' || task?.status === 'running';
|
|
18
|
+
const message = error || task?.error || task?.message || '';
|
|
19
|
+
const label = useMemo(()=>{
|
|
20
|
+
if (isBusy) {
|
|
21
|
+
return pendingLabel;
|
|
22
|
+
}
|
|
23
|
+
if (task?.status === 'completed' && completeLabel) {
|
|
24
|
+
return completeLabel;
|
|
25
|
+
}
|
|
26
|
+
return idleLabel;
|
|
27
|
+
}, [
|
|
28
|
+
completeLabel,
|
|
29
|
+
idleLabel,
|
|
30
|
+
isBusy,
|
|
31
|
+
pendingLabel,
|
|
32
|
+
task?.status
|
|
33
|
+
]);
|
|
34
|
+
const pillStyle = useMemo(()=>{
|
|
35
|
+
if (error || task?.status === 'failed') {
|
|
36
|
+
return 'error';
|
|
37
|
+
}
|
|
38
|
+
if (task?.status === 'completed') {
|
|
39
|
+
return 'success';
|
|
40
|
+
}
|
|
41
|
+
if (isBusy || task?.status === 'queued' || task?.status === 'running') {
|
|
42
|
+
return 'warning';
|
|
43
|
+
}
|
|
44
|
+
return 'light-gray';
|
|
45
|
+
}, [
|
|
46
|
+
error,
|
|
47
|
+
isBusy,
|
|
48
|
+
task?.status
|
|
49
|
+
]);
|
|
50
|
+
const statusLabel = useMemo(()=>{
|
|
51
|
+
if (error || task?.status === 'failed') {
|
|
52
|
+
return 'Failed';
|
|
53
|
+
}
|
|
54
|
+
if (task?.status === 'completed') {
|
|
55
|
+
return 'Done';
|
|
56
|
+
}
|
|
57
|
+
if (isBusy || task?.status === 'queued' || task?.status === 'running') {
|
|
58
|
+
return 'Working';
|
|
59
|
+
}
|
|
60
|
+
return 'Idle';
|
|
61
|
+
}, [
|
|
62
|
+
error,
|
|
63
|
+
isBusy,
|
|
64
|
+
task?.status
|
|
65
|
+
]);
|
|
66
|
+
useEffect(()=>{
|
|
67
|
+
return ()=>{
|
|
68
|
+
if (intervalRef.current) {
|
|
69
|
+
clearInterval(intervalRef.current);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}, []);
|
|
73
|
+
useEffect(()=>{
|
|
74
|
+
if (!task?.id || task.status === 'completed' || task.status === 'failed') {
|
|
75
|
+
if (intervalRef.current) {
|
|
76
|
+
clearInterval(intervalRef.current);
|
|
77
|
+
intervalRef.current = null;
|
|
78
|
+
}
|
|
79
|
+
if (task?.status === 'completed') {
|
|
80
|
+
if (redirectOnComplete) {
|
|
81
|
+
window.location.assign(redirectOnComplete);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (completeNotifyForTaskIdRef.current !== task.id) {
|
|
85
|
+
completeNotifyForTaskIdRef.current = task.id;
|
|
86
|
+
if (refreshOnComplete) {
|
|
87
|
+
router.refresh();
|
|
88
|
+
}
|
|
89
|
+
onComplete?.();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
intervalRef.current = setInterval(async ()=>{
|
|
95
|
+
const response = await fetch(backupPluginPublicApiPaths.adminTask(task.id), {
|
|
96
|
+
cache: 'no-store',
|
|
97
|
+
...pollSecretRef.current ? {
|
|
98
|
+
headers: {
|
|
99
|
+
Authorization: `Bearer ${pollSecretRef.current}`
|
|
100
|
+
}
|
|
101
|
+
} : {}
|
|
102
|
+
});
|
|
103
|
+
if (!response.ok) {
|
|
104
|
+
clearInterval(intervalRef.current);
|
|
105
|
+
intervalRef.current = null;
|
|
106
|
+
setError('Could not load task progress');
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const nextTask = await response.json();
|
|
110
|
+
setTask(nextTask);
|
|
111
|
+
}, 1000);
|
|
112
|
+
return ()=>{
|
|
113
|
+
if (intervalRef.current) {
|
|
114
|
+
clearInterval(intervalRef.current);
|
|
115
|
+
intervalRef.current = null;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}, [
|
|
119
|
+
onComplete,
|
|
120
|
+
redirectOnComplete,
|
|
121
|
+
refreshOnComplete,
|
|
122
|
+
router,
|
|
123
|
+
task?.id,
|
|
124
|
+
task?.status
|
|
125
|
+
]);
|
|
126
|
+
const runTask = async ()=>{
|
|
127
|
+
try {
|
|
128
|
+
setError(null);
|
|
129
|
+
setIsStarting(true);
|
|
130
|
+
pollSecretRef.current = null;
|
|
131
|
+
completeNotifyForTaskIdRef.current = null;
|
|
132
|
+
setTask(null);
|
|
133
|
+
const response = await fetch(endpoint, {
|
|
134
|
+
body: JSON.stringify(body ?? {}),
|
|
135
|
+
headers: {
|
|
136
|
+
'Content-Type': 'application/json'
|
|
137
|
+
},
|
|
138
|
+
method: 'POST'
|
|
139
|
+
});
|
|
140
|
+
if (!response.ok) {
|
|
141
|
+
const text = await response.text();
|
|
142
|
+
throw new Error(text || 'Request failed');
|
|
143
|
+
}
|
|
144
|
+
const data = await response.json();
|
|
145
|
+
pollSecretRef.current = data.pollSecret ?? null;
|
|
146
|
+
const now = new Date().toISOString();
|
|
147
|
+
setTask({
|
|
148
|
+
id: data.taskId,
|
|
149
|
+
createdAt: now,
|
|
150
|
+
kind,
|
|
151
|
+
message: 'Task queued',
|
|
152
|
+
status: 'queued',
|
|
153
|
+
updatedAt: now
|
|
154
|
+
});
|
|
155
|
+
} catch (err) {
|
|
156
|
+
setError(err instanceof Error ? err.message : 'Request failed');
|
|
157
|
+
} finally{
|
|
158
|
+
setIsStarting(false);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const handlePrimaryClick = async ()=>{
|
|
162
|
+
if (dangerConfirm?.when()) {
|
|
163
|
+
dangerDialogRef.current?.showModal();
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
await runTask();
|
|
167
|
+
};
|
|
168
|
+
const handleDangerConfirm = async ()=>{
|
|
169
|
+
dangerDialogRef.current?.close();
|
|
170
|
+
await runTask();
|
|
171
|
+
};
|
|
172
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
173
|
+
children: [
|
|
174
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
175
|
+
className: "backup-task-action",
|
|
176
|
+
children: [
|
|
177
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
178
|
+
buttonStyle: buttonStyle,
|
|
179
|
+
className: className,
|
|
180
|
+
disabled: isBusy || idleDisabled,
|
|
181
|
+
onClick: ()=>void handlePrimaryClick(),
|
|
182
|
+
size: "medium",
|
|
183
|
+
children: label
|
|
184
|
+
}),
|
|
185
|
+
(task !== null || error !== null) && /*#__PURE__*/ _jsxs("div", {
|
|
186
|
+
"aria-live": "polite",
|
|
187
|
+
className: "backup-task-status-slot",
|
|
188
|
+
children: [
|
|
189
|
+
/*#__PURE__*/ _jsx(Pill, {
|
|
190
|
+
pillStyle: pillStyle,
|
|
191
|
+
size: "small",
|
|
192
|
+
children: statusLabel
|
|
193
|
+
}),
|
|
194
|
+
/*#__PURE__*/ _jsx("span", {
|
|
195
|
+
className: "backup-task-status__message",
|
|
196
|
+
children: message
|
|
197
|
+
})
|
|
198
|
+
]
|
|
199
|
+
})
|
|
200
|
+
]
|
|
201
|
+
}),
|
|
202
|
+
dangerConfirm ? /*#__PURE__*/ _jsx(_Fragment, {
|
|
203
|
+
children: /*#__PURE__*/ _jsxs("dialog", {
|
|
204
|
+
className: "backup-confirm-dialog backup-confirm-dialog--danger-confirm",
|
|
205
|
+
onMouseDown: (e)=>closeNativeDialogOnBackdropPointer(e, dangerDialogRef),
|
|
206
|
+
ref: dangerDialogRef,
|
|
207
|
+
children: [
|
|
208
|
+
/*#__PURE__*/ _jsx("p", {
|
|
209
|
+
className: "backup-confirm-dialog__title",
|
|
210
|
+
children: dangerConfirm.title
|
|
211
|
+
}),
|
|
212
|
+
/*#__PURE__*/ _jsx("p", {
|
|
213
|
+
className: "backup-confirm-dialog__body",
|
|
214
|
+
children: dangerConfirm.body
|
|
215
|
+
}),
|
|
216
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
217
|
+
className: "backup-confirm-dialog__actions",
|
|
218
|
+
children: [
|
|
219
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
220
|
+
buttonStyle: "error",
|
|
221
|
+
onClick: ()=>void handleDangerConfirm(),
|
|
222
|
+
size: "small",
|
|
223
|
+
children: dangerConfirm.confirmLabel ?? 'I understand — continue'
|
|
224
|
+
}),
|
|
225
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
226
|
+
buttonStyle: "secondary",
|
|
227
|
+
onClick: ()=>dangerDialogRef.current?.close(),
|
|
228
|
+
size: "small",
|
|
229
|
+
children: dangerConfirm.cancelLabel ?? 'Go back'
|
|
230
|
+
})
|
|
231
|
+
]
|
|
232
|
+
})
|
|
233
|
+
]
|
|
234
|
+
})
|
|
235
|
+
}) : null
|
|
236
|
+
]
|
|
237
|
+
});
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
//# sourceMappingURL=TaskActionButton.client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/BackupDashboard/TaskActionButton.client.tsx"],"sourcesContent":["'use client'\n\nimport { Button, Pill } from '@payloadcms/ui'\nimport { useRouter } from 'next/navigation'\nimport { useEffect, useMemo, useRef, useState } from 'react'\n\nimport type { BackupTaskProgress } from '../../core/taskProgress'\n\nimport { backupPluginPublicApiPaths } from '../../publicApiPaths'\nimport { closeNativeDialogOnBackdropPointer } from '../../utils/dialogBackdrop'\n\nexport interface TaskActionDangerConfirm {\n body: string\n cancelLabel?: string\n confirmLabel?: string\n title: string\n /** If true, show a second confirmation dialog before running the request (e.g. lock-out risk). */\n when: () => boolean\n}\n\ntype TaskActionButtonProps = {\n body?: Record<string, unknown>\n buttonStyle?: 'error' | 'primary' | 'secondary' | 'subtle'\n className?: string\n completeLabel?: string\n /** Extra confirmation dialog (danger) before POST — runs when `when()` returns true on click. */\n dangerConfirm?: TaskActionDangerConfirm\n endpoint: string\n /** When true, the idle (not-yet-running) action is disabled — e.g. while a restore preview loads. */\n idleDisabled?: boolean\n idleLabel: string\n kind: BackupTaskProgress['kind']\n /** Invoked once when the task reaches `completed` (after optional `refreshOnComplete`). Not called when `redirectOnComplete` is set. */\n onComplete?: () => void\n pendingLabel: string\n redirectOnComplete?: string\n refreshOnComplete?: boolean\n}\n\nexport const TaskActionButton: React.FC<TaskActionButtonProps> = ({\n body,\n buttonStyle = 'primary',\n className,\n completeLabel,\n dangerConfirm,\n endpoint,\n idleDisabled = false,\n idleLabel,\n kind,\n onComplete,\n pendingLabel,\n redirectOnComplete,\n refreshOnComplete = false,\n}) => {\n const router = useRouter()\n const dangerDialogRef = useRef<HTMLDialogElement>(null)\n const intervalRef = useRef<null | ReturnType<typeof setInterval>>(null)\n /** Avoid firing `onComplete` twice if the polling effect re-runs while status stays `completed`. */\n const completeNotifyForTaskIdRef = useRef<null | string>(null)\n /** Lets the task GET succeed after restore replaces `users` (session becomes invalid). */\n const pollSecretRef = useRef<null | string>(null)\n const [error, setError] = useState<null | string>(null)\n const [isStarting, setIsStarting] = useState(false)\n const [task, setTask] = useState<BackupTaskProgress | null>(null)\n\n const isBusy = isStarting || task?.status === 'queued' || task?.status === 'running'\n const message = error || task?.error || task?.message || ''\n\n const label = useMemo(() => {\n if (isBusy) {\n return pendingLabel\n }\n\n if (task?.status === 'completed' && completeLabel) {\n return completeLabel\n }\n\n return idleLabel\n }, [completeLabel, idleLabel, isBusy, pendingLabel, task?.status])\n\n const pillStyle = useMemo(() => {\n if (error || task?.status === 'failed') {\n return 'error' as const\n }\n\n if (task?.status === 'completed') {\n return 'success' as const\n }\n\n if (isBusy || task?.status === 'queued' || task?.status === 'running') {\n return 'warning' as const\n }\n\n return 'light-gray' as const\n }, [error, isBusy, task?.status])\n\n const statusLabel = useMemo(() => {\n if (error || task?.status === 'failed') {\n return 'Failed'\n }\n\n if (task?.status === 'completed') {\n return 'Done'\n }\n\n if (isBusy || task?.status === 'queued' || task?.status === 'running') {\n return 'Working'\n }\n\n return 'Idle'\n }, [error, isBusy, task?.status])\n\n useEffect(() => {\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [])\n\n useEffect(() => {\n if (!task?.id || task.status === 'completed' || task.status === 'failed') {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n intervalRef.current = null\n }\n\n if (task?.status === 'completed') {\n if (redirectOnComplete) {\n window.location.assign(redirectOnComplete)\n return\n }\n\n if (completeNotifyForTaskIdRef.current !== task.id) {\n completeNotifyForTaskIdRef.current = task.id\n if (refreshOnComplete) {\n router.refresh()\n }\n onComplete?.()\n }\n }\n\n return\n }\n\n intervalRef.current = setInterval(async () => {\n const response = await fetch(backupPluginPublicApiPaths.adminTask(task.id), {\n cache: 'no-store',\n ...(pollSecretRef.current\n ? { headers: { Authorization: `Bearer ${pollSecretRef.current}` } }\n : {}),\n })\n\n if (!response.ok) {\n clearInterval(intervalRef.current!)\n intervalRef.current = null\n setError('Could not load task progress')\n return\n }\n\n const nextTask = (await response.json()) as BackupTaskProgress\n setTask(nextTask)\n }, 1000)\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n intervalRef.current = null\n }\n }\n }, [onComplete, redirectOnComplete, refreshOnComplete, router, task?.id, task?.status])\n\n const runTask = async () => {\n try {\n setError(null)\n setIsStarting(true)\n pollSecretRef.current = null\n completeNotifyForTaskIdRef.current = null\n setTask(null)\n\n const response = await fetch(endpoint, {\n body: JSON.stringify(body ?? {}),\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n if (!response.ok) {\n const text = await response.text()\n throw new Error(text || 'Request failed')\n }\n\n const data = (await response.json()) as { pollSecret?: string; taskId: string }\n pollSecretRef.current = data.pollSecret ?? null\n const now = new Date().toISOString()\n setTask({\n id: data.taskId,\n createdAt: now,\n kind,\n message: 'Task queued',\n status: 'queued',\n updatedAt: now,\n })\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Request failed')\n } finally {\n setIsStarting(false)\n }\n }\n\n const handlePrimaryClick = async () => {\n if (dangerConfirm?.when()) {\n dangerDialogRef.current?.showModal()\n return\n }\n await runTask()\n }\n\n const handleDangerConfirm = async () => {\n dangerDialogRef.current?.close()\n await runTask()\n }\n\n return (\n <>\n <div className=\"backup-task-action\">\n <Button\n buttonStyle={buttonStyle}\n className={className}\n disabled={isBusy || idleDisabled}\n onClick={() => void handlePrimaryClick()}\n size=\"medium\"\n >\n {label}\n </Button>\n\n {(task !== null || error !== null) && (\n <div aria-live=\"polite\" className=\"backup-task-status-slot\">\n <Pill pillStyle={pillStyle} size=\"small\">\n {statusLabel}\n </Pill>\n <span className=\"backup-task-status__message\">{message}</span>\n </div>\n )}\n </div>\n\n {dangerConfirm ? (\n <>\n {/* Native <dialog>: backdrop dismiss; element not in jsx-a11y interactive list */}\n {/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */}\n <dialog\n className=\"backup-confirm-dialog backup-confirm-dialog--danger-confirm\"\n onMouseDown={(e) => closeNativeDialogOnBackdropPointer(e, dangerDialogRef)}\n ref={dangerDialogRef}\n >\n <p className=\"backup-confirm-dialog__title\">{dangerConfirm.title}</p>\n <p className=\"backup-confirm-dialog__body\">{dangerConfirm.body}</p>\n <div className=\"backup-confirm-dialog__actions\">\n <Button buttonStyle=\"error\" onClick={() => void handleDangerConfirm()} size=\"small\">\n {dangerConfirm.confirmLabel ?? 'I understand — continue'}\n </Button>\n <Button\n buttonStyle=\"secondary\"\n onClick={() => dangerDialogRef.current?.close()}\n size=\"small\"\n >\n {dangerConfirm.cancelLabel ?? 'Go back'}\n </Button>\n </div>\n </dialog>\n </>\n ) : null}\n </>\n )\n}\n"],"names":["Button","Pill","useRouter","useEffect","useMemo","useRef","useState","backupPluginPublicApiPaths","closeNativeDialogOnBackdropPointer","TaskActionButton","body","buttonStyle","className","completeLabel","dangerConfirm","endpoint","idleDisabled","idleLabel","kind","onComplete","pendingLabel","redirectOnComplete","refreshOnComplete","router","dangerDialogRef","intervalRef","completeNotifyForTaskIdRef","pollSecretRef","error","setError","isStarting","setIsStarting","task","setTask","isBusy","status","message","label","pillStyle","statusLabel","current","clearInterval","id","window","location","assign","refresh","setInterval","response","fetch","adminTask","cache","headers","Authorization","ok","nextTask","json","runTask","JSON","stringify","method","text","Error","data","pollSecret","now","Date","toISOString","taskId","createdAt","updatedAt","err","handlePrimaryClick","when","showModal","handleDangerConfirm","close","div","disabled","onClick","size","aria-live","span","dialog","onMouseDown","e","ref","p","title","confirmLabel","cancelLabel"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const backupDashboardInlineCss: string;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/* Auto-generated from index.scss via scripts/embed-backup-css.mjs (run: pnpm build:css, pnpm build:embed-css, or pnpm build). */ export const backupDashboardInlineCss = "@charset \"UTF-8\";\n@layer payload-default {}\n@layer payload-default {}\n.backup-dashboard {\n box-sizing: border-box;\n width: 100%;\n max-width: 100%;\n margin-top: 60px;\n margin-inline: 5px;\n padding-inline: 0;\n}\n.backup-dashboard h2 {\n margin-bottom: 20px;\n}\n.backup-dashboard .experimental {\n color: #909090;\n font-size: 12px;\n}\n.backup-dashboard {\n margin-bottom: 30px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.backup-dashboard__collapsible-title {\n font-size: 13px;\n font-weight: 600;\n line-height: 1.3;\n color: var(--theme-elevation-900);\n letter-spacing: -0.01em;\n pointer-events: none;\n}\n.backup-dashboard__backup-list-toolbar {\n display: flex;\n justify-content: flex-start;\n align-items: center;\n margin: 2px 0 7px;\n /* Payload `.btn` often adds vertical margin — tighten only this toolbar */\n}\n.backup-dashboard__backup-list-toolbar > .btn {\n margin-block: 0;\n}\n.backup-dashboard__filter-btn {\n margin-block: 0;\n}\n.backup-dashboard__collapsible-checkbox {\n display: flex;\n /* center would vertically center the box against multi-line labels — looks misaligned */\n align-items: flex-start;\n gap: 7px;\n}\n.backup-dashboard__collapsible-checkbox .checkbox-input__input {\n appearance: none;\n width: 14px;\n height: 14px;\n border: 1px solid var(--theme-elevation-300);\n background: var(--theme-input-bg);\n border-radius: 3px;\n flex-shrink: 0;\n /* Nudge into the first line’s cap-height vs. 12px / ~1.35–1.45 line box */\n margin: 2px 0 0;\n cursor: pointer;\n position: relative;\n}\n.backup-dashboard__collapsible-checkbox .checkbox-input__input:checked {\n border-color: var(--theme-elevation-800);\n background-image: url(\"data:image/svg+xml,%3Csvg width='10' height='8' viewBox='0 0 10 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3.58333 7.5L0 3.91667L0.7 3.21667L3.58333 6.1L9.3 0.383333L10 1.08333L3.58333 7.5Z' fill='%23333333'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: center;\n background-size: 10px 8px;\n}\n.backup-dashboard__collapsible-checkbox .checkbox-input__input:hover {\n border-color: var(--theme-elevation-400);\n}\n.backup-dashboard__collapsible-checkbox .checkbox-input__input:focus {\n outline: none;\n border-color: var(--theme-elevation-400);\n}\n.backup-dashboard__collapsible-checkbox .field-label {\n font-size: 12px;\n line-height: 1.45;\n color: var(--theme-elevation-800);\n cursor: pointer;\n white-space: nowrap;\n}\n.backup-dashboard__filter-btn--active {\n box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.35);\n}\n.backup-dashboard__list-empty {\n margin: 0 0 15px;\n font-size: 13px;\n color: var(--theme-elevation-600);\n}\n.backup-dashboard__setup-hint {\n margin: 0 0 18px;\n padding: 13px 18px;\n font-size: 13px;\n line-height: 1.45;\n color: var(--theme-elevation-800);\n background: var(--theme-warning-50, rgba(255, 193, 7, 0.12));\n border: 1px solid var(--theme-warning-200, rgba(255, 152, 0, 0.35));\n border-radius: 4px;\n}\n.backup-dashboard__setup-hint-code {\n font-family: var(--font-mono, ui-monospace, monospace);\n font-size: 12px;\n font-weight: 500;\n}\n.backup-dashboard__toolbar {\n margin: 0 0 15px;\n padding: 2px 24px;\n border: 1px solid var(--theme-elevation-100);\n border-radius: 4px;\n background: var(--theme-elevation-25, #fafafa);\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 14px;\n flex-wrap: wrap;\n}\n.backup-dashboard__toolbar-meta {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n gap: 7px;\n align-items: center;\n}\n.backup-dashboard__toolbar-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n padding: 4px 9px;\n border-radius: 999px;\n border: 1px solid var(--theme-elevation-150);\n background: var(--theme-elevation-0);\n color: var(--theme-elevation-800);\n}\n.backup-dashboard__toolbar-key {\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--theme-elevation-500);\n font-weight: 600;\n}\n.backup-dashboard .backup-item {\n margin-bottom: 20px;\n display: flex;\n flex-direction: row;\n gap: 15px;\n justify-content: space-between;\n align-items: flex-start;\n background-color: var(--theme-elevation-50, #f5f5f5);\n padding: 13px 20px;\n border-radius: 5px;\n border: 1px solid var(--theme-elevation-100);\n}\n@media (max-width: 768px) {\n .backup-dashboard .backup-item {\n flex-direction: column;\n align-items: stretch;\n }\n}\n.backup-dashboard .backup-item__main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 9px;\n}\n.backup-dashboard .backup-item__primary {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: baseline;\n gap: 8px;\n}\n.backup-dashboard .backup-item__time {\n font-size: 14px;\n font-weight: 600;\n color: var(--theme-elevation-900);\n letter-spacing: -0.01em;\n}\n.backup-dashboard .backup-item__meta {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n}\n.backup-dashboard .backup-item__pill {\n display: inline-flex;\n flex-direction: row;\n align-items: center;\n gap: 5px;\n font-size: 12px;\n line-height: 1.25;\n padding: 3px 9px;\n border-radius: 999px;\n background: var(--theme-elevation-100, #ebebeb);\n color: var(--theme-elevation-800);\n border: 1px solid transparent;\n max-width: 100%;\n}\n.backup-dashboard .backup-item__pill-key {\n font-weight: 500;\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--theme-elevation-500);\n}\n.backup-dashboard .backup-item__pill--kind {\n font-weight: 600;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n.backup-dashboard .backup-item__pill--cron {\n background: rgba(46, 125, 50, 0.12);\n color: var(--theme-success-800, #1b5e20);\n border-color: rgba(46, 125, 50, 0.22);\n}\n.backup-dashboard .backup-item__pill--manual {\n background: rgba(25, 118, 210, 0.1);\n color: var(--theme-elevation-900);\n border-color: rgba(25, 118, 210, 0.2);\n}\n.backup-dashboard .backup-item__pill--media {\n font-weight: 600;\n font-size: 11px;\n background: var(--theme-elevation-0, #fff);\n border-color: var(--theme-elevation-150);\n}\n.backup-dashboard .backup-item__pill--collections {\n background: var(--theme-elevation-0, #fff);\n border-color: var(--theme-elevation-150);\n font-variant-numeric: tabular-nums;\n}\n.backup-dashboard .backup-item__pill--label {\n background: rgba(124, 58, 237, 0.1);\n color: var(--theme-elevation-900);\n border-color: rgba(124, 58, 237, 0.25);\n font-weight: 600;\n max-width: 24ch;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.backup-dashboard .backup-item__pill--label .backup-item__pill-key {\n color: rgba(124, 58, 237, 0.9);\n}\n.backup-dashboard .backup-item__pill--size {\n background: var(--theme-elevation-0, #fff);\n border-color: var(--theme-elevation-150);\n}\n.backup-dashboard .backup-item__pill--warn {\n background: var(--theme-warning-50, rgba(255, 193, 7, 0.12));\n border-color: var(--theme-warning-200, rgba(255, 152, 0, 0.35));\n color: var(--theme-warning-800, #8a5a00);\n}\n.backup-dashboard .backup-item__pill--warn .backup-item__pill-key {\n color: var(--theme-warning-700, #a26a00);\n font-weight: 700;\n}\n.backup-dashboard .backup-item__pill--danger {\n background: var(--theme-error-50, rgba(220, 38, 38, 0.1));\n border-color: var(--theme-error-200, rgba(220, 38, 38, 0.35));\n color: var(--theme-error-800, #991b1b);\n font-weight: 600;\n}\n.backup-dashboard .backup-item__pill--neutral {\n background: var(--theme-elevation-50, #f4f4f4);\n border-color: var(--theme-elevation-150);\n color: var(--theme-elevation-700);\n}\n.backup-dashboard .backup-item__size-value {\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n color: var(--theme-elevation-900);\n}\n.backup-dashboard .make-backup-container {\n padding-top: 7px;\n}\n.backup-dashboard .make-backup-actions {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n gap: 10px;\n}\n.backup-dashboard {\n /* Filter modal: checkbox row uses shared checkbox styles; allow label wrap in dialog */\n}\n.backup-dashboard .backup-list-filters__scope-row .field-label {\n white-space: normal;\n line-height: 1.35;\n}\n\n.backup-item-actions {\n flex-shrink: 0;\n}\n.backup-item-actions__buttons {\n display: flex;\n flex-direction: row;\n gap: 8px;\n align-items: center;\n}\n\n.backup-confirm-dialog {\n padding: 0;\n border: 1px solid var(--theme-elevation-200);\n border-radius: 6px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);\n min-width: 320px;\n max-width: 440px;\n background: var(--theme-elevation-0);\n}\n.backup-confirm-dialog--restore, .backup-confirm-dialog--manual, .backup-confirm-dialog--settings, .backup-confirm-dialog--backup-list-filters {\n min-width: 360px;\n max-width: min(560px, 96vw);\n}\n.backup-confirm-dialog--settings .backup-confirm-dialog__body.restore-preview {\n /* ~120px taller than default; cap keeps full dialog under the viewport */\n max-height: min(100dvh - 10rem, 660px);\n}\n.backup-confirm-dialog--settings .backup-confirm-dialog__subtitle--with-help {\n display: flex;\n flex-wrap: wrap;\n align-items: flex-start;\n gap: 7px;\n padding-bottom: 7px;\n}\n.backup-confirm-dialog--settings .backup-confirm-dialog__subtitle-text {\n flex: 1;\n min-width: 0;\n}\n.backup-confirm-dialog--settings .restore-preview__sticky-heading--with-help {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 7px;\n margin-top: 4px;\n margin-bottom: 6px;\n padding-top: 7px;\n padding-bottom: 5px;\n}\n.backup-confirm-dialog--settings .restore-preview__sticky-heading--with-help > span:first-child {\n flex: 1;\n min-width: 0;\n}\n.backup-confirm-dialog--settings .restore-preview__intro {\n margin-bottom: 7px;\n}\n.backup-confirm-dialog--settings .restore-preview__settings-fields {\n margin-bottom: 10px;\n}\n.backup-confirm-dialog--settings .restore-preview__settings-block {\n margin-bottom: 11px;\n}\n.backup-confirm-dialog--danger-confirm {\n border-color: var(--theme-error-500, #c0392b);\n box-shadow: 0 8px 28px rgba(192, 57, 43, 0.18);\n}\n.backup-confirm-dialog--danger-confirm .backup-confirm-dialog__actions .btn:first-of-type {\n background-color: var(--theme-error-600, #c0392b);\n border-color: var(--theme-error-600, #c0392b);\n color: #fff;\n}\n.backup-confirm-dialog--danger-confirm .backup-confirm-dialog__actions .btn:first-of-type:hover:not([disabled]) {\n background-color: var(--theme-error-700, #a93226);\n border-color: var(--theme-error-700, #a93226);\n}\n.backup-confirm-dialog::backdrop {\n background: rgba(0, 0, 0, 0.35);\n}\n.backup-confirm-dialog__title {\n margin: 0;\n padding: 16px 20px 6px;\n font-size: 15px;\n font-weight: 600;\n color: var(--theme-elevation-1000);\n}\n.backup-confirm-dialog__subtitle {\n margin: 0;\n padding: 0 20px 10px;\n font-size: 12px;\n line-height: 1.45;\n color: var(--theme-elevation-600);\n}\n.backup-confirm-dialog__subtitle code {\n font-size: 11px;\n}\n.backup-confirm-dialog__body {\n margin: 0;\n padding: 0 20px 16px;\n font-size: 13px;\n color: var(--theme-elevation-600);\n}\n.backup-confirm-dialog__body.restore-preview {\n max-height: min(70vh, 520px);\n overflow-y: auto;\n}\n.backup-confirm-dialog__actions {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 8px;\n padding: 12px 20px 16px;\n border-top: 1px solid var(--theme-elevation-100);\n}\n\n.backup-list-filters__body {\n display: flex;\n flex-direction: column;\n gap: 15px;\n}\n.backup-list-filters__fieldset {\n margin: 0;\n padding: 0;\n border: 0;\n min-width: 0;\n}\n.backup-list-filters__legend {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--theme-elevation-600);\n margin: 0 0 7px;\n padding: 0;\n}\n.backup-list-filters__row {\n display: grid;\n grid-template-columns: 56px 1fr;\n gap: 8px;\n align-items: center;\n margin-bottom: 7px;\n}\n.backup-list-filters__row:last-child {\n margin-bottom: 0;\n}\n.backup-list-filters__label {\n font-size: 12px;\n color: var(--theme-elevation-700);\n}\n.backup-list-filters__date {\n font-size: 13px;\n padding: 6px 8px;\n border-radius: 3px;\n border: 1px solid var(--theme-elevation-200);\n background: var(--theme-input-bg);\n color: var(--theme-elevation-900);\n}\n.backup-list-filters__text {\n font-size: 13px;\n padding: 6px 8px;\n border-radius: 3px;\n border: 1px solid var(--theme-elevation-200);\n background: var(--theme-input-bg);\n color: var(--theme-elevation-900);\n min-width: 0;\n width: 100%;\n}\n.backup-list-filters__text::placeholder {\n color: var(--theme-elevation-400);\n}\n.backup-list-filters__row--label {\n grid-template-columns: 56px 1fr;\n}\n.backup-list-filters {\n /* Payload-style radios (match checkbox-input sizing / borders, circular + dot) */\n}\n.backup-list-filters__radio-row {\n display: flex;\n align-items: center;\n gap: 7px;\n margin-bottom: 5.6px;\n cursor: pointer;\n}\n.backup-list-filters__radio-row:last-child {\n margin-bottom: 0;\n}\n.backup-list-filters__radio-row .radio-input__input {\n appearance: none;\n width: 14px;\n height: 14px;\n border: 1px solid var(--theme-elevation-300);\n background: var(--theme-input-bg);\n border-radius: 50%;\n margin: 0;\n cursor: pointer;\n flex-shrink: 0;\n position: relative;\n}\n.backup-list-filters__radio-row .radio-input__input:checked {\n border-color: var(--theme-elevation-800);\n background-color: var(--theme-input-bg);\n background-image: radial-gradient(circle at center, var(--theme-elevation-800) 0, var(--theme-elevation-800) 32%, transparent 33%);\n}\n.backup-list-filters__radio-row .radio-input__input:hover {\n border-color: var(--theme-elevation-400);\n}\n.backup-list-filters__radio-row .radio-input__input:focus {\n outline: none;\n border-color: var(--theme-elevation-400);\n}\n.backup-list-filters__radio-row .radio-input__input:focus-visible {\n outline: 2px solid var(--theme-elevation-400);\n outline-offset: 2px;\n}\n.backup-list-filters__radio-row .field-label {\n font-size: 12px;\n color: var(--theme-elevation-800);\n cursor: pointer;\n line-height: 1.35;\n}\n.backup-list-filters__scope-row {\n margin-bottom: 8px;\n}\n.backup-list-filters__scope-row:last-child {\n margin-bottom: 0;\n}\n.backup-list-filters__hint {\n font-weight: 400;\n color: var(--theme-elevation-500);\n}\n\n.manual-backup-label {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding: 0 20px;\n margin: 5px 0 11px;\n}\n.manual-backup-label__label {\n font-size: 12px;\n font-weight: 600;\n color: var(--theme-elevation-800);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n}\n.manual-backup-label__hint {\n font-weight: 400;\n text-transform: none;\n letter-spacing: 0;\n color: var(--theme-elevation-500);\n}\n.manual-backup-label__input {\n font-size: 13px;\n padding: 7px 10px;\n border-radius: 3px;\n border: 1px solid var(--theme-elevation-200);\n background: var(--theme-input-bg);\n color: var(--theme-elevation-900);\n}\n.manual-backup-label__input::placeholder {\n color: var(--theme-elevation-400);\n}\n.manual-backup-label__input:focus {\n outline: none;\n border-color: var(--theme-elevation-400);\n}\n.manual-backup-label__input:focus-visible {\n outline: 2px solid var(--theme-elevation-400);\n outline-offset: 1px;\n}\n.manual-backup-label__help {\n margin: 0;\n font-size: 11px;\n line-height: 1.35;\n color: var(--theme-elevation-500);\n}\n\n.backup-task-action {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n.backup-task-action .btn[disabled] {\n opacity: 0.7;\n cursor: wait;\n}\n.backup-task-action .btn--style-error {\n background-color: var(--theme-error-600, #c0392b);\n color: #fff;\n border-color: var(--theme-error-600, #c0392b);\n}\n.backup-task-action .btn--style-error:hover:not([disabled]) {\n background-color: var(--theme-error-700, #a93226);\n border-color: var(--theme-error-700, #a93226);\n}\n\n.backup-task-status-slot {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 6px;\n}\n.backup-task-status-slot .backup-task-status__message {\n font-size: 12px;\n line-height: 1.4;\n color: var(--theme-elevation-700);\n}\n\n.restore-preview__blob-token-row {\n display: flex;\n gap: 6px;\n align-items: center;\n width: 100%;\n align-self: stretch;\n}\n.restore-preview__blob-token-row .restore-preview__settings-input {\n flex: 1 1 auto;\n min-width: 0;\n}\n.restore-preview__blob-token-row .backup-item__pill {\n flex: 0 0 auto;\n white-space: nowrap;\n}\n.restore-preview__blob-token-pill-slot {\n flex: 0 0 86px;\n display: flex;\n justify-content: flex-end;\n align-items: center;\n min-height: 18px;\n}\n.restore-preview__blob-token-error {\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.35;\n color: var(--theme-error-700, #b91c1c);\n}\n.restore-preview__loading-block {\n padding: 10px 11px;\n border-radius: 3px;\n background: var(--theme-elevation-25, #fafafa);\n border: 1px solid var(--theme-elevation-100);\n margin-bottom: 12px;\n}\n.restore-preview__loading-block--section {\n min-height: 132px;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n.restore-preview__loading-line {\n height: 10px;\n border-radius: 999px;\n background: linear-gradient(90deg, var(--theme-elevation-100) 0%, var(--theme-elevation-150) 40%, var(--theme-elevation-100) 100%);\n background-size: 240px 100%;\n animation: backup-shimmer 1.2s linear infinite;\n margin-bottom: 6px;\n}\n.restore-preview__loading-line--short {\n width: 65%;\n}\n.restore-preview__sticky-heading {\n position: sticky;\n /* Must stay >= 0: negative top clips under overflow-y:auto on the dialog body */\n top: 0;\n z-index: 2;\n margin: 7px 0 9px;\n padding: 10px 0 7px;\n font-size: 12px;\n font-weight: 700;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--theme-elevation-700);\n background: var(--theme-elevation-0);\n border-bottom: 1px solid var(--theme-elevation-100);\n}\n.restore-preview__sticky-heading-hint {\n margin-left: 4px;\n font-size: 11px;\n font-weight: 500;\n letter-spacing: 0.01em;\n text-transform: none;\n color: var(--theme-elevation-500);\n}\n.restore-preview__status {\n margin: 0 0 10px;\n color: var(--theme-elevation-700);\n}\n.restore-preview__status--footer {\n margin: 10px 0 0;\n}\n.restore-preview__settings-block {\n margin: 0 0 15px;\n padding: 9px 10px;\n border-radius: 3px;\n background: var(--theme-elevation-50, #fafafa);\n border: 1px solid var(--theme-elevation-100);\n font-size: 12px;\n line-height: 1.45;\n color: var(--theme-elevation-800);\n}\n.restore-preview__settings-block code {\n font-size: 11px;\n}\n.restore-preview__settings-row {\n margin: 0 0 5px;\n word-break: break-all;\n}\n.restore-preview__settings-row:last-child {\n margin-bottom: 0;\n}\n.restore-preview__settings-k {\n font-weight: 600;\n color: var(--theme-elevation-700);\n margin-right: 4px;\n}\n.restore-preview__settings-human {\n margin: 7px 0 0;\n font-size: 13px;\n color: var(--theme-elevation-900);\n}\n.restore-preview__settings-human--muted {\n color: var(--theme-elevation-600);\n font-size: 12px;\n}\n.restore-preview__settings-hint {\n margin: 0 0 5px;\n font-size: 11px;\n line-height: 1.45;\n color: var(--theme-elevation-600);\n}\n.restore-preview__settings-snippet {\n margin: 3px 0 9px;\n padding: 9px 11px;\n border-radius: 3px;\n background: var(--theme-elevation-900);\n color: var(--theme-elevation-0);\n font-size: 11px;\n line-height: 1.45;\n overflow-x: auto;\n white-space: pre;\n}\n.restore-preview__settings-fields {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 7px;\n margin: 0 0 17px;\n}\n.restore-preview__settings-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--theme-elevation-900);\n}\n.restore-preview__settings-input {\n width: 5.5rem;\n padding: 7px 9px;\n border: 1px solid var(--theme-elevation-200);\n border-radius: 3px;\n font-size: 14px;\n background: var(--theme-input-bg);\n color: var(--theme-elevation-900);\n}\n.restore-preview__settings-input--wide {\n width: 100%;\n min-width: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n font-size: 12px;\n letter-spacing: 0.01em;\n}\n.restore-preview__settings-note {\n margin: 0;\n font-size: 12px;\n line-height: 1.45;\n color: var(--theme-elevation-600);\n max-width: 48ch;\n}\n.restore-preview__settings-note code {\n font-size: 11px;\n}\n.restore-preview__settings-note--warn {\n color: var(--theme-warning-700, #a26a00);\n}\n.restore-preview__blob-transfer-row {\n margin-top: 4px;\n margin-bottom: 0;\n max-width: min(48ch, 100%);\n}\n.restore-preview__blob-transfer-row .field-label {\n white-space: normal;\n line-height: 1.45;\n}\n.restore-preview__blob-transfer-row--with-help-tip .field-label {\n flex: 1;\n min-width: 0;\n}\n.restore-preview__blob-transfer-row--with-help-tip .backup-help-icon {\n margin-top: 2px;\n}\n.restore-preview__transfer-panel {\n width: 100%;\n margin-top: 5px;\n padding: 9px 10px;\n border-radius: 3px;\n background: var(--theme-elevation-50, #fafafa);\n border: 1px solid var(--theme-elevation-100);\n}\n.restore-preview__transfer-bar-track {\n height: 8px;\n border-radius: 999px;\n background: var(--theme-elevation-100);\n overflow: hidden;\n}\n.restore-preview__transfer-bar-fill {\n height: 100%;\n min-width: 0;\n border-radius: 999px;\n background: var(--theme-success-600, #2e7d32);\n transition: width 0.22s ease-out;\n}\n.restore-preview__transfer-meta {\n margin: 8px 0 0;\n font-size: 12px;\n line-height: 1.45;\n color: var(--theme-elevation-800);\n word-break: break-all;\n}\n.restore-preview__transfer-path {\n font-size: 11px;\n color: var(--theme-elevation-600);\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n}\n.restore-preview__intro, .restore-preview__note, .restore-preview__warn {\n margin: 0 0 12px;\n line-height: 1.45;\n}\n.restore-preview__media-block {\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n gap: 9px;\n margin: 0 0 13px;\n padding: 9px 10px;\n border-radius: 3px;\n background: var(--theme-elevation-50, #fafafa);\n border: 1px solid var(--theme-elevation-100);\n cursor: pointer;\n}\n.restore-preview__media-label {\n font-size: 13px;\n font-weight: 500;\n color: var(--theme-elevation-800);\n line-height: 1.4;\n}\n.restore-preview__media-block--nested {\n margin-top: 7px;\n cursor: pointer;\n}\n.restore-preview__all-block {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin: 0 0 13px;\n padding: 11px 12px 10px;\n border-radius: 3px;\n background: var(--theme-elevation-50, #fafafa);\n border: 1px solid var(--theme-elevation-100);\n}\n.restore-preview__all-block-head {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 9px;\n cursor: pointer;\n margin: 0;\n}\n.restore-preview__all-list {\n list-style: none;\n margin: 0;\n padding: 7px 0 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n border-top: 1px dashed var(--theme-elevation-150, #e5e5e5);\n}\n.restore-preview__all-item {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: baseline;\n justify-content: space-between;\n gap: 7px 12px;\n padding: 3px 2px 3px 32px;\n font-size: 12px;\n line-height: 1.4;\n color: var(--theme-elevation-800);\n}\n.restore-preview__all-name {\n flex: 1 1 12rem;\n min-width: 0;\n font-weight: 500;\n color: var(--theme-elevation-900);\n line-height: 1.45;\n}\n.restore-preview__all-count {\n flex-shrink: 0;\n font-variant-numeric: tabular-nums;\n color: var(--theme-elevation-600);\n}\n.restore-preview__all-count-sub {\n color: var(--theme-elevation-500);\n}\n.restore-preview__note--media {\n margin-top: 0;\n}\n.restore-preview__warn {\n padding: 10px 12px;\n border-radius: 4px;\n background: var(--theme-warning-50, rgba(255, 193, 7, 0.12));\n border: 1px solid var(--theme-warning-200, rgba(255, 152, 0, 0.35));\n color: var(--theme-elevation-800);\n}\n.restore-preview__warn--auth {\n background: var(--theme-error-50, rgba(192, 57, 43, 0.08));\n border-color: var(--theme-error-200, rgba(192, 57, 43, 0.25));\n}\n.restore-preview__note code {\n font-size: 12px;\n}\n.restore-preview__error {\n margin-bottom: 12px;\n}\n.restore-preview__error p {\n margin: 0 0 8px;\n}\n.restore-preview__error--inline {\n margin: 7px 20px 10px;\n color: var(--theme-error-700, #c0392b);\n font-size: 13px;\n}\n.restore-preview__error-hint {\n font-size: 12px;\n color: var(--theme-elevation-600);\n}\n.restore-preview__empty {\n margin: 0 0 10px;\n font-size: 13px;\n color: var(--theme-elevation-600);\n}\n.restore-preview__list {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n.restore-preview__group {\n padding: 9px 10px;\n border-radius: 3px;\n background: var(--theme-elevation-50, #fafafa);\n border: 1px solid var(--theme-elevation-100);\n}\n.restore-preview__group--empty {\n background: var(--theme-elevation-50, #fafafa);\n border-color: var(--theme-elevation-100);\n}\n.restore-preview__group--empty .restore-preview__group-title {\n color: var(--theme-elevation-500);\n}\n.restore-preview__group--empty .restore-preview__subline--empty {\n color: var(--theme-elevation-500);\n font-style: italic;\n}\n.restore-preview__group--disabled {\n opacity: 0.55;\n filter: saturate(0.7);\n}\n.restore-preview__group-head {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n gap: 7px;\n width: 100%;\n margin: 0 0 2px;\n}\n.restore-preview__group-label {\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n gap: 9px;\n cursor: pointer;\n margin: 0;\n flex: 1;\n min-width: 0;\n}\n.restore-preview__group-check {\n appearance: none;\n width: 14px;\n height: 14px;\n flex-shrink: 0;\n margin-top: 3px;\n border: 1px solid var(--theme-elevation-300);\n background: var(--theme-input-bg);\n border-radius: 3px;\n cursor: pointer;\n position: relative;\n}\n.restore-preview__group-check:checked {\n border-color: var(--theme-elevation-800);\n background-image: url(\"data:image/svg+xml,%3Csvg width='10' height='8' viewBox='0 0 10 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3.58333 7.5L0 3.91667L0.7 3.21667L3.58333 6.1L9.3 0.383333L10 1.08333L3.58333 7.5Z' fill='%23333333'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: center;\n background-size: 10px 8px;\n}\n.restore-preview__group-check:hover {\n border-color: var(--theme-elevation-400);\n}\n.restore-preview__group-check:focus {\n outline: none;\n border-color: var(--theme-elevation-400);\n}\n.restore-preview__group-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--theme-elevation-900);\n line-height: 1.35;\n}\n.restore-preview__sublines {\n margin: 6px 0 0 32px;\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n.restore-preview__subline {\n font-size: 12px;\n color: var(--theme-elevation-600);\n line-height: 1.4;\n}\n.restore-preview__pills {\n display: flex;\n flex-wrap: wrap;\n gap: 5px;\n margin-top: 4px;\n}\n.restore-preview__pill {\n font-size: 11px;\n line-height: 1.2;\n padding: 2px 6px;\n border-radius: 999px;\n background: var(--theme-elevation-150, #ececec);\n color: var(--theme-elevation-700);\n flex-shrink: 0;\n}\n.restore-preview__pill--signin {\n background: var(--theme-warning-50, rgba(255, 193, 7, 0.28));\n border: 1px solid var(--theme-warning-400, rgba(255, 152, 0, 0.55));\n color: var(--theme-elevation-900);\n font-weight: 500;\n}\n\n@keyframes backup-shimmer {\n 0% {\n background-position: -220px 0;\n }\n 100% {\n background-position: 220px 0;\n }\n}\nbutton.backup-help-icon {\n margin: 0;\n padding: 0;\n border: none;\n font: inherit;\n appearance: none;\n}\n\n.backup-help-icon {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background-color: var(--theme-elevation-200);\n color: var(--theme-elevation-600);\n font-size: 11px;\n font-style: normal;\n cursor: help;\n flex-shrink: 0;\n user-select: none;\n}\n.backup-help-icon::after {\n content: attr(data-tip);\n position: absolute;\n bottom: calc(100% + 6px);\n left: 50%;\n transform: translateX(-50%);\n background: var(--theme-elevation-900);\n color: var(--theme-elevation-0);\n font-size: 11px;\n line-height: 1.4;\n white-space: nowrap;\n padding: 4px 8px;\n border-radius: 4px;\n pointer-events: none;\n opacity: 0;\n transition: opacity 0.15s ease;\n z-index: 100;\n}\n.backup-help-icon:hover::after {\n opacity: 1;\n}\n.backup-help-icon {\n /* Longer copy in settings / footers — wrap instead of one endless line */\n}\n.backup-help-icon--multiline::after {\n white-space: normal;\n text-align: left;\n width: max-content;\n max-width: min(280px, 85vw);\n}\n.backup-help-icon {\n /* Settings modal body scrolls — absolute ::after gets clipped; anchor to viewport instead */\n}\n.backup-help-icon--settings-tooltip::after {\n position: fixed;\n left: var(--backup-tip-x, 50%);\n top: var(--backup-tip-y, 0);\n bottom: auto;\n transform: translate(-50%, calc(-100% - 6px));\n z-index: 2147483000;\n}\n";
|
|
2
|
+
|
|
3
|
+
//# sourceMappingURL=backupDashboardInlineCss.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/BackupDashboard/backupDashboardInlineCss.ts"],"sourcesContent":["/* Auto-generated from index.scss via scripts/embed-backup-css.mjs (run: pnpm build:css, pnpm build:embed-css, or pnpm build). */\nexport const backupDashboardInlineCss: string = \"@charset \\\"UTF-8\\\";\\n@layer payload-default {}\\n@layer payload-default {}\\n.backup-dashboard {\\n box-sizing: border-box;\\n width: 100%;\\n max-width: 100%;\\n margin-top: 60px;\\n margin-inline: 5px;\\n padding-inline: 0;\\n}\\n.backup-dashboard h2 {\\n margin-bottom: 20px;\\n}\\n.backup-dashboard .experimental {\\n color: #909090;\\n font-size: 12px;\\n}\\n.backup-dashboard {\\n margin-bottom: 30px;\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n}\\n.backup-dashboard__collapsible-title {\\n font-size: 13px;\\n font-weight: 600;\\n line-height: 1.3;\\n color: var(--theme-elevation-900);\\n letter-spacing: -0.01em;\\n pointer-events: none;\\n}\\n.backup-dashboard__backup-list-toolbar {\\n display: flex;\\n justify-content: flex-start;\\n align-items: center;\\n margin: 2px 0 7px;\\n /* Payload `.btn` often adds vertical margin — tighten only this toolbar */\\n}\\n.backup-dashboard__backup-list-toolbar > .btn {\\n margin-block: 0;\\n}\\n.backup-dashboard__filter-btn {\\n margin-block: 0;\\n}\\n.backup-dashboard__collapsible-checkbox {\\n display: flex;\\n /* center would vertically center the box against multi-line labels — looks misaligned */\\n align-items: flex-start;\\n gap: 7px;\\n}\\n.backup-dashboard__collapsible-checkbox .checkbox-input__input {\\n appearance: none;\\n width: 14px;\\n height: 14px;\\n border: 1px solid var(--theme-elevation-300);\\n background: var(--theme-input-bg);\\n border-radius: 3px;\\n flex-shrink: 0;\\n /* Nudge into the first line’s cap-height vs. 12px / ~1.35–1.45 line box */\\n margin: 2px 0 0;\\n cursor: pointer;\\n position: relative;\\n}\\n.backup-dashboard__collapsible-checkbox .checkbox-input__input:checked {\\n border-color: var(--theme-elevation-800);\\n background-image: url(\\\"data:image/svg+xml,%3Csvg width='10' height='8' viewBox='0 0 10 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3.58333 7.5L0 3.91667L0.7 3.21667L3.58333 6.1L9.3 0.383333L10 1.08333L3.58333 7.5Z' fill='%23333333'/%3E%3C/svg%3E\\\");\\n background-repeat: no-repeat;\\n background-position: center;\\n background-size: 10px 8px;\\n}\\n.backup-dashboard__collapsible-checkbox .checkbox-input__input:hover {\\n border-color: var(--theme-elevation-400);\\n}\\n.backup-dashboard__collapsible-checkbox .checkbox-input__input:focus {\\n outline: none;\\n border-color: var(--theme-elevation-400);\\n}\\n.backup-dashboard__collapsible-checkbox .field-label {\\n font-size: 12px;\\n line-height: 1.45;\\n color: var(--theme-elevation-800);\\n cursor: pointer;\\n white-space: nowrap;\\n}\\n.backup-dashboard__filter-btn--active {\\n box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.35);\\n}\\n.backup-dashboard__list-empty {\\n margin: 0 0 15px;\\n font-size: 13px;\\n color: var(--theme-elevation-600);\\n}\\n.backup-dashboard__setup-hint {\\n margin: 0 0 18px;\\n padding: 13px 18px;\\n font-size: 13px;\\n line-height: 1.45;\\n color: var(--theme-elevation-800);\\n background: var(--theme-warning-50, rgba(255, 193, 7, 0.12));\\n border: 1px solid var(--theme-warning-200, rgba(255, 152, 0, 0.35));\\n border-radius: 4px;\\n}\\n.backup-dashboard__setup-hint-code {\\n font-family: var(--font-mono, ui-monospace, monospace);\\n font-size: 12px;\\n font-weight: 500;\\n}\\n.backup-dashboard__toolbar {\\n margin: 0 0 15px;\\n padding: 2px 24px;\\n border: 1px solid var(--theme-elevation-100);\\n border-radius: 4px;\\n background: var(--theme-elevation-25, #fafafa);\\n display: flex;\\n justify-content: space-between;\\n align-items: center;\\n gap: 14px;\\n flex-wrap: wrap;\\n}\\n.backup-dashboard__toolbar-meta {\\n display: flex;\\n flex-direction: row;\\n flex-wrap: wrap;\\n gap: 7px;\\n align-items: center;\\n}\\n.backup-dashboard__toolbar-pill {\\n display: inline-flex;\\n align-items: center;\\n gap: 6px;\\n font-size: 12px;\\n padding: 4px 9px;\\n border-radius: 999px;\\n border: 1px solid var(--theme-elevation-150);\\n background: var(--theme-elevation-0);\\n color: var(--theme-elevation-800);\\n}\\n.backup-dashboard__toolbar-key {\\n font-size: 10px;\\n text-transform: uppercase;\\n letter-spacing: 0.04em;\\n color: var(--theme-elevation-500);\\n font-weight: 600;\\n}\\n.backup-dashboard .backup-item {\\n margin-bottom: 20px;\\n display: flex;\\n flex-direction: row;\\n gap: 15px;\\n justify-content: space-between;\\n align-items: flex-start;\\n background-color: var(--theme-elevation-50, #f5f5f5);\\n padding: 13px 20px;\\n border-radius: 5px;\\n border: 1px solid var(--theme-elevation-100);\\n}\\n@media (max-width: 768px) {\\n .backup-dashboard .backup-item {\\n flex-direction: column;\\n align-items: stretch;\\n }\\n}\\n.backup-dashboard .backup-item__main {\\n flex: 1;\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 9px;\\n}\\n.backup-dashboard .backup-item__primary {\\n display: flex;\\n flex-direction: row;\\n flex-wrap: wrap;\\n align-items: baseline;\\n gap: 8px;\\n}\\n.backup-dashboard .backup-item__time {\\n font-size: 14px;\\n font-weight: 600;\\n color: var(--theme-elevation-900);\\n letter-spacing: -0.01em;\\n}\\n.backup-dashboard .backup-item__meta {\\n display: flex;\\n flex-direction: row;\\n flex-wrap: wrap;\\n align-items: center;\\n gap: 6px;\\n}\\n.backup-dashboard .backup-item__pill {\\n display: inline-flex;\\n flex-direction: row;\\n align-items: center;\\n gap: 5px;\\n font-size: 12px;\\n line-height: 1.25;\\n padding: 3px 9px;\\n border-radius: 999px;\\n background: var(--theme-elevation-100, #ebebeb);\\n color: var(--theme-elevation-800);\\n border: 1px solid transparent;\\n max-width: 100%;\\n}\\n.backup-dashboard .backup-item__pill-key {\\n font-weight: 500;\\n font-size: 10px;\\n text-transform: uppercase;\\n letter-spacing: 0.04em;\\n color: var(--theme-elevation-500);\\n}\\n.backup-dashboard .backup-item__pill--kind {\\n font-weight: 600;\\n font-size: 11px;\\n text-transform: uppercase;\\n letter-spacing: 0.03em;\\n}\\n.backup-dashboard .backup-item__pill--cron {\\n background: rgba(46, 125, 50, 0.12);\\n color: var(--theme-success-800, #1b5e20);\\n border-color: rgba(46, 125, 50, 0.22);\\n}\\n.backup-dashboard .backup-item__pill--manual {\\n background: rgba(25, 118, 210, 0.1);\\n color: var(--theme-elevation-900);\\n border-color: rgba(25, 118, 210, 0.2);\\n}\\n.backup-dashboard .backup-item__pill--media {\\n font-weight: 600;\\n font-size: 11px;\\n background: var(--theme-elevation-0, #fff);\\n border-color: var(--theme-elevation-150);\\n}\\n.backup-dashboard .backup-item__pill--collections {\\n background: var(--theme-elevation-0, #fff);\\n border-color: var(--theme-elevation-150);\\n font-variant-numeric: tabular-nums;\\n}\\n.backup-dashboard .backup-item__pill--label {\\n background: rgba(124, 58, 237, 0.1);\\n color: var(--theme-elevation-900);\\n border-color: rgba(124, 58, 237, 0.25);\\n font-weight: 600;\\n max-width: 24ch;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n.backup-dashboard .backup-item__pill--label .backup-item__pill-key {\\n color: rgba(124, 58, 237, 0.9);\\n}\\n.backup-dashboard .backup-item__pill--size {\\n background: var(--theme-elevation-0, #fff);\\n border-color: var(--theme-elevation-150);\\n}\\n.backup-dashboard .backup-item__pill--warn {\\n background: var(--theme-warning-50, rgba(255, 193, 7, 0.12));\\n border-color: var(--theme-warning-200, rgba(255, 152, 0, 0.35));\\n color: var(--theme-warning-800, #8a5a00);\\n}\\n.backup-dashboard .backup-item__pill--warn .backup-item__pill-key {\\n color: var(--theme-warning-700, #a26a00);\\n font-weight: 700;\\n}\\n.backup-dashboard .backup-item__pill--danger {\\n background: var(--theme-error-50, rgba(220, 38, 38, 0.1));\\n border-color: var(--theme-error-200, rgba(220, 38, 38, 0.35));\\n color: var(--theme-error-800, #991b1b);\\n font-weight: 600;\\n}\\n.backup-dashboard .backup-item__pill--neutral {\\n background: var(--theme-elevation-50, #f4f4f4);\\n border-color: var(--theme-elevation-150);\\n color: var(--theme-elevation-700);\\n}\\n.backup-dashboard .backup-item__size-value {\\n font-weight: 600;\\n font-variant-numeric: tabular-nums;\\n color: var(--theme-elevation-900);\\n}\\n.backup-dashboard .make-backup-container {\\n padding-top: 7px;\\n}\\n.backup-dashboard .make-backup-actions {\\n display: flex;\\n flex-direction: row;\\n flex-wrap: wrap;\\n align-items: center;\\n gap: 10px;\\n}\\n.backup-dashboard {\\n /* Filter modal: checkbox row uses shared checkbox styles; allow label wrap in dialog */\\n}\\n.backup-dashboard .backup-list-filters__scope-row .field-label {\\n white-space: normal;\\n line-height: 1.35;\\n}\\n\\n.backup-item-actions {\\n flex-shrink: 0;\\n}\\n.backup-item-actions__buttons {\\n display: flex;\\n flex-direction: row;\\n gap: 8px;\\n align-items: center;\\n}\\n\\n.backup-confirm-dialog {\\n padding: 0;\\n border: 1px solid var(--theme-elevation-200);\\n border-radius: 6px;\\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);\\n min-width: 320px;\\n max-width: 440px;\\n background: var(--theme-elevation-0);\\n}\\n.backup-confirm-dialog--restore, .backup-confirm-dialog--manual, .backup-confirm-dialog--settings, .backup-confirm-dialog--backup-list-filters {\\n min-width: 360px;\\n max-width: min(560px, 96vw);\\n}\\n.backup-confirm-dialog--settings .backup-confirm-dialog__body.restore-preview {\\n /* ~120px taller than default; cap keeps full dialog under the viewport */\\n max-height: min(100dvh - 10rem, 660px);\\n}\\n.backup-confirm-dialog--settings .backup-confirm-dialog__subtitle--with-help {\\n display: flex;\\n flex-wrap: wrap;\\n align-items: flex-start;\\n gap: 7px;\\n padding-bottom: 7px;\\n}\\n.backup-confirm-dialog--settings .backup-confirm-dialog__subtitle-text {\\n flex: 1;\\n min-width: 0;\\n}\\n.backup-confirm-dialog--settings .restore-preview__sticky-heading--with-help {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 7px;\\n margin-top: 4px;\\n margin-bottom: 6px;\\n padding-top: 7px;\\n padding-bottom: 5px;\\n}\\n.backup-confirm-dialog--settings .restore-preview__sticky-heading--with-help > span:first-child {\\n flex: 1;\\n min-width: 0;\\n}\\n.backup-confirm-dialog--settings .restore-preview__intro {\\n margin-bottom: 7px;\\n}\\n.backup-confirm-dialog--settings .restore-preview__settings-fields {\\n margin-bottom: 10px;\\n}\\n.backup-confirm-dialog--settings .restore-preview__settings-block {\\n margin-bottom: 11px;\\n}\\n.backup-confirm-dialog--danger-confirm {\\n border-color: var(--theme-error-500, #c0392b);\\n box-shadow: 0 8px 28px rgba(192, 57, 43, 0.18);\\n}\\n.backup-confirm-dialog--danger-confirm .backup-confirm-dialog__actions .btn:first-of-type {\\n background-color: var(--theme-error-600, #c0392b);\\n border-color: var(--theme-error-600, #c0392b);\\n color: #fff;\\n}\\n.backup-confirm-dialog--danger-confirm .backup-confirm-dialog__actions .btn:first-of-type:hover:not([disabled]) {\\n background-color: var(--theme-error-700, #a93226);\\n border-color: var(--theme-error-700, #a93226);\\n}\\n.backup-confirm-dialog::backdrop {\\n background: rgba(0, 0, 0, 0.35);\\n}\\n.backup-confirm-dialog__title {\\n margin: 0;\\n padding: 16px 20px 6px;\\n font-size: 15px;\\n font-weight: 600;\\n color: var(--theme-elevation-1000);\\n}\\n.backup-confirm-dialog__subtitle {\\n margin: 0;\\n padding: 0 20px 10px;\\n font-size: 12px;\\n line-height: 1.45;\\n color: var(--theme-elevation-600);\\n}\\n.backup-confirm-dialog__subtitle code {\\n font-size: 11px;\\n}\\n.backup-confirm-dialog__body {\\n margin: 0;\\n padding: 0 20px 16px;\\n font-size: 13px;\\n color: var(--theme-elevation-600);\\n}\\n.backup-confirm-dialog__body.restore-preview {\\n max-height: min(70vh, 520px);\\n overflow-y: auto;\\n}\\n.backup-confirm-dialog__actions {\\n display: flex;\\n flex-direction: row;\\n align-items: center;\\n gap: 8px;\\n padding: 12px 20px 16px;\\n border-top: 1px solid var(--theme-elevation-100);\\n}\\n\\n.backup-list-filters__body {\\n display: flex;\\n flex-direction: column;\\n gap: 15px;\\n}\\n.backup-list-filters__fieldset {\\n margin: 0;\\n padding: 0;\\n border: 0;\\n min-width: 0;\\n}\\n.backup-list-filters__legend {\\n font-size: 11px;\\n font-weight: 600;\\n text-transform: uppercase;\\n letter-spacing: 0.04em;\\n color: var(--theme-elevation-600);\\n margin: 0 0 7px;\\n padding: 0;\\n}\\n.backup-list-filters__row {\\n display: grid;\\n grid-template-columns: 56px 1fr;\\n gap: 8px;\\n align-items: center;\\n margin-bottom: 7px;\\n}\\n.backup-list-filters__row:last-child {\\n margin-bottom: 0;\\n}\\n.backup-list-filters__label {\\n font-size: 12px;\\n color: var(--theme-elevation-700);\\n}\\n.backup-list-filters__date {\\n font-size: 13px;\\n padding: 6px 8px;\\n border-radius: 3px;\\n border: 1px solid var(--theme-elevation-200);\\n background: var(--theme-input-bg);\\n color: var(--theme-elevation-900);\\n}\\n.backup-list-filters__text {\\n font-size: 13px;\\n padding: 6px 8px;\\n border-radius: 3px;\\n border: 1px solid var(--theme-elevation-200);\\n background: var(--theme-input-bg);\\n color: var(--theme-elevation-900);\\n min-width: 0;\\n width: 100%;\\n}\\n.backup-list-filters__text::placeholder {\\n color: var(--theme-elevation-400);\\n}\\n.backup-list-filters__row--label {\\n grid-template-columns: 56px 1fr;\\n}\\n.backup-list-filters {\\n /* Payload-style radios (match checkbox-input sizing / borders, circular + dot) */\\n}\\n.backup-list-filters__radio-row {\\n display: flex;\\n align-items: center;\\n gap: 7px;\\n margin-bottom: 5.6px;\\n cursor: pointer;\\n}\\n.backup-list-filters__radio-row:last-child {\\n margin-bottom: 0;\\n}\\n.backup-list-filters__radio-row .radio-input__input {\\n appearance: none;\\n width: 14px;\\n height: 14px;\\n border: 1px solid var(--theme-elevation-300);\\n background: var(--theme-input-bg);\\n border-radius: 50%;\\n margin: 0;\\n cursor: pointer;\\n flex-shrink: 0;\\n position: relative;\\n}\\n.backup-list-filters__radio-row .radio-input__input:checked {\\n border-color: var(--theme-elevation-800);\\n background-color: var(--theme-input-bg);\\n background-image: radial-gradient(circle at center, var(--theme-elevation-800) 0, var(--theme-elevation-800) 32%, transparent 33%);\\n}\\n.backup-list-filters__radio-row .radio-input__input:hover {\\n border-color: var(--theme-elevation-400);\\n}\\n.backup-list-filters__radio-row .radio-input__input:focus {\\n outline: none;\\n border-color: var(--theme-elevation-400);\\n}\\n.backup-list-filters__radio-row .radio-input__input:focus-visible {\\n outline: 2px solid var(--theme-elevation-400);\\n outline-offset: 2px;\\n}\\n.backup-list-filters__radio-row .field-label {\\n font-size: 12px;\\n color: var(--theme-elevation-800);\\n cursor: pointer;\\n line-height: 1.35;\\n}\\n.backup-list-filters__scope-row {\\n margin-bottom: 8px;\\n}\\n.backup-list-filters__scope-row:last-child {\\n margin-bottom: 0;\\n}\\n.backup-list-filters__hint {\\n font-weight: 400;\\n color: var(--theme-elevation-500);\\n}\\n\\n.manual-backup-label {\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n padding: 0 20px;\\n margin: 5px 0 11px;\\n}\\n.manual-backup-label__label {\\n font-size: 12px;\\n font-weight: 600;\\n color: var(--theme-elevation-800);\\n text-transform: uppercase;\\n letter-spacing: 0.04em;\\n}\\n.manual-backup-label__hint {\\n font-weight: 400;\\n text-transform: none;\\n letter-spacing: 0;\\n color: var(--theme-elevation-500);\\n}\\n.manual-backup-label__input {\\n font-size: 13px;\\n padding: 7px 10px;\\n border-radius: 3px;\\n border: 1px solid var(--theme-elevation-200);\\n background: var(--theme-input-bg);\\n color: var(--theme-elevation-900);\\n}\\n.manual-backup-label__input::placeholder {\\n color: var(--theme-elevation-400);\\n}\\n.manual-backup-label__input:focus {\\n outline: none;\\n border-color: var(--theme-elevation-400);\\n}\\n.manual-backup-label__input:focus-visible {\\n outline: 2px solid var(--theme-elevation-400);\\n outline-offset: 1px;\\n}\\n.manual-backup-label__help {\\n margin: 0;\\n font-size: 11px;\\n line-height: 1.35;\\n color: var(--theme-elevation-500);\\n}\\n\\n.backup-task-action {\\n display: flex;\\n flex-direction: row;\\n align-items: center;\\n gap: 8px;\\n flex-wrap: wrap;\\n}\\n.backup-task-action .btn[disabled] {\\n opacity: 0.7;\\n cursor: wait;\\n}\\n.backup-task-action .btn--style-error {\\n background-color: var(--theme-error-600, #c0392b);\\n color: #fff;\\n border-color: var(--theme-error-600, #c0392b);\\n}\\n.backup-task-action .btn--style-error:hover:not([disabled]) {\\n background-color: var(--theme-error-700, #a93226);\\n border-color: var(--theme-error-700, #a93226);\\n}\\n\\n.backup-task-status-slot {\\n display: flex;\\n flex-direction: row;\\n align-items: center;\\n gap: 6px;\\n}\\n.backup-task-status-slot .backup-task-status__message {\\n font-size: 12px;\\n line-height: 1.4;\\n color: var(--theme-elevation-700);\\n}\\n\\n.restore-preview__blob-token-row {\\n display: flex;\\n gap: 6px;\\n align-items: center;\\n width: 100%;\\n align-self: stretch;\\n}\\n.restore-preview__blob-token-row .restore-preview__settings-input {\\n flex: 1 1 auto;\\n min-width: 0;\\n}\\n.restore-preview__blob-token-row .backup-item__pill {\\n flex: 0 0 auto;\\n white-space: nowrap;\\n}\\n.restore-preview__blob-token-pill-slot {\\n flex: 0 0 86px;\\n display: flex;\\n justify-content: flex-end;\\n align-items: center;\\n min-height: 18px;\\n}\\n.restore-preview__blob-token-error {\\n margin: 4px 0 0;\\n font-size: 12px;\\n line-height: 1.35;\\n color: var(--theme-error-700, #b91c1c);\\n}\\n.restore-preview__loading-block {\\n padding: 10px 11px;\\n border-radius: 3px;\\n background: var(--theme-elevation-25, #fafafa);\\n border: 1px solid var(--theme-elevation-100);\\n margin-bottom: 12px;\\n}\\n.restore-preview__loading-block--section {\\n min-height: 132px;\\n display: flex;\\n flex-direction: column;\\n justify-content: center;\\n}\\n.restore-preview__loading-line {\\n height: 10px;\\n border-radius: 999px;\\n background: linear-gradient(90deg, var(--theme-elevation-100) 0%, var(--theme-elevation-150) 40%, var(--theme-elevation-100) 100%);\\n background-size: 240px 100%;\\n animation: backup-shimmer 1.2s linear infinite;\\n margin-bottom: 6px;\\n}\\n.restore-preview__loading-line--short {\\n width: 65%;\\n}\\n.restore-preview__sticky-heading {\\n position: sticky;\\n /* Must stay >= 0: negative top clips under overflow-y:auto on the dialog body */\\n top: 0;\\n z-index: 2;\\n margin: 7px 0 9px;\\n padding: 10px 0 7px;\\n font-size: 12px;\\n font-weight: 700;\\n letter-spacing: 0.02em;\\n text-transform: uppercase;\\n color: var(--theme-elevation-700);\\n background: var(--theme-elevation-0);\\n border-bottom: 1px solid var(--theme-elevation-100);\\n}\\n.restore-preview__sticky-heading-hint {\\n margin-left: 4px;\\n font-size: 11px;\\n font-weight: 500;\\n letter-spacing: 0.01em;\\n text-transform: none;\\n color: var(--theme-elevation-500);\\n}\\n.restore-preview__status {\\n margin: 0 0 10px;\\n color: var(--theme-elevation-700);\\n}\\n.restore-preview__status--footer {\\n margin: 10px 0 0;\\n}\\n.restore-preview__settings-block {\\n margin: 0 0 15px;\\n padding: 9px 10px;\\n border-radius: 3px;\\n background: var(--theme-elevation-50, #fafafa);\\n border: 1px solid var(--theme-elevation-100);\\n font-size: 12px;\\n line-height: 1.45;\\n color: var(--theme-elevation-800);\\n}\\n.restore-preview__settings-block code {\\n font-size: 11px;\\n}\\n.restore-preview__settings-row {\\n margin: 0 0 5px;\\n word-break: break-all;\\n}\\n.restore-preview__settings-row:last-child {\\n margin-bottom: 0;\\n}\\n.restore-preview__settings-k {\\n font-weight: 600;\\n color: var(--theme-elevation-700);\\n margin-right: 4px;\\n}\\n.restore-preview__settings-human {\\n margin: 7px 0 0;\\n font-size: 13px;\\n color: var(--theme-elevation-900);\\n}\\n.restore-preview__settings-human--muted {\\n color: var(--theme-elevation-600);\\n font-size: 12px;\\n}\\n.restore-preview__settings-hint {\\n margin: 0 0 5px;\\n font-size: 11px;\\n line-height: 1.45;\\n color: var(--theme-elevation-600);\\n}\\n.restore-preview__settings-snippet {\\n margin: 3px 0 9px;\\n padding: 9px 11px;\\n border-radius: 3px;\\n background: var(--theme-elevation-900);\\n color: var(--theme-elevation-0);\\n font-size: 11px;\\n line-height: 1.45;\\n overflow-x: auto;\\n white-space: pre;\\n}\\n.restore-preview__settings-fields {\\n display: flex;\\n flex-direction: column;\\n align-items: flex-start;\\n gap: 7px;\\n margin: 0 0 17px;\\n}\\n.restore-preview__settings-label {\\n font-size: 13px;\\n font-weight: 600;\\n color: var(--theme-elevation-900);\\n}\\n.restore-preview__settings-input {\\n width: 5.5rem;\\n padding: 7px 9px;\\n border: 1px solid var(--theme-elevation-200);\\n border-radius: 3px;\\n font-size: 14px;\\n background: var(--theme-input-bg);\\n color: var(--theme-elevation-900);\\n}\\n.restore-preview__settings-input--wide {\\n width: 100%;\\n min-width: 0;\\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \\\"Liberation Mono\\\", \\\"Courier New\\\", monospace;\\n font-size: 12px;\\n letter-spacing: 0.01em;\\n}\\n.restore-preview__settings-note {\\n margin: 0;\\n font-size: 12px;\\n line-height: 1.45;\\n color: var(--theme-elevation-600);\\n max-width: 48ch;\\n}\\n.restore-preview__settings-note code {\\n font-size: 11px;\\n}\\n.restore-preview__settings-note--warn {\\n color: var(--theme-warning-700, #a26a00);\\n}\\n.restore-preview__blob-transfer-row {\\n margin-top: 4px;\\n margin-bottom: 0;\\n max-width: min(48ch, 100%);\\n}\\n.restore-preview__blob-transfer-row .field-label {\\n white-space: normal;\\n line-height: 1.45;\\n}\\n.restore-preview__blob-transfer-row--with-help-tip .field-label {\\n flex: 1;\\n min-width: 0;\\n}\\n.restore-preview__blob-transfer-row--with-help-tip .backup-help-icon {\\n margin-top: 2px;\\n}\\n.restore-preview__transfer-panel {\\n width: 100%;\\n margin-top: 5px;\\n padding: 9px 10px;\\n border-radius: 3px;\\n background: var(--theme-elevation-50, #fafafa);\\n border: 1px solid var(--theme-elevation-100);\\n}\\n.restore-preview__transfer-bar-track {\\n height: 8px;\\n border-radius: 999px;\\n background: var(--theme-elevation-100);\\n overflow: hidden;\\n}\\n.restore-preview__transfer-bar-fill {\\n height: 100%;\\n min-width: 0;\\n border-radius: 999px;\\n background: var(--theme-success-600, #2e7d32);\\n transition: width 0.22s ease-out;\\n}\\n.restore-preview__transfer-meta {\\n margin: 8px 0 0;\\n font-size: 12px;\\n line-height: 1.45;\\n color: var(--theme-elevation-800);\\n word-break: break-all;\\n}\\n.restore-preview__transfer-path {\\n font-size: 11px;\\n color: var(--theme-elevation-600);\\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \\\"Liberation Mono\\\", \\\"Courier New\\\", monospace;\\n}\\n.restore-preview__intro, .restore-preview__note, .restore-preview__warn {\\n margin: 0 0 12px;\\n line-height: 1.45;\\n}\\n.restore-preview__media-block {\\n display: flex;\\n flex-direction: row;\\n align-items: flex-start;\\n gap: 9px;\\n margin: 0 0 13px;\\n padding: 9px 10px;\\n border-radius: 3px;\\n background: var(--theme-elevation-50, #fafafa);\\n border: 1px solid var(--theme-elevation-100);\\n cursor: pointer;\\n}\\n.restore-preview__media-label {\\n font-size: 13px;\\n font-weight: 500;\\n color: var(--theme-elevation-800);\\n line-height: 1.4;\\n}\\n.restore-preview__media-block--nested {\\n margin-top: 7px;\\n cursor: pointer;\\n}\\n.restore-preview__all-block {\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n margin: 0 0 13px;\\n padding: 11px 12px 10px;\\n border-radius: 3px;\\n background: var(--theme-elevation-50, #fafafa);\\n border: 1px solid var(--theme-elevation-100);\\n}\\n.restore-preview__all-block-head {\\n display: flex;\\n flex-direction: row;\\n align-items: center;\\n gap: 9px;\\n cursor: pointer;\\n margin: 0;\\n}\\n.restore-preview__all-list {\\n list-style: none;\\n margin: 0;\\n padding: 7px 0 0;\\n display: flex;\\n flex-direction: column;\\n gap: 2px;\\n border-top: 1px dashed var(--theme-elevation-150, #e5e5e5);\\n}\\n.restore-preview__all-item {\\n display: flex;\\n flex-direction: row;\\n flex-wrap: wrap;\\n align-items: baseline;\\n justify-content: space-between;\\n gap: 7px 12px;\\n padding: 3px 2px 3px 32px;\\n font-size: 12px;\\n line-height: 1.4;\\n color: var(--theme-elevation-800);\\n}\\n.restore-preview__all-name {\\n flex: 1 1 12rem;\\n min-width: 0;\\n font-weight: 500;\\n color: var(--theme-elevation-900);\\n line-height: 1.45;\\n}\\n.restore-preview__all-count {\\n flex-shrink: 0;\\n font-variant-numeric: tabular-nums;\\n color: var(--theme-elevation-600);\\n}\\n.restore-preview__all-count-sub {\\n color: var(--theme-elevation-500);\\n}\\n.restore-preview__note--media {\\n margin-top: 0;\\n}\\n.restore-preview__warn {\\n padding: 10px 12px;\\n border-radius: 4px;\\n background: var(--theme-warning-50, rgba(255, 193, 7, 0.12));\\n border: 1px solid var(--theme-warning-200, rgba(255, 152, 0, 0.35));\\n color: var(--theme-elevation-800);\\n}\\n.restore-preview__warn--auth {\\n background: var(--theme-error-50, rgba(192, 57, 43, 0.08));\\n border-color: var(--theme-error-200, rgba(192, 57, 43, 0.25));\\n}\\n.restore-preview__note code {\\n font-size: 12px;\\n}\\n.restore-preview__error {\\n margin-bottom: 12px;\\n}\\n.restore-preview__error p {\\n margin: 0 0 8px;\\n}\\n.restore-preview__error--inline {\\n margin: 7px 20px 10px;\\n color: var(--theme-error-700, #c0392b);\\n font-size: 13px;\\n}\\n.restore-preview__error-hint {\\n font-size: 12px;\\n color: var(--theme-elevation-600);\\n}\\n.restore-preview__empty {\\n margin: 0 0 10px;\\n font-size: 13px;\\n color: var(--theme-elevation-600);\\n}\\n.restore-preview__list {\\n list-style: none;\\n margin: 0;\\n padding: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 10px;\\n}\\n.restore-preview__group {\\n padding: 9px 10px;\\n border-radius: 3px;\\n background: var(--theme-elevation-50, #fafafa);\\n border: 1px solid var(--theme-elevation-100);\\n}\\n.restore-preview__group--empty {\\n background: var(--theme-elevation-50, #fafafa);\\n border-color: var(--theme-elevation-100);\\n}\\n.restore-preview__group--empty .restore-preview__group-title {\\n color: var(--theme-elevation-500);\\n}\\n.restore-preview__group--empty .restore-preview__subline--empty {\\n color: var(--theme-elevation-500);\\n font-style: italic;\\n}\\n.restore-preview__group--disabled {\\n opacity: 0.55;\\n filter: saturate(0.7);\\n}\\n.restore-preview__group-head {\\n display: flex;\\n flex-direction: row;\\n flex-wrap: wrap;\\n align-items: center;\\n gap: 7px;\\n width: 100%;\\n margin: 0 0 2px;\\n}\\n.restore-preview__group-label {\\n display: flex;\\n flex-direction: row;\\n align-items: flex-start;\\n gap: 9px;\\n cursor: pointer;\\n margin: 0;\\n flex: 1;\\n min-width: 0;\\n}\\n.restore-preview__group-check {\\n appearance: none;\\n width: 14px;\\n height: 14px;\\n flex-shrink: 0;\\n margin-top: 3px;\\n border: 1px solid var(--theme-elevation-300);\\n background: var(--theme-input-bg);\\n border-radius: 3px;\\n cursor: pointer;\\n position: relative;\\n}\\n.restore-preview__group-check:checked {\\n border-color: var(--theme-elevation-800);\\n background-image: url(\\\"data:image/svg+xml,%3Csvg width='10' height='8' viewBox='0 0 10 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3.58333 7.5L0 3.91667L0.7 3.21667L3.58333 6.1L9.3 0.383333L10 1.08333L3.58333 7.5Z' fill='%23333333'/%3E%3C/svg%3E\\\");\\n background-repeat: no-repeat;\\n background-position: center;\\n background-size: 10px 8px;\\n}\\n.restore-preview__group-check:hover {\\n border-color: var(--theme-elevation-400);\\n}\\n.restore-preview__group-check:focus {\\n outline: none;\\n border-color: var(--theme-elevation-400);\\n}\\n.restore-preview__group-title {\\n font-size: 14px;\\n font-weight: 600;\\n color: var(--theme-elevation-900);\\n line-height: 1.35;\\n}\\n.restore-preview__sublines {\\n margin: 6px 0 0 32px;\\n display: flex;\\n flex-direction: column;\\n gap: 3px;\\n}\\n.restore-preview__subline {\\n font-size: 12px;\\n color: var(--theme-elevation-600);\\n line-height: 1.4;\\n}\\n.restore-preview__pills {\\n display: flex;\\n flex-wrap: wrap;\\n gap: 5px;\\n margin-top: 4px;\\n}\\n.restore-preview__pill {\\n font-size: 11px;\\n line-height: 1.2;\\n padding: 2px 6px;\\n border-radius: 999px;\\n background: var(--theme-elevation-150, #ececec);\\n color: var(--theme-elevation-700);\\n flex-shrink: 0;\\n}\\n.restore-preview__pill--signin {\\n background: var(--theme-warning-50, rgba(255, 193, 7, 0.28));\\n border: 1px solid var(--theme-warning-400, rgba(255, 152, 0, 0.55));\\n color: var(--theme-elevation-900);\\n font-weight: 500;\\n}\\n\\n@keyframes backup-shimmer {\\n 0% {\\n background-position: -220px 0;\\n }\\n 100% {\\n background-position: 220px 0;\\n }\\n}\\nbutton.backup-help-icon {\\n margin: 0;\\n padding: 0;\\n border: none;\\n font: inherit;\\n appearance: none;\\n}\\n\\n.backup-help-icon {\\n position: relative;\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n width: 16px;\\n height: 16px;\\n border-radius: 50%;\\n background-color: var(--theme-elevation-200);\\n color: var(--theme-elevation-600);\\n font-size: 11px;\\n font-style: normal;\\n cursor: help;\\n flex-shrink: 0;\\n user-select: none;\\n}\\n.backup-help-icon::after {\\n content: attr(data-tip);\\n position: absolute;\\n bottom: calc(100% + 6px);\\n left: 50%;\\n transform: translateX(-50%);\\n background: var(--theme-elevation-900);\\n color: var(--theme-elevation-0);\\n font-size: 11px;\\n line-height: 1.4;\\n white-space: nowrap;\\n padding: 4px 8px;\\n border-radius: 4px;\\n pointer-events: none;\\n opacity: 0;\\n transition: opacity 0.15s ease;\\n z-index: 100;\\n}\\n.backup-help-icon:hover::after {\\n opacity: 1;\\n}\\n.backup-help-icon {\\n /* Longer copy in settings / footers — wrap instead of one endless line */\\n}\\n.backup-help-icon--multiline::after {\\n white-space: normal;\\n text-align: left;\\n width: max-content;\\n max-width: min(280px, 85vw);\\n}\\n.backup-help-icon {\\n /* Settings modal body scrolls — absolute ::after gets clipped; anchor to viewport instead */\\n}\\n.backup-help-icon--settings-tooltip::after {\\n position: fixed;\\n left: var(--backup-tip-x, 50%);\\n top: var(--backup-tip-y, 0);\\n bottom: auto;\\n transform: translate(-50%, calc(-100% - 6px));\\n z-index: 2147483000;\\n}\\n\"\n"],"names":["backupDashboardInlineCss"],"mappings":"AAAA,+HAA+H,GAC/H,OAAO,MAAMA,2BAAmC,8x6BAA6x6B"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { BackupItemActions } from './BackupItemActions.client';
|
|
2
|
+
export { BackupListCollapsible } from './BackupListCollapsible.client';
|
|
3
|
+
export type { BackupListCollapsibleProps, SerializableBackupBlob, } from './BackupListCollapsible.client';
|
|
4
|
+
export { BackupSettingsModal } from './BackupSettingsModal.client';
|
|
5
|
+
export { ManualBackupDialog } from './ManualBackupDialog.client';
|
|
6
|
+
export { RestoreBackupDialog } from './RestoreBackupDialog.client';
|
|
7
|
+
export { TaskActionButton } from './TaskActionButton.client';
|
|
8
|
+
export type { TaskActionDangerConfirm } from './TaskActionButton.client';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
export { BackupItemActions } from './BackupItemActions.client';
|
|
3
|
+
export { BackupListCollapsible } from './BackupListCollapsible.client';
|
|
4
|
+
export { BackupSettingsModal } from './BackupSettingsModal.client';
|
|
5
|
+
export { ManualBackupDialog } from './ManualBackupDialog.client';
|
|
6
|
+
export { RestoreBackupDialog } from './RestoreBackupDialog.client';
|
|
7
|
+
export { TaskActionButton } from './TaskActionButton.client';
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=index.client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/BackupDashboard/index.client.tsx"],"sourcesContent":["'use client'\n\nexport { BackupItemActions } from './BackupItemActions.client'\nexport { BackupListCollapsible } from './BackupListCollapsible.client'\nexport type {\n BackupListCollapsibleProps,\n SerializableBackupBlob,\n} from './BackupListCollapsible.client'\nexport { BackupSettingsModal } from './BackupSettingsModal.client'\nexport { ManualBackupDialog } from './ManualBackupDialog.client'\nexport { RestoreBackupDialog } from './RestoreBackupDialog.client'\nexport { TaskActionButton } from './TaskActionButton.client'\nexport type { TaskActionDangerConfirm } from './TaskActionButton.client'\n"],"names":["BackupItemActions","BackupListCollapsible","BackupSettingsModal","ManualBackupDialog","RestoreBackupDialog","TaskActionButton"],"mappings":"AAAA;AAEA,SAASA,iBAAiB,QAAQ,6BAA4B;AAC9D,SAASC,qBAAqB,QAAQ,iCAAgC;AAKtE,SAASC,mBAAmB,QAAQ,+BAA8B;AAClE,SAASC,kBAAkB,QAAQ,8BAA6B;AAChE,SAASC,mBAAmB,QAAQ,+BAA8B;AAClE,SAASC,gBAAgB,QAAQ,4BAA2B"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { I18n } from '@payloadcms/translations';
|
|
2
|
+
interface BackupDashboardProps {
|
|
3
|
+
i18n: I18n;
|
|
4
|
+
/** Optional on admin server props; omitted does not mean logged out (see `defaultIsHidden`). */
|
|
5
|
+
user?: null | Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export declare const BackupDashboard: React.FC<BackupDashboardProps>;
|
|
8
|
+
export default BackupDashboard;
|