@vertesia/ui 1.5.0-dev.20260714.072725Z → 1.5.0-dev.20260722.120446Z

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 (393) hide show
  1. package/lib/core/components/SidePanel.js +1 -1
  2. package/lib/core/components/SidePanel.js.map +1 -1
  3. package/lib/core/components/shadcn/button.d.ts +10 -3
  4. package/lib/core/components/shadcn/button.d.ts.map +1 -1
  5. package/lib/core/components/shadcn/button.js +41 -9
  6. package/lib/core/components/shadcn/button.js.map +1 -1
  7. package/lib/core/components/shadcn/modal/dialog.js +1 -1
  8. package/lib/core/components/shadcn/modal/dialog.js.map +1 -1
  9. package/lib/core/components/shadcn/theme/ThemeSwitcher.js +1 -1
  10. package/lib/core/components/shadcn/theme/ThemeSwitcher.js.map +1 -1
  11. package/lib/env/index.d.ts +19 -0
  12. package/lib/env/index.d.ts.map +1 -1
  13. package/lib/env/index.js +6 -0
  14. package/lib/env/index.js.map +1 -1
  15. package/lib/features/agent/chat/AgentChatPlaybackControls.d.ts.map +1 -1
  16. package/lib/features/agent/chat/AgentChatPlaybackControls.js +2 -2
  17. package/lib/features/agent/chat/AgentChatPlaybackControls.js.map +1 -1
  18. package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts.map +1 -1
  19. package/lib/features/agent/chat/AgentRequestInputOverlay.js +2 -2
  20. package/lib/features/agent/chat/AgentRequestInputOverlay.js.map +1 -1
  21. package/lib/features/agent/chat/ArtifactsTab.d.ts.map +1 -1
  22. package/lib/features/agent/chat/ArtifactsTab.js +68 -11
  23. package/lib/features/agent/chat/ArtifactsTab.js.map +1 -1
  24. package/lib/features/agent/chat/ImageLightbox.d.ts.map +1 -1
  25. package/lib/features/agent/chat/ImageLightbox.js +1 -1
  26. package/lib/features/agent/chat/ImageLightbox.js.map +1 -1
  27. package/lib/features/agent/chat/ModernAgentConversation.js +52 -49
  28. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  29. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  30. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +5 -5
  31. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  32. package/lib/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
  33. package/lib/features/agent/chat/ModernAgentOutput/Header.js +4 -2
  34. package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  35. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
  36. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +2 -2
  37. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
  38. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  39. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +2 -1
  40. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  41. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts +6 -0
  42. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts.map +1 -1
  43. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js +15 -1
  44. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js.map +1 -1
  45. package/lib/features/agent/chat/hooks/useArtifacts.d.ts +8 -1
  46. package/lib/features/agent/chat/hooks/useArtifacts.d.ts.map +1 -1
  47. package/lib/features/agent/chat/hooks/useArtifacts.js +28 -10
  48. package/lib/features/agent/chat/hooks/useArtifacts.js.map +1 -1
  49. package/lib/features/document-viewer/UniversalDocumentViewer.d.ts +73 -0
  50. package/lib/features/document-viewer/UniversalDocumentViewer.d.ts.map +1 -0
  51. package/lib/features/document-viewer/UniversalDocumentViewer.js +415 -0
  52. package/lib/features/document-viewer/UniversalDocumentViewer.js.map +1 -0
  53. package/lib/features/document-viewer/index.d.ts +2 -0
  54. package/lib/features/document-viewer/index.d.ts.map +1 -0
  55. package/lib/features/document-viewer/index.js +2 -0
  56. package/lib/features/document-viewer/index.js.map +1 -0
  57. package/lib/features/environment/SelectEnvironment.d.ts +28 -0
  58. package/lib/features/environment/SelectEnvironment.d.ts.map +1 -0
  59. package/lib/features/environment/SelectEnvironment.js +97 -0
  60. package/lib/features/environment/SelectEnvironment.js.map +1 -0
  61. package/lib/features/environment/index.d.ts +2 -0
  62. package/lib/features/environment/index.d.ts.map +1 -0
  63. package/lib/features/environment/index.js +2 -0
  64. package/lib/features/environment/index.js.map +1 -0
  65. package/lib/features/index.d.ts +3 -0
  66. package/lib/features/index.d.ts.map +1 -1
  67. package/lib/features/index.js +3 -0
  68. package/lib/features/index.js.map +1 -1
  69. package/lib/features/magic-pdf/AnnotatedImageSlider.js +12 -12
  70. package/lib/features/magic-pdf/AnnotatedImageSlider.js.map +1 -1
  71. package/lib/features/magic-pdf/DownloadPopover.d.ts.map +1 -1
  72. package/lib/features/magic-pdf/DownloadPopover.js +3 -17
  73. package/lib/features/magic-pdf/DownloadPopover.js.map +1 -1
  74. package/lib/features/magic-pdf/ExtractedContentView.js +2 -6
  75. package/lib/features/magic-pdf/ExtractedContentView.js.map +1 -1
  76. package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.d.ts +25 -0
  77. package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.d.ts.map +1 -0
  78. package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.js +42 -0
  79. package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.js.map +1 -0
  80. package/lib/features/magic-pdf/GroundedExtractionView.d.ts +27 -0
  81. package/lib/features/magic-pdf/GroundedExtractionView.d.ts.map +1 -0
  82. package/lib/features/magic-pdf/GroundedExtractionView.js +377 -0
  83. package/lib/features/magic-pdf/GroundedExtractionView.js.map +1 -0
  84. package/lib/features/magic-pdf/MagicPdfProvider.d.ts +0 -2
  85. package/lib/features/magic-pdf/MagicPdfProvider.d.ts.map +1 -1
  86. package/lib/features/magic-pdf/MagicPdfProvider.js +15 -42
  87. package/lib/features/magic-pdf/MagicPdfProvider.js.map +1 -1
  88. package/lib/features/magic-pdf/MagicPdfView.d.ts.map +1 -1
  89. package/lib/features/magic-pdf/MagicPdfView.js +2 -19
  90. package/lib/features/magic-pdf/MagicPdfView.js.map +1 -1
  91. package/lib/features/magic-pdf/index.d.ts +1 -0
  92. package/lib/features/magic-pdf/index.d.ts.map +1 -1
  93. package/lib/features/magic-pdf/index.js +1 -0
  94. package/lib/features/magic-pdf/index.js.map +1 -1
  95. package/lib/features/magic-pdf/types.d.ts +1 -1
  96. package/lib/features/magic-pdf/types.d.ts.map +1 -1
  97. package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -1
  98. package/lib/features/oauth/McpConnectionsButton.js +2 -2
  99. package/lib/features/oauth/McpConnectionsButton.js.map +1 -1
  100. package/lib/features/oauth/McpConnectionsDialog.d.ts.map +1 -1
  101. package/lib/features/oauth/McpConnectionsDialog.js +1 -1
  102. package/lib/features/oauth/McpConnectionsDialog.js.map +1 -1
  103. package/lib/features/oauth/RemoteMcpConnectionButton.d.ts.map +1 -1
  104. package/lib/features/oauth/RemoteMcpConnectionButton.js +1 -1
  105. package/lib/features/oauth/RemoteMcpConnectionButton.js.map +1 -1
  106. package/lib/features/pdf-viewer/PdfPageSlider.js +2 -2
  107. package/lib/features/pdf-viewer/PdfPageSlider.js.map +1 -1
  108. package/lib/features/pdf-viewer/SimplePdfViewer.d.ts.map +1 -1
  109. package/lib/features/pdf-viewer/SimplePdfViewer.js +3 -3
  110. package/lib/features/pdf-viewer/SimplePdfViewer.js.map +1 -1
  111. package/lib/features/permissions/UserPermissionsProvider.d.ts +2 -3
  112. package/lib/features/permissions/UserPermissionsProvider.d.ts.map +1 -1
  113. package/lib/features/permissions/UserPermissionsProvider.js +31 -38
  114. package/lib/features/permissions/UserPermissionsProvider.js.map +1 -1
  115. package/lib/features/store/objects/DocumentQuickFilter.d.ts.map +1 -1
  116. package/lib/features/store/objects/DocumentQuickFilter.js +5 -5
  117. package/lib/features/store/objects/DocumentQuickFilter.js.map +1 -1
  118. package/lib/features/store/objects/DocumentSearchResults.d.ts.map +1 -1
  119. package/lib/features/store/objects/DocumentSearchResults.js +2 -2
  120. package/lib/features/store/objects/DocumentSearchResults.js.map +1 -1
  121. package/lib/features/store/objects/components/ContentDispositionButton.d.ts.map +1 -1
  122. package/lib/features/store/objects/components/ContentDispositionButton.js +1 -1
  123. package/lib/features/store/objects/components/ContentDispositionButton.js.map +1 -1
  124. package/lib/features/store/objects/components/ContentOverview.d.ts.map +1 -1
  125. package/lib/features/store/objects/components/ContentOverview.js +148 -31
  126. package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
  127. package/lib/features/store/objects/components/DocumentIcon.js +1 -1
  128. package/lib/features/store/objects/components/VectorSearchWidget.js +1 -1
  129. package/lib/features/store/objects/components/VectorSearchWidget.js.map +1 -1
  130. package/lib/features/store/objects/components/useContentPanelHooks.d.ts +1 -2
  131. package/lib/features/store/objects/components/useContentPanelHooks.d.ts.map +1 -1
  132. package/lib/features/store/objects/components/useContentPanelHooks.js +4 -8
  133. package/lib/features/store/objects/components/useContentPanelHooks.js.map +1 -1
  134. package/lib/features/store/objects/layout/renderers.d.ts.map +1 -1
  135. package/lib/features/store/objects/layout/renderers.js +2 -2
  136. package/lib/features/store/objects/layout/renderers.js.map +1 -1
  137. package/lib/features/store/objects/selection/SelectionActions.js +1 -1
  138. package/lib/features/store/objects/selection/SelectionActions.js.map +1 -1
  139. package/lib/features/store/types/ContentObjectTypesTable.d.ts.map +1 -1
  140. package/lib/features/store/types/ContentObjectTypesTable.js +4 -4
  141. package/lib/features/store/types/ContentObjectTypesTable.js.map +1 -1
  142. package/lib/features/store/types/IntakePolicyEditor.d.ts +15 -0
  143. package/lib/features/store/types/IntakePolicyEditor.d.ts.map +1 -0
  144. package/lib/features/store/types/IntakePolicyEditor.js +455 -0
  145. package/lib/features/store/types/IntakePolicyEditor.js.map +1 -0
  146. package/lib/features/store/types/IntakePolicyForm.d.ts +11 -0
  147. package/lib/features/store/types/IntakePolicyForm.d.ts.map +1 -0
  148. package/lib/features/store/types/IntakePolicyForm.js +91 -0
  149. package/lib/features/store/types/IntakePolicyForm.js.map +1 -0
  150. package/lib/features/store/types/SelectContentTypeModal.js +1 -1
  151. package/lib/features/store/types/SelectContentTypeModal.js.map +1 -1
  152. package/lib/features/store/types/index.d.ts +2 -0
  153. package/lib/features/store/types/index.d.ts.map +1 -1
  154. package/lib/features/store/types/index.js +2 -0
  155. package/lib/features/store/types/index.js.map +1 -1
  156. package/lib/features/store/types/intake-policy-editor.logic.d.ts +7 -0
  157. package/lib/features/store/types/intake-policy-editor.logic.d.ts.map +1 -0
  158. package/lib/features/store/types/intake-policy-editor.logic.js +60 -0
  159. package/lib/features/store/types/intake-policy-editor.logic.js.map +1 -0
  160. package/lib/features/store/types/typeCatalogCache.d.ts +5 -0
  161. package/lib/features/store/types/typeCatalogCache.d.ts.map +1 -0
  162. package/lib/features/store/types/typeCatalogCache.js +40 -0
  163. package/lib/features/store/types/typeCatalogCache.js.map +1 -0
  164. package/lib/features/user/UserInfo.js +7 -3
  165. package/lib/features/user/UserInfo.js.map +1 -1
  166. package/lib/features/views/ViewExperience.d.ts +20 -0
  167. package/lib/features/views/ViewExperience.d.ts.map +1 -0
  168. package/lib/features/views/ViewExperience.js +188 -0
  169. package/lib/features/views/ViewExperience.js.map +1 -0
  170. package/lib/features/views/ViewNavigation.d.ts +3 -0
  171. package/lib/features/views/ViewNavigation.d.ts.map +1 -0
  172. package/lib/features/views/ViewNavigation.js +36 -0
  173. package/lib/features/views/ViewNavigation.js.map +1 -0
  174. package/lib/features/views/ViewResults.d.ts +9 -0
  175. package/lib/features/views/ViewResults.d.ts.map +1 -0
  176. package/lib/features/views/ViewResults.js +229 -0
  177. package/lib/features/views/ViewResults.js.map +1 -0
  178. package/lib/features/views/ViewSearch.d.ts +3 -0
  179. package/lib/features/views/ViewSearch.d.ts.map +1 -0
  180. package/lib/features/views/ViewSearch.js +74 -0
  181. package/lib/features/views/ViewSearch.js.map +1 -0
  182. package/lib/features/views/index.d.ts +7 -0
  183. package/lib/features/views/index.d.ts.map +1 -0
  184. package/lib/features/views/index.js +7 -0
  185. package/lib/features/views/index.js.map +1 -0
  186. package/lib/features/views/types.d.ts +39 -0
  187. package/lib/features/views/types.d.ts.map +1 -0
  188. package/lib/features/views/types.js +2 -0
  189. package/lib/features/views/types.js.map +1 -0
  190. package/lib/features/views/viewState.d.ts +14 -0
  191. package/lib/features/views/viewState.d.ts.map +1 -0
  192. package/lib/features/views/viewState.js +117 -0
  193. package/lib/features/views/viewState.js.map +1 -0
  194. package/lib/i18n/locales/ar.json +18 -0
  195. package/lib/i18n/locales/de.json +14 -0
  196. package/lib/i18n/locales/en.json +246 -32
  197. package/lib/i18n/locales/es.json +15 -0
  198. package/lib/i18n/locales/fr.json +15 -0
  199. package/lib/i18n/locales/it.json +15 -0
  200. package/lib/i18n/locales/ja.json +13 -0
  201. package/lib/i18n/locales/ko.json +13 -0
  202. package/lib/i18n/locales/pt.json +15 -0
  203. package/lib/i18n/locales/ru.json +16 -0
  204. package/lib/i18n/locales/tr.json +14 -0
  205. package/lib/i18n/locales/zh-TW.json +13 -0
  206. package/lib/i18n/locales/zh.json +13 -0
  207. package/lib/router/HistoryNavigator.d.ts.map +1 -1
  208. package/lib/router/HistoryNavigator.js +27 -14
  209. package/lib/router/HistoryNavigator.js.map +1 -1
  210. package/lib/router/Nav.d.ts.map +1 -1
  211. package/lib/router/Nav.js +21 -6
  212. package/lib/router/Nav.js.map +1 -1
  213. package/lib/router/Router.d.ts.map +1 -1
  214. package/lib/router/Router.js +19 -4
  215. package/lib/router/Router.js.map +1 -1
  216. package/lib/router/path.d.ts +15 -0
  217. package/lib/router/path.d.ts.map +1 -1
  218. package/lib/router/path.js +43 -0
  219. package/lib/router/path.js.map +1 -1
  220. package/lib/session/UserSession.d.ts +6 -0
  221. package/lib/session/UserSession.d.ts.map +1 -1
  222. package/lib/session/UserSession.js +36 -12
  223. package/lib/session/UserSession.js.map +1 -1
  224. package/lib/session/UserSessionProvider.d.ts.map +1 -1
  225. package/lib/session/UserSessionProvider.js +111 -49
  226. package/lib/session/UserSessionProvider.js.map +1 -1
  227. package/lib/session/auth/composable.d.ts.map +1 -1
  228. package/lib/session/auth/composable.js +52 -3
  229. package/lib/session/auth/composable.js.map +1 -1
  230. package/lib/session/auth/domainRouting.d.ts +25 -0
  231. package/lib/session/auth/domainRouting.d.ts.map +1 -1
  232. package/lib/session/auth/domainRouting.js +36 -0
  233. package/lib/session/auth/domainRouting.js.map +1 -1
  234. package/lib/shell/login/SignInRestrictedEnvStep.d.ts +1 -1
  235. package/lib/shell/login/SignInRestrictedEnvStep.js +1 -1
  236. package/lib/shell/login/SigninScreen.js +9 -1
  237. package/lib/shell/login/SigninScreen.js.map +1 -1
  238. package/lib/shell/login/productionUrl.d.ts +0 -14
  239. package/lib/shell/login/productionUrl.d.ts.map +1 -1
  240. package/lib/shell/login/productionUrl.js +14 -5
  241. package/lib/shell/login/productionUrl.js.map +1 -1
  242. package/lib/vertesia-ui-core.js +4 -4
  243. package/lib/vertesia-ui-core.js.map +1 -1
  244. package/lib/vertesia-ui-env.js +1 -1
  245. package/lib/vertesia-ui-env.js.map +1 -1
  246. package/lib/vertesia-ui-features.js +35 -28
  247. package/lib/vertesia-ui-features.js.map +1 -1
  248. package/lib/vertesia-ui-i18n.js +15 -15
  249. package/lib/vertesia-ui-i18n.js.map +1 -1
  250. package/lib/vertesia-ui-router.js +1 -1
  251. package/lib/vertesia-ui-router.js.map +1 -1
  252. package/lib/vertesia-ui-session.js +1 -1
  253. package/lib/vertesia-ui-session.js.map +1 -1
  254. package/lib/vertesia-ui-shell.js +1 -1
  255. package/lib/vertesia-ui-shell.js.map +1 -1
  256. package/lib/vertesia-ui-widgets.js +7 -7
  257. package/lib/vertesia-ui-widgets.js.map +1 -1
  258. package/lib/widgets/form/Form.js +1 -1
  259. package/lib/widgets/form/Form.js.map +1 -1
  260. package/lib/widgets/json-view/JSONSwitcher.js +1 -1
  261. package/lib/widgets/json-view/JSONSwitcher.js.map +1 -1
  262. package/lib/widgets/json-view/JSONView.js +6 -6
  263. package/lib/widgets/json-view/JSONView.js.map +1 -1
  264. package/lib/widgets/monacoEditor/MonacoEditor.d.ts.map +1 -1
  265. package/lib/widgets/monacoEditor/MonacoEditor.js +29 -0
  266. package/lib/widgets/monacoEditor/MonacoEditor.js.map +1 -1
  267. package/lib/widgets/schema-editor/ManagedSchema.d.ts +8 -0
  268. package/lib/widgets/schema-editor/ManagedSchema.d.ts.map +1 -1
  269. package/lib/widgets/schema-editor/ManagedSchema.js +16 -0
  270. package/lib/widgets/schema-editor/ManagedSchema.js.map +1 -1
  271. package/lib/widgets/schema-editor/editor/EditableSchemaProperty.d.ts +2 -0
  272. package/lib/widgets/schema-editor/editor/EditableSchemaProperty.d.ts.map +1 -1
  273. package/lib/widgets/schema-editor/editor/EditableSchemaProperty.js +1 -0
  274. package/lib/widgets/schema-editor/editor/EditableSchemaProperty.js.map +1 -1
  275. package/lib/widgets/schema-editor/editor/PropertyViewer.d.ts.map +1 -1
  276. package/lib/widgets/schema-editor/editor/PropertyViewer.js +4 -1
  277. package/lib/widgets/schema-editor/editor/PropertyViewer.js.map +1 -1
  278. package/lib/widgets/schema-editor/editor/SchemaEditor.d.ts.map +1 -1
  279. package/lib/widgets/schema-editor/editor/SchemaEditor.js +22 -11
  280. package/lib/widgets/schema-editor/editor/SchemaEditor.js.map +1 -1
  281. package/llms.txt +70 -70
  282. package/package.json +33 -32
  283. package/src/__tests__/a11y.test.tsx +73 -0
  284. package/src/core/components/SidePanel.tsx +1 -1
  285. package/src/core/components/shadcn/button.tsx +67 -12
  286. package/src/core/components/shadcn/modal/dialog.tsx +1 -1
  287. package/src/core/components/shadcn/theme/ThemeSwitcher.tsx +1 -1
  288. package/src/env/index.ts +24 -0
  289. package/src/features/agent/chat/AgentChatPlaybackControls.tsx +0 -5
  290. package/src/features/agent/chat/AgentRequestInputOverlay.test.tsx +31 -0
  291. package/src/features/agent/chat/AgentRequestInputOverlay.tsx +6 -2
  292. package/src/features/agent/chat/ArtifactsTab.tsx +165 -21
  293. package/src/features/agent/chat/ImageLightbox.tsx +0 -1
  294. package/src/features/agent/chat/ModernAgentConversation.test.tsx +48 -0
  295. package/src/features/agent/chat/ModernAgentConversation.tsx +53 -51
  296. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +6 -1
  297. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +21 -15
  298. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +3 -3
  299. package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +0 -2
  300. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +4 -1
  301. package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.test.ts +80 -0
  302. package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.ts +21 -1
  303. package/src/features/agent/chat/hooks/useArtifacts.ts +44 -11
  304. package/src/features/document-viewer/UniversalDocumentViewer.test.tsx +123 -0
  305. package/src/features/document-viewer/UniversalDocumentViewer.tsx +746 -0
  306. package/src/features/document-viewer/index.ts +1 -0
  307. package/src/features/environment/SelectEnvironment.tsx +186 -0
  308. package/src/features/environment/index.ts +1 -0
  309. package/src/features/index.ts +3 -0
  310. package/src/features/magic-pdf/AnnotatedImageSlider.tsx +62 -66
  311. package/src/features/magic-pdf/DownloadPopover.tsx +5 -48
  312. package/src/features/magic-pdf/ExtractedContentView.tsx +2 -14
  313. package/src/features/magic-pdf/GroundedExtractionAssistantPanel.tsx +86 -0
  314. package/src/features/magic-pdf/GroundedExtractionView.test.tsx +65 -0
  315. package/src/features/magic-pdf/GroundedExtractionView.tsx +1055 -0
  316. package/src/features/magic-pdf/MagicPdfProvider.tsx +17 -47
  317. package/src/features/magic-pdf/MagicPdfView.tsx +3 -51
  318. package/src/features/magic-pdf/index.ts +1 -0
  319. package/src/features/magic-pdf/types.ts +1 -1
  320. package/src/features/oauth/McpConnectionsButton.tsx +0 -2
  321. package/src/features/oauth/McpConnectionsDialog.tsx +0 -1
  322. package/src/features/oauth/RemoteMcpConnectionButton.tsx +0 -1
  323. package/src/features/pdf-viewer/PdfPageSlider.tsx +5 -5
  324. package/src/features/pdf-viewer/SimplePdfViewer.tsx +11 -12
  325. package/src/features/permissions/UserPermissionsProvider.tsx +36 -39
  326. package/src/features/store/objects/DocumentQuickFilter.tsx +13 -15
  327. package/src/features/store/objects/DocumentSearchResults.tsx +3 -6
  328. package/src/features/store/objects/components/ContentDispositionButton.tsx +5 -1
  329. package/src/features/store/objects/components/ContentOverview.tsx +240 -67
  330. package/src/features/store/objects/components/DocumentIcon.tsx +1 -1
  331. package/src/features/store/objects/components/VectorSearchWidget.tsx +2 -2
  332. package/src/features/store/objects/components/useContentPanelHooks.ts +3 -15
  333. package/src/features/store/objects/layout/renderers.tsx +1 -2
  334. package/src/features/store/objects/selection/SelectionActions.tsx +1 -1
  335. package/src/features/store/types/ContentObjectTypesTable.tsx +12 -14
  336. package/src/features/store/types/IntakePolicyEditor.tsx +679 -0
  337. package/src/features/store/types/IntakePolicyForm.tsx +838 -0
  338. package/src/features/store/types/SelectContentTypeModal.tsx +2 -2
  339. package/src/features/store/types/index.ts +2 -0
  340. package/src/features/store/types/intake-policy-editor.logic.test.ts +109 -0
  341. package/src/features/store/types/intake-policy-editor.logic.ts +87 -0
  342. package/src/features/store/types/typeCatalogCache.ts +45 -0
  343. package/src/features/user/UserInfo.tsx +7 -7
  344. package/src/features/views/ViewExperience.test.tsx +273 -0
  345. package/src/features/views/ViewExperience.tsx +408 -0
  346. package/src/features/views/ViewNavigation.test.tsx +86 -0
  347. package/src/features/views/ViewNavigation.tsx +187 -0
  348. package/src/features/views/ViewResults.test.ts +82 -0
  349. package/src/features/views/ViewResults.tsx +609 -0
  350. package/src/features/views/ViewSearch.test.tsx +147 -0
  351. package/src/features/views/ViewSearch.tsx +205 -0
  352. package/src/features/views/index.ts +6 -0
  353. package/src/features/views/types.ts +57 -0
  354. package/src/features/views/viewState.test.ts +111 -0
  355. package/src/features/views/viewState.ts +132 -0
  356. package/src/i18n/locales/ar.json +18 -0
  357. package/src/i18n/locales/de.json +14 -0
  358. package/src/i18n/locales/en.json +965 -751
  359. package/src/i18n/locales/es.json +15 -0
  360. package/src/i18n/locales/fr.json +15 -0
  361. package/src/i18n/locales/it.json +15 -0
  362. package/src/i18n/locales/ja.json +13 -0
  363. package/src/i18n/locales/ko.json +13 -0
  364. package/src/i18n/locales/pt.json +15 -0
  365. package/src/i18n/locales/ru.json +16 -0
  366. package/src/i18n/locales/tr.json +14 -0
  367. package/src/i18n/locales/zh-TW.json +13 -0
  368. package/src/i18n/locales/zh.json +13 -0
  369. package/src/router/HistoryNavigator.test.ts +48 -0
  370. package/src/router/HistoryNavigator.ts +28 -14
  371. package/src/router/Nav.tsx +24 -8
  372. package/src/router/Router.tsx +18 -4
  373. package/src/router/path.test.ts +87 -0
  374. package/src/router/path.ts +38 -0
  375. package/src/session/UserSession.test.ts +39 -0
  376. package/src/session/UserSession.ts +37 -12
  377. package/src/session/UserSessionProvider.tsx +138 -62
  378. package/src/session/auth/composable.test.ts +111 -0
  379. package/src/session/auth/composable.ts +58 -3
  380. package/src/session/auth/domainRouting.test.ts +28 -1
  381. package/src/session/auth/domainRouting.ts +38 -0
  382. package/src/shell/login/SignInRestrictedEnvStep.tsx +1 -1
  383. package/src/shell/login/SigninScreen.tsx +9 -1
  384. package/src/shell/login/productionUrl.test.ts +8 -5
  385. package/src/shell/login/productionUrl.ts +15 -5
  386. package/src/widgets/form/Form.tsx +1 -1
  387. package/src/widgets/json-view/JSONSwitcher.tsx +2 -2
  388. package/src/widgets/json-view/JSONView.tsx +7 -7
  389. package/src/widgets/monacoEditor/MonacoEditor.tsx +29 -0
  390. package/src/widgets/schema-editor/ManagedSchema.ts +22 -0
  391. package/src/widgets/schema-editor/editor/EditableSchemaProperty.tsx +3 -0
  392. package/src/widgets/schema-editor/editor/PropertyViewer.tsx +14 -3
  393. package/src/widgets/schema-editor/editor/SchemaEditor.tsx +80 -29
