@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
package/src/app/mcp-app-view.tsx
CHANGED
|
@@ -1,23 +1,56 @@
|
|
|
1
|
-
import { useState, useCallback } from "react"
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
1
|
+
import { useState, useCallback, useEffect, useMemo, type ReactNode } from "react"
|
|
2
|
+
import { LucideProvider } from "lucide-react"
|
|
3
|
+
import { ToolCancelledError, useHostContext, useToolContext } from "mcp-use/react"
|
|
4
|
+
import { ToastProvider } from "../components/Toast.js"
|
|
5
|
+
import {
|
|
6
|
+
ToolkitLocaleFallback,
|
|
7
|
+
useToolkitLocale,
|
|
8
|
+
useToolkitMessages,
|
|
9
|
+
} from "../locale/locale-provider.js"
|
|
10
|
+
import { formatClockTime, resolveFormatLocale } from "../locale/toolkit-messages.js"
|
|
11
|
+
import { AppQueryProvider, useAppQueryClient } from "../providers/query-provider.js"
|
|
12
|
+
import { resolveToolSafety } from "../hooks/tool-result-recovery-model.js"
|
|
13
|
+
import {
|
|
14
|
+
DEFAULT_ASSUME_STRIPPED_AFTER_MS,
|
|
15
|
+
resolveRecoveryToolName,
|
|
16
|
+
useToolResultRecovery,
|
|
17
|
+
type RecoveryPolicy,
|
|
18
|
+
} from "../hooks/use-tool-result-recovery.js"
|
|
19
|
+
import { ICON_STROKE } from "../lib/icon-stroke.js"
|
|
7
20
|
import { useHostBridge } from "./host-bridge.js"
|
|
21
|
+
import { useViewResultSink } from "./mcp-use-host-bridge.js"
|
|
22
|
+
import { HostModelContext } from "./model-context.js"
|
|
8
23
|
import {
|
|
9
|
-
|
|
24
|
+
applyBuilderCommit,
|
|
10
25
|
isCompleteViewData,
|
|
11
26
|
StepErrors,
|
|
12
27
|
ViewBody,
|
|
13
|
-
ViewPlaceholder,
|
|
14
28
|
ViewToolbar,
|
|
29
|
+
type BuilderCommit,
|
|
30
|
+
type DescribeStep,
|
|
15
31
|
type McpAppViewLabels,
|
|
16
32
|
type ViewData,
|
|
33
|
+
type ViewTitleLevel,
|
|
34
|
+
type ViewTitleMode,
|
|
17
35
|
} from "./mcp-app-view-chrome.js"
|
|
36
|
+
import { ViewPlaceholder, type DescribeViewError } from "./mcp-app-view-states.js"
|
|
37
|
+
import type { LayoutBuilderLabels } from "./layout-builder.js"
|
|
38
|
+
import { useBuildModeFocus } from "./use-build-mode-focus.js"
|
|
39
|
+
import { useFullscreenToggle, useViewRefresh } from "./use-view-actions.js"
|
|
40
|
+
import { useRetryFocus, useViewLifecycle } from "./use-view-lifecycle.js"
|
|
41
|
+
import {
|
|
42
|
+
DEFAULT_SLOW_HINT_MS,
|
|
43
|
+
describeViewForModel,
|
|
44
|
+
reloadedAtOf,
|
|
45
|
+
type ViewLifecycle,
|
|
46
|
+
type ViewSource,
|
|
47
|
+
} from "./view-lifecycle.js"
|
|
18
48
|
import type { WidgetComponent } from "./widget-renderer.js"
|
|
19
49
|
|
|
20
|
-
export type { McpAppViewLabels } from "./mcp-app-view-chrome.js"
|
|
50
|
+
export type { McpAppViewLabels, ViewTitleLevel, ViewTitleMode } from "./mcp-app-view-chrome.js"
|
|
51
|
+
export type { DescribeStep } from "./mcp-app-view-chrome.js"
|
|
52
|
+
export type { DescribeViewError, ViewErrorKind } from "./mcp-app-view-states.js"
|
|
53
|
+
export type { RecoveryPolicy } from "../hooks/use-tool-result-recovery.js"
|
|
21
54
|
|
|
22
55
|
export interface McpAppViewProps {
|
|
23
56
|
/**
|
|
@@ -46,222 +79,446 @@ export interface McpAppViewProps {
|
|
|
46
79
|
*/
|
|
47
80
|
builderEnabled?: boolean
|
|
48
81
|
/**
|
|
49
|
-
* Override
|
|
50
|
-
* Defaults to
|
|
82
|
+
* Override chrome strings (loading, error, refresh, fullscreen, edit, …).
|
|
83
|
+
* Defaults to the active locale's toolkit catalog: the nearest
|
|
84
|
+
* `LocaleProvider`, else the host's locale (`en`/`de`, English otherwise).
|
|
51
85
|
*/
|
|
52
86
|
labels?: McpAppViewLabels
|
|
87
|
+
/** Override strings of the embedded view builder (defaults: the locale's catalog). */
|
|
88
|
+
builderLabels?: LayoutBuilderLabels
|
|
89
|
+
/**
|
|
90
|
+
* How the toolbar shows the view title, so a view carries ONE title:
|
|
91
|
+
* `"show"` (default) renders it as a heading, `"hide"` leaves the title to
|
|
92
|
+
* the widget's own header, `"slot"` renders {@link McpAppViewProps.renderTitle}.
|
|
93
|
+
*/
|
|
94
|
+
titleMode?: ViewTitleMode
|
|
95
|
+
/** Heading level of the toolbar title in `"show"` mode. Default `2`. */
|
|
96
|
+
titleLevel?: ViewTitleLevel
|
|
97
|
+
/** Renders the toolbar title in `"slot"` mode; receives the view's title. */
|
|
98
|
+
renderTitle?: (title: string | undefined) => ReactNode
|
|
99
|
+
/** Delay before the loading placeholder adds its "taking longer" hint. Default 8000 ms. */
|
|
100
|
+
slowHintAfterMs?: number
|
|
101
|
+
/**
|
|
102
|
+
* Map a raw rendering error (the tool's `isError` text) onto human text.
|
|
103
|
+
* The raw reason always stays available under "Details".
|
|
104
|
+
*/
|
|
105
|
+
describeError?: DescribeViewError
|
|
106
|
+
/** Human title of a pipeline step in the failed-steps alert (default: the step id). */
|
|
107
|
+
describeStep?: DescribeStep
|
|
108
|
+
/**
|
|
109
|
+
* Which originating tools the view may re-execute on its own when the host
|
|
110
|
+
* strips the result's `structuredContent` (claude.ai, Claude Desktop).
|
|
111
|
+
* `"auto"` (default): any tool the host does not report as writing
|
|
112
|
+
* (`readOnlyHint: false` or `destructiveHint: true`); `"read-only"`: only
|
|
113
|
+
* tools reported with `readOnlyHint: true`; `"never"`: none. A recovery
|
|
114
|
+
* the policy forbids shows a note that the chat did not pass the result to
|
|
115
|
+
* the view. It offers to load the view only for a tool the host does not
|
|
116
|
+
* report as writing; for a writing tool it asks for the current state in
|
|
117
|
+
* the chat, so one click never runs the write a second time.
|
|
118
|
+
*/
|
|
119
|
+
recoverStrippedResult?: RecoveryPolicy
|
|
120
|
+
/**
|
|
121
|
+
* Grace period (ms) after which a silent call counts as a stripped result.
|
|
122
|
+
* Only used where the view could not watch the host's notifications from
|
|
123
|
+
* the start (e.g. a custom shell mounted under its own `bootstrapView`
|
|
124
|
+
* without `installToolResultObserver`); a view mounted by
|
|
125
|
+
* `mountMcpToolkitApp` sees the stripped result itself and never guesses,
|
|
126
|
+
* so a slow tool is never re-run. Default 2500 ms.
|
|
127
|
+
*/
|
|
128
|
+
strippedResultGraceMs?: number
|
|
129
|
+
/**
|
|
130
|
+
* Put the tool name into the cache keys of the data hooks inside the view
|
|
131
|
+
* (`[...queryKey, toolName, args]`, see `toolQueryKey`), so two tools never
|
|
132
|
+
* share an entry. Omitted: an enclosing `AppQueryProvider`'s setting, else
|
|
133
|
+
* the 2.x key `[...queryKey, args]`. The next major makes it the default.
|
|
134
|
+
*/
|
|
135
|
+
toolNameInQueryKey?: boolean
|
|
53
136
|
}
|
|
54
137
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
138
|
+
/**
|
|
139
|
+
* The toolkit's MCP App view: lifecycle placeholder (waiting / error /
|
|
140
|
+
* cancelled), toolbar, failed-steps alert and the rendered layout (or the
|
|
141
|
+
* builder). Mounts a `ToastProvider` and binds the toolkit's own strings to
|
|
142
|
+
* the host's locale unless a `LocaleProvider` sets one, so the chrome follows
|
|
143
|
+
* the host language; `useLocale()` in consumer widgets is unaffected. Lucide
|
|
144
|
+
* icons draw at the CI stroke (2.5) throughout, the toast stack included.
|
|
145
|
+
* The widgets' data hooks fetch through an enclosing `AppQueryProvider`'s
|
|
146
|
+
* client, else the toolkit's shared `queryClient`.
|
|
147
|
+
*/
|
|
148
|
+
export function McpAppView(props: McpAppViewProps) {
|
|
149
|
+
const { locale } = useHostContext()
|
|
150
|
+
return (
|
|
151
|
+
<ToolkitLocaleFallback locale={locale}>
|
|
152
|
+
{/* Wraps the ToastProvider, whose toast stack renders beside the shell. */}
|
|
153
|
+
<LucideProvider strokeWidth={ICON_STROKE}>
|
|
154
|
+
<ToastProvider>
|
|
155
|
+
<McpAppViewShell {...props} />
|
|
156
|
+
</ToastProvider>
|
|
157
|
+
</LucideProvider>
|
|
158
|
+
</ToolkitLocaleFallback>
|
|
73
159
|
)
|
|
160
|
+
}
|
|
74
161
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
162
|
+
/** The payload the view shows, where it came from, and when the view loaded it itself. */
|
|
163
|
+
interface ShownView {
|
|
164
|
+
data: ViewData | null
|
|
165
|
+
source: ViewSource | null
|
|
166
|
+
/**
|
|
167
|
+
* When the view re-loaded the payload itself (epoch ms), so its figures can
|
|
168
|
+
* differ from the result the chat answered from (`reloadedAtOf`); `null`
|
|
169
|
+
* otherwise.
|
|
170
|
+
*/
|
|
171
|
+
reloadedAt: number | null
|
|
172
|
+
}
|
|
85
173
|
|
|
86
|
-
|
|
87
|
-
// catalogue, the user toggles into build by clicking the toolbar button.
|
|
88
|
-
const [buildMode, setBuildMode] = useState(false)
|
|
174
|
+
const NO_VIEW: ShownView = { data: null, source: null, reloadedAt: null }
|
|
89
175
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
176
|
+
/**
|
|
177
|
+
* Host-delivered payload → the shown view, recovered payloads included, each
|
|
178
|
+
* tagged with its source. Render-phase setState (not an effect) so the React
|
|
179
|
+
* Compiler doesn't flag a cascading render.
|
|
180
|
+
*/
|
|
181
|
+
function useHostViewData(
|
|
182
|
+
initialViewData: ViewData | undefined,
|
|
183
|
+
isPending: boolean,
|
|
184
|
+
recovered: ViewData | null,
|
|
185
|
+
recoveredAt: number | null,
|
|
186
|
+
) {
|
|
187
|
+
const [view, setView] = useState<ShownView>(NO_VIEW)
|
|
96
188
|
// `prev` MUST start as `null`, not `initialViewData`: hosts that expose the
|
|
97
189
|
// complete tool output before the app's first render (e.g. window.openai
|
|
98
190
|
// globals injected ahead of script execution) would otherwise never trip the
|
|
99
|
-
// identity check —
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
setPrevInitialViewData(initialViewData)
|
|
191
|
+
// identity check — the sync never runs and the app idles on the skeleton.
|
|
192
|
+
// The completeness guard stays: widgetProps may briefly drop
|
|
193
|
+
// `context`/`layout` when displayMode toggles.
|
|
194
|
+
const [prevInitial, setPrevInitial] = useState<ViewData | undefined | null>(null)
|
|
195
|
+
if (initialViewData !== prevInitial) {
|
|
196
|
+
setPrevInitial(initialViewData)
|
|
106
197
|
if (!isPending && isCompleteViewData(initialViewData)) {
|
|
107
|
-
|
|
198
|
+
setView({ data: initialViewData, source: "host", reloadedAt: null })
|
|
108
199
|
}
|
|
109
200
|
}
|
|
201
|
+
const [prevRecovered, setPrevRecovered] = useState<ViewData | null>(null)
|
|
202
|
+
if (recovered !== prevRecovered) {
|
|
203
|
+
setPrevRecovered(recovered)
|
|
204
|
+
// The host-delivered payload always wins; a recovery fills the gap, and a
|
|
205
|
+
// recovery for newer arguments replaces an older recovered payload (N21).
|
|
206
|
+
if (recovered) {
|
|
207
|
+
setView((prev) =>
|
|
208
|
+
prev.data === null || prev.source === "recovered"
|
|
209
|
+
? { data: recovered, source: "recovered", reloadedAt: recoveredAt }
|
|
210
|
+
: prev,
|
|
211
|
+
)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return [view, setView] as const
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Hands the payload the view shows (the host's, its own recovery's, the
|
|
219
|
+
* user's retry or refresh) to the host bridge, so `HostBridge.getWidgetData()`
|
|
220
|
+
* returns what the view shows (toolkit#176 K15), also after a latch the view
|
|
221
|
+
* could not render.
|
|
222
|
+
*/
|
|
223
|
+
function useReportShownPayload(view: ShownView) {
|
|
224
|
+
const report = useViewResultSink()
|
|
225
|
+
const payload = view.data
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
if (payload) report?.(payload)
|
|
228
|
+
}, [payload, report])
|
|
229
|
+
}
|
|
110
230
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
//
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
231
|
+
/** The rendering call as mcp-use 2.x latches it, plus the tool the host names. */
|
|
232
|
+
function useRenderCall() {
|
|
233
|
+
const tool = useToolContext()
|
|
234
|
+
const { hostContext } = useHostContext()
|
|
235
|
+
// Since mcp-use 2.7.1 a host cancellation latches as `status: "error"`.
|
|
236
|
+
const isCancelled = tool.status === "error" && tool.error instanceof ToolCancelledError
|
|
237
|
+
const isCallError = tool.status === "error" && !isCancelled
|
|
238
|
+
return {
|
|
239
|
+
tool,
|
|
240
|
+
hostContext,
|
|
241
|
+
isPending: tool.status === "pending",
|
|
242
|
+
isCancelled,
|
|
243
|
+
isCallError,
|
|
244
|
+
callError: isCallError ? tool.error : undefined,
|
|
245
|
+
initialViewData: tool.status === "ready" ? (tool.toolOutput as ViewData) : undefined,
|
|
246
|
+
toolName: resolveRecoveryToolName(hostContext),
|
|
247
|
+
/** The host reports the tool as writing: the view never offers to re-run it after a block. */
|
|
248
|
+
toolWrites: resolveToolSafety(hostContext) === "writes",
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* The payload the view shows: the host's, else the stripped-result recovery's.
|
|
254
|
+
* Hosts that strip `structuredContent` (claude.ai) never latch a result under
|
|
255
|
+
* mcp-use 2.x; the recovery re-executes the call once when the stripped
|
|
256
|
+
* result arrives. It never fires on a cancelled or failed call, nor while a
|
|
257
|
+
* slow tool is still running (#176): those render their state.
|
|
258
|
+
*/
|
|
259
|
+
function useShownView(
|
|
260
|
+
call: ReturnType<typeof useRenderCall>,
|
|
261
|
+
callTool: (name: string, args: Record<string, unknown>) => Promise<unknown>,
|
|
262
|
+
policy: RecoveryPolicy = "auto",
|
|
263
|
+
graceMs: number = DEFAULT_ASSUME_STRIPPED_AFTER_MS,
|
|
264
|
+
) {
|
|
119
265
|
const recovery = useToolResultRecovery<ViewData>({
|
|
120
|
-
resultReady: !isPending,
|
|
121
|
-
cancelled: isCancelled,
|
|
122
|
-
|
|
266
|
+
resultReady: !call.isPending,
|
|
267
|
+
cancelled: call.isCancelled,
|
|
268
|
+
errored: call.isCallError,
|
|
269
|
+
props: call.initialViewData,
|
|
123
270
|
isValid: isCompleteViewData,
|
|
124
|
-
toolInput,
|
|
125
|
-
hostContext,
|
|
271
|
+
toolInput: call.tool.toolInput,
|
|
272
|
+
hostContext: call.hostContext,
|
|
126
273
|
callTool,
|
|
274
|
+
policy,
|
|
275
|
+
assumeStrippedAfterMs: graceMs,
|
|
127
276
|
})
|
|
128
|
-
const [
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
277
|
+
const [view, setView] = useHostViewData(
|
|
278
|
+
call.initialViewData,
|
|
279
|
+
call.isPending,
|
|
280
|
+
recovery.data,
|
|
281
|
+
recovery.recoveredAt,
|
|
282
|
+
)
|
|
283
|
+
useReportShownPayload(view)
|
|
284
|
+
// A re-run's figures can differ from the answer in the chat (N23): stamp
|
|
285
|
+
// it, unless the original call failed and the chat never had figures.
|
|
286
|
+
const callFailed = call.isCallError || call.isCancelled
|
|
287
|
+
const showRetried = useCallback(
|
|
288
|
+
(data: ViewData) =>
|
|
289
|
+
setView({ data, source: "retry", reloadedAt: reloadedAtOf("retry", Date.now(), callFailed) }),
|
|
290
|
+
[setView, callFailed],
|
|
291
|
+
)
|
|
292
|
+
const showRefreshed = useCallback(
|
|
293
|
+
(data: ViewData) =>
|
|
294
|
+
setView({
|
|
295
|
+
data,
|
|
296
|
+
source: "refresh",
|
|
297
|
+
reloadedAt: reloadedAtOf("refresh", Date.now(), callFailed),
|
|
298
|
+
}),
|
|
299
|
+
[setView, callFailed],
|
|
300
|
+
)
|
|
301
|
+
return {
|
|
302
|
+
view,
|
|
303
|
+
setView,
|
|
304
|
+
showRetried,
|
|
305
|
+
showRefreshed,
|
|
306
|
+
// Without a named tool nothing can re-run it: a plain failure. A policy
|
|
307
|
+
// block is its own state: the tool ran, and the view must not repeat it.
|
|
308
|
+
recoveryFailed: recovery.failed || recovery.blocked === "no-tool",
|
|
309
|
+
recoveryBlocked: recovery.blocked === "policy",
|
|
133
310
|
}
|
|
311
|
+
}
|
|
134
312
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
313
|
+
/**
|
|
314
|
+
* The view's own line of model context (toolkit#176 K20, N23): an error the
|
|
315
|
+
* user sees instead of the view, failed data steps, or data the view
|
|
316
|
+
* re-loaded itself (a recovery, a retry, a refresh). Renders nothing while
|
|
317
|
+
* there is nothing to report.
|
|
318
|
+
*/
|
|
319
|
+
function ViewModelContext({
|
|
320
|
+
lifecycle,
|
|
321
|
+
toolName,
|
|
322
|
+
view,
|
|
323
|
+
}: {
|
|
324
|
+
lifecycle: ViewLifecycle
|
|
325
|
+
toolName: string | undefined
|
|
326
|
+
view: ShownView
|
|
327
|
+
}) {
|
|
328
|
+
const content = describeViewForModel({
|
|
329
|
+
lifecycle,
|
|
330
|
+
toolName,
|
|
331
|
+
stepErrors: view.data?.context.errors,
|
|
332
|
+
stepsRetryable: Boolean(view.data?._refreshParams),
|
|
333
|
+
reloadedAt: view.reloadedAt,
|
|
334
|
+
reloadedBy: reloadedByOf(view.source),
|
|
335
|
+
})
|
|
336
|
+
return content ? <HostModelContext content={content} /> : null
|
|
337
|
+
}
|
|
146
338
|
|
|
147
|
-
|
|
339
|
+
function McpAppViewShell({
|
|
340
|
+
widgets,
|
|
341
|
+
refreshToolName = "refresh-view",
|
|
342
|
+
builderEnabled,
|
|
343
|
+
labels,
|
|
344
|
+
builderLabels,
|
|
345
|
+
titleMode = "show",
|
|
346
|
+
titleLevel = 2,
|
|
347
|
+
renderTitle,
|
|
348
|
+
slowHintAfterMs = DEFAULT_SLOW_HINT_MS,
|
|
349
|
+
describeError,
|
|
350
|
+
describeStep,
|
|
351
|
+
recoverStrippedResult,
|
|
352
|
+
strippedResultGraceMs,
|
|
353
|
+
toolNameInQueryKey,
|
|
354
|
+
}: McpAppViewProps) {
|
|
355
|
+
const messages = useToolkitMessages()
|
|
356
|
+
const L = useMemo(() => ({ ...messages.view, ...labels }), [messages.view, labels])
|
|
357
|
+
// The mcp-use 2.x view channels (all need the `bootstrapView` mount
|
|
358
|
+
// `mountMcpToolkitApp` provides); tools go through the HostBridge.
|
|
359
|
+
const call = useRenderCall()
|
|
360
|
+
const { safeArea, locale, timeZone } = useHostContext()
|
|
361
|
+
// A time in the language of the sentence around it, in the host's zone.
|
|
362
|
+
const formatLocale = resolveFormatLocale(useToolkitLocale(), locale)
|
|
363
|
+
// The client the view's widgets fetch through (an enclosing
|
|
364
|
+
// AppQueryProvider's, else the shared one): a refresh invalidates it.
|
|
365
|
+
const viewClient = useAppQueryClient()
|
|
366
|
+
const bridge = useHostBridge()
|
|
367
|
+
const callTool = useCallback(
|
|
368
|
+
(name: string, args: Record<string, unknown>) => bridge.callTool(name, args),
|
|
369
|
+
[bridge],
|
|
370
|
+
)
|
|
371
|
+
// The widget-facing shape (`args: object`, so generated input interfaces
|
|
372
|
+
// without an index signature pass straight through).
|
|
148
373
|
const callToolFn = useCallback(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
},
|
|
152
|
-
[callTool],
|
|
374
|
+
(name: string, args: object) => bridge.callTool(name, args as Record<string, unknown>),
|
|
375
|
+
[bridge],
|
|
153
376
|
)
|
|
154
|
-
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
377
|
+
const shown = useShownView(call, callTool, recoverStrippedResult, strippedResultGraceMs)
|
|
378
|
+
const { view, setView } = shown
|
|
379
|
+
const viewData = view.data
|
|
380
|
+
const { lifecycle, retry: retryCall } = useViewLifecycle({
|
|
381
|
+
hasViewData: viewData !== null,
|
|
382
|
+
callStatus: call.tool.status,
|
|
383
|
+
cancelled: call.isCancelled,
|
|
384
|
+
callError: call.callError,
|
|
385
|
+
recoveryFailed: shown.recoveryFailed,
|
|
386
|
+
recoveryBlocked: shown.recoveryBlocked,
|
|
387
|
+
toolWrites: call.toolWrites,
|
|
388
|
+
toolName: call.toolName,
|
|
389
|
+
toolInput: call.tool.toolInput,
|
|
390
|
+
callTool,
|
|
391
|
+
isValid: isCompleteViewData,
|
|
392
|
+
onResult: shown.showRetried,
|
|
393
|
+
slowHintAfterMs,
|
|
394
|
+
})
|
|
395
|
+
const { frameRef, retry } = useRetryFocus(lifecycle.phase, retryCall)
|
|
396
|
+
const { isRefreshing, refreshView } = useViewRefresh({
|
|
397
|
+
viewData,
|
|
398
|
+
setViewData: shown.showRefreshed,
|
|
399
|
+
callTool,
|
|
400
|
+
refreshToolName,
|
|
401
|
+
labels: L,
|
|
402
|
+
client: viewClient,
|
|
403
|
+
})
|
|
404
|
+
const fullscreen = useFullscreenToggle(L)
|
|
405
|
+
// In-iframe build mode is purely a UI state — the LLM never sees the catalogue.
|
|
406
|
+
const [buildMode, setBuildMode] = useState(false)
|
|
407
|
+
useBuildModeFocus(buildMode, frameRef)
|
|
180
408
|
const exitBuildMode = useCallback(
|
|
181
|
-
(commit?: {
|
|
182
|
-
|
|
183
|
-
keys?: Record<string, unknown>
|
|
184
|
-
steps?: PipelineStepRef[]
|
|
185
|
-
title?: string
|
|
186
|
-
context?: ViewData["context"]
|
|
187
|
-
}) => {
|
|
188
|
-
if (commit) {
|
|
189
|
-
setViewData((prev) =>
|
|
190
|
-
prev
|
|
191
|
-
? {
|
|
192
|
-
...prev,
|
|
193
|
-
layout: commit.layout,
|
|
194
|
-
title: commit.title ?? prev.title,
|
|
195
|
-
context: commit.context ?? prev.context,
|
|
196
|
-
_refreshParams: {
|
|
197
|
-
keys: commit.keys,
|
|
198
|
-
steps: commit.steps,
|
|
199
|
-
layout: commit.layout,
|
|
200
|
-
title: commit.title ?? prev.title,
|
|
201
|
-
},
|
|
202
|
-
}
|
|
203
|
-
: prev,
|
|
204
|
-
)
|
|
205
|
-
}
|
|
409
|
+
(commit?: BuilderCommit) => {
|
|
410
|
+
if (commit) setView((prev) => withBuilderCommit(prev, commit))
|
|
206
411
|
setBuildMode(false)
|
|
207
412
|
},
|
|
208
|
-
[],
|
|
413
|
+
[setView],
|
|
414
|
+
)
|
|
415
|
+
const viewContext = (
|
|
416
|
+
<ViewModelContext lifecycle={lifecycle} toolName={call.toolName} view={view} />
|
|
209
417
|
)
|
|
210
418
|
|
|
211
|
-
// `isPending` must not gate the render: on hosts
|
|
212
|
-
//
|
|
213
|
-
//
|
|
419
|
+
// `isPending` must not gate the render: on stripping hosts the latch stays
|
|
420
|
+
// "pending" forever, and recovered viewData still has to replace it. The
|
|
421
|
+
// frame is the stable focus target of a retry (`useRetryFocus`).
|
|
214
422
|
if (!viewData) {
|
|
215
|
-
return
|
|
423
|
+
return (
|
|
424
|
+
<div ref={frameRef} tabIndex={-1} data-slot="mcp-app-view" className="outline-hidden">
|
|
425
|
+
{viewContext}
|
|
426
|
+
<ViewPlaceholder
|
|
427
|
+
lifecycle={lifecycle}
|
|
428
|
+
labels={L}
|
|
429
|
+
onRetry={retry}
|
|
430
|
+
describeError={describeError}
|
|
431
|
+
/>
|
|
432
|
+
</div>
|
|
433
|
+
)
|
|
216
434
|
}
|
|
217
435
|
|
|
218
|
-
const isFullscreen = displayMode === "fullscreen"
|
|
219
|
-
|
|
220
|
-
// Follow the server's own signal by default: render-view reports
|
|
221
|
-
// `builderAvailable` (derived from `app.builder`), so the Build button only
|
|
222
|
-
// shows when the catalogue/dashboard tools are actually registered. An
|
|
223
|
-
// explicit `builderEnabled` prop forces the affordance on or off.
|
|
224
|
-
const builderAvailable = builderEnabled ?? viewData.builderAvailable ?? false
|
|
225
|
-
|
|
226
436
|
return (
|
|
227
|
-
<
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
437
|
+
<div ref={frameRef} tabIndex={-1} data-slot="mcp-app-view" className="outline-hidden">
|
|
438
|
+
{viewContext}
|
|
439
|
+
<main
|
|
440
|
+
style={{
|
|
441
|
+
// Fullscreen: the view owns the viewport and scrolls itself. Inline:
|
|
442
|
+
// the host sizes us from our intrinsic height (bootstrapView's
|
|
443
|
+
// auto-resize), so no overflow clipping there.
|
|
444
|
+
...(fullscreen.isFullscreen ? { minHeight: "100vh", overflowY: "auto" as const } : null),
|
|
445
|
+
paddingTop: safeArea.top,
|
|
446
|
+
paddingRight: safeArea.right,
|
|
447
|
+
paddingBottom: safeArea.bottom,
|
|
448
|
+
paddingLeft: safeArea.left,
|
|
449
|
+
}}
|
|
450
|
+
>
|
|
451
|
+
<ViewToolbar
|
|
452
|
+
hidden={buildMode}
|
|
453
|
+
viewData={viewData}
|
|
454
|
+
builderAvailable={builderEnabled ?? viewData.builderAvailable ?? false}
|
|
455
|
+
isFullscreen={fullscreen.isFullscreen}
|
|
456
|
+
canFullscreen={fullscreen.canFullscreen}
|
|
457
|
+
isRefreshing={isRefreshing}
|
|
458
|
+
labels={L}
|
|
459
|
+
titleMode={titleMode}
|
|
460
|
+
titleLevel={titleLevel}
|
|
461
|
+
renderTitle={renderTitle}
|
|
462
|
+
onRefresh={refreshView}
|
|
463
|
+
onEnterBuildMode={() => setBuildMode(true)}
|
|
464
|
+
onToggleFullscreen={fullscreen.toggle}
|
|
465
|
+
dataAsOf={formatDataAsOf(view.reloadedAt, formatLocale, timeZone)}
|
|
466
|
+
/>
|
|
253
467
|
|
|
254
|
-
|
|
468
|
+
<StepErrors
|
|
469
|
+
hidden={buildMode}
|
|
470
|
+
errors={viewData.context.errors}
|
|
471
|
+
steps={viewData._refreshParams?.steps}
|
|
472
|
+
labels={L}
|
|
473
|
+
describeStep={describeStep}
|
|
474
|
+
onRetry={viewData._refreshParams ? () => void refreshView() : undefined}
|
|
475
|
+
/>
|
|
255
476
|
|
|
256
|
-
|
|
257
|
-
<ViewBody
|
|
258
|
-
buildMode={buildMode}
|
|
259
|
-
viewData={viewData}
|
|
260
|
-
widgets={widgets}
|
|
477
|
+
<AppQueryProvider
|
|
261
478
|
callTool={callToolFn}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
479
|
+
client={viewClient}
|
|
480
|
+
toolNameInQueryKey={toolNameInQueryKey}
|
|
481
|
+
>
|
|
482
|
+
<ViewBody
|
|
483
|
+
buildMode={buildMode}
|
|
484
|
+
viewData={viewData}
|
|
485
|
+
widgets={widgets}
|
|
486
|
+
callTool={callToolFn}
|
|
487
|
+
builderLabels={builderLabels}
|
|
488
|
+
onExit={exitBuildMode}
|
|
489
|
+
/>
|
|
490
|
+
</AppQueryProvider>
|
|
491
|
+
</main>
|
|
492
|
+
</div>
|
|
266
493
|
)
|
|
267
494
|
}
|
|
495
|
+
|
|
496
|
+
/** How the model line names the view's own re-load of the shown payload. */
|
|
497
|
+
function reloadedByOf(source: ViewSource | null): "recovery" | "refresh" | "builder" {
|
|
498
|
+
if (source === "refresh" || source === "builder") return source
|
|
499
|
+
return "recovery"
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* The shown view with a builder commit applied (nothing to apply without
|
|
504
|
+
* data). A commit that carries the builder's live context shows figures the
|
|
505
|
+
* builder loaded itself (its catalogue call ran the steps again), so it is
|
|
506
|
+
* stamped like a refresh: the toolbar says when, and the model learns that
|
|
507
|
+
* they can differ from the result the chat answered from. A commit without a
|
|
508
|
+
* context keeps the shown figures, and with them their source and stamp.
|
|
509
|
+
*/
|
|
510
|
+
function withBuilderCommit(view: ShownView, commit: BuilderCommit): ShownView {
|
|
511
|
+
if (!view.data) return view
|
|
512
|
+
const data = applyBuilderCommit(view.data, commit)
|
|
513
|
+
if (!commit.context) return { ...view, data }
|
|
514
|
+
return { data, source: "builder", reloadedAt: reloadedAtOf("builder", Date.now(), false) }
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/** The toolbar's "as of" time of a re-loaded payload, `undefined` for any other. */
|
|
518
|
+
function formatDataAsOf(
|
|
519
|
+
reloadedAt: number | null,
|
|
520
|
+
locale: string,
|
|
521
|
+
timeZone: string | undefined,
|
|
522
|
+
): string | undefined {
|
|
523
|
+
return reloadedAt === null ? undefined : formatClockTime(reloadedAt, locale, timeZone)
|
|
524
|
+
}
|