@pilotiq/pilotiq 0.24.1 → 0.24.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +57 -0
- package/boost/guidelines.md +571 -0
- package/boost/skills/pilotiq-actions/SKILL.md +49 -0
- package/boost/skills/pilotiq-actions/rules/dispatch-modes.md +177 -0
- package/boost/skills/pilotiq-actions/rules/factories.md +130 -0
- package/boost/skills/pilotiq-actions/rules/visibility-and-authorization.md +125 -0
- package/boost/skills/pilotiq-fields/SKILL.md +47 -0
- package/boost/skills/pilotiq-fields/rules/field-catalog.md +288 -0
- package/boost/skills/pilotiq-fields/rules/reactive-fields.md +199 -0
- package/boost/skills/pilotiq-fields/rules/validation.md +198 -0
- package/boost/skills/pilotiq-relations/SKILL.md +47 -0
- package/boost/skills/pilotiq-relations/rules/relation-managers.md +256 -0
- package/boost/skills/pilotiq-relations/rules/repeater-relationship.md +177 -0
- package/boost/skills/pilotiq-resource/SKILL.md +61 -0
- package/boost/skills/pilotiq-resource/rules/authorization.md +242 -0
- package/boost/skills/pilotiq-resource/rules/defining-resources.md +228 -0
- package/boost/skills/pilotiq-resource/rules/page-overrides.md +296 -0
- package/dist/Pilotiq.d.ts +31 -0
- package/dist/Pilotiq.d.ts.map +1 -1
- package/dist/Pilotiq.js +3 -1
- package/dist/Pilotiq.js.map +1 -1
- package/dist/PilotiqRegistry.d.ts +13 -0
- package/dist/PilotiqRegistry.d.ts.map +1 -1
- package/dist/PilotiqRegistry.js +15 -0
- package/dist/PilotiqRegistry.js.map +1 -1
- package/dist/pageData/misc.d.ts.map +1 -1
- package/dist/pageData/misc.js +6 -0
- package/dist/pageData/misc.js.map +1 -1
- package/dist/pageData/navigation.d.ts +1 -0
- package/dist/pageData/navigation.d.ts.map +1 -1
- package/dist/pageData/navigation.js +3 -0
- package/dist/pageData/navigation.js.map +1 -1
- package/dist/pageData/relationPages.d.ts.map +1 -1
- package/dist/pageData/relationPages.js +3 -0
- package/dist/pageData/relationPages.js.map +1 -1
- package/dist/pageData/resourcePages.d.ts.map +1 -1
- package/dist/pageData/resourcePages.js +8 -0
- package/dist/pageData/resourcePages.js.map +1 -1
- package/dist/react/AppShell.d.ts +8 -0
- package/dist/react/AppShell.d.ts.map +1 -1
- package/dist/react/AppShell.js.map +1 -1
- package/dist/react/layouts/SidebarLayout.d.ts.map +1 -1
- package/dist/react/layouts/SidebarLayout.js +10 -2
- package/dist/react/layouts/SidebarLayout.js.map +1 -1
- package/dist/react/widgets/StatsOverviewRenderer.d.ts.map +1 -1
- package/dist/react/widgets/StatsOverviewRenderer.js +32 -18
- package/dist/react/widgets/StatsOverviewRenderer.js.map +1 -1
- package/dist/routes/relations.d.ts.map +1 -1
- package/dist/routes/relations.js +25 -18
- package/dist/routes/relations.js.map +1 -1
- package/dist/routes/resources.js.map +1 -1
- package/package.json +10 -5
- package/.turbo/turbo-build.log +0 -8
- package/CLAUDE.md +0 -265
- package/src/Cluster.test.ts +0 -283
- package/src/Cluster.ts +0 -83
- package/src/Column.test.ts +0 -199
- package/src/Column.ts +0 -710
- package/src/Global.test.ts +0 -367
- package/src/Global.ts +0 -169
- package/src/Page.test.ts +0 -114
- package/src/Page.ts +0 -208
- package/src/Pilotiq.perf.test.ts +0 -252
- package/src/Pilotiq.test.ts +0 -129
- package/src/Pilotiq.ts +0 -1158
- package/src/PilotiqRegistry.ts +0 -36
- package/src/PilotiqServiceProvider.ts +0 -121
- package/src/RelationManager.test.ts +0 -400
- package/src/RelationManager.ts +0 -527
- package/src/RenderHook.test.ts +0 -252
- package/src/RenderHook.ts +0 -242
- package/src/Resource.test.ts +0 -284
- package/src/Resource.ts +0 -526
- package/src/RightPanel.test.ts +0 -202
- package/src/RightPanel.ts +0 -132
- package/src/Tab.test.ts +0 -91
- package/src/Tab.ts +0 -156
- package/src/UserMenuItem.ts +0 -145
- package/src/actions/Action.test.ts +0 -2526
- package/src/actions/Action.ts +0 -1515
- package/src/actions/ActionGroup.test.ts +0 -112
- package/src/actions/ActionGroup.ts +0 -173
- package/src/actions/attachFactory.ts +0 -172
- package/src/actions/bulkFactories.ts +0 -168
- package/src/actions/crudFactories.ts +0 -220
- package/src/actions/exportFactory.ts +0 -225
- package/src/actions/factoryHelpers.ts +0 -177
- package/src/actions/importFactory.ts +0 -243
- package/src/actions/index.ts +0 -17
- package/src/actions/m2mFactories.ts +0 -193
- package/src/actions/relationFactories.ts +0 -372
- package/src/applyPageHooks.test.ts +0 -463
- package/src/applyPageHooks.ts +0 -330
- package/src/authorization.test.ts +0 -483
- package/src/breadcrumbs.test.ts +0 -238
- package/src/cells/coerce.test.ts +0 -85
- package/src/cells/coerce.ts +0 -84
- package/src/clusterPaths.ts +0 -35
- package/src/columns/BadgeColumn.test.ts +0 -54
- package/src/columns/BadgeColumn.ts +0 -32
- package/src/columns/BooleanColumn.test.ts +0 -41
- package/src/columns/BooleanColumn.ts +0 -18
- package/src/columns/ColorColumn.test.ts +0 -37
- package/src/columns/ColorColumn.ts +0 -38
- package/src/columns/IconColumn.test.ts +0 -54
- package/src/columns/IconColumn.ts +0 -37
- package/src/columns/ImageColumn.test.ts +0 -41
- package/src/columns/ImageColumn.ts +0 -28
- package/src/columns/SelectColumn.ts +0 -98
- package/src/columns/TextColumn.test.ts +0 -190
- package/src/columns/TextColumn.ts +0 -20
- package/src/columns/TextInputColumn.ts +0 -68
- package/src/columns/ToggleColumn.ts +0 -46
- package/src/columns/editableColumns.test.ts +0 -238
- package/src/columns/index.ts +0 -9
- package/src/defaultGlobalPages.ts +0 -95
- package/src/defaultPages.test.ts +0 -634
- package/src/defaultPages.ts +0 -617
- package/src/defaultViewPage.test.ts +0 -147
- package/src/elements/Form.test.ts +0 -223
- package/src/elements/Form.ts +0 -416
- package/src/elements/ListTabs.ts +0 -28
- package/src/elements/Table.test.ts +0 -422
- package/src/elements/Table.ts +0 -850
- package/src/elements/TableGroup.test.ts +0 -260
- package/src/elements/TableGroup.ts +0 -334
- package/src/elements/dispatchAction.test.ts +0 -463
- package/src/elements/dispatchAction.ts +0 -355
- package/src/elements/dispatchForm.test.ts +0 -477
- package/src/elements/dispatchForm.ts +0 -1993
- package/src/elements/dispatchTable.test.ts +0 -1514
- package/src/elements/dispatchTable.ts +0 -745
- package/src/elements/index.ts +0 -21
- package/src/entries/BadgeEntry.ts +0 -39
- package/src/entries/CodeEntry.test.ts +0 -40
- package/src/entries/CodeEntry.ts +0 -52
- package/src/entries/ColorEntry.ts +0 -63
- package/src/entries/ComponentEntry.test.ts +0 -173
- package/src/entries/ComponentEntry.ts +0 -95
- package/src/entries/Entry.ts +0 -304
- package/src/entries/IconEntry.ts +0 -49
- package/src/entries/ImageEntry.ts +0 -61
- package/src/entries/KeyValueEntry.ts +0 -47
- package/src/entries/RepeatableEntry.test.ts +0 -239
- package/src/entries/RepeatableEntry.ts +0 -173
- package/src/entries/TextEntry.test.ts +0 -394
- package/src/entries/TextEntry.ts +0 -60
- package/src/entries/index.ts +0 -12
- package/src/entries/leaves.test.ts +0 -306
- package/src/entries/registry.ts +0 -54
- package/src/fields/BuilderField.test.ts +0 -1188
- package/src/fields/BuilderField.ts +0 -605
- package/src/fields/BuilderRelationship.test.ts +0 -811
- package/src/fields/CheckboxField.test.ts +0 -44
- package/src/fields/CheckboxField.ts +0 -27
- package/src/fields/CheckboxListField.test.ts +0 -99
- package/src/fields/CheckboxListField.ts +0 -66
- package/src/fields/ColorPickerField.test.ts +0 -33
- package/src/fields/ColorPickerField.ts +0 -25
- package/src/fields/DateField.ts +0 -54
- package/src/fields/DateTimeField.test.ts +0 -55
- package/src/fields/EmailField.ts +0 -16
- package/src/fields/Field.test.ts +0 -654
- package/src/fields/Field.ts +0 -817
- package/src/fields/FileUploadField.test.ts +0 -143
- package/src/fields/FileUploadField.ts +0 -159
- package/src/fields/HiddenField.test.ts +0 -27
- package/src/fields/HiddenField.ts +0 -28
- package/src/fields/KeyValueField.test.ts +0 -105
- package/src/fields/KeyValueField.ts +0 -55
- package/src/fields/MarkdownField.test.ts +0 -167
- package/src/fields/MarkdownField.ts +0 -162
- package/src/fields/NumberField.ts +0 -33
- package/src/fields/RadioField.test.ts +0 -94
- package/src/fields/RadioField.ts +0 -67
- package/src/fields/RepeaterField.test.ts +0 -1806
- package/src/fields/RepeaterField.ts +0 -939
- package/src/fields/RepeaterRelationship.test.ts +0 -1923
- package/src/fields/RepeaterSimple.test.ts +0 -248
- package/src/fields/RowButton.test.ts +0 -219
- package/src/fields/RowButton.ts +0 -135
- package/src/fields/SelectField.test.ts +0 -192
- package/src/fields/SelectField.ts +0 -235
- package/src/fields/SliderField.test.ts +0 -50
- package/src/fields/SliderField.ts +0 -53
- package/src/fields/SlugField.ts +0 -24
- package/src/fields/TagsInputField.test.ts +0 -154
- package/src/fields/TagsInputField.ts +0 -133
- package/src/fields/TextField.test.ts +0 -213
- package/src/fields/TextField.ts +0 -177
- package/src/fields/TextareaField.test.ts +0 -58
- package/src/fields/TextareaField.ts +0 -59
- package/src/fields/ToggleButtonsField.test.ts +0 -106
- package/src/fields/ToggleButtonsField.ts +0 -59
- package/src/fields/ToggleField.ts +0 -16
- package/src/fields/disableOptionsWhenSelectedInSiblingRepeaterItems.test.ts +0 -319
- package/src/fields/optionsResolver.ts +0 -95
- package/src/fields/resolveField.ts +0 -28
- package/src/filters/BooleanFilter.ts +0 -35
- package/src/filters/DateRangeFilter.test.ts +0 -194
- package/src/filters/DateRangeFilter.ts +0 -148
- package/src/filters/Filter.test.ts +0 -268
- package/src/filters/Filter.ts +0 -184
- package/src/filters/FormFilter.test.ts +0 -238
- package/src/filters/FormFilter.ts +0 -215
- package/src/filters/MultiSelectFilter.test.ts +0 -119
- package/src/filters/MultiSelectFilter.ts +0 -78
- package/src/filters/QueryBuilderFilter.test.ts +0 -662
- package/src/filters/QueryBuilderFilter.ts +0 -398
- package/src/filters/SelectFilter.ts +0 -46
- package/src/filters/TernaryFilter.test.ts +0 -160
- package/src/filters/TernaryFilter.ts +0 -72
- package/src/filters/TrashedFilter.test.ts +0 -149
- package/src/filters/TrashedFilter.ts +0 -55
- package/src/filters/queryBuilder/BooleanConstraint.ts +0 -31
- package/src/filters/queryBuilder/Constraint.ts +0 -115
- package/src/filters/queryBuilder/DateConstraint.ts +0 -69
- package/src/filters/queryBuilder/NumberConstraint.ts +0 -66
- package/src/filters/queryBuilder/SelectConstraint.ts +0 -72
- package/src/filters/queryBuilder/TextConstraint.ts +0 -64
- package/src/filters/queryBuilder/index.ts +0 -12
- package/src/icons/index.ts +0 -2
- package/src/icons/lucide.ts +0 -204
- package/src/icons/registry.test.ts +0 -56
- package/src/icons/registry.ts +0 -41
- package/src/icons/types.ts +0 -47
- package/src/index.ts +0 -525
- package/src/io/csv.test.ts +0 -142
- package/src/io/csv.ts +0 -170
- package/src/nestedRelationManagerData.test.ts +0 -547
- package/src/notifications/Notification.test.ts +0 -210
- package/src/notifications/Notification.ts +0 -354
- package/src/notifications/broadcast.test.ts +0 -110
- package/src/notifications/broadcast.ts +0 -95
- package/src/notifications/database.test.ts +0 -383
- package/src/notifications/database.ts +0 -398
- package/src/notifications/databaseNotifications.test.ts +0 -187
- package/src/notifications/dispatchNotificationAction.test.ts +0 -341
- package/src/notifications/dispatchNotificationAction.ts +0 -142
- package/src/notifications/flash.test.ts +0 -89
- package/src/notifications/flash.ts +0 -71
- package/src/notifications/index.ts +0 -45
- package/src/notifications/registerBroadcastAuth.test.ts +0 -134
- package/src/notifications/registerBroadcastAuth.ts +0 -100
- package/src/notifications/resolveSavedNotification.test.ts +0 -82
- package/src/notifications/resolveSavedNotification.ts +0 -59
- package/src/notifications/types.ts +0 -93
- package/src/orm/m2mAccessor.ts +0 -66
- package/src/orm/modelDefaults.test.ts +0 -633
- package/src/orm/modelDefaults.ts +0 -666
- package/src/pageData/breadcrumbs.ts +0 -288
- package/src/pageData/forms.ts +0 -578
- package/src/pageData/helpers.ts +0 -857
- package/src/pageData/misc.ts +0 -347
- package/src/pageData/navigation.ts +0 -842
- package/src/pageData/relationPages.ts +0 -1248
- package/src/pageData/relationTabs.ts +0 -286
- package/src/pageData/resourcePages.ts +0 -609
- package/src/pageData.test.ts +0 -1545
- package/src/pageData.ts +0 -341
- package/src/plugins/index.ts +0 -8
- package/src/plugins/themeEditor.test.ts +0 -36
- package/src/plugins/themeEditor.ts +0 -45
- package/src/react/AppShell.tsx +0 -251
- package/src/react/CollabExtensionFactoryRegistry.ts +0 -55
- package/src/react/CollabRoomContext.ts +0 -98
- package/src/react/CollabTextRendererRegistry.ts +0 -102
- package/src/react/CommandPalette.tsx +0 -375
- package/src/react/CurrentUserContext.tsx +0 -50
- package/src/react/CustomPageWrapperGate.tsx +0 -69
- package/src/react/CustomPageWrapperRegistry.ts +0 -45
- package/src/react/FieldFocusReporterRegistry.ts +0 -37
- package/src/react/FieldLabelSlotRegistry.ts +0 -30
- package/src/react/FieldPresenceRegistry.ts +0 -46
- package/src/react/FormCollabBindingRegistry.ts +0 -242
- package/src/react/FormStateContext.tsx +0 -591
- package/src/react/HeadHooks.tsx +0 -126
- package/src/react/MarkdownEditorRegistry.test.ts +0 -38
- package/src/react/MarkdownEditorRegistry.ts +0 -107
- package/src/react/NotificationActionStrip.tsx +0 -263
- package/src/react/NotificationBell.tsx +0 -426
- package/src/react/PendingSuggestionApplierRegistry.test.ts +0 -97
- package/src/react/PendingSuggestionApplierRegistry.ts +0 -98
- package/src/react/PendingSuggestionOverlayRegistry.ts +0 -54
- package/src/react/PendingSuggestionsContext.tsx +0 -172
- package/src/react/RecordWrapperGate.tsx +0 -58
- package/src/react/RecordWrapperRegistry.ts +0 -39
- package/src/react/RenderHookSlot.tsx +0 -32
- package/src/react/RightSidebar.tsx +0 -257
- package/src/react/RightSidebarContext.tsx +0 -234
- package/src/react/RightSidebarTrigger.tsx +0 -53
- package/src/react/RowCoordsContext.tsx +0 -23
- package/src/react/SchemaRenderer.tsx +0 -549
- package/src/react/SearchTrigger.tsx +0 -46
- package/src/react/ThemeProvider.tsx +0 -93
- package/src/react/ThemeSettingsPage.tsx +0 -579
- package/src/react/ThemeToggle.tsx +0 -20
- package/src/react/Toaster.tsx +0 -158
- package/src/react/UserMenu.tsx +0 -196
- package/src/react/WidgetDataContext.tsx +0 -157
- package/src/react/cells/EditableCell.tsx +0 -389
- package/src/react/component-slots.test.ts +0 -103
- package/src/react/component-slots.ts +0 -116
- package/src/react/fieldJsHandler.test.ts +0 -166
- package/src/react/fieldJsHandler.ts +0 -79
- package/src/react/fields/BuilderInput.tsx +0 -1078
- package/src/react/fields/CheckboxInput.tsx +0 -39
- package/src/react/fields/CheckboxListInput.tsx +0 -102
- package/src/react/fields/ColorInput.tsx +0 -71
- package/src/react/fields/DateFieldInput.tsx +0 -70
- package/src/react/fields/DateTimeInput.tsx +0 -62
- package/src/react/fields/FieldShell.tsx +0 -348
- package/src/react/fields/FileUploadInput.tsx +0 -639
- package/src/react/fields/HiddenInput.tsx +0 -17
- package/src/react/fields/KeyValueInput.tsx +0 -230
- package/src/react/fields/MarkdownInput.tsx +0 -560
- package/src/react/fields/RadioInput.tsx +0 -81
- package/src/react/fields/RepeaterInput.test.ts +0 -116
- package/src/react/fields/RepeaterInput.tsx +0 -1420
- package/src/react/fields/SelectFieldInput.tsx +0 -280
- package/src/react/fields/SliderInput.tsx +0 -81
- package/src/react/fields/TagsInput.tsx +0 -283
- package/src/react/fields/TextLikeInput.tsx +0 -256
- package/src/react/fields/ToggleButtonsInput.tsx +0 -60
- package/src/react/fields/ToggleFieldInput.tsx +0 -56
- package/src/react/fields/relationshipRenameDispatch.test.ts +0 -106
- package/src/react/fields/relationshipRenameDispatch.ts +0 -97
- package/src/react/fields/repeaterReconcile.test.ts +0 -114
- package/src/react/fields/repeaterReconcile.ts +0 -104
- package/src/react/fields/rowChromeButton.tsx +0 -336
- package/src/react/fields/rowState.ts +0 -106
- package/src/react/fields/syncRowGates.test.ts +0 -202
- package/src/react/fields/syncRowGates.ts +0 -66
- package/src/react/fields/textInputControls.tsx +0 -238
- package/src/react/fields/useRowReorderDnd.ts +0 -78
- package/src/react/formStateHelpers.test.ts +0 -508
- package/src/react/formStateHelpers.ts +0 -381
- package/src/react/hooks/use-mobile.ts +0 -19
- package/src/react/icon-context.tsx +0 -60
- package/src/react/index.ts +0 -194
- package/src/react/layouts/SidebarLayout.tsx +0 -250
- package/src/react/layouts/TopbarLayout.tsx +0 -258
- package/src/react/navigate.tsx +0 -37
- package/src/react/onProviderSynced.test.ts +0 -90
- package/src/react/parseRecordEditUrl.test.ts +0 -122
- package/src/react/parseRecordEditUrl.ts +0 -94
- package/src/react/persistedState.ts +0 -40
- package/src/react/registry.ts +0 -48
- package/src/react/right-panel-registry.tsx +0 -47
- package/src/react/schemaRenderer/AlertRenderer.tsx +0 -112
- package/src/react/schemaRenderer/EntryRenderer.tsx +0 -501
- package/src/react/schemaRenderer/SectionRenderer.tsx +0 -120
- package/src/react/schemaRenderer/SimpleElements.tsx +0 -306
- package/src/react/schemaRenderer/TabsRenderer.tsx +0 -62
- package/src/react/schemaRenderer/WizardRenderer.tsx +0 -338
- package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +0 -177
- package/src/react/schemaRenderer/action/ActionModalDialog.tsx +0 -273
- package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +0 -61
- package/src/react/schemaRenderer/action/HandlerActionButton.tsx +0 -43
- package/src/react/schemaRenderer/action/MethodActionButton.tsx +0 -64
- package/src/react/schemaRenderer/action/buttons.tsx +0 -99
- package/src/react/schemaRenderer/action/helpers.ts +0 -140
- package/src/react/schemaRenderer/action/renderAction.tsx +0 -245
- package/src/react/schemaRenderer/columnFormat.ts +0 -65
- package/src/react/schemaRenderer/constants.ts +0 -50
- package/src/react/schemaRenderer/form/FormRenderer.tsx +0 -274
- package/src/react/schemaRenderer/form/renderField.tsx +0 -511
- package/src/react/schemaRenderer/helpers.tsx +0 -81
- package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +0 -308
- package/src/react/schemaRenderer/table/TableRenderer.tsx +0 -123
- package/src/react/schemaRenderer/table/TableRendererBody.tsx +0 -974
- package/src/react/schemaRenderer/table/filters.tsx +0 -1233
- package/src/react/schemaRenderer/table/formatCell.tsx +0 -264
- package/src/react/schemaRenderer/table/links.tsx +0 -112
- package/src/react/schemaRenderer/table/renderRowActions.tsx +0 -52
- package/src/react/schemaRenderer/table/url.tsx +0 -143
- package/src/react/theme-preview/apply.ts +0 -99
- package/src/react/theme-preview/build-html.ts +0 -436
- package/src/react/ui/button.tsx +0 -51
- package/src/react/ui/calendar.tsx +0 -67
- package/src/react/ui/checkbox.tsx +0 -29
- package/src/react/ui/dialog.tsx +0 -108
- package/src/react/ui/dropdown-menu.tsx +0 -97
- package/src/react/ui/input.tsx +0 -20
- package/src/react/ui/label.tsx +0 -21
- package/src/react/ui/popover.tsx +0 -50
- package/src/react/ui/select.tsx +0 -169
- package/src/react/ui/separator.tsx +0 -25
- package/src/react/ui/sheet.tsx +0 -136
- package/src/react/ui/sidebar.tsx +0 -723
- package/src/react/ui/skeleton.tsx +0 -13
- package/src/react/ui/slider.tsx +0 -34
- package/src/react/ui/switch.tsx +0 -28
- package/src/react/ui/table.tsx +0 -105
- package/src/react/ui/tabs.tsx +0 -63
- package/src/react/ui/textarea.tsx +0 -18
- package/src/react/ui/tooltip.tsx +0 -64
- package/src/react/useResizableWidth.ts +0 -139
- package/src/react/utils.ts +0 -6
- package/src/react/widgetRegistry.test.ts +0 -43
- package/src/react/widgetRegistry.ts +0 -50
- package/src/react/widgets/StatsOverviewRenderer.tsx +0 -232
- package/src/react/widgets/TableWidgetRenderer.tsx +0 -231
- package/src/react/widgets/ViewRenderer.tsx +0 -71
- package/src/relationManagerData.test.ts +0 -1595
- package/src/richtext/index.ts +0 -8
- package/src/richtext/registry.ts +0 -89
- package/src/routes/globals.ts +0 -148
- package/src/routes/guard.test.ts +0 -325
- package/src/routes/helpers.ts +0 -704
- package/src/routes/pages.ts +0 -175
- package/src/routes/panel.ts +0 -204
- package/src/routes/relations.ts +0 -1243
- package/src/routes/resources.ts +0 -781
- package/src/routes/theme.ts +0 -91
- package/src/routes-nested-relations.test.ts +0 -676
- package/src/routes-relations.test.ts +0 -972
- package/src/routes.test.ts +0 -2027
- package/src/routes.ts +0 -303
- package/src/schema/Alert.test.ts +0 -109
- package/src/schema/Alert.ts +0 -131
- package/src/schema/Block.ts +0 -169
- package/src/schema/Breadcrumbs.ts +0 -40
- package/src/schema/Card.ts +0 -35
- package/src/schema/Divider.ts +0 -20
- package/src/schema/Element.ts +0 -219
- package/src/schema/EmptyState.test.ts +0 -37
- package/src/schema/EmptyState.ts +0 -63
- package/src/schema/Fieldset.ts +0 -43
- package/src/schema/Grid.ts +0 -43
- package/src/schema/Group.ts +0 -30
- package/src/schema/Heading.ts +0 -39
- package/src/schema/Html.ts +0 -67
- package/src/schema/Icon.ts +0 -54
- package/src/schema/Image.ts +0 -57
- package/src/schema/LinkTag.ts +0 -41
- package/src/schema/Markdown.ts +0 -85
- package/src/schema/MetaTag.ts +0 -41
- package/src/schema/RelationTabs.ts +0 -71
- package/src/schema/ScriptTag.ts +0 -55
- package/src/schema/Section.ts +0 -160
- package/src/schema/ServerDataElement.test.ts +0 -140
- package/src/schema/ServerDataElement.ts +0 -156
- package/src/schema/SlotComponent.test.ts +0 -77
- package/src/schema/SlotComponent.ts +0 -71
- package/src/schema/Split.ts +0 -50
- package/src/schema/Stat.test.ts +0 -118
- package/src/schema/Stat.ts +0 -154
- package/src/schema/StatsOverview.test.ts +0 -141
- package/src/schema/StatsOverview.ts +0 -119
- package/src/schema/StyleTag.ts +0 -35
- package/src/schema/TableWidget.test.ts +0 -297
- package/src/schema/TableWidget.ts +0 -289
- package/src/schema/Tabs.ts +0 -79
- package/src/schema/Text.ts +0 -58
- package/src/schema/UnorderedList.ts +0 -49
- package/src/schema/View.test.ts +0 -111
- package/src/schema/View.ts +0 -127
- package/src/schema/Wizard.ts +0 -220
- package/src/schema/containers.test.ts +0 -564
- package/src/schema/headTags.test.ts +0 -134
- package/src/schema/index.ts +0 -40
- package/src/schema/primes.test.ts +0 -269
- package/src/schema/resolveSchema.test.ts +0 -379
- package/src/schema/resolveSchema.ts +0 -917
- package/src/schema/sanitize.ts +0 -58
- package/src/search.test.ts +0 -446
- package/src/search.ts +0 -178
- package/src/sessionFilters.test.ts +0 -375
- package/src/sessionFilters.ts +0 -143
- package/src/slot-components/index.ts +0 -10
- package/src/slot-components/registry.ts +0 -56
- package/src/styles/file-upload.css +0 -13
- package/src/summarizers/Summarizer.test.ts +0 -84
- package/src/summarizers/Summarizer.ts +0 -123
- package/src/summarizers/index.ts +0 -11
- package/src/theme/base-colors.ts +0 -68
- package/src/theme/chart-colors.ts +0 -50
- package/src/theme/colors.ts +0 -447
- package/src/theme/generate-css.test.ts +0 -139
- package/src/theme/generate-css.ts +0 -44
- package/src/theme/generate-scale.test.ts +0 -106
- package/src/theme/generate-scale.ts +0 -97
- package/src/theme/icon-map.ts +0 -42
- package/src/theme/index.ts +0 -34
- package/src/theme/migrate.test.ts +0 -178
- package/src/theme/migrate.ts +0 -81
- package/src/theme/presets.ts +0 -135
- package/src/theme/radius.ts +0 -18
- package/src/theme/resolve.test.ts +0 -238
- package/src/theme/resolve.ts +0 -96
- package/src/theme/spacing.ts +0 -18
- package/src/theme/storage.test.ts +0 -126
- package/src/theme/storage.ts +0 -106
- package/src/theme/theme-colors.ts +0 -88
- package/src/theme/types.ts +0 -125
- package/src/uploads/UploadAdapter.ts +0 -35
- package/src/uploads/index.ts +0 -2
- package/src/uploads/localUpload.test.ts +0 -70
- package/src/uploads/localUpload.ts +0 -84
- package/src/validation/Validator.ts +0 -49
- package/src/validation/index.ts +0 -28
- package/src/validation/rules.ts +0 -78
- package/src/validation/runValidators.ts +0 -435
- package/src/validation/uniqueValidator.test.ts +0 -196
- package/src/validation/uniqueValidator.ts +0 -133
- package/src/validation/validators.test.ts +0 -268
- package/src/vite.test.ts +0 -184
- package/src/vite.ts +0 -787
- package/src/widgets/index.ts +0 -10
- package/src/widgets/registry.ts +0 -45
- package/src/widgets.test.ts +0 -592
- package/tsconfig.build.json +0 -11
- package/tsconfig.json +0 -4
- package/tsconfig.test.json +0 -10
- package/views/react/Dashboard.tsx +0 -27
- package/views/react/Resources/Form.tsx +0 -102
- package/views/react/Resources/Index.tsx +0 -49
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import React, { createContext, useContext, useMemo } from 'react'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* One AI- (or extension-) sourced suggested field-value change. Sits in a
|
|
5
|
-
* unified queue read by:
|
|
6
|
-
*
|
|
7
|
-
* - the Tiptap `RichTextField` renderer — for `richtext` fields, the
|
|
8
|
-
* suggestion is mirrored into the editor's `AiSuggestion` extension as
|
|
9
|
-
* an inline diff with per-hunk Approve/Reject chips
|
|
10
|
-
* - `FieldShell`'s overlay slot — for any other field type, a registered
|
|
11
|
-
* overlay component renders a `currentValue` vs `suggestedValue` diff
|
|
12
|
-
* card below the input
|
|
13
|
-
* - aggregate "Pending suggestions" pills (e.g. in a chat sidebar) — read
|
|
14
|
-
* the full list to show counts + bulk approve / reject affordances
|
|
15
|
-
*
|
|
16
|
-
* The shape is intentionally generic — the `meta` bag carries field-type-
|
|
17
|
-
* specific extras (e.g. `editorRange: { from, to }` for `richtext`).
|
|
18
|
-
*
|
|
19
|
-
* Pilotiq core does NOT push or apply suggestions itself. The provider
|
|
20
|
-
* implementation + push paths live in plugin packages (e.g.
|
|
21
|
-
* `@pilotiq-pro/ai`); core just owns the type, context, and hooks so any
|
|
22
|
-
* field renderer can subscribe through one open-core seam.
|
|
23
|
-
*/
|
|
24
|
-
/**
|
|
25
|
-
* Where a suggestion came from. Lets aggregate consumers (pill UIs)
|
|
26
|
-
* filter the shared queue by surface — e.g. a popover-chat scoped pill
|
|
27
|
-
* shows only suggestions produced by its own session, while the
|
|
28
|
-
* sidebar pill shows everything. Sparse on push; consumers treat
|
|
29
|
-
* absence as "unknown origin, include in unfiltered views".
|
|
30
|
-
*/
|
|
31
|
-
export interface PendingSuggestionOrigin {
|
|
32
|
-
/**
|
|
33
|
-
* Which UI surface initiated the agent run that produced this
|
|
34
|
-
* suggestion. `'field-action'` covers the `✦` per-field dropdown.
|
|
35
|
-
*/
|
|
36
|
-
surface: 'sidebar' | 'popover' | 'field-action'
|
|
37
|
-
/**
|
|
38
|
-
* Stable id of the agent run / chat turn that produced this
|
|
39
|
-
* suggestion. Popover pills filter on this so they only see their
|
|
40
|
-
* own session's output even when the panel-wide queue holds many.
|
|
41
|
-
*/
|
|
42
|
-
runId?: string
|
|
43
|
-
/** Slug of the agent whose tool call produced the suggestion. */
|
|
44
|
-
agentSlug?: string
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface PendingSuggestion {
|
|
48
|
-
/** Stable id; the producer is responsible for uniqueness. */
|
|
49
|
-
id: string
|
|
50
|
-
/** Field name this suggestion targets. Matched verbatim in the renderer. */
|
|
51
|
-
fieldName: string
|
|
52
|
-
/**
|
|
53
|
-
* Form scope. Multi-form pages (Plan #5 reactive fields) stamp the form's
|
|
54
|
-
* id here so a renderer in form A doesn't pick up a suggestion meant for
|
|
55
|
-
* form B. Optional — when both producer and consumer omit it, suggestions
|
|
56
|
-
* are global.
|
|
57
|
-
*/
|
|
58
|
-
formId?: string
|
|
59
|
-
/** Snapshot of the field's value at the time the suggestion was produced. */
|
|
60
|
-
currentValue: unknown
|
|
61
|
-
/** Proposed replacement. */
|
|
62
|
-
suggestedValue: unknown
|
|
63
|
-
/** Optional attribution surfaced on the diff overlay / inline chip. */
|
|
64
|
-
source?: {
|
|
65
|
-
agentSlug?: string
|
|
66
|
-
agentLabel?: string
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Provenance hint for cross-surface filtering. Sparse — pushed when
|
|
70
|
-
* the producer knows which agent run / chat surface it's running
|
|
71
|
-
* inside (e.g. the popover-chat tagging its turn id so its scoped
|
|
72
|
-
* pill can filter the shared queue). Aggregate consumers that don't
|
|
73
|
-
* care just leave the field unread.
|
|
74
|
-
*/
|
|
75
|
-
origin?: PendingSuggestionOrigin
|
|
76
|
-
/** Wallclock ms when produced. Producers fill this in on `push`. */
|
|
77
|
-
createdAt: number
|
|
78
|
-
/** Field-type-specific extras (e.g. `editorRange: { from, to }`). Sparse. */
|
|
79
|
-
meta?: Record<string, unknown>
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export interface PendingSuggestionsApi {
|
|
83
|
-
/** Full list across every field + form. Aggregate consumers read this. */
|
|
84
|
-
list: readonly PendingSuggestion[]
|
|
85
|
-
/** Add a suggestion to the queue. Returns the (possibly producer-supplied) id. */
|
|
86
|
-
push: (suggestion: Omit<PendingSuggestion, 'createdAt'> & { createdAt?: number }) => string
|
|
87
|
-
/**
|
|
88
|
-
* Drop the suggestion from the queue. Used by both inline approval
|
|
89
|
-
* paths (where the renderer applies directly and just notifies the
|
|
90
|
-
* queue) AND by Reject. For aggregate consumers (e.g. a chat-pill
|
|
91
|
-
* "Approve all" button) that live outside the form's React tree, see
|
|
92
|
-
* `approve` below — it looks up a registered applier and calls it
|
|
93
|
-
* before dismissing.
|
|
94
|
-
*/
|
|
95
|
-
dismiss: (id: string) => void
|
|
96
|
-
/**
|
|
97
|
-
* Apply + dismiss. Resolves the suggestion's `(formId, fieldName)`
|
|
98
|
-
* pair against `PendingSuggestionApplierRegistry`; if an applier is
|
|
99
|
-
* registered (FieldShell + Tiptap bridge auto-register on mount),
|
|
100
|
-
* runs it and then dismisses. If no applier is registered (or the
|
|
101
|
-
* applier throws), falls through to a plain `dismiss` so the queue
|
|
102
|
-
* still clears — never strands an entry.
|
|
103
|
-
*
|
|
104
|
-
* Use this from cross-tree surfaces (chat-sidebar pending-pill).
|
|
105
|
-
* Inline surfaces (FieldShell overlay, Tiptap chip) apply via their
|
|
106
|
-
* own React-tree-local mutators and call `dismiss` directly.
|
|
107
|
-
*/
|
|
108
|
-
approve: (id: string) => void
|
|
109
|
-
/**
|
|
110
|
-
* Drop every suggestion matching the optional filter. With no filter,
|
|
111
|
-
* empties the entire queue.
|
|
112
|
-
*/
|
|
113
|
-
dismissAll: (filter?: { fieldName?: string; formId?: string }) => void
|
|
114
|
-
/**
|
|
115
|
-
* Apply + dismiss every suggestion matching the optional filter.
|
|
116
|
-
* Calls `approve(id)` per entry — same fall-through semantics if an
|
|
117
|
-
* applier is missing or throws.
|
|
118
|
-
*/
|
|
119
|
-
approveAll: (filter?: { fieldName?: string; formId?: string }) => void
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const NOOP_API: PendingSuggestionsApi = Object.freeze({
|
|
123
|
-
list: Object.freeze([]) as readonly PendingSuggestion[],
|
|
124
|
-
push: () => '',
|
|
125
|
-
dismiss: () => {},
|
|
126
|
-
approve: () => {},
|
|
127
|
-
dismissAll: () => {},
|
|
128
|
-
approveAll: () => {},
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Context default is a no-op API — fields that subscribe in trees without a
|
|
133
|
-
* real provider mounted (e.g. the marketing site's preview, headless tests)
|
|
134
|
-
* see an empty list and no-op approval methods. Never throws.
|
|
135
|
-
*/
|
|
136
|
-
export const PendingSuggestionsContext = createContext<PendingSuggestionsApi>(NOOP_API)
|
|
137
|
-
|
|
138
|
-
/** Read the full queue + producer methods. Used by aggregate UIs. */
|
|
139
|
-
export function usePendingSuggestions(): PendingSuggestionsApi {
|
|
140
|
-
return useContext(PendingSuggestionsContext)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Subscribe a single field-renderer to its slice of the queue. Returns
|
|
145
|
-
* `list` already filtered + a `dismiss` callback that the renderer wires
|
|
146
|
-
* to its Approve / Reject buttons.
|
|
147
|
-
*
|
|
148
|
-
* Matching rules:
|
|
149
|
-
* - `s.fieldName === fieldName` (verbatim)
|
|
150
|
-
* - if both `formId` args are non-`undefined`, they must match; otherwise
|
|
151
|
-
* the entry passes (so global suggestions reach scoped readers and
|
|
152
|
-
* vice-versa)
|
|
153
|
-
*
|
|
154
|
-
* The list reference is stable across renders unless the underlying
|
|
155
|
-
* filtered slice actually changes — useful for `useEffect` dependencies
|
|
156
|
-
* in renderers that mirror suggestions into their own state.
|
|
157
|
-
*/
|
|
158
|
-
export function usePendingSuggestionsForField(
|
|
159
|
-
fieldName: string,
|
|
160
|
-
formId?: string,
|
|
161
|
-
): {
|
|
162
|
-
list: readonly PendingSuggestion[]
|
|
163
|
-
dismiss: (id: string) => void
|
|
164
|
-
} {
|
|
165
|
-
const api = useContext(PendingSuggestionsContext)
|
|
166
|
-
const list = useMemo(() => api.list.filter(s => {
|
|
167
|
-
if (s.fieldName !== fieldName) return false
|
|
168
|
-
if (formId === undefined || s.formId === undefined) return true
|
|
169
|
-
return s.formId === formId
|
|
170
|
-
}), [api.list, fieldName, formId])
|
|
171
|
-
return { list, dismiss: api.dismiss }
|
|
172
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { type ReactNode } from 'react'
|
|
2
|
-
import { getRecordWrapper } from './RecordWrapperRegistry.js'
|
|
3
|
-
import { parseRecordPageUrl } from './parseRecordEditUrl.js'
|
|
4
|
-
import type { ResourceCollabConfig } from '../Resource.js'
|
|
5
|
-
|
|
6
|
-
/** Per-resource collab opt-in keyed by URL slug (`R.getSlug()` for
|
|
7
|
-
* non-clustered, `${cluster.slug}/${R.getSlug()}` for clustered). Built
|
|
8
|
-
* server-side by `panelInfo()` as `recordCollab`. */
|
|
9
|
-
export type RecordCollabMap = Record<string, ResourceCollabConfig>
|
|
10
|
-
|
|
11
|
-
export interface RecordWrapperGateProps {
|
|
12
|
-
currentPath?: string
|
|
13
|
-
basePath: string
|
|
14
|
-
/** Resource opt-in map. Absent means no resource opted in (or the
|
|
15
|
-
* panel has no resources) — gate always passes through. */
|
|
16
|
-
recordCollab?: RecordCollabMap
|
|
17
|
-
children: ReactNode
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Conditionally wraps the page tree with the plugin-registered
|
|
22
|
-
* `RecordWrapper` when the current URL resolves to a record-bound page
|
|
23
|
-
* AND the underlying resource has opted into collab on that page role.
|
|
24
|
-
* Pass-through in every other case:
|
|
25
|
-
*
|
|
26
|
-
* - no plugin registered a wrapper (`getRecordWrapper() === null`)
|
|
27
|
-
* - the URL isn't a record edit/view page
|
|
28
|
-
* - `currentPath` not yet known on the very first SSR render
|
|
29
|
-
* - the resource has not opted in via `static collab` (or has opted in
|
|
30
|
-
* but excluded the current page role)
|
|
31
|
-
*
|
|
32
|
-
* Mounted once inside `AppShell` around the page content area so
|
|
33
|
-
* record-scoped plugins (collab room, audit trail, …) get one
|
|
34
|
-
* lifetimed mount per record-view-or-edit without each plugin having
|
|
35
|
-
* to thread URL parsing into its own provider.
|
|
36
|
-
*
|
|
37
|
-
* v1 caveat: nested-relation edit URLs (`/articles/:parentId/comments/:childId/edit`)
|
|
38
|
-
* have a dynamic-id segment baked into the URL slug, so they don't match
|
|
39
|
-
* the resource-keyed `recordCollab` map and fall through to no-collab.
|
|
40
|
-
* Collab on nested-relation edits is a follow-up.
|
|
41
|
-
*/
|
|
42
|
-
export function RecordWrapperGate({ currentPath, basePath, recordCollab, children }: RecordWrapperGateProps) {
|
|
43
|
-
const Wrapper = getRecordWrapper()
|
|
44
|
-
if (!Wrapper || !currentPath) return <>{children}</>
|
|
45
|
-
|
|
46
|
-
const identity = parseRecordPageUrl(currentPath, basePath)
|
|
47
|
-
if (!identity) return <>{children}</>
|
|
48
|
-
|
|
49
|
-
const cfg = recordCollab?.[identity.resourceSlug]
|
|
50
|
-
if (!cfg) return <>{children}</>
|
|
51
|
-
if (!cfg.pages.includes(identity.role)) return <>{children}</>
|
|
52
|
-
|
|
53
|
-
return (
|
|
54
|
-
<Wrapper resourceSlug={identity.resourceSlug} recordId={identity.recordId}>
|
|
55
|
-
{children}
|
|
56
|
-
</Wrapper>
|
|
57
|
-
)
|
|
58
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import type { ComponentType, ReactNode } from 'react'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Props the page-record wrapper receives from `RecordWrapperGate` when
|
|
5
|
-
* the current URL resolves to a record-bound edit page (`${base}/.../:id/edit`).
|
|
6
|
-
*
|
|
7
|
-
* The wrapper is responsible for whatever record-scoped context the
|
|
8
|
-
* plugin owns — `@pilotiq-pro/collab` mounts a `<RecordCollabRoom>`
|
|
9
|
-
* here so every collab field inside the page shares one Y.Doc + WS
|
|
10
|
-
* connection. Other plugins could mount per-record presence, audit
|
|
11
|
-
* logging, or anything else that's record-bound rather than panel-bound.
|
|
12
|
-
*
|
|
13
|
-
* `resourceSlug` is the slash-joined slug-path (cluster-prefixed for
|
|
14
|
-
* clustered resources, parent-prefixed for nested-relation edits) so
|
|
15
|
-
* two URLs that target different records always produce distinct
|
|
16
|
-
* wrapper keys / room names.
|
|
17
|
-
*/
|
|
18
|
-
export interface RecordWrapperProps {
|
|
19
|
-
resourceSlug: string
|
|
20
|
-
recordId: string
|
|
21
|
-
children: ReactNode
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
let _component: ComponentType<RecordWrapperProps> | null = null
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Register a component that wraps the page tree on every record-edit
|
|
28
|
-
* route. Called once at boot by a plugin (e.g. `@pilotiq-pro/collab`).
|
|
29
|
-
* No-op when no plugin registers — `RecordWrapperGate` passes through
|
|
30
|
-
* unchanged.
|
|
31
|
-
*/
|
|
32
|
-
export function registerRecordWrapper(C: ComponentType<RecordWrapperProps>): void {
|
|
33
|
-
_component = C
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Returns the registered wrapper component, or `null`. */
|
|
37
|
-
export function getRecordWrapper(): ComponentType<RecordWrapperProps> | null {
|
|
38
|
-
return _component
|
|
39
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import React from 'react'
|
|
4
|
-
import type { ElementMeta } from '../schema/Element.js'
|
|
5
|
-
import type { RenderHookMap, RenderHookName } from '../RenderHook.js'
|
|
6
|
-
import { SchemaRenderer } from './SchemaRenderer.js'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Mount point for a named render-hook slot. Reads pre-resolved
|
|
10
|
-
* `ElementMeta[]` from the wire payload and walks them through the
|
|
11
|
-
* existing `<SchemaRenderer>` so every Element type (Heading / Alert /
|
|
12
|
-
* Form / Table / …) renders the same way it does in the main schema
|
|
13
|
-
* tree.
|
|
14
|
-
*
|
|
15
|
-
* Renders `null` when no hooks were registered for the slot — every
|
|
16
|
-
* supported chrome / page-role position mounts a `<RenderHookSlot>`
|
|
17
|
-
* unconditionally, so the wire payload stays sparse on panels that
|
|
18
|
-
* don't use render hooks.
|
|
19
|
-
*
|
|
20
|
-
* <RenderHookSlot name="panels::topbar.start" hooks={panel.renderHooks} />
|
|
21
|
-
*/
|
|
22
|
-
export function RenderHookSlot({
|
|
23
|
-
name,
|
|
24
|
-
hooks,
|
|
25
|
-
}: {
|
|
26
|
-
name: RenderHookName
|
|
27
|
-
hooks: RenderHookMap | undefined
|
|
28
|
-
}) {
|
|
29
|
-
const elements = hooks?.[name]
|
|
30
|
-
if (!elements || elements.length === 0) return null
|
|
31
|
-
return <SchemaRenderer elements={elements as ElementMeta[]} />
|
|
32
|
-
}
|
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Right-sidebar chrome — outer panel that hosts plugin contributions.
|
|
3
|
-
*
|
|
4
|
-
* Mounted by `AppShell` only when `panel.rightSidebar` is present in the
|
|
5
|
-
* server-built meta. Reads runtime state (open / activeId / width) from
|
|
6
|
-
* `useRightSidebar()` and resolves each contribution's body via
|
|
7
|
-
* `useRightPanelComponent(id)` (Phase B's `_components.ts` manifest).
|
|
8
|
-
*
|
|
9
|
-
* Desktop: right-docked `position: fixed` rail with a 4px left-edge resize
|
|
10
|
-
* handle. The companion `<RightSidebarSpacer>` reserves layout width on
|
|
11
|
-
* the host so content compresses instead of clipping under the rail.
|
|
12
|
-
*
|
|
13
|
-
* Mobile (< md breakpoint): collapses to an overlay `<Sheet>` — no resize
|
|
14
|
-
* handle, fixed width.
|
|
15
|
-
*
|
|
16
|
-
* Tab strip: hidden when only one contribution is registered (single-tab
|
|
17
|
-
* UX matches VS Code's "Outline / etc." behaviour). Tabs persist active
|
|
18
|
-
* selection through the provider's localStorage round-trip.
|
|
19
|
-
*/
|
|
20
|
-
import React from 'react'
|
|
21
|
-
import { XIcon } from 'lucide-react'
|
|
22
|
-
import { cn } from './utils.js'
|
|
23
|
-
import { useRightSidebar } from './RightSidebarContext.js'
|
|
24
|
-
import { useRightPanelComponent } from './right-panel-registry.js'
|
|
25
|
-
import { useIconFor } from './icon-context.js'
|
|
26
|
-
import { useIsMobile } from './hooks/use-mobile.js'
|
|
27
|
-
import {
|
|
28
|
-
Sheet,
|
|
29
|
-
SheetContent,
|
|
30
|
-
SheetHeader,
|
|
31
|
-
SheetTitle,
|
|
32
|
-
} from './ui/sheet.js'
|
|
33
|
-
import type { SerializedIcon } from '../icons/types.js'
|
|
34
|
-
import type { RightPanelMeta } from '../pageData.js'
|
|
35
|
-
|
|
36
|
-
export interface RightSidebarProps {
|
|
37
|
-
basePath: string
|
|
38
|
-
/** Live pathname — re-renders the panel body on SPA nav so consumers
|
|
39
|
-
* can react to which page the user is on. */
|
|
40
|
-
currentPath?: string
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function PanelIcon({ value }: { value: SerializedIcon | undefined }) {
|
|
44
|
-
const Icon = useIconFor(value)
|
|
45
|
-
if (!Icon) return null
|
|
46
|
-
return <Icon className="size-4" aria-hidden="true" />
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function PanelBody({
|
|
50
|
-
contribution,
|
|
51
|
-
basePath,
|
|
52
|
-
currentPath,
|
|
53
|
-
}: {
|
|
54
|
-
contribution: RightPanelMeta
|
|
55
|
-
basePath: string
|
|
56
|
-
currentPath?: string
|
|
57
|
-
}) {
|
|
58
|
-
const Component = useRightPanelComponent(contribution.id)
|
|
59
|
-
if (!Component) {
|
|
60
|
-
return (
|
|
61
|
-
<div className="p-4 text-sm text-destructive">
|
|
62
|
-
<p className="font-medium">Right panel not registered</p>
|
|
63
|
-
<p className="mt-1 text-muted-foreground">
|
|
64
|
-
No client component is bound to <code className="rounded bg-muted px-1">{contribution.id}</code>.
|
|
65
|
-
The Vite plugin's <code className="rounded bg-muted px-1">_components.ts</code> manifest is missing this entry —
|
|
66
|
-
extract the <code className="rounded bg-muted px-1">render</code> reference to a named export.
|
|
67
|
-
</p>
|
|
68
|
-
</div>
|
|
69
|
-
)
|
|
70
|
-
}
|
|
71
|
-
// Component reads its own context as needed; we forward the well-known
|
|
72
|
-
// RightPanelProps (basePath / currentPath / activeId) defined in
|
|
73
|
-
// `RightPanel.ts` so plugin authors don't have to plumb it themselves.
|
|
74
|
-
// `currentPath` is conditionally spread so an absent value does not
|
|
75
|
-
// collide with the prop's `undefined`-disallowed (exactOptional) shape.
|
|
76
|
-
const props: { basePath: string; activeId: string; currentPath?: string } = {
|
|
77
|
-
basePath,
|
|
78
|
-
activeId: contribution.id,
|
|
79
|
-
}
|
|
80
|
-
if (currentPath !== undefined) props.currentPath = currentPath
|
|
81
|
-
return <Component {...props} />
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function TabStrip({
|
|
85
|
-
contributions,
|
|
86
|
-
activeId,
|
|
87
|
-
setActiveId,
|
|
88
|
-
}: {
|
|
89
|
-
contributions: RightPanelMeta[]
|
|
90
|
-
activeId: string | null
|
|
91
|
-
setActiveId: (id: string) => void
|
|
92
|
-
}) {
|
|
93
|
-
if (contributions.length < 2) return null
|
|
94
|
-
return (
|
|
95
|
-
<div role="tablist" className="flex items-center gap-0 border-b bg-muted/30 px-1">
|
|
96
|
-
{contributions.map((c) => {
|
|
97
|
-
const active = c.id === activeId
|
|
98
|
-
return (
|
|
99
|
-
<button
|
|
100
|
-
key={c.id}
|
|
101
|
-
type="button"
|
|
102
|
-
role="tab"
|
|
103
|
-
aria-selected={active}
|
|
104
|
-
onClick={() => setActiveId(c.id)}
|
|
105
|
-
className={cn(
|
|
106
|
-
'inline-flex items-center gap-1.5 rounded-t-md border-b-2 px-3 py-2 text-xs font-medium transition-colors',
|
|
107
|
-
active
|
|
108
|
-
? 'border-primary text-foreground'
|
|
109
|
-
: 'border-transparent text-muted-foreground hover:text-foreground',
|
|
110
|
-
)}
|
|
111
|
-
>
|
|
112
|
-
<PanelIcon value={c.icon} />
|
|
113
|
-
<span>{c.label}</span>
|
|
114
|
-
</button>
|
|
115
|
-
)
|
|
116
|
-
})}
|
|
117
|
-
</div>
|
|
118
|
-
)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function PanelHeader({
|
|
122
|
-
active,
|
|
123
|
-
onClose,
|
|
124
|
-
hideTabs,
|
|
125
|
-
}: {
|
|
126
|
-
active: RightPanelMeta | undefined
|
|
127
|
-
onClose: () => void
|
|
128
|
-
hideTabs: boolean
|
|
129
|
-
}) {
|
|
130
|
-
return (
|
|
131
|
-
<div className="flex h-11 shrink-0 items-center gap-2 border-b px-3">
|
|
132
|
-
{hideTabs && active && (
|
|
133
|
-
<>
|
|
134
|
-
<PanelIcon value={active.icon} />
|
|
135
|
-
<span className="text-sm font-medium">{active.label}</span>
|
|
136
|
-
</>
|
|
137
|
-
)}
|
|
138
|
-
<button
|
|
139
|
-
type="button"
|
|
140
|
-
onClick={onClose}
|
|
141
|
-
className={cn(
|
|
142
|
-
'ms-auto inline-flex size-7 items-center justify-center rounded-md text-muted-foreground transition-colors',
|
|
143
|
-
'hover:bg-accent hover:text-foreground',
|
|
144
|
-
)}
|
|
145
|
-
aria-label="Close right sidebar"
|
|
146
|
-
>
|
|
147
|
-
<XIcon className="size-4" aria-hidden="true" />
|
|
148
|
-
</button>
|
|
149
|
-
</div>
|
|
150
|
-
)
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Outer chrome. Renders a fixed-position rail on desktop and a Sheet on
|
|
155
|
-
* mobile. Reads its open / width / active state from the surrounding
|
|
156
|
-
* `RightSidebarProvider`.
|
|
157
|
-
*/
|
|
158
|
-
export function RightSidebar({ basePath, currentPath }: RightSidebarProps): React.ReactElement | null {
|
|
159
|
-
const sidebar = useRightSidebar()
|
|
160
|
-
const isMobile = useIsMobile()
|
|
161
|
-
|
|
162
|
-
// Drag-resize: the provider owns width state + per-basePath
|
|
163
|
-
// localStorage persistence, so the chrome just listens at the document
|
|
164
|
-
// level and forwards each delta into `sidebar.setWidth`.
|
|
165
|
-
const onPointerDown = (e: React.PointerEvent<HTMLElement>): void => {
|
|
166
|
-
e.preventDefault()
|
|
167
|
-
const startX = e.clientX
|
|
168
|
-
const startWidth = sidebar.width
|
|
169
|
-
const onMove = (ev: PointerEvent): void => {
|
|
170
|
-
const delta = startX - ev.clientX
|
|
171
|
-
sidebar.setWidth(startWidth + delta)
|
|
172
|
-
}
|
|
173
|
-
const onUp = (): void => {
|
|
174
|
-
document.removeEventListener('pointermove', onMove)
|
|
175
|
-
document.removeEventListener('pointerup', onUp)
|
|
176
|
-
}
|
|
177
|
-
document.addEventListener('pointermove', onMove)
|
|
178
|
-
document.addEventListener('pointerup', onUp)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const active = sidebar.contributions.find((c) => c.id === sidebar.activeId)
|
|
182
|
-
?? sidebar.contributions[0]
|
|
183
|
-
const hideTabs = sidebar.contributions.length < 2
|
|
184
|
-
|
|
185
|
-
if (!sidebar.open) return null
|
|
186
|
-
|
|
187
|
-
if (isMobile) {
|
|
188
|
-
return (
|
|
189
|
-
<Sheet open={sidebar.open} onOpenChange={sidebar.setOpen}>
|
|
190
|
-
<SheetContent
|
|
191
|
-
side="right"
|
|
192
|
-
className="flex w-[min(20rem,calc(100vw-3rem))] flex-col p-0"
|
|
193
|
-
showCloseButton={false}
|
|
194
|
-
>
|
|
195
|
-
<SheetHeader className="border-b">
|
|
196
|
-
<SheetTitle>{active?.label ?? 'Side panel'}</SheetTitle>
|
|
197
|
-
</SheetHeader>
|
|
198
|
-
<TabStrip
|
|
199
|
-
contributions={sidebar.contributions}
|
|
200
|
-
activeId={sidebar.activeId}
|
|
201
|
-
setActiveId={sidebar.setActiveId}
|
|
202
|
-
/>
|
|
203
|
-
<div className="flex-1 overflow-y-auto">
|
|
204
|
-
{active && (
|
|
205
|
-
<PanelBody
|
|
206
|
-
contribution={active}
|
|
207
|
-
basePath={basePath}
|
|
208
|
-
{...(currentPath !== undefined ? { currentPath } : {})}
|
|
209
|
-
/>
|
|
210
|
-
)}
|
|
211
|
-
</div>
|
|
212
|
-
</SheetContent>
|
|
213
|
-
</Sheet>
|
|
214
|
-
)
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return (
|
|
218
|
-
<aside
|
|
219
|
-
data-pilotiq-right-sidebar=""
|
|
220
|
-
style={{ width: sidebar.width }}
|
|
221
|
-
className={cn(
|
|
222
|
-
'fixed inset-y-0 end-0 z-30 flex flex-col border-s bg-background shadow-sm',
|
|
223
|
-
)}
|
|
224
|
-
role="complementary"
|
|
225
|
-
aria-label={active?.label ?? 'Side panel'}
|
|
226
|
-
>
|
|
227
|
-
{/* Left-edge resize handle. Thin strip; 4px wide hit area, 1px
|
|
228
|
-
highlight band on hover. Pointer events live at document level
|
|
229
|
-
inside the handler so leaving the strip doesn't end the drag. */}
|
|
230
|
-
<div
|
|
231
|
-
role="separator"
|
|
232
|
-
aria-orientation="vertical"
|
|
233
|
-
aria-label="Resize side panel"
|
|
234
|
-
onPointerDown={onPointerDown}
|
|
235
|
-
className={cn(
|
|
236
|
-
'absolute inset-y-0 start-0 w-1 cursor-ew-resize',
|
|
237
|
-
'hover:bg-border/80',
|
|
238
|
-
)}
|
|
239
|
-
/>
|
|
240
|
-
<PanelHeader active={active} onClose={() => sidebar.setOpen(false)} hideTabs={hideTabs} />
|
|
241
|
-
<TabStrip
|
|
242
|
-
contributions={sidebar.contributions}
|
|
243
|
-
activeId={sidebar.activeId}
|
|
244
|
-
setActiveId={sidebar.setActiveId}
|
|
245
|
-
/>
|
|
246
|
-
<div className="flex-1 overflow-y-auto">
|
|
247
|
-
{active && (
|
|
248
|
-
<PanelBody
|
|
249
|
-
contribution={active}
|
|
250
|
-
basePath={basePath}
|
|
251
|
-
{...(currentPath !== undefined ? { currentPath } : {})}
|
|
252
|
-
/>
|
|
253
|
-
)}
|
|
254
|
-
</div>
|
|
255
|
-
</aside>
|
|
256
|
-
)
|
|
257
|
-
}
|