@miragon/mcp-toolkit-ui 2.7.0 → 2.8.1
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/README.md +7 -4
- package/dist/app/adapt-data-widget.d.ts +1 -22
- package/dist/app/adapt-data-widget.d.ts.map +1 -1
- package/dist/app/adapt-data-widget.js +1 -35
- package/dist/app/adapt-data-widget.js.map +1 -1
- package/dist/app/builder/BuilderBanners.js +1 -1
- package/dist/app/builder/BuilderBanners.js.map +1 -1
- package/dist/app/builder/CanvasRow.d.ts +4 -2
- package/dist/app/builder/CanvasRow.d.ts.map +1 -1
- package/dist/app/builder/CanvasRow.js +21 -7
- package/dist/app/builder/CanvasRow.js.map +1 -1
- package/dist/app/builder/CatalogueSheet.d.ts.map +1 -1
- package/dist/app/builder/CatalogueSheet.js +11 -4
- package/dist/app/builder/CatalogueSheet.js.map +1 -1
- package/dist/app/builder/CellPropsSheet.d.ts +7 -3
- package/dist/app/builder/CellPropsSheet.d.ts.map +1 -1
- package/dist/app/builder/CellPropsSheet.js +10 -3
- package/dist/app/builder/CellPropsSheet.js.map +1 -1
- package/dist/app/builder/DiscardDialog.d.ts +18 -0
- package/dist/app/builder/DiscardDialog.d.ts.map +1 -0
- package/dist/app/builder/DiscardDialog.js +18 -0
- package/dist/app/builder/DiscardDialog.js.map +1 -0
- package/dist/app/builder/LayoutSurface.d.ts +33 -9
- package/dist/app/builder/LayoutSurface.d.ts.map +1 -1
- package/dist/app/builder/LayoutSurface.js +74 -23
- package/dist/app/builder/LayoutSurface.js.map +1 -1
- package/dist/app/builder/PipelineStrip.d.ts +2 -1
- package/dist/app/builder/PipelineStrip.d.ts.map +1 -1
- package/dist/app/builder/PipelineStrip.js +26 -13
- package/dist/app/builder/PipelineStrip.js.map +1 -1
- package/dist/app/builder/SaveDialog.d.ts +9 -1
- package/dist/app/builder/SaveDialog.d.ts.map +1 -1
- package/dist/app/builder/SaveDialog.js +8 -2
- package/dist/app/builder/SaveDialog.js.map +1 -1
- package/dist/app/builder/Toolbar.d.ts +12 -4
- package/dist/app/builder/Toolbar.d.ts.map +1 -1
- package/dist/app/builder/Toolbar.js +18 -7
- package/dist/app/builder/Toolbar.js.map +1 -1
- package/dist/app/builder/Workspace.d.ts +23 -3
- package/dist/app/builder/Workspace.d.ts.map +1 -1
- package/dist/app/builder/Workspace.js +58 -8
- package/dist/app/builder/Workspace.js.map +1 -1
- package/dist/app/builder/builder-model.d.ts +143 -1
- package/dist/app/builder/builder-model.d.ts.map +1 -1
- package/dist/app/builder/builder-model.js +191 -1
- package/dist/app/builder/builder-model.js.map +1 -1
- package/dist/app/builder/reveal.d.ts +10 -0
- package/dist/app/builder/reveal.d.ts.map +1 -0
- package/dist/app/builder/reveal.js +10 -0
- package/dist/app/builder/reveal.js.map +1 -0
- package/dist/app/builder/use-builder-catalogue.d.ts +4 -1
- package/dist/app/builder/use-builder-catalogue.d.ts.map +1 -1
- package/dist/app/builder/use-builder-catalogue.js +44 -17
- package/dist/app/builder/use-builder-catalogue.js.map +1 -1
- package/dist/app/builder/use-builder-session.d.ts +30 -0
- package/dist/app/builder/use-builder-session.d.ts.map +1 -0
- package/dist/app/builder/use-builder-session.js +58 -0
- package/dist/app/builder/use-builder-session.js.map +1 -0
- package/dist/app/builder/use-display-resolver.d.ts +17 -0
- package/dist/app/builder/use-display-resolver.d.ts.map +1 -0
- package/dist/app/builder/use-display-resolver.js +16 -0
- package/dist/app/builder/use-display-resolver.js.map +1 -0
- package/dist/app/index.d.ts +8 -3
- package/dist/app/index.d.ts.map +1 -1
- package/dist/app/index.js +8 -2
- package/dist/app/index.js.map +1 -1
- package/dist/app/layout-builder.d.ts +13 -25
- package/dist/app/layout-builder.d.ts.map +1 -1
- package/dist/app/layout-builder.js +75 -81
- package/dist/app/layout-builder.js.map +1 -1
- package/dist/app/mcp-app-view-chrome.d.ts +12 -3
- package/dist/app/mcp-app-view-chrome.d.ts.map +1 -1
- package/dist/app/mcp-app-view-chrome.js +21 -5
- package/dist/app/mcp-app-view-chrome.js.map +1 -1
- package/dist/app/mcp-app-view-states.d.ts +11 -3
- package/dist/app/mcp-app-view-states.d.ts.map +1 -1
- package/dist/app/mcp-app-view-states.js +29 -8
- package/dist/app/mcp-app-view-states.js.map +1 -1
- package/dist/app/mcp-app-view.d.ts +33 -1
- package/dist/app/mcp-app-view.d.ts.map +1 -1
- package/dist/app/mcp-app-view.js +181 -127
- package/dist/app/mcp-app-view.js.map +1 -1
- package/dist/app/mcp-toolkit-app.d.ts +6 -1
- package/dist/app/mcp-toolkit-app.d.ts.map +1 -1
- package/dist/app/mcp-toolkit-app.js +8 -1
- package/dist/app/mcp-toolkit-app.js.map +1 -1
- package/dist/app/mcp-use-host-bridge.d.ts +15 -6
- package/dist/app/mcp-use-host-bridge.d.ts.map +1 -1
- package/dist/app/mcp-use-host-bridge.js +51 -22
- package/dist/app/mcp-use-host-bridge.js.map +1 -1
- package/dist/app/model-context.d.ts +71 -0
- package/dist/app/model-context.d.ts.map +1 -0
- package/dist/app/model-context.js +101 -0
- package/dist/app/model-context.js.map +1 -0
- package/dist/app/use-build-mode-focus.d.ts +33 -0
- package/dist/app/use-build-mode-focus.d.ts.map +1 -0
- package/dist/app/use-build-mode-focus.js +59 -0
- package/dist/app/use-build-mode-focus.js.map +1 -0
- package/dist/app/use-view-actions.d.ts +31 -0
- package/dist/app/use-view-actions.d.ts.map +1 -0
- package/dist/app/use-view-actions.js +81 -0
- package/dist/app/use-view-actions.js.map +1 -0
- package/dist/app/use-view-lifecycle.d.ts +4 -0
- package/dist/app/use-view-lifecycle.d.ts.map +1 -1
- package/dist/app/use-view-lifecycle.js +2 -0
- package/dist/app/use-view-lifecycle.js.map +1 -1
- package/dist/app/view-lifecycle.d.ts +80 -4
- package/dist/app/view-lifecycle.d.ts.map +1 -1
- package/dist/app/view-lifecycle.js +90 -3
- package/dist/app/view-lifecycle.js.map +1 -1
- package/dist/app/widget-fixture.d.ts +10 -3
- package/dist/app/widget-fixture.d.ts.map +1 -1
- package/dist/app/widget-fixture.js +21 -8
- package/dist/app/widget-fixture.js.map +1 -1
- package/dist/app/widget-props-sheet.d.ts +3 -1
- package/dist/app/widget-props-sheet.d.ts.map +1 -1
- package/dist/app/widget-props-sheet.js +22 -10
- package/dist/app/widget-props-sheet.js.map +1 -1
- package/dist/app/widget-renderer.js +1 -1
- package/dist/app/widget-renderer.js.map +1 -1
- package/dist/components/DrillButton.d.ts +14 -6
- package/dist/components/DrillButton.d.ts.map +1 -1
- package/dist/components/DrillButton.js +14 -7
- package/dist/components/DrillButton.js.map +1 -1
- package/dist/components/EmptyState.d.ts.map +1 -1
- package/dist/components/EmptyState.js +4 -2
- package/dist/components/EmptyState.js.map +1 -1
- package/dist/components/ErrorState.d.ts +5 -2
- package/dist/components/ErrorState.d.ts.map +1 -1
- package/dist/components/ErrorState.js +25 -8
- package/dist/components/ErrorState.js.map +1 -1
- package/dist/components/FilterBar.d.ts +15 -4
- package/dist/components/FilterBar.d.ts.map +1 -1
- package/dist/components/FilterBar.js +11 -6
- package/dist/components/FilterBar.js.map +1 -1
- package/dist/components/KpiGrid.d.ts +66 -21
- package/dist/components/KpiGrid.d.ts.map +1 -1
- package/dist/components/KpiGrid.js +101 -34
- package/dist/components/KpiGrid.js.map +1 -1
- package/dist/components/ListFooter.d.ts +31 -4
- package/dist/components/ListFooter.d.ts.map +1 -1
- package/dist/components/ListFooter.js +30 -11
- package/dist/components/ListFooter.js.map +1 -1
- package/dist/components/PagedListFooter.d.ts +57 -0
- package/dist/components/PagedListFooter.d.ts.map +1 -0
- package/dist/components/PagedListFooter.js +27 -0
- package/dist/components/PagedListFooter.js.map +1 -0
- package/dist/components/Pills.d.ts +27 -7
- package/dist/components/Pills.d.ts.map +1 -1
- package/dist/components/Pills.js +21 -6
- package/dist/components/Pills.js.map +1 -1
- package/dist/components/SectionHeading.d.ts +3 -1
- package/dist/components/SectionHeading.d.ts.map +1 -1
- package/dist/components/SectionHeading.js +6 -2
- package/dist/components/SectionHeading.js.map +1 -1
- package/dist/components/Toast.d.ts +9 -3
- package/dist/components/Toast.d.ts.map +1 -1
- package/dist/components/Toast.js +31 -16
- package/dist/components/Toast.js.map +1 -1
- package/dist/components/WidgetHeader.d.ts +34 -10
- package/dist/components/WidgetHeader.d.ts.map +1 -1
- package/dist/components/WidgetHeader.js +11 -6
- package/dist/components/WidgetHeader.js.map +1 -1
- package/dist/hooks/index.d.ts +4 -4
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/tool-result-recovery-model.d.ts +155 -0
- package/dist/hooks/tool-result-recovery-model.d.ts.map +1 -0
- package/dist/hooks/tool-result-recovery-model.js +273 -0
- package/dist/hooks/tool-result-recovery-model.js.map +1 -0
- package/dist/hooks/use-tool-query.d.ts +56 -14
- package/dist/hooks/use-tool-query.d.ts.map +1 -1
- package/dist/hooks/use-tool-query.js +102 -25
- package/dist/hooks/use-tool-query.js.map +1 -1
- package/dist/hooks/use-tool-result-recovery.d.ts +47 -52
- package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -1
- package/dist/hooks/use-tool-result-recovery.js +58 -120
- package/dist/hooks/use-tool-result-recovery.js.map +1 -1
- package/dist/hooks/use-view-data.d.ts +52 -10
- package/dist/hooks/use-view-data.d.ts.map +1 -1
- package/dist/hooks/use-view-data.js +81 -16
- package/dist/hooks/use-view-data.js.map +1 -1
- package/dist/hooks/use-view-tool-query.d.ts +12 -7
- package/dist/hooks/use-view-tool-query.d.ts.map +1 -1
- package/dist/hooks/use-view-tool-query.js +15 -14
- package/dist/hooks/use-view-tool-query.js.map +1 -1
- package/dist/index.d.ts +17 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -6
- package/dist/index.js.map +1 -1
- package/dist/lib/focus-return.d.ts +61 -0
- package/dist/lib/focus-return.d.ts.map +1 -0
- package/dist/lib/focus-return.js +46 -0
- package/dist/lib/focus-return.js.map +1 -0
- package/dist/lib/parse-tool-result.d.ts +23 -1
- package/dist/lib/parse-tool-result.d.ts.map +1 -1
- package/dist/lib/parse-tool-result.js +38 -2
- package/dist/lib/parse-tool-result.js.map +1 -1
- package/dist/lib/toast-model.d.ts +41 -1
- package/dist/lib/toast-model.d.ts.map +1 -1
- package/dist/lib/toast-model.js +67 -1
- package/dist/lib/toast-model.js.map +1 -1
- package/dist/lib/tone-utils.d.ts +58 -6
- package/dist/lib/tone-utils.d.ts.map +1 -1
- package/dist/lib/tone-utils.js +66 -4
- package/dist/lib/tone-utils.js.map +1 -1
- package/dist/lib/tool-query.d.ts +107 -0
- package/dist/lib/tool-query.d.ts.map +1 -0
- package/dist/lib/tool-query.js +182 -0
- package/dist/lib/tool-query.js.map +1 -0
- package/dist/lib/tool-result-observer.d.ts +108 -0
- package/dist/lib/tool-result-observer.d.ts.map +1 -0
- package/dist/lib/tool-result-observer.js +158 -0
- package/dist/lib/tool-result-observer.js.map +1 -0
- package/dist/lib/typography.d.ts +37 -0
- package/dist/lib/typography.d.ts.map +1 -0
- package/dist/lib/typography.js +41 -0
- package/dist/lib/typography.js.map +1 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +11 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/locale/index.d.ts +1 -1
- package/dist/locale/index.d.ts.map +1 -1
- package/dist/locale/message-types.d.ts +117 -4
- package/dist/locale/message-types.d.ts.map +1 -1
- package/dist/locale/messages-de.d.ts.map +1 -1
- package/dist/locale/messages-de.js +44 -10
- package/dist/locale/messages-de.js.map +1 -1
- package/dist/locale/messages-en.d.ts.map +1 -1
- package/dist/locale/messages-en.js +44 -10
- package/dist/locale/messages-en.js.map +1 -1
- package/dist/locale/toolkit-messages.d.ts +19 -1
- package/dist/locale/toolkit-messages.d.ts.map +1 -1
- package/dist/locale/toolkit-messages.js +54 -1
- package/dist/locale/toolkit-messages.js.map +1 -1
- package/dist/primitives/alert.d.ts +1 -1
- package/dist/primitives/alert.d.ts.map +1 -1
- package/dist/primitives/alert.js +2 -0
- package/dist/primitives/alert.js.map +1 -1
- package/dist/primitives/badge.d.ts +1 -1
- package/dist/primitives/badge.d.ts.map +1 -1
- package/dist/primitives/badge.js +9 -4
- package/dist/primitives/badge.js.map +1 -1
- package/dist/primitives/button.d.ts +1 -1
- package/dist/primitives/button.js +1 -1
- package/dist/primitives/button.js.map +1 -1
- package/dist/primitives/dialog.d.ts +1 -1
- package/dist/primitives/dialog.d.ts.map +1 -1
- package/dist/primitives/dialog.js +10 -3
- package/dist/primitives/dialog.js.map +1 -1
- package/dist/primitives/select.js +1 -1
- package/dist/primitives/select.js.map +1 -1
- package/dist/primitives/sheet.d.ts +1 -1
- package/dist/primitives/sheet.d.ts.map +1 -1
- package/dist/primitives/sheet.js +6 -2
- package/dist/primitives/sheet.js.map +1 -1
- package/dist/providers/query-provider.d.ts +32 -1
- package/dist/providers/query-provider.d.ts.map +1 -1
- package/dist/providers/query-provider.js +53 -4
- package/dist/providers/query-provider.js.map +1 -1
- package/dist/render-cases-primitives.js +1 -1
- package/dist/render-cases-primitives.js.map +1 -1
- package/dist/render-cases.d.ts.map +1 -1
- package/dist/render-cases.js +30 -6
- package/dist/render-cases.js.map +1 -1
- package/dist/render-effects.d.ts +42 -0
- package/dist/render-effects.d.ts.map +1 -0
- package/dist/render-effects.js +81 -0
- package/dist/render-effects.js.map +1 -0
- package/dist/theme/create-theme.d.ts +19 -1
- package/dist/theme/create-theme.d.ts.map +1 -1
- package/dist/theme/create-theme.js +15 -0
- package/dist/theme/create-theme.js.map +1 -1
- package/package.json +5 -4
- package/src/app/adapt-data-widget.tsx +2 -42
- package/src/app/builder/BuilderBanners.tsx +1 -1
- package/src/app/builder/CanvasRow.tsx +63 -17
- package/src/app/builder/CatalogueSheet.tsx +50 -29
- package/src/app/builder/CellPropsSheet.tsx +17 -2
- package/src/app/builder/DiscardDialog.tsx +59 -0
- package/src/app/builder/LayoutSurface.tsx +206 -66
- package/src/app/builder/PipelineStrip.tsx +253 -153
- package/src/app/builder/SaveDialog.tsx +14 -2
- package/src/app/builder/Toolbar.tsx +144 -59
- package/src/app/builder/Workspace.tsx +226 -58
- package/src/app/builder/builder-model.ts +341 -2
- package/src/app/builder/builder-model.ux.test.ts +456 -0
- package/src/app/builder/builder-ux.test.tsx +844 -0
- package/src/app/builder/reveal.ts +10 -0
- package/src/app/builder/use-builder-catalogue.ts +56 -19
- package/src/app/builder/use-builder-session.ts +68 -0
- package/src/app/builder/use-display-resolver.ts +24 -0
- package/src/app/index.ts +12 -2
- package/src/app/layout-builder.tsx +178 -191
- package/src/app/mcp-app-view-chrome.test.tsx +141 -1
- package/src/app/mcp-app-view-chrome.tsx +56 -6
- package/src/app/mcp-app-view-states.tsx +51 -11
- package/src/app/mcp-app-view.effects.test.tsx +292 -0
- package/src/app/mcp-app-view.test.tsx +222 -2
- package/src/app/mcp-app-view.tsx +267 -117
- package/src/app/mcp-toolkit-app.test.tsx +40 -0
- package/src/app/mcp-toolkit-app.tsx +8 -1
- package/src/app/mcp-use-host-bridge.test.tsx +180 -0
- package/src/app/mcp-use-host-bridge.tsx +67 -24
- package/src/app/model-context.test.tsx +116 -0
- package/src/app/model-context.tsx +125 -0
- package/src/app/use-build-mode-focus.ts +62 -0
- package/src/app/use-view-actions.ts +89 -0
- package/src/app/use-view-lifecycle.ts +6 -0
- package/src/app/view-lifecycle.test.ts +216 -0
- package/src/app/view-lifecycle.ts +165 -5
- package/src/app/widget-fixture.effects.test.tsx +51 -0
- package/src/app/widget-fixture.render.test.tsx +81 -0
- package/src/app/widget-fixture.tsx +34 -11
- package/src/app/widget-props-sheet.tsx +57 -16
- package/src/app/widget-renderer.tsx +1 -1
- package/src/components/DrillButton.test.tsx +48 -0
- package/src/components/DrillButton.tsx +26 -11
- package/src/components/EmptyState.tsx +6 -4
- package/src/components/ErrorState.tsx +31 -9
- package/src/components/FilterBar.test.tsx +82 -0
- package/src/components/FilterBar.tsx +52 -26
- package/src/components/KpiGrid.test.tsx +279 -0
- package/src/components/KpiGrid.tsx +297 -90
- package/src/components/ListFooter.test.tsx +116 -0
- package/src/components/ListFooter.tsx +102 -15
- package/src/components/PagedListFooter.test.tsx +140 -0
- package/src/components/PagedListFooter.tsx +107 -0
- package/src/components/Pills.test.tsx +77 -0
- package/src/components/Pills.tsx +63 -10
- package/src/components/SectionHeading.tsx +9 -3
- package/src/components/Toast.tsx +37 -19
- package/src/components/WidgetHeader.test.tsx +78 -0
- package/src/components/WidgetHeader.tsx +63 -16
- package/src/components/feedback-states.test.tsx +98 -9
- package/src/components/tone-figures.test.tsx +8 -4
- package/src/hooks/index.ts +6 -3
- package/src/hooks/tool-result-recovery-model.test.ts +744 -0
- package/src/hooks/tool-result-recovery-model.ts +418 -0
- package/src/hooks/use-tool-query.effects.test.tsx +205 -0
- package/src/hooks/use-tool-query.ts +156 -33
- package/src/hooks/use-tool-result-recovery.effects.test.tsx +141 -0
- package/src/hooks/use-tool-result-recovery.test.ts +3 -4
- package/src/hooks/use-tool-result-recovery.ts +84 -142
- package/src/hooks/use-view-data.test.tsx +118 -9
- package/src/hooks/use-view-data.ts +128 -18
- package/src/hooks/use-view-tool-query.ts +25 -19
- package/src/i18n-coverage.test.tsx +104 -2
- package/src/index.ts +48 -11
- package/src/lib/focus-return.test.ts +288 -0
- package/src/lib/focus-return.ts +96 -0
- package/src/lib/parse-tool-result.test.ts +46 -1
- package/src/lib/parse-tool-result.ts +40 -2
- package/src/lib/toast-model.test.ts +166 -1
- package/src/lib/toast-model.ts +104 -2
- package/src/lib/tone-utils.test.ts +86 -10
- package/src/lib/tone-utils.ts +89 -8
- package/src/lib/tool-query.test.ts +569 -0
- package/src/lib/tool-query.ts +253 -0
- package/src/lib/tool-result-observer.test.ts +296 -0
- package/src/lib/tool-result-observer.ts +211 -0
- package/src/lib/typography.test.ts +45 -0
- package/src/lib/typography.ts +47 -0
- package/src/lib/utils.ts +12 -1
- package/src/locale/index.ts +1 -0
- package/src/locale/message-types.ts +118 -2
- package/src/locale/messages-de.ts +49 -10
- package/src/locale/messages-en.ts +49 -10
- package/src/locale/toolkit-messages.test.ts +133 -0
- package/src/locale/toolkit-messages.ts +63 -2
- package/src/primitives/alert.tsx +3 -0
- package/src/primitives/badge.tsx +9 -4
- package/src/primitives/button.tsx +1 -1
- package/src/primitives/dialog.tsx +10 -1
- package/src/primitives/select.tsx +1 -1
- package/src/primitives/sheet.tsx +7 -0
- package/src/providers/query-provider.test.tsx +154 -0
- package/src/providers/query-provider.tsx +66 -5
- package/src/render-cases-primitives.tsx +1 -1
- package/src/render-cases.tsx +38 -6
- package/src/render-effects.tsx +96 -0
- package/src/theme/cd-tokens.test.ts +3 -1
- package/src/theme/create-theme.test.ts +10 -0
- package/src/theme/create-theme.ts +28 -0
- package/src/theme/theme-css.test.ts +51 -0
- package/src/theme.css +31 -1
- package/ui-catalog.json +448 -41
|
@@ -7,8 +7,18 @@
|
|
|
7
7
|
* `parseKeyValue ↔ keysToEntries ↔ entriesToKeys` round-trip and
|
|
8
8
|
* `draftToLayout` — unit-testable in isolation.
|
|
9
9
|
*/
|
|
10
|
-
import type {
|
|
11
|
-
|
|
10
|
+
import type {
|
|
11
|
+
DisplayText,
|
|
12
|
+
LayoutConfig,
|
|
13
|
+
PipelineContext,
|
|
14
|
+
PipelineStepRef,
|
|
15
|
+
RowDef,
|
|
16
|
+
} from "@miragon/mcp-toolkit-core"
|
|
17
|
+
import {
|
|
18
|
+
normalizeLayout,
|
|
19
|
+
PROPS_SCHEMA_DISPLAY_KEYWORD,
|
|
20
|
+
resolveLocalizedText,
|
|
21
|
+
} from "@miragon/mcp-toolkit-core"
|
|
12
22
|
|
|
13
23
|
// -------------------------------------------------------------------------- //
|
|
14
24
|
// Draft types
|
|
@@ -212,3 +222,332 @@ export function toPipelineContext(ctx: WireContext): PipelineContext {
|
|
|
212
222
|
}
|
|
213
223
|
return { steps, keys: ctx.keys, errors: ctx.errors }
|
|
214
224
|
}
|
|
225
|
+
|
|
226
|
+
// -------------------------------------------------------------------------- //
|
|
227
|
+
// Display text — what the builder calls a widget, a step or a props field
|
|
228
|
+
// -------------------------------------------------------------------------- //
|
|
229
|
+
|
|
230
|
+
/** Resolves an i18n key in the active locale; `undefined` when it is unknown. */
|
|
231
|
+
export type DisplayKeyResolver = (key: string) => string | undefined
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* A {@link DisplayKeyResolver} over a translate function that echoes unknown
|
|
235
|
+
* keys (the `createTranslator` / `useTranslate` contract): the echo, or a
|
|
236
|
+
* blank result, means "unknown", so the caller falls back to its inline text.
|
|
237
|
+
*/
|
|
238
|
+
export function keyResolverFrom(translate: (key: string) => string): DisplayKeyResolver {
|
|
239
|
+
return (key) => {
|
|
240
|
+
const text = translate(key).trim()
|
|
241
|
+
return text.length > 0 && text !== key ? text : undefined
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* The i18n key's text when the resolver knows it, else the inline (per-locale)
|
|
247
|
+
* text. Display text crosses the wire (the catalogue, a `propsSchema`), so a
|
|
248
|
+
* key that is not a string is ignored instead of reaching the translator.
|
|
249
|
+
*/
|
|
250
|
+
function keyedText(
|
|
251
|
+
key: unknown,
|
|
252
|
+
text: DisplayText["title"],
|
|
253
|
+
locale: string,
|
|
254
|
+
resolveKey: DisplayKeyResolver | undefined,
|
|
255
|
+
): string | undefined {
|
|
256
|
+
const viaKey = typeof key === "string" && resolveKey ? resolveKey(key) : undefined
|
|
257
|
+
return viaKey ?? resolveLocalizedText(text, locale)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** How the builder names one entry: a label, the technical id as a quiet hint, a one-liner. */
|
|
261
|
+
export interface DisplayLabel {
|
|
262
|
+
/** The name people read: the entry's title, else its id. */
|
|
263
|
+
label: string
|
|
264
|
+
/** The technical id, set only when the label is a real title (so it is never shown twice). */
|
|
265
|
+
hint?: string
|
|
266
|
+
/** The one-line summary, when the entry has one. */
|
|
267
|
+
summary?: string
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* The builder's name for a widget or a step: its `titleKey` (when `resolveKey`
|
|
272
|
+
* knows it), its `title` in `locale`, else the id. The id comes back as `hint`
|
|
273
|
+
* only next to a real title. The `description` is the LLM's text and never
|
|
274
|
+
* appears here.
|
|
275
|
+
*/
|
|
276
|
+
export function displayLabel(
|
|
277
|
+
entry: DisplayText,
|
|
278
|
+
id: string,
|
|
279
|
+
locale: string,
|
|
280
|
+
resolveKey?: DisplayKeyResolver,
|
|
281
|
+
): DisplayLabel {
|
|
282
|
+
const title = keyedText(entry.titleKey, entry.title, locale, resolveKey)
|
|
283
|
+
const summary = keyedText(entry.summaryKey, entry.summary, locale, resolveKey)
|
|
284
|
+
return {
|
|
285
|
+
label: title ?? id,
|
|
286
|
+
...(title !== undefined && title !== id ? { hint: id } : {}),
|
|
287
|
+
...(summary !== undefined ? { summary } : {}),
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** A props-sheet field: its label, the raw property name as a hint, and its help line. */
|
|
292
|
+
export interface PropFieldText {
|
|
293
|
+
label: string
|
|
294
|
+
/** The property name, set only when the label differs from it. */
|
|
295
|
+
hint?: string
|
|
296
|
+
help?: string
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
300
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* The props sheet's text for one `propsSchema` property. Label: the
|
|
305
|
+
* `x-display` title (key or text), else the standard JSON Schema `title`,
|
|
306
|
+
* else the property name. Help: the `x-display` summary, else the property's
|
|
307
|
+
* `description`.
|
|
308
|
+
*/
|
|
309
|
+
export function propFieldText(
|
|
310
|
+
name: string,
|
|
311
|
+
prop: Record<string, unknown>,
|
|
312
|
+
locale: string,
|
|
313
|
+
resolveKey?: DisplayKeyResolver,
|
|
314
|
+
): PropFieldText {
|
|
315
|
+
const raw = prop[PROPS_SCHEMA_DISPLAY_KEYWORD]
|
|
316
|
+
const display: DisplayText = isRecord(raw) ? raw : {}
|
|
317
|
+
const schemaTitle = typeof prop.title === "string" ? prop.title : undefined
|
|
318
|
+
const label =
|
|
319
|
+
keyedText(display.titleKey, display.title, locale, resolveKey) ??
|
|
320
|
+
resolveLocalizedText(schemaTitle, locale) ??
|
|
321
|
+
name
|
|
322
|
+
const schemaHelp = typeof prop.description === "string" ? prop.description : undefined
|
|
323
|
+
const help =
|
|
324
|
+
keyedText(display.summaryKey, display.summary, locale, resolveKey) ??
|
|
325
|
+
resolveLocalizedText(schemaHelp, locale)
|
|
326
|
+
return {
|
|
327
|
+
label,
|
|
328
|
+
...(label !== name ? { hint: name } : {}),
|
|
329
|
+
...(help !== undefined ? { help } : {}),
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// -------------------------------------------------------------------------- //
|
|
334
|
+
// Draft status — what Apply, Discard and the unsaved marker compare
|
|
335
|
+
// -------------------------------------------------------------------------- //
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Whether the draft holds at least one element on ANY tab, not only the
|
|
339
|
+
* active one: a new, still empty tab must not disable "Save as dashboard" or
|
|
340
|
+
* the preview while another tab has content.
|
|
341
|
+
*/
|
|
342
|
+
export function draftHasCells(draft: DraftLayout): boolean {
|
|
343
|
+
const rows = draft.kind === "tabs" ? draft.tabs.flatMap((t) => t.rows) : draft.rows
|
|
344
|
+
return rows.some((r) => r.row.length > 0)
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* A comparable fingerprint of what Apply and Save hand on: the layout, the
|
|
349
|
+
* keys (blank names dropped, values parsed) and the steps that name a step.
|
|
350
|
+
* An empty key or step row the user has not filled in changes nothing.
|
|
351
|
+
*/
|
|
352
|
+
export function builderSnapshot(
|
|
353
|
+
draft: DraftLayout,
|
|
354
|
+
keyEntries: KeyEntry[],
|
|
355
|
+
stepEntries: PipelineStepRef[],
|
|
356
|
+
): string {
|
|
357
|
+
return JSON.stringify({
|
|
358
|
+
layout: draftToLayout(draft),
|
|
359
|
+
keys: entriesToKeys(keyEntries),
|
|
360
|
+
steps: stepEntries.filter((s) => s.step.trim().length > 0),
|
|
361
|
+
})
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/** What Apply hands to `onExit`: the draft, plus the live context it was previewed with. */
|
|
365
|
+
export interface BuilderExitCommit {
|
|
366
|
+
layout: LayoutConfig
|
|
367
|
+
keys?: Record<string, unknown>
|
|
368
|
+
steps?: PipelineStepRef[]
|
|
369
|
+
title?: string
|
|
370
|
+
context?: WireContext
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* The commit of Apply: the layout, keys and steps exactly as a save would send
|
|
375
|
+
* them, and the live context in its wire shape (`stepIds` + keyed `stepData`)
|
|
376
|
+
* so the view renders the just-built layout without another round trip.
|
|
377
|
+
*/
|
|
378
|
+
export function toExitCommit(
|
|
379
|
+
draft: DraftLayout,
|
|
380
|
+
keyEntries: KeyEntry[],
|
|
381
|
+
stepEntries: PipelineStepRef[],
|
|
382
|
+
title: string | undefined,
|
|
383
|
+
live: PipelineContext,
|
|
384
|
+
): BuilderExitCommit {
|
|
385
|
+
return {
|
|
386
|
+
layout: draftToLayout(draft),
|
|
387
|
+
keys: entriesToKeys(keyEntries),
|
|
388
|
+
steps: stepEntries.filter((s) => s.step.trim().length > 0),
|
|
389
|
+
title,
|
|
390
|
+
context: {
|
|
391
|
+
keys: live.keys,
|
|
392
|
+
stepIds: Object.keys(live.steps),
|
|
393
|
+
stepData: Object.fromEntries(
|
|
394
|
+
Object.entries(live.steps).map(([id, result]) => [
|
|
395
|
+
id,
|
|
396
|
+
{ data: result.data, keys: result.keys, _app: result._app, _dataType: result._dataType },
|
|
397
|
+
]),
|
|
398
|
+
),
|
|
399
|
+
errors: live.errors,
|
|
400
|
+
},
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export interface DraftStatus {
|
|
405
|
+
/**
|
|
406
|
+
* The draft differs from the view as it was before editing: what Discard
|
|
407
|
+
* takes out of the view, so it decides whether Discard asks first.
|
|
408
|
+
*/
|
|
409
|
+
changed: boolean
|
|
410
|
+
/**
|
|
411
|
+
* The draft has changes that would be lost: it differs from the view before
|
|
412
|
+
* editing AND from the last saved dashboard (a draft equal to either one
|
|
413
|
+
* loses nothing). Drives the unsaved marker and tells the discard
|
|
414
|
+
* confirmation whether a dashboard keeps the changes.
|
|
415
|
+
*/
|
|
416
|
+
unsaved: boolean
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/** Compares the current {@link builderSnapshot} with the pre-edit one and the last saved one. */
|
|
420
|
+
export function draftStatus(current: string, baseline: string, saved: string | null): DraftStatus {
|
|
421
|
+
const changed = current !== baseline
|
|
422
|
+
return { changed, unsaved: changed && current !== saved }
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// -------------------------------------------------------------------------- //
|
|
426
|
+
// Leaving — Apply commits, Discard restores (asking first when the view loses changes)
|
|
427
|
+
// -------------------------------------------------------------------------- //
|
|
428
|
+
|
|
429
|
+
/** The builder's leave actions, built by {@link builderLeave}. */
|
|
430
|
+
export interface BuilderLeave {
|
|
431
|
+
/** Apply: hands the commit to `onExit`. Absent without `onExit` (no view to apply to). */
|
|
432
|
+
apply?: () => void
|
|
433
|
+
/** Discard: asks first when the view would lose changes, else leaves at once. */
|
|
434
|
+
discard: () => void
|
|
435
|
+
/** Discard without asking (the confirmation's own action). */
|
|
436
|
+
discardNow: () => void
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* The builder's leave actions. Apply hands `commit()` to `onExit`. Discard
|
|
441
|
+
* calls `onExit()` WITHOUT a commit, so the view stays as it was before
|
|
442
|
+
* editing; without `onExit` it calls `onReset()`, which restores the draft in
|
|
443
|
+
* place. Discard asks first (`confirm`) only when the draft `changed` the
|
|
444
|
+
* view: a draft that matches the view before editing loses nothing, even when
|
|
445
|
+
* it differs from a saved dashboard.
|
|
446
|
+
*/
|
|
447
|
+
export function builderLeave({
|
|
448
|
+
changed,
|
|
449
|
+
onExit,
|
|
450
|
+
onReset,
|
|
451
|
+
commit,
|
|
452
|
+
confirm,
|
|
453
|
+
}: {
|
|
454
|
+
changed: boolean
|
|
455
|
+
onExit?: (commit?: BuilderExitCommit) => void
|
|
456
|
+
onReset: () => void
|
|
457
|
+
commit: () => BuilderExitCommit
|
|
458
|
+
confirm: () => void
|
|
459
|
+
}): BuilderLeave {
|
|
460
|
+
// Never hands its own arguments on: a click event must not reach `onExit` as a commit.
|
|
461
|
+
const discardNow = () => {
|
|
462
|
+
if (onExit) onExit()
|
|
463
|
+
else onReset()
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
...(onExit ? { apply: () => onExit(commit()) } : {}),
|
|
467
|
+
discard: () => {
|
|
468
|
+
if (changed) confirm()
|
|
469
|
+
else discardNow()
|
|
470
|
+
},
|
|
471
|
+
discardNow,
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// -------------------------------------------------------------------------- //
|
|
476
|
+
// Keyboard — tab rename without a double-click
|
|
477
|
+
// -------------------------------------------------------------------------- //
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* What a key press on a tab trigger does: F2 renames any tab; Enter renames
|
|
481
|
+
* the tab that is already active (on another tab Enter keeps selecting it,
|
|
482
|
+
* the tabs' own behaviour). `null` leaves the key to the tabs.
|
|
483
|
+
*/
|
|
484
|
+
export function tabTriggerKeyAction(key: string, isActive: boolean): "rename" | null {
|
|
485
|
+
if (key === "F2") return "rename"
|
|
486
|
+
if (key === "Enter" && isActive) return "rename"
|
|
487
|
+
return null
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/** What a key press in a tab's rename field does: Enter commits, Escape cancels. */
|
|
491
|
+
export function renameFieldKeyAction(key: string): "commit" | "cancel" | null {
|
|
492
|
+
if (key === "Enter") return "commit"
|
|
493
|
+
if (key === "Escape") return "cancel"
|
|
494
|
+
return null
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Hands the focus back to a tab once its rename field closes by keyboard.
|
|
499
|
+
* The tab strip holds it, by the tab's INDEX: a rename that changes the label
|
|
500
|
+
* mounts a new tab, so a request held by the tab itself would go with the old
|
|
501
|
+
* one and leave the focus on the document body.
|
|
502
|
+
*/
|
|
503
|
+
export interface TabRefocus {
|
|
504
|
+
/** The trigger of tab `tabIdx` takes the focus the next time it attaches. */
|
|
505
|
+
request: (tabIdx: number) => void
|
|
506
|
+
/** The ref callback of tab `tabIdx`'s trigger: focuses it once while a request for it is open. */
|
|
507
|
+
attach: (tabIdx: number, el: { focus: () => void } | null) => void
|
|
508
|
+
/** The two props that wire tab `tabIdx` to this hand-back: its trigger's ref and its request. */
|
|
509
|
+
forTab: (tabIdx: number) => TabRefocusProps
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/** What one tab gets from {@link TabRefocus.forTab}. */
|
|
513
|
+
export interface TabRefocusProps {
|
|
514
|
+
triggerRef: (el: { focus: () => void } | null) => void
|
|
515
|
+
onRefocus: () => void
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/** A {@link TabRefocus} with no open request. */
|
|
519
|
+
export function createTabRefocus(): TabRefocus {
|
|
520
|
+
let pending: number | null = null
|
|
521
|
+
const request = (tabIdx: number) => {
|
|
522
|
+
pending = tabIdx
|
|
523
|
+
}
|
|
524
|
+
const attach = (tabIdx: number, el: { focus: () => void } | null) => {
|
|
525
|
+
if (el === null || pending !== tabIdx) return
|
|
526
|
+
pending = null
|
|
527
|
+
el.focus()
|
|
528
|
+
}
|
|
529
|
+
return {
|
|
530
|
+
request,
|
|
531
|
+
attach,
|
|
532
|
+
forTab: (tabIdx) => ({
|
|
533
|
+
triggerRef: (el) => attach(tabIdx, el),
|
|
534
|
+
onRefocus: () => request(tabIdx),
|
|
535
|
+
}),
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// -------------------------------------------------------------------------- //
|
|
540
|
+
// Views — the data sources live behind "Advanced"
|
|
541
|
+
// -------------------------------------------------------------------------- //
|
|
542
|
+
|
|
543
|
+
export type BuilderView = "layout" | "pipeline" | "preview"
|
|
544
|
+
|
|
545
|
+
/** The builder's views in tab order: the data sources ("pipeline") only in advanced mode. */
|
|
546
|
+
export function builderViews(advanced: boolean): BuilderView[] {
|
|
547
|
+
return advanced ? ["layout", "pipeline", "preview"] : ["layout", "preview"]
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/** The view to show after advanced mode switches: a view that is now hidden falls back to the layout. */
|
|
551
|
+
export function viewAfterAdvancedToggle(view: BuilderView, advanced: boolean): BuilderView {
|
|
552
|
+
return builderViews(advanced).includes(view) ? view : "layout"
|
|
553
|
+
}
|