@miragon/mcp-toolkit-ui 2.6.0 → 2.8.0
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 +14 -5
- 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.d.ts +7 -2
- package/dist/app/builder/BuilderBanners.d.ts.map +1 -1
- package/dist/app/builder/BuilderBanners.js +8 -3
- 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 +29 -17
- 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 +14 -6
- 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/EmptyHint.d.ts +4 -0
- package/dist/app/builder/EmptyHint.d.ts.map +1 -1
- package/dist/app/builder/EmptyHint.js +6 -1
- package/dist/app/builder/EmptyHint.js.map +1 -1
- 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 +5 -2
- package/dist/app/builder/PipelineStrip.d.ts.map +1 -1
- package/dist/app/builder/PipelineStrip.js +33 -15
- 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 +9 -3
- package/dist/app/builder/SaveDialog.js.map +1 -1
- package/dist/app/builder/Toolbar.d.ts +14 -4
- package/dist/app/builder/Toolbar.d.ts.map +1 -1
- package/dist/app/builder/Toolbar.js +24 -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 +146 -3
- package/dist/app/builder/builder-model.d.ts.map +1 -1
- package/dist/app/builder/builder-model.js +196 -5
- package/dist/app/builder/builder-model.js.map +1 -1
- package/dist/app/builder/labels.d.ts +13 -62
- package/dist/app/builder/labels.d.ts.map +1 -1
- package/dist/app/builder/labels.js +9 -58
- package/dist/app/builder/labels.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/status-chip.d.ts.map +1 -1
- package/dist/app/builder/status-chip.js +3 -2
- package/dist/app/builder/status-chip.js.map +1 -1
- package/dist/app/builder/use-builder-catalogue.d.ts +5 -1
- package/dist/app/builder/use-builder-catalogue.d.ts.map +1 -1
- package/dist/app/builder/use-builder-catalogue.js +50 -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/builder/use-save-dashboard.d.ts +3 -1
- package/dist/app/builder/use-save-dashboard.d.ts.map +1 -1
- package/dist/app/builder/use-save-dashboard.js +3 -1
- package/dist/app/builder/use-save-dashboard.js.map +1 -1
- 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 +18 -25
- package/dist/app/layout-builder.d.ts.map +1 -1
- package/dist/app/layout-builder.js +84 -78
- package/dist/app/layout-builder.js.map +1 -1
- package/dist/app/mcp-app-view-chrome.d.ts +103 -20
- package/dist/app/mcp-app-view-chrome.d.ts.map +1 -1
- package/dist/app/mcp-app-view-chrome.js +125 -40
- package/dist/app/mcp-app-view-chrome.js.map +1 -1
- package/dist/app/mcp-app-view-states.d.ts +23 -0
- package/dist/app/mcp-app-view-states.d.ts.map +1 -0
- package/dist/app/mcp-app-view-states.js +55 -0
- package/dist/app/mcp-app-view-states.js.map +1 -0
- package/dist/app/mcp-app-view.d.ts +72 -5
- package/dist/app/mcp-app-view.d.ts.map +1 -1
- package/dist/app/mcp-app-view.js +241 -141
- package/dist/app/mcp-app-view.js.map +1 -1
- package/dist/app/mcp-toolkit-app.d.ts +8 -2
- package/dist/app/mcp-toolkit-app.d.ts.map +1 -1
- package/dist/app/mcp-toolkit-app.js +33 -4
- 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 +42 -0
- package/dist/app/use-view-lifecycle.d.ts.map +1 -0
- package/dist/app/use-view-lifecycle.js +81 -0
- package/dist/app/use-view-lifecycle.js.map +1 -0
- package/dist/app/view-lifecycle.d.ts +185 -0
- package/dist/app/view-lifecycle.d.ts.map +1 -0
- package/dist/app/view-lifecycle.js +207 -0
- package/dist/app/view-lifecycle.js.map +1 -0
- 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 +6 -10
- package/dist/app/widget-props-sheet.d.ts.map +1 -1
- package/dist/app/widget-props-sheet.js +25 -20
- package/dist/app/widget-props-sheet.js.map +1 -1
- package/dist/app/widget-renderer.d.ts +41 -1
- package/dist/app/widget-renderer.d.ts.map +1 -1
- package/dist/app/widget-renderer.js +82 -31
- package/dist/app/widget-renderer.js.map +1 -1
- package/dist/components/DrillButton.d.ts +9 -6
- package/dist/components/DrillButton.d.ts.map +1 -1
- package/dist/components/DrillButton.js +9 -6
- package/dist/components/DrillButton.js.map +1 -1
- package/dist/components/EmptyState.d.ts +33 -0
- package/dist/components/EmptyState.d.ts.map +1 -0
- package/dist/components/EmptyState.js +19 -0
- package/dist/components/EmptyState.js.map +1 -0
- package/dist/components/ErrorState.d.ts +53 -0
- package/dist/components/ErrorState.d.ts.map +1 -0
- package/dist/components/ErrorState.js +77 -0
- package/dist/components/ErrorState.js.map +1 -0
- package/dist/components/FilterBar.d.ts +16 -5
- package/dist/components/FilterBar.d.ts.map +1 -1
- package/dist/components/FilterBar.js +13 -5
- package/dist/components/FilterBar.js.map +1 -1
- package/dist/components/GroupCard.d.ts.map +1 -1
- package/dist/components/GroupCard.js +2 -1
- package/dist/components/GroupCard.js.map +1 -1
- package/dist/components/KpiGrid.d.ts +70 -18
- package/dist/components/KpiGrid.d.ts.map +1 -1
- package/dist/components/KpiGrid.js +112 -23
- package/dist/components/KpiGrid.js.map +1 -1
- package/dist/components/ListFooter.d.ts +32 -4
- package/dist/components/ListFooter.d.ts.map +1 -1
- package/dist/components/ListFooter.js +35 -6
- 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 +36 -12
- package/dist/components/Pills.d.ts.map +1 -1
- package/dist/components/Pills.js +29 -8
- 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 +43 -0
- package/dist/components/Toast.d.ts.map +1 -0
- package/dist/components/Toast.js +106 -0
- package/dist/components/Toast.js.map +1 -0
- 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 +61 -44
- package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -1
- package/dist/hooks/use-tool-result-recovery.js +62 -110
- package/dist/hooks/use-tool-result-recovery.js.map +1 -1
- package/dist/hooks/use-view-data.d.ts +55 -7
- package/dist/hooks/use-view-data.d.ts.map +1 -1
- package/dist/hooks/use-view-data.js +81 -11
- 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 +27 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -7
- 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/focus-ring.d.ts +18 -0
- package/dist/lib/focus-ring.d.ts.map +1 -0
- package/dist/lib/focus-ring.js +18 -0
- package/dist/lib/focus-ring.js.map +1 -0
- package/dist/lib/icon-stroke.d.ts +12 -0
- package/dist/lib/icon-stroke.d.ts.map +1 -0
- package/dist/lib/icon-stroke.js +12 -0
- package/dist/lib/icon-stroke.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 +86 -0
- package/dist/lib/toast-model.d.ts.map +1 -0
- package/dist/lib/toast-model.js +102 -0
- package/dist/lib/toast-model.js.map +1 -0
- package/dist/lib/tone-utils.d.ts +95 -9
- package/dist/lib/tone-utils.d.ts.map +1 -1
- package/dist/lib/tone-utils.js +100 -9
- 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 +3 -1
- package/dist/locale/index.d.ts.map +1 -1
- package/dist/locale/index.js +2 -1
- package/dist/locale/index.js.map +1 -1
- package/dist/locale/locale-provider.d.ts +42 -1
- package/dist/locale/locale-provider.d.ts.map +1 -1
- package/dist/locale/locale-provider.js +44 -3
- package/dist/locale/locale-provider.js.map +1 -1
- package/dist/locale/message-types.d.ts +336 -0
- package/dist/locale/message-types.d.ts.map +1 -0
- package/dist/locale/message-types.js +7 -0
- package/dist/locale/message-types.js.map +1 -0
- package/dist/locale/messages-de.d.ts +9 -0
- package/dist/locale/messages-de.d.ts.map +1 -0
- package/dist/locale/messages-de.js +185 -0
- package/dist/locale/messages-de.js.map +1 -0
- package/dist/locale/messages-en.d.ts +8 -0
- package/dist/locale/messages-en.d.ts.map +1 -0
- package/dist/locale/messages-en.js +184 -0
- package/dist/locale/messages-en.js.map +1 -0
- package/dist/locale/toolkit-messages.d.ts +57 -0
- package/dist/locale/toolkit-messages.d.ts.map +1 -0
- package/dist/locale/toolkit-messages.js +103 -0
- package/dist/locale/toolkit-messages.js.map +1 -0
- package/dist/primitives/alert.d.ts +1 -1
- package/dist/primitives/alert.d.ts.map +1 -1
- package/dist/primitives/alert.js +6 -2
- 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 +19 -6
- package/dist/primitives/badge.js.map +1 -1
- package/dist/primitives/button.d.ts +1 -1
- package/dist/primitives/button.d.ts.map +1 -1
- package/dist/primitives/button.js +12 -8
- package/dist/primitives/button.js.map +1 -1
- package/dist/primitives/card.js +4 -4
- package/dist/primitives/card.js.map +1 -1
- package/dist/primitives/dialog.d.ts +7 -3
- package/dist/primitives/dialog.d.ts.map +1 -1
- package/dist/primitives/dialog.js +22 -8
- package/dist/primitives/dialog.js.map +1 -1
- package/dist/primitives/input.d.ts.map +1 -1
- package/dist/primitives/input.js +4 -1
- package/dist/primitives/input.js.map +1 -1
- package/dist/primitives/scroll-area.js +1 -1
- package/dist/primitives/scroll-area.js.map +1 -1
- package/dist/primitives/select.d.ts.map +1 -1
- package/dist/primitives/select.js +6 -3
- package/dist/primitives/select.js.map +1 -1
- package/dist/primitives/sheet.d.ts +3 -1
- package/dist/primitives/sheet.d.ts.map +1 -1
- package/dist/primitives/sheet.js +17 -7
- package/dist/primitives/sheet.js.map +1 -1
- package/dist/primitives/skeleton.js +1 -1
- package/dist/primitives/skeleton.js.map +1 -1
- package/dist/primitives/switch.d.ts.map +1 -1
- package/dist/primitives/switch.js +2 -1
- package/dist/primitives/switch.js.map +1 -1
- package/dist/primitives/tabs.d.ts.map +1 -1
- package/dist/primitives/tabs.js +5 -3
- package/dist/primitives/tabs.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 +48 -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/render-scan.d.ts +25 -0
- package/dist/render-scan.d.ts.map +1 -0
- package/dist/render-scan.js +66 -0
- package/dist/render-scan.js.map +1 -0
- package/dist/theme/cd-tokens.d.ts +66 -0
- package/dist/theme/cd-tokens.d.ts.map +1 -0
- package/dist/theme/cd-tokens.js +64 -0
- package/dist/theme/cd-tokens.js.map +1 -0
- package/dist/theme/create-theme.d.ts +214 -39
- package/dist/theme/create-theme.d.ts.map +1 -1
- package/dist/theme/create-theme.js +204 -13
- package/dist/theme/create-theme.js.map +1 -1
- package/dist/theme/fonts.d.ts +38 -0
- package/dist/theme/fonts.d.ts.map +1 -0
- package/dist/theme/fonts.js +56 -0
- package/dist/theme/fonts.js.map +1 -0
- package/dist/theme/host-fonts.d.ts +39 -0
- package/dist/theme/host-fonts.d.ts.map +1 -0
- package/dist/theme/host-fonts.js +44 -0
- package/dist/theme/host-fonts.js.map +1 -0
- package/dist/theme/index.d.ts +8 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +5 -1
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/portal-container.d.ts +16 -0
- package/dist/theme/portal-container.d.ts.map +1 -0
- package/dist/theme/portal-container.js +19 -0
- package/dist/theme/portal-container.js.map +1 -0
- package/dist/theme/presets.d.ts +24 -9
- package/dist/theme/presets.d.ts.map +1 -1
- package/dist/theme/presets.js +44 -11
- package/dist/theme/presets.js.map +1 -1
- package/dist/theme/theme-provider.d.ts +27 -9
- package/dist/theme/theme-provider.d.ts.map +1 -1
- package/dist/theme/theme-provider.js +42 -20
- package/dist/theme/theme-provider.js.map +1 -1
- package/package.json +11 -5
- package/src/app/adapt-data-widget.tsx +2 -42
- package/src/app/builder/BuilderBanners.tsx +26 -13
- package/src/app/builder/CanvasRow.tsx +79 -32
- package/src/app/builder/CatalogueSheet.tsx +58 -35
- package/src/app/builder/CellPropsSheet.tsx +17 -2
- package/src/app/builder/DiscardDialog.tsx +59 -0
- package/src/app/builder/EmptyHint.tsx +16 -11
- package/src/app/builder/LayoutSurface.tsx +207 -67
- package/src/app/builder/PipelineStrip.tsx +265 -156
- package/src/app/builder/SaveDialog.tsx +25 -14
- package/src/app/builder/Toolbar.tsx +154 -57
- package/src/app/builder/Workspace.tsx +226 -56
- package/src/app/builder/builder-feedback.test.tsx +75 -0
- package/src/app/builder/builder-model.test.ts +5 -0
- package/src/app/builder/builder-model.ts +346 -6
- 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/labels.ts +15 -121
- package/src/app/builder/reveal.ts +10 -0
- package/src/app/builder/status-chip.tsx +8 -4
- package/src/app/builder/use-builder-catalogue.ts +62 -19
- package/src/app/builder/use-builder-session.ts +68 -0
- package/src/app/builder/use-display-resolver.ts +24 -0
- package/src/app/builder/use-save-dashboard.ts +5 -0
- package/src/app/index.ts +20 -3
- package/src/app/layout-builder.tsx +193 -186
- package/src/app/mcp-app-view-chrome.test.tsx +487 -14
- package/src/app/mcp-app-view-chrome.tsx +328 -100
- package/src/app/mcp-app-view-states.tsx +140 -0
- package/src/app/mcp-app-view.effects.test.tsx +292 -0
- package/src/app/mcp-app-view.test.tsx +478 -0
- package/src/app/mcp-app-view.tsx +447 -190
- package/src/app/mcp-toolkit-app.test.tsx +40 -0
- package/src/app/mcp-toolkit-app.tsx +39 -8
- 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 +122 -0
- package/src/app/view-lifecycle.test.ts +443 -0
- package/src/app/view-lifecycle.ts +334 -0
- 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 +67 -39
- package/src/app/widget-renderer.render.test.tsx +131 -0
- package/src/app/widget-renderer.tsx +136 -38
- package/src/components/DrillButton.tsx +24 -10
- package/src/components/EmptyState.tsx +83 -0
- package/src/components/ErrorState.tsx +204 -0
- package/src/components/FilterBar.test.tsx +82 -0
- package/src/components/FilterBar.tsx +56 -27
- package/src/components/GroupCard.tsx +3 -2
- package/src/components/KpiGrid.test.tsx +279 -0
- package/src/components/KpiGrid.tsx +329 -91
- package/src/components/ListFooter.test.tsx +116 -0
- package/src/components/ListFooter.tsx +110 -12
- 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 +78 -16
- package/src/components/SectionHeading.tsx +9 -3
- package/src/components/Toast.tsx +206 -0
- package/src/components/WidgetHeader.test.tsx +78 -0
- package/src/components/WidgetHeader.tsx +63 -16
- package/src/components/feedback-states.test.tsx +314 -0
- package/src/components/tone-figures.test.tsx +58 -0
- package/src/fonts.css +19 -0
- package/src/globals.css +9 -165
- 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 +28 -5
- package/src/hooks/use-tool-result-recovery.ts +101 -131
- package/src/hooks/use-view-data.test.tsx +169 -0
- package/src/hooks/use-view-data.ts +131 -10
- package/src/hooks/use-view-tool-query.ts +25 -19
- package/src/i18n-coverage.test.tsx +425 -0
- package/src/index.ts +102 -13
- package/src/lib/focus-return.test.ts +288 -0
- package/src/lib/focus-return.ts +96 -0
- package/src/lib/focus-ring.ts +20 -0
- package/src/lib/icon-stroke.test.ts +59 -0
- package/src/lib/icon-stroke.ts +13 -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 +233 -0
- package/src/lib/toast-model.ts +165 -0
- package/src/lib/tone-utils.test.ts +125 -16
- package/src/lib/tone-utils.ts +144 -15
- 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 +14 -1
- package/src/locale/locale-provider.test.tsx +87 -0
- package/src/locale/locale-provider.tsx +90 -3
- package/src/locale/message-types.ts +337 -0
- package/src/locale/messages-de.ts +198 -0
- package/src/locale/messages-en.ts +196 -0
- package/src/locale/toolkit-messages.test.ts +349 -0
- package/src/locale/toolkit-messages.ts +143 -0
- package/src/no-hardcoded-copy.test.ts +432 -0
- package/src/primitives/alert.tsx +7 -2
- package/src/primitives/badge.tsx +19 -7
- package/src/primitives/button.tsx +13 -8
- package/src/primitives/card.tsx +4 -4
- package/src/primitives/dialog.tsx +42 -8
- package/src/primitives/input.tsx +5 -3
- package/src/primitives/scroll-area.tsx +1 -1
- package/src/primitives/select.tsx +7 -4
- package/src/primitives/sheet.tsx +33 -6
- package/src/primitives/skeleton.tsx +1 -1
- package/src/primitives/switch.tsx +4 -2
- package/src/primitives/tabs.tsx +9 -6
- 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 +82 -6
- package/src/render-effects.tsx +96 -0
- package/src/render-scan.ts +75 -0
- package/src/theme/cd-tokens.generated.css +48 -0
- package/src/theme/cd-tokens.test.ts +109 -0
- package/src/theme/cd-tokens.ts +67 -0
- package/src/theme/create-theme.test.ts +253 -5
- package/src/theme/create-theme.ts +341 -41
- package/src/theme/fonts.test.ts +85 -0
- package/src/theme/fonts.ts +72 -0
- package/src/theme/host-fonts.test.ts +135 -0
- package/src/theme/host-fonts.ts +52 -0
- package/src/theme/index.ts +15 -1
- package/src/theme/portal-container.ts +20 -0
- package/src/theme/presets.ts +44 -11
- package/src/theme/theme-css.test.ts +619 -0
- package/src/theme/theme-provider.test.tsx +82 -0
- package/src/theme/theme-provider.tsx +60 -24
- package/src/theme.css +344 -0
- package/ui-catalog.json +783 -49
|
@@ -1,36 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Presentational chrome for `McpAppView` — the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Split out of `mcp-app-view.tsx` so the shell
|
|
6
|
-
* host-sync and state logic while
|
|
2
|
+
* Presentational chrome for `McpAppView` — the toolbar, the failed-steps
|
|
3
|
+
* alert, and the build/render body — plus the view-envelope types they share.
|
|
4
|
+
* The pre-payload states (waiting / error / cancelled) live in
|
|
5
|
+
* `mcp-app-view-states.tsx`. Split out of `mcp-app-view.tsx` so the shell
|
|
6
|
+
* component keeps only the host-sync and state logic while these files stay
|
|
7
|
+
* hook-light.
|
|
7
8
|
*/
|
|
8
|
-
import {
|
|
9
|
+
import { createElement, type ReactNode } from "react"
|
|
10
|
+
import { LucideProvider, Maximize2, Minimize2, Pencil, RefreshCw } from "lucide-react"
|
|
9
11
|
import type { LayoutConfig, PipelineStepRef } from "@miragon/mcp-toolkit-core"
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
+
import { ErrorState } from "../components/ErrorState.js"
|
|
13
|
+
import { DENSE_ICON_STROKE } from "../lib/icon-stroke.js"
|
|
14
|
+
import { TOOLKIT_MESSAGES, type ViewMessages } from "../locale/toolkit-messages.js"
|
|
15
|
+
import { Button } from "../primitives/button.js"
|
|
16
|
+
import {
|
|
17
|
+
LayoutBuilder,
|
|
18
|
+
type LayoutBuilderLabels,
|
|
19
|
+
type LayoutBuilderProps,
|
|
20
|
+
} from "./layout-builder.js"
|
|
12
21
|
import { WidgetRenderer, type WidgetComponent } from "./widget-renderer.js"
|
|
13
22
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
enterFullscreen?: string
|
|
21
|
-
exitFullscreen?: string
|
|
22
|
-
build?: string
|
|
23
|
-
}
|
|
23
|
+
/**
|
|
24
|
+
* Override strings of the view chrome (placeholder, error state, toolbar,
|
|
25
|
+
* step errors). Every field defaults to the active locale's toolkit catalog
|
|
26
|
+
* (`en`/`de`, see `useToolkitMessages`).
|
|
27
|
+
*/
|
|
28
|
+
export type McpAppViewLabels = Partial<ViewMessages>
|
|
24
29
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
/**
|
|
31
|
+
* English chrome strings.
|
|
32
|
+
* @deprecated Read the active locale's strings with `useToolkitMessages().view`
|
|
33
|
+
* (or `TOOLKIT_MESSAGES.en.view`); this alias stays for existing imports.
|
|
34
|
+
*/
|
|
35
|
+
export const DEFAULT_LABELS: Required<McpAppViewLabels> = TOOLKIT_MESSAGES.en.view
|
|
36
|
+
|
|
37
|
+
/** How the toolbar shows the view title — so a view has exactly ONE title. */
|
|
38
|
+
export type ViewTitleMode = "show" | "hide" | "slot"
|
|
39
|
+
|
|
40
|
+
/** Heading level of the toolbar title. */
|
|
41
|
+
export type ViewTitleLevel = 1 | 2 | 3 | 4 | 5 | 6
|
|
34
42
|
|
|
35
43
|
export interface RefreshParams {
|
|
36
44
|
keys?: Record<string, unknown>
|
|
@@ -71,32 +79,40 @@ export function isCompleteViewData(value: unknown): value is ViewData {
|
|
|
71
79
|
return Boolean(v?.context && v?.layout)
|
|
72
80
|
}
|
|
73
81
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
82
|
+
/** What the LayoutBuilder hands back on Apply. */
|
|
83
|
+
export interface BuilderCommit {
|
|
84
|
+
layout: LayoutConfig
|
|
85
|
+
keys?: Record<string, unknown>
|
|
86
|
+
steps?: PipelineStepRef[]
|
|
87
|
+
title?: string
|
|
88
|
+
context?: ViewData["context"]
|
|
89
|
+
}
|
|
77
90
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
</div>
|
|
91
|
-
)
|
|
91
|
+
/**
|
|
92
|
+
* Commit the builder's draft into the view payload so the renderer shows the
|
|
93
|
+
* just-built layout and Refresh re-issues it. Exported for tests.
|
|
94
|
+
*/
|
|
95
|
+
export function applyBuilderCommit(prev: ViewData, commit: BuilderCommit): ViewData {
|
|
96
|
+
const title = commit.title ?? prev.title
|
|
97
|
+
return {
|
|
98
|
+
...prev,
|
|
99
|
+
layout: commit.layout,
|
|
100
|
+
title,
|
|
101
|
+
context: commit.context ?? prev.context,
|
|
102
|
+
_refreshParams: { keys: commit.keys, steps: commit.steps, layout: commit.layout, title },
|
|
92
103
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Whether the Fullscreen toggle may render: the host offers fullscreen
|
|
108
|
+
* (mcp-use's negotiated `availableDisplayModes`, toolkit#178 K22), or the view
|
|
109
|
+
* is already there (its exit toggle must stay).
|
|
110
|
+
*/
|
|
111
|
+
export function fullscreenAvailable(
|
|
112
|
+
displayMode: string,
|
|
113
|
+
availableDisplayModes: readonly string[],
|
|
114
|
+
): boolean {
|
|
115
|
+
return displayMode === "fullscreen" || availableDisplayModes.includes("fullscreen")
|
|
100
116
|
}
|
|
101
117
|
|
|
102
118
|
// -------------------------------------------------------------------------- //
|
|
@@ -109,91 +125,294 @@ export interface ViewToolbarProps {
|
|
|
109
125
|
viewData: ViewData
|
|
110
126
|
builderAvailable: boolean
|
|
111
127
|
isFullscreen: boolean
|
|
128
|
+
/** The host offers fullscreen (see {@link fullscreenAvailable}). */
|
|
129
|
+
canFullscreen: boolean
|
|
112
130
|
isRefreshing: boolean
|
|
113
131
|
labels: Required<McpAppViewLabels>
|
|
132
|
+
titleMode: ViewTitleMode
|
|
133
|
+
titleLevel: ViewTitleLevel
|
|
134
|
+
renderTitle?: (title: string | undefined) => ReactNode
|
|
114
135
|
onRefresh: () => Promise<void>
|
|
115
136
|
onEnterBuildMode: () => void
|
|
116
137
|
onToggleFullscreen: () => Promise<void>
|
|
138
|
+
/**
|
|
139
|
+
* The pre-formatted time of a view that loaded its data again on its own
|
|
140
|
+
* (toolkit#176 N23): the toolbar stamps it in a quiet line under the title,
|
|
141
|
+
* so the figures read as live data of that time, not the result the chat
|
|
142
|
+
* answered from.
|
|
143
|
+
*/
|
|
144
|
+
dataAsOf?: string
|
|
117
145
|
}
|
|
118
146
|
|
|
147
|
+
/** The toolbar title per {@link ViewTitleMode}: a heading, the consumer's slot, or nothing. */
|
|
148
|
+
function ToolbarTitle({
|
|
149
|
+
title,
|
|
150
|
+
mode,
|
|
151
|
+
level,
|
|
152
|
+
renderTitle,
|
|
153
|
+
}: {
|
|
154
|
+
title: string | undefined
|
|
155
|
+
mode: ViewTitleMode
|
|
156
|
+
level: ViewTitleLevel
|
|
157
|
+
renderTitle?: (title: string | undefined) => ReactNode
|
|
158
|
+
}) {
|
|
159
|
+
if (mode === "slot") return <div className="min-w-0 flex-1">{renderTitle?.(title)}</div>
|
|
160
|
+
if (mode === "hide" || !title) return null
|
|
161
|
+
return createElement(
|
|
162
|
+
`h${level}`,
|
|
163
|
+
{ className: "min-w-0 flex-1 truncate text-lg font-semibold tracking-tight" },
|
|
164
|
+
title,
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* The title, and under it the stamp of data the view re-loaded itself. The
|
|
170
|
+
* stamp is a second line of the title column, never an item beside the
|
|
171
|
+
* controls: the title keeps the row's width (it is the user's orientation),
|
|
172
|
+
* and the stamp truncates only against its own column. Its words carry its
|
|
173
|
+
* meaning, so it needs no tooltip that touch and keyboard users never reach.
|
|
174
|
+
* Without a stamp the title renders as before, straight in the row.
|
|
175
|
+
*/
|
|
176
|
+
function ToolbarHeading({
|
|
177
|
+
title,
|
|
178
|
+
mode,
|
|
179
|
+
level,
|
|
180
|
+
renderTitle,
|
|
181
|
+
stamp,
|
|
182
|
+
}: {
|
|
183
|
+
title: string | undefined
|
|
184
|
+
mode: ViewTitleMode
|
|
185
|
+
level: ViewTitleLevel
|
|
186
|
+
renderTitle?: (title: string | undefined) => ReactNode
|
|
187
|
+
stamp: string | undefined
|
|
188
|
+
}) {
|
|
189
|
+
const heading = <ToolbarTitle title={title} mode={mode} level={level} renderTitle={renderTitle} />
|
|
190
|
+
if (!stamp) return heading
|
|
191
|
+
return (
|
|
192
|
+
<div data-slot="view-heading" className="min-w-0 flex-1">
|
|
193
|
+
{heading}
|
|
194
|
+
<p data-slot="view-data-as-of" className="text-muted-foreground truncate text-sm">
|
|
195
|
+
{stamp}
|
|
196
|
+
</p>
|
|
197
|
+
</div>
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** Which toolbar controls render — pure, so the gates are unit-testable. */
|
|
202
|
+
export function toolbarControls(input: {
|
|
203
|
+
viewData: Pick<ViewData, "_refreshParams" | "layout" | "title">
|
|
204
|
+
builderAvailable: boolean
|
|
205
|
+
canFullscreen: boolean
|
|
206
|
+
titleMode: ViewTitleMode
|
|
207
|
+
}): { title: boolean; refresh: boolean; edit: boolean; fullscreen: boolean; any: boolean } {
|
|
208
|
+
const refreshable = Boolean(input.viewData._refreshParams && input.viewData.layout)
|
|
209
|
+
const edit = input.builderAvailable && Boolean(input.viewData._refreshParams)
|
|
210
|
+
const title =
|
|
211
|
+
input.titleMode === "slot" || (input.titleMode === "show" && Boolean(input.viewData.title))
|
|
212
|
+
return {
|
|
213
|
+
title,
|
|
214
|
+
refresh: refreshable,
|
|
215
|
+
edit,
|
|
216
|
+
fullscreen: input.canFullscreen,
|
|
217
|
+
any: title || refreshable || edit || input.canFullscreen,
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* The CI §8 chrome button (Icon-Button, Chrome): surface, `--cd-linie` border,
|
|
223
|
+
* shadow-1, blue on hover. The `outline` variant brings the surface, the
|
|
224
|
+
* border and the blue hover (it is also CI §8's secondary button, which has no
|
|
225
|
+
* shadow), so the chrome adds `shadow-1` on top instead of changing it.
|
|
226
|
+
*/
|
|
227
|
+
const CHROME_BUTTON = { variant: "outline", className: "shadow-1" } as const
|
|
228
|
+
|
|
229
|
+
function RefreshButton({
|
|
230
|
+
isRefreshing,
|
|
231
|
+
labels,
|
|
232
|
+
onRefresh,
|
|
233
|
+
}: {
|
|
234
|
+
isRefreshing: boolean
|
|
235
|
+
labels: Required<McpAppViewLabels>
|
|
236
|
+
onRefresh: () => Promise<void>
|
|
237
|
+
}) {
|
|
238
|
+
const label = isRefreshing ? labels.refreshing : labels.refresh
|
|
239
|
+
return (
|
|
240
|
+
<Button
|
|
241
|
+
type="button"
|
|
242
|
+
{...CHROME_BUTTON}
|
|
243
|
+
size="icon-sm"
|
|
244
|
+
aria-label={label}
|
|
245
|
+
title={label}
|
|
246
|
+
disabled={isRefreshing}
|
|
247
|
+
onClick={() => {
|
|
248
|
+
void onRefresh()
|
|
249
|
+
}}
|
|
250
|
+
>
|
|
251
|
+
<RefreshCw
|
|
252
|
+
aria-hidden="true"
|
|
253
|
+
className={isRefreshing ? "motion-safe:animate-spin" : undefined}
|
|
254
|
+
/>
|
|
255
|
+
</Button>
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function FullscreenButton({
|
|
260
|
+
isFullscreen,
|
|
261
|
+
labels,
|
|
262
|
+
onToggle,
|
|
263
|
+
}: {
|
|
264
|
+
isFullscreen: boolean
|
|
265
|
+
labels: Required<McpAppViewLabels>
|
|
266
|
+
onToggle: () => Promise<void>
|
|
267
|
+
}) {
|
|
268
|
+
const label = isFullscreen ? labels.exitFullscreen : labels.enterFullscreen
|
|
269
|
+
const Icon = isFullscreen ? Minimize2 : Maximize2
|
|
270
|
+
return (
|
|
271
|
+
<Button
|
|
272
|
+
type="button"
|
|
273
|
+
{...CHROME_BUTTON}
|
|
274
|
+
size="icon-sm"
|
|
275
|
+
aria-label={label}
|
|
276
|
+
title={label}
|
|
277
|
+
onClick={() => {
|
|
278
|
+
void onToggle()
|
|
279
|
+
}}
|
|
280
|
+
>
|
|
281
|
+
<Icon aria-hidden="true" />
|
|
282
|
+
</Button>
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* The view toolbar: the title (per {@link ViewTitleMode}, so a widget that
|
|
288
|
+
* renders its own heading is not titled twice), then Edit, Refresh and
|
|
289
|
+
* Fullscreen. Refresh and Fullscreen are 32 px icon buttons named by
|
|
290
|
+
* `aria-label`; Fullscreen renders only when the host offers it. All three are
|
|
291
|
+
* chrome buttons in the CI pattern (CI §8: surface, border, shadow-1, blue
|
|
292
|
+
* hover; {@link CHROME_BUTTON}). A 16 px inset keeps the bar off the frame
|
|
293
|
+
* edge, also in fullscreen. The controls never shrink; the stamp of re-loaded
|
|
294
|
+
* data sits under the title ({@link ToolbarHeading}), so neither the title
|
|
295
|
+
* nor the stamp competes with the controls for width.
|
|
296
|
+
*/
|
|
119
297
|
export function ViewToolbar({
|
|
120
298
|
hidden,
|
|
121
299
|
viewData,
|
|
122
300
|
builderAvailable,
|
|
123
301
|
isFullscreen,
|
|
302
|
+
canFullscreen,
|
|
124
303
|
isRefreshing,
|
|
125
304
|
labels,
|
|
305
|
+
titleMode,
|
|
306
|
+
titleLevel,
|
|
307
|
+
renderTitle,
|
|
126
308
|
onRefresh,
|
|
127
309
|
onEnterBuildMode,
|
|
128
310
|
onToggleFullscreen,
|
|
311
|
+
dataAsOf,
|
|
129
312
|
}: ViewToolbarProps) {
|
|
130
|
-
|
|
313
|
+
const show = toolbarControls({ viewData, builderAvailable, canFullscreen, titleMode })
|
|
314
|
+
if (hidden || (!show.any && !dataAsOf)) return null
|
|
131
315
|
return (
|
|
132
|
-
<
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
<
|
|
144
|
-
|
|
145
|
-
|
|
316
|
+
<LucideProvider strokeWidth={DENSE_ICON_STROKE}>
|
|
317
|
+
<div data-slot="view-toolbar" className="flex min-h-12 items-center gap-2 px-4 py-2">
|
|
318
|
+
<ToolbarHeading
|
|
319
|
+
title={viewData.title}
|
|
320
|
+
mode={titleMode}
|
|
321
|
+
level={titleLevel}
|
|
322
|
+
renderTitle={renderTitle}
|
|
323
|
+
stamp={dataAsOf ? labels.dataAsOf(dataAsOf) : undefined}
|
|
324
|
+
/>
|
|
325
|
+
<div className="ml-auto flex shrink-0 items-center gap-1">
|
|
326
|
+
{show.edit && (
|
|
327
|
+
<Button
|
|
328
|
+
type="button"
|
|
329
|
+
{...CHROME_BUTTON}
|
|
330
|
+
size="sm"
|
|
331
|
+
data-slot="view-edit"
|
|
332
|
+
onClick={onEnterBuildMode}
|
|
333
|
+
>
|
|
334
|
+
<Pencil aria-hidden="true" />
|
|
335
|
+
{labels.build}
|
|
336
|
+
</Button>
|
|
337
|
+
)}
|
|
338
|
+
{show.refresh && (
|
|
339
|
+
<RefreshButton isRefreshing={isRefreshing} labels={labels} onRefresh={onRefresh} />
|
|
340
|
+
)}
|
|
341
|
+
{show.fullscreen && (
|
|
342
|
+
<FullscreenButton
|
|
343
|
+
isFullscreen={isFullscreen}
|
|
344
|
+
labels={labels}
|
|
345
|
+
onToggle={onToggleFullscreen}
|
|
146
346
|
/>
|
|
147
|
-
{isRefreshing ? labels.refreshing : labels.refresh}
|
|
148
|
-
</button>
|
|
149
|
-
)}
|
|
150
|
-
{builderAvailable && viewData._refreshParams && (
|
|
151
|
-
<button
|
|
152
|
-
onClick={onEnterBuildMode}
|
|
153
|
-
className="hover:bg-accent hover:text-accent-foreground inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-sm font-medium transition-colors"
|
|
154
|
-
>
|
|
155
|
-
<Pencil className="h-4 w-4" />
|
|
156
|
-
{labels.build}
|
|
157
|
-
</button>
|
|
158
|
-
)}
|
|
159
|
-
<button
|
|
160
|
-
onClick={() => {
|
|
161
|
-
void onToggleFullscreen()
|
|
162
|
-
}}
|
|
163
|
-
className="hover:bg-accent hover:text-accent-foreground inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-sm font-medium transition-colors"
|
|
164
|
-
>
|
|
165
|
-
{isFullscreen ? (
|
|
166
|
-
<Minimize2 aria-hidden="true" className="h-4 w-4" />
|
|
167
|
-
) : (
|
|
168
|
-
<Maximize2 aria-hidden="true" className="h-4 w-4" />
|
|
169
347
|
)}
|
|
170
|
-
|
|
171
|
-
</button>
|
|
348
|
+
</div>
|
|
172
349
|
</div>
|
|
173
|
-
</
|
|
350
|
+
</LucideProvider>
|
|
174
351
|
)
|
|
175
352
|
}
|
|
176
353
|
|
|
177
354
|
// -------------------------------------------------------------------------- //
|
|
178
|
-
//
|
|
355
|
+
// Failed data steps
|
|
179
356
|
// -------------------------------------------------------------------------- //
|
|
180
357
|
|
|
358
|
+
/** Resolves a human title for a pipeline step (`{ id, step }` from the view's steps). */
|
|
359
|
+
export type DescribeStep = (step: { id: string; step?: string }) => string | undefined
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* The failed data steps as ONE inline alert: what happened (the title), which
|
|
363
|
+
* data is affected (each step by its human title, else its step id), what you
|
|
364
|
+
* can do (retry, or ask in the chat when the view cannot refresh). The raw
|
|
365
|
+
* step reasons stay under "Details", out of the user copy.
|
|
366
|
+
*/
|
|
181
367
|
export function StepErrors({
|
|
182
368
|
hidden,
|
|
183
369
|
errors,
|
|
370
|
+
steps,
|
|
371
|
+
labels,
|
|
372
|
+
describeStep,
|
|
373
|
+
onRetry,
|
|
184
374
|
}: {
|
|
185
|
-
/** Build mode surfaces its own diagnostics; the shell
|
|
375
|
+
/** Build mode surfaces its own diagnostics; the shell alert hides. */
|
|
186
376
|
hidden: boolean
|
|
187
377
|
errors: ViewData["context"]["errors"]
|
|
378
|
+
/** The view's step refs (`_refreshParams.steps`), to name a failed step by its definition. */
|
|
379
|
+
steps?: PipelineStepRef[]
|
|
380
|
+
labels: Required<McpAppViewLabels>
|
|
381
|
+
describeStep?: DescribeStep
|
|
382
|
+
/** Re-runs the view (a refresh); omitted when the view cannot be refreshed. */
|
|
383
|
+
onRetry?: () => void
|
|
188
384
|
}) {
|
|
189
385
|
if (hidden || errors.length === 0) return null
|
|
386
|
+
const failed = errors.map((err) => {
|
|
387
|
+
const ref = { id: err.stepId, step: steps?.find((s) => s.id === err.stepId)?.step }
|
|
388
|
+
return { ref, human: describeStep?.(ref), reason: err.reason }
|
|
389
|
+
})
|
|
190
390
|
return (
|
|
191
|
-
<div className="
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
391
|
+
<div className="px-4 pb-4">
|
|
392
|
+
<ErrorState
|
|
393
|
+
variant="inline"
|
|
394
|
+
title={labels.stepErrorsTitle}
|
|
395
|
+
retryLabel={labels.retry}
|
|
396
|
+
onRetry={onRetry}
|
|
397
|
+
detailsLabel={labels.errorDetails}
|
|
398
|
+
details={failed.map(({ ref, reason }) => `${ref.step ?? ref.id}: ${reason}`).join("\n")}
|
|
399
|
+
description={
|
|
400
|
+
<>
|
|
401
|
+
<ul className="flex flex-col gap-1">
|
|
402
|
+
{failed.map(({ ref, human }) => (
|
|
403
|
+
<li key={ref.id} className="break-words">
|
|
404
|
+
{human ? (
|
|
405
|
+
<span className="font-medium">{human}</span>
|
|
406
|
+
) : (
|
|
407
|
+
<span className="text-small font-mono">{ref.step ?? ref.id}</span>
|
|
408
|
+
)}
|
|
409
|
+
</li>
|
|
410
|
+
))}
|
|
411
|
+
</ul>
|
|
412
|
+
<p className="mt-1">{onRetry ? labels.stepErrorsHint : labels.errorHintNoRetry}</p>
|
|
413
|
+
</>
|
|
414
|
+
}
|
|
415
|
+
/>
|
|
197
416
|
</div>
|
|
198
417
|
)
|
|
199
418
|
}
|
|
@@ -208,9 +427,17 @@ export interface ViewBodyProps {
|
|
|
208
427
|
widgets: Record<string, WidgetComponent>
|
|
209
428
|
callTool: (name: string, args: object) => Promise<unknown>
|
|
210
429
|
onExit: LayoutBuilderProps["onExit"]
|
|
430
|
+
builderLabels?: LayoutBuilderLabels
|
|
211
431
|
}
|
|
212
432
|
|
|
213
|
-
export function ViewBody({
|
|
433
|
+
export function ViewBody({
|
|
434
|
+
buildMode,
|
|
435
|
+
viewData,
|
|
436
|
+
widgets,
|
|
437
|
+
callTool,
|
|
438
|
+
onExit,
|
|
439
|
+
builderLabels,
|
|
440
|
+
}: ViewBodyProps) {
|
|
214
441
|
if (buildMode) {
|
|
215
442
|
return (
|
|
216
443
|
<LayoutBuilder
|
|
@@ -220,6 +447,7 @@ export function ViewBody({ buildMode, viewData, widgets, callTool, onExit }: Vie
|
|
|
220
447
|
initialSteps={viewData._refreshParams?.steps}
|
|
221
448
|
widgets={widgets}
|
|
222
449
|
callTool={callTool}
|
|
450
|
+
labels={builderLabels}
|
|
223
451
|
onExit={onExit}
|
|
224
452
|
/>
|
|
225
453
|
)
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pre-payload states of `McpAppView`, one per lifecycle phase
|
|
3
|
+
* (`view-lifecycle.ts`): waiting (skeleton + status line + slow hint),
|
|
4
|
+
* cancelled, and error (icon, title, what to do, raw reason under "Details",
|
|
5
|
+
* retry when the originating tool is known). A `blocked` error is a notice in
|
|
6
|
+
* the info tone, not a failure: the tool ran, but the chat did not pass its
|
|
7
|
+
* result to the view. Hook-free and SSR-renderable, so each phase is pinned
|
|
8
|
+
* by a test.
|
|
9
|
+
*/
|
|
10
|
+
import { ErrorState, type ErrorStateTone } from "../components/ErrorState.js"
|
|
11
|
+
import { Skeleton } from "../primitives/skeleton.js"
|
|
12
|
+
import type { McpAppViewLabels } from "./mcp-app-view-chrome.js"
|
|
13
|
+
import type { ViewErrorKind, ViewLifecycle } from "./view-lifecycle.js"
|
|
14
|
+
|
|
15
|
+
export type { ViewErrorKind } from "./view-lifecycle.js"
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Human text for a raw error reason (e.g. map "503" to "the engine is down").
|
|
19
|
+
* `info.kind` tells a failure (`"failed"`) from a result the chat did not pass
|
|
20
|
+
* to the view (`"blocked"`, no reason); return `undefined` to keep the
|
|
21
|
+
* toolkit's words for that state.
|
|
22
|
+
*/
|
|
23
|
+
export type DescribeViewError = (
|
|
24
|
+
reason: string | undefined,
|
|
25
|
+
info?: { kind: ViewErrorKind },
|
|
26
|
+
) => { title?: string; description?: string } | undefined
|
|
27
|
+
|
|
28
|
+
export function ViewPlaceholder({
|
|
29
|
+
lifecycle,
|
|
30
|
+
labels,
|
|
31
|
+
onRetry,
|
|
32
|
+
describeError,
|
|
33
|
+
}: {
|
|
34
|
+
/** The current phase; `result` renders nothing (the view takes over). */
|
|
35
|
+
lifecycle: ViewLifecycle
|
|
36
|
+
labels: Required<McpAppViewLabels>
|
|
37
|
+
onRetry: () => void
|
|
38
|
+
describeError?: DescribeViewError
|
|
39
|
+
}) {
|
|
40
|
+
switch (lifecycle.phase) {
|
|
41
|
+
case "result":
|
|
42
|
+
return null
|
|
43
|
+
case "cancelled":
|
|
44
|
+
return (
|
|
45
|
+
<div className="px-4 py-4">
|
|
46
|
+
<p role="status" className="text-muted-foreground text-sm">
|
|
47
|
+
{labels.cancelled}
|
|
48
|
+
</p>
|
|
49
|
+
</div>
|
|
50
|
+
)
|
|
51
|
+
case "error":
|
|
52
|
+
return (
|
|
53
|
+
<ViewErrorState
|
|
54
|
+
kind={lifecycle.kind}
|
|
55
|
+
reason={lifecycle.reason}
|
|
56
|
+
canRetry={lifecycle.canRetry}
|
|
57
|
+
labels={labels}
|
|
58
|
+
onRetry={onRetry}
|
|
59
|
+
describeError={describeError}
|
|
60
|
+
/>
|
|
61
|
+
)
|
|
62
|
+
case "waiting":
|
|
63
|
+
return <ViewWaiting slow={lifecycle.slow} labels={labels} />
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function ViewWaiting({ slow, labels }: { slow: boolean; labels: Required<McpAppViewLabels> }) {
|
|
68
|
+
// No aria-busy on an ancestor of the live region: assistive technology may
|
|
69
|
+
// hold back changes inside a busy subtree, and the slow hint is one.
|
|
70
|
+
return (
|
|
71
|
+
<div className="flex flex-col gap-4 px-4 py-4">
|
|
72
|
+
<Skeleton aria-hidden="true" className="h-8 w-48" />
|
|
73
|
+
<Skeleton aria-hidden="true" className="h-32 w-full" />
|
|
74
|
+
{/* One live region: the status line, then the slow hint when it appears. */}
|
|
75
|
+
<div role="status" className="text-muted-foreground flex flex-col gap-1 text-sm">
|
|
76
|
+
<p>{labels.loading}</p>
|
|
77
|
+
{slow && <p data-slot="slow-hint">{labels.slowHint}</p>}
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** The words and tone of an error phase; the hint never promises a retry the state does not offer. */
|
|
84
|
+
function errorStateCopy(
|
|
85
|
+
kind: ViewErrorKind,
|
|
86
|
+
canRetry: boolean,
|
|
87
|
+
labels: Required<McpAppViewLabels>,
|
|
88
|
+
): { tone: ErrorStateTone; role: "alert" | "status"; title: string; hint: string; retry: string } {
|
|
89
|
+
if (kind === "blocked") {
|
|
90
|
+
// Nothing failed: a quiet notice that says what happened and what to do.
|
|
91
|
+
return {
|
|
92
|
+
tone: "info",
|
|
93
|
+
role: "status",
|
|
94
|
+
title: labels.blockedTitle,
|
|
95
|
+
hint: canRetry ? labels.blockedHint : labels.blockedHintNoRetry,
|
|
96
|
+
retry: labels.blockedRetry,
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
tone: "danger",
|
|
101
|
+
role: "alert",
|
|
102
|
+
title: labels.errorTitle,
|
|
103
|
+
hint: canRetry ? labels.errorHint : labels.errorHintNoRetry,
|
|
104
|
+
retry: labels.retry,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function ViewErrorState({
|
|
109
|
+
kind = "failed",
|
|
110
|
+
reason,
|
|
111
|
+
canRetry,
|
|
112
|
+
labels,
|
|
113
|
+
onRetry,
|
|
114
|
+
describeError,
|
|
115
|
+
}: {
|
|
116
|
+
/** Absent for a failure (see `ViewLifecycle`). */
|
|
117
|
+
kind: ViewErrorKind | undefined
|
|
118
|
+
reason: string | undefined
|
|
119
|
+
canRetry: boolean
|
|
120
|
+
labels: Required<McpAppViewLabels>
|
|
121
|
+
onRetry: () => void
|
|
122
|
+
describeError?: DescribeViewError
|
|
123
|
+
}) {
|
|
124
|
+
const human = describeError?.(reason, { kind })
|
|
125
|
+
const copy = errorStateCopy(kind, canRetry, labels)
|
|
126
|
+
return (
|
|
127
|
+
<div className="px-4 py-4">
|
|
128
|
+
<ErrorState
|
|
129
|
+
tone={copy.tone}
|
|
130
|
+
role={copy.role}
|
|
131
|
+
title={human?.title ?? copy.title}
|
|
132
|
+
description={human?.description ?? copy.hint}
|
|
133
|
+
details={reason}
|
|
134
|
+
detailsLabel={labels.errorDetails}
|
|
135
|
+
retryLabel={copy.retry}
|
|
136
|
+
onRetry={canRetry ? onRetry : undefined}
|
|
137
|
+
/>
|
|
138
|
+
</div>
|
|
139
|
+
)
|
|
140
|
+
}
|