@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,220 +0,0 @@
1
- /**
2
- * CRUD single-row Action factories — `create / edit / view / delete /
3
- * replicate / restore / forceDelete`, plus the notification `markAsRead`
4
- * factory.
5
- *
6
- * Each factory builds and returns a configured `Action`. The matching
7
- * `static` methods on the `Action` class are thin delegators that call
8
- * into these functions, preserving the public `Action.create(R, base)`
9
- * call shape.
10
- *
11
- * See `docs/plans/action-split.md` for the split plan.
12
- */
13
-
14
- import { Action, type ReplicateOptions, type ResourceLike } from './Action.js'
15
- import { buildReplica, callPredicate, isTrashed, resourceBase } from './factoryHelpers.js'
16
-
17
- /** Create-action factory — link to `${basePath}/${R.slug}/create`.
18
- * Auto-hides when `R.canCreate(user)` returns false. */
19
- export function createAction(R: ResourceLike, basePath: string): Action {
20
- return Action.make('create')
21
- .label(`New ${R.labelSingular}`)
22
- .href(`${resourceBase(basePath, R)}/create`)
23
- .visible(({ user }) => callPredicate(R.canCreate, user))
24
- }
25
-
26
- /**
27
- * Edit-action factory — link to the resource's edit page.
28
- *
29
- * Pass `recordId` when building actions for a single-record context
30
- * (e.g. `ViewPage.getActions()`); the URL is baked at config time.
31
- * Omit `recordId` for row context (`Table.recordActions(...)`); the
32
- * URL keeps the `:id` template and the renderer substitutes per-row.
33
- *
34
- * Auto-hides when `R.canEdit(user, record)` returns false. For row
35
- * context the per-row record threads in via `loadTableRecords`'s
36
- * per-row eval; for view-page context, `resolveSchema` provides the
37
- * resolved record on the eval context.
38
- */
39
- export function editAction(R: ResourceLike, basePath: string, recordId?: string): Action {
40
- const id = recordId ?? ':id'
41
- return Action.make('edit')
42
- .label('Edit')
43
- .href(`${resourceBase(basePath, R)}/${id}/edit`)
44
- .visible(({ user, record }) => callPredicate(R.canEdit, user, record))
45
- }
46
-
47
- /** View-action factory — link to the resource's view page. See `editAction` for the `recordId` semantics.
48
- * Auto-hides when `R.canView(user, record)` returns false. */
49
- export function viewAction(R: ResourceLike, basePath: string, recordId?: string): Action {
50
- const id = recordId ?? ':id'
51
- return Action.make('view')
52
- .label('View')
53
- .href(`${resourceBase(basePath, R)}/${id}`)
54
- .visible(({ user, record }) => callPredicate(R.canView, user, record))
55
- }
56
-
57
- /**
58
- * Delete-action factory — POSTs to the resource's delete route,
59
- * destructive style, with a confirmation prompt referencing the
60
- * resource label. Same `recordId` semantics as `editAction`.
61
- * Auto-hides when `R.canDelete(user, record)` returns false.
62
- *
63
- * Plan #13 — when `R.softDeletes = true`, additionally hides on
64
- * rows whose `deletedAtColumn` is set (already-trashed rows get the
65
- * Restore + ForceDelete pair instead, surfaced via the matching
66
- * factories below).
67
- */
68
- export function deleteAction(R: ResourceLike, basePath: string, recordId?: string): Action {
69
- const id = recordId ?? ':id'
70
- return Action.make('delete')
71
- .label('Delete')
72
- .destructive()
73
- .method('post')
74
- .action(`${resourceBase(basePath, R)}/${id}/delete`)
75
- .confirm(`Delete this ${R.labelSingular.toLowerCase()}?`)
76
- .visible(async ({ user, record }) => {
77
- if (R.softDeletes && isTrashed(record, R)) return false
78
- return callPredicate(R.canDelete, user, record)
79
- })
80
- }
81
-
82
- /**
83
- * Replicate-action factory — handler-style. Loads the source record
84
- * from `ctx.record` (the `_action/:actionName` route already resolves
85
- * it through `R.query(ctx)` for row + single-target placements),
86
- * strips PK + soft-delete column + any `opts.excludeAttributes`,
87
- * optionally runs `opts.beforeReplicaSaved`, and creates a new row
88
- * via `R.model.create(...)`. Redirects to the new record's edit page
89
- * on success so the user can review + tweak before saving again.
90
- *
91
- * `recordId` kept in the signature for parity with `delete / edit /
92
- * view` so users can swap factories without rewriting call sites; the
93
- * dispatcher resolves the source record from the URL and hands it to
94
- * the handler as `ctx.record`, so we don't reference `recordId` here.
95
- *
96
- * Auto-hides when `R.canCreate(user)` returns false — replicating
97
- * writes a new row, so the gate is `canCreate`, not `canView`.
98
- */
99
- export function replicateAction(
100
- R: ResourceLike,
101
- basePath: string,
102
- recordId?: string,
103
- opts: ReplicateOptions = {},
104
- ): Action {
105
- void recordId
106
- return Action.make('replicate')
107
- .label('Replicate')
108
- .handler(async (ctx) => {
109
- const source = ctx.record
110
- if (!source || typeof source !== 'object') {
111
- return { notify: { title: 'Replicate failed: source record missing', type: 'error' } as never }
112
- }
113
- const M = R.model
114
- if (!M || typeof M.create !== 'function') {
115
- return { notify: { title: 'Replicate not configured (resource has no model.create)', type: 'error' } as never }
116
- }
117
-
118
- let replica: Record<string, unknown>
119
- let pkCol: string
120
- try {
121
- ({ replica, pkCol } = await buildReplica(source, M, {
122
- excludeAttributes: opts.excludeAttributes,
123
- deletedAtColumn: R.deletedAtColumn,
124
- beforeReplicaSaved: opts.beforeReplicaSaved,
125
- }))
126
- } catch (err) {
127
- return { notify: { title: `Replicate failed: ${err instanceof Error ? err.message : String(err)}`, type: 'error' } as never }
128
- }
129
-
130
- let created: unknown
131
- try {
132
- created = await M.create(replica)
133
- } catch (err) {
134
- return { notify: { title: `Replicate failed: ${err instanceof Error ? err.message : String(err)}`, type: 'error' } as never }
135
- }
136
-
137
- const newId = (created as Record<string, unknown> | null | undefined)?.[pkCol]
138
- const defaultRedirect = newId !== undefined && newId !== null
139
- ? `${resourceBase(basePath, R)}/${String(newId)}/edit`
140
- : `${resourceBase(basePath, R)}`
141
- // `!== undefined` rather than `??` so an override returning
142
- // `null`/empty-string isn't silently swallowed (see
143
- // feedback_nullish_swallows_explicit_null).
144
- const overrideRedirect = opts.getRedirectUrl
145
- ? await opts.getRedirectUrl({ replica: created, source })
146
- : undefined
147
- const redirect = overrideRedirect !== undefined ? overrideRedirect : defaultRedirect
148
- const overrideTitle = opts.getCreatedNotificationTitle
149
- ? await opts.getCreatedNotificationTitle({ replica: created, source })
150
- : undefined
151
- const title = overrideTitle !== undefined ? overrideTitle : `${R.labelSingular} replicated`
152
- return {
153
- redirect,
154
- notify: { title, type: 'success' } as never,
155
- }
156
- })
157
- .visible(({ user }) => callPredicate(R.canCreate, user))
158
- }
159
-
160
- /**
161
- * Plan #13 — Restore factory. POSTs to the resource's restore route,
162
- * success-styled, no confirm prompt (restoration is reversible).
163
- * Auto-hides on live (non-trashed) rows AND when `R.canRestore(user,
164
- * record)` returns false. Same `recordId` semantics as `editAction`.
165
- */
166
- export function restoreAction(R: ResourceLike, basePath: string, recordId?: string): Action {
167
- const id = recordId ?? ':id'
168
- return Action.make('restore')
169
- .label('Restore')
170
- .color('success')
171
- .method('post')
172
- .action(`${resourceBase(basePath, R)}/${id}/restore`)
173
- .visible(async ({ user, record }) => {
174
- if (!isTrashed(record, R)) return false
175
- return callPredicate(R.canRestore, user, record)
176
- })
177
- }
178
-
179
- /**
180
- * Plan #13 — Force-delete factory. POSTs to the resource's
181
- * force-delete route, destructive-styled, with a stricter confirm
182
- * prompt referencing permanence. Auto-hides on live (non-trashed)
183
- * rows AND when `R.canForceDelete(user, record)` returns false.
184
- */
185
- export function forceDeleteAction(R: ResourceLike, basePath: string, recordId?: string): Action {
186
- const id = recordId ?? ':id'
187
- return Action.make('forceDelete')
188
- .label('Delete forever')
189
- .destructive()
190
- .method('post')
191
- .action(`${resourceBase(basePath, R)}/${id}/force-delete`)
192
- .confirm(`Permanently delete this ${R.labelSingular.toLowerCase()}? This cannot be undone.`)
193
- .visible(async ({ user, record }) => {
194
- if (!isTrashed(record, R)) return false
195
- return callPredicate(R.canForceDelete, user, record)
196
- })
197
- }
198
-
199
- /**
200
- * Mark-as-read factory — POSTs to the panel's notification read
201
- * endpoint for the given notification id. The endpoint
202
- * (`${base}/_notifications/:id/read`) is mounted by
203
- * `Pilotiq.databaseNotifications()`, so calling this without
204
- * opting into the bell surface produces an Action whose POST 404s.
205
- *
206
- * `notificationId` is baked at config time. For row context where
207
- * the id varies per row, omit it and the URL keeps the `:id`
208
- * template; the renderer substitutes per-row at render time
209
- * (parallel to `editAction`'s row form).
210
- *
211
- * No auto-visibility. Wrap in `.visible(({ record }) => !record.readAt)`
212
- * to hide on already-read rows.
213
- */
214
- export function markAsReadAction(basePath: string, notificationId?: string): Action {
215
- const id = notificationId ?? ':id'
216
- return Action.make('markAsRead')
217
- .label('Mark as read')
218
- .method('post')
219
- .action(`${basePath}/_notifications/${id}/read`)
220
- }
@@ -1,225 +0,0 @@
1
- /**
2
- * Internals for the `Action.export` / `Action.bulkExport` factories.
3
- *
4
- * Lives in its own module to keep the cycle between `Action.ts` and
5
- * `Table.ts` honest — `Action.export` calls into here via dynamic
6
- * import inside the handler, so module-eval order never reads either
7
- * side's exports too early.
8
- *
9
- * The `R: { table?(t: any): any }` shape on `resolveExportColumns`
10
- * (and the matching parameter in `collectExportRows`) is the load-bearing
11
- * piece of this isolation: the real `Resource.table()` signature is
12
- * `(t: Table) => Table`, but importing `Table` here from a static-top
13
- * import would resurrect the cycle this file exists to break. Loosening
14
- * the parameter to `any` is the price — call sites in `Action.ts` are
15
- * typed against the proper `ResourceLike`, so the leak doesn't escape
16
- * this module. Don't widen `R`'s annotation; do narrow inside the body
17
- * if you need stricter local typing.
18
- */
19
-
20
- import { Table } from '../elements/Table.js'
21
- import { Column } from '../Column.js'
22
- import type { ActionContext } from './Action.js'
23
- import { encodeCsv, type CsvColumn } from '../io/csv.js'
24
- import { parseTableQuery, type QueryParams } from '../elements/dispatchTable.js'
25
-
26
- export type ExportFormat = 'csv' | 'json'
27
-
28
- export type ExportColumnSpec =
29
- | string
30
- | {
31
- key: string
32
- label?: string
33
- format?: (value: unknown, record: Record<string, unknown>) => string
34
- }
35
-
36
- export interface ExportOptions {
37
- /** Columns to include. Strings → bare `key` (label = key). Objects
38
- * may add `label` and `format(value, record) => string`. When omitted,
39
- * defaults to every `Column` returned by `R.table()` in declaration
40
- * order, with header label = `Column.getLabel()`. */
41
- columns?: ExportColumnSpec[]
42
- /** Output filename. Function form receives the action context (so the
43
- * filename can include the user, current filters, etc). Default:
44
- * `${R.slug}-${YYYY-MM-DD}.${format}`. */
45
- filename?: string | ((ctx: ActionContext) => string)
46
- /** Output format. Default `'csv'`. */
47
- format?: ExportFormat
48
- /** Records scope:
49
- * - `'all'` — ignore the current URL state (filters/search/sort)
50
- * - `'filtered'` — apply the current URL state (default; matches the
51
- * list page the user is looking at)
52
- * - `'page'` — only export the visible page
53
- *
54
- * Bulk variant ignores `scope` and always uses `ctx.records`.
55
- */
56
- scope?: 'all' | 'filtered' | 'page'
57
- /** Hard cap on the row count. Aborts with an error notification when
58
- * exceeded. Default `50_000`. */
59
- maxRows?: number
60
- /** Pagination chunk size when walking the records handler. Default
61
- * `1_000`. */
62
- chunkSize?: number
63
- }
64
-
65
- interface ResolvedColumn {
66
- key: string
67
- label: string
68
- format?: (value: unknown, record: Record<string, unknown>) => string
69
- }
70
-
71
- const DEFAULT_MAX_ROWS = 50_000
72
- const DEFAULT_CHUNK = 1_000
73
-
74
- /**
75
- * Resolve the column spec into a uniform `{ key, label, format? }[]`,
76
- * defaulting to every `Column` child on `R.table(Table.make())` when
77
- * the spec is omitted.
78
- */
79
- export function resolveExportColumns(
80
- spec: ExportOptions['columns'],
81
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
82
- R: { table?(t: any): any },
83
- ): ResolvedColumn[] {
84
- if (spec && spec.length > 0) {
85
- return spec.map(s => typeof s === 'string'
86
- ? { key: s, label: s }
87
- : { key: s.key, label: s.label ?? s.key, ...(s.format ? { format: s.format } : {}) })
88
- }
89
- const tableInst = R.table?.(Table.make())
90
- if (!tableInst) return []
91
- const cols: Column[] = tableInst.getColumns?.() ?? []
92
- return cols.map(c => ({ key: c.name, label: c.getLabel?.() ?? c.name }))
93
- }
94
-
95
- /**
96
- * Read the URL query record off `ctx.request`. Routes pass a Hono-like
97
- * request object whose `.query` is a `Record<string, string>`. Fall
98
- * back to `{}` when missing (programmatic dispatches in tests).
99
- */
100
- export function readRequestQuery(ctx: ActionContext): QueryParams {
101
- const req = ctx.request as { query?: unknown } | undefined
102
- const q = req?.query
103
- if (q && typeof q === 'object') return q as QueryParams
104
- return {}
105
- }
106
-
107
- /**
108
- * Drive the table's `records()` handler in pages until we run out of
109
- * rows or hit `maxRows`. Returns the collected raw records (not yet
110
- * mapped to row objects).
111
- *
112
- * Scope behavior:
113
- * - `'all'`: empty TableContext (no filters/search/sort applied)
114
- * - `'filtered'`: TableContext built from the URL query (filters /
115
- * search / sort all flow through)
116
- * - `'page'`: same as `'filtered'` but only the visible page
117
- */
118
- export async function collectExportRows(
119
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
120
- table: any,
121
- ctx: ActionContext,
122
- scope: ExportOptions['scope'] = 'filtered',
123
- maxRows: number = DEFAULT_MAX_ROWS,
124
- chunkSize: number = DEFAULT_CHUNK,
125
- ): Promise<unknown[]> {
126
- const handler = table.getRecords?.()
127
- if (!handler) {
128
- throw new Error('Resource table has no records() handler — cannot export. Set R.model or Table.records(fn).')
129
- }
130
-
131
- const baseCtx = scope === 'all' ? {} : buildTableCtxFromQuery(readRequestQuery(ctx), table)
132
-
133
- const collected: unknown[] = []
134
- let page = scope === 'page' ? (baseCtx.page ?? 1) : 1
135
- const effectivePerPage = scope === 'page' ? (baseCtx.perPage ?? chunkSize) : chunkSize
136
-
137
- while (collected.length <= maxRows) {
138
- const result = await handler({ ...baseCtx, page, perPage: effectivePerPage })
139
- const rows: unknown[] = Array.isArray(result) ? result : (result?.rows ?? [])
140
- collected.push(...rows)
141
- if (rows.length < effectivePerPage) break
142
- if (scope === 'page') break
143
- page++
144
- }
145
-
146
- return collected
147
- }
148
-
149
- /**
150
- * Build a `TableContext` from a URL-query record by reusing the same
151
- * parsing the list page does. Filters mirror onto the table's Filter
152
- * children so any `Filter.query()` overrides see them on subsequent
153
- * runs (defensive — `loadTableRecords` does the same).
154
- */
155
- function buildTableCtxFromQuery(
156
- query: QueryParams,
157
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
158
- table: any,
159
- ): {
160
- search?: string
161
- sort?: { column: string; direction: 'asc' | 'desc' }
162
- filters?: Record<string, string>
163
- page?: number
164
- perPage?: number
165
- } {
166
- const { search, sort, page, perPage } = parseTableQuery(query)
167
-
168
- const tableFilters = table.getFilters?.() ?? []
169
- const filterValues: Record<string, string> = {}
170
- const reserved = new Set(['search', 'sort', 'page', 'perPage', 'group', 'groupKey'])
171
- for (const f of tableFilters) {
172
- const name = f.name as string
173
- if (reserved.has(name)) continue
174
- const v = (query as Record<string, unknown>)[name]
175
- if (typeof v === 'string' && v !== '') filterValues[name] = v
176
- }
177
- for (const f of tableFilters) {
178
- const v = filterValues[f.name as string]
179
- if (v !== undefined && typeof f.withValue === 'function') f.withValue(v)
180
- }
181
-
182
- const out: ReturnType<typeof buildTableCtxFromQuery> = {}
183
- if (search !== undefined) out.search = search
184
- if (sort !== undefined) out.sort = sort
185
- if (Object.keys(filterValues).length > 0) out.filters = filterValues
186
- if (page !== undefined) out.page = page
187
- if (perPage !== undefined) out.perPage = perPage
188
- return out
189
- }
190
-
191
- /** Build a single CSV/JSON-shaped row by reading each resolved column's
192
- * key off the record (with `format` applied when set). */
193
- export function buildExportRow(
194
- record: unknown,
195
- cols: ReadonlyArray<ResolvedColumn>,
196
- ): Record<string, unknown> {
197
- const r = record as Record<string, unknown>
198
- const out: Record<string, unknown> = {}
199
- for (const col of cols) {
200
- const raw = r[col.key]
201
- out[col.key] = col.format ? col.format(raw, r) : raw
202
- }
203
- return out
204
- }
205
-
206
- /** Encode `rows` as the requested format. Object values that survive
207
- * to here go through the CSV escape rules / `JSON.stringify`. */
208
- export function encodeExport(
209
- rows: ReadonlyArray<Record<string, unknown>>,
210
- cols: ReadonlyArray<ResolvedColumn>,
211
- format: ExportFormat,
212
- ): { body: string; contentType: string } {
213
- if (format === 'json') {
214
- return { body: JSON.stringify(rows, null, 2), contentType: 'application/json' }
215
- }
216
- const csvCols: CsvColumn[] = cols.map(c => ({ key: c.key, label: c.label }))
217
- return { body: encodeCsv(rows, csvCols), contentType: 'text/csv; charset=utf-8' }
218
- }
219
-
220
- /** Default filename: `${slug}-${YYYY-MM-DD}.${ext}`. */
221
- export function defaultExportFilename(slug: string, format: ExportFormat): string {
222
- const date = new Date().toISOString().slice(0, 10)
223
- const ext = format === 'json' ? 'json' : 'csv'
224
- return `${slug}-${date}.${ext}`
225
- }
@@ -1,177 +0,0 @@
1
- /**
2
- * Shared helpers for the Action factory modules — `crudFactories.ts`,
3
- * `bulkFactories.ts`, `relationFactories.ts`, `m2mFactories.ts`.
4
- *
5
- * Lives in its own file so the per-phase factory modules stay focused
6
- * on their own factory bodies. Anything consumed by 2+ phase files
7
- * lands here; phase-local helpers stay alongside their phase's
8
- * factories.
9
- *
10
- * See `docs/plans/action-split.md` for the split plan.
11
- */
12
-
13
- import type { ResourceLike } from './Action.js'
14
- import type { RelationManagerContext } from '../RelationManager.js'
15
-
16
- /** Cluster-aware resource base path. Mirrors `clusterPaths.resourceBasePath`
17
- * but uses the structural `ResourceLike` shape so `Action.ts` stays
18
- * cycle-free against `Resource.ts`. */
19
- export function resourceBase(basePath: string, R: ResourceLike): string {
20
- if (R.cluster) return `${basePath}/${R.cluster.getSlug()}/${R.getSlug()}`
21
- return `${basePath}/${R.getSlug()}`
22
- }
23
-
24
- /** Call a (possibly undefined) Resource predicate. When unset, the
25
- * predicate is treated as "allowed" (returns true) so the factory
26
- * doesn't hide actions on Resources that haven't opted into Plan #10. */
27
- export function callPredicate(
28
- fn: ((user: unknown, record?: unknown) => boolean | Promise<boolean>) | undefined,
29
- user: unknown,
30
- record?: unknown,
31
- ): boolean | Promise<boolean> {
32
- if (!fn) return true
33
- return fn(user, record)
34
- }
35
-
36
- /** Read `record[R.deletedAtColumn ?? 'deletedAt']` and return true when
37
- * the row is currently trashed (soft-deleted). Permissive on shape —
38
- * bare `null` / `undefined` count as live; any other truthy value is
39
- * trashed. */
40
- export function isTrashed(record: unknown, R: ResourceLike): boolean {
41
- if (!record || typeof record !== 'object') return false
42
- const col = R.deletedAtColumn ?? 'deletedAt'
43
- const v = (record as Record<string, unknown>)[col]
44
- return v !== null && v !== undefined
45
- }
46
-
47
- /** True when a `RelationManagerContext.mode` denotes a pivot-mutation
48
- * shape — i.e. a many-to-many relation. All three modes share the
49
- * `attach` / `detach` / `sync` accessor surface (the rudder ORM stamps
50
- * + filters the polymorphic discriminator transparently for the morph
51
- * variants). The `relationCreate / Edit / Delete` factories auto-hide
52
- * under any of these modes because per-pivot-row create / edit / delete
53
- * is meaningless — users create the related record via its own Resource,
54
- * then attach via `relationAttach`. */
55
- export function isM2MMode(mode: RelationManagerContext['mode']): boolean {
56
- return mode === 'belongsToMany' || mode === 'morphToMany' || mode === 'morphedByMany'
57
- }
58
-
59
- /**
60
- * Build the URL prefix for a relation factory action. Without
61
- * a `chain` (depth-1 manager), this is the familiar
62
- * `${base}/${parentSlug}/${parentId}/${relationship}`. With a chain
63
- * (depth-2 nested manager), it threads the outer record + relationship
64
- * between the parent slug and the leaf parent id:
65
- *
66
- * `${base}/${parentSlug}/${chain[0].recordId}/${chain[0].relationship}/${parentId}/${relationship}`
67
- *
68
- * Pure; takes a `RelationManagerContext` and emits a string. The leaf
69
- * record id (and trailing `/edit`, `/delete`, etc.) gets appended by
70
- * the caller.
71
- */
72
- export function relationUrlPrefix(ctx: RelationManagerContext): string {
73
- const head = `${ctx.basePath}/${ctx.parentSlug}`
74
- const chain = ctx.chain ?? []
75
- let mid = ''
76
- for (const step of chain) {
77
- mid += `/${step.recordId}/${step.relationship}`
78
- }
79
- return `${head}${mid}/${ctx.parentId}/${ctx.relationship}`
80
- }
81
-
82
- /** Options bag for `buildReplica`. Optional fields explicitly accept
83
- * `undefined` so call sites can pass `opts.excludeAttributes` through
84
- * unconditionally under `exactOptionalPropertyTypes: true`. */
85
- export interface BuildReplicaOptions {
86
- /** Attribute keys to drop from the replicated payload IN ADDITION TO
87
- * the model's primary key and soft-delete column. */
88
- excludeAttributes?: readonly string[] | undefined
89
- /** Soft-delete column name on the source Resource. Defaults to
90
- * `'deletedAt'`. Read separately from the model because the column
91
- * lives on the Resource shape (`R.deletedAtColumn`) rather than on
92
- * the model itself. */
93
- deletedAtColumn?: string | undefined
94
- /** Force-pinned columns applied AFTER the strip and BEFORE the user
95
- * `beforeReplicaSaved` mutator. Used by the relation replicate
96
- * factories to re-stamp the parent attachment FK / morph columns
97
- * so a tampered source row can't slip a different parent in. */
98
- pin?: Record<string, unknown> | undefined
99
- /** Optional user mutator. Runs after the strip + pin. */
100
- beforeReplicaSaved?: ((
101
- replica: Record<string, unknown>,
102
- source: unknown,
103
- ) => Record<string, unknown> | Promise<Record<string, unknown>>) | undefined
104
- }
105
-
106
- /**
107
- * Build a replica payload from a source record. Used by every replicate
108
- * factory (`replicateAction / bulkReplicateAction / relationReplicateAction
109
- * / relationBulkReplicateAction`).
110
- *
111
- * Strips the model's primary key (`model.primaryKey`, defaulting to
112
- * `'id'`), the soft-delete column (defaulting to `'deletedAt'`), and any
113
- * `excludeAttributes` keys. Applies `pin` columns (parent attachment
114
- * for relation factories), then runs the optional `beforeReplicaSaved`
115
- * user mutator. Returns the replica AND the resolved primary-key column
116
- * name (callers need it to read `created[pkCol]` for redirect URLs).
117
- *
118
- * Does NOT call `model.create` — callers wrap their own create + error
119
- * handling around the returned replica.
120
- */
121
- export async function buildReplica(
122
- source: unknown,
123
- model: { primaryKey?: string },
124
- opts: BuildReplicaOptions = {},
125
- ): Promise<{ replica: Record<string, unknown>; pkCol: string }> {
126
- const pkCol = model.primaryKey ?? 'id'
127
- const trashedCol = opts.deletedAtColumn ?? 'deletedAt'
128
- const skip = new Set<string>([pkCol, trashedCol, ...(opts.excludeAttributes ?? [])])
129
- let replica: Record<string, unknown> = {}
130
- for (const [k, v] of Object.entries(source as Record<string, unknown>)) {
131
- if (skip.has(k)) continue
132
- replica[k] = v
133
- }
134
- if (opts.pin) Object.assign(replica, opts.pin)
135
- if (opts.beforeReplicaSaved) {
136
- replica = await opts.beforeReplicaSaved(replica, source)
137
- }
138
- return { replica, pkCol }
139
- }
140
-
141
- /**
142
- * Iterate `records`, run the policy probe in parallel up-front (only
143
- * allowed rows enter the serial work loop), call `op(id, record)` per
144
- * allowed row, swallow per-row throws (the aggregate notification shows
145
- * the count succeeded). Returns the success count.
146
- *
147
- * Used by every bulk handler (`bulkDeleteAction / bulkRestoreAction /
148
- * bulkForceDeleteAction / bulkReplicateAction / relationBulkReplicateAction
149
- * / relationBulkDetachAction`-style pattern).
150
- *
151
- * Rows whose `record.id` coerces to an empty string are skipped without
152
- * counting them as an attempt. The policy probe runs via `Promise.all`
153
- * so backend round-trips parallelize, but the write loop stays serial
154
- * (no transaction in v1 — concurrent writes would muddy failure
155
- * semantics).
156
- */
157
- export async function forEachAllowed(
158
- records: readonly unknown[],
159
- isAllowed: (record: unknown, index: number) => boolean | Promise<boolean>,
160
- op: (id: string, record: unknown, index: number) => Promise<void>,
161
- ): Promise<number> {
162
- const allowedFlags = await Promise.all(
163
- records.map((r, i) => isAllowed(r, i)),
164
- )
165
- let n = 0
166
- for (let i = 0; i < records.length; i++) {
167
- if (!allowedFlags[i]) continue
168
- const record = records[i]
169
- const id = String((record as { id?: unknown } | null | undefined)?.id ?? '')
170
- if (!id) continue
171
- try {
172
- await op(id, record, i)
173
- n++
174
- } catch { /* skip — agg notify shows total */ }
175
- }
176
- return n
177
- }