@questpie/admin 3.2.3 → 3.2.5
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/client/blocks/block-renderer.d.mts +2 -2
- package/dist/client/blocks/block-renderer.mjs +164 -339
- package/dist/client/components/actions/action-button.mjs +9 -9
- package/dist/client/components/actions/action-dialog.mjs +195 -493
- package/dist/client/components/actions/confirmation-dialog.mjs +44 -159
- package/dist/client/components/actions/header-actions.mjs +73 -165
- package/dist/client/components/admin-link.d.mts +2 -2
- package/dist/client/components/admin-link.mjs +40 -126
- package/dist/client/components/auth/auth-loading.mjs +9 -44
- package/dist/client/components/blocks/block-canvas.mjs +31 -95
- package/dist/client/components/blocks/block-editor-context.mjs +13 -57
- package/dist/client/components/blocks/block-editor-layout.mjs +72 -166
- package/dist/client/components/blocks/block-editor-provider.mjs +184 -245
- package/dist/client/components/blocks/block-fields-renderer.mjs +54 -229
- package/dist/client/components/blocks/block-insert-button.mjs +49 -165
- package/dist/client/components/blocks/block-item-menu.mjs +102 -301
- package/dist/client/components/blocks/block-item.mjs +136 -370
- package/dist/client/components/blocks/block-library-sidebar.mjs +106 -220
- package/dist/client/components/blocks/block-tree.mjs +12 -68
- package/dist/client/components/blocks/block-type-icon.mjs +14 -56
- package/dist/client/components/brand-logo.mjs +35 -149
- package/dist/client/components/component-renderer.mjs +42 -118
- package/dist/client/components/error-boundary.mjs +14 -58
- package/dist/client/components/fields/array-field.mjs +209 -521
- package/dist/client/components/fields/asset-preview-field.mjs +41 -141
- package/dist/client/components/fields/blocks-field/blocks-field.mjs +60 -156
- package/dist/client/components/fields/boolean-field.mjs +29 -59
- package/dist/client/components/fields/date-field.mjs +7 -37
- package/dist/client/components/fields/datetime-field.mjs +7 -38
- package/dist/client/components/fields/email-field.mjs +25 -54
- package/dist/client/components/fields/field-wrapper.mjs +30 -105
- package/dist/client/components/fields/json-field.mjs +107 -313
- package/dist/client/components/fields/locale-badge.mjs +6 -15
- package/dist/client/components/fields/number-field.mjs +27 -60
- package/dist/client/components/fields/object-array-field.mjs +283 -659
- package/dist/client/components/fields/object-field.mjs +165 -633
- package/dist/client/components/fields/relation/displays/cards-display.mjs +106 -220
- package/dist/client/components/fields/relation/displays/chips-display.mjs +78 -150
- package/dist/client/components/fields/relation/displays/grid-display.mjs +92 -186
- package/dist/client/components/fields/relation/displays/list-display.mjs +122 -239
- package/dist/client/components/fields/relation/displays/table-display.mjs +70 -244
- package/dist/client/components/fields/relation/relation-items-display.mjs +30 -126
- package/dist/client/components/fields/relation-field.mjs +10 -66
- package/dist/client/components/fields/relation-picker.mjs +18 -18
- package/dist/client/components/fields/relation-select.mjs +12 -12
- package/dist/client/components/fields/rich-text-editor/bubble-menu.mjs +80 -182
- package/dist/client/components/fields/rich-text-editor/image-popover.mjs +8 -19
- package/dist/client/components/fields/rich-text-editor/image-upload.mjs +13 -29
- package/dist/client/components/fields/rich-text-editor/index.mjs +196 -530
- package/dist/client/components/fields/rich-text-editor/slash-commands.mjs +61 -111
- package/dist/client/components/fields/rich-text-editor/table-controls.mjs +105 -415
- package/dist/client/components/fields/rich-text-editor/toolbar.mjs +256 -511
- package/dist/client/components/fields/rich-text-field.mjs +14 -53
- package/dist/client/components/fields/select-field.mjs +39 -74
- package/dist/client/components/fields/text-field.mjs +26 -59
- package/dist/client/components/fields/textarea-field.mjs +26 -58
- package/dist/client/components/fields/time-field.mjs +7 -35
- package/dist/client/components/fields/upload-field.mjs +47 -165
- package/dist/client/components/filter-builder/columns-tab.mjs +80 -280
- package/dist/client/components/filter-builder/filter-builder-sheet.mjs +197 -540
- package/dist/client/components/filter-builder/filters-tab.mjs +96 -386
- package/dist/client/components/filter-builder/saved-views-tab.mjs +133 -351
- package/dist/client/components/history-sidebar.mjs +306 -611
- package/dist/client/components/layout/field-layout-renderer.mjs +106 -254
- package/dist/client/components/locale-switcher.mjs +106 -228
- package/dist/client/components/media/media-grid.mjs +84 -273
- package/dist/client/components/media/media-picker-dialog.mjs +177 -494
- package/dist/client/components/preview/live-preview-mode.mjs +240 -438
- package/dist/client/components/preview/preview-pane.mjs +22 -22
- package/dist/client/components/primitives/asset-preview.mjs +290 -666
- package/dist/client/components/primitives/checkbox-input.mjs +9 -35
- package/dist/client/components/primitives/date-input.mjs +109 -327
- package/dist/client/components/primitives/dropzone.mjs +209 -336
- package/dist/client/components/primitives/field-select-control.mjs +12 -80
- package/dist/client/components/primitives/number-input.mjs +4 -4
- package/dist/client/components/primitives/select-multi.mjs +200 -559
- package/dist/client/components/primitives/select-single.mjs +165 -499
- package/dist/client/components/primitives/time-input.mjs +43 -117
- package/dist/client/components/primitives/toggle-input.mjs +9 -29
- package/dist/client/components/sheets/resource-sheet.mjs +61 -70
- package/dist/client/components/ui/accordion.mjs +35 -155
- package/dist/client/components/ui/alert.mjs +13 -68
- package/dist/client/components/ui/badge.mjs +9 -51
- package/dist/client/components/ui/button.mjs +8 -54
- package/dist/client/components/ui/card.mjs +37 -193
- package/dist/client/components/ui/checkbox.mjs +12 -68
- package/dist/client/components/ui/command.mjs +48 -219
- package/dist/client/components/ui/dialog.mjs +50 -262
- package/dist/client/components/ui/drawer.mjs +55 -259
- package/dist/client/components/ui/dropdown-menu.mjs +86 -427
- package/dist/client/components/ui/empty-state.mjs +28 -98
- package/dist/client/components/ui/field.mjs +73 -309
- package/dist/client/components/ui/input-group.mjs +42 -167
- package/dist/client/components/ui/input.mjs +7 -37
- package/dist/client/components/ui/kbd.mjs +6 -36
- package/dist/client/components/ui/label.mjs +7 -37
- package/dist/client/components/ui/popover.mjs +34 -169
- package/dist/client/components/ui/responsive-dialog.mjs +67 -273
- package/dist/client/components/ui/scroll-fade.mjs +63 -158
- package/dist/client/components/ui/search-input.mjs +33 -100
- package/dist/client/components/ui/select.mjs +72 -393
- package/dist/client/components/ui/separator.mjs +7 -38
- package/dist/client/components/ui/sheet.mjs +49 -269
- package/dist/client/components/ui/sidebar.mjs +171 -690
- package/dist/client/components/ui/skeleton.mjs +7 -38
- package/dist/client/components/ui/sonner.mjs +11 -42
- package/dist/client/components/ui/switch.mjs +9 -45
- package/dist/client/components/ui/table.mjs +48 -266
- package/dist/client/components/ui/tabs.mjs +26 -139
- package/dist/client/components/ui/textarea.mjs +6 -32
- package/dist/client/components/ui/tooltip.mjs +27 -129
- package/dist/client/components/widgets/chart-widget.mjs +174 -522
- package/dist/client/components/widgets/progress-widget.mjs +66 -172
- package/dist/client/components/widgets/quick-actions-widget.mjs +102 -261
- package/dist/client/components/widgets/recent-items-widget.mjs +69 -195
- package/dist/client/components/widgets/stats-widget.mjs +41 -175
- package/dist/client/components/widgets/table-widget.mjs +9 -9
- package/dist/client/components/widgets/timeline-widget.mjs +86 -226
- package/dist/client/components/widgets/value-widget.mjs +74 -381
- package/dist/client/components/widgets/widget-empty-state.mjs +26 -76
- package/dist/client/components/widgets/widget-skeletons.mjs +138 -421
- package/dist/client/contexts/focus-context.d.mts +4 -0
- package/dist/client/contexts/focus-context.mjs +87 -150
- package/dist/client/hooks/typed-hooks.mjs +241 -701
- package/dist/client/hooks/use-action.mjs +62 -198
- package/dist/client/hooks/use-admin-config.mjs +5 -35
- package/dist/client/hooks/use-admin-preferences.mjs +16 -88
- package/dist/client/hooks/use-admin-routes.mjs +22 -56
- package/dist/client/hooks/use-audit-history.mjs +21 -69
- package/dist/client/hooks/use-brand.mjs +1 -9
- package/dist/client/hooks/use-collection-fields.mjs +17 -57
- package/dist/client/hooks/use-collection-meta.mjs +12 -44
- package/dist/client/hooks/use-collection-schema.mjs +10 -33
- package/dist/client/hooks/use-collection-validation.mjs +23 -53
- package/dist/client/hooks/use-collection.mjs +194 -614
- package/dist/client/hooks/use-current-user.mjs +0 -1
- package/dist/client/hooks/use-field-hooks.mjs +10 -10
- package/dist/client/hooks/use-field-options.mjs +61 -202
- package/dist/client/hooks/use-global-fields.mjs +14 -46
- package/dist/client/hooks/use-global-meta.mjs +9 -30
- package/dist/client/hooks/use-global-schema.mjs +9 -30
- package/dist/client/hooks/use-global.mjs +63 -219
- package/dist/client/hooks/use-locks.mjs +117 -325
- package/dist/client/hooks/use-media-query.mjs +16 -36
- package/dist/client/hooks/use-prefill-params.mjs +0 -1
- package/dist/client/hooks/use-questpie-query-options.mjs +12 -29
- package/dist/client/hooks/use-reactive-fields.mjs +1 -1
- package/dist/client/hooks/use-reactive-prop.mjs +65 -223
- package/dist/client/hooks/use-realtime-highlight.mjs +51 -114
- package/dist/client/hooks/use-saved-views.mjs +22 -103
- package/dist/client/hooks/use-search-param-toggle.mjs +28 -79
- package/dist/client/hooks/use-search.mjs +31 -143
- package/dist/client/hooks/use-server-actions.mjs +18 -50
- package/dist/client/hooks/use-server-validation.mjs +72 -166
- package/dist/client/hooks/use-server-widget-data.mjs +7 -33
- package/dist/client/hooks/use-setup-status.mjs +12 -25
- package/dist/client/hooks/use-sidebar-search-param.mjs +33 -78
- package/dist/client/hooks/use-transition-stage.mjs +8 -38
- package/dist/client/hooks/use-upload.mjs +54 -152
- package/dist/client/hooks/use-validation-error-map.mjs +6 -26
- package/dist/client/hooks/use-view-state.mjs +187 -437
- package/dist/client/i18n/hooks.mjs +65 -197
- package/dist/client/lib/render-profiler.mjs +14 -41
- package/dist/client/preview/block-scope-context.d.mts +2 -2
- package/dist/client/preview/block-scope-context.mjs +14 -36
- package/dist/client/preview/diff.mjs +110 -0
- package/dist/client/preview/preview-banner.mjs +42 -108
- package/dist/client/preview/preview-field.d.mts +4 -4
- package/dist/client/preview/preview-field.mjs +166 -409
- package/dist/client/preview/use-collection-preview.mjs +135 -201
- package/dist/client/runtime/content-locales-provider.mjs +31 -83
- package/dist/client/runtime/locale-scope.mjs +22 -63
- package/dist/client/runtime/provider.mjs +100 -255
- package/dist/client/runtime/translations-provider.mjs +41 -107
- package/dist/client/scope/picker.d.mts +2 -2
- package/dist/client/scope/picker.mjs +86 -321
- package/dist/client/scope/provider.d.mts +2 -2
- package/dist/client/scope/provider.mjs +8 -17
- package/dist/client/views/auth/accept-invite-form.d.mts +2 -2
- package/dist/client/views/auth/accept-invite-form.mjs +121 -412
- package/dist/client/views/auth/auth-layout.d.mts +3 -3
- package/dist/client/views/auth/auth-layout.mjs +104 -284
- package/dist/client/views/auth/forgot-password-form.d.mts +2 -2
- package/dist/client/views/auth/forgot-password-form.mjs +94 -325
- package/dist/client/views/auth/invite-form.mjs +107 -442
- package/dist/client/views/auth/login-form.d.mts +2 -2
- package/dist/client/views/auth/login-form.mjs +116 -337
- package/dist/client/views/auth/reset-password-form.mjs +128 -453
- package/dist/client/views/auth/setup-form.mjs +140 -478
- package/dist/client/views/collection/auto-form-fields.mjs +243 -615
- package/dist/client/views/collection/bulk-action-toolbar.mjs +212 -400
- package/dist/client/views/collection/cells/complex-cells.mjs +183 -611
- package/dist/client/views/collection/cells/primitive-cells.mjs +109 -363
- package/dist/client/views/collection/cells/relation-cells.mjs +86 -233
- package/dist/client/views/collection/cells/shared/asset-thumbnail.mjs +142 -371
- package/dist/client/views/collection/cells/shared/relation-chip.mjs +35 -131
- package/dist/client/views/collection/cells/upload-cells.mjs +60 -177
- package/dist/client/views/collection/columns/build-columns.mjs +8 -48
- package/dist/client/views/collection/field-renderer.mjs +11 -24
- package/dist/client/views/collection/form-view.mjs +288 -560
- package/dist/client/views/collection/table-view.mjs +239 -469
- package/dist/client/views/collection/view-skeletons.mjs +112 -237
- package/dist/client/views/common/global-search.mjs +241 -543
- package/dist/client/views/dashboard/dashboard-grid.mjs +256 -775
- package/dist/client/views/dashboard/dashboard-widget.mjs +38 -126
- package/dist/client/views/dashboard/widget-card.mjs +61 -269
- package/dist/client/views/globals/global-form-view.mjs +478 -1298
- package/dist/client/views/layout/admin-layout-provider.mjs +28 -88
- package/dist/client/views/layout/admin-layout.mjs +83 -246
- package/dist/client/views/layout/admin-router.mjs +457 -1289
- package/dist/client/views/layout/admin-sidebar.mjs +510 -1292
- package/dist/client/views/layout/admin-theme.mjs +30 -64
- package/dist/client/views/layout/admin-view-layout.mjs +40 -144
- package/dist/client/views/pages/accept-invite-page.mjs +95 -290
- package/dist/client/views/pages/dashboard-page.mjs +11 -57
- package/dist/client/views/pages/forgot-password-page.mjs +31 -83
- package/dist/client/views/pages/invite-page.mjs +35 -90
- package/dist/client/views/pages/login-page.mjs +41 -121
- package/dist/client/views/pages/reset-password-page.d.mts +2 -2
- package/dist/client/views/pages/reset-password-page.mjs +46 -173
- package/dist/client/views/pages/setup-page.d.mts +2 -2
- package/dist/client/views/pages/setup-page.mjs +33 -95
- package/dist/components/rich-text/rich-text-renderer.d.mts +2 -2
- package/dist/components/rich-text/rich-text-renderer.mjs +9 -33
- package/dist/server/modules/admin/collections/account.d.mts +50 -50
- package/dist/server/modules/admin/collections/admin-locks.d.mts +54 -54
- package/dist/server/modules/admin/collections/admin-preferences.d.mts +39 -39
- package/dist/server/modules/admin/collections/admin-saved-views.d.mts +47 -47
- package/dist/server/modules/admin/collections/apikey.d.mts +68 -68
- package/dist/server/modules/admin/collections/assets.d.mts +34 -34
- package/dist/server/modules/admin/collections/session.d.mts +42 -42
- package/dist/server/modules/admin/collections/user.d.mts +53 -53
- package/dist/server/modules/admin/collections/verification.d.mts +36 -36
- package/dist/server/modules/admin/index.d.mts +21 -20
- package/dist/server/modules/admin/routes/admin-config.d.mts +2 -2
- package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
- package/dist/server/modules/admin/routes/locales.d.mts +2 -2
- package/dist/server/modules/admin/routes/preview.d.mts +11 -11
- package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
- package/dist/server/modules/admin/routes/setup.d.mts +7 -7
- package/dist/server/modules/admin/routes/translations.d.mts +4 -4
- package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
- package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +27 -27
- package/package.json +3 -5
|
@@ -31,11 +31,12 @@ import { getLockUser, useLock } from "../../hooks/use-locks.mjs";
|
|
|
31
31
|
import { useReactiveFields } from "../../hooks/use-reactive-fields.mjs";
|
|
32
32
|
import { useServerActions } from "../../hooks/use-server-actions.mjs";
|
|
33
33
|
import { useTransitionStage } from "../../hooks/use-transition-stage.mjs";
|
|
34
|
+
import { applyPatchBatchImmutable, cloneSnapshot } from "../../preview/patch.mjs";
|
|
35
|
+
import { diffSnapshot, diffSnapshotAtPath } from "../../preview/diff.mjs";
|
|
34
36
|
import { detectManyToManyRelations, hasManyToManyRelations } from "../../utils/detect-relations.mjs";
|
|
35
37
|
import { shouldHandleAdminShortcut } from "../../utils/keyboard-shortcuts.mjs";
|
|
36
38
|
import { AdminViewHeader } from "../layout/admin-view-layout.mjs";
|
|
37
39
|
import { FormViewSkeleton } from "./view-skeletons.mjs";
|
|
38
|
-
import { c } from "react/compiler-runtime";
|
|
39
40
|
import { Icon } from "@iconify/react";
|
|
40
41
|
import * as React from "react";
|
|
41
42
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
@@ -64,74 +65,6 @@ function extractReactiveConfigs(schema) {
|
|
|
64
65
|
for (const [fieldName, fieldDef] of Object.entries(schema.fields)) if (fieldDef.reactive) configs[fieldName] = fieldDef.reactive;
|
|
65
66
|
return configs;
|
|
66
67
|
}
|
|
67
|
-
function isPlainObject(value) {
|
|
68
|
-
if (!value || typeof value !== "object") return false;
|
|
69
|
-
const prototype = Object.getPrototypeOf(value);
|
|
70
|
-
return prototype === Object.prototype || prototype === null;
|
|
71
|
-
}
|
|
72
|
-
function clonePreviewSnapshot(value) {
|
|
73
|
-
if (typeof structuredClone === "function") try {
|
|
74
|
-
return structuredClone(value);
|
|
75
|
-
} catch {}
|
|
76
|
-
const json = JSON.stringify(value);
|
|
77
|
-
return json === void 0 ? value : JSON.parse(json);
|
|
78
|
-
}
|
|
79
|
-
function arePreviewValuesEqual(a, b) {
|
|
80
|
-
if (Object.is(a, b)) return true;
|
|
81
|
-
if (Array.isArray(a) || Array.isArray(b)) {
|
|
82
|
-
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
|
|
83
|
-
return a.every((value, index) => arePreviewValuesEqual(value, b[index]));
|
|
84
|
-
}
|
|
85
|
-
if (isPlainObject(a) || isPlainObject(b)) {
|
|
86
|
-
if (!isPlainObject(a) || !isPlainObject(b)) return false;
|
|
87
|
-
const aKeys = Object.keys(a);
|
|
88
|
-
const bKeys = Object.keys(b);
|
|
89
|
-
if (aKeys.length !== bKeys.length) return false;
|
|
90
|
-
return aKeys.every((key) => Object.prototype.hasOwnProperty.call(b, key) && arePreviewValuesEqual(a[key], b[key]));
|
|
91
|
-
}
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
function joinPreviewPath(basePath, key) {
|
|
95
|
-
return basePath ? `${basePath}.${key}` : key;
|
|
96
|
-
}
|
|
97
|
-
function diffPreviewSnapshots(previous, current, basePath = "") {
|
|
98
|
-
if (arePreviewValuesEqual(previous, current)) return [];
|
|
99
|
-
if (isPlainObject(previous) && isPlainObject(current)) {
|
|
100
|
-
const ops = [];
|
|
101
|
-
const keys = new Set([...Object.keys(previous), ...Object.keys(current)]);
|
|
102
|
-
for (const key of keys) {
|
|
103
|
-
const path = joinPreviewPath(basePath, key);
|
|
104
|
-
const previousHasKey = Object.prototype.hasOwnProperty.call(previous, key);
|
|
105
|
-
if (!Object.prototype.hasOwnProperty.call(current, key)) {
|
|
106
|
-
ops.push({
|
|
107
|
-
op: "remove",
|
|
108
|
-
path
|
|
109
|
-
});
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
if (!previousHasKey) {
|
|
113
|
-
ops.push({
|
|
114
|
-
op: "set",
|
|
115
|
-
path,
|
|
116
|
-
value: current[key]
|
|
117
|
-
});
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
ops.push(...diffPreviewSnapshots(previous[key], current[key], path));
|
|
121
|
-
}
|
|
122
|
-
return ops;
|
|
123
|
-
}
|
|
124
|
-
if (!basePath) return [{
|
|
125
|
-
op: "set",
|
|
126
|
-
path: "",
|
|
127
|
-
value: current
|
|
128
|
-
}];
|
|
129
|
-
return [{
|
|
130
|
-
op: "set",
|
|
131
|
-
path: basePath,
|
|
132
|
-
value: current
|
|
133
|
-
}];
|
|
134
|
-
}
|
|
135
68
|
function isSafePreviewEditPath(path) {
|
|
136
69
|
if (!path || path.length > 512) return false;
|
|
137
70
|
return path.split(".").every((segment) => segment.length > 0 && segment !== "__proto__" && segment !== "prototype" && segment !== "constructor");
|
|
@@ -201,419 +134,220 @@ function normalizeInlineEditValue(message) {
|
|
|
201
134
|
* Component that manages reactive field states.
|
|
202
135
|
* Must be rendered inside FormProvider to access form context.
|
|
203
136
|
*/
|
|
204
|
-
function ReactiveFieldsManager(
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
$[1] = reactiveConfigs;
|
|
213
|
-
$[2] = t2;
|
|
214
|
-
} else t2 = $[2];
|
|
215
|
-
let t3;
|
|
216
|
-
if ($[3] !== collection || $[4] !== mode || $[5] !== reactiveConfigs || $[6] !== t2) {
|
|
217
|
-
t3 = {
|
|
218
|
-
collection,
|
|
219
|
-
mode,
|
|
220
|
-
reactiveConfigs,
|
|
221
|
-
enabled: t2,
|
|
222
|
-
debounce: 300
|
|
223
|
-
};
|
|
224
|
-
$[3] = collection;
|
|
225
|
-
$[4] = mode;
|
|
226
|
-
$[5] = reactiveConfigs;
|
|
227
|
-
$[6] = t2;
|
|
228
|
-
$[7] = t3;
|
|
229
|
-
} else t3 = $[7];
|
|
230
|
-
useReactiveFields(t3);
|
|
137
|
+
function ReactiveFieldsManager({ collection, mode = "collection", reactiveConfigs, enabled }) {
|
|
138
|
+
useReactiveFields({
|
|
139
|
+
collection,
|
|
140
|
+
mode,
|
|
141
|
+
reactiveConfigs,
|
|
142
|
+
enabled: enabled && Object.keys(reactiveConfigs).length > 0,
|
|
143
|
+
debounce: 300
|
|
144
|
+
});
|
|
231
145
|
return null;
|
|
232
146
|
}
|
|
233
|
-
const FormFieldsContent = React.memo(function FormFieldsContent$1(
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
let t5;
|
|
241
|
-
if ($[0] !== registry || $[1] !== t2 || $[2] !== t3 || $[3] !== t4) {
|
|
242
|
-
t5 = /* @__PURE__ */ jsx(AutoFormFields, {
|
|
243
|
-
collection: t2,
|
|
244
|
-
config: t3,
|
|
147
|
+
const FormFieldsContent = React.memo(function FormFieldsContent$1({ collection, config, registry, allCollectionsConfig }) {
|
|
148
|
+
return /* @__PURE__ */ jsx(RenderProfiler, {
|
|
149
|
+
id: `form.fields.${collection}`,
|
|
150
|
+
minDurationMs: 10,
|
|
151
|
+
children: /* @__PURE__ */ jsx(AutoFormFields, {
|
|
152
|
+
collection,
|
|
153
|
+
config,
|
|
245
154
|
registry,
|
|
246
|
-
allCollectionsConfig
|
|
247
|
-
})
|
|
248
|
-
|
|
249
|
-
$[1] = t2;
|
|
250
|
-
$[2] = t3;
|
|
251
|
-
$[3] = t4;
|
|
252
|
-
$[4] = t5;
|
|
253
|
-
} else t5 = $[4];
|
|
254
|
-
let t6;
|
|
255
|
-
if ($[5] !== t1 || $[6] !== t5) {
|
|
256
|
-
t6 = /* @__PURE__ */ jsx(RenderProfiler, {
|
|
257
|
-
id: t1,
|
|
258
|
-
minDurationMs: 10,
|
|
259
|
-
children: t5
|
|
260
|
-
});
|
|
261
|
-
$[5] = t1;
|
|
262
|
-
$[6] = t5;
|
|
263
|
-
$[7] = t6;
|
|
264
|
-
} else t6 = $[7];
|
|
265
|
-
return t6;
|
|
155
|
+
allCollectionsConfig
|
|
156
|
+
})
|
|
157
|
+
});
|
|
266
158
|
});
|
|
267
|
-
const FormStateRefBridge = React.memo(function FormStateRefBridge$1(
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
} else t1 = $[1];
|
|
276
|
-
const { isDirty, isSubmitting } = useFormState(t1);
|
|
277
|
-
let t2;
|
|
278
|
-
let t3;
|
|
279
|
-
if ($[2] !== isDirty || $[3] !== onDirtyChange) {
|
|
280
|
-
t2 = () => {
|
|
281
|
-
onDirtyChange(isDirty);
|
|
282
|
-
};
|
|
283
|
-
t3 = [isDirty, onDirtyChange];
|
|
284
|
-
$[2] = isDirty;
|
|
285
|
-
$[3] = onDirtyChange;
|
|
286
|
-
$[4] = t2;
|
|
287
|
-
$[5] = t3;
|
|
288
|
-
} else {
|
|
289
|
-
t2 = $[4];
|
|
290
|
-
t3 = $[5];
|
|
291
|
-
}
|
|
292
|
-
React.useEffect(t2, t3);
|
|
293
|
-
let t4;
|
|
294
|
-
let t5;
|
|
295
|
-
if ($[6] !== isSubmitting || $[7] !== onSubmittingChange) {
|
|
296
|
-
t4 = () => {
|
|
297
|
-
onSubmittingChange(isSubmitting);
|
|
298
|
-
};
|
|
299
|
-
t5 = [isSubmitting, onSubmittingChange];
|
|
300
|
-
$[6] = isSubmitting;
|
|
301
|
-
$[7] = onSubmittingChange;
|
|
302
|
-
$[8] = t4;
|
|
303
|
-
$[9] = t5;
|
|
304
|
-
} else {
|
|
305
|
-
t4 = $[8];
|
|
306
|
-
t5 = $[9];
|
|
307
|
-
}
|
|
308
|
-
React.useEffect(t4, t5);
|
|
159
|
+
const FormStateRefBridge = React.memo(function FormStateRefBridge$1({ control, onDirtyChange, onSubmittingChange }) {
|
|
160
|
+
const { isDirty, isSubmitting } = useFormState({ control });
|
|
161
|
+
React.useEffect(() => {
|
|
162
|
+
onDirtyChange(isDirty);
|
|
163
|
+
}, [isDirty, onDirtyChange]);
|
|
164
|
+
React.useEffect(() => {
|
|
165
|
+
onSubmittingChange(isSubmitting);
|
|
166
|
+
}, [isSubmitting, onSubmittingChange]);
|
|
309
167
|
return null;
|
|
310
168
|
});
|
|
311
|
-
const PreviewPatchBridge = React.memo(function PreviewPatchBridge$1(
|
|
312
|
-
const $ = c(5);
|
|
313
|
-
const { form, previewRef, enabled } = t0;
|
|
169
|
+
const PreviewPatchBridge = React.memo(function PreviewPatchBridge$1({ form, previewRef, enabled }) {
|
|
314
170
|
const previousSnapshotRef = React.useRef(null);
|
|
315
171
|
const snapshotVersionRef = React.useRef(void 0);
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
172
|
+
React.useEffect(() => {
|
|
173
|
+
if (!enabled) {
|
|
174
|
+
previousSnapshotRef.current = null;
|
|
175
|
+
snapshotVersionRef.current = void 0;
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const initialSnapshot = cloneSnapshot(form.getValues());
|
|
179
|
+
previousSnapshotRef.current = initialSnapshot;
|
|
180
|
+
snapshotVersionRef.current = previewRef.current?.sendInitSnapshot(initialSnapshot);
|
|
181
|
+
let animationFrame = null;
|
|
182
|
+
const pendingOps = /* @__PURE__ */ new Map();
|
|
183
|
+
const flushPendingOps = () => {
|
|
184
|
+
animationFrame = null;
|
|
185
|
+
if (pendingOps.size === 0) return;
|
|
186
|
+
const ops = [...pendingOps.values()];
|
|
187
|
+
pendingOps.clear();
|
|
188
|
+
previewRef.current?.sendPatchBatch(ops, snapshotVersionRef.current);
|
|
189
|
+
};
|
|
190
|
+
const queuePatchOps = (ops) => {
|
|
191
|
+
for (const op of ops) if (op.path) pendingOps.set(op.path, op);
|
|
192
|
+
if (pendingOps.size === 0 || animationFrame !== null) return;
|
|
193
|
+
animationFrame = window.requestAnimationFrame(flushPendingOps);
|
|
194
|
+
};
|
|
195
|
+
const subscription = form.watch((values, info) => {
|
|
196
|
+
const previousSnapshot = previousSnapshotRef.current;
|
|
197
|
+
const nextValues = values;
|
|
198
|
+
if (!previousSnapshot) {
|
|
199
|
+
const nextSnapshot = cloneSnapshot(nextValues);
|
|
200
|
+
previousSnapshotRef.current = nextSnapshot;
|
|
201
|
+
snapshotVersionRef.current = previewRef.current?.sendInitSnapshot(nextSnapshot);
|
|
323
202
|
return;
|
|
324
203
|
}
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
const previousSnapshot = previousSnapshotRef.current;
|
|
330
|
-
const nextSnapshot = clonePreviewSnapshot(values);
|
|
331
|
-
if (!previousSnapshot) {
|
|
332
|
-
previousSnapshotRef.current = nextSnapshot;
|
|
333
|
-
snapshotVersionRef.current = previewRef.current?.sendInitSnapshot(nextSnapshot);
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
const ops = diffPreviewSnapshots(previousSnapshot, nextSnapshot).filter(_temp);
|
|
204
|
+
const changedPath = info?.name;
|
|
205
|
+
let ops = changedPath && isSafePreviewEditPath(changedPath) ? diffSnapshotAtPath(previousSnapshot, nextValues, changedPath) : diffSnapshot(previousSnapshot, nextValues);
|
|
206
|
+
if (ops.some((op) => !op.path)) {
|
|
207
|
+
const nextSnapshot = cloneSnapshot(nextValues);
|
|
337
208
|
previousSnapshotRef.current = nextSnapshot;
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
209
|
+
snapshotVersionRef.current = previewRef.current?.sendInitSnapshot(nextSnapshot);
|
|
210
|
+
pendingOps.clear();
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
ops = ops.filter((op) => op.path);
|
|
214
|
+
if (ops.length === 0) return;
|
|
215
|
+
previousSnapshotRef.current = applyPatchBatchImmutable(previousSnapshot, ops);
|
|
216
|
+
queuePatchOps(ops);
|
|
217
|
+
});
|
|
218
|
+
return () => {
|
|
219
|
+
if (animationFrame !== null) window.cancelAnimationFrame(animationFrame);
|
|
220
|
+
subscription.unsubscribe();
|
|
344
221
|
};
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
$[0] = enabled;
|
|
351
|
-
$[1] = form;
|
|
352
|
-
$[2] = previewRef;
|
|
353
|
-
$[3] = t1;
|
|
354
|
-
$[4] = t2;
|
|
355
|
-
} else {
|
|
356
|
-
t1 = $[3];
|
|
357
|
-
t2 = $[4];
|
|
358
|
-
}
|
|
359
|
-
React.useEffect(t1, t2);
|
|
222
|
+
}, [
|
|
223
|
+
enabled,
|
|
224
|
+
form,
|
|
225
|
+
previewRef
|
|
226
|
+
]);
|
|
360
227
|
return null;
|
|
361
228
|
});
|
|
362
|
-
const AutosaveManager = React.memo(function AutosaveManager$1(
|
|
363
|
-
const $ = c(19);
|
|
364
|
-
const { form, formElementRef, isEditMode, id, enabled, debounce, isDirtyRef, isSubmittingRef, updateMutation, onPreviewRefresh, onPreviewCommit, onSavingChange, onSaved } = t0;
|
|
229
|
+
const AutosaveManager = React.memo(function AutosaveManager$1({ form, formElementRef, isEditMode, id, enabled, debounce, isDirtyRef, isSubmittingRef, updateMutation, onPreviewRefresh, onPreviewCommit, onSavingChange, onSaved }) {
|
|
365
230
|
const { t } = useTranslation();
|
|
366
231
|
const timerRef = React.useRef(null);
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
onPreviewRefresh?.();
|
|
381
|
-
onSaved(/* @__PURE__ */ new Date());
|
|
382
|
-
onSavingChange(false);
|
|
383
|
-
}, () => {
|
|
384
|
-
onSavingChange(false);
|
|
385
|
-
})();
|
|
386
|
-
} catch (t2$1) {
|
|
387
|
-
const error = t2$1;
|
|
232
|
+
const runAutosave = React.useCallback(async () => {
|
|
233
|
+
if (!id || !isDirtyRef.current || isSubmittingRef.current) return;
|
|
234
|
+
try {
|
|
235
|
+
onSavingChange(true);
|
|
236
|
+
await form.handleSubmit(async (data) => {
|
|
237
|
+
const result = await updateMutation.mutateAsync({
|
|
238
|
+
id,
|
|
239
|
+
data
|
|
240
|
+
});
|
|
241
|
+
form.reset(result, { keepTouched: true });
|
|
242
|
+
onPreviewCommit?.(result);
|
|
243
|
+
onPreviewRefresh?.();
|
|
244
|
+
onSaved(/* @__PURE__ */ new Date());
|
|
388
245
|
onSavingChange(false);
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
}
|
|
246
|
+
}, () => {
|
|
247
|
+
onSavingChange(false);
|
|
248
|
+
})();
|
|
249
|
+
} catch (error) {
|
|
250
|
+
onSavingChange(false);
|
|
251
|
+
console.error("Autosave failed:", error);
|
|
252
|
+
toast.error(t("error.autosaveFailed"), { description: error instanceof Error ? error.message : void 0 });
|
|
253
|
+
}
|
|
254
|
+
}, [
|
|
255
|
+
form,
|
|
256
|
+
id,
|
|
257
|
+
isDirtyRef,
|
|
258
|
+
isSubmittingRef,
|
|
259
|
+
onSaved,
|
|
260
|
+
onSavingChange,
|
|
261
|
+
onPreviewCommit,
|
|
262
|
+
onPreviewRefresh,
|
|
263
|
+
t,
|
|
264
|
+
updateMutation
|
|
265
|
+
]);
|
|
266
|
+
React.useEffect(() => {
|
|
267
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
268
|
+
if (!enabled || !isEditMode || !id) return;
|
|
269
|
+
const target = formElementRef.current;
|
|
270
|
+
if (!target) return;
|
|
271
|
+
const scheduleAutosave = () => {
|
|
272
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
273
|
+
timerRef.current = setTimeout(() => {
|
|
274
|
+
runAutosave();
|
|
275
|
+
}, debounce);
|
|
392
276
|
};
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
$[5] = onPreviewRefresh;
|
|
399
|
-
$[6] = onSaved;
|
|
400
|
-
$[7] = onSavingChange;
|
|
401
|
-
$[8] = t;
|
|
402
|
-
$[9] = updateMutation;
|
|
403
|
-
$[10] = t1;
|
|
404
|
-
} else t1 = $[10];
|
|
405
|
-
const runAutosave = t1;
|
|
406
|
-
let t2;
|
|
407
|
-
let t3;
|
|
408
|
-
if ($[11] !== debounce || $[12] !== enabled || $[13] !== formElementRef || $[14] !== id || $[15] !== isEditMode || $[16] !== runAutosave) {
|
|
409
|
-
t2 = () => {
|
|
277
|
+
target.addEventListener("input", scheduleAutosave, { capture: true });
|
|
278
|
+
target.addEventListener("change", scheduleAutosave, { capture: true });
|
|
279
|
+
return () => {
|
|
280
|
+
target.removeEventListener("input", scheduleAutosave, { capture: true });
|
|
281
|
+
target.removeEventListener("change", scheduleAutosave, { capture: true });
|
|
410
282
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
411
|
-
if (!enabled || !isEditMode || !id) return;
|
|
412
|
-
const target = formElementRef.current;
|
|
413
|
-
if (!target) return;
|
|
414
|
-
const scheduleAutosave = () => {
|
|
415
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
416
|
-
timerRef.current = setTimeout(() => {
|
|
417
|
-
runAutosave();
|
|
418
|
-
}, debounce);
|
|
419
|
-
};
|
|
420
|
-
target.addEventListener("input", scheduleAutosave, { capture: true });
|
|
421
|
-
target.addEventListener("change", scheduleAutosave, { capture: true });
|
|
422
|
-
return () => {
|
|
423
|
-
target.removeEventListener("input", scheduleAutosave, { capture: true });
|
|
424
|
-
target.removeEventListener("change", scheduleAutosave, { capture: true });
|
|
425
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
426
|
-
};
|
|
427
283
|
};
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
$[11] = debounce;
|
|
437
|
-
$[12] = enabled;
|
|
438
|
-
$[13] = formElementRef;
|
|
439
|
-
$[14] = id;
|
|
440
|
-
$[15] = isEditMode;
|
|
441
|
-
$[16] = runAutosave;
|
|
442
|
-
$[17] = t2;
|
|
443
|
-
$[18] = t3;
|
|
444
|
-
} else {
|
|
445
|
-
t2 = $[17];
|
|
446
|
-
t3 = $[18];
|
|
447
|
-
}
|
|
448
|
-
React.useEffect(t2, t3);
|
|
284
|
+
}, [
|
|
285
|
+
debounce,
|
|
286
|
+
enabled,
|
|
287
|
+
formElementRef,
|
|
288
|
+
id,
|
|
289
|
+
isEditMode,
|
|
290
|
+
runAutosave
|
|
291
|
+
]);
|
|
449
292
|
return null;
|
|
450
293
|
});
|
|
451
|
-
const AutosaveIndicator = React.memo(function AutosaveIndicator$1(
|
|
452
|
-
const
|
|
453
|
-
const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
} else t1 = $[1];
|
|
460
|
-
const { isDirty } = useFormState(t1);
|
|
461
|
-
const [, forceUpdate] = React.useReducer(_temp2, 0);
|
|
462
|
-
let t2;
|
|
463
|
-
if ($[2] !== forceUpdate || $[3] !== lastSaved) {
|
|
464
|
-
t2 = () => {
|
|
465
|
-
if (!lastSaved) return;
|
|
466
|
-
const interval = setInterval(forceUpdate, 1e4);
|
|
467
|
-
return () => clearInterval(interval);
|
|
468
|
-
};
|
|
469
|
-
$[2] = forceUpdate;
|
|
470
|
-
$[3] = lastSaved;
|
|
471
|
-
$[4] = t2;
|
|
472
|
-
} else t2 = $[4];
|
|
473
|
-
let t3;
|
|
474
|
-
if ($[5] !== lastSaved) {
|
|
475
|
-
t3 = [lastSaved];
|
|
476
|
-
$[5] = lastSaved;
|
|
477
|
-
$[6] = t3;
|
|
478
|
-
} else t3 = $[6];
|
|
479
|
-
React.useEffect(t2, t3);
|
|
294
|
+
const AutosaveIndicator = React.memo(function AutosaveIndicator$1({ control, enabled, indicator, isEditMode, isSaving, lastSaved, formatTimeAgo, t }) {
|
|
295
|
+
const { isDirty } = useFormState({ control });
|
|
296
|
+
const [, forceUpdate] = React.useReducer((x) => x + 1, 0);
|
|
297
|
+
React.useEffect(() => {
|
|
298
|
+
if (!lastSaved) return;
|
|
299
|
+
const interval = setInterval(forceUpdate, 1e4);
|
|
300
|
+
return () => clearInterval(interval);
|
|
301
|
+
}, [lastSaved]);
|
|
480
302
|
if (!enabled || !indicator || !isEditMode) return null;
|
|
481
|
-
if (isSaving) {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
});
|
|
503
|
-
$[10] = t5;
|
|
504
|
-
$[11] = t6;
|
|
505
|
-
} else t6 = $[11];
|
|
506
|
-
return t6;
|
|
507
|
-
}
|
|
508
|
-
if (isDirty) {
|
|
509
|
-
let t4;
|
|
510
|
-
if ($[12] === Symbol.for("react.memo_cache_sentinel")) {
|
|
511
|
-
t4 = /* @__PURE__ */ jsx(Icon, {
|
|
512
|
-
icon: "ph:clock-counter-clockwise",
|
|
513
|
-
className: "size-3"
|
|
514
|
-
});
|
|
515
|
-
$[12] = t4;
|
|
516
|
-
} else t4 = $[12];
|
|
517
|
-
let t5;
|
|
518
|
-
if ($[13] !== t) {
|
|
519
|
-
t5 = t("autosave.unsavedChanges");
|
|
520
|
-
$[13] = t;
|
|
521
|
-
$[14] = t5;
|
|
522
|
-
} else t5 = $[14];
|
|
523
|
-
let t6;
|
|
524
|
-
if ($[15] !== t5) {
|
|
525
|
-
t6 = /* @__PURE__ */ jsxs(Badge, {
|
|
526
|
-
variant: "outline",
|
|
527
|
-
className: "gap-1.5",
|
|
528
|
-
children: [t4, t5]
|
|
529
|
-
});
|
|
530
|
-
$[15] = t5;
|
|
531
|
-
$[16] = t6;
|
|
532
|
-
} else t6 = $[16];
|
|
533
|
-
return t6;
|
|
534
|
-
}
|
|
535
|
-
if (lastSaved) {
|
|
536
|
-
let t4;
|
|
537
|
-
if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
|
|
538
|
-
t4 = /* @__PURE__ */ jsx(Icon, {
|
|
303
|
+
if (isSaving) return /* @__PURE__ */ jsxs(Badge, {
|
|
304
|
+
variant: "secondary",
|
|
305
|
+
className: "gap-1.5",
|
|
306
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
307
|
+
icon: "ph:spinner-gap",
|
|
308
|
+
className: "size-3 animate-spin"
|
|
309
|
+
}), t("autosave.saving")]
|
|
310
|
+
});
|
|
311
|
+
if (isDirty) return /* @__PURE__ */ jsxs(Badge, {
|
|
312
|
+
variant: "outline",
|
|
313
|
+
className: "gap-1.5",
|
|
314
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
315
|
+
icon: "ph:clock-counter-clockwise",
|
|
316
|
+
className: "size-3"
|
|
317
|
+
}), t("autosave.unsavedChanges")]
|
|
318
|
+
});
|
|
319
|
+
if (lastSaved) return /* @__PURE__ */ jsxs(Badge, {
|
|
320
|
+
variant: "secondary",
|
|
321
|
+
className: "text-muted-foreground gap-1.5",
|
|
322
|
+
children: [
|
|
323
|
+
/* @__PURE__ */ jsx(Icon, {
|
|
539
324
|
icon: "ph:check",
|
|
540
325
|
className: "size-3"
|
|
541
|
-
})
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
$[18] = t;
|
|
548
|
-
$[19] = t5;
|
|
549
|
-
} else t5 = $[19];
|
|
550
|
-
let t6;
|
|
551
|
-
if ($[20] !== formatTimeAgo || $[21] !== lastSaved) {
|
|
552
|
-
t6 = formatTimeAgo(lastSaved);
|
|
553
|
-
$[20] = formatTimeAgo;
|
|
554
|
-
$[21] = lastSaved;
|
|
555
|
-
$[22] = t6;
|
|
556
|
-
} else t6 = $[22];
|
|
557
|
-
let t7;
|
|
558
|
-
if ($[23] !== t5 || $[24] !== t6) {
|
|
559
|
-
t7 = /* @__PURE__ */ jsxs(Badge, {
|
|
560
|
-
variant: "secondary",
|
|
561
|
-
className: "text-muted-foreground gap-1.5",
|
|
562
|
-
children: [
|
|
563
|
-
t4,
|
|
564
|
-
t5,
|
|
565
|
-
" ",
|
|
566
|
-
t6
|
|
567
|
-
]
|
|
568
|
-
});
|
|
569
|
-
$[23] = t5;
|
|
570
|
-
$[24] = t6;
|
|
571
|
-
$[25] = t7;
|
|
572
|
-
} else t7 = $[25];
|
|
573
|
-
return t7;
|
|
574
|
-
}
|
|
326
|
+
}),
|
|
327
|
+
t("autosave.saved"),
|
|
328
|
+
" ",
|
|
329
|
+
formatTimeAgo(lastSaved)
|
|
330
|
+
]
|
|
331
|
+
});
|
|
575
332
|
return null;
|
|
576
333
|
});
|
|
577
|
-
const SaveSubmitButton = React.memo(function SaveSubmitButton$1(
|
|
578
|
-
const
|
|
579
|
-
const { control, isMutationPending, t } = t0;
|
|
580
|
-
let t1;
|
|
581
|
-
if ($[0] !== control) {
|
|
582
|
-
t1 = { control };
|
|
583
|
-
$[0] = control;
|
|
584
|
-
$[1] = t1;
|
|
585
|
-
} else t1 = $[1];
|
|
586
|
-
const { isDirty, isSubmitting } = useFormState(t1);
|
|
334
|
+
const SaveSubmitButton = React.memo(function SaveSubmitButton$1({ control, isMutationPending, t }) {
|
|
335
|
+
const { isDirty, isSubmitting } = useFormState({ control });
|
|
587
336
|
const isSubmittingNow = isMutationPending || isSubmitting;
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
337
|
+
return /* @__PURE__ */ jsx(Button, {
|
|
338
|
+
type: "submit",
|
|
339
|
+
size: "sm",
|
|
340
|
+
disabled: isSubmittingNow || !isDirty,
|
|
341
|
+
className: "gap-2",
|
|
342
|
+
children: isSubmittingNow ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Icon, {
|
|
592
343
|
icon: "ph:spinner-gap",
|
|
593
344
|
className: "size-4 animate-spin"
|
|
594
345
|
}), t("common.loading")] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Icon, {
|
|
595
346
|
icon: "ph:check",
|
|
596
347
|
width: 16,
|
|
597
348
|
height: 16
|
|
598
|
-
}), t("common.save")] })
|
|
599
|
-
|
|
600
|
-
$[3] = t;
|
|
601
|
-
$[4] = t3;
|
|
602
|
-
} else t3 = $[4];
|
|
603
|
-
let t4;
|
|
604
|
-
if ($[5] !== t2 || $[6] !== t3) {
|
|
605
|
-
t4 = /* @__PURE__ */ jsx(Button, {
|
|
606
|
-
type: "submit",
|
|
607
|
-
size: "sm",
|
|
608
|
-
disabled: t2,
|
|
609
|
-
className: "gap-2",
|
|
610
|
-
children: t3
|
|
611
|
-
});
|
|
612
|
-
$[5] = t2;
|
|
613
|
-
$[6] = t3;
|
|
614
|
-
$[7] = t4;
|
|
615
|
-
} else t4 = $[7];
|
|
616
|
-
return t4;
|
|
349
|
+
}), t("common.save")] })
|
|
350
|
+
});
|
|
617
351
|
});
|
|
618
352
|
/**
|
|
619
353
|
* FormView - Default form-based edit/create view for collections
|
|
@@ -735,8 +469,8 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
735
469
|
const allowedTransitions = React.useMemo(() => {
|
|
736
470
|
if (!workflowConfig?.stages || !currentStage) return [];
|
|
737
471
|
const stageNames = currentStageConfig?.transitions;
|
|
738
|
-
if (stageNames && stageNames.length > 0) return stageNames.map((name) => workflowConfig.stages.find((
|
|
739
|
-
return workflowConfig.stages.filter((
|
|
472
|
+
if (stageNames && stageNames.length > 0) return stageNames.map((name) => workflowConfig.stages.find((s) => s.name === name)).filter(Boolean);
|
|
473
|
+
return workflowConfig.stages.filter((s) => s.name !== currentStage);
|
|
740
474
|
}, [
|
|
741
475
|
workflowConfig,
|
|
742
476
|
currentStage,
|
|
@@ -760,7 +494,7 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
760
494
|
});
|
|
761
495
|
const commitPreviewSnapshot = React.useCallback((data) => {
|
|
762
496
|
if (!isLivePreviewOpen) return;
|
|
763
|
-
previewRef.current?.sendCommit(
|
|
497
|
+
previewRef.current?.sendCommit(cloneSnapshot(data));
|
|
764
498
|
}, [isLivePreviewOpen]);
|
|
765
499
|
const triggerPreviewFullResync = React.useCallback((reason) => {
|
|
766
500
|
if (!isLivePreviewOpen) return;
|
|
@@ -780,10 +514,10 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
780
514
|
shouldTouch: true,
|
|
781
515
|
shouldValidate: true
|
|
782
516
|
});
|
|
783
|
-
setTimeout(() => scrollFieldIntoView(message.path), 0);
|
|
517
|
+
setTimeout(() => scrollFieldIntoView(message.path, { focus: false }), 0);
|
|
784
518
|
}, [form, schema]);
|
|
785
|
-
const handlePreviewResyncRequest = React.useCallback((
|
|
786
|
-
triggerPreviewFullResync(
|
|
519
|
+
const handlePreviewResyncRequest = React.useCallback((reason) => {
|
|
520
|
+
triggerPreviewFullResync(reason ?? "preview-request");
|
|
787
521
|
}, [triggerPreviewFullResync]);
|
|
788
522
|
/**
|
|
789
523
|
* Execute the confirmed workflow transition (immediate or scheduled).
|
|
@@ -803,10 +537,10 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
803
537
|
setTransitionSchedule(false);
|
|
804
538
|
setTransitionScheduledAt(null);
|
|
805
539
|
};
|
|
806
|
-
transitionMutation.mutateAsync(params).then((
|
|
807
|
-
if (
|
|
808
|
-
if (typeof
|
|
809
|
-
if ("id" in
|
|
540
|
+
transitionMutation.mutateAsync(params).then((result) => {
|
|
541
|
+
if (result) {
|
|
542
|
+
if (typeof result === "object") {
|
|
543
|
+
if ("id" in result) form.reset(result);
|
|
810
544
|
}
|
|
811
545
|
}
|
|
812
546
|
triggerPreviewFullResync("workflow-transition");
|
|
@@ -933,23 +667,23 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
933
667
|
const handleLocaleDialogOpenChange = React.useCallback((open) => {
|
|
934
668
|
if (!open) handleLocaleChangeCancel();
|
|
935
669
|
}, [handleLocaleChangeCancel]);
|
|
936
|
-
const onSubmit = React.useEffectEvent(async (
|
|
670
|
+
const onSubmit = React.useEffectEvent(async (data) => {
|
|
937
671
|
const savePromise = async () => {
|
|
938
672
|
if (isEditMode && id) return await updateMutation.mutateAsync({
|
|
939
673
|
id,
|
|
940
|
-
data
|
|
674
|
+
data
|
|
941
675
|
});
|
|
942
|
-
else return await createMutation.mutateAsync(
|
|
676
|
+
else return await createMutation.mutateAsync(data);
|
|
943
677
|
};
|
|
944
678
|
toast.promise(savePromise(), {
|
|
945
679
|
loading: isEditMode ? t("toast.saving") : t("toast.creating"),
|
|
946
|
-
success: (
|
|
947
|
-
if (onSuccess) onSuccess(
|
|
680
|
+
success: (result) => {
|
|
681
|
+
if (onSuccess) onSuccess(result);
|
|
948
682
|
else if (isEditMode) {
|
|
949
|
-
form.reset(
|
|
950
|
-
commitPreviewSnapshot(
|
|
683
|
+
form.reset(result);
|
|
684
|
+
commitPreviewSnapshot(result);
|
|
951
685
|
triggerPreviewRefresh();
|
|
952
|
-
} else if (
|
|
686
|
+
} else if (result?.id) navigate(`${basePath}/collections/${collection}/${result.id}`);
|
|
953
687
|
else navigate(`${basePath}/collections/${collection}`);
|
|
954
688
|
return isEditMode ? t("toast.saveSuccess") : t("toast.createSuccess");
|
|
955
689
|
},
|
|
@@ -961,9 +695,9 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
961
695
|
});
|
|
962
696
|
return t("toast.validationFailed");
|
|
963
697
|
}
|
|
964
|
-
const
|
|
965
|
-
onError?.(error instanceof Error ? error : new Error(
|
|
966
|
-
return `${t("toast.saveFailed")}: ${
|
|
698
|
+
const message = error instanceof Error ? error.message : t("error.unknown");
|
|
699
|
+
onError?.(error instanceof Error ? error : new Error(message));
|
|
700
|
+
return `${t("toast.saveFailed")}: ${message}`;
|
|
967
701
|
}
|
|
968
702
|
});
|
|
969
703
|
});
|
|
@@ -983,13 +717,13 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
983
717
|
onSubmitRef.current = onSubmit;
|
|
984
718
|
});
|
|
985
719
|
React.useEffect(() => {
|
|
986
|
-
const handleKeyDown = (
|
|
987
|
-
if (shouldHandleAdminShortcut(
|
|
720
|
+
const handleKeyDown = (e) => {
|
|
721
|
+
if (shouldHandleAdminShortcut(e, {
|
|
988
722
|
allowEditableTarget: true,
|
|
989
723
|
key: "s"
|
|
990
724
|
})) {
|
|
991
|
-
|
|
992
|
-
|
|
725
|
+
e.preventDefault();
|
|
726
|
+
e.stopPropagation();
|
|
993
727
|
form.handleSubmit(onSubmitRef.current, (errors) => {
|
|
994
728
|
console.warn("[FormView] Validation errors:", errors);
|
|
995
729
|
toast.error(t("toast.validationFailed"));
|
|
@@ -1017,10 +751,10 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1017
751
|
const primary = [...base.primary ?? []];
|
|
1018
752
|
const secondary = [...base.secondary ?? []];
|
|
1019
753
|
const existingIds = new Set([...primary, ...secondary].map((a) => a.id));
|
|
1020
|
-
for (const
|
|
1021
|
-
if (existingIds.has(
|
|
1022
|
-
secondary.push(
|
|
1023
|
-
existingIds.add(
|
|
754
|
+
for (const action of scopedServerFormActions) {
|
|
755
|
+
if (existingIds.has(action.id)) continue;
|
|
756
|
+
secondary.push(action);
|
|
757
|
+
existingIds.add(action.id);
|
|
1024
758
|
}
|
|
1025
759
|
return {
|
|
1026
760
|
primary,
|
|
@@ -1044,8 +778,8 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1044
778
|
}), [client, contentLocale]);
|
|
1045
779
|
const actionQueryClient = React.useMemo(() => ({
|
|
1046
780
|
invalidateQueries: (filters) => queryClient.invalidateQueries(filters),
|
|
1047
|
-
refetchQueries: (
|
|
1048
|
-
resetQueries: (
|
|
781
|
+
refetchQueries: (filters) => queryClient.refetchQueries(filters),
|
|
782
|
+
resetQueries: (filters) => queryClient.resetQueries(filters)
|
|
1049
783
|
}), [queryClient]);
|
|
1050
784
|
const actionHelpers = React.useMemo(() => ({
|
|
1051
785
|
navigate: storeNavigate,
|
|
@@ -1071,18 +805,18 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1071
805
|
contentLocale
|
|
1072
806
|
]) });
|
|
1073
807
|
},
|
|
1074
|
-
invalidateItem: async (itemId,
|
|
1075
|
-
const
|
|
808
|
+
invalidateItem: async (itemId, targetCollection) => {
|
|
809
|
+
const col = targetCollection || collection;
|
|
1076
810
|
await queryClient.invalidateQueries({ queryKey: queryOpts.key([
|
|
1077
811
|
"collections",
|
|
1078
|
-
|
|
812
|
+
col,
|
|
1079
813
|
"findOne",
|
|
1080
814
|
contentLocale,
|
|
1081
815
|
{ id: itemId }
|
|
1082
816
|
]) });
|
|
1083
817
|
await queryClient.invalidateQueries({ queryKey: queryOpts.key([
|
|
1084
818
|
"collections",
|
|
1085
|
-
|
|
819
|
+
col,
|
|
1086
820
|
"find",
|
|
1087
821
|
contentLocale
|
|
1088
822
|
]) });
|
|
@@ -1135,48 +869,48 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1135
869
|
]);
|
|
1136
870
|
const filterVisibleActions = React.useCallback((actions) => {
|
|
1137
871
|
if (!actions) return [];
|
|
1138
|
-
return actions.filter((
|
|
1139
|
-
if (
|
|
1140
|
-
if (typeof
|
|
1141
|
-
return
|
|
872
|
+
return actions.filter((action) => {
|
|
873
|
+
if (action.visible === void 0) return true;
|
|
874
|
+
if (typeof action.visible === "function") return action.visible(actionContext);
|
|
875
|
+
return action.visible;
|
|
1142
876
|
});
|
|
1143
877
|
}, [actionContext]);
|
|
1144
878
|
const visiblePrimaryActions = React.useMemo(() => filterVisibleActions(formActions.primary), [formActions.primary, filterVisibleActions]);
|
|
1145
879
|
const visibleSecondaryActions = React.useMemo(() => filterVisibleActions(formActions.secondary), [formActions.secondary, filterVisibleActions]);
|
|
1146
|
-
const regularSecondary = visibleSecondaryActions.filter((
|
|
1147
|
-
const destructiveSecondary = visibleSecondaryActions.filter((
|
|
1148
|
-
const executeAction = async (
|
|
1149
|
-
const { handler } =
|
|
1150
|
-
const actionLabel = resolveText(
|
|
880
|
+
const regularSecondary = visibleSecondaryActions.filter((a) => a.variant !== "destructive");
|
|
881
|
+
const destructiveSecondary = visibleSecondaryActions.filter((a) => a.variant === "destructive");
|
|
882
|
+
const executeAction = async (action) => {
|
|
883
|
+
const { handler } = action;
|
|
884
|
+
const actionLabel = resolveText(action.label, action.id);
|
|
1151
885
|
switch (handler.type) {
|
|
1152
886
|
case "navigate":
|
|
1153
887
|
storeNavigate(typeof handler.path === "function" ? handler.path(transformedItem) : handler.path);
|
|
1154
888
|
break;
|
|
1155
889
|
case "api":
|
|
1156
890
|
if (handler.method === "POST" && handler.endpoint === "{id}/restore") {
|
|
1157
|
-
const
|
|
1158
|
-
if (!
|
|
891
|
+
const itemId = transformedItem?.id || id;
|
|
892
|
+
if (!itemId) {
|
|
1159
893
|
toast.error(t("collection.restoreError"));
|
|
1160
894
|
break;
|
|
1161
895
|
}
|
|
1162
896
|
setActionLoading(true);
|
|
1163
|
-
toast.promise(restoreMutation.mutateAsync({ id:
|
|
897
|
+
toast.promise(restoreMutation.mutateAsync({ id: itemId }).finally(() => {
|
|
1164
898
|
setActionLoading(false);
|
|
1165
899
|
}), {
|
|
1166
900
|
loading: t("collection.restoring"),
|
|
1167
901
|
success: t("collection.restoreSuccess"),
|
|
1168
|
-
error: (
|
|
902
|
+
error: (err) => err.message || t("collection.restoreError")
|
|
1169
903
|
});
|
|
1170
904
|
break;
|
|
1171
905
|
}
|
|
1172
906
|
if (handler.method === "DELETE") {
|
|
1173
|
-
const
|
|
1174
|
-
if (!
|
|
907
|
+
const itemId = transformedItem?.id || id;
|
|
908
|
+
if (!itemId) {
|
|
1175
909
|
toast.error(t("toast.deleteFailed"));
|
|
1176
910
|
break;
|
|
1177
911
|
}
|
|
1178
912
|
setActionLoading(true);
|
|
1179
|
-
toast.promise(deleteMutation.mutateAsync({ id:
|
|
913
|
+
toast.promise(deleteMutation.mutateAsync({ id: itemId }).finally(() => {
|
|
1180
914
|
setActionLoading(false);
|
|
1181
915
|
}), {
|
|
1182
916
|
loading: t("toast.deleting"),
|
|
@@ -1184,7 +918,7 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1184
918
|
storeNavigate(`${storeBasePath || basePath}/collections/${collection}`);
|
|
1185
919
|
return t("toast.deleteSuccess");
|
|
1186
920
|
},
|
|
1187
|
-
error: (
|
|
921
|
+
error: (err) => err.message || t("toast.deleteFailed")
|
|
1188
922
|
});
|
|
1189
923
|
} else {
|
|
1190
924
|
let itemId_;
|
|
@@ -1197,15 +931,15 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1197
931
|
setActionLoading(true);
|
|
1198
932
|
const apiPromise = async () => {
|
|
1199
933
|
const url = `${storeBasePath}/${collection}/${endpoint}`;
|
|
1200
|
-
const
|
|
934
|
+
const response = await fetch(url, {
|
|
1201
935
|
method,
|
|
1202
936
|
headers: { "Content-Type": "application/json" },
|
|
1203
937
|
body
|
|
1204
938
|
});
|
|
1205
|
-
if (!
|
|
939
|
+
if (!response.ok) {
|
|
1206
940
|
let errorBody = {};
|
|
1207
941
|
try {
|
|
1208
|
-
errorBody = await
|
|
942
|
+
errorBody = await response.json();
|
|
1209
943
|
} catch {}
|
|
1210
944
|
let errorMessage;
|
|
1211
945
|
if (errorBody.message) if (typeof errorBody.message === "string") errorMessage = errorBody.message;
|
|
@@ -1213,15 +947,15 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1213
947
|
else errorMessage = t("toast.actionFailed");
|
|
1214
948
|
throw new Error(errorMessage);
|
|
1215
949
|
}
|
|
1216
|
-
return
|
|
950
|
+
return response.json();
|
|
1217
951
|
};
|
|
1218
952
|
const p = apiPromise();
|
|
1219
953
|
p.then(() => setActionLoading(false), () => setActionLoading(false));
|
|
1220
954
|
toast.promise(p, {
|
|
1221
955
|
loading: `${actionLabel}...`,
|
|
1222
956
|
success: t("toast.actionSuccess"),
|
|
1223
|
-
error: (
|
|
1224
|
-
if (
|
|
957
|
+
error: (err) => {
|
|
958
|
+
if (err.message) return err.message;
|
|
1225
959
|
return t("toast.actionFailed");
|
|
1226
960
|
}
|
|
1227
961
|
});
|
|
@@ -1234,7 +968,7 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1234
968
|
toast.promise(customPromise.finally(() => setActionLoading(false)), {
|
|
1235
969
|
loading: `${actionLabel}...`,
|
|
1236
970
|
success: t("toast.actionSuccess"),
|
|
1237
|
-
error: (
|
|
971
|
+
error: (err) => err.message || t("toast.actionFailed")
|
|
1238
972
|
});
|
|
1239
973
|
}
|
|
1240
974
|
break;
|
|
@@ -1251,17 +985,17 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1251
985
|
itemId: transformedItem?.id || id
|
|
1252
986
|
});
|
|
1253
987
|
if (!response?.success || response.result?.type === "error") throw new Error(response?.error ?? response?.result?.toast?.message ?? t("error.serverActionFailed"));
|
|
1254
|
-
const
|
|
1255
|
-
if (
|
|
988
|
+
const result = response.result;
|
|
989
|
+
if (result?.toast?.message) toast.success(result.toast.message);
|
|
1256
990
|
else toast.success(t("toast.actionSuccess"));
|
|
1257
|
-
if (
|
|
1258
|
-
else if (Array.isArray(
|
|
1259
|
-
if (
|
|
1260
|
-
if (
|
|
1261
|
-
else storeNavigate(
|
|
1262
|
-
if (
|
|
1263
|
-
} catch (
|
|
1264
|
-
toast.error(
|
|
991
|
+
if (result?.effects?.invalidate === true) await actionHelpers.invalidateAll();
|
|
992
|
+
else if (Array.isArray(result?.effects?.invalidate)) for (const col of result.effects.invalidate) await actionHelpers.invalidateCollection(col);
|
|
993
|
+
if (result?.effects?.redirect) storeNavigate(result.effects.redirect);
|
|
994
|
+
if (result?.type === "redirect" && result.url) if (result.external) window.open(result.url, "_blank");
|
|
995
|
+
else storeNavigate(result.url);
|
|
996
|
+
if (result?.effects?.closeModal) actionHelpers.closeDialog();
|
|
997
|
+
} catch (error) {
|
|
998
|
+
toast.error(error instanceof Error ? error.message : t("error.actionFailed"));
|
|
1265
999
|
} finally {
|
|
1266
1000
|
setActionLoading(false);
|
|
1267
1001
|
}
|
|
@@ -1278,31 +1012,31 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1278
1012
|
const payload = { id };
|
|
1279
1013
|
if (typeof pendingRevertVersion.versionId === "string") payload.versionId = pendingRevertVersion.versionId;
|
|
1280
1014
|
else if (typeof pendingRevertVersion.versionNumber === "number") payload.version = pendingRevertVersion.versionNumber;
|
|
1281
|
-
const
|
|
1282
|
-
form.reset(
|
|
1015
|
+
const result = await revertVersionMutation.mutateAsync(payload);
|
|
1016
|
+
form.reset(result);
|
|
1283
1017
|
triggerPreviewFullResync("version-revert");
|
|
1284
1018
|
toast.success(t("version.revertSuccess"));
|
|
1285
1019
|
setPendingRevertVersion(null);
|
|
1286
1020
|
};
|
|
1287
|
-
const handleActionClick = (
|
|
1288
|
-
if (
|
|
1289
|
-
else if (
|
|
1290
|
-
else executeAction(
|
|
1021
|
+
const handleActionClick = (action) => {
|
|
1022
|
+
if (action.confirmation) setConfirmAction(action);
|
|
1023
|
+
else if (action.handler.type === "dialog" || action.handler.type === "form") setDialogAction(action);
|
|
1024
|
+
else executeAction(action);
|
|
1291
1025
|
};
|
|
1292
1026
|
const handleConfirm = async () => {
|
|
1293
1027
|
if (confirmAction) await executeAction(confirmAction);
|
|
1294
1028
|
};
|
|
1295
|
-
const handleConfirmActionOpenChange = React.useCallback((
|
|
1296
|
-
if (!
|
|
1029
|
+
const handleConfirmActionOpenChange = React.useCallback((open) => {
|
|
1030
|
+
if (!open) setConfirmAction(null);
|
|
1297
1031
|
}, []);
|
|
1298
|
-
const handleActionDialogOpenChange = React.useCallback((
|
|
1299
|
-
if (!
|
|
1032
|
+
const handleActionDialogOpenChange = React.useCallback((open) => {
|
|
1033
|
+
if (!open) setDialogAction(null);
|
|
1300
1034
|
}, []);
|
|
1301
|
-
const handleRevertDialogOpenChange = React.useCallback((
|
|
1302
|
-
if (!
|
|
1035
|
+
const handleRevertDialogOpenChange = React.useCallback((open) => {
|
|
1036
|
+
if (!open) setPendingRevertVersion(null);
|
|
1303
1037
|
}, []);
|
|
1304
|
-
const handleWorkflowDialogOpenChange = React.useCallback((
|
|
1305
|
-
if (!
|
|
1038
|
+
const handleWorkflowDialogOpenChange = React.useCallback((open) => {
|
|
1039
|
+
if (!open) {
|
|
1306
1040
|
setTransitionTarget(null);
|
|
1307
1041
|
setTransitionSchedule(false);
|
|
1308
1042
|
setTransitionScheduledAt(null);
|
|
@@ -1327,8 +1061,8 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1327
1061
|
minute: "2-digit"
|
|
1328
1062
|
});
|
|
1329
1063
|
};
|
|
1330
|
-
const formatTimeAgo = (
|
|
1331
|
-
const seconds = Math.floor((Date.now() -
|
|
1064
|
+
const formatTimeAgo = (date) => {
|
|
1065
|
+
const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
|
|
1332
1066
|
if (seconds < 10) return t("autosave.justNow");
|
|
1333
1067
|
if (seconds < 60) return t("autosave.secondsAgo", { count: seconds });
|
|
1334
1068
|
const minutes = Math.floor(seconds / 60);
|
|
@@ -1350,7 +1084,7 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1350
1084
|
for (const event of events) target.addEventListener(event, scheduleLockRefresh, { capture: true });
|
|
1351
1085
|
scheduleLockRefresh();
|
|
1352
1086
|
return () => {
|
|
1353
|
-
for (const
|
|
1087
|
+
for (const event of events) target.removeEventListener(event, scheduleLockRefresh, { capture: true });
|
|
1354
1088
|
if (lockRefreshTimerRef.current) clearTimeout(lockRefreshTimerRef.current);
|
|
1355
1089
|
};
|
|
1356
1090
|
}, [
|
|
@@ -1490,17 +1224,17 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1490
1224
|
minDurationMs: 12,
|
|
1491
1225
|
children: /* @__PURE__ */ jsxs("form", {
|
|
1492
1226
|
ref: formElementRef,
|
|
1493
|
-
onSubmit: (
|
|
1494
|
-
|
|
1227
|
+
onSubmit: (e) => {
|
|
1228
|
+
e.stopPropagation();
|
|
1495
1229
|
if (isBlocked) {
|
|
1496
|
-
|
|
1230
|
+
e.preventDefault();
|
|
1497
1231
|
toast.error(t("lock.cannotSave"));
|
|
1498
1232
|
return;
|
|
1499
1233
|
}
|
|
1500
|
-
form.handleSubmit(onSubmit, (
|
|
1501
|
-
console.warn("[FormView] Validation errors:",
|
|
1234
|
+
form.handleSubmit(onSubmit, (errors) => {
|
|
1235
|
+
console.warn("[FormView] Validation errors:", errors);
|
|
1502
1236
|
toast.error(t("toast.validationFailed"), { description: t("toast.validationDescription") });
|
|
1503
|
-
})(
|
|
1237
|
+
})(e);
|
|
1504
1238
|
},
|
|
1505
1239
|
className: "qa-form-view__form space-y-4",
|
|
1506
1240
|
children: [
|
|
@@ -1610,13 +1344,13 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1610
1344
|
}), stage.label || stage.name]
|
|
1611
1345
|
}, stage.name))
|
|
1612
1346
|
})] }),
|
|
1613
|
-
visiblePrimaryActions.map((
|
|
1614
|
-
action
|
|
1347
|
+
visiblePrimaryActions.map((action) => /* @__PURE__ */ jsx(ActionButton, {
|
|
1348
|
+
action,
|
|
1615
1349
|
collection,
|
|
1616
1350
|
helpers: actionHelpers,
|
|
1617
1351
|
size: "sm",
|
|
1618
|
-
onOpenDialog: (
|
|
1619
|
-
},
|
|
1352
|
+
onOpenDialog: (a) => setDialogAction(a)
|
|
1353
|
+
}, action.id)),
|
|
1620
1354
|
/* @__PURE__ */ jsx(SaveSubmitButton, {
|
|
1621
1355
|
control: form.control,
|
|
1622
1356
|
isMutationPending,
|
|
@@ -1634,21 +1368,21 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1634
1368
|
}), /* @__PURE__ */ jsxs(DropdownMenuContent, {
|
|
1635
1369
|
align: "end",
|
|
1636
1370
|
children: [
|
|
1637
|
-
regularSecondary.map((
|
|
1371
|
+
regularSecondary.map((action) => {
|
|
1638
1372
|
return /* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
1639
|
-
onClick: () => handleActionClick(
|
|
1373
|
+
onClick: () => handleActionClick(action),
|
|
1640
1374
|
disabled: actionLoading,
|
|
1641
|
-
children: [resolveIconElement(
|
|
1642
|
-
},
|
|
1375
|
+
children: [resolveIconElement(action.icon, { className: "mr-2 size-4" }), resolveText(action.label)]
|
|
1376
|
+
}, action.id);
|
|
1643
1377
|
}),
|
|
1644
1378
|
regularSecondary.length > 0 && destructiveSecondary.length > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
1645
|
-
destructiveSecondary.map((
|
|
1379
|
+
destructiveSecondary.map((action) => {
|
|
1646
1380
|
return /* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
1647
1381
|
variant: "destructive",
|
|
1648
|
-
onClick: () => handleActionClick(
|
|
1382
|
+
onClick: () => handleActionClick(action),
|
|
1649
1383
|
disabled: actionLoading,
|
|
1650
|
-
children: [resolveIconElement(
|
|
1651
|
-
},
|
|
1384
|
+
children: [resolveIconElement(action.icon, { className: "mr-2 size-4" }), resolveText(action.label)]
|
|
1385
|
+
}, action.id);
|
|
1652
1386
|
})
|
|
1653
1387
|
]
|
|
1654
1388
|
})] })
|
|
@@ -1719,8 +1453,8 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1719
1453
|
fields: schema?.fields,
|
|
1720
1454
|
isLoadingVersions: versionsLoading,
|
|
1721
1455
|
isReverting: revertVersionMutation.isPending,
|
|
1722
|
-
onRevert: async (
|
|
1723
|
-
handleRevertVersion(
|
|
1456
|
+
onRevert: async (version) => {
|
|
1457
|
+
handleRevertVersion(version);
|
|
1724
1458
|
},
|
|
1725
1459
|
showVersionsTab: !!schema?.options?.versioning
|
|
1726
1460
|
}),
|
|
@@ -1822,12 +1556,6 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
|
|
|
1822
1556
|
children: formShell
|
|
1823
1557
|
});
|
|
1824
1558
|
}
|
|
1825
|
-
function _temp(op) {
|
|
1826
|
-
return op.path;
|
|
1827
|
-
}
|
|
1828
|
-
function _temp2(x) {
|
|
1829
|
-
return x + 1;
|
|
1830
|
-
}
|
|
1831
1559
|
|
|
1832
1560
|
//#endregion
|
|
1833
1561
|
export { FormView as default };
|