@questpie/admin 3.5.2 → 3.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/README.md +8 -0
  2. package/dist/client/blocks/block-renderer.d.mts +2 -2
  3. package/dist/client/builder/index.d.mts +1 -1
  4. package/dist/client/builder/types/collection-types.d.mts +89 -5
  5. package/dist/client/builder/types/common.d.mts +5 -0
  6. package/dist/client/builder/types/field-types.d.mts +41 -1
  7. package/dist/client/builder/view/view.d.mts +3 -2
  8. package/dist/client/components/actions/action-dialog.mjs +5 -0
  9. package/dist/client/components/admin-link.d.mts +2 -2
  10. package/dist/client/components/fields/boolean-field.mjs +2 -1
  11. package/dist/client/components/fields/date-field.mjs +2 -1
  12. package/dist/client/components/fields/datetime-field.mjs +2 -1
  13. package/dist/client/components/fields/email-field.mjs +2 -1
  14. package/dist/client/components/fields/field-utils.d.mts +11 -0
  15. package/dist/client/components/fields/field-utils.mjs +3 -1
  16. package/dist/client/components/fields/field-wrapper.mjs +3 -3
  17. package/dist/client/components/fields/number-field.mjs +2 -1
  18. package/dist/client/components/fields/object-field.mjs +2 -1
  19. package/dist/client/components/fields/relation/displays/types.mjs +3 -3
  20. package/dist/client/components/fields/rich-text-editor/bubble-menu.mjs +7 -0
  21. package/dist/client/components/fields/rich-text-editor/extensions.mjs +19 -2
  22. package/dist/client/components/fields/rich-text-editor/image-popover.mjs +6 -2
  23. package/dist/client/components/fields/rich-text-editor/image-upload.mjs +2 -1
  24. package/dist/client/components/fields/rich-text-editor/index.d.mts +5 -3
  25. package/dist/client/components/fields/rich-text-editor/index.mjs +38 -76
  26. package/dist/client/components/fields/rich-text-editor/slash-commands.mjs +30 -7
  27. package/dist/client/components/fields/rich-text-editor/toolbar.mjs +1 -312
  28. package/dist/client/components/fields/rich-text-editor/types.d.mts +4 -0
  29. package/dist/client/components/fields/rich-text-editor/types.mjs +1 -1
  30. package/dist/client/components/fields/rich-text-editor/utils.mjs +6 -12
  31. package/dist/client/components/fields/select-field.mjs +2 -1
  32. package/dist/client/components/fields/text-field.mjs +2 -1
  33. package/dist/client/components/fields/textarea-field.mjs +2 -1
  34. package/dist/client/components/fields/time-field.mjs +2 -1
  35. package/dist/client/components/filter-builder/filter-builder-sheet.mjs +75 -22
  36. package/dist/client/components/layout/field-layout-renderer.mjs +4 -4
  37. package/dist/client/components/media/media-grid.mjs +2 -1
  38. package/dist/client/components/primitives/asset-preview.mjs +4 -2
  39. package/dist/client/components/primitives/dropzone.d.mts +100 -0
  40. package/dist/client/components/primitives/field-select-control.mjs +2 -1
  41. package/dist/client/components/ui/button.d.mts +23 -0
  42. package/dist/client/components/ui/button.mjs +2 -2
  43. package/dist/client/components/ui/dropdown-menu.d.mts +49 -0
  44. package/dist/client/components/ui/dropdown-menu.mjs +7 -19
  45. package/dist/client/components/ui/popover.mjs +1 -1
  46. package/dist/client/components/ui/search-input.d.mts +56 -0
  47. package/dist/client/components/ui/select.mjs +2 -2
  48. package/dist/client/components/ui/sheet.d.mts +40 -0
  49. package/dist/client/components/ui/table.d.mts +49 -0
  50. package/dist/client/components/ui/table.mjs +15 -1
  51. package/dist/client/components/ui/tooltip.d.mts +21 -0
  52. package/dist/client/contexts/focus-context.d.mts +2 -2
  53. package/dist/client/hooks/query-access.d.mts +9 -0
  54. package/dist/client/hooks/query-access.mjs +20 -0
  55. package/dist/client/hooks/typed-hooks.d.mts +4 -2
  56. package/dist/client/hooks/typed-hooks.mjs +30 -29
  57. package/dist/client/hooks/use-admin-config.mjs +20 -1
  58. package/dist/client/hooks/use-autosave.mjs +91 -0
  59. package/dist/client/hooks/use-collection.mjs +65 -23
  60. package/dist/client/hooks/use-reactive-fields.d.mts +1 -0
  61. package/dist/client/hooks/use-reactive-fields.mjs +16 -1
  62. package/dist/client/hooks/use-server-actions.mjs +12 -1
  63. package/dist/client/hooks/use-upload.d.mts +40 -0
  64. package/dist/client/hooks/use-upload.mjs +4 -2
  65. package/dist/client/hooks/use-view-state.mjs +15 -7
  66. package/dist/client/i18n/hooks.d.mts +20 -0
  67. package/dist/client/lib/utils.d.mts +6 -0
  68. package/dist/client/lib/view-filter-utils.mjs +30 -0
  69. package/dist/client/preview/block-scope-context.d.mts +2 -2
  70. package/dist/client/preview/preview-banner.d.mts +2 -2
  71. package/dist/client/preview/preview-field.d.mts +4 -4
  72. package/dist/client/runtime/provider.mjs +22 -3
  73. package/dist/client/scope/picker.d.mts +2 -2
  74. package/dist/client/scope/provider.d.mts +2 -2
  75. package/dist/client/styles/base.css +75 -79
  76. package/dist/client/utils/asset-url.mjs +27 -0
  77. package/dist/client/utils/build-field-definitions-from-schema.mjs +1 -0
  78. package/dist/client/views/auth/accept-invite-form.d.mts +2 -2
  79. package/dist/client/views/auth/auth-layout.d.mts +3 -3
  80. package/dist/client/views/auth/forgot-password-form.d.mts +2 -2
  81. package/dist/client/views/auth/login-form.d.mts +2 -2
  82. package/dist/client/views/auth/reset-password-form.d.mts +2 -2
  83. package/dist/client/views/auth/setup-form.d.mts +2 -2
  84. package/dist/client/views/collection/auto-form-fields.mjs +7 -6
  85. package/dist/client/views/collection/cells/primitive-cells.mjs +9 -6
  86. package/dist/client/views/collection/cells/shared/asset-thumbnail.d.mts +7 -0
  87. package/dist/client/views/collection/cells/shared/asset-thumbnail.mjs +3 -2
  88. package/dist/client/views/collection/cells/shared/cell-helpers.mjs +3 -2
  89. package/dist/client/views/collection/cells/upload-cells.mjs +2 -1
  90. package/dist/client/views/collection/columns/build-columns.mjs +3 -1
  91. package/dist/client/views/collection/document-view.d.mts +30 -0
  92. package/dist/client/views/collection/document-view.mjs +377 -0
  93. package/dist/client/views/collection/field-context.mjs +3 -2
  94. package/dist/client/views/collection/field-renderer.mjs +13 -5
  95. package/dist/client/views/collection/form-view.mjs +221 -282
  96. package/dist/client/views/collection/list-view.mjs +592 -190
  97. package/dist/client/views/collection/outline.mjs +44 -19
  98. package/dist/client/views/collection/quick-filter-bar.mjs +45 -0
  99. package/dist/client/views/collection/table-view.mjs +61 -17
  100. package/dist/client/views/globals/global-form-view.mjs +12 -9
  101. package/dist/client/views/layout/admin-layout-provider.mjs +4 -3
  102. package/dist/client/views/layout/admin-layout.mjs +108 -21
  103. package/dist/client/views/layout/admin-router.mjs +19 -3
  104. package/dist/client/views/layout/admin-sidebar.mjs +70 -20
  105. package/dist/client/views/layout/admin-theme.mjs +5 -4
  106. package/dist/client/views/layout/admin-view-layout.d.mts +36 -0
  107. package/dist/client/views/pages/accept-invite-page.d.mts +2 -2
  108. package/dist/client/views/pages/dashboard-page.d.mts +2 -2
  109. package/dist/client/views/pages/forgot-password-page.d.mts +2 -2
  110. package/dist/client/views/pages/invite-page.d.mts +2 -2
  111. package/dist/client/views/pages/login-page.d.mts +2 -2
  112. package/dist/client/views/pages/reset-password-page.d.mts +2 -2
  113. package/dist/client/views/pages/setup-page.d.mts +2 -2
  114. package/dist/client.d.mts +17 -2
  115. package/dist/client.mjs +17 -2
  116. package/dist/components/rich-text/rich-text-renderer.d.mts +5 -5
  117. package/dist/components/rich-text/rich-text-renderer.mjs +5 -2
  118. package/dist/factories.d.mts +4 -2
  119. package/dist/factories.mjs +2 -2
  120. package/dist/index.d.mts +17 -3
  121. package/dist/index.mjs +17 -2
  122. package/dist/modules/admin.d.mts +1 -1
  123. package/dist/server/adapters/index.d.mts +2 -0
  124. package/dist/server/adapters/nextjs.d.mts +1 -0
  125. package/dist/server/augmentation/actions.d.mts +9 -3
  126. package/dist/server/augmentation/dashboard.d.mts +11 -11
  127. package/dist/server/augmentation/form-layout.d.mts +16 -6
  128. package/dist/server/augmentation/index.d.mts +7 -0
  129. package/dist/server/augmentation/sidebar.d.mts +8 -8
  130. package/dist/server/augmentation/views.d.mts +4 -1
  131. package/dist/server/auth-helpers.d.mts +1 -0
  132. package/dist/server/codegen/admin-client-template.mjs +7 -6
  133. package/dist/server/fields/blocks.mjs +4 -1
  134. package/dist/server/fields/index.d.mts +1 -1
  135. package/dist/server/fields/reactive-runtime.mjs +3 -0
  136. package/dist/server/fields/rich-text.d.mts +16 -17
  137. package/dist/server/fields/rich-text.mjs +18 -7
  138. package/dist/server/i18n/messages/cs.mjs +2 -0
  139. package/dist/server/i18n/messages/de.mjs +2 -0
  140. package/dist/server/i18n/messages/en.mjs +4 -0
  141. package/dist/server/i18n/messages/es.mjs +2 -0
  142. package/dist/server/i18n/messages/fr.mjs +2 -0
  143. package/dist/server/i18n/messages/pl.mjs +2 -0
  144. package/dist/server/i18n/messages/pt.mjs +2 -0
  145. package/dist/server/i18n/messages/sk.mjs +2 -0
  146. package/dist/server/modules/admin/.generated/module.d.mts +1 -1
  147. package/dist/server/modules/admin/auth-helpers.mjs +7 -1
  148. package/dist/server/modules/admin/block/block-builder.d.mts +0 -8
  149. package/dist/server/modules/admin/block/introspection.d.mts +2 -2
  150. package/dist/server/modules/admin/block/introspection.mjs +28 -4
  151. package/dist/server/modules/admin/block/prefetch.d.mts +11 -0
  152. package/dist/server/modules/admin/block/prefetch.mjs +108 -27
  153. package/dist/server/modules/admin/client/.generated/module.d.mts +68 -67
  154. package/dist/server/modules/admin/client/.generated/module.mjs +2 -0
  155. package/dist/server/modules/admin/client/views/collection-document.d.mts +6 -0
  156. package/dist/server/modules/admin/client/views/collection-document.mjs +10 -0
  157. package/dist/server/modules/admin/collections/account.d.mts +53 -52
  158. package/dist/server/modules/admin/collections/admin-locks.d.mts +57 -56
  159. package/dist/server/modules/admin/collections/admin-preferences.d.mts +38 -37
  160. package/dist/server/modules/admin/collections/admin-saved-views.d.mts +50 -49
  161. package/dist/server/modules/admin/collections/apikey.d.mts +76 -67
  162. package/dist/server/modules/admin/collections/assets.d.mts +37 -36
  163. package/dist/server/modules/admin/collections/session.d.mts +42 -41
  164. package/dist/server/modules/admin/collections/user.d.mts +57 -56
  165. package/dist/server/modules/admin/collections/verification.d.mts +34 -33
  166. package/dist/server/modules/admin/dto/admin-config.dto.mjs +34 -4
  167. package/dist/server/modules/admin/factories.mjs +4 -34
  168. package/dist/server/modules/admin/index.d.mts +3 -3
  169. package/dist/server/modules/admin/routes/admin-config.d.mts +4 -2
  170. package/dist/server/modules/admin/routes/admin-config.mjs +56 -24
  171. package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
  172. package/dist/server/modules/admin/routes/execute-action.mjs +35 -9
  173. package/dist/server/modules/admin/routes/locales.mjs +1 -1
  174. package/dist/server/modules/admin/routes/preview.d.mts +11 -11
  175. package/dist/server/modules/admin/routes/preview.mjs +6 -5
  176. package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
  177. package/dist/server/modules/admin/routes/reactive.mjs +2 -2
  178. package/dist/server/modules/admin/routes/route-helpers.d.mts +11 -7
  179. package/dist/server/modules/admin/routes/route-helpers.mjs +1 -1
  180. package/dist/server/modules/admin/routes/setup.d.mts +7 -7
  181. package/dist/server/modules/admin/routes/translations.d.mts +4 -4
  182. package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
  183. package/dist/server/modules/admin/routes/widget-data.mjs +12 -4
  184. package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +45 -45
  185. package/dist/server/modules/audit/.generated/module.d.mts +6 -6
  186. package/dist/server/modules/audit/collections/audit-log.d.mts +81 -80
  187. package/dist/server/modules/audit/jobs/audit-cleanup.d.mts +2 -2
  188. package/dist/server/plugin.mjs +10 -5
  189. package/dist/server/proxy-factories.d.mts +8 -1
  190. package/dist/server/proxy-factories.mjs +33 -1
  191. package/dist/server.d.mts +3 -1
  192. package/dist/shared/types/index.d.mts +1 -0
  193. package/dist/shared/types/saved-views.types.d.mts +14 -7
  194. package/dist/shared.d.mts +3 -2
  195. package/package.json +5 -4
