@questpie/admin 1.1.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (566) hide show
  1. package/README.md +256 -488
  2. package/dist/augmentation.d.mts +414 -0
  3. package/dist/client/blocks/block-renderer.d.mts +45 -0
  4. package/dist/client/blocks/block-renderer.mjs +105 -0
  5. package/dist/client/blocks/index.d.mts +2 -0
  6. package/dist/client/blocks/types.d.mts +68 -0
  7. package/dist/client/blocks/types.mjs +19 -0
  8. package/dist/client/builder/admin-types.d.mts +40 -0
  9. package/dist/client/builder/admin.d.mts +110 -0
  10. package/dist/client/builder/admin.mjs +151 -0
  11. package/dist/client/builder/field/field.d.mts +51 -0
  12. package/dist/client/builder/field/field.mjs +37 -0
  13. package/dist/client/builder/index.d.mts +31 -0
  14. package/dist/client/builder/page/page.d.mts +24 -0
  15. package/dist/client/builder/page/page.mjs +31 -0
  16. package/dist/client/builder/registry.d.mts +50 -0
  17. package/dist/client/builder/types/action-registry.mjs +276 -0
  18. package/dist/client/builder/types/action-types.d.mts +226 -0
  19. package/dist/client/builder/types/collection-types.mjs +10 -0
  20. package/dist/client/builder/types/common.d.mts +46 -0
  21. package/dist/client/builder/types/field-types.d.mts +592 -0
  22. package/dist/client/builder/types/field-types.mjs +18 -0
  23. package/dist/client/builder/types/ui-config.d.mts +158 -0
  24. package/dist/client/builder/types/widget-types.d.mts +562 -0
  25. package/dist/client/builder/validation.d.mts +33 -0
  26. package/dist/client/builder/validation.mjs +227 -0
  27. package/dist/client/builder/view/view.d.mts +49 -0
  28. package/dist/client/builder/view/view.mjs +27 -0
  29. package/dist/client/builder/widget/widget.d.mts +27 -0
  30. package/dist/client/builder/widget/widget.mjs +21 -0
  31. package/dist/client/components/actions/action-button.mjs +245 -0
  32. package/dist/client/components/actions/action-dialog.mjs +559 -0
  33. package/dist/client/components/actions/confirmation-dialog.mjs +201 -0
  34. package/dist/client/components/actions/header-actions.mjs +210 -0
  35. package/dist/client/components/admin-link.d.mts +66 -0
  36. package/dist/client/components/admin-link.mjs +171 -0
  37. package/dist/client/components/auth/auth-guard.d.mts +50 -0
  38. package/dist/client/components/auth/auth-guard.mjs +60 -0
  39. package/dist/client/components/auth/auth-loading.d.mts +35 -0
  40. package/dist/client/components/auth/auth-loading.mjs +55 -0
  41. package/dist/client/components/blocks/block-canvas.mjs +159 -0
  42. package/dist/client/components/blocks/block-editor-context.mjs +125 -0
  43. package/dist/client/components/blocks/block-editor-layout.mjs +199 -0
  44. package/dist/client/components/blocks/block-editor-provider.mjs +235 -0
  45. package/dist/client/components/blocks/block-fields-renderer.mjs +240 -0
  46. package/dist/client/components/blocks/block-insert-button.mjs +189 -0
  47. package/dist/client/components/blocks/block-item-menu.mjs +363 -0
  48. package/dist/client/components/blocks/block-item.mjs +434 -0
  49. package/dist/client/components/blocks/block-library-sidebar.mjs +285 -0
  50. package/dist/client/components/blocks/block-tree.mjs +103 -0
  51. package/dist/client/components/blocks/block-type-icon.mjs +95 -0
  52. package/dist/client/components/blocks/utils/tree-utils.mjs +185 -0
  53. package/dist/client/components/component-renderer.d.mts +114 -0
  54. package/dist/client/components/component-renderer.mjs +258 -0
  55. package/dist/client/components/error-boundary.mjs +144 -0
  56. package/dist/client/components/fields/array-field.mjs +506 -0
  57. package/dist/client/components/fields/asset-preview-field.mjs +159 -0
  58. package/dist/client/components/fields/blocks-field/blocks-field.mjs +209 -0
  59. package/dist/client/components/fields/boolean-field.mjs +77 -0
  60. package/dist/client/components/fields/date-field.mjs +76 -0
  61. package/dist/client/components/fields/datetime-field.mjs +74 -0
  62. package/dist/client/components/fields/email-field.mjs +67 -0
  63. package/dist/client/components/fields/field-utils.mjs +64 -0
  64. package/dist/client/components/fields/field-wrapper.mjs +124 -0
  65. package/dist/client/components/fields/json-field.mjs +461 -0
  66. package/dist/client/components/fields/locale-badge.mjs +25 -0
  67. package/dist/client/components/fields/number-field.mjs +73 -0
  68. package/dist/client/components/fields/object-array-field.mjs +707 -0
  69. package/dist/client/components/fields/object-field.mjs +686 -0
  70. package/dist/client/components/fields/relation/displays/cards-display.mjs +254 -0
  71. package/dist/client/components/fields/relation/displays/chips-display.mjs +173 -0
  72. package/dist/client/components/fields/relation/displays/grid-display.mjs +209 -0
  73. package/dist/client/components/fields/relation/displays/list-display.mjs +247 -0
  74. package/dist/client/components/fields/relation/displays/table-display.mjs +309 -0
  75. package/dist/client/components/fields/relation/displays/types.mjs +72 -0
  76. package/dist/client/components/fields/relation/relation-items-display.mjs +143 -0
  77. package/dist/client/components/fields/relation-field.mjs +161 -0
  78. package/dist/client/components/fields/relation-picker.mjs +296 -0
  79. package/dist/client/components/fields/relation-select.mjs +232 -0
  80. package/dist/client/components/fields/rich-text-editor/bubble-menu.mjs +105 -0
  81. package/dist/client/components/fields/rich-text-editor/extensions.mjs +144 -0
  82. package/dist/client/components/fields/rich-text-editor/image-popover.mjs +221 -0
  83. package/dist/client/components/fields/rich-text-editor/index.mjs +520 -0
  84. package/dist/client/components/fields/rich-text-editor/link-popover.mjs +85 -0
  85. package/dist/client/components/fields/rich-text-editor/presets.mjs +123 -0
  86. package/dist/client/components/fields/rich-text-editor/slash-commands.mjs +188 -0
  87. package/dist/client/components/fields/rich-text-editor/table-controls.mjs +433 -0
  88. package/dist/client/components/fields/rich-text-editor/toolbar.mjs +541 -0
  89. package/dist/client/components/fields/rich-text-editor/types.mjs +30 -0
  90. package/dist/client/components/fields/rich-text-editor/utils.mjs +50 -0
  91. package/dist/client/components/fields/rich-text-field.mjs +64 -0
  92. package/dist/client/components/fields/select-field.mjs +88 -0
  93. package/dist/client/components/fields/text-field.mjs +72 -0
  94. package/dist/client/components/fields/textarea-field.mjs +71 -0
  95. package/dist/client/components/fields/time-field.mjs +67 -0
  96. package/dist/client/components/fields/upload-field.mjs +621 -0
  97. package/dist/client/components/filter-builder/columns-tab.mjs +325 -0
  98. package/dist/client/components/filter-builder/filter-builder-sheet.mjs +456 -0
  99. package/dist/client/components/filter-builder/filters-tab.mjs +663 -0
  100. package/dist/client/components/filter-builder/saved-views-tab.mjs +278 -0
  101. package/dist/client/components/history-sidebar.mjs +496 -0
  102. package/dist/client/components/layout/field-layout-renderer.mjs +301 -0
  103. package/dist/client/components/locale-switcher.mjs +251 -0
  104. package/dist/client/components/media/media-grid.mjs +314 -0
  105. package/dist/client/components/media/media-picker-dialog.mjs +563 -0
  106. package/dist/client/components/preview/live-preview-mode.mjs +503 -0
  107. package/dist/client/components/preview/preview-pane.mjs +388 -0
  108. package/dist/client/components/primitives/asset-preview.mjs +771 -0
  109. package/dist/client/components/primitives/checkbox-input.mjs +59 -0
  110. package/dist/client/components/primitives/date-input.mjs +461 -0
  111. package/dist/client/components/primitives/dropzone.mjs +368 -0
  112. package/dist/client/components/primitives/number-input.mjs +117 -0
  113. package/dist/client/components/primitives/select-multi.mjs +590 -0
  114. package/dist/client/components/primitives/select-single.mjs +473 -0
  115. package/dist/client/components/primitives/text-input.mjs +45 -0
  116. package/dist/client/components/primitives/textarea-input.mjs +43 -0
  117. package/dist/client/components/primitives/time-input.mjs +145 -0
  118. package/dist/client/components/primitives/toggle-input.mjs +51 -0
  119. package/dist/client/components/primitives/types.mjs +12 -0
  120. package/dist/client/components/sheets/resource-sheet.mjs +86 -0
  121. package/dist/client/components/ui/accordion.mjs +169 -0
  122. package/dist/client/components/ui/alert.mjs +85 -0
  123. package/dist/client/components/ui/badge.mjs +76 -0
  124. package/dist/client/components/ui/button.mjs +84 -0
  125. package/dist/client/components/ui/card.mjs +206 -0
  126. package/dist/client/components/ui/checkbox.mjs +82 -0
  127. package/dist/client/components/ui/command.mjs +239 -0
  128. package/dist/client/components/ui/dialog.mjs +296 -0
  129. package/dist/client/components/ui/drawer.mjs +278 -0
  130. package/dist/client/components/ui/dropdown-menu.mjs +315 -0
  131. package/dist/client/components/ui/empty-state.mjs +99 -0
  132. package/dist/client/components/ui/field.mjs +354 -0
  133. package/dist/client/components/ui/input-group.mjs +201 -0
  134. package/dist/client/components/ui/input.mjs +46 -0
  135. package/dist/client/components/ui/kbd.mjs +53 -0
  136. package/dist/client/components/ui/label.mjs +45 -0
  137. package/dist/client/components/ui/popover.mjs +176 -0
  138. package/dist/client/components/ui/responsive-dialog.mjs +308 -0
  139. package/dist/client/components/ui/search-input.mjs +139 -0
  140. package/dist/client/components/ui/select.mjs +325 -0
  141. package/dist/client/components/ui/separator.mjs +47 -0
  142. package/dist/client/components/ui/sheet.mjs +280 -0
  143. package/dist/client/components/ui/sidebar.mjs +774 -0
  144. package/dist/client/components/ui/skeleton.mjs +40 -0
  145. package/dist/client/components/ui/sonner.d.mts +13 -0
  146. package/dist/client/components/ui/sonner.mjs +85 -0
  147. package/dist/client/components/ui/spinner.mjs +52 -0
  148. package/dist/client/components/ui/switch.mjs +58 -0
  149. package/dist/client/components/ui/table.mjs +276 -0
  150. package/dist/client/components/ui/tabs.mjs +160 -0
  151. package/dist/client/components/ui/textarea.mjs +40 -0
  152. package/dist/client/components/ui/toolbar.mjs +136 -0
  153. package/dist/client/components/ui/tooltip.mjs +146 -0
  154. package/dist/client/components/widgets/chart-widget.mjs +582 -0
  155. package/dist/client/components/widgets/progress-widget.mjs +200 -0
  156. package/dist/client/components/widgets/quick-actions-widget.mjs +209 -0
  157. package/dist/client/components/widgets/recent-items-widget.mjs +196 -0
  158. package/dist/client/components/widgets/stats-widget.mjs +261 -0
  159. package/dist/client/components/widgets/table-widget.mjs +273 -0
  160. package/dist/client/components/widgets/timeline-widget.mjs +279 -0
  161. package/dist/client/components/widgets/value-widget.mjs +312 -0
  162. package/dist/client/components/widgets/widget-skeletons.mjs +427 -0
  163. package/dist/client/contexts/breadcrumb-context.mjs +60 -0
  164. package/dist/client/contexts/focus-context.d.mts +87 -0
  165. package/dist/client/contexts/focus-context.mjs +250 -0
  166. package/dist/client/hooks/typed-hooks.d.mts +110 -0
  167. package/dist/client/hooks/typed-hooks.mjs +888 -0
  168. package/dist/client/hooks/use-action.mjs +329 -0
  169. package/dist/client/hooks/use-admin-config.mjs +69 -0
  170. package/dist/client/hooks/use-admin-preferences.mjs +171 -0
  171. package/dist/client/hooks/use-admin-routes.mjs +130 -0
  172. package/dist/client/hooks/use-audit-history.mjs +157 -0
  173. package/dist/client/hooks/use-auth.d.mts +97 -0
  174. package/dist/{use-auth-BoLmWtmU.mjs → client/hooks/use-auth.mjs} +9 -10
  175. package/dist/client/hooks/use-collection-fields.mjs +71 -0
  176. package/dist/client/hooks/use-collection-meta.mjs +153 -0
  177. package/dist/client/hooks/use-collection-schema.mjs +90 -0
  178. package/dist/client/hooks/use-collection-validation.mjs +88 -0
  179. package/dist/client/hooks/use-collection.d.mts +96 -0
  180. package/dist/client/hooks/use-collection.mjs +673 -0
  181. package/dist/client/hooks/use-current-user.d.mts +60 -0
  182. package/dist/client/hooks/use-current-user.mjs +79 -0
  183. package/dist/client/hooks/use-field-hooks.mjs +199 -0
  184. package/dist/client/hooks/use-field-options.d.mts +57 -0
  185. package/dist/client/hooks/use-field-options.mjs +269 -0
  186. package/dist/client/hooks/use-global-fields.mjs +58 -0
  187. package/dist/client/hooks/use-global-meta.mjs +105 -0
  188. package/dist/client/hooks/use-global-schema.mjs +53 -0
  189. package/dist/client/hooks/use-global.d.mts +51 -0
  190. package/dist/client/hooks/use-global.mjs +284 -0
  191. package/dist/client/hooks/use-locks.mjs +452 -0
  192. package/dist/client/hooks/use-media-query.d.mts +22 -0
  193. package/dist/client/hooks/use-media-query.mjs +81 -0
  194. package/dist/client/hooks/use-prefill-params.mjs +47 -0
  195. package/dist/client/hooks/use-questpie-query-options.mjs +50 -0
  196. package/dist/client/hooks/use-reactive-fields.d.mts +78 -0
  197. package/dist/client/hooks/use-reactive-fields.mjs +201 -0
  198. package/dist/client/hooks/use-realtime-highlight.mjs +158 -0
  199. package/dist/client/hooks/use-saved-views.mjs +140 -0
  200. package/dist/client/hooks/use-search-param-toggle.d.mts +12 -0
  201. package/dist/client/hooks/use-search-param-toggle.mjs +115 -0
  202. package/dist/client/hooks/use-search.mjs +258 -0
  203. package/dist/client/hooks/use-server-actions.mjs +191 -0
  204. package/dist/client/hooks/use-server-validation.mjs +291 -0
  205. package/dist/client/hooks/use-server-widget-data.d.mts +25 -0
  206. package/dist/client/hooks/use-server-widget-data.mjs +65 -0
  207. package/dist/client/hooks/use-setup-status.d.mts +38 -0
  208. package/dist/client/hooks/use-setup-status.mjs +62 -0
  209. package/dist/client/hooks/use-sidebar-search-param.d.mts +9 -0
  210. package/dist/client/hooks/use-sidebar-search-param.mjs +104 -0
  211. package/dist/client/hooks/use-transition-stage.mjs +125 -0
  212. package/dist/client/hooks/use-upload-collection.mjs +31 -0
  213. package/dist/client/hooks/use-upload.mjs +209 -0
  214. package/dist/client/hooks/use-validation-error-map.mjs +57 -0
  215. package/dist/client/hooks/use-view-state.mjs +479 -0
  216. package/dist/client/i18n/hooks.mjs +284 -0
  217. package/dist/client/i18n/intl-cache.mjs +64 -0
  218. package/dist/client/i18n/messages.mjs +6 -0
  219. package/dist/client/i18n/simple.d.mts +21 -0
  220. package/dist/client/i18n/simple.mjs +156 -0
  221. package/dist/client/i18n/types.d.mts +109 -0
  222. package/dist/client/lib/cookies.mjs +9 -0
  223. package/dist/client/lib/events.mjs +5 -0
  224. package/dist/client/lib/render-profiler.mjs +51 -0
  225. package/dist/client/lib/utils.mjs +23 -0
  226. package/dist/client/preview/block-scope-context.d.mts +73 -0
  227. package/dist/client/preview/block-scope-context.mjs +116 -0
  228. package/dist/client/preview/index.d.mts +5 -0
  229. package/dist/client/preview/preview-banner.d.mts +45 -0
  230. package/dist/client/preview/preview-banner.mjs +134 -0
  231. package/dist/client/preview/preview-field.d.mts +107 -0
  232. package/dist/client/preview/preview-field.mjs +227 -0
  233. package/dist/client/preview/types.d.mts +114 -0
  234. package/dist/client/preview/types.mjs +20 -0
  235. package/dist/client/preview/use-collection-preview.d.mts +70 -0
  236. package/dist/client/preview/use-collection-preview.mjs +163 -0
  237. package/dist/client/runtime/content-locales-provider.d.mts +1 -0
  238. package/dist/client/runtime/content-locales-provider.mjs +136 -0
  239. package/dist/client/runtime/index.d.mts +5 -0
  240. package/dist/client/runtime/index.mjs +6 -0
  241. package/dist/client/runtime/locale-scope.d.mts +2 -0
  242. package/dist/client/runtime/locale-scope.mjs +108 -0
  243. package/dist/client/runtime/provider.d.mts +203 -0
  244. package/dist/client/runtime/provider.mjs +393 -0
  245. package/dist/client/runtime/routes.d.mts +49 -0
  246. package/dist/client/runtime/routes.mjs +91 -0
  247. package/dist/client/runtime/translations-provider.mjs +242 -0
  248. package/dist/client/scope/index.d.mts +3 -0
  249. package/dist/client/scope/picker.d.mts +53 -0
  250. package/dist/client/scope/picker.mjs +395 -0
  251. package/dist/client/scope/provider.d.mts +103 -0
  252. package/dist/client/scope/provider.mjs +167 -0
  253. package/dist/client/scope/types.d.mts +111 -0
  254. package/dist/client/styles/index.css +344 -188
  255. package/dist/client/utils/auto-expand-fields.mjs +83 -0
  256. package/dist/client/utils/build-field-definitions-from-schema.mjs +259 -0
  257. package/dist/client/utils/dependency-tracker.mjs +61 -0
  258. package/dist/client/utils/detect-relations.mjs +45 -0
  259. package/dist/client/utils/locale-to-flag.d.mts +119 -0
  260. package/dist/client/utils/locale-to-flag.mjs +129 -0
  261. package/dist/client/utils/routes.mjs +195 -0
  262. package/dist/client/views/auth/accept-invite-form.d.mts +72 -0
  263. package/dist/client/views/auth/accept-invite-form.mjs +473 -0
  264. package/dist/client/views/auth/auth-layout.d.mts +43 -0
  265. package/dist/client/views/auth/auth-layout.mjs +116 -0
  266. package/dist/client/views/auth/forgot-password-form.d.mts +58 -0
  267. package/dist/client/views/auth/forgot-password-form.mjs +386 -0
  268. package/dist/client/views/auth/invite-form.mjs +497 -0
  269. package/dist/client/views/auth/login-form.d.mts +75 -0
  270. package/dist/client/views/auth/login-form.mjs +387 -0
  271. package/dist/client/views/auth/reset-password-form.d.mts +65 -0
  272. package/dist/client/views/auth/reset-password-form.mjs +515 -0
  273. package/dist/client/views/auth/setup-form.d.mts +60 -0
  274. package/dist/client/views/auth/setup-form.mjs +526 -0
  275. package/dist/client/views/collection/auto-form-fields.mjs +873 -0
  276. package/dist/client/views/collection/bulk-action-toolbar.mjs +480 -0
  277. package/dist/client/views/collection/cells/complex-cells.mjs +746 -0
  278. package/dist/client/views/collection/cells/primitive-cells.mjs +395 -0
  279. package/dist/client/views/collection/cells/relation-cells.mjs +260 -0
  280. package/dist/client/views/collection/cells/shared/asset-thumbnail.mjs +509 -0
  281. package/dist/client/views/collection/cells/shared/cell-helpers.mjs +125 -0
  282. package/dist/client/views/collection/cells/shared/relation-chip.mjs +121 -0
  283. package/dist/client/views/collection/cells/upload-cells.mjs +28 -0
  284. package/dist/client/views/collection/columns/build-columns.mjs +195 -0
  285. package/dist/client/views/collection/columns/column-defaults.mjs +123 -0
  286. package/dist/client/views/collection/field-context.mjs +126 -0
  287. package/dist/client/views/collection/field-renderer.mjs +368 -0
  288. package/dist/client/views/collection/form-view.mjs +1566 -0
  289. package/dist/client/views/collection/table-view.mjs +832 -0
  290. package/dist/client/views/collection/view-skeletons.mjs +215 -0
  291. package/dist/client/views/common/global-search.mjs +700 -0
  292. package/dist/client/views/dashboard/dashboard-grid.mjs +881 -0
  293. package/dist/client/views/dashboard/dashboard-widget.mjs +265 -0
  294. package/dist/client/views/dashboard/widget-card.mjs +372 -0
  295. package/dist/client/views/globals/global-form-view.mjs +1306 -0
  296. package/dist/client/views/layout/admin-layout-provider.d.mts +137 -0
  297. package/dist/client/views/layout/admin-layout-provider.mjs +193 -0
  298. package/dist/client/views/layout/admin-layout.d.mts +133 -0
  299. package/dist/client/views/layout/admin-layout.mjs +302 -0
  300. package/dist/client/views/layout/admin-router.d.mts +93 -0
  301. package/dist/client/views/layout/admin-router.mjs +1254 -0
  302. package/dist/client/views/layout/admin-sidebar.d.mts +99 -0
  303. package/dist/client/views/layout/admin-sidebar.mjs +1379 -0
  304. package/dist/client/views/layout/admin-topbar.mjs +236 -0
  305. package/dist/client/views/pages/accept-invite-page.d.mts +66 -0
  306. package/dist/client/views/pages/accept-invite-page.mjs +349 -0
  307. package/dist/client/views/pages/dashboard-page.d.mts +43 -0
  308. package/dist/client/views/pages/dashboard-page.mjs +84 -0
  309. package/dist/client/views/pages/forgot-password-page.d.mts +56 -0
  310. package/dist/client/views/pages/forgot-password-page.mjs +152 -0
  311. package/dist/client/views/pages/invite-page.d.mts +70 -0
  312. package/dist/client/views/pages/invite-page.mjs +161 -0
  313. package/dist/client/views/pages/login-page.d.mts +69 -0
  314. package/dist/client/views/pages/login-page.mjs +193 -0
  315. package/dist/client/views/pages/reset-password-page.d.mts +63 -0
  316. package/dist/client/views/pages/reset-password-page.mjs +257 -0
  317. package/dist/client/views/pages/setup-page.d.mts +61 -0
  318. package/dist/client/views/pages/setup-page.mjs +156 -0
  319. package/dist/client-module.d.mts +3 -0
  320. package/dist/client-module.mjs +3 -0
  321. package/dist/client.d.mts +99 -3
  322. package/dist/client.mjs +52 -12
  323. package/dist/components/rich-text/index.d.mts +1 -0
  324. package/dist/components/rich-text/rich-text-renderer.d.mts +103 -0
  325. package/dist/components/rich-text/rich-text-renderer.mjs +237 -0
  326. package/dist/index.d.mts +59 -3
  327. package/dist/index.mjs +52 -12
  328. package/dist/plugin.d.mts +2 -0
  329. package/dist/plugin.mjs +3 -0
  330. package/dist/server/adapters/nextjs.d.mts +120 -0
  331. package/dist/server/adapters/nextjs.mjs +110 -0
  332. package/dist/server/adapters/tanstack.d.mts +132 -0
  333. package/dist/server/adapters/tanstack.mjs +89 -0
  334. package/dist/server/augmentation/actions.d.mts +279 -0
  335. package/dist/server/augmentation/common.d.mts +76 -0
  336. package/dist/server/augmentation/dashboard.d.mts +547 -0
  337. package/dist/server/augmentation/form-layout.d.mts +303 -0
  338. package/dist/server/augmentation/index.d.mts +44 -0
  339. package/dist/server/augmentation/index.mjs +10 -0
  340. package/dist/server/augmentation/sidebar.d.mts +181 -0
  341. package/dist/server/augmentation/views.d.mts +237 -0
  342. package/dist/server/augmentation.d.mts +7 -0
  343. package/dist/server/block/index.d.mts +4 -0
  344. package/dist/server/codegen/admin-client-template.mjs +93 -0
  345. package/dist/server/codegen/projection-validator.mjs +67 -0
  346. package/dist/server/fields/blocks.d.mts +71 -0
  347. package/dist/server/fields/blocks.mjs +151 -0
  348. package/dist/server/fields/index.d.mts +15 -0
  349. package/dist/server/fields/index.mjs +15 -0
  350. package/dist/server/fields/rich-text.d.mts +68 -0
  351. package/dist/server/fields/rich-text.mjs +147 -0
  352. package/dist/server/i18n/index.mjs +43 -0
  353. package/dist/server/i18n/messages/cs.mjs +461 -0
  354. package/dist/server/i18n/messages/de.mjs +461 -0
  355. package/dist/server/i18n/messages/en.mjs +707 -0
  356. package/dist/server/i18n/messages/es.mjs +461 -0
  357. package/dist/server/i18n/messages/fr.mjs +461 -0
  358. package/dist/server/i18n/messages/index.mjs +23 -0
  359. package/dist/server/i18n/messages/pl.mjs +461 -0
  360. package/dist/server/i18n/messages/pt.mjs +464 -0
  361. package/dist/server/i18n/messages/sk.mjs +689 -0
  362. package/dist/server/modules/admin/.generated/module.d.mts +52 -0
  363. package/dist/server/modules/admin/.generated/module.mjs +78 -0
  364. package/dist/server/modules/admin/.generated/registries.d.mts +22 -0
  365. package/dist/server/modules/admin/auth-helpers.d.mts +142 -0
  366. package/dist/server/modules/admin/auth-helpers.mjs +107 -0
  367. package/dist/server/modules/admin/block/block-builder.d.mts +383 -0
  368. package/dist/server/modules/admin/block/block-builder.mjs +315 -0
  369. package/dist/server/modules/admin/block/index.d.mts +3 -0
  370. package/dist/server/modules/admin/block/introspection.d.mts +89 -0
  371. package/dist/server/modules/admin/block/introspection.mjs +100 -0
  372. package/dist/server/modules/admin/block/prefetch.d.mts +78 -0
  373. package/dist/server/modules/admin/block/prefetch.mjs +241 -0
  374. package/dist/server/modules/admin/client/.generated/module.d.mts +94 -0
  375. package/dist/server/modules/admin/client/.generated/module.mjs +91 -0
  376. package/dist/server/modules/admin/client/components/badge.d.mts +1 -0
  377. package/dist/server/modules/admin/client/components/icon.d.mts +1 -0
  378. package/dist/server/modules/admin/client/fields/array.d.mts +6 -0
  379. package/dist/server/modules/admin/client/fields/array.mjs +12 -0
  380. package/dist/server/modules/admin/client/fields/assetPreview.d.mts +6 -0
  381. package/dist/server/modules/admin/client/fields/assetPreview.mjs +18 -0
  382. package/dist/server/modules/admin/client/fields/blocks.d.mts +6 -0
  383. package/dist/server/modules/admin/client/fields/blocks.mjs +12 -0
  384. package/dist/server/modules/admin/client/fields/boolean.d.mts +6 -0
  385. package/dist/server/modules/admin/client/fields/boolean.mjs +12 -0
  386. package/dist/server/modules/admin/client/fields/date.d.mts +6 -0
  387. package/dist/server/modules/admin/client/fields/date.mjs +12 -0
  388. package/dist/server/modules/admin/client/fields/datetime.d.mts +6 -0
  389. package/dist/server/modules/admin/client/fields/datetime.mjs +12 -0
  390. package/dist/server/modules/admin/client/fields/email.d.mts +6 -0
  391. package/dist/server/modules/admin/client/fields/email.mjs +12 -0
  392. package/dist/server/modules/admin/client/fields/json.d.mts +6 -0
  393. package/dist/server/modules/admin/client/fields/json.mjs +11 -0
  394. package/dist/server/modules/admin/client/fields/number.d.mts +6 -0
  395. package/dist/server/modules/admin/client/fields/number.mjs +12 -0
  396. package/dist/server/modules/admin/client/fields/object.d.mts +6 -0
  397. package/dist/server/modules/admin/client/fields/object.mjs +12 -0
  398. package/dist/server/modules/admin/client/fields/relation.d.mts +6 -0
  399. package/dist/server/modules/admin/client/fields/relation.mjs +12 -0
  400. package/dist/server/modules/admin/client/fields/richText.d.mts +6 -0
  401. package/dist/server/modules/admin/client/fields/richText.mjs +11 -0
  402. package/dist/server/modules/admin/client/fields/select.d.mts +6 -0
  403. package/dist/server/modules/admin/client/fields/select.mjs +12 -0
  404. package/dist/server/modules/admin/client/fields/text.d.mts +6 -0
  405. package/dist/server/modules/admin/client/fields/text.mjs +12 -0
  406. package/dist/server/modules/admin/client/fields/textarea.d.mts +6 -0
  407. package/dist/server/modules/admin/client/fields/textarea.mjs +12 -0
  408. package/dist/server/modules/admin/client/fields/time.d.mts +6 -0
  409. package/dist/server/modules/admin/client/fields/time.mjs +12 -0
  410. package/dist/server/modules/admin/client/fields/upload.d.mts +6 -0
  411. package/dist/server/modules/admin/client/fields/upload.mjs +12 -0
  412. package/dist/server/modules/admin/client/fields/url.d.mts +6 -0
  413. package/dist/server/modules/admin/client/fields/url.mjs +12 -0
  414. package/dist/server/modules/admin/client/index.d.mts +1 -0
  415. package/dist/server/modules/admin/client/pages/dashboard.d.mts +6 -0
  416. package/dist/server/modules/admin/client/pages/dashboard.mjs +11 -0
  417. package/dist/server/modules/admin/client/pages/forgotPassword.d.mts +6 -0
  418. package/dist/server/modules/admin/client/pages/forgotPassword.mjs +11 -0
  419. package/dist/server/modules/admin/client/pages/login.d.mts +6 -0
  420. package/dist/server/modules/admin/client/pages/login.mjs +11 -0
  421. package/dist/server/modules/admin/client/pages/resetPassword.d.mts +6 -0
  422. package/dist/server/modules/admin/client/pages/resetPassword.mjs +11 -0
  423. package/dist/server/modules/admin/client/pages/setup.d.mts +6 -0
  424. package/dist/server/modules/admin/client/pages/setup.mjs +11 -0
  425. package/dist/server/modules/admin/client/views/collection-form.mjs +10 -0
  426. package/dist/server/modules/admin/client/views/collection-table.mjs +10 -0
  427. package/dist/server/modules/admin/client/views/global-form.mjs +10 -0
  428. package/dist/server/modules/admin/client/widgets/chart.d.mts +6 -0
  429. package/dist/server/modules/admin/client/widgets/chart.mjs +7 -0
  430. package/dist/server/modules/admin/client/widgets/progress.d.mts +6 -0
  431. package/dist/server/modules/admin/client/widgets/progress.mjs +7 -0
  432. package/dist/server/modules/admin/client/widgets/quickActions.d.mts +6 -0
  433. package/dist/server/modules/admin/client/widgets/quickActions.mjs +7 -0
  434. package/dist/server/modules/admin/client/widgets/recentItems.d.mts +6 -0
  435. package/dist/server/modules/admin/client/widgets/recentItems.mjs +7 -0
  436. package/dist/server/modules/admin/client/widgets/stats.d.mts +6 -0
  437. package/dist/server/modules/admin/client/widgets/stats.mjs +7 -0
  438. package/dist/server/modules/admin/client/widgets/table.d.mts +6 -0
  439. package/dist/server/modules/admin/client/widgets/table.mjs +7 -0
  440. package/dist/server/modules/admin/client/widgets/timeline.d.mts +6 -0
  441. package/dist/server/modules/admin/client/widgets/timeline.mjs +7 -0
  442. package/dist/server/modules/admin/client/widgets/value.d.mts +6 -0
  443. package/dist/server/modules/admin/client/widgets/value.mjs +7 -0
  444. package/dist/server/modules/admin/collections/account.d.mts +77 -0
  445. package/dist/server/modules/admin/collections/account.mjs +23 -0
  446. package/dist/server/modules/admin/collections/admin-locks.d.mts +90 -0
  447. package/dist/server/modules/admin/collections/admin-locks.mjs +16 -0
  448. package/dist/server/modules/admin/collections/admin-preferences.d.mts +69 -0
  449. package/dist/server/modules/admin/collections/admin-preferences.mjs +16 -0
  450. package/dist/server/modules/admin/collections/admin-saved-views.d.mts +83 -0
  451. package/dist/server/modules/admin/collections/admin-saved-views.mjs +16 -0
  452. package/dist/server/modules/admin/collections/apikey.d.mts +99 -0
  453. package/dist/server/modules/admin/collections/apikey.mjs +15 -0
  454. package/dist/server/modules/admin/collections/assets.d.mts +72 -0
  455. package/dist/server/modules/admin/collections/assets.mjs +71 -0
  456. package/dist/server/modules/admin/collections/session.d.mts +69 -0
  457. package/dist/server/modules/admin/collections/session.mjs +15 -0
  458. package/dist/server/modules/admin/collections/user.d.mts +85 -0
  459. package/dist/server/modules/admin/collections/user.mjs +204 -0
  460. package/dist/server/modules/admin/collections/verification.d.mts +63 -0
  461. package/dist/server/modules/admin/collections/verification.mjs +15 -0
  462. package/dist/server/modules/admin/components/badge.d.mts +10 -0
  463. package/dist/server/modules/admin/components/badge.mjs +10 -0
  464. package/dist/server/modules/admin/components/icon.d.mts +9 -0
  465. package/dist/server/modules/admin/components/icon.mjs +11 -0
  466. package/dist/server/modules/admin/config/admin.mjs +34 -0
  467. package/dist/server/modules/admin/dto/admin-config.dto.mjs +102 -0
  468. package/dist/server/modules/admin/factories.mjs +172 -0
  469. package/dist/server/modules/admin/index.d.mts +1093 -0
  470. package/dist/server/modules/admin/index.mjs +26 -0
  471. package/dist/server/modules/admin/modules.mjs +11 -0
  472. package/dist/server/modules/admin/plugin.mjs +13 -0
  473. package/dist/server/modules/admin/routes/admin-config.d.mts +28 -0
  474. package/dist/server/modules/admin/routes/admin-config.mjs +552 -0
  475. package/dist/server/modules/admin/routes/execute-action.d.mts +92 -0
  476. package/dist/server/modules/admin/routes/execute-action.mjs +433 -0
  477. package/dist/server/modules/admin/routes/locales.d.mts +18 -0
  478. package/dist/server/modules/admin/routes/locales.mjs +69 -0
  479. package/dist/server/modules/admin/routes/preview.d.mts +80 -0
  480. package/dist/server/modules/admin/routes/preview.mjs +230 -0
  481. package/dist/server/modules/admin/routes/reactive.d.mts +74 -0
  482. package/dist/server/modules/admin/routes/reactive.mjs +350 -0
  483. package/dist/server/modules/admin/routes/route-helpers.d.mts +23 -0
  484. package/dist/server/modules/admin/routes/route-helpers.mjs +76 -0
  485. package/dist/server/modules/admin/routes/setup.d.mts +63 -0
  486. package/dist/server/modules/admin/routes/setup.mjs +114 -0
  487. package/dist/server/modules/admin/routes/translations.d.mts +26 -0
  488. package/dist/server/modules/admin/routes/translations.mjs +114 -0
  489. package/dist/server/modules/admin/routes/widget-data.d.mts +32 -0
  490. package/dist/server/modules/admin/routes/widget-data.mjs +62 -0
  491. package/dist/server/modules/admin/views/form.d.mts +8 -0
  492. package/dist/server/modules/admin/views/form.mjs +7 -0
  493. package/dist/server/modules/admin/views/global-form.d.mts +8 -0
  494. package/dist/server/modules/admin/views/global-form.mjs +7 -0
  495. package/dist/server/modules/admin/views/table.d.mts +8 -0
  496. package/dist/server/modules/admin/views/table.mjs +7 -0
  497. package/dist/server/modules/admin-preferences/collections/admin-preferences.mjs +37 -0
  498. package/dist/server/modules/admin-preferences/collections/locks.collection.mjs +55 -0
  499. package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +99 -0
  500. package/dist/server/modules/admin-preferences/collections/saved-views.mjs +38 -0
  501. package/dist/server/modules/audit/.generated/module.d.mts +60 -0
  502. package/dist/server/modules/audit/.generated/module.mjs +30 -0
  503. package/dist/server/modules/audit/collections/audit-log.d.mts +214 -0
  504. package/dist/server/modules/audit/collections/audit-log.mjs +107 -0
  505. package/dist/server/modules/audit/config/admin.mjs +21 -0
  506. package/dist/server/modules/audit/config/app.mjs +262 -0
  507. package/dist/server/modules/audit/index.d.mts +2 -0
  508. package/dist/server/modules/audit/jobs/audit-cleanup.d.mts +13 -0
  509. package/dist/server/modules/audit/jobs/audit-cleanup.mjs +28 -0
  510. package/dist/server/plugin.d.mts +26 -0
  511. package/dist/server/plugin.mjs +385 -0
  512. package/dist/server/proxy-factories.d.mts +85 -0
  513. package/dist/server/proxy-factories.mjs +302 -0
  514. package/dist/server/registry-helpers.d.mts +83 -0
  515. package/dist/server/registry-helpers.mjs +104 -0
  516. package/dist/server.d.mts +33 -250
  517. package/dist/server.mjs +22 -832
  518. package/dist/shared/preview-utils.d.mts +53 -0
  519. package/dist/{preview-utils-BKQ9-TMa.mjs → shared/preview-utils.mjs} +2 -3
  520. package/dist/{saved-views.types-BMsz5mCy.d.mts → shared/types/saved-views.types.d.mts} +7 -2
  521. package/dist/shared.d.mts +3 -57
  522. package/dist/shared.mjs +1 -1
  523. package/package.json +56 -51
  524. package/skills/questpie-admin/SKILL.md +397 -0
  525. package/skills/questpie-admin/blocks/SKILL.md +305 -0
  526. package/skills/questpie-admin/custom-ui/SKILL.md +307 -0
  527. package/skills/questpie-admin/views/SKILL.md +442 -0
  528. package/dist/auth-layout-M8K8_q5R.mjs +0 -181
  529. package/dist/auth-layout-M8K8_q5R.mjs.map +0 -1
  530. package/dist/bulk-upload-dialog-D7w7W1Hl.mjs +0 -273
  531. package/dist/bulk-upload-dialog-D7w7W1Hl.mjs.map +0 -1
  532. package/dist/card-BKHjBQfw.mjs +0 -58
  533. package/dist/card-BKHjBQfw.mjs.map +0 -1
  534. package/dist/client-D1DqawtP.d.mts +0 -13403
  535. package/dist/client-D1DqawtP.d.mts.map +0 -1
  536. package/dist/client-njX1rZmi.mjs +0 -22612
  537. package/dist/client-njX1rZmi.mjs.map +0 -1
  538. package/dist/content-locales-provider-BXvuIgfg.mjs +0 -1650
  539. package/dist/content-locales-provider-BXvuIgfg.mjs.map +0 -1
  540. package/dist/dashboard-page-B4PGEdc2.mjs +0 -2500
  541. package/dist/dashboard-page-B4PGEdc2.mjs.map +0 -1
  542. package/dist/dashboard-page-mCY0pgZv.mjs +0 -3
  543. package/dist/dropzone-Do3awXKd.mjs +0 -634
  544. package/dist/dropzone-Do3awXKd.mjs.map +0 -1
  545. package/dist/forgot-password-page-Bcp-An4Y.mjs +0 -221
  546. package/dist/forgot-password-page-Bcp-An4Y.mjs.map +0 -1
  547. package/dist/forgot-password-page-CEwsdLwn.mjs +0 -3
  548. package/dist/index-B4H3amCD.d.mts +0 -2753
  549. package/dist/index-B4H3amCD.d.mts.map +0 -1
  550. package/dist/login-page-BUnpCbCa.mjs +0 -3
  551. package/dist/login-page-CP4gA-dl.mjs +0 -298
  552. package/dist/login-page-CP4gA-dl.mjs.map +0 -1
  553. package/dist/preview-utils-BKQ9-TMa.mjs.map +0 -1
  554. package/dist/reset-password-page-BqfDmLxA.mjs +0 -281
  555. package/dist/reset-password-page-BqfDmLxA.mjs.map +0 -1
  556. package/dist/reset-password-page-CufHz3h3.mjs +0 -3
  557. package/dist/runtime-6VZM878K.mjs +0 -69
  558. package/dist/runtime-6VZM878K.mjs.map +0 -1
  559. package/dist/saved-views.types-BMsz5mCy.d.mts.map +0 -1
  560. package/dist/server.d.mts.map +0 -1
  561. package/dist/server.mjs.map +0 -1
  562. package/dist/setup-page-BNNzt_Z6.mjs +0 -3
  563. package/dist/setup-page-YAP_fzqh.mjs +0 -264
  564. package/dist/setup-page-YAP_fzqh.mjs.map +0 -1
  565. package/dist/shared.d.mts.map +0 -1
  566. package/dist/use-auth-BoLmWtmU.mjs.map +0 -1
