@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.
Files changed (511) hide show
  1. package/README.md +14 -5
  2. package/dist/app/adapt-data-widget.d.ts +1 -22
  3. package/dist/app/adapt-data-widget.d.ts.map +1 -1
  4. package/dist/app/adapt-data-widget.js +1 -35
  5. package/dist/app/adapt-data-widget.js.map +1 -1
  6. package/dist/app/builder/BuilderBanners.d.ts +7 -2
  7. package/dist/app/builder/BuilderBanners.d.ts.map +1 -1
  8. package/dist/app/builder/BuilderBanners.js +8 -3
  9. package/dist/app/builder/BuilderBanners.js.map +1 -1
  10. package/dist/app/builder/CanvasRow.d.ts +4 -2
  11. package/dist/app/builder/CanvasRow.d.ts.map +1 -1
  12. package/dist/app/builder/CanvasRow.js +29 -17
  13. package/dist/app/builder/CanvasRow.js.map +1 -1
  14. package/dist/app/builder/CatalogueSheet.d.ts.map +1 -1
  15. package/dist/app/builder/CatalogueSheet.js +14 -6
  16. package/dist/app/builder/CatalogueSheet.js.map +1 -1
  17. package/dist/app/builder/CellPropsSheet.d.ts +7 -3
  18. package/dist/app/builder/CellPropsSheet.d.ts.map +1 -1
  19. package/dist/app/builder/CellPropsSheet.js +10 -3
  20. package/dist/app/builder/CellPropsSheet.js.map +1 -1
  21. package/dist/app/builder/DiscardDialog.d.ts +18 -0
  22. package/dist/app/builder/DiscardDialog.d.ts.map +1 -0
  23. package/dist/app/builder/DiscardDialog.js +18 -0
  24. package/dist/app/builder/DiscardDialog.js.map +1 -0
  25. package/dist/app/builder/EmptyHint.d.ts +4 -0
  26. package/dist/app/builder/EmptyHint.d.ts.map +1 -1
  27. package/dist/app/builder/EmptyHint.js +6 -1
  28. package/dist/app/builder/EmptyHint.js.map +1 -1
  29. package/dist/app/builder/LayoutSurface.d.ts +33 -9
  30. package/dist/app/builder/LayoutSurface.d.ts.map +1 -1
  31. package/dist/app/builder/LayoutSurface.js +74 -23
  32. package/dist/app/builder/LayoutSurface.js.map +1 -1
  33. package/dist/app/builder/PipelineStrip.d.ts +5 -2
  34. package/dist/app/builder/PipelineStrip.d.ts.map +1 -1
  35. package/dist/app/builder/PipelineStrip.js +33 -15
  36. package/dist/app/builder/PipelineStrip.js.map +1 -1
  37. package/dist/app/builder/SaveDialog.d.ts +9 -1
  38. package/dist/app/builder/SaveDialog.d.ts.map +1 -1
  39. package/dist/app/builder/SaveDialog.js +9 -3
  40. package/dist/app/builder/SaveDialog.js.map +1 -1
  41. package/dist/app/builder/Toolbar.d.ts +14 -4
  42. package/dist/app/builder/Toolbar.d.ts.map +1 -1
  43. package/dist/app/builder/Toolbar.js +24 -7
  44. package/dist/app/builder/Toolbar.js.map +1 -1
  45. package/dist/app/builder/Workspace.d.ts +23 -3
  46. package/dist/app/builder/Workspace.d.ts.map +1 -1
  47. package/dist/app/builder/Workspace.js +58 -8
  48. package/dist/app/builder/Workspace.js.map +1 -1
  49. package/dist/app/builder/builder-model.d.ts +146 -3
  50. package/dist/app/builder/builder-model.d.ts.map +1 -1
  51. package/dist/app/builder/builder-model.js +196 -5
  52. package/dist/app/builder/builder-model.js.map +1 -1
  53. package/dist/app/builder/labels.d.ts +13 -62
  54. package/dist/app/builder/labels.d.ts.map +1 -1
  55. package/dist/app/builder/labels.js +9 -58
  56. package/dist/app/builder/labels.js.map +1 -1
  57. package/dist/app/builder/reveal.d.ts +10 -0
  58. package/dist/app/builder/reveal.d.ts.map +1 -0
  59. package/dist/app/builder/reveal.js +10 -0
  60. package/dist/app/builder/reveal.js.map +1 -0
  61. package/dist/app/builder/status-chip.d.ts.map +1 -1
  62. package/dist/app/builder/status-chip.js +3 -2
  63. package/dist/app/builder/status-chip.js.map +1 -1
  64. package/dist/app/builder/use-builder-catalogue.d.ts +5 -1
  65. package/dist/app/builder/use-builder-catalogue.d.ts.map +1 -1
  66. package/dist/app/builder/use-builder-catalogue.js +50 -17
  67. package/dist/app/builder/use-builder-catalogue.js.map +1 -1
  68. package/dist/app/builder/use-builder-session.d.ts +30 -0
  69. package/dist/app/builder/use-builder-session.d.ts.map +1 -0
  70. package/dist/app/builder/use-builder-session.js +58 -0
  71. package/dist/app/builder/use-builder-session.js.map +1 -0
  72. package/dist/app/builder/use-display-resolver.d.ts +17 -0
  73. package/dist/app/builder/use-display-resolver.d.ts.map +1 -0
  74. package/dist/app/builder/use-display-resolver.js +16 -0
  75. package/dist/app/builder/use-display-resolver.js.map +1 -0
  76. package/dist/app/builder/use-save-dashboard.d.ts +3 -1
  77. package/dist/app/builder/use-save-dashboard.d.ts.map +1 -1
  78. package/dist/app/builder/use-save-dashboard.js +3 -1
  79. package/dist/app/builder/use-save-dashboard.js.map +1 -1
  80. package/dist/app/index.d.ts +8 -3
  81. package/dist/app/index.d.ts.map +1 -1
  82. package/dist/app/index.js +8 -2
  83. package/dist/app/index.js.map +1 -1
  84. package/dist/app/layout-builder.d.ts +18 -25
  85. package/dist/app/layout-builder.d.ts.map +1 -1
  86. package/dist/app/layout-builder.js +84 -78
  87. package/dist/app/layout-builder.js.map +1 -1
  88. package/dist/app/mcp-app-view-chrome.d.ts +103 -20
  89. package/dist/app/mcp-app-view-chrome.d.ts.map +1 -1
  90. package/dist/app/mcp-app-view-chrome.js +125 -40
  91. package/dist/app/mcp-app-view-chrome.js.map +1 -1
  92. package/dist/app/mcp-app-view-states.d.ts +23 -0
  93. package/dist/app/mcp-app-view-states.d.ts.map +1 -0
  94. package/dist/app/mcp-app-view-states.js +55 -0
  95. package/dist/app/mcp-app-view-states.js.map +1 -0
  96. package/dist/app/mcp-app-view.d.ts +72 -5
  97. package/dist/app/mcp-app-view.d.ts.map +1 -1
  98. package/dist/app/mcp-app-view.js +241 -141
  99. package/dist/app/mcp-app-view.js.map +1 -1
  100. package/dist/app/mcp-toolkit-app.d.ts +8 -2
  101. package/dist/app/mcp-toolkit-app.d.ts.map +1 -1
  102. package/dist/app/mcp-toolkit-app.js +33 -4
  103. package/dist/app/mcp-toolkit-app.js.map +1 -1
  104. package/dist/app/mcp-use-host-bridge.d.ts +15 -6
  105. package/dist/app/mcp-use-host-bridge.d.ts.map +1 -1
  106. package/dist/app/mcp-use-host-bridge.js +51 -22
  107. package/dist/app/mcp-use-host-bridge.js.map +1 -1
  108. package/dist/app/model-context.d.ts +71 -0
  109. package/dist/app/model-context.d.ts.map +1 -0
  110. package/dist/app/model-context.js +101 -0
  111. package/dist/app/model-context.js.map +1 -0
  112. package/dist/app/use-build-mode-focus.d.ts +33 -0
  113. package/dist/app/use-build-mode-focus.d.ts.map +1 -0
  114. package/dist/app/use-build-mode-focus.js +59 -0
  115. package/dist/app/use-build-mode-focus.js.map +1 -0
  116. package/dist/app/use-view-actions.d.ts +31 -0
  117. package/dist/app/use-view-actions.d.ts.map +1 -0
  118. package/dist/app/use-view-actions.js +81 -0
  119. package/dist/app/use-view-actions.js.map +1 -0
  120. package/dist/app/use-view-lifecycle.d.ts +42 -0
  121. package/dist/app/use-view-lifecycle.d.ts.map +1 -0
  122. package/dist/app/use-view-lifecycle.js +81 -0
  123. package/dist/app/use-view-lifecycle.js.map +1 -0
  124. package/dist/app/view-lifecycle.d.ts +185 -0
  125. package/dist/app/view-lifecycle.d.ts.map +1 -0
  126. package/dist/app/view-lifecycle.js +207 -0
  127. package/dist/app/view-lifecycle.js.map +1 -0
  128. package/dist/app/widget-fixture.d.ts +10 -3
  129. package/dist/app/widget-fixture.d.ts.map +1 -1
  130. package/dist/app/widget-fixture.js +21 -8
  131. package/dist/app/widget-fixture.js.map +1 -1
  132. package/dist/app/widget-props-sheet.d.ts +6 -10
  133. package/dist/app/widget-props-sheet.d.ts.map +1 -1
  134. package/dist/app/widget-props-sheet.js +25 -20
  135. package/dist/app/widget-props-sheet.js.map +1 -1
  136. package/dist/app/widget-renderer.d.ts +41 -1
  137. package/dist/app/widget-renderer.d.ts.map +1 -1
  138. package/dist/app/widget-renderer.js +82 -31
  139. package/dist/app/widget-renderer.js.map +1 -1
  140. package/dist/components/DrillButton.d.ts +9 -6
  141. package/dist/components/DrillButton.d.ts.map +1 -1
  142. package/dist/components/DrillButton.js +9 -6
  143. package/dist/components/DrillButton.js.map +1 -1
  144. package/dist/components/EmptyState.d.ts +33 -0
  145. package/dist/components/EmptyState.d.ts.map +1 -0
  146. package/dist/components/EmptyState.js +19 -0
  147. package/dist/components/EmptyState.js.map +1 -0
  148. package/dist/components/ErrorState.d.ts +53 -0
  149. package/dist/components/ErrorState.d.ts.map +1 -0
  150. package/dist/components/ErrorState.js +77 -0
  151. package/dist/components/ErrorState.js.map +1 -0
  152. package/dist/components/FilterBar.d.ts +16 -5
  153. package/dist/components/FilterBar.d.ts.map +1 -1
  154. package/dist/components/FilterBar.js +13 -5
  155. package/dist/components/FilterBar.js.map +1 -1
  156. package/dist/components/GroupCard.d.ts.map +1 -1
  157. package/dist/components/GroupCard.js +2 -1
  158. package/dist/components/GroupCard.js.map +1 -1
  159. package/dist/components/KpiGrid.d.ts +70 -18
  160. package/dist/components/KpiGrid.d.ts.map +1 -1
  161. package/dist/components/KpiGrid.js +112 -23
  162. package/dist/components/KpiGrid.js.map +1 -1
  163. package/dist/components/ListFooter.d.ts +32 -4
  164. package/dist/components/ListFooter.d.ts.map +1 -1
  165. package/dist/components/ListFooter.js +35 -6
  166. package/dist/components/ListFooter.js.map +1 -1
  167. package/dist/components/PagedListFooter.d.ts +57 -0
  168. package/dist/components/PagedListFooter.d.ts.map +1 -0
  169. package/dist/components/PagedListFooter.js +27 -0
  170. package/dist/components/PagedListFooter.js.map +1 -0
  171. package/dist/components/Pills.d.ts +36 -12
  172. package/dist/components/Pills.d.ts.map +1 -1
  173. package/dist/components/Pills.js +29 -8
  174. package/dist/components/Pills.js.map +1 -1
  175. package/dist/components/SectionHeading.d.ts +3 -1
  176. package/dist/components/SectionHeading.d.ts.map +1 -1
  177. package/dist/components/SectionHeading.js +6 -2
  178. package/dist/components/SectionHeading.js.map +1 -1
  179. package/dist/components/Toast.d.ts +43 -0
  180. package/dist/components/Toast.d.ts.map +1 -0
  181. package/dist/components/Toast.js +106 -0
  182. package/dist/components/Toast.js.map +1 -0
  183. package/dist/components/WidgetHeader.d.ts +34 -10
  184. package/dist/components/WidgetHeader.d.ts.map +1 -1
  185. package/dist/components/WidgetHeader.js +11 -6
  186. package/dist/components/WidgetHeader.js.map +1 -1
  187. package/dist/hooks/index.d.ts +4 -4
  188. package/dist/hooks/index.d.ts.map +1 -1
  189. package/dist/hooks/index.js +1 -1
  190. package/dist/hooks/index.js.map +1 -1
  191. package/dist/hooks/tool-result-recovery-model.d.ts +155 -0
  192. package/dist/hooks/tool-result-recovery-model.d.ts.map +1 -0
  193. package/dist/hooks/tool-result-recovery-model.js +273 -0
  194. package/dist/hooks/tool-result-recovery-model.js.map +1 -0
  195. package/dist/hooks/use-tool-query.d.ts +56 -14
  196. package/dist/hooks/use-tool-query.d.ts.map +1 -1
  197. package/dist/hooks/use-tool-query.js +102 -25
  198. package/dist/hooks/use-tool-query.js.map +1 -1
  199. package/dist/hooks/use-tool-result-recovery.d.ts +61 -44
  200. package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -1
  201. package/dist/hooks/use-tool-result-recovery.js +62 -110
  202. package/dist/hooks/use-tool-result-recovery.js.map +1 -1
  203. package/dist/hooks/use-view-data.d.ts +55 -7
  204. package/dist/hooks/use-view-data.d.ts.map +1 -1
  205. package/dist/hooks/use-view-data.js +81 -11
  206. package/dist/hooks/use-view-data.js.map +1 -1
  207. package/dist/hooks/use-view-tool-query.d.ts +12 -7
  208. package/dist/hooks/use-view-tool-query.d.ts.map +1 -1
  209. package/dist/hooks/use-view-tool-query.js +15 -14
  210. package/dist/hooks/use-view-tool-query.js.map +1 -1
  211. package/dist/index.d.ts +27 -13
  212. package/dist/index.d.ts.map +1 -1
  213. package/dist/index.js +29 -7
  214. package/dist/index.js.map +1 -1
  215. package/dist/lib/focus-return.d.ts +61 -0
  216. package/dist/lib/focus-return.d.ts.map +1 -0
  217. package/dist/lib/focus-return.js +46 -0
  218. package/dist/lib/focus-return.js.map +1 -0
  219. package/dist/lib/focus-ring.d.ts +18 -0
  220. package/dist/lib/focus-ring.d.ts.map +1 -0
  221. package/dist/lib/focus-ring.js +18 -0
  222. package/dist/lib/focus-ring.js.map +1 -0
  223. package/dist/lib/icon-stroke.d.ts +12 -0
  224. package/dist/lib/icon-stroke.d.ts.map +1 -0
  225. package/dist/lib/icon-stroke.js +12 -0
  226. package/dist/lib/icon-stroke.js.map +1 -0
  227. package/dist/lib/parse-tool-result.d.ts +23 -1
  228. package/dist/lib/parse-tool-result.d.ts.map +1 -1
  229. package/dist/lib/parse-tool-result.js +38 -2
  230. package/dist/lib/parse-tool-result.js.map +1 -1
  231. package/dist/lib/toast-model.d.ts +86 -0
  232. package/dist/lib/toast-model.d.ts.map +1 -0
  233. package/dist/lib/toast-model.js +102 -0
  234. package/dist/lib/toast-model.js.map +1 -0
  235. package/dist/lib/tone-utils.d.ts +95 -9
  236. package/dist/lib/tone-utils.d.ts.map +1 -1
  237. package/dist/lib/tone-utils.js +100 -9
  238. package/dist/lib/tone-utils.js.map +1 -1
  239. package/dist/lib/tool-query.d.ts +107 -0
  240. package/dist/lib/tool-query.d.ts.map +1 -0
  241. package/dist/lib/tool-query.js +182 -0
  242. package/dist/lib/tool-query.js.map +1 -0
  243. package/dist/lib/tool-result-observer.d.ts +108 -0
  244. package/dist/lib/tool-result-observer.d.ts.map +1 -0
  245. package/dist/lib/tool-result-observer.js +158 -0
  246. package/dist/lib/tool-result-observer.js.map +1 -0
  247. package/dist/lib/typography.d.ts +37 -0
  248. package/dist/lib/typography.d.ts.map +1 -0
  249. package/dist/lib/typography.js +41 -0
  250. package/dist/lib/typography.js.map +1 -0
  251. package/dist/lib/utils.d.ts.map +1 -1
  252. package/dist/lib/utils.js +11 -1
  253. package/dist/lib/utils.js.map +1 -1
  254. package/dist/locale/index.d.ts +3 -1
  255. package/dist/locale/index.d.ts.map +1 -1
  256. package/dist/locale/index.js +2 -1
  257. package/dist/locale/index.js.map +1 -1
  258. package/dist/locale/locale-provider.d.ts +42 -1
  259. package/dist/locale/locale-provider.d.ts.map +1 -1
  260. package/dist/locale/locale-provider.js +44 -3
  261. package/dist/locale/locale-provider.js.map +1 -1
  262. package/dist/locale/message-types.d.ts +336 -0
  263. package/dist/locale/message-types.d.ts.map +1 -0
  264. package/dist/locale/message-types.js +7 -0
  265. package/dist/locale/message-types.js.map +1 -0
  266. package/dist/locale/messages-de.d.ts +9 -0
  267. package/dist/locale/messages-de.d.ts.map +1 -0
  268. package/dist/locale/messages-de.js +185 -0
  269. package/dist/locale/messages-de.js.map +1 -0
  270. package/dist/locale/messages-en.d.ts +8 -0
  271. package/dist/locale/messages-en.d.ts.map +1 -0
  272. package/dist/locale/messages-en.js +184 -0
  273. package/dist/locale/messages-en.js.map +1 -0
  274. package/dist/locale/toolkit-messages.d.ts +57 -0
  275. package/dist/locale/toolkit-messages.d.ts.map +1 -0
  276. package/dist/locale/toolkit-messages.js +103 -0
  277. package/dist/locale/toolkit-messages.js.map +1 -0
  278. package/dist/primitives/alert.d.ts +1 -1
  279. package/dist/primitives/alert.d.ts.map +1 -1
  280. package/dist/primitives/alert.js +6 -2
  281. package/dist/primitives/alert.js.map +1 -1
  282. package/dist/primitives/badge.d.ts +1 -1
  283. package/dist/primitives/badge.d.ts.map +1 -1
  284. package/dist/primitives/badge.js +19 -6
  285. package/dist/primitives/badge.js.map +1 -1
  286. package/dist/primitives/button.d.ts +1 -1
  287. package/dist/primitives/button.d.ts.map +1 -1
  288. package/dist/primitives/button.js +12 -8
  289. package/dist/primitives/button.js.map +1 -1
  290. package/dist/primitives/card.js +4 -4
  291. package/dist/primitives/card.js.map +1 -1
  292. package/dist/primitives/dialog.d.ts +7 -3
  293. package/dist/primitives/dialog.d.ts.map +1 -1
  294. package/dist/primitives/dialog.js +22 -8
  295. package/dist/primitives/dialog.js.map +1 -1
  296. package/dist/primitives/input.d.ts.map +1 -1
  297. package/dist/primitives/input.js +4 -1
  298. package/dist/primitives/input.js.map +1 -1
  299. package/dist/primitives/scroll-area.js +1 -1
  300. package/dist/primitives/scroll-area.js.map +1 -1
  301. package/dist/primitives/select.d.ts.map +1 -1
  302. package/dist/primitives/select.js +6 -3
  303. package/dist/primitives/select.js.map +1 -1
  304. package/dist/primitives/sheet.d.ts +3 -1
  305. package/dist/primitives/sheet.d.ts.map +1 -1
  306. package/dist/primitives/sheet.js +17 -7
  307. package/dist/primitives/sheet.js.map +1 -1
  308. package/dist/primitives/skeleton.js +1 -1
  309. package/dist/primitives/skeleton.js.map +1 -1
  310. package/dist/primitives/switch.d.ts.map +1 -1
  311. package/dist/primitives/switch.js +2 -1
  312. package/dist/primitives/switch.js.map +1 -1
  313. package/dist/primitives/tabs.d.ts.map +1 -1
  314. package/dist/primitives/tabs.js +5 -3
  315. package/dist/primitives/tabs.js.map +1 -1
  316. package/dist/providers/query-provider.d.ts +32 -1
  317. package/dist/providers/query-provider.d.ts.map +1 -1
  318. package/dist/providers/query-provider.js +53 -4
  319. package/dist/providers/query-provider.js.map +1 -1
  320. package/dist/render-cases-primitives.js +1 -1
  321. package/dist/render-cases-primitives.js.map +1 -1
  322. package/dist/render-cases.d.ts.map +1 -1
  323. package/dist/render-cases.js +48 -6
  324. package/dist/render-cases.js.map +1 -1
  325. package/dist/render-effects.d.ts +42 -0
  326. package/dist/render-effects.d.ts.map +1 -0
  327. package/dist/render-effects.js +81 -0
  328. package/dist/render-effects.js.map +1 -0
  329. package/dist/render-scan.d.ts +25 -0
  330. package/dist/render-scan.d.ts.map +1 -0
  331. package/dist/render-scan.js +66 -0
  332. package/dist/render-scan.js.map +1 -0
  333. package/dist/theme/cd-tokens.d.ts +66 -0
  334. package/dist/theme/cd-tokens.d.ts.map +1 -0
  335. package/dist/theme/cd-tokens.js +64 -0
  336. package/dist/theme/cd-tokens.js.map +1 -0
  337. package/dist/theme/create-theme.d.ts +214 -39
  338. package/dist/theme/create-theme.d.ts.map +1 -1
  339. package/dist/theme/create-theme.js +204 -13
  340. package/dist/theme/create-theme.js.map +1 -1
  341. package/dist/theme/fonts.d.ts +38 -0
  342. package/dist/theme/fonts.d.ts.map +1 -0
  343. package/dist/theme/fonts.js +56 -0
  344. package/dist/theme/fonts.js.map +1 -0
  345. package/dist/theme/host-fonts.d.ts +39 -0
  346. package/dist/theme/host-fonts.d.ts.map +1 -0
  347. package/dist/theme/host-fonts.js +44 -0
  348. package/dist/theme/host-fonts.js.map +1 -0
  349. package/dist/theme/index.d.ts +8 -1
  350. package/dist/theme/index.d.ts.map +1 -1
  351. package/dist/theme/index.js +5 -1
  352. package/dist/theme/index.js.map +1 -1
  353. package/dist/theme/portal-container.d.ts +16 -0
  354. package/dist/theme/portal-container.d.ts.map +1 -0
  355. package/dist/theme/portal-container.js +19 -0
  356. package/dist/theme/portal-container.js.map +1 -0
  357. package/dist/theme/presets.d.ts +24 -9
  358. package/dist/theme/presets.d.ts.map +1 -1
  359. package/dist/theme/presets.js +44 -11
  360. package/dist/theme/presets.js.map +1 -1
  361. package/dist/theme/theme-provider.d.ts +27 -9
  362. package/dist/theme/theme-provider.d.ts.map +1 -1
  363. package/dist/theme/theme-provider.js +42 -20
  364. package/dist/theme/theme-provider.js.map +1 -1
  365. package/package.json +11 -5
  366. package/src/app/adapt-data-widget.tsx +2 -42
  367. package/src/app/builder/BuilderBanners.tsx +26 -13
  368. package/src/app/builder/CanvasRow.tsx +79 -32
  369. package/src/app/builder/CatalogueSheet.tsx +58 -35
  370. package/src/app/builder/CellPropsSheet.tsx +17 -2
  371. package/src/app/builder/DiscardDialog.tsx +59 -0
  372. package/src/app/builder/EmptyHint.tsx +16 -11
  373. package/src/app/builder/LayoutSurface.tsx +207 -67
  374. package/src/app/builder/PipelineStrip.tsx +265 -156
  375. package/src/app/builder/SaveDialog.tsx +25 -14
  376. package/src/app/builder/Toolbar.tsx +154 -57
  377. package/src/app/builder/Workspace.tsx +226 -56
  378. package/src/app/builder/builder-feedback.test.tsx +75 -0
  379. package/src/app/builder/builder-model.test.ts +5 -0
  380. package/src/app/builder/builder-model.ts +346 -6
  381. package/src/app/builder/builder-model.ux.test.ts +456 -0
  382. package/src/app/builder/builder-ux.test.tsx +844 -0
  383. package/src/app/builder/labels.ts +15 -121
  384. package/src/app/builder/reveal.ts +10 -0
  385. package/src/app/builder/status-chip.tsx +8 -4
  386. package/src/app/builder/use-builder-catalogue.ts +62 -19
  387. package/src/app/builder/use-builder-session.ts +68 -0
  388. package/src/app/builder/use-display-resolver.ts +24 -0
  389. package/src/app/builder/use-save-dashboard.ts +5 -0
  390. package/src/app/index.ts +20 -3
  391. package/src/app/layout-builder.tsx +193 -186
  392. package/src/app/mcp-app-view-chrome.test.tsx +487 -14
  393. package/src/app/mcp-app-view-chrome.tsx +328 -100
  394. package/src/app/mcp-app-view-states.tsx +140 -0
  395. package/src/app/mcp-app-view.effects.test.tsx +292 -0
  396. package/src/app/mcp-app-view.test.tsx +478 -0
  397. package/src/app/mcp-app-view.tsx +447 -190
  398. package/src/app/mcp-toolkit-app.test.tsx +40 -0
  399. package/src/app/mcp-toolkit-app.tsx +39 -8
  400. package/src/app/mcp-use-host-bridge.test.tsx +180 -0
  401. package/src/app/mcp-use-host-bridge.tsx +67 -24
  402. package/src/app/model-context.test.tsx +116 -0
  403. package/src/app/model-context.tsx +125 -0
  404. package/src/app/use-build-mode-focus.ts +62 -0
  405. package/src/app/use-view-actions.ts +89 -0
  406. package/src/app/use-view-lifecycle.ts +122 -0
  407. package/src/app/view-lifecycle.test.ts +443 -0
  408. package/src/app/view-lifecycle.ts +334 -0
  409. package/src/app/widget-fixture.effects.test.tsx +51 -0
  410. package/src/app/widget-fixture.render.test.tsx +81 -0
  411. package/src/app/widget-fixture.tsx +34 -11
  412. package/src/app/widget-props-sheet.tsx +67 -39
  413. package/src/app/widget-renderer.render.test.tsx +131 -0
  414. package/src/app/widget-renderer.tsx +136 -38
  415. package/src/components/DrillButton.tsx +24 -10
  416. package/src/components/EmptyState.tsx +83 -0
  417. package/src/components/ErrorState.tsx +204 -0
  418. package/src/components/FilterBar.test.tsx +82 -0
  419. package/src/components/FilterBar.tsx +56 -27
  420. package/src/components/GroupCard.tsx +3 -2
  421. package/src/components/KpiGrid.test.tsx +279 -0
  422. package/src/components/KpiGrid.tsx +329 -91
  423. package/src/components/ListFooter.test.tsx +116 -0
  424. package/src/components/ListFooter.tsx +110 -12
  425. package/src/components/PagedListFooter.test.tsx +140 -0
  426. package/src/components/PagedListFooter.tsx +107 -0
  427. package/src/components/Pills.test.tsx +77 -0
  428. package/src/components/Pills.tsx +78 -16
  429. package/src/components/SectionHeading.tsx +9 -3
  430. package/src/components/Toast.tsx +206 -0
  431. package/src/components/WidgetHeader.test.tsx +78 -0
  432. package/src/components/WidgetHeader.tsx +63 -16
  433. package/src/components/feedback-states.test.tsx +314 -0
  434. package/src/components/tone-figures.test.tsx +58 -0
  435. package/src/fonts.css +19 -0
  436. package/src/globals.css +9 -165
  437. package/src/hooks/index.ts +6 -3
  438. package/src/hooks/tool-result-recovery-model.test.ts +744 -0
  439. package/src/hooks/tool-result-recovery-model.ts +418 -0
  440. package/src/hooks/use-tool-query.effects.test.tsx +205 -0
  441. package/src/hooks/use-tool-query.ts +156 -33
  442. package/src/hooks/use-tool-result-recovery.effects.test.tsx +141 -0
  443. package/src/hooks/use-tool-result-recovery.test.ts +28 -5
  444. package/src/hooks/use-tool-result-recovery.ts +101 -131
  445. package/src/hooks/use-view-data.test.tsx +169 -0
  446. package/src/hooks/use-view-data.ts +131 -10
  447. package/src/hooks/use-view-tool-query.ts +25 -19
  448. package/src/i18n-coverage.test.tsx +425 -0
  449. package/src/index.ts +102 -13
  450. package/src/lib/focus-return.test.ts +288 -0
  451. package/src/lib/focus-return.ts +96 -0
  452. package/src/lib/focus-ring.ts +20 -0
  453. package/src/lib/icon-stroke.test.ts +59 -0
  454. package/src/lib/icon-stroke.ts +13 -0
  455. package/src/lib/parse-tool-result.test.ts +46 -1
  456. package/src/lib/parse-tool-result.ts +40 -2
  457. package/src/lib/toast-model.test.ts +233 -0
  458. package/src/lib/toast-model.ts +165 -0
  459. package/src/lib/tone-utils.test.ts +125 -16
  460. package/src/lib/tone-utils.ts +144 -15
  461. package/src/lib/tool-query.test.ts +569 -0
  462. package/src/lib/tool-query.ts +253 -0
  463. package/src/lib/tool-result-observer.test.ts +296 -0
  464. package/src/lib/tool-result-observer.ts +211 -0
  465. package/src/lib/typography.test.ts +45 -0
  466. package/src/lib/typography.ts +47 -0
  467. package/src/lib/utils.ts +12 -1
  468. package/src/locale/index.ts +14 -1
  469. package/src/locale/locale-provider.test.tsx +87 -0
  470. package/src/locale/locale-provider.tsx +90 -3
  471. package/src/locale/message-types.ts +337 -0
  472. package/src/locale/messages-de.ts +198 -0
  473. package/src/locale/messages-en.ts +196 -0
  474. package/src/locale/toolkit-messages.test.ts +349 -0
  475. package/src/locale/toolkit-messages.ts +143 -0
  476. package/src/no-hardcoded-copy.test.ts +432 -0
  477. package/src/primitives/alert.tsx +7 -2
  478. package/src/primitives/badge.tsx +19 -7
  479. package/src/primitives/button.tsx +13 -8
  480. package/src/primitives/card.tsx +4 -4
  481. package/src/primitives/dialog.tsx +42 -8
  482. package/src/primitives/input.tsx +5 -3
  483. package/src/primitives/scroll-area.tsx +1 -1
  484. package/src/primitives/select.tsx +7 -4
  485. package/src/primitives/sheet.tsx +33 -6
  486. package/src/primitives/skeleton.tsx +1 -1
  487. package/src/primitives/switch.tsx +4 -2
  488. package/src/primitives/tabs.tsx +9 -6
  489. package/src/providers/query-provider.test.tsx +154 -0
  490. package/src/providers/query-provider.tsx +66 -5
  491. package/src/render-cases-primitives.tsx +1 -1
  492. package/src/render-cases.tsx +82 -6
  493. package/src/render-effects.tsx +96 -0
  494. package/src/render-scan.ts +75 -0
  495. package/src/theme/cd-tokens.generated.css +48 -0
  496. package/src/theme/cd-tokens.test.ts +109 -0
  497. package/src/theme/cd-tokens.ts +67 -0
  498. package/src/theme/create-theme.test.ts +253 -5
  499. package/src/theme/create-theme.ts +341 -41
  500. package/src/theme/fonts.test.ts +85 -0
  501. package/src/theme/fonts.ts +72 -0
  502. package/src/theme/host-fonts.test.ts +135 -0
  503. package/src/theme/host-fonts.ts +52 -0
  504. package/src/theme/index.ts +15 -1
  505. package/src/theme/portal-container.ts +20 -0
  506. package/src/theme/presets.ts +44 -11
  507. package/src/theme/theme-css.test.ts +619 -0
  508. package/src/theme/theme-provider.test.tsx +82 -0
  509. package/src/theme/theme-provider.tsx +60 -24
  510. package/src/theme.css +344 -0
  511. package/ui-catalog.json +783 -49
