@pilotiq/pilotiq 0.23.1 → 0.24.2

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 (500) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/boost/guidelines.md +566 -0
  3. package/boost/skills/pilotiq-fields/SKILL.md +47 -0
  4. package/boost/skills/pilotiq-fields/rules/field-catalog.md +288 -0
  5. package/boost/skills/pilotiq-fields/rules/reactive-fields.md +199 -0
  6. package/boost/skills/pilotiq-fields/rules/validation.md +198 -0
  7. package/boost/skills/pilotiq-relations/SKILL.md +47 -0
  8. package/boost/skills/pilotiq-relations/rules/relation-managers.md +256 -0
  9. package/boost/skills/pilotiq-relations/rules/repeater-relationship.md +177 -0
  10. package/boost/skills/pilotiq-resource/SKILL.md +61 -0
  11. package/boost/skills/pilotiq-resource/rules/authorization.md +242 -0
  12. package/boost/skills/pilotiq-resource/rules/defining-resources.md +228 -0
  13. package/boost/skills/pilotiq-resource/rules/page-overrides.md +296 -0
  14. package/dist/actions/exportFactory.d.ts +10 -0
  15. package/dist/actions/exportFactory.d.ts.map +1 -1
  16. package/dist/actions/exportFactory.js +10 -0
  17. package/dist/actions/exportFactory.js.map +1 -1
  18. package/dist/react/CollabRoomContext.d.ts +5 -5
  19. package/dist/react/index.d.ts +0 -1
  20. package/dist/react/index.d.ts.map +1 -1
  21. package/dist/react/index.js +0 -1
  22. package/dist/react/index.js.map +1 -1
  23. package/dist/routes/helpers.d.ts.map +1 -1
  24. package/dist/routes/helpers.js +6 -2
  25. package/dist/routes/helpers.js.map +1 -1
  26. package/dist/routes/relations.d.ts.map +1 -1
  27. package/dist/routes/relations.js +12 -0
  28. package/dist/routes/relations.js.map +1 -1
  29. package/package.json +6 -1
  30. package/.turbo/turbo-build.log +0 -8
  31. package/CLAUDE.md +0 -265
  32. package/dist/react/useCollabSeed.d.ts +0 -23
  33. package/dist/react/useCollabSeed.d.ts.map +0 -1
  34. package/dist/react/useCollabSeed.js +0 -82
  35. package/dist/react/useCollabSeed.js.map +0 -1
  36. package/src/Cluster.test.ts +0 -283
  37. package/src/Cluster.ts +0 -83
  38. package/src/Column.test.ts +0 -199
  39. package/src/Column.ts +0 -710
  40. package/src/Global.test.ts +0 -367
  41. package/src/Global.ts +0 -169
  42. package/src/Page.test.ts +0 -114
  43. package/src/Page.ts +0 -208
  44. package/src/Pilotiq.perf.test.ts +0 -252
  45. package/src/Pilotiq.test.ts +0 -129
  46. package/src/Pilotiq.ts +0 -1158
  47. package/src/PilotiqRegistry.ts +0 -36
  48. package/src/PilotiqServiceProvider.ts +0 -121
  49. package/src/RelationManager.test.ts +0 -400
  50. package/src/RelationManager.ts +0 -527
  51. package/src/RenderHook.test.ts +0 -252
  52. package/src/RenderHook.ts +0 -242
  53. package/src/Resource.test.ts +0 -284
  54. package/src/Resource.ts +0 -526
  55. package/src/RightPanel.test.ts +0 -202
  56. package/src/RightPanel.ts +0 -132
  57. package/src/Tab.test.ts +0 -91
  58. package/src/Tab.ts +0 -156
  59. package/src/UserMenuItem.ts +0 -145
  60. package/src/actions/Action.test.ts +0 -2526
  61. package/src/actions/Action.ts +0 -1515
  62. package/src/actions/ActionGroup.test.ts +0 -112
  63. package/src/actions/ActionGroup.ts +0 -173
  64. package/src/actions/attachFactory.ts +0 -172
  65. package/src/actions/bulkFactories.ts +0 -168
  66. package/src/actions/crudFactories.ts +0 -220
  67. package/src/actions/exportFactory.ts +0 -215
  68. package/src/actions/factoryHelpers.ts +0 -177
  69. package/src/actions/importFactory.ts +0 -243
  70. package/src/actions/index.ts +0 -17
  71. package/src/actions/m2mFactories.ts +0 -193
  72. package/src/actions/relationFactories.ts +0 -372
  73. package/src/applyPageHooks.test.ts +0 -463
  74. package/src/applyPageHooks.ts +0 -330
  75. package/src/authorization.test.ts +0 -483
  76. package/src/breadcrumbs.test.ts +0 -238
  77. package/src/cells/coerce.test.ts +0 -85
  78. package/src/cells/coerce.ts +0 -84
  79. package/src/clusterPaths.ts +0 -35
  80. package/src/columns/BadgeColumn.test.ts +0 -54
  81. package/src/columns/BadgeColumn.ts +0 -32
  82. package/src/columns/BooleanColumn.test.ts +0 -41
  83. package/src/columns/BooleanColumn.ts +0 -18
  84. package/src/columns/ColorColumn.test.ts +0 -37
  85. package/src/columns/ColorColumn.ts +0 -38
  86. package/src/columns/IconColumn.test.ts +0 -54
  87. package/src/columns/IconColumn.ts +0 -37
  88. package/src/columns/ImageColumn.test.ts +0 -41
  89. package/src/columns/ImageColumn.ts +0 -28
  90. package/src/columns/SelectColumn.ts +0 -98
  91. package/src/columns/TextColumn.test.ts +0 -190
  92. package/src/columns/TextColumn.ts +0 -20
  93. package/src/columns/TextInputColumn.ts +0 -68
  94. package/src/columns/ToggleColumn.ts +0 -46
  95. package/src/columns/editableColumns.test.ts +0 -238
  96. package/src/columns/index.ts +0 -9
  97. package/src/defaultGlobalPages.ts +0 -95
  98. package/src/defaultPages.test.ts +0 -634
  99. package/src/defaultPages.ts +0 -617
  100. package/src/defaultViewPage.test.ts +0 -147
  101. package/src/elements/Form.test.ts +0 -223
  102. package/src/elements/Form.ts +0 -416
  103. package/src/elements/ListTabs.ts +0 -28
  104. package/src/elements/Table.test.ts +0 -422
  105. package/src/elements/Table.ts +0 -850
  106. package/src/elements/TableGroup.test.ts +0 -260
  107. package/src/elements/TableGroup.ts +0 -334
  108. package/src/elements/dispatchAction.test.ts +0 -463
  109. package/src/elements/dispatchAction.ts +0 -355
  110. package/src/elements/dispatchForm.test.ts +0 -477
  111. package/src/elements/dispatchForm.ts +0 -1993
  112. package/src/elements/dispatchTable.test.ts +0 -1514
  113. package/src/elements/dispatchTable.ts +0 -745
  114. package/src/elements/index.ts +0 -21
  115. package/src/entries/BadgeEntry.ts +0 -39
  116. package/src/entries/CodeEntry.test.ts +0 -40
  117. package/src/entries/CodeEntry.ts +0 -52
  118. package/src/entries/ColorEntry.ts +0 -63
  119. package/src/entries/ComponentEntry.test.ts +0 -173
  120. package/src/entries/ComponentEntry.ts +0 -95
  121. package/src/entries/Entry.ts +0 -304
  122. package/src/entries/IconEntry.ts +0 -49
  123. package/src/entries/ImageEntry.ts +0 -61
  124. package/src/entries/KeyValueEntry.ts +0 -47
  125. package/src/entries/RepeatableEntry.test.ts +0 -239
  126. package/src/entries/RepeatableEntry.ts +0 -173
  127. package/src/entries/TextEntry.test.ts +0 -394
  128. package/src/entries/TextEntry.ts +0 -60
  129. package/src/entries/index.ts +0 -12
  130. package/src/entries/leaves.test.ts +0 -306
  131. package/src/entries/registry.ts +0 -54
  132. package/src/fields/BuilderField.test.ts +0 -1188
  133. package/src/fields/BuilderField.ts +0 -605
  134. package/src/fields/BuilderRelationship.test.ts +0 -811
  135. package/src/fields/CheckboxField.test.ts +0 -44
  136. package/src/fields/CheckboxField.ts +0 -27
  137. package/src/fields/CheckboxListField.test.ts +0 -99
  138. package/src/fields/CheckboxListField.ts +0 -66
  139. package/src/fields/ColorPickerField.test.ts +0 -33
  140. package/src/fields/ColorPickerField.ts +0 -25
  141. package/src/fields/DateField.ts +0 -54
  142. package/src/fields/DateTimeField.test.ts +0 -55
  143. package/src/fields/EmailField.ts +0 -16
  144. package/src/fields/Field.test.ts +0 -654
  145. package/src/fields/Field.ts +0 -817
  146. package/src/fields/FileUploadField.test.ts +0 -143
  147. package/src/fields/FileUploadField.ts +0 -159
  148. package/src/fields/HiddenField.test.ts +0 -27
  149. package/src/fields/HiddenField.ts +0 -28
  150. package/src/fields/KeyValueField.test.ts +0 -105
  151. package/src/fields/KeyValueField.ts +0 -55
  152. package/src/fields/MarkdownField.test.ts +0 -167
  153. package/src/fields/MarkdownField.ts +0 -162
  154. package/src/fields/NumberField.ts +0 -33
  155. package/src/fields/RadioField.test.ts +0 -94
  156. package/src/fields/RadioField.ts +0 -67
  157. package/src/fields/RepeaterField.test.ts +0 -1806
  158. package/src/fields/RepeaterField.ts +0 -939
  159. package/src/fields/RepeaterRelationship.test.ts +0 -1923
  160. package/src/fields/RepeaterSimple.test.ts +0 -248
  161. package/src/fields/RowButton.test.ts +0 -219
  162. package/src/fields/RowButton.ts +0 -135
  163. package/src/fields/SelectField.test.ts +0 -192
  164. package/src/fields/SelectField.ts +0 -235
  165. package/src/fields/SliderField.test.ts +0 -50
  166. package/src/fields/SliderField.ts +0 -53
  167. package/src/fields/SlugField.ts +0 -24
  168. package/src/fields/TagsInputField.test.ts +0 -154
  169. package/src/fields/TagsInputField.ts +0 -133
  170. package/src/fields/TextField.test.ts +0 -213
  171. package/src/fields/TextField.ts +0 -177
  172. package/src/fields/TextareaField.test.ts +0 -58
  173. package/src/fields/TextareaField.ts +0 -59
  174. package/src/fields/ToggleButtonsField.test.ts +0 -106
  175. package/src/fields/ToggleButtonsField.ts +0 -59
  176. package/src/fields/ToggleField.ts +0 -16
  177. package/src/fields/disableOptionsWhenSelectedInSiblingRepeaterItems.test.ts +0 -319
  178. package/src/fields/optionsResolver.ts +0 -95
  179. package/src/fields/resolveField.ts +0 -28
  180. package/src/filters/BooleanFilter.ts +0 -35
  181. package/src/filters/DateRangeFilter.test.ts +0 -194
  182. package/src/filters/DateRangeFilter.ts +0 -148
  183. package/src/filters/Filter.test.ts +0 -268
  184. package/src/filters/Filter.ts +0 -184
  185. package/src/filters/FormFilter.test.ts +0 -238
  186. package/src/filters/FormFilter.ts +0 -215
  187. package/src/filters/MultiSelectFilter.test.ts +0 -119
  188. package/src/filters/MultiSelectFilter.ts +0 -78
  189. package/src/filters/QueryBuilderFilter.test.ts +0 -662
  190. package/src/filters/QueryBuilderFilter.ts +0 -398
  191. package/src/filters/SelectFilter.ts +0 -46
  192. package/src/filters/TernaryFilter.test.ts +0 -160
  193. package/src/filters/TernaryFilter.ts +0 -72
  194. package/src/filters/TrashedFilter.test.ts +0 -149
  195. package/src/filters/TrashedFilter.ts +0 -55
  196. package/src/filters/queryBuilder/BooleanConstraint.ts +0 -31
  197. package/src/filters/queryBuilder/Constraint.ts +0 -115
  198. package/src/filters/queryBuilder/DateConstraint.ts +0 -69
  199. package/src/filters/queryBuilder/NumberConstraint.ts +0 -66
  200. package/src/filters/queryBuilder/SelectConstraint.ts +0 -72
  201. package/src/filters/queryBuilder/TextConstraint.ts +0 -64
  202. package/src/filters/queryBuilder/index.ts +0 -12
  203. package/src/icons/index.ts +0 -2
  204. package/src/icons/lucide.ts +0 -204
  205. package/src/icons/registry.test.ts +0 -56
  206. package/src/icons/registry.ts +0 -41
  207. package/src/icons/types.ts +0 -47
  208. package/src/index.ts +0 -525
  209. package/src/io/csv.test.ts +0 -142
  210. package/src/io/csv.ts +0 -170
  211. package/src/nestedRelationManagerData.test.ts +0 -547
  212. package/src/notifications/Notification.test.ts +0 -210
  213. package/src/notifications/Notification.ts +0 -354
  214. package/src/notifications/broadcast.test.ts +0 -110
  215. package/src/notifications/broadcast.ts +0 -95
  216. package/src/notifications/database.test.ts +0 -383
  217. package/src/notifications/database.ts +0 -398
  218. package/src/notifications/databaseNotifications.test.ts +0 -187
  219. package/src/notifications/dispatchNotificationAction.test.ts +0 -341
  220. package/src/notifications/dispatchNotificationAction.ts +0 -142
  221. package/src/notifications/flash.test.ts +0 -89
  222. package/src/notifications/flash.ts +0 -71
  223. package/src/notifications/index.ts +0 -45
  224. package/src/notifications/registerBroadcastAuth.test.ts +0 -134
  225. package/src/notifications/registerBroadcastAuth.ts +0 -100
  226. package/src/notifications/resolveSavedNotification.test.ts +0 -82
  227. package/src/notifications/resolveSavedNotification.ts +0 -59
  228. package/src/notifications/types.ts +0 -93
  229. package/src/orm/m2mAccessor.ts +0 -66
  230. package/src/orm/modelDefaults.test.ts +0 -633
  231. package/src/orm/modelDefaults.ts +0 -666
  232. package/src/pageData/breadcrumbs.ts +0 -288
  233. package/src/pageData/forms.ts +0 -578
  234. package/src/pageData/helpers.ts +0 -857
  235. package/src/pageData/misc.ts +0 -347
  236. package/src/pageData/navigation.ts +0 -842
  237. package/src/pageData/relationPages.ts +0 -1248
  238. package/src/pageData/relationTabs.ts +0 -286
  239. package/src/pageData/resourcePages.ts +0 -609
  240. package/src/pageData.test.ts +0 -1545
  241. package/src/pageData.ts +0 -341
  242. package/src/plugins/index.ts +0 -8
  243. package/src/plugins/themeEditor.test.ts +0 -36
  244. package/src/plugins/themeEditor.ts +0 -45
  245. package/src/react/AppShell.tsx +0 -251
  246. package/src/react/CollabExtensionFactoryRegistry.ts +0 -55
  247. package/src/react/CollabRoomContext.ts +0 -98
  248. package/src/react/CollabTextRendererRegistry.ts +0 -102
  249. package/src/react/CommandPalette.tsx +0 -375
  250. package/src/react/CurrentUserContext.tsx +0 -50
  251. package/src/react/CustomPageWrapperGate.tsx +0 -69
  252. package/src/react/CustomPageWrapperRegistry.ts +0 -45
  253. package/src/react/FieldFocusReporterRegistry.ts +0 -37
  254. package/src/react/FieldLabelSlotRegistry.ts +0 -30
  255. package/src/react/FieldPresenceRegistry.ts +0 -46
  256. package/src/react/FormCollabBindingRegistry.ts +0 -242
  257. package/src/react/FormStateContext.tsx +0 -591
  258. package/src/react/HeadHooks.tsx +0 -126
  259. package/src/react/MarkdownEditorRegistry.test.ts +0 -38
  260. package/src/react/MarkdownEditorRegistry.ts +0 -107
  261. package/src/react/NotificationActionStrip.tsx +0 -263
  262. package/src/react/NotificationBell.tsx +0 -426
  263. package/src/react/PendingSuggestionApplierRegistry.test.ts +0 -97
  264. package/src/react/PendingSuggestionApplierRegistry.ts +0 -98
  265. package/src/react/PendingSuggestionOverlayRegistry.ts +0 -54
  266. package/src/react/PendingSuggestionsContext.tsx +0 -172
  267. package/src/react/RecordWrapperGate.tsx +0 -58
  268. package/src/react/RecordWrapperRegistry.ts +0 -39
  269. package/src/react/RenderHookSlot.tsx +0 -32
  270. package/src/react/RightSidebar.tsx +0 -257
  271. package/src/react/RightSidebarContext.tsx +0 -234
  272. package/src/react/RightSidebarTrigger.tsx +0 -53
  273. package/src/react/RowCoordsContext.tsx +0 -23
  274. package/src/react/SchemaRenderer.tsx +0 -549
  275. package/src/react/SearchTrigger.tsx +0 -46
  276. package/src/react/ThemeProvider.tsx +0 -93
  277. package/src/react/ThemeSettingsPage.tsx +0 -579
  278. package/src/react/ThemeToggle.tsx +0 -20
  279. package/src/react/Toaster.tsx +0 -158
  280. package/src/react/UserMenu.tsx +0 -196
  281. package/src/react/WidgetDataContext.tsx +0 -157
  282. package/src/react/cells/EditableCell.tsx +0 -389
  283. package/src/react/component-slots.test.ts +0 -103
  284. package/src/react/component-slots.ts +0 -116
  285. package/src/react/fieldJsHandler.test.ts +0 -166
  286. package/src/react/fieldJsHandler.ts +0 -79
  287. package/src/react/fields/BuilderInput.tsx +0 -1078
  288. package/src/react/fields/CheckboxInput.tsx +0 -39
  289. package/src/react/fields/CheckboxListInput.tsx +0 -102
  290. package/src/react/fields/ColorInput.tsx +0 -71
  291. package/src/react/fields/DateFieldInput.tsx +0 -70
  292. package/src/react/fields/DateTimeInput.tsx +0 -62
  293. package/src/react/fields/FieldShell.tsx +0 -348
  294. package/src/react/fields/FileUploadInput.tsx +0 -639
  295. package/src/react/fields/HiddenInput.tsx +0 -17
  296. package/src/react/fields/KeyValueInput.tsx +0 -230
  297. package/src/react/fields/MarkdownInput.tsx +0 -560
  298. package/src/react/fields/RadioInput.tsx +0 -81
  299. package/src/react/fields/RepeaterInput.test.ts +0 -116
  300. package/src/react/fields/RepeaterInput.tsx +0 -1420
  301. package/src/react/fields/SelectFieldInput.tsx +0 -280
  302. package/src/react/fields/SliderInput.tsx +0 -81
  303. package/src/react/fields/TagsInput.tsx +0 -283
  304. package/src/react/fields/TextLikeInput.tsx +0 -256
  305. package/src/react/fields/ToggleButtonsInput.tsx +0 -60
  306. package/src/react/fields/ToggleFieldInput.tsx +0 -56
  307. package/src/react/fields/relationshipRenameDispatch.test.ts +0 -106
  308. package/src/react/fields/relationshipRenameDispatch.ts +0 -97
  309. package/src/react/fields/repeaterReconcile.test.ts +0 -114
  310. package/src/react/fields/repeaterReconcile.ts +0 -104
  311. package/src/react/fields/rowChromeButton.tsx +0 -336
  312. package/src/react/fields/rowState.ts +0 -106
  313. package/src/react/fields/syncRowGates.test.ts +0 -202
  314. package/src/react/fields/syncRowGates.ts +0 -66
  315. package/src/react/fields/textInputControls.tsx +0 -238
  316. package/src/react/fields/useRowReorderDnd.ts +0 -78
  317. package/src/react/formStateHelpers.test.ts +0 -508
  318. package/src/react/formStateHelpers.ts +0 -381
  319. package/src/react/hooks/use-mobile.ts +0 -19
  320. package/src/react/icon-context.tsx +0 -60
  321. package/src/react/index.ts +0 -195
  322. package/src/react/layouts/SidebarLayout.tsx +0 -250
  323. package/src/react/layouts/TopbarLayout.tsx +0 -258
  324. package/src/react/navigate.tsx +0 -37
  325. package/src/react/onProviderSynced.test.ts +0 -90
  326. package/src/react/parseRecordEditUrl.test.ts +0 -122
  327. package/src/react/parseRecordEditUrl.ts +0 -94
  328. package/src/react/persistedState.ts +0 -40
  329. package/src/react/registry.ts +0 -48
  330. package/src/react/right-panel-registry.tsx +0 -47
  331. package/src/react/schemaRenderer/AlertRenderer.tsx +0 -112
  332. package/src/react/schemaRenderer/EntryRenderer.tsx +0 -501
  333. package/src/react/schemaRenderer/SectionRenderer.tsx +0 -120
  334. package/src/react/schemaRenderer/SimpleElements.tsx +0 -306
  335. package/src/react/schemaRenderer/TabsRenderer.tsx +0 -62
  336. package/src/react/schemaRenderer/WizardRenderer.tsx +0 -338
  337. package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +0 -177
  338. package/src/react/schemaRenderer/action/ActionModalDialog.tsx +0 -273
  339. package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +0 -61
  340. package/src/react/schemaRenderer/action/HandlerActionButton.tsx +0 -43
  341. package/src/react/schemaRenderer/action/MethodActionButton.tsx +0 -64
  342. package/src/react/schemaRenderer/action/buttons.tsx +0 -99
  343. package/src/react/schemaRenderer/action/helpers.ts +0 -140
  344. package/src/react/schemaRenderer/action/renderAction.tsx +0 -245
  345. package/src/react/schemaRenderer/columnFormat.ts +0 -65
  346. package/src/react/schemaRenderer/constants.ts +0 -50
  347. package/src/react/schemaRenderer/form/FormRenderer.tsx +0 -274
  348. package/src/react/schemaRenderer/form/renderField.tsx +0 -511
  349. package/src/react/schemaRenderer/helpers.tsx +0 -81
  350. package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +0 -308
  351. package/src/react/schemaRenderer/table/TableRenderer.tsx +0 -123
  352. package/src/react/schemaRenderer/table/TableRendererBody.tsx +0 -974
  353. package/src/react/schemaRenderer/table/filters.tsx +0 -1233
  354. package/src/react/schemaRenderer/table/formatCell.tsx +0 -264
  355. package/src/react/schemaRenderer/table/links.tsx +0 -112
  356. package/src/react/schemaRenderer/table/renderRowActions.tsx +0 -52
  357. package/src/react/schemaRenderer/table/url.tsx +0 -143
  358. package/src/react/theme-preview/apply.ts +0 -99
  359. package/src/react/theme-preview/build-html.ts +0 -436
  360. package/src/react/ui/button.tsx +0 -51
  361. package/src/react/ui/calendar.tsx +0 -67
  362. package/src/react/ui/checkbox.tsx +0 -29
  363. package/src/react/ui/dialog.tsx +0 -108
  364. package/src/react/ui/dropdown-menu.tsx +0 -97
  365. package/src/react/ui/input.tsx +0 -20
  366. package/src/react/ui/label.tsx +0 -21
  367. package/src/react/ui/popover.tsx +0 -50
  368. package/src/react/ui/select.tsx +0 -169
  369. package/src/react/ui/separator.tsx +0 -25
  370. package/src/react/ui/sheet.tsx +0 -136
  371. package/src/react/ui/sidebar.tsx +0 -723
  372. package/src/react/ui/skeleton.tsx +0 -13
  373. package/src/react/ui/slider.tsx +0 -34
  374. package/src/react/ui/switch.tsx +0 -28
  375. package/src/react/ui/table.tsx +0 -105
  376. package/src/react/ui/tabs.tsx +0 -63
  377. package/src/react/ui/textarea.tsx +0 -18
  378. package/src/react/ui/tooltip.tsx +0 -64
  379. package/src/react/useCollabSeed.ts +0 -86
  380. package/src/react/useResizableWidth.ts +0 -139
  381. package/src/react/utils.ts +0 -6
  382. package/src/react/widgetRegistry.test.ts +0 -43
  383. package/src/react/widgetRegistry.ts +0 -50
  384. package/src/react/widgets/StatsOverviewRenderer.tsx +0 -232
  385. package/src/react/widgets/TableWidgetRenderer.tsx +0 -231
  386. package/src/react/widgets/ViewRenderer.tsx +0 -71
  387. package/src/relationManagerData.test.ts +0 -1595
  388. package/src/richtext/index.ts +0 -8
  389. package/src/richtext/registry.ts +0 -89
  390. package/src/routes/globals.ts +0 -148
  391. package/src/routes/guard.test.ts +0 -325
  392. package/src/routes/helpers.ts +0 -700
  393. package/src/routes/pages.ts +0 -175
  394. package/src/routes/panel.ts +0 -204
  395. package/src/routes/relations.ts +0 -1227
  396. package/src/routes/resources.ts +0 -781
  397. package/src/routes/theme.ts +0 -91
  398. package/src/routes-nested-relations.test.ts +0 -676
  399. package/src/routes-relations.test.ts +0 -972
  400. package/src/routes.test.ts +0 -2027
  401. package/src/routes.ts +0 -303
  402. package/src/schema/Alert.test.ts +0 -109
  403. package/src/schema/Alert.ts +0 -131
  404. package/src/schema/Block.ts +0 -169
  405. package/src/schema/Breadcrumbs.ts +0 -40
  406. package/src/schema/Card.ts +0 -35
  407. package/src/schema/Divider.ts +0 -20
  408. package/src/schema/Element.ts +0 -219
  409. package/src/schema/EmptyState.test.ts +0 -37
  410. package/src/schema/EmptyState.ts +0 -63
  411. package/src/schema/Fieldset.ts +0 -43
  412. package/src/schema/Grid.ts +0 -43
  413. package/src/schema/Group.ts +0 -30
  414. package/src/schema/Heading.ts +0 -39
  415. package/src/schema/Html.ts +0 -67
  416. package/src/schema/Icon.ts +0 -54
  417. package/src/schema/Image.ts +0 -57
  418. package/src/schema/LinkTag.ts +0 -41
  419. package/src/schema/Markdown.ts +0 -85
  420. package/src/schema/MetaTag.ts +0 -41
  421. package/src/schema/RelationTabs.ts +0 -71
  422. package/src/schema/ScriptTag.ts +0 -55
  423. package/src/schema/Section.ts +0 -160
  424. package/src/schema/ServerDataElement.test.ts +0 -140
  425. package/src/schema/ServerDataElement.ts +0 -156
  426. package/src/schema/SlotComponent.test.ts +0 -77
  427. package/src/schema/SlotComponent.ts +0 -71
  428. package/src/schema/Split.ts +0 -50
  429. package/src/schema/Stat.test.ts +0 -118
  430. package/src/schema/Stat.ts +0 -154
  431. package/src/schema/StatsOverview.test.ts +0 -141
  432. package/src/schema/StatsOverview.ts +0 -119
  433. package/src/schema/StyleTag.ts +0 -35
  434. package/src/schema/TableWidget.test.ts +0 -297
  435. package/src/schema/TableWidget.ts +0 -289
  436. package/src/schema/Tabs.ts +0 -79
  437. package/src/schema/Text.ts +0 -58
  438. package/src/schema/UnorderedList.ts +0 -49
  439. package/src/schema/View.test.ts +0 -111
  440. package/src/schema/View.ts +0 -127
  441. package/src/schema/Wizard.ts +0 -220
  442. package/src/schema/containers.test.ts +0 -564
  443. package/src/schema/headTags.test.ts +0 -134
  444. package/src/schema/index.ts +0 -40
  445. package/src/schema/primes.test.ts +0 -269
  446. package/src/schema/resolveSchema.test.ts +0 -379
  447. package/src/schema/resolveSchema.ts +0 -917
  448. package/src/schema/sanitize.ts +0 -58
  449. package/src/search.test.ts +0 -446
  450. package/src/search.ts +0 -178
  451. package/src/sessionFilters.test.ts +0 -375
  452. package/src/sessionFilters.ts +0 -143
  453. package/src/slot-components/index.ts +0 -10
  454. package/src/slot-components/registry.ts +0 -56
  455. package/src/styles/file-upload.css +0 -13
  456. package/src/summarizers/Summarizer.test.ts +0 -84
  457. package/src/summarizers/Summarizer.ts +0 -123
  458. package/src/summarizers/index.ts +0 -11
  459. package/src/theme/base-colors.ts +0 -68
  460. package/src/theme/chart-colors.ts +0 -50
  461. package/src/theme/colors.ts +0 -447
  462. package/src/theme/generate-css.test.ts +0 -139
  463. package/src/theme/generate-css.ts +0 -44
  464. package/src/theme/generate-scale.test.ts +0 -106
  465. package/src/theme/generate-scale.ts +0 -97
  466. package/src/theme/icon-map.ts +0 -42
  467. package/src/theme/index.ts +0 -34
  468. package/src/theme/migrate.test.ts +0 -178
  469. package/src/theme/migrate.ts +0 -81
  470. package/src/theme/presets.ts +0 -135
  471. package/src/theme/radius.ts +0 -18
  472. package/src/theme/resolve.test.ts +0 -238
  473. package/src/theme/resolve.ts +0 -96
  474. package/src/theme/spacing.ts +0 -18
  475. package/src/theme/storage.test.ts +0 -126
  476. package/src/theme/storage.ts +0 -106
  477. package/src/theme/theme-colors.ts +0 -88
  478. package/src/theme/types.ts +0 -125
  479. package/src/uploads/UploadAdapter.ts +0 -35
  480. package/src/uploads/index.ts +0 -2
  481. package/src/uploads/localUpload.test.ts +0 -70
  482. package/src/uploads/localUpload.ts +0 -84
  483. package/src/validation/Validator.ts +0 -49
  484. package/src/validation/index.ts +0 -28
  485. package/src/validation/rules.ts +0 -78
  486. package/src/validation/runValidators.ts +0 -435
  487. package/src/validation/uniqueValidator.test.ts +0 -196
  488. package/src/validation/uniqueValidator.ts +0 -133
  489. package/src/validation/validators.test.ts +0 -268
  490. package/src/vite.test.ts +0 -184
  491. package/src/vite.ts +0 -787
  492. package/src/widgets/index.ts +0 -10
  493. package/src/widgets/registry.ts +0 -45
  494. package/src/widgets.test.ts +0 -592
  495. package/tsconfig.build.json +0 -11
  496. package/tsconfig.json +0 -4
  497. package/tsconfig.test.json +0 -10
  498. package/views/react/Dashboard.tsx +0 -27
  499. package/views/react/Resources/Form.tsx +0 -102
  500. package/views/react/Resources/Index.tsx +0 -49