@@ -0,0 +1,1566 @@
1
+ import { useResolveText, useTranslation } from "../../i18n/hooks.mjs";
2
+ import { selectBasePath, selectClient, selectNavigate, useAdminStore } from "../../runtime/provider.mjs";
3
+ import { useSafeContentLocales } from "../../runtime/content-locales-provider.mjs";
4
+ import { useScopedLocale } from "../../runtime/locale-scope.mjs";
5
+ import { resolveIconElement } from "../../components/component-renderer.mjs";
6
+ import { Button } from "../../components/ui/button.mjs";
7
+ import { Badge } from "../../components/ui/badge.mjs";
8
+ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "../../components/ui/dialog.mjs";
9
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "../../components/ui/dropdown-menu.mjs";
10
+ import { LocaleSwitcher } from "../../components/locale-switcher.mjs";
11
+ import { Label } from "../../components/ui/label.mjs";
12
+ import { RenderProfiler } from "../../lib/render-profiler.mjs";
13
+ import { Checkbox } from "../../components/ui/checkbox.mjs";
14
+ import { DateTimeInput } from "../../components/primitives/date-input.mjs";
15
+ import { getDefaultFormActions } from "../../builder/types/action-registry.mjs";
16
+ import { ConfirmationDialog } from "../../components/actions/confirmation-dialog.mjs";
17
+ import { ActionButton } from "../../components/actions/action-button.mjs";
18
+ import { useCollectionFields } from "../../hooks/use-collection-fields.mjs";
19
+ import { AutoFormFields } from "./auto-form-fields.mjs";
20
+ import { ActionDialog } from "../../components/actions/action-dialog.mjs";
21
+ import { HistorySidebar } from "../../components/history-sidebar.mjs";
22
+ import { LivePreviewMode } from "../../components/preview/live-preview-mode.mjs";
23
+ import { useCollectionValidation } from "../../hooks/use-collection-validation.mjs";
24
+ import { useSearchParamToggle } from "../../hooks/use-search-param-toggle.mjs";
25
+ import { usePreferServerValidation } from "../../hooks/use-server-validation.mjs";
26
+ import { useSidebarSearchParam } from "../../hooks/use-sidebar-search-param.mjs";
27
+ import { useCollectionAuditHistory } from "../../hooks/use-audit-history.mjs";
28
+ import { useCollectionCreate, useCollectionDelete, useCollectionItem, useCollectionRestore, useCollectionRevertVersion, useCollectionUpdate, useCollectionVersions } from "../../hooks/use-collection.mjs";
29
+ import { getLockUser, useLock } from "../../hooks/use-locks.mjs";
30
+ import { useReactiveFields } from "../../hooks/use-reactive-fields.mjs";
31
+ import { useServerActions } from "../../hooks/use-server-actions.mjs";
32
+ import { useTransitionStage } from "../../hooks/use-transition-stage.mjs";
33
+ import { detectManyToManyRelations, hasManyToManyRelations } from "../../utils/detect-relations.mjs";
34
+ import { FormViewSkeleton } from "./view-skeletons.mjs";
35
+ import { c } from "react/compiler-runtime";
36
+ import { Icon } from "@iconify/react";
37
+ import * as React from "react";
38
+ import { useQuery, useQueryClient } from "@tanstack/react-query";
39
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
40
+ import { FormProvider, useForm, useFormState } from "react-hook-form";
41
+ import { toast } from "sonner";
42
+ import { createQuestpieQueryOptions } from "@questpie/tanstack-query";
43
+ import { QuestpieClientError } from "questpie/client";
44
+
45
+ //#region src/client/views/collection/form-view.tsx
46
+ /**
47
+ * Form View - Default edit view component
48
+ *
49
+ * Renders collection item edit/create form with sections, tabs, validation.
50
+ * This is the default edit view registered in the admin view registry.
51
+ */
52
+ /** Query key prefix for app queries (used for cache invalidation) */
53
+ const QUERY_KEY_PREFIX = ["questpie", "collections"];
54
+ /**
55
+ * Extract reactive configs from collection schema fields.
56
+ * Used to determine which fields have server-side reactive behaviors.
57
+ */
58
+ function extractReactiveConfigs(schema) {
59
+ if (!schema?.fields) return {};
60
+ const configs = {};
61
+ for (const [fieldName, fieldDef] of Object.entries(schema.fields)) if (fieldDef.reactive) configs[fieldName] = fieldDef.reactive;
62
+ return configs;
63
+ }
64
+ /**
65
+ * Component that manages reactive field states.
66
+ * Must be rendered inside FormProvider to access form context.
67
+ */
68
+ function ReactiveFieldsManager(t0) {
69
+ const $ = c(8);
70
+ const { collection, mode: t1, reactiveConfigs, enabled } = t0;
71
+ const mode = t1 === void 0 ? "collection" : t1;
72
+ let t2;
73
+ if ($[0] !== enabled || $[1] !== reactiveConfigs) {
74
+ t2 = enabled && Object.keys(reactiveConfigs).length > 0;
75
+ $[0] = enabled;
76
+ $[1] = reactiveConfigs;
77
+ $[2] = t2;
78
+ } else t2 = $[2];
79
+ let t3;
80
+ if ($[3] !== collection || $[4] !== mode || $[5] !== reactiveConfigs || $[6] !== t2) {
81
+ t3 = {
82
+ collection,
83
+ mode,
84
+ reactiveConfigs,
85
+ enabled: t2,
86
+ debounce: 300
87
+ };
88
+ $[3] = collection;
89
+ $[4] = mode;
90
+ $[5] = reactiveConfigs;
91
+ $[6] = t2;
92
+ $[7] = t3;
93
+ } else t3 = $[7];
94
+ useReactiveFields(t3);
95
+ return null;
96
+ }
97
+ const FormFieldsContent = React.memo(function FormFieldsContent$1(t0) {
98
+ const $ = c(8);
99
+ const { collection, config, registry, allCollectionsConfig } = t0;
100
+ const t1 = `form.fields.${collection}`;
101
+ const t2 = collection;
102
+ const t3 = config;
103
+ const t4 = allCollectionsConfig;
104
+ let t5;
105
+ if ($[0] !== registry || $[1] !== t2 || $[2] !== t3 || $[3] !== t4) {
106
+ t5 = /* @__PURE__ */ jsx(AutoFormFields, {
107
+ collection: t2,
108
+ config: t3,
109
+ registry,
110
+ allCollectionsConfig: t4
111
+ });
112
+ $[0] = registry;
113
+ $[1] = t2;
114
+ $[2] = t3;
115
+ $[3] = t4;
116
+ $[4] = t5;
117
+ } else t5 = $[4];
118
+ let t6;
119
+ if ($[5] !== t1 || $[6] !== t5) {
120
+ t6 = /* @__PURE__ */ jsx(RenderProfiler, {
121
+ id: t1,
122
+ minDurationMs: 10,
123
+ children: t5
124
+ });
125
+ $[5] = t1;
126
+ $[6] = t5;
127
+ $[7] = t6;
128
+ } else t6 = $[7];
129
+ return t6;
130
+ });
131
+ const FormStateRefBridge = React.memo(function FormStateRefBridge$1(t0) {
132
+ const $ = c(10);
133
+ const { control, onDirtyChange, onSubmittingChange } = t0;
134
+ let t1;
135
+ if ($[0] !== control) {
136
+ t1 = { control };
137
+ $[0] = control;
138
+ $[1] = t1;
139
+ } else t1 = $[1];
140
+ const { isDirty, isSubmitting } = useFormState(t1);
141
+ let t2;
142
+ let t3;
143
+ if ($[2] !== isDirty || $[3] !== onDirtyChange) {
144
+ t2 = () => {
145
+ onDirtyChange(isDirty);
146
+ };
147
+ t3 = [isDirty, onDirtyChange];
148
+ $[2] = isDirty;
149
+ $[3] = onDirtyChange;
150
+ $[4] = t2;
151
+ $[5] = t3;
152
+ } else {
153
+ t2 = $[4];
154
+ t3 = $[5];
155
+ }
156
+ React.useEffect(t2, t3);
157
+ let t4;
158
+ let t5;
159
+ if ($[6] !== isSubmitting || $[7] !== onSubmittingChange) {
160
+ t4 = () => {
161
+ onSubmittingChange(isSubmitting);
162
+ };
163
+ t5 = [isSubmitting, onSubmittingChange];
164
+ $[6] = isSubmitting;
165
+ $[7] = onSubmittingChange;
166
+ $[8] = t4;
167
+ $[9] = t5;
168
+ } else {
169
+ t4 = $[8];
170
+ t5 = $[9];
171
+ }
172
+ React.useEffect(t4, t5);
173
+ return null;
174
+ });
175
+ const AutosaveManager = React.memo(function AutosaveManager$1(t0) {
176
+ const $ = c(18);
177
+ const { form, formElementRef, isEditMode, id, enabled, debounce, isDirtyRef, isSubmittingRef, updateMutation, onPreviewRefresh, onSavingChange, onSaved } = t0;
178
+ const { t } = useTranslation();
179
+ const timerRef = React.useRef(null);
180
+ let t1;
181
+ if ($[0] !== form || $[1] !== id || $[2] !== isDirtyRef || $[3] !== isSubmittingRef || $[4] !== onPreviewRefresh || $[5] !== onSaved || $[6] !== onSavingChange || $[7] !== t || $[8] !== updateMutation) {
182
+ t1 = async () => {
183
+ if (!id || !isDirtyRef.current || isSubmittingRef.current) return;
184
+ try {
185
+ onSavingChange(true);
186
+ await form.handleSubmit(async (data) => {
187
+ const result = await updateMutation.mutateAsync({
188
+ id,
189
+ data
190
+ });
191
+ form.reset(result, { keepTouched: true });
192
+ onPreviewRefresh?.();
193
+ onSaved(/* @__PURE__ */ new Date());
194
+ onSavingChange(false);
195
+ }, () => {
196
+ onSavingChange(false);
197
+ })();
198
+ } catch (t2$1) {
199
+ const error = t2$1;
200
+ onSavingChange(false);
201
+ console.error("Autosave failed:", error);
202
+ toast.error(t("error.autosaveFailed"), { description: error instanceof Error ? error.message : void 0 });
203
+ }
204
+ };
205
+ $[0] = form;
206
+ $[1] = id;
207
+ $[2] = isDirtyRef;
208
+ $[3] = isSubmittingRef;
209
+ $[4] = onPreviewRefresh;
210
+ $[5] = onSaved;
211
+ $[6] = onSavingChange;
212
+ $[7] = t;
213
+ $[8] = updateMutation;
214
+ $[9] = t1;
215
+ } else t1 = $[9];
216
+ const runAutosave = t1;
217
+ let t2;
218
+ let t3;
219
+ if ($[10] !== debounce || $[11] !== enabled || $[12] !== formElementRef || $[13] !== id || $[14] !== isEditMode || $[15] !== runAutosave) {
220
+ t2 = () => {
221
+ if (timerRef.current) clearTimeout(timerRef.current);
222
+ if (!enabled || !isEditMode || !id) return;
223
+ const target = formElementRef.current;
224
+ if (!target) return;
225
+ const scheduleAutosave = () => {
226
+ if (timerRef.current) clearTimeout(timerRef.current);
227
+ timerRef.current = setTimeout(() => {
228
+ runAutosave();
229
+ }, debounce);
230
+ };
231
+ target.addEventListener("input", scheduleAutosave, { capture: true });
232
+ target.addEventListener("change", scheduleAutosave, { capture: true });
233
+ return () => {
234
+ target.removeEventListener("input", scheduleAutosave, { capture: true });
235
+ target.removeEventListener("change", scheduleAutosave, { capture: true });
236
+ if (timerRef.current) clearTimeout(timerRef.current);
237
+ };
238
+ };
239
+ t3 = [
240
+ debounce,
241
+ enabled,
242
+ formElementRef,
243
+ id,
244
+ isEditMode,
245
+ runAutosave
246
+ ];
247
+ $[10] = debounce;
248
+ $[11] = enabled;
249
+ $[12] = formElementRef;
250
+ $[13] = id;
251
+ $[14] = isEditMode;
252
+ $[15] = runAutosave;
253
+ $[16] = t2;
254
+ $[17] = t3;
255
+ } else {
256
+ t2 = $[16];
257
+ t3 = $[17];
258
+ }
259
+ React.useEffect(t2, t3);
260
+ return null;
261
+ });
262
+ const AutosaveIndicator = React.memo(function AutosaveIndicator$1(t0) {
263
+ const $ = c(26);
264
+ const { control, enabled, indicator, isEditMode, isSaving, lastSaved, formatTimeAgo, t } = t0;
265
+ let t1;
266
+ if ($[0] !== control) {
267
+ t1 = { control };
268
+ $[0] = control;
269
+ $[1] = t1;
270
+ } else t1 = $[1];
271
+ const { isDirty } = useFormState(t1);
272
+ const [, forceUpdate] = React.useReducer(_temp, 0);
273
+ let t2;
274
+ if ($[2] !== forceUpdate || $[3] !== lastSaved) {
275
+ t2 = () => {
276
+ if (!lastSaved) return;
277
+ const interval = setInterval(forceUpdate, 1e4);
278
+ return () => clearInterval(interval);
279
+ };
280
+ $[2] = forceUpdate;
281
+ $[3] = lastSaved;
282
+ $[4] = t2;
283
+ } else t2 = $[4];
284
+ let t3;
285
+ if ($[5] !== lastSaved) {
286
+ t3 = [lastSaved];
287
+ $[5] = lastSaved;
288
+ $[6] = t3;
289
+ } else t3 = $[6];
290
+ React.useEffect(t2, t3);
291
+ if (!enabled || !indicator || !isEditMode) return null;
292
+ if (isSaving) {
293
+ let t4;
294
+ if ($[7] === Symbol.for("react.memo_cache_sentinel")) {
295
+ t4 = /* @__PURE__ */ jsx(Icon, {
296
+ icon: "ph:spinner-gap",
297
+ className: "size-3 animate-spin"
298
+ });
299
+ $[7] = t4;
300
+ } else t4 = $[7];
301
+ let t5;
302
+ if ($[8] !== t) {
303
+ t5 = t("autosave.saving");
304
+ $[8] = t;
305
+ $[9] = t5;
306
+ } else t5 = $[9];
307
+ let t6;
308
+ if ($[10] !== t5) {
309
+ t6 = /* @__PURE__ */ jsxs(Badge, {
310
+ variant: "secondary",
311
+ className: "gap-1.5",
312
+ children: [t4, t5]
313
+ });
314
+ $[10] = t5;
315
+ $[11] = t6;
316
+ } else t6 = $[11];
317
+ return t6;
318
+ }
319
+ if (isDirty) {
320
+ let t4;
321
+ if ($[12] === Symbol.for("react.memo_cache_sentinel")) {
322
+ t4 = /* @__PURE__ */ jsx(Icon, {
323
+ icon: "ph:clock-counter-clockwise",
324
+ className: "size-3"
325
+ });
326
+ $[12] = t4;
327
+ } else t4 = $[12];
328
+ let t5;
329
+ if ($[13] !== t) {
330
+ t5 = t("autosave.unsavedChanges");
331
+ $[13] = t;
332
+ $[14] = t5;
333
+ } else t5 = $[14];
334
+ let t6;
335
+ if ($[15] !== t5) {
336
+ t6 = /* @__PURE__ */ jsxs(Badge, {
337
+ variant: "outline",
338
+ className: "gap-1.5",
339
+ children: [t4, t5]
340
+ });
341
+ $[15] = t5;
342
+ $[16] = t6;
343
+ } else t6 = $[16];
344
+ return t6;
345
+ }
346
+ if (lastSaved) {
347
+ let t4;
348
+ if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
349
+ t4 = /* @__PURE__ */ jsx(Icon, {
350
+ icon: "ph:check",
351
+ className: "size-3"
352
+ });
353
+ $[17] = t4;
354
+ } else t4 = $[17];
355
+ let t5;
356
+ if ($[18] !== t) {
357
+ t5 = t("autosave.saved");
358
+ $[18] = t;
359
+ $[19] = t5;
360
+ } else t5 = $[19];
361
+ let t6;
362
+ if ($[20] !== formatTimeAgo || $[21] !== lastSaved) {
363
+ t6 = formatTimeAgo(lastSaved);
364
+ $[20] = formatTimeAgo;
365
+ $[21] = lastSaved;
366
+ $[22] = t6;
367
+ } else t6 = $[22];
368
+ let t7;
369
+ if ($[23] !== t5 || $[24] !== t6) {
370
+ t7 = /* @__PURE__ */ jsxs(Badge, {
371
+ variant: "secondary",
372
+ className: "text-muted-foreground gap-1.5",
373
+ children: [
374
+ t4,
375
+ t5,
376
+ " ",
377
+ t6
378
+ ]
379
+ });
380
+ $[23] = t5;
381
+ $[24] = t6;
382
+ $[25] = t7;
383
+ } else t7 = $[25];
384
+ return t7;
385
+ }
386
+ return null;
387
+ });
388
+ const SaveSubmitButton = React.memo(function SaveSubmitButton$1(t0) {
389
+ const $ = c(8);
390
+ const { control, isMutationPending, t } = t0;
391
+ let t1;
392
+ if ($[0] !== control) {
393
+ t1 = { control };
394
+ $[0] = control;
395
+ $[1] = t1;
396
+ } else t1 = $[1];
397
+ const { isDirty, isSubmitting } = useFormState(t1);
398
+ const isSubmittingNow = isMutationPending || isSubmitting;
399
+ const t2 = isSubmittingNow || !isDirty;
400
+ let t3;
401
+ if ($[2] !== isSubmittingNow || $[3] !== t) {
402
+ t3 = isSubmittingNow ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Icon, {
403
+ icon: "ph:spinner-gap",
404
+ className: "size-4 animate-spin"
405
+ }), t("common.loading")] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Icon, {
406
+ icon: "ph:check",
407
+ width: 16,
408
+ height: 16
409
+ }), t("common.save")] });
410
+ $[2] = isSubmittingNow;
411
+ $[3] = t;
412
+ $[4] = t3;
413
+ } else t3 = $[4];
414
+ let t4;
415
+ if ($[5] !== t2 || $[6] !== t3) {
416
+ t4 = /* @__PURE__ */ jsx(Button, {
417
+ type: "submit",
418
+ disabled: t2,
419
+ className: "gap-2",
420
+ children: t3
421
+ });
422
+ $[5] = t2;
423
+ $[6] = t3;
424
+ $[7] = t4;
425
+ } else t4 = $[7];
426
+ return t4;
427
+ });
428
+ /**
429
+ * FormView - Default form-based edit/create view for collections
430
+ *
431
+ * Features:
432
+ * - Auto-generates form fields from collection config
433
+ * - Supports tabs, sections, and sidebar layout
434
+ * - Auto-detects M:N relations
435
+ * - Keyboard shortcut (Cmd+S) to save
436
+ * - Field-level validation errors from API
437
+ *
438
+ * @example
439
+ * ```tsx
440
+ * // Used automatically via registry when navigating to /admin/collections/:name/:id
441
+ * // Can also be used directly:
442
+ * <FormView
443
+ * collection="posts"
444
+ * id="123"
445
+ * config={postsConfig}
446
+ * navigate={navigate}
447
+ * basePath="/admin"
448
+ * />
449
+ * ```
450
+ */
451
+ function FormView({ collection, id, config, viewConfig, navigate, basePath = "/admin", defaultValues: defaultValuesProp, registry, allCollectionsConfig, showMeta = true, headerActions, onSuccess, onError }) {
452
+ const { t } = useTranslation();
453
+ const resolveText = useResolveText();
454
+ const isEditMode = !!id;
455
+ const { fields: resolvedFields, schema } = useCollectionFields(collection, { fallbackFields: config?.fields });
456
+ const resolvedFormConfig = React.useMemo(() => viewConfig ?? (config?.form)?.["~config"] ?? config?.form ?? schema?.admin?.form, [
457
+ viewConfig,
458
+ config?.form,
459
+ schema?.admin?.form
460
+ ]);
461
+ const formConfigBridge = React.useMemo(() => {
462
+ if (!resolvedFormConfig) return config;
463
+ return {
464
+ ...config ?? {},
465
+ form: resolvedFormConfig
466
+ };
467
+ }, [config, resolvedFormConfig]);
468
+ const reactiveConfigs = React.useMemo(() => extractReactiveConfigs(schema), [schema]);
469
+ const schemaPreview = schema?.admin?.preview;
470
+ const canUseLivePreview = !!schemaPreview?.hasUrlBuilder && schemaPreview?.enabled !== false && isEditMode && !!id;
471
+ const [isLivePreviewOpen, setIsLivePreviewOpen] = useSearchParamToggle("preview", React.useMemo(() => ({ legacyKeys: [{
472
+ key: "sidebar",
473
+ trueValue: "preview"
474
+ }] }), []));
475
+ const [isHistoryOpen, setIsHistoryOpen] = useSidebarSearchParam("history", { legacyKey: "history" });
476
+ const previewRef = React.useRef(null);
477
+ const triggerPreviewRefresh = React.useCallback(() => {
478
+ if (!isLivePreviewOpen) return;
479
+ previewRef.current?.triggerRefresh();
480
+ }, [isLivePreviewOpen]);
481
+ React.useEffect(() => {
482
+ if (!schema) return;
483
+ if (!canUseLivePreview && isLivePreviewOpen) setIsLivePreviewOpen(false);
484
+ }, [
485
+ canUseLivePreview,
486
+ isLivePreviewOpen,
487
+ setIsLivePreviewOpen,
488
+ schema
489
+ ]);
490
+ React.useEffect(() => {
491
+ if ((!isEditMode || !id) && isHistoryOpen) setIsHistoryOpen(false);
492
+ }, [
493
+ isEditMode,
494
+ id,
495
+ isHistoryOpen,
496
+ setIsHistoryOpen
497
+ ]);
498
+ const withRelations = React.useMemo(() => detectManyToManyRelations({
499
+ fields: resolvedFields,
500
+ schema
501
+ }), [resolvedFields, schema]);
502
+ const { data: item, isLoading, error: itemError } = useCollectionItem(collection, id ?? "", hasManyToManyRelations(withRelations) ? {
503
+ with: withRelations,
504
+ localeFallback: false
505
+ } : { localeFallback: false }, { enabled: isEditMode });
506
+ const { isBlocked, blockedBy, isOpenElsewhere, refresh: refreshLock } = useLock({
507
+ resourceType: "collection",
508
+ resource: collection,
509
+ resourceId: id ?? "",
510
+ autoAcquire: isEditMode
511
+ });
512
+ const blockedByUser = blockedBy ? getLockUser(blockedBy) : null;
513
+ const transformedItem = React.useMemo(() => {
514
+ if (!item || !hasManyToManyRelations(withRelations)) return item;
515
+ const result = { ...item };
516
+ for (const key of Object.keys(withRelations)) {
517
+ const value = result[key];
518
+ if (Array.isArray(value) && value.length > 0 && typeof value[0] === "object" && value[0]?.id) result[key] = value.map((v) => v.id);
519
+ }
520
+ return result;
521
+ }, [item, withRelations]);
522
+ const createMutation = useCollectionCreate(collection);
523
+ const updateMutation = useCollectionUpdate(collection);
524
+ const deleteMutation = useCollectionDelete(collection);
525
+ const restoreMutation = useCollectionRestore(collection);
526
+ const revertVersionMutation = useCollectionRevertVersion(collection);
527
+ const [pendingRevertVersion, setPendingRevertVersion] = React.useState(null);
528
+ const { data: versionsData, isLoading: versionsLoading } = useCollectionVersions(collection, id ?? "", { limit: 50 }, { enabled: isEditMode && !!id && isHistoryOpen && !!schema?.options?.versioning });
529
+ const { data: auditData, isLoading: auditLoading } = useCollectionAuditHistory(collection, id ?? "", { limit: 50 }, { enabled: isEditMode && !!id && isHistoryOpen });
530
+ const workflowConfig = schema?.options?.workflow;
531
+ const workflowEnabled = !!workflowConfig?.enabled;
532
+ /**
533
+ * Lightweight versions query (limit: 1) just to read the current
534
+ * `versionStage`. Runs whenever workflow is enabled and we have an item id.
535
+ * The full 50-version query is still lazy-loaded behind the History sidebar.
536
+ */
537
+ const { data: latestVersionData } = useCollectionVersions(collection, id ?? "", { limit: 1 }, { enabled: workflowEnabled && isEditMode && !!id });
538
+ const currentStage = latestVersionData?.[0]?.versionStage ?? workflowConfig?.initialStage ?? null;
539
+ const currentStageConfig = React.useMemo(() => workflowConfig?.stages?.find((s) => s.name === currentStage) ?? null, [workflowConfig?.stages, currentStage]);
540
+ const currentStageLabel = currentStageConfig?.label ?? currentStage ?? "";
541
+ /**
542
+ * Allowed transitions from the current stage.
543
+ * If the stage defines explicit `transitions`, only those are reachable.
544
+ * Otherwise fall back to all other stages (unrestricted).
545
+ */
546
+ const allowedTransitions = React.useMemo(() => {
547
+ if (!workflowConfig?.stages || !currentStage) return [];
548
+ const stageNames = currentStageConfig?.transitions;
549
+ if (stageNames && stageNames.length > 0) return stageNames.map((name) => workflowConfig.stages.find((s_0) => s_0.name === name)).filter(Boolean);
550
+ return workflowConfig.stages.filter((s_1) => s_1.name !== currentStage);
551
+ }, [
552
+ workflowConfig,
553
+ currentStage,
554
+ currentStageConfig
555
+ ]);
556
+ const transitionMutation = useTransitionStage(collection);
557
+ const [transitionTarget, setTransitionTarget] = React.useState(null);
558
+ const [transitionSchedule, setTransitionSchedule] = React.useState(false);
559
+ const [transitionScheduledAt, setTransitionScheduledAt] = React.useState(null);
560
+ const clientResolver = useCollectionValidation(collection);
561
+ const resolver = usePreferServerValidation(collection, { mode: isEditMode ? "update" : "create" }, clientResolver);
562
+ const form = useForm({
563
+ defaultValues: transformedItem ?? defaultValuesProp ?? {},
564
+ resolver,
565
+ mode: "onBlur"
566
+ });
567
+ /**
568
+ * Execute the confirmed workflow transition (immediate or scheduled).
569
+ */
570
+ const confirmTransition = () => {
571
+ if (!transitionTarget || !id) return;
572
+ const params = {
573
+ id,
574
+ stage: transitionTarget.name
575
+ };
576
+ if (transitionSchedule) {
577
+ if (transitionScheduledAt) params.scheduledAt = transitionScheduledAt;
578
+ }
579
+ const stageLabel = transitionTarget.label ? transitionTarget.label : transitionTarget.name;
580
+ const resetTransitionState = () => {
581
+ setTransitionTarget(null);
582
+ setTransitionSchedule(false);
583
+ setTransitionScheduledAt(null);
584
+ };
585
+ transitionMutation.mutateAsync(params).then((result_0) => {
586
+ if (result_0) {
587
+ if (typeof result_0 === "object") {
588
+ if ("id" in result_0) form.reset(result_0);
589
+ }
590
+ }
591
+ if (transitionSchedule) if (transitionScheduledAt) toast.success(t("workflow.scheduledSuccess", {
592
+ stage: stageLabel,
593
+ date: transitionScheduledAt.toLocaleString()
594
+ }));
595
+ else toast.success(t("workflow.transitionSuccess", { stage: stageLabel }));
596
+ else toast.success(t("workflow.transitionSuccess", { stage: stageLabel }));
597
+ resetTransitionState();
598
+ }, (err) => {
599
+ let description;
600
+ if (err instanceof Error) description = err.message;
601
+ else description = t("error.unknown");
602
+ toast.error(t("workflow.transitionFailed"), { description });
603
+ resetTransitionState();
604
+ });
605
+ };
606
+ const [isSaving, setIsSaving] = React.useState(false);
607
+ const [lastSaved, setLastSaved] = React.useState(null);
608
+ const formElementRef = React.useRef(null);
609
+ const formIsDirtyRef = React.useRef(false);
610
+ const formIsSubmittingRef = React.useRef(false);
611
+ const autoSaveConfig = React.useMemo(() => {
612
+ const cfg = config?.autoSave;
613
+ if (!cfg) return {
614
+ enabled: false,
615
+ debounce: 500,
616
+ indicator: false,
617
+ preventNavigation: false
618
+ };
619
+ return {
620
+ enabled: cfg.enabled !== false,
621
+ debounce: cfg.debounce ?? 500,
622
+ indicator: cfg.indicator !== false,
623
+ preventNavigation: cfg.preventNavigation !== false
624
+ };
625
+ }, [config]);
626
+ const { locale: contentLocale, setLocale: setContentLocale } = useScopedLocale();
627
+ const localeOptions = useSafeContentLocales()?.locales ?? [];
628
+ const prevLocaleRef = React.useRef(contentLocale);
629
+ const [localeChangeDialog, setLocaleChangeDialog] = React.useState({
630
+ open: false,
631
+ pendingLocale: null
632
+ });
633
+ const localeChangeSnapshotRef = React.useRef(null);
634
+ const skipItemResetRef = React.useRef(false);
635
+ const handleFormDirtyChange = React.useCallback((isDirty) => {
636
+ formIsDirtyRef.current = isDirty;
637
+ }, []);
638
+ const handleFormSubmittingChange = React.useCallback((isSubmitting) => {
639
+ formIsSubmittingRef.current = isSubmitting;
640
+ }, []);
641
+ React.useEffect(() => {
642
+ if (!isEditMode) {
643
+ prevLocaleRef.current = contentLocale;
644
+ return;
645
+ }
646
+ if (prevLocaleRef.current !== contentLocale) if (formIsDirtyRef.current && !localeChangeDialog.open) {
647
+ skipItemResetRef.current = true;
648
+ localeChangeSnapshotRef.current = form.getValues();
649
+ setLocaleChangeDialog({
650
+ open: true,
651
+ pendingLocale: contentLocale
652
+ });
653
+ setContentLocale(prevLocaleRef.current);
654
+ } else {
655
+ prevLocaleRef.current = contentLocale;
656
+ skipItemResetRef.current = false;
657
+ }
658
+ }, [
659
+ contentLocale,
660
+ form.getValues,
661
+ setContentLocale,
662
+ localeChangeDialog.open,
663
+ isEditMode
664
+ ]);
665
+ React.useEffect(() => {
666
+ if (skipItemResetRef.current || isLoading) return;
667
+ if (transformedItem) form.reset(transformedItem);
668
+ else if (!isEditMode && defaultValuesProp) form.reset(defaultValuesProp);
669
+ }, [
670
+ form,
671
+ transformedItem,
672
+ defaultValuesProp,
673
+ isLoading,
674
+ isEditMode
675
+ ]);
676
+ const localeQueryClient = useQueryClient();
677
+ const handleLocaleChangeConfirm = React.useCallback(() => {
678
+ skipItemResetRef.current = false;
679
+ localeChangeSnapshotRef.current = null;
680
+ if (localeChangeDialog.pendingLocale) {
681
+ prevLocaleRef.current = localeChangeDialog.pendingLocale;
682
+ setContentLocale(localeChangeDialog.pendingLocale);
683
+ localeQueryClient.invalidateQueries({ queryKey: ["collections", collection] });
684
+ }
685
+ setLocaleChangeDialog({
686
+ open: false,
687
+ pendingLocale: null
688
+ });
689
+ }, [
690
+ localeChangeDialog.pendingLocale,
691
+ setContentLocale,
692
+ localeQueryClient,
693
+ collection
694
+ ]);
695
+ const handleLocaleChangeCancel = React.useCallback(() => {
696
+ skipItemResetRef.current = false;
697
+ if (localeChangeSnapshotRef.current) form.reset(localeChangeSnapshotRef.current, {
698
+ keepDirty: true,
699
+ keepDirtyValues: true,
700
+ keepErrors: true,
701
+ keepTouched: true
702
+ });
703
+ localeChangeSnapshotRef.current = null;
704
+ setLocaleChangeDialog({
705
+ open: false,
706
+ pendingLocale: null
707
+ });
708
+ }, [form]);
709
+ const onSubmit = React.useEffectEvent(async (data) => {
710
+ const savePromise = async () => {
711
+ if (isEditMode && id) return await updateMutation.mutateAsync({
712
+ id,
713
+ data
714
+ });
715
+ else return await createMutation.mutateAsync(data);
716
+ };
717
+ toast.promise(savePromise(), {
718
+ loading: isEditMode ? t("toast.saving") : t("toast.creating"),
719
+ success: (result_1) => {
720
+ if (onSuccess) onSuccess(result_1);
721
+ else if (isEditMode) {
722
+ form.reset(result_1);
723
+ triggerPreviewRefresh();
724
+ } else if (result_1?.id) navigate(`${basePath}/collections/${collection}/${result_1.id}`);
725
+ else navigate(`${basePath}/collections/${collection}`);
726
+ return isEditMode ? t("toast.saveSuccess") : t("toast.createSuccess");
727
+ },
728
+ error: (error) => {
729
+ if (error instanceof QuestpieClientError && error.fieldErrors && error.fieldErrors.length > 0) {
730
+ for (const fieldError of error.fieldErrors) form.setError(fieldError.path, {
731
+ type: "server",
732
+ message: fieldError.message
733
+ });
734
+ return t("toast.validationFailed");
735
+ }
736
+ const message = error instanceof Error ? error.message : t("error.unknown");
737
+ onError?.(error instanceof Error ? error : new Error(message));
738
+ return `${t("toast.saveFailed")}: ${message}`;
739
+ }
740
+ });
741
+ });
742
+ React.useEffect(() => {
743
+ if (!autoSaveConfig.preventNavigation || !autoSaveConfig.enabled) return;
744
+ const handleBeforeUnload = (e) => {
745
+ if (formIsDirtyRef.current) {
746
+ e.preventDefault();
747
+ e.returnValue = "";
748
+ }
749
+ };
750
+ window.addEventListener("beforeunload", handleBeforeUnload);
751
+ return () => window.removeEventListener("beforeunload", handleBeforeUnload);
752
+ }, [autoSaveConfig.preventNavigation, autoSaveConfig.enabled]);
753
+ const onSubmitRef = React.useRef(onSubmit);
754
+ React.useEffect(() => {
755
+ onSubmitRef.current = onSubmit;
756
+ });
757
+ React.useEffect(() => {
758
+ const handleKeyDown = (e_0) => {
759
+ if ((e_0.metaKey || e_0.ctrlKey) && e_0.key === "s") {
760
+ e_0.preventDefault();
761
+ e_0.stopPropagation();
762
+ form.handleSubmit(onSubmitRef.current, (errors) => {
763
+ console.warn("[FormView] Validation errors:", errors);
764
+ toast.error(t("toast.validationFailed"));
765
+ })();
766
+ }
767
+ };
768
+ document.addEventListener("keydown", handleKeyDown);
769
+ return () => document.removeEventListener("keydown", handleKeyDown);
770
+ }, [form, t]);
771
+ const isMutationPending = createMutation.isPending || updateMutation.isPending;
772
+ const configFormActions = resolvedFormConfig?.actions;
773
+ const { serverActions } = useServerActions({ collection });
774
+ const scopedServerFormActions = React.useMemo(() => isEditMode ? serverActions.filter((action) => {
775
+ const scope = action.scope;
776
+ return scope === "single" || scope === "row";
777
+ }) : [], [isEditMode, serverActions]);
778
+ const formActions = React.useMemo(() => {
779
+ const base = configFormActions ?? (!isEditMode ? {
780
+ primary: [],
781
+ secondary: []
782
+ } : getDefaultFormActions());
783
+ const primary = [...base.primary ?? []];
784
+ const secondary = [...base.secondary ?? []];
785
+ const existingIds = new Set([...primary, ...secondary].map((a) => a.id));
786
+ for (const action_0 of scopedServerFormActions) {
787
+ if (existingIds.has(action_0.id)) continue;
788
+ secondary.push(action_0);
789
+ existingIds.add(action_0.id);
790
+ }
791
+ return {
792
+ primary,
793
+ secondary
794
+ };
795
+ }, [
796
+ configFormActions,
797
+ isEditMode,
798
+ scopedServerFormActions
799
+ ]);
800
+ const [dialogAction, setDialogAction] = React.useState(null);
801
+ const [confirmAction, setConfirmAction] = React.useState(null);
802
+ const [actionLoading, setActionLoading] = React.useState(false);
803
+ const storeNavigate = useAdminStore(selectNavigate);
804
+ const storeBasePath = useAdminStore(selectBasePath);
805
+ const client = useAdminStore(selectClient);
806
+ const queryClient = useQueryClient();
807
+ const queryOpts = React.useMemo(() => createQuestpieQueryOptions(client, {
808
+ keyPrefix: QUERY_KEY_PREFIX,
809
+ locale: contentLocale
810
+ }), [client, contentLocale]);
811
+ const actionQueryClient = React.useMemo(() => ({
812
+ invalidateQueries: (filters) => queryClient.invalidateQueries(filters),
813
+ refetchQueries: (filters_0) => queryClient.refetchQueries(filters_0),
814
+ resetQueries: (filters_1) => queryClient.resetQueries(filters_1)
815
+ }), [queryClient]);
816
+ const actionHelpers = React.useMemo(() => ({
817
+ navigate: storeNavigate,
818
+ toast: {
819
+ success: toast.success,
820
+ error: toast.error,
821
+ info: toast.info,
822
+ warning: toast.warning
823
+ },
824
+ t,
825
+ invalidateCollection: async (targetCollection) => {
826
+ const col = targetCollection || collection;
827
+ await queryClient.invalidateQueries({ queryKey: queryOpts.key([
828
+ "collections",
829
+ col,
830
+ "find",
831
+ contentLocale
832
+ ]) });
833
+ await queryClient.invalidateQueries({ queryKey: queryOpts.key([
834
+ "collections",
835
+ col,
836
+ "count",
837
+ contentLocale
838
+ ]) });
839
+ },
840
+ invalidateItem: async (itemId, targetCollection_0) => {
841
+ const col_0 = targetCollection_0 || collection;
842
+ await queryClient.invalidateQueries({ queryKey: queryOpts.key([
843
+ "collections",
844
+ col_0,
845
+ "findOne",
846
+ contentLocale,
847
+ { id: itemId }
848
+ ]) });
849
+ await queryClient.invalidateQueries({ queryKey: queryOpts.key([
850
+ "collections",
851
+ col_0,
852
+ "find",
853
+ contentLocale
854
+ ]) });
855
+ },
856
+ invalidateAll: async () => {
857
+ await queryClient.invalidateQueries({ queryKey: [...QUERY_KEY_PREFIX] });
858
+ },
859
+ refresh: () => {
860
+ queryClient.invalidateQueries({ queryKey: queryOpts.key([
861
+ "collections",
862
+ collection,
863
+ "find",
864
+ contentLocale
865
+ ]) });
866
+ queryClient.invalidateQueries({ queryKey: queryOpts.key([
867
+ "collections",
868
+ collection,
869
+ "count",
870
+ contentLocale
871
+ ]) });
872
+ },
873
+ closeDialog: () => {
874
+ setDialogAction(null);
875
+ setConfirmAction(null);
876
+ },
877
+ basePath: storeBasePath || basePath
878
+ }), [
879
+ storeNavigate,
880
+ t,
881
+ collection,
882
+ queryClient,
883
+ queryOpts,
884
+ contentLocale,
885
+ storeBasePath,
886
+ basePath
887
+ ]);
888
+ const transformedItemRef = React.useRef(transformedItem);
889
+ transformedItemRef.current = transformedItem;
890
+ const actionContext = React.useMemo(() => ({
891
+ get item() {
892
+ return transformedItemRef.current;
893
+ },
894
+ collection,
895
+ helpers: actionHelpers,
896
+ queryClient: actionQueryClient
897
+ }), [
898
+ collection,
899
+ actionHelpers,
900
+ actionQueryClient
901
+ ]);
902
+ const filterVisibleActions = React.useCallback((actions) => {
903
+ if (!actions) return [];
904
+ return actions.filter((action_1) => {
905
+ if (action_1.visible === void 0) return true;
906
+ if (typeof action_1.visible === "function") return action_1.visible(actionContext);
907
+ return action_1.visible;
908
+ });
909
+ }, [actionContext]);
910
+ const visiblePrimaryActions = React.useMemo(() => filterVisibleActions(formActions.primary), [formActions.primary, filterVisibleActions]);
911
+ const visibleSecondaryActions = React.useMemo(() => filterVisibleActions(formActions.secondary), [formActions.secondary, filterVisibleActions]);
912
+ const regularSecondary = visibleSecondaryActions.filter((a_0) => a_0.variant !== "destructive");
913
+ const destructiveSecondary = visibleSecondaryActions.filter((a_1) => a_1.variant === "destructive");
914
+ const executeAction = async (action_2) => {
915
+ const { handler } = action_2;
916
+ const actionLabel = resolveText(action_2.label, action_2.id);
917
+ switch (handler.type) {
918
+ case "navigate":
919
+ storeNavigate(typeof handler.path === "function" ? handler.path(transformedItem) : handler.path);
920
+ break;
921
+ case "api":
922
+ if (handler.method === "POST" && handler.endpoint === "{id}/restore") {
923
+ const itemId_0 = transformedItem?.id || id;
924
+ if (!itemId_0) {
925
+ toast.error(t("collection.restoreError"));
926
+ break;
927
+ }
928
+ setActionLoading(true);
929
+ toast.promise(restoreMutation.mutateAsync({ id: itemId_0 }).finally(() => {
930
+ setActionLoading(false);
931
+ }), {
932
+ loading: t("collection.restoring"),
933
+ success: t("collection.restoreSuccess"),
934
+ error: (err_1) => err_1.message || t("collection.restoreError")
935
+ });
936
+ break;
937
+ }
938
+ if (handler.method === "DELETE") {
939
+ const itemId_1 = transformedItem?.id || id;
940
+ if (!itemId_1) {
941
+ toast.error(t("toast.deleteFailed"));
942
+ break;
943
+ }
944
+ setActionLoading(true);
945
+ toast.promise(deleteMutation.mutateAsync(itemId_1).finally(() => {
946
+ setActionLoading(false);
947
+ }), {
948
+ loading: t("toast.deleting"),
949
+ success: () => {
950
+ navigate(`${basePath}/collections/${collection}`);
951
+ return t("toast.deleteSuccess");
952
+ },
953
+ error: (err_2) => err_2.message || t("toast.deleteFailed")
954
+ });
955
+ } else {
956
+ let itemId_;
957
+ if (transformedItem?.id) itemId_ = String(transformedItem.id);
958
+ else itemId_ = String(id);
959
+ const endpoint = handler.endpoint.replace("{id}", itemId_);
960
+ const method = handler.method ? handler.method : "POST";
961
+ let body;
962
+ if (handler.body) body = JSON.stringify(handler.body(actionContext));
963
+ setActionLoading(true);
964
+ const apiPromise = async () => {
965
+ const url = `${storeBasePath}/${collection}/${endpoint}`;
966
+ const response = await fetch(url, {
967
+ method,
968
+ headers: { "Content-Type": "application/json" },
969
+ body
970
+ });
971
+ if (!response.ok) {
972
+ let errorBody = {};
973
+ try {
974
+ errorBody = await response.json();
975
+ } catch (_parseErr) {}
976
+ let errorMessage;
977
+ if (errorBody.message) if (typeof errorBody.message === "string") errorMessage = errorBody.message;
978
+ else errorMessage = t("toast.actionFailed");
979
+ else errorMessage = t("toast.actionFailed");
980
+ throw new Error(errorMessage);
981
+ }
982
+ return response.json();
983
+ };
984
+ const p = apiPromise();
985
+ p.then(() => setActionLoading(false), () => setActionLoading(false));
986
+ toast.promise(p, {
987
+ loading: `${actionLabel}...`,
988
+ success: t("toast.actionSuccess"),
989
+ error: (err_3) => {
990
+ if (err_3.message) return err_3.message;
991
+ return t("toast.actionFailed");
992
+ }
993
+ });
994
+ }
995
+ break;
996
+ case "custom": {
997
+ const customPromise = handler.fn(actionContext);
998
+ if (customPromise instanceof Promise) {
999
+ setActionLoading(true);
1000
+ toast.promise(customPromise.finally(() => setActionLoading(false)), {
1001
+ loading: `${actionLabel}...`,
1002
+ success: t("toast.actionSuccess"),
1003
+ error: (err_0) => err_0.message || t("toast.actionFailed")
1004
+ });
1005
+ }
1006
+ break;
1007
+ }
1008
+ }
1009
+ setConfirmAction(null);
1010
+ };
1011
+ const handleRevertVersion = (version) => {
1012
+ setPendingRevertVersion(version);
1013
+ };
1014
+ const confirmRevertVersion = async () => {
1015
+ if (!pendingRevertVersion || !id) return;
1016
+ const payload = { id };
1017
+ if (typeof pendingRevertVersion.versionId === "string") payload.versionId = pendingRevertVersion.versionId;
1018
+ else if (typeof pendingRevertVersion.versionNumber === "number") payload.version = pendingRevertVersion.versionNumber;
1019
+ const result_2 = await revertVersionMutation.mutateAsync(payload);
1020
+ form.reset(result_2);
1021
+ triggerPreviewRefresh();
1022
+ toast.success(t("version.revertSuccess"));
1023
+ setPendingRevertVersion(null);
1024
+ };
1025
+ const handleActionClick = (action_3) => {
1026
+ if (action_3.confirmation) setConfirmAction(action_3);
1027
+ else if (action_3.handler.type === "dialog" || action_3.handler.type === "form") setDialogAction(action_3);
1028
+ else executeAction(action_3);
1029
+ };
1030
+ const handleConfirm = async () => {
1031
+ if (confirmAction) await executeAction(confirmAction);
1032
+ };
1033
+ const formatDate = (date) => {
1034
+ return new Date(date).toLocaleDateString(void 0, {
1035
+ year: "numeric",
1036
+ month: "short",
1037
+ day: "numeric",
1038
+ hour: "2-digit",
1039
+ minute: "2-digit"
1040
+ });
1041
+ };
1042
+ const formatTimeAgo = (date_0) => {
1043
+ const seconds = Math.floor((Date.now() - date_0.getTime()) / 1e3);
1044
+ if (seconds < 10) return t("autosave.justNow");
1045
+ if (seconds < 60) return t("autosave.secondsAgo", { count: seconds });
1046
+ const minutes = Math.floor(seconds / 60);
1047
+ if (minutes < 60) return t("autosave.minutesAgo", { count: minutes });
1048
+ return t("autosave.hoursAgo", { count: Math.floor(minutes / 60) });
1049
+ };
1050
+ const lockRefreshTimerRef = React.useRef(null);
1051
+ React.useEffect(() => {
1052
+ if (!isEditMode || isBlocked) return;
1053
+ const scheduleLockRefresh = () => {
1054
+ if (lockRefreshTimerRef.current) clearTimeout(lockRefreshTimerRef.current);
1055
+ lockRefreshTimerRef.current = setTimeout(() => {
1056
+ refreshLock();
1057
+ }, 1e3);
1058
+ };
1059
+ const events = [
1060
+ "input",
1061
+ "change",
1062
+ "keydown",
1063
+ "pointerdown"
1064
+ ];
1065
+ const target = formElementRef.current ?? document;
1066
+ for (const event of events) target.addEventListener(event, scheduleLockRefresh, { capture: true });
1067
+ scheduleLockRefresh();
1068
+ return () => {
1069
+ for (const event_0 of events) target.removeEventListener(event_0, scheduleLockRefresh, { capture: true });
1070
+ if (lockRefreshTimerRef.current) clearTimeout(lockRefreshTimerRef.current);
1071
+ };
1072
+ }, [
1073
+ isEditMode,
1074
+ isBlocked,
1075
+ refreshLock
1076
+ ]);
1077
+ const { data: previewUrl = null } = useQuery({
1078
+ queryKey: [
1079
+ "questpie",
1080
+ "preview-url",
1081
+ collection,
1082
+ transformedItem?.id,
1083
+ contentLocale
1084
+ ],
1085
+ queryFn: async () => {
1086
+ return (await client.routes.getPreviewUrl({
1087
+ collection,
1088
+ record: transformedItem,
1089
+ locale: contentLocale
1090
+ }))?.url ?? null;
1091
+ },
1092
+ enabled: isLivePreviewOpen && canUseLivePreview && !!client && !!transformedItem,
1093
+ staleTime: 3e4
1094
+ });
1095
+ if (isEditMode && itemError) {
1096
+ const is404 = itemError != null && typeof itemError === "object" && "status" in itemError && itemError.status === 404;
1097
+ return /* @__PURE__ */ jsxs("div", {
1098
+ className: "text-muted-foreground flex h-64 flex-col items-center justify-center gap-3",
1099
+ children: [
1100
+ /* @__PURE__ */ jsx(Icon, {
1101
+ icon: is404 ? "ph:file-dashed" : "ph:warning-circle",
1102
+ className: "text-destructive size-8"
1103
+ }),
1104
+ /* @__PURE__ */ jsx("p", {
1105
+ className: "text-sm",
1106
+ children: is404 ? t("errors.notFound") : itemError instanceof Error ? itemError.message : t("errors.failedToLoad")
1107
+ }),
1108
+ is404 && /* @__PURE__ */ jsx(Button, {
1109
+ variant: "outline",
1110
+ size: "sm",
1111
+ onClick: () => navigate(`${basePath}/collections/${collection}`),
1112
+ children: t("common.backToList")
1113
+ })
1114
+ ]
1115
+ });
1116
+ }
1117
+ if (isEditMode && isLoading) return /* @__PURE__ */ jsx(FormViewSkeleton, {});
1118
+ const collectionLabel = resolveText(config?.label ?? schema?.admin?.config?.label, collection);
1119
+ const title = isEditMode ? item?._title || item?.id || t("collection.edit", { name: collectionLabel }) : t("collection.new", { name: collectionLabel });
1120
+ const formShell = /* @__PURE__ */ jsx("div", {
1121
+ className: "qa-form-view w-full",
1122
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
1123
+ isBlocked && blockedByUser && /* @__PURE__ */ jsxs("div", {
1124
+ className: "qa-form-view__lock-banner bg-warning/10 border-warning/30 mb-4 flex items-center gap-3 border p-3",
1125
+ children: [
1126
+ blockedByUser.image ? /* @__PURE__ */ jsx("img", {
1127
+ src: blockedByUser.image,
1128
+ alt: "",
1129
+ className: "size-8 rounded-full"
1130
+ }) : /* @__PURE__ */ jsx("div", {
1131
+ className: "bg-warning/20 flex size-8 items-center justify-center rounded-full",
1132
+ children: /* @__PURE__ */ jsx(Icon, {
1133
+ icon: "ph:user",
1134
+ className: "text-warning size-4"
1135
+ })
1136
+ }),
1137
+ /* @__PURE__ */ jsxs("div", {
1138
+ className: "min-w-0 flex-1",
1139
+ children: [/* @__PURE__ */ jsx("p", {
1140
+ className: "text-warning text-sm font-medium",
1141
+ children: t("lock.blockedTitle", { name: blockedByUser.name ?? blockedByUser.email })
1142
+ }), /* @__PURE__ */ jsx("p", {
1143
+ className: "text-warning/80 text-xs",
1144
+ children: t("lock.blockedDescription")
1145
+ })]
1146
+ }),
1147
+ /* @__PURE__ */ jsx(Icon, {
1148
+ icon: "ph:lock-simple",
1149
+ className: "text-warning size-5"
1150
+ })
1151
+ ]
1152
+ }),
1153
+ isOpenElsewhere && /* @__PURE__ */ jsxs("div", {
1154
+ className: "bg-info/10 border-info/30 mb-4 flex items-center gap-3 border p-3",
1155
+ children: [/* @__PURE__ */ jsx(Icon, {
1156
+ icon: "ph:browser",
1157
+ className: "text-info size-5"
1158
+ }), /* @__PURE__ */ jsx("p", {
1159
+ className: "text-info text-sm",
1160
+ children: t("lock.openElsewhere")
1161
+ })]
1162
+ }),
1163
+ /* @__PURE__ */ jsxs(FormProvider, {
1164
+ ...form,
1165
+ children: [
1166
+ /* @__PURE__ */ jsx(FormStateRefBridge, {
1167
+ control: form.control,
1168
+ onDirtyChange: handleFormDirtyChange,
1169
+ onSubmittingChange: handleFormSubmittingChange
1170
+ }),
1171
+ /* @__PURE__ */ jsx(AutosaveManager, {
1172
+ form,
1173
+ formElementRef,
1174
+ isEditMode,
1175
+ id,
1176
+ enabled: autoSaveConfig.enabled,
1177
+ debounce: autoSaveConfig.debounce,
1178
+ isDirtyRef: formIsDirtyRef,
1179
+ isSubmittingRef: formIsSubmittingRef,
1180
+ updateMutation,
1181
+ onPreviewRefresh: triggerPreviewRefresh,
1182
+ onSavingChange: setIsSaving,
1183
+ onSaved: setLastSaved
1184
+ }),
1185
+ /* @__PURE__ */ jsx(ReactiveFieldsManager, {
1186
+ collection,
1187
+ reactiveConfigs,
1188
+ enabled: !isBlocked && !isMutationPending
1189
+ }),
1190
+ /* @__PURE__ */ jsx(RenderProfiler, {
1191
+ id: `form.shell.${collection}`,
1192
+ minDurationMs: 12,
1193
+ children: /* @__PURE__ */ jsxs("form", {
1194
+ ref: formElementRef,
1195
+ onSubmit: (e_1) => {
1196
+ e_1.stopPropagation();
1197
+ if (isBlocked) {
1198
+ e_1.preventDefault();
1199
+ toast.error(t("lock.cannotSave"));
1200
+ return;
1201
+ }
1202
+ form.handleSubmit(onSubmit, (errors_0) => {
1203
+ console.warn("[FormView] Validation errors:", errors_0);
1204
+ toast.error(t("toast.validationFailed"), { description: t("toast.validationDescription") });
1205
+ })(e_1);
1206
+ },
1207
+ className: "qa-form-view__form space-y-4",
1208
+ children: [
1209
+ /* @__PURE__ */ jsxs("div", {
1210
+ className: "qa-form-view__header flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between",
1211
+ children: [/* @__PURE__ */ jsxs("div", {
1212
+ className: "min-w-0 flex-1",
1213
+ children: [/* @__PURE__ */ jsxs("div", {
1214
+ className: "flex flex-wrap items-center gap-3",
1215
+ children: [
1216
+ /* @__PURE__ */ jsx("h1", {
1217
+ className: "qa-form-view__title truncate text-2xl font-extrabold tracking-tight md:text-3xl",
1218
+ children: title
1219
+ }),
1220
+ localeOptions.length > 0 && /* @__PURE__ */ jsx(LocaleSwitcher, {
1221
+ locales: localeOptions,
1222
+ value: contentLocale,
1223
+ onChange: setContentLocale
1224
+ }),
1225
+ /* @__PURE__ */ jsx(AutosaveIndicator, {
1226
+ control: form.control,
1227
+ enabled: autoSaveConfig.enabled,
1228
+ indicator: autoSaveConfig.indicator,
1229
+ isEditMode,
1230
+ isSaving,
1231
+ lastSaved,
1232
+ formatTimeAgo,
1233
+ t
1234
+ }),
1235
+ workflowEnabled && currentStage && /* @__PURE__ */ jsxs(Badge, {
1236
+ variant: "outline",
1237
+ className: "gap-1.5",
1238
+ children: [/* @__PURE__ */ jsx(Icon, {
1239
+ icon: "ph:git-branch",
1240
+ className: "size-3"
1241
+ }), currentStageLabel]
1242
+ })
1243
+ ]
1244
+ }), showMeta && item && /* @__PURE__ */ jsx("div", {
1245
+ className: "qa-form-view__meta no-scrollbar mt-1 overflow-x-auto",
1246
+ children: /* @__PURE__ */ jsxs("p", {
1247
+ className: "text-muted-foreground flex items-center gap-2 font-mono text-xs whitespace-nowrap",
1248
+ children: [
1249
+ /* @__PURE__ */ jsxs("span", {
1250
+ className: "opacity-60",
1251
+ children: [t("form.id"), ":"]
1252
+ }),
1253
+ /* @__PURE__ */ jsx("button", {
1254
+ type: "button",
1255
+ className: "hover:text-foreground cursor-pointer transition-colors",
1256
+ onClick: () => {
1257
+ navigator.clipboard.writeText(String(item.id)).then(() => toast.success(t("toast.idCopied")), () => toast.error(t("toast.copyFailed")));
1258
+ },
1259
+ title: t("common.copy"),
1260
+ children: item.id
1261
+ }),
1262
+ item.createdAt && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
1263
+ className: "opacity-40",
1264
+ children: "·"
1265
+ }), /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsxs("span", {
1266
+ className: "opacity-60",
1267
+ children: [t("form.created"), " "]
1268
+ }), formatDate(item.createdAt)] })] }),
1269
+ item.updatedAt && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
1270
+ className: "opacity-40",
1271
+ children: "·"
1272
+ }), /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsxs("span", {
1273
+ className: "opacity-60",
1274
+ children: [t("form.updated"), " "]
1275
+ }), formatDate(item.updatedAt)] })] })
1276
+ ]
1277
+ })
1278
+ })]
1279
+ }), /* @__PURE__ */ jsxs("div", {
1280
+ className: "qa-form-view__actions flex w-auto shrink-0 items-center gap-2",
1281
+ children: [
1282
+ headerActions,
1283
+ canUseLivePreview && /* @__PURE__ */ jsxs(Button, {
1284
+ type: "button",
1285
+ variant: "outline",
1286
+ size: "icon",
1287
+ className: "size-9",
1288
+ onClick: () => setIsLivePreviewOpen(true),
1289
+ title: t("preview.livePreview"),
1290
+ children: [/* @__PURE__ */ jsx(Icon, {
1291
+ icon: "ph:eye",
1292
+ className: "size-4"
1293
+ }), /* @__PURE__ */ jsx("span", {
1294
+ className: "sr-only",
1295
+ children: t("preview.livePreview")
1296
+ })]
1297
+ }),
1298
+ isEditMode && id && schema?.options?.versioning && /* @__PURE__ */ jsxs(Button, {
1299
+ type: "button",
1300
+ variant: "outline",
1301
+ size: "icon",
1302
+ className: "size-9",
1303
+ onClick: () => setIsHistoryOpen(true),
1304
+ title: t("history.title"),
1305
+ children: [/* @__PURE__ */ jsx(Icon, {
1306
+ icon: "ph:clock-counter-clockwise",
1307
+ className: "size-4"
1308
+ }), /* @__PURE__ */ jsx("span", {
1309
+ className: "sr-only",
1310
+ children: t("history.title")
1311
+ })]
1312
+ }),
1313
+ workflowEnabled && isEditMode && id && allowedTransitions.length > 0 && /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsxs(DropdownMenuTrigger, {
1314
+ render: /* @__PURE__ */ jsx(Button, {
1315
+ type: "button",
1316
+ variant: "outline",
1317
+ className: "gap-2"
1318
+ }),
1319
+ children: [/* @__PURE__ */ jsx(Icon, {
1320
+ icon: "ph:arrows-left-right",
1321
+ className: "size-4"
1322
+ }), t("workflow.transition")]
1323
+ }), /* @__PURE__ */ jsx(DropdownMenuContent, {
1324
+ align: "end",
1325
+ children: allowedTransitions.map((stage) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
1326
+ onClick: () => setTransitionTarget({
1327
+ name: stage.name,
1328
+ label: stage.label
1329
+ }),
1330
+ children: [/* @__PURE__ */ jsx(Icon, {
1331
+ icon: "ph:arrow-right",
1332
+ className: "mr-2 size-4"
1333
+ }), stage.label || stage.name]
1334
+ }, stage.name))
1335
+ })] }),
1336
+ visiblePrimaryActions.map((action_4) => /* @__PURE__ */ jsx(ActionButton, {
1337
+ action: action_4,
1338
+ collection,
1339
+ helpers: actionHelpers,
1340
+ onOpenDialog: (a_2) => setDialogAction(a_2)
1341
+ }, action_4.id)),
1342
+ /* @__PURE__ */ jsx(SaveSubmitButton, {
1343
+ control: form.control,
1344
+ isMutationPending,
1345
+ t
1346
+ }),
1347
+ visibleSecondaryActions.length > 0 && /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsxs(DropdownMenuTrigger, {
1348
+ render: /* @__PURE__ */ jsx(Button, {
1349
+ variant: "outline",
1350
+ size: "icon",
1351
+ className: "size-9"
1352
+ }),
1353
+ children: [/* @__PURE__ */ jsx(Icon, {
1354
+ icon: "ph:dots-three-vertical",
1355
+ className: "size-4"
1356
+ }), /* @__PURE__ */ jsx("span", {
1357
+ className: "sr-only",
1358
+ children: t("common.moreActions")
1359
+ })]
1360
+ }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
1361
+ align: "end",
1362
+ children: [
1363
+ regularSecondary.map((action_5) => {
1364
+ return /* @__PURE__ */ jsxs(DropdownMenuItem, {
1365
+ onClick: () => handleActionClick(action_5),
1366
+ disabled: actionLoading,
1367
+ children: [resolveIconElement(action_5.icon, { className: "mr-2 size-4" }), resolveText(action_5.label)]
1368
+ }, action_5.id);
1369
+ }),
1370
+ regularSecondary.length > 0 && destructiveSecondary.length > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
1371
+ destructiveSecondary.map((action_6) => {
1372
+ return /* @__PURE__ */ jsxs(DropdownMenuItem, {
1373
+ variant: "destructive",
1374
+ onClick: () => handleActionClick(action_6),
1375
+ disabled: actionLoading,
1376
+ children: [resolveIconElement(action_6.icon, { className: "mr-2 size-4" }), resolveText(action_6.label)]
1377
+ }, action_6.id);
1378
+ })
1379
+ ]
1380
+ })] })
1381
+ ]
1382
+ })]
1383
+ }),
1384
+ item?.deletedAt && /* @__PURE__ */ jsxs("div", {
1385
+ 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",
1386
+ children: [/* @__PURE__ */ jsx(Icon, {
1387
+ icon: "ph:trash",
1388
+ className: "size-4 shrink-0"
1389
+ }), /* @__PURE__ */ jsx("span", { children: t("form.deletedBanner", {
1390
+ date: formatDate(item.deletedAt),
1391
+ defaultValue: `This record was deleted on ${formatDate(item.deletedAt)}. Use the Restore action to make it active again.`
1392
+ }) })]
1393
+ }),
1394
+ /* @__PURE__ */ jsx(FormFieldsContent, {
1395
+ collection,
1396
+ config: formConfigBridge,
1397
+ registry,
1398
+ allCollectionsConfig
1399
+ })
1400
+ ]
1401
+ })
1402
+ })
1403
+ ]
1404
+ }),
1405
+ /* @__PURE__ */ jsx(Dialog, {
1406
+ open: localeChangeDialog.open,
1407
+ onOpenChange: (open) => {
1408
+ if (!open) handleLocaleChangeCancel();
1409
+ },
1410
+ children: /* @__PURE__ */ jsxs(DialogContent, {
1411
+ showCloseButton: false,
1412
+ children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsxs(DialogTitle, {
1413
+ className: "flex items-center gap-2",
1414
+ children: [/* @__PURE__ */ jsx(Icon, {
1415
+ icon: "ph:warning-fill",
1416
+ className: "text-warning size-5"
1417
+ }), t("confirm.localeChange")]
1418
+ }), /* @__PURE__ */ jsx(DialogDescription, { children: t("confirm.localeChangeDescription") })] }), /* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button, {
1419
+ variant: "outline",
1420
+ onClick: handleLocaleChangeCancel,
1421
+ children: t("confirm.localeChangeStay")
1422
+ }), /* @__PURE__ */ jsx(Button, {
1423
+ variant: "destructive",
1424
+ onClick: handleLocaleChangeConfirm,
1425
+ children: t("confirm.localeChangeDiscard")
1426
+ })] })]
1427
+ })
1428
+ }),
1429
+ confirmAction?.confirmation && /* @__PURE__ */ jsx(ConfirmationDialog, {
1430
+ open: !!confirmAction,
1431
+ onOpenChange: (open_0) => !open_0 && setConfirmAction(null),
1432
+ config: confirmAction.confirmation,
1433
+ onConfirm: handleConfirm,
1434
+ loading: actionLoading
1435
+ }),
1436
+ dialogAction && /* @__PURE__ */ jsx(ActionDialog, {
1437
+ open: !!dialogAction,
1438
+ onOpenChange: (open_1) => !open_1 && setDialogAction(null),
1439
+ action: dialogAction,
1440
+ collection,
1441
+ item: transformedItem,
1442
+ helpers: actionHelpers
1443
+ }),
1444
+ /* @__PURE__ */ jsx(HistorySidebar, {
1445
+ open: isHistoryOpen,
1446
+ onOpenChange: setIsHistoryOpen,
1447
+ auditEntries: auditData ?? [],
1448
+ isLoadingAudit: auditLoading,
1449
+ versions: versionsData ?? [],
1450
+ isLoadingVersions: versionsLoading,
1451
+ isReverting: revertVersionMutation.isPending,
1452
+ onRevert: async (version_0) => {
1453
+ handleRevertVersion(version_0);
1454
+ },
1455
+ showVersionsTab: !!schema?.options?.versioning
1456
+ }),
1457
+ /* @__PURE__ */ jsx(ConfirmationDialog, {
1458
+ open: !!pendingRevertVersion,
1459
+ onOpenChange: (open_2) => {
1460
+ if (!open_2) setPendingRevertVersion(null);
1461
+ },
1462
+ config: {
1463
+ title: t("version.revertConfirmTitle"),
1464
+ description: t("version.revertConfirmDescription", { number: pendingRevertVersion?.versionNumber ?? pendingRevertVersion?.versionId ?? "-" }),
1465
+ confirmLabel: t("version.revert"),
1466
+ cancelLabel: t("common.cancel"),
1467
+ destructive: false
1468
+ },
1469
+ onConfirm: confirmRevertVersion,
1470
+ loading: revertVersionMutation.isPending
1471
+ }),
1472
+ /* @__PURE__ */ jsx(Dialog, {
1473
+ open: !!transitionTarget,
1474
+ onOpenChange: (open_3) => {
1475
+ if (!open_3) {
1476
+ setTransitionTarget(null);
1477
+ setTransitionSchedule(false);
1478
+ setTransitionScheduledAt(null);
1479
+ }
1480
+ },
1481
+ children: /* @__PURE__ */ jsxs(DialogContent, { children: [
1482
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsxs(DialogTitle, {
1483
+ className: "flex items-center gap-2",
1484
+ children: [/* @__PURE__ */ jsx(Icon, {
1485
+ icon: "ph:arrows-left-right",
1486
+ className: "size-5"
1487
+ }), t("workflow.transitionTo", { stage: transitionTarget?.label ?? transitionTarget?.name ?? "" })]
1488
+ }), /* @__PURE__ */ jsx(DialogDescription, { children: t("workflow.transitionDescription", {
1489
+ from: currentStageLabel,
1490
+ to: transitionTarget?.label ?? transitionTarget?.name ?? ""
1491
+ }) })] }),
1492
+ /* @__PURE__ */ jsxs("div", {
1493
+ className: "space-y-3 py-2",
1494
+ children: [/* @__PURE__ */ jsxs("div", {
1495
+ className: "flex items-center gap-2",
1496
+ children: [/* @__PURE__ */ jsx(Checkbox, {
1497
+ checked: transitionSchedule,
1498
+ onCheckedChange: (val) => {
1499
+ setTransitionSchedule(!!val);
1500
+ if (!val) setTransitionScheduledAt(null);
1501
+ },
1502
+ id: "transition-schedule"
1503
+ }), /* @__PURE__ */ jsx(Label, {
1504
+ htmlFor: "transition-schedule",
1505
+ className: "cursor-pointer text-sm",
1506
+ children: t("workflow.scheduleLabel")
1507
+ })]
1508
+ }), transitionSchedule && /* @__PURE__ */ jsxs("div", {
1509
+ className: "space-y-1.5 pl-6",
1510
+ children: [
1511
+ /* @__PURE__ */ jsx(Label, {
1512
+ className: "text-muted-foreground text-xs",
1513
+ children: t("workflow.scheduledAt")
1514
+ }),
1515
+ /* @__PURE__ */ jsx(DateTimeInput, {
1516
+ value: transitionScheduledAt,
1517
+ onChange: setTransitionScheduledAt,
1518
+ minDate: /* @__PURE__ */ new Date()
1519
+ }),
1520
+ /* @__PURE__ */ jsx("p", {
1521
+ className: "text-muted-foreground text-xs",
1522
+ children: t("workflow.scheduledDescription")
1523
+ })
1524
+ ]
1525
+ })]
1526
+ }),
1527
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button, {
1528
+ type: "button",
1529
+ variant: "outline",
1530
+ onClick: () => {
1531
+ setTransitionTarget(null);
1532
+ setTransitionSchedule(false);
1533
+ setTransitionScheduledAt(null);
1534
+ },
1535
+ children: t("common.cancel")
1536
+ }), /* @__PURE__ */ jsxs(Button, {
1537
+ type: "button",
1538
+ onClick: confirmTransition,
1539
+ disabled: transitionMutation.isPending || transitionSchedule && !transitionScheduledAt,
1540
+ className: "gap-2",
1541
+ children: [transitionMutation.isPending && /* @__PURE__ */ jsx(Icon, {
1542
+ icon: "ph:spinner-gap",
1543
+ className: "size-4 animate-spin"
1544
+ }), transitionSchedule ? t("workflow.scheduleLabel") : t("workflow.transition")]
1545
+ })] })
1546
+ ] })
1547
+ })
1548
+ ] })
1549
+ });
1550
+ if (!canUseLivePreview) return formShell;
1551
+ return /* @__PURE__ */ jsx(LivePreviewMode, {
1552
+ open: isLivePreviewOpen,
1553
+ onClose: () => setIsLivePreviewOpen(false),
1554
+ previewUrl,
1555
+ previewRef,
1556
+ defaultSize: schemaPreview?.defaultSize,
1557
+ minSize: schemaPreview?.minSize,
1558
+ children: formShell
1559
+ });
1560
+ }
1561
+ function _temp(x) {
1562
+ return x + 1;
1563
+ }
1564
+
1565
+ //#endregion
1566
+ export { FormView as default };