@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/Cluster.test.ts
DELETED
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
import { describe, it, beforeEach } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { Router } from '@rudderjs/router'
|
|
5
|
-
|
|
6
|
-
import { Cluster } from './Cluster.js'
|
|
7
|
-
import { Pilotiq } from './Pilotiq.js'
|
|
8
|
-
import { Resource } from './Resource.js'
|
|
9
|
-
import { Global } from './Global.js'
|
|
10
|
-
import { Page } from './Page.js'
|
|
11
|
-
import { Form } from './elements/Form.js'
|
|
12
|
-
import { Table } from './elements/Table.js'
|
|
13
|
-
import { Heading } from './schema/Heading.js'
|
|
14
|
-
import { resourceBasePath, globalBasePath, pageBasePath, clusterBasePath } from './clusterPaths.js'
|
|
15
|
-
import { panelInfo } from './pageData.js'
|
|
16
|
-
import { registerPilotiqRoutes } from './routes.js'
|
|
17
|
-
|
|
18
|
-
class ContentCluster extends Cluster {
|
|
19
|
-
static override label = 'Content'
|
|
20
|
-
static override slug = 'content'
|
|
21
|
-
static override icon = 'folder'
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
class SettingsCluster extends Cluster {
|
|
25
|
-
static override label = 'Settings'
|
|
26
|
-
static override slug = 'settings'
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
class ArticleResource extends Resource {
|
|
30
|
-
static override label = 'Articles'
|
|
31
|
-
static override slug = 'articles'
|
|
32
|
-
static override cluster = ContentCluster
|
|
33
|
-
|
|
34
|
-
static override form(form: Form): Form { return form }
|
|
35
|
-
static override table(table: Table): Table { return table }
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
class TopLevelCategoryResource extends Resource {
|
|
39
|
-
static override label = 'Categories'
|
|
40
|
-
static override slug = 'categories'
|
|
41
|
-
|
|
42
|
-
static override form(form: Form): Form { return form }
|
|
43
|
-
static override table(table: Table): Table { return table }
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
class BrandingGlobal extends Global {
|
|
47
|
-
static override label = 'Branding'
|
|
48
|
-
static override slug = 'branding'
|
|
49
|
-
static override cluster = SettingsCluster
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
class AnalyticsPage extends Page {
|
|
53
|
-
static override slug = 'analytics'
|
|
54
|
-
static override label = 'Analytics'
|
|
55
|
-
static override cluster = ContentCluster
|
|
56
|
-
static override schema() { return [Heading.make('Analytics')] }
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
describe('Cluster — class basics', () => {
|
|
60
|
-
it('default slug derives from label, kebab-cased', () => {
|
|
61
|
-
class TwoWordCluster extends Cluster {
|
|
62
|
-
static override label = 'My Cluster'
|
|
63
|
-
}
|
|
64
|
-
assert.equal(TwoWordCluster.getSlug(), 'my-cluster')
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
it('explicit slug wins over derived', () => {
|
|
68
|
-
assert.equal(ContentCluster.getSlug(), 'content')
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it('navigationLabel falls through to label when unset', () => {
|
|
72
|
-
assert.equal(ContentCluster.getNavigationLabel(), 'Content')
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
it('navigationIcon falls through to icon when unset', () => {
|
|
76
|
-
assert.equal(ContentCluster.getNavigationIcon(), 'folder')
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('canAccess defaults to true', async () => {
|
|
80
|
-
assert.equal(await ContentCluster.canAccess(null), true)
|
|
81
|
-
})
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
describe('Cluster — URL helpers', () => {
|
|
85
|
-
it('resourceBasePath prefixes with cluster slug when set', () => {
|
|
86
|
-
assert.equal(resourceBasePath('/admin', ArticleResource), '/admin/content/articles')
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('resourceBasePath skips prefix for top-level resources', () => {
|
|
90
|
-
assert.equal(resourceBasePath('/admin', TopLevelCategoryResource), '/admin/categories')
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('globalBasePath prefixes with cluster slug when set', () => {
|
|
94
|
-
assert.equal(globalBasePath('/admin', BrandingGlobal), '/admin/settings/branding')
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('pageBasePath prefixes with cluster slug when set', () => {
|
|
98
|
-
assert.equal(pageBasePath('/admin', AnalyticsPage), '/admin/content/analytics')
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it('clusterBasePath stays panel-base + cluster slug', () => {
|
|
102
|
-
assert.equal(clusterBasePath('/admin', ContentCluster), '/admin/content')
|
|
103
|
-
})
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
describe('Cluster — boot validation', () => {
|
|
107
|
-
let router: Router
|
|
108
|
-
beforeEach(() => { router = new Router() })
|
|
109
|
-
|
|
110
|
-
it('throws when a resource references an unregistered cluster', () => {
|
|
111
|
-
class OrphanCluster extends Cluster {
|
|
112
|
-
static override label = 'Orphan'
|
|
113
|
-
static override slug = 'orphan'
|
|
114
|
-
}
|
|
115
|
-
class OrphanedResource extends Resource {
|
|
116
|
-
static override label = 'Orphans'
|
|
117
|
-
static override slug = 'orphans'
|
|
118
|
-
static override cluster = OrphanCluster
|
|
119
|
-
}
|
|
120
|
-
const panel = Pilotiq.make('boot-orphan').path('/admin')
|
|
121
|
-
.resources([OrphanedResource])
|
|
122
|
-
// no .clusters() — OrphanCluster never registered
|
|
123
|
-
|
|
124
|
-
assert.throws(
|
|
125
|
-
() => registerPilotiqRoutes(router, panel),
|
|
126
|
-
/OrphanCluster.*not registered/,
|
|
127
|
-
)
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
it('throws on duplicate cluster slugs', () => {
|
|
131
|
-
class A extends Cluster { static override label = 'A'; static override slug = 'shared' }
|
|
132
|
-
class B extends Cluster { static override label = 'B'; static override slug = 'shared' }
|
|
133
|
-
const panel = Pilotiq.make('boot-dup').path('/admin').clusters([A, B])
|
|
134
|
-
assert.throws(
|
|
135
|
-
() => registerPilotiqRoutes(router, panel),
|
|
136
|
-
/share slug "shared"/,
|
|
137
|
-
)
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
it('throws on reserved cluster slugs', () => {
|
|
141
|
-
class BadCluster extends Cluster { static override label = '_x'; static override slug = '_secret' }
|
|
142
|
-
const panel = Pilotiq.make('boot-reserved').path('/admin').clusters([BadCluster])
|
|
143
|
-
assert.throws(
|
|
144
|
-
() => registerPilotiqRoutes(router, panel),
|
|
145
|
-
/reserved slug/,
|
|
146
|
-
)
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
it('throws when a top-level resource slug collides with a cluster slug', () => {
|
|
150
|
-
class ClashResource extends Resource {
|
|
151
|
-
static override label = 'Content' // slug derives to 'content'
|
|
152
|
-
}
|
|
153
|
-
const panel = Pilotiq.make('boot-clash').path('/admin')
|
|
154
|
-
.clusters([ContentCluster])
|
|
155
|
-
.resources([ClashResource])
|
|
156
|
-
assert.throws(
|
|
157
|
-
() => registerPilotiqRoutes(router, panel),
|
|
158
|
-
/collides with a registered cluster slug/,
|
|
159
|
-
)
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
it('passes when wiring is consistent', () => {
|
|
163
|
-
const panel = Pilotiq.make('boot-ok').path('/admin')
|
|
164
|
-
.clusters([ContentCluster])
|
|
165
|
-
.resources([ArticleResource])
|
|
166
|
-
assert.doesNotThrow(() => registerPilotiqRoutes(router, panel))
|
|
167
|
-
})
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
describe('Cluster — route registration', () => {
|
|
171
|
-
it('mounts resource routes under the cluster prefix', () => {
|
|
172
|
-
const router = new Router()
|
|
173
|
-
const panel = Pilotiq.make('routes-cluster').path('/admin')
|
|
174
|
-
.clusters([ContentCluster])
|
|
175
|
-
.resources([ArticleResource])
|
|
176
|
-
registerPilotiqRoutes(router, panel)
|
|
177
|
-
const paths = router.list().map(r => `${r.method} ${r.path}`)
|
|
178
|
-
assert.ok(paths.includes('GET /admin/content/articles'))
|
|
179
|
-
assert.ok(paths.includes('GET /admin/content/articles/create'))
|
|
180
|
-
assert.ok(paths.includes('GET /admin/content/articles/:id'))
|
|
181
|
-
assert.ok(paths.includes('GET /admin/content/articles/:id/edit'))
|
|
182
|
-
assert.ok(paths.includes('POST /admin/content/articles/:id/delete'))
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
it('top-level resources stay unprefixed', () => {
|
|
186
|
-
const router = new Router()
|
|
187
|
-
const panel = Pilotiq.make('routes-mixed').path('/admin')
|
|
188
|
-
.clusters([ContentCluster])
|
|
189
|
-
.resources([ArticleResource, TopLevelCategoryResource])
|
|
190
|
-
registerPilotiqRoutes(router, panel)
|
|
191
|
-
const paths = router.list().map(r => `${r.method} ${r.path}`)
|
|
192
|
-
assert.ok(paths.includes('GET /admin/categories')) // top-level
|
|
193
|
-
assert.ok(paths.includes('GET /admin/content/articles'))
|
|
194
|
-
})
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
describe('Cluster — panelInfo navigation tree', () => {
|
|
198
|
-
it('nests children under the cluster as a parent nav item', async () => {
|
|
199
|
-
const panel = Pilotiq.make('nav-cluster').path('/admin')
|
|
200
|
-
.clusters([ContentCluster])
|
|
201
|
-
.resources([ArticleResource])
|
|
202
|
-
const info = await panelInfo(panel)
|
|
203
|
-
const nav = info.navigation
|
|
204
|
-
const cluster = nav.find(n => n.name === 'ContentCluster')
|
|
205
|
-
assert.ok(cluster, 'cluster nav item should exist')
|
|
206
|
-
assert.equal(cluster!.label, 'Content')
|
|
207
|
-
assert.equal(cluster!.url, '/admin/content/articles') // first child URL
|
|
208
|
-
assert.deepEqual(cluster!.children?.map(c => c.name), ['ArticleResource'])
|
|
209
|
-
// No top-level ArticleResource — it's nested under the cluster.
|
|
210
|
-
assert.equal(nav.find(n => n.name === 'ArticleResource'), undefined)
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
it('drops a cluster whose every child is gated by canAccess', async () => {
|
|
214
|
-
class HiddenResource extends Resource {
|
|
215
|
-
static override label = 'Hidden'
|
|
216
|
-
static override slug = 'hidden'
|
|
217
|
-
static override cluster = ContentCluster
|
|
218
|
-
static override async canAccess() { return false }
|
|
219
|
-
}
|
|
220
|
-
const panel = Pilotiq.make('nav-empty-cluster').path('/admin')
|
|
221
|
-
.clusters([ContentCluster])
|
|
222
|
-
.resources([HiddenResource])
|
|
223
|
-
const info = await panelInfo(panel)
|
|
224
|
-
assert.equal(info.navigation.find(n => n.name === 'ContentCluster'), undefined)
|
|
225
|
-
})
|
|
226
|
-
|
|
227
|
-
it('cluster.canAccess(false) hides the cluster + every child', async () => {
|
|
228
|
-
class GatedCluster extends Cluster {
|
|
229
|
-
static override label = 'Gated'
|
|
230
|
-
static override slug = 'gated'
|
|
231
|
-
static override async canAccess() { return false }
|
|
232
|
-
}
|
|
233
|
-
class GatedArticleResource extends Resource {
|
|
234
|
-
static override label = 'Articles'
|
|
235
|
-
static override slug = 'gated-articles'
|
|
236
|
-
static override cluster = GatedCluster
|
|
237
|
-
}
|
|
238
|
-
const panel = Pilotiq.make('nav-gated').path('/admin')
|
|
239
|
-
.clusters([GatedCluster])
|
|
240
|
-
.resources([GatedArticleResource])
|
|
241
|
-
const info = await panelInfo(panel)
|
|
242
|
-
assert.equal(info.navigation.find(n => n.name === 'GatedCluster'), undefined)
|
|
243
|
-
assert.equal(info.navigation.find(n => n.name === 'GatedArticleResource'), undefined)
|
|
244
|
-
})
|
|
245
|
-
|
|
246
|
-
it('uses landingPage URL when set', async () => {
|
|
247
|
-
class HomePage extends Page {
|
|
248
|
-
static override slug = 'home'
|
|
249
|
-
static override label = 'Home'
|
|
250
|
-
static override cluster = ContentCluster
|
|
251
|
-
static override schema() { return [Heading.make('Home')] }
|
|
252
|
-
}
|
|
253
|
-
class CC extends ContentCluster {
|
|
254
|
-
static override landingPage = HomePage
|
|
255
|
-
}
|
|
256
|
-
class CCArticleResource extends Resource {
|
|
257
|
-
static override label = 'Articles'
|
|
258
|
-
static override slug = 'cc-articles'
|
|
259
|
-
static override cluster = CC
|
|
260
|
-
}
|
|
261
|
-
const panel = Pilotiq.make('nav-landing').path('/admin')
|
|
262
|
-
.clusters([CC])
|
|
263
|
-
.resources([CCArticleResource])
|
|
264
|
-
.pages([HomePage])
|
|
265
|
-
const info = await panelInfo(panel)
|
|
266
|
-
const cluster = info.navigation.find(n => n.name === 'CC')
|
|
267
|
-
assert.ok(cluster)
|
|
268
|
-
assert.equal(cluster!.url, '/admin/content/home') // landingPage wins over first-child
|
|
269
|
-
})
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
describe('Cluster — global search URL', () => {
|
|
273
|
-
it('Resource.getGlobalSearchResultUrl threads cluster prefix', () => {
|
|
274
|
-
assert.equal(
|
|
275
|
-
ArticleResource.getGlobalSearchResultUrl({ id: '42' }, '/admin'),
|
|
276
|
-
'/admin/content/articles/42',
|
|
277
|
-
)
|
|
278
|
-
assert.equal(
|
|
279
|
-
TopLevelCategoryResource.getGlobalSearchResultUrl({ id: '7' }, '/admin'),
|
|
280
|
-
'/admin/categories/7',
|
|
281
|
-
)
|
|
282
|
-
})
|
|
283
|
-
})
|
package/src/Cluster.ts
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import type { IconValue } from './icons/types.js'
|
|
2
|
-
import type { NavigationBadgeColor, NavigationBadgeHandler } from './Resource.js'
|
|
3
|
-
import type { Page } from './Page.js'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* URL-prefix container that groups Resources, Globals, and custom Pages
|
|
7
|
-
* under a shared slug and a single sidebar entry. Children opt in via
|
|
8
|
-
* `static cluster = MyCluster`.
|
|
9
|
-
*/
|
|
10
|
-
export abstract class Cluster {
|
|
11
|
-
/** Human-readable label for the cluster nav entry, e.g. `'Content'`. */
|
|
12
|
-
static label: string = 'Cluster'
|
|
13
|
-
|
|
14
|
-
/** URL slug. Derived from `label` when unset. */
|
|
15
|
-
static slug: string = ''
|
|
16
|
-
|
|
17
|
-
/** Sidebar / nav icon. String registry key or React component. See
|
|
18
|
-
* `Resource.icon` for the contract. */
|
|
19
|
-
static icon: IconValue = 'folder'
|
|
20
|
-
|
|
21
|
-
// ─── Navigation metadata ──────────────────────────
|
|
22
|
-
// Mirrors Resource's nav surface so clusters compose with
|
|
23
|
-
// `navigationGroup` (a Settings cluster sitting under a 'System'
|
|
24
|
-
// group, etc.) and `navigationParentItem` (a sub-cluster under a
|
|
25
|
-
// parent nav item).
|
|
26
|
-
|
|
27
|
-
/** Group label this cluster renders under in the sidebar. */
|
|
28
|
-
static navigationGroup: string | undefined = undefined
|
|
29
|
-
|
|
30
|
-
/** Sort key within a group. Lower sorts first. */
|
|
31
|
-
static navigationSort: number | undefined = undefined
|
|
32
|
-
|
|
33
|
-
/** Sidebar label override. `Cluster.label` still drives URL paths. */
|
|
34
|
-
static navigationLabel: string | undefined = undefined
|
|
35
|
-
|
|
36
|
-
/** Sidebar icon override. */
|
|
37
|
-
static navigationIcon: IconValue = undefined
|
|
38
|
-
|
|
39
|
-
/** Server-eval'd badge handler; rendered as a small pill next to the
|
|
40
|
-
* cluster label. Errors are swallowed by `panelInfo()` so a flaky
|
|
41
|
-
* count never blanks the page. The cluster's badge does NOT aggregate
|
|
42
|
-
* its children's badges — it's an independent handler. */
|
|
43
|
-
static navigationBadge: NavigationBadgeHandler | undefined = undefined
|
|
44
|
-
|
|
45
|
-
/** Pill color for the badge. */
|
|
46
|
-
static navigationBadgeColor: NavigationBadgeColor = 'default'
|
|
47
|
-
|
|
48
|
-
/** Class name of a parent nav item. */
|
|
49
|
-
static navigationParentItem: string | undefined = undefined
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Optional landing page when the cluster nav entry is clicked. Must be
|
|
53
|
-
* a Page registered in `cfg.pages` whose `static cluster` points at
|
|
54
|
-
* this cluster. When unset, the cluster nav URL deep-links to the
|
|
55
|
-
* first accessible child (resource list / global edit / custom page).
|
|
56
|
-
*/
|
|
57
|
-
static landingPage?: typeof Page
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Coarse "should this cluster exist for this user" gate. Failing
|
|
61
|
-
* `canAccess` drops the cluster + every child from the nav tree and
|
|
62
|
-
* 403s every child route. Throws are treated as `false` (fail closed).
|
|
63
|
-
*/
|
|
64
|
-
static async canAccess(_user: unknown): Promise<boolean> { return true }
|
|
65
|
-
|
|
66
|
-
/** URL slug, derived from `label` when not set explicitly. */
|
|
67
|
-
static getSlug(): string {
|
|
68
|
-
return this.slug || this.label.toLowerCase().replace(/\s+/g, '-')
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** Sidebar label: `navigationLabel` override falls through to `label`. */
|
|
72
|
-
static getNavigationLabel(): string {
|
|
73
|
-
return this.navigationLabel ?? this.label
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/** Sidebar icon: `navigationIcon` override falls through to `icon`. */
|
|
77
|
-
static getNavigationIcon(): IconValue {
|
|
78
|
-
return this.navigationIcon ?? this.icon
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** Constructor type for `Cluster` subclasses. Used in panel registration. */
|
|
83
|
-
export type ClusterClass = typeof Cluster
|
package/src/Column.test.ts
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { Column } from './Column.js'
|
|
5
|
-
import { resolveSchema } from './schema/resolveSchema.js'
|
|
6
|
-
|
|
7
|
-
describe('Column', () => {
|
|
8
|
-
it('toMeta emits type=column with name + label + flags', () => {
|
|
9
|
-
const meta = Column.make('title').label('Title').sortable().searchable().toMeta()
|
|
10
|
-
assert.deepEqual(meta, {
|
|
11
|
-
type: 'column',
|
|
12
|
-
name: 'title',
|
|
13
|
-
label: 'Title',
|
|
14
|
-
sortable: true,
|
|
15
|
-
searchable: true,
|
|
16
|
-
})
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
it('label defaults to capitalized name when not set', () => {
|
|
20
|
-
const meta = Column.make('createdAt').toMeta()
|
|
21
|
-
assert.equal(meta.label, 'CreatedAt')
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('sortable / searchable default to false', () => {
|
|
25
|
-
const meta = Column.make('x').toMeta()
|
|
26
|
-
assert.equal(meta.sortable, false)
|
|
27
|
-
assert.equal(meta.searchable, false)
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
it('joins the resolver tree as a leaf Element', async () => {
|
|
31
|
-
const result = await resolveSchema([Column.make('title')])
|
|
32
|
-
assert.equal(result.length, 1)
|
|
33
|
-
assert.equal(result[0]!.type, 'column')
|
|
34
|
-
assert.equal('children' in result[0]!, false)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
describe('layout & cosmetics', () => {
|
|
38
|
-
it('alignment / width / default / tooltip / wrap / lineClamp / weight / color round-trip', () => {
|
|
39
|
-
const meta = Column.make('a')
|
|
40
|
-
.alignment('center')
|
|
41
|
-
.width('120px')
|
|
42
|
-
.default('—')
|
|
43
|
-
.tooltip('Help')
|
|
44
|
-
.wrap()
|
|
45
|
-
.lineClamp(2)
|
|
46
|
-
.weight('semibold')
|
|
47
|
-
.color('muted')
|
|
48
|
-
.toMeta()
|
|
49
|
-
assert.equal(meta.alignment, 'center')
|
|
50
|
-
assert.equal(meta.width, '120px')
|
|
51
|
-
assert.equal(meta.default, '—')
|
|
52
|
-
assert.equal(meta.tooltip, 'Help')
|
|
53
|
-
assert.equal(meta.wrap, true)
|
|
54
|
-
assert.equal(meta.lineClamp, 2)
|
|
55
|
-
assert.equal(meta.weight, 'semibold')
|
|
56
|
-
assert.equal(meta.color, 'muted')
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
it('placeholder() is an alias for default()', () => {
|
|
60
|
-
const meta = Column.make('a').placeholder('—').toMeta()
|
|
61
|
-
assert.equal(meta.default, '—')
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
it('cosmetic builders are absent from meta when not called', () => {
|
|
65
|
-
const meta = Column.make('a').toMeta()
|
|
66
|
-
assert.equal(meta.alignment, undefined)
|
|
67
|
-
assert.equal(meta.width, undefined)
|
|
68
|
-
assert.equal(meta.tooltip, undefined)
|
|
69
|
-
assert.equal(meta.wrap, undefined)
|
|
70
|
-
assert.equal(meta.color, undefined)
|
|
71
|
-
})
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
describe('built-in formatters', () => {
|
|
75
|
-
it('dateTime() with default pattern', () => {
|
|
76
|
-
const meta = Column.make('createdAt').dateTime().toMeta()
|
|
77
|
-
assert.deepEqual(meta.format, { kind: 'dateTime' })
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
it('dateTime("PPpp")', () => {
|
|
81
|
-
const meta = Column.make('createdAt').dateTime('PPpp').toMeta()
|
|
82
|
-
assert.deepEqual(meta.format, { kind: 'dateTime', pattern: 'PPpp' })
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('since() emits kind:since', () => {
|
|
86
|
-
const meta = Column.make('createdAt').since().toMeta()
|
|
87
|
-
assert.deepEqual(meta.format, { kind: 'since' })
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('money(currency) emits kind:money + currency', () => {
|
|
91
|
-
const meta = Column.make('amount').money('EUR').toMeta()
|
|
92
|
-
assert.deepEqual(meta.format, { kind: 'money', currency: 'EUR' })
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
it('numeric({decimals}) emits kind:numeric + decimals', () => {
|
|
96
|
-
const meta = Column.make('x').numeric({ decimals: 2 }).toMeta()
|
|
97
|
-
assert.deepEqual(meta.format, { kind: 'numeric', decimals: 2 })
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
it('limit(n) emits kind:limit + chars', () => {
|
|
101
|
-
const meta = Column.make('body').limit(40).toMeta()
|
|
102
|
-
assert.deepEqual(meta.format, { kind: 'limit', chars: 40 })
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
it('formatStateUsing stamps hasFormatter:true on meta', () => {
|
|
106
|
-
const col = Column.make('priority').formatStateUsing((v) => `${v}!`)
|
|
107
|
-
const meta = col.toMeta()
|
|
108
|
-
assert.equal(meta.hasFormatter, true)
|
|
109
|
-
assert.equal(col.hasFormatter(), true)
|
|
110
|
-
assert.equal(typeof col.getFormatStateHandler(), 'function')
|
|
111
|
-
})
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
describe('recordUrl per-column override / opt-out', () => {
|
|
115
|
-
it('absent by default — column inherits the table-level recordUrl', () => {
|
|
116
|
-
const col = Column.make('title')
|
|
117
|
-
const meta = col.toMeta()
|
|
118
|
-
assert.equal(meta.recordUrl, undefined)
|
|
119
|
-
assert.equal(col.isRecordUrlDisabled(), false)
|
|
120
|
-
assert.equal(col.hasRecordUrlHandler(), false)
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
it('recordUrl(false) emits recordUrl:false on meta', () => {
|
|
124
|
-
const col = Column.make('actions').recordUrl(false)
|
|
125
|
-
const meta = col.toMeta()
|
|
126
|
-
assert.equal(meta.recordUrl, false)
|
|
127
|
-
assert.equal(col.isRecordUrlDisabled(), true)
|
|
128
|
-
assert.equal(col.hasRecordUrlHandler(), false)
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
it('recordUrl(fn) emits recordUrl:true on meta and exposes the handler', () => {
|
|
132
|
-
const col = Column.make('title').recordUrl((r) => `/posts/${(r as { id?: string }).id}`)
|
|
133
|
-
const meta = col.toMeta()
|
|
134
|
-
assert.equal(meta.recordUrl, true)
|
|
135
|
-
assert.equal(col.hasRecordUrlHandler(), true)
|
|
136
|
-
assert.equal(col.isRecordUrlDisabled(), false)
|
|
137
|
-
assert.equal(typeof col.getRecordUrlHandler(), 'function')
|
|
138
|
-
})
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
describe('beforeStateUpdated / afterStateUpdated accessors', () => {
|
|
142
|
-
it('return undefined when no hooks are set', () => {
|
|
143
|
-
const col = Column.make('title')
|
|
144
|
-
assert.equal(col.getBeforeStateUpdated(), undefined)
|
|
145
|
-
assert.equal(col.getAfterStateUpdated(), undefined)
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
it('return the registered hook function', () => {
|
|
149
|
-
const before = async () => {}
|
|
150
|
-
const after = () => {}
|
|
151
|
-
const col = Column.make('title').beforeStateUpdated(before).afterStateUpdated(after)
|
|
152
|
-
assert.equal(col.getBeforeStateUpdated(), before)
|
|
153
|
-
assert.equal(col.getAfterStateUpdated(), after)
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
it('hooks are not serialized into the wire shape', () => {
|
|
157
|
-
const col = Column.make('title').beforeStateUpdated(() => {}).afterStateUpdated(() => {})
|
|
158
|
-
const meta = col.toMeta()
|
|
159
|
-
assert.equal((meta as Record<string, unknown>)['beforeStateUpdated'], undefined)
|
|
160
|
-
assert.equal((meta as Record<string, unknown>)['afterStateUpdated'], undefined)
|
|
161
|
-
})
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
describe('toggleable() user-visibility chrome', () => {
|
|
165
|
-
it('isToggleable + getToggleableConfig default to false / undefined', () => {
|
|
166
|
-
const col = Column.make('email')
|
|
167
|
-
assert.equal(col.isToggleable(), false)
|
|
168
|
-
assert.equal(col.getToggleableConfig(), undefined)
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
it('bare toggleable() opts in with defaults (visible by default)', () => {
|
|
172
|
-
const col = Column.make('email').toggleable()
|
|
173
|
-
assert.equal(col.isToggleable(), true)
|
|
174
|
-
assert.deepEqual(col.getToggleableConfig(), {})
|
|
175
|
-
const meta = col.toMeta() as Record<string, unknown>
|
|
176
|
-
assert.deepEqual(meta['toggleable'], {})
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
it('toggleable({ initiallyHidden: true }) starts off-screen', () => {
|
|
180
|
-
const col = Column.make('internalId').toggleable({ initiallyHidden: true })
|
|
181
|
-
const cfg = col.getToggleableConfig()
|
|
182
|
-
assert.equal(cfg?.initiallyHidden, true)
|
|
183
|
-
const meta = col.toMeta() as Record<string, unknown>
|
|
184
|
-
assert.deepEqual(meta['toggleable'], { initiallyHidden: true })
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
it('toggleable(false) explicitly opts back out', () => {
|
|
188
|
-
const col = Column.make('email').toggleable().toggleable(false)
|
|
189
|
-
assert.equal(col.isToggleable(), false)
|
|
190
|
-
const meta = col.toMeta() as Record<string, unknown>
|
|
191
|
-
assert.equal(meta['toggleable'], undefined)
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
it('omits the meta key when not opted in (sparse wire shape)', () => {
|
|
195
|
-
const meta = Column.make('plain').toMeta() as Record<string, unknown>
|
|
196
|
-
assert.equal('toggleable' in meta, false)
|
|
197
|
-
})
|
|
198
|
-
})
|
|
199
|
-
})
|