@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.
Files changed (97) hide show
  1. package/README.md +260 -90
  2. package/dist/backup-dashboard.css +18 -1
  3. package/dist/collections/BackupTasks.js +8 -1
  4. package/dist/collections/BackupTasks.js.map +1 -1
  5. package/dist/components/BackupDashboard/BackupListCollapsible.client.js.map +1 -1
  6. package/dist/components/BackupDashboard/BackupSettingsModal.client.js +203 -115
  7. package/dist/components/BackupDashboard/BackupSettingsModal.client.js.map +1 -1
  8. package/dist/components/BackupDashboard/CollectionBackupPreviewBody.client.js.map +1 -1
  9. package/dist/components/BackupDashboard/RestoreBackupDialog.client.js +1 -1
  10. package/dist/components/BackupDashboard/RestoreBackupDialog.client.js.map +1 -1
  11. package/dist/components/BackupDashboard/TaskActionButton.client.d.ts +1 -1
  12. package/dist/components/BackupDashboard/TaskActionButton.client.js +59 -26
  13. package/dist/components/BackupDashboard/TaskActionButton.client.js.map +1 -1
  14. package/dist/components/BackupDashboard/backupDashboardInlineCss.js +1 -1
  15. package/dist/components/BackupDashboard/backupDashboardInlineCss.js.map +1 -1
  16. package/dist/components/BackupDashboard/index.js +27 -3
  17. package/dist/components/BackupDashboard/index.js.map +1 -1
  18. package/dist/core/archive.js.map +1 -1
  19. package/dist/core/backup.d.ts +4 -3
  20. package/dist/core/backup.js +50 -43
  21. package/dist/core/backup.js.map +1 -1
  22. package/dist/core/backupArchiveRead.d.ts +15 -0
  23. package/dist/core/backupArchiveRead.js +30 -0
  24. package/dist/core/backupArchiveRead.js.map +1 -0
  25. package/dist/core/backupBlobIO.js.map +1 -1
  26. package/dist/core/backupSettings.js +5 -0
  27. package/dist/core/backupSettings.js.map +1 -1
  28. package/dist/core/blobTokenValidate.js.map +1 -1
  29. package/dist/core/restore.d.ts +5 -2
  30. package/dist/core/restore.js +133 -89
  31. package/dist/core/restore.js.map +1 -1
  32. package/dist/core/restorePreview.d.ts +12 -3
  33. package/dist/core/restorePreview.js +17 -13
  34. package/dist/core/restorePreview.js.map +1 -1
  35. package/dist/core/restoreResult.d.ts +34 -0
  36. package/dist/core/restoreResult.js +45 -0
  37. package/dist/core/restoreResult.js.map +1 -0
  38. package/dist/core/storage/config.d.ts +31 -0
  39. package/dist/core/storage/config.js +60 -0
  40. package/dist/core/storage/config.js.map +1 -0
  41. package/dist/core/storage/index.d.ts +23 -0
  42. package/dist/core/storage/index.js +25 -0
  43. package/dist/core/storage/index.js.map +1 -0
  44. package/dist/core/storage/s3.d.ts +35 -0
  45. package/dist/core/storage/s3.js +200 -0
  46. package/dist/core/storage/s3.js.map +1 -0
  47. package/dist/core/storage/types.d.ts +60 -0
  48. package/dist/core/storage/types.js +6 -0
  49. package/dist/core/storage/types.js.map +1 -0
  50. package/dist/core/storage/vercelBlob.d.ts +25 -0
  51. package/dist/core/storage/vercelBlob.js +53 -0
  52. package/dist/core/storage/vercelBlob.js.map +1 -0
  53. package/dist/core/taskProgress.d.ts +10 -4
  54. package/dist/core/taskProgress.js +11 -2
  55. package/dist/core/taskProgress.js.map +1 -1
  56. package/dist/core/vercelBackupCron.js.map +1 -1
  57. package/dist/endpoints/index.js +0 -5
  58. package/dist/endpoints/index.js.map +1 -1
  59. package/dist/endpoints/paths/admin-backup-download.js +8 -7
  60. package/dist/endpoints/paths/admin-backup-download.js.map +1 -1
  61. package/dist/endpoints/paths/admin-delete.js +11 -5
  62. package/dist/endpoints/paths/admin-delete.js.map +1 -1
  63. package/dist/endpoints/paths/admin-manual.js +2 -1
  64. package/dist/endpoints/paths/admin-manual.js.map +1 -1
  65. package/dist/endpoints/paths/admin-preview.js +9 -2
  66. package/dist/endpoints/paths/admin-preview.js.map +1 -1
  67. package/dist/endpoints/paths/admin-restore.js +7 -4
  68. package/dist/endpoints/paths/admin-restore.js.map +1 -1
  69. package/dist/endpoints/paths/admin-settings.js +35 -2
  70. package/dist/endpoints/paths/admin-settings.js.map +1 -1
  71. package/dist/endpoints/paths/cron-list.js +2 -1
  72. package/dist/endpoints/paths/cron-list.js.map +1 -1
  73. package/dist/endpoints/paths/cron-restore.js +14 -4
  74. package/dist/endpoints/paths/cron-restore.js.map +1 -1
  75. package/dist/endpoints/paths/cron-run.js +2 -1
  76. package/dist/endpoints/paths/cron-run.js.map +1 -1
  77. package/dist/endpoints/shared.d.ts +0 -1
  78. package/dist/endpoints/shared.js +0 -6
  79. package/dist/endpoints/shared.js.map +1 -1
  80. package/dist/index.d.ts +5 -3
  81. package/dist/index.js +3 -2
  82. package/dist/index.js.map +1 -1
  83. package/dist/plugin.js.map +1 -1
  84. package/dist/publicApiPaths.d.ts +0 -1
  85. package/dist/publicApiPaths.js +0 -1
  86. package/dist/publicApiPaths.js.map +1 -1
  87. package/dist/types.d.ts +0 -5
  88. package/dist/types.js.map +1 -1
  89. package/dist/utils/blobName.js.map +1 -1
  90. package/dist/utils/dashboardRoleAccess.js.map +1 -1
  91. package/dist/utils/dialogBackdrop.js.map +1 -1
  92. package/dist/utils/hostname.js.map +1 -1
  93. package/dist/utils/maskBlobToken.js.map +1 -1
  94. package/package.json +25 -4
  95. package/dist/endpoints/paths/admin-seed.d.ts +0 -3
  96. package/dist/endpoints/paths/admin-seed.js +0 -47
  97. package/dist/endpoints/paths/admin-seed.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/BackupDashboard/BackupListCollapsible.client.tsx"],"sourcesContent":["'use client'\n\nimport { Button, Collapsible } from '@payloadcms/ui'\nimport { useCallback, useId, useMemo, useRef, useState } from 'react'\n\nimport type { TransformBlobNameResult } from '../../utils/index'\n\nimport { closeNativeDialogOnBackdropPointer } from '../../utils/dialogBackdrop'\nimport { formatBytes, getBackupSortTimeMs, transformBlobName } from '../../utils/index'\nimport { BackupItemActions } from './BackupItemActions.client'\n\nexport interface SerializableBackupBlob {\n downloadUrl: string\n pathname: string\n size: number\n uploadedAt: string\n url: string\n}\n\nexport interface BackupListCollapsibleProps {\n blobs: SerializableBackupBlob[]\n countOtherDb: number\n countOtherHostname: number\n currentDbName: string\n currentHostname: string\n i18nLanguage: string\n}\n\ninterface BackupListFilterState {\n dateFrom: string\n dateTo: string\n label: string\n media: 'all' | 'with' | 'without'\n showOtherDb: boolean\n showOtherHostname: boolean\n source: 'all' | 'cron' | 'manual'\n}\n\nconst defaultFilterState: BackupListFilterState = {\n dateFrom: '',\n dateTo: '',\n label: '',\n media: 'all',\n showOtherDb: true,\n showOtherHostname: false,\n source: 'all',\n}\n\nfunction parseDateInputStartMs(isoDate: string): null | number {\n const parts = isoDate.split('-').map(Number)\n if (parts.length !== 3 || parts.some((n) => !Number.isFinite(n))) {\n return null\n }\n const [y, m, d] = parts\n const t = new Date(y, m - 1, d, 0, 0, 0, 0).getTime()\n return Number.isFinite(t) ? t : null\n}\n\nfunction parseDateInputEndMs(isoDate: string): null | number {\n const parts = isoDate.split('-').map(Number)\n if (parts.length !== 3 || parts.some((n) => !Number.isFinite(n))) {\n return null\n }\n const [y, m, d] = parts\n const t = new Date(y, m - 1, d, 23, 59, 59, 999).getTime()\n return Number.isFinite(t) ? t : null\n}\n\nfunction passesDateMediaSource(\n parsed: TransformBlobNameResult,\n displayMs: number,\n filters: BackupListFilterState,\n): boolean {\n if (filters.dateFrom) {\n const from = parseDateInputStartMs(filters.dateFrom)\n if (from != null && displayMs < from) {\n return false\n }\n }\n if (filters.dateTo) {\n const to = parseDateInputEndMs(filters.dateTo)\n if (to != null && displayMs > to) {\n return false\n }\n }\n if (filters.media === 'with' && parsed.fileType !== 'tar.gz') {\n return false\n }\n if (filters.media === 'without' && parsed.fileType !== 'json') {\n return false\n }\n if (filters.source === 'manual' && parsed.type !== 'manual') {\n return false\n }\n if (filters.source === 'cron' && parsed.type !== 'cron') {\n return false\n }\n const labelQuery = filters.label.trim().toLowerCase()\n if (labelQuery) {\n const blobLabel = (parsed.label ?? '').toLowerCase()\n if (!blobLabel.includes(labelQuery)) {\n return false\n }\n }\n return true\n}\n\nfunction hasNonDefaultFilters(f: BackupListFilterState): boolean {\n return (\n f.dateFrom !== defaultFilterState.dateFrom ||\n f.dateTo !== defaultFilterState.dateTo ||\n f.label !== defaultFilterState.label ||\n f.media !== defaultFilterState.media ||\n f.source !== defaultFilterState.source ||\n f.showOtherDb !== defaultFilterState.showOtherDb ||\n f.showOtherHostname !== defaultFilterState.showOtherHostname\n )\n}\n\nexport const BackupListCollapsible: React.FC<BackupListCollapsibleProps> = ({\n blobs,\n countOtherDb,\n countOtherHostname,\n currentDbName,\n currentHostname,\n i18nLanguage,\n}) => {\n const uid = useId()\n const idDb = `${uid}-show-other-db`\n const idHost = `${uid}-show-other-host`\n const dialogRef = useRef<HTMLDialogElement>(null)\n const [filters, setFilters] = useState<BackupListFilterState>(defaultFilterState)\n\n const visibleRows = useMemo(() => {\n const rows: Array<{\n blob: SerializableBackupBlob\n displayAt: Date\n displayMs: number\n parsed: TransformBlobNameResult\n }> = []\n\n for (const blob of blobs) {\n const parsed = transformBlobName(blob.pathname)\n const { dbName, hostname } = parsed\n const isCurrentDb = currentDbName === dbName\n const isCurrentHostname = currentHostname === hostname\n if (!(filters.showOtherDb || isCurrentDb)) {\n continue\n }\n if (!(filters.showOtherHostname || isCurrentHostname)) {\n continue\n }\n\n const uploadedAt = new Date(blob.uploadedAt)\n const displayMs = getBackupSortTimeMs(parsed, uploadedAt)\n if (!passesDateMediaSource(parsed, displayMs, filters)) {\n continue\n }\n\n rows.push({\n blob,\n displayAt: new Date(displayMs),\n displayMs,\n parsed,\n })\n }\n\n return rows\n }, [blobs, currentDbName, currentHostname, filters])\n\n const openFilterDialog = useCallback(() => {\n dialogRef.current?.showModal()\n }, [])\n\n const closeFilterDialog = useCallback(() => {\n dialogRef.current?.close()\n }, [])\n\n const clearFilters = useCallback(() => {\n setFilters(defaultFilterState)\n }, [])\n\n const hasScopeOptions = countOtherDb > 0 || countOtherHostname > 0\n const filtersActive = hasNonDefaultFilters(filters)\n\n const filtersButton = (\n <Button\n buttonStyle=\"secondary\"\n className={\n filtersActive\n ? 'backup-dashboard__filter-btn backup-dashboard__filter-btn--active'\n : 'backup-dashboard__filter-btn'\n }\n onClick={openFilterDialog}\n type=\"button\"\n >\n Filters\n </Button>\n )\n\n return (\n <>\n <Collapsible\n header={<span className=\"backup-dashboard__collapsible-title\">Backup list</span>}\n initCollapsed={true}\n >\n <div className=\"backup-dashboard__backup-list-toolbar\">{filtersButton}</div>\n {blobs.length === 0 ? (\n <p className=\"backup-dashboard__list-empty\">No backups yet</p>\n ) : visibleRows.length === 0 ? (\n <p className=\"backup-dashboard__list-empty\">No backups match the current filters</p>\n ) : (\n visibleRows.map(({ blob, displayAt, parsed }) => {\n const { type, collectionCount, dbName, fileType, hostname, label } = parsed\n const isCurrentDb = currentDbName === dbName\n const isCurrentHostname = currentHostname === hostname\n\n return (\n <div className=\"backup-item\" key={blob.pathname}>\n <div className=\"backup-item__main\">\n <div className=\"backup-item__primary\">\n <time\n className=\"backup-item__time\"\n dateTime={displayAt.toISOString()}\n suppressHydrationWarning\n >\n {displayAt.toLocaleString(i18nLanguage)}\n </time>\n <span\n className={`backup-item__pill backup-item__pill--kind backup-item__pill--${type === 'cron' ? 'cron' : 'manual'}`}\n >\n {type === 'cron' ? 'Cron backup' : 'Manual backup'}\n </span>\n {label ? (\n <span\n className=\"backup-item__pill backup-item__pill--label\"\n title={`Label: ${label}`}\n >\n <span className=\"backup-item__pill-key\">Label</span>\n {label}\n </span>\n ) : null}\n </div>\n <div className=\"backup-item__meta\">\n <span\n className={`backup-item__pill backup-item__pill--db${isCurrentDb ? '' : ' backup-item__pill--warn'}`}\n >\n <span className=\"backup-item__pill-key\">\n {isCurrentDb ? 'DB' : 'other DB'}\n </span>\n {dbName || 'Unknown'}\n </span>\n <span\n className={`backup-item__pill backup-item__pill--host${isCurrentHostname ? '' : ' backup-item__pill--warn'}`}\n >\n <span className=\"backup-item__pill-key\">Host</span>\n {hostname || 'Unknown'}\n </span>\n {typeof collectionCount === 'number' ? (\n <span className=\"backup-item__pill backup-item__pill--collections\">\n <span className=\"backup-item__pill-key\">Collections</span>\n {collectionCount}\n </span>\n ) : null}\n {fileType === 'tar.gz' ? (\n <span className=\"backup-item__pill backup-item__pill--media\">With media</span>\n ) : fileType === 'json' ? (\n <span className=\"backup-item__pill backup-item__pill--media\">\n Without media\n </span>\n ) : null}\n <span\n className=\"backup-item__pill backup-item__pill--size\"\n title={`${blob.size.toLocaleString(i18nLanguage)} bytes`}\n >\n <span className=\"backup-item__pill-key\">Size</span>\n <span className=\"backup-item__size-value\">{formatBytes(blob.size)}</span>\n </span>\n </div>\n </div>\n <BackupItemActions\n downloadUrl={blob.downloadUrl}\n pathname={blob.pathname}\n url={blob.url}\n />\n </div>\n )\n })\n )}\n </Collapsible>\n\n <dialog\n className=\"backup-confirm-dialog backup-confirm-dialog--backup-list-filters\"\n onPointerDown={(e) => closeNativeDialogOnBackdropPointer(e, dialogRef)}\n ref={dialogRef}\n >\n <h3 className=\"backup-confirm-dialog__title\">Filter backups</h3>\n <p className=\"backup-confirm-dialog__subtitle\">\n All filters apply in the browser only. Current DB and hostname are always shown; enable\n the options below to include backups from other databases or hosts.\n </p>\n <div className=\"backup-confirm-dialog__body backup-list-filters__body\">\n {hasScopeOptions ? (\n <fieldset className=\"backup-list-filters__fieldset\">\n <legend className=\"backup-list-filters__legend\">Scope</legend>\n {countOtherDb > 0 ? (\n <div className=\"field-type checkbox backup-dashboard__collapsible-checkbox backup-list-filters__scope-row\">\n <input\n aria-label={`Show other databases (${countOtherDb} in list)`}\n checked={filters.showOtherDb}\n className=\"checkbox-input__input\"\n id={idDb}\n onChange={(e) => setFilters((f) => ({ ...f, showOtherDb: e.target.checked }))}\n type=\"checkbox\"\n />\n <label className=\"field-label\" htmlFor={idDb}>\n Show other DBs\n <span className=\"backup-list-filters__hint\"> ({countOtherDb} in list)</span>\n </label>\n </div>\n ) : null}\n {countOtherHostname > 0 ? (\n <div className=\"field-type checkbox backup-dashboard__collapsible-checkbox backup-list-filters__scope-row\">\n <input\n aria-label={`Show other hostnames (${countOtherHostname} in list)`}\n checked={filters.showOtherHostname}\n className=\"checkbox-input__input\"\n id={idHost}\n onChange={(e) =>\n setFilters((f) => ({ ...f, showOtherHostname: e.target.checked }))\n }\n type=\"checkbox\"\n />\n <label className=\"field-label\" htmlFor={idHost}>\n Show other Hostnames\n <span className=\"backup-list-filters__hint\">\n {' '}\n ({countOtherHostname} in list)\n </span>\n </label>\n </div>\n ) : null}\n </fieldset>\n ) : null}\n\n <fieldset className=\"backup-list-filters__fieldset\">\n <legend className=\"backup-list-filters__legend\">Label</legend>\n <div className=\"backup-list-filters__row backup-list-filters__row--label\">\n <label className=\"backup-list-filters__label\" htmlFor={`${uid}-label`}>\n Search\n </label>\n <input\n aria-label=\"Filter backups by label text\"\n autoComplete=\"off\"\n className=\"backup-list-filters__text\"\n id={`${uid}-label`}\n onChange={(e) => setFilters((f) => ({ ...f, label: e.target.value }))}\n placeholder=\"Filter by label text\"\n spellCheck={false}\n type=\"text\"\n value={filters.label}\n />\n </div>\n </fieldset>\n\n <fieldset className=\"backup-list-filters__fieldset\">\n <legend className=\"backup-list-filters__legend\">Date range</legend>\n <div className=\"backup-list-filters__row\">\n <label className=\"backup-list-filters__label\" htmlFor={`${uid}-from`}>\n From\n </label>\n <input\n aria-label=\"Filter from date\"\n className=\"backup-list-filters__date\"\n id={`${uid}-from`}\n onChange={(e) => setFilters((f) => ({ ...f, dateFrom: e.target.value }))}\n type=\"date\"\n value={filters.dateFrom}\n />\n </div>\n <div className=\"backup-list-filters__row\">\n <label className=\"backup-list-filters__label\" htmlFor={`${uid}-to`}>\n To\n </label>\n <input\n aria-label=\"Filter to date\"\n className=\"backup-list-filters__date\"\n id={`${uid}-to`}\n onChange={(e) => setFilters((f) => ({ ...f, dateTo: e.target.value }))}\n type=\"date\"\n value={filters.dateTo}\n />\n </div>\n </fieldset>\n\n <fieldset className=\"backup-list-filters__fieldset\">\n <legend className=\"backup-list-filters__legend\">Media</legend>\n <div className=\"field-type radio backup-list-filters__radio-row\">\n <input\n aria-label=\"Media filter: all backups\"\n checked={filters.media === 'all'}\n className=\"radio-input__input\"\n id={`${uid}-media-all`}\n name={`${uid}-media`}\n onChange={() => setFilters((f) => ({ ...f, media: 'all' }))}\n type=\"radio\"\n />\n <label className=\"field-label\" htmlFor={`${uid}-media-all`}>\n All\n </label>\n </div>\n <div className=\"field-type radio backup-list-filters__radio-row\">\n <input\n aria-label=\"Media filter: with media\"\n checked={filters.media === 'with'}\n className=\"radio-input__input\"\n id={`${uid}-media-with`}\n name={`${uid}-media`}\n onChange={() => setFilters((f) => ({ ...f, media: 'with' }))}\n type=\"radio\"\n />\n <label className=\"field-label\" htmlFor={`${uid}-media-with`}>\n With media\n </label>\n </div>\n <div className=\"field-type radio backup-list-filters__radio-row\">\n <input\n aria-label=\"Media filter: without media\"\n checked={filters.media === 'without'}\n className=\"radio-input__input\"\n id={`${uid}-media-without`}\n name={`${uid}-media`}\n onChange={() => setFilters((f) => ({ ...f, media: 'without' }))}\n type=\"radio\"\n />\n <label className=\"field-label\" htmlFor={`${uid}-media-without`}>\n Without media\n </label>\n </div>\n </fieldset>\n\n <fieldset className=\"backup-list-filters__fieldset\">\n <legend className=\"backup-list-filters__legend\">Source</legend>\n <div className=\"field-type radio backup-list-filters__radio-row\">\n <input\n aria-label=\"Source filter: all\"\n checked={filters.source === 'all'}\n className=\"radio-input__input\"\n id={`${uid}-source-all`}\n name={`${uid}-source`}\n onChange={() => setFilters((f) => ({ ...f, source: 'all' }))}\n type=\"radio\"\n />\n <label className=\"field-label\" htmlFor={`${uid}-source-all`}>\n All\n </label>\n </div>\n <div className=\"field-type radio backup-list-filters__radio-row\">\n <input\n aria-label=\"Source filter: manual backups\"\n checked={filters.source === 'manual'}\n className=\"radio-input__input\"\n id={`${uid}-source-manual`}\n name={`${uid}-source`}\n onChange={() => setFilters((f) => ({ ...f, source: 'manual' }))}\n type=\"radio\"\n />\n <label className=\"field-label\" htmlFor={`${uid}-source-manual`}>\n Manual\n </label>\n </div>\n <div className=\"field-type radio backup-list-filters__radio-row\">\n <input\n aria-label=\"Source filter: cron backups\"\n checked={filters.source === 'cron'}\n className=\"radio-input__input\"\n id={`${uid}-source-cron`}\n name={`${uid}-source`}\n onChange={() => setFilters((f) => ({ ...f, source: 'cron' }))}\n type=\"radio\"\n />\n <label className=\"field-label\" htmlFor={`${uid}-source-cron`}>\n Cron\n </label>\n </div>\n </fieldset>\n </div>\n <div className=\"backup-confirm-dialog__actions\">\n <Button buttonStyle=\"secondary\" onClick={clearFilters} type=\"button\">\n Clear filters\n </Button>\n <Button onClick={closeFilterDialog} type=\"button\">\n Done\n </Button>\n </div>\n </dialog>\n </>\n )\n}\n"],"names":["Button","Collapsible","useCallback","useId","useMemo","useRef","useState","closeNativeDialogOnBackdropPointer","formatBytes","getBackupSortTimeMs","transformBlobName","BackupItemActions","defaultFilterState","dateFrom","dateTo","label","media","showOtherDb","showOtherHostname","source","parseDateInputStartMs","isoDate","parts","split","map","Number","length","some","n","isFinite","y","m","d","t","Date","getTime","parseDateInputEndMs","passesDateMediaSource","parsed","displayMs","filters","from","to","fileType","type","labelQuery","trim","toLowerCase","blobLabel","includes","hasNonDefaultFilters","f","BackupListCollapsible","blobs","countOtherDb","countOtherHostname","currentDbName","currentHostname","i18nLanguage","uid","idDb","idHost","dialogRef","setFilters","visibleRows","rows","blob","pathname","dbName","hostname","isCurrentDb","isCurrentHostname","uploadedAt","push","displayAt","openFilterDialog","current","showModal","closeFilterDialog","close","clearFilters","hasScopeOptions","filtersActive","filtersButton","buttonStyle","className","onClick","header","span","initCollapsed","div","p","collectionCount","time","dateTime","toISOString","suppressHydrationWarning","toLocaleString","title","size","downloadUrl","url","dialog","onPointerDown","e","ref","h3","fieldset","legend","input","aria-label","checked","id","onChange","target","htmlFor","autoComplete","value","placeholder","spellCheck","name"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/BackupDashboard/BackupListCollapsible.client.tsx"],"sourcesContent":["'use client'\n\nimport { Button, Collapsible } from '@payloadcms/ui'\nimport { useCallback, useId, useMemo, useRef, useState } from 'react'\n\nimport type { TransformBlobNameResult } from '../../utils/index'\n\nimport { closeNativeDialogOnBackdropPointer } from '../../utils/dialogBackdrop'\nimport { formatBytes, getBackupSortTimeMs, transformBlobName } from '../../utils/index'\nimport { BackupItemActions } from './BackupItemActions.client'\n\nexport interface SerializableBackupBlob {\n downloadUrl: string\n pathname: string\n size: number\n uploadedAt: string\n url: string\n}\n\nexport interface BackupListCollapsibleProps {\n blobs: SerializableBackupBlob[]\n countOtherDb: number\n countOtherHostname: number\n currentDbName: string\n currentHostname: string\n i18nLanguage: string\n}\n\ninterface BackupListFilterState {\n dateFrom: string\n dateTo: string\n label: string\n media: 'all' | 'with' | 'without'\n showOtherDb: boolean\n showOtherHostname: boolean\n source: 'all' | 'cron' | 'manual'\n}\n\nconst defaultFilterState: BackupListFilterState = {\n dateFrom: '',\n dateTo: '',\n label: '',\n media: 'all',\n showOtherDb: true,\n showOtherHostname: false,\n source: 'all',\n}\n\nfunction parseDateInputStartMs(isoDate: string): null | number {\n const parts = isoDate.split('-').map(Number)\n if (parts.length !== 3 || parts.some((n) => !Number.isFinite(n))) {\n return null\n }\n const [y, m, d] = parts\n const t = new Date(y, m - 1, d, 0, 0, 0, 0).getTime()\n return Number.isFinite(t) ? t : null\n}\n\nfunction parseDateInputEndMs(isoDate: string): null | number {\n const parts = isoDate.split('-').map(Number)\n if (parts.length !== 3 || parts.some((n) => !Number.isFinite(n))) {\n return null\n }\n const [y, m, d] = parts\n const t = new Date(y, m - 1, d, 23, 59, 59, 999).getTime()\n return Number.isFinite(t) ? t : null\n}\n\nfunction passesDateMediaSource(\n parsed: TransformBlobNameResult,\n displayMs: number,\n filters: BackupListFilterState,\n): boolean {\n if (filters.dateFrom) {\n const from = parseDateInputStartMs(filters.dateFrom)\n if (from != null && displayMs < from) {\n return false\n }\n }\n if (filters.dateTo) {\n const to = parseDateInputEndMs(filters.dateTo)\n if (to != null && displayMs > to) {\n return false\n }\n }\n if (filters.media === 'with' && parsed.fileType !== 'tar.gz') {\n return false\n }\n if (filters.media === 'without' && parsed.fileType !== 'json') {\n return false\n }\n if (filters.source === 'manual' && parsed.type !== 'manual') {\n return false\n }\n if (filters.source === 'cron' && parsed.type !== 'cron') {\n return false\n }\n const labelQuery = filters.label.trim().toLowerCase()\n if (labelQuery) {\n const blobLabel = (parsed.label ?? '').toLowerCase()\n if (!blobLabel.includes(labelQuery)) {\n return false\n }\n }\n return true\n}\n\nfunction hasNonDefaultFilters(f: BackupListFilterState): boolean {\n return (\n f.dateFrom !== defaultFilterState.dateFrom ||\n f.dateTo !== defaultFilterState.dateTo ||\n f.label !== defaultFilterState.label ||\n f.media !== defaultFilterState.media ||\n f.source !== defaultFilterState.source ||\n f.showOtherDb !== defaultFilterState.showOtherDb ||\n f.showOtherHostname !== defaultFilterState.showOtherHostname\n )\n}\n\nexport const BackupListCollapsible: React.FC<BackupListCollapsibleProps> = ({\n blobs,\n countOtherDb,\n countOtherHostname,\n currentDbName,\n currentHostname,\n i18nLanguage,\n}) => {\n const uid = useId()\n const idDb = `${uid}-show-other-db`\n const idHost = `${uid}-show-other-host`\n const dialogRef = useRef<HTMLDialogElement>(null)\n const [filters, setFilters] = useState<BackupListFilterState>(defaultFilterState)\n\n const visibleRows = useMemo(() => {\n const rows: Array<{\n blob: SerializableBackupBlob\n displayAt: Date\n displayMs: number\n parsed: TransformBlobNameResult\n }> = []\n\n for (const blob of blobs) {\n const parsed = transformBlobName(blob.pathname)\n const { dbName, hostname } = parsed\n const isCurrentDb = currentDbName === dbName\n const isCurrentHostname = currentHostname === hostname\n if (!(filters.showOtherDb || isCurrentDb)) {\n continue\n }\n if (!(filters.showOtherHostname || isCurrentHostname)) {\n continue\n }\n\n const uploadedAt = new Date(blob.uploadedAt)\n const displayMs = getBackupSortTimeMs(parsed, uploadedAt)\n if (!passesDateMediaSource(parsed, displayMs, filters)) {\n continue\n }\n\n rows.push({\n blob,\n displayAt: new Date(displayMs),\n displayMs,\n parsed,\n })\n }\n\n return rows\n }, [blobs, currentDbName, currentHostname, filters])\n\n const openFilterDialog = useCallback(() => {\n dialogRef.current?.showModal()\n }, [])\n\n const closeFilterDialog = useCallback(() => {\n dialogRef.current?.close()\n }, [])\n\n const clearFilters = useCallback(() => {\n setFilters(defaultFilterState)\n }, [])\n\n const hasScopeOptions = countOtherDb > 0 || countOtherHostname > 0\n const filtersActive = hasNonDefaultFilters(filters)\n\n const filtersButton = (\n <Button\n buttonStyle=\"secondary\"\n className={\n filtersActive ?\n 'backup-dashboard__filter-btn backup-dashboard__filter-btn--active'\n : 'backup-dashboard__filter-btn'\n }\n onClick={openFilterDialog}\n type=\"button\"\n >\n Filters\n </Button>\n )\n\n return (\n <>\n <Collapsible\n header={<span className=\"backup-dashboard__collapsible-title\">Backup list</span>}\n initCollapsed={true}\n >\n <div className=\"backup-dashboard__backup-list-toolbar\">{filtersButton}</div>\n {blobs.length === 0 ?\n <p className=\"backup-dashboard__list-empty\">No backups yet</p>\n : visibleRows.length === 0 ?\n <p className=\"backup-dashboard__list-empty\">No backups match the current filters</p>\n : visibleRows.map(({ blob, displayAt, parsed }) => {\n const { type, collectionCount, dbName, fileType, hostname, label } = parsed\n const isCurrentDb = currentDbName === dbName\n const isCurrentHostname = currentHostname === hostname\n\n return (\n <div className=\"backup-item\" key={blob.pathname}>\n <div className=\"backup-item__main\">\n <div className=\"backup-item__primary\">\n <time\n className=\"backup-item__time\"\n dateTime={displayAt.toISOString()}\n suppressHydrationWarning\n >\n {displayAt.toLocaleString(i18nLanguage)}\n </time>\n <span\n className={`backup-item__pill backup-item__pill--kind backup-item__pill--${type === 'cron' ? 'cron' : 'manual'}`}\n >\n {type === 'cron' ? 'Cron backup' : 'Manual backup'}\n </span>\n {label ?\n <span\n className=\"backup-item__pill backup-item__pill--label\"\n title={`Label: ${label}`}\n >\n <span className=\"backup-item__pill-key\">Label</span>\n {label}\n </span>\n : null}\n </div>\n <div className=\"backup-item__meta\">\n <span\n className={`backup-item__pill backup-item__pill--db${isCurrentDb ? '' : ' backup-item__pill--warn'}`}\n >\n <span className=\"backup-item__pill-key\">\n {isCurrentDb ? 'DB' : 'other DB'}\n </span>\n {dbName || 'Unknown'}\n </span>\n <span\n className={`backup-item__pill backup-item__pill--host${isCurrentHostname ? '' : ' backup-item__pill--warn'}`}\n >\n <span className=\"backup-item__pill-key\">Host</span>\n {hostname || 'Unknown'}\n </span>\n {typeof collectionCount === 'number' ?\n <span className=\"backup-item__pill backup-item__pill--collections\">\n <span className=\"backup-item__pill-key\">Collections</span>\n {collectionCount}\n </span>\n : null}\n {fileType === 'tar.gz' ?\n <span className=\"backup-item__pill backup-item__pill--media\">With media</span>\n : fileType === 'json' ?\n <span className=\"backup-item__pill backup-item__pill--media\">\n Without media\n </span>\n : null}\n <span\n className=\"backup-item__pill backup-item__pill--size\"\n title={`${blob.size.toLocaleString(i18nLanguage)} bytes`}\n >\n <span className=\"backup-item__pill-key\">Size</span>\n <span className=\"backup-item__size-value\">{formatBytes(blob.size)}</span>\n </span>\n </div>\n </div>\n <BackupItemActions\n downloadUrl={blob.downloadUrl}\n pathname={blob.pathname}\n url={blob.url}\n />\n </div>\n )\n })\n }\n </Collapsible>\n\n <dialog\n className=\"backup-confirm-dialog backup-confirm-dialog--backup-list-filters\"\n onPointerDown={(e) => closeNativeDialogOnBackdropPointer(e, dialogRef)}\n ref={dialogRef}\n >\n <h3 className=\"backup-confirm-dialog__title\">Filter backups</h3>\n <p className=\"backup-confirm-dialog__subtitle\">\n All filters apply in the browser only. Current DB and hostname are always shown; enable\n the options below to include backups from other databases or hosts.\n </p>\n <div className=\"backup-confirm-dialog__body backup-list-filters__body\">\n {hasScopeOptions ?\n <fieldset className=\"backup-list-filters__fieldset\">\n <legend className=\"backup-list-filters__legend\">Scope</legend>\n {countOtherDb > 0 ?\n <div className=\"field-type checkbox backup-dashboard__collapsible-checkbox backup-list-filters__scope-row\">\n <input\n aria-label={`Show other databases (${countOtherDb} in list)`}\n checked={filters.showOtherDb}\n className=\"checkbox-input__input\"\n id={idDb}\n onChange={(e) => setFilters((f) => ({ ...f, showOtherDb: e.target.checked }))}\n type=\"checkbox\"\n />\n <label className=\"field-label\" htmlFor={idDb}>\n Show other DBs\n <span className=\"backup-list-filters__hint\"> ({countOtherDb} in list)</span>\n </label>\n </div>\n : null}\n {countOtherHostname > 0 ?\n <div className=\"field-type checkbox backup-dashboard__collapsible-checkbox backup-list-filters__scope-row\">\n <input\n aria-label={`Show other hostnames (${countOtherHostname} in list)`}\n checked={filters.showOtherHostname}\n className=\"checkbox-input__input\"\n id={idHost}\n onChange={(e) =>\n setFilters((f) => ({ ...f, showOtherHostname: e.target.checked }))\n }\n type=\"checkbox\"\n />\n <label className=\"field-label\" htmlFor={idHost}>\n Show other Hostnames\n <span className=\"backup-list-filters__hint\">\n {' '}\n ({countOtherHostname} in list)\n </span>\n </label>\n </div>\n : null}\n </fieldset>\n : null}\n\n <fieldset className=\"backup-list-filters__fieldset\">\n <legend className=\"backup-list-filters__legend\">Label</legend>\n <div className=\"backup-list-filters__row backup-list-filters__row--label\">\n <label className=\"backup-list-filters__label\" htmlFor={`${uid}-label`}>\n Search\n </label>\n <input\n aria-label=\"Filter backups by label text\"\n autoComplete=\"off\"\n className=\"backup-list-filters__text\"\n id={`${uid}-label`}\n onChange={(e) => setFilters((f) => ({ ...f, label: e.target.value }))}\n placeholder=\"Filter by label text\"\n spellCheck={false}\n type=\"text\"\n value={filters.label}\n />\n </div>\n </fieldset>\n\n <fieldset className=\"backup-list-filters__fieldset\">\n <legend className=\"backup-list-filters__legend\">Date range</legend>\n <div className=\"backup-list-filters__row\">\n <label className=\"backup-list-filters__label\" htmlFor={`${uid}-from`}>\n From\n </label>\n <input\n aria-label=\"Filter from date\"\n className=\"backup-list-filters__date\"\n id={`${uid}-from`}\n onChange={(e) => setFilters((f) => ({ ...f, dateFrom: e.target.value }))}\n type=\"date\"\n value={filters.dateFrom}\n />\n </div>\n <div className=\"backup-list-filters__row\">\n <label className=\"backup-list-filters__label\" htmlFor={`${uid}-to`}>\n To\n </label>\n <input\n aria-label=\"Filter to date\"\n className=\"backup-list-filters__date\"\n id={`${uid}-to`}\n onChange={(e) => setFilters((f) => ({ ...f, dateTo: e.target.value }))}\n type=\"date\"\n value={filters.dateTo}\n />\n </div>\n </fieldset>\n\n <fieldset className=\"backup-list-filters__fieldset\">\n <legend className=\"backup-list-filters__legend\">Media</legend>\n <div className=\"field-type radio backup-list-filters__radio-row\">\n <input\n aria-label=\"Media filter: all backups\"\n checked={filters.media === 'all'}\n className=\"radio-input__input\"\n id={`${uid}-media-all`}\n name={`${uid}-media`}\n onChange={() => setFilters((f) => ({ ...f, media: 'all' }))}\n type=\"radio\"\n />\n <label className=\"field-label\" htmlFor={`${uid}-media-all`}>\n All\n </label>\n </div>\n <div className=\"field-type radio backup-list-filters__radio-row\">\n <input\n aria-label=\"Media filter: with media\"\n checked={filters.media === 'with'}\n className=\"radio-input__input\"\n id={`${uid}-media-with`}\n name={`${uid}-media`}\n onChange={() => setFilters((f) => ({ ...f, media: 'with' }))}\n type=\"radio\"\n />\n <label className=\"field-label\" htmlFor={`${uid}-media-with`}>\n With media\n </label>\n </div>\n <div className=\"field-type radio backup-list-filters__radio-row\">\n <input\n aria-label=\"Media filter: without media\"\n checked={filters.media === 'without'}\n className=\"radio-input__input\"\n id={`${uid}-media-without`}\n name={`${uid}-media`}\n onChange={() => setFilters((f) => ({ ...f, media: 'without' }))}\n type=\"radio\"\n />\n <label className=\"field-label\" htmlFor={`${uid}-media-without`}>\n Without media\n </label>\n </div>\n </fieldset>\n\n <fieldset className=\"backup-list-filters__fieldset\">\n <legend className=\"backup-list-filters__legend\">Source</legend>\n <div className=\"field-type radio backup-list-filters__radio-row\">\n <input\n aria-label=\"Source filter: all\"\n checked={filters.source === 'all'}\n className=\"radio-input__input\"\n id={`${uid}-source-all`}\n name={`${uid}-source`}\n onChange={() => setFilters((f) => ({ ...f, source: 'all' }))}\n type=\"radio\"\n />\n <label className=\"field-label\" htmlFor={`${uid}-source-all`}>\n All\n </label>\n </div>\n <div className=\"field-type radio backup-list-filters__radio-row\">\n <input\n aria-label=\"Source filter: manual backups\"\n checked={filters.source === 'manual'}\n className=\"radio-input__input\"\n id={`${uid}-source-manual`}\n name={`${uid}-source`}\n onChange={() => setFilters((f) => ({ ...f, source: 'manual' }))}\n type=\"radio\"\n />\n <label className=\"field-label\" htmlFor={`${uid}-source-manual`}>\n Manual\n </label>\n </div>\n <div className=\"field-type radio backup-list-filters__radio-row\">\n <input\n aria-label=\"Source filter: cron backups\"\n checked={filters.source === 'cron'}\n className=\"radio-input__input\"\n id={`${uid}-source-cron`}\n name={`${uid}-source`}\n onChange={() => setFilters((f) => ({ ...f, source: 'cron' }))}\n type=\"radio\"\n />\n <label className=\"field-label\" htmlFor={`${uid}-source-cron`}>\n Cron\n </label>\n </div>\n </fieldset>\n </div>\n <div className=\"backup-confirm-dialog__actions\">\n <Button buttonStyle=\"secondary\" onClick={clearFilters} type=\"button\">\n Clear filters\n </Button>\n <Button onClick={closeFilterDialog} type=\"button\">\n Done\n </Button>\n </div>\n </dialog>\n </>\n )\n}\n"],"names":["Button","Collapsible","useCallback","useId","useMemo","useRef","useState","closeNativeDialogOnBackdropPointer","formatBytes","getBackupSortTimeMs","transformBlobName","BackupItemActions","defaultFilterState","dateFrom","dateTo","label","media","showOtherDb","showOtherHostname","source","parseDateInputStartMs","isoDate","parts","split","map","Number","length","some","n","isFinite","y","m","d","t","Date","getTime","parseDateInputEndMs","passesDateMediaSource","parsed","displayMs","filters","from","to","fileType","type","labelQuery","trim","toLowerCase","blobLabel","includes","hasNonDefaultFilters","f","BackupListCollapsible","blobs","countOtherDb","countOtherHostname","currentDbName","currentHostname","i18nLanguage","uid","idDb","idHost","dialogRef","setFilters","visibleRows","rows","blob","pathname","dbName","hostname","isCurrentDb","isCurrentHostname","uploadedAt","push","displayAt","openFilterDialog","current","showModal","closeFilterDialog","close","clearFilters","hasScopeOptions","filtersActive","filtersButton","buttonStyle","className","onClick","header","span","initCollapsed","div","p","collectionCount","time","dateTime","toISOString","suppressHydrationWarning","toLocaleString","title","size","downloadUrl","url","dialog","onPointerDown","e","ref","h3","fieldset","legend","input","aria-label","checked","id","onChange","target","htmlFor","autoComplete","value","placeholder","spellCheck","name"],"mappings":"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"}
@@ -86,6 +86,7 @@ export const BackupSettingsModal = ()=>{
86
86
  });
87
87
  const [pluginOverridesRetention, setPluginOverridesRetention] = useState(false);
88
88
  const [cronInfo, setCronInfo] = useState(undefined);
89
+ const [storage, setStorage] = useState(undefined);
89
90
  const [transferSummary, setTransferSummary] = useState(null);
90
91
  const [activeTransfer, setActiveTransfer] = useState(null);
91
92
  const [transferLive, setTransferLive] = useState(null);
@@ -173,6 +174,7 @@ export const BackupSettingsModal = ()=>{
173
174
  });