@@ -1,26 +1,40 @@
1
1
  import { useCallback, useMemo, useReducer, useState } from "react"
2
2
  import { Eye, Layers, SlidersHorizontal } from "lucide-react"
3
3
  import type { LayoutConfig, PipelineStepRef, RowDef, WidgetProps } from "@miragon/mcp-toolkit-core"
4
- import { draftToLayout, entriesToKeys, initDraft, sizeToSpan } from "./builder/builder-model.js"
4
+ import {
5
+ builderLeave,
6
+ builderSnapshot,
7
+ draftHasCells,
8
+ initDraft,
9
+ sizeToSpan,
10
+ toExitCommit,
11
+ type BuilderExitCommit,
12
+ type BuilderView,
13
+ } from "./builder/builder-model.js"
5
14
  import {
6
15
  draftReducer,
7
16
  initBuilderState,
8
17
  type BuilderDraftState,
9
18
  } from "./builder/builder-reducer.js"
10
- import { DEFAULT_LABELS, type LayoutBuilderLabels } from "./builder/labels.js"
19
+ import type { LayoutBuilderLabels } from "./builder/labels.js"
11
20
  import { Toolbar } from "./builder/Toolbar.js"
12
21
  import { PipelineStrip } from "./builder/PipelineStrip.js"
