@miragon/mcp-toolkit-ui 1.0.1 → 1.2.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.
Files changed (82) hide show
  1. package/README.md +1 -1
  2. package/dist/app/builder/BuilderBanners.d.ts +19 -0
  3. package/dist/app/builder/BuilderBanners.d.ts.map +1 -0
  4. package/dist/app/builder/BuilderBanners.js +22 -0
  5. package/dist/app/builder/BuilderBanners.js.map +1 -0
  6. package/dist/app/builder/CanvasRow.d.ts +26 -0
  7. package/dist/app/builder/CanvasRow.d.ts.map +1 -0
  8. package/dist/app/builder/CanvasRow.js +98 -0
  9. package/dist/app/builder/CanvasRow.js.map +1 -0
  10. package/dist/app/builder/CellPropsSheet.d.ts +19 -0
  11. package/dist/app/builder/CellPropsSheet.d.ts.map +1 -0
  12. package/dist/app/builder/CellPropsSheet.js +28 -0
  13. package/dist/app/builder/CellPropsSheet.js.map +1 -0
  14. package/dist/app/builder/EmptyHint.d.ts +6 -0
  15. package/dist/app/builder/EmptyHint.d.ts.map +1 -0
  16. package/dist/app/builder/EmptyHint.js +10 -0
  17. package/dist/app/builder/EmptyHint.js.map +1 -0
  18. package/dist/app/builder/LayoutSurface.d.ts +27 -0
  19. package/dist/app/builder/LayoutSurface.d.ts.map +1 -0
  20. package/dist/app/builder/LayoutSurface.js +45 -0
  21. package/dist/app/builder/LayoutSurface.js.map +1 -0
  22. package/dist/app/builder/Workspace.d.ts +9 -3
  23. package/dist/app/builder/Workspace.d.ts.map +1 -1
  24. package/dist/app/builder/Workspace.js +3 -97
  25. package/dist/app/builder/Workspace.js.map +1 -1
  26. package/dist/app/builder/builder-reducer.d.ts.map +1 -1
  27. package/dist/app/builder/builder-reducer.js +176 -164
  28. package/dist/app/builder/builder-reducer.js.map +1 -1
  29. package/dist/app/builder/use-builder-catalogue.d.ts +33 -0
  30. package/dist/app/builder/use-builder-catalogue.d.ts.map +1 -0
  31. package/dist/app/builder/use-builder-catalogue.js +155 -0
  32. package/dist/app/builder/use-builder-catalogue.js.map +1 -0
  33. package/dist/app/builder/use-key-step-entries.d.ts +22 -0
  34. package/dist/app/builder/use-key-step-entries.d.ts.map +1 -0
  35. package/dist/app/builder/use-key-step-entries.js +46 -0
  36. package/dist/app/builder/use-key-step-entries.js.map +1 -0
  37. package/dist/app/builder/use-save-dashboard.d.ts +33 -0
  38. package/dist/app/builder/use-save-dashboard.d.ts.map +1 -0
  39. package/dist/app/builder/use-save-dashboard.js +78 -0
  40. package/dist/app/builder/use-save-dashboard.js.map +1 -0
  41. package/dist/app/host-bridge.d.ts +4 -4
  42. package/dist/app/host-bridge.js +2 -2
  43. package/dist/app/layout-builder.d.ts.map +1 -1
  44. package/dist/app/layout-builder.js +46 -277
  45. package/dist/app/layout-builder.js.map +1 -1
  46. package/dist/app/mcp-app-view-chrome.d.ts +77 -0
  47. package/dist/app/mcp-app-view-chrome.d.ts.map +1 -0
  48. package/dist/app/mcp-app-view-chrome.js +53 -0
  49. package/dist/app/mcp-app-view-chrome.js.map +1 -0
  50. package/dist/app/mcp-app-view.d.ts +3 -9
  51. package/dist/app/mcp-app-view.d.ts.map +1 -1
  52. package/dist/app/mcp-app-view.js +4 -31
  53. package/dist/app/mcp-app-view.js.map +1 -1
  54. package/dist/render-cases-primitives.d.ts +17 -0
  55. package/dist/render-cases-primitives.d.ts.map +1 -0
  56. package/dist/render-cases-primitives.js +88 -0
  57. package/dist/render-cases-primitives.js.map +1 -0
  58. package/dist/render-cases.d.ts +4 -0
  59. package/dist/render-cases.d.ts.map +1 -0
  60. package/dist/render-cases.js +140 -0
  61. package/dist/render-cases.js.map +1 -0
  62. package/package.json +12 -7
  63. package/src/app/builder/BuilderBanners.tsx +61 -0
  64. package/src/app/builder/CanvasRow.tsx +316 -0
  65. package/src/app/builder/CellPropsSheet.tsx +47 -0
  66. package/src/app/builder/EmptyHint.tsx +29 -0
  67. package/src/app/builder/LayoutSurface.tsx +140 -0
  68. package/src/app/builder/Workspace.tsx +33 -342
  69. package/src/app/builder/builder-reducer.ts +204 -170
  70. package/src/app/builder/use-builder-catalogue.ts +187 -0
  71. package/src/app/builder/use-key-step-entries.ts +60 -0
  72. package/src/app/builder/use-save-dashboard.ts +97 -0
  73. package/src/app/host-bridge.tsx +4 -4
  74. package/src/app/layout-builder.tsx +92 -497
  75. package/src/app/mcp-app-view-chrome.tsx +204 -0
  76. package/src/app/mcp-app-view.tsx +32 -140
  77. package/src/lib/parse-tool-result.property.test.ts +90 -0
  78. package/src/render-cases-primitives.tsx +255 -0
  79. package/src/render-cases.tsx +239 -0
  80. package/src/render-smoke.test.tsx +100 -0
  81. package/src/ui-catalog.test.ts +52 -0
  82. package/ui-catalog.json +1 -1
