@byline/admin 3.12.1 → 3.13.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/fields/field-services-types.d.ts +50 -0
- package/dist/forms/form-context.js +30 -60
- package/dist/forms/form-modals.d.ts +30 -0
- package/dist/forms/form-modals.js +189 -0
- package/dist/forms/form-renderer.d.ts +8 -1
- package/dist/forms/form-renderer.js +31 -365
- package/dist/forms/form-status-display.d.ts +21 -0
- package/dist/forms/form-status-display.js +94 -0
- package/dist/forms/status-transitions.d.ts +23 -0
- package/dist/forms/status-transitions.js +37 -0
- package/dist/forms/status-transitions.test.node.d.ts +8 -0
- package/dist/forms/tree-placement-widget.d.ts +23 -0
- package/dist/forms/tree-placement-widget.js +176 -0
- package/dist/forms/tree-placement-widget.module.js +15 -0
- package/dist/forms/tree-placement-widget_module.css +69 -0
- package/dist/forms/use-form-layout.d.ts +35 -0
- package/dist/forms/use-form-layout.js +77 -0
- package/dist/forms/use-form-layout.test.node.d.ts +8 -0
- package/dist/forms/use-tracked-slot.d.ts +45 -0
- package/dist/forms/use-tracked-slot.js +46 -0
- package/dist/react.d.ts +1 -1
- package/package.json +5 -5
- package/src/fields/field-services-types.ts +50 -0
- package/src/forms/form-context.tsx +36 -92
- package/src/forms/form-modals.tsx +186 -0
- package/src/forms/form-renderer.tsx +42 -387
- package/src/forms/form-status-display.tsx +108 -0
- package/src/forms/status-transitions.test.node.ts +87 -0
- package/src/forms/status-transitions.ts +86 -0
- package/src/forms/tree-placement-widget.module.css +87 -0
- package/src/forms/tree-placement-widget.tsx +202 -0
- package/src/forms/use-form-layout.test.node.ts +82 -0
- package/src/forms/use-form-layout.ts +134 -0
- package/src/forms/use-tracked-slot.ts +101 -0
- package/src/react.ts +6 -0
|
@@ -1,146 +1,27 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { useTranslation } from "@byline/i18n/react";
|
|
5
|
-
import { Alert, Button,
|
|
5
|
+
import { Alert, Button, ComboButton } from "@byline/ui/react";
|
|
6
6
|
import classnames from "classnames";
|
|
7
7
|
import { FieldRenderer } from "../fields/field-renderer.js";
|
|
8
8
|
import { useBylineFieldServices } from "../fields/field-services-context.js";
|
|
9
|
-
import { LocalDateTime } from "../fields/local-date-time.js";
|
|
10
9
|
import { AdminGroup } from "../presentation/group.js";
|
|
11
10
|
import { AdminRow } from "../presentation/row.js";
|
|
12
11
|
import { AdminTabs } from "../presentation/tabs.js";
|
|
13
12
|
import { AvailableLocalesWidget } from "./available-locales-widget.js";
|
|
14
13
|
import { DocumentActions } from "./document-actions.js";
|
|
15
14
|
import { FormProvider, useFieldValue, useFormContext } from "./form-context.js";
|
|
15
|
+
import { NavigationGuardModal, SystemFieldsConfirmModal, UnsavedChangesModal } from "./form-modals.js";
|
|
16
16
|
import form_renderer_module from "./form-renderer.module.js";
|
|
17
|
+
import { FormStatusDisplay } from "./form-status-display.js";
|
|
17
18
|
import { useNavigationGuardAdapter } from "./navigation-guard.js";
|
|
18
19
|
import { PathWidget } from "./path-widget.js";
|
|
20
|
+
import { computeStatusTransitions } from "./status-transitions.js";
|
|
21
|
+
import { TreePlacementWidget } from "./tree-placement-widget.js";
|
|
19
22
|
import { executeUploadsWithProgress } from "./upload-executor.js";
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const statusCode = initialData?.status;
|
|
23
|
-
const statusLabel = workflowStatuses?.find((s)=>s.name === statusCode)?.label ?? statusCode;
|
|
24
|
-
const showStatusCell = (workflowStatuses?.length ?? 0) > 1;
|
|
25
|
-
return /*#__PURE__*/ jsxs("div", {
|
|
26
|
-
className: classnames('byline-form-status', form_renderer_module.status),
|
|
27
|
-
children: [
|
|
28
|
-
/*#__PURE__*/ jsxs("div", {
|
|
29
|
-
className: classnames('byline-form-status-meta', form_renderer_module["status-meta"]),
|
|
30
|
-
children: [
|
|
31
|
-
showStatusCell && /*#__PURE__*/ jsxs("div", {
|
|
32
|
-
className: classnames('byline-form-status-cell', form_renderer_module["status-cell"]),
|
|
33
|
-
children: [
|
|
34
|
-
/*#__PURE__*/ jsx("span", {
|
|
35
|
-
className: classnames('byline-form-status-muted', form_renderer_module["status-muted"]),
|
|
36
|
-
children: t('forms.status.label')
|
|
37
|
-
}),
|
|
38
|
-
/*#__PURE__*/ jsx("span", {
|
|
39
|
-
className: classnames('byline-form-status-trunc', form_renderer_module["status-trunc"]),
|
|
40
|
-
children: statusLabel
|
|
41
|
-
})
|
|
42
|
-
]
|
|
43
|
-
}),
|
|
44
|
-
initialData?.updatedAt != null && /*#__PURE__*/ jsxs("div", {
|
|
45
|
-
className: classnames('byline-form-status-cell', form_renderer_module["status-cell"]),
|
|
46
|
-
children: [
|
|
47
|
-
/*#__PURE__*/ jsx("span", {
|
|
48
|
-
className: classnames('byline-form-status-muted', form_renderer_module["status-muted"]),
|
|
49
|
-
children: t('forms.status.lastModified')
|
|
50
|
-
}),
|
|
51
|
-
/*#__PURE__*/ jsx("span", {
|
|
52
|
-
className: classnames('byline-form-status-trunc', form_renderer_module["status-trunc"]),
|
|
53
|
-
children: /*#__PURE__*/ jsx(LocalDateTime, {
|
|
54
|
-
value: initialData.updatedAt
|
|
55
|
-
})
|
|
56
|
-
})
|
|
57
|
-
]
|
|
58
|
-
}),
|
|
59
|
-
initialData?.createdAt != null && /*#__PURE__*/ jsxs("div", {
|
|
60
|
-
className: classnames('byline-form-status-cell', form_renderer_module["status-cell"]),
|
|
61
|
-
children: [
|
|
62
|
-
/*#__PURE__*/ jsx("span", {
|
|
63
|
-
className: classnames('byline-form-status-muted', form_renderer_module["status-muted"]),
|
|
64
|
-
children: t('forms.status.created')
|
|
65
|
-
}),
|
|
66
|
-
/*#__PURE__*/ jsx("span", {
|
|
67
|
-
className: classnames('byline-form-status-trunc', form_renderer_module["status-trunc"]),
|
|
68
|
-
children: /*#__PURE__*/ jsx(LocalDateTime, {
|
|
69
|
-
value: initialData.createdAt
|
|
70
|
-
})
|
|
71
|
-
})
|
|
72
|
-
]
|
|
73
|
-
})
|
|
74
|
-
]
|
|
75
|
-
}),
|
|
76
|
-
null != publishedVersion && /*#__PURE__*/ jsxs("div", {
|
|
77
|
-
className: classnames('byline-form-status-published', form_renderer_module["status-published"]),
|
|
78
|
-
children: [
|
|
79
|
-
/*#__PURE__*/ jsxs("span", {
|
|
80
|
-
className: classnames('byline-form-status-muted', form_renderer_module["status-muted"]),
|
|
81
|
-
children: [
|
|
82
|
-
t('forms.status.publishedLive'),
|
|
83
|
-
' ',
|
|
84
|
-
publishedVersion.updatedAt ? /*#__PURE__*/ jsx("span", {
|
|
85
|
-
children: t('forms.status.publishedOn', {
|
|
86
|
-
date: new Date(publishedVersion.updatedAt)
|
|
87
|
-
})
|
|
88
|
-
}) : ''
|
|
89
|
-
]
|
|
90
|
-
}),
|
|
91
|
-
onUnpublish && /*#__PURE__*/ jsxs(Fragment, {
|
|
92
|
-
children: [
|
|
93
|
-
' ',
|
|
94
|
-
/*#__PURE__*/ jsx("button", {
|
|
95
|
-
type: "button",
|
|
96
|
-
onClick: onUnpublish,
|
|
97
|
-
className: classnames('byline-form-status-unpublish', form_renderer_module["status-unpublish"]),
|
|
98
|
-
children: t('common.actions.unpublish')
|
|
99
|
-
})
|
|
100
|
-
]
|
|
101
|
-
})
|
|
102
|
-
]
|
|
103
|
-
})
|
|
104
|
-
]
|
|
105
|
-
});
|
|
106
|
-
};
|
|
107
|
-
function computeStatusTransitions(currentStatus, workflowStatuses, nextStatus) {
|
|
108
|
-
if (!workflowStatuses || 0 === workflowStatuses.length || !currentStatus) return {
|
|
109
|
-
primaryStatus: nextStatus,
|
|
110
|
-
secondaryStatuses: [],
|
|
111
|
-
isTerminal: false
|
|
112
|
-
};
|
|
113
|
-
if (workflowStatuses.length <= 1) return {
|
|
114
|
-
primaryStatus: void 0,
|
|
115
|
-
secondaryStatuses: [],
|
|
116
|
-
isTerminal: false
|
|
117
|
-
};
|
|
118
|
-
const currentIndex = workflowStatuses.findIndex((s)=>s.name === currentStatus);
|
|
119
|
-
if (-1 === currentIndex) return {
|
|
120
|
-
primaryStatus: nextStatus,
|
|
121
|
-
secondaryStatuses: [],
|
|
122
|
-
isTerminal: false
|
|
123
|
-
};
|
|
124
|
-
const isAtEnd = currentIndex === workflowStatuses.length - 1;
|
|
125
|
-
const isAtStart = 0 === currentIndex;
|
|
126
|
-
const availableTargets = [];
|
|
127
|
-
if (!isAtStart && workflowStatuses[0]) availableTargets.push(workflowStatuses[0]);
|
|
128
|
-
const prev = workflowStatuses[currentIndex - 1];
|
|
129
|
-
if (currentIndex > 1 && prev) availableTargets.push(prev);
|
|
130
|
-
const next = workflowStatuses[currentIndex + 1];
|
|
131
|
-
if (!isAtEnd && next) availableTargets.push(next);
|
|
132
|
-
if (isAtEnd) return {
|
|
133
|
-
primaryStatus: workflowStatuses[currentIndex],
|
|
134
|
-
secondaryStatuses: availableTargets,
|
|
135
|
-
isTerminal: true
|
|
136
|
-
};
|
|
137
|
-
return {
|
|
138
|
-
primaryStatus: nextStatus,
|
|
139
|
-
secondaryStatuses: availableTargets.filter((s)=>s.name !== nextStatus?.name),
|
|
140
|
-
isTerminal: false
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
const FormContent = ({ mode, fields, onSubmit, onCancel, onStatusChange, onUnpublish, onDelete, onDuplicate, onCopyToLocale, onDeleteLocale, contentLocales, nextStatus, workflowStatuses, publishedVersion, initialData, adminConfig, useAsTitle, useAsPath, advertiseLocales, headingLabel, headerSlot, collectionPath, initialLocale, onLocaleChange, defaultLocale = 'en', useNavigationGuard: useNavigationGuardProp, restoreWarnings, _activeTabBySet, _onTabChange })=>{
|
|
23
|
+
import { useFormLayout } from "./use-form-layout.js";
|
|
24
|
+
const FormContent = ({ mode, fields, onSubmit, onCancel, onStatusChange, onUnpublish, onDelete, onDuplicate, onCopyToLocale, onDeleteLocale, contentLocales, nextStatus, workflowStatuses, publishedVersion, initialData, adminConfig, useAsTitle, useAsPath, advertiseLocales, tree, headingLabel, headerSlot, collectionPath, initialLocale, onLocaleChange, defaultLocale = 'en', useNavigationGuard: useNavigationGuardProp, restoreWarnings, _activeTabBySet, _onTabChange })=>{
|
|
144
25
|
const { getFieldValues, runFieldHooks, validateForm, errors: initialErrors, hasChanges: hasChangesFn, resetHasChanges, getPatches, getDirtyBreakdown, getSystemPath, getSystemAvailableLocales, subscribeErrors, subscribeMeta, setFieldValue, setFieldError, getPendingUploads, clearPendingUploads, setFieldUploading } = useFormContext();
|
|
145
26
|
const { t } = useTranslation('byline-admin');
|
|
146
27
|
const [errors, setErrors] = useState(initialErrors);
|
|
@@ -156,69 +37,7 @@ const FormContent = ({ mode, fields, onSubmit, onCancel, onStatusChange, onUnpub
|
|
|
156
37
|
}, [
|
|
157
38
|
initialLocale
|
|
158
39
|
]);
|
|
159
|
-
const fieldByName =
|
|
160
|
-
const map = new Map();
|
|
161
|
-
for (const field of fields)if ('name' in field) map.set(field.name, field);
|
|
162
|
-
return map;
|
|
163
|
-
}, [
|
|
164
|
-
fields
|
|
165
|
-
]);
|
|
166
|
-
const tabSetByName = useMemo(()=>{
|
|
167
|
-
const map = new Map();
|
|
168
|
-
for (const set of adminConfig?.tabSets ?? [])map.set(set.name, set);
|
|
169
|
-
return map;
|
|
170
|
-
}, [
|
|
171
|
-
adminConfig
|
|
172
|
-
]);
|
|
173
|
-
const rowByName = useMemo(()=>{
|
|
174
|
-
const map = new Map();
|
|
175
|
-
for (const row of adminConfig?.rows ?? [])map.set(row.name, row);
|
|
176
|
-
return map;
|
|
177
|
-
}, [
|
|
178
|
-
adminConfig
|
|
179
|
-
]);
|
|
180
|
-
const groupByName = useMemo(()=>{
|
|
181
|
-
const map = new Map();
|
|
182
|
-
for (const group of adminConfig?.groups ?? [])map.set(group.name, group);
|
|
183
|
-
return map;
|
|
184
|
-
}, [
|
|
185
|
-
adminConfig
|
|
186
|
-
]);
|
|
187
|
-
const layout = useMemo(()=>{
|
|
188
|
-
if (adminConfig?.layout) return adminConfig.layout;
|
|
189
|
-
return {
|
|
190
|
-
main: fields.filter((f)=>'name' in f).map((f)=>f.name)
|
|
191
|
-
};
|
|
192
|
-
}, [
|
|
193
|
-
adminConfig,
|
|
194
|
-
fields
|
|
195
|
-
]);
|
|
196
|
-
const fieldToTabPath = useMemo(()=>{
|
|
197
|
-
const map = new Map();
|
|
198
|
-
const visit = (names, tabSetName, tabName, seen)=>{
|
|
199
|
-
for (const name of names)if (fieldByName.has(name)) map.set(name, {
|
|
200
|
-
tabSetName,
|
|
201
|
-
tabName
|
|
202
|
-
});
|
|
203
|
-
else if (seen.has(name)) ;
|
|
204
|
-
else if (rowByName.has(name)) {
|
|
205
|
-
const row = rowByName.get(name);
|
|
206
|
-
const next = new Set(seen).add(name);
|
|
207
|
-
visit(row.fields, tabSetName, tabName, next);
|
|
208
|
-
} else if (groupByName.has(name)) {
|
|
209
|
-
const group = groupByName.get(name);
|
|
210
|
-
const next = new Set(seen).add(name);
|
|
211
|
-
visit(group.fields, tabSetName, tabName, next);
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
for (const set of adminConfig?.tabSets ?? [])for (const tab of set.tabs)visit(tab.fields, set.name, tab.name, new Set());
|
|
215
|
-
return map;
|
|
216
|
-
}, [
|
|
217
|
-
adminConfig,
|
|
218
|
-
fieldByName,
|
|
219
|
-
rowByName,
|
|
220
|
-
groupByName
|
|
221
|
-
]);
|
|
40
|
+
const { fieldByName, tabSetByName, rowByName, groupByName, layout, fieldToTabPath } = useFormLayout(adminConfig, fields);
|
|
222
41
|
const tabSets = adminConfig?.tabSets ?? [];
|
|
223
42
|
const initialActiveTabBySet = useMemo(()=>{
|
|
224
43
|
const result = {};
|
|
@@ -528,6 +347,11 @@ const FormContent = ({ mode, fields, onSubmit, onCancel, onStatusChange, onUnpub
|
|
|
528
347
|
activeLocale: contentLocale,
|
|
529
348
|
mode: mode
|
|
530
349
|
}),
|
|
350
|
+
tree && 'edit' === mode && 'string' == typeof initialData?.id && /*#__PURE__*/ jsx(TreePlacementWidget, {
|
|
351
|
+
collectionPath: collectionPath ?? '',
|
|
352
|
+
documentId: initialData.id,
|
|
353
|
+
useAsTitle: useAsTitle
|
|
354
|
+
}),
|
|
531
355
|
advertiseLocales && /*#__PURE__*/ jsx(AvailableLocalesWidget, {
|
|
532
356
|
contentLocales: contentLocales ?? [],
|
|
533
357
|
availableVersionLocales: initialData?._availableVersionLocales ?? []
|
|
@@ -537,187 +361,28 @@ const FormContent = ({ mode, fields, onSubmit, onCancel, onStatusChange, onUnpub
|
|
|
537
361
|
})
|
|
538
362
|
]
|
|
539
363
|
}),
|
|
540
|
-
showUnsavedModal && /*#__PURE__*/ jsx(
|
|
541
|
-
|
|
542
|
-
closeOnOverlayClick: true,
|
|
543
|
-
onDismiss: ()=>setShowUnsavedModal(false),
|
|
544
|
-
children: /*#__PURE__*/ jsxs(Modal.Container, {
|
|
545
|
-
style: {
|
|
546
|
-
maxWidth: '460px'
|
|
547
|
-
},
|
|
548
|
-
children: [
|
|
549
|
-
/*#__PURE__*/ jsx(Modal.Header, {
|
|
550
|
-
className: classnames('byline-form-guard-modal-head', form_renderer_module["guard-modal-head"]),
|
|
551
|
-
children: /*#__PURE__*/ jsx("h3", {
|
|
552
|
-
className: classnames('byline-form-guard-modal-title', form_renderer_module["guard-modal-title"]),
|
|
553
|
-
children: t('forms.unsavedChanges.title')
|
|
554
|
-
})
|
|
555
|
-
}),
|
|
556
|
-
/*#__PURE__*/ jsx(Modal.Content, {
|
|
557
|
-
children: /*#__PURE__*/ jsx("p", {
|
|
558
|
-
className: classnames('byline-form-guard-modal-text', form_renderer_module["guard-modal-text"]),
|
|
559
|
-
children: t('forms.unsavedChanges.message')
|
|
560
|
-
})
|
|
561
|
-
}),
|
|
562
|
-
/*#__PURE__*/ jsx(Modal.Actions, {
|
|
563
|
-
children: /*#__PURE__*/ jsx(Button, {
|
|
564
|
-
size: "sm",
|
|
565
|
-
style: {
|
|
566
|
-
minWidth: '60px'
|
|
567
|
-
},
|
|
568
|
-
intent: "primary",
|
|
569
|
-
type: "button",
|
|
570
|
-
onClick: ()=>setShowUnsavedModal(false),
|
|
571
|
-
children: t('forms.unsavedChanges.okButton')
|
|
572
|
-
})
|
|
573
|
-
})
|
|
574
|
-
]
|
|
575
|
-
})
|
|
364
|
+
showUnsavedModal && /*#__PURE__*/ jsx(UnsavedChangesModal, {
|
|
365
|
+
onClose: ()=>setShowUnsavedModal(false)
|
|
576
366
|
}),
|
|
577
|
-
null != pendingSystemFieldsSubmit && /*#__PURE__*/ jsx(
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
className: classnames('byline-form-guard-modal-head', form_renderer_module["guard-modal-head"]),
|
|
588
|
-
children: [
|
|
589
|
-
/*#__PURE__*/ jsx("h3", {
|
|
590
|
-
className: classnames('byline-form-guard-modal-title', form_renderer_module["guard-modal-title"]),
|
|
591
|
-
children: pendingSystemFieldsSubmit.contentDirty ? t('forms.systemFieldsConfirm.bothTitle') : t('forms.systemFieldsConfirm.title')
|
|
592
|
-
}),
|
|
593
|
-
/*#__PURE__*/ jsx(IconButton, {
|
|
594
|
-
"aria-label": t('common.actions.close'),
|
|
595
|
-
size: "xs",
|
|
596
|
-
onClick: ()=>setPendingSystemFieldsSubmit(null),
|
|
597
|
-
children: /*#__PURE__*/ jsx(CloseIcon, {
|
|
598
|
-
width: "16px",
|
|
599
|
-
height: "16px",
|
|
600
|
-
svgClassName: "white-icon"
|
|
601
|
-
})
|
|
602
|
-
})
|
|
603
|
-
]
|
|
604
|
-
}),
|
|
605
|
-
/*#__PURE__*/ jsxs(Modal.Content, {
|
|
606
|
-
className: "prose",
|
|
607
|
-
children: [
|
|
608
|
-
pendingSystemFieldsSubmit.contentDirty && /*#__PURE__*/ jsx("p", {
|
|
609
|
-
className: classnames('byline-form-system-fields-content-note', 'm-0 mt-2'),
|
|
610
|
-
children: t('forms.systemFieldsConfirm.contentNote')
|
|
611
|
-
}),
|
|
612
|
-
/*#__PURE__*/ jsx("p", {
|
|
613
|
-
className: "m-0 mt-2",
|
|
614
|
-
style: pendingSystemFieldsSubmit.contentDirty ? {
|
|
615
|
-
marginTop: 'var(--spacing-8)',
|
|
616
|
-
paddingTop: 'var(--spacing-12)',
|
|
617
|
-
borderTop: '1px solid var(--border-color)'
|
|
618
|
-
} : void 0,
|
|
619
|
-
children: t('forms.systemFieldsConfirm.intro')
|
|
620
|
-
}),
|
|
621
|
-
/*#__PURE__*/ jsxs("ul", {
|
|
622
|
-
className: classnames('byline-form-system-fields-list', form_renderer_module["guard-modal-text"], 'm-0'),
|
|
623
|
-
children: [
|
|
624
|
-
pendingSystemFieldsSubmit.pathDirty && /*#__PURE__*/ jsx("li", {
|
|
625
|
-
children: t('forms.systemFieldsConfirm.bulletPath')
|
|
626
|
-
}),
|
|
627
|
-
pendingSystemFieldsSubmit.availableLocalesDirty && /*#__PURE__*/ jsx("li", {
|
|
628
|
-
children: t('forms.systemFieldsConfirm.bulletLocales')
|
|
629
|
-
})
|
|
630
|
-
]
|
|
631
|
-
}),
|
|
632
|
-
/*#__PURE__*/ jsx("p", {
|
|
633
|
-
className: classnames('byline-form-system-fields-effect', form_renderer_module["guard-modal-text"]),
|
|
634
|
-
style: {
|
|
635
|
-
marginTop: 'var(--spacing-4)',
|
|
636
|
-
marginBottom: 0,
|
|
637
|
-
color: 'var(--text-subtle)'
|
|
638
|
-
},
|
|
639
|
-
children: t('forms.systemFieldsConfirm.effectLine')
|
|
640
|
-
})
|
|
641
|
-
]
|
|
642
|
-
}),
|
|
643
|
-
/*#__PURE__*/ jsxs(Modal.Actions, {
|
|
644
|
-
children: [
|
|
645
|
-
/*#__PURE__*/ jsx(Button, {
|
|
646
|
-
size: "sm",
|
|
647
|
-
style: {
|
|
648
|
-
minWidth: '80px'
|
|
649
|
-
},
|
|
650
|
-
intent: "noeffect",
|
|
651
|
-
type: "button",
|
|
652
|
-
onClick: ()=>setPendingSystemFieldsSubmit(null),
|
|
653
|
-
children: t('common.actions.cancel')
|
|
654
|
-
}),
|
|
655
|
-
/*#__PURE__*/ jsx(Button, {
|
|
656
|
-
size: "sm",
|
|
657
|
-
style: {
|
|
658
|
-
minWidth: '80px'
|
|
659
|
-
},
|
|
660
|
-
intent: "primary",
|
|
661
|
-
type: "button",
|
|
662
|
-
onClick: ()=>{
|
|
663
|
-
const payload = pendingSystemFieldsSubmit;
|
|
664
|
-
setPendingSystemFieldsSubmit(null);
|
|
665
|
-
submitPayload(payload);
|
|
666
|
-
},
|
|
667
|
-
children: t('forms.systemFieldsConfirm.confirmButton')
|
|
668
|
-
})
|
|
669
|
-
]
|
|
670
|
-
})
|
|
671
|
-
]
|
|
672
|
-
})
|
|
367
|
+
null != pendingSystemFieldsSubmit && /*#__PURE__*/ jsx(SystemFieldsConfirmModal, {
|
|
368
|
+
contentDirty: pendingSystemFieldsSubmit.contentDirty,
|
|
369
|
+
pathDirty: pendingSystemFieldsSubmit.pathDirty,
|
|
370
|
+
availableLocalesDirty: pendingSystemFieldsSubmit.availableLocalesDirty,
|
|
371
|
+
onCancel: ()=>setPendingSystemFieldsSubmit(null),
|
|
372
|
+
onConfirm: ()=>{
|
|
373
|
+
const payload = pendingSystemFieldsSubmit;
|
|
374
|
+
setPendingSystemFieldsSubmit(null);
|
|
375
|
+
submitPayload(payload);
|
|
376
|
+
}
|
|
673
377
|
}),
|
|
674
|
-
guard.isBlocked && /*#__PURE__*/ jsx(
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
onDismiss: guard.stay,
|
|
678
|
-
children: /*#__PURE__*/ jsxs(Modal.Container, {
|
|
679
|
-
style: {
|
|
680
|
-
maxWidth: '460px'
|
|
681
|
-
},
|
|
682
|
-
children: [
|
|
683
|
-
/*#__PURE__*/ jsx(Modal.Header, {
|
|
684
|
-
className: classnames('byline-form-guard-modal-head', form_renderer_module["guard-modal-head"]),
|
|
685
|
-
children: /*#__PURE__*/ jsx("h3", {
|
|
686
|
-
className: classnames('byline-form-guard-modal-title', form_renderer_module["guard-modal-title"]),
|
|
687
|
-
children: t('forms.navigationGuard.title')
|
|
688
|
-
})
|
|
689
|
-
}),
|
|
690
|
-
/*#__PURE__*/ jsx(Modal.Content, {
|
|
691
|
-
children: /*#__PURE__*/ jsx("p", {
|
|
692
|
-
className: classnames('byline-form-guard-modal-text', form_renderer_module["guard-modal-text"]),
|
|
693
|
-
children: t('forms.navigationGuard.message')
|
|
694
|
-
})
|
|
695
|
-
}),
|
|
696
|
-
/*#__PURE__*/ jsxs(Modal.Actions, {
|
|
697
|
-
children: [
|
|
698
|
-
/*#__PURE__*/ jsx(Button, {
|
|
699
|
-
size: "sm",
|
|
700
|
-
intent: "noeffect",
|
|
701
|
-
type: "button",
|
|
702
|
-
onClick: guard.stay,
|
|
703
|
-
children: t('forms.navigationGuard.stayButton')
|
|
704
|
-
}),
|
|
705
|
-
/*#__PURE__*/ jsx(Button, {
|
|
706
|
-
size: "sm",
|
|
707
|
-
intent: "danger",
|
|
708
|
-
type: "button",
|
|
709
|
-
onClick: guard.proceed,
|
|
710
|
-
children: t('forms.navigationGuard.leaveButton')
|
|
711
|
-
})
|
|
712
|
-
]
|
|
713
|
-
})
|
|
714
|
-
]
|
|
715
|
-
})
|
|
378
|
+
guard.isBlocked && /*#__PURE__*/ jsx(NavigationGuardModal, {
|
|
379
|
+
onStay: guard.stay,
|
|
380
|
+
onProceed: guard.proceed
|
|
716
381
|
})
|
|
717
382
|
]
|
|
718
383
|
});
|
|
719
384
|
};
|
|
720
|
-
const FormRenderer = ({ mode, fields, onSubmit, onCancel, onStatusChange, onUnpublish, onDelete, onDuplicate, onCopyToLocale, onDeleteLocale, contentLocales, nextStatus, workflowStatuses, publishedVersion, initialData, adminConfig, useAsTitle, useAsPath, advertiseLocales, headingLabel, headerSlot, collectionPath, initialLocale, onLocaleChange, defaultLocale, useNavigationGuard, restoreWarnings })=>{
|
|
385
|
+
const FormRenderer = ({ mode, fields, onSubmit, onCancel, onStatusChange, onUnpublish, onDelete, onDuplicate, onCopyToLocale, onDeleteLocale, contentLocales, nextStatus, workflowStatuses, publishedVersion, initialData, adminConfig, useAsTitle, useAsPath, advertiseLocales, tree, headingLabel, headerSlot, collectionPath, initialLocale, onLocaleChange, defaultLocale, useNavigationGuard, restoreWarnings })=>{
|
|
721
386
|
const savedTabsRef = useRef({});
|
|
722
387
|
return /*#__PURE__*/ jsx(FormProvider, {
|
|
723
388
|
initialData: initialData,
|
|
@@ -741,6 +406,7 @@ const FormRenderer = ({ mode, fields, onSubmit, onCancel, onStatusChange, onUnpu
|
|
|
741
406
|
useAsTitle: useAsTitle,
|
|
742
407
|
useAsPath: useAsPath,
|
|
743
408
|
advertiseLocales: advertiseLocales,
|
|
409
|
+
tree: tree,
|
|
744
410
|
headingLabel: headingLabel,
|
|
745
411
|
headerSlot: headerSlot,
|
|
746
412
|
collectionPath: collectionPath,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
import type { WorkflowStatus } from '@byline/core';
|
|
9
|
+
import type { PublishedVersionInfo } from './form-renderer';
|
|
10
|
+
/**
|
|
11
|
+
* The status / metadata strip at the top of a document form — current
|
|
12
|
+
* workflow status (suppressed for single-status workflows), last-modified and
|
|
13
|
+
* created timestamps, and a "published live" indicator with an inline
|
|
14
|
+
* Unpublish action when a previously-published version is still live.
|
|
15
|
+
*/
|
|
16
|
+
export declare const FormStatusDisplay: ({ initialData, workflowStatuses, publishedVersion, onUnpublish, }: {
|
|
17
|
+
initialData?: Record<string, any>;
|
|
18
|
+
workflowStatuses?: WorkflowStatus[];
|
|
19
|
+
publishedVersion?: PublishedVersionInfo | null;
|
|
20
|
+
onUnpublish?: () => Promise<void>;
|
|
21
|
+
}) => import("react").JSX.Element;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useTranslation } from "@byline/i18n/react";
|
|
4
|
+
import classnames from "classnames";
|
|
5
|
+
import { LocalDateTime } from "../fields/local-date-time.js";
|
|
6
|
+
import form_renderer_module from "./form-renderer.module.js";
|
|
7
|
+
const FormStatusDisplay = ({ initialData, workflowStatuses, publishedVersion, onUnpublish })=>{
|
|
8
|
+
const { t } = useTranslation('byline-admin');
|
|
9
|
+
const statusCode = initialData?.status;
|
|
10
|
+
const statusLabel = workflowStatuses?.find((s)=>s.name === statusCode)?.label ?? statusCode;
|
|
11
|
+
const showStatusCell = (workflowStatuses?.length ?? 0) > 1;
|
|
12
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
13
|
+
className: classnames('byline-form-status', form_renderer_module.status),
|
|
14
|
+
children: [
|
|
15
|
+
/*#__PURE__*/ jsxs("div", {
|
|
16
|
+
className: classnames('byline-form-status-meta', form_renderer_module["status-meta"]),
|
|
17
|
+
children: [
|
|
18
|
+
showStatusCell && /*#__PURE__*/ jsxs("div", {
|
|
19
|
+
className: classnames('byline-form-status-cell', form_renderer_module["status-cell"]),
|
|
20
|
+
children: [
|
|
21
|
+
/*#__PURE__*/ jsx("span", {
|
|
22
|
+
className: classnames('byline-form-status-muted', form_renderer_module["status-muted"]),
|
|
23
|
+
children: t('forms.status.label')
|
|
24
|
+
}),
|
|
25
|
+
/*#__PURE__*/ jsx("span", {
|
|
26
|
+
className: classnames('byline-form-status-trunc', form_renderer_module["status-trunc"]),
|
|
27
|
+
children: statusLabel
|
|
28
|
+
})
|
|
29
|
+
]
|
|
30
|
+
}),
|
|
31
|
+
initialData?.updatedAt != null && /*#__PURE__*/ jsxs("div", {
|
|
32
|
+
className: classnames('byline-form-status-cell', form_renderer_module["status-cell"]),
|
|
33
|
+
children: [
|
|
34
|
+
/*#__PURE__*/ jsx("span", {
|
|
35
|
+
className: classnames('byline-form-status-muted', form_renderer_module["status-muted"]),
|
|
36
|
+
children: t('forms.status.lastModified')
|
|
37
|
+
}),
|
|
38
|
+
/*#__PURE__*/ jsx("span", {
|
|
39
|
+
className: classnames('byline-form-status-trunc', form_renderer_module["status-trunc"]),
|
|
40
|
+
children: /*#__PURE__*/ jsx(LocalDateTime, {
|
|
41
|
+
value: initialData.updatedAt
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
]
|
|
45
|
+
}),
|
|
46
|
+
initialData?.createdAt != null && /*#__PURE__*/ jsxs("div", {
|
|
47
|
+
className: classnames('byline-form-status-cell', form_renderer_module["status-cell"]),
|
|
48
|
+
children: [
|
|
49
|
+
/*#__PURE__*/ jsx("span", {
|
|
50
|
+
className: classnames('byline-form-status-muted', form_renderer_module["status-muted"]),
|
|
51
|
+
children: t('forms.status.created')
|
|
52
|
+
}),
|
|
53
|
+
/*#__PURE__*/ jsx("span", {
|
|
54
|
+
className: classnames('byline-form-status-trunc', form_renderer_module["status-trunc"]),
|
|
55
|
+
children: /*#__PURE__*/ jsx(LocalDateTime, {
|
|
56
|
+
value: initialData.createdAt
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
]
|
|
60
|
+
})
|
|
61
|
+
]
|
|
62
|
+
}),
|
|
63
|
+
null != publishedVersion && /*#__PURE__*/ jsxs("div", {
|
|
64
|
+
className: classnames('byline-form-status-published', form_renderer_module["status-published"]),
|
|
65
|
+
children: [
|
|
66
|
+
/*#__PURE__*/ jsxs("span", {
|
|
67
|
+
className: classnames('byline-form-status-muted', form_renderer_module["status-muted"]),
|
|
68
|
+
children: [
|
|
69
|
+
t('forms.status.publishedLive'),
|
|
70
|
+
' ',
|
|
71
|
+
publishedVersion.updatedAt ? /*#__PURE__*/ jsx("span", {
|
|
72
|
+
children: t('forms.status.publishedOn', {
|
|
73
|
+
date: new Date(publishedVersion.updatedAt)
|
|
74
|
+
})
|
|
75
|
+
}) : ''
|
|
76
|
+
]
|
|
77
|
+
}),
|
|
78
|
+
onUnpublish && /*#__PURE__*/ jsxs(Fragment, {
|
|
79
|
+
children: [
|
|
80
|
+
' ',
|
|
81
|
+
/*#__PURE__*/ jsx("button", {
|
|
82
|
+
type: "button",
|
|
83
|
+
onClick: onUnpublish,
|
|
84
|
+
className: classnames('byline-form-status-unpublish', form_renderer_module["status-unpublish"]),
|
|
85
|
+
children: t('common.actions.unpublish')
|
|
86
|
+
})
|
|
87
|
+
]
|
|
88
|
+
})
|
|
89
|
+
]
|
|
90
|
+
})
|
|
91
|
+
]
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
export { FormStatusDisplay };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
import type { WorkflowStatus } from '@byline/core';
|
|
9
|
+
export interface StatusTransitions {
|
|
10
|
+
primaryStatus: WorkflowStatus | undefined;
|
|
11
|
+
secondaryStatuses: WorkflowStatus[];
|
|
12
|
+
isTerminal: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Compute the primary and secondary status transitions for the ComboButton.
|
|
16
|
+
* - Primary: the main action (forward step), or the current status itself
|
|
17
|
+
* when the document has reached the final workflow step (terminal state).
|
|
18
|
+
* - Secondary: other available transitions to show as dropdown options.
|
|
19
|
+
* - isTerminal: true when the document is at the final workflow status —
|
|
20
|
+
* the primary button renders as a non-actionable indicator and all
|
|
21
|
+
* back-steps move into the dropdown.
|
|
22
|
+
*/
|
|
23
|
+
export declare function computeStatusTransitions(currentStatus: string | undefined, workflowStatuses: WorkflowStatus[] | undefined, nextStatus: WorkflowStatus | undefined): StatusTransitions;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
function computeStatusTransitions(currentStatus, workflowStatuses, nextStatus) {
|
|
2
|
+
if (!workflowStatuses || 0 === workflowStatuses.length || !currentStatus) return {
|
|
3
|
+
primaryStatus: nextStatus,
|
|
4
|
+
secondaryStatuses: [],
|
|
5
|
+
isTerminal: false
|
|
6
|
+
};
|
|
7
|
+
if (workflowStatuses.length <= 1) return {
|
|
8
|
+
primaryStatus: void 0,
|
|
9
|
+
secondaryStatuses: [],
|
|
10
|
+
isTerminal: false
|
|
11
|
+
};
|
|
12
|
+
const currentIndex = workflowStatuses.findIndex((s)=>s.name === currentStatus);
|
|
13
|
+
if (-1 === currentIndex) return {
|
|
14
|
+
primaryStatus: nextStatus,
|
|
15
|
+
secondaryStatuses: [],
|
|
16
|
+
isTerminal: false
|
|
17
|
+
};
|
|
18
|
+
const isAtEnd = currentIndex === workflowStatuses.length - 1;
|
|
19
|
+
const isAtStart = 0 === currentIndex;
|
|
20
|
+
const availableTargets = [];
|
|
21
|
+
if (!isAtStart && workflowStatuses[0]) availableTargets.push(workflowStatuses[0]);
|
|
22
|
+
const prev = workflowStatuses[currentIndex - 1];
|
|
23
|
+
if (currentIndex > 1 && prev) availableTargets.push(prev);
|
|
24
|
+
const next = workflowStatuses[currentIndex + 1];
|
|
25
|
+
if (!isAtEnd && next) availableTargets.push(next);
|
|
26
|
+
if (isAtEnd) return {
|
|
27
|
+
primaryStatus: workflowStatuses[currentIndex],
|
|
28
|
+
secondaryStatuses: availableTargets,
|
|
29
|
+
isTerminal: true
|
|
30
|
+
};
|
|
31
|
+
return {
|
|
32
|
+
primaryStatus: nextStatus,
|
|
33
|
+
secondaryStatuses: availableTargets.filter((s)=>s.name !== nextStatus?.name),
|
|
34
|
+
isTerminal: false
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export { computeStatusTransitions };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
export {};
|