@byline/host-tanstack-start 4.19.0 → 5.0.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/collections/edit.d.ts +1 -1
- package/dist/admin-shell/collections/edit.js +151 -31
- package/dist/admin-shell/collections/history.js +4 -2
- package/dist/admin-shell/collections/list.js +30 -6
- package/dist/admin-shell/collections/restore-version-modal.d.ts +3 -1
- package/dist/admin-shell/collections/restore-version-modal.js +9 -4
- package/dist/admin-shell/collections/tree-list.js +16 -6
- package/dist/admin-shell/collections/version-history.d.ts +2 -1
- package/dist/admin-shell/collections/version-history.js +11 -2
- package/dist/admin-shell/document-mutation-notice.d.ts +6 -0
- package/dist/admin-shell/document-mutation-notice.js +53 -0
- package/dist/admin-shell/document-mutation-state.d.ts +22 -0
- package/dist/admin-shell/document-mutation-state.js +71 -0
- package/dist/admin-shell/document-mutation-state.test.d.ts +1 -0
- package/dist/admin-shell/scheduled-publications/list.js +15 -5
- package/dist/admin-shell/singletons/history.js +4 -2
- package/dist/admin-shell/singletons/view.d.ts +1 -1
- package/dist/admin-shell/singletons/view.js +98 -19
- package/dist/integrations/byline-field-services.js +2 -9
- package/dist/routes/create-collection-edit-route.js +1 -1
- package/dist/routes/create-collection-list-route.d.ts +0 -7
- package/dist/routes/create-collection-list-route.js +7 -9
- package/dist/routes/create-singleton-route.d.ts +2 -0
- package/dist/routes/create-singleton-route.js +4 -3
- package/dist/server-fns/collections/copy-to-locale.d.ts +2 -7
- package/dist/server-fns/collections/copy-to-locale.js +4 -2
- package/dist/server-fns/collections/create.d.ts +1 -7
- package/dist/server-fns/collections/create.js +5 -3
- package/dist/server-fns/collections/delete-locale.d.ts +2 -7
- package/dist/server-fns/collections/delete-locale.js +4 -2
- package/dist/server-fns/collections/delete-outcome.d.ts +7 -3
- package/dist/server-fns/collections/delete-outcome.js +4 -0
- package/dist/server-fns/collections/delete.d.ts +2 -7
- package/dist/server-fns/collections/delete.js +5 -3
- package/dist/server-fns/collections/duplicate.d.ts +2 -7
- package/dist/server-fns/collections/duplicate.js +5 -3
- package/dist/server-fns/collections/get.d.ts +1 -7
- package/dist/server-fns/collections/get.js +5 -4
- package/dist/server-fns/collections/list.d.ts +0 -7
- package/dist/server-fns/collections/list.js +11 -3
- package/dist/server-fns/collections/reorder.d.ts +7 -8
- package/dist/server-fns/collections/reorder.js +20 -76
- package/dist/server-fns/collections/restore-version.d.ts +3 -7
- package/dist/server-fns/collections/restore-version.js +5 -2
- package/dist/server-fns/collections/save-outcome.d.ts +1 -0
- package/dist/server-fns/collections/save-outcome.js +1 -0
- package/dist/server-fns/collections/scheduled-publication.d.ts +49 -9
- package/dist/server-fns/collections/scheduled-publication.js +31 -21
- package/dist/server-fns/collections/status.d.ts +8 -7
- package/dist/server-fns/collections/status.js +13 -5
- package/dist/server-fns/collections/tree-mutation.d.ts +7 -6
- package/dist/server-fns/collections/tree-mutation.js +17 -5
- package/dist/server-fns/collections/tree.d.ts +14 -8
- package/dist/server-fns/collections/tree.js +21 -17
- package/dist/server-fns/collections/update.d.ts +12 -11
- package/dist/server-fns/collections/update.js +34 -20
- package/dist/server-fns/collections/upload.d.ts +1 -0
- package/dist/server-fns/collections/upload.js +3 -2
- package/dist/server-fns/document-mutation-errors.d.ts +5 -0
- package/dist/server-fns/document-mutation-errors.js +50 -0
- package/dist/server-fns/editable-revision.d.ts +9 -0
- package/dist/server-fns/editable-revision.js +11 -0
- package/dist/server-fns/singleton-document-read.d.ts +1 -1
- package/dist/server-fns/singleton-document-read.js +7 -3
- package/dist/server-fns/singletons/cancel-scheduled-publish.d.ts +6 -8
- package/dist/server-fns/singletons/cancel-scheduled-publish.js +4 -1
- package/dist/server-fns/singletons/change-status.d.ts +2 -7
- package/dist/server-fns/singletons/change-status.js +4 -1
- package/dist/server-fns/singletons/confirm-scheduled-publish.d.ts +5 -8
- package/dist/server-fns/singletons/confirm-scheduled-publish.js +4 -2
- package/dist/server-fns/singletons/copy-to-locale.d.ts +2 -7
- package/dist/server-fns/singletons/copy-to-locale.js +4 -2
- package/dist/server-fns/singletons/get.d.ts +4 -4
- package/dist/server-fns/singletons/restore-version.d.ts +2 -7
- package/dist/server-fns/singletons/restore-version.js +6 -3
- package/dist/server-fns/singletons/schedule-publish.d.ts +5 -8
- package/dist/server-fns/singletons/schedule-publish.js +4 -2
- package/dist/server-fns/singletons/unpublish.d.ts +2 -7
- package/dist/server-fns/singletons/unpublish.js +4 -1
- package/dist/server-fns/singletons/update.d.ts +4 -11
- package/dist/server-fns/singletons/update.js +5 -4
- package/dist/server-fns/structural-receipt.d.ts +4 -0
- package/dist/server-fns/structural-receipt.js +31 -0
- package/package.json +11 -11
- package/src/admin-shell/collections/edit.tsx +173 -54
- package/src/admin-shell/collections/history.tsx +11 -2
- package/src/admin-shell/collections/list.tsx +22 -6
- package/src/admin-shell/collections/restore-version-modal.tsx +12 -3
- package/src/admin-shell/collections/save-navigation.test.tsx +156 -8
- package/src/admin-shell/collections/tree-list.tsx +16 -6
- package/src/admin-shell/collections/version-history.tsx +13 -3
- package/src/admin-shell/document-mutation-notice.tsx +45 -0
- package/src/admin-shell/document-mutation-state.test.tsx +146 -0
- package/src/admin-shell/document-mutation-state.ts +95 -0
- package/src/admin-shell/scheduled-publications/list.tsx +16 -6
- package/src/admin-shell/singletons/history.test.tsx +3 -1
- package/src/admin-shell/singletons/history.tsx +10 -2
- package/src/admin-shell/singletons/view.test.tsx +59 -18
- package/src/admin-shell/singletons/view.tsx +110 -29
- package/src/integrations/byline-field-services.ts +2 -3
- package/src/routes/create-collection-edit-route.tsx +1 -0
- package/src/routes/create-collection-list-route.tsx +13 -2
- package/src/routes/create-singleton-route.test.node.ts +10 -2
- package/src/routes/create-singleton-route.tsx +6 -4
- package/src/server-fns/collections/copy-to-locale.ts +41 -36
- package/src/server-fns/collections/create.ts +54 -50
- package/src/server-fns/collections/delete-locale.ts +41 -32
- package/src/server-fns/collections/delete-outcome.test.node.ts +16 -0
- package/src/server-fns/collections/delete-outcome.ts +27 -16
- package/src/server-fns/collections/delete.ts +44 -38
- package/src/server-fns/collections/duplicate.ts +38 -32
- package/src/server-fns/collections/get.ts +8 -4
- package/src/server-fns/collections/list.ts +8 -3
- package/src/server-fns/collections/reorder.ts +32 -124
- package/src/server-fns/collections/restore-version.ts +47 -39
- package/src/server-fns/collections/revision-input.test.node.ts +108 -0
- package/src/server-fns/collections/save-outcome.test.node.ts +3 -0
- package/src/server-fns/collections/save-outcome.ts +2 -0
- package/src/server-fns/collections/scheduled-publication.ts +138 -111
- package/src/server-fns/collections/status.ts +86 -64
- package/src/server-fns/collections/tree-mutation.test.node.ts +87 -29
- package/src/server-fns/collections/tree-mutation.ts +28 -11
- package/src/server-fns/collections/tree.ts +150 -122
- package/src/server-fns/collections/update.ts +110 -86
- package/src/server-fns/collections/upload-singleton.test.node.ts +3 -7
- package/src/server-fns/collections/upload.ts +81 -77
- package/src/server-fns/document-mutation-errors.ts +67 -0
- package/src/server-fns/document-mutation-transport.test.node.ts +211 -0
- package/src/server-fns/editable-revision.test.node.ts +23 -0
- package/src/server-fns/editable-revision.ts +18 -0
- package/src/server-fns/singleton-document-read.ts +7 -3
- package/src/server-fns/singletons/cancel-scheduled-publish.ts +10 -3
- package/src/server-fns/singletons/change-status.ts +10 -3
- package/src/server-fns/singletons/confirm-scheduled-publish.ts +12 -6
- package/src/server-fns/singletons/copy-to-locale.ts +20 -15
- package/src/server-fns/singletons/get.ts +3 -3
- package/src/server-fns/singletons/restore-version.ts +17 -12
- package/src/server-fns/singletons/schedule-publish.ts +18 -7
- package/src/server-fns/singletons/singletons.test.node.ts +63 -25
- package/src/server-fns/singletons/unpublish.ts +10 -3
- package/src/server-fns/singletons/update.ts +21 -16
- package/src/server-fns/structural-receipt.ts +41 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { DocumentMutationNotice } from "../document-mutation-notice.js";
|
|
3
|
+
import { useDocumentMutationState } from "../document-mutation-state.js";
|
|
2
4
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
5
|
import { useRouter } from "@tanstack/react-router";
|
|
4
6
|
import { StatusBadge, renderFormatted } from "@byline/admin/react";
|
|
@@ -55,6 +57,7 @@ function SortableTreeRow({ id, dragging, disabled, dragHandleLabel, children })
|
|
|
55
57
|
});
|
|
56
58
|
}
|
|
57
59
|
const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection, collectionLabels, onMove, listActions })=>{
|
|
60
|
+
const mutation = useDocumentMutationState(void 0);
|
|
58
61
|
const { t } = useTranslation('byline-admin');
|
|
59
62
|
const router = useRouter();
|
|
60
63
|
const toastManager = useToastManager();
|
|
@@ -66,12 +69,13 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
|
|
|
66
69
|
const [moveController] = useState(()=>createAdminTreeMoveController());
|
|
67
70
|
const preserveOptimisticForRows = useRef(null);
|
|
68
71
|
useEffect(()=>{
|
|
69
|
-
if (!shouldSyncAdminTreeRows(rows, preserveOptimisticForRows.current, isMoving)) return;
|
|
72
|
+
if (mutation.blocked || !shouldSyncAdminTreeRows(rows, preserveOptimisticForRows.current, isMoving)) return;
|
|
70
73
|
preserveOptimisticForRows.current = null;
|
|
71
74
|
setLocalPlaced(rows.filter((r)=>!r.unplaced));
|
|
72
75
|
}, [
|
|
73
76
|
rows,
|
|
74
|
-
isMoving
|
|
77
|
+
isMoving,
|
|
78
|
+
mutation.blocked
|
|
75
79
|
]);
|
|
76
80
|
const [activeId, setActiveId] = useState(null);
|
|
77
81
|
const [overId, setOverId] = useState(null);
|
|
@@ -98,12 +102,12 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
|
|
|
98
102
|
setOffsetLeft(0);
|
|
99
103
|
};
|
|
100
104
|
const handleDragStart = ({ active })=>{
|
|
101
|
-
if (!moveController.isMoving()) setActiveId(String(active.id));
|
|
105
|
+
if (!mutation.blocked && !moveController.isMoving()) setActiveId(String(active.id));
|
|
102
106
|
};
|
|
103
107
|
const handleDragMove = ({ delta })=>setOffsetLeft(delta.x);
|
|
104
108
|
const handleDragOver = ({ over })=>setOverId(over ? String(over.id) : null);
|
|
105
109
|
const handleDragEnd = async ({ active, over })=>{
|
|
106
|
-
if (moveController.isMoving()) return void resetDnd();
|
|
110
|
+
if (mutation.blocked || moveController.isMoving()) return void resetDnd();
|
|
107
111
|
const proj = null != over ? getTreeProjection(localPlaced, String(active.id), String(over.id), offsetLeft, INDENT) : null;
|
|
108
112
|
resetDnd();
|
|
109
113
|
if (!onMove || null == proj) return;
|
|
@@ -125,9 +129,11 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
|
|
|
125
129
|
setIsMoving(moveController.isMoving());
|
|
126
130
|
return;
|
|
127
131
|
}
|
|
132
|
+
if ('receipt' in outcome) mutation.reportStructure(outcome.receipt);
|
|
133
|
+
const handled = 'error' in outcome ? mutation.report(outcome.error) : null;
|
|
128
134
|
const effects = getAdminTreeMoveUiEffects(outcome);
|
|
129
135
|
if (effects.rollback) setLocalPlaced(current);
|
|
130
|
-
if (null != effects.structuralFailure) {
|
|
136
|
+
if (!handled && null != effects.structuralFailure) {
|
|
131
137
|
const conflict = 'conflict' === effects.structuralFailure;
|
|
132
138
|
toastManager.add({
|
|
133
139
|
title: t(conflict ? 'collections.list.treeConflictToast' : 'collections.list.reorderFailedToast'),
|
|
@@ -202,6 +208,10 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
|
|
|
202
208
|
return /*#__PURE__*/ jsx(Section, {
|
|
203
209
|
children: /*#__PURE__*/ jsxs(Container, {
|
|
204
210
|
children: [
|
|
211
|
+
/*#__PURE__*/ jsx(DocumentMutationNotice, {
|
|
212
|
+
issue: mutation.issue,
|
|
213
|
+
scheduleNotice: mutation.scheduleNotice
|
|
214
|
+
}),
|
|
205
215
|
/*#__PURE__*/ jsxs("div", {
|
|
206
216
|
className: clsx('byline-coll-list-head', tree_list_module.head),
|
|
207
217
|
children: [
|
|
@@ -271,7 +281,7 @@ const TreeListView = ({ rows, columns, workflowStatuses, useAsTitle, collection,
|
|
|
271
281
|
return dndEnabled ? /*#__PURE__*/ jsx(SortableTreeRow, {
|
|
272
282
|
id: row.id,
|
|
273
283
|
dragging: row.id === activeId,
|
|
274
|
-
disabled: isMoving,
|
|
284
|
+
disabled: mutation.blocked || isMoving,
|
|
275
285
|
dragHandleLabel: t('collections.list.dragHandleAriaLabel'),
|
|
276
286
|
children: renderCells(row, depth)
|
|
277
287
|
}, row.id) : /*#__PURE__*/ jsx(Table.Row, {
|
|
@@ -40,6 +40,7 @@ interface VersionHistoryRowContext {
|
|
|
40
40
|
actionLabel: string;
|
|
41
41
|
restoreStatusLabel: string;
|
|
42
42
|
openCompare: () => void;
|
|
43
|
+
mutationsBlocked: boolean;
|
|
43
44
|
openRestore: () => void;
|
|
44
45
|
}
|
|
45
46
|
/**
|
|
@@ -66,7 +67,7 @@ export declare function VersionHistoryCore({ data, resourceDefinition, resourceP
|
|
|
66
67
|
rowPresentation: VersionHistoryRowPresentation;
|
|
67
68
|
loadHistoricalVersion: HistoricalVersionLoader;
|
|
68
69
|
onPageSizeChange: (pageSize: number) => void;
|
|
69
|
-
restoreVersion: (versionId: string) => Promise<unknown>;
|
|
70
|
+
restoreVersion: (versionId: string, expectedRevision: number) => Promise<unknown>;
|
|
70
71
|
onRestoreComplete: () => void | Promise<void>;
|
|
71
72
|
}): import("react").JSX.Element;
|
|
72
73
|
export {};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { DocumentMutationNotice } from "../document-mutation-notice.js";
|
|
3
|
+
import { useDocumentMutationState } from "../document-mutation-state.js";
|
|
2
4
|
import { Fragment as external_react_Fragment, Suspense, lazy, useState } from "react";
|
|
3
5
|
import { getDefaultStatus, getWorkflowStatuses } from "@byline/core";
|
|
4
6
|
import { useTranslation } from "@byline/i18n/react";
|
|
@@ -33,6 +35,7 @@ function padRows(value) {
|
|
|
33
35
|
}, `empty-row-${index}`));
|
|
34
36
|
}
|
|
35
37
|
function VersionHistoryCore({ data, resourceDefinition, resourcePath, documentId, currentDocument, locale, rowPresentation, loadHistoricalVersion, onPageSizeChange, restoreVersion, onRestoreComplete }) {
|
|
38
|
+
const mutation = useDocumentMutationState(currentDocument);
|
|
36
39
|
const { t } = useTranslation('byline-admin');
|
|
37
40
|
const [selectedVersion, setSelectedVersion] = useState(null);
|
|
38
41
|
const [restoreTarget, setRestoreTarget] = useState(null);
|
|
@@ -41,6 +44,9 @@ function VersionHistoryCore({ data, resourceDefinition, resourcePath, documentId
|
|
|
41
44
|
const restoreStatusLabel = getWorkflowStatuses(resourceDefinition).find((status)=>status.name === restoreStatus)?.label ?? restoreStatus;
|
|
42
45
|
return /*#__PURE__*/ jsxs(Fragment, {
|
|
43
46
|
children: [
|
|
47
|
+
/*#__PURE__*/ jsx(DocumentMutationNotice, {
|
|
48
|
+
issue: mutation.issue
|
|
49
|
+
}),
|
|
44
50
|
/*#__PURE__*/ jsx("div", {
|
|
45
51
|
className: clsx('byline-coll-history-options', history_module.options),
|
|
46
52
|
children: /*#__PURE__*/ jsx(RouterPager, {
|
|
@@ -85,7 +91,7 @@ function VersionHistoryCore({ data, resourceDefinition, resourcePath, documentId
|
|
|
85
91
|
});
|
|
86
92
|
};
|
|
87
93
|
const openRestore = ()=>{
|
|
88
|
-
if (null == versionId || versionId === currentVersionId) return;
|
|
94
|
+
if (mutation.blocked || null == versionId || versionId === currentVersionId) return;
|
|
89
95
|
setRestoreTarget({
|
|
90
96
|
versionId,
|
|
91
97
|
label: versionLabel,
|
|
@@ -119,6 +125,7 @@ function VersionHistoryCore({ data, resourceDefinition, resourcePath, documentId
|
|
|
119
125
|
actionLabel,
|
|
120
126
|
restoreStatusLabel,
|
|
121
127
|
openCompare,
|
|
128
|
+
mutationsBlocked: mutation.blocked,
|
|
122
129
|
openRestore
|
|
123
130
|
})
|
|
124
131
|
]
|
|
@@ -243,11 +250,13 @@ function VersionHistoryCore({ data, resourceDefinition, resourcePath, documentId
|
|
|
243
250
|
]
|
|
244
251
|
}),
|
|
245
252
|
restoreTarget ? /*#__PURE__*/ jsx(RestoreVersionModal, {
|
|
253
|
+
disabled: mutation.blocked,
|
|
254
|
+
onMutationError: mutation.report,
|
|
246
255
|
versionLabel: restoreTarget.label,
|
|
247
256
|
versionNumber: restoreTarget.versionNumber,
|
|
248
257
|
restoreStatusLabel: restoreStatusLabel,
|
|
249
258
|
onClose: ()=>setRestoreTarget(null),
|
|
250
|
-
restoreVersion: ()=>restoreVersion(restoreTarget.versionId),
|
|
259
|
+
restoreVersion: ()=>restoreVersion(restoreTarget.versionId, mutation.expectedRevision()),
|
|
251
260
|
onRestoreComplete: onRestoreComplete
|
|
252
261
|
}) : null
|
|
253
262
|
]
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DocumentMutationIssue } from './document-mutation-state.js';
|
|
2
|
+
/** Persistent recovery for list, history and schedule views without local form drafts. */
|
|
3
|
+
export declare function DocumentMutationNotice({ issue, scheduleNotice, }: {
|
|
4
|
+
issue: DocumentMutationIssue | null;
|
|
5
|
+
scheduleNotice?: boolean;
|
|
6
|
+
}): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
import { useTranslation } from "@byline/i18n/react";
|
|
4
|
+
import { Alert, Button } from "@byline/ui/react";
|
|
5
|
+
import { getAdminRoutePath } from "../routes/admin-path.js";
|
|
6
|
+
function DocumentMutationNotice({ issue, scheduleNotice = false }) {
|
|
7
|
+
const { t } = useTranslation('byline-admin');
|
|
8
|
+
const warning = useRef(null);
|
|
9
|
+
useEffect(()=>{
|
|
10
|
+
if (issue) warning.current?.focus();
|
|
11
|
+
}, [
|
|
12
|
+
issue
|
|
13
|
+
]);
|
|
14
|
+
if (!issue && !scheduleNotice) return null;
|
|
15
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
16
|
+
ref: warning,
|
|
17
|
+
tabIndex: -1,
|
|
18
|
+
role: "alert",
|
|
19
|
+
"aria-live": "assertive",
|
|
20
|
+
children: [
|
|
21
|
+
issue && /*#__PURE__*/ jsxs(Alert, {
|
|
22
|
+
close: false,
|
|
23
|
+
intent: "warning",
|
|
24
|
+
title: t(`documentConcurrency.${issue}Title`),
|
|
25
|
+
children: [
|
|
26
|
+
/*#__PURE__*/ jsx("p", {
|
|
27
|
+
children: t(`documentConcurrency.${issue}`)
|
|
28
|
+
}),
|
|
29
|
+
'committed' !== issue && /*#__PURE__*/ jsx(Button, {
|
|
30
|
+
type: "button",
|
|
31
|
+
onClick: ()=>window.location.reload(),
|
|
32
|
+
children: t('documentConcurrency.reloadAction')
|
|
33
|
+
})
|
|
34
|
+
]
|
|
35
|
+
}),
|
|
36
|
+
scheduleNotice && /*#__PURE__*/ jsxs(Alert, {
|
|
37
|
+
close: false,
|
|
38
|
+
intent: "warning",
|
|
39
|
+
title: t('documentConcurrency.schedulesTitle'),
|
|
40
|
+
children: [
|
|
41
|
+
/*#__PURE__*/ jsx("p", {
|
|
42
|
+
children: t('documentConcurrency.schedules')
|
|
43
|
+
}),
|
|
44
|
+
/*#__PURE__*/ jsx("a", {
|
|
45
|
+
href: getAdminRoutePath('scheduled-publications'),
|
|
46
|
+
children: t('documentConcurrency.reviewSchedules')
|
|
47
|
+
})
|
|
48
|
+
]
|
|
49
|
+
})
|
|
50
|
+
]
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
export { DocumentMutationNotice };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type DocumentMutationIssue = 'stale' | 'reload' | 'lock' | 'unavailable' | 'committed';
|
|
2
|
+
/** A rejected observation stays frozen until an explicit editor reload. */
|
|
3
|
+
export declare function useDocumentMutationState<T extends {
|
|
4
|
+
id?: unknown;
|
|
5
|
+
versionId?: unknown;
|
|
6
|
+
revision?: unknown;
|
|
7
|
+
}>(document: T | null | undefined): {
|
|
8
|
+
issue: DocumentMutationIssue | null;
|
|
9
|
+
blocked: boolean;
|
|
10
|
+
scheduleNotice: boolean;
|
|
11
|
+
document: T | null | undefined;
|
|
12
|
+
revision: number | undefined;
|
|
13
|
+
expectedRevision: () => number;
|
|
14
|
+
assertWritable: () => void;
|
|
15
|
+
adopt: (receipt: {
|
|
16
|
+
documentId: string;
|
|
17
|
+
revision: number;
|
|
18
|
+
scheduledPublicationsNeedReconfirmation?: boolean;
|
|
19
|
+
}) => void;
|
|
20
|
+
report: (error: unknown) => 'blocked' | 'committed' | null;
|
|
21
|
+
reportStructure: (result: unknown) => void;
|
|
22
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { useRef, useState } from "react";
|
|
2
|
+
import { ErrorCodes, getDocumentRevisionValidationDetails, getDocumentStaleDetails, getLockConflictDetails, parseDocumentRevision } from "@byline/core";
|
|
3
|
+
import { getDocumentHookCommittedDetails } from "@byline/core/services";
|
|
4
|
+
import { committedTreeReceipt, structuralReceipt } from "../server-fns/structural-receipt.js";
|
|
5
|
+
function documentMutationIssue(error) {
|
|
6
|
+
if (getDocumentStaleDetails(error)) return 'stale';
|
|
7
|
+
if (getDocumentRevisionValidationDetails(error)) return 'reload';
|
|
8
|
+
if (getLockConflictDetails(error)) return 'lock';
|
|
9
|
+
if (getDocumentHookCommittedDetails(error) || committedTreeReceipt(error)) return 'committed';
|
|
10
|
+
if ('object' == typeof error && null !== error && Reflect.get(error, 'code') === ErrorCodes.NOT_FOUND) return 'unavailable';
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
function useDocumentMutationState(document) {
|
|
14
|
+
const [issue, setIssue] = useState(null);
|
|
15
|
+
const [scheduleNotice, setScheduleNotice] = useState(false);
|
|
16
|
+
const [, setReceiptRevision] = useState();
|
|
17
|
+
const blockedError = useRef(void 0);
|
|
18
|
+
const observation = useRef({
|
|
19
|
+
identity: document,
|
|
20
|
+
revision: document?.revision
|
|
21
|
+
});
|
|
22
|
+
if (observation.current.identity !== document && void 0 === blockedError.current && document?.revision === observation.current.revision) observation.current = {
|
|
23
|
+
identity: document,
|
|
24
|
+
revision: document?.revision
|
|
25
|
+
};
|
|
26
|
+
const assertWritable = ()=>{
|
|
27
|
+
if (void 0 !== blockedError.current) throw blockedError.current;
|
|
28
|
+
};
|
|
29
|
+
const expectedRevision = ()=>{
|
|
30
|
+
assertWritable();
|
|
31
|
+
return parseDocumentRevision(observation.current.revision);
|
|
32
|
+
};
|
|
33
|
+
const adopt = (receipt)=>{
|
|
34
|
+
if (void 0 !== blockedError.current) return;
|
|
35
|
+
if (document?.id != null && receipt.documentId !== document.id) return;
|
|
36
|
+
observation.current.revision = parseDocumentRevision(receipt.revision);
|
|
37
|
+
setReceiptRevision(receipt.revision);
|
|
38
|
+
if (receipt.scheduledPublicationsNeedReconfirmation) setScheduleNotice(true);
|
|
39
|
+
};
|
|
40
|
+
const reportStructure = (result)=>{
|
|
41
|
+
const receipt = structuralReceipt(result);
|
|
42
|
+
if (receipt) adopt(receipt);
|
|
43
|
+
};
|
|
44
|
+
const report = (error)=>{
|
|
45
|
+
const kind = documentMutationIssue(error);
|
|
46
|
+
if (null === kind) return null;
|
|
47
|
+
if ('committed' === kind) {
|
|
48
|
+
if (void 0 !== blockedError.current) return 'blocked';
|
|
49
|
+
const details = getDocumentHookCommittedDetails(error) ?? committedTreeReceipt(error);
|
|
50
|
+
if (details) adopt(details);
|
|
51
|
+
setIssue(kind);
|
|
52
|
+
return 'committed';
|
|
53
|
+
}
|
|
54
|
+
blockedError.current = error;
|
|
55
|
+
setIssue(kind);
|
|
56
|
+
return 'blocked';
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
issue,
|
|
60
|
+
blocked: null !== issue && 'committed' !== issue,
|
|
61
|
+
scheduleNotice,
|
|
62
|
+
document: observation.current.identity,
|
|
63
|
+
revision: 'number' == typeof observation.current.revision ? observation.current.revision : void 0,
|
|
64
|
+
expectedRevision,
|
|
65
|
+
assertWritable,
|
|
66
|
+
adopt,
|
|
67
|
+
report,
|
|
68
|
+
reportStructure
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export { useDocumentMutationState };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { DocumentMutationNotice } from "../document-mutation-notice.js";
|
|
4
|
+
import { useDocumentMutationState } from "../document-mutation-state.js";
|
|
3
5
|
import { useMemo, useState } from "react";
|
|
4
6
|
import { useRouterState } from "@tanstack/react-router";
|
|
5
7
|
import { deriveScheduledPublicationState } from "@byline/admin/react";
|
|
@@ -35,6 +37,7 @@ function ScheduledPublicationsView({ data }) {
|
|
|
35
37
|
select: (state)=>state.location
|
|
36
38
|
});
|
|
37
39
|
const search = location.search;
|
|
40
|
+
const mutation = useDocumentMutationState(void 0);
|
|
38
41
|
const [cancelling, setCancelling] = useState(null);
|
|
39
42
|
const applySearch = (patch)=>{
|
|
40
43
|
navigate({
|
|
@@ -46,13 +49,16 @@ function ScheduledPublicationsView({ data }) {
|
|
|
46
49
|
}
|
|
47
50
|
});
|
|
48
51
|
};
|
|
49
|
-
const cancel = async (collection, documentId)=>{
|
|
52
|
+
const cancel = async (collection, documentId, expectedRevision)=>{
|
|
53
|
+
if (mutation.blocked || cancelling) return;
|
|
50
54
|
setCancelling(documentId);
|
|
51
55
|
try {
|
|
56
|
+
mutation.assertWritable();
|
|
52
57
|
const result = await cancelCollectionDocumentScheduledPublish({
|
|
53
58
|
data: {
|
|
54
59
|
collection,
|
|
55
|
-
id: documentId
|
|
60
|
+
id: documentId,
|
|
61
|
+
expectedRevision
|
|
56
62
|
}
|
|
57
63
|
});
|
|
58
64
|
const cancelled = 'cancelled' === result.status;
|
|
@@ -71,9 +77,10 @@ function ScheduledPublicationsView({ data }) {
|
|
|
71
77
|
search: location.search
|
|
72
78
|
});
|
|
73
79
|
} catch (error) {
|
|
80
|
+
if (mutation.report(error)) return;
|
|
74
81
|
toastManager.add({
|
|
75
82
|
title: t('scheduledPublication.toast.failedTitle'),
|
|
76
|
-
description:
|
|
83
|
+
description: t('documentConcurrency.failed'),
|
|
77
84
|
data: {
|
|
78
85
|
intent: 'danger',
|
|
79
86
|
iconType: 'danger',
|
|
@@ -89,6 +96,9 @@ function ScheduledPublicationsView({ data }) {
|
|
|
89
96
|
return /*#__PURE__*/ jsx(Section, {
|
|
90
97
|
children: /*#__PURE__*/ jsxs(Container, {
|
|
91
98
|
children: [
|
|
99
|
+
/*#__PURE__*/ jsx(DocumentMutationNotice, {
|
|
100
|
+
issue: mutation.issue
|
|
101
|
+
}),
|
|
92
102
|
/*#__PURE__*/ jsxs("div", {
|
|
93
103
|
className: clsx('byline-scheduled-list-head', list_module.head),
|
|
94
104
|
children: [
|
|
@@ -264,9 +274,9 @@ function ScheduledPublicationsView({ data }) {
|
|
|
264
274
|
size: "xs",
|
|
265
275
|
type: "button",
|
|
266
276
|
intent: "danger",
|
|
267
|
-
disabled:
|
|
277
|
+
disabled: mutation.blocked || null !== cancelling,
|
|
268
278
|
"aria-label": t('scheduledPublication.actions.cancel'),
|
|
269
|
-
onClick: ()=>cancel(schedule.collectionPath, schedule.documentId),
|
|
279
|
+
onClick: ()=>cancel(schedule.collectionPath, schedule.documentId, schedule.revision),
|
|
270
280
|
children: t('common.actions.cancel')
|
|
271
281
|
})
|
|
272
282
|
})
|
|
@@ -53,7 +53,7 @@ function SingletonHistoryView({ singletonDefinition, adminConfig, data, currentD
|
|
|
53
53
|
]
|
|
54
54
|
}),
|
|
55
55
|
auditColSpan: 4,
|
|
56
|
-
renderCells: ({ document, versionId, currentVersionId, actorLabel, restoreStatusLabel, openRestore })=>/*#__PURE__*/ jsxs(Fragment, {
|
|
56
|
+
renderCells: ({ document, versionId, currentVersionId, actorLabel, restoreStatusLabel, mutationsBlocked, openRestore })=>/*#__PURE__*/ jsxs(Fragment, {
|
|
57
57
|
children: [
|
|
58
58
|
/*#__PURE__*/ jsx(Table.Cell, {
|
|
59
59
|
className: "byline-singleton-history-status-cell",
|
|
@@ -77,6 +77,7 @@ function SingletonHistoryView({ singletonDefinition, adminConfig, data, currentD
|
|
|
77
77
|
variant: "outlined",
|
|
78
78
|
size: "xs",
|
|
79
79
|
intent: "noeffect",
|
|
80
|
+
disabled: mutationsBlocked,
|
|
80
81
|
onClick: openRestore,
|
|
81
82
|
className: clsx('byline-coll-history-restore-button', history_module.restoreButton),
|
|
82
83
|
title: t('collections.history.restoreButtonTitle', {
|
|
@@ -143,8 +144,9 @@ function SingletonHistoryView({ singletonDefinition, adminConfig, data, currentD
|
|
|
143
144
|
return historical;
|
|
144
145
|
},
|
|
145
146
|
onPageSizeChange: handlePageSizeChange,
|
|
146
|
-
restoreVersion: (versionId)=>restoreSingletonVersion({
|
|
147
|
+
restoreVersion: (versionId, expectedRevision)=>restoreSingletonVersion({
|
|
147
148
|
data: {
|
|
149
|
+
expectedRevision,
|
|
148
150
|
singleton,
|
|
149
151
|
versionId
|
|
150
152
|
}
|
|
@@ -5,7 +5,7 @@ type SingletonDocument = Record<string, any> & {
|
|
|
5
5
|
status: string;
|
|
6
6
|
fields: Record<string, any>;
|
|
7
7
|
};
|
|
8
|
-
export declare function SingletonView({ singletonDefinition, adminConfig, document, initialData, locale, contentLocales, defaultContentLocale, }: {
|
|
8
|
+
export declare function SingletonView({ singletonDefinition, adminConfig, document: loadedDocument, initialData, locale, contentLocales, defaultContentLocale, }: {
|
|
9
9
|
singletonDefinition: SingletonDefinition;
|
|
10
10
|
adminConfig?: SingletonAdminConfig;
|
|
11
11
|
document: SingletonDocument | null;
|