@trieb.work/payload-plugin-backup-mongodb 0.1.5 → 0.2.0
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 +260 -90
- package/dist/backup-dashboard.css +18 -1
- package/dist/collections/BackupTasks.js +8 -1
- package/dist/collections/BackupTasks.js.map +1 -1
- package/dist/components/BackupDashboard/BackupListCollapsible.client.js.map +1 -1
- package/dist/components/BackupDashboard/BackupSettingsModal.client.js +203 -115
- package/dist/components/BackupDashboard/BackupSettingsModal.client.js.map +1 -1
- package/dist/components/BackupDashboard/CollectionBackupPreviewBody.client.js.map +1 -1
- package/dist/components/BackupDashboard/RestoreBackupDialog.client.js +1 -1
- package/dist/components/BackupDashboard/RestoreBackupDialog.client.js.map +1 -1
- package/dist/components/BackupDashboard/TaskActionButton.client.d.ts +1 -1
- package/dist/components/BackupDashboard/TaskActionButton.client.js +59 -26
- package/dist/components/BackupDashboard/TaskActionButton.client.js.map +1 -1
- package/dist/components/BackupDashboard/backupDashboardInlineCss.js +1 -1
- package/dist/components/BackupDashboard/backupDashboardInlineCss.js.map +1 -1
- package/dist/components/BackupDashboard/index.js +27 -3
- package/dist/components/BackupDashboard/index.js.map +1 -1
- package/dist/core/archive.js.map +1 -1
- package/dist/core/backup.d.ts +4 -3
- package/dist/core/backup.js +50 -43
- package/dist/core/backup.js.map +1 -1
- package/dist/core/backupArchiveRead.d.ts +15 -0
- package/dist/core/backupArchiveRead.js +30 -0
- package/dist/core/backupArchiveRead.js.map +1 -0
- package/dist/core/backupBlobIO.js.map +1 -1
- package/dist/core/backupSettings.js +5 -0
- package/dist/core/backupSettings.js.map +1 -1
- package/dist/core/blobTokenValidate.js.map +1 -1
- package/dist/core/restore.d.ts +5 -2
- package/dist/core/restore.js +133 -89
- package/dist/core/restore.js.map +1 -1
- package/dist/core/restorePreview.d.ts +12 -3
- package/dist/core/restorePreview.js +17 -13
- package/dist/core/restorePreview.js.map +1 -1
- package/dist/core/restoreResult.d.ts +34 -0
- package/dist/core/restoreResult.js +45 -0
- package/dist/core/restoreResult.js.map +1 -0
- package/dist/core/storage/config.d.ts +31 -0
- package/dist/core/storage/config.js +60 -0
- package/dist/core/storage/config.js.map +1 -0
- package/dist/core/storage/index.d.ts +23 -0
- package/dist/core/storage/index.js +25 -0
- package/dist/core/storage/index.js.map +1 -0
- package/dist/core/storage/s3.d.ts +35 -0
- package/dist/core/storage/s3.js +200 -0
- package/dist/core/storage/s3.js.map +1 -0
- package/dist/core/storage/types.d.ts +60 -0
- package/dist/core/storage/types.js +6 -0
- package/dist/core/storage/types.js.map +1 -0
- package/dist/core/storage/vercelBlob.d.ts +25 -0
- package/dist/core/storage/vercelBlob.js +53 -0
- package/dist/core/storage/vercelBlob.js.map +1 -0
- package/dist/core/taskProgress.d.ts +10 -4
- package/dist/core/taskProgress.js +11 -2
- package/dist/core/taskProgress.js.map +1 -1
- package/dist/core/vercelBackupCron.js.map +1 -1
- package/dist/endpoints/index.js +0 -5
- package/dist/endpoints/index.js.map +1 -1
- package/dist/endpoints/paths/admin-backup-download.js +8 -7
- package/dist/endpoints/paths/admin-backup-download.js.map +1 -1
- package/dist/endpoints/paths/admin-delete.js +11 -5
- package/dist/endpoints/paths/admin-delete.js.map +1 -1
- package/dist/endpoints/paths/admin-manual.js +2 -1
- package/dist/endpoints/paths/admin-manual.js.map +1 -1
- package/dist/endpoints/paths/admin-preview.js +9 -2
- package/dist/endpoints/paths/admin-preview.js.map +1 -1
- package/dist/endpoints/paths/admin-restore.js +7 -4
- package/dist/endpoints/paths/admin-restore.js.map +1 -1
- package/dist/endpoints/paths/admin-settings.js +35 -2
- package/dist/endpoints/paths/admin-settings.js.map +1 -1
- package/dist/endpoints/paths/cron-list.js +2 -1
- package/dist/endpoints/paths/cron-list.js.map +1 -1
- package/dist/endpoints/paths/cron-restore.js +14 -4
- package/dist/endpoints/paths/cron-restore.js.map +1 -1
- package/dist/endpoints/paths/cron-run.js +2 -1
- package/dist/endpoints/paths/cron-run.js.map +1 -1
- package/dist/endpoints/shared.d.ts +0 -1
- package/dist/endpoints/shared.js +0 -6
- package/dist/endpoints/shared.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/plugin.js.map +1 -1
- package/dist/publicApiPaths.d.ts +0 -1
- package/dist/publicApiPaths.js +0 -1
- package/dist/publicApiPaths.js.map +1 -1
- package/dist/types.d.ts +0 -5
- package/dist/types.js.map +1 -1
- package/dist/utils/blobName.js.map +1 -1
- package/dist/utils/dashboardRoleAccess.js.map +1 -1
- package/dist/utils/dialogBackdrop.js.map +1 -1
- package/dist/utils/hostname.js.map +1 -1
- package/dist/utils/maskBlobToken.js.map +1 -1
- package/package.json +25 -4
- package/dist/endpoints/paths/admin-seed.d.ts +0 -3
- package/dist/endpoints/paths/admin-seed.js +0 -47
- package/dist/endpoints/paths/admin-seed.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/BackupDashboard/BackupSettingsModal.client.tsx"],"sourcesContent":["'use client'\n\nimport type { FC } from 'react'\n\nimport { Button } from '@payloadcms/ui'\nimport { useRouter } from 'next/navigation'\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react'\n\nimport type { BackupSourcePreviewResponse } from '../../core/backupSourcePreview'\nimport type { BackupTaskProgress } from '../../core/taskProgress'\n\nimport { backupPluginPublicApiPaths } from '../../publicApiPaths'\nimport { selectedFromSkipMongoNames, skipMongoNamesFromPreview } from '../../utils/backupSelection'\nimport { closeNativeDialogOnBackdropPointer } from '../../utils/dialogBackdrop'\nimport { CollectionBackupPreviewBody } from './CollectionBackupPreviewBody.client'\n\nfunction parseBlobTransferTaskMessage(msg: string): {\n failed: number\n pathname?: string\n total: number\n transferred: number\n} | null {\n try {\n const o = JSON.parse(msg) as Record<string, unknown>\n if (typeof o.total !== 'number' || typeof o.transferred !== 'number') {\n return null\n }\n return {\n failed: typeof o.failed === 'number' ? o.failed : 0,\n pathname: typeof o.pathname === 'string' ? o.pathname : undefined,\n total: o.total,\n transferred: o.transferred,\n }\n } catch {\n return null\n }\n}\n\nconst TIP_SETTINGS_SUBTITLE =\n 'These settings apply to scheduled (cron) backups only. Manual backups use the choices in the manual backup dialog each time you create one.'\n\nconst TIP_TRANSFER_COPY =\n 'When enabled, objects under backups/ are copied from the previous backup token (or from BLOB_READ_WRITE_TOKEN on first setup) into the new store. When disabled, only the new token is saved — existing backups stay in the old storage and remain reachable with the previous token.'\n\nconst TIP_TRANSFER_DELETE =\n 'Destructive: when enabled, each blob is removed from the old store only after a successful copy to the new store. Leave disabled to keep a full copy in the previous storage as a safety net.'\n\ninterface SettingsHelpTipProps {\n multiline?: boolean\n tip: string\n}\n\nfunction settingsHelpIconClassName(multiline?: boolean): string {\n return [\n 'backup-help-icon',\n 'backup-help-icon--settings-tooltip',\n multiline ? 'backup-help-icon--multiline' : '',\n ]\n .filter(Boolean)\n .join(' ')\n}\n\n/** Info icon + CSS tooltip; fixed positioning so scroll/clipping in the dialog body does not hide it. */\nconst SettingsHelpTip: FC<SettingsHelpTipProps> = ({ multiline, tip }) => {\n const elRef = useRef<HTMLButtonElement>(null)\n\n const syncTooltipAnchor = useCallback(() => {\n const el = elRef.current\n if (!el) {\n return\n }\n const r = el.getBoundingClientRect()\n el.style.setProperty('--backup-tip-x', `${r.left + r.width / 2}px`)\n el.style.setProperty('--backup-tip-y', `${r.top}px`)\n }, [])\n\n return (\n <button\n aria-label={tip}\n className={settingsHelpIconClassName(multiline)}\n data-tip={tip}\n onFocus={syncTooltipAnchor}\n onMouseEnter={syncTooltipAnchor}\n ref={elRef}\n title={tip}\n type=\"button\"\n >\n i\n </button>\n )\n}\n\ninterface BackupSettingsApiResponse {\n /** Persisted access level after the last successful token validation, or null. */\n backupBlobAccess?: 'private' | 'public' | null\n /** Either the persisted access level or a heuristic derived value (never null). */\n backupBlobAccessEffective?: 'private' | 'public'\n backupBlobTokenMasked?: string\n backupsToKeep?: number\n cron?: {\n configFileRelative: string\n humanDescription: null | string\n path: string\n schedule: string\n } | null\n effectiveBackupsToKeep?: number\n error?: string\n hasBackupBlobReadWriteToken?: boolean\n id?: string\n includeMediaForCron?: boolean\n pluginBackupsToKeepOverride?: boolean\n skipMongoCollections?: string[]\n transfer?: {\n deferred?: boolean\n failed: number\n performed: boolean\n pollSecret?: string\n skipped: number\n taskId?: string\n total: number\n transferred: number\n }\n}\n\nexport const BackupSettingsModal: FC = () => {\n const router = useRouter()\n const transferOptId = useId()\n const deleteSourceOptId = useId()\n const dialogRef = useRef<HTMLDialogElement>(null)\n const isPreparingOpenRef = useRef(false)\n const [preview, setPreview] = useState<BackupSourcePreviewResponse | null>(null)\n const [phase, setPhase] = useState<'error' | 'idle' | 'loading' | 'ready'>('idle')\n const [errorMessage, setErrorMessage] = useState<null | string>(null)\n const [selected, setSelected] = useState<Record<string, boolean>>({})\n const [backupAllCollections, setBackupAllCollections] = useState(false)\n const [includeMediaBlobs, setIncludeMediaBlobs] = useState(true)\n const [backupsToKeep, setBackupsToKeep] = useState(10)\n const [backupBlobReadWriteToken, setBackupBlobReadWriteToken] = useState('')\n /**\n * When saving a new raw token, copy backup blobs from the old store. Default on so rotating a\n * token automatically migrates existing archives; delete-from-source stays opt-in.\n */\n const [transferBackupBlobs, setTransferBackupBlobs] = useState(true)\n /**\n * When copying blobs into the new store, also delete them from the old store.\n * Default: off — the user must explicitly opt in to destructive behavior.\n */\n const [deleteBackupBlobsFromSource, setDeleteBackupBlobsFromSource] = useState(false)\n const [, setHasExistingBackupBlobToken] = useState(false)\n const [storedBackupBlobAccess, setStoredBackupBlobAccess] = useState<'private' | 'public' | null>(\n null,\n )\n const [effectiveBackupBlobAccess, setEffectiveBackupBlobAccess] = useState<\n 'private' | 'public' | null\n >(null)\n const [tokenCheck, setTokenCheck] = useState<{\n access?: 'private' | 'public'\n message?: string\n status: 'checking' | 'idle' | 'invalid' | 'valid'\n }>({ status: 'idle' })\n const [pluginOverridesRetention, setPluginOverridesRetention] = useState(false)\n const [cronInfo, setCronInfo] = useState<BackupSettingsApiResponse['cron'] | undefined>(undefined)\n const [transferSummary, setTransferSummary] = useState<\n BackupSettingsApiResponse['transfer'] | null\n >(null)\n const [activeTransfer, setActiveTransfer] = useState<{\n pollSecret: string\n taskId: string\n total: number\n } | null>(null)\n const [transferLive, setTransferLive] = useState<{\n failed: number\n pathname?: string\n total: number\n transferred: number\n } | null>(null)\n const [savePhase, setSavePhase] = useState<\n 'error' | 'idle' | 'saved' | 'saving' | 'transferring'\n >('idle')\n const [saveError, setSaveError] = useState<null | string>(null)\n const [isPreparingOpen, setIsPreparingOpen] = useState(false)\n\n const resetState = useCallback(() => {\n setPreview(null)\n setPhase('idle')\n setErrorMessage(null)\n setSelected({})\n setBackupAllCollections(false)\n setIncludeMediaBlobs(false)\n setBackupsToKeep(10)\n setBackupBlobReadWriteToken('')\n setTransferBackupBlobs(true)\n setDeleteBackupBlobsFromSource(false)\n setHasExistingBackupBlobToken(false)\n setStoredBackupBlobAccess(null)\n setEffectiveBackupBlobAccess(null)\n setTokenCheck({ status: 'idle' })\n setPluginOverridesRetention(false)\n setCronInfo(undefined)\n setTransferSummary(null)\n setActiveTransfer(null)\n setTransferLive(null)\n setSavePhase('idle')\n setSaveError(null)\n isPreparingOpenRef.current = false\n setIsPreparingOpen(false)\n }, [])\n\n useEffect(() => {\n const el = dialogRef.current\n if (!el) {\n return\n }\n const onClose = () => resetState()\n el.addEventListener('close', onClose)\n return () => el.removeEventListener('close', onClose)\n }, [resetState])\n\n const fetchSettingsAndPreview = useCallback(async () => {\n const locale =\n typeof document !== 'undefined' ? (document.documentElement.lang || 'en').slice(0, 2) : 'en'\n const [settingsRes, previewRes] = await Promise.all([\n fetch(backupPluginPublicApiPaths.adminSettings, { method: 'GET' }),\n fetch(backupPluginPublicApiPaths.adminBackupPreview, {\n body: JSON.stringify({ locale }),\n headers: { 'Content-Type': 'application/json' },\n method: 'POST',\n }),\n ])\n\n const settingsJson = (await settingsRes.json()) as BackupSettingsApiResponse\n if (!settingsRes.ok) {\n throw new Error(settingsJson.error || 'Could not load settings')\n }\n\n const previewJson = (await previewRes.json()) as {\n error?: string\n } & BackupSourcePreviewResponse\n if (!previewRes.ok) {\n throw new Error(previewJson.error || 'Could not load collections')\n }\n\n return { previewJson, settingsJson }\n }, [])\n\n const applyLoadedSettingsPreview = useCallback(\n (settingsJson: BackupSettingsApiResponse, previewJson: BackupSourcePreviewResponse) => {\n setActiveTransfer(null)\n setTransferLive(null)\n setPreview(previewJson)\n setBackupsToKeep(\n typeof settingsJson.backupsToKeep === 'number' ? settingsJson.backupsToKeep : 10,\n )\n setBackupBlobReadWriteToken(settingsJson.backupBlobTokenMasked || '')\n setHasExistingBackupBlobToken(settingsJson.hasBackupBlobReadWriteToken === true)\n setStoredBackupBlobAccess(settingsJson.backupBlobAccess ?? null)\n setEffectiveBackupBlobAccess(settingsJson.backupBlobAccessEffective ?? null)\n setTokenCheck({ status: 'idle' })\n setPluginOverridesRetention(settingsJson.pluginBackupsToKeepOverride === true)\n setCronInfo(settingsJson.cron ?? null)\n setIncludeMediaBlobs(settingsJson.includeMediaForCron === true)\n\n const skip = Array.isArray(settingsJson.skipMongoCollections)\n ? settingsJson.skipMongoCollections\n : []\n setSelected(selectedFromSkipMongoNames(previewJson, skip))\n setBackupAllCollections(skip.length === 0)\n setTransferBackupBlobs(true)\n setDeleteBackupBlobsFromSource(false)\n setPhase('ready')\n },\n [],\n )\n\n const loadPreview = useCallback(async () => {\n setPhase('loading')\n setErrorMessage(null)\n setPreview(null)\n setCronInfo(undefined)\n try {\n const { previewJson, settingsJson } = await fetchSettingsAndPreview()\n applyLoadedSettingsPreview(settingsJson, previewJson)\n } catch (e) {\n setPhase('error')\n setErrorMessage(e instanceof Error ? e.message : 'Could not load backup settings')\n }\n }, [applyLoadedSettingsPreview, fetchSettingsAndPreview])\n\n const openDialog = useCallback(() => {\n if (isPreparingOpenRef.current) {\n return\n }\n isPreparingOpenRef.current = true\n setSavePhase('idle')\n setSaveError(null)\n setIsPreparingOpen(true)\n void (async () => {\n try {\n const { previewJson, settingsJson } = await fetchSettingsAndPreview()\n applyLoadedSettingsPreview(settingsJson, previewJson)\n dialogRef.current?.showModal()\n } catch (e) {\n setPhase('error')\n setErrorMessage(e instanceof Error ? e.message : 'Could not load backup settings')\n setPreview(null)\n setCronInfo(undefined)\n dialogRef.current?.showModal()\n } finally {\n isPreparingOpenRef.current = false\n setIsPreparingOpen(false)\n }\n })()\n }, [applyLoadedSettingsPreview, fetchSettingsAndPreview])\n\n const skipCollections = useMemo(() => {\n if (!preview) {\n return []\n }\n if (backupAllCollections) {\n return []\n }\n return skipMongoNamesFromPreview(preview, selected)\n }, [backupAllCollections, preview, selected])\n\n const mediaGroupIncluded = preview ? backupAllCollections || selected['media'] !== false : false\n const hasMediaBlobOption = Boolean(\n preview && preview.mediaBlobCandidates > 0 && mediaGroupIncluded,\n )\n\n const willSaveNewRawToken = useMemo(\n () => backupBlobReadWriteToken.trim().length > 0 && !/\\*{2,}/.test(backupBlobReadWriteToken),\n [backupBlobReadWriteToken],\n )\n\n const onChangeBackupBlobToken = useCallback((value: string) => {\n setBackupBlobReadWriteToken(value)\n setTokenCheck({ status: 'idle' })\n }, [])\n\n // Auto-validate a freshly pasted/typed token after a short debounce. The masked token coming\n // from the server (contains \"**\") never triggers this because `willSaveNewRawToken` stays false.\n useEffect(() => {\n if (!willSaveNewRawToken) {\n setTokenCheck((prev) => (prev.status === 'idle' ? prev : { status: 'idle' }))\n return\n }\n\n const candidate = backupBlobReadWriteToken.trim()\n if (!candidate) {\n return\n }\n\n let cancelled = false\n const timer = window.setTimeout(async () => {\n if (cancelled) {\n return\n }\n setTokenCheck({ status: 'checking' })\n try {\n const response = await fetch(backupPluginPublicApiPaths.adminValidateBlobToken, {\n body: JSON.stringify({ token: candidate }),\n headers: { 'Content-Type': 'application/json' },\n method: 'POST',\n })\n if (cancelled) {\n return\n }\n const data = (await response.json()) as {\n access?: 'private' | 'public'\n error?: string\n ok?: boolean\n }\n if (cancelled) {\n return\n }\n if (response.ok && data.ok && (data.access === 'public' || data.access === 'private')) {\n setTokenCheck({ access: data.access, status: 'valid' })\n } else {\n setTokenCheck({ message: data.error || 'Token rejected', status: 'invalid' })\n }\n } catch (error) {\n if (cancelled) {\n return\n }\n setTokenCheck({\n message: error instanceof Error ? error.message : 'Token validation failed',\n status: 'invalid',\n })\n }\n }, 150)\n\n return () => {\n cancelled = true\n window.clearTimeout(timer)\n }\n }, [backupBlobReadWriteToken, willSaveNewRawToken])\n\n const blockSaveForTokenCheck =\n willSaveNewRawToken && (tokenCheck.status === 'checking' || tokenCheck.status === 'invalid')\n\n const tokenStatusPill = (() => {\n if (willSaveNewRawToken) {\n if (tokenCheck.status === 'checking') {\n return <span className=\"backup-item__pill backup-item__pill--neutral\">Checking…</span>\n }\n if (tokenCheck.status === 'valid' && tokenCheck.access) {\n return (\n <span\n className={`backup-item__pill backup-item__pill--${\n tokenCheck.access === 'private' ? 'cron' : 'manual'\n }`}\n >\n {tokenCheck.access === 'private' ? 'Private' : 'Public'}\n </span>\n )\n }\n if (tokenCheck.status === 'invalid') {\n return <span className=\"backup-item__pill backup-item__pill--danger\">Invalid</span>\n }\n return null\n }\n if (effectiveBackupBlobAccess) {\n return (\n <span\n className={`backup-item__pill backup-item__pill--${\n effectiveBackupBlobAccess === 'private' ? 'cron' : 'manual'\n }`}\n title={\n storedBackupBlobAccess\n ? 'Detected and persisted after last validation'\n : 'Heuristic fallback — will be re-validated when saving a new token'\n }\n >\n {effectiveBackupBlobAccess === 'private' ? 'Private' : 'Public'}\n </span>\n )\n }\n return null\n })()\n\n const includeMediaForCron = useMemo(() => {\n if (!hasMediaBlobOption) {\n return false\n }\n return includeMediaBlobs\n }, [hasMediaBlobOption, includeMediaBlobs])\n\n const onToggleGroup = useCallback((groupId: string) => {\n setSelected((prev) => {\n const isOn = prev[groupId] !== false\n return { ...prev, [groupId]: !isOn }\n })\n }, [])\n\n const onToggleBackupAllCollections = useCallback(() => {\n setBackupAllCollections((prev) => {\n const next = !prev\n if (next && preview) {\n setSelected(Object.fromEntries(preview.groups.map((g) => [g.groupId, true])))\n }\n return next\n })\n }, [preview])\n\n const save = useCallback(async () => {\n if (!preview) {\n return\n }\n setSavePhase('saving')\n setSaveError(null)\n setTransferSummary(null)\n setActiveTransfer(null)\n setTransferLive(null)\n try {\n const response = await fetch(backupPluginPublicApiPaths.adminSettings, {\n body: JSON.stringify({\n backupBlobReadWriteToken,\n backupsToKeep,\n deleteBackupBlobsFromSource: transferBackupBlobs && deleteBackupBlobsFromSource,\n includeMediaForCron,\n skipMongoCollections: skipCollections,\n transferBackupBlobs,\n }),\n headers: { 'Content-Type': 'application/json' },\n method: 'PATCH',\n })\n const data = (await response.json()) as BackupSettingsApiResponse\n if (!response.ok) {\n throw new Error(data.error || 'Save failed')\n }\n\n setHasExistingBackupBlobToken(data.hasBackupBlobReadWriteToken === true)\n setBackupBlobReadWriteToken(data.backupBlobTokenMasked || '')\n setStoredBackupBlobAccess(data.backupBlobAccess ?? null)\n setEffectiveBackupBlobAccess(data.backupBlobAccessEffective ?? null)\n setTokenCheck({ status: 'idle' })\n\n const tr = data.transfer\n if (tr?.performed && tr.deferred && tr.taskId && tr.pollSecret) {\n setActiveTransfer({ pollSecret: tr.pollSecret, taskId: tr.taskId, total: tr.total })\n setTransferLive({ failed: 0, total: tr.total, transferred: 0 })\n setSavePhase('transferring')\n return\n }\n\n setTransferSummary(tr ?? null)\n setSavePhase('saved')\n router.refresh()\n if (!tr?.performed) {\n window.setTimeout(() => {\n setSavePhase('idle')\n dialogRef.current?.close()\n }, 800)\n } else {\n window.setTimeout(() => {\n setSavePhase('idle')\n dialogRef.current?.close()\n }, 1200)\n }\n } catch (e) {\n setSavePhase('error')\n setSaveError(e instanceof Error ? e.message : 'Save failed')\n }\n }, [\n preview,\n backupsToKeep,\n backupBlobReadWriteToken,\n skipCollections,\n includeMediaForCron,\n transferBackupBlobs,\n deleteBackupBlobsFromSource,\n router,\n ])\n\n useEffect(() => {\n if (!activeTransfer) {\n return\n }\n\n let cancelled = false\n let intervalId: null | number = null\n let successCloseTimer: null | number = null\n\n const stopPolling = () => {\n if (intervalId != null) {\n window.clearInterval(intervalId)\n intervalId = null\n }\n }\n\n const pollOnce = async () => {\n const res = await fetch(backupPluginPublicApiPaths.adminTask(activeTransfer.taskId), {\n cache: 'no-store',\n headers: { Authorization: `Bearer ${activeTransfer.pollSecret}` },\n })\n if (!res.ok || cancelled) {\n return\n }\n const task = (await res.json()) as BackupTaskProgress\n const parsed = parseBlobTransferTaskMessage(task.message)\n if (parsed) {\n setTransferLive({\n failed: parsed.failed,\n pathname: parsed.pathname,\n total: parsed.total,\n transferred: parsed.transferred,\n })\n }\n if (task.status === 'completed') {\n stopPolling()\n const final = parseBlobTransferTaskMessage(task.message)\n setTransferSummary({\n deferred: false,\n failed: final?.failed ?? 0,\n performed: true,\n skipped: 0,\n total: final?.total ?? activeTransfer.total,\n transferred: final?.transferred ?? 0,\n })\n setActiveTransfer(null)\n setTransferLive(null)\n setSavePhase('saved')\n try {\n const settingsRes = await fetch(backupPluginPublicApiPaths.adminSettings, {\n method: 'GET',\n })\n const refreshed = (await settingsRes.json()) as BackupSettingsApiResponse\n if (settingsRes.ok) {\n setBackupBlobReadWriteToken(refreshed.backupBlobTokenMasked || '')\n setHasExistingBackupBlobToken(refreshed.hasBackupBlobReadWriteToken === true)\n }\n } catch {\n /* ignore */\n }\n router.refresh()\n successCloseTimer = window.setTimeout(() => {\n successCloseTimer = null\n setSavePhase('idle')\n setTransferSummary(null)\n dialogRef.current?.close()\n }, 1400)\n return\n }\n if (task.status === 'failed') {\n stopPolling()\n setSavePhase('error')\n setSaveError(task.error || task.message || 'Transfer failed')\n setActiveTransfer(null)\n setTransferLive(null)\n }\n }\n\n intervalId = window.setInterval(() => void pollOnce(), 900)\n void pollOnce()\n return () => {\n cancelled = true\n stopPolling()\n if (successCloseTimer != null) {\n window.clearTimeout(successCloseTimer)\n }\n }\n }, [activeTransfer, router])\n\n const retentionDisabled = pluginOverridesRetention\n\n return (\n <>\n <Button buttonStyle=\"secondary\" disabled={isPreparingOpen} onClick={openDialog} size=\"small\">\n {isPreparingOpen ? 'Loading…' : 'Backup settings'}\n </Button>\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--settings\"\n onMouseDown={(e) => closeNativeDialogOnBackdropPointer(e, dialogRef)}\n ref={dialogRef}\n >\n <p className=\"backup-confirm-dialog__title\">Scheduled backup settings</p>\n <p className=\"backup-confirm-dialog__subtitle backup-confirm-dialog__subtitle--with-help\">\n <span className=\"backup-confirm-dialog__subtitle-text\">{TIP_SETTINGS_SUBTITLE}</span>\n </p>\n\n <div className=\"backup-confirm-dialog__body restore-preview\">\n {phase !== 'idle' ? (\n <>\n <p className=\"restore-preview__sticky-heading\">Schedule</p>\n {phase === 'loading' ? (\n <div\n aria-live=\"polite\"\n className=\"restore-preview__loading-block restore-preview__loading-block--section\"\n >\n <p className=\"restore-preview__status\">Loading cron configuration…</p>\n <div className=\"restore-preview__loading-line\" />\n <div className=\"restore-preview__loading-line restore-preview__loading-line--short\" />\n </div>\n ) : phase === 'error' ? (\n <p className=\"restore-preview__intro\">Schedule details could not be loaded.</p>\n ) : cronInfo ? (\n <>\n <p className=\"restore-preview__intro\">\n Active job: <code>{cronInfo.configFileRelative}</code> — edit and redeploy to\n change the schedule.\n </p>\n <div aria-label=\"Configured schedule\" className=\"restore-preview__settings-block\">\n <p className=\"restore-preview__settings-row\">\n <span className=\"restore-preview__settings-k\">HTTP path</span>{' '}\n <code>{cronInfo.path}</code>\n </p>\n <p className=\"restore-preview__settings-row\">\n <span className=\"restore-preview__settings-k\">Cron expression</span>{' '}\n <code>{cronInfo.schedule}</code>\n </p>\n {cronInfo.humanDescription ? (\n <p className=\"restore-preview__settings-human\">{cronInfo.humanDescription}</p>\n ) : (\n <p className=\"restore-preview__settings-human restore-preview__settings-human--muted\">\n Could not turn the cron expression into a short description.\n </p>\n )}\n </div>\n </>\n ) : (\n <>\n <p className=\"restore-preview__intro\">\n No vercel <code>crons</code> entry for the backup path yet. You can either setup\n an external service to call /api/backup-mongodb/cron/run with your cron secret\n or use Vercel. To use vercel create a file <code>vercel.json</code> in your\n project root with the following content:\n </p>\n <p className=\"restore-preview__settings-hint\">Example</p>\n <pre className=\"restore-preview__settings-snippet\">{`{\n \"crons\": [\n {\n \"path\": \"/api/backup-mongodb/cron/run\",\n \"schedule\": \"0 3 * * *\"\n }\n ]\n}`}</pre>\n <p>\n Then add a <code>CRON_SECRET</code> environment variable to your Vercel project\n and redeploy on Vercel so the cron job is registered.\n </p>\n </>\n )}\n </>\n ) : null}\n\n <p className=\"restore-preview__sticky-heading\">Retention</p>\n <p className=\"restore-preview__intro\">\n {retentionDisabled ? (\n <>\n Locked by <code>backupMongodbPlugin({'{ backupsToKeep }'})</code> in Payload config.\n </>\n ) : (\n <>Oldest cron archives are deleted once the count exceeds this limit.</>\n )}\n </p>\n <div className=\"restore-preview__settings-fields\">\n <label className=\"restore-preview__settings-label\" htmlFor=\"backups-to-keep\">\n Cron backups to keep\n </label>\n <input\n aria-label=\"Cron backups to keep\"\n className=\"restore-preview__settings-input\"\n disabled={retentionDisabled}\n id=\"backups-to-keep\"\n max={365}\n min={1}\n onChange={(e) => setBackupsToKeep(Number(e.target.value) || 1)}\n type=\"number\"\n value={backupsToKeep}\n />\n </div>\n\n <p className=\"restore-preview__sticky-heading\">\n Dedicated backup storage{' '}\n <span className=\"restore-preview__sticky-heading-hint\">(optional)</span>\n </p>\n <p className=\"restore-preview__intro\">\n Separate Vercel Blob token for <code>backups/</code>. Without one, archives share the\n default media store.\n </p>\n <div className=\"restore-preview__settings-fields\">\n <label className=\"restore-preview__settings-label\" htmlFor=\"backup-blob-token\">\n Backup Blob read/write token\n </label>\n <div className=\"restore-preview__blob-token-row\">\n <input\n aria-label=\"Backup Blob read/write token\"\n autoComplete=\"off\"\n className=\"restore-preview__settings-input restore-preview__settings-input--wide\"\n id=\"backup-blob-token\"\n onChange={(e) => onChangeBackupBlobToken(e.target.value)}\n placeholder=\"vercel_blob_rw_...\"\n spellCheck={false}\n type=\"text\"\n value={backupBlobReadWriteToken}\n />\n <span className=\"restore-preview__blob-token-pill-slot\">{tokenStatusPill}</span>\n </div>\n {tokenCheck.status === 'invalid' && tokenCheck.message ? (\n <p aria-live=\"polite\" className=\"restore-preview__blob-token-error\">\n {tokenCheck.message}\n </p>\n ) : null}\n {savePhase === 'transferring' && transferLive && transferLive.total > 0 ? (\n <div aria-live=\"polite\" className=\"restore-preview__transfer-panel\">\n <div className=\"restore-preview__transfer-bar-track\">\n <div\n className=\"restore-preview__transfer-bar-fill\"\n style={{\n width: `${Math.min(\n 100,\n ((transferLive.transferred + transferLive.failed) / transferLive.total) *\n 100,\n )}%`,\n }}\n />\n </div>\n <p className=\"restore-preview__transfer-meta\">\n Copying backup files: {transferLive.transferred + transferLive.failed} /{' '}\n {transferLive.total}\n {transferLive.failed > 0 ? ` (${transferLive.failed} failed)` : ''}\n {transferLive.pathname ? (\n <>\n <br />\n <span\n className=\"restore-preview__transfer-path\"\n title={transferLive.pathname}\n >\n {transferLive.pathname.length > 56\n ? `${transferLive.pathname.slice(0, 28)}…${transferLive.pathname.slice(-24)}`\n : transferLive.pathname}\n </span>\n </>\n ) : null}\n </p>\n </div>\n ) : null}\n {willSaveNewRawToken ? (\n <>\n <div className=\"field-type checkbox backup-dashboard__collapsible-checkbox restore-preview__blob-transfer-row restore-preview__blob-transfer-row--with-help-tip\">\n <input\n aria-label=\"Copy existing backup files into this storage when saving\"\n checked={transferBackupBlobs}\n className=\"checkbox-input__input\"\n id={transferOptId}\n onChange={(e) => setTransferBackupBlobs(e.target.checked)}\n type=\"checkbox\"\n />\n <label className=\"field-label\" htmlFor={transferOptId}>\n Copy existing backup files into this storage when saving\n </label>\n <SettingsHelpTip multiline tip={TIP_TRANSFER_COPY} />\n </div>\n {transferBackupBlobs ? (\n <div className=\"field-type checkbox backup-dashboard__collapsible-checkbox restore-preview__blob-transfer-row restore-preview__blob-transfer-row--with-help-tip\">\n <input\n aria-label=\"Delete from previous storage after successful copy\"\n checked={deleteBackupBlobsFromSource}\n className=\"checkbox-input__input\"\n id={deleteSourceOptId}\n onChange={(e) => setDeleteBackupBlobsFromSource(e.target.checked)}\n type=\"checkbox\"\n />\n <label className=\"field-label\" htmlFor={deleteSourceOptId}>\n Delete from previous storage after successful copy\n </label>\n <SettingsHelpTip multiline tip={TIP_TRANSFER_DELETE} />\n </div>\n ) : null}\n </>\n ) : null}\n </div>\n\n <CollectionBackupPreviewBody\n embedded\n errorMessage={errorMessage}\n includeAllCollections={backupAllCollections}\n includeAllLabel=\"Backup all collections\"\n includeMediaBlobs={includeMediaBlobs}\n onRetry={loadPreview}\n onToggleGroup={onToggleGroup}\n onToggleIncludeAllCollections={onToggleBackupAllCollections}\n onToggleIncludeMedia={() => setIncludeMediaBlobs((v) => !v)}\n phase={phase}\n preview={preview}\n selected={selected}\n />\n\n {saveError ? (\n <p className=\"restore-preview__error restore-preview__error--inline\">{saveError}</p>\n ) : null}\n {savePhase === 'saving' ? (\n <p className=\"restore-preview__status restore-preview__status--footer\">\n Saving settings…\n </p>\n ) : null}\n {transferSummary?.performed ? (\n <p className=\"restore-preview__status restore-preview__status--footer\">\n Migrated backups: {transferSummary.transferred}/{transferSummary.total}\n {transferSummary.failed > 0 ? `, failed: ${transferSummary.failed}` : ''}\n </p>\n ) : null}\n </div>\n\n <div className=\"backup-confirm-dialog__actions\">\n <Button\n buttonStyle=\"primary\"\n disabled={\n phase !== 'ready' ||\n savePhase === 'saving' ||\n savePhase === 'transferring' ||\n blockSaveForTokenCheck\n }\n onClick={() => void save()}\n size=\"small\"\n >\n {savePhase === 'transferring'\n ? 'Transferring…'\n : savePhase === 'saving'\n ? 'Saving…'\n : savePhase === 'saved'\n ? 'Saved'\n : 'Save settings'}\n </Button>\n <Button buttonStyle=\"secondary\" onClick={() => dialogRef.current?.close()} size=\"small\">\n Cancel\n </Button>\n </div>\n </dialog>\n </>\n )\n}\n"],"names":["Button","useRouter","useCallback","useEffect","useId","useMemo","useRef","useState","backupPluginPublicApiPaths","selectedFromSkipMongoNames","skipMongoNamesFromPreview","closeNativeDialogOnBackdropPointer","CollectionBackupPreviewBody","parseBlobTransferTaskMessage","msg","o","JSON","parse","total","transferred","failed","pathname","undefined","TIP_SETTINGS_SUBTITLE","TIP_TRANSFER_COPY","TIP_TRANSFER_DELETE","settingsHelpIconClassName","multiline","filter","Boolean","join","SettingsHelpTip","tip","elRef","syncTooltipAnchor","el","current","r","getBoundingClientRect","style","setProperty","left","width","top","button","aria-label","className","data-tip","onFocus","onMouseEnter","ref","title","type","BackupSettingsModal","router","transferOptId","deleteSourceOptId","dialogRef","isPreparingOpenRef","preview","setPreview","phase","setPhase","errorMessage","setErrorMessage","selected","setSelected","backupAllCollections","setBackupAllCollections","includeMediaBlobs","setIncludeMediaBlobs","backupsToKeep","setBackupsToKeep","backupBlobReadWriteToken","setBackupBlobReadWriteToken","transferBackupBlobs","setTransferBackupBlobs","deleteBackupBlobsFromSource","setDeleteBackupBlobsFromSource","setHasExistingBackupBlobToken","storedBackupBlobAccess","setStoredBackupBlobAccess","effectiveBackupBlobAccess","setEffectiveBackupBlobAccess","tokenCheck","setTokenCheck","status","pluginOverridesRetention","setPluginOverridesRetention","cronInfo","setCronInfo","transferSummary","setTransferSummary","activeTransfer","setActiveTransfer","transferLive","setTransferLive","savePhase","setSavePhase","saveError","setSaveError","isPreparingOpen","setIsPreparingOpen","resetState","onClose","addEventListener","removeEventListener","fetchSettingsAndPreview","locale","document","documentElement","lang","slice","settingsRes","previewRes","Promise","all","fetch","adminSettings","method","adminBackupPreview","body","stringify","headers","settingsJson","json","ok","Error","error","previewJson","applyLoadedSettingsPreview","backupBlobTokenMasked","hasBackupBlobReadWriteToken","backupBlobAccess","backupBlobAccessEffective","pluginBackupsToKeepOverride","cron","includeMediaForCron","skip","Array","isArray","skipMongoCollections","length","loadPreview","e","message","openDialog","showModal","skipCollections","mediaGroupIncluded","hasMediaBlobOption","mediaBlobCandidates","willSaveNewRawToken","trim","test","onChangeBackupBlobToken","value","prev","candidate","cancelled","timer","window","setTimeout","response","adminValidateBlobToken","token","data","access","clearTimeout","blockSaveForTokenCheck","tokenStatusPill","span","onToggleGroup","groupId","isOn","onToggleBackupAllCollections","next","Object","fromEntries","groups","map","g","save","tr","transfer","performed","deferred","taskId","pollSecret","refresh","close","intervalId","successCloseTimer","stopPolling","clearInterval","pollOnce","res","adminTask","cache","Authorization","task","parsed","final","skipped","refreshed","setInterval","retentionDisabled","buttonStyle","disabled","onClick","size","dialog","onMouseDown","p","div","aria-live","code","configFileRelative","path","schedule","humanDescription","pre","label","htmlFor","input","id","max","min","onChange","Number","target","autoComplete","placeholder","spellCheck","Math","br","checked","embedded","includeAllCollections","includeAllLabel","onRetry","onToggleIncludeAllCollections","onToggleIncludeMedia","v"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/BackupDashboard/BackupSettingsModal.client.tsx"],"sourcesContent":["'use client'\n\nimport type { FC } from 'react'\n\nimport { Button } from '@payloadcms/ui'\nimport { useRouter } from 'next/navigation'\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react'\n\nimport type { BackupSourcePreviewResponse } from '../../core/backupSourcePreview'\nimport type { BackupTaskProgress } from '../../core/taskProgress'\n\nimport { backupPluginPublicApiPaths } from '../../publicApiPaths'\nimport { selectedFromSkipMongoNames, skipMongoNamesFromPreview } from '../../utils/backupSelection'\nimport { closeNativeDialogOnBackdropPointer } from '../../utils/dialogBackdrop'\nimport { CollectionBackupPreviewBody } from './CollectionBackupPreviewBody.client'\n\nfunction parseBlobTransferTaskMessage(msg: string): {\n failed: number\n pathname?: string\n total: number\n transferred: number\n} | null {\n try {\n const o = JSON.parse(msg) as Record<string, unknown>\n if (typeof o.total !== 'number' || typeof o.transferred !== 'number') {\n return null\n }\n return {\n failed: typeof o.failed === 'number' ? o.failed : 0,\n pathname: typeof o.pathname === 'string' ? o.pathname : undefined,\n total: o.total,\n transferred: o.transferred,\n }\n } catch {\n return null\n }\n}\n\nconst TIP_SETTINGS_SUBTITLE =\n 'These settings apply to scheduled (cron) backups only. Manual backups use the choices in the manual backup dialog each time you create one.'\n\nconst TIP_TRANSFER_COPY =\n 'When enabled, objects under backups/ are copied from the previous backup token (or from BLOB_READ_WRITE_TOKEN on first setup) into the new store. When disabled, only the new token is saved — existing backups stay in the old storage and remain reachable with the previous token.'\n\nconst TIP_TRANSFER_DELETE =\n 'Destructive: when enabled, each blob is removed from the old store only after a successful copy to the new store. Leave disabled to keep a full copy in the previous storage as a safety net.'\n\ninterface SettingsHelpTipProps {\n multiline?: boolean\n tip: string\n}\n\nfunction settingsHelpIconClassName(multiline?: boolean): string {\n return [\n 'backup-help-icon',\n 'backup-help-icon--settings-tooltip',\n multiline ? 'backup-help-icon--multiline' : '',\n ]\n .filter(Boolean)\n .join(' ')\n}\n\n/** Info icon + CSS tooltip; fixed positioning so scroll/clipping in the dialog body does not hide it. */\nconst SettingsHelpTip: FC<SettingsHelpTipProps> = ({ multiline, tip }) => {\n const elRef = useRef<HTMLButtonElement>(null)\n\n const syncTooltipAnchor = useCallback(() => {\n const el = elRef.current\n if (!el) {\n return\n }\n const r = el.getBoundingClientRect()\n el.style.setProperty('--backup-tip-x', `${r.left + r.width / 2}px`)\n el.style.setProperty('--backup-tip-y', `${r.top}px`)\n }, [])\n\n return (\n <button\n aria-label={tip}\n className={settingsHelpIconClassName(multiline)}\n data-tip={tip}\n onFocus={syncTooltipAnchor}\n onMouseEnter={syncTooltipAnchor}\n ref={elRef}\n title={tip}\n type=\"button\"\n >\n i\n </button>\n )\n}\n\ninterface BackupSettingsApiResponse {\n /** Persisted access level after the last successful token validation, or null. */\n backupBlobAccess?: 'private' | 'public' | null\n /** Either the persisted access level or a heuristic derived value (never null). */\n backupBlobAccessEffective?: 'private' | 'public'\n backupBlobTokenMasked?: string\n backupsToKeep?: number\n cron?: {\n configFileRelative: string\n humanDescription: null | string\n path: string\n schedule: string\n } | null\n effectiveBackupsToKeep?: number\n error?: string\n hasBackupBlobReadWriteToken?: boolean\n id?: string\n includeMediaForCron?: boolean\n pluginBackupsToKeepOverride?: boolean\n skipMongoCollections?: string[]\n storage?: {\n kind: 's3' | 'vercel-blob'\n s3?: {\n bucket: string\n endpoint?: string\n prefix?: string\n region: string\n } | null\n }\n transfer?: {\n deferred?: boolean\n failed: number\n performed: boolean\n pollSecret?: string\n skipped: number\n taskId?: string\n total: number\n transferred: number\n }\n}\n\nexport const BackupSettingsModal: FC = () => {\n const router = useRouter()\n const transferOptId = useId()\n const deleteSourceOptId = useId()\n const dialogRef = useRef<HTMLDialogElement>(null)\n const isPreparingOpenRef = useRef(false)\n const [preview, setPreview] = useState<BackupSourcePreviewResponse | null>(null)\n const [phase, setPhase] = useState<'error' | 'idle' | 'loading' | 'ready'>('idle')\n const [errorMessage, setErrorMessage] = useState<null | string>(null)\n const [selected, setSelected] = useState<Record<string, boolean>>({})\n const [backupAllCollections, setBackupAllCollections] = useState(false)\n const [includeMediaBlobs, setIncludeMediaBlobs] = useState(true)\n const [backupsToKeep, setBackupsToKeep] = useState(10)\n const [backupBlobReadWriteToken, setBackupBlobReadWriteToken] = useState('')\n /**\n * When saving a new raw token, copy backup blobs from the old store. Default on so rotating a\n * token automatically migrates existing archives; delete-from-source stays opt-in.\n */\n const [transferBackupBlobs, setTransferBackupBlobs] = useState(true)\n /**\n * When copying blobs into the new store, also delete them from the old store.\n * Default: off — the user must explicitly opt in to destructive behavior.\n */\n const [deleteBackupBlobsFromSource, setDeleteBackupBlobsFromSource] = useState(false)\n const [, setHasExistingBackupBlobToken] = useState(false)\n const [storedBackupBlobAccess, setStoredBackupBlobAccess] = useState<'private' | 'public' | null>(\n null,\n )\n const [effectiveBackupBlobAccess, setEffectiveBackupBlobAccess] = useState<\n 'private' | 'public' | null\n >(null)\n const [tokenCheck, setTokenCheck] = useState<{\n access?: 'private' | 'public'\n message?: string\n status: 'checking' | 'idle' | 'invalid' | 'valid'\n }>({ status: 'idle' })\n const [pluginOverridesRetention, setPluginOverridesRetention] = useState(false)\n const [cronInfo, setCronInfo] = useState<BackupSettingsApiResponse['cron'] | undefined>(undefined)\n const [storage, setStorage] = useState<BackupSettingsApiResponse['storage']>(undefined)\n const [transferSummary, setTransferSummary] = useState<\n BackupSettingsApiResponse['transfer'] | null\n >(null)\n const [activeTransfer, setActiveTransfer] = useState<{\n pollSecret: string\n taskId: string\n total: number\n } | null>(null)\n const [transferLive, setTransferLive] = useState<{\n failed: number\n pathname?: string\n total: number\n transferred: number\n } | null>(null)\n const [savePhase, setSavePhase] = useState<\n 'error' | 'idle' | 'saved' | 'saving' | 'transferring'\n >('idle')\n const [saveError, setSaveError] = useState<null | string>(null)\n const [isPreparingOpen, setIsPreparingOpen] = useState(false)\n\n const resetState = useCallback(() => {\n setPreview(null)\n setPhase('idle')\n setErrorMessage(null)\n setSelected({})\n setBackupAllCollections(false)\n setIncludeMediaBlobs(false)\n setBackupsToKeep(10)\n setBackupBlobReadWriteToken('')\n setTransferBackupBlobs(true)\n setDeleteBackupBlobsFromSource(false)\n setHasExistingBackupBlobToken(false)\n setStoredBackupBlobAccess(null)\n setEffectiveBackupBlobAccess(null)\n setTokenCheck({ status: 'idle' })\n setPluginOverridesRetention(false)\n setCronInfo(undefined)\n setTransferSummary(null)\n setActiveTransfer(null)\n setTransferLive(null)\n setSavePhase('idle')\n setSaveError(null)\n isPreparingOpenRef.current = false\n setIsPreparingOpen(false)\n }, [])\n\n useEffect(() => {\n const el = dialogRef.current\n if (!el) {\n return\n }\n const onClose = () => resetState()\n el.addEventListener('close', onClose)\n return () => el.removeEventListener('close', onClose)\n }, [resetState])\n\n const fetchSettingsAndPreview = useCallback(async () => {\n const locale =\n typeof document !== 'undefined' ? (document.documentElement.lang || 'en').slice(0, 2) : 'en'\n const [settingsRes, previewRes] = await Promise.all([\n fetch(backupPluginPublicApiPaths.adminSettings, { method: 'GET' }),\n fetch(backupPluginPublicApiPaths.adminBackupPreview, {\n body: JSON.stringify({ locale }),\n headers: { 'Content-Type': 'application/json' },\n method: 'POST',\n }),\n ])\n\n const settingsJson = (await settingsRes.json()) as BackupSettingsApiResponse\n if (!settingsRes.ok) {\n throw new Error(settingsJson.error || 'Could not load settings')\n }\n\n const previewJson = (await previewRes.json()) as {\n error?: string\n } & BackupSourcePreviewResponse\n if (!previewRes.ok) {\n throw new Error(previewJson.error || 'Could not load collections')\n }\n\n return { previewJson, settingsJson }\n }, [])\n\n const applyLoadedSettingsPreview = useCallback(\n (settingsJson: BackupSettingsApiResponse, previewJson: BackupSourcePreviewResponse) => {\n setActiveTransfer(null)\n setTransferLive(null)\n setPreview(previewJson)\n setBackupsToKeep(\n typeof settingsJson.backupsToKeep === 'number' ? settingsJson.backupsToKeep : 10,\n )\n setBackupBlobReadWriteToken(settingsJson.backupBlobTokenMasked || '')\n setHasExistingBackupBlobToken(settingsJson.hasBackupBlobReadWriteToken === true)\n setStoredBackupBlobAccess(settingsJson.backupBlobAccess ?? null)\n setEffectiveBackupBlobAccess(settingsJson.backupBlobAccessEffective ?? null)\n setTokenCheck({ status: 'idle' })\n setPluginOverridesRetention(settingsJson.pluginBackupsToKeepOverride === true)\n setCronInfo(settingsJson.cron ?? null)\n setStorage(settingsJson.storage)\n setIncludeMediaBlobs(settingsJson.includeMediaForCron === true)\n\n const skip =\n Array.isArray(settingsJson.skipMongoCollections) ? settingsJson.skipMongoCollections : []\n setSelected(selectedFromSkipMongoNames(previewJson, skip))\n setBackupAllCollections(skip.length === 0)\n setTransferBackupBlobs(true)\n setDeleteBackupBlobsFromSource(false)\n setPhase('ready')\n },\n [],\n )\n\n const loadPreview = useCallback(async () => {\n setPhase('loading')\n setErrorMessage(null)\n setPreview(null)\n setCronInfo(undefined)\n try {\n const { previewJson, settingsJson } = await fetchSettingsAndPreview()\n applyLoadedSettingsPreview(settingsJson, previewJson)\n } catch (e) {\n setPhase('error')\n setErrorMessage(e instanceof Error ? e.message : 'Could not load backup settings')\n }\n }, [applyLoadedSettingsPreview, fetchSettingsAndPreview])\n\n const openDialog = useCallback(() => {\n if (isPreparingOpenRef.current) {\n return\n }\n isPreparingOpenRef.current = true\n setSavePhase('idle')\n setSaveError(null)\n setIsPreparingOpen(true)\n void (async () => {\n try {\n const { previewJson, settingsJson } = await fetchSettingsAndPreview()\n applyLoadedSettingsPreview(settingsJson, previewJson)\n dialogRef.current?.showModal()\n } catch (e) {\n setPhase('error')\n setErrorMessage(e instanceof Error ? e.message : 'Could not load backup settings')\n setPreview(null)\n setCronInfo(undefined)\n dialogRef.current?.showModal()\n } finally {\n isPreparingOpenRef.current = false\n setIsPreparingOpen(false)\n }\n })()\n }, [applyLoadedSettingsPreview, fetchSettingsAndPreview])\n\n const skipCollections = useMemo(() => {\n if (!preview) {\n return []\n }\n if (backupAllCollections) {\n return []\n }\n return skipMongoNamesFromPreview(preview, selected)\n }, [backupAllCollections, preview, selected])\n\n const mediaGroupIncluded = preview ? backupAllCollections || selected['media'] !== false : false\n const hasMediaBlobOption = Boolean(\n preview && preview.mediaBlobCandidates > 0 && mediaGroupIncluded,\n )\n\n const willSaveNewRawToken = useMemo(\n () => backupBlobReadWriteToken.trim().length > 0 && !/\\*{2,}/.test(backupBlobReadWriteToken),\n [backupBlobReadWriteToken],\n )\n\n const onChangeBackupBlobToken = useCallback((value: string) => {\n setBackupBlobReadWriteToken(value)\n setTokenCheck({ status: 'idle' })\n }, [])\n\n // Auto-validate a freshly pasted/typed token after a short debounce. The masked token coming\n // from the server (contains \"**\") never triggers this because `willSaveNewRawToken` stays false.\n useEffect(() => {\n if (!willSaveNewRawToken) {\n setTokenCheck((prev) => (prev.status === 'idle' ? prev : { status: 'idle' }))\n return\n }\n\n const candidate = backupBlobReadWriteToken.trim()\n if (!candidate) {\n return\n }\n\n let cancelled = false\n const timer = window.setTimeout(async () => {\n if (cancelled) {\n return\n }\n setTokenCheck({ status: 'checking' })\n try {\n const response = await fetch(backupPluginPublicApiPaths.adminValidateBlobToken, {\n body: JSON.stringify({ token: candidate }),\n headers: { 'Content-Type': 'application/json' },\n method: 'POST',\n })\n if (cancelled) {\n return\n }\n const data = (await response.json()) as {\n access?: 'private' | 'public'\n error?: string\n ok?: boolean\n }\n if (cancelled) {\n return\n }\n if (response.ok && data.ok && (data.access === 'public' || data.access === 'private')) {\n setTokenCheck({ access: data.access, status: 'valid' })\n } else {\n setTokenCheck({ message: data.error || 'Token rejected', status: 'invalid' })\n }\n } catch (error) {\n if (cancelled) {\n return\n }\n setTokenCheck({\n message: error instanceof Error ? error.message : 'Token validation failed',\n status: 'invalid',\n })\n }\n }, 150)\n\n return () => {\n cancelled = true\n window.clearTimeout(timer)\n }\n }, [backupBlobReadWriteToken, willSaveNewRawToken])\n\n const blockSaveForTokenCheck =\n willSaveNewRawToken && (tokenCheck.status === 'checking' || tokenCheck.status === 'invalid')\n\n const tokenStatusPill = (() => {\n if (willSaveNewRawToken) {\n if (tokenCheck.status === 'checking') {\n return <span className=\"backup-item__pill backup-item__pill--neutral\">Checking…</span>\n }\n if (tokenCheck.status === 'valid' && tokenCheck.access) {\n return (\n <span\n className={`backup-item__pill backup-item__pill--${\n tokenCheck.access === 'private' ? 'cron' : 'manual'\n }`}\n >\n {tokenCheck.access === 'private' ? 'Private' : 'Public'}\n </span>\n )\n }\n if (tokenCheck.status === 'invalid') {\n return <span className=\"backup-item__pill backup-item__pill--danger\">Invalid</span>\n }\n return null\n }\n if (effectiveBackupBlobAccess) {\n return (\n <span\n className={`backup-item__pill backup-item__pill--${\n effectiveBackupBlobAccess === 'private' ? 'cron' : 'manual'\n }`}\n title={\n storedBackupBlobAccess ?\n 'Detected and persisted after last validation'\n : 'Heuristic fallback — will be re-validated when saving a new token'\n }\n >\n {effectiveBackupBlobAccess === 'private' ? 'Private' : 'Public'}\n </span>\n )\n }\n return null\n })()\n\n const includeMediaForCron = useMemo(() => {\n if (!hasMediaBlobOption) {\n return false\n }\n return includeMediaBlobs\n }, [hasMediaBlobOption, includeMediaBlobs])\n\n const onToggleGroup = useCallback((groupId: string) => {\n setSelected((prev) => {\n const isOn = prev[groupId] !== false\n return { ...prev, [groupId]: !isOn }\n })\n }, [])\n\n const onToggleBackupAllCollections = useCallback(() => {\n setBackupAllCollections((prev) => {\n const next = !prev\n if (next && preview) {\n setSelected(Object.fromEntries(preview.groups.map((g) => [g.groupId, true])))\n }\n return next\n })\n }, [preview])\n\n const save = useCallback(async () => {\n if (!preview) {\n return\n }\n setSavePhase('saving')\n setSaveError(null)\n setTransferSummary(null)\n setActiveTransfer(null)\n setTransferLive(null)\n try {\n const response = await fetch(backupPluginPublicApiPaths.adminSettings, {\n body: JSON.stringify({\n backupBlobReadWriteToken,\n backupsToKeep,\n deleteBackupBlobsFromSource: transferBackupBlobs && deleteBackupBlobsFromSource,\n includeMediaForCron,\n skipMongoCollections: skipCollections,\n transferBackupBlobs,\n }),\n headers: { 'Content-Type': 'application/json' },\n method: 'PATCH',\n })\n const data = (await response.json()) as BackupSettingsApiResponse\n if (!response.ok) {\n throw new Error(data.error || 'Save failed')\n }\n\n setHasExistingBackupBlobToken(data.hasBackupBlobReadWriteToken === true)\n setBackupBlobReadWriteToken(data.backupBlobTokenMasked || '')\n setStoredBackupBlobAccess(data.backupBlobAccess ?? null)\n setEffectiveBackupBlobAccess(data.backupBlobAccessEffective ?? null)\n setTokenCheck({ status: 'idle' })\n\n const tr = data.transfer\n if (tr?.performed && tr.deferred && tr.taskId && tr.pollSecret) {\n setActiveTransfer({ pollSecret: tr.pollSecret, taskId: tr.taskId, total: tr.total })\n setTransferLive({ failed: 0, total: tr.total, transferred: 0 })\n setSavePhase('transferring')\n return\n }\n\n setTransferSummary(tr ?? null)\n setSavePhase('saved')\n router.refresh()\n if (!tr?.performed) {\n window.setTimeout(() => {\n setSavePhase('idle')\n dialogRef.current?.close()\n }, 800)\n } else {\n window.setTimeout(() => {\n setSavePhase('idle')\n dialogRef.current?.close()\n }, 1200)\n }\n } catch (e) {\n setSavePhase('error')\n setSaveError(e instanceof Error ? e.message : 'Save failed')\n }\n }, [\n preview,\n backupsToKeep,\n backupBlobReadWriteToken,\n skipCollections,\n includeMediaForCron,\n transferBackupBlobs,\n deleteBackupBlobsFromSource,\n router,\n ])\n\n useEffect(() => {\n if (!activeTransfer) {\n return\n }\n\n let cancelled = false\n let intervalId: null | number = null\n let successCloseTimer: null | number = null\n\n const stopPolling = () => {\n if (intervalId != null) {\n window.clearInterval(intervalId)\n intervalId = null\n }\n }\n\n const pollOnce = async () => {\n const res = await fetch(backupPluginPublicApiPaths.adminTask(activeTransfer.taskId), {\n cache: 'no-store',\n headers: { Authorization: `Bearer ${activeTransfer.pollSecret}` },\n })\n if (!res.ok || cancelled) {\n return\n }\n const task = (await res.json()) as BackupTaskProgress\n const parsed = parseBlobTransferTaskMessage(task.message)\n if (parsed) {\n setTransferLive({\n failed: parsed.failed,\n pathname: parsed.pathname,\n total: parsed.total,\n transferred: parsed.transferred,\n })\n }\n if (task.status === 'completed') {\n stopPolling()\n const final = parseBlobTransferTaskMessage(task.message)\n setTransferSummary({\n deferred: false,\n failed: final?.failed ?? 0,\n performed: true,\n skipped: 0,\n total: final?.total ?? activeTransfer.total,\n transferred: final?.transferred ?? 0,\n })\n setActiveTransfer(null)\n setTransferLive(null)\n setSavePhase('saved')\n try {\n const settingsRes = await fetch(backupPluginPublicApiPaths.adminSettings, {\n method: 'GET',\n })\n const refreshed = (await settingsRes.json()) as BackupSettingsApiResponse\n if (settingsRes.ok) {\n setBackupBlobReadWriteToken(refreshed.backupBlobTokenMasked || '')\n setHasExistingBackupBlobToken(refreshed.hasBackupBlobReadWriteToken === true)\n }\n } catch {\n /* ignore */\n }\n router.refresh()\n successCloseTimer = window.setTimeout(() => {\n successCloseTimer = null\n setSavePhase('idle')\n setTransferSummary(null)\n dialogRef.current?.close()\n }, 1400)\n return\n }\n if (task.status === 'failed') {\n stopPolling()\n setSavePhase('error')\n setSaveError(task.error || task.message || 'Transfer failed')\n setActiveTransfer(null)\n setTransferLive(null)\n }\n }\n\n intervalId = window.setInterval(() => void pollOnce(), 900)\n void pollOnce()\n return () => {\n cancelled = true\n stopPolling()\n if (successCloseTimer != null) {\n window.clearTimeout(successCloseTimer)\n }\n }\n }, [activeTransfer, router])\n\n const retentionDisabled = pluginOverridesRetention\n\n return (\n <>\n <Button buttonStyle=\"secondary\" disabled={isPreparingOpen} onClick={openDialog} size=\"small\">\n {isPreparingOpen ? 'Loading…' : 'Backup settings'}\n </Button>\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--settings\"\n onMouseDown={(e) => closeNativeDialogOnBackdropPointer(e, dialogRef)}\n ref={dialogRef}\n >\n <p className=\"backup-confirm-dialog__title\">Scheduled backup settings</p>\n <p className=\"backup-confirm-dialog__subtitle backup-confirm-dialog__subtitle--with-help\">\n <span className=\"backup-confirm-dialog__subtitle-text\">{TIP_SETTINGS_SUBTITLE}</span>\n </p>\n\n <div className=\"backup-confirm-dialog__body restore-preview\">\n {storage ?\n <>\n <p className=\"restore-preview__sticky-heading\">Storage target</p>\n {storage.kind === 's3' ?\n <>\n <p className=\"restore-preview__intro\">\n Backups use <strong>AWS S3</strong> (or S3-compatible). Selected via the{' '}\n <code>BACKUP_STORAGE</code> environment variable.\n </p>\n {storage.s3 ?\n <p className=\"restore-preview__intro\">\n Bucket <code>{storage.s3.bucket}</code> · region{' '}\n <code>{storage.s3.region}</code>\n {storage.s3.endpoint ?\n <>\n {' '}\n · endpoint <code>{storage.s3.endpoint}</code>\n </>\n : null}\n {storage.s3.prefix ?\n <>\n {' '}\n · prefix <code>{storage.s3.prefix}</code>\n </>\n : null}\n </p>\n : <p className=\"restore-preview__intro\">\n Set <code>BACKUP_S3_BUCKET</code> (and credentials) to finish configuring S3.\n </p>\n }\n </>\n : <p className=\"restore-preview__intro\">\n Backups use <strong>Vercel Blob</strong> (default). Set{' '}\n <code>BACKUP_STORAGE=s3</code> in the environment to use AWS S3 instead.\n </p>\n }\n </>\n : null}\n {phase !== 'idle' ?\n <>\n <p className=\"restore-preview__sticky-heading\">Schedule</p>\n {phase === 'loading' ?\n <div\n aria-live=\"polite\"\n className=\"restore-preview__loading-block restore-preview__loading-block--section\"\n >\n <p className=\"restore-preview__status\">Loading cron configuration…</p>\n <div className=\"restore-preview__loading-line\" />\n <div className=\"restore-preview__loading-line restore-preview__loading-line--short\" />\n </div>\n : phase === 'error' ?\n <p className=\"restore-preview__intro\">Schedule details could not be loaded.</p>\n : cronInfo ?\n <>\n <p className=\"restore-preview__intro\">\n Active job: <code>{cronInfo.configFileRelative}</code> — edit and redeploy to\n change the schedule.\n </p>\n <div aria-label=\"Configured schedule\" className=\"restore-preview__settings-block\">\n <p className=\"restore-preview__settings-row\">\n <span className=\"restore-preview__settings-k\">HTTP path</span>{' '}\n <code>{cronInfo.path}</code>\n </p>\n <p className=\"restore-preview__settings-row\">\n <span className=\"restore-preview__settings-k\">Cron expression</span>{' '}\n <code>{cronInfo.schedule}</code>\n </p>\n {cronInfo.humanDescription ?\n <p className=\"restore-preview__settings-human\">{cronInfo.humanDescription}</p>\n : <p className=\"restore-preview__settings-human restore-preview__settings-human--muted\">\n Could not turn the cron expression into a short description.\n </p>\n }\n </div>\n </>\n : <>\n <p className=\"restore-preview__intro\">\n No vercel <code>crons</code> entry for the backup path yet. You can either setup\n an external service to call /api/backup-mongodb/cron/run with your cron secret\n or use Vercel. To use vercel create a file <code>vercel.json</code> in your\n project root with the following content:\n </p>\n <p className=\"restore-preview__settings-hint\">Example</p>\n <pre className=\"restore-preview__settings-snippet\">{`{\n \"crons\": [\n {\n \"path\": \"/api/backup-mongodb/cron/run\",\n \"schedule\": \"0 3 * * *\"\n }\n ]\n}`}</pre>\n <p>\n Then add a <code>CRON_SECRET</code> environment variable to your Vercel project\n and redeploy on Vercel so the cron job is registered.\n </p>\n </>\n }\n </>\n : null}\n\n <p className=\"restore-preview__sticky-heading\">Retention</p>\n <p className=\"restore-preview__intro\">\n {retentionDisabled ?\n <>\n Locked by <code>backupMongodbPlugin({'{ backupsToKeep }'})</code> in Payload config.\n </>\n : <>Oldest cron archives are deleted once the count exceeds this limit.</>}\n </p>\n <div className=\"restore-preview__settings-fields\">\n <label className=\"restore-preview__settings-label\" htmlFor=\"backups-to-keep\">\n Cron backups to keep\n </label>\n <input\n aria-label=\"Cron backups to keep\"\n className=\"restore-preview__settings-input\"\n disabled={retentionDisabled}\n id=\"backups-to-keep\"\n max={365}\n min={1}\n onChange={(e) => setBackupsToKeep(Number(e.target.value) || 1)}\n type=\"number\"\n value={backupsToKeep}\n />\n </div>\n\n {storage?.kind === 's3' ? null : (\n <>\n <p className=\"restore-preview__sticky-heading\">\n Dedicated backup storage{' '}\n <span className=\"restore-preview__sticky-heading-hint\">(optional)</span>\n </p>\n <p className=\"restore-preview__intro\">\n Separate Vercel Blob token for <code>backups/</code>. Without one, archives share\n the default media store.\n </p>\n <div className=\"restore-preview__settings-fields\">\n <label className=\"restore-preview__settings-label\" htmlFor=\"backup-blob-token\">\n Backup Blob read/write token\n </label>\n <div className=\"restore-preview__blob-token-row\">\n <input\n aria-label=\"Backup Blob read/write token\"\n autoComplete=\"off\"\n className=\"restore-preview__settings-input restore-preview__settings-input--wide\"\n id=\"backup-blob-token\"\n onChange={(e) => onChangeBackupBlobToken(e.target.value)}\n placeholder=\"vercel_blob_rw_...\"\n spellCheck={false}\n type=\"text\"\n value={backupBlobReadWriteToken}\n />\n <span className=\"restore-preview__blob-token-pill-slot\">{tokenStatusPill}</span>\n </div>\n {tokenCheck.status === 'invalid' && tokenCheck.message ?\n <p aria-live=\"polite\" className=\"restore-preview__blob-token-error\">\n {tokenCheck.message}\n </p>\n : null}\n {savePhase === 'transferring' && transferLive && transferLive.total > 0 ?\n <div aria-live=\"polite\" className=\"restore-preview__transfer-panel\">\n <div className=\"restore-preview__transfer-bar-track\">\n <div\n className=\"restore-preview__transfer-bar-fill\"\n style={{\n width: `${Math.min(\n 100,\n ((transferLive.transferred + transferLive.failed) /\n transferLive.total) *\n 100,\n )}%`,\n }}\n />\n </div>\n <p className=\"restore-preview__transfer-meta\">\n Copying backup files: {transferLive.transferred + transferLive.failed} /{' '}\n {transferLive.total}\n {transferLive.failed > 0 ? ` (${transferLive.failed} failed)` : ''}\n {transferLive.pathname ?\n <>\n <br />\n <span\n className=\"restore-preview__transfer-path\"\n title={transferLive.pathname}\n >\n {transferLive.pathname.length > 56 ?\n `${transferLive.pathname.slice(0, 28)}…${transferLive.pathname.slice(-24)}`\n : transferLive.pathname}\n </span>\n </>\n : null}\n </p>\n </div>\n : null}\n {willSaveNewRawToken ?\n <>\n <div className=\"field-type checkbox backup-dashboard__collapsible-checkbox restore-preview__blob-transfer-row restore-preview__blob-transfer-row--with-help-tip\">\n <input\n aria-label=\"Copy existing backup files into this storage when saving\"\n checked={transferBackupBlobs}\n className=\"checkbox-input__input\"\n id={transferOptId}\n onChange={(e) => setTransferBackupBlobs(e.target.checked)}\n type=\"checkbox\"\n />\n <label className=\"field-label\" htmlFor={transferOptId}>\n Copy existing backup files into this storage when saving\n </label>\n <SettingsHelpTip multiline tip={TIP_TRANSFER_COPY} />\n </div>\n {transferBackupBlobs ?\n <div className=\"field-type checkbox backup-dashboard__collapsible-checkbox restore-preview__blob-transfer-row restore-preview__blob-transfer-row--with-help-tip\">\n <input\n aria-label=\"Delete from previous storage after successful copy\"\n checked={deleteBackupBlobsFromSource}\n className=\"checkbox-input__input\"\n id={deleteSourceOptId}\n onChange={(e) => setDeleteBackupBlobsFromSource(e.target.checked)}\n type=\"checkbox\"\n />\n <label className=\"field-label\" htmlFor={deleteSourceOptId}>\n Delete from previous storage after successful copy\n </label>\n <SettingsHelpTip multiline tip={TIP_TRANSFER_DELETE} />\n </div>\n : null}\n </>\n : null}\n </div>\n </>\n )}\n\n <CollectionBackupPreviewBody\n embedded\n errorMessage={errorMessage}\n includeAllCollections={backupAllCollections}\n includeAllLabel=\"Backup all collections\"\n includeMediaBlobs={includeMediaBlobs}\n onRetry={loadPreview}\n onToggleGroup={onToggleGroup}\n onToggleIncludeAllCollections={onToggleBackupAllCollections}\n onToggleIncludeMedia={() => setIncludeMediaBlobs((v) => !v)}\n phase={phase}\n preview={preview}\n selected={selected}\n />\n\n {saveError ?\n <p className=\"restore-preview__error restore-preview__error--inline\">{saveError}</p>\n : null}\n {savePhase === 'saving' ?\n <p className=\"restore-preview__status restore-preview__status--footer\">\n Saving settings…\n </p>\n : null}\n {transferSummary?.performed ?\n <p className=\"restore-preview__status restore-preview__status--footer\">\n Migrated backups: {transferSummary.transferred}/{transferSummary.total}\n {transferSummary.failed > 0 ? `, failed: ${transferSummary.failed}` : ''}\n </p>\n : null}\n </div>\n\n <div className=\"backup-confirm-dialog__actions\">\n <Button\n buttonStyle=\"primary\"\n disabled={\n phase !== 'ready' ||\n savePhase === 'saving' ||\n savePhase === 'transferring' ||\n blockSaveForTokenCheck\n }\n onClick={() => void save()}\n size=\"small\"\n >\n {savePhase === 'transferring' ?\n 'Transferring…'\n : savePhase === 'saving' ?\n 'Saving…'\n : savePhase === 'saved' ?\n 'Saved'\n : 'Save settings'}\n </Button>\n <Button buttonStyle=\"secondary\" onClick={() => dialogRef.current?.close()} size=\"small\">\n Cancel\n </Button>\n </div>\n </dialog>\n </>\n )\n}\n"],"names":["Button","useRouter","useCallback","useEffect","useId","useMemo","useRef","useState","backupPluginPublicApiPaths","selectedFromSkipMongoNames","skipMongoNamesFromPreview","closeNativeDialogOnBackdropPointer","CollectionBackupPreviewBody","parseBlobTransferTaskMessage","msg","o","JSON","parse","total","transferred","failed","pathname","undefined","TIP_SETTINGS_SUBTITLE","TIP_TRANSFER_COPY","TIP_TRANSFER_DELETE","settingsHelpIconClassName","multiline","filter","Boolean","join","SettingsHelpTip","tip","elRef","syncTooltipAnchor","el","current","r","getBoundingClientRect","style","setProperty","left","width","top","button","aria-label","className","data-tip","onFocus","onMouseEnter","ref","title","type","BackupSettingsModal","router","transferOptId","deleteSourceOptId","dialogRef","isPreparingOpenRef","preview","setPreview","phase","setPhase","errorMessage","setErrorMessage","selected","setSelected","backupAllCollections","setBackupAllCollections","includeMediaBlobs","setIncludeMediaBlobs","backupsToKeep","setBackupsToKeep","backupBlobReadWriteToken","setBackupBlobReadWriteToken","transferBackupBlobs","setTransferBackupBlobs","deleteBackupBlobsFromSource","setDeleteBackupBlobsFromSource","setHasExistingBackupBlobToken","storedBackupBlobAccess","setStoredBackupBlobAccess","effectiveBackupBlobAccess","setEffectiveBackupBlobAccess","tokenCheck","setTokenCheck","status","pluginOverridesRetention","setPluginOverridesRetention","cronInfo","setCronInfo","storage","setStorage","transferSummary","setTransferSummary","activeTransfer","setActiveTransfer","transferLive","setTransferLive","savePhase","setSavePhase","saveError","setSaveError","isPreparingOpen","setIsPreparingOpen","resetState","onClose","addEventListener","removeEventListener","fetchSettingsAndPreview","locale","document","documentElement","lang","slice","settingsRes","previewRes","Promise","all","fetch","adminSettings","method","adminBackupPreview","body","stringify","headers","settingsJson","json","ok","Error","error","previewJson","applyLoadedSettingsPreview","backupBlobTokenMasked","hasBackupBlobReadWriteToken","backupBlobAccess","backupBlobAccessEffective","pluginBackupsToKeepOverride","cron","includeMediaForCron","skip","Array","isArray","skipMongoCollections","length","loadPreview","e","message","openDialog","showModal","skipCollections","mediaGroupIncluded","hasMediaBlobOption","mediaBlobCandidates","willSaveNewRawToken","trim","test","onChangeBackupBlobToken","value","prev","candidate","cancelled","timer","window","setTimeout","response","adminValidateBlobToken","token","data","access","clearTimeout","blockSaveForTokenCheck","tokenStatusPill","span","onToggleGroup","groupId","isOn","onToggleBackupAllCollections","next","Object","fromEntries","groups","map","g","save","tr","transfer","performed","deferred","taskId","pollSecret","refresh","close","intervalId","successCloseTimer","stopPolling","clearInterval","pollOnce","res","adminTask","cache","Authorization","task","parsed","final","skipped","refreshed","setInterval","retentionDisabled","buttonStyle","disabled","onClick","size","dialog","onMouseDown","p","div","kind","strong","code","s3","bucket","region","endpoint","prefix","aria-live","configFileRelative","path","schedule","humanDescription","pre","label","htmlFor","input","id","max","min","onChange","Number","target","autoComplete","placeholder","spellCheck","Math","br","checked","embedded","includeAllCollections","includeAllLabel","onRetry","onToggleIncludeAllCollections","onToggleIncludeMedia","v"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/BackupDashboard/CollectionBackupPreviewBody.client.tsx"],"sourcesContent":["'use client'\n\nimport type { FC } from 'react'\n\nimport { Button } from '@payloadcms/ui'\n\nimport type { BackupSourcePreviewResponse } from '../../core/backupSourcePreview'\n\nfunction hiddenPills(\n reasons: BackupSourcePreviewResponse['groups'][number]['adminHiddenReasons'],\n): string[] {\n const out: string[] = []\n if (reasons.includes('collection-config')) {\n out.push('Hidden in admin')\n }\n return out\n}\n\nexport interface CollectionBackupPreviewBodyProps {\n /** When true, omit the scrollable dialog body wrapper (use inside another `restore-preview` container). */\n embedded?: boolean\n errorMessage: null | string\n includeAllCollections: boolean\n includeAllLabel?: string\n includeMediaBlobs: boolean\n onRetry: () => void\n onToggleGroup: (groupId: string) => void\n onToggleIncludeAllCollections: () => void\n onToggleIncludeMedia: () => void\n phase: 'error' | 'idle' | 'loading' | 'ready'\n preview: BackupSourcePreviewResponse | null\n selected: Record<string, boolean>\n}\n\nexport const CollectionBackupPreviewBody: FC<CollectionBackupPreviewBodyProps> = ({\n embedded = false,\n errorMessage,\n includeAllCollections,\n includeAllLabel = 'Backup all collections',\n includeMediaBlobs,\n onRetry,\n onToggleGroup,\n onToggleIncludeAllCollections,\n onToggleIncludeMedia,\n phase,\n preview,\n selected,\n}) => {\n const mediaGroupIncluded = preview ? includeAllCollections || selected['media'] !== false : false\n const hasMediaBlobOption = Boolean(\n preview && preview.mediaBlobCandidates > 0 && mediaGroupIncluded,\n )\n\n const inner = (\n <>\n {phase === 'loading' && (\n <div aria-live=\"polite\" className=\"restore-preview__loading-block\">\n <p className=\"restore-preview__status\">Loading collections…</p>\n <div className=\"restore-preview__loading-line\" />\n <div className=\"restore-preview__loading-line restore-preview__loading-line--short\" />\n <div className=\"restore-preview__loading-line\" />\n </div>\n )}\n\n {phase === 'error' && (\n <div className=\"restore-preview__error\">\n <p>{errorMessage}</p>\n <Button buttonStyle=\"secondary\" onClick={() => void onRetry()} size=\"small\">\n Retry\n </Button>\n </div>\n )}\n\n {phase === 'ready' && preview && (\n <>\n <p className=\"restore-preview__sticky-heading\">Collection selection</p>\n <p className=\"restore-preview__intro\">\n Choose which collections to include. Version drafts are grouped with their collection.\n Collections with no documents still appear so you can exclude them explicitly. If you\n add new collections later, they are automatically included in backups by default.\n </p>\n\n {preview.groups.length === 0 && (\n <p className=\"restore-preview__empty\">No collections found to list.</p>\n )}\n\n {includeAllCollections ? (\n <div className=\"restore-preview__all-block\">\n <label className=\"restore-preview__all-block-head\">\n <input\n aria-label={includeAllLabel}\n checked\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={onToggleIncludeAllCollections}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">{includeAllLabel}</span>\n </label>\n {preview.groups.length > 0 ? (\n <ul aria-label=\"Collections to back up\" className=\"restore-preview__all-list\">\n {preview.groups.map((g) => {\n const mainDocs = g.main?.docCount ?? 0\n const versionDocs = g.versions?.docCount ?? 0\n const totalDocs = mainDocs + versionDocs\n return (\n <li className=\"restore-preview__all-item\" key={g.groupId}>\n <span className=\"restore-preview__all-name\">{g.displayTitle}</span>\n <span className=\"restore-preview__all-count\">\n {totalDocs} doc{totalDocs === 1 ? '' : 's'}\n {versionDocs > 0 ? (\n <>\n {' '}\n <span className=\"restore-preview__all-count-sub\">\n (incl. {versionDocs} version{versionDocs === 1 ? '' : 's'})\n </span>\n </>\n ) : null}\n </span>\n </li>\n )\n })}\n </ul>\n ) : null}\n {hasMediaBlobOption ? (\n <label className=\"restore-preview__media-block restore-preview__media-block--nested\">\n <input\n aria-label={`Include media files from storage (${preview.mediaBlobCandidates} files)`}\n checked={includeMediaBlobs}\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={onToggleIncludeMedia}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">\n Include media files from storage? ({preview.mediaBlobCandidates} file\n {preview.mediaBlobCandidates === 1 ? '' : 's'})\n </span>\n </label>\n ) : null}\n </div>\n ) : (\n <>\n <label className=\"restore-preview__media-block\">\n <input\n aria-label={includeAllLabel}\n checked={false}\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={onToggleIncludeAllCollections}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">{includeAllLabel}</span>\n </label>\n\n <ul aria-label=\"Collections to back up\" className=\"restore-preview__list\">\n {preview.groups.map((g) => {\n const adminPills = hiddenPills(g.adminHiddenReasons)\n const isMedia = g.groupId === 'media'\n return (\n <li className=\"restore-preview__group\" key={g.groupId}>\n <div className=\"restore-preview__group-head\">\n <label className=\"restore-preview__group-label\">\n <input\n aria-label={`Include collection ${g.displayTitle} in backup`}\n checked={selected[g.groupId] !== false}\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={() => onToggleGroup(g.groupId)}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__group-title\">{g.displayTitle}</span>\n </label>\n </div>\n <div className=\"restore-preview__sublines\">\n {g.main ? (\n <div className=\"restore-preview__subline\">\n {g.main.docCount} doc{g.main.docCount === 1 ? '' : 's'} to include\n </div>\n ) : null}\n {g.versions ? (\n <div className=\"restore-preview__subline\">\n {g.versions.docCount} version doc\n {g.versions.docCount === 1 ? '' : 's'} to include\n </div>\n ) : null}\n {isMedia &&\n selected['media'] !== false &&\n preview.mediaBlobCandidates === 0 &&\n (g.main?.docCount ?? 0) + (g.versions?.docCount ?? 0) > 0 && (\n <div className=\"restore-preview__note restore-preview__note--media\">\n No blob paths in media docs — only collection data will be in the\n backup file.\n </div>\n )}\n {isMedia && hasMediaBlobOption && (\n <label className=\"restore-preview__media-block restore-preview__media-block--nested\">\n <input\n aria-label={`Include media files from storage (${preview.mediaBlobCandidates} files)`}\n checked={includeMediaBlobs}\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={onToggleIncludeMedia}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">\n Include media files from storage? ({preview.mediaBlobCandidates} file\n {preview.mediaBlobCandidates === 1 ? '' : 's'})\n </span>\n </label>\n )}\n {adminPills.length > 0 && (\n <div className=\"restore-preview__pills\">\n {adminPills.map((t) => (\n <span className=\"restore-preview__pill\" key={t}>\n {t}\n </span>\n ))}\n </div>\n )}\n </div>\n </li>\n )\n })}\n </ul>\n </>\n )}\n </>\n )}\n </>\n )\n\n if (embedded) {\n return inner\n }\n\n return <div className=\"backup-confirm-dialog__body restore-preview\">{inner}</div>\n}\n"],"names":["Button","hiddenPills","reasons","out","includes","push","CollectionBackupPreviewBody","embedded","errorMessage","includeAllCollections","includeAllLabel","includeMediaBlobs","onRetry","onToggleGroup","onToggleIncludeAllCollections","onToggleIncludeMedia","phase","preview","selected","mediaGroupIncluded","hasMediaBlobOption","Boolean","mediaBlobCandidates","inner","div","aria-live","className","p","buttonStyle","onClick","size","groups","length","label","input","aria-label","checked","onChange","type","span","ul","map","g","mainDocs","main","docCount","versionDocs","versions","totalDocs","li","displayTitle","groupId","adminPills","adminHiddenReasons","isMedia","t"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/BackupDashboard/CollectionBackupPreviewBody.client.tsx"],"sourcesContent":["'use client'\n\nimport type { FC } from 'react'\n\nimport { Button } from '@payloadcms/ui'\n\nimport type { BackupSourcePreviewResponse } from '../../core/backupSourcePreview'\n\nfunction hiddenPills(\n reasons: BackupSourcePreviewResponse['groups'][number]['adminHiddenReasons'],\n): string[] {\n const out: string[] = []\n if (reasons.includes('collection-config')) {\n out.push('Hidden in admin')\n }\n return out\n}\n\nexport interface CollectionBackupPreviewBodyProps {\n /** When true, omit the scrollable dialog body wrapper (use inside another `restore-preview` container). */\n embedded?: boolean\n errorMessage: null | string\n includeAllCollections: boolean\n includeAllLabel?: string\n includeMediaBlobs: boolean\n onRetry: () => void\n onToggleGroup: (groupId: string) => void\n onToggleIncludeAllCollections: () => void\n onToggleIncludeMedia: () => void\n phase: 'error' | 'idle' | 'loading' | 'ready'\n preview: BackupSourcePreviewResponse | null\n selected: Record<string, boolean>\n}\n\nexport const CollectionBackupPreviewBody: FC<CollectionBackupPreviewBodyProps> = ({\n embedded = false,\n errorMessage,\n includeAllCollections,\n includeAllLabel = 'Backup all collections',\n includeMediaBlobs,\n onRetry,\n onToggleGroup,\n onToggleIncludeAllCollections,\n onToggleIncludeMedia,\n phase,\n preview,\n selected,\n}) => {\n const mediaGroupIncluded = preview ? includeAllCollections || selected['media'] !== false : false\n const hasMediaBlobOption = Boolean(\n preview && preview.mediaBlobCandidates > 0 && mediaGroupIncluded,\n )\n\n const inner = (\n <>\n {phase === 'loading' && (\n <div aria-live=\"polite\" className=\"restore-preview__loading-block\">\n <p className=\"restore-preview__status\">Loading collections…</p>\n <div className=\"restore-preview__loading-line\" />\n <div className=\"restore-preview__loading-line restore-preview__loading-line--short\" />\n <div className=\"restore-preview__loading-line\" />\n </div>\n )}\n\n {phase === 'error' && (\n <div className=\"restore-preview__error\">\n <p>{errorMessage}</p>\n <Button buttonStyle=\"secondary\" onClick={() => void onRetry()} size=\"small\">\n Retry\n </Button>\n </div>\n )}\n\n {phase === 'ready' && preview && (\n <>\n <p className=\"restore-preview__sticky-heading\">Collection selection</p>\n <p className=\"restore-preview__intro\">\n Choose which collections to include. Version drafts are grouped with their collection.\n Collections with no documents still appear so you can exclude them explicitly. If you\n add new collections later, they are automatically included in backups by default.\n </p>\n\n {preview.groups.length === 0 && (\n <p className=\"restore-preview__empty\">No collections found to list.</p>\n )}\n\n {includeAllCollections ?\n <div className=\"restore-preview__all-block\">\n <label className=\"restore-preview__all-block-head\">\n <input\n aria-label={includeAllLabel}\n checked\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={onToggleIncludeAllCollections}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">{includeAllLabel}</span>\n </label>\n {preview.groups.length > 0 ?\n <ul aria-label=\"Collections to back up\" className=\"restore-preview__all-list\">\n {preview.groups.map((g) => {\n const mainDocs = g.main?.docCount ?? 0\n const versionDocs = g.versions?.docCount ?? 0\n const totalDocs = mainDocs + versionDocs\n return (\n <li className=\"restore-preview__all-item\" key={g.groupId}>\n <span className=\"restore-preview__all-name\">{g.displayTitle}</span>\n <span className=\"restore-preview__all-count\">\n {totalDocs} doc{totalDocs === 1 ? '' : 's'}\n {versionDocs > 0 ?\n <>\n {' '}\n <span className=\"restore-preview__all-count-sub\">\n (incl. {versionDocs} version{versionDocs === 1 ? '' : 's'})\n </span>\n </>\n : null}\n </span>\n </li>\n )\n })}\n </ul>\n : null}\n {hasMediaBlobOption ?\n <label className=\"restore-preview__media-block restore-preview__media-block--nested\">\n <input\n aria-label={`Include media files from storage (${preview.mediaBlobCandidates} files)`}\n checked={includeMediaBlobs}\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={onToggleIncludeMedia}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">\n Include media files from storage? ({preview.mediaBlobCandidates} file\n {preview.mediaBlobCandidates === 1 ? '' : 's'})\n </span>\n </label>\n : null}\n </div>\n : <>\n <label className=\"restore-preview__media-block\">\n <input\n aria-label={includeAllLabel}\n checked={false}\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={onToggleIncludeAllCollections}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">{includeAllLabel}</span>\n </label>\n\n <ul aria-label=\"Collections to back up\" className=\"restore-preview__list\">\n {preview.groups.map((g) => {\n const adminPills = hiddenPills(g.adminHiddenReasons)\n const isMedia = g.groupId === 'media'\n return (\n <li className=\"restore-preview__group\" key={g.groupId}>\n <div className=\"restore-preview__group-head\">\n <label className=\"restore-preview__group-label\">\n <input\n aria-label={`Include collection ${g.displayTitle} in backup`}\n checked={selected[g.groupId] !== false}\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={() => onToggleGroup(g.groupId)}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__group-title\">{g.displayTitle}</span>\n </label>\n </div>\n <div className=\"restore-preview__sublines\">\n {g.main ?\n <div className=\"restore-preview__subline\">\n {g.main.docCount} doc{g.main.docCount === 1 ? '' : 's'} to include\n </div>\n : null}\n {g.versions ?\n <div className=\"restore-preview__subline\">\n {g.versions.docCount} version doc\n {g.versions.docCount === 1 ? '' : 's'} to include\n </div>\n : null}\n {isMedia &&\n selected['media'] !== false &&\n preview.mediaBlobCandidates === 0 &&\n (g.main?.docCount ?? 0) + (g.versions?.docCount ?? 0) > 0 && (\n <div className=\"restore-preview__note restore-preview__note--media\">\n No blob paths in media docs — only collection data will be in the\n backup file.\n </div>\n )}\n {isMedia && hasMediaBlobOption && (\n <label className=\"restore-preview__media-block restore-preview__media-block--nested\">\n <input\n aria-label={`Include media files from storage (${preview.mediaBlobCandidates} files)`}\n checked={includeMediaBlobs}\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={onToggleIncludeMedia}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">\n Include media files from storage? ({preview.mediaBlobCandidates} file\n {preview.mediaBlobCandidates === 1 ? '' : 's'})\n </span>\n </label>\n )}\n {adminPills.length > 0 && (\n <div className=\"restore-preview__pills\">\n {adminPills.map((t) => (\n <span className=\"restore-preview__pill\" key={t}>\n {t}\n </span>\n ))}\n </div>\n )}\n </div>\n </li>\n )\n })}\n </ul>\n </>\n }\n </>\n )}\n </>\n )\n\n if (embedded) {\n return inner\n }\n\n return <div className=\"backup-confirm-dialog__body restore-preview\">{inner}</div>\n}\n"],"names":["Button","hiddenPills","reasons","out","includes","push","CollectionBackupPreviewBody","embedded","errorMessage","includeAllCollections","includeAllLabel","includeMediaBlobs","onRetry","onToggleGroup","onToggleIncludeAllCollections","onToggleIncludeMedia","phase","preview","selected","mediaGroupIncluded","hasMediaBlobOption","Boolean","mediaBlobCandidates","inner","div","aria-live","className","p","buttonStyle","onClick","size","groups","length","label","input","aria-label","checked","onChange","type","span","ul","map","g","mainDocs","main","docCount","versionDocs","versions","totalDocs","li","displayTitle","groupId","adminPills","adminHiddenReasons","isMedia","t"],"mappings":"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"}
|
|
@@ -518,7 +518,7 @@ export const RestoreBackupDialog = ({ downloadUrl, pathname })=>{
|
|
|
518
518
|
/*#__PURE__*/ _jsx(TaskActionButton, {
|
|
519
519
|
body: restoreBody,
|
|
520
520
|
buttonStyle: "error",
|
|
521
|
-
completeLabel: "Restore
|
|
521
|
+
completeLabel: "Restore finished",
|
|
522
522
|
dangerConfirm: {
|
|
523
523
|
body: 'You have selected Users, Roles, and/or Payload preferences. Restoring these collections replaces login accounts, role definitions, and/or UI session data. You can be locked out until you sign in again with the restored credentials. After a successful restore you will be signed out automatically.',
|
|
524
524
|
cancelLabel: 'Go back',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/BackupDashboard/RestoreBackupDialog.client.tsx"],"sourcesContent":["'use client'\n\nimport { Button } from '@payloadcms/ui'\nimport { useRouter } from 'next/navigation'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport type { RestorePreviewResponse } from '../../core/restorePreview'\n\nimport { backupPluginPublicApiPaths } from '../../publicApiPaths'\nimport { closeNativeDialogOnBackdropPointer } from '../../utils/dialogBackdrop'\nimport { TaskActionButton } from './TaskActionButton.client'\n\ntype RestoreBackupDialogProps = {\n downloadUrl: string\n pathname: string\n}\n\nfunction hiddenPills(\n reasons: RestorePreviewResponse['groups'][number]['adminHiddenReasons'],\n): string[] {\n const out: string[] = []\n if (reasons.includes('collection-config')) {\n out.push('Hidden in admin')\n }\n return out\n}\n\nfunction groupDocTotal(g: RestorePreviewResponse['groups'][number]): number {\n return (g.main?.docCount ?? 0) + (g.versions?.docCount ?? 0)\n}\n\nfunction isRestoreRowVisuallyEmpty(\n g: RestorePreviewResponse['groups'][number],\n preview: RestorePreviewResponse,\n): boolean {\n const t = groupDocTotal(g)\n const isMedia = g.groupId === 'media'\n const hasBlobs = preview.mediaBlobCount > 0\n return t === 0 && !(isMedia && hasBlobs)\n}\n\nfunction isRestoreCollectionCheckboxDisabled(\n g: RestorePreviewResponse['groups'][number],\n preview: RestorePreviewResponse,\n): boolean {\n return isRestoreRowVisuallyEmpty(g, preview)\n}\n\nfunction isRestoreSignInAgainGroup(groupId: string): boolean {\n return groupId === 'users' || groupId === 'roles' || groupId === 'payload-preferences'\n}\n\nexport const RestoreBackupDialog: React.FC<RestoreBackupDialogProps> = ({\n downloadUrl,\n pathname,\n}) => {\n const router = useRouter()\n const dialogRef = useRef<HTMLDialogElement>(null)\n const postSuccessCloseTimerRef = useRef<null | ReturnType<typeof setTimeout>>(null)\n const [preview, setPreview] = useState<null | RestorePreviewResponse>(null)\n const [phase, setPhase] = useState<'error' | 'idle' | 'loading' | 'ready'>('idle')\n const [errorMessage, setErrorMessage] = useState<null | string>(null)\n const [selected, setSelected] = useState<Record<string, boolean>>({})\n const [restoreAllCollections, setRestoreAllCollections] = useState(false)\n const [restoreArchiveMedia, setRestoreArchiveMedia] = useState(true)\n\n const resetState = useCallback(() => {\n setPreview(null)\n setPhase('idle')\n setErrorMessage(null)\n setSelected({})\n setRestoreAllCollections(false)\n setRestoreArchiveMedia(true)\n }, [])\n\n useEffect(() => {\n const el = dialogRef.current\n if (!el) {\n return\n }\n const onClose = () => {\n if (postSuccessCloseTimerRef.current) {\n clearTimeout(postSuccessCloseTimerRef.current)\n postSuccessCloseTimerRef.current = null\n }\n resetState()\n }\n el.addEventListener('close', onClose)\n return () => el.removeEventListener('close', onClose)\n }, [resetState])\n\n useEffect(() => {\n return () => {\n if (postSuccessCloseTimerRef.current) {\n clearTimeout(postSuccessCloseTimerRef.current)\n }\n }\n }, [])\n\n useEffect(() => {\n if (!preview) {\n return\n }\n setSelected(\n Object.fromEntries(\n preview.groups.map((g) => {\n const t = groupDocTotal(g)\n const isMedia = g.groupId === 'media'\n const hasBlobs = preview.mediaBlobCount > 0\n if (t === 0 && !(isMedia && hasBlobs)) {\n return [g.groupId, false]\n }\n return [g.groupId, true]\n }),\n ),\n )\n setRestoreAllCollections(false)\n setRestoreArchiveMedia(true)\n }, [preview])\n\n const loadPreview = useCallback(async () => {\n setPhase('loading')\n setErrorMessage(null)\n setPreview(null)\n try {\n const locale =\n typeof document !== 'undefined' ? (document.documentElement.lang || 'en').slice(0, 2) : 'en'\n const response = await fetch(backupPluginPublicApiPaths.adminRestorePreview, {\n body: JSON.stringify({\n locale,\n pathname,\n url: downloadUrl,\n }),\n headers: { 'Content-Type': 'application/json' },\n method: 'POST',\n })\n const data = (await response.json()) as { error?: string } & RestorePreviewResponse\n if (!response.ok) {\n throw new Error(data.error || 'Could not analyse backup')\n }\n setPreview(data)\n setPhase('ready')\n } catch (e) {\n setPhase('error')\n setErrorMessage(e instanceof Error ? e.message : 'Could not analyse backup')\n }\n }, [downloadUrl, pathname])\n\n const openDialog = () => {\n setPhase('loading')\n setErrorMessage(null)\n setPreview(null)\n setSelected({})\n setRestoreAllCollections(false)\n setRestoreArchiveMedia(true)\n dialogRef.current?.showModal()\n void loadPreview()\n }\n\n const skipCollections = useMemo(() => {\n if (!preview) {\n return []\n }\n if (restoreAllCollections) {\n return []\n }\n return preview.groups.filter((g) => selected[g.groupId] === false).flatMap((g) => g.mongoNames)\n }, [preview, restoreAllCollections, selected])\n\n const willAutoLogout = useMemo(() => {\n if (!preview) {\n return false\n }\n return preview.groups.some(\n (g) => (restoreAllCollections || selected[g.groupId] !== false) && g.affectsAuthSession,\n )\n }, [preview, restoreAllCollections, selected])\n\n const needsAuthLockoutConfirm = useCallback(() => {\n if (!preview) {\n return false\n }\n return preview.groups.some(\n (g) =>\n isRestoreSignInAgainGroup(g.groupId) &&\n (restoreAllCollections || selected[g.groupId] !== false),\n )\n }, [preview, restoreAllCollections, selected])\n\n const hasArchiveMedia = preview ? preview.mediaBlobCount > 0 : false\n const mediaGroupIncluded = preview ? restoreAllCollections || selected['media'] !== false : false\n const hasMediaBlobOption = Boolean(preview && preview.mediaBlobCount > 0 && mediaGroupIncluded)\n\n const restoreBody = useMemo(\n () => ({\n pathname,\n restoreArchiveMedia: hasArchiveMedia ? restoreArchiveMedia : true,\n skipCollections,\n url: downloadUrl,\n }),\n [downloadUrl, hasArchiveMedia, pathname, restoreArchiveMedia, skipCollections],\n )\n\n const closeModalAfterRestoreSuccess = useCallback(() => {\n if (postSuccessCloseTimerRef.current) {\n clearTimeout(postSuccessCloseTimerRef.current)\n }\n postSuccessCloseTimerRef.current = setTimeout(() => {\n postSuccessCloseTimerRef.current = null\n router.refresh()\n dialogRef.current?.close()\n }, 1000)\n }, [router])\n\n return (\n <>\n <Button buttonStyle=\"secondary\" onClick={openDialog} size=\"small\">\n Restore\n </Button>\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--restore\"\n onMouseDown={(e) => closeNativeDialogOnBackdropPointer(e, dialogRef)}\n ref={dialogRef}\n >\n <p className=\"backup-confirm-dialog__title\">Restore this backup?</p>\n\n <div className=\"backup-confirm-dialog__body restore-preview\">\n {phase === 'loading' && (\n <div aria-live=\"polite\" className=\"restore-preview__loading-block\">\n <p className=\"restore-preview__status\">Downloading and analysing backup…</p>\n <div className=\"restore-preview__loading-line\" />\n <div className=\"restore-preview__loading-line restore-preview__loading-line--short\" />\n <div className=\"restore-preview__loading-line\" />\n </div>\n )}\n\n {phase === 'error' && (\n <div className=\"restore-preview__error\">\n <p>{errorMessage}</p>\n <p className=\"restore-preview__error-hint\">\n You can still start restore below. If this backup replaces users or sessions, sign\n out manually afterwards if you are not redirected automatically.\n </p>\n <Button buttonStyle=\"secondary\" onClick={() => void loadPreview()} size=\"small\">\n Retry analysis\n </Button>\n </div>\n )}\n\n {phase === 'ready' && preview && (\n <>\n <p className=\"restore-preview__sticky-heading\">Collection selection</p>\n <p className=\"restore-preview__intro\">\n Choose which collections to restore. Version history is grouped with its collection.\n Collections with no documents in this backup still appear (greyed); you can leave\n them unchecked.\n </p>\n\n {preview.groups.length === 0 && (\n <p className=\"restore-preview__empty\">No collections found to list.</p>\n )}\n\n {restoreAllCollections ? (\n <div className=\"restore-preview__all-block\">\n <label className=\"restore-preview__all-block-head\">\n <input\n aria-label=\"Restore all collections\"\n checked\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={() =>\n setRestoreAllCollections((prev) => {\n const next = !prev\n if (next && preview) {\n setSelected(\n Object.fromEntries(preview.groups.map((g) => [g.groupId, true])),\n )\n }\n return next\n })\n }\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">Restore all collections</span>\n </label>\n {preview.groups.length > 0 ? (\n <ul aria-label=\"Collections in backup\" className=\"restore-preview__all-list\">\n {preview.groups.map((g) => {\n const isMedia = g.groupId === 'media'\n const rowEmpty = isRestoreRowVisuallyEmpty(g, preview)\n const versionDocs = g.versions?.docCount ?? 0\n const docTotal = groupDocTotal(g)\n const signInAgain = isRestoreSignInAgainGroup(g.groupId)\n\n let countLabel: string\n if (rowEmpty) {\n countLabel = 'Nothing to restore'\n } else if (docTotal === 0 && isMedia && preview.mediaBlobCount > 0) {\n countLabel = `0 docs · ${preview.mediaBlobCount} media file${preview.mediaBlobCount === 1 ? '' : 's'} in archive`\n } else {\n countLabel = `${docTotal} doc${docTotal === 1 ? '' : 's'} to restore`\n if (versionDocs > 0) {\n countLabel += ` (incl. ${versionDocs} version${versionDocs === 1 ? '' : 's'})`\n }\n }\n\n return (\n <li className=\"restore-preview__all-item\" key={g.groupId}>\n <span className=\"restore-preview__all-name\">\n {g.displayTitle}\n {signInAgain ? (\n <>\n {' '}\n <span className=\"restore-preview__pill restore-preview__pill--signin\">\n Sign-in again\n </span>\n </>\n ) : null}\n </span>\n <span className=\"restore-preview__all-count\">{countLabel}</span>\n </li>\n )\n })}\n </ul>\n ) : null}\n {hasMediaBlobOption ? (\n <label className=\"restore-preview__media-block restore-preview__media-block--nested\">\n <input\n aria-label={`Restore media files from backup (${preview.mediaBlobCount} files in archive)`}\n checked={restoreArchiveMedia}\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={() => setRestoreArchiveMedia((v) => !v)}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">\n Restore media files from backup? ({preview.mediaBlobCount} file\n {preview.mediaBlobCount === 1 ? '' : 's'} in archive)\n </span>\n </label>\n ) : null}\n </div>\n ) : (\n <>\n <label className=\"restore-preview__media-block\">\n <input\n aria-label=\"Restore all collections\"\n checked={false}\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={() =>\n setRestoreAllCollections((prev) => {\n const next = !prev\n if (next && preview) {\n setSelected(\n Object.fromEntries(preview.groups.map((g) => [g.groupId, true])),\n )\n }\n return next\n })\n }\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">Restore all collections</span>\n </label>\n\n <ul aria-label=\"Collections in backup\" className=\"restore-preview__list\">\n {preview.groups.map((g) => {\n const adminPills = hiddenPills(g.adminHiddenReasons)\n const isMedia = g.groupId === 'media'\n const rowEmpty = isRestoreRowVisuallyEmpty(g, preview)\n const checkboxDisabled = isRestoreCollectionCheckboxDisabled(g, preview)\n const docTotal = groupDocTotal(g)\n\n return (\n <li\n className={`restore-preview__group${rowEmpty ? 'restore-preview__group--empty' : ''}`}\n key={g.groupId}\n >\n <div className=\"restore-preview__group-head\">\n <label className=\"restore-preview__group-label\">\n <input\n aria-label={`Restore collection ${g.displayTitle}`}\n checked={selected[g.groupId] !== false}\n className=\"checkbox-input__input restore-preview__group-check\"\n disabled={checkboxDisabled}\n onChange={() => {\n setSelected((prev) => {\n const isOn = prev[g.groupId] !== false\n return { ...prev, [g.groupId]: !isOn }\n })\n }}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__group-title\">{g.displayTitle}</span>\n </label>\n {isRestoreSignInAgainGroup(g.groupId) && (\n <span className=\"restore-preview__pill restore-preview__pill--signin\">\n Requires sign-in again\n </span>\n )}\n </div>\n <div className=\"restore-preview__sublines\">\n {rowEmpty ? (\n <div className=\"restore-preview__subline restore-preview__subline--empty\">\n 0 docs, nothing to restore\n </div>\n ) : docTotal === 0 && isMedia && preview.mediaBlobCount > 0 ? (\n <div className=\"restore-preview__subline\">\n 0 collection docs in backup\n </div>\n ) : (\n <>\n {g.main ? (\n <div className=\"restore-preview__subline\">\n {g.main.docCount} doc{g.main.docCount === 1 ? '' : 's'} to\n restore\n </div>\n ) : null}\n {g.versions ? (\n <div className=\"restore-preview__subline\">\n {g.versions.docCount} version doc\n {g.versions.docCount === 1 ? '' : 's'} to restore\n </div>\n ) : null}\n </>\n )}\n {isMedia &&\n selected['media'] !== false &&\n preview.mediaBlobCount === 0 &&\n docTotal > 0 && (\n <div className=\"restore-preview__note restore-preview__note--media\">\n No media files in this backup archive — only collection data will\n be restored for media.\n </div>\n )}\n {isMedia && hasMediaBlobOption && (\n <label className=\"restore-preview__media-block restore-preview__media-block--nested\">\n <input\n aria-label={`Restore media files from backup (${preview.mediaBlobCount} files in archive)`}\n checked={restoreArchiveMedia}\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={() => setRestoreArchiveMedia((v) => !v)}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">\n Restore media files from backup? ({preview.mediaBlobCount} file\n {preview.mediaBlobCount === 1 ? '' : 's'} in archive)\n </span>\n </label>\n )}\n {adminPills.length > 0 && (\n <div className=\"restore-preview__pills\">\n {adminPills.map((t) => (\n <span className=\"restore-preview__pill\" key={t}>\n {t}\n </span>\n ))}\n </div>\n )}\n </div>\n </li>\n )\n })}\n </ul>\n </>\n )}\n </>\n )}\n </div>\n\n <div className=\"backup-confirm-dialog__actions\">\n <TaskActionButton\n body={restoreBody}\n buttonStyle=\"error\"\n completeLabel=\"Restore started\"\n dangerConfirm={{\n body: 'You have selected Users, Roles, and/or Payload preferences. Restoring these collections replaces login accounts, role definitions, and/or UI session data. You can be locked out until you sign in again with the restored credentials. After a successful restore you will be signed out automatically.',\n cancelLabel: 'Go back',\n confirmLabel: 'I understand — restore anyway',\n title: 'Danger: lock-out risk',\n when: needsAuthLockoutConfirm,\n }}\n endpoint={backupPluginPublicApiPaths.adminRestore}\n idleDisabled={phase !== 'ready' && phase !== 'error'}\n idleLabel=\"Yes, restore\"\n kind=\"restore\"\n onComplete={closeModalAfterRestoreSuccess}\n pendingLabel=\"Restoring...\"\n redirectOnComplete={willAutoLogout ? '/admin/logout' : undefined}\n />\n <Button buttonStyle=\"secondary\" onClick={() => dialogRef.current?.close()} size=\"small\">\n Cancel\n </Button>\n </div>\n </dialog>\n </>\n )\n}\n"],"names":["Button","useRouter","useCallback","useEffect","useMemo","useRef","useState","backupPluginPublicApiPaths","closeNativeDialogOnBackdropPointer","TaskActionButton","hiddenPills","reasons","out","includes","push","groupDocTotal","g","main","docCount","versions","isRestoreRowVisuallyEmpty","preview","t","isMedia","groupId","hasBlobs","mediaBlobCount","isRestoreCollectionCheckboxDisabled","isRestoreSignInAgainGroup","RestoreBackupDialog","downloadUrl","pathname","router","dialogRef","postSuccessCloseTimerRef","setPreview","phase","setPhase","errorMessage","setErrorMessage","selected","setSelected","restoreAllCollections","setRestoreAllCollections","restoreArchiveMedia","setRestoreArchiveMedia","resetState","el","current","onClose","clearTimeout","addEventListener","removeEventListener","Object","fromEntries","groups","map","loadPreview","locale","document","documentElement","lang","slice","response","fetch","adminRestorePreview","body","JSON","stringify","url","headers","method","data","json","ok","Error","error","e","message","openDialog","showModal","skipCollections","filter","flatMap","mongoNames","willAutoLogout","some","affectsAuthSession","needsAuthLockoutConfirm","hasArchiveMedia","mediaGroupIncluded","hasMediaBlobOption","Boolean","restoreBody","closeModalAfterRestoreSuccess","setTimeout","refresh","close","buttonStyle","onClick","size","dialog","className","onMouseDown","ref","p","div","aria-live","length","label","input","aria-label","checked","onChange","prev","next","type","span","ul","rowEmpty","versionDocs","docTotal","signInAgain","countLabel","li","displayTitle","v","adminPills","adminHiddenReasons","checkboxDisabled","disabled","isOn","completeLabel","dangerConfirm","cancelLabel","confirmLabel","title","when","endpoint","adminRestore","idleDisabled","idleLabel","kind","onComplete","pendingLabel","redirectOnComplete","undefined"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/BackupDashboard/RestoreBackupDialog.client.tsx"],"sourcesContent":["'use client'\n\nimport { Button } from '@payloadcms/ui'\nimport { useRouter } from 'next/navigation'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport type { RestorePreviewResponse } from '../../core/restorePreview'\n\nimport { backupPluginPublicApiPaths } from '../../publicApiPaths'\nimport { closeNativeDialogOnBackdropPointer } from '../../utils/dialogBackdrop'\nimport { TaskActionButton } from './TaskActionButton.client'\n\ntype RestoreBackupDialogProps = {\n downloadUrl: string\n pathname: string\n}\n\nfunction hiddenPills(\n reasons: RestorePreviewResponse['groups'][number]['adminHiddenReasons'],\n): string[] {\n const out: string[] = []\n if (reasons.includes('collection-config')) {\n out.push('Hidden in admin')\n }\n return out\n}\n\nfunction groupDocTotal(g: RestorePreviewResponse['groups'][number]): number {\n return (g.main?.docCount ?? 0) + (g.versions?.docCount ?? 0)\n}\n\nfunction isRestoreRowVisuallyEmpty(\n g: RestorePreviewResponse['groups'][number],\n preview: RestorePreviewResponse,\n): boolean {\n const t = groupDocTotal(g)\n const isMedia = g.groupId === 'media'\n const hasBlobs = preview.mediaBlobCount > 0\n return t === 0 && !(isMedia && hasBlobs)\n}\n\nfunction isRestoreCollectionCheckboxDisabled(\n g: RestorePreviewResponse['groups'][number],\n preview: RestorePreviewResponse,\n): boolean {\n return isRestoreRowVisuallyEmpty(g, preview)\n}\n\nfunction isRestoreSignInAgainGroup(groupId: string): boolean {\n return groupId === 'users' || groupId === 'roles' || groupId === 'payload-preferences'\n}\n\nexport const RestoreBackupDialog: React.FC<RestoreBackupDialogProps> = ({\n downloadUrl,\n pathname,\n}) => {\n const router = useRouter()\n const dialogRef = useRef<HTMLDialogElement>(null)\n const postSuccessCloseTimerRef = useRef<null | ReturnType<typeof setTimeout>>(null)\n const [preview, setPreview] = useState<null | RestorePreviewResponse>(null)\n const [phase, setPhase] = useState<'error' | 'idle' | 'loading' | 'ready'>('idle')\n const [errorMessage, setErrorMessage] = useState<null | string>(null)\n const [selected, setSelected] = useState<Record<string, boolean>>({})\n const [restoreAllCollections, setRestoreAllCollections] = useState(false)\n const [restoreArchiveMedia, setRestoreArchiveMedia] = useState(true)\n\n const resetState = useCallback(() => {\n setPreview(null)\n setPhase('idle')\n setErrorMessage(null)\n setSelected({})\n setRestoreAllCollections(false)\n setRestoreArchiveMedia(true)\n }, [])\n\n useEffect(() => {\n const el = dialogRef.current\n if (!el) {\n return\n }\n const onClose = () => {\n if (postSuccessCloseTimerRef.current) {\n clearTimeout(postSuccessCloseTimerRef.current)\n postSuccessCloseTimerRef.current = null\n }\n resetState()\n }\n el.addEventListener('close', onClose)\n return () => el.removeEventListener('close', onClose)\n }, [resetState])\n\n useEffect(() => {\n return () => {\n if (postSuccessCloseTimerRef.current) {\n clearTimeout(postSuccessCloseTimerRef.current)\n }\n }\n }, [])\n\n useEffect(() => {\n if (!preview) {\n return\n }\n setSelected(\n Object.fromEntries(\n preview.groups.map((g) => {\n const t = groupDocTotal(g)\n const isMedia = g.groupId === 'media'\n const hasBlobs = preview.mediaBlobCount > 0\n if (t === 0 && !(isMedia && hasBlobs)) {\n return [g.groupId, false]\n }\n return [g.groupId, true]\n }),\n ),\n )\n setRestoreAllCollections(false)\n setRestoreArchiveMedia(true)\n }, [preview])\n\n const loadPreview = useCallback(async () => {\n setPhase('loading')\n setErrorMessage(null)\n setPreview(null)\n try {\n const locale =\n typeof document !== 'undefined' ? (document.documentElement.lang || 'en').slice(0, 2) : 'en'\n const response = await fetch(backupPluginPublicApiPaths.adminRestorePreview, {\n body: JSON.stringify({\n locale,\n pathname,\n url: downloadUrl,\n }),\n headers: { 'Content-Type': 'application/json' },\n method: 'POST',\n })\n const data = (await response.json()) as { error?: string } & RestorePreviewResponse\n if (!response.ok) {\n throw new Error(data.error || 'Could not analyse backup')\n }\n setPreview(data)\n setPhase('ready')\n } catch (e) {\n setPhase('error')\n setErrorMessage(e instanceof Error ? e.message : 'Could not analyse backup')\n }\n }, [downloadUrl, pathname])\n\n const openDialog = () => {\n setPhase('loading')\n setErrorMessage(null)\n setPreview(null)\n setSelected({})\n setRestoreAllCollections(false)\n setRestoreArchiveMedia(true)\n dialogRef.current?.showModal()\n void loadPreview()\n }\n\n const skipCollections = useMemo(() => {\n if (!preview) {\n return []\n }\n if (restoreAllCollections) {\n return []\n }\n return preview.groups.filter((g) => selected[g.groupId] === false).flatMap((g) => g.mongoNames)\n }, [preview, restoreAllCollections, selected])\n\n const willAutoLogout = useMemo(() => {\n if (!preview) {\n return false\n }\n return preview.groups.some(\n (g) => (restoreAllCollections || selected[g.groupId] !== false) && g.affectsAuthSession,\n )\n }, [preview, restoreAllCollections, selected])\n\n const needsAuthLockoutConfirm = useCallback(() => {\n if (!preview) {\n return false\n }\n return preview.groups.some(\n (g) =>\n isRestoreSignInAgainGroup(g.groupId) &&\n (restoreAllCollections || selected[g.groupId] !== false),\n )\n }, [preview, restoreAllCollections, selected])\n\n const hasArchiveMedia = preview ? preview.mediaBlobCount > 0 : false\n const mediaGroupIncluded = preview ? restoreAllCollections || selected['media'] !== false : false\n const hasMediaBlobOption = Boolean(preview && preview.mediaBlobCount > 0 && mediaGroupIncluded)\n\n const restoreBody = useMemo(\n () => ({\n pathname,\n restoreArchiveMedia: hasArchiveMedia ? restoreArchiveMedia : true,\n skipCollections,\n url: downloadUrl,\n }),\n [downloadUrl, hasArchiveMedia, pathname, restoreArchiveMedia, skipCollections],\n )\n\n const closeModalAfterRestoreSuccess = useCallback(() => {\n if (postSuccessCloseTimerRef.current) {\n clearTimeout(postSuccessCloseTimerRef.current)\n }\n postSuccessCloseTimerRef.current = setTimeout(() => {\n postSuccessCloseTimerRef.current = null\n router.refresh()\n dialogRef.current?.close()\n }, 1000)\n }, [router])\n\n return (\n <>\n <Button buttonStyle=\"secondary\" onClick={openDialog} size=\"small\">\n Restore\n </Button>\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--restore\"\n onMouseDown={(e) => closeNativeDialogOnBackdropPointer(e, dialogRef)}\n ref={dialogRef}\n >\n <p className=\"backup-confirm-dialog__title\">Restore this backup?</p>\n\n <div className=\"backup-confirm-dialog__body restore-preview\">\n {phase === 'loading' && (\n <div aria-live=\"polite\" className=\"restore-preview__loading-block\">\n <p className=\"restore-preview__status\">Downloading and analysing backup…</p>\n <div className=\"restore-preview__loading-line\" />\n <div className=\"restore-preview__loading-line restore-preview__loading-line--short\" />\n <div className=\"restore-preview__loading-line\" />\n </div>\n )}\n\n {phase === 'error' && (\n <div className=\"restore-preview__error\">\n <p>{errorMessage}</p>\n <p className=\"restore-preview__error-hint\">\n You can still start restore below. If this backup replaces users or sessions, sign\n out manually afterwards if you are not redirected automatically.\n </p>\n <Button buttonStyle=\"secondary\" onClick={() => void loadPreview()} size=\"small\">\n Retry analysis\n </Button>\n </div>\n )}\n\n {phase === 'ready' && preview && (\n <>\n <p className=\"restore-preview__sticky-heading\">Collection selection</p>\n <p className=\"restore-preview__intro\">\n Choose which collections to restore. Version history is grouped with its collection.\n Collections with no documents in this backup still appear (greyed); you can leave\n them unchecked.\n </p>\n\n {preview.groups.length === 0 && (\n <p className=\"restore-preview__empty\">No collections found to list.</p>\n )}\n\n {restoreAllCollections ?\n <div className=\"restore-preview__all-block\">\n <label className=\"restore-preview__all-block-head\">\n <input\n aria-label=\"Restore all collections\"\n checked\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={() =>\n setRestoreAllCollections((prev) => {\n const next = !prev\n if (next && preview) {\n setSelected(\n Object.fromEntries(preview.groups.map((g) => [g.groupId, true])),\n )\n }\n return next\n })\n }\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">Restore all collections</span>\n </label>\n {preview.groups.length > 0 ?\n <ul aria-label=\"Collections in backup\" className=\"restore-preview__all-list\">\n {preview.groups.map((g) => {\n const isMedia = g.groupId === 'media'\n const rowEmpty = isRestoreRowVisuallyEmpty(g, preview)\n const versionDocs = g.versions?.docCount ?? 0\n const docTotal = groupDocTotal(g)\n const signInAgain = isRestoreSignInAgainGroup(g.groupId)\n\n let countLabel: string\n if (rowEmpty) {\n countLabel = 'Nothing to restore'\n } else if (docTotal === 0 && isMedia && preview.mediaBlobCount > 0) {\n countLabel = `0 docs · ${preview.mediaBlobCount} media file${preview.mediaBlobCount === 1 ? '' : 's'} in archive`\n } else {\n countLabel = `${docTotal} doc${docTotal === 1 ? '' : 's'} to restore`\n if (versionDocs > 0) {\n countLabel += ` (incl. ${versionDocs} version${versionDocs === 1 ? '' : 's'})`\n }\n }\n\n return (\n <li className=\"restore-preview__all-item\" key={g.groupId}>\n <span className=\"restore-preview__all-name\">\n {g.displayTitle}\n {signInAgain ?\n <>\n {' '}\n <span className=\"restore-preview__pill restore-preview__pill--signin\">\n Sign-in again\n </span>\n </>\n : null}\n </span>\n <span className=\"restore-preview__all-count\">{countLabel}</span>\n </li>\n )\n })}\n </ul>\n : null}\n {hasMediaBlobOption ?\n <label className=\"restore-preview__media-block restore-preview__media-block--nested\">\n <input\n aria-label={`Restore media files from backup (${preview.mediaBlobCount} files in archive)`}\n checked={restoreArchiveMedia}\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={() => setRestoreArchiveMedia((v) => !v)}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">\n Restore media files from backup? ({preview.mediaBlobCount} file\n {preview.mediaBlobCount === 1 ? '' : 's'} in archive)\n </span>\n </label>\n : null}\n </div>\n : <>\n <label className=\"restore-preview__media-block\">\n <input\n aria-label=\"Restore all collections\"\n checked={false}\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={() =>\n setRestoreAllCollections((prev) => {\n const next = !prev\n if (next && preview) {\n setSelected(\n Object.fromEntries(preview.groups.map((g) => [g.groupId, true])),\n )\n }\n return next\n })\n }\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">Restore all collections</span>\n </label>\n\n <ul aria-label=\"Collections in backup\" className=\"restore-preview__list\">\n {preview.groups.map((g) => {\n const adminPills = hiddenPills(g.adminHiddenReasons)\n const isMedia = g.groupId === 'media'\n const rowEmpty = isRestoreRowVisuallyEmpty(g, preview)\n const checkboxDisabled = isRestoreCollectionCheckboxDisabled(g, preview)\n const docTotal = groupDocTotal(g)\n\n return (\n <li\n className={`restore-preview__group${rowEmpty ? 'restore-preview__group--empty' : ''}`}\n key={g.groupId}\n >\n <div className=\"restore-preview__group-head\">\n <label className=\"restore-preview__group-label\">\n <input\n aria-label={`Restore collection ${g.displayTitle}`}\n checked={selected[g.groupId] !== false}\n className=\"checkbox-input__input restore-preview__group-check\"\n disabled={checkboxDisabled}\n onChange={() => {\n setSelected((prev) => {\n const isOn = prev[g.groupId] !== false\n return { ...prev, [g.groupId]: !isOn }\n })\n }}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__group-title\">{g.displayTitle}</span>\n </label>\n {isRestoreSignInAgainGroup(g.groupId) && (\n <span className=\"restore-preview__pill restore-preview__pill--signin\">\n Requires sign-in again\n </span>\n )}\n </div>\n <div className=\"restore-preview__sublines\">\n {rowEmpty ?\n <div className=\"restore-preview__subline restore-preview__subline--empty\">\n 0 docs, nothing to restore\n </div>\n : docTotal === 0 && isMedia && preview.mediaBlobCount > 0 ?\n <div className=\"restore-preview__subline\">\n 0 collection docs in backup\n </div>\n : <>\n {g.main ?\n <div className=\"restore-preview__subline\">\n {g.main.docCount} doc{g.main.docCount === 1 ? '' : 's'} to\n restore\n </div>\n : null}\n {g.versions ?\n <div className=\"restore-preview__subline\">\n {g.versions.docCount} version doc\n {g.versions.docCount === 1 ? '' : 's'} to restore\n </div>\n : null}\n </>\n }\n {isMedia &&\n selected['media'] !== false &&\n preview.mediaBlobCount === 0 &&\n docTotal > 0 && (\n <div className=\"restore-preview__note restore-preview__note--media\">\n No media files in this backup archive — only collection data will\n be restored for media.\n </div>\n )}\n {isMedia && hasMediaBlobOption && (\n <label className=\"restore-preview__media-block restore-preview__media-block--nested\">\n <input\n aria-label={`Restore media files from backup (${preview.mediaBlobCount} files in archive)`}\n checked={restoreArchiveMedia}\n className=\"checkbox-input__input restore-preview__group-check\"\n onChange={() => setRestoreArchiveMedia((v) => !v)}\n type=\"checkbox\"\n />\n <span className=\"restore-preview__media-label\">\n Restore media files from backup? ({preview.mediaBlobCount} file\n {preview.mediaBlobCount === 1 ? '' : 's'} in archive)\n </span>\n </label>\n )}\n {adminPills.length > 0 && (\n <div className=\"restore-preview__pills\">\n {adminPills.map((t) => (\n <span className=\"restore-preview__pill\" key={t}>\n {t}\n </span>\n ))}\n </div>\n )}\n </div>\n </li>\n )\n })}\n </ul>\n </>\n }\n </>\n )}\n </div>\n\n <div className=\"backup-confirm-dialog__actions\">\n <TaskActionButton\n body={restoreBody}\n buttonStyle=\"error\"\n completeLabel=\"Restore finished\"\n dangerConfirm={{\n body: 'You have selected Users, Roles, and/or Payload preferences. Restoring these collections replaces login accounts, role definitions, and/or UI session data. You can be locked out until you sign in again with the restored credentials. After a successful restore you will be signed out automatically.',\n cancelLabel: 'Go back',\n confirmLabel: 'I understand — restore anyway',\n title: 'Danger: lock-out risk',\n when: needsAuthLockoutConfirm,\n }}\n endpoint={backupPluginPublicApiPaths.adminRestore}\n idleDisabled={phase !== 'ready' && phase !== 'error'}\n idleLabel=\"Yes, restore\"\n kind=\"restore\"\n onComplete={closeModalAfterRestoreSuccess}\n pendingLabel=\"Restoring...\"\n redirectOnComplete={willAutoLogout ? '/admin/logout' : undefined}\n />\n <Button buttonStyle=\"secondary\" onClick={() => dialogRef.current?.close()} size=\"small\">\n Cancel\n </Button>\n </div>\n </dialog>\n </>\n )\n}\n"],"names":["Button","useRouter","useCallback","useEffect","useMemo","useRef","useState","backupPluginPublicApiPaths","closeNativeDialogOnBackdropPointer","TaskActionButton","hiddenPills","reasons","out","includes","push","groupDocTotal","g","main","docCount","versions","isRestoreRowVisuallyEmpty","preview","t","isMedia","groupId","hasBlobs","mediaBlobCount","isRestoreCollectionCheckboxDisabled","isRestoreSignInAgainGroup","RestoreBackupDialog","downloadUrl","pathname","router","dialogRef","postSuccessCloseTimerRef","setPreview","phase","setPhase","errorMessage","setErrorMessage","selected","setSelected","restoreAllCollections","setRestoreAllCollections","restoreArchiveMedia","setRestoreArchiveMedia","resetState","el","current","onClose","clearTimeout","addEventListener","removeEventListener","Object","fromEntries","groups","map","loadPreview","locale","document","documentElement","lang","slice","response","fetch","adminRestorePreview","body","JSON","stringify","url","headers","method","data","json","ok","Error","error","e","message","openDialog","showModal","skipCollections","filter","flatMap","mongoNames","willAutoLogout","some","affectsAuthSession","needsAuthLockoutConfirm","hasArchiveMedia","mediaGroupIncluded","hasMediaBlobOption","Boolean","restoreBody","closeModalAfterRestoreSuccess","setTimeout","refresh","close","buttonStyle","onClick","size","dialog","className","onMouseDown","ref","p","div","aria-live","length","label","input","aria-label","checked","onChange","prev","next","type","span","ul","rowEmpty","versionDocs","docTotal","signInAgain","countLabel","li","displayTitle","v","adminPills","adminHiddenReasons","checkboxDisabled","disabled","isOn","completeLabel","dangerConfirm","cancelLabel","confirmLabel","title","when","endpoint","adminRestore","idleDisabled","idleLabel","kind","onComplete","pendingLabel","redirectOnComplete","undefined"],"mappings":"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"}
|
|
@@ -19,7 +19,7 @@ type TaskActionButtonProps = {
|
|
|
19
19
|
idleDisabled?: boolean;
|
|
20
20
|
idleLabel: string;
|
|
21
21
|
kind: BackupTaskProgress['kind'];
|
|
22
|
-
/** Invoked once when the task reaches
|
|
22
|
+
/** Invoked once when the task reaches a successful terminal state (`completed` or `completed_with_warnings`). */
|
|
23
23
|
onComplete?: () => void;
|
|
24
24
|
pendingLabel: string;
|
|
25
25
|
redirectOnComplete?: string;
|