@byline/host-tanstack-start 1.0.6 → 1.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/dist/admin-shell/admin-roles/container.js +1 -3
- package/dist/admin-shell/admin-roles/delete.js +1 -1
- package/dist/admin-shell/admin-roles/list.js +1 -3
- package/dist/admin-shell/admin-users/container.js +1 -3
- package/dist/admin-shell/admin-users/delete.js +1 -1
- package/dist/admin-shell/admin-users/list.js +1 -3
- package/dist/admin-shell/chrome/admin-app-bar.js +1 -1
- package/dist/admin-shell/chrome/dashboard.js +1 -1
- package/dist/admin-shell/chrome/drawer-toggle.js +1 -1
- package/dist/admin-shell/chrome/menu-drawer.js +1 -1
- package/dist/admin-shell/chrome/preview-toggle.js +1 -1
- package/dist/admin-shell/chrome/route-error.js +1 -1
- package/dist/admin-shell/chrome/router-pager.d.ts +1 -1
- package/dist/admin-shell/chrome/router-pager.js +1 -1
- package/dist/admin-shell/chrome/sign-in-page.js +1 -1
- package/dist/admin-shell/chrome/th-sortable.js +1 -1
- package/dist/admin-shell/collections/api.js +1 -1
- package/dist/admin-shell/collections/create.js +1 -2
- package/dist/admin-shell/collections/edit.js +1 -2
- package/dist/admin-shell/collections/history.js +83 -8
- package/dist/admin-shell/collections/history.module.js +5 -0
- package/dist/admin-shell/collections/history_module.css +46 -0
- package/dist/admin-shell/collections/list.js +1 -3
- package/dist/admin-shell/collections/preview-link.js +1 -1
- package/dist/admin-shell/collections/restore-version-modal.d.ts +10 -0
- package/dist/admin-shell/collections/restore-version-modal.js +118 -0
- package/dist/admin-shell/collections/restore-version-modal.module.js +10 -0
- package/dist/admin-shell/collections/restore-version-modal_module.css +31 -0
- package/dist/admin-shell/collections/tanstack-navigation-guard.d.ts +1 -1
- package/dist/admin-shell/collections/view-menu.js +1 -1
- package/dist/integrations/byline-admin-services.d.ts +1 -1
- package/dist/integrations/byline-field-services.d.ts +1 -1
- package/dist/routes/create-admin-account-route.js +1 -2
- package/dist/routes/create-admin-layout-route.js +1 -2
- package/dist/routes/create-admin-permissions-route.js +1 -1
- package/dist/routes/create-admin-role-edit-route.js +1 -1
- package/dist/routes/create-admin-user-edit-route.js +1 -1
- package/dist/routes/create-collection-list-route.js +1 -1
- package/dist/server-fns/collections/index.d.ts +1 -0
- package/dist/server-fns/collections/index.js +1 -0
- package/dist/server-fns/collections/restore-version.d.ts +21 -0
- package/dist/server-fns/collections/restore-version.js +41 -0
- package/package.json +10 -10
- package/src/admin-shell/admin-roles/container.tsx +2 -3
- package/src/admin-shell/admin-roles/delete.tsx +1 -1
- package/src/admin-shell/admin-roles/list.tsx +2 -3
- package/src/admin-shell/admin-users/container.tsx +2 -3
- package/src/admin-shell/admin-users/delete.tsx +1 -1
- package/src/admin-shell/admin-users/list.tsx +2 -3
- package/src/admin-shell/chrome/admin-app-bar.tsx +1 -1
- package/src/admin-shell/chrome/dashboard.tsx +1 -1
- package/src/admin-shell/chrome/drawer-toggle.tsx +1 -1
- package/src/admin-shell/chrome/menu-drawer.tsx +1 -1
- package/src/admin-shell/chrome/preview-toggle.tsx +1 -1
- package/src/admin-shell/chrome/route-error.tsx +1 -1
- package/src/admin-shell/chrome/router-pager.tsx +2 -2
- package/src/admin-shell/chrome/sign-in-page.tsx +1 -1
- package/src/admin-shell/chrome/th-sortable.tsx +1 -1
- package/src/admin-shell/collections/api.tsx +1 -1
- package/src/admin-shell/collections/create.tsx +2 -2
- package/src/admin-shell/collections/edit.tsx +2 -2
- package/src/admin-shell/collections/history.module.css +50 -1
- package/src/admin-shell/collections/history.tsx +151 -72
- package/src/admin-shell/collections/list.tsx +2 -3
- package/src/admin-shell/collections/preview-link.tsx +1 -1
- package/src/admin-shell/collections/restore-version-modal.module.css +48 -0
- package/src/admin-shell/collections/restore-version-modal.tsx +131 -0
- package/src/admin-shell/collections/tanstack-navigation-guard.ts +1 -1
- package/src/admin-shell/collections/view-menu.tsx +1 -1
- package/src/integrations/byline-admin-services.ts +1 -1
- package/src/integrations/byline-field-services.ts +1 -5
- package/src/routes/create-admin-account-route.tsx +2 -2
- package/src/routes/create-admin-layout-route.tsx +1 -2
- package/src/routes/create-admin-permissions-route.tsx +1 -1
- package/src/routes/create-admin-role-edit-route.tsx +1 -1
- package/src/routes/create-admin-user-edit-route.tsx +1 -1
- package/src/routes/create-collection-list-route.tsx +1 -1
- package/src/server-fns/collections/index.ts +1 -0
- package/src/server-fns/collections/restore-version.ts +59 -0
|
@@ -11,9 +11,8 @@ import { useParams, useRouterState } from '@tanstack/react-router'
|
|
|
11
11
|
|
|
12
12
|
import type { CollectionAdminConfig, CollectionDefinition, WorkflowStatus } from '@byline/core'
|
|
13
13
|
import type { AnyCollectionSchemaTypes } from '@byline/core/zod-schemas'
|
|
14
|
-
import { Container, IconButton, Section, Select, Table } from '@byline/ui'
|
|
15
|
-
import { StatusBadge } from '@byline/ui/react
|
|
16
|
-
import { renderFormatted } from '@byline/ui/react/fields'
|
|
14
|
+
import { Button, CloseIcon, Container, IconButton, Modal, Section, Select, Table } from '@byline/ui/react'
|
|
15
|
+
import { renderFormatted, StatusBadge } from '@byline/ui/react'
|
|
17
16
|
import cx from 'classnames'
|
|
18
17
|
|
|
19
18
|
import { Link, useNavigate } from '../chrome/loose-router.js'
|
|
@@ -21,6 +20,7 @@ import { RouterPager } from '../chrome/router-pager.js'
|
|
|
21
20
|
import { TableHeadingCellSortable } from '../chrome/th-sortable.js'
|
|
22
21
|
import { formatNumber } from '../chrome/utils.js'
|
|
23
22
|
import styles from './history.module.css'
|
|
23
|
+
import { RestoreVersionModal } from './restore-version-modal.js'
|
|
24
24
|
import { ViewMenu } from './view-menu.js'
|
|
25
25
|
import type { ContentLocaleOption } from './view-menu.js'
|
|
26
26
|
|
|
@@ -28,7 +28,6 @@ import type { ContentLocaleOption } from './view-menu.js'
|
|
|
28
28
|
* Resolve a column value from a document, checking `fields` first (user-defined
|
|
29
29
|
* collection fields) then the root (metadata like status, updated_at).
|
|
30
30
|
*/
|
|
31
|
-
// biome-ignore lint/suspicious/noExplicitAny: collection rows are heterogeneous
|
|
32
31
|
function getColumnValue(document: any, fieldName: string): any {
|
|
33
32
|
if (document.fields && fieldName in document.fields) {
|
|
34
33
|
return document.fields[fieldName]
|
|
@@ -38,9 +37,7 @@ function getColumnValue(document: any, fieldName: string): any {
|
|
|
38
37
|
|
|
39
38
|
// Lazy-load DiffModal because react-diff-viewer-continued uses a web worker
|
|
40
39
|
// bundle that cannot be resolved by Node during SSR.
|
|
41
|
-
const DiffModal = lazy(() =>
|
|
42
|
-
import('@byline/ui/react/admin').then((m) => ({ default: m.DiffModal }))
|
|
43
|
-
)
|
|
40
|
+
const DiffModal = lazy(() => import('@byline/ui/react').then((m) => ({ default: m.DiffModal })))
|
|
44
41
|
|
|
45
42
|
/**
|
|
46
43
|
* Safely extract a displayable string from a field value that may be a plain
|
|
@@ -78,7 +75,7 @@ function padRows(value: number) {
|
|
|
78
75
|
key={`empty-row-${
|
|
79
76
|
// biome-ignore lint/suspicious/noArrayIndexKey: we're okay here
|
|
80
77
|
index
|
|
81
|
-
|
|
78
|
+
}`}
|
|
82
79
|
className={cx('byline-coll-history-pad-row', styles.padRow)}
|
|
83
80
|
>
|
|
84
81
|
|
|
@@ -115,6 +112,15 @@ export const HistoryView = ({
|
|
|
115
112
|
versionId: string
|
|
116
113
|
label: string
|
|
117
114
|
} | null>(null)
|
|
115
|
+
const [restoreTarget, setRestoreTarget] = useState<{
|
|
116
|
+
versionId: string
|
|
117
|
+
label: string
|
|
118
|
+
versionNumber: number
|
|
119
|
+
} | null>(null)
|
|
120
|
+
const currentVersionId =
|
|
121
|
+
currentDocument && typeof currentDocument.versionId === 'string'
|
|
122
|
+
? (currentDocument.versionId as string)
|
|
123
|
+
: null
|
|
118
124
|
|
|
119
125
|
function handleOnPageSizeChange(value: string | null): void {
|
|
120
126
|
if (typeof value !== 'string' || value.length === 0) return
|
|
@@ -167,8 +173,8 @@ export const HistoryView = ({
|
|
|
167
173
|
scope="col"
|
|
168
174
|
className={cx('byline-coll-history-col-version', styles.colVersion)}
|
|
169
175
|
/>
|
|
170
|
-
{columns.
|
|
171
|
-
|
|
176
|
+
{columns.flatMap((column) => {
|
|
177
|
+
const cell = (
|
|
172
178
|
<TableHeadingCellSortable
|
|
173
179
|
key={String(column.fieldName)}
|
|
174
180
|
fieldName={String(column.fieldName)}
|
|
@@ -179,6 +185,17 @@ export const HistoryView = ({
|
|
|
179
185
|
className={column.className}
|
|
180
186
|
/>
|
|
181
187
|
)
|
|
188
|
+
if (column.fieldName === 'title') {
|
|
189
|
+
return [
|
|
190
|
+
cell,
|
|
191
|
+
<th
|
|
192
|
+
key="__restore"
|
|
193
|
+
scope="col"
|
|
194
|
+
className={cx('byline-coll-history-col-restore', styles.colRestore)}
|
|
195
|
+
/>,
|
|
196
|
+
]
|
|
197
|
+
}
|
|
198
|
+
return [cell]
|
|
182
199
|
})}
|
|
183
200
|
</Table.Row>
|
|
184
201
|
</Table.Header>
|
|
@@ -217,84 +234,119 @@ export const HistoryView = ({
|
|
|
217
234
|
</IconButton>
|
|
218
235
|
) : null}
|
|
219
236
|
</Table.Cell>
|
|
220
|
-
{columns.
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
237
|
+
{columns.flatMap((column) => {
|
|
238
|
+
const dataCell = (
|
|
239
|
+
<Table.Cell
|
|
240
|
+
key={String(column.fieldName)}
|
|
241
|
+
className={cx({
|
|
242
|
+
'byline-coll-history-cell-right': column.align === 'right',
|
|
243
|
+
[styles.cellRight]: column.align === 'right',
|
|
244
|
+
'byline-coll-history-cell-center': column.align === 'center',
|
|
245
|
+
[styles.cellCenter]: column.align === 'center',
|
|
246
|
+
})}
|
|
247
|
+
>
|
|
248
|
+
{column.fieldName === 'title' ? (
|
|
249
|
+
versionId && currentDocument ? (
|
|
250
|
+
<button
|
|
251
|
+
type="button"
|
|
252
|
+
className={cx(
|
|
253
|
+
'byline-coll-history-title-button',
|
|
254
|
+
styles.titleButton
|
|
255
|
+
)}
|
|
256
|
+
onClick={() =>
|
|
257
|
+
setSelectedVersion({
|
|
258
|
+
versionId,
|
|
259
|
+
label: new Date(document.createdAt).toLocaleString(),
|
|
260
|
+
})
|
|
261
|
+
}
|
|
262
|
+
>
|
|
263
|
+
{column.formatter
|
|
264
|
+
? renderFormatted(
|
|
247
265
|
getColumnValue(document, column.fieldName as string),
|
|
248
266
|
document,
|
|
249
267
|
column.formatter
|
|
250
268
|
)
|
|
251
|
-
|
|
269
|
+
: resolveDisplayValue(
|
|
252
270
|
getColumnValue(document, column.fieldName as string),
|
|
253
271
|
locale,
|
|
254
272
|
defaultContentLocale
|
|
255
273
|
) || '------'}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
274
|
+
</button>
|
|
275
|
+
) : (
|
|
276
|
+
<Link
|
|
277
|
+
to={'/admin/collections/$collection/$id' as never}
|
|
278
|
+
params={{
|
|
279
|
+
collection,
|
|
280
|
+
id: document.id,
|
|
281
|
+
}}
|
|
282
|
+
>
|
|
283
|
+
{column.formatter
|
|
284
|
+
? renderFormatted(
|
|
267
285
|
getColumnValue(document, column.fieldName as string),
|
|
268
286
|
document,
|
|
269
287
|
column.formatter
|
|
270
288
|
)
|
|
271
|
-
|
|
289
|
+
: resolveDisplayValue(
|
|
272
290
|
getColumnValue(document, column.fieldName as string),
|
|
273
291
|
locale,
|
|
274
292
|
defaultContentLocale
|
|
275
293
|
) || '------'}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
294
|
+
</Link>
|
|
295
|
+
)
|
|
296
|
+
) : column.formatter ? (
|
|
297
|
+
renderFormatted(
|
|
298
|
+
getColumnValue(document, column.fieldName as string),
|
|
299
|
+
document,
|
|
300
|
+
column.formatter
|
|
301
|
+
)
|
|
302
|
+
) : column.fieldName === 'status' && workflowStatuses ? (
|
|
303
|
+
<StatusBadge
|
|
304
|
+
status={document.status}
|
|
305
|
+
workflowStatuses={workflowStatuses}
|
|
306
|
+
/>
|
|
307
|
+
) : (
|
|
308
|
+
resolveDisplayValue(
|
|
309
|
+
getColumnValue(document, column.fieldName as string),
|
|
310
|
+
locale,
|
|
311
|
+
defaultContentLocale
|
|
312
|
+
) || ''
|
|
313
|
+
)}
|
|
314
|
+
</Table.Cell>
|
|
315
|
+
)
|
|
316
|
+
if (column.fieldName === 'title') {
|
|
317
|
+
return [
|
|
318
|
+
dataCell,
|
|
319
|
+
<Table.Cell
|
|
320
|
+
key="__restore"
|
|
321
|
+
className={cx('byline-coll-history-restore-cell', styles.restoreCell)}
|
|
322
|
+
>
|
|
323
|
+
{versionId && versionId !== currentVersionId ? (
|
|
324
|
+
<Button
|
|
325
|
+
type="button"
|
|
326
|
+
variant="outlined"
|
|
327
|
+
size="xs"
|
|
328
|
+
intent="noeffect"
|
|
329
|
+
onClick={() =>
|
|
330
|
+
setRestoreTarget({
|
|
331
|
+
versionId,
|
|
332
|
+
label: new Date(document.createdAt).toLocaleString(),
|
|
333
|
+
versionNumber,
|
|
334
|
+
})
|
|
335
|
+
}
|
|
336
|
+
className={cx(
|
|
337
|
+
'byline-coll-history-restore-button',
|
|
338
|
+
styles.restoreButton
|
|
339
|
+
)}
|
|
340
|
+
title="Restore this version as the current draft"
|
|
341
|
+
>
|
|
342
|
+
Restore
|
|
343
|
+
</Button>
|
|
344
|
+
) : null}
|
|
345
|
+
</Table.Cell>,
|
|
346
|
+
]
|
|
347
|
+
}
|
|
348
|
+
return [dataCell]
|
|
349
|
+
})}
|
|
298
350
|
</Table.Row>
|
|
299
351
|
)
|
|
300
352
|
})}
|
|
@@ -350,6 +402,33 @@ export const HistoryView = ({
|
|
|
350
402
|
/>
|
|
351
403
|
</Suspense>
|
|
352
404
|
)}
|
|
405
|
+
|
|
406
|
+
<Modal
|
|
407
|
+
isOpen={restoreTarget != null}
|
|
408
|
+
onDismiss={() => setRestoreTarget(null)}
|
|
409
|
+
closeOnOverlayClick={false}
|
|
410
|
+
>
|
|
411
|
+
<Modal.Container className={cx('byline-coll-history-restore-modal', styles.restoreModal)}>
|
|
412
|
+
<Modal.Header
|
|
413
|
+
className={cx('byline-coll-history-restore-modal-head', styles.restoreModalHead)}
|
|
414
|
+
>
|
|
415
|
+
<h3 className="m-0">Restore version</h3>
|
|
416
|
+
<IconButton aria-label="Close" size="xs" onClick={() => setRestoreTarget(null)}>
|
|
417
|
+
<CloseIcon width="14px" height="14px" svgClassName="white-icon" />
|
|
418
|
+
</IconButton>
|
|
419
|
+
</Modal.Header>
|
|
420
|
+
{restoreTarget ? (
|
|
421
|
+
<RestoreVersionModal
|
|
422
|
+
collection={collection}
|
|
423
|
+
documentId={id}
|
|
424
|
+
versionId={restoreTarget.versionId}
|
|
425
|
+
versionLabel={restoreTarget.label}
|
|
426
|
+
versionNumber={restoreTarget.versionNumber}
|
|
427
|
+
onClose={() => setRestoreTarget(null)}
|
|
428
|
+
/>
|
|
429
|
+
) : null}
|
|
430
|
+
</Modal.Container>
|
|
431
|
+
</Modal>
|
|
353
432
|
</>
|
|
354
433
|
)
|
|
355
434
|
}
|
|
@@ -20,9 +20,8 @@ import {
|
|
|
20
20
|
Section,
|
|
21
21
|
Select,
|
|
22
22
|
Table,
|
|
23
|
-
} from '@byline/ui'
|
|
24
|
-
import { StatusBadge } from '@byline/ui/react
|
|
25
|
-
import { renderFormatted } from '@byline/ui/react/fields'
|
|
23
|
+
} from '@byline/ui/react'
|
|
24
|
+
import { renderFormatted, StatusBadge } from '@byline/ui/react'
|
|
26
25
|
import cx from 'classnames'
|
|
27
26
|
|
|
28
27
|
import { Link, useNavigate } from '../chrome/loose-router.js'
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
import { useState } from 'react'
|
|
41
41
|
|
|
42
42
|
import type { CollectionAdminConfig, PreviewDocument } from '@byline/core'
|
|
43
|
-
import { ExternalLinkIcon, IconButton, useToastManager } from '@byline/ui'
|
|
43
|
+
import { ExternalLinkIcon, IconButton, useToastManager } from '@byline/ui/react'
|
|
44
44
|
import cx from 'classnames'
|
|
45
45
|
|
|
46
46
|
import { enablePreviewModeFn } from '../../server-fns/preview/index.js'
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RestoreVersionModal — modal body for the "make current" action on the
|
|
3
|
+
* collection history view.
|
|
4
|
+
*
|
|
5
|
+
* Override handles:
|
|
6
|
+
* .byline-coll-restore-content — outer Modal.Content (gap)
|
|
7
|
+
* .byline-coll-restore-body — vertical stack of identity rows
|
|
8
|
+
* .byline-coll-restore-warning — warning paragraph
|
|
9
|
+
* .byline-coll-restore-actions — Cancel/Restore row
|
|
10
|
+
* .byline-coll-restore-button — action buttons (min-width)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
.content,
|
|
14
|
+
:global(.byline-coll-restore-content) {
|
|
15
|
+
gap: 0.25rem;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.body,
|
|
19
|
+
:global(.byline-coll-restore-body) {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
gap: 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.row,
|
|
26
|
+
:global(.byline-coll-restore-row) {
|
|
27
|
+
margin: 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.warning,
|
|
31
|
+
:global(.byline-coll-restore-warning) {
|
|
32
|
+
margin-top: 0.75rem;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.actions,
|
|
36
|
+
:global(.byline-coll-restore-actions) {
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
justify-content: flex-end;
|
|
40
|
+
gap: 0.5rem;
|
|
41
|
+
margin-top: 1.5rem;
|
|
42
|
+
margin-bottom: 1rem;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.button,
|
|
46
|
+
:global(.byline-coll-restore-button) {
|
|
47
|
+
min-width: 4rem;
|
|
48
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
5
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) Infonomic Company Limited
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Restore-version modal body.
|
|
13
|
+
*
|
|
14
|
+
* Confirmation dialog for the "make current" action on the history view.
|
|
15
|
+
* Calls the restore-version server fn, invalidates the router, and
|
|
16
|
+
* navigates to the document's edit view so the user lands on the freshly
|
|
17
|
+
* restored draft.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { useState } from 'react'
|
|
21
|
+
import { useRouter } from '@tanstack/react-router'
|
|
22
|
+
|
|
23
|
+
import { Alert, Button, LoaderEllipsis, Modal } from '@byline/ui/react'
|
|
24
|
+
import cx from 'classnames'
|
|
25
|
+
|
|
26
|
+
import { restoreDocumentVersion } from '../../server-fns/collections/index.js'
|
|
27
|
+
import { useNavigate } from '../chrome/loose-router.js'
|
|
28
|
+
import styles from './restore-version-modal.module.css'
|
|
29
|
+
|
|
30
|
+
interface RestoreVersionModalProps {
|
|
31
|
+
collection: string
|
|
32
|
+
documentId: string
|
|
33
|
+
versionId: string
|
|
34
|
+
versionLabel: string
|
|
35
|
+
versionNumber: number
|
|
36
|
+
onClose: () => void
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function RestoreVersionModal({
|
|
40
|
+
collection,
|
|
41
|
+
documentId,
|
|
42
|
+
versionId,
|
|
43
|
+
versionLabel,
|
|
44
|
+
versionNumber,
|
|
45
|
+
onClose,
|
|
46
|
+
}: RestoreVersionModalProps) {
|
|
47
|
+
const navigate = useNavigate()
|
|
48
|
+
const router = useRouter()
|
|
49
|
+
const [error, setError] = useState<string | null>(null)
|
|
50
|
+
const [pending, setPending] = useState(false)
|
|
51
|
+
|
|
52
|
+
async function handleRestore() {
|
|
53
|
+
if (pending) return
|
|
54
|
+
setPending(true)
|
|
55
|
+
setError(null)
|
|
56
|
+
try {
|
|
57
|
+
await restoreDocumentVersion({
|
|
58
|
+
data: { collection, id: documentId, versionId },
|
|
59
|
+
})
|
|
60
|
+
onClose()
|
|
61
|
+
await router.invalidate()
|
|
62
|
+
navigate({
|
|
63
|
+
to: '/admin/collections/$collection/$id' as never,
|
|
64
|
+
params: { collection, id: documentId },
|
|
65
|
+
})
|
|
66
|
+
} catch (err) {
|
|
67
|
+
const code = getErrorCode(err)
|
|
68
|
+
if (code === 'ERR_INVALID_TRANSITION') {
|
|
69
|
+
setError('This version is already the current version of the document.')
|
|
70
|
+
} else if (code === 'ERR_NOT_FOUND') {
|
|
71
|
+
setError('The selected version could not be found. The history may be out of date.')
|
|
72
|
+
} else if (code === 'ERR_FORBIDDEN' || code === 'ERR_UNAUTHENTICATED') {
|
|
73
|
+
setError('You do not have permission to restore versions for this collection.')
|
|
74
|
+
} else {
|
|
75
|
+
setError('Could not restore this version. Please try again.')
|
|
76
|
+
}
|
|
77
|
+
setPending(false)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<Modal.Content className={cx('byline-coll-restore-content', styles.content)}>
|
|
83
|
+
<div className={cx('byline-coll-restore-body', styles.body)}>
|
|
84
|
+
{error ? (
|
|
85
|
+
<Alert intent="danger" close={false}>
|
|
86
|
+
{error}
|
|
87
|
+
</Alert>
|
|
88
|
+
) : null}
|
|
89
|
+
<p className={cx('byline-coll-restore-row', styles.row)}>
|
|
90
|
+
<span className="muted">Version:</span> {versionNumber}
|
|
91
|
+
</p>
|
|
92
|
+
<p className={cx('byline-coll-restore-row', styles.row)}>
|
|
93
|
+
<span className="muted">Created:</span> {versionLabel}
|
|
94
|
+
</p>
|
|
95
|
+
<p className={cx('byline-coll-restore-warning', styles.warning)}>
|
|
96
|
+
This will create a new draft version of this document with the content from version{' '}
|
|
97
|
+
{versionNumber}, and that draft will become the current version. The existing versions
|
|
98
|
+
(including any published version) are preserved in history. The restored draft will need
|
|
99
|
+
to be published through the normal workflow.
|
|
100
|
+
</p>
|
|
101
|
+
</div>
|
|
102
|
+
<div className={cx('byline-coll-restore-actions', styles.actions)}>
|
|
103
|
+
<Button
|
|
104
|
+
type="button"
|
|
105
|
+
intent="secondary"
|
|
106
|
+
size="sm"
|
|
107
|
+
onClick={onClose}
|
|
108
|
+
disabled={pending}
|
|
109
|
+
className={cx('byline-coll-restore-button', styles.button)}
|
|
110
|
+
>
|
|
111
|
+
Cancel
|
|
112
|
+
</Button>
|
|
113
|
+
<Button
|
|
114
|
+
size="sm"
|
|
115
|
+
intent="primary"
|
|
116
|
+
onClick={handleRestore}
|
|
117
|
+
disabled={pending}
|
|
118
|
+
className={cx('byline-coll-restore-button', styles.button)}
|
|
119
|
+
>
|
|
120
|
+
{pending === true ? <LoaderEllipsis size={42} /> : 'Restore as Draft'}
|
|
121
|
+
</Button>
|
|
122
|
+
</div>
|
|
123
|
+
</Modal.Content>
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function getErrorCode(err: unknown): string | null {
|
|
128
|
+
return typeof (err as { code?: unknown })?.code === 'string'
|
|
129
|
+
? (err as { code: string }).code
|
|
130
|
+
: null
|
|
131
|
+
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import { useCallback } from 'react'
|
|
17
17
|
import { useBlocker } from '@tanstack/react-router'
|
|
18
18
|
|
|
19
|
-
import type { NavigationGuardResult, UseNavigationGuard } from '@byline/ui/react
|
|
19
|
+
import type { NavigationGuardResult, UseNavigationGuard } from '@byline/ui/react'
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Navigation guard backed by TanStack Router's `useBlocker`.
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { useEffect } from 'react'
|
|
10
10
|
|
|
11
11
|
import type { CollectionAdminConfig, PreviewDocument } from '@byline/core'
|
|
12
|
-
import { Button, HistoryIcon, IconButton, Label, Select } from '@byline/ui'
|
|
12
|
+
import { Button, HistoryIcon, IconButton, Label, Select } from '@byline/ui/react'
|
|
13
13
|
import cx from 'classnames'
|
|
14
14
|
|
|
15
15
|
import { useNavigate } from '../chrome/loose-router.js'
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* inside the host's deferred router-coupled containers.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import type { BylineAdminServices } from '@byline/ui/react
|
|
25
|
+
import type { BylineAdminServices } from '@byline/ui/react'
|
|
26
26
|
|
|
27
27
|
import { changeAccountPassword, updateAccount } from '../server-fns/admin-account/index.js'
|
|
28
28
|
import { setRoleAbilities, whoHasAbility } from '../server-fns/admin-permissions/index.js'
|
|
@@ -16,11 +16,7 @@
|
|
|
16
16
|
* @byline/ui surface is unchanged.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import type {
|
|
20
|
-
BylineFieldServices,
|
|
21
|
-
GetCollectionDocumentsFn,
|
|
22
|
-
UploadFieldFn,
|
|
23
|
-
} from '@byline/ui/react/services'
|
|
19
|
+
import type { BylineFieldServices, GetCollectionDocumentsFn, UploadFieldFn } from '@byline/ui/react'
|
|
24
20
|
|
|
25
21
|
import { getCollectionDocuments as serverGetCollectionDocuments } from '../server-fns/collections/list.js'
|
|
26
22
|
import { uploadField as serverUploadField } from '../server-fns/collections/upload.js'
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
import { createFileRoute } from '@tanstack/react-router'
|
|
10
10
|
|
|
11
|
-
import { Container, Section } from '@byline/ui'
|
|
12
|
-
import { AccountSelfContainer } from '@byline/ui/react
|
|
11
|
+
import { Container, Section } from '@byline/ui/react'
|
|
12
|
+
import { AccountSelfContainer } from '@byline/ui/react'
|
|
13
13
|
|
|
14
14
|
import { BreadcrumbsClient } from '../admin-shell/chrome/breadcrumbs/breadcrumbs-client.js'
|
|
15
15
|
import { type AccountResponse, getAccount } from '../server-fns/admin-account/index.js'
|
|
@@ -21,8 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
import { createFileRoute, Outlet, redirect } from '@tanstack/react-router'
|
|
23
23
|
|
|
24
|
-
import { BylineAdminServicesProvider } from '@byline/ui/react
|
|
25
|
-
import { BylineFieldServicesProvider } from '@byline/ui/react/services'
|
|
24
|
+
import { BylineAdminServicesProvider, BylineFieldServicesProvider } from '@byline/ui/react'
|
|
26
25
|
import cx from 'classnames'
|
|
27
26
|
|
|
28
27
|
import { AdminAppBar } from '../admin-shell/chrome/admin-app-bar.js'
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { createFileRoute } from '@tanstack/react-router'
|
|
10
10
|
|
|
11
|
-
import { AbilitiesInspector } from '@byline/ui/react
|
|
11
|
+
import { AbilitiesInspector } from '@byline/ui/react'
|
|
12
12
|
|
|
13
13
|
import { BreadcrumbsClient } from '../admin-shell/chrome/breadcrumbs/breadcrumbs-client.js'
|
|
14
14
|
import {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { createFileRoute, notFound } from '@tanstack/react-router'
|
|
10
10
|
|
|
11
|
-
import { Container, Section } from '@byline/ui'
|
|
11
|
+
import { Container, Section } from '@byline/ui/react'
|
|
12
12
|
|
|
13
13
|
import { RoleContainer } from '../admin-shell/admin-roles/container.js'
|
|
14
14
|
import { BreadcrumbsClient } from '../admin-shell/chrome/breadcrumbs/breadcrumbs-client.js'
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { createFileRoute, notFound } from '@tanstack/react-router'
|
|
10
10
|
|
|
11
|
-
import { Container, Section } from '@byline/ui'
|
|
11
|
+
import { Container, Section } from '@byline/ui/react'
|
|
12
12
|
|
|
13
13
|
import { AccountContainer } from '../admin-shell/admin-users/container.js'
|
|
14
14
|
import { BreadcrumbsClient } from '../admin-shell/chrome/breadcrumbs/breadcrumbs-client.js'
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
getCollectionDefinition,
|
|
16
16
|
getWorkflowStatuses,
|
|
17
17
|
} from '@byline/core'
|
|
18
|
-
import { useToastManager } from '@byline/ui'
|
|
18
|
+
import { useToastManager } from '@byline/ui/react'
|
|
19
19
|
import { z } from 'zod'
|
|
20
20
|
|
|
21
21
|
import { BreadcrumbsClient } from '../admin-shell/chrome/breadcrumbs/breadcrumbs-client.js'
|