@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,268 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { Table } from '../elements/Table.js'
|
|
5
|
-
import { Column } from '../Column.js'
|
|
6
|
-
import { SelectFilter } from './SelectFilter.js'
|
|
7
|
-
import { BooleanFilter, coerceBooleanFilterValue } from './BooleanFilter.js'
|
|
8
|
-
import { TernaryFilter } from './TernaryFilter.js'
|
|
9
|
-
import { DateRangeFilter } from './DateRangeFilter.js'
|
|
10
|
-
import { parseFilterValues, loadTableRecords } from '../elements/dispatchTable.js'
|
|
11
|
-
import { modelTableRecords } from '../orm/modelDefaults.js'
|
|
12
|
-
import type { ModelLike, ModelQuery } from '../orm/modelDefaults.js'
|
|
13
|
-
|
|
14
|
-
describe('SelectFilter / BooleanFilter shape', () => {
|
|
15
|
-
it('SelectFilter.toMeta emits kind:select + options + placeholder', () => {
|
|
16
|
-
const meta = SelectFilter.make('status')
|
|
17
|
-
.options([{ value: 'draft', label: 'Draft' }, { value: 'published', label: 'Published' }])
|
|
18
|
-
.toMeta()
|
|
19
|
-
assert.equal(meta.kind, 'select')
|
|
20
|
-
assert.equal(meta.name, 'status')
|
|
21
|
-
assert.equal(meta.label, 'Status')
|
|
22
|
-
assert.deepEqual(meta.options, [
|
|
23
|
-
{ value: 'draft', label: 'Draft' },
|
|
24
|
-
{ value: 'published', label: 'Published' },
|
|
25
|
-
])
|
|
26
|
-
assert.equal(meta.placeholder, 'All')
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it('BooleanFilter.toMeta emits kind:boolean + Any placeholder', () => {
|
|
30
|
-
const meta = BooleanFilter.make('featured').toMeta()
|
|
31
|
-
assert.equal(meta.kind, 'boolean')
|
|
32
|
-
assert.equal(meta.placeholder, 'Any')
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it('label() override wins over the auto-derived label', () => {
|
|
36
|
-
assert.equal(SelectFilter.make('status').label('Publish state').toMeta().label, 'Publish state')
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it('withValue mirrors current selection into meta', () => {
|
|
40
|
-
const meta = SelectFilter.make('status').withValue('published').toMeta()
|
|
41
|
-
assert.equal(meta.value, 'published')
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('coerceBooleanFilterValue maps string values to booleans', () => {
|
|
45
|
-
assert.equal(coerceBooleanFilterValue('1'), true)
|
|
46
|
-
assert.equal(coerceBooleanFilterValue('true'), true)
|
|
47
|
-
assert.equal(coerceBooleanFilterValue('yes'), true)
|
|
48
|
-
assert.equal(coerceBooleanFilterValue('on'), true)
|
|
49
|
-
assert.equal(coerceBooleanFilterValue('0'), false)
|
|
50
|
-
assert.equal(coerceBooleanFilterValue('false'), false)
|
|
51
|
-
assert.equal(coerceBooleanFilterValue(''), false)
|
|
52
|
-
})
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
describe('Filter.indicator + active-value formatting', () => {
|
|
56
|
-
it('omits indicator when no value is set', () => {
|
|
57
|
-
const meta = SelectFilter.make('status').toMeta()
|
|
58
|
-
assert.equal(meta.indicator, undefined)
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('SelectFilter formats active value via option label', () => {
|
|
62
|
-
const meta = SelectFilter.make('status')
|
|
63
|
-
.options([{ value: 'draft', label: 'Draft' }, { value: 'published', label: 'Published' }])
|
|
64
|
-
.withValue('published')
|
|
65
|
-
.toMeta()
|
|
66
|
-
assert.equal(meta.indicator, 'Status: Published')
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('SelectFilter falls back to raw value when option missing', () => {
|
|
70
|
-
const meta = SelectFilter.make('status').withValue('mystery').toMeta()
|
|
71
|
-
assert.equal(meta.indicator, 'Status: mystery')
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('BooleanFilter renders Yes / No', () => {
|
|
75
|
-
assert.equal(BooleanFilter.make('featured').withValue('1').toMeta().indicator, 'Featured: Yes')
|
|
76
|
-
assert.equal(BooleanFilter.make('featured').withValue('0').toMeta().indicator, 'Featured: No')
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('TernaryFilter maps yes / no / blank through the configured labels', () => {
|
|
80
|
-
const f = TernaryFilter.make('verified')
|
|
81
|
-
.trueLabel('Verified').falseLabel('Unverified').blankLabel('Pending')
|
|
82
|
-
assert.equal(f.withValue('yes').toMeta().indicator, 'Verified: Verified')
|
|
83
|
-
assert.equal(f.withValue('no').toMeta().indicator, 'Verified: Unverified')
|
|
84
|
-
assert.equal(f.withValue('blank').toMeta().indicator, 'Verified: Pending')
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
it('DateRangeFilter formats both / one-sided ranges', () => {
|
|
88
|
-
const f = DateRangeFilter.make('publishedAt')
|
|
89
|
-
assert.equal(f.withValue('2026-01-01..2026-12-31').toMeta().indicator, 'PublishedAt: 2026-01-01 → 2026-12-31')
|
|
90
|
-
assert.equal(f.withValue('2026-01-01..').toMeta().indicator, 'PublishedAt: ≥ 2026-01-01')
|
|
91
|
-
assert.equal(f.withValue('..2026-12-31').toMeta().indicator, 'PublishedAt: ≤ 2026-12-31')
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
it('Filter.indicator(string) is a literal override', () => {
|
|
95
|
-
const meta = SelectFilter.make('status')
|
|
96
|
-
.options([{ value: 'draft', label: 'Draft' }])
|
|
97
|
-
.indicator('Filtered')
|
|
98
|
-
.withValue('draft')
|
|
99
|
-
.toMeta()
|
|
100
|
-
assert.equal(meta.indicator, 'Filtered')
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
it('Filter.indicator(fn) receives value + filter for custom formatting', () => {
|
|
104
|
-
const meta = SelectFilter.make('status')
|
|
105
|
-
.label('Publish state')
|
|
106
|
-
.options([{ value: 'draft', label: 'Draft' }])
|
|
107
|
-
.indicator((v, f) => `${f.getLabel()} = ${v}`)
|
|
108
|
-
.withValue('draft')
|
|
109
|
-
.toMeta()
|
|
110
|
-
assert.equal(meta.indicator, 'Publish state = draft')
|
|
111
|
-
})
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
describe('Table.filters() + getFilters()', () => {
|
|
115
|
-
it('attaches filters as children alongside columns', () => {
|
|
116
|
-
const table = Table.make()
|
|
117
|
-
.columns([Column.make('title')])
|
|
118
|
-
.filters([SelectFilter.make('status'), BooleanFilter.make('featured')])
|
|
119
|
-
const filters = table.getFilters()
|
|
120
|
-
assert.equal(filters.length, 2)
|
|
121
|
-
assert.equal(filters[0]!.name, 'status')
|
|
122
|
-
assert.equal(filters[1]!.name, 'featured')
|
|
123
|
-
// Columns still present
|
|
124
|
-
assert.equal(table.getColumns().length, 1)
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
it('replacing filters does not clobber columns', () => {
|
|
128
|
-
const table = Table.make()
|
|
129
|
-
.columns([Column.make('title')])
|
|
130
|
-
.filters([SelectFilter.make('status')])
|
|
131
|
-
.filters([BooleanFilter.make('featured')]) // replace
|
|
132
|
-
assert.equal(table.getFilters().length, 1)
|
|
133
|
-
assert.equal(table.getFilters()[0]!.name, 'featured')
|
|
134
|
-
assert.equal(table.getColumns().length, 1)
|
|
135
|
-
})
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
describe('parseFilterValues', () => {
|
|
139
|
-
it('returns empty when no filters are registered', () => {
|
|
140
|
-
assert.deepEqual(parseFilterValues({ status: 'x' }, []), {})
|
|
141
|
-
})
|
|
142
|
-
|
|
143
|
-
it('drops reserved query keys + non-matching names', () => {
|
|
144
|
-
const filters = [SelectFilter.make('status'), BooleanFilter.make('featured')]
|
|
145
|
-
const r = parseFilterValues(
|
|
146
|
-
{ status: 'published', featured: '1', search: 'hi', sort: 'title:asc', unknown: 'x' },
|
|
147
|
-
filters,
|
|
148
|
-
)
|
|
149
|
-
assert.deepEqual(r, { status: 'published', featured: '1' })
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
it('drops empty-string values', () => {
|
|
153
|
-
const filters = [SelectFilter.make('status')]
|
|
154
|
-
assert.deepEqual(parseFilterValues({ status: '' }, filters), {})
|
|
155
|
-
})
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
describe('loadTableRecords mirrors filter values + passes them in TableContext', () => {
|
|
159
|
-
it('Filter.withValue is called for each parsed filter, ctx.filters reaches the records handler', async () => {
|
|
160
|
-
let receivedCtx: unknown
|
|
161
|
-
const table = Table.make()
|
|
162
|
-
.columns([Column.make('title')])
|
|
163
|
-
.filters([
|
|
164
|
-
SelectFilter.make('status').options([{ value: 'published', label: 'Published' }]),
|
|
165
|
-
BooleanFilter.make('featured'),
|
|
166
|
-
])
|
|
167
|
-
.records(async (ctx) => { receivedCtx = ctx; return { rows: [], total: 0 } })
|
|
168
|
-
|
|
169
|
-
await loadTableRecords([table], { status: 'published', featured: '1' })
|
|
170
|
-
|
|
171
|
-
const ctx = receivedCtx as { filters?: Record<string, string> }
|
|
172
|
-
assert.deepEqual(ctx.filters, { status: 'published', featured: '1' })
|
|
173
|
-
|
|
174
|
-
const filters = table.getFilters()
|
|
175
|
-
assert.equal(filters[0]!.getValue(), 'published')
|
|
176
|
-
assert.equal(filters[1]!.getValue(), '1')
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
it('omits ctx.filters when no filter values are present', async () => {
|
|
180
|
-
let receivedCtx: { filters?: unknown } = {}
|
|
181
|
-
const table = Table.make()
|
|
182
|
-
.columns([Column.make('title')])
|
|
183
|
-
.filters([SelectFilter.make('status')])
|
|
184
|
-
.records(async (ctx) => { receivedCtx = ctx; return { rows: [], total: 0 } })
|
|
185
|
-
|
|
186
|
-
await loadTableRecords([table], {})
|
|
187
|
-
assert.equal(receivedCtx.filters, undefined)
|
|
188
|
-
})
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
// ── modelTableRecords applies filter where-clauses ────────────────────
|
|
192
|
-
|
|
193
|
-
interface FakeOp { op: string; args: unknown[] }
|
|
194
|
-
class FakeQuery implements ModelQuery {
|
|
195
|
-
ops: FakeOp[] = []
|
|
196
|
-
where(...args: unknown[]): ModelQuery { this.ops.push({ op: 'where', args }); return this }
|
|
197
|
-
orWhere(...args: unknown[]): ModelQuery { this.ops.push({ op: 'orWhere', args }); return this }
|
|
198
|
-
orderBy(c: string, d: 'ASC' | 'DESC' = 'ASC'): ModelQuery { this.ops.push({ op: 'orderBy', args: [c, d] }); return this }
|
|
199
|
-
async paginate(p: number, pp?: number) { this.ops.push({ op: 'paginate', args: [p, pp] }); return { data: [], total: 0 } }
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function fakeModel(): ModelLike & { name: string; model: ModelLike; lastQuery: FakeQuery | null } {
|
|
203
|
-
let lastQuery: FakeQuery | null = null
|
|
204
|
-
const M = {
|
|
205
|
-
name: 'TestResource',
|
|
206
|
-
async find() { return null },
|
|
207
|
-
async create(d: Record<string, unknown>) { return d },
|
|
208
|
-
async update(_id: string | number, d: Record<string, unknown>) { return d },
|
|
209
|
-
async delete() {},
|
|
210
|
-
query(): ModelQuery {
|
|
211
|
-
const q = new FakeQuery()
|
|
212
|
-
lastQuery = q
|
|
213
|
-
return q
|
|
214
|
-
},
|
|
215
|
-
get lastQuery() { return lastQuery },
|
|
216
|
-
} as unknown as ModelLike & { name: string; model: ModelLike; lastQuery: FakeQuery | null }
|
|
217
|
-
M.model = M
|
|
218
|
-
return M
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
describe('modelTableRecords applies filters', () => {
|
|
222
|
-
it('select filter contributes a where(name, value) clause', async () => {
|
|
223
|
-
const M = fakeModel()
|
|
224
|
-
const table = Table.make()
|
|
225
|
-
.columns([Column.make('title')])
|
|
226
|
-
.filters([SelectFilter.make('status').options([{ value: 'published', label: 'Published' }])])
|
|
227
|
-
const handler = modelTableRecords(M, table)
|
|
228
|
-
await handler({ filters: { status: 'published' }, page: 1 })
|
|
229
|
-
const ops = M.lastQuery!.ops
|
|
230
|
-
assert.deepEqual(ops[0], { op: 'where', args: ['status', 'published'] })
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
it('boolean filter coerces the string value to a boolean', async () => {
|
|
234
|
-
const M = fakeModel()
|
|
235
|
-
const table = Table.make()
|
|
236
|
-
.columns([Column.make('title')])
|
|
237
|
-
.filters([BooleanFilter.make('featured')])
|
|
238
|
-
const handler = modelTableRecords(M, table)
|
|
239
|
-
await handler({ filters: { featured: '1' }, page: 1 })
|
|
240
|
-
const ops = M.lastQuery!.ops
|
|
241
|
-
assert.deepEqual(ops[0], { op: 'where', args: ['featured', true] })
|
|
242
|
-
})
|
|
243
|
-
|
|
244
|
-
it('Filter.query(fn) custom hook overrides the default where clause', async () => {
|
|
245
|
-
const M = fakeModel()
|
|
246
|
-
const table = Table.make()
|
|
247
|
-
.columns([Column.make('title')])
|
|
248
|
-
.filters([
|
|
249
|
-
SelectFilter.make('age').query((q, value) => q.where('age', '>=', Number(value))),
|
|
250
|
-
])
|
|
251
|
-
const handler = modelTableRecords(M, table)
|
|
252
|
-
await handler({ filters: { age: '18' }, page: 1 })
|
|
253
|
-
const ops = M.lastQuery!.ops
|
|
254
|
-
assert.deepEqual(ops[0], { op: 'where', args: ['age', '>=', 18] })
|
|
255
|
-
})
|
|
256
|
-
|
|
257
|
-
it('skips filters with empty / undefined values', async () => {
|
|
258
|
-
const M = fakeModel()
|
|
259
|
-
const table = Table.make()
|
|
260
|
-
.columns([Column.make('title').searchable()])
|
|
261
|
-
.filters([SelectFilter.make('status')])
|
|
262
|
-
const handler = modelTableRecords(M, table)
|
|
263
|
-
await handler({ filters: { status: '' }, search: 'hi', page: 1 })
|
|
264
|
-
const ops = M.lastQuery!.ops
|
|
265
|
-
// Only the search clause + paginate, no status where.
|
|
266
|
-
assert.equal(ops.find(o => o.op === 'where' && (o.args as unknown[])[0] === 'status'), undefined)
|
|
267
|
-
})
|
|
268
|
-
})
|
package/src/filters/Filter.ts
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import { Element, type ElementMeta } from '../schema/Element.js'
|
|
2
|
-
import type { ModelQuery } from '../orm/modelDefaults.js'
|
|
3
|
-
import type { RenderContext } from '../schema/resolveSchema.js'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Discriminator for the renderer to pick a control.
|
|
7
|
-
*
|
|
8
|
-
* - `'select'` — single-value dropdown (`SelectFilter`, `TrashedFilter`).
|
|
9
|
-
* - `'multiSelect'` — checkbox list; URL value is comma-separated.
|
|
10
|
-
* - `'boolean'` — three-state yes/no/any.
|
|
11
|
-
* - `'ternary'` — three-state with a meaningful "blank" (NULL) bucket.
|
|
12
|
-
* - `'dateRange'` — pair of date / datetime inputs encoded as `from..to`.
|
|
13
|
-
* - `'form'` — arbitrary-schema multi-field popover; URL value is
|
|
14
|
-
* a JSON-encoded object keyed by inner-field name.
|
|
15
|
-
* - `'queryBuilder'` — composable rules with per-column constraints; URL
|
|
16
|
-
* value is a JSON-encoded `{ operator, rules }` tree.
|
|
17
|
-
*
|
|
18
|
-
* Extends naturally — future kinds may include `'numberRange'`.
|
|
19
|
-
*/
|
|
20
|
-
export type FilterKind = 'select' | 'multiSelect' | 'boolean' | 'ternary' | 'dateRange' | 'form' | 'queryBuilder'
|
|
21
|
-
|
|
22
|
-
export interface FilterMeta extends ElementMeta {
|
|
23
|
-
type: 'filter'
|
|
24
|
-
name: string
|
|
25
|
-
label: string
|
|
26
|
-
kind: FilterKind
|
|
27
|
-
/** Currently-selected value, mirrored from the URL query at render time. */
|
|
28
|
-
value?: string
|
|
29
|
-
/** Placeholder shown when no value is selected (e.g. "All", "Any"). */
|
|
30
|
-
placeholder?: string
|
|
31
|
-
/** Options for `kind === 'select' | 'multiSelect' | 'ternary'`. Boolean uses fixed yes/no. */
|
|
32
|
-
options?: Array<{ value: string; label: string }>
|
|
33
|
-
/** `kind === 'dateRange'` — true switches the inputs to `datetime-local`. */
|
|
34
|
-
includesTime?: boolean
|
|
35
|
-
/** `kind === 'dateRange'` — clamp the inputs' `min` attribute. */
|
|
36
|
-
minDate?: string
|
|
37
|
-
/** `kind === 'dateRange'` — clamp the inputs' `max` attribute. */
|
|
38
|
-
maxDate?: string
|
|
39
|
-
/**
|
|
40
|
-
* `kind === 'form'` — resolved schema for the popover sub-form. Each
|
|
41
|
-
* field's `defaultValue` is pre-hydrated from the active URL value so
|
|
42
|
-
* the inputs round-trip across navigations.
|
|
43
|
-
*/
|
|
44
|
-
formSchema?: ElementMeta[]
|
|
45
|
-
/**
|
|
46
|
-
* `kind === 'queryBuilder'` — declared constraints (one per queryable
|
|
47
|
-
* column) the user can pick from when adding a rule. Wire shape comes
|
|
48
|
-
* from `Constraint.toMeta()`.
|
|
49
|
-
*/
|
|
50
|
-
constraints?: Array<Record<string, unknown>>
|
|
51
|
-
/**
|
|
52
|
-
* Active-filter indicator pill text. Present only when the filter has an
|
|
53
|
-
* active value. Default format is `"<label>: <displayValue>"`; users can
|
|
54
|
-
* override via `Filter.indicator(string | (value, filter) => string)`.
|
|
55
|
-
*/
|
|
56
|
-
indicator?: string
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* User-supplied query customizer. Receives the active filter value plus
|
|
61
|
-
* the running ORM query and returns the modified query. When supplied,
|
|
62
|
-
* `Filter.query(fn)` overrides the default `where(name, value)` clause.
|
|
63
|
-
*/
|
|
64
|
-
export type FilterQueryHandler = (query: ModelQuery, value: string) => ModelQuery
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* User-supplied indicator-pill formatter. Receives the active value plus
|
|
68
|
-
* the filter so callbacks can read its label / option set. The default
|
|
69
|
-
* indicator is `"<label>: <displayValue>"` where `displayValue` comes from
|
|
70
|
-
* each subclass's `formatActiveValue` hook.
|
|
71
|
-
*/
|
|
72
|
-
export type FilterIndicatorHandler = (value: string, filter: Filter) => string
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Base class for table filters. Filters live as children of `Table` and
|
|
76
|
-
* surface as form controls in the table's header bar. Their values are
|
|
77
|
-
* carried through the URL query (`?status=published&featured=1`) and
|
|
78
|
-
* applied to the underlying ORM query for `Table.records`.
|
|
79
|
-
*/
|
|
80
|
-
export abstract class Filter extends Element {
|
|
81
|
-
readonly name: string
|
|
82
|
-
protected _label?: string
|
|
83
|
-
protected _value?: string
|
|
84
|
-
protected _queryFn?: FilterQueryHandler
|
|
85
|
-
protected _placeholder?: string
|
|
86
|
-
protected _indicatorFn?: FilterIndicatorHandler
|
|
87
|
-
|
|
88
|
-
protected constructor(name: string) {
|
|
89
|
-
super()
|
|
90
|
-
this.name = name
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
label(l: string): this { this._label = l; return this }
|
|
94
|
-
|
|
95
|
-
/** Override the placeholder shown when no value is selected. */
|
|
96
|
-
placeholder(p: string): this { this._placeholder = p; return this }
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Override the default `where(name, value)` clause this filter
|
|
100
|
-
* contributes to the ORM query. Receives the current `ModelQuery` plus
|
|
101
|
-
* the active value and must return the modified query.
|
|
102
|
-
*/
|
|
103
|
-
query(fn: FilterQueryHandler): this { this._queryFn = fn; return this }
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Override the active-filter indicator pill text. Accepts either a
|
|
107
|
-
* literal string or a `(value, filter) => string` callback. The default
|
|
108
|
-
* indicator is `"<label>: <displayValue>"`, where `<displayValue>` comes
|
|
109
|
-
* from each subclass's `formatActiveValue(value)` hook (e.g. SelectFilter
|
|
110
|
-
* maps `'draft'` → its option label `'Draft'`).
|
|
111
|
-
*/
|
|
112
|
-
indicator(fn: string | FilterIndicatorHandler): this {
|
|
113
|
-
this._indicatorFn = typeof fn === 'function' ? fn : () => fn
|
|
114
|
-
return this
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/** Render-time setter: framework calls this with the URL-supplied value. */
|
|
118
|
-
withValue(v: string): this { this._value = v; return this }
|
|
119
|
-
|
|
120
|
-
// ─── Getters ──────────────────────────────────────────
|
|
121
|
-
|
|
122
|
-
getLabel(): string {
|
|
123
|
-
return this._label ?? this.name.charAt(0).toUpperCase() + this.name.slice(1)
|
|
124
|
-
}
|
|
125
|
-
getValue(): string | undefined { return this._value }
|
|
126
|
-
getPlaceholder(): string | undefined { return this._placeholder }
|
|
127
|
-
getQuery(): FilterQueryHandler | undefined { return this._queryFn }
|
|
128
|
-
|
|
129
|
-
abstract getKind(): FilterKind
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Subclass hook — render the active value as a human-readable string for
|
|
133
|
-
* the indicator pill. Default is the raw value; SelectFilter/TernaryFilter
|
|
134
|
-
* map to option labels, BooleanFilter to "Yes"/"No", DateRangeFilter to a
|
|
135
|
-
* `from → to` range. Override when the URL value isn't user-friendly.
|
|
136
|
-
*/
|
|
137
|
-
protected formatActiveValue(value: string): string { return value }
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Render the indicator pill text. Returns `undefined` when no value is
|
|
141
|
-
* active so the renderer can skip the pill entirely. Honours the user's
|
|
142
|
-
* `indicator(fn)` override when supplied.
|
|
143
|
-
*/
|
|
144
|
-
getIndicator(): string | undefined {
|
|
145
|
-
const value = this._value
|
|
146
|
-
if (value === undefined || value === '') return undefined
|
|
147
|
-
if (this._indicatorFn) return this._indicatorFn(value, this)
|
|
148
|
-
return `${this.getLabel()}: ${this.formatActiveValue(value)}`
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// ─── Element contract ────────────────────────────────
|
|
152
|
-
|
|
153
|
-
getType(): string { return 'filter' }
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Sync by default — `kind: 'form'` filters override to async because they
|
|
157
|
-
* need to resolve their inner schema. The optional `_ctx` parameter is
|
|
158
|
-
* threaded by `resolveSchema` so subclasses can read the active user /
|
|
159
|
-
* record / values when building their meta. Existing typed filters
|
|
160
|
-
* (Select / Boolean / Ternary / DateRange / MultiSelect / Trashed)
|
|
161
|
-
* ignore the parameter.
|
|
162
|
-
*/
|
|
163
|
-
override toMeta(_ctx?: RenderContext): FilterMeta | Promise<FilterMeta> {
|
|
164
|
-
return this.buildBaseMeta()
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Shared meta construction for `Filter` subclasses — exposed as a
|
|
169
|
-
* protected helper so async subclasses (e.g. `FormFilter`) can pull
|
|
170
|
-
* the same shape without spreading a `Promise<FilterMeta>` union.
|
|
171
|
-
*/
|
|
172
|
-
protected buildBaseMeta(): FilterMeta {
|
|
173
|
-
const indicator = this.getIndicator()
|
|
174
|
-
return {
|
|
175
|
-
type: 'filter',
|
|
176
|
-
name: this.name,
|
|
177
|
-
label: this.getLabel(),
|
|
178
|
-
kind: this.getKind(),
|
|
179
|
-
...(this._value !== undefined ? { value: this._value } : {}),
|
|
180
|
-
...(this._placeholder !== undefined ? { placeholder: this._placeholder } : {}),
|
|
181
|
-
...(indicator !== undefined ? { indicator } : {}),
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|