@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,149 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { TrashedFilter } from './TrashedFilter.js'
|
|
5
|
-
import type { FilterMeta } from './Filter.js'
|
|
6
|
-
import { Table } from '../elements/Table.js'
|
|
7
|
-
import { Resource } from '../Resource.js'
|
|
8
|
-
import { applyTableDefaults } from '../defaultPages.js'
|
|
9
|
-
import type { ModelQuery } from '../orm/modelDefaults.js'
|
|
10
|
-
|
|
11
|
-
/** Stub query that records which trashed-scope methods got called. */
|
|
12
|
-
function makeStubQuery() {
|
|
13
|
-
const calls: string[] = []
|
|
14
|
-
const q = {
|
|
15
|
-
where: () => q,
|
|
16
|
-
orWhere: () => q,
|
|
17
|
-
orderBy: () => q,
|
|
18
|
-
paginate: async () => ({ data: [], total: 0 }),
|
|
19
|
-
withTrashed: () => { calls.push('withTrashed'); return q },
|
|
20
|
-
onlyTrashed: () => { calls.push('onlyTrashed'); return q },
|
|
21
|
-
} as unknown as ModelQuery
|
|
22
|
-
return { q, calls }
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
describe('TrashedFilter', () => {
|
|
26
|
-
it('default name is "trashed"', () => {
|
|
27
|
-
const f = TrashedFilter.make()
|
|
28
|
-
assert.equal(f.name, 'trashed')
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('accepts a custom URL key (e.g. archived)', () => {
|
|
32
|
-
const f = TrashedFilter.make('archived')
|
|
33
|
-
assert.equal(f.name, 'archived')
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('renders as a select kind with two options + "Active" placeholder', () => {
|
|
37
|
-
const meta = TrashedFilter.make().toMeta()
|
|
38
|
-
assert.equal(meta.kind, 'select')
|
|
39
|
-
assert.equal(meta.placeholder, 'Active')
|
|
40
|
-
assert.deepEqual(meta.options, [
|
|
41
|
-
{ value: 'withTrashed', label: 'With trashed' },
|
|
42
|
-
{ value: 'onlyTrashed', label: 'Only trashed' },
|
|
43
|
-
])
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
it('value=withTrashed calls query.withTrashed()', () => {
|
|
47
|
-
const f = TrashedFilter.make()
|
|
48
|
-
const handler = f.getQuery()!
|
|
49
|
-
const { q, calls } = makeStubQuery()
|
|
50
|
-
handler(q, 'withTrashed')
|
|
51
|
-
assert.deepEqual(calls, ['withTrashed'])
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
it('value=onlyTrashed calls query.onlyTrashed()', () => {
|
|
55
|
-
const f = TrashedFilter.make()
|
|
56
|
-
const handler = f.getQuery()!
|
|
57
|
-
const { q, calls } = makeStubQuery()
|
|
58
|
-
handler(q, 'onlyTrashed')
|
|
59
|
-
assert.deepEqual(calls, ['onlyTrashed'])
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
it('empty / unknown value is a no-op (default scope already excludes trashed)', () => {
|
|
63
|
-
const f = TrashedFilter.make()
|
|
64
|
-
const handler = f.getQuery()!
|
|
65
|
-
const { q, calls } = makeStubQuery()
|
|
66
|
-
handler(q, '')
|
|
67
|
-
handler(q, 'active')
|
|
68
|
-
handler(q, 'garbage')
|
|
69
|
-
assert.deepEqual(calls, [])
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
it('gracefully no-ops when query lacks withTrashed (e.g. non-soft-delete query)', () => {
|
|
73
|
-
const f = TrashedFilter.make()
|
|
74
|
-
const handler = f.getQuery()!
|
|
75
|
-
const bareQ = {
|
|
76
|
-
where: () => bareQ,
|
|
77
|
-
orWhere: () => bareQ,
|
|
78
|
-
orderBy: () => bareQ,
|
|
79
|
-
paginate: async () => ({ data: [], total: 0 }),
|
|
80
|
-
} as unknown as ModelQuery
|
|
81
|
-
const result = handler(bareQ, 'withTrashed')
|
|
82
|
-
assert.equal(result, bareQ, 'returns the query unchanged when withTrashed is absent')
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('label can be overridden via .label()', () => {
|
|
86
|
-
const f = TrashedFilter.make().label('Archive status')
|
|
87
|
-
assert.equal(f.toMeta().label, 'Archive status')
|
|
88
|
-
})
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
describe('applyTableDefaults — TrashedFilter auto-injection', () => {
|
|
92
|
-
it('auto-injects TrashedFilter when Resource.softDeletes = true', () => {
|
|
93
|
-
class R extends Resource {
|
|
94
|
-
static override label = 'Posts'
|
|
95
|
-
static override softDeletes = true
|
|
96
|
-
}
|
|
97
|
-
const table = R.table(Table.make())
|
|
98
|
-
applyTableDefaults(R, table)
|
|
99
|
-
const filters = table.getFilters()
|
|
100
|
-
assert.equal(filters.length, 1)
|
|
101
|
-
assert.ok(filters[0] instanceof TrashedFilter)
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
it('does not double-inject when the user already added a TrashedFilter', () => {
|
|
105
|
-
class R extends Resource {
|
|
106
|
-
static override label = 'Posts'
|
|
107
|
-
static override softDeletes = true
|
|
108
|
-
static override table(t: Table): Table {
|
|
109
|
-
return t.filters([TrashedFilter.make().label('Custom label')])
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
const table = R.table(Table.make())
|
|
113
|
-
applyTableDefaults(R, table)
|
|
114
|
-
const filters = table.getFilters()
|
|
115
|
-
assert.equal(filters.length, 1)
|
|
116
|
-
const meta = filters[0]!.toMeta() as FilterMeta
|
|
117
|
-
assert.equal(meta.label, 'Custom label',
|
|
118
|
-
'user-supplied filter wins over the auto-injected one')
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
it('does not inject when Resource.softDeletes = false (default)', () => {
|
|
122
|
-
class R extends Resource { static override label = 'Posts' }
|
|
123
|
-
const table = R.table(Table.make())
|
|
124
|
-
applyTableDefaults(R, table)
|
|
125
|
-
assert.equal(table.getFilters().length, 0)
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
it('preserves user-supplied non-trashed filters alongside the auto-injected one', async () => {
|
|
129
|
-
const { SelectFilter } = await import('./SelectFilter.js')
|
|
130
|
-
class R extends Resource {
|
|
131
|
-
static override label = 'Posts'
|
|
132
|
-
static override softDeletes = true
|
|
133
|
-
static override table(t: Table): Table {
|
|
134
|
-
return t.filters([
|
|
135
|
-
SelectFilter.make('status').options([
|
|
136
|
-
{ value: 'draft', label: 'Draft' },
|
|
137
|
-
{ value: 'published', label: 'Published' },
|
|
138
|
-
]),
|
|
139
|
-
])
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
const table = R.table(Table.make())
|
|
143
|
-
applyTableDefaults(R, table)
|
|
144
|
-
const filters = table.getFilters()
|
|
145
|
-
assert.equal(filters.length, 2)
|
|
146
|
-
assert.equal(filters[0]!.name, 'status')
|
|
147
|
-
assert.ok(filters[1] instanceof TrashedFilter)
|
|
148
|
-
})
|
|
149
|
-
})
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { Filter, type FilterKind, type FilterMeta } from './Filter.js'
|
|
2
|
-
import type { ModelQuery } from '../orm/modelDefaults.js'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Plan #13 — three-state filter for soft-deleted resources.
|
|
6
|
-
*
|
|
7
|
-
* `''` (default) — active records only (default scope already
|
|
8
|
-
* excludes trashed; no clause added)
|
|
9
|
-
* `'withTrashed'` — active + trashed records together
|
|
10
|
-
* `'onlyTrashed'` — trashed records only
|
|
11
|
-
*
|
|
12
|
-
* Auto-injected on `ListPage` for resources with `softDeletes = true`
|
|
13
|
-
* unless the user attached one explicitly. URL key defaults to
|
|
14
|
-
* `?trashed=…`; rename via `TrashedFilter.make('archived')` for
|
|
15
|
-
* resources using a different column name (the URL key, not the
|
|
16
|
-
* predicate path — the predicate always calls `query.withTrashed() /
|
|
17
|
-
* onlyTrashed()` regardless of the filter's name).
|
|
18
|
-
*
|
|
19
|
-
* Renders as a `'select'` kind so the existing select-renderer handles
|
|
20
|
-
* it without changes. The default `query()` handler short-circuits to
|
|
21
|
-
* the running ORM query when `withTrashed / onlyTrashed` aren't on the
|
|
22
|
-
* `ModelQuery` (e.g. during testing with a stub query) — production
|
|
23
|
-
* paths always have them when the model has `softDeletes = true`.
|
|
24
|
-
*/
|
|
25
|
-
export class TrashedFilter extends Filter {
|
|
26
|
-
static make(name = 'trashed'): TrashedFilter {
|
|
27
|
-
const f = new TrashedFilter(name)
|
|
28
|
-
f.query((q: ModelQuery, value: string) => {
|
|
29
|
-
if (value === 'withTrashed' && typeof q.withTrashed === 'function') {
|
|
30
|
-
return q.withTrashed()
|
|
31
|
-
}
|
|
32
|
-
if (value === 'onlyTrashed' && typeof q.onlyTrashed === 'function') {
|
|
33
|
-
return q.onlyTrashed()
|
|
34
|
-
}
|
|
35
|
-
return q
|
|
36
|
-
})
|
|
37
|
-
return f
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
override getKind(): FilterKind { return 'select' }
|
|
41
|
-
|
|
42
|
-
override toMeta(): FilterMeta {
|
|
43
|
-
return {
|
|
44
|
-
...this.buildBaseMeta(),
|
|
45
|
-
// Default-scope value (empty / "active only") is implicit — no
|
|
46
|
-
// option needed. Users select withTrashed / onlyTrashed to
|
|
47
|
-
// broaden; clearing the select returns to active-only.
|
|
48
|
-
options: [
|
|
49
|
-
{ value: 'withTrashed', label: 'With trashed' },
|
|
50
|
-
{ value: 'onlyTrashed', label: 'Only trashed' },
|
|
51
|
-
],
|
|
52
|
-
placeholder: this.getPlaceholder() ?? 'Active',
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { Constraint, type ConstraintOperator, type ConstraintOperatorName } from './Constraint.js'
|
|
2
|
-
import type { ModelQuery } from '../../orm/modelDefaults.js'
|
|
3
|
-
|
|
4
|
-
const OPERATORS: ConstraintOperator[] = [
|
|
5
|
-
{ name: 'isTrue', label: 'Is true', valueKind: 'none' },
|
|
6
|
-
{ name: 'isFalse', label: 'Is false', valueKind: 'none' },
|
|
7
|
-
{ name: 'isEmpty', label: 'Is empty', valueKind: 'none' },
|
|
8
|
-
{ name: 'isNotEmpty', label: 'Is not empty', valueKind: 'none' },
|
|
9
|
-
]
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Boolean-column constraint. No value input — every operator is binary.
|
|
13
|
-
* `isEmpty / isNotEmpty` exist for nullable boolean columns and rely on
|
|
14
|
-
* `ModelQuery.whereNull?` (mirrors `TernaryFilter`'s blank bucket).
|
|
15
|
-
*/
|
|
16
|
-
export class BooleanConstraint extends Constraint {
|
|
17
|
-
static make(name: string): BooleanConstraint { return new BooleanConstraint(name) }
|
|
18
|
-
|
|
19
|
-
override getOperators(): ConstraintOperator[] { return OPERATORS }
|
|
20
|
-
|
|
21
|
-
override apply(query: ModelQuery, operator: ConstraintOperatorName, _value: unknown): ModelQuery {
|
|
22
|
-
switch (operator) {
|
|
23
|
-
case 'isTrue': return query.where(this.name, '=', true)
|
|
24
|
-
case 'isFalse': return query.where(this.name, '=', false)
|
|
25
|
-
case 'isEmpty':
|
|
26
|
-
return typeof query.whereNull === 'function' ? query.whereNull(this.name) : query.where(this.name, '=', null)
|
|
27
|
-
case 'isNotEmpty': return query.where(this.name, '!=', null)
|
|
28
|
-
default: return query
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import type { ModelQuery } from '../../orm/modelDefaults.js'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Wire-side discriminator for the value input the renderer mounts under
|
|
5
|
-
* a constraint row. `'none'` means the operator implies no value (e.g.
|
|
6
|
-
* `isEmpty / isNotEmpty / isTrue / isFalse`) — the renderer hides the
|
|
7
|
-
* value input entirely.
|
|
8
|
-
*/
|
|
9
|
-
export type ConstraintValueKind =
|
|
10
|
-
| 'text'
|
|
11
|
-
| 'number'
|
|
12
|
-
| 'date'
|
|
13
|
-
| 'dateTime'
|
|
14
|
-
| 'select'
|
|
15
|
-
| 'multiSelect'
|
|
16
|
-
| 'boolean'
|
|
17
|
-
| 'numberRange'
|
|
18
|
-
| 'dateRange'
|
|
19
|
-
| 'none'
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Canonical operator names a constraint advertises. The set is wider than
|
|
23
|
-
* any single subclass returns — each `Constraint` exposes its valid subset
|
|
24
|
-
* via `getOperators()`. Storage / URL value rules reference operators by
|
|
25
|
-
* this string.
|
|
26
|
-
*/
|
|
27
|
-
export type ConstraintOperatorName =
|
|
28
|
-
| 'equals' | 'notEquals'
|
|
29
|
-
| 'contains' | 'notContains' | 'startsWith' | 'endsWith'
|
|
30
|
-
| 'lt' | 'lte' | 'gt' | 'gte' | 'between'
|
|
31
|
-
| 'before' | 'after' | 'dateBetween'
|
|
32
|
-
| 'in' | 'notIn'
|
|
33
|
-
| 'isEmpty' | 'isNotEmpty'
|
|
34
|
-
| 'isTrue' | 'isFalse'
|
|
35
|
-
|
|
36
|
-
/** A single operator option with renderer-side label + value-input kind. */
|
|
37
|
-
export interface ConstraintOperator {
|
|
38
|
-
name: ConstraintOperatorName
|
|
39
|
-
label: string
|
|
40
|
-
valueKind: ConstraintValueKind
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** Wire shape consumed by the renderer to mount a constraint row. */
|
|
44
|
-
export interface ConstraintMeta {
|
|
45
|
-
name: string
|
|
46
|
-
label: string
|
|
47
|
-
operators: ConstraintOperator[]
|
|
48
|
-
options?: Array<{ value: string; label: string }>
|
|
49
|
-
/** Default operator pre-selected when the user adds a fresh row. */
|
|
50
|
-
defaultOperator?: ConstraintOperatorName
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Base class for `QueryBuilder` constraints — declares which column the
|
|
55
|
-
* user can query, which operators they get, and how to translate a
|
|
56
|
-
* `(operator, value)` pair into ORM `where` clauses.
|
|
57
|
-
*
|
|
58
|
-
* Subclasses are typed value-objects (NOT `Element`) — they live as
|
|
59
|
-
* children of `QueryBuilderFilter.constraints([...])`, never standalone.
|
|
60
|
-
*
|
|
61
|
-
* The `apply()` contract takes a `ModelQuery` and returns it with any
|
|
62
|
-
* number of `.where()` calls chained on. v1 dispatches every rule through
|
|
63
|
-
* `.where()` (AND-root only) — see `QueryBuilderFilter` for the why.
|
|
64
|
-
*/
|
|
65
|
-
export abstract class Constraint {
|
|
66
|
-
readonly name: string
|
|
67
|
-
protected _label?: string
|
|
68
|
-
|
|
69
|
-
protected constructor(name: string) {
|
|
70
|
-
this.name = name
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
label(l: string): this { this._label = l; return this }
|
|
74
|
-
|
|
75
|
-
getLabel(): string {
|
|
76
|
-
return this._label ?? this.name.charAt(0).toUpperCase() + this.name.slice(1)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** Operators this constraint advertises. Subclasses override. */
|
|
80
|
-
abstract getOperators(): ConstraintOperator[]
|
|
81
|
-
|
|
82
|
-
/** Default operator pre-selected on a fresh row. Defaults to first. */
|
|
83
|
-
getDefaultOperator(): ConstraintOperatorName {
|
|
84
|
-
const ops = this.getOperators()
|
|
85
|
-
return ops[0]?.name ?? 'equals'
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/** Optional select-style options surfaced under `meta.options`. */
|
|
89
|
-
getOptions(): Array<{ value: string; label: string }> | undefined { return undefined }
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Translate a single rule into ORM `where` clauses. Returns the modified
|
|
93
|
-
* query. Always called inside the QueryBuilder's AND-root pipeline in
|
|
94
|
-
* v1 — multi-clause operators (e.g. `between` → two `where` calls) are
|
|
95
|
-
* naturally AND'd by the running pipeline.
|
|
96
|
-
*
|
|
97
|
-
* Implementations should silently no-op on malformed values (return `q`
|
|
98
|
-
* unchanged). Throwing would abort the whole list query.
|
|
99
|
-
*/
|
|
100
|
-
abstract apply(query: ModelQuery, operator: ConstraintOperatorName, value: unknown): ModelQuery
|
|
101
|
-
|
|
102
|
-
/** Wire shape consumed by the React renderer. */
|
|
103
|
-
toMeta(): ConstraintMeta {
|
|
104
|
-
const ops = this.getOperators()
|
|
105
|
-
const out: ConstraintMeta = {
|
|
106
|
-
name: this.name,
|
|
107
|
-
label: this.getLabel(),
|
|
108
|
-
operators: ops,
|
|
109
|
-
defaultOperator: this.getDefaultOperator(),
|
|
110
|
-
}
|
|
111
|
-
const options = this.getOptions()
|
|
112
|
-
if (options) out.options = options
|
|
113
|
-
return out
|
|
114
|
-
}
|
|
115
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { Constraint, type ConstraintOperator, type ConstraintOperatorName } from './Constraint.js'
|
|
2
|
-
import type { ModelQuery } from '../../orm/modelDefaults.js'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Date-column constraint. `includesTime()` flips the value inputs to
|
|
6
|
-
* `datetime-local` and the wire `valueKind` to `'dateTime'`.
|
|
7
|
-
*
|
|
8
|
-
* Values arrive as ISO strings (`'2026-05-04'` / `'2026-05-04T13:00'`) and
|
|
9
|
-
* are passed through to the ORM as-is — Prisma / SQLite / MySQL all accept
|
|
10
|
-
* ISO strings on date columns.
|
|
11
|
-
*/
|
|
12
|
-
export class DateConstraint extends Constraint {
|
|
13
|
-
static make(name: string): DateConstraint { return new DateConstraint(name) }
|
|
14
|
-
|
|
15
|
-
private _includesTime = false
|
|
16
|
-
|
|
17
|
-
includesTime(v = true): this { this._includesTime = v; return this }
|
|
18
|
-
|
|
19
|
-
override getOperators(): ConstraintOperator[] {
|
|
20
|
-
const kind = this._includesTime ? 'dateTime' : 'date'
|
|
21
|
-
const range = this._includesTime ? 'dateTime' : 'dateRange'
|
|
22
|
-
return [
|
|
23
|
-
{ name: 'equals', label: 'On', valueKind: kind },
|
|
24
|
-
{ name: 'before', label: 'Before', valueKind: kind },
|
|
25
|
-
{ name: 'after', label: 'After', valueKind: kind },
|
|
26
|
-
{ name: 'dateBetween', label: 'Between', valueKind: range },
|
|
27
|
-
{ name: 'isEmpty', label: 'Is empty', valueKind: 'none' },
|
|
28
|
-
{ name: 'isNotEmpty', label: 'Is not empty', valueKind: 'none' },
|
|
29
|
-
]
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
override apply(query: ModelQuery, operator: ConstraintOperatorName, value: unknown): ModelQuery {
|
|
33
|
-
if (operator === 'isEmpty') {
|
|
34
|
-
return typeof query.whereNull === 'function' ? query.whereNull(this.name) : query.where(this.name, '=', null)
|
|
35
|
-
}
|
|
36
|
-
if (operator === 'isNotEmpty') {
|
|
37
|
-
return query.where(this.name, '!=', null)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (operator === 'dateBetween') {
|
|
41
|
-
const [from, to] = parseDatePair(value)
|
|
42
|
-
if (from) query = query.where(this.name, '>=', from)
|
|
43
|
-
if (to) query = query.where(this.name, '<=', to)
|
|
44
|
-
return query
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const v = parseDate(value)
|
|
48
|
-
if (v === undefined) return query
|
|
49
|
-
|
|
50
|
-
switch (operator) {
|
|
51
|
-
case 'equals': return query.where(this.name, '=', v)
|
|
52
|
-
case 'before': return query.where(this.name, '<', v)
|
|
53
|
-
case 'after': return query.where(this.name, '>', v)
|
|
54
|
-
default: return query
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function parseDate(v: unknown): string | undefined {
|
|
60
|
-
if (v === null || v === undefined || v === '') return undefined
|
|
61
|
-
return String(v)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function parseDatePair(v: unknown): [string | undefined, string | undefined] {
|
|
65
|
-
if (Array.isArray(v)) {
|
|
66
|
-
return [parseDate(v[0]), parseDate(v[1])]
|
|
67
|
-
}
|
|
68
|
-
return [undefined, undefined]
|
|
69
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { Constraint, type ConstraintOperator, type ConstraintOperatorName } from './Constraint.js'
|
|
2
|
-
import type { ModelQuery } from '../../orm/modelDefaults.js'
|
|
3
|
-
|
|
4
|
-
const OPERATORS: ConstraintOperator[] = [
|
|
5
|
-
{ name: 'equals', label: 'Equals', valueKind: 'number' },
|
|
6
|
-
{ name: 'notEquals', label: 'Does not equal', valueKind: 'number' },
|
|
7
|
-
{ name: 'gt', label: 'Greater than', valueKind: 'number' },
|
|
8
|
-
{ name: 'gte', label: 'Greater or equal', valueKind: 'number' },
|
|
9
|
-
{ name: 'lt', label: 'Less than', valueKind: 'number' },
|
|
10
|
-
{ name: 'lte', label: 'Less or equal', valueKind: 'number' },
|
|
11
|
-
{ name: 'between', label: 'Between', valueKind: 'numberRange' },
|
|
12
|
-
{ name: 'isEmpty', label: 'Is empty', valueKind: 'none' },
|
|
13
|
-
{ name: 'isNotEmpty', label: 'Is not empty', valueKind: 'none' },
|
|
14
|
-
]
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Numeric-column constraint. `between` takes a `[min, max]` tuple — both
|
|
18
|
-
* sides optional, missing side skipped (mirrors `DateRangeFilter`).
|
|
19
|
-
*/
|
|
20
|
-
export class NumberConstraint extends Constraint {
|
|
21
|
-
static make(name: string): NumberConstraint { return new NumberConstraint(name) }
|
|
22
|
-
|
|
23
|
-
override getOperators(): ConstraintOperator[] { return OPERATORS }
|
|
24
|
-
|
|
25
|
-
override apply(query: ModelQuery, operator: ConstraintOperatorName, value: unknown): ModelQuery {
|
|
26
|
-
if (operator === 'isEmpty') {
|
|
27
|
-
return typeof query.whereNull === 'function' ? query.whereNull(this.name) : query.where(this.name, '=', null)
|
|
28
|
-
}
|
|
29
|
-
if (operator === 'isNotEmpty') {
|
|
30
|
-
return query.where(this.name, '!=', null)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (operator === 'between') {
|
|
34
|
-
const [min, max] = parseNumberPair(value)
|
|
35
|
-
if (min !== undefined) query = query.where(this.name, '>=', min)
|
|
36
|
-
if (max !== undefined) query = query.where(this.name, '<=', max)
|
|
37
|
-
return query
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const n = parseNumber(value)
|
|
41
|
-
if (n === undefined) return query
|
|
42
|
-
|
|
43
|
-
switch (operator) {
|
|
44
|
-
case 'equals': return query.where(this.name, '=', n)
|
|
45
|
-
case 'notEquals': return query.where(this.name, '!=', n)
|
|
46
|
-
case 'gt': return query.where(this.name, '>', n)
|
|
47
|
-
case 'gte': return query.where(this.name, '>=', n)
|
|
48
|
-
case 'lt': return query.where(this.name, '<', n)
|
|
49
|
-
case 'lte': return query.where(this.name, '<=', n)
|
|
50
|
-
default: return query
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function parseNumber(v: unknown): number | undefined {
|
|
56
|
-
if (v === null || v === undefined || v === '') return undefined
|
|
57
|
-
const n = Number(v)
|
|
58
|
-
return Number.isFinite(n) ? n : undefined
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function parseNumberPair(v: unknown): [number | undefined, number | undefined] {
|
|
62
|
-
if (Array.isArray(v)) {
|
|
63
|
-
return [parseNumber(v[0]), parseNumber(v[1])]
|
|
64
|
-
}
|
|
65
|
-
return [undefined, undefined]
|
|
66
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { Constraint, type ConstraintOperator, type ConstraintOperatorName } from './Constraint.js'
|
|
2
|
-
import type { ModelQuery } from '../../orm/modelDefaults.js'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Enum-column constraint. Values come from a fixed `options([...])` list;
|
|
6
|
-
* the renderer mounts a single-select for `equals / notEquals` and a
|
|
7
|
-
* multi-select chip stack for `in / notIn`.
|
|
8
|
-
*/
|
|
9
|
-
export class SelectConstraint extends Constraint {
|
|
10
|
-
static make(name: string): SelectConstraint { return new SelectConstraint(name) }
|
|
11
|
-
|
|
12
|
-
private _options: Array<{ value: string; label: string }> = []
|
|
13
|
-
|
|
14
|
-
options(opts: Array<{ value: string; label: string }>): this {
|
|
15
|
-
this._options = opts
|
|
16
|
-
return this
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
override getOptions(): Array<{ value: string; label: string }> | undefined {
|
|
20
|
-
return this._options.length > 0 ? this._options : undefined
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
override getOperators(): ConstraintOperator[] {
|
|
24
|
-
return [
|
|
25
|
-
{ name: 'equals', label: 'Equals', valueKind: 'select' },
|
|
26
|
-
{ name: 'notEquals', label: 'Does not equal', valueKind: 'select' },
|
|
27
|
-
{ name: 'in', label: 'Is one of', valueKind: 'multiSelect' },
|
|
28
|
-
{ name: 'notIn', label: 'Is not one of', valueKind: 'multiSelect' },
|
|
29
|
-
{ name: 'isEmpty', label: 'Is empty', valueKind: 'none' },
|
|
30
|
-
{ name: 'isNotEmpty', label: 'Is not empty', valueKind: 'none' },
|
|
31
|
-
]
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
override apply(query: ModelQuery, operator: ConstraintOperatorName, value: unknown): ModelQuery {
|
|
35
|
-
if (operator === 'isEmpty') {
|
|
36
|
-
return typeof query.whereNull === 'function' ? query.whereNull(this.name) : query.where(this.name, '=', null)
|
|
37
|
-
}
|
|
38
|
-
if (operator === 'isNotEmpty') {
|
|
39
|
-
return query.where(this.name, '!=', null)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (operator === 'in' || operator === 'notIn') {
|
|
43
|
-
const list = parseList(value)
|
|
44
|
-
if (list.length === 0) return query
|
|
45
|
-
return query.where(this.name, operator === 'in' ? 'IN' : 'NOT IN', list)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const v = parseScalar(value)
|
|
49
|
-
if (v === undefined) return query
|
|
50
|
-
|
|
51
|
-
switch (operator) {
|
|
52
|
-
case 'equals': return query.where(this.name, '=', v)
|
|
53
|
-
case 'notEquals': return query.where(this.name, '!=', v)
|
|
54
|
-
default: return query
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function parseScalar(v: unknown): string | undefined {
|
|
60
|
-
if (v === null || v === undefined || v === '') return undefined
|
|
61
|
-
return String(v)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function parseList(v: unknown): string[] {
|
|
65
|
-
if (!Array.isArray(v)) return []
|
|
66
|
-
const out: string[] = []
|
|
67
|
-
for (const item of v) {
|
|
68
|
-
if (item === null || item === undefined || item === '') continue
|
|
69
|
-
out.push(String(item))
|
|
70
|
-
}
|
|
71
|
-
return out
|
|
72
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { Constraint, type ConstraintOperator, type ConstraintOperatorName } from './Constraint.js'
|
|
2
|
-
import type { ModelQuery } from '../../orm/modelDefaults.js'
|
|
3
|
-
|
|
4
|
-
const OPERATORS: ConstraintOperator[] = [
|
|
5
|
-
{ name: 'contains', label: 'Contains', valueKind: 'text' },
|
|
6
|
-
{ name: 'notContains', label: 'Does not contain', valueKind: 'text' },
|
|
7
|
-
{ name: 'equals', label: 'Equals', valueKind: 'text' },
|
|
8
|
-
{ name: 'notEquals', label: 'Does not equal', valueKind: 'text' },
|
|
9
|
-
{ name: 'startsWith', label: 'Starts with', valueKind: 'text' },
|
|
10
|
-
{ name: 'endsWith', label: 'Ends with', valueKind: 'text' },
|
|
11
|
-
{ name: 'isEmpty', label: 'Is empty', valueKind: 'none' },
|
|
12
|
-
{ name: 'isNotEmpty', label: 'Is not empty', valueKind: 'none' },
|
|
13
|
-
]
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* String-column constraint. Default operator is `'contains'` because text
|
|
17
|
-
* filters in admin tables almost always want substring search rather than
|
|
18
|
-
* exact match.
|
|
19
|
-
*
|
|
20
|
-
* `isEmpty / isNotEmpty` rely on `ModelQuery.whereNull?` (added for
|
|
21
|
-
* `TernaryFilter`). When unavailable they fall back to `where(name, '')`
|
|
22
|
-
* which still catches the common case for non-NULL string columns.
|
|
23
|
-
*/
|
|
24
|
-
export class TextConstraint extends Constraint {
|
|
25
|
-
static make(name: string): TextConstraint { return new TextConstraint(name) }
|
|
26
|
-
|
|
27
|
-
override getOperators(): ConstraintOperator[] { return OPERATORS }
|
|
28
|
-
|
|
29
|
-
override getDefaultOperator(): ConstraintOperatorName { return 'contains' }
|
|
30
|
-
|
|
31
|
-
override apply(query: ModelQuery, operator: ConstraintOperatorName, value: unknown): ModelQuery {
|
|
32
|
-
if (operator === 'isEmpty') return whereNullOrEmpty(query, this.name)
|
|
33
|
-
if (operator === 'isNotEmpty') return whereNotNullAndNotEmpty(query, this.name)
|
|
34
|
-
|
|
35
|
-
const v = value === null || value === undefined ? '' : String(value)
|
|
36
|
-
if (v === '') return query
|
|
37
|
-
|
|
38
|
-
switch (operator) {
|
|
39
|
-
case 'contains': return query.where(this.name, 'LIKE', `%${escapeLike(v)}%`)
|
|
40
|
-
case 'notContains': return query.where(this.name, 'NOT LIKE', `%${escapeLike(v)}%`)
|
|
41
|
-
case 'startsWith': return query.where(this.name, 'LIKE', `${escapeLike(v)}%`)
|
|
42
|
-
case 'endsWith': return query.where(this.name, 'LIKE', `%${escapeLike(v)}`)
|
|
43
|
-
case 'equals': return query.where(this.name, '=', v)
|
|
44
|
-
case 'notEquals': return query.where(this.name, '!=', v)
|
|
45
|
-
default: return query
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function whereNullOrEmpty(q: ModelQuery, col: string): ModelQuery {
|
|
51
|
-
if (typeof q.whereNull === 'function') {
|
|
52
|
-
return q.whereNull(col).orWhere(col, '=', '')
|
|
53
|
-
}
|
|
54
|
-
return q.where(col, '=', '')
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function whereNotNullAndNotEmpty(q: ModelQuery, col: string): ModelQuery {
|
|
58
|
-
return q.where(col, '!=', '')
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** Escape SQL `LIKE` wildcards in user input. Mirrors `unique` validator. */
|
|
62
|
-
function escapeLike(input: string): string {
|
|
63
|
-
return input.replace(/\\/g, '\\\\').replace(/%/g, '\\%').replace(/_/g, '\\_')
|
|
64
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export {
|
|
2
|
-
Constraint,
|
|
3
|
-
type ConstraintMeta,
|
|
4
|
-
type ConstraintOperator,
|
|
5
|
-
type ConstraintOperatorName,
|
|
6
|
-
type ConstraintValueKind,
|
|
7
|
-
} from './Constraint.js'
|
|
8
|
-
export { TextConstraint } from './TextConstraint.js'
|
|
9
|
-
export { NumberConstraint } from './NumberConstraint.js'
|
|
10
|
-
export { DateConstraint } from './DateConstraint.js'
|
|
11
|
-
export { SelectConstraint } from './SelectConstraint.js'
|
|
12
|
-
export { BooleanConstraint } from './BooleanConstraint.js'
|
package/src/icons/index.ts
DELETED