@pilotiq/pilotiq 0.24.1 → 0.24.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (480) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/boost/guidelines.md +566 -0
  3. package/boost/skills/pilotiq-fields/SKILL.md +47 -0
  4. package/boost/skills/pilotiq-fields/rules/field-catalog.md +288 -0
  5. package/boost/skills/pilotiq-fields/rules/reactive-fields.md +199 -0
  6. package/boost/skills/pilotiq-fields/rules/validation.md +198 -0
  7. package/boost/skills/pilotiq-relations/SKILL.md +47 -0
  8. package/boost/skills/pilotiq-relations/rules/relation-managers.md +256 -0
  9. package/boost/skills/pilotiq-relations/rules/repeater-relationship.md +177 -0
  10. package/boost/skills/pilotiq-resource/SKILL.md +61 -0
  11. package/boost/skills/pilotiq-resource/rules/authorization.md +242 -0
  12. package/boost/skills/pilotiq-resource/rules/defining-resources.md +228 -0
  13. package/boost/skills/pilotiq-resource/rules/page-overrides.md +296 -0
  14. package/package.json +6 -1
  15. package/.turbo/turbo-build.log +0 -8
  16. package/CLAUDE.md +0 -265
  17. package/src/Cluster.test.ts +0 -283
  18. package/src/Cluster.ts +0 -83
  19. package/src/Column.test.ts +0 -199
  20. package/src/Column.ts +0 -710
  21. package/src/Global.test.ts +0 -367
  22. package/src/Global.ts +0 -169
  23. package/src/Page.test.ts +0 -114
  24. package/src/Page.ts +0 -208
  25. package/src/Pilotiq.perf.test.ts +0 -252
  26. package/src/Pilotiq.test.ts +0 -129
  27. package/src/Pilotiq.ts +0 -1158
  28. package/src/PilotiqRegistry.ts +0 -36
  29. package/src/PilotiqServiceProvider.ts +0 -121
  30. package/src/RelationManager.test.ts +0 -400
  31. package/src/RelationManager.ts +0 -527
  32. package/src/RenderHook.test.ts +0 -252
  33. package/src/RenderHook.ts +0 -242
  34. package/src/Resource.test.ts +0 -284
  35. package/src/Resource.ts +0 -526
  36. package/src/RightPanel.test.ts +0 -202
  37. package/src/RightPanel.ts +0 -132
  38. package/src/Tab.test.ts +0 -91
  39. package/src/Tab.ts +0 -156
  40. package/src/UserMenuItem.ts +0 -145
  41. package/src/actions/Action.test.ts +0 -2526
  42. package/src/actions/Action.ts +0 -1515
  43. package/src/actions/ActionGroup.test.ts +0 -112
  44. package/src/actions/ActionGroup.ts +0 -173
  45. package/src/actions/attachFactory.ts +0 -172
  46. package/src/actions/bulkFactories.ts +0 -168
  47. package/src/actions/crudFactories.ts +0 -220
  48. package/src/actions/exportFactory.ts +0 -225
  49. package/src/actions/factoryHelpers.ts +0 -177
  50. package/src/actions/importFactory.ts +0 -243
  51. package/src/actions/index.ts +0 -17
  52. package/src/actions/m2mFactories.ts +0 -193
  53. package/src/actions/relationFactories.ts +0 -372
  54. package/src/applyPageHooks.test.ts +0 -463
  55. package/src/applyPageHooks.ts +0 -330
  56. package/src/authorization.test.ts +0 -483
  57. package/src/breadcrumbs.test.ts +0 -238
  58. package/src/cells/coerce.test.ts +0 -85
  59. package/src/cells/coerce.ts +0 -84
  60. package/src/clusterPaths.ts +0 -35
  61. package/src/columns/BadgeColumn.test.ts +0 -54
  62. package/src/columns/BadgeColumn.ts +0 -32
  63. package/src/columns/BooleanColumn.test.ts +0 -41
  64. package/src/columns/BooleanColumn.ts +0 -18
  65. package/src/columns/ColorColumn.test.ts +0 -37
  66. package/src/columns/ColorColumn.ts +0 -38
  67. package/src/columns/IconColumn.test.ts +0 -54
  68. package/src/columns/IconColumn.ts +0 -37
  69. package/src/columns/ImageColumn.test.ts +0 -41
  70. package/src/columns/ImageColumn.ts +0 -28
  71. package/src/columns/SelectColumn.ts +0 -98
  72. package/src/columns/TextColumn.test.ts +0 -190
  73. package/src/columns/TextColumn.ts +0 -20
  74. package/src/columns/TextInputColumn.ts +0 -68
  75. package/src/columns/ToggleColumn.ts +0 -46
  76. package/src/columns/editableColumns.test.ts +0 -238
  77. package/src/columns/index.ts +0 -9
  78. package/src/defaultGlobalPages.ts +0 -95
  79. package/src/defaultPages.test.ts +0 -634
  80. package/src/defaultPages.ts +0 -617
  81. package/src/defaultViewPage.test.ts +0 -147
  82. package/src/elements/Form.test.ts +0 -223
  83. package/src/elements/Form.ts +0 -416
  84. package/src/elements/ListTabs.ts +0 -28
  85. package/src/elements/Table.test.ts +0 -422
  86. package/src/elements/Table.ts +0 -850
  87. package/src/elements/TableGroup.test.ts +0 -260
  88. package/src/elements/TableGroup.ts +0 -334
  89. package/src/elements/dispatchAction.test.ts +0 -463
  90. package/src/elements/dispatchAction.ts +0 -355
  91. package/src/elements/dispatchForm.test.ts +0 -477
  92. package/src/elements/dispatchForm.ts +0 -1993
  93. package/src/elements/dispatchTable.test.ts +0 -1514
  94. package/src/elements/dispatchTable.ts +0 -745
  95. package/src/elements/index.ts +0 -21
  96. package/src/entries/BadgeEntry.ts +0 -39
  97. package/src/entries/CodeEntry.test.ts +0 -40
  98. package/src/entries/CodeEntry.ts +0 -52
  99. package/src/entries/ColorEntry.ts +0 -63
  100. package/src/entries/ComponentEntry.test.ts +0 -173
  101. package/src/entries/ComponentEntry.ts +0 -95
  102. package/src/entries/Entry.ts +0 -304
  103. package/src/entries/IconEntry.ts +0 -49
  104. package/src/entries/ImageEntry.ts +0 -61
  105. package/src/entries/KeyValueEntry.ts +0 -47
  106. package/src/entries/RepeatableEntry.test.ts +0 -239
  107. package/src/entries/RepeatableEntry.ts +0 -173
  108. package/src/entries/TextEntry.test.ts +0 -394
  109. package/src/entries/TextEntry.ts +0 -60
  110. package/src/entries/index.ts +0 -12
  111. package/src/entries/leaves.test.ts +0 -306
  112. package/src/entries/registry.ts +0 -54
  113. package/src/fields/BuilderField.test.ts +0 -1188
  114. package/src/fields/BuilderField.ts +0 -605
  115. package/src/fields/BuilderRelationship.test.ts +0 -811
  116. package/src/fields/CheckboxField.test.ts +0 -44
  117. package/src/fields/CheckboxField.ts +0 -27
  118. package/src/fields/CheckboxListField.test.ts +0 -99
  119. package/src/fields/CheckboxListField.ts +0 -66
  120. package/src/fields/ColorPickerField.test.ts +0 -33
  121. package/src/fields/ColorPickerField.ts +0 -25
  122. package/src/fields/DateField.ts +0 -54
  123. package/src/fields/DateTimeField.test.ts +0 -55
  124. package/src/fields/EmailField.ts +0 -16
  125. package/src/fields/Field.test.ts +0 -654
  126. package/src/fields/Field.ts +0 -817
  127. package/src/fields/FileUploadField.test.ts +0 -143
  128. package/src/fields/FileUploadField.ts +0 -159
  129. package/src/fields/HiddenField.test.ts +0 -27
  130. package/src/fields/HiddenField.ts +0 -28
  131. package/src/fields/KeyValueField.test.ts +0 -105
  132. package/src/fields/KeyValueField.ts +0 -55
  133. package/src/fields/MarkdownField.test.ts +0 -167
  134. package/src/fields/MarkdownField.ts +0 -162
  135. package/src/fields/NumberField.ts +0 -33
  136. package/src/fields/RadioField.test.ts +0 -94
  137. package/src/fields/RadioField.ts +0 -67
  138. package/src/fields/RepeaterField.test.ts +0 -1806
  139. package/src/fields/RepeaterField.ts +0 -939
  140. package/src/fields/RepeaterRelationship.test.ts +0 -1923
  141. package/src/fields/RepeaterSimple.test.ts +0 -248
  142. package/src/fields/RowButton.test.ts +0 -219
  143. package/src/fields/RowButton.ts +0 -135
  144. package/src/fields/SelectField.test.ts +0 -192
  145. package/src/fields/SelectField.ts +0 -235
  146. package/src/fields/SliderField.test.ts +0 -50
  147. package/src/fields/SliderField.ts +0 -53
  148. package/src/fields/SlugField.ts +0 -24
  149. package/src/fields/TagsInputField.test.ts +0 -154
  150. package/src/fields/TagsInputField.ts +0 -133
  151. package/src/fields/TextField.test.ts +0 -213
  152. package/src/fields/TextField.ts +0 -177
  153. package/src/fields/TextareaField.test.ts +0 -58
  154. package/src/fields/TextareaField.ts +0 -59
  155. package/src/fields/ToggleButtonsField.test.ts +0 -106
  156. package/src/fields/ToggleButtonsField.ts +0 -59
  157. package/src/fields/ToggleField.ts +0 -16
  158. package/src/fields/disableOptionsWhenSelectedInSiblingRepeaterItems.test.ts +0 -319
  159. package/src/fields/optionsResolver.ts +0 -95
  160. package/src/fields/resolveField.ts +0 -28
  161. package/src/filters/BooleanFilter.ts +0 -35
  162. package/src/filters/DateRangeFilter.test.ts +0 -194
  163. package/src/filters/DateRangeFilter.ts +0 -148
  164. package/src/filters/Filter.test.ts +0 -268
  165. package/src/filters/Filter.ts +0 -184
  166. package/src/filters/FormFilter.test.ts +0 -238
  167. package/src/filters/FormFilter.ts +0 -215
  168. package/src/filters/MultiSelectFilter.test.ts +0 -119
  169. package/src/filters/MultiSelectFilter.ts +0 -78
  170. package/src/filters/QueryBuilderFilter.test.ts +0 -662
  171. package/src/filters/QueryBuilderFilter.ts +0 -398
  172. package/src/filters/SelectFilter.ts +0 -46
  173. package/src/filters/TernaryFilter.test.ts +0 -160
  174. package/src/filters/TernaryFilter.ts +0 -72
  175. package/src/filters/TrashedFilter.test.ts +0 -149
  176. package/src/filters/TrashedFilter.ts +0 -55
  177. package/src/filters/queryBuilder/BooleanConstraint.ts +0 -31
  178. package/src/filters/queryBuilder/Constraint.ts +0 -115
  179. package/src/filters/queryBuilder/DateConstraint.ts +0 -69
  180. package/src/filters/queryBuilder/NumberConstraint.ts +0 -66
  181. package/src/filters/queryBuilder/SelectConstraint.ts +0 -72
  182. package/src/filters/queryBuilder/TextConstraint.ts +0 -64
  183. package/src/filters/queryBuilder/index.ts +0 -12
  184. package/src/icons/index.ts +0 -2
  185. package/src/icons/lucide.ts +0 -204
  186. package/src/icons/registry.test.ts +0 -56
  187. package/src/icons/registry.ts +0 -41
  188. package/src/icons/types.ts +0 -47
  189. package/src/index.ts +0 -525
  190. package/src/io/csv.test.ts +0 -142
  191. package/src/io/csv.ts +0 -170
  192. package/src/nestedRelationManagerData.test.ts +0 -547
  193. package/src/notifications/Notification.test.ts +0 -210
  194. package/src/notifications/Notification.ts +0 -354
  195. package/src/notifications/broadcast.test.ts +0 -110
  196. package/src/notifications/broadcast.ts +0 -95
  197. package/src/notifications/database.test.ts +0 -383
  198. package/src/notifications/database.ts +0 -398
  199. package/src/notifications/databaseNotifications.test.ts +0 -187
  200. package/src/notifications/dispatchNotificationAction.test.ts +0 -341
  201. package/src/notifications/dispatchNotificationAction.ts +0 -142
  202. package/src/notifications/flash.test.ts +0 -89
  203. package/src/notifications/flash.ts +0 -71
  204. package/src/notifications/index.ts +0 -45
  205. package/src/notifications/registerBroadcastAuth.test.ts +0 -134
  206. package/src/notifications/registerBroadcastAuth.ts +0 -100
  207. package/src/notifications/resolveSavedNotification.test.ts +0 -82
  208. package/src/notifications/resolveSavedNotification.ts +0 -59
  209. package/src/notifications/types.ts +0 -93
  210. package/src/orm/m2mAccessor.ts +0 -66
  211. package/src/orm/modelDefaults.test.ts +0 -633
  212. package/src/orm/modelDefaults.ts +0 -666
  213. package/src/pageData/breadcrumbs.ts +0 -288
  214. package/src/pageData/forms.ts +0 -578
  215. package/src/pageData/helpers.ts +0 -857
  216. package/src/pageData/misc.ts +0 -347
  217. package/src/pageData/navigation.ts +0 -842
  218. package/src/pageData/relationPages.ts +0 -1248
  219. package/src/pageData/relationTabs.ts +0 -286
  220. package/src/pageData/resourcePages.ts +0 -609
  221. package/src/pageData.test.ts +0 -1545
  222. package/src/pageData.ts +0 -341
  223. package/src/plugins/index.ts +0 -8
  224. package/src/plugins/themeEditor.test.ts +0 -36
  225. package/src/plugins/themeEditor.ts +0 -45
  226. package/src/react/AppShell.tsx +0 -251
  227. package/src/react/CollabExtensionFactoryRegistry.ts +0 -55
  228. package/src/react/CollabRoomContext.ts +0 -98
  229. package/src/react/CollabTextRendererRegistry.ts +0 -102
  230. package/src/react/CommandPalette.tsx +0 -375
  231. package/src/react/CurrentUserContext.tsx +0 -50
  232. package/src/react/CustomPageWrapperGate.tsx +0 -69
  233. package/src/react/CustomPageWrapperRegistry.ts +0 -45
  234. package/src/react/FieldFocusReporterRegistry.ts +0 -37
  235. package/src/react/FieldLabelSlotRegistry.ts +0 -30
  236. package/src/react/FieldPresenceRegistry.ts +0 -46
  237. package/src/react/FormCollabBindingRegistry.ts +0 -242
  238. package/src/react/FormStateContext.tsx +0 -591
  239. package/src/react/HeadHooks.tsx +0 -126
  240. package/src/react/MarkdownEditorRegistry.test.ts +0 -38
  241. package/src/react/MarkdownEditorRegistry.ts +0 -107
  242. package/src/react/NotificationActionStrip.tsx +0 -263
  243. package/src/react/NotificationBell.tsx +0 -426
  244. package/src/react/PendingSuggestionApplierRegistry.test.ts +0 -97
  245. package/src/react/PendingSuggestionApplierRegistry.ts +0 -98
  246. package/src/react/PendingSuggestionOverlayRegistry.ts +0 -54
  247. package/src/react/PendingSuggestionsContext.tsx +0 -172
  248. package/src/react/RecordWrapperGate.tsx +0 -58
  249. package/src/react/RecordWrapperRegistry.ts +0 -39
  250. package/src/react/RenderHookSlot.tsx +0 -32
  251. package/src/react/RightSidebar.tsx +0 -257
  252. package/src/react/RightSidebarContext.tsx +0 -234
  253. package/src/react/RightSidebarTrigger.tsx +0 -53
  254. package/src/react/RowCoordsContext.tsx +0 -23
  255. package/src/react/SchemaRenderer.tsx +0 -549
  256. package/src/react/SearchTrigger.tsx +0 -46
  257. package/src/react/ThemeProvider.tsx +0 -93
  258. package/src/react/ThemeSettingsPage.tsx +0 -579
  259. package/src/react/ThemeToggle.tsx +0 -20
  260. package/src/react/Toaster.tsx +0 -158
  261. package/src/react/UserMenu.tsx +0 -196
  262. package/src/react/WidgetDataContext.tsx +0 -157
  263. package/src/react/cells/EditableCell.tsx +0 -389
  264. package/src/react/component-slots.test.ts +0 -103
  265. package/src/react/component-slots.ts +0 -116
  266. package/src/react/fieldJsHandler.test.ts +0 -166
  267. package/src/react/fieldJsHandler.ts +0 -79
  268. package/src/react/fields/BuilderInput.tsx +0 -1078
  269. package/src/react/fields/CheckboxInput.tsx +0 -39
  270. package/src/react/fields/CheckboxListInput.tsx +0 -102
  271. package/src/react/fields/ColorInput.tsx +0 -71
  272. package/src/react/fields/DateFieldInput.tsx +0 -70
  273. package/src/react/fields/DateTimeInput.tsx +0 -62
  274. package/src/react/fields/FieldShell.tsx +0 -348
  275. package/src/react/fields/FileUploadInput.tsx +0 -639
  276. package/src/react/fields/HiddenInput.tsx +0 -17
  277. package/src/react/fields/KeyValueInput.tsx +0 -230
  278. package/src/react/fields/MarkdownInput.tsx +0 -560
  279. package/src/react/fields/RadioInput.tsx +0 -81
  280. package/src/react/fields/RepeaterInput.test.ts +0 -116
  281. package/src/react/fields/RepeaterInput.tsx +0 -1420
  282. package/src/react/fields/SelectFieldInput.tsx +0 -280
  283. package/src/react/fields/SliderInput.tsx +0 -81
  284. package/src/react/fields/TagsInput.tsx +0 -283
  285. package/src/react/fields/TextLikeInput.tsx +0 -256
  286. package/src/react/fields/ToggleButtonsInput.tsx +0 -60
  287. package/src/react/fields/ToggleFieldInput.tsx +0 -56
  288. package/src/react/fields/relationshipRenameDispatch.test.ts +0 -106
  289. package/src/react/fields/relationshipRenameDispatch.ts +0 -97
  290. package/src/react/fields/repeaterReconcile.test.ts +0 -114
  291. package/src/react/fields/repeaterReconcile.ts +0 -104
  292. package/src/react/fields/rowChromeButton.tsx +0 -336
  293. package/src/react/fields/rowState.ts +0 -106
  294. package/src/react/fields/syncRowGates.test.ts +0 -202
  295. package/src/react/fields/syncRowGates.ts +0 -66
  296. package/src/react/fields/textInputControls.tsx +0 -238
  297. package/src/react/fields/useRowReorderDnd.ts +0 -78
  298. package/src/react/formStateHelpers.test.ts +0 -508
  299. package/src/react/formStateHelpers.ts +0 -381
  300. package/src/react/hooks/use-mobile.ts +0 -19
  301. package/src/react/icon-context.tsx +0 -60
  302. package/src/react/index.ts +0 -194
  303. package/src/react/layouts/SidebarLayout.tsx +0 -250
  304. package/src/react/layouts/TopbarLayout.tsx +0 -258
  305. package/src/react/navigate.tsx +0 -37
  306. package/src/react/onProviderSynced.test.ts +0 -90
  307. package/src/react/parseRecordEditUrl.test.ts +0 -122
  308. package/src/react/parseRecordEditUrl.ts +0 -94
  309. package/src/react/persistedState.ts +0 -40
  310. package/src/react/registry.ts +0 -48
  311. package/src/react/right-panel-registry.tsx +0 -47
  312. package/src/react/schemaRenderer/AlertRenderer.tsx +0 -112
  313. package/src/react/schemaRenderer/EntryRenderer.tsx +0 -501
  314. package/src/react/schemaRenderer/SectionRenderer.tsx +0 -120
  315. package/src/react/schemaRenderer/SimpleElements.tsx +0 -306
  316. package/src/react/schemaRenderer/TabsRenderer.tsx +0 -62
  317. package/src/react/schemaRenderer/WizardRenderer.tsx +0 -338
  318. package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +0 -177
  319. package/src/react/schemaRenderer/action/ActionModalDialog.tsx +0 -273
  320. package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +0 -61
  321. package/src/react/schemaRenderer/action/HandlerActionButton.tsx +0 -43
  322. package/src/react/schemaRenderer/action/MethodActionButton.tsx +0 -64
  323. package/src/react/schemaRenderer/action/buttons.tsx +0 -99
  324. package/src/react/schemaRenderer/action/helpers.ts +0 -140
  325. package/src/react/schemaRenderer/action/renderAction.tsx +0 -245
  326. package/src/react/schemaRenderer/columnFormat.ts +0 -65
  327. package/src/react/schemaRenderer/constants.ts +0 -50
  328. package/src/react/schemaRenderer/form/FormRenderer.tsx +0 -274
  329. package/src/react/schemaRenderer/form/renderField.tsx +0 -511
  330. package/src/react/schemaRenderer/helpers.tsx +0 -81
  331. package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +0 -308
  332. package/src/react/schemaRenderer/table/TableRenderer.tsx +0 -123
  333. package/src/react/schemaRenderer/table/TableRendererBody.tsx +0 -974
  334. package/src/react/schemaRenderer/table/filters.tsx +0 -1233
  335. package/src/react/schemaRenderer/table/formatCell.tsx +0 -264
  336. package/src/react/schemaRenderer/table/links.tsx +0 -112
  337. package/src/react/schemaRenderer/table/renderRowActions.tsx +0 -52
  338. package/src/react/schemaRenderer/table/url.tsx +0 -143
  339. package/src/react/theme-preview/apply.ts +0 -99
  340. package/src/react/theme-preview/build-html.ts +0 -436
  341. package/src/react/ui/button.tsx +0 -51
  342. package/src/react/ui/calendar.tsx +0 -67
  343. package/src/react/ui/checkbox.tsx +0 -29
  344. package/src/react/ui/dialog.tsx +0 -108
  345. package/src/react/ui/dropdown-menu.tsx +0 -97
  346. package/src/react/ui/input.tsx +0 -20
  347. package/src/react/ui/label.tsx +0 -21
  348. package/src/react/ui/popover.tsx +0 -50
  349. package/src/react/ui/select.tsx +0 -169
  350. package/src/react/ui/separator.tsx +0 -25
  351. package/src/react/ui/sheet.tsx +0 -136
  352. package/src/react/ui/sidebar.tsx +0 -723
  353. package/src/react/ui/skeleton.tsx +0 -13
  354. package/src/react/ui/slider.tsx +0 -34
  355. package/src/react/ui/switch.tsx +0 -28
  356. package/src/react/ui/table.tsx +0 -105
  357. package/src/react/ui/tabs.tsx +0 -63
  358. package/src/react/ui/textarea.tsx +0 -18
  359. package/src/react/ui/tooltip.tsx +0 -64
  360. package/src/react/useResizableWidth.ts +0 -139
  361. package/src/react/utils.ts +0 -6
  362. package/src/react/widgetRegistry.test.ts +0 -43
  363. package/src/react/widgetRegistry.ts +0 -50
  364. package/src/react/widgets/StatsOverviewRenderer.tsx +0 -232
  365. package/src/react/widgets/TableWidgetRenderer.tsx +0 -231
  366. package/src/react/widgets/ViewRenderer.tsx +0 -71
  367. package/src/relationManagerData.test.ts +0 -1595
  368. package/src/richtext/index.ts +0 -8
  369. package/src/richtext/registry.ts +0 -89
  370. package/src/routes/globals.ts +0 -148
  371. package/src/routes/guard.test.ts +0 -325
  372. package/src/routes/helpers.ts +0 -704
  373. package/src/routes/pages.ts +0 -175
  374. package/src/routes/panel.ts +0 -204
  375. package/src/routes/relations.ts +0 -1243
  376. package/src/routes/resources.ts +0 -781
  377. package/src/routes/theme.ts +0 -91
  378. package/src/routes-nested-relations.test.ts +0 -676
  379. package/src/routes-relations.test.ts +0 -972
  380. package/src/routes.test.ts +0 -2027
  381. package/src/routes.ts +0 -303
  382. package/src/schema/Alert.test.ts +0 -109
  383. package/src/schema/Alert.ts +0 -131
  384. package/src/schema/Block.ts +0 -169
  385. package/src/schema/Breadcrumbs.ts +0 -40
  386. package/src/schema/Card.ts +0 -35
  387. package/src/schema/Divider.ts +0 -20
  388. package/src/schema/Element.ts +0 -219
  389. package/src/schema/EmptyState.test.ts +0 -37
  390. package/src/schema/EmptyState.ts +0 -63
  391. package/src/schema/Fieldset.ts +0 -43
  392. package/src/schema/Grid.ts +0 -43
  393. package/src/schema/Group.ts +0 -30
  394. package/src/schema/Heading.ts +0 -39
  395. package/src/schema/Html.ts +0 -67
  396. package/src/schema/Icon.ts +0 -54
  397. package/src/schema/Image.ts +0 -57
  398. package/src/schema/LinkTag.ts +0 -41
  399. package/src/schema/Markdown.ts +0 -85
  400. package/src/schema/MetaTag.ts +0 -41
  401. package/src/schema/RelationTabs.ts +0 -71
  402. package/src/schema/ScriptTag.ts +0 -55
  403. package/src/schema/Section.ts +0 -160
  404. package/src/schema/ServerDataElement.test.ts +0 -140
  405. package/src/schema/ServerDataElement.ts +0 -156
  406. package/src/schema/SlotComponent.test.ts +0 -77
  407. package/src/schema/SlotComponent.ts +0 -71
  408. package/src/schema/Split.ts +0 -50
  409. package/src/schema/Stat.test.ts +0 -118
  410. package/src/schema/Stat.ts +0 -154
  411. package/src/schema/StatsOverview.test.ts +0 -141
  412. package/src/schema/StatsOverview.ts +0 -119
  413. package/src/schema/StyleTag.ts +0 -35
  414. package/src/schema/TableWidget.test.ts +0 -297
  415. package/src/schema/TableWidget.ts +0 -289
  416. package/src/schema/Tabs.ts +0 -79
  417. package/src/schema/Text.ts +0 -58
  418. package/src/schema/UnorderedList.ts +0 -49
  419. package/src/schema/View.test.ts +0 -111
  420. package/src/schema/View.ts +0 -127
  421. package/src/schema/Wizard.ts +0 -220
  422. package/src/schema/containers.test.ts +0 -564
  423. package/src/schema/headTags.test.ts +0 -134
  424. package/src/schema/index.ts +0 -40
  425. package/src/schema/primes.test.ts +0 -269
  426. package/src/schema/resolveSchema.test.ts +0 -379
  427. package/src/schema/resolveSchema.ts +0 -917
  428. package/src/schema/sanitize.ts +0 -58
  429. package/src/search.test.ts +0 -446
  430. package/src/search.ts +0 -178
  431. package/src/sessionFilters.test.ts +0 -375
  432. package/src/sessionFilters.ts +0 -143
  433. package/src/slot-components/index.ts +0 -10
  434. package/src/slot-components/registry.ts +0 -56
  435. package/src/styles/file-upload.css +0 -13
  436. package/src/summarizers/Summarizer.test.ts +0 -84
  437. package/src/summarizers/Summarizer.ts +0 -123
  438. package/src/summarizers/index.ts +0 -11
  439. package/src/theme/base-colors.ts +0 -68
  440. package/src/theme/chart-colors.ts +0 -50
  441. package/src/theme/colors.ts +0 -447
  442. package/src/theme/generate-css.test.ts +0 -139
  443. package/src/theme/generate-css.ts +0 -44
  444. package/src/theme/generate-scale.test.ts +0 -106
  445. package/src/theme/generate-scale.ts +0 -97
  446. package/src/theme/icon-map.ts +0 -42
  447. package/src/theme/index.ts +0 -34
  448. package/src/theme/migrate.test.ts +0 -178
  449. package/src/theme/migrate.ts +0 -81
  450. package/src/theme/presets.ts +0 -135
  451. package/src/theme/radius.ts +0 -18
  452. package/src/theme/resolve.test.ts +0 -238
  453. package/src/theme/resolve.ts +0 -96
  454. package/src/theme/spacing.ts +0 -18
  455. package/src/theme/storage.test.ts +0 -126
  456. package/src/theme/storage.ts +0 -106
  457. package/src/theme/theme-colors.ts +0 -88
  458. package/src/theme/types.ts +0 -125
  459. package/src/uploads/UploadAdapter.ts +0 -35
  460. package/src/uploads/index.ts +0 -2
  461. package/src/uploads/localUpload.test.ts +0 -70
  462. package/src/uploads/localUpload.ts +0 -84
  463. package/src/validation/Validator.ts +0 -49
  464. package/src/validation/index.ts +0 -28
  465. package/src/validation/rules.ts +0 -78
  466. package/src/validation/runValidators.ts +0 -435
  467. package/src/validation/uniqueValidator.test.ts +0 -196
  468. package/src/validation/uniqueValidator.ts +0 -133
  469. package/src/validation/validators.test.ts +0 -268
  470. package/src/vite.test.ts +0 -184
  471. package/src/vite.ts +0 -787
  472. package/src/widgets/index.ts +0 -10
  473. package/src/widgets/registry.ts +0 -45
  474. package/src/widgets.test.ts +0 -592
  475. package/tsconfig.build.json +0 -11
  476. package/tsconfig.json +0 -4
  477. package/tsconfig.test.json +0 -10
  478. package/views/react/Dashboard.tsx +0 -27
  479. package/views/react/Resources/Form.tsx +0 -102
  480. package/views/react/Resources/Index.tsx +0 -49
