@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,338 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react'
|
|
2
|
-
import type { ElementMeta } from '../../schema/Element.js'
|
|
3
|
-
import { useFormState } from '../FormStateContext.js'
|
|
4
|
-
import { readStoredString, writeStoredString } from '../persistedState.js'
|
|
5
|
-
import { layoutClasses, resolveIcon, withTooltip } from './helpers.js'
|
|
6
|
-
import { actionButtonClass, renderActionBadge, renderActionIcon } from './action/buttons.js'
|
|
7
|
-
|
|
8
|
-
// ─── Wizard (Plan #8) ───────────────────────────────────────
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Deps injected from the top-level dispatch so the wizard body can
|
|
12
|
-
* recurse into the main element renderer without creating a cycle
|
|
13
|
-
* with SchemaRenderer.tsx.
|
|
14
|
-
*/
|
|
15
|
-
export interface WizardRendererDeps {
|
|
16
|
-
renderElement: (el: ElementMeta, index: number) => React.ReactNode
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Resolve the initial active step for `WizardRenderer`. Priority:
|
|
21
|
-
* 1. URL `?<queryKey>=N` (1-based — wizards expose human-friendly indexes
|
|
22
|
-
* when `Wizard.persistStepInQueryString()` is enabled).
|
|
23
|
-
* 2. `localStorage[<storageKey>]` (0-based, set by the persist effect).
|
|
24
|
-
* 3. `startOnStep` configured on the Wizard.
|
|
25
|
-
*
|
|
26
|
-
* SSR-safe: returns `startOnStep` when `window` is undefined.
|
|
27
|
-
*/
|
|
28
|
-
function readInitialWizardStep(
|
|
29
|
-
total: number,
|
|
30
|
-
startOnStep: number,
|
|
31
|
-
storageKey: string | undefined,
|
|
32
|
-
queryKey: string | undefined,
|
|
33
|
-
): number {
|
|
34
|
-
if (typeof window === 'undefined') return startOnStep
|
|
35
|
-
if (queryKey) {
|
|
36
|
-
try {
|
|
37
|
-
const raw = new URL(window.location.href).searchParams.get(queryKey)
|
|
38
|
-
if (raw !== null && raw !== '') {
|
|
39
|
-
const n = Number(raw) - 1
|
|
40
|
-
if (Number.isFinite(n) && n >= 0 && n < total) return n
|
|
41
|
-
}
|
|
42
|
-
} catch { /* ignore */ }
|
|
43
|
-
}
|
|
44
|
-
if (storageKey) {
|
|
45
|
-
const stored = readStoredString(storageKey)
|
|
46
|
-
if (stored !== null) {
|
|
47
|
-
const n = Number(stored)
|
|
48
|
-
if (Number.isFinite(n) && n >= 0 && n < total) return n
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return startOnStep
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Multi-step form layout. Tracks active step in `useState`, optionally
|
|
56
|
-
* persisted to localStorage and/or the URL query string. On Next click,
|
|
57
|
-
* POSTs `{ step, values }` to the form's `wizardUrl` (stamped by the
|
|
58
|
-
* route handler when the form has a Wizard descendant). 200 → advance;
|
|
59
|
-
* 422 → stamp inline errors; absent `wizardUrl` → advance immediately
|
|
60
|
-
* (no validation).
|
|
61
|
-
*
|
|
62
|
-
* Inactive steps render hidden (display:none) rather than unmounted so
|
|
63
|
-
* controlled inputs preserve their values across step transitions and
|
|
64
|
-
* cross-step `$get` works on the resolved meta.
|
|
65
|
-
*
|
|
66
|
-
* Nav buttons honor `Wizard.submitAction() / nextAction() / previousAction()`
|
|
67
|
-
* — chrome (label / icon / color / size / outlined / iconOnly / tooltip /
|
|
68
|
-
* disabled rules) carries through to the rendered button while the click
|
|
69
|
-
* behavior stays hardwired (advance / recede / submit-form). Bare wizards
|
|
70
|
-
* keep the built-in defaults.
|
|
71
|
-
*/
|
|
72
|
-
export function WizardRenderer({
|
|
73
|
-
el,
|
|
74
|
-
index,
|
|
75
|
-
deps,
|
|
76
|
-
}: {
|
|
77
|
-
el: ElementMeta
|
|
78
|
-
index: number
|
|
79
|
-
deps: WizardRendererDeps
|
|
80
|
-
}) {
|
|
81
|
-
const { renderElement } = deps
|
|
82
|
-
const formState = useFormState()
|
|
83
|
-
const formId = formState?.formMeta['formId'] ? String(formState.formMeta['formId']) : undefined
|
|
84
|
-
const wizardUrl = formState?.formMeta['wizardUrl'] ? String(formState.formMeta['wizardUrl']) : undefined
|
|
85
|
-
|
|
86
|
-
const steps = (el.children ?? []).filter(c => c.type === 'step')
|
|
87
|
-
const skippable = Boolean(el['skippable'])
|
|
88
|
-
const startOnStep = Math.max(0, Math.min(Math.max(0, steps.length - 1), Number(el['startOnStep'] ?? 0)))
|
|
89
|
-
const persist = el['persist'] !== false
|
|
90
|
-
const storageKey = persist && formId ? `pilotiq.wizard.${formId}.step` : undefined
|
|
91
|
-
const queryKey = typeof el['persistStepInQueryString'] === 'string'
|
|
92
|
-
? String(el['persistStepInQueryString'])
|
|
93
|
-
: undefined
|
|
94
|
-
|
|
95
|
-
const submitActionMeta = el['submitAction'] as ElementMeta | undefined
|
|
96
|
-
const nextActionMeta = el['nextAction'] as ElementMeta | undefined
|
|
97
|
-
const previousActionMeta = el['previousAction'] as ElementMeta | undefined
|
|
98
|
-
|
|
99
|
-
// Initial-step resolution priority: URL (?<key>=N, 1-based) > localStorage >
|
|
100
|
-
// startOnStep. URL wins on first paint so deep links land on the right step
|
|
101
|
-
// before localStorage can override. Lazy initializer — resolution runs once.
|
|
102
|
-
const [active, setActive] = useState(() => readInitialWizardStep(steps.length, startOnStep, storageKey, queryKey))
|
|
103
|
-
const [advancing, setAdvancing] = useState(false)
|
|
104
|
-
const [advanceError, setAdvanceError] = useState<string | null>(null)
|
|
105
|
-
|
|
106
|
-
// Persist active step changes to localStorage (when enabled).
|
|
107
|
-
useEffect(() => {
|
|
108
|
-
if (!storageKey) return
|
|
109
|
-
writeStoredString(storageKey, String(active))
|
|
110
|
-
}, [storageKey, active])
|
|
111
|
-
|
|
112
|
-
// Mirror active step to the URL via replaceState — purely client-side state
|
|
113
|
-
// sync, no SPA re-fetch. 1-based externally; cleared when on the first step
|
|
114
|
-
// so bare URLs don't grow ?step=1 noise.
|
|
115
|
-
useEffect(() => {
|
|
116
|
-
if (!queryKey) return
|
|
117
|
-
if (typeof window === 'undefined') return
|
|
118
|
-
try {
|
|
119
|
-
const url = new URL(window.location.href)
|
|
120
|
-
if (active === 0) url.searchParams.delete(queryKey)
|
|
121
|
-
else url.searchParams.set(queryKey, String(active + 1))
|
|
122
|
-
window.history.replaceState(window.history.state, '', url.toString())
|
|
123
|
-
} catch { /* ignore */ }
|
|
124
|
-
}, [queryKey, active])
|
|
125
|
-
|
|
126
|
-
if (steps.length === 0) {
|
|
127
|
-
return (
|
|
128
|
-
<div key={index} className="rounded-lg border border-dashed p-8 text-center text-sm text-muted-foreground">
|
|
129
|
-
No steps configured.
|
|
130
|
-
</div>
|
|
131
|
-
)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const isLast = active === steps.length - 1
|
|
135
|
-
const isFirst = active === 0
|
|
136
|
-
|
|
137
|
-
const advance = async (target: number) => {
|
|
138
|
-
setAdvanceError(null)
|
|
139
|
-
if (!wizardUrl) {
|
|
140
|
-
setActive(target)
|
|
141
|
-
return
|
|
142
|
-
}
|
|
143
|
-
setAdvancing(true)
|
|
144
|
-
try {
|
|
145
|
-
const values = formState?.values ?? {}
|
|
146
|
-
// Validate intermediate steps in order when jumping ahead.
|
|
147
|
-
const path = target > active
|
|
148
|
-
? Array.from({ length: target - active }, (_, k) => active + k)
|
|
149
|
-
: [active] // jumping back is unconstrained
|
|
150
|
-
let landed = active
|
|
151
|
-
for (const stepIdx of path) {
|
|
152
|
-
const res = await fetch(wizardUrl, {
|
|
153
|
-
method: 'POST',
|
|
154
|
-
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
|
|
155
|
-
body: JSON.stringify({ step: stepIdx, values }),
|
|
156
|
-
})
|
|
157
|
-
if (res.status === 422) {
|
|
158
|
-
const data = await res.json().catch(() => ({}))
|
|
159
|
-
const errors = (data?.errors ?? {}) as Record<string, string[]>
|
|
160
|
-
if (formState?.applyErrors) formState.applyErrors(errors)
|
|
161
|
-
landed = stepIdx
|
|
162
|
-
setAdvanceError('Please fix the highlighted fields.')
|
|
163
|
-
break
|
|
164
|
-
}
|
|
165
|
-
if (!res.ok) {
|
|
166
|
-
setAdvanceError('Step validation failed.')
|
|
167
|
-
break
|
|
168
|
-
}
|
|
169
|
-
landed = stepIdx + 1
|
|
170
|
-
}
|
|
171
|
-
setActive(target > active ? landed : target)
|
|
172
|
-
} catch {
|
|
173
|
-
setAdvanceError('Step validation failed.')
|
|
174
|
-
} finally {
|
|
175
|
-
setAdvancing(false)
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return (
|
|
180
|
-
<div key={index} className={`flex flex-col gap-6 ${layoutClasses(el)}`.trim()}>
|
|
181
|
-
{/* Step indicator */}
|
|
182
|
-
<ol className="flex items-center gap-3 overflow-x-auto" aria-label="Wizard progress">
|
|
183
|
-
{steps.map((s, i) => {
|
|
184
|
-
const Icon = resolveIcon(s['icon'] ? String(s['icon']) : undefined)
|
|
185
|
-
const reachable = skippable || i <= active
|
|
186
|
-
const isActive = i === active
|
|
187
|
-
const isDone = i < active
|
|
188
|
-
return (
|
|
189
|
-
<li key={i} className="flex items-center gap-2 shrink-0">
|
|
190
|
-
<button
|
|
191
|
-
type="button"
|
|
192
|
-
disabled={!reachable || advancing}
|
|
193
|
-
onClick={() => reachable && advance(i)}
|
|
194
|
-
className={[
|
|
195
|
-
'flex items-center gap-2 rounded-md border px-3 py-1.5 text-sm transition',
|
|
196
|
-
isActive ? 'border-primary bg-primary/10 text-foreground'
|
|
197
|
-
: isDone ? 'border-border text-muted-foreground hover:bg-muted'
|
|
198
|
-
: 'border-border text-muted-foreground',
|
|
199
|
-
reachable ? 'cursor-pointer' : 'opacity-50 cursor-not-allowed',
|
|
200
|
-
].join(' ')}
|
|
201
|
-
aria-current={isActive ? 'step' : undefined}
|
|
202
|
-
>
|
|
203
|
-
<span className={[
|
|
204
|
-
'flex size-5 items-center justify-center rounded-full text-[11px] font-semibold',
|
|
205
|
-
isActive ? 'bg-primary text-primary-foreground'
|
|
206
|
-
: isDone ? 'bg-muted-foreground/20 text-foreground'
|
|
207
|
-
: 'bg-muted text-muted-foreground',
|
|
208
|
-
].join(' ')}>
|
|
209
|
-
{Icon ? <Icon className="size-3" aria-hidden="true" /> : i + 1}
|
|
210
|
-
</span>
|
|
211
|
-
<span className="font-medium">{String(s['label'] ?? `Step ${i + 1}`)}</span>
|
|
212
|
-
</button>
|
|
213
|
-
{i < steps.length - 1 && <span className="h-px w-6 bg-border" aria-hidden="true" />}
|
|
214
|
-
</li>
|
|
215
|
-
)
|
|
216
|
-
})}
|
|
217
|
-
</ol>
|
|
218
|
-
|
|
219
|
-
{/* Active step heading */}
|
|
220
|
-
{Boolean(steps[active]?.['description']) && (
|
|
221
|
-
<p className="text-sm text-muted-foreground">{String(steps[active]!['description'])}</p>
|
|
222
|
-
)}
|
|
223
|
-
|
|
224
|
-
{/* Step content. Inactive steps render hidden so controlled inputs survive. */}
|
|
225
|
-
{steps.map((s, i) => (
|
|
226
|
-
<div
|
|
227
|
-
key={i}
|
|
228
|
-
className={i === active ? 'flex flex-col gap-4' : 'hidden'}
|
|
229
|
-
aria-hidden={i === active ? undefined : true}
|
|
230
|
-
>
|
|
231
|
-
{(s.children ?? []).map((c, ci) => renderElement(c, ci))}
|
|
232
|
-
</div>
|
|
233
|
-
))}
|
|
234
|
-
|
|
235
|
-
{advanceError && (
|
|
236
|
-
<p className="text-sm text-destructive" role="alert">{advanceError}</p>
|
|
237
|
-
)}
|
|
238
|
-
|
|
239
|
-
{/* Step nav. The Form's Save button (in Heading actions or page chrome)
|
|
240
|
-
stays as-is by default — only the final step's submit goes through
|
|
241
|
-
the form. `Wizard.submitAction()` opts into a wizard-owned submit
|
|
242
|
-
button on the final step (use this when the wizard is the entire
|
|
243
|
-
form and there's no page chrome). `nextAction() / previousAction()`
|
|
244
|
-
customize the chrome of the built-in Back / Next buttons. */}
|
|
245
|
-
<div className="flex items-center justify-between gap-2">
|
|
246
|
-
<WizardNavButton
|
|
247
|
-
actionMeta={previousActionMeta}
|
|
248
|
-
fallbackLabel="Back"
|
|
249
|
-
disabled={isFirst || advancing}
|
|
250
|
-
onClick={() => advance(active - 1)}
|
|
251
|
-
/>
|
|
252
|
-
{isLast
|
|
253
|
-
? (submitActionMeta
|
|
254
|
-
? <WizardNavButton
|
|
255
|
-
actionMeta={submitActionMeta}
|
|
256
|
-
fallbackLabel="Submit"
|
|
257
|
-
type="submit"
|
|
258
|
-
disabled={advancing}
|
|
259
|
-
/>
|
|
260
|
-
: <span className="text-xs text-muted-foreground">Submit the form to finish.</span>)
|
|
261
|
-
: <WizardNavButton
|
|
262
|
-
actionMeta={nextActionMeta}
|
|
263
|
-
fallbackLabel={advancing ? 'Validating…' : 'Next'}
|
|
264
|
-
disabled={advancing}
|
|
265
|
-
onClick={() => advance(active + 1)}
|
|
266
|
-
/>
|
|
267
|
-
}
|
|
268
|
-
</div>
|
|
269
|
-
</div>
|
|
270
|
-
)
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Renders one wizard nav slot (Back / Next / Submit). Falls back to plain
|
|
275
|
-
* built-in chrome (border button for Back, primary button for Next/Submit)
|
|
276
|
-
* when no `actionMeta` is supplied; otherwise reads the resolved Action's
|
|
277
|
-
* chrome (`label / icon / color / size / outlined / iconOnly / tooltip /
|
|
278
|
-
* disabled`) and applies it to a button whose click is hardwired by the
|
|
279
|
-
* surrounding wizard. `type="submit"` lets the Submit slot trigger the
|
|
280
|
-
* surrounding form's onSubmit dispatcher (no `onClick` needed).
|
|
281
|
-
*
|
|
282
|
-
* Hidden actions (`.visible(false)` resolved-away) drop the slot entirely
|
|
283
|
-
* — the resolver returns `undefined` for hidden Action elements, which
|
|
284
|
-
* arrives here as `actionMeta == null` so we fall through to the default
|
|
285
|
-
* chrome. Use `Wizard.skippable()` semantics to hide nav buttons when
|
|
286
|
-
* appropriate; for permanent removal subclass the wizard.
|
|
287
|
-
*/
|
|
288
|
-
function WizardNavButton({
|
|
289
|
-
actionMeta,
|
|
290
|
-
fallbackLabel,
|
|
291
|
-
type = 'button',
|
|
292
|
-
disabled,
|
|
293
|
-
onClick,
|
|
294
|
-
}: {
|
|
295
|
-
actionMeta: ElementMeta | undefined
|
|
296
|
-
fallbackLabel: string
|
|
297
|
-
type?: 'button' | 'submit'
|
|
298
|
-
disabled?: boolean
|
|
299
|
-
onClick?: () => void
|
|
300
|
-
}) {
|
|
301
|
-
// Bare default — keep historical chrome for back-compat (un-customized
|
|
302
|
-
// wizards look identical to before this change).
|
|
303
|
-
if (!actionMeta) {
|
|
304
|
-
const isPrimary = type === 'submit' || fallbackLabel !== 'Back'
|
|
305
|
-
return (
|
|
306
|
-
<button
|
|
307
|
-
type={type}
|
|
308
|
-
disabled={disabled}
|
|
309
|
-
onClick={onClick}
|
|
310
|
-
className={isPrimary
|
|
311
|
-
? 'rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:opacity-90 disabled:opacity-50 disabled:cursor-not-allowed'
|
|
312
|
-
: 'rounded-md border border-border px-3 py-1.5 text-sm font-medium text-foreground hover:bg-muted disabled:opacity-50 disabled:cursor-not-allowed'}
|
|
313
|
-
>
|
|
314
|
-
{fallbackLabel}
|
|
315
|
-
</button>
|
|
316
|
-
)
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
const ownDisabled = Boolean(actionMeta['disabled'])
|
|
320
|
-
const label = String(actionMeta['label'] ?? fallbackLabel)
|
|
321
|
-
const tooltip = actionMeta['tooltip'] ? String(actionMeta['tooltip']) : undefined
|
|
322
|
-
const iconOnly = Boolean(actionMeta['iconOnly'])
|
|
323
|
-
const className = actionButtonClass(actionMeta, {})
|
|
324
|
-
const node = (
|
|
325
|
-
<button
|
|
326
|
-
type={type}
|
|
327
|
-
disabled={disabled || ownDisabled}
|
|
328
|
-
onClick={onClick}
|
|
329
|
-
className={`${className} disabled:opacity-50 disabled:cursor-not-allowed`}
|
|
330
|
-
aria-label={iconOnly ? label : undefined}
|
|
331
|
-
>
|
|
332
|
-
{renderActionIcon(actionMeta)}
|
|
333
|
-
{!iconOnly && <span>{label}</span>}
|
|
334
|
-
{renderActionBadge(actionMeta)}
|
|
335
|
-
</button>
|
|
336
|
-
)
|
|
337
|
-
return <>{withTooltip(node, tooltip)}</>
|
|
338
|
-
}
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react'
|
|
2
|
-
import type { ElementMeta } from '../../../schema/Element.js'
|
|
3
|
-
import {
|
|
4
|
-
Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle,
|
|
5
|
-
} from '../../ui/dialog.js'
|
|
6
|
-
import {
|
|
7
|
-
DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger,
|
|
8
|
-
} from '../../ui/dropdown-menu.js'
|
|
9
|
-
import { useNavigate } from '../../navigate.js'
|
|
10
|
-
import { useToast } from '../../Toaster.js'
|
|
11
|
-
import { withTooltip } from '../helpers.js'
|
|
12
|
-
import { actionButtonClass } from './buttons.js'
|
|
13
|
-
import { dispatchHandlerAction, dispatchMethodAction } from './helpers.js'
|
|
14
|
-
import { ActionModalDialog } from './ActionModalDialog.js'
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Trigger button + dropdown menu for an `ActionGroup` meta. Reuses the
|
|
18
|
-
* action button styling helpers so a group's chrome (color/size/outlined/
|
|
19
|
-
* tooltip/iconButton) matches a regular Action. Each child Action
|
|
20
|
-
* dispatches via the same logic as `renderAction` — link/method/handler/
|
|
21
|
-
* confirm/modal — but routed through a `pending` state so the dropdown
|
|
22
|
-
* closes before any dialog opens (shadcn pattern: one popup at a time).
|
|
23
|
-
*
|
|
24
|
-
* `renderFormChild` + `renderElement` are injected through to
|
|
25
|
-
* `ActionModalDialog` for modal-form bodies. They originate in
|
|
26
|
-
* `SchemaRenderer.tsx` (form / dispatch layers).
|
|
27
|
-
*/
|
|
28
|
-
export function ActionGroupTrigger({
|
|
29
|
-
el,
|
|
30
|
-
ids = [],
|
|
31
|
-
renderFormChild,
|
|
32
|
-
renderElement,
|
|
33
|
-
}: {
|
|
34
|
-
el: ElementMeta
|
|
35
|
-
ids?: string[]
|
|
36
|
-
renderFormChild: (child: ElementMeta, index: number, values: Record<string, unknown>, errors: Record<string, string[]>) => React.ReactNode
|
|
37
|
-
renderElement: (el: ElementMeta, index: number) => React.ReactNode
|
|
38
|
-
}) {
|
|
39
|
-
const [pending, setPending] = useState<ElementMeta | null>(null)
|
|
40
|
-
const navigate = useNavigate()
|
|
41
|
-
const { notify } = useToast()
|
|
42
|
-
|
|
43
|
-
const name = String(el['name'] ?? '')
|
|
44
|
-
const label = String(el['label'] ?? name)
|
|
45
|
-
const tooltip = el['tooltip'] as string | undefined
|
|
46
|
-
const iconOnly = Boolean(el['iconOnly'])
|
|
47
|
-
const isDisabled = Boolean(el['disabled'])
|
|
48
|
-
const childActions = (el.children ?? []).filter(c => c.type === 'action')
|
|
49
|
-
|
|
50
|
-
const className = actionButtonClass(el, {}) + (isDisabled ? ' opacity-50 cursor-not-allowed pointer-events-none' : '')
|
|
51
|
-
const ariaLabel = iconOnly ? label : undefined
|
|
52
|
-
|
|
53
|
-
// Direct-dispatch path mirrors renderAction's branches but skipping
|
|
54
|
-
// confirm/modal (those queue into `pending` so the dropdown can close).
|
|
55
|
-
const dispatch = (action: ElementMeta): void => {
|
|
56
|
-
const href = action['href'] as string | undefined
|
|
57
|
-
const method = action['method'] as 'post' | 'put' | 'patch' | 'delete' | undefined
|
|
58
|
-
const actionUrl = action['action'] as string | undefined
|
|
59
|
-
const dispatchUrl = action['dispatchUrl'] as string | undefined
|
|
60
|
-
if (href) {
|
|
61
|
-
navigate(href)
|
|
62
|
-
return
|
|
63
|
-
}
|
|
64
|
-
if (method && actionUrl) {
|
|
65
|
-
void dispatchMethodAction(actionUrl, method, navigate, notify)
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
if (dispatchUrl) {
|
|
69
|
-
void dispatchHandlerAction(dispatchUrl, ids, navigate, notify)
|
|
70
|
-
return
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const onItemClick = (action: ElementMeta): void => {
|
|
75
|
-
if (action['modal'] || action['confirm']) {
|
|
76
|
-
setPending(action)
|
|
77
|
-
return
|
|
78
|
-
}
|
|
79
|
-
dispatch(action)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const pendingHandler = pending && pending['dispatchUrl']
|
|
83
|
-
const pendingConfirmOnly = pending && !pendingHandler && (pending['confirm'] as { title?: string; message: string } | undefined)
|
|
84
|
-
const pendingConfirm = pendingConfirmOnly || (pending?.['confirm'] as { title?: string; message: string } | undefined)
|
|
85
|
-
|
|
86
|
-
return (
|
|
87
|
-
<>
|
|
88
|
-
<DropdownMenu>
|
|
89
|
-
<DropdownMenuTrigger
|
|
90
|
-
render={(props) => withTooltip(
|
|
91
|
-
<button
|
|
92
|
-
{...props}
|
|
93
|
-
type="button"
|
|
94
|
-
className={className}
|
|
95
|
-
data-action-group-name={name}
|
|
96
|
-
aria-label={ariaLabel}
|
|
97
|
-
>
|
|
98
|
-
{iconOnly ? null : <span>{label}</span>}
|
|
99
|
-
</button>,
|
|
100
|
-
tooltip,
|
|
101
|
-
) as React.ReactElement}
|
|
102
|
-
/>
|
|
103
|
-
<DropdownMenuContent align="end">
|
|
104
|
-
{childActions.map((a, i) => {
|
|
105
|
-
const itemLabel = String(a['label'] ?? a['name'] ?? '')
|
|
106
|
-
const destructive = Boolean(a['destructive'])
|
|
107
|
-
const itemDisabled = Boolean(a['disabled'])
|
|
108
|
-
return (
|
|
109
|
-
<DropdownMenuItem
|
|
110
|
-
key={i}
|
|
111
|
-
destructive={destructive}
|
|
112
|
-
disabled={itemDisabled}
|
|
113
|
-
onClick={() => { if (!itemDisabled) onItemClick(a) }}
|
|
114
|
-
>
|
|
115
|
-
{itemLabel}
|
|
116
|
-
</DropdownMenuItem>
|
|
117
|
-
)
|
|
118
|
-
})}
|
|
119
|
-
</DropdownMenuContent>
|
|
120
|
-
</DropdownMenu>
|
|
121
|
-
|
|
122
|
-
{/* Modal / handler-style pending — fetch+JSON dispatch via ActionModalDialog. */}
|
|
123
|
-
{pendingHandler && pending && (
|
|
124
|
-
<ActionModalDialog
|
|
125
|
-
meta={pending}
|
|
126
|
-
ids={ids}
|
|
127
|
-
open={true}
|
|
128
|
-
onOpenChange={(o) => { if (!o) setPending(null) }}
|
|
129
|
-
renderFormChild={renderFormChild}
|
|
130
|
-
renderElement={renderElement}
|
|
131
|
-
/>
|
|
132
|
-
)}
|
|
133
|
-
|
|
134
|
-
{/* Form-method confirm — fetch+JSON dispatch via dispatchMethodAction; SPA-navigates on success. */}
|
|
135
|
-
<Dialog
|
|
136
|
-
open={Boolean(pendingConfirmOnly)}
|
|
137
|
-
onOpenChange={(o) => { if (!o) setPending(null) }}
|
|
138
|
-
>
|
|
139
|
-
<DialogContent>
|
|
140
|
-
{pendingConfirmOnly && pendingConfirm && (
|
|
141
|
-
<>
|
|
142
|
-
<DialogHeader>
|
|
143
|
-
<DialogTitle>{pendingConfirm.title ?? 'Are you sure?'}</DialogTitle>
|
|
144
|
-
<DialogDescription>{pendingConfirm.message}</DialogDescription>
|
|
145
|
-
</DialogHeader>
|
|
146
|
-
<DialogFooter>
|
|
147
|
-
<button
|
|
148
|
-
type="button"
|
|
149
|
-
onClick={() => setPending(null)}
|
|
150
|
-
className="inline-flex items-center justify-center rounded-md border border-input bg-background px-3 h-9 text-sm font-medium hover:bg-accent hover:text-accent-foreground"
|
|
151
|
-
>
|
|
152
|
-
Cancel
|
|
153
|
-
</button>
|
|
154
|
-
<button
|
|
155
|
-
type="button"
|
|
156
|
-
autoFocus
|
|
157
|
-
onClick={() => {
|
|
158
|
-
const action = pending
|
|
159
|
-
setPending(null)
|
|
160
|
-
if (action) dispatch(action)
|
|
161
|
-
}}
|
|
162
|
-
className={
|
|
163
|
-
pending && pending['destructive']
|
|
164
|
-
? 'inline-flex items-center justify-center rounded-md bg-destructive px-3 h-9 text-sm font-medium text-destructive-foreground hover:bg-destructive/90'
|
|
165
|
-
: 'inline-flex items-center justify-center rounded-md bg-primary px-3 h-9 text-sm font-medium text-primary-foreground hover:bg-primary/90'
|
|
166
|
-
}
|
|
167
|
-
>
|
|
168
|
-
{pending && pending['destructive'] ? 'Delete' : 'Confirm'}
|
|
169
|
-
</button>
|
|
170
|
-
</DialogFooter>
|
|
171
|
-
</>
|
|
172
|
-
)}
|
|
173
|
-
</DialogContent>
|
|
174
|
-
</Dialog>
|
|
175
|
-
</>
|
|
176
|
-
)
|
|
177
|
-
}
|