13
22
  import { CatalogueSheet } from "./builder/CatalogueSheet.js"
14
23
  import { SaveDialog } from "./builder/SaveDialog.js"
24
+ import { DiscardDialog } from "./builder/DiscardDialog.js"
15
25
  import { PreviewPane } from "./builder/PreviewPane.js"
16
26
  import { LayoutSurface } from "./builder/LayoutSurface.js"
17
27
  import { BuilderBanners } from "./builder/BuilderBanners.js"
18
28
  import { EmptyHint } from "./builder/EmptyHint.js"
19
29
  import { CellPropsSheet } from "./builder/CellPropsSheet.js"
20
30
  import { useBuilderCatalogue } from "./builder/use-builder-catalogue.js"
31
+ import { useBuilderMode, useDraftStatus, useRenameFeedback } from "./builder/use-builder-session.js"
21
32
  import { useKeyStepEntries } from "./builder/use-key-step-entries.js"
22
33
  import { useSaveDashboard } from "./builder/use-save-dashboard.js"
23
34
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "../primitives/tabs.js"
35
+ import { ToastProvider, useToast } from "../components/Toast.js"
36
+ import { useToolkitMessages } from "../locale/locale-provider.js"
37
+ import { builderMountFocusTarget, useFocusOnMount } from "./use-build-mode-focus.js"
24
38
  import { type WidgetComponent } from "./widget-renderer.js"