@@ -0,0 +1 @@
1
+ export * from './UniversalDocumentViewer.js';
@@ -0,0 +1,186 @@
1
+ import type { ExecutionEnvironmentRef } from '@vertesia/common';
2
+ import { SelectBox, useFetch, useFetchOnce } from '@vertesia/ui/core';
3
+ import { useUITranslation } from '@vertesia/ui/i18n';
4
+ import { useUserSession } from '@vertesia/ui/session';
5
+ import { useEffect, useState } from 'react';
6
+
7
+ type EnvironmentModel = NonNullable<ExecutionEnvironmentRef['enabled_models']>[number];
8
+
9
+ function environmentLabel(option: ExecutionEnvironmentRef) {
10
+ return option.name;
11
+ }
12
+
13
+ interface SelectEnvironmentProps {
14
+ onChange: (environment?: ExecutionEnvironmentRef) => void;
15
+ isClearable?: boolean;
16
+ ignoreVirtuals?: boolean;
17
+ selectedEnvId?: string;
18
+ disabled?: boolean;
19
+ }
20
+
21
+ export function SelectEnvironment({
22
+ isClearable = false,
23
+ onChange,
24
+ ignoreVirtuals = false,
25
+ selectedEnvId,
26
+ disabled = false,
27
+ }: SelectEnvironmentProps) {
28
+ const { t } = useUITranslation();
29
+ const { client } = useUserSession();
30
+ const [value, setValue] = useState<ExecutionEnvironmentRef | undefined>();
31
+ const { data: environments, isLoading } = useFetchOnce(() =>
32
+ client.environments.list().then((result) => {
33
+ const available = ignoreVirtuals
34
+ ? result.filter((environment) => !environment.provider.startsWith('virtual_'))
35
+ : result;
36
+ return available.slice().sort((left, right) => left.name.localeCompare(right.name));
37
+ }),
38
+ );
39
+
40
+ useEffect(() => {
41
+ setValue(environments?.find((environment) => environment.id === selectedEnvId));
42
+ }, [environments, selectedEnvId]);
43
+
44
+ return (
45
+ <SelectBox
46
+ isClearable={isClearable}
47
+ optionLabel={environmentLabel}
48
+ options={environments ?? []}
49
+ value={value}
50
+ onChange={(environment) => {
51
+ setValue(environment);
52
+ onChange(environment);
53
+ }}
54
+ placeholder={t('intakePolicy.placeholder.environment')}
55
+ filterBy="name"
56
+ disabled={disabled}
57
+ isLoading={isLoading}
58
+ />
59
+ );
60
+ }
61
+
62
+ function modelLabel(option: EnvironmentModel) {
63
+ return option.name;
64
+ }
65
+
66
+ function createModelLabel(greyedModels?: EnvironmentModel[]) {
67
+ if (!greyedModels?.length) {
68
+ return modelLabel;
69
+ }
70
+ return (option: EnvironmentModel) => {
71
+ const isGreyed = greyedModels.some((model) => model.id === option.id);
72
+ return <span className={isGreyed ? 'opacity-50' : ''}>{option.name}</span>;
73
+ };
74
+ }
75
+
76
+ interface SelectModelProps {
77
+ envId: string | undefined;
78
+ onChange: (model?: EnvironmentModel) => void;
79
+ isClearable?: boolean;
80
+ selectedModelId?: string;
81
+ disabled?: boolean;
82
+ greyedModels?: EnvironmentModel[];
83
+ onModelsLoaded?: (models: EnvironmentModel[]) => void;
84
+ }
85
+
86
+ export function SelectModel({
87
+ envId,
88
+ isClearable,
89
+ onChange,
90
+ selectedModelId,
91
+ disabled = false,
92
+ greyedModels,
93
+ onModelsLoaded,
94
+ }: SelectModelProps) {
95
+ const { t } = useUITranslation();
96
+ const { client } = useUserSession();
97
+ const [value, setValue] = useState<EnvironmentModel | undefined>();
98
+ const { data: models, isLoading } = useFetch(async () => {
99
+ if (!envId) {
100
+ return [];
101
+ }
102
+ try {
103
+ const environment = await client.environments.retrieve(envId);
104
+ return [...(environment.enabled_models ?? [])].sort((left, right) => left.name.localeCompare(right.name));
105
+ } catch {
106
+ return [];
107
+ }
108
+ }, [envId]);
109
+
110
+ useEffect(() => {
111
+ if (!selectedModelId) {
112
+ setValue(undefined);
113
+ return;
114
+ }
115
+ const selected = models?.find((model) => model.id === selectedModelId);
116
+ setValue(
117
+ selected ?? {
118
+ id: selectedModelId,
119
+ name: selectedModelId,
120
+ provider: 'unknown',
121
+ },
122
+ );
123
+ }, [models, selectedModelId]);
124
+
125
+ useEffect(() => {
126
+ if (models) {
127
+ onModelsLoaded?.(models);
128
+ }
129
+ }, [models, onModelsLoaded]);
130
+
131
+ return (
132
+ <SelectBox
133
+ isClearable={isClearable}
134
+ by="id"
135
+ optionLabel={createModelLabel(greyedModels)}
136
+ options={models ?? []}
137
+ value={value}
138
+ onChange={(model) => {
139
+ setValue(model);
140
+ onChange(model);
141
+ }}
142
+ placeholder={t('intakePolicy.placeholder.model')}
143
+ disabled={disabled}
144
+ isLoading={isLoading}
145
+ />
146
+ );
147
+ }
148
+
149
+ interface SelectTrainingModelProps {
150
+ env: ExecutionEnvironmentRef | undefined;
151
+ onChange: (model?: EnvironmentModel) => void;
152
+ isClearable?: boolean;
153
+ }
154
+
155
+ export function SelectTrainingModel({ env, isClearable, onChange }: SelectTrainingModelProps) {
156
+ const { t } = useUITranslation();
157
+ const { client } = useUserSession();
158
+ const [value, setValue] = useState<EnvironmentModel | undefined>();
159
+ const { data: models, isLoading } = useFetch(async () => {
160
+ if (!env) {
161
+ return [];
162
+ }
163
+ try {
164
+ return client.environments.listTrainableModels(env.id);
165
+ } catch {
166
+ return [];
167
+ }
168
+ }, [env?.id]);
169
+
170
+ return (
171
+ <SelectBox
172
+ isClearable={isClearable}
173
+ by="id"
174
+ optionLabel={modelLabel}
175
+ options={models ?? []}
176
+ value={value}
177
+ onChange={(model) => {
178
+ setValue(model);
179
+ onChange(model);
180
+ }}
181
+ placeholder={t('intakePolicy.placeholder.model')}
182
+ disabled={!env}
183
+ isLoading={isLoading}
184
+ />
185
+ );
186
+ }
@@ -0,0 +1 @@
1
+ export * from './SelectEnvironment.js';
@@ -1,5 +1,7 @@
1
1
  export * from './activity-doc/index.js';
