@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/defaultPages.ts
DELETED
|
@@ -1,617 +0,0 @@
|
|
|
1
|
-
import { Page } from './Page.js'
|
|
2
|
-
import {
|
|
3
|
-
Form,
|
|
4
|
-
type SavedNotificationHandler,
|
|
5
|
-
type LifecycleHandler,
|
|
6
|
-
type AfterSaveHandler,
|
|
7
|
-
type SaveHandler,
|
|
8
|
-
type RedirectHandler,
|
|
9
|
-
type MutateDataHandler,
|
|
10
|
-
type FillMutator,
|
|
11
|
-
} from './elements/Form.js'
|
|
12
|
-
import { Table } from './elements/Table.js'
|
|
13
|
-
import { Filter } from './filters/Filter.js'
|
|
14
|
-
import { TrashedFilter } from './filters/TrashedFilter.js'
|
|
15
|
-
import { ListTabs } from './elements/ListTabs.js'
|
|
16
|
-
import type { ListTab } from './Tab.js'
|
|
17
|
-
import { Heading } from './schema/Heading.js'
|
|
18
|
-
import { Wizard, Step } from './schema/Wizard.js'
|
|
19
|
-
import { Action } from './actions/Action.js'
|
|
20
|
-
import type { Element } from './schema/Element.js'
|
|
21
|
-
import type { SchemaContext } from './schema/resolveSchema.js'
|
|
22
|
-
import type { ResourceClass, ResourcePages } from './Resource.js'
|
|
23
|
-
import type { PageMeta } from './Page.js'
|
|
24
|
-
import { modelSave, modelLoadRecord, modelTableRecords } from './orm/modelDefaults.js'
|
|
25
|
-
import { serializeIcon } from './icons/types.js'
|
|
26
|
-
|
|
27
|
-
// ─── Sentinels for missing handlers ──────────────────────────
|
|
28
|
-
|
|
29
|
-
/** Sentinel save handler — throws unless the user overrides via a custom Page or Form.save(). */
|
|
30
|
-
function noSaveHandler(R: ResourceClass): () => never {
|
|
31
|
-
return () => {
|
|
32
|
-
throw new Error(
|
|
33
|
-
`[Pilotiq] ${R.name}: no save handler. Set Resource.model = … to use the ORM defaults, or call Form.save(...) inside Resource.form().`,
|
|
34
|
-
)
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** Sentinel loadRecord handler — throws unless the user overrides via a custom Page or Form.loadRecord(). */
|
|
39
|
-
function noLoadRecordHandler(R: ResourceClass): () => never {
|
|
40
|
-
return () => {
|
|
41
|
-
throw new Error(
|
|
42
|
-
`[Pilotiq] ${R.name}: no loadRecord handler. Set Resource.model = … to use the ORM defaults, or call Form.loadRecord(...) inside Resource.form().`,
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Install model-backed save/loadRecord on a freshly-built form when the user hasn't supplied them. */
|
|
48
|
-
export function applyFormDefaults(R: ResourceClass, form: Form, mode: 'create' | 'edit' | 'view'): void {
|
|
49
|
-
const M = R.model
|
|
50
|
-
if (!form.getSave()) {
|
|
51
|
-
form.save(M ? modelSave(M) : noSaveHandler(R))
|
|
52
|
-
}
|
|
53
|
-
if (mode !== 'create' && !form.getLoadRecord()) {
|
|
54
|
-
form.loadRecord(M ? modelLoadRecord(R) : noLoadRecordHandler(R))
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Install model-backed records on a freshly-built table when the user hasn't supplied them. */
|
|
59
|
-
export function applyTableDefaults(R: ResourceClass, table: Table): void {
|
|
60
|
-
// Plan #13 — auto-inject `TrashedFilter` for soft-delete resources
|
|
61
|
-
// unless the user already added one. The filter drives `withTrashed /
|
|
62
|
-
// onlyTrashed` on the model query via its built-in `query(fn)` handler;
|
|
63
|
-
// matching against the class catches user-renamed instances too.
|
|
64
|
-
if (R.softDeletes) {
|
|
65
|
-
const hasTrashedFilter = (table.getChildren() ?? [])
|
|
66
|
-
.some(c => c instanceof TrashedFilter)
|
|
67
|
-
if (!hasTrashedFilter) {
|
|
68
|
-
const existing = (table.getChildren() ?? []).filter(c => c instanceof Filter) as Filter[]
|
|
69
|
-
table.filters([...existing, TrashedFilter.make()])
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (table.getRecords()) return
|
|
74
|
-
const M = R.model
|
|
75
|
-
if (M) table.records(modelTableRecords(R, table))
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// ─── Base classes for resource page roles ────────────────────
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Base class subclasses extend to bind a Page to a Resource. Each role
|
|
82
|
-
* (`ListPage`, `CreatePage`, `EditPage`, `ViewPage`) provides the
|
|
83
|
-
* boilerplate so a per-resource page file is typically a one-liner
|
|
84
|
-
* override of `getResource()`.
|
|
85
|
-
*
|
|
86
|
-
* @example
|
|
87
|
-
* class ListArticles extends ListPage {
|
|
88
|
-
* static override getResource() { return ArticleResource }
|
|
89
|
-
* }
|
|
90
|
-
*
|
|
91
|
-
* Override hooks (`getHeader`, `getActions` on `ViewPage`) let you tweak
|
|
92
|
-
* the rendered schema without re-implementing the wiring.
|
|
93
|
-
*/
|
|
94
|
-
abstract class ResourcePage extends Page {
|
|
95
|
-
/** Subclasses must override to bind to a Resource. */
|
|
96
|
-
static override getResource(): ResourceClass {
|
|
97
|
-
throw new Error(`[Pilotiq] ${this.name}: must override static getResource() to bind to a Resource.`)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/** Falls back to the resource's icon when the page didn't set one. */
|
|
101
|
-
static override toMeta(): PageMeta {
|
|
102
|
-
const meta = super.toMeta()
|
|
103
|
-
if (meta.icon !== undefined) return meta
|
|
104
|
-
const R = this.getResource()
|
|
105
|
-
return { ...meta, icon: serializeIcon(R.icon, R.name) }
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export class ListPage extends ResourcePage {
|
|
110
|
-
static override getMode() { return 'list' as const }
|
|
111
|
-
|
|
112
|
-
static override getSlug(): string {
|
|
113
|
-
return this.slug ?? this.getResource().getSlug()
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
static override getLabel(): string {
|
|
117
|
-
return this.label ?? this.getResource().label
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
static override async schema(ctx?: SchemaContext): Promise<Element[]> {
|
|
121
|
-
const R = this.getResource()
|
|
122
|
-
const basePath = (ctx?.['basePath'] as string | undefined) ?? ''
|
|
123
|
-
const table = R.table(Table.make())
|
|
124
|
-
applyTableDefaults(R, table)
|
|
125
|
-
|
|
126
|
-
// Layer in default header + row actions. Skip any whose name the user
|
|
127
|
-
// already added in `Resource.table()` so customization wins.
|
|
128
|
-
const existing = new Set(
|
|
129
|
-
(table.getChildren() ?? [])
|
|
130
|
-
.filter((c): c is Action => c instanceof Action)
|
|
131
|
-
.map(a => a.name),
|
|
132
|
-
)
|
|
133
|
-
const headers = this.getHeaderActions(R, basePath).filter(a => !existing.has(a.name))
|
|
134
|
-
const rows = this.getRowActions(R, basePath).filter(a => !existing.has(a.name))
|
|
135
|
-
if (headers.length > 0) table.headerActions(headers)
|
|
136
|
-
if (rows.length > 0) table.recordActions(rows)
|
|
137
|
-
|
|
138
|
-
// Wrap the user's `getTabs()` array (if any) in a ListTabs container
|
|
139
|
-
// and slot it between the heading and the Table. The page-data
|
|
140
|
-
// pipeline activates the right tab and resolves badges before
|
|
141
|
-
// serialization — the schema-build path here just sets the structure.
|
|
142
|
-
const tabs = this.getTabs(R)
|
|
143
|
-
const listTabs = tabs.length > 0
|
|
144
|
-
? ListTabs.make().tabs(tabs)
|
|
145
|
-
: undefined
|
|
146
|
-
|
|
147
|
-
// Plan #15 — `Resource.headerSchema(ctx) / footerSchema(ctx)` slot
|
|
148
|
-
// dashboard widgets above and below the list table. Resolved with the
|
|
149
|
-
// same `SchemaContext` so widgets see `mode: 'table'`, `basePath`, `user`.
|
|
150
|
-
const [header, footer] = await Promise.all([
|
|
151
|
-
Promise.resolve(R.headerSchema(ctx)),
|
|
152
|
-
Promise.resolve(R.footerSchema(ctx)),
|
|
153
|
-
])
|
|
154
|
-
|
|
155
|
-
const elements: Element[] = [...this.getHeader(R)]
|
|
156
|
-
if (header.length > 0) elements.push(...header)
|
|
157
|
-
if (listTabs) elements.push(listTabs)
|
|
158
|
-
elements.push(table)
|
|
159
|
-
if (footer.length > 0) elements.push(...footer)
|
|
160
|
-
return elements
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/** Override to customize the heading rendered above the table. */
|
|
164
|
-
static getHeader(R: ResourceClass): Element[] {
|
|
165
|
-
return [Heading.make(R.label).level(1)]
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Header actions rendered in the table's top bar. Returns `[]` by
|
|
170
|
-
* default — Filament-style explicit. Override to add a Create button:
|
|
171
|
-
*
|
|
172
|
-
* @example
|
|
173
|
-
* static override getHeaderActions(R, basePath) {
|
|
174
|
-
* return [Action.create(R, basePath)]
|
|
175
|
-
* }
|
|
176
|
-
*
|
|
177
|
-
* Or call it explicitly inside `Resource.table()` via
|
|
178
|
-
* `table.headerActions([Action.create(R, basePath)])`.
|
|
179
|
-
*/
|
|
180
|
-
static getHeaderActions(_R: ResourceClass, _basePath: string): Action[] {
|
|
181
|
-
return []
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Row actions rendered in a per-row Actions column. Returns `[]` by
|
|
186
|
-
* default — Filament-style explicit. Override to add Edit/Delete:
|
|
187
|
-
*
|
|
188
|
-
* @example
|
|
189
|
-
* static override getRowActions(R, basePath) {
|
|
190
|
-
* return [Action.edit(R, basePath), Action.delete(R, basePath)]
|
|
191
|
-
* }
|
|
192
|
-
*
|
|
193
|
-
* Or call them explicitly inside `Resource.table()` via
|
|
194
|
-
* `table.recordActions([Action.edit(R, basePath), Action.delete(R, basePath)])`.
|
|
195
|
-
*
|
|
196
|
-
* Per-row `:id` substitution still happens automatically — factories
|
|
197
|
-
* use the `:id` template; the renderer fills it in for each row.
|
|
198
|
-
*/
|
|
199
|
-
static getRowActions(_R: ResourceClass, _basePath: string): Action[] {
|
|
200
|
-
return []
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* List-page tabs rendered above the table — Filament-style query
|
|
205
|
-
* shortcuts ("All / Drafts / Published / Archived"). Returns `[]` by
|
|
206
|
-
* default. Each tab has a label + optional icon + optional count badge
|
|
207
|
-
* + a `modifyQuery` predicate that narrows the table. Active tab is
|
|
208
|
-
* carried through `?tab=name` in the URL.
|
|
209
|
-
*
|
|
210
|
-
* @example
|
|
211
|
-
* static override getTabs() {
|
|
212
|
-
* return [
|
|
213
|
-
* ListTab.make('all').label('All'),
|
|
214
|
-
* ListTab.make('drafts')
|
|
215
|
-
* .label('Drafts')
|
|
216
|
-
* .badge(() => prisma.article.count({ where: { status: 'draft' } }))
|
|
217
|
-
* .modifyQuery(q => q.where('status', 'draft')),
|
|
218
|
-
* ]
|
|
219
|
-
* }
|
|
220
|
-
*/
|
|
221
|
-
static getTabs(_R?: ResourceClass): ListTab[] {
|
|
222
|
-
return []
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Build the page heading and attach `formActions` as right-aligned
|
|
228
|
-
* buttons. Each submit action is automatically retargeted at the form's
|
|
229
|
-
* generated id so a header-mounted Save button submits the form below.
|
|
230
|
-
*
|
|
231
|
-
* If `getHeader()` returns multiple elements or non-Heading roots, the
|
|
232
|
-
* actions get attached to the first Heading in the list; if none exists,
|
|
233
|
-
* actions are dropped (custom headers carry their own action layout).
|
|
234
|
-
*/
|
|
235
|
-
function buildHeader(
|
|
236
|
-
header: Element[],
|
|
237
|
-
formActions: Action[],
|
|
238
|
-
formId: string,
|
|
239
|
-
): Element[] {
|
|
240
|
-
if (formActions.length === 0) return header
|
|
241
|
-
const targeted = formActions.map(a => (a.isSubmit() ? a.form(formId) : a))
|
|
242
|
-
for (const el of header) {
|
|
243
|
-
if (el instanceof Heading) {
|
|
244
|
-
el.actions(targeted)
|
|
245
|
-
return header
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
return header
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Install lifecycle overrides defined as static methods on a form-bearing
|
|
253
|
-
* page subclass onto the freshly-built `Form`. Called by `CreatePage` and
|
|
254
|
-
* `EditPage` after `R.form(...)` runs so user `Resource.form()` config
|
|
255
|
-
* stays the canonical seam, with page subclasses layering on top.
|
|
256
|
-
*
|
|
257
|
-
* Mode-specific hooks (`beforeCreate` etc.) only fire on the matching mode.
|
|
258
|
-
* Generic ones (`mutateData`, `beforeSave`, `afterSave`) fire on both. The
|
|
259
|
-
* page methods get `.bind(PageClass)` so `this` inside the override resolves
|
|
260
|
-
* to the page class — useful when an override delegates to another static.
|
|
261
|
-
*/
|
|
262
|
-
function installLifecycleHooks(
|
|
263
|
-
PageClass: typeof CreatePage | typeof EditPage,
|
|
264
|
-
form: Form,
|
|
265
|
-
mode: 'create' | 'edit',
|
|
266
|
-
): void {
|
|
267
|
-
// Coerce to a record-typed view so we can probe optional statics through
|
|
268
|
-
// a single property bag without writing a wide intersection.
|
|
269
|
-
const P = PageClass as unknown as Record<string, unknown>
|
|
270
|
-
const bind = <T extends (...args: never[]) => unknown>(fn: T): T => fn.bind(PageClass) as T
|
|
271
|
-
|
|
272
|
-
if (typeof P['mutateFormDataBeforeFill'] === 'function') form.mutateFormDataBeforeFill(bind(P['mutateFormDataBeforeFill'] as never))
|
|
273
|
-
if (typeof P['mutateFormDataAfterFill'] === 'function') form.mutateFormDataAfterFill (bind(P['mutateFormDataAfterFill'] as never))
|
|
274
|
-
if (typeof P['mutateData'] === 'function') form.mutateData (bind(P['mutateData'] as never))
|
|
275
|
-
if (typeof P['mutateDataBeforeCreate'] === 'function') form.mutateDataBeforeCreate (bind(P['mutateDataBeforeCreate'] as never))
|
|
276
|
-
if (typeof P['mutateDataBeforeUpdate'] === 'function') form.mutateDataBeforeUpdate (bind(P['mutateDataBeforeUpdate'] as never))
|
|
277
|
-
if (typeof P['beforeSave'] === 'function') form.beforeSave (bind(P['beforeSave'] as never))
|
|
278
|
-
if (typeof P['afterSave'] === 'function') form.afterSave (bind(P['afterSave'] as never))
|
|
279
|
-
if (typeof P['beforeCreate'] === 'function') form.beforeCreate (bind(P['beforeCreate'] as never))
|
|
280
|
-
if (typeof P['afterCreate'] === 'function') form.afterCreate (bind(P['afterCreate'] as never))
|
|
281
|
-
if (typeof P['beforeUpdate'] === 'function') form.beforeUpdate (bind(P['beforeUpdate'] as never))
|
|
282
|
-
if (typeof P['afterUpdate'] === 'function') form.afterUpdate (bind(P['afterUpdate'] as never))
|
|
283
|
-
if (typeof P['handleCreate'] === 'function') form.handleCreate (bind(P['handleCreate'] as never))
|
|
284
|
-
if (typeof P['handleUpdate'] === 'function') form.handleUpdate (bind(P['handleUpdate'] as never))
|
|
285
|
-
if (typeof P['getRedirectUrl'] === 'function') form.redirectAfterSave (bind(P['getRedirectUrl'] as never))
|
|
286
|
-
|
|
287
|
-
// Notifications: page hook returns string | null. `null` disables. A
|
|
288
|
-
// string installs the spec for the matching mode. The framework default
|
|
289
|
-
// (resource-aware "Created"/"Saved") is layered in here unless the
|
|
290
|
-
// user overrode it; passing `null` from the override suppresses it.
|
|
291
|
-
const R = PageClass.getResource()
|
|
292
|
-
const getCreatedTitle = P['getCreatedNotificationTitle'] as (() => string | null | undefined) | undefined
|
|
293
|
-
const getSavedTitle = P['getSavedNotificationTitle'] as (() => string | null | undefined) | undefined
|
|
294
|
-
|
|
295
|
-
// Explicit `null` from the override means "suppress this toast" — keep
|
|
296
|
-
// it; only fall through to the framework default when the override was
|
|
297
|
-
// omitted or returned undefined.
|
|
298
|
-
const explicitCreated = getCreatedTitle?.()
|
|
299
|
-
const createdTitle = explicitCreated !== undefined
|
|
300
|
-
? explicitCreated
|
|
301
|
-
: (mode === 'create' ? `${R.labelSingular} created` : undefined)
|
|
302
|
-
if (createdTitle === null) form.createdNotification(null)
|
|
303
|
-
else if (createdTitle !== undefined) form.createdNotification(createdTitle as SavedNotificationHandler)
|
|
304
|
-
|
|
305
|
-
const explicitSaved = getSavedTitle?.()
|
|
306
|
-
const savedTitle = explicitSaved !== undefined
|
|
307
|
-
? explicitSaved
|
|
308
|
-
: (mode === 'edit' ? `${R.labelSingular} saved` : undefined)
|
|
309
|
-
if (savedTitle === null) form.savedNotification(null)
|
|
310
|
-
else if (savedTitle !== undefined) form.savedNotification(savedTitle as SavedNotificationHandler)
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
export class CreatePage extends ResourcePage {
|
|
314
|
-
static override getMode() { return 'create' as const }
|
|
315
|
-
|
|
316
|
-
static override getSlug(): string {
|
|
317
|
-
return this.slug ?? `${this.getResource().getSlug()}/create`
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
static override getLabel(): string {
|
|
321
|
-
return this.label ?? `Create ${this.getResource().labelSingular}`
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
static override schema(ctx?: SchemaContext): Element[] {
|
|
325
|
-
const R = this.getResource()
|
|
326
|
-
const basePath = (ctx?.['basePath'] as string | undefined) ?? ''
|
|
327
|
-
const form = R.form(Form.make())
|
|
328
|
-
applyFormDefaults(R, form, 'create')
|
|
329
|
-
installLifecycleHooks(this, form, 'create')
|
|
330
|
-
|
|
331
|
-
// Wizard mode (Filament's `HasWizard` equivalent). When `getSteps()`
|
|
332
|
-
// returns one or more `Step` instances, the form's children are
|
|
333
|
-
// replaced with a `Wizard` wrapping those steps. Lifecycle hooks
|
|
334
|
-
// installed on the form still fire on final-step submit; per-step
|
|
335
|
-
// validation flows through the existing `tagFormWizardUrls /
|
|
336
|
-
// formWizardData` pipeline (Plan #8). Custom Wizard chrome
|
|
337
|
-
// (`skippable`, `startOnStep`, `persist`) goes through `getWizard()`,
|
|
338
|
-
// which receives the configured Wizard instance and may swap or
|
|
339
|
-
// tweak it.
|
|
340
|
-
const steps = this.getSteps(R)
|
|
341
|
-
if (steps.length > 0) {
|
|
342
|
-
const wizard = this.getWizard(Wizard.make().steps(steps), R)
|
|
343
|
-
form.schema([wizard])
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
const header = buildHeader(this.getHeader(R), this.getFormActions(R, basePath), form.getFormId())
|
|
347
|
-
return [...header, form]
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/** Override to customize the heading rendered above the form. */
|
|
351
|
-
static getHeader(R: ResourceClass): Element[] {
|
|
352
|
-
return [Heading.make(`Create ${R.labelSingular}`).level(1)]
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
/**
|
|
356
|
-
* Wizard mode opt-in. Override to return one or more steps and the
|
|
357
|
-
* create flow becomes a multi-step wizard. Per-step validation runs
|
|
358
|
-
* on Next click; `Form.save()` still fires on final-step submit.
|
|
359
|
-
*
|
|
360
|
-
* Default `[]` ships the regular single-page form. When non-empty,
|
|
361
|
-
* the form's children (whatever `Resource.form()` configured) are
|
|
362
|
-
* REPLACED with a Wizard wrapping these steps — author the wizard's
|
|
363
|
-
* fields directly inside the steps, not via `Resource.form().schema()`.
|
|
364
|
-
*
|
|
365
|
-
* @example
|
|
366
|
-
* static override getSteps(R) {
|
|
367
|
-
* return [
|
|
368
|
-
* Step.make('Account').schema([
|
|
369
|
-
* EmailField.make('email').required(),
|
|
370
|
-
* TextField.make('password').required(),
|
|
371
|
-
* ]),
|
|
372
|
-
* Step.make('Profile').schema([
|
|
373
|
-
* TextField.make('name').required(),
|
|
374
|
-
* ]),
|
|
375
|
-
* ]
|
|
376
|
-
* }
|
|
377
|
-
*/
|
|
378
|
-
static getSteps(_R: ResourceClass): Step[] { return [] }
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* Customize wizard chrome (skippable / startOnStep / persist) before
|
|
382
|
-
* it lands in the form. The framework calls this with `Wizard.make().steps(getSteps(R))`
|
|
383
|
-
* already configured; mutate or replace as needed and return.
|
|
384
|
-
* Default returns the wizard untouched.
|
|
385
|
-
*
|
|
386
|
-
* @example
|
|
387
|
-
* static override getWizard(wizard, _R) {
|
|
388
|
-
* return wizard.skippable().persist(false)
|
|
389
|
-
* }
|
|
390
|
-
*/
|
|
391
|
-
static getWizard(wizard: Wizard, _R: ResourceClass): Wizard {
|
|
392
|
-
return wizard
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
/**
|
|
396
|
-
* Action buttons rendered to the right of the page heading. Default:
|
|
397
|
-
* primary "Create" submit + a secondary "Create & create another"
|
|
398
|
-
* (outlined) submit. The "create another" button posts a sentinel
|
|
399
|
-
* (`_continueCreate=1`) so the server routes the redirect back to
|
|
400
|
-
* `/create` instead of the new record's `/edit` page. Override to
|
|
401
|
-
* customize (drop the secondary button, add a Cancel link, etc.) or
|
|
402
|
-
* return `[]` to suppress.
|
|
403
|
-
*
|
|
404
|
-
* `basePath` is the panel's mount path (e.g. `/admin`). Pass it
|
|
405
|
-
* through to `Action.create / .href / etc.` factories that need a
|
|
406
|
-
* full URL — same surface as `ListPage.getRowActions(R, basePath)`.
|
|
407
|
-
*/
|
|
408
|
-
static getFormActions(R: ResourceClass, _basePath: string = ''): Action[] {
|
|
409
|
-
return [
|
|
410
|
-
Action.make('submit').label(`Create ${R.labelSingular}`).submit(),
|
|
411
|
-
Action.make('createAnother')
|
|
412
|
-
.label('Create & create another')
|
|
413
|
-
.submit()
|
|
414
|
-
.outlined()
|
|
415
|
-
.formField('_continueCreate', '1'),
|
|
416
|
-
]
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// ─── Optional lifecycle overrides ─────────────────────
|
|
420
|
-
// Subclasses may override any of these. They install onto the form
|
|
421
|
-
// during `schema()` via `installLifecycleHooks`. Signatures match the
|
|
422
|
-
// matching `Form.*` setter parameter type.
|
|
423
|
-
static mutateFormDataBeforeFill?: FillMutator
|
|
424
|
-
static mutateFormDataAfterFill?: FillMutator
|
|
425
|
-
static mutateData?: MutateDataHandler
|
|
426
|
-
static mutateDataBeforeCreate?: MutateDataHandler
|
|
427
|
-
static beforeSave?: LifecycleHandler
|
|
428
|
-
static afterSave?: AfterSaveHandler
|
|
429
|
-
static beforeCreate?: LifecycleHandler
|
|
430
|
-
static afterCreate?: AfterSaveHandler
|
|
431
|
-
static handleCreate?: SaveHandler
|
|
432
|
-
static getRedirectUrl?: RedirectHandler
|
|
433
|
-
/**
|
|
434
|
-
* Return the toast title for the post-create success notification.
|
|
435
|
-
* Returning `null` suppresses the toast; `undefined` or omission falls
|
|
436
|
-
* back to the framework default `"${R.labelSingular} created"`.
|
|
437
|
-
*/
|
|
438
|
-
static getCreatedNotificationTitle?: () => string | null | undefined
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
export class EditPage extends ResourcePage {
|
|
442
|
-
static override getMode() { return 'edit' as const }
|
|
443
|
-
|
|
444
|
-
static override getSlug(): string {
|
|
445
|
-
return this.slug ?? `${this.getResource().getSlug()}/edit`
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
static override getLabel(): string {
|
|
449
|
-
return this.label ?? `Edit ${this.getResource().labelSingular}`
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
static override schema(ctx?: SchemaContext): Element[] {
|
|
453
|
-
const R = this.getResource()
|
|
454
|
-
const basePath = (ctx?.['basePath'] as string | undefined) ?? ''
|
|
455
|
-
const recordId = ctx?.['recordId'] as string | undefined
|
|
456
|
-
const form = R.form(Form.make())
|
|
457
|
-
applyFormDefaults(R, form, 'edit')
|
|
458
|
-
installLifecycleHooks(this, form, 'edit')
|
|
459
|
-
const header = buildHeader(this.getHeader(R), this.getFormActions(R, basePath, recordId), form.getFormId())
|
|
460
|
-
return [...header, form]
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
/** Override to customize the heading rendered above the form. */
|
|
464
|
-
static getHeader(R: ResourceClass): Element[] {
|
|
465
|
-
return [Heading.make(`Edit ${R.labelSingular}`).level(1)]
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
/**
|
|
469
|
-
* Action buttons rendered to the right of the page heading. Default:
|
|
470
|
-
* a single submit button labeled "Save changes". The submit action is
|
|
471
|
-
* auto-targeted at the form below via the HTML `form` attribute.
|
|
472
|
-
*
|
|
473
|
-
* `basePath` and `recordId` let overrides drop in `Action.delete /
|
|
474
|
-
* .view / .replicate(R, basePath)` factories alongside Save without
|
|
475
|
-
* hardcoding the panel mount path. Filament-style "delete this
|
|
476
|
-
* record" / "view" / "replicate" buttons cluster right of the heading
|
|
477
|
-
* with the Save button — they're all rendered as a single right-
|
|
478
|
-
* aligned action group.
|
|
479
|
-
*
|
|
480
|
-
* @example
|
|
481
|
-
* static override getFormActions(R, basePath) {
|
|
482
|
-
* return [
|
|
483
|
-
* Action.delete(R, basePath),
|
|
484
|
-
* Action.view (R, basePath),
|
|
485
|
-
* Action.make('submit').label('Save changes').submit(),
|
|
486
|
-
* ]
|
|
487
|
-
* }
|
|
488
|
-
*/
|
|
489
|
-
static getFormActions(_R: ResourceClass, _basePath: string = '', _recordId?: string): Action[] {
|
|
490
|
-
return [
|
|
491
|
-
Action.make('submit').label('Save changes').submit(),
|
|
492
|
-
]
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
// ─── Optional lifecycle overrides ─────────────────────
|
|
496
|
-
// Same surface as CreatePage but for update mode.
|
|
497
|
-
static mutateFormDataBeforeFill?: FillMutator
|
|
498
|
-
static mutateFormDataAfterFill?: FillMutator
|
|
499
|
-
static mutateData?: MutateDataHandler
|
|
500
|
-
static mutateDataBeforeUpdate?: MutateDataHandler
|
|
501
|
-
static beforeSave?: LifecycleHandler
|
|
502
|
-
static afterSave?: AfterSaveHandler
|
|
503
|
-
static beforeUpdate?: LifecycleHandler
|
|
504
|
-
static afterUpdate?: AfterSaveHandler
|
|
505
|
-
static handleUpdate?: SaveHandler
|
|
506
|
-
static getRedirectUrl?: RedirectHandler
|
|
507
|
-
/**
|
|
508
|
-
* Return the toast title for the post-save success notification.
|
|
509
|
-
* Returning `null` suppresses the toast; `undefined` or omission falls
|
|
510
|
-
* back to the framework default `"${R.labelSingular} saved"`.
|
|
511
|
-
*/
|
|
512
|
-
static getSavedNotificationTitle?: () => string | null | undefined
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
export class ViewPage extends ResourcePage {
|
|
516
|
-
static override getMode() { return 'view' as const }
|
|
517
|
-
|
|
518
|
-
static override getSlug(): string {
|
|
519
|
-
return this.slug ?? `${this.getResource().getSlug()}/view`
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
static override getLabel(): string {
|
|
523
|
-
return this.label ?? `View ${this.getResource().labelSingular}`
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
static override async schema(ctx?: SchemaContext): Promise<Element[]> {
|
|
527
|
-
const R = this.getResource()
|
|
528
|
-
const recordId = ctx?.['recordId'] as string | undefined
|
|
529
|
-
const basePath = (ctx?.['basePath'] as string | undefined) ?? ''
|
|
530
|
-
|
|
531
|
-
// Reuse the form's loadRecord — same loader powers edit mode, including
|
|
532
|
-
// the model-backed default when `R.model` is set.
|
|
533
|
-
let record: unknown = null
|
|
534
|
-
if (recordId) {
|
|
535
|
-
const form = R.form(Form.make())
|
|
536
|
-
applyFormDefaults(R, form, 'view')
|
|
537
|
-
const loader = form.getLoadRecord()
|
|
538
|
-
if (loader) {
|
|
539
|
-
try { record = await loader(recordId, { values: {} }) } catch { /* sentinel/missing */ }
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
return [
|
|
544
|
-
...this.getHeader(R, record),
|
|
545
|
-
...this.getActions(R, recordId, basePath),
|
|
546
|
-
...R.detail(record),
|
|
547
|
-
]
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/** Override to customize the page header. Receives the loaded record. */
|
|
551
|
-
static getHeader(R: ResourceClass, _record: unknown): Element[] {
|
|
552
|
-
return [Heading.make(R.labelSingular).level(1)]
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
/**
|
|
556
|
-
* Override to set the action row above the detail content. Returns
|
|
557
|
-
* `[]` by default — Filament-style explicit. Wire Edit/Delete with
|
|
558
|
-
* the `:id`-substituted factories:
|
|
559
|
-
*
|
|
560
|
-
* @example
|
|
561
|
-
* static override getActions(R, recordId, basePath) {
|
|
562
|
-
* if (!recordId) return []
|
|
563
|
-
* return [Action.edit(R, basePath), Action.delete(R, basePath)]
|
|
564
|
-
* }
|
|
565
|
-
*
|
|
566
|
-
* The renderer fills the `:id` placeholder using the page's
|
|
567
|
-
* `recordId`, so the same factory works for row + view contexts.
|
|
568
|
-
*/
|
|
569
|
-
static getActions(_R: ResourceClass, _recordId: string | undefined, _basePath: string): Element[] {
|
|
570
|
-
return []
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
// ─── Factory functions (anonymous subclasses bound to R) ─────
|
|
575
|
-
|
|
576
|
-
export function defaultListPage(R: ResourceClass): typeof Page {
|
|
577
|
-
return class extends ListPage {
|
|
578
|
-
static override getResource(): ResourceClass { return R }
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
export function defaultCreatePage(R: ResourceClass): typeof Page {
|
|
583
|
-
return class extends CreatePage {
|
|
584
|
-
static override getResource(): ResourceClass { return R }
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
export function defaultEditPage(R: ResourceClass): typeof Page {
|
|
589
|
-
return class extends EditPage {
|
|
590
|
-
static override getResource(): ResourceClass { return R }
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
export function defaultViewPage(R: ResourceClass): typeof Page {
|
|
595
|
-
return class extends ViewPage {
|
|
596
|
-
static override getResource(): ResourceClass { return R }
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
/**
|
|
601
|
-
* Auto-generate the index/create/edit/view page classes from a Resource.
|
|
602
|
-
* Consumed by `Resource.resolvePages()` to fill in keys the user didn't
|
|
603
|
-
* override. `view` is included whenever the resource has a meaningful
|
|
604
|
-
* `detail()` — a no-op `detail()` still ships a default header with the
|
|
605
|
-
* Edit / Delete actions, which is useful on its own.
|
|
606
|
-
*/
|
|
607
|
-
export function defaultPages(R: ResourceClass): Required<ResourcePages> {
|
|
608
|
-
return {
|
|
609
|
-
index: defaultListPage(R),
|
|
610
|
-
create: defaultCreatePage(R),
|
|
611
|
-
edit: defaultEditPage(R),
|
|
612
|
-
view: defaultViewPage(R),
|
|
613
|
-
// Record sub-pages have no framework defaults — users register them
|
|
614
|
-
// explicitly via `static pages() { return { record: { … } } }`.
|
|
615
|
-
record: {},
|
|
616
|
-
}
|
|
617
|
-
}
|