25
39
 
26
40
  // -------------------------------------------------------------------------- //
@@ -48,32 +62,62 @@ export interface LayoutBuilderProps {
48
62
  labels?: LayoutBuilderLabels
49
63
  onSaved?: (result: { id: string; name: string }) => void
50
64
  /**
51
- * Called when the user clicks "Done" / exits the builder. Receives
52
- * the final draft so the parent can swap into the rendered view with
53
- * the just-built layout. Omit `commit` to leave parent state untouched.
65
+ * Leaves the builder. "Apply" calls it WITH the final draft (`commit`) so
66
+ * the parent swaps the just-built layout into its view; "Discard" calls it
67
+ * WITHOUT one, so the parent keeps the view as it was before editing (after
68
+ * a confirmation when the draft changed it). Without `onExit` the builder
69
+ * has no Apply, and Discard resets the draft in place.
54
70
  */
55
- onExit?: (commit?: {
56
- layout: LayoutConfig
57
- keys?: Record<string, unknown>
58
- steps?: PipelineStepRef[]
59
- title?: string
60
- context?: {
61
- keys: Record<string, unknown>
62
- stepIds: string[]
63
- stepData: Record<
64
- string,
65
- { data: unknown; keys: Record<string, unknown>; _app: string; _dataType: string }
66
- >
67
- errors: { stepId: string; reason: string }[]
68
- }
69
- }) => void
71
+ onExit?: (commit?: BuilderExitCommit) => void
70
72
  }
