@pilotiq/pilotiq 0.24.1 → 0.24.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/boost/guidelines.md +566 -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/package.json +6 -1
- 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/Resource.ts
DELETED
|
@@ -1,526 +0,0 @@
|
|
|
1
|
-
import type { Element } from './schema/Element.js'
|
|
2
|
-
import type { Form } from './elements/Form.js'
|
|
3
|
-
import { Table } from './elements/Table.js'
|
|
4
|
-
import type { Page } from './Page.js'
|
|
5
|
-
import type { ModelLike, ModelQuery, QueryContext } from './orm/modelDefaults.js'
|
|
6
|
-
import type { IconValue } from './icons/types.js'
|
|
7
|
-
import { defaultPages } from './defaultPages.js'
|
|
8
|
-
import type { RelationManager } from './RelationManager.js'
|
|
9
|
-
import type { SchemaContext } from './schema/resolveSchema.js'
|
|
10
|
-
import type { ClusterClass } from './Cluster.js'
|
|
11
|
-
import { resourceBasePath } from './clusterPaths.js'
|
|
12
|
-
|
|
13
|
-
/** Map of resource page roles to Page subclasses. */
|
|
14
|
-
export interface ResourcePages {
|
|
15
|
-
index?: typeof Page
|
|
16
|
-
create?: typeof Page
|
|
17
|
-
edit?: typeof Page
|
|
18
|
-
view?: typeof Page
|
|
19
|
-
/**
|
|
20
|
-
* Record-scoped custom sub-pages. Each entry is a `Page` subclass
|
|
21
|
-
* mounted at `${resourceBase}/${slug}/:id/${subPageSlug}`. Tabs show
|
|
22
|
-
* up in the `RelationTabs` sub-nav strip between the `__edit` tab
|
|
23
|
-
* and the relation-manager tabs.
|
|
24
|
-
*
|
|
25
|
-
* Sub-page slugs are validated at panel boot:
|
|
26
|
-
* - Must match `[A-Za-z0-9_-]+`.
|
|
27
|
-
* - Must not collide with reserved tokens (`edit`, `delete`,
|
|
28
|
-
* `restore`, `force-delete`, `_form`, `_action`, `_search`,
|
|
29
|
-
* `_uploads`, `_attach`, `_detach`, `_bulk-detach`, `create`).
|
|
30
|
-
* - Must not collide with any `RelationManager.relationship` on
|
|
31
|
-
* the same resource.
|
|
32
|
-
*
|
|
33
|
-
* Each sub-page receives the loaded record in `ctx.record` and runs
|
|
34
|
-
* its own `Page.canAccess(user, record)` gate after the parent
|
|
35
|
-
* resource's `canAccess` + `canView` predicates have passed.
|
|
36
|
-
*/
|
|
37
|
-
record?: Record<string, typeof Page>
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Pill color tokens for `navigationBadgeColor`. Matches the shared color
|
|
41
|
-
* palette used by `ListTab.badgeColor` so the renderer can re-use the
|
|
42
|
-
* same Tailwind utility map. */
|
|
43
|
-
export type NavigationBadgeColor =
|
|
44
|
-
| 'default' | 'primary' | 'success' | 'warning' | 'destructive' | 'info'
|
|
45
|
-
|
|
46
|
-
/** Returned by `navigationBadge`: a string/number to render as a pill,
|
|
47
|
-
* or undefined to render no pill. May be async. Errors thrown from this
|
|
48
|
-
* handler are swallowed by `panelInfo()` so a flaky count never blanks
|
|
49
|
-
* the page. */
|
|
50
|
-
export type NavigationBadgeHandler =
|
|
51
|
-
() => string | number | undefined | Promise<string | number | undefined>
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Per-resource collab configuration. Set via `static collab = true` (the
|
|
55
|
-
* 90% case — opts the edit page in with presence) or via the object form
|
|
56
|
-
* for finer control. Omitting `static collab` entirely keeps the resource
|
|
57
|
-
* collab-free even when the `@pilotiq-pro/collab` plugin is registered.
|
|
58
|
-
*
|
|
59
|
-
* pages — page roles where collab activates. `'edit'` syncs values +
|
|
60
|
-
* presence; `'view'` is presence-only (the page is read-only,
|
|
61
|
-
* value-sync would be moot). Defaults to `['edit']`.
|
|
62
|
-
* presence — when false, suppress the awareness layer (focus chips,
|
|
63
|
-
* cursor positions) while keeping value-sync. Defaults to true.
|
|
64
|
-
*
|
|
65
|
-
* Field-level `.collab(false)` always wins over this setting — opting the
|
|
66
|
-
* resource in then opting individual fields out is the supported shape.
|
|
67
|
-
*/
|
|
68
|
-
export interface ResourceCollabConfig {
|
|
69
|
-
pages: ReadonlyArray<'edit' | 'view'>
|
|
70
|
-
presence: boolean
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** Raw shape accepted by `static collab` before normalization. `true` is a
|
|
74
|
-
* shorthand for `{ pages: ['edit'], presence: true }`. */
|
|
75
|
-
export type ResourceCollabInput = boolean | {
|
|
76
|
-
pages?: ReadonlyArray<'edit' | 'view'>
|
|
77
|
-
presence?: boolean
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Abstract Resource base class. **All methods are static** — resources are
|
|
82
|
-
* registered by class, not by instance. Routes look up the class and call
|
|
83
|
-
* statics directly.
|
|
84
|
-
*
|
|
85
|
-
* Subclasses override `form()`, `table()`, `detail()`, and `pages()` to
|
|
86
|
-
* shape the resource. Defaults make the most-common case (CRUD with a
|
|
87
|
-
* form + a table) work with minimal boilerplate; 2.2 will fill in
|
|
88
|
-
* auto-generated default Page classes.
|
|
89
|
-
*/
|
|
90
|
-
export abstract class Resource {
|
|
91
|
-
/** Human-readable plural label, e.g. `'Articles'`. */
|
|
92
|
-
static label: string = 'Resources'
|
|
93
|
-
|
|
94
|
-
/** Singular label, e.g. `'Article'`. */
|
|
95
|
-
static labelSingular: string = 'Resource'
|
|
96
|
-
|
|
97
|
-
/** Breadcrumb label override. Falls through to `label`. Use this when
|
|
98
|
-
* the breadcrumb chain reads better with a different word than the
|
|
99
|
-
* sidebar / page-title plural — e.g. `label = 'Blog Posts'` paired
|
|
100
|
-
* with `breadcrumb = 'Posts'` for a tighter chain. */
|
|
101
|
-
static breadcrumb: string | undefined = undefined
|
|
102
|
-
|
|
103
|
-
/** URL slug. Derived from `label` when unset. */
|
|
104
|
-
static slug: string = ''
|
|
105
|
-
|
|
106
|
-
/** Sidebar / nav icon. Either a kebab-case registry name (e.g.,
|
|
107
|
-
* `'file'`) or a React component reference imported from any icon
|
|
108
|
-
* library (e.g., `import { Newspaper } from 'lucide-react'`).
|
|
109
|
-
* See `@pilotiq/pilotiq/icons` for the registry; component refs
|
|
110
|
-
* resolve via the Vite-plugin `_components.ts` manifest. */
|
|
111
|
-
static icon: IconValue = 'file'
|
|
112
|
-
|
|
113
|
-
// ─── Plan #9: navigation metadata ──────────────────────────
|
|
114
|
-
// Static fields evaluated once at panel-config time; only
|
|
115
|
-
// `navigationBadge` runs per request. See docs/plans/resource-navigation.md.
|
|
116
|
-
|
|
117
|
-
/** Group label this resource renders under in the sidebar. Items
|
|
118
|
-
* without a group land in an unnamed top section. */
|
|
119
|
-
static navigationGroup: string | undefined = undefined
|
|
120
|
-
|
|
121
|
-
/** Sort key within a group. Lower sorts first; ties fall back to
|
|
122
|
-
* registration order. Items without a sort go after sorted items. */
|
|
123
|
-
static navigationSort: number | undefined = undefined
|
|
124
|
-
|
|
125
|
-
/** Sidebar label override. `Resource.label` still drives page titles. */
|
|
126
|
-
static navigationLabel: string | undefined = undefined
|
|
127
|
-
|
|
128
|
-
/** Sidebar icon override. Same `IconValue` contract as `icon`. */
|
|
129
|
-
static navigationIcon: IconValue = undefined
|
|
130
|
-
|
|
131
|
-
/** Server-eval'd badge handler; rendered as a small pill next to the
|
|
132
|
-
* label. Errors thrown here are swallowed so a broken count never
|
|
133
|
-
* breaks page render. */
|
|
134
|
-
static navigationBadge: NavigationBadgeHandler | undefined = undefined
|
|
135
|
-
|
|
136
|
-
/** Pill color for the badge. */
|
|
137
|
-
static navigationBadgeColor: NavigationBadgeColor = 'default'
|
|
138
|
-
|
|
139
|
-
/** Class name (`Resource.name` / `Global.name` / `Page.name`) of a
|
|
140
|
-
* parent nav item. Renders nested under the parent when set; renders
|
|
141
|
-
* at top level when the name doesn't resolve. */
|
|
142
|
-
static navigationParentItem: string | undefined = undefined
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Cluster this resource belongs to. When set, the resource's URLs gain
|
|
146
|
-
* the cluster's slug as a prefix segment (e.g. `/admin/content/articles`
|
|
147
|
-
* instead of `/admin/articles`) and the resource nests under the
|
|
148
|
-
* cluster's nav entry instead of appearing at the panel top level.
|
|
149
|
-
*
|
|
150
|
-
* The referenced class must be registered via `Pilotiq.clusters([…])`;
|
|
151
|
-
* boot fails otherwise.
|
|
152
|
-
*/
|
|
153
|
-
static cluster?: ClusterClass
|
|
154
|
-
|
|
155
|
-
/** Column that names a record when referring to it in search results,
|
|
156
|
-
* breadcrumbs, or relation pickers. Resolution order at the call site
|
|
157
|
-
* is `recordTitleAttribute` → `'name'` → `'title'` → `'id'`. */
|
|
158
|
-
static recordTitleAttribute: string | undefined = undefined
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Optional ORM model. When set, `defaultPages` auto-fills `Form.save`,
|
|
162
|
-
* `Form.loadRecord`, `Table.records`, and `Resource.deleteRecord` so
|
|
163
|
-
* the common CRUD case needs no manual wiring. Anything explicitly
|
|
164
|
-
* configured on `form()` / `table()` still wins.
|
|
165
|
-
*
|
|
166
|
-
* Any object satisfying `ModelLike` works — `@rudderjs/orm` `Model`
|
|
167
|
-
* subclasses do so structurally via their static methods.
|
|
168
|
-
*/
|
|
169
|
-
static model?: ModelLike
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Hook for scoping every query against this resource's table — list
|
|
173
|
-
* pages, global search, find-by-PK loads (record load for view / edit
|
|
174
|
-
* pages, policy lookups). Default returns `this.model.query()`.
|
|
175
|
-
*
|
|
176
|
-
* Override to install tenant scopes, default ordering, eager-load
|
|
177
|
-
* defaults, or any other always-on filter:
|
|
178
|
-
*
|
|
179
|
-
* @example
|
|
180
|
-
* static override query(ctx) {
|
|
181
|
-
* return super.query(ctx).where('tenantId', (ctx?.user as any)?.tenantId)
|
|
182
|
-
* }
|
|
183
|
-
*
|
|
184
|
-
* @example
|
|
185
|
-
* static override query(ctx) {
|
|
186
|
-
* return super.query(ctx).orderBy('createdAt', 'DESC')
|
|
187
|
-
* }
|
|
188
|
-
*
|
|
189
|
-
* Soft-delete restore / force-delete routes deliberately bypass this
|
|
190
|
-
* — they build their own `query().withTrashed()` chain so a scope that
|
|
191
|
-
* hides trashed rows doesn't hide records the operator is trying to
|
|
192
|
-
* recover. Everything else routes through here.
|
|
193
|
-
*
|
|
194
|
-
* Throws when `static model` isn't set; subclasses without a model
|
|
195
|
-
* must override `query()` directly to return whatever query builder
|
|
196
|
-
* they're driving.
|
|
197
|
-
*/
|
|
198
|
-
static query(_ctx?: QueryContext): ModelQuery {
|
|
199
|
-
if (!this.model) {
|
|
200
|
-
throw new Error(
|
|
201
|
-
`[Pilotiq] ${this.name}.query() requires \`static model = …\` to be set, ` +
|
|
202
|
-
`or override \`static query(ctx)\` directly to return a custom ModelQuery.`,
|
|
203
|
-
)
|
|
204
|
-
}
|
|
205
|
-
return this.model.query()
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// ─── Plan #13: soft deletes ────────────────────────────────
|
|
209
|
-
// Opt-in: when true, pilotiq routes the standard delete action
|
|
210
|
-
// through `model.delete()` (which writes `deletedAt`), surfaces a
|
|
211
|
-
// TrashedFilter on the list page, swaps the row-action set on
|
|
212
|
-
// trashed rows (Restore + Force-delete instead of Edit + Delete),
|
|
213
|
-
// and exposes two new POST routes: `/:id/restore` and
|
|
214
|
-
// `/:id/force-delete`. The rudder ORM side must also opt in
|
|
215
|
-
// (`Model.softDeletes = true`) for the underlying behavior to
|
|
216
|
-
// engage — pilotiq throws a clear boot error when the flag is
|
|
217
|
-
// set here but the model lacks `restore` / `forceDelete`.
|
|
218
|
-
|
|
219
|
-
/** Enable soft-delete UX (TrashedFilter, Restore action,
|
|
220
|
-
* Force-delete action, soft-delete-aware row visibility). Default
|
|
221
|
-
* `false`. Requires `Resource.model` to be set, with
|
|
222
|
-
* `Model.softDeletes = true` on the rudder side. */
|
|
223
|
-
static softDeletes: boolean = false
|
|
224
|
-
|
|
225
|
-
/** Column name carrying the soft-delete timestamp on each row.
|
|
226
|
-
* Per-row visibility predicates and the trashed-row branch in
|
|
227
|
-
* `Action.delete` consult `record[deletedAtColumn]`. Default
|
|
228
|
-
* matches rudder's `'deletedAt'`. */
|
|
229
|
-
static deletedAtColumn: string = 'deletedAt'
|
|
230
|
-
|
|
231
|
-
/** Persist the active list filter / search / sort slice on the
|
|
232
|
-
* user's session so revisiting the resource lands on the same view.
|
|
233
|
-
* No-ops silently when `@rudderjs/session` isn't mounted. */
|
|
234
|
-
static persistFiltersInSession: boolean = false
|
|
235
|
-
|
|
236
|
-
/** Skip server-side row loading on list pages; the client paints a
|
|
237
|
-
* skeleton and fetches rows from `GET {base}/{slug}/_table` after
|
|
238
|
-
* mount. URL chrome (filters / search / page / group) still mirrors
|
|
239
|
-
* on the SSR pass so the skeleton frame doesn't reset visible state. */
|
|
240
|
-
static deferLoading: boolean = false
|
|
241
|
-
|
|
242
|
-
// ─── Plan #12: global search ───────────────────────────────
|
|
243
|
-
// Opt-in: resources with `globalSearch = false` are skipped by the
|
|
244
|
-
// panel-level Cmd+K palette. Defaults below derive everything from
|
|
245
|
-
// already-shipped surfaces (`recordTitleAttribute`, `Column.searchable()`,
|
|
246
|
-
// the standard view URL) so the common case needs zero overrides.
|
|
247
|
-
|
|
248
|
-
/** Include this resource in Cmd+K palette results. Default `false` —
|
|
249
|
-
* quiet resources don't pollute results until users opt in. */
|
|
250
|
-
static globalSearch: boolean = false
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Columns the default search query LIKE-matches against. The default
|
|
254
|
-
* dedupes `recordTitleAttribute` (Plan #9) with every searchable
|
|
255
|
-
* column on the resource's table. Override to constrain or extend.
|
|
256
|
-
* Returning an empty array effectively opts the resource out even
|
|
257
|
-
* when `globalSearch=true`.
|
|
258
|
-
*/
|
|
259
|
-
static globallySearchableAttributes(): string[] {
|
|
260
|
-
const attrs = new Set<string>()
|
|
261
|
-
if (this.recordTitleAttribute) attrs.add(this.recordTitleAttribute)
|
|
262
|
-
// Materialise the resource's configured table once and read every
|
|
263
|
-
// `searchable()` column off it. The Table builder is a pure
|
|
264
|
-
// configuration call (no DB hits, no I/O), so doing this per
|
|
265
|
-
// search request is fine; resources that don't want this can
|
|
266
|
-
// override `globallySearchableAttributes()` directly.
|
|
267
|
-
try {
|
|
268
|
-
const table = this.table(Table.make())
|
|
269
|
-
for (const col of table.getColumns()) {
|
|
270
|
-
if (col.isSearchable()) attrs.add(col.name)
|
|
271
|
-
}
|
|
272
|
-
} catch { /* defensive — bad user table()? skip */ }
|
|
273
|
-
return [...attrs]
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Title shown in the palette result row. Default resolution chain:
|
|
278
|
-
* `record[recordTitleAttribute]` → `record.name` → `record.title` →
|
|
279
|
-
* `record.id`. Override to customise (e.g. include the id).
|
|
280
|
-
*/
|
|
281
|
-
static getGlobalSearchResultTitle(record: unknown): string {
|
|
282
|
-
const r = record as Record<string, unknown> | null | undefined
|
|
283
|
-
if (!r) return ''
|
|
284
|
-
if (this.recordTitleAttribute && r[this.recordTitleAttribute] !== undefined) {
|
|
285
|
-
return String(r[this.recordTitleAttribute])
|
|
286
|
-
}
|
|
287
|
-
if (r['name'] !== undefined) return String(r['name'])
|
|
288
|
-
if (r['title'] !== undefined) return String(r['title'])
|
|
289
|
-
if (r['id'] !== undefined) return String(r['id'])
|
|
290
|
-
return ''
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Optional second-line text under the title. Returning `undefined`
|
|
295
|
-
* tells the renderer to skip the subtitle row. Useful for status,
|
|
296
|
-
* timestamps, or category pills.
|
|
297
|
-
*/
|
|
298
|
-
static getGlobalSearchResultSubtitle(_record: unknown): string | undefined {
|
|
299
|
-
return undefined
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* URL the palette navigates to on Enter. Default uses the View page
|
|
304
|
-
* when one exists, else the Edit page, else the resource list. Pass
|
|
305
|
-
* `base` (the panel base path) so overrides don't have to thread it
|
|
306
|
-
* through the panel config.
|
|
307
|
-
*/
|
|
308
|
-
static getGlobalSearchResultUrl(record: unknown, base: string): string {
|
|
309
|
-
const r = record as Record<string, unknown> | null | undefined
|
|
310
|
-
const prefix = resourceBasePath(base, this)
|
|
311
|
-
if (!r) return prefix
|
|
312
|
-
const id = r['id']
|
|
313
|
-
if (id === undefined || id === null) return prefix
|
|
314
|
-
return `${prefix}/${String(id)}`
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* Override the default LIKE-on-attributes search query. Return a
|
|
319
|
-
* `ModelQuery` (still chainable through `paginate(1, limit)`) for
|
|
320
|
-
* advanced cases — joins, full-text, `pg_trgm`. Returning `undefined`
|
|
321
|
-
* (the default) falls through to the framework-built query.
|
|
322
|
-
*/
|
|
323
|
-
static getGlobalSearchQuery(_needle: string): ModelQuery | undefined {
|
|
324
|
-
return undefined
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// ─── Realtime collab opt-in ────────────────────────────────
|
|
328
|
-
// Opt-in per resource. The `@pilotiq-pro/collab` plugin registers the
|
|
329
|
-
// global singletons (transport, Tiptap extension factory, RecordWrapper
|
|
330
|
-
// factory); resources with `static collab` unset stay collab-free even
|
|
331
|
-
// when the plugin is installed. Field-level `.collab(false)` overrides
|
|
332
|
-
// this setting per field.
|
|
333
|
-
|
|
334
|
-
/** Enable collab on this resource. `true` is the 90% case — shorthand
|
|
335
|
-
* for `{ pages: ['edit'], presence: true }`. Use the object form to
|
|
336
|
-
* narrow which page roles activate or to suppress presence. Default
|
|
337
|
-
* `false` (collab off — the WS room is never opened for this resource). */
|
|
338
|
-
static collab: ResourceCollabInput = false
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* Normalize `static collab` into the canonical wire shape, or return
|
|
342
|
-
* `null` when the resource has opted out. Centralizes the `true` →
|
|
343
|
-
* defaults expansion and the `{ pages?: … }` merge.
|
|
344
|
-
*
|
|
345
|
-
* Result lands on `panelInfo().recordCollab[slug]`; the gate reads it
|
|
346
|
-
* to decide whether to mount the record wrapper.
|
|
347
|
-
*/
|
|
348
|
-
static getResolvedCollabConfig(): ResourceCollabConfig | null {
|
|
349
|
-
const raw = this.collab
|
|
350
|
-
if (raw === false || raw == null) return null
|
|
351
|
-
if (raw === true) return { pages: ['edit'], presence: true }
|
|
352
|
-
return {
|
|
353
|
-
pages: raw.pages ?? ['edit'],
|
|
354
|
-
presence: raw.presence ?? true,
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
// ─── Plan #10: authorization predicates ────────────────────
|
|
359
|
-
// All async, all default `true`. Routes call them with the resolved
|
|
360
|
-
// user (from `Pilotiq.user(fn)`); the renderer threads the same user
|
|
361
|
-
// into nav-tree filtering and `Action.create/edit/view/delete`
|
|
362
|
-
// factories. Override per-resource with role/policy logic. The user
|
|
363
|
-
// argument is whatever `Pilotiq.user(req => …)` returns — opaque to
|
|
364
|
-
// pilotiq, your shape.
|
|
365
|
-
|
|
366
|
-
/** Coarse "should this resource exist for this user at all" gate.
|
|
367
|
-
* Failing `canAccess` drops the resource from the nav tree entirely
|
|
368
|
-
* and 403s every route under it. */
|
|
369
|
-
static async canAccess(_user: unknown): Promise<boolean> { return true }
|
|
370
|
-
|
|
371
|
-
/** Allowed to load the index/list page. Item still appears in nav
|
|
372
|
-
* when `canAccess` passes but `canViewAny` fails — the URL just 403s. */
|
|
373
|
-
static async canViewAny(_user: unknown): Promise<boolean> { return true }
|
|
374
|
-
|
|
375
|
-
/** Allowed to load the read-only view page for a given record. */
|
|
376
|
-
static async canView(_user: unknown, _record: unknown): Promise<boolean> { return true }
|
|
377
|
-
|
|
378
|
-
/** Allowed to access the create page + invoke the create form.
|
|
379
|
-
* Auto-hides `Action.create(R, …)` triggers that haven't set an
|
|
380
|
-
* explicit `.visible()` rule. */
|
|
381
|
-
static async canCreate(_user: unknown): Promise<boolean> { return true }
|
|
382
|
-
|
|
383
|
-
/** Allowed to edit a given record. Auto-hides `Action.edit(R, …)`
|
|
384
|
-
* triggers without an explicit `.visible()` rule. */
|
|
385
|
-
static async canEdit(_user: unknown, _record: unknown): Promise<boolean> { return true }
|
|
386
|
-
|
|
387
|
-
/** Allowed to delete a given record. Auto-hides `Action.delete(R, …)`
|
|
388
|
-
* triggers without an explicit `.visible()` rule. */
|
|
389
|
-
static async canDelete(_user: unknown, _record: unknown): Promise<boolean> { return true }
|
|
390
|
-
|
|
391
|
-
/** Plan #13 — allowed to restore a soft-deleted record. Defaults
|
|
392
|
-
* `true`; auto-hides `Action.restore(R, …)` when false. Only
|
|
393
|
-
* checked on resources with `softDeletes = true`. */
|
|
394
|
-
static async canRestore(_user: unknown, _record: unknown): Promise<boolean> { return true }
|
|
395
|
-
|
|
396
|
-
/** Plan #13 — allowed to permanently delete a soft-deleted record.
|
|
397
|
-
* Defaults to whatever `canDelete` returns when this method is *not*
|
|
398
|
-
* overridden — soft-delete restore is generally lower-privilege
|
|
399
|
-
* than force-delete, but force-delete inheriting from delete is the
|
|
400
|
-
* conservative starting point. Override this to tighten or loosen
|
|
401
|
-
* independently. Only checked on resources with `softDeletes = true`.
|
|
402
|
-
*
|
|
403
|
-
* The `safeForceDeletePolicy` helper (used by routes + `Action.forceDelete`
|
|
404
|
-
* visibility) detects the un-overridden case via reference equality
|
|
405
|
-
* against `Resource.canForceDelete` — same trick Plan #11 uses for
|
|
406
|
-
* `safeManagerPolicy`. Don't reassign `Resource.canForceDelete`
|
|
407
|
-
* outside of subclass overrides; it'd break the detection globally. */
|
|
408
|
-
static async canForceDelete(this: ResourceClass, user: unknown, record: unknown): Promise<boolean> {
|
|
409
|
-
return this.canDelete(user, record)
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Configure the form used by `create` and `edit` pages by default.
|
|
414
|
-
* Receives a fresh `Form` instance; return the configured form.
|
|
415
|
-
*/
|
|
416
|
-
static form(form: Form): Form { return form }
|
|
417
|
-
|
|
418
|
-
/**
|
|
419
|
-
* Configure the table used by the `index` page by default.
|
|
420
|
-
* Receives a fresh `Table` instance; return the configured table.
|
|
421
|
-
*/
|
|
422
|
-
static table(table: Table): Table { return table }
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Schema for the read-only `view` page. Receives the loaded record.
|
|
426
|
-
* Returns an array of Elements (typically Sections + display elements).
|
|
427
|
-
*/
|
|
428
|
-
static detail(_record: unknown): Element[] { return [] }
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Plan #15 — schema rendered above the list-page table. Default `[]`.
|
|
432
|
-
* Typical use: dashboard widgets that contextualize the list (KPI cards,
|
|
433
|
-
* charts, status alerts). Anything Element-typed is allowed —
|
|
434
|
-
* `Group / Card / Section` for layout, `Stat / StatsOverview / Chart /
|
|
435
|
-
* TableWidget / View` for server-data widgets, `Heading / Alert` for
|
|
436
|
-
* static chrome. Resolves with the same `SchemaContext` passed to the
|
|
437
|
-
* list page's schema (carries `mode: 'table'`, `basePath`, `user`).
|
|
438
|
-
* Server-data widgets inside resolve in parallel via the shared
|
|
439
|
-
* `_widgetData` map and re-fetch through `POST {base}/{slug}/_widget/:id`.
|
|
440
|
-
* The hook only fires after `Resource.canAccess(user)` passes (route-level
|
|
441
|
-
* gate) — there's no extra per-hook authorization.
|
|
442
|
-
*/
|
|
443
|
-
static headerSchema(_ctx?: SchemaContext): Element[] | Promise<Element[]> { return [] }
|
|
444
|
-
|
|
445
|
-
/**
|
|
446
|
-
* Plan #15 — schema rendered below the list-page table. Default `[]`.
|
|
447
|
-
* Same shape and posture as `headerSchema()`; useful for footnotes,
|
|
448
|
-
* legends, or "longest-running…" tables that contextualize the list
|
|
449
|
-
* from below.
|
|
450
|
-
*/
|
|
451
|
-
static footerSchema(_ctx?: SchemaContext): Element[] | Promise<Element[]> { return [] }
|
|
452
|
-
|
|
453
|
-
/**
|
|
454
|
-
* Delete a record by id. Falls through to `model.delete(id)` when
|
|
455
|
-
* `static model` is set; otherwise throws so the user knows to wire
|
|
456
|
-
* something up. Override on the subclass for custom delete logic.
|
|
457
|
-
* Wired up by the `POST {base}/{slug}/{id}/delete` route.
|
|
458
|
-
*/
|
|
459
|
-
static async deleteRecord(id: string): Promise<void> {
|
|
460
|
-
if (this.model) {
|
|
461
|
-
await this.model.delete(id)
|
|
462
|
-
return
|
|
463
|
-
}
|
|
464
|
-
throw new Error(
|
|
465
|
-
`[Pilotiq] ${this.name}: no deleteRecord(id) implementation. Set Resource.model = … or override Resource.deleteRecord to wire up deletion.`,
|
|
466
|
-
)
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* User-overridable page map. Return any subset of `{ index, create, edit, view }`
|
|
471
|
-
* to override the auto-generated defaults; missing keys fall through to
|
|
472
|
-
* defaults via `resolvePages()`.
|
|
473
|
-
*/
|
|
474
|
-
static pages(): ResourcePages { return {} }
|
|
475
|
-
|
|
476
|
-
/**
|
|
477
|
-
* Resolved page map: defaults from `defaultPages(this)` overlaid with whatever
|
|
478
|
-
* `pages()` returns. This is what routing consumes (wired in 2.3).
|
|
479
|
-
*/
|
|
480
|
-
static resolvePages(): ResourcePages {
|
|
481
|
-
const defaults = defaultPages(this as unknown as ResourceClass)
|
|
482
|
-
const overrides = this.pages()
|
|
483
|
-
return { ...defaults, ...overrides }
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
/**
|
|
487
|
-
* Sugar over `resolvePages().record ?? {}` for callers that only need
|
|
488
|
-
* the record-scoped sub-pages (route registration, tab insertion, boot
|
|
489
|
-
* validation). Returns an empty object when no record sub-pages are
|
|
490
|
-
* declared so callers can iterate without a defensive null check.
|
|
491
|
-
*/
|
|
492
|
-
static getRecordPages(): Record<string, typeof Page> {
|
|
493
|
-
return this.resolvePages().record ?? {}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
/**
|
|
497
|
-
* Plan #11 — relation managers mounted under this resource's edit /
|
|
498
|
-
* view pages. Each entry is a `RelationManager` subclass; routes are
|
|
499
|
-
* registered under `${base}/${slug}/:id/${manager.relationship}`.
|
|
500
|
-
* Default empty.
|
|
501
|
-
*/
|
|
502
|
-
static relations(): Array<typeof RelationManager> { return [] }
|
|
503
|
-
|
|
504
|
-
/** URL slug, derived from `label` when not set explicitly. */
|
|
505
|
-
static getSlug(): string {
|
|
506
|
-
return this.slug || this.label.toLowerCase().replace(/\s+/g, '-')
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
/** Sidebar label: `navigationLabel` override falls through to `label`. */
|
|
510
|
-
static getNavigationLabel(): string {
|
|
511
|
-
return this.navigationLabel ?? this.label
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
/** Breadcrumb label: `breadcrumb` override falls through to `label`. */
|
|
515
|
-
static getBreadcrumb(): string {
|
|
516
|
-
return this.breadcrumb ?? this.label
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
/** Sidebar icon: `navigationIcon` override falls through to `icon`. */
|
|
520
|
-
static getNavigationIcon(): IconValue {
|
|
521
|
-
return this.navigationIcon ?? this.icon
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
/** Constructor type for `Resource` subclasses. Used in panel registration. */
|
|
526
|
-
export type ResourceClass = typeof Resource
|