@pilotiq/pilotiq 0.24.1 → 0.24.3

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 (518) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/boost/guidelines.md +571 -0
  3. package/boost/skills/pilotiq-actions/SKILL.md +49 -0
  4. package/boost/skills/pilotiq-actions/rules/dispatch-modes.md +177 -0
  5. package/boost/skills/pilotiq-actions/rules/factories.md +130 -0
  6. package/boost/skills/pilotiq-actions/rules/visibility-and-authorization.md +125 -0
  7. package/boost/skills/pilotiq-fields/SKILL.md +47 -0
  8. package/boost/skills/pilotiq-fields/rules/field-catalog.md +288 -0
  9. package/boost/skills/pilotiq-fields/rules/reactive-fields.md +199 -0
  10. package/boost/skills/pilotiq-fields/rules/validation.md +198 -0
  11. package/boost/skills/pilotiq-relations/SKILL.md +47 -0
  12. package/boost/skills/pilotiq-relations/rules/relation-managers.md +256 -0
  13. package/boost/skills/pilotiq-relations/rules/repeater-relationship.md +177 -0
  14. package/boost/skills/pilotiq-resource/SKILL.md +61 -0
  15. package/boost/skills/pilotiq-resource/rules/authorization.md +242 -0
  16. package/boost/skills/pilotiq-resource/rules/defining-resources.md +228 -0
  17. package/boost/skills/pilotiq-resource/rules/page-overrides.md +296 -0
  18. package/dist/Pilotiq.d.ts +31 -0
  19. package/dist/Pilotiq.d.ts.map +1 -1
  20. package/dist/Pilotiq.js +3 -1
  21. package/dist/Pilotiq.js.map +1 -1
  22. package/dist/PilotiqRegistry.d.ts +13 -0
  23. package/dist/PilotiqRegistry.d.ts.map +1 -1
  24. package/dist/PilotiqRegistry.js +15 -0
  25. package/dist/PilotiqRegistry.js.map +1 -1
  26. package/dist/pageData/misc.d.ts.map +1 -1
  27. package/dist/pageData/misc.js +6 -0
  28. package/dist/pageData/misc.js.map +1 -1
  29. package/dist/pageData/navigation.d.ts +1 -0
  30. package/dist/pageData/navigation.d.ts.map +1 -1
  31. package/dist/pageData/navigation.js +3 -0
  32. package/dist/pageData/navigation.js.map +1 -1
  33. package/dist/pageData/relationPages.d.ts.map +1 -1
  34. package/dist/pageData/relationPages.js +3 -0
  35. package/dist/pageData/relationPages.js.map +1 -1
  36. package/dist/pageData/resourcePages.d.ts.map +1 -1
  37. package/dist/pageData/resourcePages.js +8 -0
  38. package/dist/pageData/resourcePages.js.map +1 -1
  39. package/dist/react/AppShell.d.ts +8 -0
  40. package/dist/react/AppShell.d.ts.map +1 -1
  41. package/dist/react/AppShell.js.map +1 -1
  42. package/dist/react/layouts/SidebarLayout.d.ts.map +1 -1
  43. package/dist/react/layouts/SidebarLayout.js +10 -2
  44. package/dist/react/layouts/SidebarLayout.js.map +1 -1
  45. package/dist/react/widgets/StatsOverviewRenderer.d.ts.map +1 -1
  46. package/dist/react/widgets/StatsOverviewRenderer.js +32 -18
  47. package/dist/react/widgets/StatsOverviewRenderer.js.map +1 -1
  48. package/dist/routes/relations.d.ts.map +1 -1
  49. package/dist/routes/relations.js +25 -18
  50. package/dist/routes/relations.js.map +1 -1
  51. package/dist/routes/resources.js.map +1 -1
  52. package/package.json +10 -5
  53. package/.turbo/turbo-build.log +0 -8
  54. package/CLAUDE.md +0 -265
  55. package/src/Cluster.test.ts +0 -283
  56. package/src/Cluster.ts +0 -83
  57. package/src/Column.test.ts +0 -199
  58. package/src/Column.ts +0 -710
  59. package/src/Global.test.ts +0 -367
  60. package/src/Global.ts +0 -169
  61. package/src/Page.test.ts +0 -114
  62. package/src/Page.ts +0 -208
  63. package/src/Pilotiq.perf.test.ts +0 -252
  64. package/src/Pilotiq.test.ts +0 -129
  65. package/src/Pilotiq.ts +0 -1158
  66. package/src/PilotiqRegistry.ts +0 -36
  67. package/src/PilotiqServiceProvider.ts +0 -121
  68. package/src/RelationManager.test.ts +0 -400
  69. package/src/RelationManager.ts +0 -527
  70. package/src/RenderHook.test.ts +0 -252
  71. package/src/RenderHook.ts +0 -242
  72. package/src/Resource.test.ts +0 -284
  73. package/src/Resource.ts +0 -526
  74. package/src/RightPanel.test.ts +0 -202
  75. package/src/RightPanel.ts +0 -132
  76. package/src/Tab.test.ts +0 -91
  77. package/src/Tab.ts +0 -156
  78. package/src/UserMenuItem.ts +0 -145
  79. package/src/actions/Action.test.ts +0 -2526
  80. package/src/actions/Action.ts +0 -1515
  81. package/src/actions/ActionGroup.test.ts +0 -112
  82. package/src/actions/ActionGroup.ts +0 -173
  83. package/src/actions/attachFactory.ts +0 -172
  84. package/src/actions/bulkFactories.ts +0 -168
  85. package/src/actions/crudFactories.ts +0 -220
  86. package/src/actions/exportFactory.ts +0 -225
  87. package/src/actions/factoryHelpers.ts +0 -177
  88. package/src/actions/importFactory.ts +0 -243
  89. package/src/actions/index.ts +0 -17
  90. package/src/actions/m2mFactories.ts +0 -193
  91. package/src/actions/relationFactories.ts +0 -372
  92. package/src/applyPageHooks.test.ts +0 -463
  93. package/src/applyPageHooks.ts +0 -330
  94. package/src/authorization.test.ts +0 -483
  95. package/src/breadcrumbs.test.ts +0 -238
  96. package/src/cells/coerce.test.ts +0 -85
  97. package/src/cells/coerce.ts +0 -84
  98. package/src/clusterPaths.ts +0 -35
  99. package/src/columns/BadgeColumn.test.ts +0 -54
  100. package/src/columns/BadgeColumn.ts +0 -32
  101. package/src/columns/BooleanColumn.test.ts +0 -41
  102. package/src/columns/BooleanColumn.ts +0 -18
  103. package/src/columns/ColorColumn.test.ts +0 -37
  104. package/src/columns/ColorColumn.ts +0 -38
  105. package/src/columns/IconColumn.test.ts +0 -54
  106. package/src/columns/IconColumn.ts +0 -37
  107. package/src/columns/ImageColumn.test.ts +0 -41
  108. package/src/columns/ImageColumn.ts +0 -28
  109. package/src/columns/SelectColumn.ts +0 -98
  110. package/src/columns/TextColumn.test.ts +0 -190
  111. package/src/columns/TextColumn.ts +0 -20
  112. package/src/columns/TextInputColumn.ts +0 -68
  113. package/src/columns/ToggleColumn.ts +0 -46
  114. package/src/columns/editableColumns.test.ts +0 -238
  115. package/src/columns/index.ts +0 -9
  116. package/src/defaultGlobalPages.ts +0 -95
  117. package/src/defaultPages.test.ts +0 -634
  118. package/src/defaultPages.ts +0 -617
  119. package/src/defaultViewPage.test.ts +0 -147
  120. package/src/elements/Form.test.ts +0 -223
  121. package/src/elements/Form.ts +0 -416
  122. package/src/elements/ListTabs.ts +0 -28
  123. package/src/elements/Table.test.ts +0 -422
  124. package/src/elements/Table.ts +0 -850
  125. package/src/elements/TableGroup.test.ts +0 -260
  126. package/src/elements/TableGroup.ts +0 -334
  127. package/src/elements/dispatchAction.test.ts +0 -463
  128. package/src/elements/dispatchAction.ts +0 -355
  129. package/src/elements/dispatchForm.test.ts +0 -477
  130. package/src/elements/dispatchForm.ts +0 -1993
  131. package/src/elements/dispatchTable.test.ts +0 -1514
  132. package/src/elements/dispatchTable.ts +0 -745
  133. package/src/elements/index.ts +0 -21
  134. package/src/entries/BadgeEntry.ts +0 -39
  135. package/src/entries/CodeEntry.test.ts +0 -40
  136. package/src/entries/CodeEntry.ts +0 -52
  137. package/src/entries/ColorEntry.ts +0 -63
  138. package/src/entries/ComponentEntry.test.ts +0 -173
  139. package/src/entries/ComponentEntry.ts +0 -95
  140. package/src/entries/Entry.ts +0 -304
  141. package/src/entries/IconEntry.ts +0 -49
  142. package/src/entries/ImageEntry.ts +0 -61
  143. package/src/entries/KeyValueEntry.ts +0 -47
  144. package/src/entries/RepeatableEntry.test.ts +0 -239
  145. package/src/entries/RepeatableEntry.ts +0 -173
  146. package/src/entries/TextEntry.test.ts +0 -394
  147. package/src/entries/TextEntry.ts +0 -60
  148. package/src/entries/index.ts +0 -12
  149. package/src/entries/leaves.test.ts +0 -306
  150. package/src/entries/registry.ts +0 -54
  151. package/src/fields/BuilderField.test.ts +0 -1188
  152. package/src/fields/BuilderField.ts +0 -605
  153. package/src/fields/BuilderRelationship.test.ts +0 -811
  154. package/src/fields/CheckboxField.test.ts +0 -44
  155. package/src/fields/CheckboxField.ts +0 -27
  156. package/src/fields/CheckboxListField.test.ts +0 -99
  157. package/src/fields/CheckboxListField.ts +0 -66
  158. package/src/fields/ColorPickerField.test.ts +0 -33
  159. package/src/fields/ColorPickerField.ts +0 -25
  160. package/src/fields/DateField.ts +0 -54
  161. package/src/fields/DateTimeField.test.ts +0 -55
  162. package/src/fields/EmailField.ts +0 -16
  163. package/src/fields/Field.test.ts +0 -654
  164. package/src/fields/Field.ts +0 -817
  165. package/src/fields/FileUploadField.test.ts +0 -143
  166. package/src/fields/FileUploadField.ts +0 -159
  167. package/src/fields/HiddenField.test.ts +0 -27
  168. package/src/fields/HiddenField.ts +0 -28
  169. package/src/fields/KeyValueField.test.ts +0 -105
  170. package/src/fields/KeyValueField.ts +0 -55
  171. package/src/fields/MarkdownField.test.ts +0 -167
  172. package/src/fields/MarkdownField.ts +0 -162
  173. package/src/fields/NumberField.ts +0 -33
  174. package/src/fields/RadioField.test.ts +0 -94
  175. package/src/fields/RadioField.ts +0 -67
  176. package/src/fields/RepeaterField.test.ts +0 -1806
  177. package/src/fields/RepeaterField.ts +0 -939
  178. package/src/fields/RepeaterRelationship.test.ts +0 -1923
  179. package/src/fields/RepeaterSimple.test.ts +0 -248
  180. package/src/fields/RowButton.test.ts +0 -219
  181. package/src/fields/RowButton.ts +0 -135
  182. package/src/fields/SelectField.test.ts +0 -192
  183. package/src/fields/SelectField.ts +0 -235
  184. package/src/fields/SliderField.test.ts +0 -50
  185. package/src/fields/SliderField.ts +0 -53
  186. package/src/fields/SlugField.ts +0 -24
  187. package/src/fields/TagsInputField.test.ts +0 -154
  188. package/src/fields/TagsInputField.ts +0 -133
  189. package/src/fields/TextField.test.ts +0 -213
  190. package/src/fields/TextField.ts +0 -177
  191. package/src/fields/TextareaField.test.ts +0 -58
  192. package/src/fields/TextareaField.ts +0 -59
  193. package/src/fields/ToggleButtonsField.test.ts +0 -106
  194. package/src/fields/ToggleButtonsField.ts +0 -59
  195. package/src/fields/ToggleField.ts +0 -16
  196. package/src/fields/disableOptionsWhenSelectedInSiblingRepeaterItems.test.ts +0 -319
  197. package/src/fields/optionsResolver.ts +0 -95
  198. package/src/fields/resolveField.ts +0 -28
  199. package/src/filters/BooleanFilter.ts +0 -35
  200. package/src/filters/DateRangeFilter.test.ts +0 -194
  201. package/src/filters/DateRangeFilter.ts +0 -148
  202. package/src/filters/Filter.test.ts +0 -268
  203. package/src/filters/Filter.ts +0 -184
  204. package/src/filters/FormFilter.test.ts +0 -238
  205. package/src/filters/FormFilter.ts +0 -215
  206. package/src/filters/MultiSelectFilter.test.ts +0 -119
  207. package/src/filters/MultiSelectFilter.ts +0 -78
  208. package/src/filters/QueryBuilderFilter.test.ts +0 -662
  209. package/src/filters/QueryBuilderFilter.ts +0 -398
  210. package/src/filters/SelectFilter.ts +0 -46
  211. package/src/filters/TernaryFilter.test.ts +0 -160
  212. package/src/filters/TernaryFilter.ts +0 -72
  213. package/src/filters/TrashedFilter.test.ts +0 -149
  214. package/src/filters/TrashedFilter.ts +0 -55
  215. package/src/filters/queryBuilder/BooleanConstraint.ts +0 -31
  216. package/src/filters/queryBuilder/Constraint.ts +0 -115
  217. package/src/filters/queryBuilder/DateConstraint.ts +0 -69
  218. package/src/filters/queryBuilder/NumberConstraint.ts +0 -66
  219. package/src/filters/queryBuilder/SelectConstraint.ts +0 -72
  220. package/src/filters/queryBuilder/TextConstraint.ts +0 -64
  221. package/src/filters/queryBuilder/index.ts +0 -12
  222. package/src/icons/index.ts +0 -2
  223. package/src/icons/lucide.ts +0 -204
  224. package/src/icons/registry.test.ts +0 -56
  225. package/src/icons/registry.ts +0 -41
  226. package/src/icons/types.ts +0 -47
  227. package/src/index.ts +0 -525
  228. package/src/io/csv.test.ts +0 -142
  229. package/src/io/csv.ts +0 -170
  230. package/src/nestedRelationManagerData.test.ts +0 -547
  231. package/src/notifications/Notification.test.ts +0 -210
  232. package/src/notifications/Notification.ts +0 -354
  233. package/src/notifications/broadcast.test.ts +0 -110
  234. package/src/notifications/broadcast.ts +0 -95
  235. package/src/notifications/database.test.ts +0 -383
  236. package/src/notifications/database.ts +0 -398
  237. package/src/notifications/databaseNotifications.test.ts +0 -187
  238. package/src/notifications/dispatchNotificationAction.test.ts +0 -341
  239. package/src/notifications/dispatchNotificationAction.ts +0 -142
  240. package/src/notifications/flash.test.ts +0 -89
  241. package/src/notifications/flash.ts +0 -71
  242. package/src/notifications/index.ts +0 -45
  243. package/src/notifications/registerBroadcastAuth.test.ts +0 -134
  244. package/src/notifications/registerBroadcastAuth.ts +0 -100
  245. package/src/notifications/resolveSavedNotification.test.ts +0 -82
  246. package/src/notifications/resolveSavedNotification.ts +0 -59
  247. package/src/notifications/types.ts +0 -93
  248. package/src/orm/m2mAccessor.ts +0 -66
  249. package/src/orm/modelDefaults.test.ts +0 -633
  250. package/src/orm/modelDefaults.ts +0 -666
  251. package/src/pageData/breadcrumbs.ts +0 -288
  252. package/src/pageData/forms.ts +0 -578
  253. package/src/pageData/helpers.ts +0 -857
  254. package/src/pageData/misc.ts +0 -347
  255. package/src/pageData/navigation.ts +0 -842
  256. package/src/pageData/relationPages.ts +0 -1248
  257. package/src/pageData/relationTabs.ts +0 -286
  258. package/src/pageData/resourcePages.ts +0 -609
  259. package/src/pageData.test.ts +0 -1545
  260. package/src/pageData.ts +0 -341
  261. package/src/plugins/index.ts +0 -8
  262. package/src/plugins/themeEditor.test.ts +0 -36
  263. package/src/plugins/themeEditor.ts +0 -45
  264. package/src/react/AppShell.tsx +0 -251
  265. package/src/react/CollabExtensionFactoryRegistry.ts +0 -55
  266. package/src/react/CollabRoomContext.ts +0 -98
  267. package/src/react/CollabTextRendererRegistry.ts +0 -102
  268. package/src/react/CommandPalette.tsx +0 -375
  269. package/src/react/CurrentUserContext.tsx +0 -50
  270. package/src/react/CustomPageWrapperGate.tsx +0 -69
  271. package/src/react/CustomPageWrapperRegistry.ts +0 -45
  272. package/src/react/FieldFocusReporterRegistry.ts +0 -37
  273. package/src/react/FieldLabelSlotRegistry.ts +0 -30
  274. package/src/react/FieldPresenceRegistry.ts +0 -46
  275. package/src/react/FormCollabBindingRegistry.ts +0 -242
  276. package/src/react/FormStateContext.tsx +0 -591
  277. package/src/react/HeadHooks.tsx +0 -126
  278. package/src/react/MarkdownEditorRegistry.test.ts +0 -38
  279. package/src/react/MarkdownEditorRegistry.ts +0 -107
  280. package/src/react/NotificationActionStrip.tsx +0 -263
  281. package/src/react/NotificationBell.tsx +0 -426
  282. package/src/react/PendingSuggestionApplierRegistry.test.ts +0 -97
  283. package/src/react/PendingSuggestionApplierRegistry.ts +0 -98
  284. package/src/react/PendingSuggestionOverlayRegistry.ts +0 -54
  285. package/src/react/PendingSuggestionsContext.tsx +0 -172
  286. package/src/react/RecordWrapperGate.tsx +0 -58
  287. package/src/react/RecordWrapperRegistry.ts +0 -39
  288. package/src/react/RenderHookSlot.tsx +0 -32
  289. package/src/react/RightSidebar.tsx +0 -257
  290. package/src/react/RightSidebarContext.tsx +0 -234
  291. package/src/react/RightSidebarTrigger.tsx +0 -53
  292. package/src/react/RowCoordsContext.tsx +0 -23
  293. package/src/react/SchemaRenderer.tsx +0 -549
  294. package/src/react/SearchTrigger.tsx +0 -46
  295. package/src/react/ThemeProvider.tsx +0 -93
  296. package/src/react/ThemeSettingsPage.tsx +0 -579
  297. package/src/react/ThemeToggle.tsx +0 -20
  298. package/src/react/Toaster.tsx +0 -158
  299. package/src/react/UserMenu.tsx +0 -196
  300. package/src/react/WidgetDataContext.tsx +0 -157
  301. package/src/react/cells/EditableCell.tsx +0 -389
  302. package/src/react/component-slots.test.ts +0 -103
  303. package/src/react/component-slots.ts +0 -116
  304. package/src/react/fieldJsHandler.test.ts +0 -166
  305. package/src/react/fieldJsHandler.ts +0 -79
  306. package/src/react/fields/BuilderInput.tsx +0 -1078
  307. package/src/react/fields/CheckboxInput.tsx +0 -39
  308. package/src/react/fields/CheckboxListInput.tsx +0 -102
  309. package/src/react/fields/ColorInput.tsx +0 -71
  310. package/src/react/fields/DateFieldInput.tsx +0 -70
  311. package/src/react/fields/DateTimeInput.tsx +0 -62
  312. package/src/react/fields/FieldShell.tsx +0 -348
  313. package/src/react/fields/FileUploadInput.tsx +0 -639
  314. package/src/react/fields/HiddenInput.tsx +0 -17
  315. package/src/react/fields/KeyValueInput.tsx +0 -230
  316. package/src/react/fields/MarkdownInput.tsx +0 -560
  317. package/src/react/fields/RadioInput.tsx +0 -81
  318. package/src/react/fields/RepeaterInput.test.ts +0 -116
  319. package/src/react/fields/RepeaterInput.tsx +0 -1420
  320. package/src/react/fields/SelectFieldInput.tsx +0 -280
  321. package/src/react/fields/SliderInput.tsx +0 -81
  322. package/src/react/fields/TagsInput.tsx +0 -283
  323. package/src/react/fields/TextLikeInput.tsx +0 -256
  324. package/src/react/fields/ToggleButtonsInput.tsx +0 -60
  325. package/src/react/fields/ToggleFieldInput.tsx +0 -56
  326. package/src/react/fields/relationshipRenameDispatch.test.ts +0 -106
  327. package/src/react/fields/relationshipRenameDispatch.ts +0 -97
  328. package/src/react/fields/repeaterReconcile.test.ts +0 -114
  329. package/src/react/fields/repeaterReconcile.ts +0 -104
  330. package/src/react/fields/rowChromeButton.tsx +0 -336
  331. package/src/react/fields/rowState.ts +0 -106
  332. package/src/react/fields/syncRowGates.test.ts +0 -202
  333. package/src/react/fields/syncRowGates.ts +0 -66
  334. package/src/react/fields/textInputControls.tsx +0 -238
  335. package/src/react/fields/useRowReorderDnd.ts +0 -78
  336. package/src/react/formStateHelpers.test.ts +0 -508
  337. package/src/react/formStateHelpers.ts +0 -381
  338. package/src/react/hooks/use-mobile.ts +0 -19
  339. package/src/react/icon-context.tsx +0 -60
  340. package/src/react/index.ts +0 -194
  341. package/src/react/layouts/SidebarLayout.tsx +0 -250
  342. package/src/react/layouts/TopbarLayout.tsx +0 -258
  343. package/src/react/navigate.tsx +0 -37
  344. package/src/react/onProviderSynced.test.ts +0 -90
  345. package/src/react/parseRecordEditUrl.test.ts +0 -122
  346. package/src/react/parseRecordEditUrl.ts +0 -94
  347. package/src/react/persistedState.ts +0 -40
  348. package/src/react/registry.ts +0 -48
  349. package/src/react/right-panel-registry.tsx +0 -47
  350. package/src/react/schemaRenderer/AlertRenderer.tsx +0 -112
  351. package/src/react/schemaRenderer/EntryRenderer.tsx +0 -501
  352. package/src/react/schemaRenderer/SectionRenderer.tsx +0 -120
  353. package/src/react/schemaRenderer/SimpleElements.tsx +0 -306
  354. package/src/react/schemaRenderer/TabsRenderer.tsx +0 -62
  355. package/src/react/schemaRenderer/WizardRenderer.tsx +0 -338
  356. package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +0 -177
  357. package/src/react/schemaRenderer/action/ActionModalDialog.tsx +0 -273
  358. package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +0 -61
  359. package/src/react/schemaRenderer/action/HandlerActionButton.tsx +0 -43
  360. package/src/react/schemaRenderer/action/MethodActionButton.tsx +0 -64
  361. package/src/react/schemaRenderer/action/buttons.tsx +0 -99
  362. package/src/react/schemaRenderer/action/helpers.ts +0 -140
  363. package/src/react/schemaRenderer/action/renderAction.tsx +0 -245
  364. package/src/react/schemaRenderer/columnFormat.ts +0 -65
  365. package/src/react/schemaRenderer/constants.ts +0 -50
  366. package/src/react/schemaRenderer/form/FormRenderer.tsx +0 -274
  367. package/src/react/schemaRenderer/form/renderField.tsx +0 -511
  368. package/src/react/schemaRenderer/helpers.tsx +0 -81
  369. package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +0 -308
  370. package/src/react/schemaRenderer/table/TableRenderer.tsx +0 -123
  371. package/src/react/schemaRenderer/table/TableRendererBody.tsx +0 -974
  372. package/src/react/schemaRenderer/table/filters.tsx +0 -1233
  373. package/src/react/schemaRenderer/table/formatCell.tsx +0 -264
  374. package/src/react/schemaRenderer/table/links.tsx +0 -112
  375. package/src/react/schemaRenderer/table/renderRowActions.tsx +0 -52
  376. package/src/react/schemaRenderer/table/url.tsx +0 -143
  377. package/src/react/theme-preview/apply.ts +0 -99
  378. package/src/react/theme-preview/build-html.ts +0 -436
  379. package/src/react/ui/button.tsx +0 -51
  380. package/src/react/ui/calendar.tsx +0 -67
  381. package/src/react/ui/checkbox.tsx +0 -29
  382. package/src/react/ui/dialog.tsx +0 -108
  383. package/src/react/ui/dropdown-menu.tsx +0 -97
  384. package/src/react/ui/input.tsx +0 -20
  385. package/src/react/ui/label.tsx +0 -21
  386. package/src/react/ui/popover.tsx +0 -50
  387. package/src/react/ui/select.tsx +0 -169
  388. package/src/react/ui/separator.tsx +0 -25
  389. package/src/react/ui/sheet.tsx +0 -136
  390. package/src/react/ui/sidebar.tsx +0 -723
  391. package/src/react/ui/skeleton.tsx +0 -13
  392. package/src/react/ui/slider.tsx +0 -34
  393. package/src/react/ui/switch.tsx +0 -28
  394. package/src/react/ui/table.tsx +0 -105
  395. package/src/react/ui/tabs.tsx +0 -63
  396. package/src/react/ui/textarea.tsx +0 -18
  397. package/src/react/ui/tooltip.tsx +0 -64
  398. package/src/react/useResizableWidth.ts +0 -139
  399. package/src/react/utils.ts +0 -6
  400. package/src/react/widgetRegistry.test.ts +0 -43
  401. package/src/react/widgetRegistry.ts +0 -50
  402. package/src/react/widgets/StatsOverviewRenderer.tsx +0 -232
  403. package/src/react/widgets/TableWidgetRenderer.tsx +0 -231
  404. package/src/react/widgets/ViewRenderer.tsx +0 -71
  405. package/src/relationManagerData.test.ts +0 -1595
  406. package/src/richtext/index.ts +0 -8
  407. package/src/richtext/registry.ts +0 -89
  408. package/src/routes/globals.ts +0 -148
  409. package/src/routes/guard.test.ts +0 -325
  410. package/src/routes/helpers.ts +0 -704
  411. package/src/routes/pages.ts +0 -175
  412. package/src/routes/panel.ts +0 -204
  413. package/src/routes/relations.ts +0 -1243
  414. package/src/routes/resources.ts +0 -781
  415. package/src/routes/theme.ts +0 -91
  416. package/src/routes-nested-relations.test.ts +0 -676
  417. package/src/routes-relations.test.ts +0 -972
  418. package/src/routes.test.ts +0 -2027
  419. package/src/routes.ts +0 -303
  420. package/src/schema/Alert.test.ts +0 -109
  421. package/src/schema/Alert.ts +0 -131
  422. package/src/schema/Block.ts +0 -169
  423. package/src/schema/Breadcrumbs.ts +0 -40
  424. package/src/schema/Card.ts +0 -35
  425. package/src/schema/Divider.ts +0 -20
  426. package/src/schema/Element.ts +0 -219
  427. package/src/schema/EmptyState.test.ts +0 -37
  428. package/src/schema/EmptyState.ts +0 -63
  429. package/src/schema/Fieldset.ts +0 -43
  430. package/src/schema/Grid.ts +0 -43
  431. package/src/schema/Group.ts +0 -30
  432. package/src/schema/Heading.ts +0 -39
  433. package/src/schema/Html.ts +0 -67
  434. package/src/schema/Icon.ts +0 -54
  435. package/src/schema/Image.ts +0 -57
  436. package/src/schema/LinkTag.ts +0 -41
  437. package/src/schema/Markdown.ts +0 -85
  438. package/src/schema/MetaTag.ts +0 -41
  439. package/src/schema/RelationTabs.ts +0 -71
  440. package/src/schema/ScriptTag.ts +0 -55
  441. package/src/schema/Section.ts +0 -160
  442. package/src/schema/ServerDataElement.test.ts +0 -140
  443. package/src/schema/ServerDataElement.ts +0 -156
  444. package/src/schema/SlotComponent.test.ts +0 -77
  445. package/src/schema/SlotComponent.ts +0 -71
  446. package/src/schema/Split.ts +0 -50
  447. package/src/schema/Stat.test.ts +0 -118
  448. package/src/schema/Stat.ts +0 -154
  449. package/src/schema/StatsOverview.test.ts +0 -141
  450. package/src/schema/StatsOverview.ts +0 -119
  451. package/src/schema/StyleTag.ts +0 -35
  452. package/src/schema/TableWidget.test.ts +0 -297
  453. package/src/schema/TableWidget.ts +0 -289
  454. package/src/schema/Tabs.ts +0 -79
  455. package/src/schema/Text.ts +0 -58
  456. package/src/schema/UnorderedList.ts +0 -49
  457. package/src/schema/View.test.ts +0 -111
  458. package/src/schema/View.ts +0 -127
  459. package/src/schema/Wizard.ts +0 -220
  460. package/src/schema/containers.test.ts +0 -564
  461. package/src/schema/headTags.test.ts +0 -134
  462. package/src/schema/index.ts +0 -40
  463. package/src/schema/primes.test.ts +0 -269
  464. package/src/schema/resolveSchema.test.ts +0 -379
  465. package/src/schema/resolveSchema.ts +0 -917
  466. package/src/schema/sanitize.ts +0 -58
  467. package/src/search.test.ts +0 -446
  468. package/src/search.ts +0 -178
  469. package/src/sessionFilters.test.ts +0 -375
  470. package/src/sessionFilters.ts +0 -143
  471. package/src/slot-components/index.ts +0 -10
  472. package/src/slot-components/registry.ts +0 -56
  473. package/src/styles/file-upload.css +0 -13
  474. package/src/summarizers/Summarizer.test.ts +0 -84
  475. package/src/summarizers/Summarizer.ts +0 -123
  476. package/src/summarizers/index.ts +0 -11
  477. package/src/theme/base-colors.ts +0 -68
  478. package/src/theme/chart-colors.ts +0 -50
  479. package/src/theme/colors.ts +0 -447
  480. package/src/theme/generate-css.test.ts +0 -139
  481. package/src/theme/generate-css.ts +0 -44
  482. package/src/theme/generate-scale.test.ts +0 -106
  483. package/src/theme/generate-scale.ts +0 -97
  484. package/src/theme/icon-map.ts +0 -42
  485. package/src/theme/index.ts +0 -34
  486. package/src/theme/migrate.test.ts +0 -178
  487. package/src/theme/migrate.ts +0 -81
  488. package/src/theme/presets.ts +0 -135
  489. package/src/theme/radius.ts +0 -18
  490. package/src/theme/resolve.test.ts +0 -238
  491. package/src/theme/resolve.ts +0 -96
  492. package/src/theme/spacing.ts +0 -18
  493. package/src/theme/storage.test.ts +0 -126
  494. package/src/theme/storage.ts +0 -106
  495. package/src/theme/theme-colors.ts +0 -88
  496. package/src/theme/types.ts +0 -125
  497. package/src/uploads/UploadAdapter.ts +0 -35
  498. package/src/uploads/index.ts +0 -2
  499. package/src/uploads/localUpload.test.ts +0 -70
  500. package/src/uploads/localUpload.ts +0 -84
  501. package/src/validation/Validator.ts +0 -49
  502. package/src/validation/index.ts +0 -28
  503. package/src/validation/rules.ts +0 -78
  504. package/src/validation/runValidators.ts +0 -435
  505. package/src/validation/uniqueValidator.test.ts +0 -196
  506. package/src/validation/uniqueValidator.ts +0 -133
  507. package/src/validation/validators.test.ts +0 -268
  508. package/src/vite.test.ts +0 -184
  509. package/src/vite.ts +0 -787
  510. package/src/widgets/index.ts +0 -10
  511. package/src/widgets/registry.ts +0 -45
  512. package/src/widgets.test.ts +0 -592
  513. package/tsconfig.build.json +0 -11
  514. package/tsconfig.json +0 -4
  515. package/tsconfig.test.json +0 -10
  516. package/views/react/Dashboard.tsx +0 -27
  517. package/views/react/Resources/Form.tsx +0 -102
  518. package/views/react/Resources/Index.tsx +0 -49