@@ -1,617 +0,0 @@
1
- import { Page } from './Page.js'
2
- import {
3
- Form,
4
- type SavedNotificationHandler,
5
- type LifecycleHandler,
6
- type AfterSaveHandler,
7
- type SaveHandler,
8
- type RedirectHandler,
9
- type MutateDataHandler,
10
- type FillMutator,
11
- } from './elements/Form.js'
12
- import { Table } from './elements/Table.js'
13
- import { Filter } from './filters/Filter.js'
14
- import { TrashedFilter } from './filters/TrashedFilter.js'
15
- import { ListTabs } from './elements/ListTabs.js'
16
- import type { ListTab } from './Tab.js'
17
- import { Heading } from './schema/Heading.js'
18
- import { Wizard, Step } from './schema/Wizard.js'
19
- import { Action } from './actions/Action.js'
20
- import type { Element } from './schema/Element.js'
21
- import type { SchemaContext } from './schema/resolveSchema.js'
22
- import type { ResourceClass, ResourcePages } from './Resource.js'
23
- import type { PageMeta } from './Page.js'
24
- import { modelSave, modelLoadRecord, modelTableRecords } from './orm/modelDefaults.js'
25
- import { serializeIcon } from './icons/types.js'
26
-
27
- // ─── Sentinels for missing handlers ──────────────────────────
28
-
29
- /** Sentinel save handler — throws unless the user overrides via a custom Page or Form.save(). */
30
- function noSaveHandler(R: ResourceClass): () => never {
31
- return () => {
32
- throw new Error(
33
- `[Pilotiq] ${R.name}: no save handler. Set Resource.model = … to use the ORM defaults, or call Form.save(...) inside Resource.form().`,
34
- )
35
- }
36
- }
37
-
38
- /** Sentinel loadRecord handler — throws unless the user overrides via a custom Page or Form.loadRecord(). */
39
- function noLoadRecordHandler(R: ResourceClass): () => never {
40
- return () => {
41
- throw new Error(
42
- `[Pilotiq] ${R.name}: no loadRecord handler. Set Resource.model = … to use the ORM defaults, or call Form.loadRecord(...) inside Resource.form().`,
43
- )
44
- }
45
- }
46
-
47
- /** Install model-backed save/loadRecord on a freshly-built form when the user hasn't supplied them. */
48
- export function applyFormDefaults(R: ResourceClass, form: Form, mode: 'create' | 'edit' | 'view'): void {
49
- const M = R.model
50
- if (!form.getSave()) {
51
- form.save(M ? modelSave(M) : noSaveHandler(R))
52
- }
53
- if (mode !== 'create' && !form.getLoadRecord()) {
54
- form.loadRecord(M ? modelLoadRecord(R) : noLoadRecordHandler(R))
55
- }
56
- }
57
-
58
- /** Install model-backed records on a freshly-built table when the user hasn't supplied them. */
59
- export function applyTableDefaults(R: ResourceClass, table: Table): void {
60
- // Plan #13 — auto-inject `TrashedFilter` for soft-delete resources
61
- // unless the user already added one. The filter drives `withTrashed /
62
- // onlyTrashed` on the model query via its built-in `query(fn)` handler;
63
- // matching against the class catches user-renamed instances too.
64
- if (R.softDeletes) {
65
- const hasTrashedFilter = (table.getChildren() ?? [])
66
- .some(c => c instanceof TrashedFilter)
67
- if (!hasTrashedFilter) {
68
- const existing = (table.getChildren() ?? []).filter(c => c instanceof Filter) as Filter[]
69
- table.filters([...existing, TrashedFilter.make()])
70
- }
71
- }
72
-
73
- if (table.getRecords()) return
74
- const M = R.model
75
- if (M) table.records(modelTableRecords(R, table))
76
- }
77
-
78
- // ─── Base classes for resource page roles ────────────────────
79
-
80
- /**
81
- * Base class subclasses extend to bind a Page to a Resource. Each role
82
- * (`ListPage`, `CreatePage`, `EditPage`, `ViewPage`) provides the
83
- * boilerplate so a per-resource page file is typically a one-liner
84
- * override of `getResource()`.
85
- *
86
- * @example
87
- * class ListArticles extends ListPage {
88
- * static override getResource() { return ArticleResource }
89
- * }
90
- *
91
- * Override hooks (`getHeader`, `getActions` on `ViewPage`) let you tweak
92
- * the rendered schema without re-implementing the wiring.
93
- */
94
- abstract class ResourcePage extends Page {
95
- /** Subclasses must override to bind to a Resource. */
96
- static override getResource(): ResourceClass {
97
- throw new Error(`[Pilotiq] ${this.name}: must override static getResource() to bind to a Resource.`)
98
- }
99
-
100
- /** Falls back to the resource's icon when the page didn't set one. */
101
- static override toMeta(): PageMeta {
102
- const meta = super.toMeta()
103
- if (meta.icon !== undefined) return meta
104
- const R = this.getResource()
105
- return { ...meta, icon: serializeIcon(R.icon, R.name) }
106
- }
107
- }
108
-
109
- export class ListPage extends ResourcePage {
110
- static override getMode() { return 'list' as const }
111
-
112
- static override getSlug(): string {
113
- return this.slug ?? this.getResource().getSlug()
114
- }
115
-
116
- static override getLabel(): string {
117
- return this.label ?? this.getResource().label
118
- }
119
-
120
- static override async schema(ctx?: SchemaContext): Promise<Element[]> {
121
- const R = this.getResource()
122
- const basePath = (ctx?.['basePath'] as string | undefined) ?? ''
123
- const table = R.table(Table.make())
124
- applyTableDefaults(R, table)
125
-
126
- // Layer in default header + row actions. Skip any whose name the user
127
- // already added in `Resource.table()` so customization wins.
128
- const existing = new Set(
129
- (table.getChildren() ?? [])
130
- .filter((c): c is Action => c instanceof Action)
131
- .map(a => a.name),
132
- )
133
- const headers = this.getHeaderActions(R, basePath).filter(a => !existing.has(a.name))
134
- const rows = this.getRowActions(R, basePath).filter(a => !existing.has(a.name))
135
- if (headers.length > 0) table.headerActions(headers)
136
- if (rows.length > 0) table.recordActions(rows)
137
-
138
- // Wrap the user's `getTabs()` array (if any) in a ListTabs container
139
- // and slot it between the heading and the Table. The page-data
140
- // pipeline activates the right tab and resolves badges before
141
- // serialization — the schema-build path here just sets the structure.
142
- const tabs = this.getTabs(R)
143
- const listTabs = tabs.length > 0
144
- ? ListTabs.make().tabs(tabs)
145
- : undefined
146
-
147
- // Plan #15 — `Resource.headerSchema(ctx) / footerSchema(ctx)` slot
148
- // dashboard widgets above and below the list table. Resolved with the
149
- // same `SchemaContext` so widgets see `mode: 'table'`, `basePath`, `user`.
150
- const [header, footer] = await Promise.all([
151
- Promise.resolve(R.headerSchema(ctx)),
152
- Promise.resolve(R.footerSchema(ctx)),
153
- ])
154
-
155
- const elements: Element[] = [...this.getHeader(R)]
156
- if (header.length > 0) elements.push(...header)
157
- if (listTabs) elements.push(listTabs)
158
- elements.push(table)
159
- if (footer.length > 0) elements.push(...footer)
160
- return elements
161
- }
162
-
163
- /** Override to customize the heading rendered above the table. */
164
- static getHeader(R: ResourceClass): Element[] {
165
- return [Heading.make(R.label).level(1)]
166
- }
167
-
168
- /**
169
- * Header actions rendered in the table's top bar. Returns `[]` by
170
- * default — Filament-style explicit. Override to add a Create button:
171
- *
172
- * @example
173
- * static override getHeaderActions(R, basePath) {
174
- * return [Action.create(R, basePath)]
175
- * }
176
- *
177
- * Or call it explicitly inside `Resource.table()` via
178
- * `table.headerActions([Action.create(R, basePath)])`.
179
- */
180
- static getHeaderActions(_R: ResourceClass, _basePath: string): Action[] {
181
- return []
182
- }
183
-
184
- /**
185
- * Row actions rendered in a per-row Actions column. Returns `[]` by
186
- * default — Filament-style explicit. Override to add Edit/Delete:
187
- *
188
- * @example
189
- * static override getRowActions(R, basePath) {
190
- * return [Action.edit(R, basePath), Action.delete(R, basePath)]
191
- * }
192
- *
193
- * Or call them explicitly inside `Resource.table()` via
194
- * `table.recordActions([Action.edit(R, basePath), Action.delete(R, basePath)])`.
195
- *
196
- * Per-row `:id` substitution still happens automatically — factories
197
- * use the `:id` template; the renderer fills it in for each row.
198
- */
199
- static getRowActions(_R: ResourceClass, _basePath: string): Action[] {
200
- return []
201
- }
202
-
203
- /**
204
- * List-page tabs rendered above the table — Filament-style query
205
- * shortcuts ("All / Drafts / Published / Archived"). Returns `[]` by
206
- * default. Each tab has a label + optional icon + optional count badge
207
- * + a `modifyQuery` predicate that narrows the table. Active tab is
208
- * carried through `?tab=name` in the URL.
209
- *
210
- * @example
211
- * static override getTabs() {
212
- * return [
213
- * ListTab.make('all').label('All'),
214
- * ListTab.make('drafts')
215
- * .label('Drafts')
216
- * .badge(() => prisma.article.count({ where: { status: 'draft' } }))
217
- * .modifyQuery(q => q.where('status', 'draft')),
218
- * ]
219
- * }
220
- */
221
- static getTabs(_R?: ResourceClass): ListTab[] {
222
- return []
223
- }
224
- }
225
-
226
- /**
227
- * Build the page heading and attach `formActions` as right-aligned
228
- * buttons. Each submit action is automatically retargeted at the form's
229
- * generated id so a header-mounted Save button submits the form below.
230
- *
231
- * If `getHeader()` returns multiple elements or non-Heading roots, the
232
- * actions get attached to the first Heading in the list; if none exists,
233
- * actions are dropped (custom headers carry their own action layout).
234
- */
235
- function buildHeader(
236
- header: Element[],
237
- formActions: Action[],
238
- formId: string,
239
- ): Element[] {
240
- if (formActions.length === 0) return header
241
- const targeted = formActions.map(a => (a.isSubmit() ? a.form(formId) : a))
242
- for (const el of header) {
243
- if (el instanceof Heading) {
244
- el.actions(targeted)
245
- return header
246
- }
247
- }
248
- return header
249
- }
250
-
251
- /**
252
- * Install lifecycle overrides defined as static methods on a form-bearing
253
- * page subclass onto the freshly-built `Form`. Called by `CreatePage` and
254
- * `EditPage` after `R.form(...)` runs so user `Resource.form()` config
255
- * stays the canonical seam, with page subclasses layering on top.
256
- *
257
- * Mode-specific hooks (`beforeCreate` etc.) only fire on the matching mode.
258
- * Generic ones (`mutateData`, `beforeSave`, `afterSave`) fire on both. The
259
- * page methods get `.bind(PageClass)` so `this` inside the override resolves
260
- * to the page class — useful when an override delegates to another static.
261
- */
262
- function installLifecycleHooks(
263
- PageClass: typeof CreatePage | typeof EditPage,
264
- form: Form,
265
- mode: 'create' | 'edit',
266
- ): void {
267
- // Coerce to a record-typed view so we can probe optional statics through
268
- // a single property bag without writing a wide intersection.
269
- const P = PageClass as unknown as Record<string, unknown>
270
- const bind = <T extends (...args: never[]) => unknown>(fn: T): T => fn.bind(PageClass) as T
271
-
272
- if (typeof P['mutateFormDataBeforeFill'] === 'function') form.mutateFormDataBeforeFill(bind(P['mutateFormDataBeforeFill'] as never))
273
- if (typeof P['mutateFormDataAfterFill'] === 'function') form.mutateFormDataAfterFill (bind(P['mutateFormDataAfterFill'] as never))
274
- if (typeof P['mutateData'] === 'function') form.mutateData (bind(P['mutateData'] as never))
275
- if (typeof P['mutateDataBeforeCreate'] === 'function') form.mutateDataBeforeCreate (bind(P['mutateDataBeforeCreate'] as never))
276
- if (typeof P['mutateDataBeforeUpdate'] === 'function') form.mutateDataBeforeUpdate (bind(P['mutateDataBeforeUpdate'] as never))
277
- if (typeof P['beforeSave'] === 'function') form.beforeSave (bind(P['beforeSave'] as never))
278
- if (typeof P['afterSave'] === 'function') form.afterSave (bind(P['afterSave'] as never))
279
- if (typeof P['beforeCreate'] === 'function') form.beforeCreate (bind(P['beforeCreate'] as never))
280
- if (typeof P['afterCreate'] === 'function') form.afterCreate (bind(P['afterCreate'] as never))
281
- if (typeof P['beforeUpdate'] === 'function') form.beforeUpdate (bind(P['beforeUpdate'] as never))
282
- if (typeof P['afterUpdate'] === 'function') form.afterUpdate (bind(P['afterUpdate'] as never))
283
- if (typeof P['handleCreate'] === 'function') form.handleCreate (bind(P['handleCreate'] as never))
284
- if (typeof P['handleUpdate'] === 'function') form.handleUpdate (bind(P['handleUpdate'] as never))
285
- if (typeof P['getRedirectUrl'] === 'function') form.redirectAfterSave (bind(P['getRedirectUrl'] as never))
286
-
287
- // Notifications: page hook returns string | null. `null` disables. A
288
- // string installs the spec for the matching mode. The framework default
289
- // (resource-aware "Created"/"Saved") is layered in here unless the
290
- // user overrode it; passing `null` from the override suppresses it.
291
- const R = PageClass.getResource()
292
- const getCreatedTitle = P['getCreatedNotificationTitle'] as (() => string | null | undefined) | undefined
293
- const getSavedTitle = P['getSavedNotificationTitle'] as (() => string | null | undefined) | undefined
294
-
295
- // Explicit `null` from the override means "suppress this toast" — keep
296
- // it; only fall through to the framework default when the override was
297
- // omitted or returned undefined.
298
- const explicitCreated = getCreatedTitle?.()
299
- const createdTitle = explicitCreated !== undefined
300
- ? explicitCreated
301
- : (mode === 'create' ? `${R.labelSingular} created` : undefined)
302
- if (createdTitle === null) form.createdNotification(null)
303
- else if (createdTitle !== undefined) form.createdNotification(createdTitle as SavedNotificationHandler)
304
-
305
- const explicitSaved = getSavedTitle?.()
306
- const savedTitle = explicitSaved !== undefined
307
- ? explicitSaved
308
- : (mode === 'edit' ? `${R.labelSingular} saved` : undefined)
309
- if (savedTitle === null) form.savedNotification(null)
310
- else if (savedTitle !== undefined) form.savedNotification(savedTitle as SavedNotificationHandler)
311
- }
312
-
313
- export class CreatePage extends ResourcePage {
314
- static override getMode() { return 'create' as const }
315
-
316
- static override getSlug(): string {
317
- return this.slug ?? `${this.getResource().getSlug()}/create`
318
- }
319
-
320
- static override getLabel(): string {
321
- return this.label ?? `Create ${this.getResource().labelSingular}`
322
- }
323
-
324
- static override schema(ctx?: SchemaContext): Element[] {
325
- const R = this.getResource()
326
- const basePath = (ctx?.['basePath'] as string | undefined) ?? ''
327
- const form = R.form(Form.make())
328
- applyFormDefaults(R, form, 'create')
329
- installLifecycleHooks(this, form, 'create')
330
-
331
- // Wizard mode (Filament's `HasWizard` equivalent). When `getSteps()`
332
- // returns one or more `Step` instances, the form's children are
333
- // replaced with a `Wizard` wrapping those steps. Lifecycle hooks
334
- // installed on the form still fire on final-step submit; per-step
335
- // validation flows through the existing `tagFormWizardUrls /
336
- // formWizardData` pipeline (Plan #8). Custom Wizard chrome
337
- // (`skippable`, `startOnStep`, `persist`) goes through `getWizard()`,
338
- // which receives the configured Wizard instance and may swap or
339
- // tweak it.
340
- const steps = this.getSteps(R)
341
- if (steps.length > 0) {
342
- const wizard = this.getWizard(Wizard.make().steps(steps), R)
343
- form.schema([wizard])
344
- }
345
-
346
- const header = buildHeader(this.getHeader(R), this.getFormActions(R, basePath), form.getFormId())
347
- return [...header, form]
348
- }
349
-
350
- /** Override to customize the heading rendered above the form. */
351
- static getHeader(R: ResourceClass): Element[] {
352
- return [Heading.make(`Create ${R.labelSingular}`).level(1)]
353
- }
354
-
355
- /**
356
- * Wizard mode opt-in. Override to return one or more steps and the
357
- * create flow becomes a multi-step wizard. Per-step validation runs
358
- * on Next click; `Form.save()` still fires on final-step submit.
359
- *
360
- * Default `[]` ships the regular single-page form. When non-empty,
361
- * the form's children (whatever `Resource.form()` configured) are
362
- * REPLACED with a Wizard wrapping these steps — author the wizard's
363
- * fields directly inside the steps, not via `Resource.form().schema()`.
364
- *
365
- * @example
366
- * static override getSteps(R) {
367
- * return [
368
- * Step.make('Account').schema([
369
- * EmailField.make('email').required(),
370
- * TextField.make('password').required(),
371
- * ]),
372
- * Step.make('Profile').schema([
373
- * TextField.make('name').required(),
374
- * ]),
375
- * ]
376
- * }
377
- */
378
- static getSteps(_R: ResourceClass): Step[] { return [] }
379
-
380
- /**
381
- * Customize wizard chrome (skippable / startOnStep / persist) before
382
- * it lands in the form. The framework calls this with `Wizard.make().steps(getSteps(R))`
383
- * already configured; mutate or replace as needed and return.
384
- * Default returns the wizard untouched.
385
- *
386
- * @example
387
- * static override getWizard(wizard, _R) {
388
- * return wizard.skippable().persist(false)
389
- * }
390
- */
391
- static getWizard(wizard: Wizard, _R: ResourceClass): Wizard {
392
- return wizard
393
- }
394
-
395
- /**
396
- * Action buttons rendered to the right of the page heading. Default:
397
- * primary "Create" submit + a secondary "Create & create another"
398
- * (outlined) submit. The "create another" button posts a sentinel
399
- * (`_continueCreate=1`) so the server routes the redirect back to
400
- * `/create` instead of the new record's `/edit` page. Override to
401
- * customize (drop the secondary button, add a Cancel link, etc.) or
402
- * return `[]` to suppress.
403
- *
404
- * `basePath` is the panel's mount path (e.g. `/admin`). Pass it
405
- * through to `Action.create / .href / etc.` factories that need a
406
- * full URL — same surface as `ListPage.getRowActions(R, basePath)`.
407
- */
408
- static getFormActions(R: ResourceClass, _basePath: string = ''): Action[] {
409
- return [
410
- Action.make('submit').label(`Create ${R.labelSingular}`).submit(),
411
- Action.make('createAnother')
412
- .label('Create & create another')
413
- .submit()
414
- .outlined()
415
- .formField('_continueCreate', '1'),
416
- ]
417
- }
418
-
419
- // ─── Optional lifecycle overrides ─────────────────────
420
- // Subclasses may override any of these. They install onto the form
421
- // during `schema()` via `installLifecycleHooks`. Signatures match the
422
- // matching `Form.*` setter parameter type.
423
- static mutateFormDataBeforeFill?: FillMutator
424
- static mutateFormDataAfterFill?: FillMutator
425
- static mutateData?: MutateDataHandler
426
- static mutateDataBeforeCreate?: MutateDataHandler
427
- static beforeSave?: LifecycleHandler
428
- static afterSave?: AfterSaveHandler
429
- static beforeCreate?: LifecycleHandler
430
- static afterCreate?: AfterSaveHandler
431
- static handleCreate?: SaveHandler
432
- static getRedirectUrl?: RedirectHandler
433
- /**
434
- * Return the toast title for the post-create success notification.
435
- * Returning `null` suppresses the toast; `undefined` or omission falls
436
- * back to the framework default `"${R.labelSingular} created"`.
437
- */
438
- static getCreatedNotificationTitle?: () => string | null | undefined
439
- }
440
-
441
- export class EditPage extends ResourcePage {
442
- static override getMode() { return 'edit' as const }
443
-
444
- static override getSlug(): string {
445
- return this.slug ?? `${this.getResource().getSlug()}/edit`
446
- }
447
-
448
- static override getLabel(): string {
449
- return this.label ?? `Edit ${this.getResource().labelSingular}`
450
- }
451
-
452
- static override schema(ctx?: SchemaContext): Element[] {
453
- const R = this.getResource()
454
- const basePath = (ctx?.['basePath'] as string | undefined) ?? ''
455
- const recordId = ctx?.['recordId'] as string | undefined
456
- const form = R.form(Form.make())
457
- applyFormDefaults(R, form, 'edit')
458
- installLifecycleHooks(this, form, 'edit')
459
- const header = buildHeader(this.getHeader(R), this.getFormActions(R, basePath, recordId), form.getFormId())
460
- return [...header, form]
461
- }
462
-
463
- /** Override to customize the heading rendered above the form. */
464
- static getHeader(R: ResourceClass): Element[] {
465
- return [Heading.make(`Edit ${R.labelSingular}`).level(1)]
466
- }
467
-
468
- /**
469
- * Action buttons rendered to the right of the page heading. Default:
470
- * a single submit button labeled "Save changes". The submit action is
471
- * auto-targeted at the form below via the HTML `form` attribute.
472
- *
473
- * `basePath` and `recordId` let overrides drop in `Action.delete /
474
- * .view / .replicate(R, basePath)` factories alongside Save without
475
- * hardcoding the panel mount path. Filament-style "delete this
476
- * record" / "view" / "replicate" buttons cluster right of the heading
477
- * with the Save button — they're all rendered as a single right-
478
- * aligned action group.
479
- *
480
- * @example
481
- * static override getFormActions(R, basePath) {
482
- * return [
483
- * Action.delete(R, basePath),
484
- * Action.view (R, basePath),
485
- * Action.make('submit').label('Save changes').submit(),
486
- * ]
487
- * }
488
- */
489
- static getFormActions(_R: ResourceClass, _basePath: string = '', _recordId?: string): Action[] {
490
- return [
491
- Action.make('submit').label('Save changes').submit(),
492
- ]
493
- }
494
-
495
- // ─── Optional lifecycle overrides ─────────────────────
496
- // Same surface as CreatePage but for update mode.
497
- static mutateFormDataBeforeFill?: FillMutator
498
- static mutateFormDataAfterFill?: FillMutator
499
- static mutateData?: MutateDataHandler
500
- static mutateDataBeforeUpdate?: MutateDataHandler
501
- static beforeSave?: LifecycleHandler
502
- static afterSave?: AfterSaveHandler
503
- static beforeUpdate?: LifecycleHandler
504
- static afterUpdate?: AfterSaveHandler
505
- static handleUpdate?: SaveHandler
506
- static getRedirectUrl?: RedirectHandler
507
- /**
508
- * Return the toast title for the post-save success notification.
509
- * Returning `null` suppresses the toast; `undefined` or omission falls
510
- * back to the framework default `"${R.labelSingular} saved"`.
511
- */
512
- static getSavedNotificationTitle?: () => string | null | undefined
513
- }
514
-
515
- export class ViewPage extends ResourcePage {
516
- static override getMode() { return 'view' as const }
517
-
518
- static override getSlug(): string {
519
- return this.slug ?? `${this.getResource().getSlug()}/view`
520
- }
521
-
522
- static override getLabel(): string {
523
- return this.label ?? `View ${this.getResource().labelSingular}`
524
- }
525
-
526
- static override async schema(ctx?: SchemaContext): Promise<Element[]> {
527
- const R = this.getResource()
528
- const recordId = ctx?.['recordId'] as string | undefined
529
- const basePath = (ctx?.['basePath'] as string | undefined) ?? ''
530
-
531
- // Reuse the form's loadRecord — same loader powers edit mode, including
532
- // the model-backed default when `R.model` is set.
533
- let record: unknown = null
534
- if (recordId) {
535
- const form = R.form(Form.make())
536
- applyFormDefaults(R, form, 'view')
537
- const loader = form.getLoadRecord()
538
- if (loader) {
539
- try { record = await loader(recordId, { values: {} }) } catch { /* sentinel/missing */ }
540
- }
541
- }
542
-
543
- return [
544
- ...this.getHeader(R, record),
545
- ...this.getActions(R, recordId, basePath),
546
- ...R.detail(record),
547
- ]
548
- }
549
-
550
- /** Override to customize the page header. Receives the loaded record. */
551
- static getHeader(R: ResourceClass, _record: unknown): Element[] {
552
- return [Heading.make(R.labelSingular).level(1)]
553
- }
554
-
555
- /**
556
- * Override to set the action row above the detail content. Returns
557
- * `[]` by default — Filament-style explicit. Wire Edit/Delete with
558
- * the `:id`-substituted factories:
559
- *
560
- * @example
561
- * static override getActions(R, recordId, basePath) {
562
- * if (!recordId) return []
563
- * return [Action.edit(R, basePath), Action.delete(R, basePath)]
564
- * }
565
- *
566
- * The renderer fills the `:id` placeholder using the page's
567
- * `recordId`, so the same factory works for row + view contexts.
568
- */
569
- static getActions(_R: ResourceClass, _recordId: string | undefined, _basePath: string): Element[] {
570
- return []
571
- }
572
- }
573
-
574
- // ─── Factory functions (anonymous subclasses bound to R) ─────
575
-
576
- export function defaultListPage(R: ResourceClass): typeof Page {
577
- return class extends ListPage {
578
- static override getResource(): ResourceClass { return R }
579
- }
580
- }
581
-
582
- export function defaultCreatePage(R: ResourceClass): typeof Page {
583
- return class extends CreatePage {
584
- static override getResource(): ResourceClass { return R }
585
- }
586
- }
587
-
588
- export function defaultEditPage(R: ResourceClass): typeof Page {
589
- return class extends EditPage {
590
- static override getResource(): ResourceClass { return R }
591
- }
592
- }
593
-
594
- export function defaultViewPage(R: ResourceClass): typeof Page {
595
- return class extends ViewPage {
596
- static override getResource(): ResourceClass { return R }
597
- }
598
- }
599
-
600
- /**
601
- * Auto-generate the index/create/edit/view page classes from a Resource.
602
- * Consumed by `Resource.resolvePages()` to fill in keys the user didn't
603
- * override. `view` is included whenever the resource has a meaningful
604
- * `detail()` — a no-op `detail()` still ships a default header with the
605
- * Edit / Delete actions, which is useful on its own.
606
- */
607
- export function defaultPages(R: ResourceClass): Required<ResourcePages> {
608
- return {
609
- index: defaultListPage(R),
610
- create: defaultCreatePage(R),
611
- edit: defaultEditPage(R),
612
- view: defaultViewPage(R),
613
- // Record sub-pages have no framework defaults — users register them
614
- // explicitly via `static pages() { return { record: { … } } }`.
615
- record: {},
616
- }
617
- }