@pilotiq/pilotiq 0.24.1 → 0.24.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +57 -0
- package/boost/guidelines.md +571 -0
- package/boost/skills/pilotiq-actions/SKILL.md +49 -0
- package/boost/skills/pilotiq-actions/rules/dispatch-modes.md +177 -0
- package/boost/skills/pilotiq-actions/rules/factories.md +130 -0
- package/boost/skills/pilotiq-actions/rules/visibility-and-authorization.md +125 -0
- package/boost/skills/pilotiq-fields/SKILL.md +47 -0
- package/boost/skills/pilotiq-fields/rules/field-catalog.md +288 -0
- package/boost/skills/pilotiq-fields/rules/reactive-fields.md +199 -0
- package/boost/skills/pilotiq-fields/rules/validation.md +198 -0
- package/boost/skills/pilotiq-relations/SKILL.md +47 -0
- package/boost/skills/pilotiq-relations/rules/relation-managers.md +256 -0
- package/boost/skills/pilotiq-relations/rules/repeater-relationship.md +177 -0
- package/boost/skills/pilotiq-resource/SKILL.md +61 -0
- package/boost/skills/pilotiq-resource/rules/authorization.md +242 -0
- package/boost/skills/pilotiq-resource/rules/defining-resources.md +228 -0
- package/boost/skills/pilotiq-resource/rules/page-overrides.md +296 -0
- package/dist/Pilotiq.d.ts +31 -0
- package/dist/Pilotiq.d.ts.map +1 -1
- package/dist/Pilotiq.js +3 -1
- package/dist/Pilotiq.js.map +1 -1
- package/dist/PilotiqRegistry.d.ts +13 -0
- package/dist/PilotiqRegistry.d.ts.map +1 -1
- package/dist/PilotiqRegistry.js +15 -0
- package/dist/PilotiqRegistry.js.map +1 -1
- package/dist/pageData/misc.d.ts.map +1 -1
- package/dist/pageData/misc.js +6 -0
- package/dist/pageData/misc.js.map +1 -1
- package/dist/pageData/navigation.d.ts +1 -0
- package/dist/pageData/navigation.d.ts.map +1 -1
- package/dist/pageData/navigation.js +3 -0
- package/dist/pageData/navigation.js.map +1 -1
- package/dist/pageData/relationPages.d.ts.map +1 -1
- package/dist/pageData/relationPages.js +3 -0
- package/dist/pageData/relationPages.js.map +1 -1
- package/dist/pageData/resourcePages.d.ts.map +1 -1
- package/dist/pageData/resourcePages.js +8 -0
- package/dist/pageData/resourcePages.js.map +1 -1
- package/dist/react/AppShell.d.ts +8 -0
- package/dist/react/AppShell.d.ts.map +1 -1
- package/dist/react/AppShell.js.map +1 -1
- package/dist/react/layouts/SidebarLayout.d.ts.map +1 -1
- package/dist/react/layouts/SidebarLayout.js +10 -2
- package/dist/react/layouts/SidebarLayout.js.map +1 -1
- package/dist/react/widgets/StatsOverviewRenderer.d.ts.map +1 -1
- package/dist/react/widgets/StatsOverviewRenderer.js +32 -18
- package/dist/react/widgets/StatsOverviewRenderer.js.map +1 -1
- package/dist/routes/relations.d.ts.map +1 -1
- package/dist/routes/relations.js +25 -18
- package/dist/routes/relations.js.map +1 -1
- package/dist/routes/resources.js.map +1 -1
- package/package.json +10 -5
- package/.turbo/turbo-build.log +0 -8
- package/CLAUDE.md +0 -265
- package/src/Cluster.test.ts +0 -283
- package/src/Cluster.ts +0 -83
- package/src/Column.test.ts +0 -199
- package/src/Column.ts +0 -710
- package/src/Global.test.ts +0 -367
- package/src/Global.ts +0 -169
- package/src/Page.test.ts +0 -114
- package/src/Page.ts +0 -208
- package/src/Pilotiq.perf.test.ts +0 -252
- package/src/Pilotiq.test.ts +0 -129
- package/src/Pilotiq.ts +0 -1158
- package/src/PilotiqRegistry.ts +0 -36
- package/src/PilotiqServiceProvider.ts +0 -121
- package/src/RelationManager.test.ts +0 -400
- package/src/RelationManager.ts +0 -527
- package/src/RenderHook.test.ts +0 -252
- package/src/RenderHook.ts +0 -242
- package/src/Resource.test.ts +0 -284
- package/src/Resource.ts +0 -526
- package/src/RightPanel.test.ts +0 -202
- package/src/RightPanel.ts +0 -132
- package/src/Tab.test.ts +0 -91
- package/src/Tab.ts +0 -156
- package/src/UserMenuItem.ts +0 -145
- package/src/actions/Action.test.ts +0 -2526
- package/src/actions/Action.ts +0 -1515
- package/src/actions/ActionGroup.test.ts +0 -112
- package/src/actions/ActionGroup.ts +0 -173
- package/src/actions/attachFactory.ts +0 -172
- package/src/actions/bulkFactories.ts +0 -168
- package/src/actions/crudFactories.ts +0 -220
- package/src/actions/exportFactory.ts +0 -225
- package/src/actions/factoryHelpers.ts +0 -177
- package/src/actions/importFactory.ts +0 -243
- package/src/actions/index.ts +0 -17
- package/src/actions/m2mFactories.ts +0 -193
- package/src/actions/relationFactories.ts +0 -372
- package/src/applyPageHooks.test.ts +0 -463
- package/src/applyPageHooks.ts +0 -330
- package/src/authorization.test.ts +0 -483
- package/src/breadcrumbs.test.ts +0 -238
- package/src/cells/coerce.test.ts +0 -85
- package/src/cells/coerce.ts +0 -84
- package/src/clusterPaths.ts +0 -35
- package/src/columns/BadgeColumn.test.ts +0 -54
- package/src/columns/BadgeColumn.ts +0 -32
- package/src/columns/BooleanColumn.test.ts +0 -41
- package/src/columns/BooleanColumn.ts +0 -18
- package/src/columns/ColorColumn.test.ts +0 -37
- package/src/columns/ColorColumn.ts +0 -38
- package/src/columns/IconColumn.test.ts +0 -54
- package/src/columns/IconColumn.ts +0 -37
- package/src/columns/ImageColumn.test.ts +0 -41
- package/src/columns/ImageColumn.ts +0 -28
- package/src/columns/SelectColumn.ts +0 -98
- package/src/columns/TextColumn.test.ts +0 -190
- package/src/columns/TextColumn.ts +0 -20
- package/src/columns/TextInputColumn.ts +0 -68
- package/src/columns/ToggleColumn.ts +0 -46
- package/src/columns/editableColumns.test.ts +0 -238
- package/src/columns/index.ts +0 -9
- package/src/defaultGlobalPages.ts +0 -95
- package/src/defaultPages.test.ts +0 -634
- package/src/defaultPages.ts +0 -617
- package/src/defaultViewPage.test.ts +0 -147
- package/src/elements/Form.test.ts +0 -223
- package/src/elements/Form.ts +0 -416
- package/src/elements/ListTabs.ts +0 -28
- package/src/elements/Table.test.ts +0 -422
- package/src/elements/Table.ts +0 -850
- package/src/elements/TableGroup.test.ts +0 -260
- package/src/elements/TableGroup.ts +0 -334
- package/src/elements/dispatchAction.test.ts +0 -463
- package/src/elements/dispatchAction.ts +0 -355
- package/src/elements/dispatchForm.test.ts +0 -477
- package/src/elements/dispatchForm.ts +0 -1993
- package/src/elements/dispatchTable.test.ts +0 -1514
- package/src/elements/dispatchTable.ts +0 -745
- package/src/elements/index.ts +0 -21
- package/src/entries/BadgeEntry.ts +0 -39
- package/src/entries/CodeEntry.test.ts +0 -40
- package/src/entries/CodeEntry.ts +0 -52
- package/src/entries/ColorEntry.ts +0 -63
- package/src/entries/ComponentEntry.test.ts +0 -173
- package/src/entries/ComponentEntry.ts +0 -95
- package/src/entries/Entry.ts +0 -304
- package/src/entries/IconEntry.ts +0 -49
- package/src/entries/ImageEntry.ts +0 -61
- package/src/entries/KeyValueEntry.ts +0 -47
- package/src/entries/RepeatableEntry.test.ts +0 -239
- package/src/entries/RepeatableEntry.ts +0 -173
- package/src/entries/TextEntry.test.ts +0 -394
- package/src/entries/TextEntry.ts +0 -60
- package/src/entries/index.ts +0 -12
- package/src/entries/leaves.test.ts +0 -306
- package/src/entries/registry.ts +0 -54
- package/src/fields/BuilderField.test.ts +0 -1188
- package/src/fields/BuilderField.ts +0 -605
- package/src/fields/BuilderRelationship.test.ts +0 -811
- package/src/fields/CheckboxField.test.ts +0 -44
- package/src/fields/CheckboxField.ts +0 -27
- package/src/fields/CheckboxListField.test.ts +0 -99
- package/src/fields/CheckboxListField.ts +0 -66
- package/src/fields/ColorPickerField.test.ts +0 -33
- package/src/fields/ColorPickerField.ts +0 -25
- package/src/fields/DateField.ts +0 -54
- package/src/fields/DateTimeField.test.ts +0 -55
- package/src/fields/EmailField.ts +0 -16
- package/src/fields/Field.test.ts +0 -654
- package/src/fields/Field.ts +0 -817
- package/src/fields/FileUploadField.test.ts +0 -143
- package/src/fields/FileUploadField.ts +0 -159
- package/src/fields/HiddenField.test.ts +0 -27
- package/src/fields/HiddenField.ts +0 -28
- package/src/fields/KeyValueField.test.ts +0 -105
- package/src/fields/KeyValueField.ts +0 -55
- package/src/fields/MarkdownField.test.ts +0 -167
- package/src/fields/MarkdownField.ts +0 -162
- package/src/fields/NumberField.ts +0 -33
- package/src/fields/RadioField.test.ts +0 -94
- package/src/fields/RadioField.ts +0 -67
- package/src/fields/RepeaterField.test.ts +0 -1806
- package/src/fields/RepeaterField.ts +0 -939
- package/src/fields/RepeaterRelationship.test.ts +0 -1923
- package/src/fields/RepeaterSimple.test.ts +0 -248
- package/src/fields/RowButton.test.ts +0 -219
- package/src/fields/RowButton.ts +0 -135
- package/src/fields/SelectField.test.ts +0 -192
- package/src/fields/SelectField.ts +0 -235
- package/src/fields/SliderField.test.ts +0 -50
- package/src/fields/SliderField.ts +0 -53
- package/src/fields/SlugField.ts +0 -24
- package/src/fields/TagsInputField.test.ts +0 -154
- package/src/fields/TagsInputField.ts +0 -133
- package/src/fields/TextField.test.ts +0 -213
- package/src/fields/TextField.ts +0 -177
- package/src/fields/TextareaField.test.ts +0 -58
- package/src/fields/TextareaField.ts +0 -59
- package/src/fields/ToggleButtonsField.test.ts +0 -106
- package/src/fields/ToggleButtonsField.ts +0 -59
- package/src/fields/ToggleField.ts +0 -16
- package/src/fields/disableOptionsWhenSelectedInSiblingRepeaterItems.test.ts +0 -319
- package/src/fields/optionsResolver.ts +0 -95
- package/src/fields/resolveField.ts +0 -28
- package/src/filters/BooleanFilter.ts +0 -35
- package/src/filters/DateRangeFilter.test.ts +0 -194
- package/src/filters/DateRangeFilter.ts +0 -148
- package/src/filters/Filter.test.ts +0 -268
- package/src/filters/Filter.ts +0 -184
- package/src/filters/FormFilter.test.ts +0 -238
- package/src/filters/FormFilter.ts +0 -215
- package/src/filters/MultiSelectFilter.test.ts +0 -119
- package/src/filters/MultiSelectFilter.ts +0 -78
- package/src/filters/QueryBuilderFilter.test.ts +0 -662
- package/src/filters/QueryBuilderFilter.ts +0 -398
- package/src/filters/SelectFilter.ts +0 -46
- package/src/filters/TernaryFilter.test.ts +0 -160
- package/src/filters/TernaryFilter.ts +0 -72
- package/src/filters/TrashedFilter.test.ts +0 -149
- package/src/filters/TrashedFilter.ts +0 -55
- package/src/filters/queryBuilder/BooleanConstraint.ts +0 -31
- package/src/filters/queryBuilder/Constraint.ts +0 -115
- package/src/filters/queryBuilder/DateConstraint.ts +0 -69
- package/src/filters/queryBuilder/NumberConstraint.ts +0 -66
- package/src/filters/queryBuilder/SelectConstraint.ts +0 -72
- package/src/filters/queryBuilder/TextConstraint.ts +0 -64
- package/src/filters/queryBuilder/index.ts +0 -12
- package/src/icons/index.ts +0 -2
- package/src/icons/lucide.ts +0 -204
- package/src/icons/registry.test.ts +0 -56
- package/src/icons/registry.ts +0 -41
- package/src/icons/types.ts +0 -47
- package/src/index.ts +0 -525
- package/src/io/csv.test.ts +0 -142
- package/src/io/csv.ts +0 -170
- package/src/nestedRelationManagerData.test.ts +0 -547
- package/src/notifications/Notification.test.ts +0 -210
- package/src/notifications/Notification.ts +0 -354
- package/src/notifications/broadcast.test.ts +0 -110
- package/src/notifications/broadcast.ts +0 -95
- package/src/notifications/database.test.ts +0 -383
- package/src/notifications/database.ts +0 -398
- package/src/notifications/databaseNotifications.test.ts +0 -187
- package/src/notifications/dispatchNotificationAction.test.ts +0 -341
- package/src/notifications/dispatchNotificationAction.ts +0 -142
- package/src/notifications/flash.test.ts +0 -89
- package/src/notifications/flash.ts +0 -71
- package/src/notifications/index.ts +0 -45
- package/src/notifications/registerBroadcastAuth.test.ts +0 -134
- package/src/notifications/registerBroadcastAuth.ts +0 -100
- package/src/notifications/resolveSavedNotification.test.ts +0 -82
- package/src/notifications/resolveSavedNotification.ts +0 -59
- package/src/notifications/types.ts +0 -93
- package/src/orm/m2mAccessor.ts +0 -66
- package/src/orm/modelDefaults.test.ts +0 -633
- package/src/orm/modelDefaults.ts +0 -666
- package/src/pageData/breadcrumbs.ts +0 -288
- package/src/pageData/forms.ts +0 -578
- package/src/pageData/helpers.ts +0 -857
- package/src/pageData/misc.ts +0 -347
- package/src/pageData/navigation.ts +0 -842
- package/src/pageData/relationPages.ts +0 -1248
- package/src/pageData/relationTabs.ts +0 -286
- package/src/pageData/resourcePages.ts +0 -609
- package/src/pageData.test.ts +0 -1545
- package/src/pageData.ts +0 -341
- package/src/plugins/index.ts +0 -8
- package/src/plugins/themeEditor.test.ts +0 -36
- package/src/plugins/themeEditor.ts +0 -45
- package/src/react/AppShell.tsx +0 -251
- package/src/react/CollabExtensionFactoryRegistry.ts +0 -55
- package/src/react/CollabRoomContext.ts +0 -98
- package/src/react/CollabTextRendererRegistry.ts +0 -102
- package/src/react/CommandPalette.tsx +0 -375
- package/src/react/CurrentUserContext.tsx +0 -50
- package/src/react/CustomPageWrapperGate.tsx +0 -69
- package/src/react/CustomPageWrapperRegistry.ts +0 -45
- package/src/react/FieldFocusReporterRegistry.ts +0 -37
- package/src/react/FieldLabelSlotRegistry.ts +0 -30
- package/src/react/FieldPresenceRegistry.ts +0 -46
- package/src/react/FormCollabBindingRegistry.ts +0 -242
- package/src/react/FormStateContext.tsx +0 -591
- package/src/react/HeadHooks.tsx +0 -126
- package/src/react/MarkdownEditorRegistry.test.ts +0 -38
- package/src/react/MarkdownEditorRegistry.ts +0 -107
- package/src/react/NotificationActionStrip.tsx +0 -263
- package/src/react/NotificationBell.tsx +0 -426
- package/src/react/PendingSuggestionApplierRegistry.test.ts +0 -97
- package/src/react/PendingSuggestionApplierRegistry.ts +0 -98
- package/src/react/PendingSuggestionOverlayRegistry.ts +0 -54
- package/src/react/PendingSuggestionsContext.tsx +0 -172
- package/src/react/RecordWrapperGate.tsx +0 -58
- package/src/react/RecordWrapperRegistry.ts +0 -39
- package/src/react/RenderHookSlot.tsx +0 -32
- package/src/react/RightSidebar.tsx +0 -257
- package/src/react/RightSidebarContext.tsx +0 -234
- package/src/react/RightSidebarTrigger.tsx +0 -53
- package/src/react/RowCoordsContext.tsx +0 -23
- package/src/react/SchemaRenderer.tsx +0 -549
- package/src/react/SearchTrigger.tsx +0 -46
- package/src/react/ThemeProvider.tsx +0 -93
- package/src/react/ThemeSettingsPage.tsx +0 -579
- package/src/react/ThemeToggle.tsx +0 -20
- package/src/react/Toaster.tsx +0 -158
- package/src/react/UserMenu.tsx +0 -196
- package/src/react/WidgetDataContext.tsx +0 -157
- package/src/react/cells/EditableCell.tsx +0 -389
- package/src/react/component-slots.test.ts +0 -103
- package/src/react/component-slots.ts +0 -116
- package/src/react/fieldJsHandler.test.ts +0 -166
- package/src/react/fieldJsHandler.ts +0 -79
- package/src/react/fields/BuilderInput.tsx +0 -1078
- package/src/react/fields/CheckboxInput.tsx +0 -39
- package/src/react/fields/CheckboxListInput.tsx +0 -102
- package/src/react/fields/ColorInput.tsx +0 -71
- package/src/react/fields/DateFieldInput.tsx +0 -70
- package/src/react/fields/DateTimeInput.tsx +0 -62
- package/src/react/fields/FieldShell.tsx +0 -348
- package/src/react/fields/FileUploadInput.tsx +0 -639
- package/src/react/fields/HiddenInput.tsx +0 -17
- package/src/react/fields/KeyValueInput.tsx +0 -230
- package/src/react/fields/MarkdownInput.tsx +0 -560
- package/src/react/fields/RadioInput.tsx +0 -81
- package/src/react/fields/RepeaterInput.test.ts +0 -116
- package/src/react/fields/RepeaterInput.tsx +0 -1420
- package/src/react/fields/SelectFieldInput.tsx +0 -280
- package/src/react/fields/SliderInput.tsx +0 -81
- package/src/react/fields/TagsInput.tsx +0 -283
- package/src/react/fields/TextLikeInput.tsx +0 -256
- package/src/react/fields/ToggleButtonsInput.tsx +0 -60
- package/src/react/fields/ToggleFieldInput.tsx +0 -56
- package/src/react/fields/relationshipRenameDispatch.test.ts +0 -106
- package/src/react/fields/relationshipRenameDispatch.ts +0 -97
- package/src/react/fields/repeaterReconcile.test.ts +0 -114
- package/src/react/fields/repeaterReconcile.ts +0 -104
- package/src/react/fields/rowChromeButton.tsx +0 -336
- package/src/react/fields/rowState.ts +0 -106
- package/src/react/fields/syncRowGates.test.ts +0 -202
- package/src/react/fields/syncRowGates.ts +0 -66
- package/src/react/fields/textInputControls.tsx +0 -238
- package/src/react/fields/useRowReorderDnd.ts +0 -78
- package/src/react/formStateHelpers.test.ts +0 -508
- package/src/react/formStateHelpers.ts +0 -381
- package/src/react/hooks/use-mobile.ts +0 -19
- package/src/react/icon-context.tsx +0 -60
- package/src/react/index.ts +0 -194
- package/src/react/layouts/SidebarLayout.tsx +0 -250
- package/src/react/layouts/TopbarLayout.tsx +0 -258
- package/src/react/navigate.tsx +0 -37
- package/src/react/onProviderSynced.test.ts +0 -90
- package/src/react/parseRecordEditUrl.test.ts +0 -122
- package/src/react/parseRecordEditUrl.ts +0 -94
- package/src/react/persistedState.ts +0 -40
- package/src/react/registry.ts +0 -48
- package/src/react/right-panel-registry.tsx +0 -47
- package/src/react/schemaRenderer/AlertRenderer.tsx +0 -112
- package/src/react/schemaRenderer/EntryRenderer.tsx +0 -501
- package/src/react/schemaRenderer/SectionRenderer.tsx +0 -120
- package/src/react/schemaRenderer/SimpleElements.tsx +0 -306
- package/src/react/schemaRenderer/TabsRenderer.tsx +0 -62
- package/src/react/schemaRenderer/WizardRenderer.tsx +0 -338
- package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +0 -177
- package/src/react/schemaRenderer/action/ActionModalDialog.tsx +0 -273
- package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +0 -61
- package/src/react/schemaRenderer/action/HandlerActionButton.tsx +0 -43
- package/src/react/schemaRenderer/action/MethodActionButton.tsx +0 -64
- package/src/react/schemaRenderer/action/buttons.tsx +0 -99
- package/src/react/schemaRenderer/action/helpers.ts +0 -140
- package/src/react/schemaRenderer/action/renderAction.tsx +0 -245
- package/src/react/schemaRenderer/columnFormat.ts +0 -65
- package/src/react/schemaRenderer/constants.ts +0 -50
- package/src/react/schemaRenderer/form/FormRenderer.tsx +0 -274
- package/src/react/schemaRenderer/form/renderField.tsx +0 -511
- package/src/react/schemaRenderer/helpers.tsx +0 -81
- package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +0 -308
- package/src/react/schemaRenderer/table/TableRenderer.tsx +0 -123
- package/src/react/schemaRenderer/table/TableRendererBody.tsx +0 -974
- package/src/react/schemaRenderer/table/filters.tsx +0 -1233
- package/src/react/schemaRenderer/table/formatCell.tsx +0 -264
- package/src/react/schemaRenderer/table/links.tsx +0 -112
- package/src/react/schemaRenderer/table/renderRowActions.tsx +0 -52
- package/src/react/schemaRenderer/table/url.tsx +0 -143
- package/src/react/theme-preview/apply.ts +0 -99
- package/src/react/theme-preview/build-html.ts +0 -436
- package/src/react/ui/button.tsx +0 -51
- package/src/react/ui/calendar.tsx +0 -67
- package/src/react/ui/checkbox.tsx +0 -29
- package/src/react/ui/dialog.tsx +0 -108
- package/src/react/ui/dropdown-menu.tsx +0 -97
- package/src/react/ui/input.tsx +0 -20
- package/src/react/ui/label.tsx +0 -21
- package/src/react/ui/popover.tsx +0 -50
- package/src/react/ui/select.tsx +0 -169
- package/src/react/ui/separator.tsx +0 -25
- package/src/react/ui/sheet.tsx +0 -136
- package/src/react/ui/sidebar.tsx +0 -723
- package/src/react/ui/skeleton.tsx +0 -13
- package/src/react/ui/slider.tsx +0 -34
- package/src/react/ui/switch.tsx +0 -28
- package/src/react/ui/table.tsx +0 -105
- package/src/react/ui/tabs.tsx +0 -63
- package/src/react/ui/textarea.tsx +0 -18
- package/src/react/ui/tooltip.tsx +0 -64
- package/src/react/useResizableWidth.ts +0 -139
- package/src/react/utils.ts +0 -6
- package/src/react/widgetRegistry.test.ts +0 -43
- package/src/react/widgetRegistry.ts +0 -50
- package/src/react/widgets/StatsOverviewRenderer.tsx +0 -232
- package/src/react/widgets/TableWidgetRenderer.tsx +0 -231
- package/src/react/widgets/ViewRenderer.tsx +0 -71
- package/src/relationManagerData.test.ts +0 -1595
- package/src/richtext/index.ts +0 -8
- package/src/richtext/registry.ts +0 -89
- package/src/routes/globals.ts +0 -148
- package/src/routes/guard.test.ts +0 -325
- package/src/routes/helpers.ts +0 -704
- package/src/routes/pages.ts +0 -175
- package/src/routes/panel.ts +0 -204
- package/src/routes/relations.ts +0 -1243
- package/src/routes/resources.ts +0 -781
- package/src/routes/theme.ts +0 -91
- package/src/routes-nested-relations.test.ts +0 -676
- package/src/routes-relations.test.ts +0 -972
- package/src/routes.test.ts +0 -2027
- package/src/routes.ts +0 -303
- package/src/schema/Alert.test.ts +0 -109
- package/src/schema/Alert.ts +0 -131
- package/src/schema/Block.ts +0 -169
- package/src/schema/Breadcrumbs.ts +0 -40
- package/src/schema/Card.ts +0 -35
- package/src/schema/Divider.ts +0 -20
- package/src/schema/Element.ts +0 -219
- package/src/schema/EmptyState.test.ts +0 -37
- package/src/schema/EmptyState.ts +0 -63
- package/src/schema/Fieldset.ts +0 -43
- package/src/schema/Grid.ts +0 -43
- package/src/schema/Group.ts +0 -30
- package/src/schema/Heading.ts +0 -39
- package/src/schema/Html.ts +0 -67
- package/src/schema/Icon.ts +0 -54
- package/src/schema/Image.ts +0 -57
- package/src/schema/LinkTag.ts +0 -41
- package/src/schema/Markdown.ts +0 -85
- package/src/schema/MetaTag.ts +0 -41
- package/src/schema/RelationTabs.ts +0 -71
- package/src/schema/ScriptTag.ts +0 -55
- package/src/schema/Section.ts +0 -160
- package/src/schema/ServerDataElement.test.ts +0 -140
- package/src/schema/ServerDataElement.ts +0 -156
- package/src/schema/SlotComponent.test.ts +0 -77
- package/src/schema/SlotComponent.ts +0 -71
- package/src/schema/Split.ts +0 -50
- package/src/schema/Stat.test.ts +0 -118
- package/src/schema/Stat.ts +0 -154
- package/src/schema/StatsOverview.test.ts +0 -141
- package/src/schema/StatsOverview.ts +0 -119
- package/src/schema/StyleTag.ts +0 -35
- package/src/schema/TableWidget.test.ts +0 -297
- package/src/schema/TableWidget.ts +0 -289
- package/src/schema/Tabs.ts +0 -79
- package/src/schema/Text.ts +0 -58
- package/src/schema/UnorderedList.ts +0 -49
- package/src/schema/View.test.ts +0 -111
- package/src/schema/View.ts +0 -127
- package/src/schema/Wizard.ts +0 -220
- package/src/schema/containers.test.ts +0 -564
- package/src/schema/headTags.test.ts +0 -134
- package/src/schema/index.ts +0 -40
- package/src/schema/primes.test.ts +0 -269
- package/src/schema/resolveSchema.test.ts +0 -379
- package/src/schema/resolveSchema.ts +0 -917
- package/src/schema/sanitize.ts +0 -58
- package/src/search.test.ts +0 -446
- package/src/search.ts +0 -178
- package/src/sessionFilters.test.ts +0 -375
- package/src/sessionFilters.ts +0 -143
- package/src/slot-components/index.ts +0 -10
- package/src/slot-components/registry.ts +0 -56
- package/src/styles/file-upload.css +0 -13
- package/src/summarizers/Summarizer.test.ts +0 -84
- package/src/summarizers/Summarizer.ts +0 -123
- package/src/summarizers/index.ts +0 -11
- package/src/theme/base-colors.ts +0 -68
- package/src/theme/chart-colors.ts +0 -50
- package/src/theme/colors.ts +0 -447
- package/src/theme/generate-css.test.ts +0 -139
- package/src/theme/generate-css.ts +0 -44
- package/src/theme/generate-scale.test.ts +0 -106
- package/src/theme/generate-scale.ts +0 -97
- package/src/theme/icon-map.ts +0 -42
- package/src/theme/index.ts +0 -34
- package/src/theme/migrate.test.ts +0 -178
- package/src/theme/migrate.ts +0 -81
- package/src/theme/presets.ts +0 -135
- package/src/theme/radius.ts +0 -18
- package/src/theme/resolve.test.ts +0 -238
- package/src/theme/resolve.ts +0 -96
- package/src/theme/spacing.ts +0 -18
- package/src/theme/storage.test.ts +0 -126
- package/src/theme/storage.ts +0 -106
- package/src/theme/theme-colors.ts +0 -88
- package/src/theme/types.ts +0 -125
- package/src/uploads/UploadAdapter.ts +0 -35
- package/src/uploads/index.ts +0 -2
- package/src/uploads/localUpload.test.ts +0 -70
- package/src/uploads/localUpload.ts +0 -84
- package/src/validation/Validator.ts +0 -49
- package/src/validation/index.ts +0 -28
- package/src/validation/rules.ts +0 -78
- package/src/validation/runValidators.ts +0 -435
- package/src/validation/uniqueValidator.test.ts +0 -196
- package/src/validation/uniqueValidator.ts +0 -133
- package/src/validation/validators.test.ts +0 -268
- package/src/vite.test.ts +0 -184
- package/src/vite.ts +0 -787
- package/src/widgets/index.ts +0 -10
- package/src/widgets/registry.ts +0 -45
- package/src/widgets.test.ts +0 -592
- package/tsconfig.build.json +0 -11
- package/tsconfig.json +0 -4
- package/tsconfig.test.json +0 -10
- package/views/react/Dashboard.tsx +0 -27
- package/views/react/Resources/Form.tsx +0 -102
- package/views/react/Resources/Index.tsx +0 -49
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { SelectField } from './SelectField.js'
|
|
5
|
-
import { TextField } from './TextField.js'
|
|
6
|
-
|
|
7
|
-
describe('SelectField', () => {
|
|
8
|
-
it('emits fieldType "select"', async () => {
|
|
9
|
-
const meta = await SelectField.make('country').toMeta()
|
|
10
|
-
assert.equal(meta.fieldType, 'select')
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
describe('createOptionForm', () => {
|
|
14
|
-
it('bare SelectField emits no createOption slot', async () => {
|
|
15
|
-
const meta = await SelectField.make('categoryId').options([
|
|
16
|
-
{ value: '1', label: 'News' },
|
|
17
|
-
]).toMeta()
|
|
18
|
-
assert.equal('createOption' in meta, false)
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('createOptionForm without createOptionUsing throws at meta-build', async () => {
|
|
22
|
-
const f = SelectField.make('categoryId')
|
|
23
|
-
.options([])
|
|
24
|
-
.createOptionForm([TextField.make('name')])
|
|
25
|
-
await assert.rejects(
|
|
26
|
-
() => f.toMeta(),
|
|
27
|
-
/createOptionForm\(\) requires createOptionUsing\(handler\)/,
|
|
28
|
-
)
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('emits createOption slot with formId + schema when fully configured', async () => {
|
|
32
|
-
const meta = await SelectField.make('categoryId')
|
|
33
|
-
.options([])
|
|
34
|
-
.createOptionForm([
|
|
35
|
-
TextField.make('name'),
|
|
36
|
-
TextField.make('slug'),
|
|
37
|
-
])
|
|
38
|
-
.createOptionUsing(async ({ name }) => ({
|
|
39
|
-
value: 'new-id',
|
|
40
|
-
label: String(name),
|
|
41
|
-
}))
|
|
42
|
-
.toMeta()
|
|
43
|
-
|
|
44
|
-
const slot = (meta as { createOption?: { formId: string; schema: unknown[]; url?: string } }).createOption
|
|
45
|
-
assert.ok(slot, 'createOption slot should be present')
|
|
46
|
-
assert.equal(slot.formId, 'categoryId_create-option')
|
|
47
|
-
assert.equal(Array.isArray(slot.schema), true)
|
|
48
|
-
assert.equal(slot.schema.length, 2)
|
|
49
|
-
// url is filled in by the walker — absent at this layer
|
|
50
|
-
assert.equal(slot.url, undefined)
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
it('hasCreateOption reflects configuration', () => {
|
|
54
|
-
const off = SelectField.make('a').options([])
|
|
55
|
-
const on = SelectField.make('a').options([])
|
|
56
|
-
.createOptionForm([TextField.make('name')])
|
|
57
|
-
assert.equal(off.hasCreateOption(), false)
|
|
58
|
-
assert.equal(on.hasCreateOption(), true)
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('child schema resolves with parent ctx — values flow through', async () => {
|
|
62
|
-
const f = SelectField.make('categoryId')
|
|
63
|
-
.options([])
|
|
64
|
-
.createOptionForm([TextField.make('name').default('seeded')])
|
|
65
|
-
.createOptionUsing(async () => ({ value: '1', label: 'x' }))
|
|
66
|
-
|
|
67
|
-
const meta = await f.toMeta({ values: { irrelevant: 'parent' } })
|
|
68
|
-
const slot = (meta as { createOption?: { schema: Array<{ defaultValue?: string }> } }).createOption
|
|
69
|
-
assert.ok(slot)
|
|
70
|
-
// The child TextField resolved through its own toMeta — defaultValue
|
|
71
|
-
// flows into FieldMeta.defaultValue (string field). Not asserting the
|
|
72
|
-
// exact key (TextField may stamp `defaultValue` or not), but the
|
|
73
|
-
// schema array has length 1 with the right name.
|
|
74
|
-
assert.equal(slot.schema.length, 1)
|
|
75
|
-
assert.equal((slot.schema[0] as { name?: string }).name, 'name')
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
describe('createOptionAuthorize', () => {
|
|
79
|
-
it('default visibility is true (slot stamped)', async () => {
|
|
80
|
-
const meta = await SelectField.make('a').options([])
|
|
81
|
-
.createOptionForm([TextField.make('name')])
|
|
82
|
-
.createOptionUsing(async () => ({ value: '1', label: 'x' }))
|
|
83
|
-
.toMeta()
|
|
84
|
-
assert.ok((meta as { createOption?: unknown }).createOption)
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
it('boolean false suppresses the slot', async () => {
|
|
88
|
-
const meta = await SelectField.make('a').options([])
|
|
89
|
-
.createOptionForm([TextField.make('name')])
|
|
90
|
-
.createOptionUsing(async () => ({ value: '1', label: 'x' }))
|
|
91
|
-
.createOptionAuthorize(false)
|
|
92
|
-
.toMeta()
|
|
93
|
-
assert.equal('createOption' in meta, false)
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
it('boolean true keeps the slot', async () => {
|
|
97
|
-
const meta = await SelectField.make('a').options([])
|
|
98
|
-
.createOptionForm([TextField.make('name')])
|
|
99
|
-
.createOptionUsing(async () => ({ value: '1', label: 'x' }))
|
|
100
|
-
.createOptionAuthorize(true)
|
|
101
|
-
.toMeta()
|
|
102
|
-
assert.ok((meta as { createOption?: unknown }).createOption)
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
it('callback rule sees ctx.user', async () => {
|
|
106
|
-
let seenUser: unknown = undefined
|
|
107
|
-
const meta = await SelectField.make('a').options([])
|
|
108
|
-
.createOptionForm([TextField.make('name')])
|
|
109
|
-
.createOptionUsing(async () => ({ value: '1', label: 'x' }))
|
|
110
|
-
.createOptionAuthorize((ctx) => { seenUser = ctx.user; return true })
|
|
111
|
-
.toMeta({ user: { id: 42 } })
|
|
112
|
-
assert.deepEqual(seenUser, { id: 42 })
|
|
113
|
-
assert.ok((meta as { createOption?: unknown }).createOption)
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
it('callback returning false suppresses the slot', async () => {
|
|
117
|
-
const meta = await SelectField.make('a').options([])
|
|
118
|
-
.createOptionForm([TextField.make('name')])
|
|
119
|
-
.createOptionUsing(async () => ({ value: '1', label: 'x' }))
|
|
120
|
-
.createOptionAuthorize(() => false)
|
|
121
|
-
.toMeta()
|
|
122
|
-
assert.equal('createOption' in meta, false)
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
it('throwing rule fails CLOSED (slot suppressed)', async () => {
|
|
126
|
-
const meta = await SelectField.make('a').options([])
|
|
127
|
-
.createOptionForm([TextField.make('name')])
|
|
128
|
-
.createOptionUsing(async () => ({ value: '1', label: 'x' }))
|
|
129
|
-
.createOptionAuthorize(() => { throw new Error('boom') })
|
|
130
|
-
.toMeta()
|
|
131
|
-
assert.equal('createOption' in meta, false)
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
it('async callback resolves correctly', async () => {
|
|
135
|
-
const meta = await SelectField.make('a').options([])
|
|
136
|
-
.createOptionForm([TextField.make('name')])
|
|
137
|
-
.createOptionUsing(async () => ({ value: '1', label: 'x' }))
|
|
138
|
-
.createOptionAuthorize(async () => true)
|
|
139
|
-
.toMeta()
|
|
140
|
-
assert.ok((meta as { createOption?: unknown }).createOption)
|
|
141
|
-
})
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
describe('withCreateOptionUrl', () => {
|
|
145
|
-
it('round-trips via getCreateOptionUrl', () => {
|
|
146
|
-
const f = SelectField.make('a').withCreateOptionUrl('/p/_form/x/create-option/a')
|
|
147
|
-
assert.equal(f.getCreateOptionUrl(), '/p/_form/x/create-option/a')
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
it('emits url into createOption slot when set', async () => {
|
|
151
|
-
const meta = await SelectField.make('a').options([])
|
|
152
|
-
.createOptionForm([TextField.make('name')])
|
|
153
|
-
.createOptionUsing(async () => ({ value: '1', label: 'x' }))
|
|
154
|
-
.withCreateOptionUrl('/admin/things/_form/parent/create-option/a')
|
|
155
|
-
.toMeta()
|
|
156
|
-
const slot = (meta as { createOption?: { url?: string } }).createOption!
|
|
157
|
-
assert.equal(slot.url, '/admin/things/_form/parent/create-option/a')
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
it('omits url key when no walker has stamped it', async () => {
|
|
161
|
-
const meta = await SelectField.make('a').options([])
|
|
162
|
-
.createOptionForm([TextField.make('name')])
|
|
163
|
-
.createOptionUsing(async () => ({ value: '1', label: 'x' }))
|
|
164
|
-
.toMeta()
|
|
165
|
-
const slot = (meta as { createOption?: { url?: string } }).createOption!
|
|
166
|
-
assert.equal('url' in slot, false)
|
|
167
|
-
})
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
describe('accessors', () => {
|
|
171
|
-
it('getCreateOptionForm / Handler / Authorize round-trip', () => {
|
|
172
|
-
const fields = [TextField.make('name')]
|
|
173
|
-
const handler = async () => ({ value: '1', label: 'x' })
|
|
174
|
-
const authorize = () => true
|
|
175
|
-
const f = SelectField.make('a')
|
|
176
|
-
.createOptionForm(fields)
|
|
177
|
-
.createOptionUsing(handler)
|
|
178
|
-
.createOptionAuthorize(authorize)
|
|
179
|
-
assert.equal(f.getCreateOptionForm(), fields)
|
|
180
|
-
assert.equal(f.getCreateOptionHandler(), handler)
|
|
181
|
-
assert.equal(f.getCreateOptionAuthorize(), authorize)
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
it('accessors return undefined when not set', () => {
|
|
185
|
-
const f = SelectField.make('a')
|
|
186
|
-
assert.equal(f.getCreateOptionForm(), undefined)
|
|
187
|
-
assert.equal(f.getCreateOptionHandler(), undefined)
|
|
188
|
-
assert.equal(f.getCreateOptionAuthorize(), undefined)
|
|
189
|
-
})
|
|
190
|
-
})
|
|
191
|
-
})
|
|
192
|
-
})
|
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
import { Field, type FieldMeta } from './Field.js'
|
|
2
|
-
import {
|
|
3
|
-
resolveOptions,
|
|
4
|
-
disableOptionsTakenInSiblings,
|
|
5
|
-
type OptionsResolver,
|
|
6
|
-
type SelectOption,
|
|
7
|
-
} from './optionsResolver.js'
|
|
8
|
-
import type { Element, ElementMeta } from '../schema/Element.js'
|
|
9
|
-
import { resolveSchema, type RenderContext } from '../schema/resolveSchema.js'
|
|
10
|
-
import type {
|
|
11
|
-
ActionVisibilityContext,
|
|
12
|
-
VisibilityRule,
|
|
13
|
-
} from '../actions/Action.js'
|
|
14
|
-
|
|
15
|
-
// Re-export for back-compat — earlier code imported these directly from
|
|
16
|
-
// SelectField. New code should prefer `fields/optionsResolver.ts`.
|
|
17
|
-
export type { OptionsResolver, SelectOption }
|
|
18
|
-
|
|
19
|
-
/** The new option produced by `createOptionUsing(fn)`. Returns the
|
|
20
|
-
* `value` to post back to the parent form and the `label` to display
|
|
21
|
-
* in the option list. The handler is user-supplied — pilotiq does not
|
|
22
|
-
* auto-create against any model. */
|
|
23
|
-
export interface CreateOptionResult {
|
|
24
|
-
value: string
|
|
25
|
-
label: string
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/** Server-side handler for `SelectField.createOptionUsing`. Receives the
|
|
29
|
-
* modal form's coerced + validated values and the parent form's
|
|
30
|
-
* RenderContext (so `ctx.user` etc. are available). Returns the new
|
|
31
|
-
* option synchronously or via Promise. Throwing surfaces as a 500 with
|
|
32
|
-
* the message in the response body. */
|
|
33
|
-
export type CreateOptionHandler = (
|
|
34
|
-
values: Record<string, unknown>,
|
|
35
|
-
ctx: RenderContext,
|
|
36
|
-
) => CreateOptionResult | Promise<CreateOptionResult>
|
|
37
|
-
|
|
38
|
-
/** Wire-shape carried on `SelectFieldMeta.createOption` when the field
|
|
39
|
-
* has opted into inline create. `url` is filled in by
|
|
40
|
-
* `tagSelectCreateOptionUrls` at page-data time; absent when the field
|
|
41
|
-
* has no `createOptionForm` set or the authorize rule returned false. */
|
|
42
|
-
export interface CreateOptionMeta {
|
|
43
|
-
/** Sub-form id, deterministic so the renderer can target it without a
|
|
44
|
-
* server round-trip. Format: `${parentFormId}_create-option_${fieldName}`,
|
|
45
|
-
* but the parent formId isn't known here — the field just emits a
|
|
46
|
-
* formId derived from its own name. The walker rewrites this when it
|
|
47
|
-
* has the parent in scope. */
|
|
48
|
-
formId: string
|
|
49
|
-
/** Resolved meta for the `createOptionForm` children. Same shape as
|
|
50
|
-
* any other element subtree on the wire. */
|
|
51
|
-
schema: ElementMeta[]
|
|
52
|
-
/** POST endpoint stamped by `tagSelectCreateOptionUrls` walker. When
|
|
53
|
-
* absent, the renderer skips mounting the "+" trigger (no endpoint
|
|
54
|
-
* configured for the parent's scope). */
|
|
55
|
-
url?: string
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export class SelectField extends Field {
|
|
59
|
-
private _options: SelectOption[] | OptionsResolver = []
|
|
60
|
-
|
|
61
|
-
/** Element subtree that renders inside the inline-create modal.
|
|
62
|
-
* Resolved at meta-build time via `Promise.all(toMeta)` so dependent
|
|
63
|
-
* options and reactive visibility see the parent form's
|
|
64
|
-
* `RenderContext`. */
|
|
65
|
-
private _createOptionForm?: Element[]
|
|
66
|
-
/** Server-side handler that returns the new option. Required when
|
|
67
|
-
* `createOptionForm` is set — meta-build throws otherwise to catch
|
|
68
|
-
* the configuration error early instead of at first click. */
|
|
69
|
-
private _createOptionHandler?: CreateOptionHandler
|
|
70
|
-
/** Visibility rule for the "+" trigger. Default: visible. The
|
|
71
|
-
* endpoint re-evaluates the same rule server-side so a tampered
|
|
72
|
-
* client can't bypass. Does NOT auto-inherit any `Resource.canCreate` —
|
|
73
|
-
* the option being created is rarely the same model as the parent
|
|
74
|
-
* form's record. */
|
|
75
|
-
private _createOptionAuthorize?: VisibilityRule
|
|
76
|
-
/** POST endpoint stamped at page-data time by `tagSelectCreateOptionUrls`.
|
|
77
|
-
* Field-instance state (parallel to `Form.withStateUrl`); read by
|
|
78
|
-
* `toMeta` and emitted into the `createOption.url` slot. Absent ⇒ no
|
|
79
|
-
* walker has run yet ⇒ renderer skips the trigger. */
|
|
80
|
-
private _createOptionUrl?: string
|
|
81
|
-
|
|
82
|
-
private constructor(name: string) {
|
|
83
|
-
super(name, 'select')
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
static make(name: string): SelectField {
|
|
87
|
-
return new SelectField(name)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Static option list, or a resolver function for dependent options.
|
|
92
|
-
* The function form receives `{ $get, $set, record, user, values }`
|
|
93
|
-
* and runs every resolve — server-canonical, so it's safe to read
|
|
94
|
-
* from a database.
|
|
95
|
-
*/
|
|
96
|
-
options(opts: SelectOption[] | OptionsResolver): this {
|
|
97
|
-
this._options = opts
|
|
98
|
-
return this
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Returns the static option array. Returns the empty array when
|
|
103
|
-
* options are configured as a function — callers wanting the
|
|
104
|
-
* resolved list should go through `toMeta(ctx)`.
|
|
105
|
-
*/
|
|
106
|
-
getOptions(): SelectOption[] {
|
|
107
|
-
return Array.isArray(this._options) ? this._options : []
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/** Whether options are configured as a (potentially async) resolver. */
|
|
111
|
-
hasDynamicOptions(): boolean {
|
|
112
|
-
return typeof this._options === 'function'
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Inline create-option modal. When set, the rendered SelectField
|
|
117
|
-
* grows a "+" trigger that opens a Dialog hosting the supplied
|
|
118
|
-
* sub-form. Submitting POSTs to a scope-derived endpoint that runs
|
|
119
|
-
* `createOptionUsing` and returns `{ value, label }` for the new
|
|
120
|
-
* option. The new option is appended to the local options state and
|
|
121
|
-
* selected; no parent-form roundtrip required.
|
|
122
|
-
*
|
|
123
|
-
* Pair with `createOptionUsing(fn)` — both are required for the
|
|
124
|
-
* trigger to mount. Optionally gate visibility with
|
|
125
|
-
* `createOptionAuthorize(rule)`.
|
|
126
|
-
*
|
|
127
|
-
* Two call shapes:
|
|
128
|
-
* - Bare array: `createOptionForm([TextField.make('name'), …])`
|
|
129
|
-
* - Builder fn: `createOptionForm(form => form.schema([…]))` —
|
|
130
|
-
* reserved; v1 accepts the array form only.
|
|
131
|
-
*/
|
|
132
|
-
createOptionForm(elements: Element[]): this {
|
|
133
|
-
this._createOptionForm = elements
|
|
134
|
-
return this
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/** Server-side handler called when the modal form submits. Receives
|
|
138
|
-
* coerced + validated values and the parent form's `RenderContext`.
|
|
139
|
-
* Returns the new `{ value, label }` option. Throwing surfaces as a
|
|
140
|
-
* 500 to the modal — typical use is to wrap a model `.create()` and
|
|
141
|
-
* format a label. */
|
|
142
|
-
createOptionUsing(handler: CreateOptionHandler): this {
|
|
143
|
-
this._createOptionHandler = handler
|
|
144
|
-
return this
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/** Visibility gate on the "+" trigger. Same shape as
|
|
148
|
-
* `Action.visible / .authorize`. Default: visible. Server re-runs
|
|
149
|
-
* the same predicate so URL access can't bypass. */
|
|
150
|
-
createOptionAuthorize(rule: VisibilityRule): this {
|
|
151
|
-
this._createOptionAuthorize = rule
|
|
152
|
-
return this
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/** True when the field has opted into inline create. */
|
|
156
|
-
hasCreateOption(): boolean {
|
|
157
|
-
return this._createOptionForm !== undefined
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/** Internal accessor used by the route handler at request time. */
|
|
161
|
-
getCreateOptionForm(): Element[] | undefined { return this._createOptionForm }
|
|
162
|
-
getCreateOptionHandler(): CreateOptionHandler | undefined { return this._createOptionHandler }
|
|
163
|
-
getCreateOptionAuthorize(): VisibilityRule | undefined { return this._createOptionAuthorize }
|
|
164
|
-
|
|
165
|
-
/** Stamped by `tagSelectCreateOptionUrls` at page-data time. Mirrors
|
|
166
|
-
* the `Form.withStateUrl` / `Table.withReorderUrl` pattern. */
|
|
167
|
-
withCreateOptionUrl(url: string): this {
|
|
168
|
-
this._createOptionUrl = url
|
|
169
|
-
return this
|
|
170
|
-
}
|
|
171
|
-
getCreateOptionUrl(): string | undefined { return this._createOptionUrl }
|
|
172
|
-
|
|
173
|
-
override async toMeta(ctx?: RenderContext): Promise<FieldMeta & { options: SelectOption[]; createOption?: CreateOptionMeta }> {
|
|
174
|
-
const base = this.buildMeta(ctx)
|
|
175
|
-
const options = disableOptionsTakenInSiblings(
|
|
176
|
-
await resolveOptions(this._options, ctx, this.name),
|
|
177
|
-
this.shouldDisableOptionsTakenInSiblings(),
|
|
178
|
-
this.name,
|
|
179
|
-
ctx,
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
const createOption = await this.buildCreateOptionMeta(ctx)
|
|
183
|
-
|
|
184
|
-
return {
|
|
185
|
-
...base,
|
|
186
|
-
options,
|
|
187
|
-
...(createOption ? { createOption } : {}),
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/** Resolve the createOption slot. Returns undefined when not
|
|
192
|
-
* configured OR when the authorize rule rejects. Throws when the
|
|
193
|
-
* form is set without a handler — caught at meta-build to surface
|
|
194
|
-
* the config error during dev rather than at first click. */
|
|
195
|
-
private async buildCreateOptionMeta(ctx?: RenderContext): Promise<CreateOptionMeta | undefined> {
|
|
196
|
-
if (this._createOptionForm === undefined) return undefined
|
|
197
|
-
if (this._createOptionHandler === undefined) {
|
|
198
|
-
throw new Error(
|
|
199
|
-
`SelectField '${this.name}': createOptionForm() requires createOptionUsing(handler) to be set. ` +
|
|
200
|
-
`Without a handler the modal submit has no destination.`
|
|
201
|
-
)
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const visible = await evalCreateOptionAuthorize(this._createOptionAuthorize, ctx)
|
|
205
|
-
if (!visible) return undefined
|
|
206
|
-
|
|
207
|
-
const schema = await resolveSchema(this._createOptionForm, ctx ?? {})
|
|
208
|
-
|
|
209
|
-
return {
|
|
210
|
-
formId: `${this.name}_create-option`,
|
|
211
|
-
schema,
|
|
212
|
-
...(this._createOptionUrl !== undefined ? { url: this._createOptionUrl } : {}),
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/** Evaluate the authorize rule. Mirrors `Action.evaluate` posture — a
|
|
218
|
-
* thrown rule is treated as fail-CLOSED (visible: false) so an
|
|
219
|
-
* in-progress predicate change can't accidentally expose the trigger. */
|
|
220
|
-
async function evalCreateOptionAuthorize(
|
|
221
|
-
rule: VisibilityRule | undefined,
|
|
222
|
-
ctx: RenderContext | undefined,
|
|
223
|
-
): Promise<boolean> {
|
|
224
|
-
if (rule === undefined) return true
|
|
225
|
-
if (typeof rule !== 'function') return rule
|
|
226
|
-
const visCtx: ActionVisibilityContext = {}
|
|
227
|
-
if (ctx?.record !== undefined) visCtx.record = ctx.record
|
|
228
|
-
if (ctx?.user !== undefined) visCtx.user = ctx.user
|
|
229
|
-
if (ctx?.values !== undefined) visCtx.values = ctx.values
|
|
230
|
-
try {
|
|
231
|
-
return await rule(visCtx)
|
|
232
|
-
} catch {
|
|
233
|
-
return false
|
|
234
|
-
}
|
|
235
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { SliderField, Slider } from './SliderField.js'
|
|
5
|
-
import { coerceFormValues } from '../elements/dispatchForm.js'
|
|
6
|
-
|
|
7
|
-
describe('SliderField', () => {
|
|
8
|
-
it('emits fieldType "slider"', () => {
|
|
9
|
-
const meta = SliderField.make('rating').toMeta()
|
|
10
|
-
assert.equal(meta.fieldType, 'slider')
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
it('exports an alias `Slider`', () => {
|
|
14
|
-
assert.equal(Slider, SliderField)
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
it('emits min/max/step on meta', () => {
|
|
18
|
-
const meta = SliderField.make('rating').min(0).max(5).step(0.5).toMeta()
|
|
19
|
-
assert.equal(meta['min'], 0)
|
|
20
|
-
assert.equal(meta['max'], 5)
|
|
21
|
-
assert.equal(meta['step'], 0.5)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('defaults min=0, max=100, step=1', () => {
|
|
25
|
-
const meta = SliderField.make('x').toMeta()
|
|
26
|
-
assert.equal(meta['min'], 0)
|
|
27
|
-
assert.equal(meta['max'], 100)
|
|
28
|
-
assert.equal(meta['step'], 1)
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('emits showValue when set', () => {
|
|
32
|
-
const meta = SliderField.make('x').showValue().toMeta()
|
|
33
|
-
assert.equal(meta['showValue'], true)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('omits showValue by default', () => {
|
|
37
|
-
const meta = SliderField.make('x').toMeta()
|
|
38
|
-
assert.equal('showValue' in meta, false)
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it('coerces string body to number via the slider branch', () => {
|
|
42
|
-
const out = coerceFormValues([SliderField.make('rating')], { rating: '3.5' })
|
|
43
|
-
assert.equal(out['rating'], 3.5)
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
it('empty body → null', () => {
|
|
47
|
-
const out = coerceFormValues([SliderField.make('rating')], { rating: '' })
|
|
48
|
-
assert.equal(out['rating'], null)
|
|
49
|
-
})
|
|
50
|
-
})
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { Field, type FieldMeta } from './Field.js'
|
|
2
|
-
import type { RenderContext } from '../schema/resolveSchema.js'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Numeric slider. `min`, `max` required at config time (we don't
|
|
6
|
-
* fall back to 0/100 silently — most use cases have meaningful bounds
|
|
7
|
-
* and a forgotten `.min()` should surface fast). `step` defaults to 1.
|
|
8
|
-
*
|
|
9
|
-
* Value coerces through the same path as `NumberField` — we declare
|
|
10
|
-
* `fieldType: 'slider'` for the renderer dispatch but `coerceFormValues`
|
|
11
|
-
* routes both through the number branch.
|
|
12
|
-
*/
|
|
13
|
-
export class SliderField extends Field {
|
|
14
|
-
private _min = 0
|
|
15
|
-
private _max = 100
|
|
16
|
-
private _step = 1
|
|
17
|
-
private _showValue = false
|
|
18
|
-
|
|
19
|
-
private constructor(name: string) {
|
|
20
|
-
super(name, 'slider')
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
static make(name: string): SliderField {
|
|
24
|
-
return new SliderField(name)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
min(n: number): this { this._min = n; return this }
|
|
28
|
-
max(n: number): this { this._max = n; return this }
|
|
29
|
-
step(n: number): this { this._step = n; return this }
|
|
30
|
-
|
|
31
|
-
/** Display the current numeric value next to the slider. */
|
|
32
|
-
showValue(value: boolean = true): this {
|
|
33
|
-
this._showValue = value
|
|
34
|
-
return this
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
getMin(): number { return this._min }
|
|
38
|
-
getMax(): number { return this._max }
|
|
39
|
-
getStep(): number { return this._step }
|
|
40
|
-
isShowingValue(): boolean { return this._showValue }
|
|
41
|
-
|
|
42
|
-
override toMeta(ctx?: RenderContext): FieldMeta {
|
|
43
|
-
return {
|
|
44
|
-
...this.buildMeta(ctx),
|
|
45
|
-
min: this._min,
|
|
46
|
-
max: this._max,
|
|
47
|
-
step: this._step,
|
|
48
|
-
...(this._showValue ? { showValue: true } : {}),
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export const Slider = SliderField
|
package/src/fields/SlugField.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Field, type FieldMeta } from './Field.js'
|
|
2
|
-
import type { RenderContext } from '../schema/resolveSchema.js'
|
|
3
|
-
|
|
4
|
-
export class SlugField extends Field {
|
|
5
|
-
private _from?: string
|
|
6
|
-
|
|
7
|
-
private constructor(name: string) {
|
|
8
|
-
super(name, 'slug')
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
static make(name: string): SlugField {
|
|
12
|
-
return new SlugField(name)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
from(field: string): this { this._from = field; return this }
|
|
16
|
-
getFrom(): string | undefined { return this._from }
|
|
17
|
-
|
|
18
|
-
override toMeta(ctx?: RenderContext): FieldMeta {
|
|
19
|
-
return {
|
|
20
|
-
...this.buildMeta(ctx),
|
|
21
|
-
...(this._from ? { from: this._from } : {}),
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|