@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.
- package/CHANGELOG.md +57 -0
- package/boost/guidelines.md +571 -0
- package/boost/skills/pilotiq-actions/SKILL.md +49 -0
- package/boost/skills/pilotiq-actions/rules/dispatch-modes.md +177 -0
- package/boost/skills/pilotiq-actions/rules/factories.md +130 -0
- package/boost/skills/pilotiq-actions/rules/visibility-and-authorization.md +125 -0
- package/boost/skills/pilotiq-fields/SKILL.md +47 -0
- package/boost/skills/pilotiq-fields/rules/field-catalog.md +288 -0
- package/boost/skills/pilotiq-fields/rules/reactive-fields.md +199 -0
- package/boost/skills/pilotiq-fields/rules/validation.md +198 -0
- package/boost/skills/pilotiq-relations/SKILL.md +47 -0
- package/boost/skills/pilotiq-relations/rules/relation-managers.md +256 -0
- package/boost/skills/pilotiq-relations/rules/repeater-relationship.md +177 -0
- package/boost/skills/pilotiq-resource/SKILL.md +61 -0
- package/boost/skills/pilotiq-resource/rules/authorization.md +242 -0
- package/boost/skills/pilotiq-resource/rules/defining-resources.md +228 -0
- package/boost/skills/pilotiq-resource/rules/page-overrides.md +296 -0
- package/dist/Pilotiq.d.ts +31 -0
- package/dist/Pilotiq.d.ts.map +1 -1
- package/dist/Pilotiq.js +3 -1
- package/dist/Pilotiq.js.map +1 -1
- package/dist/PilotiqRegistry.d.ts +13 -0
- package/dist/PilotiqRegistry.d.ts.map +1 -1
- package/dist/PilotiqRegistry.js +15 -0
- package/dist/PilotiqRegistry.js.map +1 -1
- package/dist/pageData/misc.d.ts.map +1 -1
- package/dist/pageData/misc.js +6 -0
- package/dist/pageData/misc.js.map +1 -1
- package/dist/pageData/navigation.d.ts +1 -0
- package/dist/pageData/navigation.d.ts.map +1 -1
- package/dist/pageData/navigation.js +3 -0
- package/dist/pageData/navigation.js.map +1 -1
- package/dist/pageData/relationPages.d.ts.map +1 -1
- package/dist/pageData/relationPages.js +3 -0
- package/dist/pageData/relationPages.js.map +1 -1
- package/dist/pageData/resourcePages.d.ts.map +1 -1
- package/dist/pageData/resourcePages.js +8 -0
- package/dist/pageData/resourcePages.js.map +1 -1
- package/dist/react/AppShell.d.ts +8 -0
- package/dist/react/AppShell.d.ts.map +1 -1
- package/dist/react/AppShell.js.map +1 -1
- package/dist/react/layouts/SidebarLayout.d.ts.map +1 -1
- package/dist/react/layouts/SidebarLayout.js +10 -2
- package/dist/react/layouts/SidebarLayout.js.map +1 -1
- package/dist/react/widgets/StatsOverviewRenderer.d.ts.map +1 -1
- package/dist/react/widgets/StatsOverviewRenderer.js +32 -18
- package/dist/react/widgets/StatsOverviewRenderer.js.map +1 -1
- package/dist/routes/relations.d.ts.map +1 -1
- package/dist/routes/relations.js +25 -18
- package/dist/routes/relations.js.map +1 -1
- package/dist/routes/resources.js.map +1 -1
- package/package.json +10 -5
- package/.turbo/turbo-build.log +0 -8
- package/CLAUDE.md +0 -265
- package/src/Cluster.test.ts +0 -283
- package/src/Cluster.ts +0 -83
- package/src/Column.test.ts +0 -199
- package/src/Column.ts +0 -710
- package/src/Global.test.ts +0 -367
- package/src/Global.ts +0 -169
- package/src/Page.test.ts +0 -114
- package/src/Page.ts +0 -208
- package/src/Pilotiq.perf.test.ts +0 -252
- package/src/Pilotiq.test.ts +0 -129
- package/src/Pilotiq.ts +0 -1158
- package/src/PilotiqRegistry.ts +0 -36
- package/src/PilotiqServiceProvider.ts +0 -121
- package/src/RelationManager.test.ts +0 -400
- package/src/RelationManager.ts +0 -527
- package/src/RenderHook.test.ts +0 -252
- package/src/RenderHook.ts +0 -242
- package/src/Resource.test.ts +0 -284
- package/src/Resource.ts +0 -526
- package/src/RightPanel.test.ts +0 -202
- package/src/RightPanel.ts +0 -132
- package/src/Tab.test.ts +0 -91
- package/src/Tab.ts +0 -156
- package/src/UserMenuItem.ts +0 -145
- package/src/actions/Action.test.ts +0 -2526
- package/src/actions/Action.ts +0 -1515
- package/src/actions/ActionGroup.test.ts +0 -112
- package/src/actions/ActionGroup.ts +0 -173
- package/src/actions/attachFactory.ts +0 -172
- package/src/actions/bulkFactories.ts +0 -168
- package/src/actions/crudFactories.ts +0 -220
- package/src/actions/exportFactory.ts +0 -225
- package/src/actions/factoryHelpers.ts +0 -177
- package/src/actions/importFactory.ts +0 -243
- package/src/actions/index.ts +0 -17
- package/src/actions/m2mFactories.ts +0 -193
- package/src/actions/relationFactories.ts +0 -372
- package/src/applyPageHooks.test.ts +0 -463
- package/src/applyPageHooks.ts +0 -330
- package/src/authorization.test.ts +0 -483
- package/src/breadcrumbs.test.ts +0 -238
- package/src/cells/coerce.test.ts +0 -85
- package/src/cells/coerce.ts +0 -84
- package/src/clusterPaths.ts +0 -35
- package/src/columns/BadgeColumn.test.ts +0 -54
- package/src/columns/BadgeColumn.ts +0 -32
- package/src/columns/BooleanColumn.test.ts +0 -41
- package/src/columns/BooleanColumn.ts +0 -18
- package/src/columns/ColorColumn.test.ts +0 -37
- package/src/columns/ColorColumn.ts +0 -38
- package/src/columns/IconColumn.test.ts +0 -54
- package/src/columns/IconColumn.ts +0 -37
- package/src/columns/ImageColumn.test.ts +0 -41
- package/src/columns/ImageColumn.ts +0 -28
- package/src/columns/SelectColumn.ts +0 -98
- package/src/columns/TextColumn.test.ts +0 -190
- package/src/columns/TextColumn.ts +0 -20
- package/src/columns/TextInputColumn.ts +0 -68
- package/src/columns/ToggleColumn.ts +0 -46
- package/src/columns/editableColumns.test.ts +0 -238
- package/src/columns/index.ts +0 -9
- package/src/defaultGlobalPages.ts +0 -95
- package/src/defaultPages.test.ts +0 -634
- package/src/defaultPages.ts +0 -617
- package/src/defaultViewPage.test.ts +0 -147
- package/src/elements/Form.test.ts +0 -223
- package/src/elements/Form.ts +0 -416
- package/src/elements/ListTabs.ts +0 -28
- package/src/elements/Table.test.ts +0 -422
- package/src/elements/Table.ts +0 -850
- package/src/elements/TableGroup.test.ts +0 -260
- package/src/elements/TableGroup.ts +0 -334
- package/src/elements/dispatchAction.test.ts +0 -463
- package/src/elements/dispatchAction.ts +0 -355
- package/src/elements/dispatchForm.test.ts +0 -477
- package/src/elements/dispatchForm.ts +0 -1993
- package/src/elements/dispatchTable.test.ts +0 -1514
- package/src/elements/dispatchTable.ts +0 -745
- package/src/elements/index.ts +0 -21
- package/src/entries/BadgeEntry.ts +0 -39
- package/src/entries/CodeEntry.test.ts +0 -40
- package/src/entries/CodeEntry.ts +0 -52
- package/src/entries/ColorEntry.ts +0 -63
- package/src/entries/ComponentEntry.test.ts +0 -173
- package/src/entries/ComponentEntry.ts +0 -95
- package/src/entries/Entry.ts +0 -304
- package/src/entries/IconEntry.ts +0 -49
- package/src/entries/ImageEntry.ts +0 -61
- package/src/entries/KeyValueEntry.ts +0 -47
- package/src/entries/RepeatableEntry.test.ts +0 -239
- package/src/entries/RepeatableEntry.ts +0 -173
- package/src/entries/TextEntry.test.ts +0 -394
- package/src/entries/TextEntry.ts +0 -60
- package/src/entries/index.ts +0 -12
- package/src/entries/leaves.test.ts +0 -306
- package/src/entries/registry.ts +0 -54
- package/src/fields/BuilderField.test.ts +0 -1188
- package/src/fields/BuilderField.ts +0 -605
- package/src/fields/BuilderRelationship.test.ts +0 -811
- package/src/fields/CheckboxField.test.ts +0 -44
- package/src/fields/CheckboxField.ts +0 -27
- package/src/fields/CheckboxListField.test.ts +0 -99
- package/src/fields/CheckboxListField.ts +0 -66
- package/src/fields/ColorPickerField.test.ts +0 -33
- package/src/fields/ColorPickerField.ts +0 -25
- package/src/fields/DateField.ts +0 -54
- package/src/fields/DateTimeField.test.ts +0 -55
- package/src/fields/EmailField.ts +0 -16
- package/src/fields/Field.test.ts +0 -654
- package/src/fields/Field.ts +0 -817
- package/src/fields/FileUploadField.test.ts +0 -143
- package/src/fields/FileUploadField.ts +0 -159
- package/src/fields/HiddenField.test.ts +0 -27
- package/src/fields/HiddenField.ts +0 -28
- package/src/fields/KeyValueField.test.ts +0 -105
- package/src/fields/KeyValueField.ts +0 -55
- package/src/fields/MarkdownField.test.ts +0 -167
- package/src/fields/MarkdownField.ts +0 -162
- package/src/fields/NumberField.ts +0 -33
- package/src/fields/RadioField.test.ts +0 -94
- package/src/fields/RadioField.ts +0 -67
- package/src/fields/RepeaterField.test.ts +0 -1806
- package/src/fields/RepeaterField.ts +0 -939
- package/src/fields/RepeaterRelationship.test.ts +0 -1923
- package/src/fields/RepeaterSimple.test.ts +0 -248
- package/src/fields/RowButton.test.ts +0 -219
- package/src/fields/RowButton.ts +0 -135
- package/src/fields/SelectField.test.ts +0 -192
- package/src/fields/SelectField.ts +0 -235
- package/src/fields/SliderField.test.ts +0 -50
- package/src/fields/SliderField.ts +0 -53
- package/src/fields/SlugField.ts +0 -24
- package/src/fields/TagsInputField.test.ts +0 -154
- package/src/fields/TagsInputField.ts +0 -133
- package/src/fields/TextField.test.ts +0 -213
- package/src/fields/TextField.ts +0 -177
- package/src/fields/TextareaField.test.ts +0 -58
- package/src/fields/TextareaField.ts +0 -59
- package/src/fields/ToggleButtonsField.test.ts +0 -106
- package/src/fields/ToggleButtonsField.ts +0 -59
- package/src/fields/ToggleField.ts +0 -16
- package/src/fields/disableOptionsWhenSelectedInSiblingRepeaterItems.test.ts +0 -319
- package/src/fields/optionsResolver.ts +0 -95
- package/src/fields/resolveField.ts +0 -28
- package/src/filters/BooleanFilter.ts +0 -35
- package/src/filters/DateRangeFilter.test.ts +0 -194
- package/src/filters/DateRangeFilter.ts +0 -148
- package/src/filters/Filter.test.ts +0 -268
- package/src/filters/Filter.ts +0 -184
- package/src/filters/FormFilter.test.ts +0 -238
- package/src/filters/FormFilter.ts +0 -215
- package/src/filters/MultiSelectFilter.test.ts +0 -119
- package/src/filters/MultiSelectFilter.ts +0 -78
- package/src/filters/QueryBuilderFilter.test.ts +0 -662
- package/src/filters/QueryBuilderFilter.ts +0 -398
- package/src/filters/SelectFilter.ts +0 -46
- package/src/filters/TernaryFilter.test.ts +0 -160
- package/src/filters/TernaryFilter.ts +0 -72
- package/src/filters/TrashedFilter.test.ts +0 -149
- package/src/filters/TrashedFilter.ts +0 -55
- package/src/filters/queryBuilder/BooleanConstraint.ts +0 -31
- package/src/filters/queryBuilder/Constraint.ts +0 -115
- package/src/filters/queryBuilder/DateConstraint.ts +0 -69
- package/src/filters/queryBuilder/NumberConstraint.ts +0 -66
- package/src/filters/queryBuilder/SelectConstraint.ts +0 -72
- package/src/filters/queryBuilder/TextConstraint.ts +0 -64
- package/src/filters/queryBuilder/index.ts +0 -12
- package/src/icons/index.ts +0 -2
- package/src/icons/lucide.ts +0 -204
- package/src/icons/registry.test.ts +0 -56
- package/src/icons/registry.ts +0 -41
- package/src/icons/types.ts +0 -47
- package/src/index.ts +0 -525
- package/src/io/csv.test.ts +0 -142
- package/src/io/csv.ts +0 -170
- package/src/nestedRelationManagerData.test.ts +0 -547
- package/src/notifications/Notification.test.ts +0 -210
- package/src/notifications/Notification.ts +0 -354
- package/src/notifications/broadcast.test.ts +0 -110
- package/src/notifications/broadcast.ts +0 -95
- package/src/notifications/database.test.ts +0 -383
- package/src/notifications/database.ts +0 -398
- package/src/notifications/databaseNotifications.test.ts +0 -187
- package/src/notifications/dispatchNotificationAction.test.ts +0 -341
- package/src/notifications/dispatchNotificationAction.ts +0 -142
- package/src/notifications/flash.test.ts +0 -89
- package/src/notifications/flash.ts +0 -71
- package/src/notifications/index.ts +0 -45
- package/src/notifications/registerBroadcastAuth.test.ts +0 -134
- package/src/notifications/registerBroadcastAuth.ts +0 -100
- package/src/notifications/resolveSavedNotification.test.ts +0 -82
- package/src/notifications/resolveSavedNotification.ts +0 -59
- package/src/notifications/types.ts +0 -93
- package/src/orm/m2mAccessor.ts +0 -66
- package/src/orm/modelDefaults.test.ts +0 -633
- package/src/orm/modelDefaults.ts +0 -666
- package/src/pageData/breadcrumbs.ts +0 -288
- package/src/pageData/forms.ts +0 -578
- package/src/pageData/helpers.ts +0 -857
- package/src/pageData/misc.ts +0 -347
- package/src/pageData/navigation.ts +0 -842
- package/src/pageData/relationPages.ts +0 -1248
- package/src/pageData/relationTabs.ts +0 -286
- package/src/pageData/resourcePages.ts +0 -609
- package/src/pageData.test.ts +0 -1545
- package/src/pageData.ts +0 -341
- package/src/plugins/index.ts +0 -8
- package/src/plugins/themeEditor.test.ts +0 -36
- package/src/plugins/themeEditor.ts +0 -45
- package/src/react/AppShell.tsx +0 -251
- package/src/react/CollabExtensionFactoryRegistry.ts +0 -55
- package/src/react/CollabRoomContext.ts +0 -98
- package/src/react/CollabTextRendererRegistry.ts +0 -102
- package/src/react/CommandPalette.tsx +0 -375
- package/src/react/CurrentUserContext.tsx +0 -50
- package/src/react/CustomPageWrapperGate.tsx +0 -69
- package/src/react/CustomPageWrapperRegistry.ts +0 -45
- package/src/react/FieldFocusReporterRegistry.ts +0 -37
- package/src/react/FieldLabelSlotRegistry.ts +0 -30
- package/src/react/FieldPresenceRegistry.ts +0 -46
- package/src/react/FormCollabBindingRegistry.ts +0 -242
- package/src/react/FormStateContext.tsx +0 -591
- package/src/react/HeadHooks.tsx +0 -126
- package/src/react/MarkdownEditorRegistry.test.ts +0 -38
- package/src/react/MarkdownEditorRegistry.ts +0 -107
- package/src/react/NotificationActionStrip.tsx +0 -263
- package/src/react/NotificationBell.tsx +0 -426
- package/src/react/PendingSuggestionApplierRegistry.test.ts +0 -97
- package/src/react/PendingSuggestionApplierRegistry.ts +0 -98
- package/src/react/PendingSuggestionOverlayRegistry.ts +0 -54
- package/src/react/PendingSuggestionsContext.tsx +0 -172
- package/src/react/RecordWrapperGate.tsx +0 -58
- package/src/react/RecordWrapperRegistry.ts +0 -39
- package/src/react/RenderHookSlot.tsx +0 -32
- package/src/react/RightSidebar.tsx +0 -257
- package/src/react/RightSidebarContext.tsx +0 -234
- package/src/react/RightSidebarTrigger.tsx +0 -53
- package/src/react/RowCoordsContext.tsx +0 -23
- package/src/react/SchemaRenderer.tsx +0 -549
- package/src/react/SearchTrigger.tsx +0 -46
- package/src/react/ThemeProvider.tsx +0 -93
- package/src/react/ThemeSettingsPage.tsx +0 -579
- package/src/react/ThemeToggle.tsx +0 -20
- package/src/react/Toaster.tsx +0 -158
- package/src/react/UserMenu.tsx +0 -196
- package/src/react/WidgetDataContext.tsx +0 -157
- package/src/react/cells/EditableCell.tsx +0 -389
- package/src/react/component-slots.test.ts +0 -103
- package/src/react/component-slots.ts +0 -116
- package/src/react/fieldJsHandler.test.ts +0 -166
- package/src/react/fieldJsHandler.ts +0 -79
- package/src/react/fields/BuilderInput.tsx +0 -1078
- package/src/react/fields/CheckboxInput.tsx +0 -39
- package/src/react/fields/CheckboxListInput.tsx +0 -102
- package/src/react/fields/ColorInput.tsx +0 -71
- package/src/react/fields/DateFieldInput.tsx +0 -70
- package/src/react/fields/DateTimeInput.tsx +0 -62
- package/src/react/fields/FieldShell.tsx +0 -348
- package/src/react/fields/FileUploadInput.tsx +0 -639
- package/src/react/fields/HiddenInput.tsx +0 -17
- package/src/react/fields/KeyValueInput.tsx +0 -230
- package/src/react/fields/MarkdownInput.tsx +0 -560
- package/src/react/fields/RadioInput.tsx +0 -81
- package/src/react/fields/RepeaterInput.test.ts +0 -116
- package/src/react/fields/RepeaterInput.tsx +0 -1420
- package/src/react/fields/SelectFieldInput.tsx +0 -280
- package/src/react/fields/SliderInput.tsx +0 -81
- package/src/react/fields/TagsInput.tsx +0 -283
- package/src/react/fields/TextLikeInput.tsx +0 -256
- package/src/react/fields/ToggleButtonsInput.tsx +0 -60
- package/src/react/fields/ToggleFieldInput.tsx +0 -56
- package/src/react/fields/relationshipRenameDispatch.test.ts +0 -106
- package/src/react/fields/relationshipRenameDispatch.ts +0 -97
- package/src/react/fields/repeaterReconcile.test.ts +0 -114
- package/src/react/fields/repeaterReconcile.ts +0 -104
- package/src/react/fields/rowChromeButton.tsx +0 -336
- package/src/react/fields/rowState.ts +0 -106
- package/src/react/fields/syncRowGates.test.ts +0 -202
- package/src/react/fields/syncRowGates.ts +0 -66
- package/src/react/fields/textInputControls.tsx +0 -238
- package/src/react/fields/useRowReorderDnd.ts +0 -78
- package/src/react/formStateHelpers.test.ts +0 -508
- package/src/react/formStateHelpers.ts +0 -381
- package/src/react/hooks/use-mobile.ts +0 -19
- package/src/react/icon-context.tsx +0 -60
- package/src/react/index.ts +0 -194
- package/src/react/layouts/SidebarLayout.tsx +0 -250
- package/src/react/layouts/TopbarLayout.tsx +0 -258
- package/src/react/navigate.tsx +0 -37
- package/src/react/onProviderSynced.test.ts +0 -90
- package/src/react/parseRecordEditUrl.test.ts +0 -122
- package/src/react/parseRecordEditUrl.ts +0 -94
- package/src/react/persistedState.ts +0 -40
- package/src/react/registry.ts +0 -48
- package/src/react/right-panel-registry.tsx +0 -47
- package/src/react/schemaRenderer/AlertRenderer.tsx +0 -112
- package/src/react/schemaRenderer/EntryRenderer.tsx +0 -501
- package/src/react/schemaRenderer/SectionRenderer.tsx +0 -120
- package/src/react/schemaRenderer/SimpleElements.tsx +0 -306
- package/src/react/schemaRenderer/TabsRenderer.tsx +0 -62
- package/src/react/schemaRenderer/WizardRenderer.tsx +0 -338
- package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +0 -177
- package/src/react/schemaRenderer/action/ActionModalDialog.tsx +0 -273
- package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +0 -61
- package/src/react/schemaRenderer/action/HandlerActionButton.tsx +0 -43
- package/src/react/schemaRenderer/action/MethodActionButton.tsx +0 -64
- package/src/react/schemaRenderer/action/buttons.tsx +0 -99
- package/src/react/schemaRenderer/action/helpers.ts +0 -140
- package/src/react/schemaRenderer/action/renderAction.tsx +0 -245
- package/src/react/schemaRenderer/columnFormat.ts +0 -65
- package/src/react/schemaRenderer/constants.ts +0 -50
- package/src/react/schemaRenderer/form/FormRenderer.tsx +0 -274
- package/src/react/schemaRenderer/form/renderField.tsx +0 -511
- package/src/react/schemaRenderer/helpers.tsx +0 -81
- package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +0 -308
- package/src/react/schemaRenderer/table/TableRenderer.tsx +0 -123
- package/src/react/schemaRenderer/table/TableRendererBody.tsx +0 -974
- package/src/react/schemaRenderer/table/filters.tsx +0 -1233
- package/src/react/schemaRenderer/table/formatCell.tsx +0 -264
- package/src/react/schemaRenderer/table/links.tsx +0 -112
- package/src/react/schemaRenderer/table/renderRowActions.tsx +0 -52
- package/src/react/schemaRenderer/table/url.tsx +0 -143
- package/src/react/theme-preview/apply.ts +0 -99
- package/src/react/theme-preview/build-html.ts +0 -436
- package/src/react/ui/button.tsx +0 -51
- package/src/react/ui/calendar.tsx +0 -67
- package/src/react/ui/checkbox.tsx +0 -29
- package/src/react/ui/dialog.tsx +0 -108
- package/src/react/ui/dropdown-menu.tsx +0 -97
- package/src/react/ui/input.tsx +0 -20
- package/src/react/ui/label.tsx +0 -21
- package/src/react/ui/popover.tsx +0 -50
- package/src/react/ui/select.tsx +0 -169
- package/src/react/ui/separator.tsx +0 -25
- package/src/react/ui/sheet.tsx +0 -136
- package/src/react/ui/sidebar.tsx +0 -723
- package/src/react/ui/skeleton.tsx +0 -13
- package/src/react/ui/slider.tsx +0 -34
- package/src/react/ui/switch.tsx +0 -28
- package/src/react/ui/table.tsx +0 -105
- package/src/react/ui/tabs.tsx +0 -63
- package/src/react/ui/textarea.tsx +0 -18
- package/src/react/ui/tooltip.tsx +0 -64
- package/src/react/useResizableWidth.ts +0 -139
- package/src/react/utils.ts +0 -6
- package/src/react/widgetRegistry.test.ts +0 -43
- package/src/react/widgetRegistry.ts +0 -50
- package/src/react/widgets/StatsOverviewRenderer.tsx +0 -232
- package/src/react/widgets/TableWidgetRenderer.tsx +0 -231
- package/src/react/widgets/ViewRenderer.tsx +0 -71
- package/src/relationManagerData.test.ts +0 -1595
- package/src/richtext/index.ts +0 -8
- package/src/richtext/registry.ts +0 -89
- package/src/routes/globals.ts +0 -148
- package/src/routes/guard.test.ts +0 -325
- package/src/routes/helpers.ts +0 -704
- package/src/routes/pages.ts +0 -175
- package/src/routes/panel.ts +0 -204
- package/src/routes/relations.ts +0 -1243
- package/src/routes/resources.ts +0 -781
- package/src/routes/theme.ts +0 -91
- package/src/routes-nested-relations.test.ts +0 -676
- package/src/routes-relations.test.ts +0 -972
- package/src/routes.test.ts +0 -2027
- package/src/routes.ts +0 -303
- package/src/schema/Alert.test.ts +0 -109
- package/src/schema/Alert.ts +0 -131
- package/src/schema/Block.ts +0 -169
- package/src/schema/Breadcrumbs.ts +0 -40
- package/src/schema/Card.ts +0 -35
- package/src/schema/Divider.ts +0 -20
- package/src/schema/Element.ts +0 -219
- package/src/schema/EmptyState.test.ts +0 -37
- package/src/schema/EmptyState.ts +0 -63
- package/src/schema/Fieldset.ts +0 -43
- package/src/schema/Grid.ts +0 -43
- package/src/schema/Group.ts +0 -30
- package/src/schema/Heading.ts +0 -39
- package/src/schema/Html.ts +0 -67
- package/src/schema/Icon.ts +0 -54
- package/src/schema/Image.ts +0 -57
- package/src/schema/LinkTag.ts +0 -41
- package/src/schema/Markdown.ts +0 -85
- package/src/schema/MetaTag.ts +0 -41
- package/src/schema/RelationTabs.ts +0 -71
- package/src/schema/ScriptTag.ts +0 -55
- package/src/schema/Section.ts +0 -160
- package/src/schema/ServerDataElement.test.ts +0 -140
- package/src/schema/ServerDataElement.ts +0 -156
- package/src/schema/SlotComponent.test.ts +0 -77
- package/src/schema/SlotComponent.ts +0 -71
- package/src/schema/Split.ts +0 -50
- package/src/schema/Stat.test.ts +0 -118
- package/src/schema/Stat.ts +0 -154
- package/src/schema/StatsOverview.test.ts +0 -141
- package/src/schema/StatsOverview.ts +0 -119
- package/src/schema/StyleTag.ts +0 -35
- package/src/schema/TableWidget.test.ts +0 -297
- package/src/schema/TableWidget.ts +0 -289
- package/src/schema/Tabs.ts +0 -79
- package/src/schema/Text.ts +0 -58
- package/src/schema/UnorderedList.ts +0 -49
- package/src/schema/View.test.ts +0 -111
- package/src/schema/View.ts +0 -127
- package/src/schema/Wizard.ts +0 -220
- package/src/schema/containers.test.ts +0 -564
- package/src/schema/headTags.test.ts +0 -134
- package/src/schema/index.ts +0 -40
- package/src/schema/primes.test.ts +0 -269
- package/src/schema/resolveSchema.test.ts +0 -379
- package/src/schema/resolveSchema.ts +0 -917
- package/src/schema/sanitize.ts +0 -58
- package/src/search.test.ts +0 -446
- package/src/search.ts +0 -178
- package/src/sessionFilters.test.ts +0 -375
- package/src/sessionFilters.ts +0 -143
- package/src/slot-components/index.ts +0 -10
- package/src/slot-components/registry.ts +0 -56
- package/src/styles/file-upload.css +0 -13
- package/src/summarizers/Summarizer.test.ts +0 -84
- package/src/summarizers/Summarizer.ts +0 -123
- package/src/summarizers/index.ts +0 -11
- package/src/theme/base-colors.ts +0 -68
- package/src/theme/chart-colors.ts +0 -50
- package/src/theme/colors.ts +0 -447
- package/src/theme/generate-css.test.ts +0 -139
- package/src/theme/generate-css.ts +0 -44
- package/src/theme/generate-scale.test.ts +0 -106
- package/src/theme/generate-scale.ts +0 -97
- package/src/theme/icon-map.ts +0 -42
- package/src/theme/index.ts +0 -34
- package/src/theme/migrate.test.ts +0 -178
- package/src/theme/migrate.ts +0 -81
- package/src/theme/presets.ts +0 -135
- package/src/theme/radius.ts +0 -18
- package/src/theme/resolve.test.ts +0 -238
- package/src/theme/resolve.ts +0 -96
- package/src/theme/spacing.ts +0 -18
- package/src/theme/storage.test.ts +0 -126
- package/src/theme/storage.ts +0 -106
- package/src/theme/theme-colors.ts +0 -88
- package/src/theme/types.ts +0 -125
- package/src/uploads/UploadAdapter.ts +0 -35
- package/src/uploads/index.ts +0 -2
- package/src/uploads/localUpload.test.ts +0 -70
- package/src/uploads/localUpload.ts +0 -84
- package/src/validation/Validator.ts +0 -49
- package/src/validation/index.ts +0 -28
- package/src/validation/rules.ts +0 -78
- package/src/validation/runValidators.ts +0 -435
- package/src/validation/uniqueValidator.test.ts +0 -196
- package/src/validation/uniqueValidator.ts +0 -133
- package/src/validation/validators.test.ts +0 -268
- package/src/vite.test.ts +0 -184
- package/src/vite.ts +0 -787
- package/src/widgets/index.ts +0 -10
- package/src/widgets/registry.ts +0 -45
- package/src/widgets.test.ts +0 -592
- package/tsconfig.build.json +0 -11
- package/tsconfig.json +0 -4
- package/tsconfig.test.json +0 -10
- package/views/react/Dashboard.tsx +0 -27
- package/views/react/Resources/Form.tsx +0 -102
- package/views/react/Resources/Index.tsx +0 -49
package/src/react/HeadHooks.tsx
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import type { ElementMeta } from '../schema/Element.js'
|
|
3
|
-
import type { RenderHookMap, RenderHookName } from '../RenderHook.js'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Mount point for the four `panels::head.*` render-hook slots inside the
|
|
7
|
-
* generated `+Head.tsx`. Walks the resolved `ElementMeta[]` per slot and
|
|
8
|
-
* emits real React elements (`<meta>` / `<link>` / `<script>` / `<style>`)
|
|
9
|
-
* directly into the head fragment.
|
|
10
|
-
*
|
|
11
|
-
* Body-level Element types in a head slot are silently skipped with a
|
|
12
|
-
* warning — `<div>` / `<p>` etc. would terminate `<head>` parsing in the
|
|
13
|
-
* browser and break the whole page.
|
|
14
|
-
*
|
|
15
|
-
* Slot ordering matches Filament's documented layout:
|
|
16
|
-
* 1. `panels::head.start` — first head children
|
|
17
|
-
* 2. (built-in chrome — fonts, FOUC script — emitted by `+Head.tsx`)
|
|
18
|
-
* 3. `panels::head.end` — after built-in chrome
|
|
19
|
-
* 4. `panels::scripts` — late-load `<script>` block
|
|
20
|
-
* 5. `panels::styles` — late-load `<style>` block
|
|
21
|
-
*
|
|
22
|
-
* Renders nothing when no hooks were registered for any of the four
|
|
23
|
-
* slots. Cheap when unused.
|
|
24
|
-
*/
|
|
25
|
-
export function HeadHooks({
|
|
26
|
-
hooks,
|
|
27
|
-
position,
|
|
28
|
-
}: {
|
|
29
|
-
hooks: RenderHookMap | undefined
|
|
30
|
-
position: 'start' | 'end'
|
|
31
|
-
}) {
|
|
32
|
-
if (!hooks) return null
|
|
33
|
-
|
|
34
|
-
const slots: readonly RenderHookName[] = position === 'start'
|
|
35
|
-
? ['panels::head.start']
|
|
36
|
-
: ['panels::head.end', 'panels::scripts', 'panels::styles']
|
|
37
|
-
|
|
38
|
-
const out: React.ReactNode[] = []
|
|
39
|
-
let key = 0
|
|
40
|
-
for (const slot of slots) {
|
|
41
|
-
const metas = hooks[slot]
|
|
42
|
-
if (!metas || metas.length === 0) continue
|
|
43
|
-
for (const meta of metas) {
|
|
44
|
-
const node = renderHeadElement(meta, slot, key++)
|
|
45
|
-
if (node !== null) out.push(node)
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
if (out.length === 0) return null
|
|
49
|
-
return <>{out}</>
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function renderHeadElement(
|
|
53
|
-
meta: ElementMeta,
|
|
54
|
-
slot: string,
|
|
55
|
-
key: number,
|
|
56
|
-
): React.ReactNode {
|
|
57
|
-
// Cast through `unknown` — wire shapes carry whatever the head-tag's
|
|
58
|
-
// `toMeta()` emitted; the `type` discriminator already disambiguates.
|
|
59
|
-
const m = meta as unknown as Record<string, unknown> & { type: string }
|
|
60
|
-
switch (m.type) {
|
|
61
|
-
case 'meta': {
|
|
62
|
-
const props: Record<string, unknown> = { key }
|
|
63
|
-
if (m['name'] !== undefined) props['name'] = m['name']
|
|
64
|
-
if (m['property'] !== undefined) props['property'] = m['property']
|
|
65
|
-
if (m['httpEquiv'] !== undefined) props['httpEquiv'] = m['httpEquiv']
|
|
66
|
-
if (m['charset'] !== undefined) props['charSet'] = m['charset']
|
|
67
|
-
if (m['content'] !== undefined) props['content'] = m['content']
|
|
68
|
-
if (props['name'] === undefined && props['property'] === undefined &&
|
|
69
|
-
props['httpEquiv'] === undefined && props['charSet'] === undefined) {
|
|
70
|
-
if (typeof console !== 'undefined') {
|
|
71
|
-
console.warn(`[pilotiq] MetaTag in ${slot} skipped — needs name / property / httpEquiv / charset`)
|
|
72
|
-
}
|
|
73
|
-
return null
|
|
74
|
-
}
|
|
75
|
-
return React.createElement('meta', props)
|
|
76
|
-
}
|
|
77
|
-
case 'link': {
|
|
78
|
-
const props: Record<string, unknown> = { key, rel: m['rel'] }
|
|
79
|
-
if (m['href'] !== undefined) props['href'] = m['href']
|
|
80
|
-
if (m['mimeType'] !== undefined) props['type'] = m['mimeType']
|
|
81
|
-
if (m['media'] !== undefined) props['media'] = m['media']
|
|
82
|
-
if (m['sizes'] !== undefined) props['sizes'] = m['sizes']
|
|
83
|
-
if (m['as'] !== undefined) props['as'] = m['as']
|
|
84
|
-
if (m['integrity'] !== undefined) props['integrity'] = m['integrity']
|
|
85
|
-
if (m['crossOrigin'] !== undefined) props['crossOrigin'] = m['crossOrigin']
|
|
86
|
-
if (m['referrerPolicy'] !== undefined) props['referrerPolicy'] = m['referrerPolicy']
|
|
87
|
-
if (m['hrefLang'] !== undefined) props['hrefLang'] = m['hrefLang']
|
|
88
|
-
return React.createElement('link', props)
|
|
89
|
-
}
|
|
90
|
-
case 'script': {
|
|
91
|
-
const props: Record<string, unknown> = { key }
|
|
92
|
-
if (m['src'] !== undefined) props['src'] = m['src']
|
|
93
|
-
if (m['mimeType'] !== undefined) props['type'] = m['mimeType']
|
|
94
|
-
if (m['async']) props['async'] = true
|
|
95
|
-
if (m['defer']) props['defer'] = true
|
|
96
|
-
if (m['noModule']) props['noModule'] = true
|
|
97
|
-
if (m['integrity'] !== undefined) props['integrity'] = m['integrity']
|
|
98
|
-
if (m['crossOrigin'] !== undefined) props['crossOrigin'] = m['crossOrigin']
|
|
99
|
-
if (m['referrerPolicy'] !== undefined) props['referrerPolicy'] = m['referrerPolicy']
|
|
100
|
-
if (m['nonce'] !== undefined) props['nonce'] = m['nonce']
|
|
101
|
-
const dataAttrs = m['dataAttributes'] as Record<string, string> | undefined
|
|
102
|
-
if (dataAttrs) {
|
|
103
|
-
for (const [k, v] of Object.entries(dataAttrs)) props[`data-${k}`] = v
|
|
104
|
-
}
|
|
105
|
-
// src-mode and inline-mode are mutually exclusive — src wins per HTML spec.
|
|
106
|
-
if (m['src'] === undefined && typeof m['body'] === 'string') {
|
|
107
|
-
props['dangerouslySetInnerHTML'] = { __html: m['body'] as string }
|
|
108
|
-
}
|
|
109
|
-
return React.createElement('script', props)
|
|
110
|
-
}
|
|
111
|
-
case 'style': {
|
|
112
|
-
const props: Record<string, unknown> = {
|
|
113
|
-
key,
|
|
114
|
-
dangerouslySetInnerHTML: { __html: (m['css'] as string) ?? '' },
|
|
115
|
-
}
|
|
116
|
-
if (m['nonce'] !== undefined) props['nonce'] = m['nonce']
|
|
117
|
-
return React.createElement('style', props)
|
|
118
|
-
}
|
|
119
|
-
default: {
|
|
120
|
-
if (typeof console !== 'undefined') {
|
|
121
|
-
console.warn(`[pilotiq] non-head element type "${m.type}" in ${slot} skipped`)
|
|
122
|
-
}
|
|
123
|
-
return null
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { describe, it, beforeEach } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
registerMarkdownEditor,
|
|
6
|
-
getMarkdownEditor,
|
|
7
|
-
} from './MarkdownEditorRegistry.js'
|
|
8
|
-
|
|
9
|
-
describe('MarkdownEditorRegistry', () => {
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
registerMarkdownEditor(null)
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
it('returns null when no editor is registered', () => {
|
|
15
|
-
assert.equal(getMarkdownEditor(), null)
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
it('stores the registered editor component', () => {
|
|
19
|
-
const Component = () => null
|
|
20
|
-
registerMarkdownEditor(Component)
|
|
21
|
-
assert.equal(getMarkdownEditor(), Component)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('clears when called with null', () => {
|
|
25
|
-
const Component = () => null
|
|
26
|
-
registerMarkdownEditor(Component)
|
|
27
|
-
registerMarkdownEditor(null)
|
|
28
|
-
assert.equal(getMarkdownEditor(), null)
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('last registration wins', () => {
|
|
32
|
-
const A = () => null
|
|
33
|
-
const B = () => null
|
|
34
|
-
registerMarkdownEditor(A)
|
|
35
|
-
registerMarkdownEditor(B)
|
|
36
|
-
assert.equal(getMarkdownEditor(), B)
|
|
37
|
-
})
|
|
38
|
-
})
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import type { ComponentType } from 'react'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Module-level registry slot for the WYSIWYG markdown editor renderer.
|
|
5
|
-
*
|
|
6
|
-
* Wiring posture (mirrors `CollabTextRendererRegistry` /
|
|
7
|
-
* `FormCollabBindingRegistry`):
|
|
8
|
-
* - `@pilotiq/tiptap`'s `registerTiptap(...)` calls `registerMarkdownEditor(...)`
|
|
9
|
-
* once at boot. The registered component closes over `@tiptap/*` +
|
|
10
|
-
* `tiptap-markdown` imports so pilotiq core stays free of any tiptap peer
|
|
11
|
-
* dep — same posture as `CollabTextRendererRegistry`.
|
|
12
|
-
* - `MarkdownInput` checks for the registered component on every mount. When
|
|
13
|
-
* present, it replaces the legacy textarea + manual-toolbar path with a
|
|
14
|
-
* real WYSIWYG editor that serializes to / parses from markdown on the
|
|
15
|
-
* wire. When absent, `MarkdownInput` falls back to today's textarea path so
|
|
16
|
-
* panels that don't install `@pilotiq/tiptap` still get a working editor.
|
|
17
|
-
* - The adapter handles collab itself via the existing `useCollabRoom()` +
|
|
18
|
-
* `getCollabExtensions()` plumbing — when a `<RecordCollabRoom>` is mounted
|
|
19
|
-
* up-tree it binds the editor to the shared `Y.XmlFragment`. Markdown
|
|
20
|
-
* serialization runs locally on every change; only the ProseMirror tree
|
|
21
|
-
* ships over the wire.
|
|
22
|
-
*
|
|
23
|
-
* Wire format on the form remains a plain markdown string under the field
|
|
24
|
-
* `name` — `MarkdownField` doesn't add a new coerce branch. The editor is
|
|
25
|
-
* expected to write the current markdown to a hidden input (or call
|
|
26
|
-
* `onChange` and let the host stamp it) so the form submission round-trip
|
|
27
|
-
* stays identical to the textarea path.
|
|
28
|
-
*/
|
|
29
|
-
export interface MarkdownEditorProps {
|
|
30
|
-
/**
|
|
31
|
-
* Field name — drives the FormData hidden input AND the routing key
|
|
32
|
-
* for AI suggestion delivery, applier registry, and the inline-diff
|
|
33
|
-
* banner. For Repeater / Builder row leaves this is the dotted
|
|
34
|
-
* positional path (`items.0.body`).
|
|
35
|
-
*/
|
|
36
|
-
name: string
|
|
37
|
-
/**
|
|
38
|
-
* Collab-stable identifier for the `Y.XmlFragment` selector. When
|
|
39
|
-
* present, the editor binds its collab fragment under this key
|
|
40
|
-
* instead of `name`. Row leaves pass a row-id-anchored composite
|
|
41
|
-
* (`items.<rowId>.body`) so the fragment survives reorders even as
|
|
42
|
-
* the dotted positional `name` shifts. Top-level fields omit it —
|
|
43
|
-
* `name` is stable on its own, so the fragment key tracks it
|
|
44
|
-
* directly.
|
|
45
|
-
*
|
|
46
|
-
* AI suggestion routing and the FormData hidden input continue to
|
|
47
|
-
* use `name`. The two concerns are intentionally separated: AI tool
|
|
48
|
-
* calls reference fields by their positional FormData name (what
|
|
49
|
-
* the agent sees), while collab needs a key that doesn't churn
|
|
50
|
-
* when rows reorder.
|
|
51
|
-
*/
|
|
52
|
-
fragmentKey?: string
|
|
53
|
-
/**
|
|
54
|
-
* Server-rendered default value (raw markdown string). The renderer parses
|
|
55
|
-
* this into the editor's initial document. When collab is active and the
|
|
56
|
-
* room has no persisted state for this field, the renderer also seeds the
|
|
57
|
-
* `Y.XmlFragment` from this value.
|
|
58
|
-
*/
|
|
59
|
-
defaultValue: string
|
|
60
|
-
/** Optional placeholder hint shown in the editor when empty. */
|
|
61
|
-
placeholder?: string
|
|
62
|
-
/** Disabled / read-only state. */
|
|
63
|
-
disabled?: boolean
|
|
64
|
-
/** Fired on every editor change with the current serialized markdown. */
|
|
65
|
-
onChange: (markdown: string) => void
|
|
66
|
-
/** Fired on editor blur — host wires this to live-onBlur trigger semantics. */
|
|
67
|
-
onBlur?: () => void
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Configured toolbar buttons. The adapter is free to map these onto its own
|
|
71
|
-
* command set; unknown / unsupported ids are skipped. Empty array hides
|
|
72
|
-
* the toolbar entirely. See `MarkdownField.toolbarButtons()`.
|
|
73
|
-
*/
|
|
74
|
-
toolbarButtons: ReadonlyArray<string>
|
|
75
|
-
/** CSS height for the editor's collapsed state. */
|
|
76
|
-
minHeight?: string
|
|
77
|
-
/** CSS cap on grown height. */
|
|
78
|
-
maxHeight?: string
|
|
79
|
-
/** Sub-directory hint forwarded to the upload adapter on paste-image. */
|
|
80
|
-
fileAttachmentsDirectory?: string
|
|
81
|
-
/** Adapter-defined visibility hint (`'public'` or `'private'`). */
|
|
82
|
-
fileAttachmentsVisibility?: string
|
|
83
|
-
/** Panel upload route — stamped by `pageData.uploadCtx` only when an
|
|
84
|
-
* `UploadAdapter` is registered. Absent → adapter hides upload affordances. */
|
|
85
|
-
uploadUrl?: string
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export type MarkdownEditor = ComponentType<MarkdownEditorProps>
|
|
89
|
-
|
|
90
|
-
let _editor: MarkdownEditor | null = null
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Register the WYSIWYG markdown editor component. Called once at boot by
|
|
94
|
-
* `@pilotiq/tiptap`'s `registerTiptap()` (or directly by an app that imports
|
|
95
|
-
* the renderer). Calling with `null` clears the registry — useful for tests.
|
|
96
|
-
*
|
|
97
|
-
* When no editor is registered, `MarkdownInput` falls back to the textarea +
|
|
98
|
-
* manual-toolbar path that's worked since `MarkdownField` shipped.
|
|
99
|
-
*/
|
|
100
|
-
export function registerMarkdownEditor(component: MarkdownEditor | null): void {
|
|
101
|
-
_editor = component
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/** Returns the registered editor component, or `null` when no adapter is installed. */
|
|
105
|
-
export function getMarkdownEditor(): MarkdownEditor | null {
|
|
106
|
-
return _editor
|
|
107
|
-
}
|
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import React from 'react'
|
|
4
|
-
import type { NotificationActionMeta } from '../notifications/types.js'
|
|
5
|
-
import type { NotificationMeta } from '../notifications/Notification.js'
|
|
6
|
-
import { useNavigate } from './navigate.js'
|
|
7
|
-
import { useIconFor } from './icon-context.js'
|
|
8
|
-
import { cn } from './utils.js'
|
|
9
|
-
import type { ActionColor } from '../actions/Action.js'
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Action strip rendered inside a notification — bell row OR transient
|
|
13
|
-
* toast. Same wire shape on both transports; the differences are:
|
|
14
|
-
*
|
|
15
|
-
* - **Bell rows** carry a `notificationId`, so handler-mode actions
|
|
16
|
-
* dispatch via `${actionUrl}` (the registry-handler endpoint
|
|
17
|
-
* mounted by `databaseNotifications()`). url/post actions also
|
|
18
|
-
* fire a `markAsRead` POST as a client-side side-effect when the
|
|
19
|
-
* stored action carries the flag.
|
|
20
|
-
*
|
|
21
|
-
* - **Transient toasts** have no `notificationId`. v1 supports
|
|
22
|
-
* url/post only — handler-mode actions on toasts log a warning
|
|
23
|
-
* and render disabled. (Named handlers without an id have no
|
|
24
|
-
* dispatch target; closure handlers can't survive the wire round
|
|
25
|
-
* trip into this component anyway.)
|
|
26
|
-
*/
|
|
27
|
-
export interface NotificationActionStripProps {
|
|
28
|
-
actions: readonly NotificationActionMeta[]
|
|
29
|
-
/** Template URL with `:id` and `:actionName` placeholders — set on
|
|
30
|
-
* bell rows; omitted on transient toasts. */
|
|
31
|
-
actionUrlTemplate?: string
|
|
32
|
-
/** Bell-row context — set when the strip lives inside a persisted
|
|
33
|
-
* notification. Drives mark-as-read dispatch + handler routing. */
|
|
34
|
-
notificationId?: string
|
|
35
|
-
/** Bell-row callback — fires when a url/post action with
|
|
36
|
-
* `markAsRead: true` is clicked. Implementer fires the
|
|
37
|
-
* `markAsRead` POST and updates local state optimistically. */
|
|
38
|
-
onMarkAsRead?: (id: string) => void
|
|
39
|
-
/** Drain notifications from a handler dispatch. Bell wires its
|
|
40
|
-
* `useToast()`; toaster passes a no-op (no nesting). */
|
|
41
|
-
onNotify?: (notifs: NotificationMeta[]) => void
|
|
42
|
-
/** Bell wires `setOpen(false)` so the dropdown closes after nav;
|
|
43
|
-
* toaster passes a no-op. */
|
|
44
|
-
onAfterClick?: () => void
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const COLOR_CLASSES: Record<ActionColor, string> = {
|
|
48
|
-
primary: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
49
|
-
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
|
50
|
-
success: 'bg-emerald-500 text-white hover:bg-emerald-600',
|
|
51
|
-
warning: 'bg-amber-500 text-white hover:bg-amber-600',
|
|
52
|
-
info: 'bg-sky-500 text-white hover:bg-sky-600',
|
|
53
|
-
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const COLOR_OUTLINED: Record<ActionColor, string> = {
|
|
57
|
-
primary: 'border border-primary text-primary hover:bg-primary/10',
|
|
58
|
-
destructive: 'border border-destructive text-destructive hover:bg-destructive/10',
|
|
59
|
-
success: 'border border-emerald-500 text-emerald-600 hover:bg-emerald-500/10',
|
|
60
|
-
warning: 'border border-amber-500 text-amber-600 hover:bg-amber-500/10',
|
|
61
|
-
info: 'border border-sky-500 text-sky-600 hover:bg-sky-500/10',
|
|
62
|
-
ghost: 'border border-input hover:bg-accent hover:text-accent-foreground',
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const SIZE_CLASSES: Record<'sm' | 'md' | 'lg', string> = {
|
|
66
|
-
sm: 'h-7 px-2.5 text-xs',
|
|
67
|
-
md: 'h-8 px-3 text-xs',
|
|
68
|
-
lg: 'h-9 px-3.5 text-sm',
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function NotificationActionStrip({
|
|
72
|
-
actions,
|
|
73
|
-
actionUrlTemplate,
|
|
74
|
-
notificationId,
|
|
75
|
-
onMarkAsRead,
|
|
76
|
-
onNotify,
|
|
77
|
-
onAfterClick,
|
|
78
|
-
}: NotificationActionStripProps) {
|
|
79
|
-
if (actions.length === 0) return null
|
|
80
|
-
return (
|
|
81
|
-
<div className="flex flex-wrap items-center gap-1.5 mt-2">
|
|
82
|
-
{actions.map(a => (
|
|
83
|
-
<NotificationActionButton
|
|
84
|
-
key={a.name}
|
|
85
|
-
action={a}
|
|
86
|
-
{...(actionUrlTemplate !== undefined ? { actionUrlTemplate } : {})}
|
|
87
|
-
{...(notificationId !== undefined ? { notificationId } : {})}
|
|
88
|
-
{...(onMarkAsRead !== undefined ? { onMarkAsRead } : {})}
|
|
89
|
-
{...(onNotify !== undefined ? { onNotify } : {})}
|
|
90
|
-
{...(onAfterClick !== undefined ? { onAfterClick } : {})}
|
|
91
|
-
/>
|
|
92
|
-
))}
|
|
93
|
-
</div>
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function NotificationActionButton({
|
|
98
|
-
action: a,
|
|
99
|
-
actionUrlTemplate,
|
|
100
|
-
notificationId,
|
|
101
|
-
onMarkAsRead,
|
|
102
|
-
onNotify,
|
|
103
|
-
onAfterClick,
|
|
104
|
-
}: {
|
|
105
|
-
action: NotificationActionMeta
|
|
106
|
-
actionUrlTemplate?: string
|
|
107
|
-
notificationId?: string
|
|
108
|
-
onMarkAsRead?: (id: string) => void
|
|
109
|
-
onNotify?: (notifs: NotificationMeta[]) => void
|
|
110
|
-
onAfterClick?: () => void
|
|
111
|
-
}) {
|
|
112
|
-
const navigate = useNavigate()
|
|
113
|
-
const Icon = useIconFor(a.icon)
|
|
114
|
-
|
|
115
|
-
const baseClass = cn(
|
|
116
|
-
'inline-flex items-center gap-1 rounded-md font-medium transition-colors disabled:opacity-50 disabled:pointer-events-none',
|
|
117
|
-
SIZE_CLASSES[a.size ?? 'sm'],
|
|
118
|
-
a.color
|
|
119
|
-
? (a.outlined ? COLOR_OUTLINED[a.color] : COLOR_CLASSES[a.color])
|
|
120
|
-
: (a.outlined
|
|
121
|
-
? 'border border-input bg-background hover:bg-accent hover:text-accent-foreground'
|
|
122
|
-
: 'bg-secondary text-secondary-foreground hover:bg-secondary/80'),
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
const Body = () => (
|
|
126
|
-
<>
|
|
127
|
-
{Icon && <Icon className="size-3.5" aria-hidden="true" />}
|
|
128
|
-
<span>{a.label}</span>
|
|
129
|
-
</>
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
// ─── url-mode action ──────────────────────────────────
|
|
133
|
-
if (typeof a.url === 'string') {
|
|
134
|
-
const newTab = a.openUrlInNewTab
|
|
135
|
-
const href = a.url
|
|
136
|
-
const onClick = (e: React.MouseEvent) => {
|
|
137
|
-
e.stopPropagation()
|
|
138
|
-
// Modified clicks (cmd/ctrl/shift) preserve native semantics —
|
|
139
|
-
// open-in-new-tab / save-link / etc. The browser handles the
|
|
140
|
-
// navigation; we still fire mark-as-read so the inbox state
|
|
141
|
-
// converges.
|
|
142
|
-
if (a.markAsRead && notificationId && onMarkAsRead) onMarkAsRead(notificationId)
|
|
143
|
-
if (e.metaKey || e.ctrlKey || e.shiftKey || newTab) return
|
|
144
|
-
e.preventDefault()
|
|
145
|
-
onAfterClick?.()
|
|
146
|
-
navigate(href)
|
|
147
|
-
}
|
|
148
|
-
return (
|
|
149
|
-
<a
|
|
150
|
-
href={href}
|
|
151
|
-
target={newTab ? '_blank' : undefined}
|
|
152
|
-
rel={newTab ? 'noopener noreferrer' : undefined}
|
|
153
|
-
className={baseClass}
|
|
154
|
-
onClick={onClick}
|
|
155
|
-
data-no-row-nav=""
|
|
156
|
-
>
|
|
157
|
-
<Body />
|
|
158
|
-
</a>
|
|
159
|
-
)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// ─── post-mode action ─────────────────────────────────
|
|
163
|
-
if (typeof a.post === 'string') {
|
|
164
|
-
const target = a.post
|
|
165
|
-
const onSubmit = (e: React.FormEvent) => {
|
|
166
|
-
e.stopPropagation()
|
|
167
|
-
// Form-POST navigates the browser away — fire mark-as-read
|
|
168
|
-
// first so the row's read state converges before the page
|
|
169
|
-
// unloads. Optimistic local flip handles the bell UX.
|
|
170
|
-
if (a.markAsRead && notificationId && onMarkAsRead) onMarkAsRead(notificationId)
|
|
171
|
-
onAfterClick?.()
|
|
172
|
-
// Let the native submission proceed.
|
|
173
|
-
}
|
|
174
|
-
return (
|
|
175
|
-
<form
|
|
176
|
-
method="post"
|
|
177
|
-
action={target}
|
|
178
|
-
onSubmit={onSubmit}
|
|
179
|
-
className="inline-flex"
|
|
180
|
-
data-no-row-nav=""
|
|
181
|
-
>
|
|
182
|
-
<button type="submit" className={baseClass}>
|
|
183
|
-
<Body />
|
|
184
|
-
</button>
|
|
185
|
-
</form>
|
|
186
|
-
)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// ─── handler-mode action ──────────────────────────────
|
|
190
|
-
// Bell row: dispatch via the action endpoint. Server-side handles
|
|
191
|
-
// markAsRead atomically so the round-trip is one request.
|
|
192
|
-
// Transient toast (no actionUrlTemplate / no notificationId): no
|
|
193
|
-
// dispatch target available in v1 — render disabled with a tooltip.
|
|
194
|
-
if (typeof a.handler === 'string') {
|
|
195
|
-
if (!actionUrlTemplate || !notificationId) {
|
|
196
|
-
return (
|
|
197
|
-
<button
|
|
198
|
-
type="button"
|
|
199
|
-
className={baseClass}
|
|
200
|
-
disabled
|
|
201
|
-
title="Handler-mode actions on transient toasts aren't supported in v1"
|
|
202
|
-
data-no-row-nav=""
|
|
203
|
-
>
|
|
204
|
-
<Body />
|
|
205
|
-
</button>
|
|
206
|
-
)
|
|
207
|
-
}
|
|
208
|
-
const url = actionUrlTemplate
|
|
209
|
-
.replace(':id', encodeURIComponent(notificationId))
|
|
210
|
-
.replace(':actionName', encodeURIComponent(a.name))
|
|
211
|
-
const onClick = async (e: React.MouseEvent) => {
|
|
212
|
-
e.preventDefault()
|
|
213
|
-
e.stopPropagation()
|
|
214
|
-
try {
|
|
215
|
-
const r = await fetch(url, {
|
|
216
|
-
method: 'POST',
|
|
217
|
-
headers: { Accept: 'application/json' },
|
|
218
|
-
credentials: 'same-origin',
|
|
219
|
-
})
|
|
220
|
-
const json = await r.json().catch(() => null) as {
|
|
221
|
-
ok?: boolean
|
|
222
|
-
redirect?: string
|
|
223
|
-
notifications?: NotificationMeta[]
|
|
224
|
-
markedAsRead?: boolean
|
|
225
|
-
error?: string
|
|
226
|
-
} | null
|
|
227
|
-
if (!r.ok || !json?.ok) {
|
|
228
|
-
onNotify?.([{
|
|
229
|
-
id: `nact-err-${Date.now()}`,
|
|
230
|
-
type: 'error',
|
|
231
|
-
title: json?.error ?? 'Action failed',
|
|
232
|
-
}])
|
|
233
|
-
return
|
|
234
|
-
}
|
|
235
|
-
if (json.notifications?.length) onNotify?.(json.notifications)
|
|
236
|
-
if (json.markedAsRead && notificationId && onMarkAsRead) onMarkAsRead(notificationId)
|
|
237
|
-
onAfterClick?.()
|
|
238
|
-
if (json.redirect) navigate(json.redirect)
|
|
239
|
-
} catch (err) {
|
|
240
|
-
onNotify?.([{
|
|
241
|
-
id: `nact-err-${Date.now()}`,
|
|
242
|
-
type: 'error',
|
|
243
|
-
title: err instanceof Error ? err.message : 'Action failed',
|
|
244
|
-
}])
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
return (
|
|
248
|
-
<button
|
|
249
|
-
type="button"
|
|
250
|
-
className={baseClass}
|
|
251
|
-
onClick={onClick}
|
|
252
|
-
data-no-row-nav=""
|
|
253
|
-
>
|
|
254
|
-
<Body />
|
|
255
|
-
</button>
|
|
256
|
-
)
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Defensive fallback — wire shape validation should have stripped
|
|
260
|
-
// any malformed entry upstream, but render an inert chip rather
|
|
261
|
-
// than throw.
|
|
262
|
-
return null
|
|
263
|
-
}
|