@pilotiq/pilotiq 0.23.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 +91 -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/dist/actions/exportFactory.d.ts +10 -0
- package/dist/actions/exportFactory.d.ts.map +1 -1
- package/dist/actions/exportFactory.js +10 -0
- package/dist/actions/exportFactory.js.map +1 -1
- package/dist/react/CollabRoomContext.d.ts +5 -5
- package/dist/react/index.d.ts +0 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +0 -1
- package/dist/react/index.js.map +1 -1
- package/dist/routes/helpers.d.ts.map +1 -1
- package/dist/routes/helpers.js +6 -2
- package/dist/routes/helpers.js.map +1 -1
- package/dist/routes/relations.d.ts.map +1 -1
- package/dist/routes/relations.js +12 -0
- package/dist/routes/relations.js.map +1 -1
- package/package.json +6 -1
- package/.turbo/turbo-build.log +0 -8
- package/CLAUDE.md +0 -265
- package/dist/react/useCollabSeed.d.ts +0 -23
- package/dist/react/useCollabSeed.d.ts.map +0 -1
- package/dist/react/useCollabSeed.js +0 -82
- package/dist/react/useCollabSeed.js.map +0 -1
- 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 -215
- 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 -195
- 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/useCollabSeed.ts +0 -86
- 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 -700
- package/src/routes/pages.ts +0 -175
- package/src/routes/panel.ts +0 -204
- package/src/routes/relations.ts +0 -1227
- package/src/routes/resources.ts +0 -781
- package/src/routes/theme.ts +0 -91
- package/src/routes-nested-relations.test.ts +0 -676
- package/src/routes-relations.test.ts +0 -972
- package/src/routes.test.ts +0 -2027
- package/src/routes.ts +0 -303
- package/src/schema/Alert.test.ts +0 -109
- package/src/schema/Alert.ts +0 -131
- package/src/schema/Block.ts +0 -169
- package/src/schema/Breadcrumbs.ts +0 -40
- package/src/schema/Card.ts +0 -35
- package/src/schema/Divider.ts +0 -20
- package/src/schema/Element.ts +0 -219
- package/src/schema/EmptyState.test.ts +0 -37
- package/src/schema/EmptyState.ts +0 -63
- package/src/schema/Fieldset.ts +0 -43
- package/src/schema/Grid.ts +0 -43
- package/src/schema/Group.ts +0 -30
- package/src/schema/Heading.ts +0 -39
- package/src/schema/Html.ts +0 -67
- package/src/schema/Icon.ts +0 -54
- package/src/schema/Image.ts +0 -57
- package/src/schema/LinkTag.ts +0 -41
- package/src/schema/Markdown.ts +0 -85
- package/src/schema/MetaTag.ts +0 -41
- package/src/schema/RelationTabs.ts +0 -71
- package/src/schema/ScriptTag.ts +0 -55
- package/src/schema/Section.ts +0 -160
- package/src/schema/ServerDataElement.test.ts +0 -140
- package/src/schema/ServerDataElement.ts +0 -156
- package/src/schema/SlotComponent.test.ts +0 -77
- package/src/schema/SlotComponent.ts +0 -71
- package/src/schema/Split.ts +0 -50
- package/src/schema/Stat.test.ts +0 -118
- package/src/schema/Stat.ts +0 -154
- package/src/schema/StatsOverview.test.ts +0 -141
- package/src/schema/StatsOverview.ts +0 -119
- package/src/schema/StyleTag.ts +0 -35
- package/src/schema/TableWidget.test.ts +0 -297
- package/src/schema/TableWidget.ts +0 -289
- package/src/schema/Tabs.ts +0 -79
- package/src/schema/Text.ts +0 -58
- package/src/schema/UnorderedList.ts +0 -49
- package/src/schema/View.test.ts +0 -111
- package/src/schema/View.ts +0 -127
- package/src/schema/Wizard.ts +0 -220
- package/src/schema/containers.test.ts +0 -564
- package/src/schema/headTags.test.ts +0 -134
- package/src/schema/index.ts +0 -40
- package/src/schema/primes.test.ts +0 -269
- package/src/schema/resolveSchema.test.ts +0 -379
- package/src/schema/resolveSchema.ts +0 -917
- package/src/schema/sanitize.ts +0 -58
- package/src/search.test.ts +0 -446
- package/src/search.ts +0 -178
- package/src/sessionFilters.test.ts +0 -375
- package/src/sessionFilters.ts +0 -143
- package/src/slot-components/index.ts +0 -10
- package/src/slot-components/registry.ts +0 -56
- package/src/styles/file-upload.css +0 -13
- package/src/summarizers/Summarizer.test.ts +0 -84
- package/src/summarizers/Summarizer.ts +0 -123
- package/src/summarizers/index.ts +0 -11
- package/src/theme/base-colors.ts +0 -68
- package/src/theme/chart-colors.ts +0 -50
- package/src/theme/colors.ts +0 -447
- package/src/theme/generate-css.test.ts +0 -139
- package/src/theme/generate-css.ts +0 -44
- package/src/theme/generate-scale.test.ts +0 -106
- package/src/theme/generate-scale.ts +0 -97
- package/src/theme/icon-map.ts +0 -42
- package/src/theme/index.ts +0 -34
- package/src/theme/migrate.test.ts +0 -178
- package/src/theme/migrate.ts +0 -81
- package/src/theme/presets.ts +0 -135
- package/src/theme/radius.ts +0 -18
- package/src/theme/resolve.test.ts +0 -238
- package/src/theme/resolve.ts +0 -96
- package/src/theme/spacing.ts +0 -18
- package/src/theme/storage.test.ts +0 -126
- package/src/theme/storage.ts +0 -106
- package/src/theme/theme-colors.ts +0 -88
- package/src/theme/types.ts +0 -125
- package/src/uploads/UploadAdapter.ts +0 -35
- package/src/uploads/index.ts +0 -2
- package/src/uploads/localUpload.test.ts +0 -70
- package/src/uploads/localUpload.ts +0 -84
- package/src/validation/Validator.ts +0 -49
- package/src/validation/index.ts +0 -28
- package/src/validation/rules.ts +0 -78
- package/src/validation/runValidators.ts +0 -435
- package/src/validation/uniqueValidator.test.ts +0 -196
- package/src/validation/uniqueValidator.ts +0 -133
- package/src/validation/validators.test.ts +0 -268
- package/src/vite.test.ts +0 -184
- package/src/vite.ts +0 -787
- package/src/widgets/index.ts +0 -10
- package/src/widgets/registry.ts +0 -45
- package/src/widgets.test.ts +0 -592
- package/tsconfig.build.json +0 -11
- package/tsconfig.json +0 -4
- package/tsconfig.test.json +0 -10
- package/views/react/Dashboard.tsx +0 -27
- package/views/react/Resources/Form.tsx +0 -102
- package/views/react/Resources/Index.tsx +0 -49
|
@@ -1,609 +0,0 @@
|
|
|
1
|
-
import type { Pilotiq } from '../Pilotiq.js'
|
|
2
|
-
import { PilotiqRegistry } from '../PilotiqRegistry.js'
|
|
3
|
-
import type { Page } from '../Page.js'
|
|
4
|
-
import type { ResourceClass } from '../Resource.js'
|
|
5
|
-
import { resourceBasePath } from '../clusterPaths.js'
|
|
6
|
-
import { Element } from '../schema/Element.js'
|
|
7
|
-
import { resolveSchema, type SchemaContext } from '../schema/resolveSchema.js'
|
|
8
|
-
import { Form } from '../elements/Form.js'
|
|
9
|
-
import { Table } from '../elements/Table.js'
|
|
10
|
-
import { Column } from '../Column.js'
|
|
11
|
-
import { ListTabs } from '../elements/ListTabs.js'
|
|
12
|
-
import { ListTab } from '../Tab.js'
|
|
13
|
-
import { TrashedFilter } from '../filters/TrashedFilter.js'
|
|
14
|
-
import { loadTableRecords } from '../elements/dispatchTable.js'
|
|
15
|
-
import { consumeFlashedNotifications } from '../notifications/flash.js'
|
|
16
|
-
import { serializeIcon } from '../icons/types.js'
|
|
17
|
-
import {
|
|
18
|
-
findRecord, getPrimaryKey, modelLoadRecord, modelSave,
|
|
19
|
-
type ModelLike,
|
|
20
|
-
} from '../orm/modelDefaults.js'
|
|
21
|
-
import {
|
|
22
|
-
resourceCreateBreadcrumbs,
|
|
23
|
-
resourceEditBreadcrumbs,
|
|
24
|
-
resourceListBreadcrumbs,
|
|
25
|
-
resourceViewBreadcrumbs,
|
|
26
|
-
} from './breadcrumbs.js'
|
|
27
|
-
import {
|
|
28
|
-
applyEditPageHydrators,
|
|
29
|
-
applyFillPipeline,
|
|
30
|
-
applyRelationshipBuilderFill,
|
|
31
|
-
applyRelationshipRepeaterFill,
|
|
32
|
-
callPageSchema,
|
|
33
|
-
resolveServerDataElements,
|
|
34
|
-
tagActionDispatch,
|
|
35
|
-
tagCellEditUrls,
|
|
36
|
-
tagFieldAiUrls,
|
|
37
|
-
tagFormActions,
|
|
38
|
-
tagFormSubresourceUrls,
|
|
39
|
-
tagTableDeferred,
|
|
40
|
-
tagTableReorderUrls,
|
|
41
|
-
tagWidgetUrls,
|
|
42
|
-
uploadCtx,
|
|
43
|
-
userCtx,
|
|
44
|
-
} from './helpers.js'
|
|
45
|
-
import { applyRoleHooks, panelInfo, type PanelInfoRoute } from './navigation.js'
|
|
46
|
-
import { findForms } from '../elements/dispatchForm.js'
|
|
47
|
-
import { buildRelationTabs, deriveParentTitle, safeBool } from './relationTabs.js'
|
|
48
|
-
|
|
49
|
-
// ─── Resource page builders ─────────────────────────────────
|
|
50
|
-
//
|
|
51
|
-
// Resource-scoped GET-route data builders: dashboard, list, table
|
|
52
|
-
// (deferred-load shell), create, edit, view, and the optional record
|
|
53
|
-
// sub-page roles. Each loads its own context (record / parent / etc.),
|
|
54
|
-
// resolves the page schema through `resolveSchema`, stamps URL-tag
|
|
55
|
-
// helpers for dispatch endpoints, and returns the wire-shape envelope
|
|
56
|
-
// the page renderer consumes.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Per-row stamping spine shared by SSR `resourceIndexData` and the
|
|
61
|
-
* deferred-load JSON endpoint `resourceTableData`. Both walk the same
|
|
62
|
-
* Table tree and need the same dispatch / active-tab / reorder / cell-edit
|
|
63
|
-
* URL stamps in the same order — running them through one helper keeps
|
|
64
|
-
* the two paths in lock-step so any future addition (per-row chrome
|
|
65
|
-
* stamp, etc.) lands on both surfaces.
|
|
66
|
-
*
|
|
67
|
-
* Widget URL stamping + the `tagTableDeferred` flag stay outside the
|
|
68
|
-
* helper since only `resourceIndexData` mounts widgets / the deferred
|
|
69
|
-
* skeleton — the JSON endpoint re-runs without the flag and never
|
|
70
|
-
* collects widget metas.
|
|
71
|
-
*/
|
|
72
|
-
async function prepareResourceTable(
|
|
73
|
-
elements: Element[],
|
|
74
|
-
R: ResourceClass,
|
|
75
|
-
indexUrl: string,
|
|
76
|
-
query: Record<string, string>,
|
|
77
|
-
user: unknown,
|
|
78
|
-
): Promise<void> {
|
|
79
|
-
tagActionDispatch(elements, indexUrl)
|
|
80
|
-
// Mark the active tab + parallel-eval badges + stamp per-tab URLs
|
|
81
|
-
// before the table records run — `loadTableRecords` walks the schema
|
|
82
|
-
// for the active tab and splices its `modifyQuery` predicate into the
|
|
83
|
-
// ORM chain alongside filters.
|
|
84
|
-
await resolveActiveTab(elements, query, indexUrl)
|
|
85
|
-
await loadTableRecords(elements, query, indexUrl, user, {
|
|
86
|
-
canEdit: (u, record) => R.canEdit(u, record),
|
|
87
|
-
})
|
|
88
|
-
tagTableReorderUrls(elements, `${indexUrl}/_reorder`)
|
|
89
|
-
tagCellEditUrls(elements, indexUrl)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export async function dashboardData(pilotiq: Pilotiq, req?: unknown): Promise<Record<string, unknown>> {
|
|
93
|
-
const cfg = pilotiq.getConfig()
|
|
94
|
-
const user = await pilotiq.resolveUser(req)
|
|
95
|
-
const ctx: SchemaContext = uploadCtx(userCtx({ basePath: cfg.path }, user), cfg)
|
|
96
|
-
|
|
97
|
-
// Plan #15 — when `panel.dashboard(P)` was called, resolve P's
|
|
98
|
-
// schema instead of the builder-level `cfg.schema`. Page-scoped
|
|
99
|
-
// schema means widget elements read like a regular custom page —
|
|
100
|
-
// including action dispatch, form-state, and `_widget/:id` polling.
|
|
101
|
-
let elements: Element[]
|
|
102
|
-
if (cfg.dashboardPage) {
|
|
103
|
-
elements = await callPageSchema(cfg.dashboardPage, ctx)
|
|
104
|
-
tagFormActions(elements, cfg.path)
|
|
105
|
-
tagFormSubresourceUrls(elements, cfg.path)
|
|
106
|
-
tagActionDispatch(elements, cfg.path)
|
|
107
|
-
} else {
|
|
108
|
-
elements = []
|
|
109
|
-
if (cfg.schema) {
|
|
110
|
-
const def = cfg.schema
|
|
111
|
-
elements = typeof def === 'function' ? await def(ctx) : def
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Stamp polling URLs on every widget — panel-scope (no pageSlug
|
|
116
|
-
// segment) for the dashboard. Done before schema resolve so the URL
|
|
117
|
-
// rides on each widget's stamped meta.
|
|
118
|
-
tagWidgetUrls(elements, id => `${cfg.path}/_widget/${id}`)
|
|
119
|
-
|
|
120
|
-
const widgetData = await resolveServerDataElements(elements, ctx)
|
|
121
|
-
const dashRoute: PanelInfoRoute = cfg.dashboardPage ? { page: cfg.dashboardPage } : {}
|
|
122
|
-
const [panel, schemaData] = await Promise.all([
|
|
123
|
-
panelInfo(pilotiq, req, dashRoute),
|
|
124
|
-
resolveSchema(elements, ctx).then(metas => applyRoleHooks(pilotiq, user, 'dashboard', metas, dashRoute)),
|
|
125
|
-
])
|
|
126
|
-
|
|
127
|
-
return {
|
|
128
|
-
panel,
|
|
129
|
-
page: cfg.dashboardPage ? cfg.dashboardPage.toMeta() : undefined,
|
|
130
|
-
basePath: cfg.path,
|
|
131
|
-
layout: cfg.layout,
|
|
132
|
-
schemaData,
|
|
133
|
-
_widgetData: widgetData,
|
|
134
|
-
notifications: consumeFlashedNotifications(req),
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export async function resourceIndexData(
|
|
139
|
-
pilotiq: Pilotiq,
|
|
140
|
-
slug: string,
|
|
141
|
-
query: Record<string, string> = {},
|
|
142
|
-
req?: unknown,
|
|
143
|
-
): Promise<Record<string, unknown> | null> {
|
|
144
|
-
const cfg = pilotiq.getConfig()
|
|
145
|
-
const R = pilotiq.findResource(slug)
|
|
146
|
-
if (!R) return null
|
|
147
|
-
|
|
148
|
-
const pages = R.resolvePages()
|
|
149
|
-
if (!pages.index) return null
|
|
150
|
-
const PageClass = pages.index
|
|
151
|
-
|
|
152
|
-
const indexUrl = resourceBasePath(cfg.path, R)
|
|
153
|
-
const user = await pilotiq.resolveUser(req)
|
|
154
|
-
const ctx: SchemaContext = uploadCtx(userCtx({ mode: 'table', basePath: cfg.path }, user), cfg)
|
|
155
|
-
const elements = await callPageSchema(PageClass, ctx)
|
|
156
|
-
// Plan #15 — resource-scope widget polling URL. Stamped before the
|
|
157
|
-
// schema resolves so each widget's meta carries its endpoint.
|
|
158
|
-
tagWidgetUrls(elements, id => `${indexUrl}/_widget/${id}`)
|
|
159
|
-
if (R.deferLoading) tagTableDeferred(elements, `${indexUrl}/_table`)
|
|
160
|
-
await prepareResourceTable(elements, R, indexUrl, query, user)
|
|
161
|
-
const widgetData = await resolveServerDataElements(elements, ctx)
|
|
162
|
-
|
|
163
|
-
const breadcrumbs = resourceListBreadcrumbs(cfg, R)
|
|
164
|
-
if (breadcrumbs) elements.unshift(breadcrumbs)
|
|
165
|
-
|
|
166
|
-
const listRoute: PanelInfoRoute = { resource: R, page: PageClass }
|
|
167
|
-
const [panel, schemaData] = await Promise.all([
|
|
168
|
-
panelInfo(pilotiq, req, listRoute),
|
|
169
|
-
resolveSchema(elements, ctx).then(metas => applyRoleHooks(pilotiq, user, 'list', metas, listRoute)),
|
|
170
|
-
])
|
|
171
|
-
|
|
172
|
-
return {
|
|
173
|
-
pageType: 'resource',
|
|
174
|
-
panel,
|
|
175
|
-
page: PageClass.toMeta(),
|
|
176
|
-
resource: { name: R.name, label: R.label, labelSingular: R.labelSingular, slug, icon: serializeIcon(R.icon, R.name) },
|
|
177
|
-
basePath: cfg.path,
|
|
178
|
-
layout: cfg.layout,
|
|
179
|
-
schemaData,
|
|
180
|
-
_widgetData: widgetData,
|
|
181
|
-
notifications: consumeFlashedNotifications(req),
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Deferred-load JSON endpoint payload — `GET {base}/{slug}/_table`
|
|
186
|
-
// re-runs the list-page builder without the deferred flag, then returns
|
|
187
|
-
// every resolved `TableMeta` as a flat array. Returns null on missing
|
|
188
|
-
// resource / index page (route 404s).
|
|
189
|
-
export async function resourceTableData(
|
|
190
|
-
pilotiq: Pilotiq,
|
|
191
|
-
slug: string,
|
|
192
|
-
query: Record<string, string> = {},
|
|
193
|
-
req?: unknown,
|
|
194
|
-
): Promise<{ tables: Record<string, unknown>[] } | null> {
|
|
195
|
-
const cfg = pilotiq.getConfig()
|
|
196
|
-
const R = pilotiq.findResource(slug)
|
|
197
|
-
if (!R) return null
|
|
198
|
-
|
|
199
|
-
const pages = R.resolvePages()
|
|
200
|
-
if (!pages.index) return null
|
|
201
|
-
const PageClass = pages.index
|
|
202
|
-
|
|
203
|
-
const indexUrl = resourceBasePath(cfg.path, R)
|
|
204
|
-
const user = await pilotiq.resolveUser(req)
|
|
205
|
-
const ctx: SchemaContext = uploadCtx(userCtx({ mode: 'table', basePath: cfg.path }, user), cfg)
|
|
206
|
-
const elements = await callPageSchema(PageClass, ctx)
|
|
207
|
-
await prepareResourceTable(elements, R, indexUrl, query, user)
|
|
208
|
-
const schemaData = await resolveSchema(elements, ctx)
|
|
209
|
-
|
|
210
|
-
const tables = collectTableMetas(schemaData)
|
|
211
|
-
return { tables }
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
function collectTableMetas(
|
|
215
|
-
metas: ReadonlyArray<Record<string, unknown>>,
|
|
216
|
-
): Record<string, unknown>[] {
|
|
217
|
-
const out: Record<string, unknown>[] = []
|
|
218
|
-
const walk = (nodes: ReadonlyArray<Record<string, unknown>>): void => {
|
|
219
|
-
for (const node of nodes) {
|
|
220
|
-
if (node['type'] === 'table') out.push(node)
|
|
221
|
-
const children = node['children']
|
|
222
|
-
if (Array.isArray(children)) walk(children as Record<string, unknown>[])
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
walk(metas)
|
|
226
|
-
return out
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Walk the schema for `ListTabs` containers, pick the active tab from
|
|
231
|
-
* `?tab=…` (defaulting to the tab marked `.default()` or the first one),
|
|
232
|
-
* stamp render-time state (`active` flag, per-tab `?tab=` URL, and
|
|
233
|
-
* resolved badge counts) onto each tab. The active tab's query/context
|
|
234
|
-
* modifier is NOT applied here — `loadTableRecords` walks for the active
|
|
235
|
-
* tab and splices in its modifier when it builds the records-handler
|
|
236
|
-
* `TableContext`.
|
|
237
|
-
*
|
|
238
|
-
* No-op when the page has no `ListTabs`.
|
|
239
|
-
*/
|
|
240
|
-
export async function resolveActiveTab(
|
|
241
|
-
elements: ReadonlyArray<Element>,
|
|
242
|
-
query: Record<string, string>,
|
|
243
|
-
currentPath: string,
|
|
244
|
-
): Promise<void> {
|
|
245
|
-
const listTabs = findListTabs(elements)
|
|
246
|
-
if (listTabs.length === 0) return
|
|
247
|
-
|
|
248
|
-
for (const container of listTabs) {
|
|
249
|
-
const children = (container.getChildren() ?? []).filter((c): c is ListTab => c.getType() === 'listTab')
|
|
250
|
-
if (children.length === 0) continue
|
|
251
|
-
|
|
252
|
-
// Default tab (used both for `?tab=` fallback and to omit the param
|
|
253
|
-
// from the canonical URL of that tab — see `buildTabUrl`).
|
|
254
|
-
const defaultTab = children.find(t => t.isDefault()) ?? children[0]!
|
|
255
|
-
|
|
256
|
-
// Active tab: explicit `?tab=name` → default tab.
|
|
257
|
-
const wanted = typeof query['tab'] === 'string' ? query['tab'] : undefined
|
|
258
|
-
const active = (wanted && children.find(t => t.name === wanted)) || defaultTab
|
|
259
|
-
|
|
260
|
-
// Stamp render-time state on each tab.
|
|
261
|
-
children.forEach(t => {
|
|
262
|
-
t.withActive(t === active)
|
|
263
|
-
t.withUrl(buildTabUrl(currentPath, query, t.name, defaultTab.name))
|
|
264
|
-
})
|
|
265
|
-
|
|
266
|
-
// Resolve every tab's badge in parallel — failed handlers swallow
|
|
267
|
-
// silently (badge omitted) so a flaky count never blanks the page.
|
|
268
|
-
await Promise.all(children.map(async (tab) => {
|
|
269
|
-
const handler = tab.getBadgeHandler()
|
|
270
|
-
if (!handler) return
|
|
271
|
-
try {
|
|
272
|
-
const v = await handler()
|
|
273
|
-
if (v === undefined || v === null) return
|
|
274
|
-
tab.withResolvedBadge(String(v))
|
|
275
|
-
} catch {
|
|
276
|
-
// Per-tab badge errors stay silent.
|
|
277
|
-
}
|
|
278
|
-
}))
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function findListTabs(elements: ReadonlyArray<Element>): ListTabs[] {
|
|
283
|
-
const out: ListTabs[] = []
|
|
284
|
-
const walk = (els: ReadonlyArray<Element>): void => {
|
|
285
|
-
for (const el of els) {
|
|
286
|
-
if (el.getType() === 'listTabs') out.push(el as ListTabs)
|
|
287
|
-
const children = el.getChildren()
|
|
288
|
-
if (children) walk(children)
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
walk(elements)
|
|
292
|
-
return out
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
function buildTabUrl(
|
|
296
|
-
pathname: string,
|
|
297
|
-
query: Record<string, string>,
|
|
298
|
-
tabName: string,
|
|
299
|
-
defaultTabName: string,
|
|
300
|
-
): string {
|
|
301
|
-
// Carry forward search/sort/perPage + any filter values; reset page to 1
|
|
302
|
-
// (tab change reshapes the result set, page numbers don't translate).
|
|
303
|
-
// The default tab gets the canonical, paramless URL — visiting that URL
|
|
304
|
-
// already lands on the default, so emitting `?tab=default` would just be
|
|
305
|
-
// noise that bookmarks/share-links pick up.
|
|
306
|
-
const params = new URLSearchParams()
|
|
307
|
-
for (const [k, v] of Object.entries(query)) {
|
|
308
|
-
if (v === undefined || v === '' || v === null) continue
|
|
309
|
-
if (k === 'tab' || k === 'page') continue
|
|
310
|
-
params.set(k, String(v))
|
|
311
|
-
}
|
|
312
|
-
if (tabName !== defaultTabName) params.set('tab', tabName)
|
|
313
|
-
const qs = params.toString()
|
|
314
|
-
return qs ? `${pathname}?${qs}` : pathname
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
export async function resourceCreateData(
|
|
318
|
-
pilotiq: Pilotiq,
|
|
319
|
-
slug: string,
|
|
320
|
-
prefill?: { values?: Record<string, unknown>; errors?: Record<string, string[]> },
|
|
321
|
-
req?: unknown,
|
|
322
|
-
): Promise<Record<string, unknown> | null> {
|
|
323
|
-
const cfg = pilotiq.getConfig()
|
|
324
|
-
const R = pilotiq.findResource(slug)
|
|
325
|
-
if (!R) return null
|
|
326
|
-
const pages = R.resolvePages()
|
|
327
|
-
if (!pages.create) return null
|
|
328
|
-
const PageClass = pages.create
|
|
329
|
-
|
|
330
|
-
const resourceBase = resourceBasePath(cfg.path, R)
|
|
331
|
-
const createUrl = `${resourceBase}/create`
|
|
332
|
-
const user = await pilotiq.resolveUser(req)
|
|
333
|
-
const ctx: SchemaContext = uploadCtx(userCtx({ mode: 'create', basePath: cfg.path }, user), cfg)
|
|
334
|
-
const elements = await callPageSchema(PageClass, ctx)
|
|
335
|
-
tagFormActions(elements, createUrl)
|
|
336
|
-
tagActionDispatch(elements, createUrl)
|
|
337
|
-
tagFormSubresourceUrls(elements, resourceBase)
|
|
338
|
-
if (prefill) {
|
|
339
|
-
const form = findForms(elements)[0]
|
|
340
|
-
if (form) {
|
|
341
|
-
if (prefill.values) form.withValues(prefill.values)
|
|
342
|
-
if (prefill.errors) form.withErrors(prefill.errors)
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
const breadcrumbs = resourceCreateBreadcrumbs(cfg, R)
|
|
347
|
-
if (breadcrumbs) elements.unshift(breadcrumbs)
|
|
348
|
-
|
|
349
|
-
const createRoute: PanelInfoRoute = { resource: R, page: PageClass }
|
|
350
|
-
const [panel, schemaData] = await Promise.all([
|
|
351
|
-
panelInfo(pilotiq, req, createRoute),
|
|
352
|
-
resolveSchema(elements, ctx).then(metas => applyRoleHooks(pilotiq, user, 'create', metas, createRoute)),
|
|
353
|
-
])
|
|
354
|
-
|
|
355
|
-
return {
|
|
356
|
-
panel,
|
|
357
|
-
page: PageClass.toMeta(),
|
|
358
|
-
resource: { name: R.name, label: R.labelSingular, slug, icon: serializeIcon(R.icon, R.name) },
|
|
359
|
-
mode: 'create' as const,
|
|
360
|
-
basePath: cfg.path,
|
|
361
|
-
layout: cfg.layout,
|
|
362
|
-
schemaData,
|
|
363
|
-
notifications: consumeFlashedNotifications(req),
|
|
364
|
-
...(prefill?.errors ? { hasErrors: true } : {}),
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
export async function resourceEditData(
|
|
369
|
-
pilotiq: Pilotiq,
|
|
370
|
-
slug: string,
|
|
371
|
-
recordId: string,
|
|
372
|
-
prefill?: { values?: Record<string, unknown>; errors?: Record<string, string[]> },
|
|
373
|
-
req?: unknown,
|
|
374
|
-
): Promise<Record<string, unknown> | null> {
|
|
375
|
-
const cfg = pilotiq.getConfig()
|
|
376
|
-
const R = pilotiq.findResource(slug)
|
|
377
|
-
if (!R) return null
|
|
378
|
-
const pages = R.resolvePages()
|
|
379
|
-
if (!pages.edit) return null
|
|
380
|
-
const PageClass = pages.edit
|
|
381
|
-
|
|
382
|
-
const resourceBase = resourceBasePath(cfg.path, R)
|
|
383
|
-
const editUrl = `${resourceBase}/${recordId}/edit`
|
|
384
|
-
const user = await pilotiq.resolveUser(req)
|
|
385
|
-
const ctx: SchemaContext = uploadCtx(userCtx({ mode: 'edit', recordId, basePath: cfg.path }, user), cfg)
|
|
386
|
-
const elements = await callPageSchema(PageClass, ctx)
|
|
387
|
-
tagFormActions(elements, editUrl)
|
|
388
|
-
tagActionDispatch(elements, editUrl)
|
|
389
|
-
tagFormSubresourceUrls(elements, `${resourceBase}/${recordId}`)
|
|
390
|
-
|
|
391
|
-
// Locate the primary form, load the record, fill values.
|
|
392
|
-
const form = findForms(elements)[0]
|
|
393
|
-
let record: unknown = undefined
|
|
394
|
-
if (form?.getLoadRecord()) {
|
|
395
|
-
try {
|
|
396
|
-
record = await form.getLoadRecord()!(recordId, { values: prefill?.values ?? {} })
|
|
397
|
-
} catch {
|
|
398
|
-
// sentinel/missing record — fall through
|
|
399
|
-
}
|
|
400
|
-
if (!prefill?.values && record != null) {
|
|
401
|
-
const values = await applyFillPipeline(form, record)
|
|
402
|
-
const withRelations = await applyRelationshipRepeaterFill(form, values, record, R.model)
|
|
403
|
-
const withBuilders = await applyRelationshipBuilderFill(form, withRelations, record, R.model)
|
|
404
|
-
// Hydrators run AFTER the standard fill pipeline so they overlay
|
|
405
|
-
// on top of DB-row + relationship-row values. Skipped on the
|
|
406
|
-
// prefill branch (validation-error round-trip) — overlaying there
|
|
407
|
-
// would clobber the user's just-submitted input that the page is
|
|
408
|
-
// re-displaying for them to fix.
|
|
409
|
-
const hydrators = cfg.editPageHydrators ?? []
|
|
410
|
-
const overlay = hydrators.length > 0
|
|
411
|
-
? await applyEditPageHydrators(hydrators, {
|
|
412
|
-
resource: R,
|
|
413
|
-
recordId,
|
|
414
|
-
currentValues: withBuilders,
|
|
415
|
-
})
|
|
416
|
-
: {}
|
|
417
|
-
form.withValues(Object.keys(overlay).length > 0
|
|
418
|
-
? { ...withBuilders, ...overlay }
|
|
419
|
-
: withBuilders)
|
|
420
|
-
} else if (prefill?.values) {
|
|
421
|
-
form.withValues(prefill.values)
|
|
422
|
-
}
|
|
423
|
-
if (prefill?.errors) form.withErrors(prefill.errors)
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
// Plan #11 — when the resource has relation managers, prepend a
|
|
427
|
-
// navigation strip so users can drill into each manager's table
|
|
428
|
-
// without leaving the parent record context. The "Edit" tab is
|
|
429
|
-
// active here.
|
|
430
|
-
const relationTabsEl = await buildRelationTabs(R, recordId, cfg.path, '__edit', user, record)
|
|
431
|
-
if (relationTabsEl) elements.unshift(relationTabsEl)
|
|
432
|
-
|
|
433
|
-
const recordTitle = record !== undefined && record !== null
|
|
434
|
-
? deriveParentTitle(R, record)
|
|
435
|
-
: recordId
|
|
436
|
-
const breadcrumbs = resourceEditBreadcrumbs(cfg, R, recordId, recordTitle)
|
|
437
|
-
if (breadcrumbs) elements.unshift(breadcrumbs)
|
|
438
|
-
|
|
439
|
-
const editRoute: PanelInfoRoute = { resource: R, page: PageClass, recordId }
|
|
440
|
-
const editCtx = record !== undefined ? { ...ctx, record } : ctx
|
|
441
|
-
const [panel, schemaData] = await Promise.all([
|
|
442
|
-
panelInfo(pilotiq, req, editRoute),
|
|
443
|
-
resolveSchema(elements, editCtx).then(metas => applyRoleHooks(pilotiq, user, 'edit', metas, editRoute)),
|
|
444
|
-
])
|
|
445
|
-
|
|
446
|
-
tagFieldAiUrls(schemaData as Record<string, unknown>[], `${resourceBase}/${recordId}/_agents`)
|
|
447
|
-
|
|
448
|
-
return {
|
|
449
|
-
panel,
|
|
450
|
-
page: PageClass.toMeta(),
|
|
451
|
-
resource: { name: R.name, label: R.labelSingular, slug, icon: serializeIcon(R.icon, R.name) },
|
|
452
|
-
mode: 'edit' as const,
|
|
453
|
-
recordId,
|
|
454
|
-
basePath: cfg.path,
|
|
455
|
-
layout: cfg.layout,
|
|
456
|
-
schemaData,
|
|
457
|
-
notifications: consumeFlashedNotifications(req),
|
|
458
|
-
...(prefill?.errors ? { hasErrors: true } : {}),
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
export async function resourceViewData(
|
|
463
|
-
pilotiq: Pilotiq,
|
|
464
|
-
slug: string,
|
|
465
|
-
recordId: string,
|
|
466
|
-
req?: unknown,
|
|
467
|
-
): Promise<Record<string, unknown> | null> {
|
|
468
|
-
const cfg = pilotiq.getConfig()
|
|
469
|
-
const R = pilotiq.findResource(slug)
|
|
470
|
-
if (!R) return null
|
|
471
|
-
const pages = R.resolvePages()
|
|
472
|
-
if (!pages.view) return null
|
|
473
|
-
const PageClass = pages.view
|
|
474
|
-
|
|
475
|
-
const user = await pilotiq.resolveUser(req)
|
|
476
|
-
const ctx: SchemaContext = uploadCtx(userCtx({ mode: 'view', recordId, basePath: cfg.path }, user), cfg)
|
|
477
|
-
const elements = await callPageSchema(PageClass, ctx)
|
|
478
|
-
// For the view page we want the record threaded into resolveSchema so
|
|
479
|
-
// factory-attached visibility predicates see it. Resource.detail()
|
|
480
|
-
// already runs against the loaded record in user code; here we mirror
|
|
481
|
-
// that into ctx.record for the action eval pass.
|
|
482
|
-
let record: unknown = undefined
|
|
483
|
-
if (R.model) {
|
|
484
|
-
try { record = await findRecord(R, recordId, { user }) } catch { /* ignore */ }
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
// Plan #11 — prepend the relation tabs strip with the "Details" tab
|
|
488
|
-
// active when the resource has relation managers configured.
|
|
489
|
-
const relationTabsEl = await buildRelationTabs(R, recordId, cfg.path, '__view', user, record)
|
|
490
|
-
if (relationTabsEl) elements.unshift(relationTabsEl)
|
|
491
|
-
|
|
492
|
-
const recordTitle = record !== undefined && record !== null
|
|
493
|
-
? deriveParentTitle(R, record)
|
|
494
|
-
: recordId
|
|
495
|
-
const breadcrumbs = resourceViewBreadcrumbs(cfg, R, recordTitle)
|
|
496
|
-
if (breadcrumbs) elements.unshift(breadcrumbs)
|
|
497
|
-
|
|
498
|
-
const viewRoute: PanelInfoRoute = { resource: R, page: PageClass, recordId }
|
|
499
|
-
const viewCtx = record !== undefined ? { ...ctx, record } : ctx
|
|
500
|
-
const [panel, schemaData] = await Promise.all([
|
|
501
|
-
panelInfo(pilotiq, req, viewRoute),
|
|
502
|
-
resolveSchema(elements, viewCtx).then(metas => applyRoleHooks(pilotiq, user, 'view', metas, viewRoute)),
|
|
503
|
-
])
|
|
504
|
-
|
|
505
|
-
return {
|
|
506
|
-
panel,
|
|
507
|
-
page: PageClass.toMeta(),
|
|
508
|
-
resource: { name: R.name, label: R.labelSingular, slug, icon: serializeIcon(R.icon, R.name) },
|
|
509
|
-
mode: 'view' as const,
|
|
510
|
-
recordId,
|
|
511
|
-
basePath: cfg.path,
|
|
512
|
-
layout: cfg.layout,
|
|
513
|
-
schemaData,
|
|
514
|
-
notifications: consumeFlashedNotifications(req),
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
/**
|
|
519
|
-
* Custom record sub-page data builder. Mounted at
|
|
520
|
-
* `${resourceBase}/${slug}/:id/${subPageSlug}` for each entry in
|
|
521
|
-
* `Resource.pages().record`. Mirrors `resourceViewData`'s shape: load
|
|
522
|
-
* the record, run R.canAccess + R.canView (parent-resource gates),
|
|
523
|
-
* then SubPage.canAccess(user, record) (sub-page-specific gate),
|
|
524
|
-
* then render the sub-page's schema with `ctx.record` set. Tab strip
|
|
525
|
-
* carries the sub-page slug as the active key so the matching record
|
|
526
|
-
* sub-page tab highlights.
|
|
527
|
-
*
|
|
528
|
-
* Returns:
|
|
529
|
-
* - `null` — resource / sub-page slug not found (404 upstream).
|
|
530
|
-
* - `{ ok: false, status: 403 }` — any gate fails or throws.
|
|
531
|
-
* - resolved page data — on success.
|
|
532
|
-
*/
|
|
533
|
-
export async function resourceRecordPageData(
|
|
534
|
-
pilotiq: Pilotiq,
|
|
535
|
-
slug: string,
|
|
536
|
-
recordId: string,
|
|
537
|
-
subPageSlug: string,
|
|
538
|
-
req?: unknown,
|
|
539
|
-
): Promise<Record<string, unknown> | null | { ok: false; status: 403 }> {
|
|
540
|
-
const cfg = pilotiq.getConfig()
|
|
541
|
-
const R = pilotiq.findResource(slug)
|
|
542
|
-
if (!R) return null
|
|
543
|
-
const recordPages = R.getRecordPages()
|
|
544
|
-
const PageClass = recordPages[subPageSlug]
|
|
545
|
-
if (!PageClass) return null
|
|
546
|
-
|
|
547
|
-
const user = await pilotiq.resolveUser(req)
|
|
548
|
-
|
|
549
|
-
// Load the parent record before gating so canView / SubPage.canAccess
|
|
550
|
-
// can branch on record state. Sub-pages without a Resource.model
|
|
551
|
-
// still get gated against an `undefined` record — the same posture as
|
|
552
|
-
// resourceViewData when no model is bound.
|
|
553
|
-
let record: unknown = undefined
|
|
554
|
-
if (R.model) {
|
|
555
|
-
try { record = await findRecord(R, recordId, { user }) } catch { /* ignore */ }
|
|
556
|
-
}
|
|
557
|
-
if (record === undefined || record === null) {
|
|
558
|
-
// Distinguish "model bound but record missing" (route should 404)
|
|
559
|
-
// from "no model bound" (treat record as `{ id: recordId }` so the
|
|
560
|
-
// page can still render — same convention as the edit page).
|
|
561
|
-
if (R.model) return null
|
|
562
|
-
record = { id: recordId }
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
// Three gates: parent resource access + view, then the sub-page's own
|
|
566
|
-
// canAccess. The route would have run R.canAccess upstream, but
|
|
567
|
-
// re-running here makes resourceRecordPageData safe to call from
|
|
568
|
-
// dispatchPageData (where the SPA path skips the route prelude).
|
|
569
|
-
if (!await safeBool(() => R.canAccess(user))) return { ok: false, status: 403 }
|
|
570
|
-
if (!await safeBool(() => R.canView(user, record))) return { ok: false, status: 403 }
|
|
571
|
-
if (!await safeBool(() => PageClass.canAccess(user, record))) return { ok: false, status: 403 }
|
|
572
|
-
|
|
573
|
-
const ctx: SchemaContext = uploadCtx(userCtx({ mode: 'view', recordId, basePath: cfg.path }, user), cfg)
|
|
574
|
-
const elements = await callPageSchema(PageClass, ctx)
|
|
575
|
-
|
|
576
|
-
// Insert the relation-tabs strip with the sub-page slug active so the
|
|
577
|
-
// matching tab highlights. `buildRelationTabs` evaluates per-tab
|
|
578
|
-
// gating against `user + record` — record sub-page tabs are gated
|
|
579
|
-
// alongside __view/__edit/managers.
|
|
580
|
-
const relationTabsEl = await buildRelationTabs(R, recordId, cfg.path, subPageSlug, user, record)
|
|
581
|
-
if (relationTabsEl) elements.unshift(relationTabsEl)
|
|
582
|
-
|
|
583
|
-
const recordTitle = record !== undefined && record !== null
|
|
584
|
-
? deriveParentTitle(R, record)
|
|
585
|
-
: recordId
|
|
586
|
-
const breadcrumbs = resourceViewBreadcrumbs(cfg, R, recordTitle)
|
|
587
|
-
if (breadcrumbs) elements.unshift(breadcrumbs)
|
|
588
|
-
|
|
589
|
-
const recordPageRoute: PanelInfoRoute = { resource: R, page: PageClass, recordId }
|
|
590
|
-
const recordCtx = record !== undefined ? { ...ctx, record } : ctx
|
|
591
|
-
const [panel, schemaData] = await Promise.all([
|
|
592
|
-
panelInfo(pilotiq, req, recordPageRoute),
|
|
593
|
-
resolveSchema(elements, recordCtx).then(metas => applyRoleHooks(pilotiq, user, 'view', metas, recordPageRoute)),
|
|
594
|
-
])
|
|
595
|
-
|
|
596
|
-
return {
|
|
597
|
-
pageType: 'record-page' as const,
|
|
598
|
-
panel,
|
|
599
|
-
page: PageClass.toMeta(),
|
|
600
|
-
resource: { name: R.name, label: R.labelSingular, slug, icon: serializeIcon(R.icon, R.name) },
|
|
601
|
-
mode: 'record' as const,
|
|
602
|
-
recordId,
|
|
603
|
-
subPage: { slug: subPageSlug, label: PageClass.getLabel() },
|
|
604
|
-
basePath: cfg.path,
|
|
605
|
-
layout: cfg.layout,
|
|
606
|
-
schemaData,
|
|
607
|
-
notifications: consumeFlashedNotifications(req),
|
|
608
|
-
}
|
|
609
|
-
}
|