@@ -17,7 +17,9 @@ import { DateTimeInput } from "../../components/primitives/date-input.mjs";
17
17
  import { getDefaultFormActions } from "../../builder/types/action-registry.mjs";
18
18
  import { ConfirmationDialog } from "../../components/actions/confirmation-dialog.mjs";
19
19
  import { ActionButton } from "../../components/actions/action-button.mjs";
20
+ import { adminCollectionKey } from "../../hooks/query-access.mjs";
20
21
  import { useCollectionFields } from "../../hooks/use-collection-fields.mjs";
22
+ import { ReactiveFieldStatesProvider, useReactiveFields } from "../../hooks/use-reactive-fields.mjs";
21
23
  import { AutoFormFields } from "./auto-form-fields.mjs";
22
24
  import { ActionDialog } from "../../components/actions/action-dialog.mjs";
23
25
  import { EmptyState } from "../../components/ui/empty-state.mjs";
@@ -27,9 +29,9 @@ import { useCollectionValidation } from "../../hooks/use-collection-validation.m
27
29
  import { useSearchParamToggle } from "../../hooks/use-search-param-toggle.mjs";
28
30
  import { usePreferServerValidation } from "../../hooks/use-server-validation.mjs";
29
31
  import { useSidebarSearchParam } from "../../hooks/use-sidebar-search-param.mjs";
