@vertesia/ui 0.80.0-dev.20251121 → 0.80.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 (277) hide show
  1. package/README.md +105 -0
  2. package/lib/esm/core/components/MenuList.js +2 -5
  3. package/lib/esm/core/components/MenuList.js.map +1 -1
  4. package/lib/esm/core/components/MessageBox.js +1 -1
  5. package/lib/esm/core/components/MessageBox.js.map +1 -1
  6. package/lib/esm/core/components/shadcn/dialog.js +16 -2
  7. package/lib/esm/core/components/shadcn/dialog.js.map +1 -1
  8. package/lib/esm/core/components/shadcn/filters/filter/SelectFilter.js +6 -9
  9. package/lib/esm/core/components/shadcn/filters/filter/SelectFilter.js.map +1 -1
  10. package/lib/esm/core/components/shadcn/filters/filterBar.js +1 -1
  11. package/lib/esm/core/components/shadcn/filters/filterBar.js.map +1 -1
  12. package/lib/esm/core/components/shadcn/selectBox.js +23 -5
  13. package/lib/esm/core/components/shadcn/selectBox.js.map +1 -1
  14. package/lib/esm/core/components/shadcn/tabs.js +3 -3
  15. package/lib/esm/core/components/shadcn/tabs.js.map +1 -1
  16. package/lib/esm/env/index.js +3 -0
  17. package/lib/esm/env/index.js.map +1 -1
  18. package/lib/esm/features/agent/chat/AgentChart.js +184 -0
  19. package/lib/esm/features/agent/chat/AgentChart.js.map +1 -0
  20. package/lib/esm/features/agent/chat/ModernAgentConversation.js +87 -10
  21. package/lib/esm/features/agent/chat/ModernAgentConversation.js.map +1 -1
  22. package/lib/esm/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +6 -2
  23. package/lib/esm/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  24. package/lib/esm/features/agent/chat/ModernAgentOutput/Header.js +4 -4
  25. package/lib/esm/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  26. package/lib/esm/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.js +4 -1
  27. package/lib/esm/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.js.map +1 -1
  28. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageInput.js +12 -4
  29. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
  30. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageItem.js +60 -56
  31. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  32. package/lib/esm/features/agent/chat/index.js +1 -0
  33. package/lib/esm/features/agent/chat/index.js.map +1 -1
  34. package/lib/esm/features/agent/createChartTool.js +354 -0
  35. package/lib/esm/features/agent/createChartTool.js.map +1 -0
  36. package/lib/esm/features/agent/examples.js +295 -0
  37. package/lib/esm/features/agent/examples.js.map +1 -0
  38. package/lib/esm/features/agent/index.js +2 -0
  39. package/lib/esm/features/agent/index.js.map +1 -1
  40. package/lib/esm/features/agent/visualization.js +165 -0
  41. package/lib/esm/features/agent/visualization.js.map +1 -0
  42. package/lib/esm/features/facets/CollectionsFacetsNav.js +5 -1
  43. package/lib/esm/features/facets/CollectionsFacetsNav.js.map +1 -1
  44. package/lib/esm/features/index.js +1 -0
  45. package/lib/esm/features/index.js.map +1 -1
  46. package/lib/esm/features/layout/GenericPageNavHeader.js +14 -4
  47. package/lib/esm/features/layout/GenericPageNavHeader.js.map +1 -1
  48. package/lib/esm/features/magic-pdf/AnnotatedImageSlider.js +268 -0
  49. package/lib/esm/features/magic-pdf/AnnotatedImageSlider.js.map +1 -0
  50. package/lib/esm/features/magic-pdf/DownloadPopover.js +11 -11
  51. package/lib/esm/features/magic-pdf/DownloadPopover.js.map +1 -1
  52. package/lib/esm/features/magic-pdf/ExtractedContentView.js +77 -0
  53. package/lib/esm/features/magic-pdf/ExtractedContentView.js.map +1 -0
  54. package/lib/esm/features/magic-pdf/MagicPdfProvider.js +242 -0
  55. package/lib/esm/features/magic-pdf/MagicPdfProvider.js.map +1 -0
  56. package/lib/esm/features/magic-pdf/MagicPdfView.js +41 -47
  57. package/lib/esm/features/magic-pdf/MagicPdfView.js.map +1 -1
  58. package/lib/esm/features/pdf-viewer/PdfPageRenderer.js +261 -0
  59. package/lib/esm/features/pdf-viewer/PdfPageRenderer.js.map +1 -0
  60. package/lib/esm/features/pdf-viewer/PdfPageSlider.js +276 -0
  61. package/lib/esm/features/pdf-viewer/PdfPageSlider.js.map +1 -0
  62. package/lib/esm/features/pdf-viewer/SimplePdfViewer.js +71 -0
  63. package/lib/esm/features/pdf-viewer/SimplePdfViewer.js.map +1 -0
  64. package/lib/esm/features/pdf-viewer/index.js +4 -0
  65. package/lib/esm/features/pdf-viewer/index.js.map +1 -0
  66. package/lib/esm/features/store/collections/EditCollectionView.js +3 -5
  67. package/lib/esm/features/store/collections/EditCollectionView.js.map +1 -1
  68. package/lib/esm/features/store/collections/SharedPropsEditor.js +1 -2
  69. package/lib/esm/features/store/collections/SharedPropsEditor.js.map +1 -1
  70. package/lib/esm/features/store/objects/DocumentSearchResults.js +0 -7
  71. package/lib/esm/features/store/objects/DocumentSearchResults.js.map +1 -1
  72. package/lib/esm/features/store/objects/components/ContentOverview.js +273 -83
  73. package/lib/esm/features/store/objects/components/ContentOverview.js.map +1 -1
  74. package/lib/esm/features/store/objects/components/useContentPanelHooks.js +153 -0
  75. package/lib/esm/features/store/objects/components/useContentPanelHooks.js.map +1 -0
  76. package/lib/esm/features/store/objects/layout/DocumentTableColumn.js +3 -3
  77. package/lib/esm/features/store/objects/layout/DocumentTableColumn.js.map +1 -1
  78. package/lib/esm/features/store/objects/layout/renderers.js +13 -0
  79. package/lib/esm/features/store/objects/layout/renderers.js.map +1 -1
  80. package/lib/esm/features/utils/index.js +2 -0
  81. package/lib/esm/features/utils/index.js.map +1 -1
  82. package/lib/esm/features/utils/mimeType.js +8 -0
  83. package/lib/esm/features/utils/mimeType.js.map +1 -1
  84. package/lib/esm/features/utils/print.js +181 -0
  85. package/lib/esm/features/utils/print.js.map +1 -0
  86. package/lib/esm/features/utils/workflowStatus.js +43 -0
  87. package/lib/esm/features/utils/workflowStatus.js.map +1 -0
  88. package/lib/esm/router/HistoryNavigator.js +22 -2
  89. package/lib/esm/router/HistoryNavigator.js.map +1 -1
  90. package/lib/esm/shell/login/UserInfo.js +2 -1
  91. package/lib/esm/shell/login/UserInfo.js.map +1 -1
  92. package/lib/esm/shell/login/UserSessionMenu.js +7 -1
  93. package/lib/esm/shell/login/UserSessionMenu.js.map +1 -1
  94. package/lib/esm/widgets/form/Form.js +6 -2
  95. package/lib/esm/widgets/form/Form.js.map +1 -1
  96. package/lib/esm/widgets/markdown/MarkdownRenderer.js +226 -4
  97. package/lib/esm/widgets/markdown/MarkdownRenderer.js.map +1 -1
  98. package/lib/esm/widgets/schema-editor/ManagedSchema.js +0 -3
  99. package/lib/esm/widgets/schema-editor/ManagedSchema.js.map +1 -1
  100. package/lib/esm/widgets/schema-editor/json-schema4-utils.js +1 -1
  101. package/lib/esm/widgets/schema-editor/json-schema4-utils.js.map +1 -1
  102. package/lib/esm/widgets/xml-viewer/components/XMLViewer.js +18 -9
  103. package/lib/esm/widgets/xml-viewer/components/XMLViewer.js.map +1 -1
  104. package/lib/esm/widgets/xml-viewer/constants/index.js +10 -0
  105. package/lib/esm/widgets/xml-viewer/constants/index.js.map +1 -1
  106. package/lib/tsconfig.tsbuildinfo +1 -1
  107. package/lib/types/core/components/MessageBox.d.ts.map +1 -1
  108. package/lib/types/core/components/shadcn/dialog.d.ts +2 -1
  109. package/lib/types/core/components/shadcn/dialog.d.ts.map +1 -1
  110. package/lib/types/core/components/shadcn/filters/filterBar.d.ts.map +1 -1
  111. package/lib/types/core/components/shadcn/selectBox.d.ts +5 -1
  112. package/lib/types/core/components/shadcn/selectBox.d.ts.map +1 -1
  113. package/lib/types/core/components/shadcn/tabs.d.ts +3 -1
  114. package/lib/types/core/components/shadcn/tabs.d.ts.map +1 -1
  115. package/lib/types/env/index.d.ts +2 -0
  116. package/lib/types/env/index.d.ts.map +1 -1
  117. package/lib/types/features/agent/chat/AgentChart.d.ts +48 -0
  118. package/lib/types/features/agent/chat/AgentChart.d.ts.map +1 -0
  119. package/lib/types/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  120. package/lib/types/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +3 -2
  121. package/lib/types/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  122. package/lib/types/features/agent/chat/ModernAgentOutput/Header.d.ts +2 -1
  123. package/lib/types/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
  124. package/lib/types/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.d.ts +4 -2
  125. package/lib/types/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.d.ts.map +1 -1
  126. package/lib/types/features/agent/chat/ModernAgentOutput/MessageInput.d.ts +2 -4
  127. package/lib/types/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
  128. package/lib/types/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  129. package/lib/types/features/agent/chat/index.d.ts +1 -0
  130. package/lib/types/features/agent/chat/index.d.ts.map +1 -1
  131. package/lib/types/features/agent/createChartTool.d.ts +178 -0
  132. package/lib/types/features/agent/createChartTool.d.ts.map +1 -0
  133. package/lib/types/features/agent/examples.d.ts +59 -0
  134. package/lib/types/features/agent/examples.d.ts.map +1 -0
  135. package/lib/types/features/agent/index.d.ts +2 -0
  136. package/lib/types/features/agent/index.d.ts.map +1 -1
  137. package/lib/types/features/agent/visualization.d.ts +95 -0
  138. package/lib/types/features/agent/visualization.d.ts.map +1 -0
  139. package/lib/types/features/facets/CollectionsFacetsNav.d.ts.map +1 -1
  140. package/lib/types/features/index.d.ts +1 -0
  141. package/lib/types/features/index.d.ts.map +1 -1
  142. package/lib/types/features/layout/GenericPageNavHeader.d.ts.map +1 -1
  143. package/lib/types/features/magic-pdf/AnnotatedImageSlider.d.ts +13 -0
  144. package/lib/types/features/magic-pdf/AnnotatedImageSlider.d.ts.map +1 -0
  145. package/lib/types/features/magic-pdf/DownloadPopover.d.ts.map +1 -1
  146. package/lib/types/features/magic-pdf/ExtractedContentView.d.ts +8 -0
  147. package/lib/types/features/magic-pdf/ExtractedContentView.d.ts.map +1 -0
  148. package/lib/types/features/magic-pdf/MagicPdfProvider.d.ts +58 -0
  149. package/lib/types/features/magic-pdf/MagicPdfProvider.d.ts.map +1 -0
  150. package/lib/types/features/magic-pdf/MagicPdfView.d.ts +1 -1
  151. package/lib/types/features/magic-pdf/MagicPdfView.d.ts.map +1 -1
  152. package/lib/types/features/pdf-viewer/PdfPageRenderer.d.ts +83 -0
  153. package/lib/types/features/pdf-viewer/PdfPageRenderer.d.ts.map +1 -0
  154. package/lib/types/features/pdf-viewer/PdfPageSlider.d.ts +29 -0
  155. package/lib/types/features/pdf-viewer/PdfPageSlider.d.ts.map +1 -0
  156. package/lib/types/features/pdf-viewer/SimplePdfViewer.d.ts +19 -0
  157. package/lib/types/features/pdf-viewer/SimplePdfViewer.d.ts.map +1 -0
  158. package/lib/types/features/pdf-viewer/index.d.ts +4 -0
  159. package/lib/types/features/pdf-viewer/index.d.ts.map +1 -0
  160. package/lib/types/features/store/collections/EditCollectionView.d.ts.map +1 -1
  161. package/lib/types/features/store/collections/SharedPropsEditor.d.ts.map +1 -1
  162. package/lib/types/features/store/objects/DocumentSearchResults.d.ts.map +1 -1
  163. package/lib/types/features/store/objects/components/ContentOverview.d.ts.map +1 -1
  164. package/lib/types/features/store/objects/components/useContentPanelHooks.d.ts +30 -0
  165. package/lib/types/features/store/objects/components/useContentPanelHooks.d.ts.map +1 -0
  166. package/lib/types/features/store/objects/layout/renderers.d.ts.map +1 -1
  167. package/lib/types/features/utils/index.d.ts +2 -0
  168. package/lib/types/features/utils/index.d.ts.map +1 -1
  169. package/lib/types/features/utils/mimeType.d.ts +1 -0
  170. package/lib/types/features/utils/mimeType.d.ts.map +1 -1
  171. package/lib/types/features/utils/print.d.ts +10 -0
  172. package/lib/types/features/utils/print.d.ts.map +1 -0
  173. package/lib/types/features/utils/workflowStatus.d.ts +10 -0
  174. package/lib/types/features/utils/workflowStatus.d.ts.map +1 -0
  175. package/lib/types/router/HistoryNavigator.d.ts +3 -0
  176. package/lib/types/router/HistoryNavigator.d.ts.map +1 -1
  177. package/lib/types/shell/login/UserInfo.d.ts.map +1 -1
  178. package/lib/types/shell/login/UserSessionMenu.d.ts.map +1 -1
  179. package/lib/types/widgets/form/Form.d.ts.map +1 -1
  180. package/lib/types/widgets/markdown/MarkdownRenderer.d.ts +5 -1
  181. package/lib/types/widgets/markdown/MarkdownRenderer.d.ts.map +1 -1
  182. package/lib/types/widgets/schema-editor/ManagedSchema.d.ts.map +1 -1
  183. package/lib/types/widgets/xml-viewer/components/XMLViewer.d.ts.map +1 -1
  184. package/lib/types/widgets/xml-viewer/constants/index.d.ts +10 -0
  185. package/lib/types/widgets/xml-viewer/constants/index.d.ts.map +1 -1
  186. package/lib/vertesia-ui-core.js +1 -1
  187. package/lib/vertesia-ui-core.js.map +1 -1
  188. package/lib/vertesia-ui-env.js +1 -1
  189. package/lib/vertesia-ui-env.js.map +1 -1
  190. package/lib/vertesia-ui-features.js +1 -1
  191. package/lib/vertesia-ui-features.js.map +1 -1
  192. package/lib/vertesia-ui-layout.js +1 -1
  193. package/lib/vertesia-ui-layout.js.map +1 -1
  194. package/lib/vertesia-ui-router.js +1 -1
  195. package/lib/vertesia-ui-router.js.map +1 -1
  196. package/lib/vertesia-ui-session.js +1 -1
  197. package/lib/vertesia-ui-session.js.map +1 -1
  198. package/lib/vertesia-ui-shell.js +1 -1
  199. package/lib/vertesia-ui-shell.js.map +1 -1
  200. package/lib/vertesia-ui-widgets.js +1 -1
  201. package/lib/vertesia-ui-widgets.js.map +1 -1
  202. package/package.json +11 -8
  203. package/src/core/components/MenuList.tsx +3 -6
  204. package/src/core/components/MessageBox.tsx +7 -2
  205. package/src/core/components/SelectBox.tsx +1 -1
  206. package/src/core/components/shadcn/dialog.tsx +19 -1
  207. package/src/core/components/shadcn/filters/filter/SelectFilter.tsx +31 -31
  208. package/src/core/components/shadcn/filters/filterBar.tsx +1 -0
  209. package/src/core/components/shadcn/selectBox.tsx +32 -6
  210. package/src/core/components/shadcn/tabs.tsx +3 -2
  211. package/src/env/index.ts +5 -0
  212. package/src/features/agent/CHART_INSTRUCTIONS.md +228 -0
  213. package/src/features/agent/chat/AgentChart.tsx +601 -0
  214. package/src/features/agent/chat/ModernAgentConversation.tsx +123 -11
  215. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +8 -2
  216. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +12 -2
  217. package/src/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.tsx +6 -1
  218. package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +15 -10
  219. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +122 -87
  220. package/src/features/agent/chat/index.ts +1 -0
  221. package/src/features/agent/createChartTool.ts +364 -0
  222. package/src/features/agent/examples.ts +321 -0
  223. package/src/features/agent/index.ts +2 -0
  224. package/src/features/agent/visualization.ts +227 -0
  225. package/src/features/facets/CollectionsFacetsNav.tsx +5 -1
  226. package/src/features/index.ts +1 -0
  227. package/src/features/layout/GenericPageNavHeader.tsx +15 -4
  228. package/src/features/magic-pdf/AnnotatedImageSlider.tsx +482 -0
  229. package/src/features/magic-pdf/DownloadPopover.tsx +45 -40
  230. package/src/features/magic-pdf/ExtractedContentView.tsx +132 -0
  231. package/src/features/magic-pdf/MagicPdfProvider.tsx +297 -0
  232. package/src/features/magic-pdf/MagicPdfView.tsx +184 -91
  233. package/src/features/pdf-viewer/PdfPageRenderer.tsx +612 -0
  234. package/src/features/pdf-viewer/PdfPageSlider.tsx +473 -0
  235. package/src/features/pdf-viewer/SimplePdfViewer.tsx +142 -0
  236. package/src/features/pdf-viewer/index.ts +3 -0
  237. package/src/features/store/collections/EditCollectionView.tsx +3 -5
  238. package/src/features/store/collections/SharedPropsEditor.tsx +1 -2
  239. package/src/features/store/objects/DocumentSearchResults.tsx +0 -7
  240. package/src/features/store/objects/components/ContentOverview.tsx +677 -210
  241. package/src/features/store/objects/components/useContentPanelHooks.ts +169 -0
  242. package/src/features/store/objects/layout/DocumentTableColumn.tsx +3 -3
  243. package/src/features/store/objects/layout/knowledge.md +1 -0
  244. package/src/features/store/objects/layout/renderers.tsx +25 -0
  245. package/src/features/utils/index.ts +3 -1
  246. package/src/features/utils/mimeType.ts +10 -1
  247. package/src/features/utils/print.ts +189 -0
  248. package/src/features/utils/workflowStatus.ts +44 -0
  249. package/src/router/HistoryNavigator.ts +30 -2
  250. package/src/shell/login/UserInfo.tsx +2 -0
  251. package/src/shell/login/UserSessionMenu.tsx +12 -1
  252. package/src/widgets/form/Form.tsx +8 -3
  253. package/src/widgets/markdown/MarkdownRenderer.tsx +350 -6
  254. package/src/widgets/schema-editor/ManagedSchema.ts +0 -3
  255. package/src/widgets/schema-editor/json-schema4-utils.ts +1 -1
  256. package/src/widgets/xml-viewer/components/XMLViewer.tsx +22 -10
  257. package/src/widgets/xml-viewer/constants/index.ts +11 -0
  258. package/lib/esm/features/magic-pdf/PageSlider.js +0 -70
  259. package/lib/esm/features/magic-pdf/PageSlider.js.map +0 -1
  260. package/lib/esm/features/magic-pdf/PdfPageProvider.js +0 -188
  261. package/lib/esm/features/magic-pdf/PdfPageProvider.js.map +0 -1
  262. package/lib/esm/features/magic-pdf/TextPageView.js +0 -62
  263. package/lib/esm/features/magic-pdf/TextPageView.js.map +0 -1
  264. package/lib/esm/features/magic-pdf/useResizeOnDrag.js +0 -34
  265. package/lib/esm/features/magic-pdf/useResizeOnDrag.js.map +0 -1
  266. package/lib/types/features/magic-pdf/PageSlider.d.ts +0 -9
  267. package/lib/types/features/magic-pdf/PageSlider.d.ts.map +0 -1
  268. package/lib/types/features/magic-pdf/PdfPageProvider.d.ts +0 -39
  269. package/lib/types/features/magic-pdf/PdfPageProvider.d.ts.map +0 -1
  270. package/lib/types/features/magic-pdf/TextPageView.d.ts +0 -8
  271. package/lib/types/features/magic-pdf/TextPageView.d.ts.map +0 -1
  272. package/lib/types/features/magic-pdf/useResizeOnDrag.d.ts +0 -9
  273. package/lib/types/features/magic-pdf/useResizeOnDrag.d.ts.map +0 -1
  274. package/src/features/magic-pdf/PageSlider.tsx +0 -142
  275. package/src/features/magic-pdf/PdfPageProvider.tsx +0 -310
  276. package/src/features/magic-pdf/TextPageView.tsx +0 -91
  277. package/src/features/magic-pdf/useResizeOnDrag.ts +0 -42