@@ -1,398 +0,0 @@
1
- /**
2
- * Database-backed notifications — server-side store helpers.
3
- *
4
- * Pilotiq doesn't ship a Prisma model; we read/write the
5
- * `notification` table that `@rudderjs/notification`'s
6
- * `NotificationProvider` publishes (`prisma/schema/notification.prisma`).
7
- * Apps that want bell-icon notifications add `NotificationProvider` to
8
- * their providers list and run `prisma generate`/`db push`; pilotiq
9
- * then queries the same table via `@rudderjs/orm`'s `ModelRegistry`
10
- * adapter so the wire shape matches what
11
- * `Notifier.send(user, new MyNotification())` already writes.
12
- *
13
- * `@rudderjs/orm` is a runtime soft-import — pilotiq has no hard
14
- * dependency on it. When the host app hasn't installed orm (or no
15
- * adapter is registered), every helper resolves to a clean
16
- * "store unavailable" sentinel rather than throwing.
17
- */
18
-
19
- import type { NotificationMeta, NotificationType } from './Notification.js'
20
- import type { NotificationActionMeta } from './types.js'
21
-
22
- /** Wire shape returned by the list endpoint to the bell client. */
23
- export interface DatabaseNotificationMeta {
24
- /** Stable PK from the `notification.id` column. */
25
- id: string
26
- /** Unix-ms timestamp the row was created. */
27
- createdAt: number
28
- /** ISO `read_at` timestamp; absent when unread. */
29
- readAt?: string
30
- /** Display title — read from the `data` JSON `title` key. */
31
- title: string
32
- /** Optional supporting text. */
33
- body?: string
34
- /** Optional UI tint. Mirrors the transient toast types so the bell can
35
- * share badge styling with the toaster. */
36
- type?: NotificationType
37
- /** Optional icon (registry name). */
38
- icon?: string
39
- /** Optional click-through URL. When set, clicking the row navigates
40
- * there + marks the notification as read. */
41
- url?: string
42
- /** Optional action strip rendered below the body. Round-trips
43
- * verbatim through the `data.actions` JSON column (`Notification`
44
- * emits the slim wire shape; `rowToMeta` validates each entry and
45
- * drops malformed ones with a `console.warn` rather than failing
46
- * the dropdown). */
47
- actions?: NotificationActionMeta[]
48
- }
49
-
50
- /** Raw row shape on the `notification` table — matches the schema
51
- * shipped by `@rudderjs/notification`. The `data` column is a
52
- * JSON-encoded string blob. */
53
- interface NotificationRow {
54
- id: string
55
- notifiable_id: string
56
- notifiable_type: string
57
- type: string
58
- data: string | Record<string, unknown>
59
- read_at: string | null
60
- created_at: string
61
- updated_at: string
62
- }
63
-
64
- /** Minimal query surface we use against the orm adapter. */
65
- interface QB {
66
- where(column: string, value: unknown): QB
67
- where(column: string, op: string, value: unknown): QB
68
- orderBy(column: string, dir?: 'ASC' | 'DESC'): QB
69
- paginate(page: number, perPage?: number): Promise<{ data: unknown[]; total: number }>
70
- get?(): Promise<unknown[]>
71
- count?(): Promise<number>
72
- update?(data: Record<string, unknown>): Promise<unknown>
73
- updateAll?(data: Record<string, unknown>): Promise<number>
74
- create?(data: Record<string, unknown>): Promise<unknown>
75
- }
76
-
77
- /** Test-injected adapter override; `null` falls back to dynamic import. */
78
- let _testAdapter: { query: <T>(table: string) => QB } | null | 'unset' = 'unset'
79
-
80
- /** Soft-resolved orm adapter. `null` when no orm adapter is registered.
81
- *
82
- * Prefers the rudder service container (`app().make('db')`) — the
83
- * orm-prisma / orm-drizzle providers register the adapter as a
84
- * globalThis-rooted singleton there, so this resolution path survives
85
- * the Vite SSR module-cache duplication that breaks shared singletons
86
- * in raw ES module land. Falls back to `ModelRegistry.get()` for
87
- * setups that wired the adapter directly.
88
- *
89
- * Both modules are imported indirectly so TypeScript doesn't try to
90
- * resolve them at type-check time — pilotiq doesn't peer-depend on
91
- * `@rudderjs/orm` or `@rudderjs/core` (the bell-icon is opt-in).
92
- */
93
- async function adapter(): Promise<{ query: <T>(table: string) => QB } | null> {
94
- if (_testAdapter !== 'unset') return _testAdapter
95
- const fromContainer = await resolveFromContainer()
96
- if (fromContainer) return fromContainer
97
- return resolveFromOrmModule()
98
- }
99
-
100
- async function resolveFromContainer(): Promise<{ query: <T>(table: string) => QB } | null> {
101
- const moduleName = '@rudderjs/core'
102
- try {
103
- const mod = await import(/* @vite-ignore */ moduleName) as {
104
- app?: () => { make(key: string): unknown }
105
- }
106
- if (!mod.app) return null
107
- const adapter = mod.app().make('db')
108
- if (!adapter || typeof adapter !== 'object') return null
109
- if (typeof (adapter as { query?: unknown }).query !== 'function') return null
110
- return adapter as { query: <T>(table: string) => QB }
111
- } catch {
112
- return null
113
- }
114
- }
115
-
116
- async function resolveFromOrmModule(): Promise<{ query: <T>(table: string) => QB } | null> {
117
- const moduleName = '@rudderjs/orm'
118
- try {
119
- const mod = await import(/* @vite-ignore */ moduleName) as {
120
- ModelRegistry?: { get(): { query: <T>(table: string) => QB } | null }
121
- }
122
- return mod.ModelRegistry?.get() ?? null
123
- } catch {
124
- return null
125
- }
126
- }
127
-
128
- /** Notification-table row JSON-decoded `data` payload. We always store
129
- * pilotiq's `NotificationMeta` shape; rows written by
130
- * `@rudderjs/notification.Notifier.send(...)` may carry arbitrary
131
- * application keys — we surface what we can recognize and ignore the rest. */
132
- function parseRowData(raw: string | Record<string, unknown>): Record<string, unknown> {
133
- if (typeof raw !== 'string') return raw
134
- try { return JSON.parse(raw) as Record<string, unknown> }
135
- catch { return {} }
136
- }
137
-
138
- function rowToMeta(row: NotificationRow): DatabaseNotificationMeta {
139
- const data = parseRowData(row.data)
140
- const meta: DatabaseNotificationMeta = {
141
- id: row.id,
142
- createdAt: Date.parse(row.created_at) || Date.now(),
143
- title: typeof data['title'] === 'string' ? (data['title'] as string) : '',
144
- }
145
- if (row.read_at) meta.readAt = row.read_at
146
- if (typeof data['body'] === 'string') meta.body = data['body'] as string
147
- if (typeof data['icon'] === 'string') meta.icon = data['icon'] as string
148
- if (typeof data['url'] === 'string') meta.url = data['url'] as string
149
- if (
150
- data['type'] === 'info' || data['type'] === 'success' ||
151
- data['type'] === 'warning' || data['type'] === 'error'
152
- ) {
153
- meta.type = data['type']
154
- }
155
- const actions = parseStoredActions(data['actions'])
156
- if (actions.length > 0) meta.actions = actions
157
- return meta
158
- }
159
-
160
- /**
161
- * Validate the stored action array shape — the `data.actions` column
162
- * is end-user controllable through the `Notification` builder, so we
163
- * defend in depth: malformed entries are dropped with a warning rather
164
- * than crashing the bell dropdown render.
165
- *
166
- * Required: `name: string`, `label: string`, exactly one of `url` /
167
- * `post` / `handler` set to a string.
168
- */
169
- function parseStoredActions(raw: unknown): NotificationActionMeta[] {
170
- if (!Array.isArray(raw)) return []
171
- const out: NotificationActionMeta[] = []
172
- for (const entry of raw) {
173
- if (!entry || typeof entry !== 'object') continue
174
- const e = entry as Record<string, unknown>
175
- if (typeof e['name'] !== 'string' || !e['name']) { warnDrop(e, 'missing name'); continue }
176
- if (typeof e['label'] !== 'string' || !e['label']) { warnDrop(e, 'missing label'); continue }
177
- const url = typeof e['url'] === 'string' ? e['url'] as string : undefined
178
- const post = typeof e['post'] === 'string' ? e['post'] as string : undefined
179
- const handler = typeof e['handler'] === 'string' ? e['handler'] as string : undefined
180
- const dispatchModes = [url, post, handler].filter(v => v !== undefined).length
181
- if (dispatchModes !== 1) { warnDrop(e, 'must set exactly one of url/post/handler'); continue }
182
-
183
- const action: NotificationActionMeta = { name: e['name'] as string, label: e['label'] as string }
184
- if (url !== undefined) action.url = url
185
- if (post !== undefined) action.post = post
186
- if (handler !== undefined) action.handler = handler
187
- if (e['payload'] && typeof e['payload'] === 'object' && !Array.isArray(e['payload'])) {
188
- action.payload = e['payload'] as Record<string, unknown>
189
- }
190
- if (typeof e['color'] === 'string') action.color = e['color'] as never
191
- if (typeof e['icon'] === 'string') action.icon = e['icon'] as string
192
- if (e['outlined'] === true) action.outlined = true
193
- if (typeof e['size'] === 'string') action.size = e['size'] as never
194
- if (e['openUrlInNewTab'] === true) action.openUrlInNewTab = true
195
- if (e['markAsRead'] === true) action.markAsRead = true
196
- out.push(action)
197
- }
198
- return out
199
- }
200
-
201
- function warnDrop(entry: Record<string, unknown>, reason: string): void {
202
- // Only warn in non-production — keep the bell quiet on prod where
203
- // a dropped row is preferable to console spam.
204
- if (typeof process !== 'undefined' && process.env?.['NODE_ENV'] === 'production') return
205
-
206
- console.warn(
207
- `[Pilotiq] notification action dropped: ${reason}. Entry:`,
208
- entry,
209
- )
210
- }
211
-
212
- export interface ListOptions {
213
- /** `notifiable_type` column value. */
214
- notifiableType: string
215
- /** `notifiable_id` column value (typically the user's id). */
216
- notifiableId: string
217
- /** Hard cap on rows returned. Default 25. */
218
- limit?: number
219
- /** When true, only rows with `read_at IS NULL` are returned. */
220
- unreadOnly?: boolean
221
- }
222
-
223
- export interface ListResult {
224
- notifications: DatabaseNotificationMeta[]
225
- unreadCount: number
226
- }
227
-
228
- /**
229
- * Fetch the latest notifications for a notifiable + the unread count.
230
- * Returns `{ notifications: [], unreadCount: 0 }` when no orm adapter is
231
- * registered — apps without a database stay quiet rather than 500.
232
- */
233
- export async function listForUser(opts: ListOptions): Promise<ListResult> {
234
- const adp = await adapter()
235
- if (!adp) return { notifications: [], unreadCount: 0 }
236
-
237
- const limit = opts.limit ?? 25
238
- let q: QB = adp.query<NotificationRow>('notification')
239
- .where('notifiable_type', opts.notifiableType)
240
- .where('notifiable_id', opts.notifiableId)
241
- if (opts.unreadOnly) q = q.where('read_at', null)
242
- q = q.orderBy('created_at', 'DESC')
243
-
244
- const [page, count] = await Promise.all([
245
- q.paginate(1, limit),
246
- unreadCount({ notifiableType: opts.notifiableType, notifiableId: opts.notifiableId }),
247
- ])
248
- const rows = (page.data as NotificationRow[]).map(rowToMeta)
249
- return { notifications: rows, unreadCount: count }
250
- }
251
-
252
- /**
253
- * Fetch a single row by id, scoped to the notifiable. Returns
254
- * `undefined` when no row matches (already-deleted / wrong owner /
255
- * store unavailable). Used by the notification action route to look
256
- * up the stored `data.actions` array before dispatching.
257
- */
258
- export async function findOneForUser(
259
- id: string,
260
- opts: { notifiableType: string; notifiableId: string },
261
- ): Promise<DatabaseNotificationMeta | undefined> {
262
- const adp = await adapter()
263
- if (!adp) return undefined
264
- const q = adp.query<NotificationRow>('notification')
265
- .where('notifiable_type', opts.notifiableType)
266
- .where('notifiable_id', opts.notifiableId)
267
- .where('id', id)
268
- const page = await q.paginate(1, 1)
269
- const row = (page.data as NotificationRow[])[0]
270
- if (!row) return undefined
271
- return rowToMeta(row)
272
- }
273
-
274
- /** Count rows with `read_at IS NULL` for the notifiable. */
275
- export async function unreadCount(opts: {
276
- notifiableType: string
277
- notifiableId: string
278
- }): Promise<number> {
279
- const adp = await adapter()
280
- if (!adp) return 0
281
- const q = adp.query<NotificationRow>('notification')
282
- .where('notifiable_type', opts.notifiableType)
283
- .where('notifiable_id', opts.notifiableId)
284
- .where('read_at', null)
285
- // Cheap path when the adapter implements `count()`; fall back to
286
- // paginate(1,1).total which both Prisma and Drizzle adapters support.
287
- if (q.count) return q.count()
288
- const page = await q.paginate(1, 1)
289
- return page.total
290
- }
291
-
292
- /**
293
- * Mark a single notification row as read. Always scoped to
294
- * `notifiableId` so a tampered POST can't mark another user's row.
295
- *
296
- * Returns `true` when a row was updated, `false` when no row matched
297
- * (already-deleted / wrong owner / store unavailable).
298
- */
299
- export async function markAsRead(
300
- id: string,
301
- opts: { notifiableType: string; notifiableId: string },
302
- ): Promise<boolean> {
303
- const adp = await adapter()
304
- if (!adp) return false
305
- const q = adp.query<NotificationRow>('notification')
306
- .where('notifiable_type', opts.notifiableType)
307
- .where('notifiable_id', opts.notifiableId)
308
- .where('id', id)
309
- if (!q.updateAll) return false
310
- const n = await q.updateAll({ read_at: new Date().toISOString() })
311
- return n > 0
312
- }
313
-
314
- /** Mark a row unread again — used by the bell's "mark unread" affordance. */
315
- export async function markAsUnread(
316
- id: string,
317
- opts: { notifiableType: string; notifiableId: string },
318
- ): Promise<boolean> {
319
- const adp = await adapter()
320
- if (!adp) return false
321
- const q = adp.query<NotificationRow>('notification')
322
- .where('notifiable_type', opts.notifiableType)
323
- .where('notifiable_id', opts.notifiableId)
324
- .where('id', id)
325
- if (!q.updateAll) return false
326
- const n = await q.updateAll({ read_at: null })
327
- return n > 0
328
- }
329
-
330
- /** Mark every unread notification for the notifiable as read. */
331
- export async function markAllAsRead(opts: {
332
- notifiableType: string
333
- notifiableId: string
334
- }): Promise<number> {
335
- const adp = await adapter()
336
- if (!adp) return 0
337
- const q = adp.query<NotificationRow>('notification')
338
- .where('notifiable_type', opts.notifiableType)
339
- .where('notifiable_id', opts.notifiableId)
340
- .where('read_at', null)
341
- if (!q.updateAll) return 0
342
- return q.updateAll({ read_at: new Date().toISOString() })
343
- }
344
-
345
- /**
346
- * Insert a notification row directly. Powers
347
- * `Notification.make(...).sendToDatabase(recipient)`. Throws when the
348
- * orm adapter isn't registered — the caller has explicitly asked to
349
- * persist, so silent no-op would hide a real config error.
350
- */
351
- export async function persist(opts: {
352
- notifiableType: string
353
- notifiableId: string
354
- type?: string
355
- data: NotificationMeta & Record<string, unknown>
356
- }): Promise<{ id: string }> {
357
- const adp = await adapter()
358
- if (!adp) {
359
- throw new Error(
360
- '[Pilotiq] sendToDatabase() called but no @rudderjs/orm adapter is registered. ' +
361
- 'Add a database provider (orm-prisma / orm-drizzle) to your providers list, ' +
362
- "or call .sendToDatabase() only when the orm is wired up.",
363
- )
364
- }
365
- const q = adp.query<NotificationRow>('notification')
366
- if (!q.create) {
367
- throw new Error('[Pilotiq] orm adapter does not support `query.create()`.')
368
- }
369
- const id = `pn_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`
370
- const now = new Date().toISOString()
371
- await q.create({
372
- id,
373
- notifiable_id: opts.notifiableId,
374
- notifiable_type: opts.notifiableType,
375
- type: opts.type ?? 'PilotiqNotification',
376
- data: JSON.stringify(opts.data),
377
- read_at: null,
378
- created_at: now,
379
- updated_at: now,
380
- })
381
- return { id }
382
- }
383
-
384
- /** @internal — test seam. Inject a fake adapter (or `null` to mimic
385
- * "store unavailable"). Pass `undefined` to clear and fall back to the
386
- * dynamic `@rudderjs/orm` import. Tests should clear in `afterEach`. */
387
- export function _setTestAdapter(
388
- adp: { query: <T>(table: string) => QB } | null | undefined,
389
- ): void {
390
- _testAdapter = adp === undefined ? 'unset' : adp
391
- }
392
-
393
- /** @internal — exposed for tests; lets a unit test inject a fake
394
- * ModelRegistry without monkey-patching dynamic-import. */
395
- export const _internal = {
396
- parseRowData,
397
- rowToMeta,
398
- }
@@ -1,187 +0,0 @@
1
- /**
2
- * Builder + panelInfo() integration tests for
3
- * `Pilotiq.databaseNotifications()`. The transport layer (the
4
- * `_notifications` route family) is exercised via the storage tests +
5
- * `database.test.ts`; here we lock down the wire shape consumers
6
- * actually depend on.
7
- */
8
- import { describe, it } from 'node:test'
9
- import assert from 'node:assert/strict'
10
-
11
- import { Pilotiq } from '../Pilotiq.js'
12
- import { panelInfo } from '../pageData.js'
13
-
14
- describe('Pilotiq.databaseNotifications() — builder', () => {
15
- it('opt-out by default — cfg.databaseNotifications is undefined', () => {
16
- const cfg = Pilotiq.make('admin').getConfig()
17
- assert.equal(cfg.databaseNotifications, undefined)
18
- })
19
-
20
- it('toggle without options enables with defaults', () => {
21
- const cfg = Pilotiq.make('admin').databaseNotifications().getConfig()
22
- assert.equal(cfg.databaseNotifications?.enabled, true)
23
- assert.equal(cfg.databaseNotifications?.position, undefined)
24
- assert.equal(cfg.databaseNotifications?.polling, undefined)
25
- })
26
-
27
- it('options round-trip', () => {
28
- const cfg = Pilotiq.make('admin').databaseNotifications({
29
- position: 'sidebar',
30
- polling: 10,
31
- pageSize: 50,
32
- badgeColor: 'success',
33
- trigger: { icon: 'bell', label: 'Inbox' },
34
- }).getConfig()
35
- assert.equal(cfg.databaseNotifications?.position, 'sidebar')
36
- assert.equal(cfg.databaseNotifications?.polling, 10)
37
- assert.equal(cfg.databaseNotifications?.pageSize, 50)
38
- assert.equal(cfg.databaseNotifications?.badgeColor, 'success')
39
- assert.equal(cfg.databaseNotifications?.trigger?.icon, 'bell')
40
- })
41
-
42
- it('null polling round-trips (disable auto-poll)', () => {
43
- const cfg = Pilotiq.make('admin').databaseNotifications({ polling: null }).getConfig()
44
- assert.equal(cfg.databaseNotifications?.polling, null)
45
- })
46
-
47
- it('databaseNotificationsPolling sugar updates the slot', () => {
48
- const cfg = Pilotiq.make('admin')
49
- .databaseNotifications()
50
- .databaseNotificationsPolling(120)
51
- .getConfig()
52
- assert.equal(cfg.databaseNotifications?.polling, 120)
53
- })
54
-
55
- it('databaseNotificationsPolling is a no-op when not enabled', () => {
56
- const cfg = Pilotiq.make('admin').databaseNotificationsPolling(5).getConfig()
57
- assert.equal(cfg.databaseNotifications, undefined)
58
- })
59
-
60
- it('databaseNotificationsPosition sugar updates the slot', () => {
61
- const cfg = Pilotiq.make('admin')
62
- .databaseNotifications()
63
- .databaseNotificationsPosition('sidebar')
64
- .getConfig()
65
- assert.equal(cfg.databaseNotifications?.position, 'sidebar')
66
- })
67
- })
68
-
69
- describe('panelInfo() — databaseNotifications meta', () => {
70
- it('absent when never opted in', async () => {
71
- const panel = await panelInfo(Pilotiq.make('admin'))
72
- assert.equal((panel as Record<string, unknown>)['databaseNotifications'], undefined)
73
- })
74
-
75
- it('absent when no user resolves', async () => {
76
- const p = Pilotiq.make('admin').databaseNotifications()
77
- const panel = await panelInfo(p)
78
- assert.equal((panel as Record<string, unknown>)['databaseNotifications'], undefined)
79
- })
80
-
81
- it('present with resolver + defaults', async () => {
82
- const p = Pilotiq.make('admin')
83
- .user(() => ({ id: 1, name: 'Sue' }))
84
- .databaseNotifications()
85
- const panel = await panelInfo(p)
86
- const dn = (panel as any).databaseNotifications
87
- assert.ok(dn, 'databaseNotifications is present')
88
- assert.equal(dn.position, 'topbar')
89
- assert.equal(dn.polling, 30)
90
- assert.equal(dn.pageSize, 25)
91
- assert.equal(dn.badgeColor, 'primary')
92
- assert.equal(dn.listUrl, '/admin/_notifications')
93
- assert.equal(dn.readAllUrl, '/admin/_notifications/read-all')
94
- assert.equal(dn.readUrl, '/admin/_notifications/:id/read')
95
- assert.equal(dn.unreadUrl, '/admin/_notifications/:id/unread')
96
- assert.equal(dn.actionUrl, '/admin/_notifications/:id/_action/:actionName')
97
- })
98
-
99
- it('honors custom path for URL building', async () => {
100
- const p = Pilotiq.make('admin')
101
- .path('/dashboard')
102
- .user(() => ({ id: 1 }))
103
- .databaseNotifications()
104
- const panel = await panelInfo(p)
105
- const dn = (panel as any).databaseNotifications
106
- assert.equal(dn.listUrl, '/dashboard/_notifications')
107
- })
108
-
109
- it('null polling round-trips to the wire', async () => {
110
- const p = Pilotiq.make('admin')
111
- .user(() => ({ id: 1 }))
112
- .databaseNotifications({ polling: null })
113
- const panel = await panelInfo(p)
114
- const dn = (panel as any).databaseNotifications
115
- assert.equal(dn.polling, null)
116
- })
117
-
118
- it('per-call options override defaults', async () => {
119
- const p = Pilotiq.make('admin')
120
- .user(() => ({ id: 1 }))
121
- .databaseNotifications({
122
- position: 'sidebar',
123
- polling: 5,
124
- pageSize: 10,
125
- badgeColor: 'warning',
126
- })
127
- const panel = await panelInfo(p)
128
- const dn = (panel as any).databaseNotifications
129
- assert.equal(dn.position, 'sidebar')
130
- assert.equal(dn.polling, 5)
131
- assert.equal(dn.pageSize, 10)
132
- assert.equal(dn.badgeColor, 'warning')
133
- })
134
-
135
- it('trigger overrides ride through to the wire', async () => {
136
- const p = Pilotiq.make('admin')
137
- .user(() => ({ id: 1 }))
138
- .databaseNotifications({ trigger: { icon: 'bell', label: 'Inbox' } })
139
- const panel = await panelInfo(p)
140
- const dn = (panel as any).databaseNotifications
141
- assert.deepEqual(dn.trigger, { icon: 'bell', label: 'Inbox' })
142
- })
143
- })
144
-
145
- describe('panelInfo() — broadcast (Phase 2)', () => {
146
- it('absent when broadcast wasn\'t enabled', async () => {
147
- const p = Pilotiq.make('admin')
148
- .user(() => ({ id: 1 }))
149
- .databaseNotifications()
150
- const panel = await panelInfo(p)
151
- const dn = (panel as any).databaseNotifications
152
- assert.equal(dn.broadcast, undefined)
153
- })
154
-
155
- it('present when databaseNotificationsBroadcast() is called', async () => {
156
- const p = Pilotiq.make('admin')
157
- .user(() => ({ id: 42 }))
158
- .databaseNotifications()
159
- .databaseNotificationsBroadcast()
160
- const panel = await panelInfo(p)
161
- const dn = (panel as any).databaseNotifications
162
- assert.ok(dn.broadcast, 'broadcast meta is present')
163
- assert.equal(dn.broadcast.channel, 'private-pilotiq-notifications.42')
164
- assert.equal(dn.broadcast.event, 'notification.created')
165
- assert.equal(dn.broadcast.wsUrl, '') // empty -> client falls back to same-origin
166
- })
167
-
168
- it('honors a custom wsUrl', async () => {
169
- const p = Pilotiq.make('admin')
170
- .user(() => ({ id: 'u-1' }))
171
- .databaseNotifications({ broadcast: { wsUrl: 'wss://x.test/ws' } })
172
- const panel = await panelInfo(p)
173
- const dn = (panel as any).databaseNotifications
174
- assert.equal(dn.broadcast.wsUrl, 'wss://x.test/ws')
175
- assert.equal(dn.broadcast.channel, 'private-pilotiq-notifications.u-1')
176
- })
177
-
178
- it('absent when user has no id (channel cannot be scoped)', async () => {
179
- const p = Pilotiq.make('admin')
180
- .user(() => ({ name: 'Anonymous' }) as unknown as { id: string })
181
- .databaseNotifications()
182
- .databaseNotificationsBroadcast()
183
- const panel = await panelInfo(p)
184
- const dn = (panel as any).databaseNotifications
185
- assert.equal(dn?.broadcast, undefined)
186
- })
187
- })