174
175
  setPluginOverridesRetention(settingsJson.pluginBackupsToKeepOverride === true);
175
176
  setCronInfo(settingsJson.cron ?? null);
177
+ setStorage(settingsJson.storage);
176
178
  setIncludeMediaBlobs(settingsJson.includeMediaForCron === true);
177
179
  const skip = Array.isArray(settingsJson.skipMongoCollections) ? settingsJson.skipMongoCollections : [];
178
180
  setSelected(selectedFromSkipMongoNames(previewJson, skip));
@@ -575,6 +577,88 @@ export const BackupSettingsModal = ()=>{
575
577
  /*#__PURE__*/ _jsxs("div", {
576
578
  className: "backup-confirm-dialog__body restore-preview",
577
579
  children: [
580
+ storage ? /*#__PURE__*/ _jsxs(_Fragment, {
581
+ children: [
582
+ /*#__PURE__*/ _jsx("p", {
583
+ className: "restore-preview__sticky-heading",
584
+ children: "Storage target"
585
+ }),
586
+ storage.kind === 's3' ? /*#__PURE__*/ _jsxs(_Fragment, {
587
+ children: [
588
+ /*#__PURE__*/ _jsxs("p", {
589
+ className: "restore-preview__intro",
590
+ children: [
591
+ "Backups use ",
592
+ /*#__PURE__*/ _jsx("strong", {
593
+ children: "AWS S3"
594
+ }),
595
+ " (or S3-compatible). Selected via the",
596
+ ' ',
597
+ /*#__PURE__*/ _jsx("code", {
598
+ children: "BACKUP_STORAGE"
599
+ }),
600
+ " environment variable."
601
+ ]
602
+ }),
603
+ storage.s3 ? /*#__PURE__*/ _jsxs("p", {
604
+ className: "restore-preview__intro",
605
+ children: [
606
+ "Bucket ",
607
+ /*#__PURE__*/ _jsx("code", {
608
+ children: storage.s3.bucket
609
+ }),
610
+ " · region",
611
+ ' ',
612
+ /*#__PURE__*/ _jsx("code", {
613
+ children: storage.s3.region
614
+ }),
615
+ storage.s3.endpoint ? /*#__PURE__*/ _jsxs(_Fragment, {
616
+ children: [
617
+ ' ',
618
+ "· endpoint ",
619
+ /*#__PURE__*/ _jsx("code", {
620
+ children: storage.s3.endpoint
621
+ })
622
+ ]
623
+ }) : null,
624
+ storage.s3.prefix ? /*#__PURE__*/ _jsxs(_Fragment, {
625
+ children: [
626
+ ' ',
627
+ "· prefix ",
628
+ /*#__PURE__*/ _jsx("code", {
629
+ children: storage.s3.prefix
630
+ })
631
+ ]
632
+ }) : null
633
+ ]
634
+ }) : /*#__PURE__*/ _jsxs("p", {
635
+ className: "restore-preview__intro",
636
+ children: [
637
+ "Set ",
638
+ /*#__PURE__*/ _jsx("code", {
639
+ children: "BACKUP_S3_BUCKET"
640
+ }),
641
+ " (and credentials) to finish configuring S3."
642
+ ]
643
+ })
644
+ ]
645
+ }) : /*#__PURE__*/ _jsxs("p", {
646
+ className: "restore-preview__intro",
647
+ children: [
648
+ "Backups use ",
649
+ /*#__PURE__*/ _jsx("strong", {
650
+ children: "Vercel Blob"
651
+ }),
652
+ " (default). Set",
653
+ ' ',
654
+ /*#__PURE__*/ _jsx("code", {
655
+ children: "BACKUP_STORAGE=s3"
656
+ }),
657
+ " in the environment to use AWS S3 instead."
658
+ ]
659
+ })
660
+ ]
661
+ }) : null,
578
662
  phase !== 'idle' ? /*#__PURE__*/ _jsxs(_Fragment, {
579
663
  children: [
580
664
  /*#__PURE__*/ _jsx("p", {
@@ -738,144 +822,148 @@ export const BackupSettingsModal = ()=>{
738
822
  })
739
823
  ]
740
824
  }),
741
- /*#__PURE__*/ _jsxs("p", {
742
- className: "restore-preview__sticky-heading",
825
+ storage?.kind === 's3' ? null : /*#__PURE__*/ _jsxs(_Fragment, {
743
826
  children: [
744
- "Dedicated backup storage",
745
- ' ',
746
- /*#__PURE__*/ _jsx("span", {
747
- className: "restore-preview__sticky-heading-hint",
748
- children: "(optional)"
749
- })
750
- ]
751
- }),
752
- /*#__PURE__*/ _jsxs("p", {
753
- className: "restore-preview__intro",
754
- children: [
755
- "Separate Vercel Blob token for ",
756
- /*#__PURE__*/ _jsx("code", {
757
- children: "backups/"
758
- }),
759
- ". Without one, archives share the default media store."
760
- ]
761
- }),
762
- /*#__PURE__*/ _jsxs("div", {
763
- className: "restore-preview__settings-fields",
764
- children: [
765
- /*#__PURE__*/ _jsx("label", {
766
- className: "restore-preview__settings-label",
767
- htmlFor: "backup-blob-token",
768
- children: "Backup Blob read/write token"
769
- }),
770
- /*#__PURE__*/ _jsxs("div", {
771
- className: "restore-preview__blob-token-row",
827
+ /*#__PURE__*/ _jsxs("p", {
828
+ className: "restore-preview__sticky-heading",
772
829
  children: [
773
- /*#__PURE__*/ _jsx("input", {
774
- "aria-label": "Backup Blob read/write token",
775
- autoComplete: "off",
776
- className: "restore-preview__settings-input restore-preview__settings-input--wide",
777
- id: "backup-blob-token",
778
- onChange: (e)=>onChangeBackupBlobToken(e.target.value),
779
- placeholder: "vercel_blob_rw_...",
780
- spellCheck: false,
781
- type: "text",
782
- value: backupBlobReadWriteToken
783
- }),
830
+ "Dedicated backup storage",
831
+ ' ',
784
832
  /*#__PURE__*/ _jsx("span", {
785
- className: "restore-preview__blob-token-pill-slot",
786
- children: tokenStatusPill
833
+ className: "restore-preview__sticky-heading-hint",
834
+ children: "(optional)"
787
835
  })
788
836
  ]
789
837
  }),
790
- tokenCheck.status === 'invalid' && tokenCheck.message ? /*#__PURE__*/ _jsx("p", {
791
- "aria-live": "polite",
792
- className: "restore-preview__blob-token-error",
793
- children: tokenCheck.message
794
- }) : null,
795
- savePhase === 'transferring' && transferLive && transferLive.total > 0 ? /*#__PURE__*/ _jsxs("div", {
796
- "aria-live": "polite",
797
- className: "restore-preview__transfer-panel",
838
+ /*#__PURE__*/ _jsxs("p", {
839
+ className: "restore-preview__intro",
798
840
  children: [
799
- /*#__PURE__*/ _jsx("div", {
800
- className: "restore-preview__transfer-bar-track",
801
- children: /*#__PURE__*/ _jsx("div", {
802
- className: "restore-preview__transfer-bar-fill",
803
- style: {
804
- width: `${Math.min(100, (transferLive.transferred + transferLive.failed) / transferLive.total * 100)}%`
805
- }
806
- })
841
+ "Separate Vercel Blob token for ",
842
+ /*#__PURE__*/ _jsx("code", {
843
+ children: "backups/"
807
844
  }),
808
- /*#__PURE__*/ _jsxs("p", {
809
- className: "restore-preview__transfer-meta",
810
- children: [
811
- "Copying backup files: ",
812
- transferLive.transferred + transferLive.failed,
813
- " /",
814
- ' ',
815
- transferLive.total,
816
- transferLive.failed > 0 ? ` (${transferLive.failed} failed)` : '',
817
- transferLive.pathname ? /*#__PURE__*/ _jsxs(_Fragment, {
818
- children: [
819
- /*#__PURE__*/ _jsx("br", {}),
820
- /*#__PURE__*/ _jsx("span", {
821
- className: "restore-preview__transfer-path",
822
- title: transferLive.pathname,
823
- children: transferLive.pathname.length > 56 ? `${transferLive.pathname.slice(0, 28)}…${transferLive.pathname.slice(-24)}` : transferLive.pathname
824
- })
825
- ]
826
- }) : null
827
- ]
828
- })
845
+ ". Without one, archives share the default media store."
829
846
  ]
830
- }) : null,
831
- willSaveNewRawToken ? /*#__PURE__*/ _jsxs(_Fragment, {
847
+ }),
848
+ /*#__PURE__*/ _jsxs("div", {
849
+ className: "restore-preview__settings-fields",
832
850
  children: [
851
+ /*#__PURE__*/ _jsx("label", {
852
+ className: "restore-preview__settings-label",
853
+ htmlFor: "backup-blob-token",
854
+ children: "Backup Blob read/write token"
855
+ }),
833
856
  /*#__PURE__*/ _jsxs("div", {
834
- className: "field-type checkbox backup-dashboard__collapsible-checkbox restore-preview__blob-transfer-row restore-preview__blob-transfer-row--with-help-tip",
857
+ className: "restore-preview__blob-token-row",
835
858
  children: [
836
859
  /*#__PURE__*/ _jsx("input", {
837
- "aria-label": "Copy existing backup files into this storage when saving",
838
- checked: transferBackupBlobs,
839
- className: "checkbox-input__input",
840
- id: transferOptId,
841
- onChange: (e)=>setTransferBackupBlobs(e.target.checked),
842
- type: "checkbox"
860
+ "aria-label": "Backup Blob read/write token",
861
+ autoComplete: "off",
862
+ className: "restore-preview__settings-input restore-preview__settings-input--wide",
863
+ id: "backup-blob-token",
864
+ onChange: (e)=>onChangeBackupBlobToken(e.target.value),
865
+ placeholder: "vercel_blob_rw_...",
866
+ spellCheck: false,
867
+ type: "text",
868
+ value: backupBlobReadWriteToken
843
869
  }),
844
- /*#__PURE__*/ _jsx("label", {
845
- className: "field-label",
846
- htmlFor: transferOptId,
847
- children: "Copy existing backup files into this storage when saving"
848
- }),
849
- /*#__PURE__*/ _jsx(SettingsHelpTip, {
850
- multiline: true,
851
- tip: TIP_TRANSFER_COPY
870
+ /*#__PURE__*/ _jsx("span", {
871
+ className: "restore-preview__blob-token-pill-slot",
872
+ children: tokenStatusPill
852
873
  })
853
874
  ]
854
875
  }),
855
- transferBackupBlobs ? /*#__PURE__*/ _jsxs("div", {
856
- className: "field-type checkbox backup-dashboard__collapsible-checkbox restore-preview__blob-transfer-row restore-preview__blob-transfer-row--with-help-tip",
876
+ tokenCheck.status === 'invalid' && tokenCheck.message ? /*#__PURE__*/ _jsx("p", {
877
+ "aria-live": "polite",
878
+ className: "restore-preview__blob-token-error",
879
+ children: tokenCheck.message
880
+ }) : null,
881
+ savePhase === 'transferring' && transferLive && transferLive.total > 0 ? /*#__PURE__*/ _jsxs("div", {
882
+ "aria-live": "polite",
883
+ className: "restore-preview__transfer-panel",
857
884
  children: [
858
- /*#__PURE__*/ _jsx("input", {
859
- "aria-label": "Delete from previous storage after successful copy",
860
- checked: deleteBackupBlobsFromSource,
861
- className: "checkbox-input__input",
862
- id: deleteSourceOptId,
863
- onChange: (e)=>setDeleteBackupBlobsFromSource(e.target.checked),
864
- type: "checkbox"
865
- }),
866
- /*#__PURE__*/ _jsx("label", {
867
- className: "field-label",
868
- htmlFor: deleteSourceOptId,
869
- children: "Delete from previous storage after successful copy"
885
+ /*#__PURE__*/ _jsx("div", {
886
+ className: "restore-preview__transfer-bar-track",
887
+ children: /*#__PURE__*/ _jsx("div", {
888
+ className: "restore-preview__transfer-bar-fill",
889
+ style: {
890
+ width: `${Math.min(100, (transferLive.transferred + transferLive.failed) / transferLive.total * 100)}%`
891
+ }
892
+ })
870
893
  }),
871
- /*#__PURE__*/ _jsx(SettingsHelpTip, {
872
- multiline: true,
873
- tip: TIP_TRANSFER_DELETE
894
+ /*#__PURE__*/ _jsxs("p", {
895
+ className: "restore-preview__transfer-meta",
896
+ children: [
897
+ "Copying backup files: ",
898
+ transferLive.transferred + transferLive.failed,
899
+ " /",
900
+ ' ',
901
+ transferLive.total,
902
+ transferLive.failed > 0 ? ` (${transferLive.failed} failed)` : '',
903
+ transferLive.pathname ? /*#__PURE__*/ _jsxs(_Fragment, {
904
+ children: [
905
+ /*#__PURE__*/ _jsx("br", {}),
906
+ /*#__PURE__*/ _jsx("span", {
907
+ className: "restore-preview__transfer-path",
908
+ title: transferLive.pathname,
909
+ children: transferLive.pathname.length > 56 ? `${transferLive.pathname.slice(0, 28)}…${transferLive.pathname.slice(-24)}` : transferLive.pathname
910
+ })
911
+ ]
912
+ }) : null
913
+ ]
874
914
  })
875
915
  ]
916
+ }) : null,
917
+ willSaveNewRawToken ? /*#__PURE__*/ _jsxs(_Fragment, {
918
+ children: [
919
+ /*#__PURE__*/ _jsxs("div", {
920
+ className: "field-type checkbox backup-dashboard__collapsible-checkbox restore-preview__blob-transfer-row restore-preview__blob-transfer-row--with-help-tip",
921
+ children: [
922
+ /*#__PURE__*/ _jsx("input", {
923
+ "aria-label": "Copy existing backup files into this storage when saving",
924
+ checked: transferBackupBlobs,
925
+ className: "checkbox-input__input",
926
+ id: transferOptId,
927
+ onChange: (e)=>setTransferBackupBlobs(e.target.checked),
928
+ type: "checkbox"
929
+ }),
930
+ /*#__PURE__*/ _jsx("label", {
931
+ className: "field-label",
932
+ htmlFor: transferOptId,
933
+ children: "Copy existing backup files into this storage when saving"
934
+ }),
935
+ /*#__PURE__*/ _jsx(SettingsHelpTip, {
936
+ multiline: true,
937
+ tip: TIP_TRANSFER_COPY
938
+ })
939
+ ]
940
+ }),
941
+ transferBackupBlobs ? /*#__PURE__*/ _jsxs("div", {
942
+ className: "field-type checkbox backup-dashboard__collapsible-checkbox restore-preview__blob-transfer-row restore-preview__blob-transfer-row--with-help-tip",
943
+ children: [
944
+ /*#__PURE__*/ _jsx("input", {
945
+ "aria-label": "Delete from previous storage after successful copy",
946
+ checked: deleteBackupBlobsFromSource,
947
+ className: "checkbox-input__input",
948
+ id: deleteSourceOptId,
949
+ onChange: (e)=>setDeleteBackupBlobsFromSource(e.target.checked),
950
+ type: "checkbox"
951
+ }),
952
+ /*#__PURE__*/ _jsx("label", {
953
+ className: "field-label",
954
+ htmlFor: deleteSourceOptId,
955
+ children: "Delete from previous storage after successful copy"
956
+ }),
957
+ /*#__PURE__*/ _jsx(SettingsHelpTip, {
958
+ multiline: true,
959
+ tip: TIP_TRANSFER_DELETE
960
+ })
961
+ ]
962
+ }) : null
963
+ ]
876
964
  }) : null
877
965
  ]
878
- }) : null
966
+ })
879
967
  ]
880
968
  }),
881
969
  /*#__PURE__*/ _jsx(CollectionBackupPreviewBody, {