@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
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import {
|
|
3
|
-
Sidebar,
|
|
4
|
-
SidebarContent,
|
|
5
|
-
SidebarFooter,
|
|
6
|
-
SidebarGroup,
|
|
7
|
-
SidebarGroupContent,
|
|
8
|
-
SidebarGroupLabel,
|
|
9
|
-
SidebarHeader,
|
|
10
|
-
SidebarInset,
|
|
11
|
-
SidebarMenu,
|
|
12
|
-
SidebarMenuBadge,
|
|
13
|
-
SidebarMenuButton,
|
|
14
|
-
SidebarMenuItem,
|
|
15
|
-
SidebarMenuSub,
|
|
16
|
-
SidebarMenuSubButton,
|
|
17
|
-
SidebarMenuSubItem,
|
|
18
|
-
SidebarProvider,
|
|
19
|
-
SidebarRail,
|
|
20
|
-
SidebarTrigger,
|
|
21
|
-
} from '../ui/sidebar.js'
|
|
22
|
-
import { Separator } from '../ui/separator.js'
|
|
23
|
-
import { ThemeToggle } from '../ThemeToggle.js'
|
|
24
|
-
import { SearchTrigger } from '../SearchTrigger.js'
|
|
25
|
-
import { UserMenu } from '../UserMenu.js'
|
|
26
|
-
import { NotificationBell } from '../NotificationBell.js'
|
|
27
|
-
import { RightSidebarTrigger } from '../RightSidebarTrigger.js'
|
|
28
|
-
import { RenderHookSlot } from '../RenderHookSlot.js'
|
|
29
|
-
import type { AppShellProps } from '../AppShell.js'
|
|
30
|
-
import { useIconFor } from '../icon-context.js'
|
|
31
|
-
import type { SerializedIcon } from '../../icons/types.js'
|
|
32
|
-
import type { NavItem } from '../../pageData.js'
|
|
33
|
-
import type { NavigationBadgeColor } from '../../Resource.js'
|
|
34
|
-
import { cn } from '../utils.js'
|
|
35
|
-
|
|
36
|
-
function NavIcon({ value }: { value: SerializedIcon | undefined }) {
|
|
37
|
-
const Icon = useIconFor(value)
|
|
38
|
-
if (!Icon) return null
|
|
39
|
-
return <Icon className="size-4" aria-hidden="true" />
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** Tailwind utility map shared with `ListTab.badgeColor` so badges read
|
|
43
|
-
* consistently across the admin panel. */
|
|
44
|
-
const BADGE_COLOR: Record<NavigationBadgeColor, string> = {
|
|
45
|
-
default: 'bg-muted text-muted-foreground',
|
|
46
|
-
primary: 'bg-primary/10 text-primary',
|
|
47
|
-
success: 'bg-emerald-500/10 text-emerald-600 dark:text-emerald-400',
|
|
48
|
-
warning: 'bg-amber-500/10 text-amber-600 dark:text-amber-400',
|
|
49
|
-
destructive: 'bg-red-500/10 text-red-600 dark:text-red-400',
|
|
50
|
-
info: 'bg-sky-500/10 text-sky-600 dark:text-sky-400',
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function Badge({ value, color }: { value: string | undefined; color: NavigationBadgeColor | undefined }) {
|
|
54
|
-
if (value === undefined) return null
|
|
55
|
-
return (
|
|
56
|
-
<SidebarMenuBadge className={cn('px-1.5 rounded-md', BADGE_COLOR[color ?? 'default'])}>
|
|
57
|
-
{value}
|
|
58
|
-
</SidebarMenuBadge>
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Active-link match is a longest-prefix walk. The dashboard URL (e.g.
|
|
64
|
-
* `/admin`) is a prefix of every other panel URL, so we only return
|
|
65
|
-
* "active" for it on an exact match. Otherwise we accept the URL as a
|
|
66
|
-
* prefix of `pathname` if it is followed by `/` or end-of-string —
|
|
67
|
-
* `/admin/users` should not light up `/admin/user`.
|
|
68
|
-
*/
|
|
69
|
-
function isActive(url: string, pathname: string | undefined, basePath: string): boolean {
|
|
70
|
-
if (!pathname) return false
|
|
71
|
-
if (url === basePath) return pathname === basePath
|
|
72
|
-
if (url === pathname) return true
|
|
73
|
-
return pathname.startsWith(url + '/')
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/** Group nav items by `group`, preserving the order each group's first
|
|
77
|
-
* member appeared in the (already-sorted) flat list. Items without a
|
|
78
|
-
* group land in a leading unnamed bucket. */
|
|
79
|
-
function groupItems(items: NavItem[]): Array<{ group: string | undefined; items: NavItem[] }> {
|
|
80
|
-
const order: Array<string | undefined> = []
|
|
81
|
-
const buckets = new Map<string | undefined, NavItem[]>()
|
|
82
|
-
for (const it of items) {
|
|
83
|
-
const key = it.group
|
|
84
|
-
if (!buckets.has(key)) {
|
|
85
|
-
buckets.set(key, [])
|
|
86
|
-
order.push(key)
|
|
87
|
-
}
|
|
88
|
-
buckets.get(key)!.push(it)
|
|
89
|
-
}
|
|
90
|
-
return order.map(g => ({ group: g, items: buckets.get(g)! }))
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function NavTree({
|
|
94
|
-
items,
|
|
95
|
-
pathname,
|
|
96
|
-
basePath,
|
|
97
|
-
}: {
|
|
98
|
-
items: NavItem[]
|
|
99
|
-
pathname: string | undefined
|
|
100
|
-
basePath: string
|
|
101
|
-
}) {
|
|
102
|
-
return (
|
|
103
|
-
<SidebarMenu>
|
|
104
|
-
{items.map(it => {
|
|
105
|
-
const active = isActive(it.url, pathname, basePath)
|
|
106
|
-
return (
|
|
107
|
-
<SidebarMenuItem key={it.name}>
|
|
108
|
-
<SidebarMenuButton
|
|
109
|
-
isActive={active}
|
|
110
|
-
render={<a href={it.url} />}
|
|
111
|
-
tooltip={it.label}
|
|
112
|
-
>
|
|
113
|
-
<NavIcon value={it.icon} />
|
|
114
|
-
<span>{it.label}</span>
|
|
115
|
-
<Badge value={it.badge} color={it.badgeColor} />
|
|
116
|
-
</SidebarMenuButton>
|
|
117
|
-
{it.children && it.children.length > 0 && (
|
|
118
|
-
<SidebarMenuSub>
|
|
119
|
-
{it.children.map(child => {
|
|
120
|
-
const childActive = isActive(child.url, pathname, basePath)
|
|
121
|
-
return (
|
|
122
|
-
<SidebarMenuSubItem key={child.name}>
|
|
123
|
-
<SidebarMenuSubButton
|
|
124
|
-
isActive={childActive}
|
|
125
|
-
render={<a href={child.url} />}
|
|
126
|
-
>
|
|
127
|
-
<NavIcon value={child.icon} />
|
|
128
|
-
<span>{child.label}</span>
|
|
129
|
-
<Badge value={child.badge} color={child.badgeColor} />
|
|
130
|
-
</SidebarMenuSubButton>
|
|
131
|
-
</SidebarMenuSubItem>
|
|
132
|
-
)
|
|
133
|
-
})}
|
|
134
|
-
</SidebarMenuSub>
|
|
135
|
-
)}
|
|
136
|
-
</SidebarMenuItem>
|
|
137
|
-
)
|
|
138
|
-
})}
|
|
139
|
-
</SidebarMenu>
|
|
140
|
-
)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export function SidebarLayout({ panel, basePath, currentPath, children, componentSlotRegistry }: AppShellProps) {
|
|
144
|
-
const title = panel.branding?.title ?? panel.name
|
|
145
|
-
const groups = groupItems(panel.navigation ?? [])
|
|
146
|
-
const hooks = panel.renderHooks
|
|
147
|
-
const dn = panel.databaseNotifications
|
|
148
|
-
const bellInTopbar = dn && dn.position === 'topbar'
|
|
149
|
-
const bellInSidebar = dn && dn.position === 'sidebar'
|
|
150
|
-
const NavSlot = componentSlotRegistry?.nav
|
|
151
|
-
const HeaderSlot = componentSlotRegistry?.header
|
|
152
|
-
const FooterSlot = componentSlotRegistry?.footer
|
|
153
|
-
const slotProps = currentPath !== undefined ? { currentPath } : {}
|
|
154
|
-
|
|
155
|
-
return (
|
|
156
|
-
<SidebarProvider>
|
|
157
|
-
<Sidebar variant="inset" collapsible="icon">
|
|
158
|
-
<SidebarHeader>
|
|
159
|
-
<RenderHookSlot name="panels::sidebar.start" hooks={hooks} />
|
|
160
|
-
<SidebarMenu>
|
|
161
|
-
<SidebarMenuItem>
|
|
162
|
-
<SidebarMenuButton size="lg" render={<a href={basePath} />} tooltip={title}>
|
|
163
|
-
<div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
|
|
164
|
-
{panel.branding?.logo
|
|
165
|
-
? <img src={panel.branding.logo} alt={title} className="size-4" />
|
|
166
|
-
: <span className="text-xs font-bold">{title.charAt(0).toUpperCase()}</span>
|
|
167
|
-
}
|
|
168
|
-
</div>
|
|
169
|
-
<div className="grid flex-1 text-start text-sm leading-tight">
|
|
170
|
-
<span className="truncate font-semibold">{title}</span>
|
|
171
|
-
</div>
|
|
172
|
-
</SidebarMenuButton>
|
|
173
|
-
</SidebarMenuItem>
|
|
174
|
-
</SidebarMenu>
|
|
175
|
-
</SidebarHeader>
|
|
176
|
-
|
|
177
|
-
<SidebarContent>
|
|
178
|
-
<RenderHookSlot name="panels::sidebar.nav.start" hooks={hooks} />
|
|
179
|
-
{NavSlot
|
|
180
|
-
? <NavSlot navigation={panel.navigation ?? []} basePath={basePath} {...slotProps} />
|
|
181
|
-
: groups.map((g, idx) => (
|
|
182
|
-
<SidebarGroup key={g.group ?? `__top__${idx}`}>
|
|
183
|
-
{g.group !== undefined && <SidebarGroupLabel>{g.group}</SidebarGroupLabel>}
|
|
184
|
-
<SidebarGroupContent>
|
|
185
|
-
<NavTree items={g.items} pathname={currentPath} basePath={basePath} />
|
|
186
|
-
</SidebarGroupContent>
|
|
187
|
-
</SidebarGroup>
|
|
188
|
-
))
|
|
189
|
-
}
|
|
190
|
-
<RenderHookSlot name="panels::sidebar.nav.end" hooks={hooks} />
|
|
191
|
-
</SidebarContent>
|
|
192
|
-
|
|
193
|
-
<SidebarFooter>
|
|
194
|
-
<RenderHookSlot name="panels::sidebar.footer" hooks={hooks} />
|
|
195
|
-
{bellInSidebar && (
|
|
196
|
-
<SidebarMenu>
|
|
197
|
-
<SidebarMenuItem>
|
|
198
|
-
<div className="flex items-center justify-between px-2 py-1">
|
|
199
|
-
<span className="text-xs text-muted-foreground">Notifications</span>
|
|
200
|
-
<NotificationBell meta={dn} />
|
|
201
|
-
</div>
|
|
202
|
-
</SidebarMenuItem>
|
|
203
|
-
</SidebarMenu>
|
|
204
|
-
)}
|
|
205
|
-
{panel.themeEditor && (
|
|
206
|
-
<SidebarMenu>
|
|
207
|
-
<SidebarMenuItem>
|
|
208
|
-
<SidebarMenuButton render={<a href={`${basePath}/theme`} />} tooltip="Theme">
|
|
209
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="13.5" cy="6.5" r="2.5"/><path d="M17.5 10.5 19 12l-5.5 5.5"/><circle cx="8.5" cy="8.5" r="2.5"/><path d="M5 12 2.5 14.5 8 20l2.5-2.5"/><path d="m6 18 4-4"/></svg>
|
|
210
|
-
<span>Theme</span>
|
|
211
|
-
</SidebarMenuButton>
|
|
212
|
-
</SidebarMenuItem>
|
|
213
|
-
</SidebarMenu>
|
|
214
|
-
)}
|
|
215
|
-
</SidebarFooter>
|
|
216
|
-
<SidebarRail />
|
|
217
|
-
</Sidebar>
|
|
218
|
-
|
|
219
|
-
<SidebarInset>
|
|
220
|
-
{HeaderSlot
|
|
221
|
-
? <HeaderSlot navigation={panel.navigation ?? []} basePath={basePath} {...slotProps} />
|
|
222
|
-
: <header className="sticky top-0 z-10 flex h-14 shrink-0 items-center gap-2">
|
|
223
|
-
<div className="flex flex-1 items-center gap-2 px-3">
|
|
224
|
-
<SidebarTrigger />
|
|
225
|
-
<Separator orientation="vertical" className="me-2 data-[orientation=vertical]:h-4" />
|
|
226
|
-
<RenderHookSlot name="panels::topbar.start" hooks={hooks} />
|
|
227
|
-
<SearchTrigger />
|
|
228
|
-
</div>
|
|
229
|
-
<div className="flex items-center gap-1 px-3">
|
|
230
|
-
<ThemeToggle />
|
|
231
|
-
{bellInTopbar && <NotificationBell meta={dn} />}
|
|
232
|
-
<RightSidebarTrigger />
|
|
233
|
-
<UserMenu
|
|
234
|
-
userMenu={panel.userMenu}
|
|
235
|
-
before={<RenderHookSlot name="panels::user-menu.before" hooks={hooks} />}
|
|
236
|
-
after={<RenderHookSlot name="panels::user-menu.after" hooks={hooks} />}
|
|
237
|
-
/>
|
|
238
|
-
<RenderHookSlot name="panels::topbar.end" hooks={hooks} />
|
|
239
|
-
</div>
|
|
240
|
-
</header>
|
|
241
|
-
}
|
|
242
|
-
<div className="flex flex-1 flex-col px-4 pb-4">
|
|
243
|
-
{children}
|
|
244
|
-
<RenderHookSlot name="panels::footer" hooks={hooks} />
|
|
245
|
-
</div>
|
|
246
|
-
{FooterSlot && <FooterSlot basePath={basePath} {...slotProps} />}
|
|
247
|
-
</SidebarInset>
|
|
248
|
-
</SidebarProvider>
|
|
249
|
-
)
|
|
250
|
-
}
|
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import { Separator } from '../ui/separator.js'
|
|
3
|
-
import { ThemeToggle } from '../ThemeToggle.js'
|
|
4
|
-
import { SearchTrigger } from '../SearchTrigger.js'
|
|
5
|
-
import { UserMenu } from '../UserMenu.js'
|
|
6
|
-
import { NotificationBell } from '../NotificationBell.js'
|
|
7
|
-
import { RightSidebarTrigger } from '../RightSidebarTrigger.js'
|
|
8
|
-
import { RenderHookSlot } from '../RenderHookSlot.js'
|
|
9
|
-
import {
|
|
10
|
-
DropdownMenu,
|
|
11
|
-
DropdownMenuContent,
|
|
12
|
-
DropdownMenuItem,
|
|
13
|
-
DropdownMenuTrigger,
|
|
14
|
-
} from '../ui/dropdown-menu.js'
|
|
15
|
-
import type { AppShellProps } from '../AppShell.js'
|
|
16
|
-
import { useIconFor } from '../icon-context.js'
|
|
17
|
-
import type { SerializedIcon } from '../../icons/types.js'
|
|
18
|
-
import type { NavItem } from '../../pageData.js'
|
|
19
|
-
import type { NavigationBadgeColor } from '../../Resource.js'
|
|
20
|
-
import { cn } from '../utils.js'
|
|
21
|
-
|
|
22
|
-
function NavIcon({ value }: { value: SerializedIcon | undefined }) {
|
|
23
|
-
const Icon = useIconFor(value)
|
|
24
|
-
if (!Icon) return null
|
|
25
|
-
return <Icon className="size-4" aria-hidden="true" />
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const BADGE_COLOR: Record<NavigationBadgeColor, string> = {
|
|
29
|
-
default: 'bg-muted text-muted-foreground',
|
|
30
|
-
primary: 'bg-primary/10 text-primary',
|
|
31
|
-
success: 'bg-emerald-500/10 text-emerald-600 dark:text-emerald-400',
|
|
32
|
-
warning: 'bg-amber-500/10 text-amber-600 dark:text-amber-400',
|
|
33
|
-
destructive: 'bg-red-500/10 text-red-600 dark:text-red-400',
|
|
34
|
-
info: 'bg-sky-500/10 text-sky-600 dark:text-sky-400',
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function Badge({ value, color }: { value: string | undefined; color: NavigationBadgeColor | undefined }) {
|
|
38
|
-
if (value === undefined) return null
|
|
39
|
-
return (
|
|
40
|
-
<span className={cn('ms-1 inline-flex items-center justify-center rounded-md px-1.5 text-xs', BADGE_COLOR[color ?? 'default'])}>
|
|
41
|
-
{value}
|
|
42
|
-
</span>
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function isActive(url: string, pathname: string | undefined, basePath: string): boolean {
|
|
47
|
-
if (!pathname) return false
|
|
48
|
-
if (url === basePath) return pathname === basePath
|
|
49
|
-
if (url === pathname) return true
|
|
50
|
-
return pathname.startsWith(url + '/')
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const linkBase =
|
|
54
|
-
'flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm whitespace-nowrap transition-colors'
|
|
55
|
-
const linkIdle =
|
|
56
|
-
'text-muted-foreground hover:bg-accent hover:text-accent-foreground'
|
|
57
|
-
const linkActive =
|
|
58
|
-
'bg-accent text-accent-foreground'
|
|
59
|
-
|
|
60
|
-
/** Bare item: a single nav link with no children. */
|
|
61
|
-
function FlatLink({ item, pathname, basePath }: { item: NavItem; pathname: string | undefined; basePath: string }) {
|
|
62
|
-
return (
|
|
63
|
-
<a
|
|
64
|
-
href={item.url}
|
|
65
|
-
className={cn(linkBase, isActive(item.url, pathname, basePath) ? linkActive : linkIdle)}
|
|
66
|
-
>
|
|
67
|
-
<NavIcon value={item.icon} />
|
|
68
|
-
<span>{item.label}</span>
|
|
69
|
-
<Badge value={item.badge} color={item.badgeColor} />
|
|
70
|
-
</a>
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Item with children: render as a dropdown trigger; the parent's own URL
|
|
76
|
-
* becomes the first menu entry so users can still navigate to it.
|
|
77
|
-
*/
|
|
78
|
-
function ParentDropdown({ item, pathname, basePath }: { item: NavItem; pathname: string | undefined; basePath: string }) {
|
|
79
|
-
return (
|
|
80
|
-
<DropdownMenu>
|
|
81
|
-
<DropdownMenuTrigger
|
|
82
|
-
className={cn(linkBase, isActive(item.url, pathname, basePath) ? linkActive : linkIdle)}
|
|
83
|
-
>
|
|
84
|
-
<NavIcon value={item.icon} />
|
|
85
|
-
<span>{item.label}</span>
|
|
86
|
-
<Badge value={item.badge} color={item.badgeColor} />
|
|
87
|
-
</DropdownMenuTrigger>
|
|
88
|
-
<DropdownMenuContent align="start">
|
|
89
|
-
<DropdownMenuItem render={<a href={item.url} />}>
|
|
90
|
-
<NavIcon value={item.icon} />
|
|
91
|
-
<span>{item.label}</span>
|
|
92
|
-
</DropdownMenuItem>
|
|
93
|
-
{item.children!.map(c => (
|
|
94
|
-
<DropdownMenuItem key={c.name} render={<a href={c.url} />}>
|
|
95
|
-
<NavIcon value={c.icon} />
|
|
96
|
-
<span>{c.label}</span>
|
|
97
|
-
<Badge value={c.badge} color={c.badgeColor} />
|
|
98
|
-
</DropdownMenuItem>
|
|
99
|
-
))}
|
|
100
|
-
</DropdownMenuContent>
|
|
101
|
-
</DropdownMenu>
|
|
102
|
-
)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Group dropdown: the group label triggers the menu; every member
|
|
107
|
-
* (and its children) renders as menu items.
|
|
108
|
-
*/
|
|
109
|
-
function GroupDropdown({
|
|
110
|
-
label,
|
|
111
|
-
items,
|
|
112
|
-
pathname,
|
|
113
|
-
basePath,
|
|
114
|
-
}: {
|
|
115
|
-
label: string
|
|
116
|
-
items: NavItem[]
|
|
117
|
-
pathname: string | undefined
|
|
118
|
-
basePath: string
|
|
119
|
-
}) {
|
|
120
|
-
const anyActive = items.some(it =>
|
|
121
|
-
isActive(it.url, pathname, basePath) ||
|
|
122
|
-
it.children?.some(c => isActive(c.url, pathname, basePath)),
|
|
123
|
-
)
|
|
124
|
-
return (
|
|
125
|
-
<DropdownMenu>
|
|
126
|
-
<DropdownMenuTrigger className={cn(linkBase, anyActive ? linkActive : linkIdle)}>
|
|
127
|
-
<span>{label}</span>
|
|
128
|
-
</DropdownMenuTrigger>
|
|
129
|
-
<DropdownMenuContent align="start">
|
|
130
|
-
{items.flatMap(it => {
|
|
131
|
-
const self = (
|
|
132
|
-
<DropdownMenuItem key={it.name} render={<a href={it.url} />}>
|
|
133
|
-
<NavIcon value={it.icon} />
|
|
134
|
-
<span>{it.label}</span>
|
|
135
|
-
<Badge value={it.badge} color={it.badgeColor} />
|
|
136
|
-
</DropdownMenuItem>
|
|
137
|
-
)
|
|
138
|
-
if (!it.children || it.children.length === 0) return [self]
|
|
139
|
-
return [
|
|
140
|
-
self,
|
|
141
|
-
...it.children.map(c => (
|
|
142
|
-
<DropdownMenuItem key={`${it.name}/${c.name}`} render={<a href={c.url} />} className="ps-6">
|
|
143
|
-
<NavIcon value={c.icon} />
|
|
144
|
-
<span>{c.label}</span>
|
|
145
|
-
<Badge value={c.badge} color={c.badgeColor} />
|
|
146
|
-
</DropdownMenuItem>
|
|
147
|
-
)),
|
|
148
|
-
]
|
|
149
|
-
})}
|
|
150
|
-
</DropdownMenuContent>
|
|
151
|
-
</DropdownMenu>
|
|
152
|
-
)
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function groupItems(items: NavItem[]): Array<{ group: string | undefined; items: NavItem[] }> {
|
|
156
|
-
const order: Array<string | undefined> = []
|
|
157
|
-
const buckets = new Map<string | undefined, NavItem[]>()
|
|
158
|
-
for (const it of items) {
|
|
159
|
-
const key = it.group
|
|
160
|
-
if (!buckets.has(key)) {
|
|
161
|
-
buckets.set(key, [])
|
|
162
|
-
order.push(key)
|
|
163
|
-
}
|
|
164
|
-
buckets.get(key)!.push(it)
|
|
165
|
-
}
|
|
166
|
-
return order.map(g => ({ group: g, items: buckets.get(g)! }))
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export function TopbarLayout({ panel, basePath, currentPath, children, componentSlotRegistry }: AppShellProps) {
|
|
170
|
-
const title = panel.branding?.title ?? panel.name
|
|
171
|
-
const groups = groupItems(panel.navigation ?? [])
|
|
172
|
-
const hooks = panel.renderHooks
|
|
173
|
-
// Topbar layout treats `position: 'sidebar'` as a fallback to topbar —
|
|
174
|
-
// no sidebar exists in this layout, so the bell rides in the topbar
|
|
175
|
-
// chrome regardless of the configured position.
|
|
176
|
-
const dn = panel.databaseNotifications
|
|
177
|
-
const NavSlot = componentSlotRegistry?.nav
|
|
178
|
-
const HeaderSlot = componentSlotRegistry?.header
|
|
179
|
-
const FooterSlot = componentSlotRegistry?.footer
|
|
180
|
-
const slotProps = currentPath !== undefined ? { currentPath } : {}
|
|
181
|
-
|
|
182
|
-
return (
|
|
183
|
-
<div className="flex flex-col h-screen bg-background text-foreground overflow-hidden">
|
|
184
|
-
{HeaderSlot
|
|
185
|
-
? <HeaderSlot navigation={panel.navigation ?? []} basePath={basePath} {...slotProps} />
|
|
186
|
-
: <header className="h-14 shrink-0 border-b bg-card flex items-center gap-4 px-6">
|
|
187
|
-
<div className="flex items-center gap-2 me-2">
|
|
188
|
-
{panel.branding?.logo
|
|
189
|
-
? <>
|
|
190
|
-
<img src={panel.branding.logo} alt={title} className="h-6 w-6" />
|
|
191
|
-
<span className="text-sm font-semibold">{title}</span>
|
|
192
|
-
</>
|
|
193
|
-
: <span className="text-sm font-semibold">{title}</span>
|
|
194
|
-
}
|
|
195
|
-
</div>
|
|
196
|
-
<Separator orientation="vertical" className="h-4" />
|
|
197
|
-
<RenderHookSlot name="panels::topbar.start" hooks={hooks} />
|
|
198
|
-
{NavSlot
|
|
199
|
-
? <div className="flex items-center gap-1 flex-1 overflow-x-auto">
|
|
200
|
-
<NavSlot navigation={panel.navigation ?? []} basePath={basePath} {...slotProps} />
|
|
201
|
-
</div>
|
|
202
|
-
: <nav className="flex items-center gap-1 flex-1 overflow-x-auto">
|
|
203
|
-
<a
|
|
204
|
-
href={basePath}
|
|
205
|
-
className={cn(linkBase, currentPath === basePath ? linkActive : linkIdle)}
|
|
206
|
-
>
|
|
207
|
-
Dashboard
|
|
208
|
-
</a>
|
|
209
|
-
{groups.map((g, idx) => {
|
|
210
|
-
if (g.group === undefined) {
|
|
211
|
-
return g.items.map(it => (
|
|
212
|
-
it.children && it.children.length > 0
|
|
213
|
-
? <ParentDropdown key={it.name} item={it} pathname={currentPath} basePath={basePath} />
|
|
214
|
-
: <FlatLink key={it.name} item={it} pathname={currentPath} basePath={basePath} />
|
|
215
|
-
))
|
|
216
|
-
}
|
|
217
|
-
return (
|
|
218
|
-
<GroupDropdown
|
|
219
|
-
key={`${g.group}__${idx}`}
|
|
220
|
-
label={g.group}
|
|
221
|
-
items={g.items}
|
|
222
|
-
pathname={currentPath}
|
|
223
|
-
basePath={basePath}
|
|
224
|
-
/>
|
|
225
|
-
)
|
|
226
|
-
})}
|
|
227
|
-
{panel.themeEditor && (
|
|
228
|
-
<a
|
|
229
|
-
href={`${basePath}/theme`}
|
|
230
|
-
className={cn(linkBase, currentPath === `${basePath}/theme` ? linkActive : linkIdle)}
|
|
231
|
-
>
|
|
232
|
-
Theme
|
|
233
|
-
</a>
|
|
234
|
-
)}
|
|
235
|
-
</nav>
|
|
236
|
-
}
|
|
237
|
-
<SearchTrigger />
|
|
238
|
-
<ThemeToggle />
|
|
239
|
-
{dn && <NotificationBell meta={dn} />}
|
|
240
|
-
<RightSidebarTrigger />
|
|
241
|
-
<UserMenu
|
|
242
|
-
userMenu={panel.userMenu}
|
|
243
|
-
before={<RenderHookSlot name="panels::user-menu.before" hooks={hooks} />}
|
|
244
|
-
after={<RenderHookSlot name="panels::user-menu.after" hooks={hooks} />}
|
|
245
|
-
/>
|
|
246
|
-
<RenderHookSlot name="panels::topbar.end" hooks={hooks} />
|
|
247
|
-
</header>
|
|
248
|
-
}
|
|
249
|
-
<div className="flex flex-1 overflow-hidden">
|
|
250
|
-
<main className="flex-1 overflow-y-auto p-6">
|
|
251
|
-
{children}
|
|
252
|
-
<RenderHookSlot name="panels::footer" hooks={hooks} />
|
|
253
|
-
</main>
|
|
254
|
-
</div>
|
|
255
|
-
{FooterSlot && <FooterSlot basePath={basePath} {...slotProps} />}
|
|
256
|
-
</div>
|
|
257
|
-
)
|
|
258
|
-
}
|
package/src/react/navigate.tsx
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { createContext, useContext, type ReactNode } from 'react'
|
|
2
|
-
|
|
3
|
-
export type NavigateFn = (url: string) => void | Promise<void>
|
|
4
|
-
|
|
5
|
-
const NavigateContext = createContext<NavigateFn | null>(null)
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Provides an SPA navigation function to pilotiq components — `FilterSelect`
|
|
9
|
-
* uses it so changing a filter doesn't full-reload the page (the surrounding
|
|
10
|
-
* `<FilterPopover>` would unmount on reload, defeating "stay open across
|
|
11
|
-
* filter changes").
|
|
12
|
-
*
|
|
13
|
-
* The auto-generated Vike `+Layout.tsx` wires this with `navigate` from
|
|
14
|
-
* `vike/client/router`. Pilotiq itself does NOT import vike — keeps the
|
|
15
|
-
* package framework-agnostic for future non-vike consumers.
|
|
16
|
-
*/
|
|
17
|
-
export function NavigateProvider({
|
|
18
|
-
navigate,
|
|
19
|
-
children,
|
|
20
|
-
}: {
|
|
21
|
-
navigate: NavigateFn
|
|
22
|
-
children: ReactNode
|
|
23
|
-
}) {
|
|
24
|
-
return <NavigateContext.Provider value={navigate}>{children}</NavigateContext.Provider>
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Returns a navigate fn. Falls back to `window.location.href = url` (full
|
|
29
|
-
* reload) when no provider is mounted, so callers don't have to branch.
|
|
30
|
-
*/
|
|
31
|
-
export function useNavigate(): NavigateFn {
|
|
32
|
-
const ctx = useContext(NavigateContext)
|
|
33
|
-
if (ctx) return ctx
|
|
34
|
-
return (url: string) => {
|
|
35
|
-
if (typeof window !== 'undefined') window.location.href = url
|
|
36
|
-
}
|
|
37
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { onProviderSynced, type SyncedProviderLike } from './CollabRoomContext.js'
|
|
5
|
-
|
|
6
|
-
/** Bare provider double — captures `once` registrations and supports
|
|
7
|
-
* flipping `synced` so we can assert the deferred path. */
|
|
8
|
-
function mockProvider(initialSynced = false): SyncedProviderLike & {
|
|
9
|
-
fire(): void
|
|
10
|
-
registered: number
|
|
11
|
-
unregistered: number
|
|
12
|
-
offThrows: boolean
|
|
13
|
-
} {
|
|
14
|
-
let synced = initialSynced
|
|
15
|
-
let pending: (() => void) | null = null
|
|
16
|
-
const inst = {
|
|
17
|
-
get synced() { return synced },
|
|
18
|
-
set synced(v: boolean) { synced = v },
|
|
19
|
-
once(event: 'synced', fn: () => void) {
|
|
20
|
-
assert.equal(event, 'synced', 'only synced is registered')
|
|
21
|
-
pending = fn
|
|
22
|
-
inst.registered++
|
|
23
|
-
},
|
|
24
|
-
off(event: 'synced', fn: () => void) {
|
|
25
|
-
assert.equal(event, 'synced', 'only synced is unregistered')
|
|
26
|
-
if (inst.offThrows) throw new Error('boom')
|
|
27
|
-
if (pending === fn) pending = null
|
|
28
|
-
inst.unregistered++
|
|
29
|
-
},
|
|
30
|
-
fire() { if (pending) { const f = pending; pending = null; f() } },
|
|
31
|
-
registered: 0,
|
|
32
|
-
unregistered: 0,
|
|
33
|
-
offThrows: false,
|
|
34
|
-
}
|
|
35
|
-
return inst
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
describe('onProviderSynced', () => {
|
|
39
|
-
it('fires fn synchronously when provider is already synced', () => {
|
|
40
|
-
const provider = mockProvider(true)
|
|
41
|
-
let calls = 0
|
|
42
|
-
const cleanup = onProviderSynced(provider, () => { calls++ })
|
|
43
|
-
assert.equal(calls, 1, 'fn ran synchronously')
|
|
44
|
-
assert.equal(provider.registered, 0, 'once never registered')
|
|
45
|
-
cleanup()
|
|
46
|
-
assert.equal(provider.unregistered, 0, 'no-op cleanup did not call off')
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
it('defers fn until synced event when provider not yet synced', () => {
|
|
50
|
-
const provider = mockProvider(false)
|
|
51
|
-
let calls = 0
|
|
52
|
-
const cleanup = onProviderSynced(provider, () => { calls++ })
|
|
53
|
-
assert.equal(calls, 0, 'fn not yet called')
|
|
54
|
-
assert.equal(provider.registered, 1, 'once was registered')
|
|
55
|
-
provider.fire()
|
|
56
|
-
assert.equal(calls, 1, 'fn ran after synced fired')
|
|
57
|
-
cleanup()
|
|
58
|
-
assert.equal(provider.unregistered, 1, 'cleanup called off')
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('cleanup unregisters the once handler when called before synced fires', () => {
|
|
62
|
-
const provider = mockProvider(false)
|
|
63
|
-
let calls = 0
|
|
64
|
-
const cleanup = onProviderSynced(provider, () => { calls++ })
|
|
65
|
-
cleanup()
|
|
66
|
-
assert.equal(provider.unregistered, 1, 'off was called')
|
|
67
|
-
provider.fire()
|
|
68
|
-
assert.equal(calls, 0, 'fn never fired after cleanup')
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it('returns a no-op cleanup when provider is null or undefined', () => {
|
|
72
|
-
const noopCleanup = onProviderSynced(null, () => { throw new Error('unreachable') })
|
|
73
|
-
assert.doesNotThrow(() => noopCleanup())
|
|
74
|
-
const noopCleanup2 = onProviderSynced(undefined, () => { throw new Error('unreachable') })
|
|
75
|
-
assert.doesNotThrow(() => noopCleanup2())
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
it('swallows errors thrown by provider.off so cleanup never breaks an effect', () => {
|
|
79
|
-
const provider = mockProvider(false)
|
|
80
|
-
provider.offThrows = true
|
|
81
|
-
const cleanup = onProviderSynced(provider, () => {})
|
|
82
|
-
assert.doesNotThrow(cleanup, 'cleanup did not propagate the throw')
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('gracefully handles a provider missing once/off methods', () => {
|
|
86
|
-
const sparse: SyncedProviderLike = { synced: false }
|
|
87
|
-
const cleanup = onProviderSynced(sparse, () => {})
|
|
88
|
-
assert.doesNotThrow(cleanup, 'cleanup is safe when off is undefined')
|
|
89
|
-
})
|
|
90
|
-
})
|