@@ -0,0 +1,169 @@
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import { useUserSession } from "@vertesia/ui/session";
3
+ import { DocAnalyzerProgress, DocProcessorOutputFormat, MarkdownRenditionFormat, WorkflowExecutionStatus } from "@vertesia/common";
4
+
5
+ // Maximum text size before cropping (128K characters)
6
+ const MAX_TEXT_DISPLAY_SIZE = 128 * 1024;
7
+
8
+ /**
9
+ * Hook for managing object text loading and cropping.
10
+ */
11
+ export function useObjectText(objectId: string, initialText?: string, loadOnMount = false) {
12
+ const { store } = useUserSession();
13
+
14
+ const [fullText, setFullText] = useState<string | undefined>(initialText);
15
+ const [displayText, setDisplayText] = useState<string | undefined>(() => {
16
+ if (initialText && initialText.length > MAX_TEXT_DISPLAY_SIZE) {
17
+ return initialText.substring(0, MAX_TEXT_DISPLAY_SIZE);
18
+ }
19
+ return initialText;
20
+ });
21
+ const [isLoading, setIsLoading] = useState(false);
22
+ const [isCropped, setIsCropped] = useState(
23
+ () => !!initialText && initialText.length > MAX_TEXT_DISPLAY_SIZE
24
+ );
25
+
26
+ const loadText = useCallback(() => {
27
+ setIsLoading(true);
28
+ store.objects
29
+ .getObjectText(objectId)
30
+ .then((res) => {
31
+ setFullText(res.text);
32
+ if (res.text.length > MAX_TEXT_DISPLAY_SIZE) {
33
+ setDisplayText(res.text.substring(0, MAX_TEXT_DISPLAY_SIZE));
34
+ setIsCropped(true);
35
+ } else {
36
+ setDisplayText(res.text);
37
+ setIsCropped(false);
38
+ }
39
+ })
40
+ .catch((err) => {
41
+ console.error("Failed to load text", err);
42
+ })
43
+ .finally(() => {
44
+ setIsLoading(false);
45
+ });
46
+ }, [objectId, store]);
47
+
48
+ useEffect(() => {
49
+ if (loadOnMount && !displayText) {
50
+ loadText();
51
+ }
52
+ }, [loadOnMount, displayText, loadText]);
53
+
54
+ return {
55
+ fullText,
56
+ displayText,
57
+ isLoading,
58
+ isCropped,
59
+ loadText,
60
+ };
61
+ }
62
+
63
+ /**
64
+ * Hook for polling PDF/document processing status.
65
+ */
66
+ export function usePdfProcessingStatus(objectId: string, shouldPoll: boolean) {
67
+ const { client } = useUserSession();
68
+
69
+ const [progress, setProgress] = useState<DocAnalyzerProgress | undefined>();
70
+ const [status, setStatus] = useState<WorkflowExecutionStatus | undefined>();
71
+ const [outputFormat, setOutputFormat] = useState<DocProcessorOutputFormat | undefined>();
72
+ const [isComplete, setIsComplete] = useState(false);
73
+
74
+ useEffect(() => {
75
+ if (!shouldPoll) return;
76
+
77
+ let interrupted = false;
78
+
79
+ function poll() {
80
+ if (interrupted) return;
81
+
82
+ client.objects.analyze(objectId).getStatus()
83
+ .then((r) => {
84
+ setProgress(r.progress);
85
+ setStatus(r.status);
86
+ setOutputFormat(r.output_format ?? r.progress?.output_format);
87
+
88
+ if (r.status === WorkflowExecutionStatus.RUNNING) {
89
+ // Workflow is running, poll every 2 seconds for progress
90
+ if (!interrupted) {
91
+ setTimeout(poll, 2000);
92
+ }
93
+ } else {
94
+ // Workflow completed or terminal state
95
+ setIsComplete(true);
96
+ }
97
+ })
98
+ .catch(() => {
99
+ // No workflow found yet, poll every 10 seconds to check if one starts
100
+ if (!interrupted) {
101
+ setTimeout(poll, 10000);
102
+ }
103
+ });
104
+ }
105
+
106
+ poll();
107
+ return () => { interrupted = true; };
108
+ }, [shouldPoll, objectId, client]);
109
+
110
+ return {
111
+ progress,
112
+ status,
113
+ outputFormat,
114
+ isComplete,
115
+ };
116
+ }
117
+
118
+ /**
119
+ * Hook for managing Office document to PDF conversion.
120
+ */
121
+ export function useOfficePdfConversion(objectId: string, enabled: boolean) {
122
+ const { client } = useUserSession();
123
+
124
+ const [pdfUrl, setPdfUrl] = useState<string | undefined>();
125
+ const [isConverting, setIsConverting] = useState(false);
126
+ const [error, setError] = useState<string | undefined>();
127
+
128
+ const triggerConversion = useCallback(async () => {
129
+ if (!enabled || isConverting) return;
130
+
131
+ setIsConverting(true);
132
+ setError(undefined);
133
+
134
+ const pollForPdf = async (isFirstCall: boolean) => {
135
+ try {
136
+ const response = await client.objects.getRendition(objectId, {
137
+ format: MarkdownRenditionFormat.pdf,
138
+ generate_if_missing: isFirstCall,
139
+ sign_url: true,
140
+ block_on_generation: false,
141
+ });
142
+
143
+ if (response.status === "generating") {
144
+ // Poll every 5 seconds
145
+ setTimeout(() => pollForPdf(false), 5000);
146
+ } else if (response.status === "found" && response.renditions?.length) {
147
+ setPdfUrl(response.renditions[0]);
148
+ setIsConverting(false);
149
+ } else if (response.status === "failed") {
150
+ setError("PDF conversion failed");
151
+ setIsConverting(false);
152
+ }
153
+ } catch (err) {
154
+ console.error("Failed to convert Office document to PDF:", err);
155
+ setError("Failed to convert to PDF");
156
+ setIsConverting(false);
157
+ }
158
+ };
159
+
160
+ await pollForPdf(true);
161
+ }, [objectId, enabled, isConverting, client]);
162
+
163
+ return {
164
+ pdfUrl,
165
+ isConverting,
166
+ error,
167
+ triggerConversion,
168
+ };
169
+ }
@@ -84,13 +84,13 @@ export class DocumentTableColumn {
84
84
  const type = this.layout.type || 'string';
85
85
  const baseType = type.indexOf('?') > 0 ? type.substring(0, type.indexOf('?')) : type;
86
86
 
87
- if (baseType === 'objectId' && this.previewObject) {
87
+ if ((baseType === 'objectId' || baseType === 'objectLink') && this.previewObject) {
88
88
  const i = type.indexOf('?');
89
89
  const params = i > 0 ? new URLSearchParams(type.substring(i + 1)) : undefined;
90
- const objectIdRenderer = renderers.objectId(params, (_id: string) => {
90
+ const renderer = renderers[baseType](params, (_id: string) => {
91
91
  this.previewObject!(object.id);
92
92
  });
93
- return objectIdRenderer(object, index);
93
+ return renderer(object, index);
94
94
  }
95
95
 
96
96
  // Otherwise use the type-based renderer with the resolved value
@@ -32,6 +32,7 @@ Complete list of supported types:
32
32
  3. **date** - Date/time display
33
33
  4. **objectId** - object id with preview button
34
34
  5. **objectName** - object name display
35
+ 6. **objectLink** - *(deprecated)* alias for objectId, kept for backward compatibility
35
36
 
36
37
  ### Column Types and Renderers
37
38
  Built-in renderers with parameters:
@@ -131,6 +131,31 @@ const renderers: Record<string, (params?: URLSearchParams, onClick?: (id: string
131
131
  );
132
132
  };
133
133
  },
134
+ // objectLink - same implementation as objectId but defaults to slice=-7
135
+ objectLink(_params?: URLSearchParams, onClick?: (id: string) => void) {
136
+ const transforms: ((value: string) => string)[] = [];
137
+ const hasSlice = true;
138
+ transforms.push((value) => value.slice(-7));
139
+
140
+ return (value: any, index: number) => {
141
+ const displayValue = transforms.reduce((v, t) => t(v), value.id);
142
+ return (
143
+ <td key={index} className="flex justify-between items-center gap-2 max-w-48">
144
+ {hasSlice ? "~" : ""}{displayValue}
145
+ <Button
146
+ variant="ghost"
147
+ alt="Preview Object"
148
+ onClick={(e) => {
149
+ e.stopPropagation();
150
+ onClick?.(value.id);
151
+ }}
152
+ >
153
+ <Eye className="size-4" />
154
+ </Button>
155
+ </td>
156
+ );
157
+ };
158
+ },
134
159
  typeLink(_params?: URLSearchParams, _onClick?: (id: string) => void) {
135
160
  return (value: any, index: number) => {
136
161
  return <td key={index}>{value?.name || "n/a"}</td>;
@@ -1,3 +1,5 @@
1
1
  export * from "./text.js";
2
2
  export * from "./mimeType.js";
3
- export * from "./rendition.js";
3
+ export * from "./rendition.js";
4
+ export * from "./print.js";
5
+ export * from "./workflowStatus.js";
@@ -3,7 +3,16 @@ const IMAGE_PREFIX = 'image/'
3
3
  const PDF_PREFIX = 'application/pdf'
4
4
  const VIDEO_PREFIX = 'video/'
5
5
 
6
+ // Office document MIME types that can be converted to PDF for preview
7
+ const PREVIEWABLE_AS_PDF_TYPES = [
8
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
9
+ 'application/msword', // .doc
10
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx
11
+ 'application/vnd.ms-powerpoint', // .ppt
12
+ ]
13
+
6
14
  export const isCsv = (type: string) => type === CSV_PREFIX || CSV_PREFIX.includes(type)
7
15
  export const isImage = (type: string) => type.startsWith(IMAGE_PREFIX) || IMAGE_PREFIX.includes(type)
8
16
  export const isPdf = (type: string) => type === PDF_PREFIX || PDF_PREFIX.includes(type)
9
- export const isVideo = (type: string) => type.startsWith(VIDEO_PREFIX) || VIDEO_PREFIX.includes(type)
17
+ export const isVideo = (type: string) => type.startsWith(VIDEO_PREFIX) || VIDEO_PREFIX.includes(type)
18
+ export const isPreviewableAsPdf = (type: string) => PREVIEWABLE_AS_PDF_TYPES.includes(type)
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Print styles for markdown content export to PDF.
3
+ * These styles ensure tables and other elements render properly in print mode,
4
+ * independent from the application theme.
5
+ */
6
+ const PRINT_STYLES = `
7
+ @media print {
8
+ body {
9
+ margin: 24px;
10
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
11
+ font-size: 14px;
12
+ line-height: 1.5;
13
+ color: #111827;
14
+ background-color: #ffffff;
15
+ }
16
+
17
+ .vprose {
18
+ max-width: 800px;
19
+ margin: 0 auto;
20
+ }
21
+
22
+ .vprose h1 {
23
+ font-size: 24px;
24
+ font-weight: 700;
25
+ margin: 1.5rem 0 0.75rem;
26
+ }
27
+
28
+ .vprose h2 {
29
+ font-size: 20px;
30
+ font-weight: 600;
31
+ margin: 1.25rem 0 0.75rem;
32
+ }
33
+
34
+ .vprose h3 {
35
+ font-size: 18px;
36
+ font-weight: 600;
37
+ margin: 1rem 0 0.5rem;
38
+ }
39
+
40
+ .vprose p {
41
+ margin: 0 0 0.5rem;
42
+ }
43
+
44
+ .vprose ul,
45
+ .vprose ol {
46
+ margin: 0.5rem 0 0.5rem 1.5rem;
47
+ padding: 0;
48
+ }
49
+
50
+ .vprose li {
51
+ margin: 0.25rem 0;
52
+ }
53
+
54
+ .vprose table {
55
+ width: 100%;
56
+ border-collapse: collapse;
57
+ margin: 1rem 0;
58
+ }
59
+
60
+ .vprose th,
61
+ .vprose td {
62
+ border: 1px solid #d1d5db;
63
+ padding: 0.5rem 0.75rem;
64
+ vertical-align: top;
65
+ }
66
+
67
+ .vprose thead th {
68
+ background-color: #f3f4f6;
69
+ font-weight: 600;
70
+ }
71
+
72
+ .vprose pre,
73
+ .vprose code {
74
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
75
+ font-size: 12px;
76
+ }
77
+
78
+ .vprose pre {
79
+ padding: 0.75rem;
80
+ border-radius: 4px;
81
+ border: 1px solid #e5e7eb;
82
+ background-color: #f9fafb;
83
+ white-space: pre-wrap;
84
+ word-break: break-word;
85
+ }
86
+
87
+ /* Hide chart action buttons when printing */
88
+ .chart-actions {
89
+ display: none !important;
90
+ }
91
+
92
+ /* Hide interactive elements in agent conversation when printing */
93
+ .print-hidden,
94
+ [class*="print:hidden"],
95
+ button[title="Copy message"],
96
+ button[title="Copy to clipboard"],
97
+ button[title="Export as PNG"],
98
+ .message-actions {
99
+ display: none !important;
100
+ }
101
+
102
+ /* Prevent page breaks inside elements */
103
+ .vprose table,
104
+ .vprose pre,
105
+ .vprose blockquote,
106
+ .vprose figure,
107
+ .vprose img,
108
+ .recharts-wrapper,
109
+ [class*="chart"],
110
+ [class*="Chart"] {
111
+ break-inside: avoid;
112
+ page-break-inside: avoid;
113
+ }
114
+
115
+ /* Keep headings with following content */
116
+ .vprose h1,
117
+ .vprose h2,
118
+ .vprose h3,
119
+ .vprose h4,
120
+ .vprose h5,
121
+ .vprose h6 {
122
+ break-after: avoid;
123
+ page-break-after: avoid;
124
+ }
125
+
126
+ /* Keep list items together when possible */
127
+ .vprose li {
128
+ break-inside: avoid;
129
+ page-break-inside: avoid;
130
+ }
131
+ }
132
+ `;
133
+
134
+ /**
135
+ * Opens the browser print dialog with the content of a given HTML element.
136
+ * Uses a hidden iframe to avoid opening a new window.
137
+ *
138
+ * @param sourceElement - The HTML element whose content to print
139
+ * @param title - The document title for the printed page
140
+ * @returns true if print dialog was opened successfully, false otherwise
141
+ */
142
+ export function printElementToPdf(sourceElement: HTMLElement, title: string): boolean {
143
+ if (typeof window === "undefined" || typeof document === "undefined") {
144
+ return false;
145
+ }
146
+
147
+ // Use a hidden iframe to avoid opening a new window
148
+ const iframe = document.createElement("iframe");
149
+ iframe.style.position = "fixed";
150
+ iframe.style.right = "0";
151
+ iframe.style.bottom = "0";
152
+ iframe.style.width = "0";
153
+ iframe.style.height = "0";
154
+ iframe.style.border = "0";
155
+ iframe.style.visibility = "hidden";
156
+ document.body.appendChild(iframe);
157
+
158
+ const iframeWindow = iframe.contentWindow;
159
+ if (!iframeWindow) {
160
+ iframe.parentNode?.removeChild(iframe);
161
+ return false;
162
+ }
163
+
164
+ const doc = iframeWindow.document;
165
+ doc.open();
166
+ doc.write(`<!doctype html><html><head><title>${title}</title></head><body></body></html>`);
167
+ doc.close();
168
+ doc.title = title;
169
+
170
+ const styles = document.querySelectorAll<HTMLLinkElement | HTMLStyleElement>("link[rel=\"stylesheet\"], style");
171
+ styles.forEach((node) => {
172
+ doc.head.appendChild(node.cloneNode(true));
173
+ });
174
+
175
+ // Add dedicated print styles
176
+ const printStyle = doc.createElement("style");
177
+ printStyle.textContent = PRINT_STYLES;
178
+ doc.head.appendChild(printStyle);
179
+
180
+ doc.body.innerHTML = sourceElement.innerHTML;
181
+ iframeWindow.focus();
182
+ iframeWindow.print();
183
+
184
+ setTimeout(() => {
185
+ iframe.parentNode?.removeChild(iframe);
186
+ }, 1000);
187
+
188
+ return true;
189
+ }
@@ -0,0 +1,44 @@
1
+ import { WorkflowExecutionStatus } from "@vertesia/common";
2
+
3
+ /**
4
+ * Get the semantic color class for a workflow execution status.
5
+ */
6
+ export function getWorkflowStatusColor(status?: WorkflowExecutionStatus): string {
7
+ switch (status) {
8
+ case WorkflowExecutionStatus.RUNNING:
9
+ return "text-info";
10
+ case WorkflowExecutionStatus.COMPLETED:
11
+ return "text-success";
12
+ case WorkflowExecutionStatus.FAILED:
13
+ return "text-destructive";
14
+ case WorkflowExecutionStatus.TERMINATED:
15
+ case WorkflowExecutionStatus.CANCELED:
16
+ return "text-attention";
17
+ default:
18
+ return "text-muted";
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Get a human-readable name for a workflow execution status.
24
+ */
25
+ export function getWorkflowStatusName(status?: WorkflowExecutionStatus): string {
26
+ switch (status) {
27
+ case WorkflowExecutionStatus.RUNNING:
28
+ return "Running";
29
+ case WorkflowExecutionStatus.COMPLETED:
30
+ return "Completed";
31
+ case WorkflowExecutionStatus.FAILED:
32
+ return "Failed";
33
+ case WorkflowExecutionStatus.CONTINUED_AS_NEW:
34
+ return "Continued As New";
35
+ case WorkflowExecutionStatus.TERMINATED:
36
+ return "Terminated";
37
+ case WorkflowExecutionStatus.TIMED_OUT:
38
+ return "Timed Out";
39
+ case WorkflowExecutionStatus.CANCELED:
40
+ return "Canceled";
41
+ default:
42
+ return "Unknown";
43
+ }
44
+ }
@@ -66,6 +66,10 @@ export interface NavigateOptions {
66
66
  * if defined, indicate whether the basePath will be used as a top-level base path or a nested base path.
67
67
  */
68
68
  isBasePathNested?: boolean;
69
+ // Number of steps to go back in history, which will pop the history stack instead of pushing a new entry
70
+ stepsBack?: number;
71
+ // the title to set for the new history entry
72
+ title?: string;
69
73
  }
70
74
 
71
75
  function getElementHrefAsUrl(elem: HTMLElement) {
@@ -113,6 +117,11 @@ export class HistoryNavigator {
113
117
  }
114
118
 
115
119
  navigate(to: string, options: NavigateOptions = {}) {
120
+ if (options.stepsBack && options.stepsBack > 0) {
121
+ this.stepBack(options.stepsBack, options);
122
+ return;
123
+ }
124
+
116
125
  if (options.basePath) {
117
126
  let basePath = options.basePath;
118
127
  if (!basePath.startsWith('/')) {
@@ -124,6 +133,24 @@ export class HistoryNavigator {
124
133
  this._navigate(new URL(to, window.location.href), 'navigate', options);
125
134
  }
126
135
 
136
+ stepBack(steps: number, options: NavigateOptions = {}) {
137
+ const historyChain = window.history.state.historyChain || [];
138
+ const to = historyChain.length >= steps
139
+ ? new URL(historyChain[historyChain.length - steps].href, window.location.href)
140
+ : new URL(window.location.origin, window.location.href);
141
+ this._navigate(to, 'popState', options);
142
+
143
+ const stateToStore = {
144
+ from: window.location.href,
145
+ historyChain: historyChain.slice(0, -steps),
146
+ data: options.state || undefined,
147
+ title: options.title || document.title
148
+ };
149
+
150
+ window.history['replaceState'](stateToStore, '', to.href);
151
+ this.fireLocationChange(new AfterLocationChangeEvent('popState', to, options.state));
152
+ }
153
+
127
154
  _navigate(to: URL, type: LocationChangeType, options: NavigateOptions) {
128
155
  const beforeEvent = new BeforeLocationChangeEvent(type, to, options.state);
129
156
  this.fireLocationChange(beforeEvent);
@@ -133,7 +160,7 @@ export class HistoryNavigator {
133
160
 
134
161
  // Build navigation chain by preserving previous history
135
162
  const currentState = window.history.state;
136
- const currentTitle = document.title;
163
+ const currentTitle = options.title || document.title;
137
164
 
138
165
  // Create new history chain entry
139
166
  const newChainEntry = {
@@ -160,7 +187,8 @@ export class HistoryNavigator {
160
187
  const stateToStore = {
161
188
  from: window.location.href,
162
189
  historyChain: historyChain,
163
- data: options.state || undefined
190
+ data: options.state || undefined,
191
+ title: options.title || document.title
164
192
  };
165
193
 
166
194
  window.history[options.replace ? 'replaceState' : 'pushState'](stateToStore, '', to.href);
@@ -2,6 +2,7 @@ import { getTenantIdFromProject } from "@vertesia/common";
2
2
  import { VTabs, VTabsBar, VTabsPanel, VTooltip } from "@vertesia/ui/core";
3
3
  import { Env } from "@vertesia/ui/env";
4
4
  import { useUserSession } from "@vertesia/ui/session";
5
+ // Package version is now passed as prop from the consuming application
5
6
  import { Check, CopyIcon } from "lucide-react";
6
7
  import { useState } from "react";
7
8
 
@@ -61,6 +62,7 @@ export default function InfoList() {
61
62
  <InfoItems title="Server" value={server} />
62
63
  <InfoItems title="Store" value={store} />
63
64
  <InfoItems title="App Version" value={Env.version} />
65
+ <InfoItems title="SDK Version" value={Env.sdkVersion || 'unknown'} />
64
66
  </div>
65
67
  }
66
68
  ];
@@ -1,4 +1,4 @@
1
- import { AuthTokenPayload } from "@vertesia/common";
1
+ import { AuthTokenPayload, Permission } from "@vertesia/common";
2
2
  import { Avatar, Button, MenuList, ModeToggle, Spinner } from "@vertesia/ui/core";
3
3
  import { useUserSession } from "@vertesia/ui/session";
4
4
  import { Popover } from "@vertesia/ui/widgets";
@@ -6,6 +6,8 @@ import clsx from "clsx";
6
6
  import { useState } from "react";
7
7
  import SignInModal from "./SignInModal";
8
8
  import InfoList from "./UserInfo";
9
+ import { useNavigate } from "@vertesia/ui/router";
10
+ import { useUserPermissions } from "@vertesia/ui/features";
9
11
  interface UserSessionMenuProps {
10
12
  name?: string
11
13
  picture?: string;
@@ -38,9 +40,13 @@ interface UserSessionPopupProps {
38
40
  }
39
41
  function UserSessionPopup({ className, asMenuTrigger = false }: UserSessionPopupProps) {
40
42
  const session = useUserSession();
43
+ const navigate = useNavigate();
44
+ const perms = useUserPermissions();
41
45
  const { user } = session;
42
46
  if (!session || !user) return null;
43
47
 
48
+ const isProjectManager = perms.hasPermission(Permission.project_admin);
49
+
44
50
  return (
45
51
  <Popover strategy='fixed' placement='bottom-start' zIndex={100}>
46
52
  <Popover.Trigger click>
@@ -68,6 +74,11 @@ function UserSessionPopup({ className, asMenuTrigger = false }: UserSessionPopup
68
74
  </div>
69
75
  <div className='py-2'>
70
76
  <MenuList>
77
+ {isProjectManager && (
78
+ <MenuList.Item className='px-2' onClick={() => navigate('/settings', { replace: true })}>
79
+ Settings
80
+ </MenuList.Item>
81
+ )}
71
82
  <MenuList.Item className='px-2' onClick={() => session.logout()}>
72
83
  Sign out
73
84
  </MenuList.Item>
@@ -1,8 +1,8 @@
1
1
 
2
- import { Plus, Trash2 } from "lucide-react";
2
+ import type { JSONSchemaObject } from "@vertesia/common";
3
3
  import { Button, FormItem } from "@vertesia/ui/core";
4
4
  import clsx from "clsx";
5
- import type { JSONSchemaObject } from "@vertesia/common";
5
+ import { Plus, Trash2 } from "lucide-react";
6
6
  import { ComponentType, ReactNode, SyntheticEvent, useState } from "react";
7
7
  import { FormContext, FormContextProvider, InputComponentProps, useForm } from "./FormContext.js";
8
8
  import { ManagedListProperty, ManagedObject, ManagedObjectBase, ManagedProperty, Node } from "./ManagedObject.js";
@@ -94,10 +94,15 @@ export function ScalarField({ object, editor, inline = false }: ScalarFieldProps
94
94
  object.value = object.schema.isNumber ? parseFloat(value) : value
95
95
  }
96
96
 
97
+ if (object.isListItem) {
98
+ // List items don't need the FormItem wrapper (no label, description, etc.)
99
+ return <Component object={object} type={inputType} onChange={handleOnChange} disabled={disabled} />;
100
+ }
101
+
97
102
  return (
98
103
  <FormItem label={object.title} required={object.schema.isRequired} description={object.schema.description}
99
104
  className={clsx('flex', inline ? 'flex-row items-center' : 'flex-col')}>
100
- {!object.isListItem && <Component object={object} type={inputType} onChange={handleOnChange} disabled={disabled} />}
105
+ <Component object={object} type={inputType} onChange={handleOnChange} disabled={disabled} />
101
106
  </FormItem>
102
107
  )
103
108
  }