@@ -1,609 +0,0 @@
1
- import type { Pilotiq } from '../Pilotiq.js'
2
- import { PilotiqRegistry } from '../PilotiqRegistry.js'
3
- import type { Page } from '../Page.js'
4
- import type { ResourceClass } from '../Resource.js'
5
- import { resourceBasePath } from '../clusterPaths.js'
6
- import { Element } from '../schema/Element.js'
7
- import { resolveSchema, type SchemaContext } from '../schema/resolveSchema.js'
8
- import { Form } from '../elements/Form.js'
9
- import { Table } from '../elements/Table.js'
10
- import { Column } from '../Column.js'
11
- import { ListTabs } from '../elements/ListTabs.js'
12
- import { ListTab } from '../Tab.js'
13
- import { TrashedFilter } from '../filters/TrashedFilter.js'
14
- import { loadTableRecords } from '../elements/dispatchTable.js'
15
- import { consumeFlashedNotifications } from '../notifications/flash.js'
16
- import { serializeIcon } from '../icons/types.js'
17
- import {
18
- findRecord, getPrimaryKey, modelLoadRecord, modelSave,
19
- type ModelLike,
20
- } from '../orm/modelDefaults.js'
21
- import {
22
- resourceCreateBreadcrumbs,
23
- resourceEditBreadcrumbs,
24
- resourceListBreadcrumbs,
25
- resourceViewBreadcrumbs,
26
- } from './breadcrumbs.js'
27
- import {
28
- applyEditPageHydrators,
29
- applyFillPipeline,
30
- applyRelationshipBuilderFill,
31
- applyRelationshipRepeaterFill,
32
- callPageSchema,
33
- resolveServerDataElements,
34
- tagActionDispatch,
35
- tagCellEditUrls,
36
- tagFieldAiUrls,
37
- tagFormActions,
38
- tagFormSubresourceUrls,
39
- tagTableDeferred,
40
- tagTableReorderUrls,
41
- tagWidgetUrls,
42
- uploadCtx,
43
- userCtx,
44
- } from './helpers.js'
45
- import { applyRoleHooks, panelInfo, type PanelInfoRoute } from './navigation.js'
46
- import { findForms } from '../elements/dispatchForm.js'
47
- import { buildRelationTabs, deriveParentTitle, safeBool } from './relationTabs.js'
48
-
49
- // ─── Resource page builders ─────────────────────────────────
50
- //
51
- // Resource-scoped GET-route data builders: dashboard, list, table
52
- // (deferred-load shell), create, edit, view, and the optional record
53
- // sub-page roles. Each loads its own context (record / parent / etc.),
54
- // resolves the page schema through `resolveSchema`, stamps URL-tag
55
- // helpers for dispatch endpoints, and returns the wire-shape envelope
56
- // the page renderer consumes.
57
-
58
-
59
- /**
60
- * Per-row stamping spine shared by SSR `resourceIndexData` and the
61
- * deferred-load JSON endpoint `resourceTableData`. Both walk the same
62
- * Table tree and need the same dispatch / active-tab / reorder / cell-edit
63
- * URL stamps in the same order — running them through one helper keeps
64
- * the two paths in lock-step so any future addition (per-row chrome
65
- * stamp, etc.) lands on both surfaces.
66
- *
67
- * Widget URL stamping + the `tagTableDeferred` flag stay outside the
68
- * helper since only `resourceIndexData` mounts widgets / the deferred
69
- * skeleton — the JSON endpoint re-runs without the flag and never
70
- * collects widget metas.
71
- */
72
- async function prepareResourceTable(
73
- elements: Element[],
74
- R: ResourceClass,
75
- indexUrl: string,
76
- query: Record<string, string>,
77
- user: unknown,
78
- ): Promise<void> {
79
- tagActionDispatch(elements, indexUrl)
80
- // Mark the active tab + parallel-eval badges + stamp per-tab URLs
81
- // before the table records run — `loadTableRecords` walks the schema
82
- // for the active tab and splices its `modifyQuery` predicate into the
83
- // ORM chain alongside filters.
84
- await resolveActiveTab(elements, query, indexUrl)
85
- await loadTableRecords(elements, query, indexUrl, user, {
86
- canEdit: (u, record) => R.canEdit(u, record),
87
- })
88
- tagTableReorderUrls(elements, `${indexUrl}/_reorder`)
89
- tagCellEditUrls(elements, indexUrl)
90
- }
91
-
92
- export async function dashboardData(pilotiq: Pilotiq, req?: unknown): Promise<Record<string, unknown>> {
93
- const cfg = pilotiq.getConfig()
94
- const user = await pilotiq.resolveUser(req)
95
- const ctx: SchemaContext = uploadCtx(userCtx({ basePath: cfg.path }, user), cfg)
96
-
97
- // Plan #15 — when `panel.dashboard(P)` was called, resolve P's
98
- // schema instead of the builder-level `cfg.schema`. Page-scoped
99
- // schema means widget elements read like a regular custom page —
100
- // including action dispatch, form-state, and `_widget/:id` polling.
101
- let elements: Element[]
102
- if (cfg.dashboardPage) {
103
- elements = await callPageSchema(cfg.dashboardPage, ctx)
104
- tagFormActions(elements, cfg.path)
105
- tagFormSubresourceUrls(elements, cfg.path)
106
- tagActionDispatch(elements, cfg.path)
107
- } else {
108
- elements = []
109
- if (cfg.schema) {
110
- const def = cfg.schema
111
- elements = typeof def === 'function' ? await def(ctx) : def
112
- }
113
- }
114
-
115
- // Stamp polling URLs on every widget — panel-scope (no pageSlug
116
- // segment) for the dashboard. Done before schema resolve so the URL
117
- // rides on each widget's stamped meta.
118
- tagWidgetUrls(elements, id => `${cfg.path}/_widget/${id}`)
119
-
120
- const widgetData = await resolveServerDataElements(elements, ctx)
121
- const dashRoute: PanelInfoRoute = cfg.dashboardPage ? { page: cfg.dashboardPage } : {}
122
- const [panel, schemaData] = await Promise.all([
123
- panelInfo(pilotiq, req, dashRoute),
124
- resolveSchema(elements, ctx).then(metas => applyRoleHooks(pilotiq, user, 'dashboard', metas, dashRoute)),
125
- ])
126
-
127
- return {
128
- panel,
129
- page: cfg.dashboardPage ? cfg.dashboardPage.toMeta() : undefined,
130
- basePath: cfg.path,
131
- layout: cfg.layout,
132
- schemaData,
133
- _widgetData: widgetData,
134
- notifications: consumeFlashedNotifications(req),
135
- }
136
- }
137
-
138
- export async function resourceIndexData(
139
- pilotiq: Pilotiq,
140
- slug: string,
141
- query: Record<string, string> = {},
142
- req?: unknown,
143
- ): Promise<Record<string, unknown> | null> {
144
- const cfg = pilotiq.getConfig()
145
- const R = pilotiq.findResource(slug)
146
- if (!R) return null
147
-
148
- const pages = R.resolvePages()
149
- if (!pages.index) return null
150
- const PageClass = pages.index
151
-
152
- const indexUrl = resourceBasePath(cfg.path, R)
153
- const user = await pilotiq.resolveUser(req)
154
- const ctx: SchemaContext = uploadCtx(userCtx({ mode: 'table', basePath: cfg.path }, user), cfg)
155
- const elements = await callPageSchema(PageClass, ctx)
156
- // Plan #15 — resource-scope widget polling URL. Stamped before the
157
- // schema resolves so each widget's meta carries its endpoint.
158
- tagWidgetUrls(elements, id => `${indexUrl}/_widget/${id}`)
159
- if (R.deferLoading) tagTableDeferred(elements, `${indexUrl}/_table`)
160
- await prepareResourceTable(elements, R, indexUrl, query, user)
161
- const widgetData = await resolveServerDataElements(elements, ctx)
162
-
163
- const breadcrumbs = resourceListBreadcrumbs(cfg, R)
164
- if (breadcrumbs) elements.unshift(breadcrumbs)
165
-
166
- const listRoute: PanelInfoRoute = { resource: R, page: PageClass }
167
- const [panel, schemaData] = await Promise.all([
168
- panelInfo(pilotiq, req, listRoute),
169
- resolveSchema(elements, ctx).then(metas => applyRoleHooks(pilotiq, user, 'list', metas, listRoute)),
170
- ])
171
-
172
- return {
173
- pageType: 'resource',
174
- panel,
175
- page: PageClass.toMeta(),
176
- resource: { name: R.name, label: R.label, labelSingular: R.labelSingular, slug, icon: serializeIcon(R.icon, R.name) },
177
- basePath: cfg.path,
178
- layout: cfg.layout,
179
- schemaData,
180
- _widgetData: widgetData,
181
- notifications: consumeFlashedNotifications(req),
182
- }
183
- }
184
-
185
- // Deferred-load JSON endpoint payload — `GET {base}/{slug}/_table`
186
- // re-runs the list-page builder without the deferred flag, then returns
187
- // every resolved `TableMeta` as a flat array. Returns null on missing
188
- // resource / index page (route 404s).
189
- export async function resourceTableData(
190
- pilotiq: Pilotiq,
191
- slug: string,
192
- query: Record<string, string> = {},
193
- req?: unknown,
194
- ): Promise<{ tables: Record<string, unknown>[] } | null> {
195
- const cfg = pilotiq.getConfig()
196
- const R = pilotiq.findResource(slug)
197
- if (!R) return null
198
-
199
- const pages = R.resolvePages()
200
- if (!pages.index) return null
201
- const PageClass = pages.index
202
-
203
- const indexUrl = resourceBasePath(cfg.path, R)
204
- const user = await pilotiq.resolveUser(req)
205
- const ctx: SchemaContext = uploadCtx(userCtx({ mode: 'table', basePath: cfg.path }, user), cfg)
206
- const elements = await callPageSchema(PageClass, ctx)
207
- await prepareResourceTable(elements, R, indexUrl, query, user)
208
- const schemaData = await resolveSchema(elements, ctx)
209
-
210
- const tables = collectTableMetas(schemaData)
211
- return { tables }
212
- }
213
-
214
- function collectTableMetas(
215
- metas: ReadonlyArray<Record<string, unknown>>,
216
- ): Record<string, unknown>[] {
217
- const out: Record<string, unknown>[] = []
218
- const walk = (nodes: ReadonlyArray<Record<string, unknown>>): void => {
219
- for (const node of nodes) {
220
- if (node['type'] === 'table') out.push(node)
221
- const children = node['children']
222
- if (Array.isArray(children)) walk(children as Record<string, unknown>[])
223
- }
224
- }
225
- walk(metas)
226
- return out
227
- }
228
-
229
- /**
230
- * Walk the schema for `ListTabs` containers, pick the active tab from
231
- * `?tab=…` (defaulting to the tab marked `.default()` or the first one),
232
- * stamp render-time state (`active` flag, per-tab `?tab=` URL, and
233
- * resolved badge counts) onto each tab. The active tab's query/context
234
- * modifier is NOT applied here — `loadTableRecords` walks for the active
235
- * tab and splices in its modifier when it builds the records-handler
236
- * `TableContext`.
237
- *
238
- * No-op when the page has no `ListTabs`.
239
- */
240
- export async function resolveActiveTab(
241
- elements: ReadonlyArray<Element>,
242
- query: Record<string, string>,
243
- currentPath: string,
244
- ): Promise<void> {
245
- const listTabs = findListTabs(elements)
246
- if (listTabs.length === 0) return
247
-
248
- for (const container of listTabs) {
249
- const children = (container.getChildren() ?? []).filter((c): c is ListTab => c.getType() === 'listTab')
250
- if (children.length === 0) continue
251
-
252
- // Default tab (used both for `?tab=` fallback and to omit the param
253
- // from the canonical URL of that tab — see `buildTabUrl`).
254
- const defaultTab = children.find(t => t.isDefault()) ?? children[0]!
255
-
256
- // Active tab: explicit `?tab=name` → default tab.
257
- const wanted = typeof query['tab'] === 'string' ? query['tab'] : undefined
258
- const active = (wanted && children.find(t => t.name === wanted)) || defaultTab
259
-
260
- // Stamp render-time state on each tab.
261
- children.forEach(t => {
262
- t.withActive(t === active)
263
- t.withUrl(buildTabUrl(currentPath, query, t.name, defaultTab.name))
264
- })
265
-
266
- // Resolve every tab's badge in parallel — failed handlers swallow
267
- // silently (badge omitted) so a flaky count never blanks the page.
268
- await Promise.all(children.map(async (tab) => {
269
- const handler = tab.getBadgeHandler()
270
- if (!handler) return
271
- try {
272
- const v = await handler()
273
- if (v === undefined || v === null) return
274
- tab.withResolvedBadge(String(v))
275
- } catch {
276
- // Per-tab badge errors stay silent.
277
- }
278
- }))
279
- }
280
- }
281
-
282
- function findListTabs(elements: ReadonlyArray<Element>): ListTabs[] {
283
- const out: ListTabs[] = []
284
- const walk = (els: ReadonlyArray<Element>): void => {
285
- for (const el of els) {
286
- if (el.getType() === 'listTabs') out.push(el as ListTabs)
287
- const children = el.getChildren()
288
- if (children) walk(children)
289
- }
290
- }
291
- walk(elements)
292
- return out
293
- }
294
-
295
- function buildTabUrl(
296
- pathname: string,
297
- query: Record<string, string>,
298
- tabName: string,
299
- defaultTabName: string,
300
- ): string {
301
- // Carry forward search/sort/perPage + any filter values; reset page to 1
302
- // (tab change reshapes the result set, page numbers don't translate).
303
- // The default tab gets the canonical, paramless URL — visiting that URL
304
- // already lands on the default, so emitting `?tab=default` would just be
305
- // noise that bookmarks/share-links pick up.
306
- const params = new URLSearchParams()
307
- for (const [k, v] of Object.entries(query)) {
308
- if (v === undefined || v === '' || v === null) continue
309
- if (k === 'tab' || k === 'page') continue
310
- params.set(k, String(v))
311
- }
312
- if (tabName !== defaultTabName) params.set('tab', tabName)
313
- const qs = params.toString()
314
- return qs ? `${pathname}?${qs}` : pathname
315
- }
316
-
317
- export async function resourceCreateData(
318
- pilotiq: Pilotiq,
319
- slug: string,
320
- prefill?: { values?: Record<string, unknown>; errors?: Record<string, string[]> },
321
- req?: unknown,
322
- ): Promise<Record<string, unknown> | null> {
323
- const cfg = pilotiq.getConfig()
324
- const R = pilotiq.findResource(slug)
325
- if (!R) return null
326
- const pages = R.resolvePages()
327
- if (!pages.create) return null
328
- const PageClass = pages.create
329
-
330
- const resourceBase = resourceBasePath(cfg.path, R)
331
- const createUrl = `${resourceBase}/create`
332
- const user = await pilotiq.resolveUser(req)
333
- const ctx: SchemaContext = uploadCtx(userCtx({ mode: 'create', basePath: cfg.path }, user), cfg)
334
- const elements = await callPageSchema(PageClass, ctx)
335
- tagFormActions(elements, createUrl)
336
- tagActionDispatch(elements, createUrl)
337
- tagFormSubresourceUrls(elements, resourceBase)
338
- if (prefill) {
339
- const form = findForms(elements)[0]
340
- if (form) {
341
- if (prefill.values) form.withValues(prefill.values)
342
- if (prefill.errors) form.withErrors(prefill.errors)
343
- }
344
- }
345
-
346
- const breadcrumbs = resourceCreateBreadcrumbs(cfg, R)
347
- if (breadcrumbs) elements.unshift(breadcrumbs)
348
-
349
- const createRoute: PanelInfoRoute = { resource: R, page: PageClass }
350
- const [panel, schemaData] = await Promise.all([
351
- panelInfo(pilotiq, req, createRoute),
352
- resolveSchema(elements, ctx).then(metas => applyRoleHooks(pilotiq, user, 'create', metas, createRoute)),
353
- ])
354
-
355
- return {
356
- panel,
357
- page: PageClass.toMeta(),
358
- resource: { name: R.name, label: R.labelSingular, slug, icon: serializeIcon(R.icon, R.name) },
359
- mode: 'create' as const,
360
- basePath: cfg.path,
361
- layout: cfg.layout,
362
- schemaData,
363
- notifications: consumeFlashedNotifications(req),
364
- ...(prefill?.errors ? { hasErrors: true } : {}),
365
- }
366
- }
367
-
368
- export async function resourceEditData(
369
- pilotiq: Pilotiq,
370
- slug: string,
371
- recordId: string,
372
- prefill?: { values?: Record<string, unknown>; errors?: Record<string, string[]> },
373
- req?: unknown,
374
- ): Promise<Record<string, unknown> | null> {
375
- const cfg = pilotiq.getConfig()
376
- const R = pilotiq.findResource(slug)
377
- if (!R) return null
378
- const pages = R.resolvePages()
379
- if (!pages.edit) return null
380
- const PageClass = pages.edit
381
-
382
- const resourceBase = resourceBasePath(cfg.path, R)
383
- const editUrl = `${resourceBase}/${recordId}/edit`
384
- const user = await pilotiq.resolveUser(req)
385
- const ctx: SchemaContext = uploadCtx(userCtx({ mode: 'edit', recordId, basePath: cfg.path }, user), cfg)
386
- const elements = await callPageSchema(PageClass, ctx)
387
- tagFormActions(elements, editUrl)
388
- tagActionDispatch(elements, editUrl)
389
- tagFormSubresourceUrls(elements, `${resourceBase}/${recordId}`)
390
-
391
- // Locate the primary form, load the record, fill values.
392
- const form = findForms(elements)[0]
393
- let record: unknown = undefined
394
- if (form?.getLoadRecord()) {
395
- try {
396
- record = await form.getLoadRecord()!(recordId, { values: prefill?.values ?? {} })
397
- } catch {
398
- // sentinel/missing record — fall through
399
- }
400
- if (!prefill?.values && record != null) {
401
- const values = await applyFillPipeline(form, record)
402
- const withRelations = await applyRelationshipRepeaterFill(form, values, record, R.model)
403
- const withBuilders = await applyRelationshipBuilderFill(form, withRelations, record, R.model)
404
- // Hydrators run AFTER the standard fill pipeline so they overlay
405
- // on top of DB-row + relationship-row values. Skipped on the
406
- // prefill branch (validation-error round-trip) — overlaying there
407
- // would clobber the user's just-submitted input that the page is
408
- // re-displaying for them to fix.
409
- const hydrators = cfg.editPageHydrators ?? []
410
- const overlay = hydrators.length > 0
411
- ? await applyEditPageHydrators(hydrators, {
412
- resource: R,
413
- recordId,
414
- currentValues: withBuilders,
415
- })
416
- : {}
417
- form.withValues(Object.keys(overlay).length > 0
418
- ? { ...withBuilders, ...overlay }
419
- : withBuilders)
420
- } else if (prefill?.values) {
421
- form.withValues(prefill.values)
422
- }
423
- if (prefill?.errors) form.withErrors(prefill.errors)
424
- }
425
-
426
- // Plan #11 — when the resource has relation managers, prepend a
427
- // navigation strip so users can drill into each manager's table
428
- // without leaving the parent record context. The "Edit" tab is
429
- // active here.
430
- const relationTabsEl = await buildRelationTabs(R, recordId, cfg.path, '__edit', user, record)
431
- if (relationTabsEl) elements.unshift(relationTabsEl)
432
-
433
- const recordTitle = record !== undefined && record !== null
434
- ? deriveParentTitle(R, record)
435
- : recordId
436
- const breadcrumbs = resourceEditBreadcrumbs(cfg, R, recordId, recordTitle)
437
- if (breadcrumbs) elements.unshift(breadcrumbs)
438
-
439
- const editRoute: PanelInfoRoute = { resource: R, page: PageClass, recordId }
440
- const editCtx = record !== undefined ? { ...ctx, record } : ctx
441
- const [panel, schemaData] = await Promise.all([
442
- panelInfo(pilotiq, req, editRoute),
443
- resolveSchema(elements, editCtx).then(metas => applyRoleHooks(pilotiq, user, 'edit', metas, editRoute)),
444
- ])
445
-
446
- tagFieldAiUrls(schemaData as Record<string, unknown>[], `${resourceBase}/${recordId}/_agents`)
447
-
448
- return {
449
- panel,
450
- page: PageClass.toMeta(),
451
- resource: { name: R.name, label: R.labelSingular, slug, icon: serializeIcon(R.icon, R.name) },
452
- mode: 'edit' as const,
453
- recordId,
454
- basePath: cfg.path,
455
- layout: cfg.layout,
456
- schemaData,
457
- notifications: consumeFlashedNotifications(req),
458
- ...(prefill?.errors ? { hasErrors: true } : {}),
459
- }
460
- }
461
-
462
- export async function resourceViewData(
463
- pilotiq: Pilotiq,
464
- slug: string,
465
- recordId: string,
466
- req?: unknown,
467
- ): Promise<Record<string, unknown> | null> {
468
- const cfg = pilotiq.getConfig()
469
- const R = pilotiq.findResource(slug)
470
- if (!R) return null
471
- const pages = R.resolvePages()
472
- if (!pages.view) return null
473
- const PageClass = pages.view
474
-
475
- const user = await pilotiq.resolveUser(req)
476
- const ctx: SchemaContext = uploadCtx(userCtx({ mode: 'view', recordId, basePath: cfg.path }, user), cfg)
477
- const elements = await callPageSchema(PageClass, ctx)
478
- // For the view page we want the record threaded into resolveSchema so
479
- // factory-attached visibility predicates see it. Resource.detail()
480
- // already runs against the loaded record in user code; here we mirror
481
- // that into ctx.record for the action eval pass.
482
- let record: unknown = undefined
483
- if (R.model) {
484
- try { record = await findRecord(R, recordId, { user }) } catch { /* ignore */ }
485
- }
486
-
487
- // Plan #11 — prepend the relation tabs strip with the "Details" tab
488
- // active when the resource has relation managers configured.
489
- const relationTabsEl = await buildRelationTabs(R, recordId, cfg.path, '__view', user, record)
490
- if (relationTabsEl) elements.unshift(relationTabsEl)
491
-
492
- const recordTitle = record !== undefined && record !== null
493
- ? deriveParentTitle(R, record)
494
- : recordId
495
- const breadcrumbs = resourceViewBreadcrumbs(cfg, R, recordTitle)
496
- if (breadcrumbs) elements.unshift(breadcrumbs)
497
-
498
- const viewRoute: PanelInfoRoute = { resource: R, page: PageClass, recordId }
499
- const viewCtx = record !== undefined ? { ...ctx, record } : ctx
500
- const [panel, schemaData] = await Promise.all([
501
- panelInfo(pilotiq, req, viewRoute),
502
- resolveSchema(elements, viewCtx).then(metas => applyRoleHooks(pilotiq, user, 'view', metas, viewRoute)),
503
- ])
504
-
505
- return {
506
- panel,
507
- page: PageClass.toMeta(),
508
- resource: { name: R.name, label: R.labelSingular, slug, icon: serializeIcon(R.icon, R.name) },
509
- mode: 'view' as const,
510
- recordId,
511
- basePath: cfg.path,
512
- layout: cfg.layout,
513
- schemaData,
514
- notifications: consumeFlashedNotifications(req),
515
- }
516
- }
517
-
518
- /**
519
- * Custom record sub-page data builder. Mounted at
520
- * `${resourceBase}/${slug}/:id/${subPageSlug}` for each entry in
521
- * `Resource.pages().record`. Mirrors `resourceViewData`'s shape: load
522
- * the record, run R.canAccess + R.canView (parent-resource gates),
523
- * then SubPage.canAccess(user, record) (sub-page-specific gate),
524
- * then render the sub-page's schema with `ctx.record` set. Tab strip
525
- * carries the sub-page slug as the active key so the matching record
526
- * sub-page tab highlights.
527
- *
528
- * Returns:
529
- * - `null` — resource / sub-page slug not found (404 upstream).
530
- * - `{ ok: false, status: 403 }` — any gate fails or throws.
531
- * - resolved page data — on success.
532
- */
533
- export async function resourceRecordPageData(
534
- pilotiq: Pilotiq,
535
- slug: string,
536
- recordId: string,
537
- subPageSlug: string,
538
- req?: unknown,
539
- ): Promise<Record<string, unknown> | null | { ok: false; status: 403 }> {
540
- const cfg = pilotiq.getConfig()
541
- const R = pilotiq.findResource(slug)
542
- if (!R) return null
543
- const recordPages = R.getRecordPages()
544
- const PageClass = recordPages[subPageSlug]
545
- if (!PageClass) return null
546
-
547
- const user = await pilotiq.resolveUser(req)
548
-
549
- // Load the parent record before gating so canView / SubPage.canAccess
550
- // can branch on record state. Sub-pages without a Resource.model
551
- // still get gated against an `undefined` record — the same posture as
552
- // resourceViewData when no model is bound.
553
- let record: unknown = undefined
554
- if (R.model) {
555
- try { record = await findRecord(R, recordId, { user }) } catch { /* ignore */ }
556
- }
557
- if (record === undefined || record === null) {
558
- // Distinguish "model bound but record missing" (route should 404)
559
- // from "no model bound" (treat record as `{ id: recordId }` so the
560
- // page can still render — same convention as the edit page).
561
- if (R.model) return null
562
- record = { id: recordId }
563
- }
564
-
565
- // Three gates: parent resource access + view, then the sub-page's own
566
- // canAccess. The route would have run R.canAccess upstream, but
567
- // re-running here makes resourceRecordPageData safe to call from
568
- // dispatchPageData (where the SPA path skips the route prelude).
569
- if (!await safeBool(() => R.canAccess(user))) return { ok: false, status: 403 }
570
- if (!await safeBool(() => R.canView(user, record))) return { ok: false, status: 403 }
571
- if (!await safeBool(() => PageClass.canAccess(user, record))) return { ok: false, status: 403 }
572
-
573
- const ctx: SchemaContext = uploadCtx(userCtx({ mode: 'view', recordId, basePath: cfg.path }, user), cfg)
574
- const elements = await callPageSchema(PageClass, ctx)
575
-
576
- // Insert the relation-tabs strip with the sub-page slug active so the
577
- // matching tab highlights. `buildRelationTabs` evaluates per-tab
578
- // gating against `user + record` — record sub-page tabs are gated
579
- // alongside __view/__edit/managers.
580
- const relationTabsEl = await buildRelationTabs(R, recordId, cfg.path, subPageSlug, user, record)
581
- if (relationTabsEl) elements.unshift(relationTabsEl)
582
-
583
- const recordTitle = record !== undefined && record !== null
584
- ? deriveParentTitle(R, record)
585
- : recordId
586
- const breadcrumbs = resourceViewBreadcrumbs(cfg, R, recordTitle)
587
- if (breadcrumbs) elements.unshift(breadcrumbs)
588
-
589
- const recordPageRoute: PanelInfoRoute = { resource: R, page: PageClass, recordId }
590
- const recordCtx = record !== undefined ? { ...ctx, record } : ctx
591
- const [panel, schemaData] = await Promise.all([
592
- panelInfo(pilotiq, req, recordPageRoute),
593
- resolveSchema(elements, recordCtx).then(metas => applyRoleHooks(pilotiq, user, 'view', metas, recordPageRoute)),
594
- ])
595
-
596
- return {
597
- pageType: 'record-page' as const,
598
- panel,
599
- page: PageClass.toMeta(),
600
- resource: { name: R.name, label: R.labelSingular, slug, icon: serializeIcon(R.icon, R.name) },
601
- mode: 'record' as const,
602
- recordId,
603
- subPage: { slug: subPageSlug, label: PageClass.getLabel() },
604
- basePath: cfg.path,
605
- layout: cfg.layout,
606
- schemaData,
607
- notifications: consumeFlashedNotifications(req),
608
- }
609
- }