@@ -0,0 +1,97 @@
1
+ import { useCallback, useState } from "react"
2
+ import type { PipelineStepRef } from "@miragon/mcp-toolkit-core"
3
+ import { parseToolResult } from "../../lib/parse-tool-result.js"
4
+ import { draftToLayout, entriesToKeys, type DraftLayout, type KeyEntry } from "./builder-model.js"
5
+
6
+ // -------------------------------------------------------------------------- //
7
+ // Save-dashboard hook — dialog state + the `save-dashboard` call
8
+ // -------------------------------------------------------------------------- //
9
+
10
+ /**
11
+ * Owns the save dialog's state (open flag, name/description inputs, busy
12
+ * flag, inline error) and the `save-dashboard` call. Extracted from
13
+ * `layout-builder.tsx` unchanged: a rejected save surfaces its reason
14
+ * inline in the SaveDialog instead of failing silently (Finding [3]).
15
+ */
16
+ export function useSaveDashboard({
17
+ callTool,
18
+ saveToolName,
19
+ dashboardId,
20
+ title,
21
+ keyEntries,
22
+ stepEntries,
23
+ draft,
24
+ onSaved,
25
+ }: {
26
+ callTool: (name: string, args: object) => Promise<unknown>
27
+ saveToolName: string
28
+ dashboardId?: string
29
+ title?: string
30
+ keyEntries: KeyEntry[]
31
+ stepEntries: PipelineStepRef[]
32
+ draft: DraftLayout
33
+ onSaved?: (result: { id: string; name: string }) => void
34
+ }) {
35
+ const [isBusy, setBusy] = useState(false)
36
+ const [saveOpen, setSaveOpen] = useState(false)
37
+ const [saveName, setSaveName] = useState(title ?? "")
38
+ const [saveDescription, setSaveDescription] = useState("")
39
+ // Last save failure (Finding [3]). Shown inline in the SaveDialog so a
40
+ // rejected `save-dashboard` call no longer fails silently.
41
+ const [saveError, setSaveError] = useState<string | null>(null)
42
+
43
+ const saveDraft = useCallback(async () => {
44
+ if (!saveName.trim()) return
45
+ setBusy(true)
46
+ setSaveError(null)
47
+ try {
48
+ const result = await callTool(saveToolName, {
49
+ id: dashboardId,
50
+ name: saveName.trim(),
51
+ description: saveDescription.trim() || undefined,
52
+ keys: entriesToKeys(keyEntries),
53
+ steps: stepEntries.filter((s) => s.step.trim().length > 0),
54
+ layout: draftToLayout(draft),
55
+ title,
56
+ })
57
+ const saved = parseToolResult<{ id?: string; name?: string } | null>(result)
58
+ setSaveOpen(false)
59
+ if (saved?.id && onSaved) {
60
+ onSaved({
61
+ id: saved.id,
62
+ name: saved.name ?? saveName.trim(),
63
+ })
64
+ }
65
+ } catch (err) {
66
+ // Previously uncaught: a rejected `save-dashboard` left the dialog open
67
+ // with no feedback. Surface the reason inline (Finding [3]).
68
+ setSaveError(err instanceof Error ? err.message : String(err))
69
+ } finally {
70
+ setBusy(false)
71
+ }
72
+ }, [
73
+ callTool,
74
+ dashboardId,
75
+ draft,
76
+ keyEntries,
77
+ onSaved,
78
+ saveDescription,
79
+ saveName,
80
+ saveToolName,
81
+ stepEntries,
82
+ title,
83
+ ])
84
+
85
+ return {
86
+ isBusy,
87
+ saveOpen,
88
+ setSaveOpen,
89
+ saveName,
90
+ setSaveName,
91
+ saveDescription,
92
+ setSaveDescription,
93
+ saveError,
94
+ setSaveError,
95
+ saveDraft,
96
+ }
97
+ }
@@ -5,7 +5,7 @@ import { createContext, useContext, type ReactNode } from "react"
5
5
  * host runtime. A `HostBridge` is the single seam a portable widget talks to:
6
6
  * write the widget against {@link useHostBridge} and it runs unchanged in our
7
7
  * own `mcp-use` host, inside ChatGPT (OpenAI Apps SDK), or as a standalone web
8
- * app driven directly by a `@modelcontextprotocol/sdk` client — only the
8
+ * app driven directly by a `@modelcontextprotocol/client` client — only the
9
9
  * surrounding adapter changes.
10
10
  *
11
11
  * This is deliberately the *minimum* a deterministic UI needs, not a mirror of
@@ -288,7 +288,7 @@ export function createChatGptHostBridge(sdk?: OpenAiAppsSdk | null): HostBridge
288
288
  export interface StandaloneHostBridgeOptions {
289
289
  /**
290
290
  * The only required capability: how to call a tool on the server. In a
291
- * standalone web app this typically wraps a `@modelcontextprotocol/sdk`
291
+ * standalone web app this typically wraps a `@modelcontextprotocol/client`
292
292
  * `Client.callTool({ name, arguments })`, but any function with this shape
293
293
  * works — that injection is the whole point: hand-built widgets render
294
294
  * against *any* existing MCP server without the toolkit's host runtime.
@@ -322,7 +322,7 @@ export interface StandaloneHostBridgeOptions {
322
322
  /**
323
323
  * Build a {@link HostBridge} for a standalone web app driven against an existing
324
324
  * MCP server — no toolkit host, no `createFrameworkApp`. You inject `callTool`
325
- * (usually a thin wrapper over a `@modelcontextprotocol/sdk` client); the
325
+ * (usually a thin wrapper over a `@modelcontextprotocol/client` client); the
326
326
  * conversation-shaped verbs (`sendFollowup`, `setModelContext`) are no-ops
327
327
  * unless you wire handlers, and `openExternal` defaults to `window.open`.
328
328
  *
@@ -332,7 +332,7 @@ export interface StandaloneHostBridgeOptions {
332
332
  * harness also builds on this factory so host simulation has a single source.
333
333
  *
334
334
  * @example
335
- * const client = new Client(…) // @modelcontextprotocol/sdk
335
+ * const client = new Client(…) // @modelcontextprotocol/client
336
336
  * const bridge = createStandaloneHostBridge({
337
337
  * callTool: (name, args) => client.callTool({ name, arguments: args }),
338
338
  * getData: () => currentRecord,