2
2
  export * from './agent';
3
+ export * from './document-viewer/index.js';
4
+ export * from './environment/index.js';
3
5
  export * from './errors/index.js';
4
6
  export * from './facets/index.js';
5
7
  export * from './layout/index.js';
@@ -11,3 +13,4 @@ export * from './permissions/index.js';
11
13
  export * from './store/index.js';
12
14
  export * from './user/index.js';
13
15
  export * from './utils/index.js';
16
+ export * from './views/index.js';
@@ -1,4 +1,4 @@
1
- import { Button, Center, VTooltip } from '@vertesia/ui/core';
1
+ import { Button, Center } from '@vertesia/ui/core';
2
2
  import { useUITranslation } from '@vertesia/ui/i18n';
3
3
  import clsx from 'clsx';
4
4
  import { ChevronsDown, ChevronsUp, Image, Loader2, Maximize, Minus, Plus, ScanSearch } from 'lucide-react';
@@ -255,7 +255,7 @@ export function AnnotatedImageSlider({ className, currentPage, onChange }: Annot
255
255
  return (
256
256
  <div ref={ref} className={clsx('flex flex-col items-stretch gap-y-2', className)}>
257
257
  <div className="relative flex items-center justify-center px-2 h-9">
258
- <Button variant="ghost" size="xs" onClick={goPrev} alt={t('pdf.previousPage')}>
258
+ <Button variant="ghost" size="xs" onClick={goPrev} title={t('pdf.previousPage')}>
259
259
  <ChevronsUp className="size-4" />
260
260
  </Button>
261
261
  <div className="absolute start-2 flex items-center gap-x-1">
@@ -301,7 +301,7 @@ export function AnnotatedImageSlider({ className, currentPage, onChange }: Annot
301
301
  ))}
