@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
package/src/Resource.ts DELETED
@@ -1,526 +0,0 @@
1
- import type { Element } from './schema/Element.js'
2
- import type { Form } from './elements/Form.js'
3
- import { Table } from './elements/Table.js'
4
- import type { Page } from './Page.js'
5
- import type { ModelLike, ModelQuery, QueryContext } from './orm/modelDefaults.js'
6
- import type { IconValue } from './icons/types.js'
7
- import { defaultPages } from './defaultPages.js'
8
- import type { RelationManager } from './RelationManager.js'
9
- import type { SchemaContext } from './schema/resolveSchema.js'
10
- import type { ClusterClass } from './Cluster.js'
11
- import { resourceBasePath } from './clusterPaths.js'
12
-
13
- /** Map of resource page roles to Page subclasses. */
14
- export interface ResourcePages {
15
- index?: typeof Page
16
- create?: typeof Page
17
- edit?: typeof Page
18
- view?: typeof Page
19
- /**
20
- * Record-scoped custom sub-pages. Each entry is a `Page` subclass
21
- * mounted at `${resourceBase}/${slug}/:id/${subPageSlug}`. Tabs show
22
- * up in the `RelationTabs` sub-nav strip between the `__edit` tab
23
- * and the relation-manager tabs.
24
- *
25
- * Sub-page slugs are validated at panel boot:
26
- * - Must match `[A-Za-z0-9_-]+`.
27
- * - Must not collide with reserved tokens (`edit`, `delete`,
28
- * `restore`, `force-delete`, `_form`, `_action`, `_search`,
29
- * `_uploads`, `_attach`, `_detach`, `_bulk-detach`, `create`).
30
- * - Must not collide with any `RelationManager.relationship` on
31
- * the same resource.
32
- *
33
- * Each sub-page receives the loaded record in `ctx.record` and runs
34
- * its own `Page.canAccess(user, record)` gate after the parent
35
- * resource's `canAccess` + `canView` predicates have passed.
36
- */
37
- record?: Record<string, typeof Page>
38
- }
39
-
40
- /** Pill color tokens for `navigationBadgeColor`. Matches the shared color
41
- * palette used by `ListTab.badgeColor` so the renderer can re-use the
42
- * same Tailwind utility map. */
43
- export type NavigationBadgeColor =
44
- | 'default' | 'primary' | 'success' | 'warning' | 'destructive' | 'info'
45
-
46
- /** Returned by `navigationBadge`: a string/number to render as a pill,
47
- * or undefined to render no pill. May be async. Errors thrown from this
48
- * handler are swallowed by `panelInfo()` so a flaky count never blanks
49
- * the page. */
50
- export type NavigationBadgeHandler =
51
- () => string | number | undefined | Promise<string | number | undefined>
52
-
53
- /**
54
- * Per-resource collab configuration. Set via `static collab = true` (the
55
- * 90% case — opts the edit page in with presence) or via the object form
56
- * for finer control. Omitting `static collab` entirely keeps the resource
57
- * collab-free even when the `@pilotiq-pro/collab` plugin is registered.
58
- *
59
- * pages — page roles where collab activates. `'edit'` syncs values +
60
- * presence; `'view'` is presence-only (the page is read-only,
61
- * value-sync would be moot). Defaults to `['edit']`.
62
- * presence — when false, suppress the awareness layer (focus chips,
63
- * cursor positions) while keeping value-sync. Defaults to true.
64
- *
65
- * Field-level `.collab(false)` always wins over this setting — opting the
66
- * resource in then opting individual fields out is the supported shape.
67
- */
68
- export interface ResourceCollabConfig {
69
- pages: ReadonlyArray<'edit' | 'view'>
70
- presence: boolean
71
- }
72
-
73
- /** Raw shape accepted by `static collab` before normalization. `true` is a
74
- * shorthand for `{ pages: ['edit'], presence: true }`. */
75
- export type ResourceCollabInput = boolean | {
76
- pages?: ReadonlyArray<'edit' | 'view'>
77
- presence?: boolean
78
- }
79
-
80
- /**
81
- * Abstract Resource base class. **All methods are static** — resources are
82
- * registered by class, not by instance. Routes look up the class and call
83
- * statics directly.
84
- *
85
- * Subclasses override `form()`, `table()`, `detail()`, and `pages()` to
86
- * shape the resource. Defaults make the most-common case (CRUD with a
87
- * form + a table) work with minimal boilerplate; 2.2 will fill in
88
- * auto-generated default Page classes.
89
- */
90
- export abstract class Resource {
91
- /** Human-readable plural label, e.g. `'Articles'`. */
92
- static label: string = 'Resources'
93
-
94
- /** Singular label, e.g. `'Article'`. */
95
- static labelSingular: string = 'Resource'
96
-
97
- /** Breadcrumb label override. Falls through to `label`. Use this when
98
- * the breadcrumb chain reads better with a different word than the
99
- * sidebar / page-title plural — e.g. `label = 'Blog Posts'` paired
100
- * with `breadcrumb = 'Posts'` for a tighter chain. */
101
- static breadcrumb: string | undefined = undefined
102
-
103
- /** URL slug. Derived from `label` when unset. */
104
- static slug: string = ''
105
-
106
- /** Sidebar / nav icon. Either a kebab-case registry name (e.g.,
107
- * `'file'`) or a React component reference imported from any icon
108
- * library (e.g., `import { Newspaper } from 'lucide-react'`).
109
- * See `@pilotiq/pilotiq/icons` for the registry; component refs
110
- * resolve via the Vite-plugin `_components.ts` manifest. */
111
- static icon: IconValue = 'file'
112
-
113
- // ─── Plan #9: navigation metadata ──────────────────────────
114
- // Static fields evaluated once at panel-config time; only
115
- // `navigationBadge` runs per request. See docs/plans/resource-navigation.md.
116
-
117
- /** Group label this resource renders under in the sidebar. Items
118
- * without a group land in an unnamed top section. */
119
- static navigationGroup: string | undefined = undefined
120
-
121
- /** Sort key within a group. Lower sorts first; ties fall back to
122
- * registration order. Items without a sort go after sorted items. */
123
- static navigationSort: number | undefined = undefined
124
-
125
- /** Sidebar label override. `Resource.label` still drives page titles. */
126
- static navigationLabel: string | undefined = undefined
127
-
128
- /** Sidebar icon override. Same `IconValue` contract as `icon`. */
129
- static navigationIcon: IconValue = undefined
130
-
131
- /** Server-eval'd badge handler; rendered as a small pill next to the
132
- * label. Errors thrown here are swallowed so a broken count never
133
- * breaks page render. */
134
- static navigationBadge: NavigationBadgeHandler | undefined = undefined
135
-
136
- /** Pill color for the badge. */
137
- static navigationBadgeColor: NavigationBadgeColor = 'default'
138
-
139
- /** Class name (`Resource.name` / `Global.name` / `Page.name`) of a
140
- * parent nav item. Renders nested under the parent when set; renders
141
- * at top level when the name doesn't resolve. */
142
- static navigationParentItem: string | undefined = undefined
143
-
144
- /**
145
- * Cluster this resource belongs to. When set, the resource's URLs gain
146
- * the cluster's slug as a prefix segment (e.g. `/admin/content/articles`
147
- * instead of `/admin/articles`) and the resource nests under the
148
- * cluster's nav entry instead of appearing at the panel top level.
149
- *
150
- * The referenced class must be registered via `Pilotiq.clusters([…])`;
151
- * boot fails otherwise.
152
- */
153
- static cluster?: ClusterClass
154
-
155
- /** Column that names a record when referring to it in search results,
156
- * breadcrumbs, or relation pickers. Resolution order at the call site
157
- * is `recordTitleAttribute` → `'name'` → `'title'` → `'id'`. */
158
- static recordTitleAttribute: string | undefined = undefined
159
-
160
- /**
161
- * Optional ORM model. When set, `defaultPages` auto-fills `Form.save`,
162
- * `Form.loadRecord`, `Table.records`, and `Resource.deleteRecord` so
163
- * the common CRUD case needs no manual wiring. Anything explicitly
164
- * configured on `form()` / `table()` still wins.
165
- *
166
- * Any object satisfying `ModelLike` works — `@rudderjs/orm` `Model`
167
- * subclasses do so structurally via their static methods.
168
- */
169
- static model?: ModelLike
170
-
171
- /**
172
- * Hook for scoping every query against this resource's table — list
173
- * pages, global search, find-by-PK loads (record load for view / edit
174
- * pages, policy lookups). Default returns `this.model.query()`.
175
- *
176
- * Override to install tenant scopes, default ordering, eager-load
177
- * defaults, or any other always-on filter:
178
- *
179
- * @example
180
- * static override query(ctx) {
181
- * return super.query(ctx).where('tenantId', (ctx?.user as any)?.tenantId)
182
- * }
183
- *
184
- * @example
185
- * static override query(ctx) {
186
- * return super.query(ctx).orderBy('createdAt', 'DESC')
187
- * }
188
- *
189
- * Soft-delete restore / force-delete routes deliberately bypass this
190
- * — they build their own `query().withTrashed()` chain so a scope that
191
- * hides trashed rows doesn't hide records the operator is trying to
192
- * recover. Everything else routes through here.
193
- *
194
- * Throws when `static model` isn't set; subclasses without a model
195
- * must override `query()` directly to return whatever query builder
196
- * they're driving.
197
- */
198
- static query(_ctx?: QueryContext): ModelQuery {
199
- if (!this.model) {
200
- throw new Error(
201
- `[Pilotiq] ${this.name}.query() requires \`static model = …\` to be set, ` +
202
- `or override \`static query(ctx)\` directly to return a custom ModelQuery.`,
203
- )
204
- }
205
- return this.model.query()
206
- }
207
-
208
- // ─── Plan #13: soft deletes ────────────────────────────────
209
- // Opt-in: when true, pilotiq routes the standard delete action
210
- // through `model.delete()` (which writes `deletedAt`), surfaces a
211
- // TrashedFilter on the list page, swaps the row-action set on
212
- // trashed rows (Restore + Force-delete instead of Edit + Delete),
213
- // and exposes two new POST routes: `/:id/restore` and
214
- // `/:id/force-delete`. The rudder ORM side must also opt in
215
- // (`Model.softDeletes = true`) for the underlying behavior to
216
- // engage — pilotiq throws a clear boot error when the flag is
217
- // set here but the model lacks `restore` / `forceDelete`.
218
-
219
- /** Enable soft-delete UX (TrashedFilter, Restore action,
220
- * Force-delete action, soft-delete-aware row visibility). Default
221
- * `false`. Requires `Resource.model` to be set, with
222
- * `Model.softDeletes = true` on the rudder side. */
223
- static softDeletes: boolean = false
224
-
225
- /** Column name carrying the soft-delete timestamp on each row.
226
- * Per-row visibility predicates and the trashed-row branch in
227
- * `Action.delete` consult `record[deletedAtColumn]`. Default
228
- * matches rudder's `'deletedAt'`. */
229
- static deletedAtColumn: string = 'deletedAt'
230
-
231
- /** Persist the active list filter / search / sort slice on the
232
- * user's session so revisiting the resource lands on the same view.
233
- * No-ops silently when `@rudderjs/session` isn't mounted. */
234
- static persistFiltersInSession: boolean = false
235
-
236
- /** Skip server-side row loading on list pages; the client paints a
237
- * skeleton and fetches rows from `GET {base}/{slug}/_table` after
238
- * mount. URL chrome (filters / search / page / group) still mirrors
239
- * on the SSR pass so the skeleton frame doesn't reset visible state. */
240
- static deferLoading: boolean = false
241
-
242
- // ─── Plan #12: global search ───────────────────────────────
243
- // Opt-in: resources with `globalSearch = false` are skipped by the
244
- // panel-level Cmd+K palette. Defaults below derive everything from
245
- // already-shipped surfaces (`recordTitleAttribute`, `Column.searchable()`,
246
- // the standard view URL) so the common case needs zero overrides.
247
-
248
- /** Include this resource in Cmd+K palette results. Default `false` —
249
- * quiet resources don't pollute results until users opt in. */
250
- static globalSearch: boolean = false
251
-
252
- /**
253
- * Columns the default search query LIKE-matches against. The default
254
- * dedupes `recordTitleAttribute` (Plan #9) with every searchable
255
- * column on the resource's table. Override to constrain or extend.
256
- * Returning an empty array effectively opts the resource out even
257
- * when `globalSearch=true`.
258
- */
259
- static globallySearchableAttributes(): string[] {
260
- const attrs = new Set<string>()
261
- if (this.recordTitleAttribute) attrs.add(this.recordTitleAttribute)
262
- // Materialise the resource's configured table once and read every
263
- // `searchable()` column off it. The Table builder is a pure
264
- // configuration call (no DB hits, no I/O), so doing this per
265
- // search request is fine; resources that don't want this can
266
- // override `globallySearchableAttributes()` directly.
267
- try {
268
- const table = this.table(Table.make())
269
- for (const col of table.getColumns()) {
270
- if (col.isSearchable()) attrs.add(col.name)
271
- }
272
- } catch { /* defensive — bad user table()? skip */ }
273
- return [...attrs]
274
- }
275
-
276
- /**
277
- * Title shown in the palette result row. Default resolution chain:
278
- * `record[recordTitleAttribute]` → `record.name` → `record.title` →
279
- * `record.id`. Override to customise (e.g. include the id).
280
- */
281
- static getGlobalSearchResultTitle(record: unknown): string {
282
- const r = record as Record<string, unknown> | null | undefined
283
- if (!r) return ''
284
- if (this.recordTitleAttribute && r[this.recordTitleAttribute] !== undefined) {
285
- return String(r[this.recordTitleAttribute])
286
- }
287
- if (r['name'] !== undefined) return String(r['name'])
288
- if (r['title'] !== undefined) return String(r['title'])
289
- if (r['id'] !== undefined) return String(r['id'])
290
- return ''
291
- }
292
-
293
- /**
294
- * Optional second-line text under the title. Returning `undefined`
295
- * tells the renderer to skip the subtitle row. Useful for status,
296
- * timestamps, or category pills.
297
- */
298
- static getGlobalSearchResultSubtitle(_record: unknown): string | undefined {
299
- return undefined
300
- }
301
-
302
- /**
303
- * URL the palette navigates to on Enter. Default uses the View page
304
- * when one exists, else the Edit page, else the resource list. Pass
305
- * `base` (the panel base path) so overrides don't have to thread it
306
- * through the panel config.
307
- */
308
- static getGlobalSearchResultUrl(record: unknown, base: string): string {
309
- const r = record as Record<string, unknown> | null | undefined
310
- const prefix = resourceBasePath(base, this)
311
- if (!r) return prefix
312
- const id = r['id']
313
- if (id === undefined || id === null) return prefix
314
- return `${prefix}/${String(id)}`
315
- }
316
-
317
- /**
318
- * Override the default LIKE-on-attributes search query. Return a
319
- * `ModelQuery` (still chainable through `paginate(1, limit)`) for
320
- * advanced cases — joins, full-text, `pg_trgm`. Returning `undefined`
321
- * (the default) falls through to the framework-built query.
322
- */
323
- static getGlobalSearchQuery(_needle: string): ModelQuery | undefined {
324
- return undefined
325
- }
326
-
327
- // ─── Realtime collab opt-in ────────────────────────────────
328
- // Opt-in per resource. The `@pilotiq-pro/collab` plugin registers the
329
- // global singletons (transport, Tiptap extension factory, RecordWrapper
330
- // factory); resources with `static collab` unset stay collab-free even
331
- // when the plugin is installed. Field-level `.collab(false)` overrides
332
- // this setting per field.
333
-
334
- /** Enable collab on this resource. `true` is the 90% case — shorthand
335
- * for `{ pages: ['edit'], presence: true }`. Use the object form to
336
- * narrow which page roles activate or to suppress presence. Default
337
- * `false` (collab off — the WS room is never opened for this resource). */
338
- static collab: ResourceCollabInput = false
339
-
340
- /**
341
- * Normalize `static collab` into the canonical wire shape, or return
342
- * `null` when the resource has opted out. Centralizes the `true` →
343
- * defaults expansion and the `{ pages?: … }` merge.
344
- *
345
- * Result lands on `panelInfo().recordCollab[slug]`; the gate reads it
346
- * to decide whether to mount the record wrapper.
347
- */
348
- static getResolvedCollabConfig(): ResourceCollabConfig | null {
349
- const raw = this.collab
350
- if (raw === false || raw == null) return null
351
- if (raw === true) return { pages: ['edit'], presence: true }
352
- return {
353
- pages: raw.pages ?? ['edit'],
354
- presence: raw.presence ?? true,
355
- }
356
- }
357
-
358
- // ─── Plan #10: authorization predicates ────────────────────
359
- // All async, all default `true`. Routes call them with the resolved
360
- // user (from `Pilotiq.user(fn)`); the renderer threads the same user
361
- // into nav-tree filtering and `Action.create/edit/view/delete`
362
- // factories. Override per-resource with role/policy logic. The user
363
- // argument is whatever `Pilotiq.user(req => …)` returns — opaque to
364
- // pilotiq, your shape.
365
-
366
- /** Coarse "should this resource exist for this user at all" gate.
367
- * Failing `canAccess` drops the resource from the nav tree entirely
368
- * and 403s every route under it. */
369
- static async canAccess(_user: unknown): Promise<boolean> { return true }
370
-
371
- /** Allowed to load the index/list page. Item still appears in nav
372
- * when `canAccess` passes but `canViewAny` fails — the URL just 403s. */
373
- static async canViewAny(_user: unknown): Promise<boolean> { return true }
374
-
375
- /** Allowed to load the read-only view page for a given record. */
376
- static async canView(_user: unknown, _record: unknown): Promise<boolean> { return true }
377
-
378
- /** Allowed to access the create page + invoke the create form.
379
- * Auto-hides `Action.create(R, …)` triggers that haven't set an
380
- * explicit `.visible()` rule. */
381
- static async canCreate(_user: unknown): Promise<boolean> { return true }
382
-
383
- /** Allowed to edit a given record. Auto-hides `Action.edit(R, …)`
384
- * triggers without an explicit `.visible()` rule. */
385
- static async canEdit(_user: unknown, _record: unknown): Promise<boolean> { return true }
386
-
387
- /** Allowed to delete a given record. Auto-hides `Action.delete(R, …)`
388
- * triggers without an explicit `.visible()` rule. */
389
- static async canDelete(_user: unknown, _record: unknown): Promise<boolean> { return true }
390
-
391
- /** Plan #13 — allowed to restore a soft-deleted record. Defaults
392
- * `true`; auto-hides `Action.restore(R, …)` when false. Only
393
- * checked on resources with `softDeletes = true`. */
394
- static async canRestore(_user: unknown, _record: unknown): Promise<boolean> { return true }
395
-
396
- /** Plan #13 — allowed to permanently delete a soft-deleted record.
397
- * Defaults to whatever `canDelete` returns when this method is *not*
398
- * overridden — soft-delete restore is generally lower-privilege
399
- * than force-delete, but force-delete inheriting from delete is the
400
- * conservative starting point. Override this to tighten or loosen
401
- * independently. Only checked on resources with `softDeletes = true`.
402
- *
403
- * The `safeForceDeletePolicy` helper (used by routes + `Action.forceDelete`
404
- * visibility) detects the un-overridden case via reference equality
405
- * against `Resource.canForceDelete` — same trick Plan #11 uses for
406
- * `safeManagerPolicy`. Don't reassign `Resource.canForceDelete`
407
- * outside of subclass overrides; it'd break the detection globally. */
408
- static async canForceDelete(this: ResourceClass, user: unknown, record: unknown): Promise<boolean> {
409
- return this.canDelete(user, record)
410
- }
411
-
412
- /**
413
- * Configure the form used by `create` and `edit` pages by default.
414
- * Receives a fresh `Form` instance; return the configured form.
415
- */
416
- static form(form: Form): Form { return form }
417
-
418
- /**
419
- * Configure the table used by the `index` page by default.
420
- * Receives a fresh `Table` instance; return the configured table.
421
- */
422
- static table(table: Table): Table { return table }
423
-
424
- /**
425
- * Schema for the read-only `view` page. Receives the loaded record.
426
- * Returns an array of Elements (typically Sections + display elements).
427
- */
428
- static detail(_record: unknown): Element[] { return [] }
429
-
430
- /**
431
- * Plan #15 — schema rendered above the list-page table. Default `[]`.
432
- * Typical use: dashboard widgets that contextualize the list (KPI cards,
433
- * charts, status alerts). Anything Element-typed is allowed —
434
- * `Group / Card / Section` for layout, `Stat / StatsOverview / Chart /
435
- * TableWidget / View` for server-data widgets, `Heading / Alert` for
436
- * static chrome. Resolves with the same `SchemaContext` passed to the
437
- * list page's schema (carries `mode: 'table'`, `basePath`, `user`).
438
- * Server-data widgets inside resolve in parallel via the shared
439
- * `_widgetData` map and re-fetch through `POST {base}/{slug}/_widget/:id`.
440
- * The hook only fires after `Resource.canAccess(user)` passes (route-level
441
- * gate) — there's no extra per-hook authorization.
442
- */
443
- static headerSchema(_ctx?: SchemaContext): Element[] | Promise<Element[]> { return [] }
444
-
445
- /**
446
- * Plan #15 — schema rendered below the list-page table. Default `[]`.
447
- * Same shape and posture as `headerSchema()`; useful for footnotes,
448
- * legends, or "longest-running…" tables that contextualize the list
449
- * from below.
450
- */
451
- static footerSchema(_ctx?: SchemaContext): Element[] | Promise<Element[]> { return [] }
452
-
453
- /**
454
- * Delete a record by id. Falls through to `model.delete(id)` when
455
- * `static model` is set; otherwise throws so the user knows to wire
456
- * something up. Override on the subclass for custom delete logic.
457
- * Wired up by the `POST {base}/{slug}/{id}/delete` route.
458
- */
459
- static async deleteRecord(id: string): Promise<void> {
460
- if (this.model) {
461
- await this.model.delete(id)
462
- return
463
- }
464
- throw new Error(
465
- `[Pilotiq] ${this.name}: no deleteRecord(id) implementation. Set Resource.model = … or override Resource.deleteRecord to wire up deletion.`,
466
- )
467
- }
468
-
469
- /**
470
- * User-overridable page map. Return any subset of `{ index, create, edit, view }`
471
- * to override the auto-generated defaults; missing keys fall through to
472
- * defaults via `resolvePages()`.
473
- */
474
- static pages(): ResourcePages { return {} }
475
-
476
- /**
477
- * Resolved page map: defaults from `defaultPages(this)` overlaid with whatever
478
- * `pages()` returns. This is what routing consumes (wired in 2.3).
479
- */
480
- static resolvePages(): ResourcePages {
481
- const defaults = defaultPages(this as unknown as ResourceClass)
482
- const overrides = this.pages()
483
- return { ...defaults, ...overrides }
484
- }
485
-
486
- /**
487
- * Sugar over `resolvePages().record ?? {}` for callers that only need
488
- * the record-scoped sub-pages (route registration, tab insertion, boot
489
- * validation). Returns an empty object when no record sub-pages are
490
- * declared so callers can iterate without a defensive null check.
491
- */
492
- static getRecordPages(): Record<string, typeof Page> {
493
- return this.resolvePages().record ?? {}
494
- }
495
-
496
- /**
497
- * Plan #11 — relation managers mounted under this resource's edit /
498
- * view pages. Each entry is a `RelationManager` subclass; routes are
499
- * registered under `${base}/${slug}/:id/${manager.relationship}`.
500
- * Default empty.
501
- */
502
- static relations(): Array<typeof RelationManager> { return [] }
503
-
504
- /** URL slug, derived from `label` when not set explicitly. */
505
- static getSlug(): string {
506
- return this.slug || this.label.toLowerCase().replace(/\s+/g, '-')
507
- }
508
-
509
- /** Sidebar label: `navigationLabel` override falls through to `label`. */
510
- static getNavigationLabel(): string {
511
- return this.navigationLabel ?? this.label
512
- }
513
-
514
- /** Breadcrumb label: `breadcrumb` override falls through to `label`. */
515
- static getBreadcrumb(): string {
516
- return this.breadcrumb ?? this.label
517
- }
518
-
519
- /** Sidebar icon: `navigationIcon` override falls through to `icon`. */
520
- static getNavigationIcon(): IconValue {
521
- return this.navigationIcon ?? this.icon
522
- }
523
- }
524
-
525
- /** Constructor type for `Resource` subclasses. Used in panel registration. */
526
- export type ResourceClass = typeof Resource