@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,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Module-level registry slot for the Tiptap extension factory that turns
|
|
3
|
-
* a collab room into editor-attachable extensions (`Collaboration` +
|
|
4
|
-
* `CollaborationCursor`).
|
|
5
|
-
*
|
|
6
|
-
* Wiring posture (mirrors `PendingSuggestionOverlayRegistry`):
|
|
7
|
-
* - `@pilotiq-pro/collab`'s plugin calls `registerCollabExtensions(...)`
|
|
8
|
-
* once at boot from inside `register(panel)`. The factory closes over
|
|
9
|
-
* the `@tiptap/extension-collaboration` + `-cursor` imports, so pilotiq
|
|
10
|
-
* core (and `@pilotiq/tiptap`) never carry those as peer deps.
|
|
11
|
-
* - `@pilotiq/tiptap`'s `TiptapEditor` calls `getCollabExtensions()` at
|
|
12
|
-
* mount; if non-null AND a `useCollabRoom()` value is present, it calls
|
|
13
|
-
* the factory and spreads the returned array into the editor's
|
|
14
|
-
* `extensions` slot. If either is missing, plain Tiptap + History runs.
|
|
15
|
-
*
|
|
16
|
-
* `unknown[]` return type is deliberate — pilotiq core has zero `@tiptap/*`
|
|
17
|
-
* imports and treats the returned values as opaque editor-extension refs.
|
|
18
|
-
* The Tiptap host trusts them and spreads them in.
|
|
19
|
-
*/
|
|
20
|
-
export interface CollabExtensionFactoryArgs {
|
|
21
|
-
/** `Y.Doc` for the surrounding record. Opaque to pilotiq core. */
|
|
22
|
-
ydoc: unknown
|
|
23
|
-
/** `WebsocketProvider` for the same room. Opaque to pilotiq core. */
|
|
24
|
-
provider: unknown
|
|
25
|
-
/**
|
|
26
|
-
* Field name — becomes the `Y.XmlFragment` selector
|
|
27
|
-
* (`Collaboration.configure({ field: fieldName })`) so multiple
|
|
28
|
-
* collab editors on the same record write to distinct fragments
|
|
29
|
-
* inside one shared ydoc.
|
|
30
|
-
*/
|
|
31
|
-
fieldName: string
|
|
32
|
-
/** Presence info forwarded to `CollaborationCursor`. Sparse. */
|
|
33
|
-
user?: {
|
|
34
|
-
name?: string
|
|
35
|
-
color?: string
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export type CollabExtensionFactory = (args: CollabExtensionFactoryArgs) => unknown[]
|
|
40
|
-
|
|
41
|
-
let _factory: CollabExtensionFactory | null = null
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Register the factory that builds collab extensions for one field +
|
|
45
|
-
* room. Called once at boot by `@pilotiq-pro/collab`'s plugin. No-op when
|
|
46
|
-
* no plugin registers — Tiptap renderers fall back to plain editing.
|
|
47
|
-
*/
|
|
48
|
-
export function registerCollabExtensions(factory: CollabExtensionFactory): void {
|
|
49
|
-
_factory = factory
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** Returns the registered factory, or `null`. */
|
|
53
|
-
export function getCollabExtensions(): CollabExtensionFactory | null {
|
|
54
|
-
return _factory
|
|
55
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { createContext, useContext } from 'react'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Per-record realtime-collab room — a Y.Doc plus its WebsocketProvider,
|
|
5
|
-
* shared across every collaborative field in the same form. Mirrors the
|
|
6
|
-
* Tiptap "Collaborative Fields" pattern: one ydoc per record, each editor
|
|
7
|
-
* scopes itself to its own `Y.XmlFragment` via the field's `name`.
|
|
8
|
-
*
|
|
9
|
-
* Pilotiq core does NOT instantiate the room — implementation lives in
|
|
10
|
-
* `@pilotiq-pro/collab`, which mounts the context with real Yjs values
|
|
11
|
-
* via `<RecordCollabRoom>`. Core just owns the shape so any field
|
|
12
|
-
* renderer (Tiptap, in-house, third-party) can subscribe through one
|
|
13
|
-
* open-core seam without taking a hard peer dep on Yjs.
|
|
14
|
-
*
|
|
15
|
-
* `ydoc` and `provider` are typed `unknown` deliberately — the consumer
|
|
16
|
-
* (typically `@pilotiq/tiptap`) hands them straight to a registered
|
|
17
|
-
* `CollabExtensionFactory` and never touches them directly, so pilotiq
|
|
18
|
-
* core stays Yjs-free.
|
|
19
|
-
*/
|
|
20
|
-
export interface CollabRoom {
|
|
21
|
-
/** `Y.Doc` instance. Opaque to pilotiq core. */
|
|
22
|
-
ydoc: unknown
|
|
23
|
-
/** `WebsocketProvider` instance. Opaque to pilotiq core. */
|
|
24
|
-
provider: unknown
|
|
25
|
-
/**
|
|
26
|
-
* Resolves on the provider's first sync. Present when the room is
|
|
27
|
-
* wired through `@rudderjs/sync/react`'s `CollabRoomManager` (which is
|
|
28
|
-
* what `@pilotiq-pro/collab@>=0.2`'s `<RecordCollabRoom>` does);
|
|
29
|
-
* absent for legacy / hand-rolled providers. `useCollabSeed` gates
|
|
30
|
-
* its seed callback on this Promise — adapters that need a
|
|
31
|
-
* "fragment-empty?" check after first sync should consume the hook
|
|
32
|
-
* rather than calling `onProviderSynced` themselves.
|
|
33
|
-
*/
|
|
34
|
-
synced?: Promise<void>
|
|
35
|
-
/** IndexedDB persistence handle, when the room wraps `y-indexeddb`. Opaque. */
|
|
36
|
-
persistence?: unknown
|
|
37
|
-
/** Presence info for cursors / avatars. Forwarded to the extension factory. */
|
|
38
|
-
user?: {
|
|
39
|
-
name?: string
|
|
40
|
-
color?: string
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* `null` default — fields read the context, and a null result means
|
|
46
|
-
* "no collab room mounted, fall back to local-only editing." This is
|
|
47
|
-
* the 99% case (collab plugin not installed).
|
|
48
|
-
*/
|
|
49
|
-
export const CollabRoomContext = createContext<CollabRoom | null>(null)
|
|
50
|
-
|
|
51
|
-
/** Read the active collab room for the surrounding record, or `null`. */
|
|
52
|
-
export function useCollabRoom(): CollabRoom | null {
|
|
53
|
-
return useContext(CollabRoomContext)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Minimal structural shape every collab provider exposes for the
|
|
58
|
-
* "initial room state has streamed in" signal. Kept structural so callers
|
|
59
|
-
* (`@pilotiq/tiptap`, `@pilotiq/codemirror`, future adapters) can pass
|
|
60
|
-
* `provider as unknown as SyncedProviderLike` without taking a hard peer
|
|
61
|
-
* dep on yjs / y-websocket / y-webrtc.
|
|
62
|
-
*/
|
|
63
|
-
export interface SyncedProviderLike {
|
|
64
|
-
synced?: boolean
|
|
65
|
-
once?(event: 'synced', fn: () => void): void
|
|
66
|
-
off?(event: 'synced', fn: () => void): void
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const NOOP_CLEANUP = (): void => {}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Run `fn` once the collab provider's initial room state has streamed in.
|
|
73
|
-
* If the provider is already synced, `fn` fires synchronously; otherwise
|
|
74
|
-
* it's registered via `provider.once('synced', fn)`. The returned cleanup
|
|
75
|
-
* unregisters the once handler safely (idempotent + try/catch) so callers
|
|
76
|
-
* can wire it directly into a React effect's cleanup return.
|
|
77
|
-
*
|
|
78
|
-
* Useful for the brand-new-record seed pattern: editors mounting against
|
|
79
|
-
* a freshly-created record want to push the SSR-rendered default into
|
|
80
|
-
* the empty `Y.Text` / `Y.XmlFragment` exactly once after sync, before
|
|
81
|
-
* the user types. Race caveat: two peers simultaneously mounting against
|
|
82
|
-
* a brand-new record can both see `length === 0` and both seed —
|
|
83
|
-
* accepted today across every adapter's seed path.
|
|
84
|
-
*/
|
|
85
|
-
export function onProviderSynced(
|
|
86
|
-
provider: SyncedProviderLike | null | undefined,
|
|
87
|
-
fn: () => void,
|
|
88
|
-
): () => void {
|
|
89
|
-
if (!provider) return NOOP_CLEANUP
|
|
90
|
-
if (provider.synced) {
|
|
91
|
-
fn()
|
|
92
|
-
return NOOP_CLEANUP
|
|
93
|
-
}
|
|
94
|
-
provider.once?.('synced', fn)
|
|
95
|
-
return () => {
|
|
96
|
-
try { provider.off?.('synced', fn) } catch { /* ignore */ }
|
|
97
|
-
}
|
|
98
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import type { ComponentType } from 'react'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Module-level registry slot for the collab-aware plain-text editor renderer.
|
|
5
|
-
*
|
|
6
|
-
* Wiring posture (mirrors `CollabExtensionFactoryRegistry` /
|
|
7
|
-
* `FormCollabBindingRegistry`):
|
|
8
|
-
* - `@pilotiq/tiptap`'s `registerTiptap(...)` calls `registerCollabTextRenderer(...)`
|
|
9
|
-
* once at boot. The registered component closes over `@tiptap/*` imports so
|
|
10
|
-
* pilotiq core stays free of any tiptap peer dep — same posture as the
|
|
11
|
-
* existing rich-text renderer registry.
|
|
12
|
-
* - `TextLikeInput` checks for the registered component when a `<RecordCollabRoom>`
|
|
13
|
-
* is mounted up-tree AND the field hasn't opted out via `.collab(false)` AND
|
|
14
|
-
* the field has no `.mask()`. If present, the legacy `BoundTextInput`
|
|
15
|
-
* (Y.Text + `computeDelta` + heuristic `preserveCursor`) is bypassed in
|
|
16
|
-
* favour of a y-prosemirror-backed Tiptap editor that anchors selections to
|
|
17
|
-
* `Yjs.RelativePosition` — the architectural fix for the cursor-jump and
|
|
18
|
-
* two-peer concurrent-insert races documented in
|
|
19
|
-
* `docs/plans/text-fields-tiptap-backed-collab.md`.
|
|
20
|
-
*
|
|
21
|
-
* Wire props are deliberately framework-agnostic — the renderer doesn't take a
|
|
22
|
-
* `binding` since it consumes the room's `ydoc` directly via the existing
|
|
23
|
-
* `useCollabRoom()` + `getCollabExtensions()` plumbing on its own side. Core
|
|
24
|
-
* keeps the seam narrow: handler callbacks + DOM chrome only.
|
|
25
|
-
*/
|
|
26
|
-
export interface CollabTextRendererProps {
|
|
27
|
-
/**
|
|
28
|
-
* Field name — drives the FormData hidden input AND the routing key
|
|
29
|
-
* for AI suggestion delivery (chip widget, applier registry). For
|
|
30
|
-
* Repeater / Builder row leaves this is the dotted positional path
|
|
31
|
-
* (`items.0.title`).
|
|
32
|
-
*/
|
|
33
|
-
name: string
|
|
34
|
-
/**
|
|
35
|
-
* Collab-stable identifier for the `Y.XmlFragment` selector. When
|
|
36
|
-
* present, the renderer binds its collab fragment under this key
|
|
37
|
-
* instead of `name`. Row leaves pass a row-id-anchored composite
|
|
38
|
-
* (`items.<rowId>.title`) so the fragment survives reorders even
|
|
39
|
-
* as the dotted positional `name` shifts. Top-level fields omit
|
|
40
|
-
* it — `name` is stable on its own.
|
|
41
|
-
*
|
|
42
|
-
* AI suggestion routing continues to use `name` regardless. Tool
|
|
43
|
-
* calls reference fields by their positional FormData name, not
|
|
44
|
-
* the collab-stable composite.
|
|
45
|
-
*/
|
|
46
|
-
fragmentKey?: string
|
|
47
|
-
/** `true` for textarea-like (multiple paragraphs); `false` for input-like. */
|
|
48
|
-
multiline: boolean
|
|
49
|
-
/**
|
|
50
|
-
* Server-rendered default value. The renderer is expected to seed the
|
|
51
|
-
* `Y.XmlFragment` from this on first connect when the room has no
|
|
52
|
-
* persisted state for this field (i.e. brand-new record).
|
|
53
|
-
*/
|
|
54
|
-
defaultValue: string
|
|
55
|
-
/** Optional placeholder hint. */
|
|
56
|
-
placeholder?: string
|
|
57
|
-
/** Disabled / read-only state. */
|
|
58
|
-
disabled?: boolean
|
|
59
|
-
/** Fired on every editor `update` with the editor's current plain text. */
|
|
60
|
-
onChange: (text: string) => void
|
|
61
|
-
/** Fired on editor blur — host wires this to live-onBlur trigger semantics. */
|
|
62
|
-
onBlur: () => void
|
|
63
|
-
/**
|
|
64
|
-
* Single-line submit — fired when `multiline: false` AND the user presses
|
|
65
|
-
* Enter. The renderer is expected to blur the editor after invoking this.
|
|
66
|
-
* Multiline mode ignores it (Enter inserts a paragraph instead).
|
|
67
|
-
*/
|
|
68
|
-
onSubmit?: () => void
|
|
69
|
-
/**
|
|
70
|
-
* Tailwind className applied to the editor's contenteditable wrapper so the
|
|
71
|
-
* rendered editor matches the native `<input>` / `<textarea>` chrome it
|
|
72
|
-
* replaces. The host owns the styling — the adapter just forwards.
|
|
73
|
-
*/
|
|
74
|
-
className?: string
|
|
75
|
-
/**
|
|
76
|
-
* Additional DOM attributes for the editor's contenteditable wrapper —
|
|
77
|
-
* typically `id`, `aria-*`, `autocomplete`, etc.
|
|
78
|
-
*/
|
|
79
|
-
editorAttributes?: Record<string, string>
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export type CollabTextRenderer = ComponentType<CollabTextRendererProps>
|
|
83
|
-
|
|
84
|
-
let _renderer: CollabTextRenderer | null = null
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Register the collab plain-text editor component. Called once at boot by
|
|
88
|
-
* `@pilotiq/tiptap`'s `registerTiptap()` (or directly by an app that imports
|
|
89
|
-
* the renderer). Calling with `null` clears the registry — useful for tests.
|
|
90
|
-
*
|
|
91
|
-
* No-op behaviour when no renderer is registered: `TextLikeInput` falls back
|
|
92
|
-
* to the legacy `BoundTextInput` path (or the plain controlled / uncontrolled
|
|
93
|
-
* input when no collab room is mounted).
|
|
94
|
-
*/
|
|
95
|
-
export function registerCollabTextRenderer(component: CollabTextRenderer | null): void {
|
|
96
|
-
_renderer = component
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/** Returns the registered component, or `null` when no adapter is installed. */
|
|
100
|
-
export function getCollabTextRenderer(): CollabTextRenderer | null {
|
|
101
|
-
return _renderer
|
|
102
|
-
}
|
|
@@ -1,375 +0,0 @@
|
|
|
1
|
-
import * as React from 'react'
|
|
2
|
-
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'
|
|
3
|
-
import { SearchIcon, CornerDownLeftIcon, ArrowUpDownIcon } from 'lucide-react'
|
|
4
|
-
|
|
5
|
-
import { Dialog, DialogContent } from './ui/dialog.js'
|
|
6
|
-
import { useNavigate } from './navigate.js'
|
|
7
|
-
import { useIconFor } from './icon-context.js'
|
|
8
|
-
import { RenderHookSlot } from './RenderHookSlot.js'
|
|
9
|
-
import type { GlobalSearchResult } from '../search.js'
|
|
10
|
-
import type { NavItem } from '../pageData.js'
|
|
11
|
-
import type { SerializedIcon } from '../icons/types.js'
|
|
12
|
-
import type { RenderHookMap } from '../RenderHook.js'
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Context exposing the palette's open setter. AppShell hosts the
|
|
16
|
-
* provider; trigger pills (sidebar + topbar headers) call
|
|
17
|
-
* `useCommandPaletteOpener()` to open the palette from anywhere in the
|
|
18
|
-
* tree without prop-drilling.
|
|
19
|
-
*/
|
|
20
|
-
const CommandPaletteContext = createContext<((open: boolean) => void) | null>(null)
|
|
21
|
-
|
|
22
|
-
export function CommandPaletteProvider({
|
|
23
|
-
children,
|
|
24
|
-
setOpen,
|
|
25
|
-
}: {
|
|
26
|
-
children: React.ReactNode
|
|
27
|
-
setOpen: (open: boolean) => void
|
|
28
|
-
}): React.ReactElement {
|
|
29
|
-
return (
|
|
30
|
-
<CommandPaletteContext.Provider value={setOpen}>
|
|
31
|
-
{children}
|
|
32
|
-
</CommandPaletteContext.Provider>
|
|
33
|
-
)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function useCommandPaletteOpener(): (() => void) | null {
|
|
37
|
-
const setOpen = useContext(CommandPaletteContext)
|
|
38
|
-
return setOpen ? () => setOpen(true) : null
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Plan #12 — Cmd+K palette. Hand-rolled on the existing Dialog primitive
|
|
43
|
-
* (no `cmdk` dep yet). Listens for Cmd/Ctrl+K globally; renders an input
|
|
44
|
-
* + grouped result list; debounced fetch with in-flight cancellation
|
|
45
|
-
* (same pattern as Plan #5 FormStateContext).
|
|
46
|
-
*
|
|
47
|
-
* Empty input shows the panel navigation entries — Cmd+K becomes a fast
|
|
48
|
-
* resource picker. Typing replaces the list with search results grouped
|
|
49
|
-
* by resource.
|
|
50
|
-
*/
|
|
51
|
-
|
|
52
|
-
const DEBOUNCE_MS = 150
|
|
53
|
-
const MIN_QUERY_LENGTH = 2
|
|
54
|
-
|
|
55
|
-
interface SearchResponse {
|
|
56
|
-
ok: boolean
|
|
57
|
-
results: GlobalSearchResult[]
|
|
58
|
-
renderHooks?: RenderHookMap
|
|
59
|
-
error?: string
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface CommandPaletteProps {
|
|
63
|
-
basePath: string
|
|
64
|
-
navigation?: NavItem[]
|
|
65
|
-
/** Controlled open state. AppShell hosts; the palette + the trigger
|
|
66
|
-
* pill share via context. */
|
|
67
|
-
open: boolean
|
|
68
|
-
onOpenChange: (open: boolean) => void
|
|
69
|
-
/** Test seam — defaults to `globalThis.fetch`. */
|
|
70
|
-
fetchImpl?: typeof fetch
|
|
71
|
-
/** Test seam — defaults to `useNavigate()`. */
|
|
72
|
-
navigateOverride?: (url: string) => void
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
interface PaletteEntry {
|
|
76
|
-
/** `'result'` rows are search hits; `'nav'` rows are nav-entry shortcuts. */
|
|
77
|
-
kind: 'result' | 'nav'
|
|
78
|
-
/** Group header label (resource label for results, group name for nav). */
|
|
79
|
-
group: string
|
|
80
|
-
title: string
|
|
81
|
-
subtitle?: string
|
|
82
|
-
url: string
|
|
83
|
-
icon?: SerializedIcon
|
|
84
|
-
/** Stable key for keyboard nav. */
|
|
85
|
-
key: string
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function CommandPalette({
|
|
89
|
-
basePath,
|
|
90
|
-
navigation,
|
|
91
|
-
open,
|
|
92
|
-
onOpenChange,
|
|
93
|
-
fetchImpl,
|
|
94
|
-
navigateOverride,
|
|
95
|
-
}: CommandPaletteProps): React.ReactElement {
|
|
96
|
-
const navigate = useNavigate()
|
|
97
|
-
const go = navigateOverride ?? navigate
|
|
98
|
-
|
|
99
|
-
const setOpen = onOpenChange
|
|
100
|
-
const [query, setQuery] = useState('')
|
|
101
|
-
const [results, setResults] = useState<GlobalSearchResult[]>([])
|
|
102
|
-
const [renderHooks, setRenderHooks] = useState<RenderHookMap | undefined>(undefined)
|
|
103
|
-
const [active, setActive] = useState(0)
|
|
104
|
-
const [loading, setLoading] = useState(false)
|
|
105
|
-
|
|
106
|
-
// ─── Cmd+K global listener ───────────────────────────
|
|
107
|
-
useEffect(() => {
|
|
108
|
-
function onKey(e: KeyboardEvent) {
|
|
109
|
-
const isCmdK = (e.metaKey || e.ctrlKey) && (e.key === 'k' || e.key === 'K')
|
|
110
|
-
if (!isCmdK) return
|
|
111
|
-
e.preventDefault()
|
|
112
|
-
setOpen(!open)
|
|
113
|
-
}
|
|
114
|
-
document.addEventListener('keydown', onKey)
|
|
115
|
-
return () => document.removeEventListener('keydown', onKey)
|
|
116
|
-
}, [open, setOpen])
|
|
117
|
-
|
|
118
|
-
// Reset query + active row whenever the palette closes.
|
|
119
|
-
useEffect(() => {
|
|
120
|
-
if (!open) {
|
|
121
|
-
setQuery('')
|
|
122
|
-
setResults([])
|
|
123
|
-
setRenderHooks(undefined)
|
|
124
|
-
setActive(0)
|
|
125
|
-
}
|
|
126
|
-
}, [open])
|
|
127
|
-
|
|
128
|
-
// ─── Fetch with debounce + in-flight seq ─────────────
|
|
129
|
-
// Mirrors Plan #5 FormStateContext: refs (not state) for the seq
|
|
130
|
-
// counters so React StrictMode dev double-invokes don't produce
|
|
131
|
-
// stale closures.
|
|
132
|
-
const requestSeqRef = useRef(0)
|
|
133
|
-
const latestSeenRef = useRef(0)
|
|
134
|
-
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
135
|
-
|
|
136
|
-
const runFetch = useCallback(async (q: string) => {
|
|
137
|
-
if (q.trim().length < MIN_QUERY_LENGTH) {
|
|
138
|
-
setResults([])
|
|
139
|
-
setRenderHooks(undefined)
|
|
140
|
-
setLoading(false)
|
|
141
|
-
return
|
|
142
|
-
}
|
|
143
|
-
const seq = ++requestSeqRef.current
|
|
144
|
-
const doFetch = fetchImpl ?? fetch
|
|
145
|
-
setLoading(true)
|
|
146
|
-
try {
|
|
147
|
-
const url = `${basePath}/_search?q=${encodeURIComponent(q)}`
|
|
148
|
-
const res = await doFetch(url, {
|
|
149
|
-
method: 'GET',
|
|
150
|
-
headers: { 'Accept': 'application/json' },
|
|
151
|
-
})
|
|
152
|
-
if (seq < latestSeenRef.current) return
|
|
153
|
-
latestSeenRef.current = seq
|
|
154
|
-
if (!res.ok) {
|
|
155
|
-
setResults([])
|
|
156
|
-
setRenderHooks(undefined)
|
|
157
|
-
return
|
|
158
|
-
}
|
|
159
|
-
const data = await res.json().catch(() => null) as SearchResponse | null
|
|
160
|
-
if (!data?.ok) {
|
|
161
|
-
setResults([])
|
|
162
|
-
setRenderHooks(undefined)
|
|
163
|
-
return
|
|
164
|
-
}
|
|
165
|
-
setResults(data.results ?? [])
|
|
166
|
-
setRenderHooks(data.renderHooks)
|
|
167
|
-
setActive(0)
|
|
168
|
-
} catch {
|
|
169
|
-
setResults([])
|
|
170
|
-
setRenderHooks(undefined)
|
|
171
|
-
} finally {
|
|
172
|
-
// Only flip loading off when this is the latest in-flight.
|
|
173
|
-
if (seq === requestSeqRef.current) setLoading(false)
|
|
174
|
-
}
|
|
175
|
-
}, [basePath, fetchImpl])
|
|
176
|
-
|
|
177
|
-
// Debounce on query change.
|
|
178
|
-
useEffect(() => {
|
|
179
|
-
if (debounceRef.current) clearTimeout(debounceRef.current)
|
|
180
|
-
if (!open) return
|
|
181
|
-
debounceRef.current = setTimeout(() => {
|
|
182
|
-
void runFetch(query)
|
|
183
|
-
}, DEBOUNCE_MS)
|
|
184
|
-
return () => {
|
|
185
|
-
if (debounceRef.current) clearTimeout(debounceRef.current)
|
|
186
|
-
}
|
|
187
|
-
}, [query, open, runFetch])
|
|
188
|
-
|
|
189
|
-
// ─── Compose the entry list shown in the palette ─────
|
|
190
|
-
const entries = useMemo<PaletteEntry[]>(() => {
|
|
191
|
-
if (query.trim().length >= MIN_QUERY_LENGTH) {
|
|
192
|
-
return results.map((r, i) => {
|
|
193
|
-
const entry: PaletteEntry = {
|
|
194
|
-
kind: 'result',
|
|
195
|
-
group: r.resourceLabel,
|
|
196
|
-
title: r.title,
|
|
197
|
-
url: r.url,
|
|
198
|
-
key: `${r.resource}:${r.id}:${i}`,
|
|
199
|
-
}
|
|
200
|
-
if (r.subtitle !== undefined) entry.subtitle = r.subtitle
|
|
201
|
-
if (r.icon !== undefined) entry.icon = r.icon
|
|
202
|
-
return entry
|
|
203
|
-
})
|
|
204
|
-
}
|
|
205
|
-
// Empty-input state: flatten navigation tree.
|
|
206
|
-
return flattenNavigation(navigation ?? [])
|
|
207
|
-
}, [query, results, navigation])
|
|
208
|
-
|
|
209
|
-
// ─── Keyboard navigation ─────────────────────────────
|
|
210
|
-
const onKeyDown = useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
211
|
-
if (e.key === 'ArrowDown') {
|
|
212
|
-
e.preventDefault()
|
|
213
|
-
setActive((i) => Math.min(i + 1, Math.max(0, entries.length - 1)))
|
|
214
|
-
} else if (e.key === 'ArrowUp') {
|
|
215
|
-
e.preventDefault()
|
|
216
|
-
setActive((i) => Math.max(i - 1, 0))
|
|
217
|
-
} else if (e.key === 'Enter') {
|
|
218
|
-
e.preventDefault()
|
|
219
|
-
const entry = entries[active]
|
|
220
|
-
if (entry) {
|
|
221
|
-
setOpen(false)
|
|
222
|
-
// Defer the navigate so the close transition fires first.
|
|
223
|
-
Promise.resolve().then(() => go(entry.url))
|
|
224
|
-
}
|
|
225
|
-
} else if (e.key === 'Escape') {
|
|
226
|
-
setOpen(false)
|
|
227
|
-
}
|
|
228
|
-
}, [entries, active, go])
|
|
229
|
-
|
|
230
|
-
// Hooks render only when the user is actively searching (>= MIN_QUERY_LENGTH);
|
|
231
|
-
// empty-input nav state stays clean — chrome / nav slots cover that elsewhere.
|
|
232
|
-
const showHooks = query.trim().length >= MIN_QUERY_LENGTH
|
|
233
|
-
|
|
234
|
-
// ─── Group entries for rendering ─────────────────────
|
|
235
|
-
const grouped = useMemo(() => {
|
|
236
|
-
const map = new Map<string, PaletteEntry[]>()
|
|
237
|
-
for (const e of entries) {
|
|
238
|
-
const arr = map.get(e.group) ?? []
|
|
239
|
-
arr.push(e)
|
|
240
|
-
map.set(e.group, arr)
|
|
241
|
-
}
|
|
242
|
-
return [...map.entries()]
|
|
243
|
-
}, [entries])
|
|
244
|
-
|
|
245
|
-
return (
|
|
246
|
-
<Dialog open={open} onOpenChange={setOpen}>
|
|
247
|
-
<DialogContent className="max-w-xl p-0 gap-0 overflow-hidden">
|
|
248
|
-
<div className="flex items-center gap-2 border-b border-border px-4 py-3">
|
|
249
|
-
<SearchIcon className="size-4 text-muted-foreground" aria-hidden="true" />
|
|
250
|
-
<input
|
|
251
|
-
type="text"
|
|
252
|
-
autoFocus
|
|
253
|
-
placeholder="Search resources, records, or pages…"
|
|
254
|
-
value={query}
|
|
255
|
-
onChange={(e) => setQuery(e.target.value)}
|
|
256
|
-
onKeyDown={onKeyDown}
|
|
257
|
-
className="flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
|
|
258
|
-
aria-label="Search"
|
|
259
|
-
/>
|
|
260
|
-
{loading && <span className="text-xs text-muted-foreground">…</span>}
|
|
261
|
-
<kbd className="text-[10px] font-mono text-muted-foreground border border-border rounded px-1 py-0.5">esc</kbd>
|
|
262
|
-
</div>
|
|
263
|
-
|
|
264
|
-
<div className="max-h-96 overflow-y-auto py-1">
|
|
265
|
-
{showHooks && renderHooks?.['panels::global-search.results.before'] && (
|
|
266
|
-
<div className="px-4 py-2">
|
|
267
|
-
<RenderHookSlot name="panels::global-search.results.before" hooks={renderHooks} />
|
|
268
|
-
</div>
|
|
269
|
-
)}
|
|
270
|
-
{entries.length === 0 && (
|
|
271
|
-
<p className="px-4 py-6 text-center text-sm text-muted-foreground">
|
|
272
|
-
{query.trim().length < MIN_QUERY_LENGTH
|
|
273
|
-
? 'Type to search…'
|
|
274
|
-
: loading
|
|
275
|
-
? 'Searching…'
|
|
276
|
-
: 'No results.'}
|
|
277
|
-
</p>
|
|
278
|
-
)}
|
|
279
|
-
{grouped.map(([group, rows]) => (
|
|
280
|
-
<div key={group}>
|
|
281
|
-
<div className="px-4 pt-3 pb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground">
|
|
282
|
-
{group}
|
|
283
|
-
</div>
|
|
284
|
-
<ul role="listbox">
|
|
285
|
-
{rows.map((entry) => {
|
|
286
|
-
const flatIdx = entries.indexOf(entry)
|
|
287
|
-
const isActive = flatIdx === active
|
|
288
|
-
return (
|
|
289
|
-
<li key={entry.key}>
|
|
290
|
-
<button
|
|
291
|
-
type="button"
|
|
292
|
-
role="option"
|
|
293
|
-
aria-selected={isActive}
|
|
294
|
-
onMouseEnter={() => setActive(flatIdx)}
|
|
295
|
-
onClick={() => {
|
|
296
|
-
setOpen(false)
|
|
297
|
-
Promise.resolve().then(() => go(entry.url))
|
|
298
|
-
}}
|
|
299
|
-
className={[
|
|
300
|
-
'flex w-full items-center gap-3 px-4 py-2 text-left text-sm transition',
|
|
301
|
-
isActive ? 'bg-accent text-accent-foreground' : 'hover:bg-muted',
|
|
302
|
-
].join(' ')}
|
|
303
|
-
>
|
|
304
|
-
<PaletteIcon icon={entry.icon} />
|
|
305
|
-
<div className="min-w-0 flex-1">
|
|
306
|
-
<div className="truncate font-medium">{entry.title}</div>
|
|
307
|
-
{entry.subtitle && (
|
|
308
|
-
<div className="truncate text-xs text-muted-foreground">{entry.subtitle}</div>
|
|
309
|
-
)}
|
|
310
|
-
</div>
|
|
311
|
-
{isActive && (
|
|
312
|
-
<CornerDownLeftIcon className="size-3 text-muted-foreground" aria-hidden="true" />
|
|
313
|
-
)}
|
|
314
|
-
</button>
|
|
315
|
-
</li>
|
|
316
|
-
)
|
|
317
|
-
})}
|
|
318
|
-
</ul>
|
|
319
|
-
</div>
|
|
320
|
-
))}
|
|
321
|
-
{showHooks && renderHooks?.['panels::global-search.results.after'] && (
|
|
322
|
-
<div className="px-4 py-2">
|
|
323
|
-
<RenderHookSlot name="panels::global-search.results.after" hooks={renderHooks} />
|
|
324
|
-
</div>
|
|
325
|
-
)}
|
|
326
|
-
</div>
|
|
327
|
-
|
|
328
|
-
<div className="flex items-center justify-between border-t border-border px-4 py-2 text-[10px] text-muted-foreground">
|
|
329
|
-
<span className="flex items-center gap-1">
|
|
330
|
-
<ArrowUpDownIcon className="size-3" aria-hidden="true" />
|
|
331
|
-
navigate
|
|
332
|
-
</span>
|
|
333
|
-
<span className="flex items-center gap-1">
|
|
334
|
-
<CornerDownLeftIcon className="size-3" aria-hidden="true" />
|
|
335
|
-
open
|
|
336
|
-
</span>
|
|
337
|
-
</div>
|
|
338
|
-
</DialogContent>
|
|
339
|
-
</Dialog>
|
|
340
|
-
)
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
function PaletteIcon({ icon }: { icon: SerializedIcon | undefined }) {
|
|
344
|
-
const Icon = useIconFor(icon)
|
|
345
|
-
if (!Icon) {
|
|
346
|
-
return <span className="size-4 rounded bg-muted" aria-hidden="true" />
|
|
347
|
-
}
|
|
348
|
-
return <Icon className="size-4 text-muted-foreground" aria-hidden="true" />
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* Flatten the navigation tree (nested children) into a single PaletteEntry
|
|
353
|
-
* list. Used for the empty-input quick-nav state. Group label is the
|
|
354
|
-
* NavItem's `group` (or `'Navigation'` when unset).
|
|
355
|
-
*/
|
|
356
|
-
function flattenNavigation(items: NavItem[]): PaletteEntry[] {
|
|
357
|
-
const out: PaletteEntry[] = []
|
|
358
|
-
const walk = (nodes: NavItem[], inheritedGroup?: string) => {
|
|
359
|
-
for (const n of nodes) {
|
|
360
|
-
const group = n.group ?? inheritedGroup ?? 'Navigation'
|
|
361
|
-
const entry: PaletteEntry = {
|
|
362
|
-
kind: 'nav',
|
|
363
|
-
group,
|
|
364
|
-
title: n.label,
|
|
365
|
-
url: n.url,
|
|
366
|
-
key: `nav:${n.name}:${n.url}`,
|
|
367
|
-
}
|
|
368
|
-
if (n.icon !== undefined) entry.icon = n.icon
|
|
369
|
-
out.push(entry)
|
|
370
|
-
if (n.children && n.children.length > 0) walk(n.children, group)
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
walk(items)
|
|
374
|
-
return out
|
|
375
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { createContext, useContext, type ReactNode } from 'react'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Resolved identity of the user driving the current page. Mirrors the
|
|
5
|
-
* `UserMenuMeta.user` shape that `panelInfo()` ships to the renderer —
|
|
6
|
-
* whichever fields the `Pilotiq.user(req => …)` resolver populated.
|
|
7
|
-
*
|
|
8
|
-
* `null` is the no-user state: either the panel never wired a resolver,
|
|
9
|
-
* or the resolver returned `null` for this request. Consumers should
|
|
10
|
-
* gracefully fall back (no avatar, no presence label, etc.) rather than
|
|
11
|
-
* treating absence as an error.
|
|
12
|
-
*/
|
|
13
|
-
export interface CurrentUser {
|
|
14
|
-
name?: string
|
|
15
|
-
email?: string
|
|
16
|
-
avatar?: string
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const CurrentUserContext = createContext<CurrentUser | null>(null)
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Mounted by `AppShell` around the layout-provider chain so plugins
|
|
23
|
-
* (collab user presence, audit-trail attribution, analytics
|
|
24
|
-
* client-side opt-outs, …) can read the active user via
|
|
25
|
-
* `useCurrentUser()` without prop-drilling through `panel`.
|
|
26
|
-
*
|
|
27
|
-
* Value source is `viewProps.panel.userMenu?.user` — the same shape the
|
|
28
|
-
* top-right dropdown renders. The provider sits OUTSIDE
|
|
29
|
-
* `layoutProviderRegistry` so plugin-registered layout providers can
|
|
30
|
-
* subscribe.
|
|
31
|
-
*/
|
|
32
|
-
export function CurrentUserProvider({
|
|
33
|
-
value,
|
|
34
|
-
children,
|
|
35
|
-
}: {
|
|
36
|
-
value: CurrentUser | null
|
|
37
|
-
children: ReactNode
|
|
38
|
-
}): ReactNode {
|
|
39
|
-
return <CurrentUserContext.Provider value={value}>{children}</CurrentUserContext.Provider>
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Read the active user inside any descendant of `<AppShell>`. Returns
|
|
44
|
-
* `null` outside an `AppShell` mount (defensive — keeps storybook /
|
|
45
|
-
* isolated-render tests from throwing) and when no user resolved for
|
|
46
|
-
* the request.
|
|
47
|
-
*/
|
|
48
|
-
export function useCurrentUser(): CurrentUser | null {
|
|
49
|
-
return useContext(CurrentUserContext)
|
|
50
|
-
}
|