302
302
  </div>
303
303
  <div className="flex items-center justify-center h-9">
304
- <Button variant="ghost" size="xs" onClick={goNext} alt={t('pdf.nextPage')}>
304
+ <Button variant="ghost" size="xs" onClick={goNext} title={t('pdf.nextPage')}>
305
305
  <ChevronsDown className="size-4" />
306
306
  </Button>
307
307
  </div>
@@ -319,22 +319,21 @@ interface ImageTypeButtonProps {
319
319
  function ImageTypeButton({ type, currentType, onClick, icon, tooltip }: ImageTypeButtonProps) {
320
320
  const isSelected = type === currentType;
321
321
  return (
322
- <VTooltip description={tooltip} placement="bottom" size="xs">
323
- <Button
324
- variant="unstyled"
325
- aria-label={tooltip}
326
- aria-pressed={isSelected}
327
- className={clsx(
328
- 'p-1 rounded cursor-pointer transition-colors',
329
- isSelected
330
- ? 'text-primary bg-primary/10'
331
- : 'text-muted-foreground hover:text-foreground hover:bg-muted',
332
- )}
333
- onClick={onClick}
334
- >
335
- {icon}
336
- </Button>
337
- </VTooltip>
322
+ <Button
323
+ title={tooltip}
324
+ tooltipPlacement="bottom"
325
+ variant="unstyled"
326
+ aria-pressed={isSelected}
327
+ className={clsx(
328
+ 'p-1 rounded cursor-pointer transition-colors',
329
+ isSelected
330
+ ? 'text-primary bg-primary/10'
331
+ : 'text-muted-foreground hover:text-foreground hover:bg-muted',
332
+ )}
333
+ onClick={onClick}
334
+ >
335
+ {icon}
336
+ </Button>
338
337
  );
339
338
  }
340
339
 
@@ -350,54 +349,51 @@ function ZoomControls({ zoom, onZoomIn, onZoomOut, onFitToView, canZoomIn, canZo
350
349
  const { t } = useUITranslation();
351
350
  return (
352
351
  <div className="flex items-center gap-x-0.5">
353
- <VTooltip description={t('pdf.zoomOut')} placement="bottom" size="xs">
354
- <Button
355
- variant="unstyled"
356
- aria-label={t('pdf.zoomOut')}
357
- className={clsx(
358
- 'p-1 rounded cursor-pointer transition-colors',
359
- canZoomOut
360
- ? 'text-muted-foreground hover:text-foreground hover:bg-muted'
361
- : 'text-muted-foreground/40 cursor-not-allowed',
362
- )}
363
- onClick={onZoomOut}
364
- disabled={!canZoomOut}
365
- >
366
- <Minus className="size-4" />
367
- </Button>
368
- </VTooltip>
352
+ <Button
353
+ title={t('pdf.zoomOut')}
354
+ tooltipPlacement="bottom"
355
+ variant="unstyled"
356
+ className={clsx(
357
+ 'p-1 rounded cursor-pointer transition-colors',
358
+ canZoomOut
359
+ ? 'text-muted-foreground hover:text-foreground hover:bg-muted'
360
+ : 'text-muted-foreground/40 cursor-not-allowed',
361
+ )}
362
+ onClick={onZoomOut}
363
+ disabled={!canZoomOut}
364
+ >
365
+ <Minus className="size-4" />
366
+ </Button>
369
367
  <span className="text-xs text-muted-foreground min-w-[32px] text-center">{zoom}%</span>
370
- <VTooltip description={t('pdf.zoomIn')} placement="bottom" size="xs">
371
- <Button
372
- variant="unstyled"
373
- aria-label={t('pdf.zoomIn')}
374
- className={clsx(
375
- 'p-1 rounded cursor-pointer transition-colors',
376
- canZoomIn
377
- ? 'text-muted-foreground hover:text-foreground hover:bg-muted'
378
- : 'text-muted-foreground/40 cursor-not-allowed',
379
- )}
380
- onClick={onZoomIn}
381
- disabled={!canZoomIn}
382
- >
383
- <Plus className="size-4" />
384
- </Button>
385
- </VTooltip>
386
- <VTooltip description={t('pdf.fitToWidth')} placement="bottom" size="xs">
387
- <Button
388
- variant="unstyled"
389
- aria-label={t('pdf.fitToWidth')}
390
- className={clsx(
391
- 'p-1 rounded cursor-pointer transition-colors',
392
- zoom !== DEFAULT_ZOOM
393
- ? 'text-muted-foreground hover:text-foreground hover:bg-muted'
394
- : 'text-muted-foreground/40',
395
- )}
396
- onClick={onFitToView}
397
- >
398
- <Maximize className="size-4" />
399
- </Button>
400
- </VTooltip>
368
+ <Button
369
+ title={t('pdf.zoomIn')}
370
+ tooltipPlacement="bottom"
371
+ variant="unstyled"
372
+ className={clsx(
373
+ 'p-1 rounded cursor-pointer transition-colors',
374
+ canZoomIn
375
+ ? 'text-muted-foreground hover:text-foreground hover:bg-muted'
376
+ : 'text-muted-foreground/40 cursor-not-allowed',
377
+ )}
378
+ onClick={onZoomIn}
379
+ disabled={!canZoomIn}
380
+ >
381
+ <Plus className="size-4" />
382
+ </Button>
383
+ <Button
384
+ title={t('pdf.fitToWidth')}
385
+ tooltipPlacement="bottom"
386
+ variant="unstyled"
387
+ className={clsx(
388
+ 'p-1 rounded cursor-pointer transition-colors',
389
+ zoom !== DEFAULT_ZOOM
390
+ ? 'text-muted-foreground hover:text-foreground hover:bg-muted'
391
+ : 'text-muted-foreground/40',
392
+ )}
393
+ onClick={onFitToView}
394
+ >
395
+ <Maximize className="size-4" />
396
+ </Button>
401
397
  </div>
402
398
  );
403
399
  }
@@ -1,5 +1,5 @@
1
- import type { ContentObject, DocumentMetadata } from '@vertesia/common';
2
- import { Button, Popover, PopoverContent, PopoverTrigger } from '@vertesia/ui/core';
1
+ import type { ContentObject } from '@vertesia/common';
2
+ import { Button } from '@vertesia/ui/core';
3
3
  import { useUITranslation } from '@vertesia/ui/i18n';
4
4
  import { useUserSession } from '@vertesia/ui/session';
5
5
  import { Download } from 'lucide-react';
@@ -15,52 +15,9 @@ export function DownloadPopover({ object }: DownloadPopoverProps) {
15
15
  void getResourceUrl(client, object.id, name).then((url) => window.open(url, '_blank'));
16
16
  };
17
17
 
18
- const getProcessorType = (): string => {
19
- if (object.metadata?.type === 'document') {
20
- const docMetadata = object.metadata as DocumentMetadata;
21
- return docMetadata.content_processor?.type || 'xml';
22
- }
23
- return 'xml'; // default
24
- };
25
-
26
- const processorType = getProcessorType();
27
-
28
- const buttonClass = 'p-2 cursor-pointer hover:bg-muted text-start text-sm';
29
-
30
- // For markdown processor, only one download option - render simple button
31
- if (processorType === 'markdown') {
32
- return (
33
- <Button variant="ghost" size="xs" onClick={() => onDownload('document.md')} alt={t('pdf.download')}>
34
- <Download className="size-4" />
35
- </Button>
36
- );
37
- }
38
-
39
- // Default XML processor - multiple options, use popover
40
18
  return (
41
- <Popover>
42
- <PopoverTrigger>
43
- <Button variant="ghost" size="xs" alt={t('pdf.download')}>
44
- <Download className="size-4" />
45
- </Button>
46
- </PopoverTrigger>
47
- <PopoverContent align="start" className="p-0 w-auto">
48
- <div className="min-w-[200px] flex flex-col divide-y divide-border">
49
- <Button variant="unstyled" className={buttonClass} onClick={() => onDownload('annotated.pdf')}>
50
- annotated.pdf
51
- </Button>
52
- <Button variant="unstyled" className={buttonClass} onClick={() => onDownload('document.xml')}>
53
- document.xml
54
- </Button>
55
- <Button
56
- variant="unstyled"
57
- className={buttonClass}
58
- onClick={() => onDownload('analyzed-pages.json')}
59
- >
60
- analyzed-pages.json
61
- </Button>
62
- </div>
63
- </PopoverContent>
64
- </Popover>
19
+ <Button variant="ghost" size="xs" onClick={() => onDownload('document.md')} title={t('pdf.download')}>
20
+ <Download className="size-4" />
21
+ </Button>
65
22
  );
66
23
  }
@@ -1,4 +1,4 @@
1
- import { JSONCode, MarkdownRenderer, XMLViewer } from '@vertesia/ui/widgets';
1
+ import { JSONCode, MarkdownRenderer } from '@vertesia/ui/widgets';
2
2
  import { Loader2 } from 'lucide-react';
3
3
  import { useEffect, useState } from 'react';
4
4
  import { useMagicPdfContext } from './MagicPdfProvider';
@@ -23,22 +23,10 @@ export function ExtractedContentView({ viewType, pageNumber }: ExtractedContentV
23
23
  case 'markdown':
24
24
  return <MarkdownPageView pageNumber={pageNumber} />;
25
25
  default:
26
- return <XmlPageView pageNumber={pageNumber} />;
26
+ return <MarkdownPageView pageNumber={pageNumber} />;
27
27
  }
28
28
  }
