@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
package/src/orm/modelDefaults.ts
DELETED
|
@@ -1,666 +0,0 @@
|
|
|
1
|
-
import type { Column } from '../Column.js'
|
|
2
|
-
import type { Table, TableRecordsHandler, TableRecordsResult } from '../elements/Table.js'
|
|
3
|
-
import type { SaveHandler, LoadRecordHandler, FormContext } from '../elements/Form.js'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* SQL-style operators understood by `ModelLike.query()`. Mirrors the
|
|
7
|
-
* `WhereOperator` set from `@rudderjs/contracts` so any rudder Model is
|
|
8
|
-
* structurally assignable to `ModelLike` — but pilotiq doesn't import
|
|
9
|
-
* `@rudderjs/contracts` here to keep this file dependency-light.
|
|
10
|
-
*/
|
|
11
|
-
export type ModelWhereOperator = '=' | '!=' | '>' | '>=' | '<' | '<=' | 'LIKE' | 'NOT LIKE' | 'IN' | 'NOT IN'
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Context passed into `Resource.query(ctx)`. Carries the resolved user so
|
|
15
|
-
* tenant-scoping / role-driven default ordering / etc. can branch on it.
|
|
16
|
-
* Optional everywhere; bare `R.query()` calls receive `undefined`.
|
|
17
|
-
*/
|
|
18
|
-
export interface QueryContext {
|
|
19
|
-
/** Whatever `Pilotiq.user(req => …)` returned for the current request.
|
|
20
|
-
* `undefined` for anonymous routes or when no user resolver is set. */
|
|
21
|
-
user?: unknown
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Minimal structural shape of a `Resource` class as far as the ORM helpers
|
|
26
|
-
* here need to see it — `name` for diagnostics, `model` for the default
|
|
27
|
-
* branch, and `query(ctx?)` for the override hook. Declared here (instead
|
|
28
|
-
* of importing `ResourceClass` from `../Resource.js`) to avoid a
|
|
29
|
-
* `Resource → modelDefaults → Resource` import cycle. The real
|
|
30
|
-
* `Resource` static class is structurally assignable to this shape.
|
|
31
|
-
*/
|
|
32
|
-
export interface ResourceLike {
|
|
33
|
-
name: string
|
|
34
|
-
model?: ModelLike
|
|
35
|
-
query(ctx?: QueryContext): ModelQuery
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Eloquent-style query builder pilotiq drives when it auto-generates
|
|
40
|
-
* `Table.records()` / `Form.save()` / `Form.loadRecord()` from a
|
|
41
|
-
* Resource's `static model`. Any query builder that satisfies this shape
|
|
42
|
-
* works — the rudder `QueryBuilder<T>` from `@rudderjs/contracts` does,
|
|
43
|
-
* and so does anything user-supplied with the same method names.
|
|
44
|
-
*/
|
|
45
|
-
export interface ModelQuery {
|
|
46
|
-
where(column: string, value: unknown): ModelQuery
|
|
47
|
-
where(column: string, operator: ModelWhereOperator, value: unknown): ModelQuery
|
|
48
|
-
orWhere(column: string, value: unknown): ModelQuery
|
|
49
|
-
orWhere(column: string, operator: ModelWhereOperator, value: unknown): ModelQuery
|
|
50
|
-
orderBy(column: string, direction?: 'ASC' | 'DESC'): ModelQuery
|
|
51
|
-
paginate(page: number, perPage?: number): Promise<{ data: unknown[]; total: number }>
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Single-row `LIMIT 1` SELECT — Laravel-parity sibling of `paginate`
|
|
55
|
-
* for the "first matching row" case. Optional on the structural shape;
|
|
56
|
-
* the `@rudderjs/orm` `QueryBuilder` ships it, test stubs typically
|
|
57
|
-
* don't. Callers that need it should fall back to
|
|
58
|
-
* `(await q.paginate(1, 1)).data[0]` when absent — see `findRecord` /
|
|
59
|
-
* `loadSingularRecord` / `childBelongsToParent` for the pattern.
|
|
60
|
-
*/
|
|
61
|
-
first?(): Promise<unknown | null>
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Plan #13 — soft-delete query scopes. Optional on the structural
|
|
65
|
-
* shape; the `@rudderjs/orm-prisma` QueryBuilder ships them when
|
|
66
|
-
* `Model.softDeletes = true`. Pilotiq's `TrashedFilter` checks for
|
|
67
|
-
* presence at runtime and no-ops when missing (so non-soft-delete
|
|
68
|
-
* resources don't pay the cost).
|
|
69
|
-
*/
|
|
70
|
-
withTrashed?(): ModelQuery
|
|
71
|
-
onlyTrashed?(): ModelQuery
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Optional `IS NULL` clause used by `TernaryFilter`'s `'blank'` value.
|
|
75
|
-
* When absent, `TernaryFilter` falls back to `where(name, null)` —
|
|
76
|
-
* accurate against rudder's QueryBuilder, less reliable against bare
|
|
77
|
-
* Knex/raw drivers. The rudder ORM ships this; the structural shape
|
|
78
|
-
* keeps it optional so test stubs don't need to implement it.
|
|
79
|
-
*/
|
|
80
|
-
whereNull?(column: string): ModelQuery
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* M2M pivot-extra projection — declares which pivot-table columns to
|
|
84
|
-
* surface on each loaded related row under `row.pivot = { col: val }`.
|
|
85
|
-
* Used by `Repeater.relationship.pivotColumns([...])`. No-op (or
|
|
86
|
-
* irrelevant) on hasMany / morphMany queries; the rudder ORM
|
|
87
|
-
* implements this only on the M2M deferred-QB family. Optional on
|
|
88
|
-
* the structural shape so test stubs don't need to implement it.
|
|
89
|
-
*/
|
|
90
|
-
withPivot?(...columns: string[]): ModelQuery
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Wrap a chain of `where`/`orWhere` (and nested `whereGroup`s) in a
|
|
94
|
-
* single AND-grouped clause. Used by `QueryBuilderFilter` v2 to
|
|
95
|
-
* translate nested AND/OR trees into parenthesized SQL groups. The
|
|
96
|
-
* callback receives a fresh sub-builder and may return it explicitly
|
|
97
|
-
* or implicitly (`void`); in either case the clauses recorded inside
|
|
98
|
-
* are spliced back into this builder as one composite clause.
|
|
99
|
-
*
|
|
100
|
-
* Optional on the structural shape — when missing, `applyTreeToQuery`
|
|
101
|
-
* falls back to flat AND chaining (v1 behaviour). The rudder ORM ships
|
|
102
|
-
* this on every QueryBuilder; test stubs don't have to.
|
|
103
|
-
*/
|
|
104
|
-
whereGroup?(fn: (q: ModelQuery) => ModelQuery | void): ModelQuery
|
|
105
|
-
|
|
106
|
-
/** OR-rooted variant of {@link whereGroup}. */
|
|
107
|
-
orWhereGroup?(fn: (q: ModelQuery) => ModelQuery | void): ModelQuery
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Structural shape pilotiq calls to wire ORM defaults. A class extending
|
|
112
|
-
* `@rudderjs/orm`'s `Model` satisfies this automatically via its static
|
|
113
|
-
* methods. Users with a different ORM can build their own object.
|
|
114
|
-
*/
|
|
115
|
-
export interface ModelLike {
|
|
116
|
-
/** Primary-key column name. Defaults to `'id'`. */
|
|
117
|
-
primaryKey?: string
|
|
118
|
-
|
|
119
|
-
find(id: string | number): Promise<unknown>
|
|
120
|
-
create(data: Record<string, unknown>): Promise<unknown>
|
|
121
|
-
update(id: string | number, data: Record<string, unknown>): Promise<unknown>
|
|
122
|
-
delete(id: string | number): Promise<void>
|
|
123
|
-
query(): ModelQuery
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Plan #11 — return a `ModelQuery` scoped to the given parent record's
|
|
127
|
-
* relation. Optional. When absent, pilotiq falls back to the rudder ORM
|
|
128
|
-
* convention `parent.related(relationName)`. Override when your ORM
|
|
129
|
-
* doesn't follow that convention or when you need a custom join shape.
|
|
130
|
-
*/
|
|
131
|
-
relatedQuery?(parent: unknown, relationName: string): ModelQuery
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Plan #13 — restore a soft-deleted record. Optional on the structural
|
|
135
|
-
* shape; rudder's `Model.restore` ships when `softDeletes = true`. Pilotiq
|
|
136
|
-
* detects presence at boot when `Resource.softDeletes = true` and throws
|
|
137
|
-
* a clear error pointing at the rudder upgrade if absent.
|
|
138
|
-
*/
|
|
139
|
-
restore?(id: string | number): Promise<unknown>
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Plan #13 — permanently delete a record (bypassing soft-delete).
|
|
143
|
-
* Optional on the structural shape; same boot-time check as `restore`.
|
|
144
|
-
*/
|
|
145
|
-
forceDelete?(id: string | number): Promise<void>
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Reorderable rows — write a new explicit ordering for the rows whose
|
|
149
|
-
* primary keys are in `ids`. The implementation overwrites the
|
|
150
|
-
* configured sort column (`Table.reorderable(col)`) so each id's value
|
|
151
|
-
* matches its position in the array (1..n). Optional on the structural
|
|
152
|
-
* shape; pilotiq throws a clear boot error when `Table.reorderable()`
|
|
153
|
-
* is set but this is missing.
|
|
154
|
-
*/
|
|
155
|
-
reorder?(ids: Array<string | number>): Promise<void>
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/** Read the configured primary key (default `'id'`) off a `ModelLike`. */
|
|
159
|
-
export function getPrimaryKey(M: ModelLike): string {
|
|
160
|
-
return M.primaryKey ?? 'id'
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Default `Form.save` handler for resources with `static model = …`.
|
|
165
|
-
* Discriminates create vs update by reading the primary-key off
|
|
166
|
-
* `ctx.record` (set by the route handler in edit mode after `loadRecord`
|
|
167
|
-
* + `fillFromRecord`). Create mode has no `ctx.record`, so we hit
|
|
168
|
-
* `model.create(data)`.
|
|
169
|
-
*/
|
|
170
|
-
export function modelSave(M: ModelLike): SaveHandler {
|
|
171
|
-
return async (data: Record<string, unknown>, ctx: FormContext): Promise<unknown> => {
|
|
172
|
-
const pk = getPrimaryKey(M)
|
|
173
|
-
const existing = ctx.record as Record<string, unknown> | undefined
|
|
174
|
-
const id = existing?.[pk] as string | number | undefined
|
|
175
|
-
if (id !== undefined && id !== null) {
|
|
176
|
-
return M.update(id, data)
|
|
177
|
-
}
|
|
178
|
-
return M.create(data)
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Default `Form.loadRecord` handler for resources with `static model = …`.
|
|
184
|
-
* Routes through `R.query(ctx)` so tenant scopes / default-ordering hooks
|
|
185
|
-
* the user installed on `Resource.query(ctx)` ALSO scope the per-record
|
|
186
|
-
* load — without this, a tampered `:id` URL could load a record outside
|
|
187
|
-
* the user's scope and pass it to the form for editing. Falls back to the
|
|
188
|
-
* bare `M.find(id)` only when `R.query()` is missing — defensive against
|
|
189
|
-
* test stubs that hand-roll a partial Resource shape.
|
|
190
|
-
*/
|
|
191
|
-
export function modelLoadRecord(R: ResourceLike): LoadRecordHandler {
|
|
192
|
-
return async (id: string, ctx): Promise<unknown> => {
|
|
193
|
-
const user = (ctx as { user?: unknown } | undefined)?.user
|
|
194
|
-
const found = await findRecord(R, id, user !== undefined ? { user } : undefined)
|
|
195
|
-
return found ?? null
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Default `Form.loadRecord` handler for the singular-record settings
|
|
201
|
-
* pattern — one row in a table, auto-loaded on every page render.
|
|
202
|
-
* `Global` subclasses with `static model = M` set get this wired
|
|
203
|
-
* automatically by `defaultGlobalEditPage`.
|
|
204
|
-
*
|
|
205
|
-
* Default strategy: `.first()` — i.e. the first matching row. Pass
|
|
206
|
-
* `findSingular` to switch to a fixed-id lookup
|
|
207
|
-
* (`(q) => q.where('id', '=', 1)`) or a slug-style lookup
|
|
208
|
-
* (`(q) => q.where('key', '=', 'site')`).
|
|
209
|
-
*
|
|
210
|
-
* Returns `null` when no row exists yet — the paired `modelSave(M)`
|
|
211
|
-
* handler will then run `M.create(data)` on the first POST so the
|
|
212
|
-
* record auto-creates on first save.
|
|
213
|
-
*/
|
|
214
|
-
export function loadSingularRecord(
|
|
215
|
-
M: ModelLike,
|
|
216
|
-
opts?: { findSingular?: (q: ModelQuery) => ModelQuery },
|
|
217
|
-
): LoadRecordHandler {
|
|
218
|
-
return async (): Promise<unknown> => {
|
|
219
|
-
let q = M.query()
|
|
220
|
-
if (opts?.findSingular) q = opts.findSingular(q)
|
|
221
|
-
if (q.first) return (await q.first()) ?? null
|
|
222
|
-
const result = await q.paginate(1, 1)
|
|
223
|
-
const data = (result?.data ?? []) as unknown[]
|
|
224
|
-
return data[0] ?? null
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Find a record by primary key through `R.query(ctx)`. The standard
|
|
230
|
-
* "load record for edit / view / policy" path — replaces direct
|
|
231
|
-
* `R.model.find(id)` calls so user `Resource.query` overrides scope the
|
|
232
|
-
* lookup too. Returns `undefined` when no row matches (or no `R.model`
|
|
233
|
-
* is set), letting callers convert to 404 / fail closed.
|
|
234
|
-
*
|
|
235
|
-
* Soft-delete restore / force-delete deliberately bypass this helper —
|
|
236
|
-
* those paths build their own `query().withTrashed().where(pk, id)` so a
|
|
237
|
-
* record's own user-installed scope (which typically excludes trashed
|
|
238
|
-
* rows) doesn't hide a row the operator is trying to recover.
|
|
239
|
-
*/
|
|
240
|
-
export async function findRecord<T = unknown>(
|
|
241
|
-
R: ResourceLike,
|
|
242
|
-
id: string | number,
|
|
243
|
-
ctx?: QueryContext,
|
|
244
|
-
): Promise<T | undefined> {
|
|
245
|
-
const M = R.model
|
|
246
|
-
if (!M) return undefined
|
|
247
|
-
const pk = getPrimaryKey(M)
|
|
248
|
-
const q = R.query(ctx).where(pk, '=', id)
|
|
249
|
-
if (q.first) return ((await q.first()) ?? undefined) as T | undefined
|
|
250
|
-
const result = await q.paginate(1, 1)
|
|
251
|
-
const data = (result?.data ?? []) as unknown[]
|
|
252
|
-
return data[0] as T | undefined
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Build a default `Table.records` handler from a `Resource` class plus
|
|
257
|
-
* the `Table` instance the page just configured. Reads the column
|
|
258
|
-
* children to drive search (any `Column.searchable()` joins via
|
|
259
|
-
* `LIKE`/`orWhere`) and sort fallback (`Table.defaultSort()` when the
|
|
260
|
-
* URL didn't override).
|
|
261
|
-
*
|
|
262
|
-
* The handler hits `R.query(ctx).paginate(page, perPage)` once per page
|
|
263
|
-
* render — search/sort/pagination all push down to the ORM rather than
|
|
264
|
-
* loading everything and slicing in memory. Going through `R.query(ctx)`
|
|
265
|
-
* (instead of `R.model.query()` directly) means user-installed scopes
|
|
266
|
-
* — tenant filters, default ordering, soft-delete-default behavior —
|
|
267
|
-
* apply to list pages out of the box.
|
|
268
|
-
*/
|
|
269
|
-
export function modelTableRecords(R: ResourceLike, table: Table): TableRecordsHandler {
|
|
270
|
-
// Snapshot the column-derived config at handler-construction time so
|
|
271
|
-
// we don't re-walk the children on every request.
|
|
272
|
-
const columns: Column[] = table.getColumns()
|
|
273
|
-
const searchable: string[] = columns.filter(c => c.isSearchable()).map(c => c.name)
|
|
274
|
-
const filters = table.getFilters()
|
|
275
|
-
|
|
276
|
-
return async (ctx): Promise<TableRecordsResult> => {
|
|
277
|
-
const user = (ctx as { user?: unknown }).user
|
|
278
|
-
let q = R.query(user !== undefined ? { user } : undefined)
|
|
279
|
-
|
|
280
|
-
if (ctx.search && searchable.length > 0) {
|
|
281
|
-
const needle = `%${ctx.search}%`
|
|
282
|
-
searchable.forEach((col, i) => {
|
|
283
|
-
q = i === 0
|
|
284
|
-
? q.where(col, 'LIKE', needle)
|
|
285
|
-
: q.orWhere(col, 'LIKE', needle)
|
|
286
|
-
})
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// Apply filters. Each Filter contributes a `where` clause with type
|
|
290
|
-
// coercion based on its `kind` — boolean filters cast '1'/'true' to
|
|
291
|
-
// a real boolean. Custom `Filter.query(fn)` overrides the default.
|
|
292
|
-
const filterValues = ctx.filters ?? {}
|
|
293
|
-
for (const filter of filters) {
|
|
294
|
-
const value = filterValues[filter.name]
|
|
295
|
-
if (value === undefined || value === '') continue
|
|
296
|
-
const customQuery = filter.getQuery()
|
|
297
|
-
if (customQuery) {
|
|
298
|
-
q = customQuery(q, value)
|
|
299
|
-
} else if (filter.getKind() === 'boolean') {
|
|
300
|
-
const bool = value === '1' || value === 'true' || value === 'yes' || value === 'on'
|
|
301
|
-
q = q.where(filter.name, bool)
|
|
302
|
-
} else {
|
|
303
|
-
q = q.where(filter.name, value)
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Apply the active list-page tab's query modifier (from
|
|
308
|
-
// `ListTab.modifyQuery(fn)`). Tabs are the primary axis (status,
|
|
309
|
-
// type) and filters are secondary refinements within a tab — running
|
|
310
|
-
// the tab's predicate after filters keeps that mental model intact
|
|
311
|
-
// and lets a tab's narrower `where` win on collision.
|
|
312
|
-
if (ctx.tabQuery) q = ctx.tabQuery(q)
|
|
313
|
-
|
|
314
|
-
// Apply group drill-in scoper when the user clicked a banded heading.
|
|
315
|
-
// Runs after filters + tab so the bucket narrowing composes on top of
|
|
316
|
-
// whatever scope the page already had. User-supplied
|
|
317
|
-
// `TableGroup.scopeQueryByKey(fn)` wins over the framework default
|
|
318
|
-
// (exact-match `where(column, '=', key)` / whole-day range for date
|
|
319
|
-
// groups); throwing scopers propagate so a config bug surfaces loudly
|
|
320
|
-
// rather than silently rendering every row.
|
|
321
|
-
if (ctx.groupScope) {
|
|
322
|
-
const scope = ctx.groupScope
|
|
323
|
-
const scoper = scope.group.resolveScoper<ModelQuery>()
|
|
324
|
-
q = scoper(q, scope.key)
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
if (ctx.sort) {
|
|
328
|
-
q = q.orderBy(ctx.sort.column, ctx.sort.direction === 'desc' ? 'DESC' : 'ASC')
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
const page = ctx.page ?? 1
|
|
332
|
-
const perPage = ctx.perPage ?? table.getPerPage() ?? 15
|
|
333
|
-
|
|
334
|
-
const result = await q.paginate(page, perPage)
|
|
335
|
-
return { rows: result.data, total: result.total }
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// ─── Repeater.relationship — parent relation descriptor ──────
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* Structural shape of a single entry in the parent model's
|
|
343
|
-
* `static relations` map (rudder ORM convention). The `model` thunk
|
|
344
|
-
* defers child-class resolution to call time so circular imports
|
|
345
|
-
* between sibling models still work.
|
|
346
|
-
*
|
|
347
|
-
* Pilotiq doesn't import this from `@rudderjs/orm` — keeping the
|
|
348
|
-
* shape duck-typed lets users stub a relations map for tests without
|
|
349
|
-
* pulling in the full ORM.
|
|
350
|
-
*/
|
|
351
|
-
export interface ParentRelationDescriptor {
|
|
352
|
-
/** Relation type. v1 of `Repeater.relationship` only handles `'hasMany'`. */
|
|
353
|
-
type: string
|
|
354
|
-
/** Thunk returning the child model class (a `ModelLike`). */
|
|
355
|
-
model: () => ModelLike
|
|
356
|
-
/** FK column on the child pointing back at the parent. */
|
|
357
|
-
foreignKey: string
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Read a single entry off a parent model's `static relations` map.
|
|
362
|
-
* Returns `undefined` when the map is missing, the named relation is
|
|
363
|
-
* absent, or the entry doesn't have the required `model` thunk +
|
|
364
|
-
* `foreignKey` string. Callers (e.g. `Repeater.relationship`'s save
|
|
365
|
-
* pipeline) throw a clear error from outside to surface configuration
|
|
366
|
-
* problems eagerly.
|
|
367
|
-
*/
|
|
368
|
-
export function getParentRelationDescriptor(
|
|
369
|
-
parentModel: ModelLike,
|
|
370
|
-
name: string,
|
|
371
|
-
): ParentRelationDescriptor | undefined {
|
|
372
|
-
const relations = (parentModel as unknown as Record<string, unknown>)['relations']
|
|
373
|
-
if (!relations || typeof relations !== 'object') return undefined
|
|
374
|
-
const entry = (relations as Record<string, unknown>)[name]
|
|
375
|
-
if (!entry || typeof entry !== 'object') return undefined
|
|
376
|
-
const e = entry as Record<string, unknown>
|
|
377
|
-
if (typeof e['foreignKey'] !== 'string') return undefined
|
|
378
|
-
if (typeof e['model'] !== 'function') return undefined
|
|
379
|
-
// `type` defaults to 'hasMany' when missing — keeps test stubs lean.
|
|
380
|
-
const type = typeof e['type'] === 'string' ? (e['type'] as string) : 'hasMany'
|
|
381
|
-
return {
|
|
382
|
-
type,
|
|
383
|
-
model: e['model'] as () => ModelLike,
|
|
384
|
-
foreignKey: e['foreignKey'] as string,
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* Read just the `type` field off a parent's `static relations[name]`.
|
|
390
|
-
* Returns `'hasMany'` when the relations map is missing the entry or
|
|
391
|
-
* doesn't expose a string `type` — same lenient default as
|
|
392
|
-
* `getParentRelationDescriptor`. Used by `relationManagerData` to set
|
|
393
|
-
* `RelationManagerContext.mode` for action injection / factory short-
|
|
394
|
-
* circuiting under M2M. Doesn't require the `foreignKey` field that
|
|
395
|
-
* `getParentRelationDescriptor` insists on, because M2M relations
|
|
396
|
-
* don't carry one (they have pivot keys instead).
|
|
397
|
-
*/
|
|
398
|
-
export function getRelationType(
|
|
399
|
-
parentModel: ModelLike,
|
|
400
|
-
name: string,
|
|
401
|
-
): string {
|
|
402
|
-
const relations = (parentModel as unknown as Record<string, unknown>)['relations']
|
|
403
|
-
if (!relations || typeof relations !== 'object') return 'hasMany'
|
|
404
|
-
const entry = (relations as Record<string, unknown>)[name]
|
|
405
|
-
if (!entry || typeof entry !== 'object') return 'hasMany'
|
|
406
|
-
const e = entry as Record<string, unknown>
|
|
407
|
-
return typeof e['type'] === 'string' ? (e['type'] as string) : 'hasMany'
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
/**
|
|
411
|
-
* Many-to-many relation descriptor read off a parent's `static
|
|
412
|
-
* relations[name]`. Returned by `getM2MRelationDescriptor` for the
|
|
413
|
-
* three M2M variants (`belongsToMany`, `morphToMany`, `morphedByMany`).
|
|
414
|
-
*
|
|
415
|
-
* Shape is intentionally minimal — pilotiq's M2M dispatch uses the
|
|
416
|
-
* `parent[rel]()` accessor for pivot writes, so neither `pivotTable`
|
|
417
|
-
* nor `morphName` need to surface here. The `model` thunk is the only
|
|
418
|
-
* field consumed by `Repeater.relationship`'s save pipeline (for
|
|
419
|
-
* `M.create` / `M.update` calls on the related child).
|
|
420
|
-
*/
|
|
421
|
-
export interface M2MRelationDescriptor {
|
|
422
|
-
/** Relation type. Discriminator for the `Repeater.relationship` M2M
|
|
423
|
-
* branches; all three share the same persist-side dispatch but the
|
|
424
|
-
* type round-trips into error messages and tests. */
|
|
425
|
-
type: 'belongsToMany' | 'morphToMany' | 'morphedByMany'
|
|
426
|
-
/** Thunk returning the related (child) model class. */
|
|
427
|
-
model: () => ModelLike
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Read a many-to-many relation entry off a parent model's `static
|
|
432
|
-
* relations[name]`. Returns `undefined` when the entry is missing,
|
|
433
|
-
* isn't an M2M type, or doesn't carry a `model` thunk. Lenient on
|
|
434
|
-
* the structural shape so test stubs can supply just `{ type, model }`.
|
|
435
|
-
*
|
|
436
|
-
* Caller responsibility: the lookup checks `relations[name].type`
|
|
437
|
-
* against the three M2M variants. Other relation types (hasMany,
|
|
438
|
-
* morphMany, etc.) return `undefined` so callers (e.g.
|
|
439
|
-
* `resolveChildAndAttachment`) can fall through to the corresponding
|
|
440
|
-
* descriptor lookup.
|
|
441
|
-
*/
|
|
442
|
-
export function getM2MRelationDescriptor(
|
|
443
|
-
parentModel: ModelLike,
|
|
444
|
-
name: string,
|
|
445
|
-
): M2MRelationDescriptor | undefined {
|
|
446
|
-
const relations = (parentModel as unknown as Record<string, unknown>)['relations']
|
|
447
|
-
if (!relations || typeof relations !== 'object') return undefined
|
|
448
|
-
const entry = (relations as Record<string, unknown>)[name]
|
|
449
|
-
if (!entry || typeof entry !== 'object') return undefined
|
|
450
|
-
const e = entry as Record<string, unknown>
|
|
451
|
-
const type = e['type']
|
|
452
|
-
if (type !== 'belongsToMany' && type !== 'morphToMany' && type !== 'morphedByMany') return undefined
|
|
453
|
-
if (typeof e['model'] !== 'function') return undefined
|
|
454
|
-
return {
|
|
455
|
-
type: type as M2MRelationDescriptor['type'],
|
|
456
|
-
model: e['model'] as () => ModelLike,
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
/**
|
|
461
|
-
* Polymorphic relation descriptor read off a parent's `static relations[name]`.
|
|
462
|
-
* Returned by `getMorphRelationDescriptor` for `morphMany` / `morphOne` (where
|
|
463
|
-
* the parent IS the polymorphic owner — `Post.comments`). For `morphTo`, the
|
|
464
|
-
* `model` thunk is missing on the rudder side (the child has a `types: () =>
|
|
465
|
-
* [...]` list instead) — `getMorphRelationDescriptor` returns `undefined` in
|
|
466
|
-
* that case because `RelationManager` on the morphTo side requires
|
|
467
|
-
* `M.relatedResource` to be set anyway (auto-discovery is impossible).
|
|
468
|
-
*/
|
|
469
|
-
export interface MorphRelationDescriptor {
|
|
470
|
-
/** Polymorphic relation name. Drives column names: `{morphName}Id`,
|
|
471
|
-
* `{morphName}Type`. e.g. `'commentable'` → `commentableId` / `commentableType`. */
|
|
472
|
-
morphName: string
|
|
473
|
-
/** Override for the discriminator value persisted in `{morphName}Type`.
|
|
474
|
-
* Defaults to `parent.constructor.morphAlias ?? parent.constructor.name`
|
|
475
|
-
* when missing. */
|
|
476
|
-
morphType?: string
|
|
477
|
-
/** Thunk returning the related (child) model class — present for
|
|
478
|
-
* `morphMany` / `morphOne`, absent for `morphTo`. */
|
|
479
|
-
model?: () => ModelLike
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
/**
|
|
483
|
-
* Read a polymorphic-relation entry off a parent model's `static
|
|
484
|
-
* relations[name]`. Returns `undefined` when the entry is missing,
|
|
485
|
-
* isn't a polymorphic type, or doesn't carry a string `morphName`.
|
|
486
|
-
* Lenient on the structural shape so test stubs can supply just the
|
|
487
|
-
* fields the consumer needs.
|
|
488
|
-
*
|
|
489
|
-
* Caller responsibility: the lookup checks
|
|
490
|
-
* `relations[name].type === 'morphMany' | 'morphOne'`. For `morphTo` —
|
|
491
|
-
* which has no `model` thunk on the rudder side — this returns
|
|
492
|
-
* `undefined`. The consumer (relation-create POST handler) only uses
|
|
493
|
-
* this for the morphMany auto-injection path; morphTo managers don't
|
|
494
|
-
* need it (they require `static relatedResource` and don't auto-fill
|
|
495
|
-
* any columns).
|
|
496
|
-
*/
|
|
497
|
-
export function getMorphRelationDescriptor(
|
|
498
|
-
parentModel: ModelLike,
|
|
499
|
-
name: string,
|
|
500
|
-
): MorphRelationDescriptor | undefined {
|
|
501
|
-
const relations = (parentModel as unknown as Record<string, unknown>)['relations']
|
|
502
|
-
if (!relations || typeof relations !== 'object') return undefined
|
|
503
|
-
const entry = (relations as Record<string, unknown>)[name]
|
|
504
|
-
if (!entry || typeof entry !== 'object') return undefined
|
|
505
|
-
const e = entry as Record<string, unknown>
|
|
506
|
-
const type = e['type']
|
|
507
|
-
if (type !== 'morphMany' && type !== 'morphOne') return undefined
|
|
508
|
-
if (typeof e['morphName'] !== 'string') return undefined
|
|
509
|
-
return {
|
|
510
|
-
morphName: e['morphName'] as string,
|
|
511
|
-
...(typeof e['morphType'] === 'string' ? { morphType: e['morphType'] as string } : {}),
|
|
512
|
-
...(typeof e['model'] === 'function' ? { model: e['model'] as () => ModelLike } : {}),
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
/**
|
|
517
|
-
* Compute the `{ <morphName>Id, <morphName>Type }` payload for a
|
|
518
|
-
* polymorphic write. Mirrors rudder's `Model.morph(name, parent)` but
|
|
519
|
-
* lives here so pilotiq stays free of a runtime `@rudderjs/orm` dep.
|
|
520
|
-
*
|
|
521
|
-
* Resolution rules:
|
|
522
|
-
* - `<morphName>Id` ← `parent[parent.constructor.primaryKey ?? 'id']`
|
|
523
|
-
* - `<morphName>Type` ← `descriptor.morphType` if set, else
|
|
524
|
-
* `parent.constructor.morphAlias ?? parent.constructor.name`
|
|
525
|
-
*
|
|
526
|
-
* Throws when the parent's primary key is unset (matches rudder's
|
|
527
|
-
* `Model.morph` behavior — a parent must be saved before a child can
|
|
528
|
-
* be linked).
|
|
529
|
-
*/
|
|
530
|
-
export function computeMorphPayload(
|
|
531
|
-
parent: unknown,
|
|
532
|
-
descriptor: MorphRelationDescriptor,
|
|
533
|
-
): Record<string, unknown> {
|
|
534
|
-
const ctor = (parent as { constructor?: { name?: string; primaryKey?: string; morphAlias?: string } } | null | undefined)?.constructor
|
|
535
|
-
const pkColumn = ctor?.primaryKey ?? 'id'
|
|
536
|
-
const pk = (parent as Record<string, unknown> | null | undefined)?.[pkColumn]
|
|
537
|
-
if (pk === undefined || pk === null) {
|
|
538
|
-
throw new Error(
|
|
539
|
-
`[Pilotiq] computeMorphPayload("${descriptor.morphName}", parent): ` +
|
|
540
|
-
`parent.${pkColumn} is unset — parent record must be saved before linking a polymorphic child.`,
|
|
541
|
-
)
|
|
542
|
-
}
|
|
543
|
-
const typeAlias = descriptor.morphType ?? ctor?.morphAlias ?? ctor?.name
|
|
544
|
-
if (typeAlias === undefined) {
|
|
545
|
-
throw new Error(
|
|
546
|
-
`[Pilotiq] computeMorphPayload("${descriptor.morphName}", parent): ` +
|
|
547
|
-
`cannot resolve discriminator — parent has no constructor.name or morphAlias. ` +
|
|
548
|
-
`Set \`static morphAlias = '<value>'\` on the parent model, or pass \`morphType\` on the relation entry.`,
|
|
549
|
-
)
|
|
550
|
-
}
|
|
551
|
-
return {
|
|
552
|
-
[`${descriptor.morphName}Id`]: pk,
|
|
553
|
-
[`${descriptor.morphName}Type`]: typeAlias,
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
// ─── Plan #11: relation helpers ────────────────────────────
|
|
558
|
-
|
|
559
|
-
/** Minimal shape we need on a parent record to resolve a relation under
|
|
560
|
-
* the rudder ORM convention. */
|
|
561
|
-
interface ParentWithRelated {
|
|
562
|
-
related(name: string): ModelQuery
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
/**
|
|
566
|
-
* Default relation-query resolver. Calls `parent.related(relationName)`
|
|
567
|
-
* — the rudder ORM convention — and returns the resulting `ModelQuery`.
|
|
568
|
-
* Throws a clear error when the parent record doesn't expose `.related()`,
|
|
569
|
-
* pointing the user at `ModelLike.relatedQuery` as the override slot.
|
|
570
|
-
*/
|
|
571
|
-
export function defaultRelatedQuery(parent: unknown, relationName: string): ModelQuery {
|
|
572
|
-
const p = parent as Partial<ParentWithRelated>
|
|
573
|
-
if (typeof p?.related !== 'function') {
|
|
574
|
-
throw new Error(
|
|
575
|
-
`[Pilotiq] Cannot resolve relation "${relationName}" — parent record has no .related() method. ` +
|
|
576
|
-
`Implement ModelLike.relatedQuery(parent, name) on the parent's static model to provide a custom resolver.`,
|
|
577
|
-
)
|
|
578
|
-
}
|
|
579
|
-
return (p as ParentWithRelated).related(relationName)
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
/**
|
|
583
|
-
* Resolve a relation query by preferring the parent model's
|
|
584
|
-
* `relatedQuery` override and falling back to the rudder convention.
|
|
585
|
-
* The single entry point pilotiq's manager code calls.
|
|
586
|
-
*/
|
|
587
|
-
export function resolveRelatedQuery(
|
|
588
|
-
M: ModelLike,
|
|
589
|
-
parent: unknown,
|
|
590
|
-
relationName: string,
|
|
591
|
-
): ModelQuery {
|
|
592
|
-
if (typeof M.relatedQuery === 'function') {
|
|
593
|
-
return M.relatedQuery(parent, relationName)
|
|
594
|
-
}
|
|
595
|
-
return defaultRelatedQuery(parent, relationName)
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
/**
|
|
599
|
-
* Sibling of `modelTableRecords` for `RelationManager` tables. Drives
|
|
600
|
-
* pagination/search/sort/filters against `parent.related(relationName)`
|
|
601
|
-
* (or the parent model's `relatedQuery` override) instead of the related
|
|
602
|
-
* model's bare `query()`. Used by the page-data builder when a manager's
|
|
603
|
-
* `Table.records()` hasn't been set explicitly.
|
|
604
|
-
*
|
|
605
|
-
* `parentModel` is the **parent's** ModelLike (where `relatedQuery` lives
|
|
606
|
-
* if a custom override was set); `parent` is the resolved parent record
|
|
607
|
-
* instance the manager is scoped under.
|
|
608
|
-
*/
|
|
609
|
-
export function modelRelationTableRecords(
|
|
610
|
-
parentModel: ModelLike,
|
|
611
|
-
parent: unknown,
|
|
612
|
-
relationName: string,
|
|
613
|
-
table: Table,
|
|
614
|
-
): TableRecordsHandler {
|
|
615
|
-
const columns: Column[] = table.getColumns()
|
|
616
|
-
const searchable: string[] = columns.filter(c => c.isSearchable()).map(c => c.name)
|
|
617
|
-
const filters = table.getFilters()
|
|
618
|
-
|
|
619
|
-
return async (ctx): Promise<TableRecordsResult> => {
|
|
620
|
-
let q = resolveRelatedQuery(parentModel, parent, relationName)
|
|
621
|
-
|
|
622
|
-
if (ctx.search && searchable.length > 0) {
|
|
623
|
-
const needle = `%${ctx.search}%`
|
|
624
|
-
searchable.forEach((col, i) => {
|
|
625
|
-
q = i === 0
|
|
626
|
-
? q.where(col, 'LIKE', needle)
|
|
627
|
-
: q.orWhere(col, 'LIKE', needle)
|
|
628
|
-
})
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
const filterValues = ctx.filters ?? {}
|
|
632
|
-
for (const filter of filters) {
|
|
633
|
-
const value = filterValues[filter.name]
|
|
634
|
-
if (value === undefined || value === '') continue
|
|
635
|
-
const customQuery = filter.getQuery()
|
|
636
|
-
if (customQuery) {
|
|
637
|
-
q = customQuery(q, value)
|
|
638
|
-
} else if (filter.getKind() === 'boolean') {
|
|
639
|
-
const bool = value === '1' || value === 'true' || value === 'yes' || value === 'on'
|
|
640
|
-
q = q.where(filter.name, bool)
|
|
641
|
-
} else {
|
|
642
|
-
q = q.where(filter.name, value)
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
if (ctx.tabQuery) q = ctx.tabQuery(q)
|
|
647
|
-
|
|
648
|
-
// Group drill-in scoper — same shape as `modelTableRecords`. Composes
|
|
649
|
-
// with `relatedQuery` since the scoper just chains another `where`.
|
|
650
|
-
if (ctx.groupScope) {
|
|
651
|
-
const scope = ctx.groupScope
|
|
652
|
-
const scoper = scope.group.resolveScoper<ModelQuery>()
|
|
653
|
-
q = scoper(q, scope.key)
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
if (ctx.sort) {
|
|
657
|
-
q = q.orderBy(ctx.sort.column, ctx.sort.direction === 'desc' ? 'DESC' : 'ASC')
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
const page = ctx.page ?? 1
|
|
661
|
-
const perPage = ctx.perPage ?? table.getPerPage() ?? 15
|
|
662
|
-
|
|
663
|
-
const result = await q.paginate(page, perPage)
|
|
664
|
-
return { rows: result.data, total: result.total }
|
|
665
|
-
}
|
|
666
|
-
}
|