32
+ import { useAutosave } from "../../hooks/use-autosave.mjs";
30
33
  import { useCollectionCreate, useCollectionDelete, useCollectionItem, useCollectionRestore, useCollectionRevertVersion, useCollectionUpdate, useCollectionVersions } from "../../hooks/use-collection.mjs";
31
34
  import { getLockUser, useLock } from "../../hooks/use-locks.mjs";
32
- import { useReactiveFields } from "../../hooks/use-reactive-fields.mjs";
33
35
  import { useServerActions } from "../../hooks/use-server-actions.mjs";
34
36
  import { useTransitionStage } from "../../hooks/use-transition-stage.mjs";
35
37
  import { applyPatchBatchImmutable, cloneSnapshot } from "../../preview/patch.mjs";
@@ -136,22 +138,25 @@ function normalizeInlineEditValue(message) {
136
138
  * Component that manages reactive field states.
137
139
  * Must be rendered inside FormProvider to access form context.
138
140
  */
139
- function ReactiveFieldsManager({ collection, mode = "collection", reactiveConfigs, enabled }) {
140
- useReactiveFields({
141
+ function ReactiveFieldsManager({ collection, mode = "collection", reactiveConfigs, enabled, children }) {
142
+ const { fieldStates } = useReactiveFields({
141
143
  collection,
142
144
  mode,
143
145
  reactiveConfigs,
144
146
  enabled: enabled && Object.keys(reactiveConfigs).length > 0,
145
147
  debounce: 300
146
148
  });
147
- return null;
149
+ return /* @__PURE__ */ jsx(ReactiveFieldStatesProvider, {
150
+ fieldStates,
151
+ children
152
+ });
148
153
  }
149
154
  const FormFieldsContent = React.memo(function FormFieldsContent$1({ collection, config, registry, allCollectionsConfig, resolvedFields, schema }) {
150
155
  return /* @__PURE__ */ jsx(RenderProfiler, {
151
156
  id: `form.fields.${collection}`,
152
157
  minDurationMs: 10,
153
158
  children: /* @__PURE__ */ jsx(AutoFormFields, {
154
- collection,
159
+ collection: adminCollectionKey(collection),
155
160
  config,
156
161
  registry,
157
162
  allCollectionsConfig,
@@ -244,71 +249,6 @@ const PreviewPatchBridge = React.memo(function PreviewPatchBridge$1({ form, prev
244
249
  ]);
245
250
  return null;
246
251
  });
247
- const AutosaveManager = React.memo(function AutosaveManager$1({ form, formElementRef, isEditMode, id, enabled, debounce, isDirtyRef, isSubmittingRef, updateMutation, onPreviewRefresh, onPreviewCommit, onSavingChange, onSaved }) {
248
- const { t } = useTranslation();
249
- const timerRef = React.useRef(null);
250
- const runAutosave = React.useCallback(async () => {
251
- if (!id || !isDirtyRef.current || isSubmittingRef.current) return;
252
- try {
253
- onSavingChange(true);
254
- await form.handleSubmit(async (data) => {
255
- const result = await updateMutation.mutateAsync({
256
- id,
257
- data
258
- });
259
- form.reset(result, { keepTouched: true });
260
- onPreviewCommit?.(result);
261
- onPreviewRefresh?.();
262
- onSaved(/* @__PURE__ */ new Date());
263
- onSavingChange(false);
264
- }, () => {
265
- onSavingChange(false);
266
- })();
267
- } catch (error) {
268
- onSavingChange(false);
269
- console.error("Autosave failed:", error);
270
- toast.error(t("error.autosaveFailed"), { description: error instanceof Error ? error.message : void 0 });
271
- }
272
- }, [
273
- form,
274
- id,
275
- isDirtyRef,
276
- isSubmittingRef,
277
- onSaved,
278
- onSavingChange,
279
- onPreviewCommit,
280
- onPreviewRefresh,
281
- t,
282
- updateMutation
283
- ]);
284
- React.useEffect(() => {
285
- if (timerRef.current) clearTimeout(timerRef.current);
286
- if (!enabled || !isEditMode || !id) return;
287
- const target = formElementRef.current;
288
- if (!target) return;
289
- const scheduleAutosave = () => {
290
- if (timerRef.current) clearTimeout(timerRef.current);
291
- timerRef.current = setTimeout(() => {
292
- runAutosave();
293
- }, debounce);
294
- };
295
- target.addEventListener("input", scheduleAutosave, { capture: true });
296
- target.addEventListener("change", scheduleAutosave, { capture: true });
297
- return () => {
298
- target.removeEventListener("input", scheduleAutosave, { capture: true });
299
- target.removeEventListener("change", scheduleAutosave, { capture: true });
300
- if (timerRef.current) clearTimeout(timerRef.current);
301
- };
302
- }, [
303
- debounce,
304
- enabled,
305
- formElementRef,
306
- id,
307
- isEditMode,
308
- runAutosave
309
- ]);
310
- return null;
311
- });
312
252
  const AutosaveIndicator = React.memo(function AutosaveIndicator$1({ control, enabled, indicator, isEditMode, isSaving, lastSaved, formatTimeAgo, t }) {
313
253
  const { isDirty } = useFormState({ control });
314
254
  const [, forceUpdate] = React.useReducer((x) => x + 1, 0);
@@ -394,6 +334,7 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
394
334
  const { t } = useTranslation();
395
335
  const resolveText = useResolveText();
396
336
  const isEditMode = !!id;
337
+ const collectionKey = adminCollectionKey(collection);
397
338
  const { fields: resolvedFields, schema, isLoading: isFieldsLoading } = useCollectionFields(collection, { fallbackFields: config?.fields });
398
339
  const { data: adminConfig } = useAdminConfig();
399
340
  const resolvedFormConfig = React.useMemo(() => viewConfig ?? (config?.form)?.["~config"] ?? config?.form ?? schema?.admin?.form, [
@@ -442,7 +383,7 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
442
383
  fields: resolvedFields,
443
384
  schema
444
385
  }), [resolvedFields, schema]);
445
- const { data: item, isLoading, error: itemError } = useCollectionItem(collection, id ?? "", hasManyToManyRelations(withRelations) ? {
386
+ const { data: item, isLoading, error: itemError } = useCollectionItem(collectionKey, id ?? "", hasManyToManyRelations(withRelations) ? {
446
387
  with: withRelations,
447
388
  localeFallback: false
448
389
  } : { localeFallback: false }, { enabled: isEditMode });
@@ -462,13 +403,13 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
462
403
  }
463
404
  return result;
464
405
  }, [item, withRelations]);
465
- const createMutation = useCollectionCreate(collection);
466
- const updateMutation = useCollectionUpdate(collection);
467
- const deleteMutation = useCollectionDelete(collection);
468
- const restoreMutation = useCollectionRestore(collection);
469
- const revertVersionMutation = useCollectionRevertVersion(collection);
406
+ const createMutation = useCollectionCreate(collectionKey);
407
+ const updateMutation = useCollectionUpdate(collectionKey);
408
+ const deleteMutation = useCollectionDelete(collectionKey);
409
+ const restoreMutation = useCollectionRestore(collectionKey);
410
+ const revertVersionMutation = useCollectionRevertVersion(collectionKey);
470
411
  const [pendingRevertVersion, setPendingRevertVersion] = React.useState(null);
471
- const { data: versionsData, isLoading: versionsLoading } = useCollectionVersions(collection, id ?? "", { limit: 50 }, { enabled: isEditMode && !!id && isHistoryOpen && !!schema?.options?.versioning });
412
+ const { data: versionsData, isLoading: versionsLoading } = useCollectionVersions(collectionKey, id ?? "", { limit: 50 }, { enabled: isEditMode && !!id && isHistoryOpen && !!schema?.options?.versioning });
472
413
  const workflowConfig = schema?.options?.workflow;
473
414
  const workflowEnabled = !!workflowConfig?.enabled;
474
415
  /**
@@ -476,7 +417,7 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
476
417
  * `versionStage`. Runs whenever workflow is enabled and we have an item id.
477
418
  * The full 50-version query is still lazy-loaded behind the History sidebar.
478
419
  */
479
- const { data: latestVersionData } = useCollectionVersions(collection, id ?? "", { limit: 1 }, { enabled: workflowEnabled && isEditMode && !!id });
420
+ const { data: latestVersionData } = useCollectionVersions(collectionKey, id ?? "", { limit: 1 }, { enabled: workflowEnabled && isEditMode && !!id });
480
421
  const currentStage = latestVersionData?.[0]?.versionStage ?? workflowConfig?.initialStage ?? null;
481
422
  const currentStageConfig = React.useMemo(() => workflowConfig?.stages?.find((s) => s.name === currentStage) ?? null, [workflowConfig?.stages, currentStage]);
482
423
  const currentStageLabel = currentStageConfig?.label ?? currentStage ?? "";
@@ -598,6 +539,19 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
598
539
  preventNavigation: cfg.preventNavigation !== false
599
540
  };
600
541
  }, [config]);
542
+ useAutosave({
543
+ form,
544
+ id,
545
+ enabled: autoSaveConfig.enabled,
546
+ debounce: autoSaveConfig.debounce,
547
+ isDirtyRef: formIsDirtyRef,
548
+ isSubmittingRef: formIsSubmittingRef,
549
+ updateMutation,
550
+ onPreviewCommit: commitPreviewSnapshot,
551
+ onPreviewRefresh: triggerPreviewRefresh,
552
+ onSavingChange: setIsSaving,
553
+ onSaved: setLastSaved
554
+ });
601
555
  const { locale: contentLocale, setLocale: setContentLocale } = useScopedLocale();
602
556
  const localeOptions = useSafeContentLocales()?.locales ?? [];
603
557
  const prevLocaleRef = React.useRef(contentLocale);
@@ -1213,21 +1167,6 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
1213
1167
  onDirtyChange: handleFormDirtyChange,
1214
1168
  onSubmittingChange: handleFormSubmittingChange
1215
1169
  }),
1216
- /* @__PURE__ */ jsx(AutosaveManager, {
1217
- form,
1218
- formElementRef,
1219
- isEditMode,
1220
- id,
1221
- enabled: autoSaveConfig.enabled,
1222
- debounce: autoSaveConfig.debounce,
1223
- isDirtyRef: formIsDirtyRef,
1224
- isSubmittingRef: formIsSubmittingRef,
1225
- updateMutation,
1226
- onPreviewCommit: commitPreviewSnapshot,
1227
- onPreviewRefresh: triggerPreviewRefresh,
1228
- onSavingChange: setIsSaving,
1229
- onSaved: setLastSaved
1230
- }),
1231
1170
  /* @__PURE__ */ jsx(PreviewPatchBridge, {
1232
1171
  form,
1233
1172
  previewRef,
@@ -1238,196 +1177,196 @@ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/a
1238
1177
  /* @__PURE__ */ jsx(ReactiveFieldsManager, {
1239
1178
  collection,
1240
1179
  reactiveConfigs,
1241
- enabled: !isBlocked && !isMutationPending
1242
- }),
1243
- /* @__PURE__ */ jsx(RenderProfiler, {
1244
- id: `form.shell.${collection}`,
1245
- minDurationMs: 12,
1246
- children: /* @__PURE__ */ jsxs("form", {
1247
- ref: formElementRef,
1248
- onSubmit: (e) => {
1249
- e.stopPropagation();
1250
- if (isBlocked) {
1251
- e.preventDefault();
1252
- toast.error(t("lock.cannotSave"));
1253
- return;
1254
- }
1255
- form.handleSubmit(onSubmit, (errors) => {
1256
- console.warn("[FormView] Validation errors:", errors);
1257
- toast.error(t("toast.validationFailed"), { description: t("toast.validationDescription") });
1258
- })(e);
1259
- },
1260
- className: "qa-form-view__form space-y-4",
1261
- children: [
1262
- /* @__PURE__ */ jsx(AdminViewHeader, {
1263
- className: "qa-form-view__header",
1264
- title,
1265
- titleAccessory: /* @__PURE__ */ jsxs(Fragment, { children: [
1266
- localeOptions.length > 0 && /* @__PURE__ */ jsx(LocaleSwitcher, {
1267
- locales: localeOptions,
1268
- value: contentLocale,
1269
- onChange: setContentLocale
1270
- }),
1271
- /* @__PURE__ */ jsx(AutosaveIndicator, {
1272
- control: form.control,
1273
- enabled: autoSaveConfig.enabled,
1274
- indicator: autoSaveConfig.indicator,
1275
- isEditMode,
1276
- isSaving,
1277
- lastSaved,
1278
- formatTimeAgo,
1279
- t
1280
- }),
1281
- workflowEnabled && currentStage && /* @__PURE__ */ jsxs(Badge, {
1282
- variant: "outline",
1283
- className: "gap-1.5",
1284
- children: [/* @__PURE__ */ jsx(Icon, {
1285
- icon: "ph:git-branch",
1286
- className: "size-3"
1287
- }), currentStageLabel]
1288
- })
1289
- ] }),
1290
- meta: showMeta && item ? /* @__PURE__ */ jsxs(Fragment, { children: [
1291
- /* @__PURE__ */ jsxs("span", {
1292
- className: "opacity-60",
1293
- children: [t("form.id"), ":"]
1294
- }),
1295
- /* @__PURE__ */ jsx("button", {
1296
- type: "button",
1297
- className: "hover:text-foreground cursor-pointer transition-colors",
1298
- onClick: () => {
1299
- navigator.clipboard.writeText(String(item.id)).then(() => toast.success(t("toast.idCopied")), () => toast.error(t("toast.copyFailed")));
1300
- },
1301
- title: t("common.copy"),
1302
- children: item.id
1303
- }),
1304
- item.createdAt && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
1305
- className: "opacity-40",
1306
- children: "·"
1307
- }), /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsxs("span", {
1308
- className: "opacity-60",
1309
- children: [t("form.created"), " "]
1310
- }), formatDate(item.createdAt)] })] }),
1311
- item.updatedAt && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
1312
- className: "opacity-40",
1313
- children: "·"
1314
- }), /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsxs("span", {
1315
- className: "opacity-60",
1316
- children: [t("form.updated"), " "]
1317
- }), formatDate(item.updatedAt)] })] })
1318
- ] }) : void 0,
1319
- actions: /* @__PURE__ */ jsxs(Fragment, { children: [
1320
- headerActions,
1321
- canUseLivePreview && /* @__PURE__ */ jsxs(Button, {
1322
- type: "button",
1323
- variant: "outline",
1324
- size: "icon-sm",
1325
- onClick: () => setIsLivePreviewOpen(true),
1326
- title: t("preview.livePreview"),
1327
- children: [/* @__PURE__ */ jsx(Icon, {
1328
- icon: "ph:eye",
1329
- className: "size-4"
1330
- }), /* @__PURE__ */ jsx("span", {
1331
- className: "sr-only",
1332
- children: t("preview.livePreview")
1333
- })]
1334
- }),
1335
- isEditMode && id && schema?.options?.versioning && /* @__PURE__ */ jsxs(Button, {
1336
- type: "button",
1337
- variant: "outline",
1338
- size: "icon-sm",
1339
- onClick: () => setIsHistoryOpen(true),
1340
- title: t("history.title"),
1341
- children: [/* @__PURE__ */ jsx(Icon, {
1342
- icon: "ph:clock-counter-clockwise",
1343
- className: "size-4"
1344
- }), /* @__PURE__ */ jsx("span", {
1345
- className: "sr-only",
1346
- children: t("history.title")
1347
- })]
1348
- }),
1349
- workflowEnabled && isEditMode && id && allowedTransitions.length > 0 && /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsxs(DropdownMenuTrigger, {
1350
- render: workflowTransitionTriggerRender,
1351
- children: [/* @__PURE__ */ jsx(Icon, {
1352
- icon: "ph:arrows-left-right",
1353
- className: "size-4"
1354
- }), t("workflow.transition")]
1355
- }), /* @__PURE__ */ jsx(DropdownMenuContent, {
1356
- align: "end",
1357
- children: allowedTransitions.map((stage) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
1358
- onClick: () => setTransitionTarget({
1359
- name: stage.name,
1360
- label: stage.label
1361
- }),
1180
+ enabled: !isBlocked && !isMutationPending,
1181
+ children: /* @__PURE__ */ jsx(RenderProfiler, {
1182
+ id: `form.shell.${collection}`,
1183
+ minDurationMs: 12,
1184
+ children: /* @__PURE__ */ jsxs("form", {
1185
+ ref: formElementRef,
1186
+ onSubmit: (e) => {
1187
+ e.stopPropagation();
1188
+ if (isBlocked) {
1189
+ e.preventDefault();
1190
+ toast.error(t("lock.cannotSave"));
1191
+ return;
1192
+ }
1193
+ form.handleSubmit(onSubmit, (errors) => {
1194
+ console.warn("[FormView] Validation errors:", errors);
1195
+ toast.error(t("toast.validationFailed"), { description: t("toast.validationDescription") });
1196
+ })(e);
1197
+ },
1198
+ className: "qa-form-view__form space-y-4",
1199
+ children: [
1200
+ /* @__PURE__ */ jsx(AdminViewHeader, {
1201
+ className: "qa-form-view__header",
1202
+ title,
1203
+ titleAccessory: /* @__PURE__ */ jsxs(Fragment, { children: [
1204
+ localeOptions.length > 0 && /* @__PURE__ */ jsx(LocaleSwitcher, {
1205
+ locales: localeOptions,
1206
+ value: contentLocale,
1207
+ onChange: setContentLocale
1208
+ }),
1209
+ /* @__PURE__ */ jsx(AutosaveIndicator, {
1210
+ control: form.control,
1211
+ enabled: autoSaveConfig.enabled,
1212
+ indicator: autoSaveConfig.indicator,
1213
+ isEditMode,
1214
+ isSaving,
1215
+ lastSaved,
1216
+ formatTimeAgo,
1217
+ t
1218
+ }),
1219
+ workflowEnabled && currentStage && /* @__PURE__ */ jsxs(Badge, {
1220
+ variant: "outline",
1221
+ className: "gap-1.5",
1362
1222
  children: [/* @__PURE__ */ jsx(Icon, {
1363
- icon: "ph:arrow-right",
1364
- className: "mr-2 size-4"
1365
- }), stage.label || stage.name]
1366
- }, stage.name))
1367
- })] }),
1368
- visiblePrimaryActions.map((action) => /* @__PURE__ */ jsx(ActionButton, {
1369
- action,
1370
- collection,
1371
- helpers: actionHelpers,
1372
- size: "sm",
1373
- onOpenDialog: (a) => setDialogAction(a)
1374
- }, action.id)),
1375
- /* @__PURE__ */ jsx(SaveSubmitButton, {
1376
- control: form.control,
1377
- isMutationPending,
1378
- t
1379
- }),
1380
- visibleSecondaryActions.length > 0 && /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsxs(DropdownMenuTrigger, {
1381
- render: secondaryActionsTriggerRender,
1382
- children: [/* @__PURE__ */ jsx(Icon, {
1383
- icon: "ph:dots-three-vertical",
1384
- className: "size-4"
1385
- }), /* @__PURE__ */ jsx("span", {
1386
- className: "sr-only",
1387
- children: t("common.moreActions")
1388
- })]
1389
- }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
1390
- align: "end",
1391
- children: [
1392
- regularSecondary.map((action) => {
1393
- return /* @__PURE__ */ jsxs(DropdownMenuItem, {
1394
- onClick: () => handleActionClick(action),
1395
- disabled: actionLoading,
1396
- children: [resolveIconElement(action.icon, { className: "mr-2 size-4" }), resolveText(action.label)]
1397
- }, action.id);
1398
- }),
1399
- regularSecondary.length > 0 && destructiveSecondary.length > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
1400
- destructiveSecondary.map((action) => {
1401
- return /* @__PURE__ */ jsxs(DropdownMenuItem, {
1402
- variant: "destructive",
1403
- onClick: () => handleActionClick(action),
1404
- disabled: actionLoading,
1405
- children: [resolveIconElement(action.icon, { className: "mr-2 size-4" }), resolveText(action.label)]
1406
- }, action.id);
1407
- })
1408
- ]
1409
- })] })
1410
- ] })
1411
- }),
1412
- item?.deletedAt && /* @__PURE__ */ jsxs("div", {
1413
- className: "qa-form-view__deleted-banner border-destructive/30 bg-destructive/5 text-destructive flex items-center gap-2 border px-4 py-3 text-sm",
1414
- children: [/* @__PURE__ */ jsx(Icon, {
1415
- icon: "ph:trash",
1416
- className: "size-4 shrink-0"
1417
- }), /* @__PURE__ */ jsx("span", { children: t("form.deletedBanner", {
1418
- date: formatDate(item.deletedAt),
1419
- defaultValue: `This record was deleted on ${formatDate(item.deletedAt)}. Use the Restore action to make it active again.`
1420
- }) })]
1421
- }),
1422
- /* @__PURE__ */ jsx(FormFieldsContent, {
1423
- collection,
1424
- config: formConfigBridge,
1425
- registry,
1426
- allCollectionsConfig,
1427
- resolvedFields,
1428
- schema
1429
- })
1430
- ]
1223
+ icon: "ph:git-branch",
1224
+ className: "size-3"
1225
+ }), currentStageLabel]
1226
+ })
1227
+ ] }),
1228
+ meta: showMeta && item ? /* @__PURE__ */ jsxs(Fragment, { children: [
1229
+ /* @__PURE__ */ jsxs("span", {
1230
+ className: "opacity-60",
1231
+ children: [t("form.id"), ":"]
1232
+ }),
1233
+ /* @__PURE__ */ jsx("button", {
1234
+ type: "button",
1235
+ className: "hover:text-foreground cursor-pointer transition-colors",
1236
+ onClick: () => {
1237
+ navigator.clipboard.writeText(String(item.id)).then(() => toast.success(t("toast.idCopied")), () => toast.error(t("toast.copyFailed")));
1238
+ },
1239
+ title: t("common.copy"),
1240
+ children: item.id
1241
+ }),
1242
+ item.createdAt && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
1243
+ className: "opacity-40",
1244
+ children: "·"
1245
+ }), /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsxs("span", {
1246
+ className: "opacity-60",
1247
+ children: [t("form.created"), " "]
1248
+ }), formatDate(item.createdAt)] })] }),
1249
+ item.updatedAt && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
1250
+ className: "opacity-40",
1251
+ children: "·"
1252
+ }), /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsxs("span", {
1253
+ className: "opacity-60",
1254
+ children: [t("form.updated"), " "]
1255
+ }), formatDate(item.updatedAt)] })] })
1256
+ ] }) : void 0,
1257
+ actions: /* @__PURE__ */ jsxs(Fragment, { children: [
1258
+ headerActions,
1259
+ canUseLivePreview && /* @__PURE__ */ jsxs(Button, {
1260
+ type: "button",
1261
+ variant: "outline",
1262
+ size: "icon-sm",
1263
+ onClick: () => setIsLivePreviewOpen(true),
1264
+ title: t("preview.livePreview"),
1265
+ children: [/* @__PURE__ */ jsx(Icon, {
1266
+ icon: "ph:eye",
1267
+ className: "size-4"
1268
+ }), /* @__PURE__ */ jsx("span", {
1269
+ className: "sr-only",
1270
+ children: t("preview.livePreview")
1271
+ })]
1272
+ }),
1273
+ isEditMode && id && schema?.options?.versioning && /* @__PURE__ */ jsxs(Button, {
1274
+ type: "button",
1275
+ variant: "outline",
1276
+ size: "icon-sm",
1277
+ onClick: () => setIsHistoryOpen(true),
1278
+ title: t("history.title"),
1279
+ children: [/* @__PURE__ */ jsx(Icon, {
1280
+ icon: "ph:clock-counter-clockwise",
1281
+ className: "size-4"
1282
+ }), /* @__PURE__ */ jsx("span", {
1283
+ className: "sr-only",
1284
+ children: t("history.title")
1285
+ })]
1286
+ }),
1287
+ workflowEnabled && isEditMode && id && allowedTransitions.length > 0 && /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsxs(DropdownMenuTrigger, {
1288
+ render: workflowTransitionTriggerRender,
1289
+ children: [/* @__PURE__ */ jsx(Icon, {
1290
+ icon: "ph:arrows-left-right",
1291
+ className: "size-4"
1292
+ }), t("workflow.transition")]
1293
+ }), /* @__PURE__ */ jsx(DropdownMenuContent, {
1294
+ align: "end",
1295
+ children: allowedTransitions.map((stage) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
1296
+ onClick: () => setTransitionTarget({
1297
+ name: stage.name,
1298
+ label: stage.label
1299
+ }),
1300
+ children: [/* @__PURE__ */ jsx(Icon, {
1301
+ icon: "ph:arrow-right",
1302
+ className: "mr-2 size-4"
1303
+ }), stage.label || stage.name]
1304
+ }, stage.name))
1305
+ })] }),
1306
+ visiblePrimaryActions.map((action) => /* @__PURE__ */ jsx(ActionButton, {
1307
+ action,
1308
+ collection,
1309
+ helpers: actionHelpers,
1310
+ size: "sm",
1311
+ onOpenDialog: (a) => setDialogAction(a)
1312
+ }, action.id)),
1313
+ /* @__PURE__ */ jsx(SaveSubmitButton, {
1314
+ control: form.control,
1315
+ isMutationPending,
1316
+ t
1317
+ }),
1318
+ visibleSecondaryActions.length > 0 && /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsxs(DropdownMenuTrigger, {
1319
+ render: secondaryActionsTriggerRender,
1320
+ children: [/* @__PURE__ */ jsx(Icon, {
1321
+ icon: "ph:dots-three-vertical",
1322
+ className: "size-4"
1323
+ }), /* @__PURE__ */ jsx("span", {
1324
+ className: "sr-only",
1325
+ children: t("common.moreActions")
1326
+ })]
1327
+ }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
1328
+ align: "end",
1329
+ children: [
1330
+ regularSecondary.map((action) => {
1331
+ return /* @__PURE__ */ jsxs(DropdownMenuItem, {
1332
+ onClick: () => handleActionClick(action),
1333
+ disabled: actionLoading,
1334
+ children: [resolveIconElement(action.icon, { className: "mr-2 size-4" }), resolveText(action.label)]
1335
+ }, action.id);
1336
+ }),
1337
+ regularSecondary.length > 0 && destructiveSecondary.length > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
1338
+ destructiveSecondary.map((action) => {
1339
+ return /* @__PURE__ */ jsxs(DropdownMenuItem, {
1340
+ variant: "destructive",
1341
+ onClick: () => handleActionClick(action),
1342
+ disabled: actionLoading,
1343
+ children: [resolveIconElement(action.icon, { className: "mr-2 size-4" }), resolveText(action.label)]
1344
+ }, action.id);
1345
+ })
1346
+ ]
1347
+ })] })
1348
+ ] })
1349
+ }),
1350
+ item?.deletedAt && /* @__PURE__ */ jsxs("div", {
1351
+ className: "qa-form-view__deleted-banner border-destructive/30 bg-destructive/5 text-destructive flex items-center gap-2 border px-4 py-3 text-sm",
1352
+ children: [/* @__PURE__ */ jsx(Icon, {
1353
+ icon: "ph:trash",
1354
+ className: "size-4 shrink-0"
1355
+ }), /* @__PURE__ */ jsx("span", { children: t("form.deletedBanner", {
1356
+ date: formatDate(item.deletedAt),
1357
+ defaultValue: `This record was deleted on ${formatDate(item.deletedAt)}. Use the Restore action to make it active again.`
1358
+ }) })]
1359
+ }),
1360
+ /* @__PURE__ */ jsx(FormFieldsContent, {
1361
+ collection,
1362
+ config: formConfigBridge,
1363
+ registry,
1364
+ allCollectionsConfig,
1365
+ resolvedFields,
1366
+ schema
1367
+ })
1368
+ ]
1369
+ })
1431
1370
  })
1432
1371
  })
1433
1372
  ]