29
29
 
30
- interface XmlPageViewProps {
31
- pageNumber: number;
32
- }
33
- function XmlPageView({ pageNumber }: XmlPageViewProps) {
34
- const { xmlPages: pages } = useMagicPdfContext();
35
- return (
36
- <div className="px-4 py-2">
37
- <XMLViewer xml={pages[pageNumber - 1]} collapsible />
38
- </div>
39
- );
40
- }
41
-
42
30
  interface JsonPageLayoutViewProps {
43
31
  pageNumber: number;
44
32
  }
@@ -0,0 +1,86 @@
1
+ import { useUITranslation } from '@vertesia/ui/i18n';
2
+ import { useUserSession } from '@vertesia/ui/session';
3
+ import { useCallback, useRef, useState } from 'react';
4
+ import { ModernAgentConversation, type StartWorkflowFn } from '../agent/chat';
5
+
6
+ interface GroundedExtractionAssistantPanelProps {
7
+ objectId: string;
8
+ /**
9
+ * Called after the assistant finishes a turn (which may have applied a grounded
10
+ * edit) so the grounded view can re-fetch and re-render the data + citation boxes.
11
+ */
12
+ onExtractionChanged?: () => void;
13
+ /**
14
+ * The field path currently selected in the view. When set (before the
15
+ * conversation starts), it seeds the assistant: the first message is scoped to
16
+ * this field so "click a field, say what's wrong" reaches the model.
17
+ */
18
+ selectedField?: string;
19
+ onClose?: () => void;
20
+ }
21
+
22
+ /**
23
+ * Interactive assistant embedded in the grounded-extraction view. Starts the
24
+ * server-side GroundedExtractionAssistant conversation (recordRun -> stage the
25
+ * document into the agent space -> launch interactive), then renders the live
26
+ * conversation. Each completed turn triggers `onExtractionChanged` so an operator's
27
+ * grounded edits appear in the data tree + citation overlay without a manual reload.
28
+ */
29
+ export function GroundedExtractionAssistantPanel({
30
+ objectId,
31
+ onExtractionChanged,
32
+ selectedField,
33
+ onClose,
34
+ }: GroundedExtractionAssistantPanelProps) {
35
+ const { t } = useUITranslation();
36
+ const { client } = useUserSession();
37
+ const [agentRunId, setAgentRunId] = useState<string | undefined>(undefined);
38
+ // Keep the latest callback/selection without re-creating the handlers each render.
39
+ const changedRef = useRef(onExtractionChanged);
40
+ changedRef.current = onExtractionChanged;
41
+ const selectedRef = useRef(selectedField);
42
+ selectedRef.current = selectedField;
43
+
44
+ const startWorkflow: StartWorkflowFn = useCallback(
45
+ async (initialMessage) => {
46
+ const field = selectedRef.current;
47
+ // Scope the opening message to the field the operator had selected, so
48
+ // "click a field, say what's wrong" reaches the model with the target.
49
+ const prompt =
50
+ field && initialMessage ? `Regarding the field "${field}": ${initialMessage}` : initialMessage;
51
+ const res = await client.store.objects
52
+ .analyze(objectId)
53
+ .startGroundedAssistant(prompt ? { user_prompt: prompt } : {});
54
+ setAgentRunId(res.agent_run_id);
55
+ return { agent_run_id: res.agent_run_id };
56
+ },
57
+ [client, objectId],
58
+ );
59
+
60
+ // The agent re-enables the follow-up input when a turn completes; that turn may
61
+ // have applied a grounded edit, so refresh the extraction at that point.
62
+ const handleShowInputChange = useCallback((canSendFollowUp: boolean) => {
63
+ if (canSendFollowUp) {
64
+ changedRef.current?.();
65
+ }
66
+ }, []);
67
+
68
+ return (
69
+ <div className="flex h-full flex-col">
70
+ {selectedField && !agentRunId && (
71
+ <div className="shrink-0 border-b border-border bg-muted/40 px-3 py-1.5 text-xs text-muted-foreground">
72
+ {t('grounded.assistantField')} <span className="font-mono text-foreground">{selectedField}</span>
73
+ </div>
74
+ )}
75
+ <ModernAgentConversation
76
+ agentRunId={agentRunId}
77
+ startWorkflow={startWorkflow}
78
+ interactive
79
+ fullWidth
80
+ hideObjectLinking
81
+ onShowInputChange={handleShowInputChange}
82
+ onClose={onClose}
83
+ />
84
+ </div>
85
+ );
86
+ }
@@ -0,0 +1,65 @@
1
+ import { fireEvent, screen, waitFor } from '@testing-library/react';
2
+ import { afterEach, describe, expect, it, vi } from 'vitest';
3
+ import { renderWithProviders } from '../../__tests__/test-utils.js';
4
+ import { GroundedExtractionPanel } from './GroundedExtractionView.js';
5
+
6
+ const { mockClient } = vi.hoisted(() => {
7
+ const downloadUrl = vi.fn((path: string) => Promise.resolve({ url: `https://files.test/${path}` }));
8
+ return {
9
+ mockClient: { files: { getDownloadUrl: downloadUrl } },
10
+ };
11
+ });
12
+
13
+ vi.mock('@vertesia/ui/session', () => ({
14
+ useUserSession: () => ({
15
+ client: mockClient,
16
+ }),
17
+ }));
18
+
19
+ describe('GroundedExtractionPanel', () => {
20
+ afterEach(() => {
21
+ vi.restoreAllMocks();
22
+ });
23
+
24
+ it('switches between the original and checkerboard page and shows the selected A1 range', async () => {
25
+ const extraction = {
26
+ version: 1,
27
+ object_id: 'object-1',
28
+ run_id: 'run-1',
29
+ generated_at: '2026-07-13T16:30:27.418Z',
30
+ pages: { '1': { width: 612, height: 792 } },
31
+ data: { part_number: 'DFVS25' },
32
+ citations: [
33
+ {
34
+ path: 'part_number',
35
+ page: 1,
36
+ block_ids: [],
37
+ cells: { start: 'E38', end: 'J38' },
38
+ verified: false,
39
+ reviewed: true,
40
+ value: 'DFVS25',
41
+ boxes: [{ x: 59.7, y: 552.9, w: 89.6, h: 17.4 }],
42
+ confidence: 0.99,
43
+ },
44
+ ],
45
+ };
46
+ vi.spyOn(globalThis, 'fetch').mockResolvedValueOnce(
47
+ new Response(JSON.stringify(extraction), {
48
+ status: 200,
49
+ headers: { 'Content-Type': 'application/json' },
50
+ }),
51
+ );
52
+
53
+ renderWithProviders(<GroundedExtractionPanel objectId="object-1" />);
54
+
55
+ const pageImage = await screen.findByAltText('Page 1');
56
+ expect(pageImage.getAttribute('src')).toContain('page-1.original.jpg');
57
+
58
+ fireEvent.click(screen.getByRole('button', { name: 'Checkerboard' }));
59
+ await waitFor(() => expect(screen.getByAltText('Page 1').getAttribute('src')).toContain('page-1.grid.jpg'));
60
+
61
+ fireEvent.click(screen.getByText('DFVS25'));
62
+ expect(screen.getByText('E38:J38')).not.toBeNull();
63
+ expect(screen.getByRole('button', { name: 'part_number' }).getAttribute('title')).toContain('E38:J38');
64
+ });
65
+ });