@miragon/mcp-toolkit-ui 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/app/adapt-data-widget.d.ts +33 -0
- package/dist/app/adapt-data-widget.d.ts.map +1 -0
- package/dist/app/adapt-data-widget.js +35 -0
- package/dist/app/adapt-data-widget.js.map +1 -0
- package/dist/app/builder/CatalogueSheet.d.ts +13 -0
- package/dist/app/builder/CatalogueSheet.d.ts.map +1 -0
- package/dist/app/builder/CatalogueSheet.js +33 -0
- package/dist/app/builder/CatalogueSheet.js.map +1 -0
- package/dist/app/builder/PipelineStrip.d.ts +22 -0
- package/dist/app/builder/PipelineStrip.d.ts.map +1 -0
- package/dist/app/builder/PipelineStrip.js +31 -0
- package/dist/app/builder/PipelineStrip.js.map +1 -0
- package/dist/app/builder/PreviewPane.d.ts +13 -0
- package/dist/app/builder/PreviewPane.d.ts.map +1 -0
- package/dist/app/builder/PreviewPane.js +21 -0
- package/dist/app/builder/PreviewPane.js.map +1 -0
- package/dist/app/builder/SaveDialog.d.ts +14 -0
- package/dist/app/builder/SaveDialog.d.ts.map +1 -0
- package/dist/app/builder/SaveDialog.js +14 -0
- package/dist/app/builder/SaveDialog.js.map +1 -0
- package/dist/app/builder/Toolbar.d.ts +17 -0
- package/dist/app/builder/Toolbar.d.ts.map +1 -0
- package/dist/app/builder/Toolbar.js +15 -0
- package/dist/app/builder/Toolbar.js.map +1 -0
- package/dist/app/builder/Workspace.d.ts +28 -0
- package/dist/app/builder/Workspace.d.ts.map +1 -0
- package/dist/app/builder/Workspace.js +117 -0
- package/dist/app/builder/Workspace.js.map +1 -0
- package/dist/app/builder/builder-model.d.ts +86 -0
- package/dist/app/builder/builder-model.d.ts.map +1 -0
- package/dist/app/builder/builder-model.js +174 -0
- package/dist/app/builder/builder-model.js.map +1 -0
- package/dist/app/builder/builder-reducer.d.ts +71 -0
- package/dist/app/builder/builder-reducer.d.ts.map +1 -0
- package/dist/app/builder/builder-reducer.js +201 -0
- package/dist/app/builder/builder-reducer.js.map +1 -0
- package/dist/app/builder/labels.d.ts +78 -0
- package/dist/app/builder/labels.d.ts.map +1 -0
- package/dist/app/builder/labels.js +71 -0
- package/dist/app/builder/labels.js.map +1 -0
- package/dist/app/builder/status-chip.d.ts +10 -0
- package/dist/app/builder/status-chip.d.ts.map +1 -0
- package/dist/app/builder/status-chip.js +16 -0
- package/dist/app/builder/status-chip.js.map +1 -0
- package/dist/app/host-bridge.d.ts +211 -0
- package/dist/app/host-bridge.d.ts.map +1 -0
- package/dist/app/host-bridge.js +247 -0
- package/dist/app/host-bridge.js.map +1 -0
- package/dist/app/index.d.ts +16 -0
- package/dist/app/index.d.ts.map +1 -0
- package/dist/app/index.js +18 -0
- package/dist/app/index.js.map +1 -0
- package/dist/app/layout-builder.d.ts +48 -0
- package/dist/app/layout-builder.d.ts.map +1 -0
- package/dist/app/layout-builder.js +418 -0
- package/dist/app/layout-builder.js.map +1 -0
- package/dist/app/mcp-app-view.d.ts +43 -0
- package/dist/app/mcp-app-view.d.ts.map +1 -0
- package/dist/app/mcp-app-view.js +169 -0
- package/dist/app/mcp-app-view.js.map +1 -0
- package/dist/app/mcp-toolkit-app.d.ts +18 -0
- package/dist/app/mcp-toolkit-app.d.ts.map +1 -0
- package/dist/app/mcp-toolkit-app.js +22 -0
- package/dist/app/mcp-toolkit-app.js.map +1 -0
- package/dist/app/use-host-actions.d.ts +57 -0
- package/dist/app/use-host-actions.d.ts.map +1 -0
- package/dist/app/use-host-actions.js +42 -0
- package/dist/app/use-host-actions.js.map +1 -0
- package/dist/app/widget-fixture.d.ts +180 -0
- package/dist/app/widget-fixture.d.ts.map +1 -0
- package/dist/app/widget-fixture.js +273 -0
- package/dist/app/widget-fixture.js.map +1 -0
- package/dist/app/widget-props-sheet.d.ts +20 -0
- package/dist/app/widget-props-sheet.d.ts.map +1 -0
- package/dist/app/widget-props-sheet.js +87 -0
- package/dist/app/widget-props-sheet.js.map +1 -0
- package/dist/app/widget-renderer.d.ts +87 -0
- package/dist/app/widget-renderer.d.ts.map +1 -0
- package/dist/app/widget-renderer.js +105 -0
- package/dist/app/widget-renderer.js.map +1 -0
- package/dist/components/DrillButton.d.ts +22 -0
- package/dist/components/DrillButton.d.ts.map +1 -0
- package/dist/components/DrillButton.js +13 -0
- package/dist/components/DrillButton.js.map +1 -0
- package/dist/components/FilterBar.d.ts +28 -0
- package/dist/components/FilterBar.d.ts.map +1 -0
- package/dist/components/FilterBar.js +12 -0
- package/dist/components/FilterBar.js.map +1 -0
- package/dist/components/GridLayout.d.ts +26 -0
- package/dist/components/GridLayout.d.ts.map +1 -0
- package/dist/components/GridLayout.js +31 -0
- package/dist/components/GridLayout.js.map +1 -0
- package/dist/components/GroupCard.d.ts +21 -0
- package/dist/components/GroupCard.d.ts.map +1 -0
- package/dist/components/GroupCard.js +24 -0
- package/dist/components/GroupCard.js.map +1 -0
- package/dist/components/KpiGrid.d.ts +43 -0
- package/dist/components/KpiGrid.d.ts.map +1 -0
- package/dist/components/KpiGrid.js +35 -0
- package/dist/components/KpiGrid.js.map +1 -0
- package/dist/components/ListFooter.d.ts +22 -0
- package/dist/components/ListFooter.d.ts.map +1 -0
- package/dist/components/ListFooter.js +13 -0
- package/dist/components/ListFooter.js.map +1 -0
- package/dist/components/Pills.d.ts +25 -0
- package/dist/components/Pills.d.ts.map +1 -0
- package/dist/components/Pills.js +17 -0
- package/dist/components/Pills.js.map +1 -0
- package/dist/components/SectionHeading.d.ts +16 -0
- package/dist/components/SectionHeading.d.ts.map +1 -0
- package/dist/components/SectionHeading.js +10 -0
- package/dist/components/SectionHeading.js.map +1 -0
- package/dist/components/WidgetHeader.d.ts +21 -0
- package/dist/components/WidgetHeader.d.ts.map +1 -0
- package/dist/components/WidgetHeader.js +11 -0
- package/dist/components/WidgetHeader.js.map +1 -0
- package/dist/hooks/index.d.ts +11 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +7 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/use-debounced-value.d.ts +7 -0
- package/dist/hooks/use-debounced-value.d.ts.map +1 -0
- package/dist/hooks/use-debounced-value.js +15 -0
- package/dist/hooks/use-debounced-value.js.map +1 -0
- package/dist/hooks/use-mobile.d.ts +6 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -0
- package/dist/hooks/use-mobile.js +19 -0
- package/dist/hooks/use-mobile.js.map +1 -0
- package/dist/hooks/use-tool-query.d.ts +21 -0
- package/dist/hooks/use-tool-query.d.ts.map +1 -0
- package/dist/hooks/use-tool-query.js +47 -0
- package/dist/hooks/use-tool-query.js.map +1 -0
- package/dist/hooks/use-tool-result-recovery.d.ts +54 -0
- package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -0
- package/dist/hooks/use-tool-result-recovery.js +93 -0
- package/dist/hooks/use-tool-result-recovery.js.map +1 -0
- package/dist/hooks/use-view-data.d.ts +19 -0
- package/dist/hooks/use-view-data.d.ts.map +1 -0
- package/dist/hooks/use-view-data.js +18 -0
- package/dist/hooks/use-view-data.js.map +1 -0
- package/dist/hooks/use-view-tool-query.d.ts +18 -0
- package/dist/hooks/use-view-tool-query.d.ts.map +1 -0
- package/dist/hooks/use-view-tool-query.js +29 -0
- package/dist/hooks/use-view-tool-query.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/parse-tool-result.d.ts +39 -0
- package/dist/lib/parse-tool-result.d.ts.map +1 -0
- package/dist/lib/parse-tool-result.js +66 -0
- package/dist/lib/parse-tool-result.js.map +1 -0
- package/dist/lib/tone-utils.d.ts +18 -0
- package/dist/lib/tone-utils.d.ts.map +1 -0
- package/dist/lib/tone-utils.js +25 -0
- package/dist/lib/tone-utils.js.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +6 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/locale/index.d.ts +3 -0
- package/dist/locale/index.d.ts.map +1 -0
- package/dist/locale/index.js +7 -0
- package/dist/locale/index.js.map +1 -0
- package/dist/locale/locale-provider.d.ts +50 -0
- package/dist/locale/locale-provider.d.ts.map +1 -0
- package/dist/locale/locale-provider.js +47 -0
- package/dist/locale/locale-provider.js.map +1 -0
- package/dist/primitives/alert.d.ts +10 -0
- package/dist/primitives/alert.d.ts.map +1 -0
- package/dist/primitives/alert.js +25 -0
- package/dist/primitives/alert.js.map +1 -0
- package/dist/primitives/badge.d.ts +8 -0
- package/dist/primitives/badge.d.ts.map +1 -0
- package/dist/primitives/badge.js +34 -0
- package/dist/primitives/badge.js.map +1 -0
- package/dist/primitives/button.d.ts +11 -0
- package/dist/primitives/button.d.ts.map +1 -0
- package/dist/primitives/button.js +36 -0
- package/dist/primitives/button.js.map +1 -0
- package/dist/primitives/card.d.ts +12 -0
- package/dist/primitives/card.d.ts.map +1 -0
- package/dist/primitives/card.js +25 -0
- package/dist/primitives/card.js.map +1 -0
- package/dist/primitives/dialog.d.ts +18 -0
- package/dist/primitives/dialog.d.ts.map +1 -0
- package/dist/primitives/dialog.js +38 -0
- package/dist/primitives/dialog.js.map +1 -0
- package/dist/primitives/input.d.ts +4 -0
- package/dist/primitives/input.d.ts.map +1 -0
- package/dist/primitives/input.js +7 -0
- package/dist/primitives/input.js.map +1 -0
- package/dist/primitives/scroll-area.d.ts +6 -0
- package/dist/primitives/scroll-area.d.ts.map +1 -0
- package/dist/primitives/scroll-area.js +11 -0
- package/dist/primitives/scroll-area.js.map +1 -0
- package/dist/primitives/select.d.ts +16 -0
- package/dist/primitives/select.d.ts.map +1 -0
- package/dist/primitives/select.js +38 -0
- package/dist/primitives/select.js.map +1 -0
- package/dist/primitives/separator.d.ts +4 -0
- package/dist/primitives/separator.d.ts.map +1 -0
- package/dist/primitives/separator.js +9 -0
- package/dist/primitives/separator.js.map +1 -0
- package/dist/primitives/sheet.d.ts +15 -0
- package/dist/primitives/sheet.d.ts.map +1 -0
- package/dist/primitives/sheet.js +41 -0
- package/dist/primitives/sheet.js.map +1 -0
- package/dist/primitives/skeleton.d.ts +3 -0
- package/dist/primitives/skeleton.d.ts.map +1 -0
- package/dist/primitives/skeleton.js +7 -0
- package/dist/primitives/skeleton.js.map +1 -0
- package/dist/primitives/switch.d.ts +5 -0
- package/dist/primitives/switch.d.ts.map +1 -0
- package/dist/primitives/switch.js +8 -0
- package/dist/primitives/switch.js.map +1 -0
- package/dist/primitives/table.d.ts +11 -0
- package/dist/primitives/table.d.ts.map +1 -0
- package/dist/primitives/table.js +28 -0
- package/dist/primitives/table.js.map +1 -0
- package/dist/primitives/tabs.d.ts +12 -0
- package/dist/primitives/tabs.d.ts.map +1 -0
- package/dist/primitives/tabs.js +29 -0
- package/dist/primitives/tabs.js.map +1 -0
- package/dist/providers/query-provider.d.ts +11 -0
- package/dist/providers/query-provider.d.ts.map +1 -0
- package/dist/providers/query-provider.js +20 -0
- package/dist/providers/query-provider.js.map +1 -0
- package/dist/theme/create-theme.d.ts +130 -0
- package/dist/theme/create-theme.d.ts.map +1 -0
- package/dist/theme/create-theme.js +65 -0
- package/dist/theme/create-theme.js.map +1 -0
- package/dist/theme/index.d.ts +7 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +7 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/presets.d.ts +25 -0
- package/dist/theme/presets.d.ts.map +1 -0
- package/dist/theme/presets.js +68 -0
- package/dist/theme/presets.js.map +1 -0
- package/dist/theme/theme-provider.d.ts +69 -0
- package/dist/theme/theme-provider.d.ts.map +1 -0
- package/dist/theme/theme-provider.js +79 -0
- package/dist/theme/theme-provider.js.map +1 -0
- package/package.json +71 -0
- package/src/app/adapt-data-widget.tsx +51 -0
- package/src/app/builder/CatalogueSheet.tsx +230 -0
- package/src/app/builder/PipelineStrip.tsx +260 -0
- package/src/app/builder/PreviewPane.tsx +72 -0
- package/src/app/builder/SaveDialog.tsx +95 -0
- package/src/app/builder/Toolbar.tsx +95 -0
- package/src/app/builder/Workspace.tsx +483 -0
- package/src/app/builder/builder-model.test.ts +351 -0
- package/src/app/builder/builder-model.ts +213 -0
- package/src/app/builder/builder-reducer.test.ts +441 -0
- package/src/app/builder/builder-reducer.ts +289 -0
- package/src/app/builder/labels.ts +139 -0
- package/src/app/builder/status-chip.tsx +37 -0
- package/src/app/host-bridge.test.ts +206 -0
- package/src/app/host-bridge.tsx +371 -0
- package/src/app/index.ts +51 -0
- package/src/app/layout-builder.tsx +872 -0
- package/src/app/mcp-app-view.tsx +367 -0
- package/src/app/mcp-toolkit-app.tsx +25 -0
- package/src/app/use-host-actions.test.ts +16 -0
- package/src/app/use-host-actions.tsx +88 -0
- package/src/app/widget-fixture.test.ts +108 -0
- package/src/app/widget-fixture.tsx +441 -0
- package/src/app/widget-props-sheet.tsx +285 -0
- package/src/app/widget-renderer.test.ts +42 -0
- package/src/app/widget-renderer.tsx +200 -0
- package/src/components/DrillButton.tsx +37 -0
- package/src/components/FilterBar.tsx +68 -0
- package/src/components/GridLayout.tsx +49 -0
- package/src/components/GroupCard.tsx +52 -0
- package/src/components/KpiGrid.tsx +134 -0
- package/src/components/ListFooter.tsx +48 -0
- package/src/components/Pills.tsx +45 -0
- package/src/components/SectionHeading.tsx +26 -0
- package/src/components/WidgetHeader.tsx +51 -0
- package/src/globals.css +168 -0
- package/src/hooks/index.ts +17 -0
- package/src/hooks/use-debounced-value.ts +15 -0
- package/src/hooks/use-mobile.ts +24 -0
- package/src/hooks/use-tool-query.ts +63 -0
- package/src/hooks/use-tool-result-recovery.test.ts +65 -0
- package/src/hooks/use-tool-result-recovery.ts +144 -0
- package/src/hooks/use-view-data.ts +31 -0
- package/src/hooks/use-view-tool-query.ts +38 -0
- package/src/index.ts +134 -0
- package/src/lib/parse-tool-result.test.ts +139 -0
- package/src/lib/parse-tool-result.ts +89 -0
- package/src/lib/tone-utils.test.ts +35 -0
- package/src/lib/tone-utils.ts +38 -0
- package/src/lib/utils.ts +6 -0
- package/src/locale/index.ts +7 -0
- package/src/locale/locale-provider.tsx +81 -0
- package/src/primitives/alert.tsx +60 -0
- package/src/primitives/badge.tsx +49 -0
- package/src/primitives/button.tsx +62 -0
- package/src/primitives/card.tsx +92 -0
- package/src/primitives/dialog.tsx +144 -0
- package/src/primitives/input.tsx +21 -0
- package/src/primitives/scroll-area.tsx +54 -0
- package/src/primitives/select.tsx +173 -0
- package/src/primitives/separator.tsx +21 -0
- package/src/primitives/sheet.tsx +134 -0
- package/src/primitives/skeleton.tsx +13 -0
- package/src/primitives/switch.tsx +24 -0
- package/src/primitives/table.tsx +87 -0
- package/src/primitives/tabs.tsx +79 -0
- package/src/providers/query-provider.tsx +38 -0
- package/src/theme/create-theme.test.ts +108 -0
- package/src/theme/create-theme.ts +158 -0
- package/src/theme/index.ts +9 -0
- package/src/theme/presets.ts +82 -0
- package/src/theme/theme-provider.tsx +152 -0
- package/src/ui-catalog.test.ts +112 -0
- package/ui-catalog.json +1280 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useEffect, useMemo, useRef, useSyncExternalStore, } from "react";
|
|
3
|
+
import { useWidget } from "mcp-use/react";
|
|
4
|
+
import { AppQueryProvider } from "../providers/query-provider.js";
|
|
5
|
+
import { HostBridgeProvider, createStandaloneHostBridge } from "./host-bridge.js";
|
|
6
|
+
/**
|
|
7
|
+
* Key `mcp-use` writes the serialized model-context string under when it flushes
|
|
8
|
+
* to `window.openai.setWidgetState`. Mirrors `MODEL_CONTEXT_KEY` in
|
|
9
|
+
* `mcp-use/react` (not exported, so duplicated here). The harness intercepts
|
|
10
|
+
* `setWidgetState` and reads this field to surface what the model would see.
|
|
11
|
+
*/
|
|
12
|
+
const MODEL_CONTEXT_KEY = "__model_context";
|
|
13
|
+
/**
|
|
14
|
+
* Pure, host-free registry of fake tool implementations. Drives every
|
|
15
|
+
* `callTool` path the harness exposes (`window.openai.callTool`, the toolkit's
|
|
16
|
+
* `AppQueryProvider` bridge). Kept free of React/DOM so its semantics are unit
|
|
17
|
+
* testable in a plain Node environment.
|
|
18
|
+
*
|
|
19
|
+
* Resolution rules:
|
|
20
|
+
* - A registered **function** entry is called with `args` and its return value
|
|
21
|
+
* (awaited) is wrapped into a {@link FixtureToolResult}.
|
|
22
|
+
* - A registered **value** entry is returned as-is when it already looks like a
|
|
23
|
+
* tool response (has `structuredContent`/`content`), otherwise wrapped under
|
|
24
|
+
* `structuredContent` so widgets that read structured data Just Work.
|
|
25
|
+
* - An **unknown** tool rejects with a descriptive error. This is the
|
|
26
|
+
* error-friendly path: the rejection flows into the widget's own error state
|
|
27
|
+
* (TanStack Query `error`, `mcp-use` `isError`) instead of crashing the
|
|
28
|
+
* harness, and the message names the missing tool so the gap is obvious.
|
|
29
|
+
*/
|
|
30
|
+
export class FixtureCallToolRegistry {
|
|
31
|
+
entries = new Map();
|
|
32
|
+
constructor(initial) {
|
|
33
|
+
if (initial) {
|
|
34
|
+
for (const [name, entry] of Object.entries(initial))
|
|
35
|
+
this.register(name, entry);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Register (or overwrite) the fixture for a tool name. */
|
|
39
|
+
register(name, resultOrHandler) {
|
|
40
|
+
this.entries.set(name, resultOrHandler);
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
/** True if a fixture is registered for `name`. */
|
|
44
|
+
has(name) {
|
|
45
|
+
return this.entries.has(name);
|
|
46
|
+
}
|
|
47
|
+
/** Registered tool names, for diagnostics / the harness log. */
|
|
48
|
+
names() {
|
|
49
|
+
return [...this.entries.keys()];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Resolve a tool call against the registered fixtures. Always returns a
|
|
53
|
+
* promise so callers can `await` uniformly regardless of whether the fixture
|
|
54
|
+
* was a static value or an async handler.
|
|
55
|
+
*/
|
|
56
|
+
async call(name, args = {}) {
|
|
57
|
+
if (!this.entries.has(name)) {
|
|
58
|
+
throw new Error(`[widget-fixture] No fixture registered for tool "${name}". ` +
|
|
59
|
+
`Registered: ${this.names().length ? this.names().join(", ") : "(none)"}.`);
|
|
60
|
+
}
|
|
61
|
+
const entry = this.entries.get(name);
|
|
62
|
+
const raw = typeof entry === "function" ? await entry(args) : entry;
|
|
63
|
+
return toToolResult(raw);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Wrap an arbitrary fixture value into a {@link FixtureToolResult}. Values that
|
|
68
|
+
* already carry `structuredContent` or `content` are passed through untouched
|
|
69
|
+
* so a fixture can opt into the full envelope; everything else is placed under
|
|
70
|
+
* `structuredContent` (the field `parseToolResult` reads first) and mirrored
|
|
71
|
+
* into a `content` text block so `mcp-use`'s text-oriented decoder also sees it.
|
|
72
|
+
*/
|
|
73
|
+
function toToolResult(raw) {
|
|
74
|
+
if (raw != null && typeof raw === "object" && ("structuredContent" in raw || "content" in raw)) {
|
|
75
|
+
return raw;
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
structuredContent: raw,
|
|
79
|
+
content: [{ type: "text", text: typeof raw === "string" ? raw : JSON.stringify(raw) }],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const FixtureHostContext = createContext(null);
|
|
83
|
+
/**
|
|
84
|
+
* Access the active fixture registry from inside a {@link WidgetFixtureHost}.
|
|
85
|
+
* Returns `null` outside a harness — callers should treat that as "no fixture
|
|
86
|
+
* host present" rather than an error.
|
|
87
|
+
*/
|
|
88
|
+
export function useFixtureHost() {
|
|
89
|
+
return useContext(FixtureHostContext);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Default host-context globals a widget sees in the harness. Chosen to be
|
|
93
|
+
* harmless and inert: inline display, light theme, desktop, no safe-area
|
|
94
|
+
* insets. Overridable per-mount via {@link WidgetFixtureHostProps.globals}.
|
|
95
|
+
*/
|
|
96
|
+
const DEFAULT_GLOBALS = {
|
|
97
|
+
theme: "light",
|
|
98
|
+
displayMode: "inline",
|
|
99
|
+
locale: "en-US",
|
|
100
|
+
maxHeight: 4096,
|
|
101
|
+
safeArea: { insets: { top: 0, right: 0, bottom: 0, left: 0 } },
|
|
102
|
+
userAgent: {
|
|
103
|
+
device: { type: "desktop" },
|
|
104
|
+
capabilities: { hover: true, touch: false },
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Build the `window.openai` shim the `mcp-use` React hooks read from. Routes
|
|
109
|
+
* `callTool` through the fixture registry and reports every other bridge verb
|
|
110
|
+
* to `onHostAction`. Returns `null` outside a browser-like environment (SSR)
|
|
111
|
+
* so the harness degrades to a plain render rather than throwing.
|
|
112
|
+
*/
|
|
113
|
+
function buildOpenAiShim(registry, toolOutput, toolInput, globals, onHostAction, onModelContext) {
|
|
114
|
+
if (typeof window === "undefined")
|
|
115
|
+
return null;
|
|
116
|
+
return {
|
|
117
|
+
...DEFAULT_GLOBALS,
|
|
118
|
+
...globals,
|
|
119
|
+
toolInput,
|
|
120
|
+
toolOutput,
|
|
121
|
+
toolResponseMetadata: null,
|
|
122
|
+
widgetState: null,
|
|
123
|
+
callTool: async (name, args) => {
|
|
124
|
+
onHostAction?.({ type: "callTool", name, args });
|
|
125
|
+
return registry.call(name, args);
|
|
126
|
+
},
|
|
127
|
+
sendFollowUpMessage: (args) => {
|
|
128
|
+
onHostAction?.({ type: "sendFollowUpMessage", prompt: args.prompt });
|
|
129
|
+
return Promise.resolve();
|
|
130
|
+
},
|
|
131
|
+
openExternal: (payload) => {
|
|
132
|
+
onHostAction?.({ type: "openExternal", href: payload.href });
|
|
133
|
+
},
|
|
134
|
+
requestDisplayMode: (args) => {
|
|
135
|
+
onHostAction?.({ type: "requestDisplayMode", mode: args.mode });
|
|
136
|
+
return Promise.resolve({ mode: args.mode });
|
|
137
|
+
},
|
|
138
|
+
setWidgetState: (state) => {
|
|
139
|
+
onHostAction?.({ type: "setWidgetState", state });
|
|
140
|
+
// `mcp-use` flushes the serialized `<ModelContext>` tree through
|
|
141
|
+
// setWidgetState under MODEL_CONTEXT_KEY — surface it as the model view.
|
|
142
|
+
const ctx = state?.[MODEL_CONTEXT_KEY];
|
|
143
|
+
if (typeof ctx === "string")
|
|
144
|
+
onModelContext?.(ctx);
|
|
145
|
+
return Promise.resolve();
|
|
146
|
+
},
|
|
147
|
+
notifyIntrinsicHeight: () => Promise.resolve(),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Renders nothing but mounts a `useWidget()` so `mcp-use` registers its
|
|
152
|
+
* model-context flush handler — even for widgets that never call `useWidget`
|
|
153
|
+
* themselves (e.g. a simple `({ keys })` card). Without this, a widget's
|
|
154
|
+
* `<ModelContext>` would render but never flush, and `onModelContext` would
|
|
155
|
+
* stay silent. The flush routes through our `setWidgetState` shim above.
|
|
156
|
+
*/
|
|
157
|
+
function ModelContextPump() {
|
|
158
|
+
useWidget();
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Build the `WidgetProps` envelope the harness passes to the widget. Seeds a
|
|
163
|
+
* single pipeline step from `data` (keyed by `dataType` when given) and uses
|
|
164
|
+
* `data` as the `keys` map, so widgets that read `keys[...]` and adapted
|
|
165
|
+
* widgets that scan `context.steps` are both satisfied from one fixture.
|
|
166
|
+
*
|
|
167
|
+
* Exported for unit testing the envelope shape without rendering React.
|
|
168
|
+
*/
|
|
169
|
+
export function buildFixtureWidgetProps(data, dataType) {
|
|
170
|
+
const steps = {};
|
|
171
|
+
if (dataType) {
|
|
172
|
+
steps.fixture = {
|
|
173
|
+
_app: "fixture",
|
|
174
|
+
_step: "fixture",
|
|
175
|
+
_dataType: dataType,
|
|
176
|
+
data,
|
|
177
|
+
keys: data,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const context = { steps, keys: data, errors: [] };
|
|
181
|
+
return { keys: data, context };
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Storybook-style harness for MCP widgets. Renders a single widget with fixture
|
|
185
|
+
* data and a mocked host environment so it can be developed in isolation —
|
|
186
|
+
* without booting a real MCP host or backend.
|
|
187
|
+
*
|
|
188
|
+
* ### What it mocks
|
|
189
|
+
* - **`window.openai`** — the `mcp-use` Apps-SDK bridge `useWidget`/`useCallTool`
|
|
190
|
+
* read from. Installed on mount, removed on unmount. `callTool` is routed to a
|
|
191
|
+
* {@link FixtureCallToolRegistry} built from `tools`; `sendFollowUpMessage`,
|
|
192
|
+
* `openExternal`, etc. are reported to `onHostAction`.
|
|
193
|
+
* - **The toolkit `AppQueryProvider`** — so widgets that fetch via `useToolQuery`
|
|
194
|
+
* (e.g. generated `use*` hooks) resolve against the same registry.
|
|
195
|
+
* - **`ModelContext`** — a flush handler captures the serialized context string
|
|
196
|
+
* and forwards it to `onModelContext`, so you can *see* what the model would.
|
|
197
|
+
* - **A {@link HostBridge}** — a `createStandaloneHostBridge` over the same
|
|
198
|
+
* registry and callbacks, provided via `HostBridgeProvider`, so widgets
|
|
199
|
+
* written against `useHostBridge` (the host-portable pattern) are simulated
|
|
200
|
+
* from the same single source as the `window.openai` shim above.
|
|
201
|
+
*
|
|
202
|
+
* ### Boundaries
|
|
203
|
+
* `mcp-use`'s hooks select their provider from `window.openai` presence; this
|
|
204
|
+
* harness deliberately drives the Apps-SDK path (sets `window.openai`) rather
|
|
205
|
+
* than the `postMessage` bridge, which only activates inside a cross-origin
|
|
206
|
+
* iframe. The shim is intentionally minimal — it is not a host, and host
|
|
207
|
+
* features beyond the bridge verbs above are out of scope.
|
|
208
|
+
*/
|
|
209
|
+
export function WidgetFixtureHost({ widget: Widget, data = {}, dataType, tools, globals, onModelContext, onHostAction, }) {
|
|
210
|
+
// One registry per `tools` identity. Rebuilt when the fixture map changes so
|
|
211
|
+
// edits in the playground take effect without a full remount.
|
|
212
|
+
const registry = useMemo(() => new FixtureCallToolRegistry(tools), [tools]);
|
|
213
|
+
// Latest callbacks without re-installing the shim on every render. Updated in
|
|
214
|
+
// an effect (not during render) so the shim's closures always see the newest
|
|
215
|
+
// handler while the `window.openai` install effect stays stable.
|
|
216
|
+
const onHostActionRef = useRef(onHostAction);
|
|
217
|
+
const onModelContextRef = useRef(onModelContext);
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
onHostActionRef.current = onHostAction;
|
|
220
|
+
onModelContextRef.current = onModelContext;
|
|
221
|
+
});
|
|
222
|
+
const widgetProps = useMemo(() => buildFixtureWidgetProps(data, dataType), [data, dataType]);
|
|
223
|
+
// Install the `window.openai` shim for the lifetime of this mount. Wake any
|
|
224
|
+
// already-mounted `mcp-use` hooks via the `set_globals` event they listen for.
|
|
225
|
+
useEffect(() => {
|
|
226
|
+
if (typeof window === "undefined")
|
|
227
|
+
return;
|
|
228
|
+
const shim = buildOpenAiShim(registry, data ?? null, data ?? {}, globals ?? {}, (action) => onHostActionRef.current?.(action), (text) => onModelContextRef.current?.(text));
|
|
229
|
+
if (!shim)
|
|
230
|
+
return;
|
|
231
|
+
const prev = window.openai;
|
|
232
|
+
window.openai = shim;
|
|
233
|
+
window.dispatchEvent(new CustomEvent("openai:set_globals", { detail: { globals: shim } }));
|
|
234
|
+
return () => {
|
|
235
|
+
;
|
|
236
|
+
window.openai = prev;
|
|
237
|
+
};
|
|
238
|
+
}, [registry, data, globals]);
|
|
239
|
+
const callTool = useMemo(() => async (name, args) => registry.call(name, args ?? {}), [registry]);
|
|
240
|
+
// A standalone host bridge over the same registry + callbacks, so portable
|
|
241
|
+
// widgets written against `useHostBridge` (rather than the `mcp-use` host
|
|
242
|
+
// hooks) are simulated from the *same* source as the `window.openai` shim.
|
|
243
|
+
// It logs through the same `HostActionLog` channel, so the playground's
|
|
244
|
+
// activity log shows tool calls, follow-ups, and links identically whether the
|
|
245
|
+
// widget uses the mcp-use path or the host bridge. Reading globals.theme keeps
|
|
246
|
+
// the bridge's reported theme in sync with the shim. Depends on the callback
|
|
247
|
+
// props directly (not the refs) — a fresh Provider value on callback change is
|
|
248
|
+
// fine for a dev harness, and keeps the bridge's closures pure of ref reads.
|
|
249
|
+
const bridgeTheme = (globals?.theme ?? DEFAULT_GLOBALS.theme) === "dark" ? "dark" : "light";
|
|
250
|
+
const bridge = useMemo(() => createStandaloneHostBridge({
|
|
251
|
+
callTool: (name, args) => {
|
|
252
|
+
onHostAction?.({ type: "callTool", name, args });
|
|
253
|
+
return registry.call(name, args);
|
|
254
|
+
},
|
|
255
|
+
getData: () => data ?? null,
|
|
256
|
+
onFollowup: (prompt) => onHostAction?.({ type: "sendFollowUpMessage", prompt }),
|
|
257
|
+
onOpenExternal: (href) => onHostAction?.({ type: "openExternal", href }),
|
|
258
|
+
onModelContext: (text) => onModelContext?.(text),
|
|
259
|
+
theme: bridgeTheme,
|
|
260
|
+
}), [registry, data, bridgeTheme, onHostAction, onModelContext]);
|
|
261
|
+
const value = useMemo(() => ({ registry }), [registry]);
|
|
262
|
+
// Mount the model-context pump only on the client. The pump calls `mcp-use`'s
|
|
263
|
+
// `useWidget`, whose `useSyncExternalStore` lacks a server snapshot and throws
|
|
264
|
+
// under `react-dom/server` — gating it keeps the harness (and any widget
|
|
265
|
+
// rendered through it) SSR-safe. `useSyncExternalStore` with a `false` server
|
|
266
|
+
// snapshot is the idiomatic "are we on the client?" check (no setState-in-effect).
|
|
267
|
+
const isClient = useSyncExternalStore(() => () => { }, () => true, () => false);
|
|
268
|
+
// Spread `widgetProps` (keys/context) AND a `data` alias so both adapted
|
|
269
|
+
// widgets and raw `({ data })` widgets read their fixture from one mount.
|
|
270
|
+
const RenderWidget = Widget;
|
|
271
|
+
return (_jsxs(FixtureHostContext.Provider, { value: value, children: [isClient && _jsx(ModelContextPump, {}), _jsx(HostBridgeProvider, { bridge: bridge, children: _jsx(AppQueryProvider, { callTool: callTool, children: _jsx(RenderWidget, { ...widgetProps, data: data }) }) })] }));
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=widget-fixture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widget-fixture.js","sourceRoot":"","sources":["../../src/app/widget-fixture.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface WidgetPropsSheetLabels {
|
|
2
|
+
title?: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
apply?: string;
|
|
5
|
+
cancel?: string;
|
|
6
|
+
reset?: string;
|
|
7
|
+
noProps?: string;
|
|
8
|
+
unsetOption?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface WidgetPropsSheetProps {
|
|
11
|
+
open: boolean;
|
|
12
|
+
onOpenChange: (open: boolean) => void;
|
|
13
|
+
widgetId: string;
|
|
14
|
+
schema: Record<string, unknown> | undefined;
|
|
15
|
+
value: Record<string, unknown> | undefined;
|
|
16
|
+
onApply: (next: Record<string, unknown> | undefined) => void;
|
|
17
|
+
labels?: WidgetPropsSheetLabels;
|
|
18
|
+
}
|
|
19
|
+
export declare function WidgetPropsSheet({ open, onOpenChange, widgetId, schema, value, onApply, labels, }: WidgetPropsSheetProps): import("react").JSX.Element;
|
|
20
|
+
//# sourceMappingURL=widget-props-sheet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widget-props-sheet.d.ts","sourceRoot":"","sources":["../../src/app/widget-props-sheet.tsx"],"names":[],"mappings":"AAkDA,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAcD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IAC3C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IAC1C,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,KAAK,IAAI,CAAA;IAC5D,MAAM,CAAC,EAAE,sBAAsB,CAAA;CAChC;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,YAAY,EACZ,QAAQ,EACR,MAAM,EACN,KAAK,EACL,OAAO,EACP,MAAM,GACP,EAAE,qBAAqB,+BA6EvB"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { Button } from "../primitives/button.js";
|
|
4
|
+
import { Input } from "../primitives/input.js";
|
|
5
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "../primitives/select.js";
|
|
6
|
+
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, } from "../primitives/sheet.js";
|
|
7
|
+
import { Switch } from "../primitives/switch.js";
|
|
8
|
+
const DEFAULT_LABELS = {
|
|
9
|
+
title: "Configure widget",
|
|
10
|
+
description: "Set per-instance props for this widget.",
|
|
11
|
+
apply: "Apply",
|
|
12
|
+
cancel: "Cancel",
|
|
13
|
+
reset: "Reset",
|
|
14
|
+
noProps: "This widget takes no per-instance props.",
|
|
15
|
+
unsetOption: "(unset)",
|
|
16
|
+
};
|
|
17
|
+
const UNSET_SENTINEL = "__unset__";
|
|
18
|
+
export function WidgetPropsSheet({ open, onOpenChange, widgetId, schema, value, onApply, labels, }) {
|
|
19
|
+
const L = { ...DEFAULT_LABELS, ...labels };
|
|
20
|
+
const obj = (schema ?? {});
|
|
21
|
+
const [draft, setDraft] = useState(value ?? {});
|
|
22
|
+
// Reset the form to the saved value on the open→true transition so a
|
|
23
|
+
// user who closes the sheet without applying gets their unsaved edits
|
|
24
|
+
// discarded next time. Render-time state update with a "prev" tracker
|
|
25
|
+
// is the React-recommended alternative to a setState-in-effect.
|
|
26
|
+
const [prevOpen, setPrevOpen] = useState(open);
|
|
27
|
+
if (open !== prevOpen) {
|
|
28
|
+
setPrevOpen(open);
|
|
29
|
+
if (open)
|
|
30
|
+
setDraft(value ?? {});
|
|
31
|
+
}
|
|
32
|
+
const properties = obj.properties ?? {};
|
|
33
|
+
const propEntries = Object.entries(properties);
|
|
34
|
+
const handleApply = () => {
|
|
35
|
+
const cleaned = {};
|
|
36
|
+
for (const [k, v] of Object.entries(draft)) {
|
|
37
|
+
if (v === "" || v === undefined || v === null)
|
|
38
|
+
continue;
|
|
39
|
+
cleaned[k] = v;
|
|
40
|
+
}
|
|
41
|
+
onApply(Object.keys(cleaned).length > 0 ? cleaned : undefined);
|
|
42
|
+
onOpenChange(false);
|
|
43
|
+
};
|
|
44
|
+
return (_jsx(Sheet, { open: open, onOpenChange: onOpenChange, children: _jsxs(SheetContent, { className: "w-[400px] sm:max-w-md", children: [_jsxs(SheetHeader, { children: [_jsx(SheetTitle, { children: L.title }), _jsxs(SheetDescription, { children: [_jsx("span", { className: "bg-muted rounded px-1 font-mono text-xs", children: widgetId }), " \u2014", " ", L.description] })] }), _jsx("div", { className: "flex flex-col gap-4 px-4 py-4", children: propEntries.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-sm", children: L.noProps })) : (propEntries.map(([key, prop]) => (_jsx(PropertyField, { name: key, prop: prop, value: draft[key], unsetLabel: L.unsetOption, onChange: (v) => setDraft((prev) => {
|
|
45
|
+
if (v === undefined) {
|
|
46
|
+
const rest = {};
|
|
47
|
+
for (const [k, val] of Object.entries(prev)) {
|
|
48
|
+
if (k !== key)
|
|
49
|
+
rest[k] = val;
|
|
50
|
+
}
|
|
51
|
+
return rest;
|
|
52
|
+
}
|
|
53
|
+
return { ...prev, [key]: v };
|
|
54
|
+
}) }, key)))) }), _jsxs("div", { className: "flex items-center justify-end gap-2 border-t px-4 py-3", children: [_jsx(Button, { variant: "ghost", onClick: () => setDraft({}), children: L.reset }), _jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: L.cancel }), _jsx(Button, { onClick: handleApply, children: L.apply })] })] }) }));
|
|
55
|
+
}
|
|
56
|
+
function PropertyField({ name, prop, value, unsetLabel, onChange, }) {
|
|
57
|
+
const id = `prop-${name}`;
|
|
58
|
+
if (prop.type === "string" && Array.isArray(prop.enum)) {
|
|
59
|
+
const options = prop.enum.filter((v) => typeof v === "string");
|
|
60
|
+
const current = typeof value === "string" && value !== "" ? value : UNSET_SENTINEL;
|
|
61
|
+
return (_jsx(FieldShell, { id: id, name: name, description: prop.description, children: _jsxs(Select, { value: current, onValueChange: (v) => onChange(v === UNSET_SENTINEL ? undefined : v), children: [_jsx(SelectTrigger, { id: id, children: _jsx(SelectValue, { placeholder: unsetLabel }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: UNSET_SENTINEL, children: unsetLabel }), options.map((opt) => (_jsx(SelectItem, { value: opt, children: opt }, opt)))] })] }) }));
|
|
62
|
+
}
|
|
63
|
+
if (prop.type === "string") {
|
|
64
|
+
const current = typeof value === "string" ? value : "";
|
|
65
|
+
return (_jsx(FieldShell, { id: id, name: name, description: prop.description, children: _jsx(Input, { id: id, value: current, onChange: (e) => onChange(e.target.value === "" ? undefined : e.target.value) }) }));
|
|
66
|
+
}
|
|
67
|
+
if (prop.type === "number" || prop.type === "integer") {
|
|
68
|
+
const current = typeof value === "number" ? String(value) : "";
|
|
69
|
+
return (_jsx(FieldShell, { id: id, name: name, description: prop.description, children: _jsx(Input, { id: id, type: "number", value: current, onChange: (e) => {
|
|
70
|
+
const raw = e.target.value;
|
|
71
|
+
if (raw === "")
|
|
72
|
+
return onChange(undefined);
|
|
73
|
+
const parsed = prop.type === "integer" ? Number.parseInt(raw, 10) : Number.parseFloat(raw);
|
|
74
|
+
if (Number.isFinite(parsed))
|
|
75
|
+
onChange(parsed);
|
|
76
|
+
} }) }));
|
|
77
|
+
}
|
|
78
|
+
if (prop.type === "boolean") {
|
|
79
|
+
const current = value === true;
|
|
80
|
+
return (_jsx(FieldShell, { id: id, name: name, description: prop.description, children: _jsx(Switch, { id: id, checked: current, onCheckedChange: (checked) => onChange(checked || undefined) }) }));
|
|
81
|
+
}
|
|
82
|
+
return (_jsx(FieldShell, { id: id, name: name, description: prop.description, children: _jsxs("p", { className: "text-muted-foreground text-xs italic", children: ["Unsupported type \"", prop.type ?? "(none)", "\" \u2014 edit raw JSON to set this field."] }) }));
|
|
83
|
+
}
|
|
84
|
+
function FieldShell({ id, name, description, children, }) {
|
|
85
|
+
return (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx("label", { htmlFor: id, className: "text-sm font-medium", children: name }), children, description ? _jsx("p", { className: "text-muted-foreground text-xs", children: description }) : null] }));
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=widget-props-sheet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widget-props-sheet.js","sourceRoot":"","sources":["../../src/app/widget-props-sheet.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAkB,MAAM,OAAO,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAC9C,OAAO,EACL,MAAM,EACN,aAAa,EACb,UAAU,EACV,aAAa,EACb,WAAW,GACZ,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,KAAK,EACL,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,UAAU,GACX,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AA2ChD,MAAM,cAAc,GAAqC;IACvD,KAAK,EAAE,kBAAkB;IACzB,WAAW,EAAE,yCAAyC;IACtD,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,0CAA0C;IACnD,WAAW,EAAE,SAAS;CACvB,CAAA;AAED,MAAM,cAAc,GAAG,WAAW,CAAA;AAYlC,MAAM,UAAU,gBAAgB,CAAC,EAC/B,IAAI,EACJ,YAAY,EACZ,QAAQ,EACR,MAAM,EACN,KAAK,EACL,OAAO,EACP,MAAM,GACgB;IACtB,MAAM,CAAC,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,MAAM,EAAE,CAAA;IAC1C,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,EAAE,CAAqB,CAAA;IAC9C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAA0B,KAAK,IAAI,EAAE,CAAC,CAAA;IAExE,qEAAqE;IACrE,sEAAsE;IACtE,sEAAsE;IACtE,gEAAgE;IAChE,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC9C,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,WAAW,CAAC,IAAI,CAAC,CAAA;QACjB,IAAI,IAAI;YAAE,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,CAAA;IACjC,CAAC;IAED,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,IAAI,EAAE,CAAA;IACvC,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IAE9C,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,MAAM,OAAO,GAA4B,EAAE,CAAA;QAC3C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI;gBAAE,SAAQ;YACvD,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QAChB,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;QAC9D,YAAY,CAAC,KAAK,CAAC,CAAA;IACrB,CAAC,CAAA;IAED,OAAO,CACL,KAAC,KAAK,IAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,YAC3C,MAAC,YAAY,IAAC,SAAS,EAAC,uBAAuB,aAC7C,MAAC,WAAW,eACV,KAAC,UAAU,cAAE,CAAC,CAAC,KAAK,GAAc,EAClC,MAAC,gBAAgB,eACf,eAAM,SAAS,EAAC,yCAAyC,YAAE,QAAQ,GAAQ,aAAG,GAAG,EAChF,CAAC,CAAC,WAAW,IACG,IACP,EACd,cAAK,SAAS,EAAC,+BAA+B,YAC3C,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAC1B,YAAG,SAAS,EAAC,+BAA+B,YAAE,CAAC,CAAC,OAAO,GAAK,CAC7D,CAAC,CAAC,CAAC,CACF,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAC/B,KAAC,aAAa,IAEZ,IAAI,EAAE,GAAG,EACT,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,UAAU,EAAE,CAAC,CAAC,WAAW,EACzB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CACd,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE;4BAChB,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;gCACpB,MAAM,IAAI,GAA4B,EAAE,CAAA;gCACxC,KAAK,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;oCAC5C,IAAI,CAAC,KAAK,GAAG;wCAAE,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAA;gCAC9B,CAAC;gCACD,OAAO,IAAI,CAAA;4BACb,CAAC;4BACD,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAA;wBAC9B,CAAC,CAAC,IAfC,GAAG,CAiBR,CACH,CAAC,CACH,GACG,EACN,eAAK,SAAS,EAAC,wDAAwD,aACrE,KAAC,MAAM,IAAC,OAAO,EAAC,OAAO,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,YAChD,CAAC,CAAC,KAAK,GACD,EACT,KAAC,MAAM,IAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,YACzD,CAAC,CAAC,MAAM,GACF,EACT,KAAC,MAAM,IAAC,OAAO,EAAE,WAAW,YAAG,CAAC,CAAC,KAAK,GAAU,IAC5C,IACO,GACT,CACT,CAAA;AACH,CAAC;AAED,SAAS,aAAa,CAAC,EACrB,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,UAAU,EACV,QAAQ,GAOT;IACC,MAAM,EAAE,GAAG,QAAQ,IAAI,EAAE,CAAA;IAEzB,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACvD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAA;QAC3E,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAA;QAClF,OAAO,CACL,KAAC,UAAU,IAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,YAC3D,MAAC,MAAM,IACL,KAAK,EAAE,OAAO,EACd,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,aAEpE,KAAC,aAAa,IAAC,EAAE,EAAE,EAAE,YACnB,KAAC,WAAW,IAAC,WAAW,EAAE,UAAU,GAAI,GAC1B,EAChB,MAAC,aAAa,eACZ,KAAC,UAAU,IAAC,KAAK,EAAE,cAAc,YAAG,UAAU,GAAc,EAC3D,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACpB,KAAC,UAAU,IAAW,KAAK,EAAE,GAAG,YAC7B,GAAG,IADW,GAAG,CAEP,CACd,CAAC,IACY,IACT,GACE,CACd,CAAA;IACH,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;QACtD,OAAO,CACL,KAAC,UAAU,IAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,YAC3D,KAAC,KAAK,IACJ,EAAE,EAAE,EAAE,EACN,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAC7E,GACS,CACd,CAAA;IACH,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACtD,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAC9D,OAAO,CACL,KAAC,UAAU,IAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,YAC3D,KAAC,KAAK,IACJ,EAAE,EAAE,EAAE,EACN,IAAI,EAAC,QAAQ,EACb,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;oBACd,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAA;oBAC1B,IAAI,GAAG,KAAK,EAAE;wBAAE,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAA;oBAC1C,MAAM,MAAM,GACV,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;oBAC7E,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;wBAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;gBAC/C,CAAC,GACD,GACS,CACd,CAAA;IACH,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,KAAK,KAAK,IAAI,CAAA;QAC9B,OAAO,CACL,KAAC,UAAU,IAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,YAC3D,KAAC,MAAM,IACL,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,OAAO,EAChB,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,IAAI,SAAS,CAAC,GAC5D,GACS,CACd,CAAA;IACH,CAAC;IAED,OAAO,CACL,KAAC,UAAU,IAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,YAC3D,aAAG,SAAS,EAAC,sCAAsC,oCAC9B,IAAI,CAAC,IAAI,IAAI,QAAQ,kDACtC,GACO,CACd,CAAA;AACH,CAAC;AAED,SAAS,UAAU,CAAC,EAClB,EAAE,EACF,IAAI,EACJ,WAAW,EACX,QAAQ,GAMT;IACC,OAAO,CACL,eAAK,SAAS,EAAC,uBAAuB,aACpC,gBAAO,OAAO,EAAE,EAAE,EAAE,SAAS,EAAC,qBAAqB,YAChD,IAAI,GACC,EACP,QAAQ,EACR,WAAW,CAAC,CAAC,CAAC,YAAG,SAAS,EAAC,+BAA+B,YAAE,WAAW,GAAK,CAAC,CAAC,CAAC,IAAI,IAChF,CACP,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Component, type ComponentType, type ReactNode, type ErrorInfo } from "react";
|
|
2
|
+
import type { LayoutConfig, PipelineContext, WidgetProps } from "@miragon/mcp-toolkit-core";
|
|
3
|
+
export type WidgetComponent = ComponentType<WidgetProps>;
|
|
4
|
+
/**
|
|
5
|
+
* Catches render-time crashes from a single widget so one broken widget
|
|
6
|
+
* can't take down the entire iframe view (or the builder canvas/preview).
|
|
7
|
+
*
|
|
8
|
+
* Exported so the visual builder's canvas + preview render sites reuse the
|
|
9
|
+
* same isolation the rendered `WidgetRenderer` already had — every place a
|
|
10
|
+
* widget component is rendered goes through {@link RenderedWidget}, which
|
|
11
|
+
* wraps the component in this boundary.
|
|
12
|
+
*/
|
|
13
|
+
export declare class WidgetErrorBoundary extends Component<{
|
|
14
|
+
widgetId: string;
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
}, {
|
|
17
|
+
error: Error | null;
|
|
18
|
+
}> {
|
|
19
|
+
state: {
|
|
20
|
+
error: Error | null;
|
|
21
|
+
};
|
|
22
|
+
static getDerivedStateFromError(error: Error): {
|
|
23
|
+
error: Error;
|
|
24
|
+
};
|
|
25
|
+
componentDidCatch(error: Error, info: ErrorInfo): void;
|
|
26
|
+
render(): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* True when the pipeline context carries no widget data at all — no step
|
|
30
|
+
* results and no keys. A widget rendered against an empty context typically
|
|
31
|
+
* paints an empty shell (Finding [4]); callers use this to swap in a
|
|
32
|
+
* "data appears after refresh" hint instead.
|
|
33
|
+
*
|
|
34
|
+
* Intentionally coarse (per-view, not per-widget): the toolkit can't know
|
|
35
|
+
* which slice each widget reads without running its adapter, so it only
|
|
36
|
+
* degrades when there is provably nothing for any widget to show.
|
|
37
|
+
*/
|
|
38
|
+
export declare function contextHasNoData(context: PipelineContext): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* The single render site for a layout cell's widget, shared across the
|
|
41
|
+
* rendered view (`RowsRenderer`), the builder canvas, and the builder
|
|
42
|
+
* preview so all three isolate crashes identically:
|
|
43
|
+
* - missing component → "not bundled" fallback,
|
|
44
|
+
* - render crash → caught by {@link WidgetErrorBoundary} (Finding [1]),
|
|
45
|
+
* - (builder only, opt-in) empty pipeline context → a dezent
|
|
46
|
+
* "no data yet" hint (Finding [4]).
|
|
47
|
+
*
|
|
48
|
+
* The empty-state hint is gated behind `showEmptyHint` and defaults off so
|
|
49
|
+
* the shipped rendered view is unchanged: self-fetching control widgets
|
|
50
|
+
* there render correctly against an empty key-only context. The builder's
|
|
51
|
+
* canvas/preview opt in because their live context is empty until the first
|
|
52
|
+
* catalogue refresh resolves, and an empty widget shell reads as broken.
|
|
53
|
+
*
|
|
54
|
+
* `notBundledClassName` lets each surface match its own chrome (the builder
|
|
55
|
+
* uses denser padding/text than the rendered view).
|
|
56
|
+
*/
|
|
57
|
+
export declare function RenderedWidget({ widget: Widget, widgetId, props, cellProps, showEmptyHint, notBundledClassName, }: {
|
|
58
|
+
widget: WidgetComponent | undefined;
|
|
59
|
+
widgetId: string;
|
|
60
|
+
props: WidgetProps;
|
|
61
|
+
cellProps?: Record<string, unknown>;
|
|
62
|
+
showEmptyHint?: boolean;
|
|
63
|
+
notBundledClassName?: string;
|
|
64
|
+
}): import("react").JSX.Element;
|
|
65
|
+
export interface WidgetRendererProps {
|
|
66
|
+
layout: LayoutConfig;
|
|
67
|
+
keys: Record<string, unknown>;
|
|
68
|
+
stepData?: Record<string, {
|
|
69
|
+
data: unknown;
|
|
70
|
+
keys: Record<string, unknown>;
|
|
71
|
+
_app: string;
|
|
72
|
+
_dataType: string;
|
|
73
|
+
}>;
|
|
74
|
+
errors: {
|
|
75
|
+
stepId: string;
|
|
76
|
+
reason: string;
|
|
77
|
+
}[];
|
|
78
|
+
/**
|
|
79
|
+
* Map of widget ID to React component. Consumers provide this so that the
|
|
80
|
+
* renderer can dispatch layout entries like `{widget: "camunda7:incident-panel"}`
|
|
81
|
+
* to the concrete component. The map is usually aggregated from each module's
|
|
82
|
+
* widget exports at the consumer's `main.tsx` entry point.
|
|
83
|
+
*/
|
|
84
|
+
widgets: Record<string, WidgetComponent>;
|
|
85
|
+
}
|
|
86
|
+
export declare function WidgetRenderer({ layout, keys, stepData, errors, widgets }: WidgetRendererProps): import("react").JSX.Element;
|
|
87
|
+
//# sourceMappingURL=widget-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widget-renderer.d.ts","sourceRoot":"","sources":["../../src/app/widget-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAU,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAMnG,MAAM,MAAM,eAAe,GAAG,aAAa,CAAC,WAAW,CAAC,CAAA;AAExD;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,SAAQ,SAAS,CAChD;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,EACzC;IAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CAAE,CACxB;IACU,KAAK,EAAE;QAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;KAAE,CAAkB;IACzD,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK;;;IAGnC,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS;IAG/C,MAAM;CAYhB;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAElE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EAAE,MAAM,EACd,QAAQ,EACR,KAAK,EACL,SAAS,EACT,aAAqB,EACrB,mBAAkG,GACnG,EAAE;IACD,MAAM,EAAE,eAAe,GAAG,SAAS,CAAA;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,WAAW,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACnC,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,+BAgBA;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,YAAY,CAAA;IACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,QAAQ,CAAC,EAAE,MAAM,CACf,MAAM,EACN;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAClF,CAAA;IACD,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC5C;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;CACzC;AA0CD,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,mBAAmB,+BAmC9F"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Component } from "react";
|
|
3
|
+
import { normalizeLayout } from "@miragon/mcp-toolkit-core";
|
|
4
|
+
import { GridLayout, GridItem } from "../components/GridLayout.js";
|
|
5
|
+
import { Card, CardContent } from "../primitives/card.js";
|
|
6
|
+
import { Tabs, TabsList, TabsTrigger, TabsContent } from "../primitives/tabs.js";
|
|
7
|
+
/**
|
|
8
|
+
* Catches render-time crashes from a single widget so one broken widget
|
|
9
|
+
* can't take down the entire iframe view (or the builder canvas/preview).
|
|
10
|
+
*
|
|
11
|
+
* Exported so the visual builder's canvas + preview render sites reuse the
|
|
12
|
+
* same isolation the rendered `WidgetRenderer` already had — every place a
|
|
13
|
+
* widget component is rendered goes through {@link RenderedWidget}, which
|
|
14
|
+
* wraps the component in this boundary.
|
|
15
|
+
*/
|
|
16
|
+
export class WidgetErrorBoundary extends Component {
|
|
17
|
+
state = { error: null };
|
|
18
|
+
static getDerivedStateFromError(error) {
|
|
19
|
+
return { error };
|
|
20
|
+
}
|
|
21
|
+
componentDidCatch(error, info) {
|
|
22
|
+
console.error(`Widget ${this.props.widgetId} crashed:`, error, info);
|
|
23
|
+
}
|
|
24
|
+
render() {
|
|
25
|
+
if (this.state.error) {
|
|
26
|
+
return (_jsx(Card, { children: _jsxs(CardContent, { className: "text-muted-foreground py-3 text-sm", children: ["Widget \"", this.props.widgetId, "\" failed to render."] }) }));
|
|
27
|
+
}
|
|
28
|
+
return this.props.children;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* True when the pipeline context carries no widget data at all — no step
|
|
33
|
+
* results and no keys. A widget rendered against an empty context typically
|
|
34
|
+
* paints an empty shell (Finding [4]); callers use this to swap in a
|
|
35
|
+
* "data appears after refresh" hint instead.
|
|
36
|
+
*
|
|
37
|
+
* Intentionally coarse (per-view, not per-widget): the toolkit can't know
|
|
38
|
+
* which slice each widget reads without running its adapter, so it only
|
|
39
|
+
* degrades when there is provably nothing for any widget to show.
|
|
40
|
+
*/
|
|
41
|
+
export function contextHasNoData(context) {
|
|
42
|
+
return Object.keys(context.steps).length === 0 && Object.keys(context.keys).length === 0;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The single render site for a layout cell's widget, shared across the
|
|
46
|
+
* rendered view (`RowsRenderer`), the builder canvas, and the builder
|
|
47
|
+
* preview so all three isolate crashes identically:
|
|
48
|
+
* - missing component → "not bundled" fallback,
|
|
49
|
+
* - render crash → caught by {@link WidgetErrorBoundary} (Finding [1]),
|
|
50
|
+
* - (builder only, opt-in) empty pipeline context → a dezent
|
|
51
|
+
* "no data yet" hint (Finding [4]).
|
|
52
|
+
*
|
|
53
|
+
* The empty-state hint is gated behind `showEmptyHint` and defaults off so
|
|
54
|
+
* the shipped rendered view is unchanged: self-fetching control widgets
|
|
55
|
+
* there render correctly against an empty key-only context. The builder's
|
|
56
|
+
* canvas/preview opt in because their live context is empty until the first
|
|
57
|
+
* catalogue refresh resolves, and an empty widget shell reads as broken.
|
|
58
|
+
*
|
|
59
|
+
* `notBundledClassName` lets each surface match its own chrome (the builder
|
|
60
|
+
* uses denser padding/text than the rendered view).
|
|
61
|
+
*/
|
|
62
|
+
export function RenderedWidget({ widget: Widget, widgetId, props, cellProps, showEmptyHint = false, notBundledClassName = "text-muted-foreground rounded border border-dashed p-4 text-center text-xs", }) {
|
|
63
|
+
if (!Widget) {
|
|
64
|
+
return _jsxs("div", { className: notBundledClassName, children: ["Widget \"", widgetId, "\" not bundled."] });
|
|
65
|
+
}
|
|
66
|
+
if (showEmptyHint && contextHasNoData(props.context)) {
|
|
67
|
+
return (_jsx("div", { className: notBundledClassName, children: "No data for this widget yet \u2014 it appears after a refresh." }));
|
|
68
|
+
}
|
|
69
|
+
return (_jsx(WidgetErrorBoundary, { widgetId: widgetId, children: _jsx(Widget, { ...props, widgetProps: cellProps }) }));
|
|
70
|
+
}
|
|
71
|
+
function RowsRenderer({ rows, props, widgets, }) {
|
|
72
|
+
return (_jsx("div", { className: "flex flex-col gap-4", children: rows.map((row, rowIdx) => (_jsx(GridLayout, { children: row.row.map((cell, cellIdx) => {
|
|
73
|
+
const WidgetComponent = widgets[cell.widget];
|
|
74
|
+
// Keep the rendered view's original behaviour of skipping cells
|
|
75
|
+
// whose component isn't bundled (no placeholder in the shipped
|
|
76
|
+
// view), while still routing the resolvable ones through the
|
|
77
|
+
// shared `RenderedWidget` for error-boundary + empty-state.
|
|
78
|
+
if (!WidgetComponent)
|
|
79
|
+
return null;
|
|
80
|
+
// Use a composite key so the same widget can appear in multiple
|
|
81
|
+
// cells of one row (e.g. side-by-side scoped dashboards) without
|
|
82
|
+
// colliding on React's reconciliation key.
|
|
83
|
+
return (_jsx(GridItem, { span: cell.span ?? 12, children: _jsx(RenderedWidget, { widget: WidgetComponent, widgetId: cell.widget, props: props, cellProps: cell.props }) }, `${cell.widget}-${cellIdx}`));
|
|
84
|
+
}) }, rowIdx))) }));
|
|
85
|
+
}
|
|
86
|
+
export function WidgetRenderer({ layout, keys, stepData, errors, widgets }) {
|
|
87
|
+
const steps = {};
|
|
88
|
+
if (stepData) {
|
|
89
|
+
for (const [id, result] of Object.entries(stepData)) {
|
|
90
|
+
steps[id] = { ...result, _step: id };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const pipelineContext = {
|
|
94
|
+
steps,
|
|
95
|
+
keys,
|
|
96
|
+
errors,
|
|
97
|
+
};
|
|
98
|
+
const widgetProps = { keys, context: pipelineContext };
|
|
99
|
+
const normalized = normalizeLayout(layout);
|
|
100
|
+
if ("tabs" in normalized) {
|
|
101
|
+
return (_jsxs(Tabs, { defaultValue: normalized.tabs[0]?.label, children: [_jsx(TabsList, { children: normalized.tabs.map((tab) => (_jsx(TabsTrigger, { value: tab.label, children: tab.label }, tab.label))) }), normalized.tabs.map((tab) => (_jsx(TabsContent, { value: tab.label, children: _jsx(RowsRenderer, { rows: tab.rows, props: widgetProps, widgets: widgets }) }, tab.label)))] }));
|
|
102
|
+
}
|
|
103
|
+
return _jsx(RowsRenderer, { rows: normalized.rows, props: widgetProps, widgets: widgets });
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=widget-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widget-renderer.js","sourceRoot":"","sources":["../../src/app/widget-renderer.tsx"],"names":[],"mappings":"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"}
|