@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,238 +0,0 @@
1
- import { describe, it } from 'node:test'
2
- import assert from 'node:assert/strict'
3
-
4
- import { Pilotiq } from './Pilotiq.js'
5
- import { Resource } from './Resource.js'
6
- import { Global } from './Global.js'
7
- import { Page } from './Page.js'
8
- import { Form } from './elements/Form.js'
9
- import { Cluster } from './Cluster.js'
10
- import { TextField } from './fields/TextField.js'
11
- import { Heading } from './schema/Heading.js'
12
- import { defaultGlobalViewPage } from './defaultGlobalPages.js'
13
- import {
14
- resourceIndexData,
15
- resourceCreateData,
16
- resourceEditData,
17
- resourceViewData,
18
- globalEditData,
19
- globalViewData,
20
- customPageData,
21
- } from './pageData.js'
22
-
23
- interface BreadcrumbItem { label: string; url?: string }
24
- interface BreadcrumbMeta { type: string; items: BreadcrumbItem[] }
25
-
26
- function findBreadcrumbs(schema: Array<Record<string, unknown>>): BreadcrumbItem[] {
27
- const meta = schema.find(s => s['type'] === 'breadcrumbs') as BreadcrumbMeta | undefined
28
- assert.ok(meta, 'expected a breadcrumbs element on the page')
29
- return meta!.items
30
- }
31
-
32
- class Articles extends Resource {
33
- static override label = 'Articles'
34
- static override labelSingular = 'Article'
35
- static override slug = 'articles'
36
- // No record loader → resourceEditData / View fall back to the recordId
37
- // for the title; that's still valid copy and exercises the unloaded
38
- // path. (Loader-backed paths are covered separately.)
39
- static override form(form: Form): Form {
40
- return form.schema([TextField.make('title')])
41
- }
42
- }
43
-
44
- describe('Phase C breadcrumbs — resource pages', () => {
45
- it('list page emits Home / Articles with the trailing item unlinked', async () => {
46
- const panel = Pilotiq.make('My Panel').path('/admin').resources([Articles])
47
- const data = await resourceIndexData(panel, 'articles')
48
- const items = findBreadcrumbs(data!['schemaData'] as Array<Record<string, unknown>>)
49
- assert.deepEqual(items, [
50
- { label: 'My Panel', url: '/admin' },
51
- { label: 'Articles' },
52
- ])
53
- })
54
-
55
- it('Resource.breadcrumb overrides label in the resource crumb', async () => {
56
- class BlogPosts extends Resource {
57
- static override label = 'Blog Posts'
58
- static override labelSingular = 'Blog Post'
59
- static override slug = 'blog-posts'
60
- // Tighter chain — the breadcrumb reads better as just "Posts".
61
- static override breadcrumb = 'Posts'
62
- static override form(form: Form): Form { return form.schema([TextField.make('title')]) }
63
- }
64
- const panel = Pilotiq.make('My Panel').path('/admin').resources([BlogPosts])
65
- const data = await resourceCreateData(panel, 'blog-posts')
66
- const items = findBreadcrumbs(data!['schemaData'] as Array<Record<string, unknown>>)
67
- assert.deepEqual(items, [
68
- { label: 'My Panel', url: '/admin' },
69
- { label: 'Posts', url: '/admin/blog-posts' },
70
- { label: 'Create' },
71
- ])
72
- })
73
-
74
- it('create page appends a "Create" trailing item', async () => {
75
- const panel = Pilotiq.make('My Panel').path('/admin').resources([Articles])
76
- const data = await resourceCreateData(panel, 'articles')
77
- const items = findBreadcrumbs(data!['schemaData'] as Array<Record<string, unknown>>)
78
- assert.deepEqual(items, [
79
- { label: 'My Panel', url: '/admin' },
80
- { label: 'Articles', url: '/admin/articles' },
81
- { label: 'Create' },
82
- ])
83
- })
84
-
85
- it('view page renders the record title as the trailing item', async () => {
86
- class Loaded extends Articles {
87
- static override form(form: Form): Form {
88
- return form
89
- .schema([TextField.make('title')])
90
- .loadRecord(async (id) => ({ id, title: `Loaded ${id}` }))
91
- }
92
- }
93
- const panel = Pilotiq.make('My Panel').path('/admin').resources([Loaded])
94
- const data = await resourceViewData(panel, 'articles', '7')
95
- const items = findBreadcrumbs(data!['schemaData'] as Array<Record<string, unknown>>)
96
- // ViewPage doesn't run loadRecord (only edit pages do); without an
97
- // R.model the resourceViewData record is undefined → falls back to
98
- // the recordId.
99
- assert.deepEqual(items, [
100
- { label: 'My Panel', url: '/admin' },
101
- { label: 'Articles', url: '/admin/articles' },
102
- { label: '7' },
103
- ])
104
- })
105
-
106
- it('edit page links the title to the view page when registered', async () => {
107
- class Loaded extends Articles {
108
- static override form(form: Form): Form {
109
- return form
110
- .schema([TextField.make('title')])
111
- .loadRecord(async (id) => ({ id, title: `Loaded ${id}` }))
112
- }
113
- }
114
- const panel = Pilotiq.make('My Panel').path('/admin').resources([Loaded])
115
- const data = await resourceEditData(panel, 'articles', '7')
116
- const items = findBreadcrumbs(data!['schemaData'] as Array<Record<string, unknown>>)
117
- assert.deepEqual(items, [
118
- { label: 'My Panel', url: '/admin' },
119
- { label: 'Articles', url: '/admin/articles' },
120
- { label: 'Loaded 7', url: '/admin/articles/7' },
121
- { label: 'Edit' },
122
- ])
123
- })
124
-
125
- it('edit page leaves the title unlinked when the resource has no view page', async () => {
126
- class NoView extends Articles {
127
- static override pages() { return { view: undefined as never } }
128
- static override form(form: Form): Form {
129
- return form
130
- .schema([TextField.make('title')])
131
- .loadRecord(async (id) => ({ id, title: `Loaded ${id}` }))
132
- }
133
- }
134
- const panel = Pilotiq.make('My Panel').path('/admin').resources([NoView])
135
- const data = await resourceEditData(panel, 'articles', '7')
136
- const items = findBreadcrumbs(data!['schemaData'] as Array<Record<string, unknown>>)
137
- // Title rung carries no `url` — pruned ViewPage means no link.
138
- const titleRung = items[items.length - 2]!
139
- assert.equal(titleRung.label, 'Loaded 7')
140
- assert.equal(titleRung.url, undefined)
141
- assert.equal(items[items.length - 1]!.label, 'Edit')
142
- })
143
-
144
- it('inserts the cluster rung between Home and the resource', async () => {
145
- class ContentCluster extends Cluster {
146
- static override label = 'Content'
147
- static override slug = 'content'
148
- }
149
- class Clustered extends Articles {
150
- static override cluster = ContentCluster
151
- }
152
- const panel = Pilotiq.make('My Panel').path('/admin').resources([Clustered])
153
- const data = await resourceIndexData(panel, 'articles')
154
- const items = findBreadcrumbs(data!['schemaData'] as Array<Record<string, unknown>>)
155
- assert.deepEqual(items, [
156
- { label: 'My Panel', url: '/admin' },
157
- { label: 'Content', url: '/admin/content' },
158
- { label: 'Articles' },
159
- ])
160
- })
161
- })
162
-
163
- describe('Phase C breadcrumbs — global pages', () => {
164
- class SiteSettings extends Global {
165
- static override label = 'Site Settings'
166
- static override labelSingular = 'Site Settings'
167
- static override slug = 'site-settings'
168
- static override form(form: Form): Form {
169
- return form.schema([TextField.make('siteName')])
170
- }
171
- }
172
-
173
- it('emits Home / <Global label> on the edit page', async () => {
174
- const panel = Pilotiq.make('My Panel').path('/admin').globals([SiteSettings])
175
- const data = await globalEditData(panel, 'site-settings')
176
- const items = findBreadcrumbs(data!['schemaData'] as Array<Record<string, unknown>>)
177
- assert.deepEqual(items, [
178
- { label: 'My Panel', url: '/admin' },
179
- { label: 'Site Settings' },
180
- ])
181
- })
182
-
183
- it('emits the same chain on the view page', async () => {
184
- class WithView extends SiteSettings {
185
- static override pages() {
186
- return { view: defaultGlobalViewPage(this as unknown as typeof Global) }
187
- }
188
- }
189
- const panel = Pilotiq.make('My Panel').path('/admin').globals([WithView])
190
- const data = await globalViewData(panel, 'site-settings')
191
- const items = findBreadcrumbs(data!['schemaData'] as Array<Record<string, unknown>>)
192
- assert.deepEqual(items, [
193
- { label: 'My Panel', url: '/admin' },
194
- { label: 'Site Settings' },
195
- ])
196
- })
197
- })
198
-
199
- describe('Phase C breadcrumbs — custom pages', () => {
200
- it('emits Home / <Page label>', async () => {
201
- class Reports extends Page {
202
- static override slug = 'reports'
203
- static override label = 'Reports'
204
- static override schema() { return [Heading.make('Reports')] }
205
- }
206
- const panel = Pilotiq.make('My Panel').path('/admin').pages([Reports])
207
- const data = await customPageData(panel, 'reports')
208
- const items = findBreadcrumbs(data!['schemaData'] as Array<Record<string, unknown>>)
209
- assert.deepEqual(items, [
210
- { label: 'My Panel', url: '/admin' },
211
- { label: 'Reports' },
212
- ])
213
- })
214
-
215
- it('a single-rung chain (only Home) is suppressed entirely', async () => {
216
- // Constructing a panel with only the dashboard page never triggers
217
- // breadcrumbs at all (we don't prepend on the dashboard). Used as
218
- // sanity that a "Home" rung alone doesn't render.
219
- const panel = Pilotiq.make('My Panel').path('/admin').schema([Heading.make('Hi')])
220
- const data = await import('./pageData.js').then(m => m.dashboardData(panel))
221
- const schema = data['schemaData'] as Array<Record<string, unknown>>
222
- const meta = schema.find(s => s['type'] === 'breadcrumbs')
223
- assert.equal(meta, undefined, 'dashboard page should never carry breadcrumbs')
224
- })
225
- })
226
-
227
- describe('Phase C breadcrumbs — branding fallback', () => {
228
- it('uses branding.title when set', async () => {
229
- const panel = Pilotiq.make('My Panel')
230
- .path('/admin')
231
- .branding({ title: 'Acme Admin' })
232
- .resources([Articles])
233
- const data = await resourceIndexData(panel, 'articles')
234
- const items = findBreadcrumbs(data!['schemaData'] as Array<Record<string, unknown>>)
235
- assert.equal(items[0]!.label, 'Acme Admin')
236
- assert.equal(items[0]!.url, '/admin')
237
- })
238
- })
@@ -1,85 +0,0 @@
1
- import { describe, it } from 'node:test'
2
- import assert from 'node:assert/strict'
3
-
4
- import { TextInputColumn, ToggleColumn, SelectColumn } from '../columns/index.js'
5
- import { coerceCellValue, CellCoerceError } from './coerce.js'
6
-
7
- describe('coerceCellValue — TextInputColumn', () => {
8
- it('passes string values through unchanged for type=text', () => {
9
- const col = TextInputColumn.make('title')
10
- assert.equal(coerceCellValue(col, 'hello'), 'hello')
11
- assert.equal(coerceCellValue(col, ''), '')
12
- })
13
-
14
- it('coerces numeric input to JS number when type=number', () => {
15
- const col = TextInputColumn.make('price').type('number')
16
- assert.equal(coerceCellValue(col, '42'), 42)
17
- assert.equal(coerceCellValue(col, '3.14'), 3.14)
18
- assert.equal(coerceCellValue(col, 7), 7)
19
- })
20
-
21
- it('returns null for empty number input (clear semantic)', () => {
22
- const col = TextInputColumn.make('price').type('number')
23
- assert.equal(coerceCellValue(col, ''), null)
24
- assert.equal(coerceCellValue(col, null), null)
25
- })
26
-
27
- it('throws CellCoerceError for non-numeric strings on type=number', () => {
28
- const col = TextInputColumn.make('price').type('number')
29
- assert.throws(() => coerceCellValue(col, 'abc'), CellCoerceError)
30
- })
31
-
32
- it('survives null for non-numeric text input (cell cleared)', () => {
33
- const col = TextInputColumn.make('title')
34
- assert.equal(coerceCellValue(col, null), null)
35
- })
36
- })
37
-
38
- describe('coerceCellValue — ToggleColumn', () => {
39
- it('accepts native booleans verbatim', () => {
40
- const col = ToggleColumn.make('featured')
41
- assert.equal(coerceCellValue(col, true), true)
42
- assert.equal(coerceCellValue(col, false), false)
43
- })
44
-
45
- it('parses stringified truthy / falsy markers', () => {
46
- const col = ToggleColumn.make('featured')
47
- assert.equal(coerceCellValue(col, 'true'), true)
48
- assert.equal(coerceCellValue(col, '1'), true)
49
- assert.equal(coerceCellValue(col, 'on'), true)
50
- assert.equal(coerceCellValue(col, 'false'), false)
51
- assert.equal(coerceCellValue(col, '0'), false)
52
- assert.equal(coerceCellValue(col, ''), false)
53
- })
54
-
55
- it('coerces numbers via !==0 like the JS truthiness rule', () => {
56
- const col = ToggleColumn.make('featured')
57
- assert.equal(coerceCellValue(col, 1), true)
58
- assert.equal(coerceCellValue(col, 0), false)
59
- })
60
- })
61
-
62
- describe('coerceCellValue — SelectColumn', () => {
63
- it('returns the value unchanged when it matches an option', () => {
64
- const col = SelectColumn.make('status').options({ draft: 'Draft', published: 'Published' })
65
- assert.equal(coerceCellValue(col, 'draft'), 'draft')
66
- assert.equal(coerceCellValue(col, 'published'), 'published')
67
- })
68
-
69
- it('throws on values not in the option set', () => {
70
- const col = SelectColumn.make('status').options({ draft: 'Draft' })
71
- assert.throws(() => coerceCellValue(col, 'forged'), CellCoerceError)
72
- })
73
-
74
- it('rejects empty / null when the column is NOT nullable', () => {
75
- const col = SelectColumn.make('status').options({ draft: 'Draft' })
76
- assert.throws(() => coerceCellValue(col, null), CellCoerceError)
77
- assert.throws(() => coerceCellValue(col, ''), CellCoerceError)
78
- })
79
-
80
- it('returns null for empty / null when the column IS nullable', () => {
81
- const col = SelectColumn.make('status').options({ draft: 'Draft' }).nullable()
82
- assert.equal(coerceCellValue(col, null), null)
83
- assert.equal(coerceCellValue(col, ''), null)
84
- })
85
- })
@@ -1,84 +0,0 @@
1
- import type { Column } from '../Column.js'
2
- import type { TextInputColumn } from '../columns/TextInputColumn.js'
3
- import type { SelectColumn } from '../columns/SelectColumn.js'
4
-
5
- /**
6
- * Coerce a raw `_cell` PATCH body value into the right shape for the
7
- * given column. JSON / urlencoded bodies arrive as strings; this is the
8
- * single place we normalize them before validators run + before the
9
- * value lands in `R.model.update(id, { [col]: value })`.
10
- *
11
- * Throws when a `'number'` text input receives a non-numeric string —
12
- * the route handler maps the throw to a 422 with a friendly message
13
- * (mirrors how form-level coerce surfaces invalid numeric inputs).
14
- *
15
- * coerceCellValue(textInputCol, '42') → 42 when type='number'
16
- * coerceCellValue(textInputCol, '') → ''
17
- * coerceCellValue(toggleCol, 'true') → true
18
- * coerceCellValue(toggleCol, 1) → true
19
- * coerceCellValue(selectCol, 'draft') → 'draft'
20
- * coerceCellValue(selectCol, null) → null (when nullable)
21
- */
22
- export function coerceCellValue(col: Column, raw: unknown): unknown {
23
- switch (col.getColumnType()) {
24
- case 'textInput': {
25
- const t = (col as TextInputColumn).getInputType()
26
- if (t === 'number') {
27
- if (raw === null || raw === '' || raw === undefined) return null
28
- const n = typeof raw === 'number' ? raw : Number(String(raw).trim())
29
- if (Number.isNaN(n)) {
30
- throw new CellCoerceError('Must be a number')
31
- }
32
- return n
33
- }
34
- // text / email / url / tel — always a string. `null` survives so
35
- // a nullable column can be cleared from the cell.
36
- if (raw === null || raw === undefined) return null
37
- return typeof raw === 'string' ? raw : String(raw)
38
- }
39
- case 'toggle': {
40
- // Accept boolean, number, and the common string truthy markers
41
- // ('true', '1', 'on'). Falsy strings ('', 'false', '0') → false.
42
- if (typeof raw === 'boolean') return raw
43
- if (typeof raw === 'number') return raw !== 0
44
- if (typeof raw === 'string') {
45
- const v = raw.toLowerCase().trim()
46
- if (v === 'true' || v === '1' || v === 'on' || v === 'yes') return true
47
- if (v === 'false' || v === '0' || v === 'off' || v === 'no' || v === '') return false
48
- }
49
- return Boolean(raw)
50
- }
51
- case 'select': {
52
- // Validate against the configured option set so a forged body
53
- // can't write an arbitrary string. `null` is accepted only when
54
- // the column was marked `.nullable()`.
55
- const sel = col as SelectColumn
56
- const opts = sel.getOptions()
57
- if (raw === null || raw === '' || raw === undefined) {
58
- // `selectNullable` is internal to SelectColumn — re-derive from
59
- // toMeta so we don't have to expose a getter.
60
- const meta = sel.toMeta()
61
- if (meta.selectNullable) return null
62
- throw new CellCoerceError('A value is required')
63
- }
64
- const value = String(raw)
65
- if (!opts.some(o => o.value === value)) {
66
- throw new CellCoerceError(`"${value}" is not a valid option`)
67
- }
68
- return value
69
- }
70
- default:
71
- // Read-only columns can't reach the route (the handler 400s on
72
- // `!col.isEditable()`), but stay defensive — return raw verbatim.
73
- return raw
74
- }
75
- }
76
-
77
- /** Thrown by `coerceCellValue` when the raw value doesn't fit the column.
78
- * The route handler catches this and replies with 422 + the message. */
79
- export class CellCoerceError extends Error {
80
- constructor(message: string) {
81
- super(message)
82
- this.name = 'CellCoerceError'
83
- }
84
- }
@@ -1,35 +0,0 @@
1
- import type { ResourceClass } from './Resource.js'
2
- import type { GlobalClass } from './Global.js'
3
- import type { ClusterClass } from './Cluster.js'
4
- import type { Page } from './Page.js'
5
-
6
- // Lives in its own module so Resource / Global / Page can import the
7
- // helpers without dragging in Cluster.ts and tripping a cycle.
8
-
9
- interface ClusterableChild {
10
- cluster?: ClusterClass
11
- getSlug(): string
12
- }
13
-
14
- function childBasePath(panelBase: string, child: ClusterableChild): string {
15
- const slug = child.getSlug()
16
- return child.cluster
17
- ? `${panelBase}/${child.cluster.getSlug()}/${slug}`
18
- : `${panelBase}/${slug}`
19
- }
20
-
21
- export function resourceBasePath(panelBase: string, R: ResourceClass): string {
22
- return childBasePath(panelBase, R)
23
- }
24
-
25
- export function globalBasePath(panelBase: string, G: GlobalClass): string {
26
- return childBasePath(panelBase, G)
27
- }
28
-
29
- export function pageBasePath(panelBase: string, P: typeof Page): string {
30
- return childBasePath(panelBase, P)
31
- }
32
-
33
- export function clusterBasePath(panelBase: string, C: ClusterClass): string {
34
- return `${panelBase}/${C.getSlug()}`
35
- }
@@ -1,54 +0,0 @@
1
- import { describe, it } from 'node:test'
2
- import assert from 'node:assert/strict'
3
-
4
- import { BadgeColumn } from './BadgeColumn.js'
5
-
6
- describe('BadgeColumn', () => {
7
- it('emits columnType:badge with the value→color map', () => {
8
- const meta = BadgeColumn.make('status')
9
- .colors({ draft: 'gray', published: 'success', archived: 'warning' })
10
- .toMeta()
11
- assert.equal(meta.columnType, 'badge')
12
- assert.deepEqual(meta.badgeColors, {
13
- draft: 'gray', published: 'success', archived: 'warning',
14
- })
15
- })
16
-
17
- it('omits badgeColors when no map is set', () => {
18
- const meta = BadgeColumn.make('status').toMeta()
19
- assert.equal(meta.columnType, 'badge')
20
- assert.equal(meta.badgeColors, undefined)
21
- })
22
-
23
- it('inherits all base column builders', () => {
24
- const meta = BadgeColumn.make('status').sortable().tooltip('Status').toMeta()
25
- assert.equal(meta.sortable, true)
26
- assert.equal(meta.tooltip, 'Status')
27
- })
28
-
29
- it('successive .colors() calls merge instead of replace', () => {
30
- const meta = BadgeColumn.make('status')
31
- .colors({ draft: 'gray' })
32
- .colors({ published: 'success' })
33
- .toMeta()
34
- assert.deepEqual(meta.badgeColors, { draft: 'gray', published: 'success' })
35
- })
36
-
37
- it('later keys win on collision', () => {
38
- const meta = BadgeColumn.make('status')
39
- .colors({ pending: 'gray' })
40
- .colors({ pending: 'warning' })
41
- .toMeta()
42
- assert.equal(meta.badgeColors?.['pending'], 'warning')
43
- })
44
-
45
- it('composes with formatStateUsing for server-side label rewrites', () => {
46
- const col = BadgeColumn.make('status')
47
- .colors({ draft: 'gray' })
48
- .formatStateUsing((v) => `[${v}]`)
49
- const meta = col.toMeta()
50
- assert.equal(meta.columnType, 'badge')
51
- assert.equal(meta.hasFormatter, true)
52
- assert.deepEqual(meta.badgeColors, { draft: 'gray' })
53
- })
54
- })
@@ -1,32 +0,0 @@
1
- import { Column, type ColumnMeta } from '../Column.js'
2
-
3
- /** Badge color preset → tailwind class group. Resolved client-side. */
4
- export type BadgeColor =
5
- | 'gray' | 'primary' | 'success' | 'warning' | 'destructive' | 'info'
6
-
7
- /**
8
- * Renders the cell value as a colored pill / chip. Use a value→color map
9
- * to assign different presets per status: e.g. drafts grey, published
10
- * green, archived amber. Unknown values fall back to `gray`.
11
- */
12
- export class BadgeColumn extends Column {
13
- protected _colors: Record<string, BadgeColor> = {}
14
-
15
- static override make(name: string): BadgeColumn {
16
- const c = new BadgeColumn(name)
17
- c.setColumnType('badge')
18
- return c
19
- }
20
-
21
- /** value-to-color map. */
22
- colors(map: Record<string, BadgeColor>): this {
23
- this._colors = { ...this._colors, ...map }
24
- return this
25
- }
26
-
27
- protected override serializeExtras(meta: ColumnMeta): void {
28
- if (Object.keys(this._colors).length > 0) {
29
- meta.badgeColors = this._colors
30
- }
31
- }
32
- }
@@ -1,41 +0,0 @@
1
- import { describe, it } from 'node:test'
2
- import assert from 'node:assert/strict'
3
-
4
- import { BooleanColumn } from './BooleanColumn.js'
5
- import { IconColumn } from './IconColumn.js'
6
-
7
- describe('BooleanColumn', () => {
8
- it('extends IconColumn with default true/false icons', () => {
9
- const meta = BooleanColumn.make('featured').toMeta()
10
- assert.equal(meta.columnType, 'boolean')
11
- assert.equal(meta.iconOptions?.['true']?.icon, 'check-circle-2')
12
- assert.equal(meta.iconOptions?.['true']?.color, 'success')
13
- assert.equal(meta.iconOptions?.['false']?.icon, 'circle')
14
- assert.equal(meta.iconOptions?.['false']?.color, 'muted')
15
- })
16
-
17
- it('options() override the defaults', () => {
18
- const meta = BooleanColumn.make('active')
19
- .options({
20
- true: { icon: 'check', color: 'success' },
21
- false: { icon: 'x', color: 'muted' },
22
- })
23
- .toMeta()
24
- assert.equal(meta.iconOptions?.['true']?.icon, 'check')
25
- assert.equal(meta.iconOptions?.['false']?.icon, 'x')
26
- })
27
-
28
- it('is structurally an IconColumn', () => {
29
- const c = BooleanColumn.make('featured')
30
- assert.equal(c instanceof IconColumn, true)
31
- })
32
-
33
- it('inherits the cosmetic chain', () => {
34
- const meta = BooleanColumn.make('on')
35
- .alignment('center')
36
- .tooltip('On / off')
37
- .toMeta()
38
- assert.equal(meta.alignment, 'center')
39
- assert.equal(meta.tooltip, 'On / off')
40
- })
41
- })
@@ -1,18 +0,0 @@
1
- import { IconColumn } from './IconColumn.js'
2
-
3
- /**
4
- * Sugar over `IconColumn` that defaults to a check / x rendering for
5
- * boolean values. Override the icons / colors via `.options()` if the
6
- * defaults don't fit.
7
- */
8
- export class BooleanColumn extends IconColumn {
9
- static override make(name: string): BooleanColumn {
10
- const c = new BooleanColumn(name)
11
- c.setColumnType('boolean')
12
- c.options({
13
- true: { icon: 'check-circle-2', color: 'success' },
14
- false: { icon: 'circle', color: 'muted' },
15
- })
16
- return c
17
- }
18
- }
@@ -1,37 +0,0 @@
1
- import { describe, it } from 'node:test'
2
- import assert from 'node:assert/strict'
3
-
4
- import { ColorColumn } from './ColorColumn.js'
5
-
6
- describe('ColorColumn', () => {
7
- it('emits columnType:color with the default rounded shape', () => {
8
- const meta = ColorColumn.make('accent').toMeta()
9
- assert.equal(meta.columnType, 'color')
10
- assert.equal(meta.colorShape, 'rounded')
11
- assert.equal(meta.colorHideValue, undefined)
12
- })
13
-
14
- it('square() flips the shape', () => {
15
- const meta = ColorColumn.make('accent').square().toMeta()
16
- assert.equal(meta.colorShape, 'square')
17
- })
18
-
19
- it('circle() flips the shape', () => {
20
- const meta = ColorColumn.make('accent').circle().toMeta()
21
- assert.equal(meta.colorShape, 'circle')
22
- })
23
-
24
- it('hideValue() emits the suppress flag', () => {
25
- const meta = ColorColumn.make('accent').hideValue().toMeta()
26
- assert.equal(meta.colorHideValue, true)
27
- })
28
-
29
- it('inherits alignment / tooltip chain from Column', () => {
30
- const meta = ColorColumn.make('accent')
31
- .alignment('center')
32
- .tooltip('Brand color')
33
- .toMeta()
34
- assert.equal(meta.alignment, 'center')
35
- assert.equal(meta.tooltip, 'Brand color')
36
- })
37
- })
@@ -1,38 +0,0 @@
1
- import { Column, type ColumnMeta } from '../Column.js'
2
-
3
- /**
4
- * Renders the cell as a color swatch — pairs with `ColorPickerField`.
5
- * The raw cell value is treated as a CSS color string (HEX, HSL, RGB,
6
- * RGBA, named) and applied as the swatch's `background-color`. The
7
- * accompanying value text is shown beside the swatch unless
8
- * `hideValue()` is set.
9
- *
10
- * ColorColumn.make('accent')
11
- * .square() // shape; default is `rounded()`
12
- * .hideValue() // chip only
13
- */
14
- export class ColorColumn extends Column {
15
- protected _shape: 'rounded' | 'square' | 'circle' = 'rounded'
16
- protected _hideValue: boolean = false
17
-
18
- static override make(name: string): ColorColumn {
19
- const c = new ColorColumn(name)
20
- c.setColumnType('color')
21
- return c
22
- }
23
-
24
- /** Default — slightly rounded swatch. */
25
- rounded(): this { this._shape = 'rounded'; return this }
26
- /** Sharp-cornered swatch. */
27
- square(): this { this._shape = 'square'; return this }
28
- /** Circle swatch. */
29
- circle(): this { this._shape = 'circle'; return this }
30
-
31
- /** Drop the value text — render only the swatch. */
32
- hideValue(v = true): this { this._hideValue = v; return this }
33
-
34
- protected override serializeExtras(meta: ColumnMeta): void {
35
- meta.colorShape = this._shape
36
- if (this._hideValue) meta.colorHideValue = true
37
- }
38
- }