71
73
 
72
74
  // -------------------------------------------------------------------------- //
73
75
  // Main component
74
76
  // -------------------------------------------------------------------------- //
75
77
 
76
- export function LayoutBuilder({
78
+ /**
79
+ * The visual view builder. People see widgets and steps by their titles
80
+ * (`title`/`titleKey` of the definitions, else the id); the data sources, the
81
+ * catalogue and the technical ids sit behind "Advanced". "Apply" shows the
82
+ * draft in the view, "Save as dashboard" stores it, "Discard" restores the
83
+ * view as it was. Confirms a successful save with a toast (it mounts a
84
+ * `ToastProvider` when none is above it — inside `McpAppView` it shares the
85
+ * view's). Every caption follows the active locale (`labels` overrides).
86
+ */
87
+ export function LayoutBuilder(props: LayoutBuilderProps) {
88
+ // Discard without an `onExit` restores the initial props by remounting.
89
+ const [generation, setGeneration] = useState(0)
90
+ const reset = useCallback(() => setGeneration((g) => g + 1), [])
91
+ return (
92
+ <ToastProvider>
93
+ <LayoutBuilderImpl
94
+ key={generation}
95
+ {...props}
96
+ onReset={reset}
97
+ mountFocus={builderMountFocusTarget(generation)}
98
+ />
99
+ </ToastProvider>
100
+ )
101
+ }
102
+
103
+ /**
104
+ * The catalog strings, overrides merged; a `labels` override of the deprecated
105
+ * `done` still labels Apply (a catalog override of it already did, in
106
+ * `resolveToolkitMessages`).
107
+ */
108
+ function useBuilderLabels(labels: LayoutBuilderLabels | undefined): Required<LayoutBuilderLabels> {
109
+ const messages = useToolkitMessages()
110
+ return useMemo(
111
+ () => ({
112
+ ...messages.builder,
113
+ ...labels,
114
+ apply: labels?.apply ?? labels?.done ?? messages.builder.apply,
115
+ }),
116
+ [messages.builder, labels],
117
+ )
118
+ }
119
+
120
+ function LayoutBuilderImpl({
77
121
  initialLayout,
78
122
  title,
79
123
  initialKeys,
@@ -86,14 +130,16 @@ export function LayoutBuilder({
86
130
  labels,
87
131
  onSaved,
88
132
  onExit,
89
- }: LayoutBuilderProps) {
90
- const L = useMemo(() => ({ ...DEFAULT_LABELS, ...labels }), [labels])
133
+ onReset,
134
+ mountFocus,
135
+ }: LayoutBuilderProps & { onReset: () => void; mountFocus: string | null }) {
136
+ const L = useBuilderLabels(labels)
137
+ const toast = useToast()
138
+
139
+ // A reset remounts the builder: the element that had the focus is gone.
140
+ const rootRef = useFocusOnMount<HTMLDivElement>(mountFocus)
91
141
 
92
142
  // ── Draft layout (pure reducer) ─────────────────────────────────────────
93
- // The draft plus the UI indices coupled to draft mutations
94
- // (activeTabIndex / focusedRowIndex / editingTabIdx) live in a single pure
95
- // reducer (see ./builder/builder-reducer.ts) so every mutation is testable
96
- // and the old setState-in-updater pattern is gone.
97
143
  const [builderState, dispatch] = useReducer(
98
144
  draftReducer,
99
145
  initialLayout,
@@ -111,63 +157,28 @@ export function LayoutBuilder({
111
157
  const setEditingTabIdx = useCallback((idx: number | null) => {
112
158
  dispatch(idx === null ? { type: "stopEditingTab" } : { type: "startEditingTab", tabIdx: idx })
113
159
  }, [])
114
- const [view, setView] = useState<"layout" | "pipeline" | "preview">("layout")
160
+ const { advanced, view, setView, toggleAdvanced, openDataSources } = useBuilderMode()
115
161
  const [catalogueOpen, setCatalogueOpen] = useState(false)
116
-
117
- // ── Inline rename feedback ──────────────────────────────────────────────
118
- // The reducer rejects duplicate tab labels and bumps `renameRejectedAt`
119
- // (Phase 1 signal). Mirror each bump into a transient flag so the rename
120
- // input can show "name already exists" inline (Finding [3]). Tracked via
121
- // the render-phase setState pattern used elsewhere in this codebase; cleared
122
- // when the inline editor closes (editingTabIdx → null).
123
- const [renameRejected, setRenameRejected] = useState(false)
124
- const [prevRenameRejectedAt, setPrevRenameRejectedAt] = useState(renameRejectedAt)
125
- if (renameRejectedAt !== prevRenameRejectedAt) {
126
- setPrevRenameRejectedAt(renameRejectedAt)
127
- setRenameRejected(true)
128
- }
129
- const [prevEditingTabIdx, setPrevEditingTabIdx] = useState(editingTabIdx)
130
- if (editingTabIdx !== prevEditingTabIdx) {
131
- setPrevEditingTabIdx(editingTabIdx)
132
- if (editingTabIdx === null) setRenameRejected(false)
133
- }
162
+ const [discardOpen, setDiscardOpen] = useState(false)
163
+ const renameRejected = useRenameFeedback(renameRejectedAt, editingTabIdx)
134
164
 
135
165
  // ── Keys + steps editor state ───────────────────────────────────────────
136
166
  const { keyEntries, stepEntries, addKey, updateKey, removeKey, addStep, updateStep, removeStep } =
137
167
  useKeyStepEntries({ initialKeys, initialSteps })
138
168
 
169
+ // ── Draft status: what Apply / Discard / the unsaved marker compare ─────
170
+ const snapshot = useMemo(
171
+ () => builderSnapshot(draft, keyEntries, stepEntries),
172
+ [draft, keyEntries, stepEntries],
173
+ )
174
+ const draftState = useDraftStatus(snapshot)
175
+
139
176
  // ── Catalogue fetch (mount + on key/step edits) ─────────────────────────
140
- // The builder fetches its own catalogue from the app-only
141
- // `get-builder-catalogue` tool; the LLM never sees this data.
142
- const {
143
- liveReachable,
144
- liveUnreachable,
145
- liveCatalog,
146
- liveSteps,
147
- liveContext,
148
- validationIssues,
149
- status,
150
- refreshError,
151
- widgetById,
152
- propsSchemaByWidgetId,
153
- paletteByApp,
154
- liveKeyCount,
155
- stepsByApp,
156
- } = useBuilderCatalogue({ callTool, catalogueToolName, keyEntries, stepEntries })
177
+ const catalogue = useBuilderCatalogue({ callTool, catalogueToolName, keyEntries, stepEntries })
178
+ const { liveReachable, liveCatalog, liveContext, widgetById } = catalogue
157
179
 
158
180
  // ── Save dialog ─────────────────────────────────────────────────────────
159
- const {
160
- isBusy,
161
- saveOpen,
162
- setSaveOpen,
163
- saveName,
164
- setSaveName,
165
- saveDescription,
166
- setSaveDescription,
167
- saveError,
168
- setSaveError,
169
- saveDraft,
170
- } = useSaveDashboard({
181
+ const save = useSaveDashboard({
171
182
  callTool,
172
183
  saveToolName,
173
184
  dashboardId,
@@ -176,16 +187,14 @@ export function LayoutBuilder({
176
187
  stepEntries,
177
188
  draft,
178
189
  onSaved,
190
+ onSuccess: (name) => {
191
+ draftState.markSaved(snapshot)
192
+ toast.show({ tone: "success", title: L.saved(name) })
193
+ },
179
194
  })
180
195
 
181
- // ── DnD ──────────────────────────────────────────────────────────────────
196
+ // ── DnD + the cell whose props are being configured ─────────────────────
182
197
  const [dragOverRow, setDragOverRow] = useState<number | null>(null)
183
-
184
- // Which cell (if any) is having its props configured. The
185
- // WidgetPropsSheet is mounted once at the LayoutBuilder root so that
186
- // exactly one editor can be open at a time across the entire workspace
187
- // — including across tabs. Stored as `{ rowIdx, cellIdx }` against the
188
- // currently active draft surface (rows or active tab's rows).
189
198
  const [configuringCell, setConfiguringCell] = useState<{
190
199
  rowIdx: number
191
200
  cellIdx: number
@@ -208,47 +217,34 @@ export function LayoutBuilder({
208
217
  },
209
218
  [widgetById],
210
219
  )
211
-
212
220
  const addRow = useCallback(() => dispatch({ type: "addRow" }), [])
213
-
214
221
  const removeRow = useCallback((rowIdx: number) => dispatch({ type: "removeRow", rowIdx }), [])
215
-
216
222
  const moveRow = useCallback(
217
223
  (rowIdx: number, direction: -1 | 1) => dispatch({ type: "moveRow", rowIdx, direction }),
218
224
  [],
219
225
  )
220
-
221
226
  const setCellSpan = useCallback(
222
227
  (rowIdx: number, cellIdx: number, span: number) =>
223
228
  dispatch({ type: "setCellSpan", rowIdx, cellIdx, span }),
224
229
  [],
225
230
  )
226
-
227
231
  const removeCell = useCallback(
228
232
  (rowIdx: number, cellIdx: number) => dispatch({ type: "removeCell", rowIdx, cellIdx }),
229
233
  [],
230
234
  )
231
-
232
- // Sets (or clears, when `next` is undefined) the per-instance `props` on
233
- // a cell. Triggered by the WidgetPropsSheet's Apply button. Storing
234
- // `undefined` rather than `{}` keeps the saved layout's wire format
235
- // identical to one a hand-coded LLM call would produce — the field is
236
- // simply absent.
235
+ // Sets (or clears, when `next` is undefined) a cell's per-instance `props`
236
+ // from the props sheet's Apply; `undefined` keeps the field absent on the wire.
237
237
  const setCellProps = useCallback(
238
238
  (rowIdx: number, cellIdx: number, next: Record<string, unknown> | undefined) =>
239
239
  dispatch({ type: "setCellProps", rowIdx, cellIdx, next }),
240
240
  [],
241
241
  )
242
-
243
242
  const addTab = useCallback(() => dispatch({ type: "addTab" }), [])
244
-
245
- // Commit an inline tab rename and decide whether to close the editor.
246
- // Dispatches the rename, then keeps the input open when the trimmed label
247
- // collides with another tab so the reducer's rejection (`renameRejectedAt`)
248
- // can drive the inline "name already exists" feedback instead of the editor
249
- // silently snapping shut on the old label.
243
+ // Commit an inline tab rename. A label that collides with another tab keeps
244
+ // the editor open (the reducer's rejection drives the inline error); the
245
+ // return value tells the field whether it closed.
250
246
  const commitRename = useCallback(
251
- (tabIdx: number, label: string) => {
247
+ (tabIdx: number, label: string): boolean => {
252
248
  dispatch({ type: "renameTab", tabIdx, label })
253
249
  const trimmed = label.trim()
254
250
  const isDuplicate =
@@ -256,10 +252,10 @@ export function LayoutBuilder({
256
252
  trimmed.length > 0 &&
257
253
  draft.tabs.some((t, i) => i !== tabIdx && t.label === trimmed)
258
254
  if (!isDuplicate) setEditingTabIdx(null)
255
+ return !isDuplicate
259
256
  },
260
257
  [draft, setEditingTabIdx],
261
258
  )
262
-
263
259
  const removeTab = useCallback((tabIdx: number) => dispatch({ type: "removeTab", tabIdx }), [])
264
260
 
265
261
  // ── Smart action: add a producing step for a missing key ────────────────
@@ -272,86 +268,77 @@ export function LayoutBuilder({
272
268
  [addStep, liveCatalog],
273
269
  )
274
270
 
271
+ // ── Leaving: Apply commits, Discard restores (asking first when the view loses changes) ─
272
+ const leave = builderLeave({
273
+ changed: draftState.changed,
274
+ onExit,
275
+ onReset,
276
+ commit: () => toExitCommit(draft, keyEntries, stepEntries, title, liveContext),
277
+ confirm: () => setDiscardOpen(true),
278
+ })
279
+
275
280
  const widgetProps: WidgetProps = useMemo(
276
281
  () => ({ keys: liveContext.keys, context: liveContext }),
277
282
  [liveContext],
278
283
  )
279
- const hasAnyCell = activeRows.some((r) => r.row.length > 0)
280
- const liveKeysMap = liveContext.keys
284
+ const hasAnyCell = draftHasCells(draft)
281
285
 
282
286
  return (
283
- <div className="flex min-h-[60vh] flex-col gap-4 p-1">
287
+ <div ref={rootRef} className="flex min-h-[60vh] flex-col gap-4 p-1">
284
288
  <Toolbar
285
289
  L={L}
286
290
  previewMode={view === "preview"}
287
- isBusy={isBusy}
288
- status={status}
289
- liveKeys={liveKeyCount}
291
+ isBusy={save.isBusy}
292
+ status={catalogue.status}
293
+ liveKeys={catalogue.liveKeyCount}
290
294
  reachableCount={liveReachable.length}
291
- unreachableCount={liveUnreachable.length}
295
+ unreachableCount={catalogue.liveUnreachable.length}
296
+ advanced={advanced}
297
+ onToggleAdvanced={toggleAdvanced}
298
+ unsaved={draftState.unsaved}
292
299
  onOpenCatalogue={() => setCatalogueOpen(true)}
293
- onOpenSave={() => setSaveOpen(true)}
294
- onDone={
295
- onExit
296
- ? () =>
297
- onExit({
298
- layout: draftToLayout(draft),
299
- keys: entriesToKeys(keyEntries),
300
- steps: stepEntries.filter((s) => s.step.trim().length > 0),
301
- title,
302
- context: {
303
- keys: liveContext.keys,
304
- stepIds: Object.keys(liveContext.steps),
305
- stepData: Object.fromEntries(
306
- Object.entries(liveContext.steps).map(([id, result]) => [
307
- id,
308
- {
309
- data: result.data,
310
- keys: result.keys,
311
- _app: result._app,
312
- _dataType: result._dataType,
313
- },
314
- ]),
315
- ),
316
- errors: liveContext.errors,
317
- },
318
- })
319
- : undefined
320
- }
300
+ onOpenSave={() => save.setSaveOpen(true)}
301
+ onDiscard={leave.discard}
302
+ onApply={leave.apply}
321
303
  hasAnyCell={hasAnyCell}
322
304
  />
323
305
 
324
306
  <BuilderBanners
325
307
  L={L}
326
308
  catalogueToolName={catalogueToolName}
327
- refreshError={refreshError}
328
- validationIssues={validationIssues}
309
+ refreshError={catalogue.refreshError}
310
+ validationIssues={catalogue.validationIssues}
311
+ onRetry={catalogue.retryCatalogue}
329
312
  />
330
313
 
331
- <Tabs value={view} onValueChange={(v) => setView(v as typeof view)}>
314
+ <Tabs value={view} onValueChange={(v) => setView(v as BuilderView)}>
332
315
  <TabsList>
333
316
  <TabsTrigger value="layout">
334
- <Layers className="size-3.5" />
317
+ <Layers aria-hidden="true" className="size-3.5" />
335
318
  {L.viewLayoutTab}
336
319
  </TabsTrigger>
337
- <TabsTrigger value="pipeline">
338
- <SlidersHorizontal className="size-3.5" />
339
- {L.viewPipelineTab}
340
- {(keyEntries.length > 0 || stepEntries.length > 0) && (
341
- <span className="bg-muted text-muted-foreground ml-1 rounded px-1 font-mono text-[10px]">
342
- {keyEntries.length}/{stepEntries.length}
343
- </span>
344
- )}
345
- </TabsTrigger>
320
+ {advanced && (
321
+ <TabsTrigger value="pipeline">
322
+ <SlidersHorizontal aria-hidden="true" className="size-3.5" />
323
+ {L.viewPipelineTab}
324
+ {(keyEntries.length > 0 || stepEntries.length > 0) && (
325
+ <span className="bg-muted text-muted-foreground text-small ml-1 rounded px-1 tabular-nums">
326
+ {keyEntries.length}/{stepEntries.length}
327
+ </span>
328
+ )}
329
+ </TabsTrigger>
330
+ )}
346
331
  <TabsTrigger value="preview" disabled={!hasAnyCell}>
347
- <Eye className="size-3.5" />
332
+ <Eye aria-hidden="true" className="size-3.5" />
348
333
  {L.viewPreviewTab}
349
334
  </TabsTrigger>
350
335
  </TabsList>
351
336
 
352
337
  <TabsContent value="layout" className="mt-4">
353
- {liveReachable.length === 0 && !hasAnyCell ? (
354
- <EmptyHint L={L} onGotoPipeline={() => setView("pipeline")} />
338
+ {/* Until the catalogue answers, the palette shows a loading state
339
+ (an empty state now would flash on every open). */}
340
+ {catalogue.loaded && liveReachable.length === 0 && !hasAnyCell ? (
341
+ <EmptyHint L={L} onGotoPipeline={openDataSources} />
355
342
  ) : (
356
343
  <LayoutSurface
357
344
  L={L}
@@ -366,8 +353,11 @@ export function LayoutBuilder({
366
353
  onRemoveTab={removeTab}
367
354
  workspace={{
368
355
  L,
369
- paletteByApp,
356
+ paletteByApp: catalogue.paletteByApp,
357
+ appDisplayByName: catalogue.appDisplayByName,
370
358
  paletteCount: liveReachable.length,
359
+ paletteLoading: !catalogue.loaded,
360
+ onOpenDataSources: openDataSources,
371
361
  activeRows,
372
362
  focusedRowIndex,
373
363
  setFocusedRowIndex,
@@ -380,7 +370,9 @@ export function LayoutBuilder({
380
370
  onRemoveCell: removeCell,
381
371
  onAddWidget: addWidgetToRow,
382
372
  onConfigureCell: (rowIdx, cellIdx) => setConfiguringCell({ rowIdx, cellIdx }),
383
- propsSchemaByWidgetId,
373
+ propsSchemaByWidgetId: catalogue.propsSchemaByWidgetId,
374
+ displayByWidgetId: catalogue.displayByWidgetId,
375
+ advanced,
384
376
  widgets,
385
377
  widgetProps,
386
378
  }}
@@ -388,24 +380,26 @@ export function LayoutBuilder({
388
380
  )}
389
381
  </TabsContent>
390
382
 
391
- <TabsContent value="pipeline" className="mt-4">
392
- <PipelineStrip
393
- L={L}
394
- keyEntries={keyEntries}
395
- stepEntries={stepEntries}
396
- keyCatalog={liveCatalog}
397
- availableSteps={liveSteps}
398
- stepsByApp={stepsByApp}
399
- liveKeys={liveKeysMap}
400
- onAddKey={addKey}
401
- onUpdateKey={updateKey}
402
- onRemoveKey={removeKey}
403
- onAddStep={addStep}
404
- onUpdateStep={updateStep}
405
- onRemoveStep={removeStep}
406
- status={status}
407
- />
408
- </TabsContent>
383
+ {advanced && (
384
+ <TabsContent value="pipeline" className="mt-4">
385
+ <PipelineStrip
386
+ L={L}
387
+ keyEntries={keyEntries}
388
+ stepEntries={stepEntries}
389
+ keyCatalog={liveCatalog}
390
+ availableSteps={catalogue.liveSteps}
391
+ stepsByApp={catalogue.stepsByApp}
392
+ liveKeys={liveContext.keys}
393
+ onAddKey={addKey}
394
+ onUpdateKey={updateKey}
395
+ onRemoveKey={removeKey}
396
+ onAddStep={addStep}
397
+ onUpdateStep={updateStep}
398
+ onRemoveStep={removeStep}
399
+ status={catalogue.status}
400
+ />
401
+ </TabsContent>
402
+ )}
409
403
 
410
404
  <TabsContent value="preview" className="mt-4">
411
405
  <PreviewPane
@@ -423,8 +417,8 @@ export function LayoutBuilder({
423
417
  open={catalogueOpen}
424
418
  onOpenChange={setCatalogueOpen}
425
419
  keyCatalog={liveCatalog}
426
- availableSteps={liveSteps}
427
- unreachableWidgets={liveUnreachable}
420
+ availableSteps={catalogue.liveSteps}
421
+ unreachableWidgets={catalogue.liveUnreachable}
428
422
  onSeedKey={(name) => {
429
423
  addKey(name)
430
424
  setCatalogueOpen(false)
@@ -439,26 +433,39 @@ export function LayoutBuilder({
439
433
 
440
434
  <SaveDialog
441
435
  L={L}
442
- open={saveOpen}
436
+ open={save.saveOpen}
437
+ canApply={onExit !== undefined}
443
438
  onOpenChange={(open) => {
444
439
  // Clear any stale save error whenever the dialog is opened or
445
440
  // dismissed so a fresh attempt starts clean.
446
- setSaveError(null)
447
- setSaveOpen(open)
441
+ save.setSaveError(null)
442
+ save.setSaveOpen(open)
443
+ }}
444
+ name={save.saveName}
445
+ setName={save.setSaveName}
446
+ description={save.saveDescription}
447
+ setDescription={save.setSaveDescription}
448
+ onSubmit={save.saveDraft}
449
+ busy={save.isBusy}
450
+ error={save.saveError}
451
+ />
452
+
453
+ <DiscardDialog
454
+ L={L}
455
+ open={discardOpen}
456
+ onOpenChange={setDiscardOpen}
457
+ changesSaved={!draftState.unsaved}
458
+ onConfirm={() => {
459
+ setDiscardOpen(false)
460
+ leave.discardNow()
448
461
  }}
449
- name={saveName}
450
- setName={setSaveName}
451
- description={saveDescription}
452
- setDescription={setSaveDescription}
453
- onSubmit={saveDraft}
454
- busy={isBusy}
455
- error={saveError}
456
462
  />
457
463
 
458
464
  <CellPropsSheet
459
465
  configuringCell={configuringCell}
460
466
  activeRows={activeRows}
461
- propsSchemaByWidgetId={propsSchemaByWidgetId}
467
+ propsSchemaByWidgetId={catalogue.propsSchemaByWidgetId}
468
+ displayByWidgetId={catalogue.displayByWidgetId}
462
469
  onApply={setCellProps}
463
470
  onClose={() => setConfiguringCell(null)}
464
471
  />