@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,578 +0,0 @@
1
- import type { Pilotiq } from '../Pilotiq.js'
2
- import type { Page } from '../Page.js'
3
- import { Element } from '../schema/Element.js'
4
- import { resolveSchema, type SchemaContext, type RenderContext } from '../schema/resolveSchema.js'
5
- import { Form } from '../elements/Form.js'
6
- import { applyStateUpdate, coerceFormValues, findForms, findWizardStep, selectFormById } from '../elements/dispatchForm.js'
7
- import { findRecord } from '../orm/modelDefaults.js'
8
- import { isRepeaterField, RepeaterField } from '../fields/RepeaterField.js'
9
- import { isBuilderField, BuilderField } from '../fields/BuilderField.js'
10
- import { SelectField } from '../fields/SelectField.js'
11
- import { validateSchema } from '../validation/index.js'
12
- import { callPageSchema, uploadCtx, userCtx } from './helpers.js'
13
-
14
- // ─── Shared scope → page+form+record resolver ────────────────
15
- //
16
- // Every form-subresource builder (`formStateData / formWizardData /
17
- // formCreateOptionData / mentionResolveData`) needs to: resolve the
18
- // `FormStateScope` to a concrete `PageClass`, build the upload/user-aware
19
- // `SchemaContext`, call the page's `schema()`, and pick the requested form
20
- // by id. `resolveScopeForm` does that whole prelude in one async step.
21
-
22
- interface ResolveScopeFormSuccess {
23
- ok: true
24
- PageClass: typeof Page
25
- baseCtx: SchemaContext
26
- elements: Element[]
27
- form: Form
28
- record: unknown
29
- mode: 'create' | 'edit'
30
- }
31
-
32
- interface ResolveScopeFormFormMissing {
33
- ok: false
34
- status: 404
35
- error: string
36
- }
37
-
38
- /**
39
- * Resolve `FormStateScope` → `{ PageClass, baseCtx, elements, form, record, mode }`.
40
- *
41
- * Returns `null` when the scope's slug doesn't resolve to a real
42
- * resource/global/page or the matching page-role (`create`/`edit`) isn't
43
- * registered — caller returns 404 to the client. Returns
44
- * `{ ok: false, status: 404, error }` when the page resolves but the
45
- * requested `formId` isn't on it.
46
- */
47
- async function resolveScopeForm(
48
- pilotiq: Pilotiq,
49
- scope: FormStateScope,
50
- formId: string,
51
- user: unknown,
52
- ): Promise<ResolveScopeFormSuccess | ResolveScopeFormFormMissing | null> {
53
- const cfg = pilotiq.getConfig()
54
-
55
- let PageClass: typeof Page | undefined
56
- let mode: 'create' | 'edit'
57
- let record: unknown = undefined
58
- let baseCtxExtras: Record<string, unknown> = {}
59
-
60
- if (scope.kind === 'resource-create' || scope.kind === 'resource-edit') {
61
- const R = pilotiq.findResource(scope.slug)
62
- if (!R) return null
63
- const pages = R.resolvePages()
64
- if (scope.kind === 'resource-create') {
65
- if (!pages.create) return null
66
- PageClass = pages.create
67
- mode = 'create'
68
- } else {
69
- if (!pages.edit) return null
70
- PageClass = pages.edit
71
- mode = 'edit'
72
- baseCtxExtras = { recordId: scope.recordId }
73
- if (R.model) {
74
- try { record = await findRecord(R, scope.recordId, { user }) } catch { /* ignore */ }
75
- } else {
76
- record = { id: scope.recordId }
77
- }
78
- }
79
- } else if (scope.kind === 'global-edit') {
80
- const G = pilotiq.findGlobal(scope.slug)
81
- if (!G) return null
82
- const pages = G.resolvePages()
83
- if (!pages.edit) return null
84
- PageClass = pages.edit
85
- mode = 'edit'
86
- } else {
87
- const P = pilotiq.findPage(scope.pageSlug)
88
- if (!P) return null
89
- PageClass = P
90
- // Custom pages don't have a record/edit-mode concept — pass mode
91
- // 'edit' so resolveSchema treats fields as form inputs (not table
92
- // cells / view-mode read-only).
93
- mode = 'edit'
94
- }
95
-
96
- const baseCtx: SchemaContext = uploadCtx(userCtx({ mode, basePath: cfg.path, ...baseCtxExtras }, user), cfg)
97
- const elements = await callPageSchema(PageClass, baseCtx)
98
- const form = selectFormById(findForms(elements), formId)
99
- if (!form) return { ok: false, status: 404, error: `Form "${formId}" not found on page` }
100
-
101
- return { ok: true, PageClass, baseCtx, elements, form, record, mode }
102
- }
103
-
104
- // ─── Form-related data builders ─────────────────────────────
105
- //
106
- // Plan #5 partial-resolve (formStateData), Plan #8 wizard step-validate
107
- // (formWizardData), inline-create-option (formCreateOptionData), and
108
- // async-mention resolve (mentionResolveData). All four sit downstream
109
- // of `resolveSchema` and re-run the form lifecycle in narrower modes
110
- // (just the changed field; just the requested step; etc.).
111
-
112
-
113
- // ─── Plan #5 partial-resolve data builder ────────────────────
114
-
115
- export type FormStateScope =
116
- | { kind: 'resource-create'; slug: string }
117
- | { kind: 'resource-edit'; slug: string; recordId: string }
118
- | { kind: 'global-edit'; slug: string }
119
- | { kind: 'page'; pageSlug: string }
120
-
121
- export interface FormStateRequest {
122
- formId: string
123
- changed: string
124
- values: Record<string, unknown>
125
- }
126
-
127
- export interface FormStateResult {
128
- ok: true
129
- form: Record<string, unknown> // resolved FormMeta
130
- dirty: string[]
131
- }
132
-
133
- export interface FormStateError {
134
- ok: false
135
- status: 404 | 422
136
- error: string
137
- }
138
-
139
- /**
140
- * Plan #5 — handle a partial-resolve roundtrip from a `live()` field.
141
- *
142
- * Locates the page's schema, finds the targeted form by `formId`, runs
143
- * `applyStateUpdate` to apply the changed value + run
144
- * `afterStateUpdated`, then re-resolves the form's children with the
145
- * mutated values + bound `$get / $set` so dependent options /
146
- * conditional visibility re-evaluate. Returns the resolved FormMeta the
147
- * client uses to replace its rendered form.
148
- *
149
- * Returns `null` when the route prefix doesn't resolve to a real
150
- * resource/global/page — the route handler turns this into a 404. The
151
- * inner `{ status: 422 }` failure is for "form found but `changed`
152
- * field doesn't exist on it" — also a client-side bug.
153
- */
154
- export async function formStateData(
155
- pilotiq: Pilotiq,
156
- scope: FormStateScope,
157
- body: FormStateRequest,
158
- req?: unknown,
159
- ): Promise<FormStateResult | FormStateError | null> {
160
- const user = await pilotiq.resolveUser(req)
161
- const loaded = await resolveScopeForm(pilotiq, scope, body.formId, user)
162
- if (!loaded) return null
163
- if (!loaded.ok) return loaded
164
- const { baseCtx, form, record } = loaded
165
-
166
- const update = await applyStateUpdate(form, body.values, body.changed, {
167
- ...(record !== undefined ? { record } : {}),
168
- ...(user !== null ? { user } : {}),
169
- request: req,
170
- })
171
- if (!update) {
172
- return { ok: false, status: 422, error: `Field "${body.changed}" not found on form "${body.formId}"` }
173
- }
174
-
175
- // Re-resolve the form with the mutated values bound. We bind
176
- // `$get / $set` against the post-update values map so further
177
- // resolve-time logic (SelectField.options(fn), reactive
178
- // visibility) reads current state.
179
- const $get = (name: string): unknown => update.values[name]
180
- // $set on the resolve pass is a no-op — only afterStateUpdated
181
- // mutations survive into the response. Resolve-time `$set` would
182
- // race against the client's view of the world.
183
- const $set = (_name: string, _v: unknown): void => { /* intentional no-op */ }
184
-
185
- const resolveCtx = {
186
- ...baseCtx,
187
- values: update.values,
188
- $get,
189
- $set,
190
- changed: body.changed,
191
- ...(record !== undefined ? { record } : {}),
192
- }
193
- // Snapshot values onto the form so its FormMeta carries them.
194
- form.withValues(update.values)
195
- const resolved = await resolveSchema([form], resolveCtx)
196
- const formMeta = resolved[0]
197
- if (!formMeta || formMeta.type !== 'form') {
198
- return { ok: false, status: 422, error: 'Form re-resolved to non-form meta' }
199
- }
200
-
201
- return { ok: true, form: formMeta, dirty: update.dirty }
202
- }
203
-
204
- // ─── Plan #8 wizard step-validate data builder ────────────────
205
-
206
- export interface FormWizardRequest {
207
- formId: string
208
- step: number
209
- values: Record<string, unknown>
210
- }
211
-
212
- export interface FormWizardSuccess {
213
- ok: true
214
- }
215
-
216
- export interface FormWizardFailure {
217
- ok: false
218
- status: 404 | 422
219
- error?: string
220
- errors?: Record<string, string[]>
221
- }
222
-
223
- /**
224
- * Plan #8 — handle a Wizard step-validate POST. Locates the form by id,
225
- * walks to the Wizard descendant, validates only the fields inside step
226
- * `step` against `values`. Returns `{ ok: true }` on success or
227
- * `{ ok: false, status: 422, errors }` when fields fail validation.
228
- *
229
- * Errors are keyed by field name, same shape as the form-submit 422 path,
230
- * so the client (`FormStateApi.applyErrors`) can surface them in-place.
231
- */
232
- export async function formWizardData(
233
- pilotiq: Pilotiq,
234
- scope: FormStateScope,
235
- body: FormWizardRequest,
236
- req?: unknown,
237
- ): Promise<FormWizardSuccess | FormWizardFailure | null> {
238
- const user = await pilotiq.resolveUser(req)
239
- const loaded = await resolveScopeForm(pilotiq, scope, body.formId, user)
240
- if (!loaded) return null
241
- if (!loaded.ok) return loaded
242
- const { form, record } = loaded
243
-
244
- const formChildren = form.getChildren() ?? []
245
- const step = findWizardStep(formChildren, body.step)
246
- if (!step) return { ok: false, status: 404, error: `Step ${body.step} not found on form "${body.formId}"` }
247
-
248
- // Step.beforeValidation — runs before validators. May mutate `body.values`
249
- // in place (the validator reads from the same object), or throw to halt
250
- // with a 422 stamped under the reserved `_step` key.
251
- type StepHook = (values: Record<string, unknown>, ctx: { record?: unknown; user?: unknown }) => void | Promise<void>
252
- const stepHooks = step as {
253
- getBeforeValidation?: () => StepHook | undefined
254
- getAfterValidation?: () => StepHook | undefined
255
- }
256
- const beforeHook = stepHooks.getBeforeValidation?.call(step)
257
- if (beforeHook) {
258
- try { await beforeHook(body.values, { record, user }) }
259
- catch (err) {
260
- return { ok: false, status: 422, errors: { _step: [stepHookErrorMessage(err)] } }
261
- }
262
- }
263
-
264
- const errors = await validateSchema(step.getChildren() ?? [], body.values, record)
265
- if (Object.keys(errors).length > 0) {
266
- return { ok: false, status: 422, errors }
267
- }
268
-
269
- // Step.afterValidation — fires only when validators pass. Same throw →
270
- // 422 contract as beforeValidation.
271
- const afterHook = stepHooks.getAfterValidation?.call(step)
272
- if (afterHook) {
273
- try { await afterHook(body.values, { record, user }) }
274
- catch (err) {
275
- return { ok: false, status: 422, errors: { _step: [stepHookErrorMessage(err)] } }
276
- }
277
- }
278
-
279
- return { ok: true }
280
- }
281
-
282
- function stepHookErrorMessage(err: unknown): string {
283
- if (err instanceof Error && err.message) return err.message
284
- if (typeof err === 'string' && err.length > 0) return err
285
- return 'Step validation failed'
286
- }
287
-
288
- // ─── SelectField inline-create-option data builder ───────────
289
-
290
- export interface FormCreateOptionRequest {
291
- formId: string
292
- fieldName: string
293
- values: Record<string, unknown>
294
- }
295
-
296
- export interface FormCreateOptionSuccess {
297
- ok: true
298
- option: { value: string; label: string }
299
- }
300
-
301
- export interface FormCreateOptionFailure {
302
- ok: false
303
- status: 403 | 404 | 422 | 500
304
- error?: string
305
- errors?: Record<string, string[]>
306
- }
307
-
308
- /** Find a `SelectField` by name inside a form's children, walking through
309
- * layout containers but stopping at Repeater / Builder boundaries
310
- * (parallel to `tagSelectCreateOptionUrls`'s walker). Returns the first
311
- * match or `undefined`. */
312
- function findSelectFieldByName(elements: Element[], name: string): SelectField | undefined {
313
- for (const el of elements) {
314
- if (el instanceof SelectField) {
315
- if (el.name === name) return el
316
- continue
317
- }
318
- if (el instanceof RepeaterField) continue
319
- if (el instanceof BuilderField) continue
320
- const children = el.getChildren()
321
- if (children && children.length > 0) {
322
- const found = findSelectFieldByName(children as Element[], name)
323
- if (found) return found
324
- }
325
- }
326
- return undefined
327
- }
328
-
329
- /**
330
- * Audit row 2026-05-07 cont'd⁸ — handle a `SelectField.createOptionForm()`
331
- * modal submit. Locates the parent form by `formId`, finds the SelectField
332
- * by `fieldName`, re-evaluates the `createOptionAuthorize` rule (so a
333
- * tampered URL can't bypass), coerces + validates the body against the
334
- * sub-form's fields, then calls `createOptionUsing(handler)` and returns
335
- * `{ option }` for the client to append + select.
336
- *
337
- * Returns `null` when the route prefix doesn't resolve to a real
338
- * resource/global/page (route handler turns into 404).
339
- */
340
- export async function formCreateOptionData(
341
- pilotiq: Pilotiq,
342
- scope: FormStateScope,
343
- body: FormCreateOptionRequest,
344
- req?: unknown,
345
- ): Promise<FormCreateOptionSuccess | FormCreateOptionFailure | null> {
346
- const user = await pilotiq.resolveUser(req)
347
- const loaded = await resolveScopeForm(pilotiq, scope, body.formId, user)
348
- if (!loaded) return null
349
- if (!loaded.ok) return loaded
350
- const { baseCtx, form, record } = loaded
351
-
352
- const field = findSelectFieldByName(form.getChildren() as Element[] ?? [], body.fieldName)
353
- if (!field) return { ok: false, status: 404, error: `SelectField "${body.fieldName}" not found on form "${body.formId}"` }
354
- if (!field.hasCreateOption()) return { ok: false, status: 404, error: `SelectField "${body.fieldName}" does not configure createOptionForm()` }
355
-
356
- const createForm = field.getCreateOptionForm()!
357
- const handler = field.getCreateOptionHandler()
358
- if (!handler) {
359
- return { ok: false, status: 500, error: `SelectField "${body.fieldName}" has createOptionForm() but no createOptionUsing() handler` }
360
- }
361
-
362
- // Re-evaluate authorize. Build the same ActionVisibilityContext shape
363
- // the field's `toMeta` did — keeps server / meta-build paths consistent.
364
- const authorize = field.getCreateOptionAuthorize()
365
- if (authorize !== undefined) {
366
- const authVisible = await (async () => {
367
- if (typeof authorize !== 'function') return authorize
368
- const visCtx: import('../actions/Action.js').ActionVisibilityContext = {}
369
- if (record !== undefined) visCtx.record = record
370
- if (user !== null ) visCtx.user = user
371
- try { return await authorize(visCtx) } catch { return false }
372
- })()
373
- if (!authVisible) return { ok: false, status: 403, error: 'createOptionAuthorize denied' }
374
- }
375
-
376
- // Coerce + validate body against the sub-form's fields. The createOption
377
- // sub-schema is detached from the parent form so we run it against its
378
- // own children only — coerceFormValues mutates `out` to normalize toggle
379
- // / number / date / etc. shapes (same shape parent forms use).
380
- const coerced = coerceFormValues(createForm, { ...body.values })
381
- const errors = await validateSchema(createForm, coerced, undefined)
382
- if (Object.keys(errors).length > 0) {
383
- return { ok: false, status: 422, errors }
384
- }
385
-
386
- const ctx: RenderContext = {
387
- ...baseCtx,
388
- values: coerced,
389
- ...(record !== undefined ? { record } : {}),
390
- }
391
- let option: { value: string; label: string }
392
- try {
393
- option = await handler(coerced, ctx)
394
- } catch (e) {
395
- return { ok: false, status: 500, error: e instanceof Error ? e.message : String(e) }
396
- }
397
-
398
- if (!option || typeof option.value !== 'string' || typeof option.label !== 'string') {
399
- return { ok: false, status: 500, error: `createOptionUsing must return { value: string, label: string }` }
400
- }
401
-
402
- return { ok: true, option }
403
- }
404
-
405
- // ─── Async-mention resolve data builder ──────────────────────
406
-
407
- export interface MentionResolveRequest {
408
- formId: string
409
- field: string
410
- trigger: string
411
- query: string
412
- }
413
-
414
- /** Wire-side shape for a single resolved item — mirrors `MentionItem` from
415
- * `@pilotiq/tiptap`. Pilotiq core doesn't import that package, so the
416
- * duck-typed shape lives here. */
417
- export interface MentionResolveItem {
418
- id: string
419
- label: string
420
- group?: string
421
- }
422
-
423
- export interface MentionResolveSuccess {
424
- ok: true
425
- items: MentionResolveItem[]
426
- }
427
-
428
- export interface MentionResolveError {
429
- ok: false
430
- status: 404 | 422
431
- error: string
432
- }
433
-
434
- interface AsyncMentionResolverField {
435
- resolveMention(
436
- trigger: string,
437
- query: string,
438
- ctx: { user?: unknown; record?: unknown; request?: unknown },
439
- ): Promise<MentionResolveItem[] | null>
440
- }
441
-
442
- function isMentionResolverField(el: Element): el is Element & AsyncMentionResolverField {
443
- if (el.getType() !== 'richtext') return false
444
- const candidate = el as unknown as Partial<AsyncMentionResolverField>
445
- return typeof candidate.resolveMention === 'function'
446
- }
447
-
448
- /**
449
- * Walk a form's tree looking for the named field. Descends into Repeater /
450
- * Builder rows when the requested name carries the row-prefix shape:
451
- *
452
- * - Repeater rows: `<repeaterName>.<index>.<innerPath>` — looks up
453
- * `<innerPath>` against the Repeater's template schema. Field config
454
- * (providers, async resolver) is shared across rows, so any row index
455
- * resolves to the same template field.
456
- * - Builder rows: `<builderName>.<index>.data.<innerPath>` — looks up
457
- * `<innerPath>` against every block's schema; first match wins. Block
458
- * schemas often share leaf names — if two blocks define a RichTextField
459
- * with the same name and different async-mention providers, only the
460
- * first block in declaration order is reachable here. Authors needing
461
- * per-block resolution should give the leaves distinct names.
462
- *
463
- * Mirrors the boundary-stopping posture of `findFieldByName` inside
464
- * `dispatchForm.ts` for top-level matches — only the dotted-prefix branch
465
- * crosses into row schemas.
466
- */
467
- function findRichTextFieldByName(
468
- elements: ReadonlyArray<Element>,
469
- name: string,
470
- ): (Element & AsyncMentionResolverField) | undefined {
471
- for (const el of elements) {
472
- if (isMentionResolverField(el) && (el as unknown as { name: string }).name === name) {
473
- return el
474
- }
475
- if (isRepeaterField(el)) {
476
- const inner = stripRepeaterRowPrefix(name, (el as RepeaterField).name)
477
- if (inner !== undefined) {
478
- const hit = findRichTextFieldByName((el as RepeaterField).getInnerSchema(), inner)
479
- if (hit) return hit
480
- }
481
- continue
482
- }
483
- if (isBuilderField(el)) {
484
- const inner = stripBuilderRowPrefix(name, (el as BuilderField).name)
485
- if (inner !== undefined) {
486
- for (const block of (el as BuilderField).getBlocks()) {
487
- const hit = findRichTextFieldByName(block.getSchema(), inner)
488
- if (hit) return hit
489
- }
490
- }
491
- continue
492
- }
493
- const children = el.getChildren()
494
- if (children && children.length > 0) {
495
- const hit = findRichTextFieldByName(children, name)
496
- if (hit) return hit
497
- }
498
- }
499
- return undefined
500
- }
501
-
502
- /**
503
- * `items.0.body` → `body`. Returns `undefined` when the path doesn't match
504
- * the `<repeaterName>.<digits>.<rest>` shape so the walker keeps searching
505
- * other branches instead of misinterpreting an unrelated dotted name.
506
- */
507
- function stripRepeaterRowPrefix(path: string, repeaterName: string): string | undefined {
508
- const parts = path.split('.')
509
- if (parts.length < 3) return undefined
510
- if (parts[0] !== repeaterName) return undefined
511
- if (!/^\d+$/.test(parts[1] ?? '')) return undefined
512
- return parts.slice(2).join('.')
513
- }
514
-
515
- /**
516
- * `blocks.0.data.heading` → `heading`. The literal `data` segment matches
517
- * Builder's wire shape (`{ __id, type, data: {…} }`) and distinguishes a
518
- * Builder leaf from a Repeater leaf at the same depth.
519
- */
520
- function stripBuilderRowPrefix(path: string, builderName: string): string | undefined {
521
- const parts = path.split('.')
522
- if (parts.length < 4) return undefined
523
- if (parts[0] !== builderName) return undefined
524
- if (!/^\d+$/.test(parts[1] ?? '')) return undefined
525
- if (parts[2] !== 'data') return undefined
526
- return parts.slice(3).join('.')
527
- }
528
-
529
- /**
530
- * Resolve one async-mention round-trip. Locates the page's schema, finds
531
- * the form by `formId` and the RichTextField by `field`, calls its
532
- * `resolveMention(trigger, query, ctx)`. Returns `{ ok, items }`, a 404
533
- * when the form / field / trigger isn't present, or `null` for a missing
534
- * page (the route handler turns `null` into a 404 too).
535
- *
536
- * The dispatcher is duck-typed against the contract in `@pilotiq/tiptap`'s
537
- * `RichTextField` — pilotiq core never imports the adapter. Any future
538
- * field-type that ships an async-resolve trigger can implement the same
539
- * shape and pick up routing for free.
540
- */
541
- export async function mentionResolveData(
542
- pilotiq: Pilotiq,
543
- scope: FormStateScope,
544
- body: MentionResolveRequest,
545
- req?: unknown,
546
- ): Promise<MentionResolveSuccess | MentionResolveError | null> {
547
- const user = await pilotiq.resolveUser(req)
548
- const loaded = await resolveScopeForm(pilotiq, scope, body.formId, user)
549
- if (!loaded) return null
550
- if (!loaded.ok) return loaded
551
- const { form, record } = loaded
552
-
553
- const field = findRichTextFieldByName(form.getChildren() ?? [], body.field)
554
- if (!field) {
555
- return { ok: false, status: 404, error: `Rich-text field "${body.field}" not found on form "${body.formId}"` }
556
- }
557
-
558
- let items: MentionResolveItem[] | null
559
- try {
560
- items = await field.resolveMention(body.trigger, body.query, {
561
- ...(record !== undefined ? { record } : {}),
562
- ...(user !== null ? { user } : {}),
563
- request: req,
564
- })
565
- } catch (err) {
566
- return {
567
- ok: false,
568
- status: 422,
569
- error: err instanceof Error ? err.message : 'Mention resolver threw',
570
- }
571
- }
572
-
573
- if (items === null) {
574
- return { ok: false, status: 404, error: `No mention provider for trigger "${body.trigger}" on field "${body.field}"` }
575
- }
576
-
577
- return { ok: true, items }
578
- }