orcheo-studio 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (329) hide show
  1. package/.bumpversion.cfg +14 -0
  2. package/.eslintrc +1 -0
  3. package/CHANGELOG.md +32 -0
  4. package/README.md +60 -0
  5. package/bin/orcheo-studio.js +39 -0
  6. package/components.json +21 -0
  7. package/dist/assets/arc-BbeTokFd.js +1 -0
  8. package/dist/assets/architectureDiagram-VXUJARFQ-CN00R9LC.js +36 -0
  9. package/dist/assets/avatar-01-CIAd4XAq.svg +1 -0
  10. package/dist/assets/avatar-02-BkgLJWQZ.svg +1 -0
  11. package/dist/assets/avatar-03-DVVcnD3b.svg +1 -0
  12. package/dist/assets/avatar-04-ydqFTDdh.svg +1 -0
  13. package/dist/assets/avatar-05-CSIhgJow.svg +1 -0
  14. package/dist/assets/avatar-06-B-h1Nz9Y.svg +1 -0
  15. package/dist/assets/avatar-07-BgkDZuBW.svg +1 -0
  16. package/dist/assets/avatar-08-C5KZjVH6.svg +1 -0
  17. package/dist/assets/avatar-09-2EGeSlPh.svg +1 -0
  18. package/dist/assets/avatar-10-DRf4ZGD2.svg +1 -0
  19. package/dist/assets/avatar-11-CEzBCpib.svg +1 -0
  20. package/dist/assets/avatar-12-COVngNEy.svg +1 -0
  21. package/dist/assets/avatar-13-D1i1tZVO.svg +1 -0
  22. package/dist/assets/avatar-14-B68CNAEs.svg +1 -0
  23. package/dist/assets/avatar-15-B9NsRNUX.svg +1 -0
  24. package/dist/assets/avatar-16-DQ_JJRGR.svg +1 -0
  25. package/dist/assets/avatar-17-DfDJkGv5.svg +1 -0
  26. package/dist/assets/avatar-18-BuxiqOaJ.svg +1 -0
  27. package/dist/assets/avatar-19-C2mJfrwW.svg +1 -0
  28. package/dist/assets/avatar-20-DPE_yE1a.svg +1 -0
  29. package/dist/assets/avatar-21-DbB0Lj6t.svg +1 -0
  30. package/dist/assets/blockDiagram-VD42YOAC-BPpieIRz.js +122 -0
  31. package/dist/assets/c4Diagram-YG6GDRKO-DAhuY1fj.js +10 -0
  32. package/dist/assets/channel-DtVQHWfl.js +1 -0
  33. package/dist/assets/chunk-4BX2VUAB-7RJQCroR.js +1 -0
  34. package/dist/assets/chunk-55IACEB6-CEN5yOA_.js +1 -0
  35. package/dist/assets/chunk-B4BG7PRW-vdlAz_3Q.js +165 -0
  36. package/dist/assets/chunk-DI55MBZ5-BTmKjGVg.js +220 -0
  37. package/dist/assets/chunk-FMBD7UC4-CwWvFfrg.js +15 -0
  38. package/dist/assets/chunk-QN33PNHL-XH90lUUN.js +1 -0
  39. package/dist/assets/chunk-QZHKN3VN-DMoMVES0.js +1 -0
  40. package/dist/assets/chunk-TZMSLE5B-Bx2XTXDY.js +1 -0
  41. package/dist/assets/classDiagram-2ON5EDUG-pw6P8q-u.js +1 -0
  42. package/dist/assets/classDiagram-v2-WZHVMYZB-pw6P8q-u.js +1 -0
  43. package/dist/assets/clone-DJq6GzHg.js +1 -0
  44. package/dist/assets/cose-bilkent-S5V4N54A-DS1MNwZB.js +1 -0
  45. package/dist/assets/cytoscape.esm-BQaXIfA_.js +331 -0
  46. package/dist/assets/dagre-6UL2VRFP-DdklXSXB.js +4 -0
  47. package/dist/assets/defaultLocale-C4B-KCzX.js +1 -0
  48. package/dist/assets/diagram-PSM6KHXK-BKBo8pqg.js +24 -0
  49. package/dist/assets/diagram-QEK2KX5R-DaavZhFO.js +43 -0
  50. package/dist/assets/diagram-S2PKOQOG-DkTwknYd.js +24 -0
  51. package/dist/assets/erDiagram-Q2GNP2WA-ClR5qEsI.js +60 -0
  52. package/dist/assets/flowDiagram-NV44I4VS-Cxt_sJHB.js +162 -0
  53. package/dist/assets/ganttDiagram-JELNMOA3-CIbs3JPJ.js +267 -0
  54. package/dist/assets/gitGraphDiagram-V2S2FVAM-DmqLh_uo.js +65 -0
  55. package/dist/assets/graph-zo28rS-a.js +1 -0
  56. package/dist/assets/index-B0_h2wCA.css +1 -0
  57. package/dist/assets/index-Be29_rJf.js +775 -0
  58. package/dist/assets/infoDiagram-HS3SLOUP-D9_rMkAf.js +2 -0
  59. package/dist/assets/init-Gi6I4Gst.js +1 -0
  60. package/dist/assets/isUndefined-C59bc74c.js +1 -0
  61. package/dist/assets/journeyDiagram-XKPGCS4Q-4ZuggLXE.js +139 -0
  62. package/dist/assets/kanban-definition-3W4ZIXB7-BQDNrhHL.js +89 -0
  63. package/dist/assets/katex-CBSAILhF.js +261 -0
  64. package/dist/assets/layout-CXbNm-Yo.js +1 -0
  65. package/dist/assets/linear-DQWATg1F.js +1 -0
  66. package/dist/assets/min-DJjRzMm8.js +1 -0
  67. package/dist/assets/mindmap-definition-VGOIOE7T-DiZQmsHT.js +68 -0
  68. package/dist/assets/ordinal-Cboi1Yqb.js +1 -0
  69. package/dist/assets/pieDiagram-ADFJNKIX-Bkju7jCD.js +30 -0
  70. package/dist/assets/quadrantDiagram-AYHSOK5B-CIB47UvU.js +7 -0
  71. package/dist/assets/requirementDiagram-UZGBJVZJ-BSB3uACk.js +64 -0
  72. package/dist/assets/sankeyDiagram-TZEHDZUN-rB8wD2kd.js +10 -0
  73. package/dist/assets/sequenceDiagram-WL72ISMW-Cd9s3Q_1.js +145 -0
  74. package/dist/assets/stateDiagram-FKZM4ZOC-zAxtjcM9.js +1 -0
  75. package/dist/assets/stateDiagram-v2-4FDKWEC3-C4DctH65.js +1 -0
  76. package/dist/assets/timeline-definition-IT6M3QCI-Et89F1F3.js +61 -0
  77. package/dist/assets/treemap-GDKQZRPO-6mZVX2Gv.js +162 -0
  78. package/dist/assets/xychartDiagram-PRI3JC2R-CgyY8dNz.js +7 -0
  79. package/dist/favicon.ico +0 -0
  80. package/dist/index.html +19 -0
  81. package/dist/robots.txt +2 -0
  82. package/eslint.config.js +49 -0
  83. package/index.html +18 -0
  84. package/package.json +183 -0
  85. package/postcss.config.js +6 -0
  86. package/public/favicon.ico +0 -0
  87. package/public/robots.txt +2 -0
  88. package/src/App.tsx +115 -0
  89. package/src/assets/avatars/avatar-01.svg +1 -0
  90. package/src/assets/avatars/avatar-02.svg +1 -0
  91. package/src/assets/avatars/avatar-03.svg +1 -0
  92. package/src/assets/avatars/avatar-04.svg +1 -0
  93. package/src/assets/avatars/avatar-05.svg +1 -0
  94. package/src/assets/avatars/avatar-06.svg +1 -0
  95. package/src/assets/avatars/avatar-07.svg +1 -0
  96. package/src/assets/avatars/avatar-08.svg +1 -0
  97. package/src/assets/avatars/avatar-09.svg +1 -0
  98. package/src/assets/avatars/avatar-10.svg +1 -0
  99. package/src/assets/avatars/avatar-11.svg +1 -0
  100. package/src/assets/avatars/avatar-12.svg +1 -0
  101. package/src/assets/avatars/avatar-13.svg +1 -0
  102. package/src/assets/avatars/avatar-14.svg +1 -0
  103. package/src/assets/avatars/avatar-15.svg +1 -0
  104. package/src/assets/avatars/avatar-16.svg +1 -0
  105. package/src/assets/avatars/avatar-17.svg +1 -0
  106. package/src/assets/avatars/avatar-18.svg +1 -0
  107. package/src/assets/avatars/avatar-19.svg +1 -0
  108. package/src/assets/avatars/avatar-20.svg +1 -0
  109. package/src/assets/avatars/avatar-21.svg +1 -0
  110. package/src/assets/avatars/index.ts +99 -0
  111. package/src/design-system/ui/alert-dialog.tsx +141 -0
  112. package/src/design-system/ui/alert.tsx +59 -0
  113. package/src/design-system/ui/avatar.tsx +51 -0
  114. package/src/design-system/ui/badge.tsx +38 -0
  115. package/src/design-system/ui/button.tsx +59 -0
  116. package/src/design-system/ui/card.tsx +83 -0
  117. package/src/design-system/ui/dialog.tsx +122 -0
  118. package/src/design-system/ui/dropdown-menu.tsx +201 -0
  119. package/src/design-system/ui/input.tsx +22 -0
  120. package/src/design-system/ui/label.tsx +26 -0
  121. package/src/design-system/ui/scroll-area.tsx +48 -0
  122. package/src/design-system/ui/select.tsx +159 -0
  123. package/src/design-system/ui/separator.tsx +31 -0
  124. package/src/design-system/ui/sheet.tsx +141 -0
  125. package/src/design-system/ui/skeleton.tsx +15 -0
  126. package/src/design-system/ui/switch.tsx +29 -0
  127. package/src/design-system/ui/table.tsx +120 -0
  128. package/src/design-system/ui/tabs.tsx +55 -0
  129. package/src/design-system/ui/textarea.tsx +22 -0
  130. package/src/design-system/ui/toast.tsx +132 -0
  131. package/src/design-system/ui/toaster.tsx +35 -0
  132. package/src/design-system/ui/toggle-group.tsx +61 -0
  133. package/src/design-system/ui/toggle.tsx +46 -0
  134. package/src/design-system/ui/tooltip.tsx +32 -0
  135. package/src/features/MODULES.md +199 -0
  136. package/src/features/account/components/settings/appearance-settings-tab.tsx +24 -0
  137. package/src/features/account/components/theme-settings.tsx +70 -0
  138. package/src/features/account/components/use-theme-preferences.ts +106 -0
  139. package/src/features/account/pages/profile/components/profile-general-tab.tsx +89 -0
  140. package/src/features/account/pages/profile/types.ts +7 -0
  141. package/src/features/account/pages/profile.tsx +71 -0
  142. package/src/features/account/pages/service-tokens.tsx +522 -0
  143. package/src/features/account/pages/settings.tsx +42 -0
  144. package/src/features/account/pages/workspace-management.tsx +63 -0
  145. package/src/features/account/pages/workspace-members.tsx +335 -0
  146. package/src/features/auth/components/auto-login.tsx +51 -0
  147. package/src/features/auth/components/require-auth.tsx +56 -0
  148. package/src/features/auth/lib/auth-session.ts +448 -0
  149. package/src/features/auth/lib/oidc-client.ts +565 -0
  150. package/src/features/auth/pages/login.tsx +24 -0
  151. package/src/features/auth/pages/oauth-callback.tsx +63 -0
  152. package/src/features/chatkit/components/chatkit-surface.tsx +60 -0
  153. package/src/features/chatkit/components/public-chat-config.ts +70 -0
  154. package/src/features/chatkit/components/public-chat-error-boundary.tsx +74 -0
  155. package/src/features/chatkit/components/public-chat-widget.tsx +150 -0
  156. package/src/features/chatkit/components/studio-chat-bubble.tsx +451 -0
  157. package/src/features/chatkit/lib/chatkit-attachments.ts +31 -0
  158. package/src/features/chatkit/lib/chatkit-client.ts +195 -0
  159. package/src/features/chatkit/lib/chatkit-theme.ts +20 -0
  160. package/src/features/chatkit/lib/telemetry.ts +29 -0
  161. package/src/features/chatkit/lib/workflow-session.ts +70 -0
  162. package/src/features/chatkit/pages/public-chat.tsx +445 -0
  163. package/src/features/shared/components/chat-interface-options.ts +325 -0
  164. package/src/features/shared/components/chat-interface.types.ts +47 -0
  165. package/src/features/shared/components/top-navigation/account-menu.tsx +172 -0
  166. package/src/features/shared/components/top-navigation/active-workspace-indicator.tsx +280 -0
  167. package/src/features/shared/components/top-navigation/studio-brand.tsx +59 -0
  168. package/src/features/shared/components/top-navigation/top-navigation-types.ts +22 -0
  169. package/src/features/shared/components/top-navigation/version-status.tsx +280 -0
  170. package/src/features/shared/components/top-navigation.tsx +42 -0
  171. package/src/features/shared/components/workspace-bootstrap-gate.tsx +235 -0
  172. package/src/features/workflow/components/dialogs/add-credential-dialog.tsx +245 -0
  173. package/src/features/workflow/components/dialogs/confirm-delete-workflow-dialog.tsx +52 -0
  174. package/src/features/workflow/components/dialogs/credential-access-badge.tsx +34 -0
  175. package/src/features/workflow/components/dialogs/credential-status-badge.tsx +45 -0
  176. package/src/features/workflow/components/dialogs/credentials-table.tsx +453 -0
  177. package/src/features/workflow/components/dialogs/credentials-vault.tsx +85 -0
  178. package/src/features/workflow/components/dialogs/edit-credential-dialog.tsx +264 -0
  179. package/src/features/workflow/components/dialogs/update-workflow-dialog.tsx +214 -0
  180. package/src/features/workflow/components/dialogs/upload-workflow-dialog.tsx +288 -0
  181. package/src/features/workflow/components/forms/schema-config-form.tsx +41 -0
  182. package/src/features/workflow/components/layouts/sidebar-layout.tsx +288 -0
  183. package/src/features/workflow/components/layouts/use-sidebar-resize.ts +164 -0
  184. package/src/features/workflow/components/layouts/workflow-page-layout.tsx +69 -0
  185. package/src/features/workflow/components/panels/json-object-field.tsx +138 -0
  186. package/src/features/workflow/components/panels/rjsf-basic-widgets.tsx +21 -0
  187. package/src/features/workflow/components/panels/rjsf-input-widgets.tsx +105 -0
  188. package/src/features/workflow/components/panels/rjsf-templates.tsx +147 -0
  189. package/src/features/workflow/components/panels/rjsf-text-widgets.tsx +139 -0
  190. package/src/features/workflow/components/panels/rjsf-theme.tsx +10 -0
  191. package/src/features/workflow/components/panels/schema-dnd.ts +79 -0
  192. package/src/features/workflow/components/panels/workflow-diff-dialog.tsx +207 -0
  193. package/src/features/workflow/components/panels/workflow-history-filters.tsx +62 -0
  194. package/src/features/workflow/components/panels/workflow-history-footer.tsx +28 -0
  195. package/src/features/workflow/components/panels/workflow-history-header.tsx +47 -0
  196. package/src/features/workflow/components/panels/workflow-history-table.tsx +148 -0
  197. package/src/features/workflow/components/panels/workflow-history.tsx +150 -0
  198. package/src/features/workflow/components/panels/workflow-tabs.tsx +29 -0
  199. package/src/features/workflow/components/trace/agent-prism/Avatar.tsx +146 -0
  200. package/src/features/workflow/components/trace/agent-prism/Badge.tsx +95 -0
  201. package/src/features/workflow/components/trace/agent-prism/BrandLogo.tsx +102 -0
  202. package/src/features/workflow/components/trace/agent-prism/Button.tsx +124 -0
  203. package/src/features/workflow/components/trace/agent-prism/CollapseAndExpandControls.tsx +45 -0
  204. package/src/features/workflow/components/trace/agent-prism/CollapsibleSection.tsx +124 -0
  205. package/src/features/workflow/components/trace/agent-prism/CopyButton.tsx +63 -0
  206. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsView.tsx +146 -0
  207. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewAttributesTab.tsx +125 -0
  208. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewContentViewer.tsx +51 -0
  209. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewHeader.tsx +100 -0
  210. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewInputOutputTab.tsx +401 -0
  211. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewJsonOutput.tsx +33 -0
  212. package/src/features/workflow/components/trace/agent-prism/DetailsView/DetailsViewRawDataTab.tsx +27 -0
  213. package/src/features/workflow/components/trace/agent-prism/IconButton.tsx +75 -0
  214. package/src/features/workflow/components/trace/agent-prism/PriceBadge.tsx +14 -0
  215. package/src/features/workflow/components/trace/agent-prism/SearchInput.tsx +17 -0
  216. package/src/features/workflow/components/trace/agent-prism/SpanBadge.tsx +54 -0
  217. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCard.tsx +480 -0
  218. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardBadges.tsx +23 -0
  219. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardConnector.tsx +36 -0
  220. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardTimeline.tsx +60 -0
  221. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardToggle.tsx +39 -0
  222. package/src/features/workflow/components/trace/agent-prism/SpanStatus.tsx +80 -0
  223. package/src/features/workflow/components/trace/agent-prism/TabSelector.tsx +35 -0
  224. package/src/features/workflow/components/trace/agent-prism/Tabs.tsx +140 -0
  225. package/src/features/workflow/components/trace/agent-prism/TextInput.tsx +143 -0
  226. package/src/features/workflow/components/trace/agent-prism/TimestampBadge.tsx +22 -0
  227. package/src/features/workflow/components/trace/agent-prism/TokensBadge.tsx +27 -0
  228. package/src/features/workflow/components/trace/agent-prism/TraceList/TraceList.tsx +123 -0
  229. package/src/features/workflow/components/trace/agent-prism/TraceList/TraceListItem.tsx +86 -0
  230. package/src/features/workflow/components/trace/agent-prism/TraceList/TraceListItemHeader.tsx +37 -0
  231. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewer.tsx +208 -0
  232. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerDesktopLayout.tsx +99 -0
  233. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerMobileLayout.tsx +103 -0
  234. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerPlaceholder.tsx +5 -0
  235. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerSearchAndControls.tsx +30 -0
  236. package/src/features/workflow/components/trace/agent-prism/TraceViewer/TraceViewerTreeViewContainer.tsx +76 -0
  237. package/src/features/workflow/components/trace/agent-prism/TraceViewer/useTraceSelection.ts +186 -0
  238. package/src/features/workflow/components/trace/agent-prism/TreeView.tsx +73 -0
  239. package/src/features/workflow/components/trace/agent-prism/index.ts +7 -0
  240. package/src/features/workflow/components/trace/agent-prism/shared.ts +170 -0
  241. package/src/features/workflow/components/trace/agent-prism/theme/index.ts +101 -0
  242. package/src/features/workflow/components/trace/agent-prism/theme/theme.css +247 -0
  243. package/src/features/workflow/data/templates/assets/vibe-agent/config.json +5 -0
  244. package/src/features/workflow/data/templates/candidate-badges.ts +138 -0
  245. package/src/features/workflow/data/templates/index.ts +29 -0
  246. package/src/features/workflow/data/templates/template-definition.ts +77 -0
  247. package/src/features/workflow/data/templates/template-owner.ts +7 -0
  248. package/src/features/workflow/data/workflow-data.ts +8 -0
  249. package/src/features/workflow/data/workflow-types.ts +57 -0
  250. package/src/features/workflow/lib/mermaid-renderer.ts +334 -0
  251. package/src/features/workflow/lib/workflow-diff.ts +191 -0
  252. package/src/features/workflow/lib/workflow-execution-builders.ts +103 -0
  253. package/src/features/workflow/lib/workflow-execution-formatters.ts +145 -0
  254. package/src/features/workflow/lib/workflow-execution-storage.ts +63 -0
  255. package/src/features/workflow/lib/workflow-execution.types.ts +80 -0
  256. package/src/features/workflow/lib/workflow-storage-api.ts +581 -0
  257. package/src/features/workflow/lib/workflow-storage-helpers.ts +373 -0
  258. package/src/features/workflow/lib/workflow-storage-versioning.ts +127 -0
  259. package/src/features/workflow/lib/workflow-storage.constants.ts +21 -0
  260. package/src/features/workflow/lib/workflow-storage.ts +482 -0
  261. package/src/features/workflow/lib/workflow-storage.types.ts +261 -0
  262. package/src/features/workflow/pages/workflow/components/settings-tab-content.tsx +428 -0
  263. package/src/features/workflow/pages/workflow/components/trace-tab-content.tsx +183 -0
  264. package/src/features/workflow/pages/workflow/components/workflow-config-sheet.tsx +207 -0
  265. package/src/features/workflow/pages/workflow/components/workflow-config-sheet.utils.ts +275 -0
  266. package/src/features/workflow/pages/workflow/components/workflow-layout.tsx +143 -0
  267. package/src/features/workflow/pages/workflow/components/workflow-tab-content.tsx +766 -0
  268. package/src/features/workflow/pages/workflow/handlers/credentials.ts +338 -0
  269. package/src/features/workflow/pages/workflow/helpers/execution.ts +39 -0
  270. package/src/features/workflow/pages/workflow/helpers/trace.ts +838 -0
  271. package/src/features/workflow/pages/workflow/helpers/types.ts +28 -0
  272. package/src/features/workflow/pages/workflow/hooks/controller/build-layout-props.ts +171 -0
  273. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-controller.ts +19 -0
  274. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-core.ts +84 -0
  275. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-execution-controller.ts +167 -0
  276. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-lifecycle.ts +37 -0
  277. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-resources.ts +57 -0
  278. package/src/features/workflow/pages/workflow/hooks/execution-log-helpers.ts +75 -0
  279. package/src/features/workflow/pages/workflow/hooks/execution-node-status.ts +46 -0
  280. package/src/features/workflow/pages/workflow/hooks/execution-record-updater.ts +119 -0
  281. package/src/features/workflow/pages/workflow/hooks/execution-record.ts +31 -0
  282. package/src/features/workflow/pages/workflow/hooks/execution-runtime-updates.ts +96 -0
  283. package/src/features/workflow/pages/workflow/hooks/use-execution-trace.ts +512 -0
  284. package/src/features/workflow/pages/workflow/hooks/use-execution-updates.ts +125 -0
  285. package/src/features/workflow/pages/workflow/hooks/use-pause-workflow.ts +70 -0
  286. package/src/features/workflow/pages/workflow/hooks/use-studio-ui-state.ts +10 -0
  287. package/src/features/workflow/pages/workflow/hooks/use-workflow-chat.ts +212 -0
  288. package/src/features/workflow/pages/workflow/hooks/use-workflow-credential-readiness.ts +72 -0
  289. package/src/features/workflow/pages/workflow/hooks/use-workflow-credentials.ts +167 -0
  290. package/src/features/workflow/pages/workflow/hooks/use-workflow-execution-state.ts +20 -0
  291. package/src/features/workflow/pages/workflow/hooks/use-workflow-listeners.ts +182 -0
  292. package/src/features/workflow/pages/workflow/hooks/use-workflow-loader.ts +236 -0
  293. package/src/features/workflow/pages/workflow/hooks/use-workflow-metadata-state.ts +56 -0
  294. package/src/features/workflow/pages/workflow/hooks/use-workflow-saver.ts +191 -0
  295. package/src/features/workflow/pages/workflow/hooks/use-workflow-storage-listener.ts +81 -0
  296. package/src/features/workflow/pages/workflow/hooks/workflow-runner-websocket.ts +150 -0
  297. package/src/features/workflow/pages/workflow-gallery/types.ts +3 -0
  298. package/src/features/workflow/pages/workflow-gallery/use-workflow-gallery-actions.ts +223 -0
  299. package/src/features/workflow/pages/workflow-gallery/use-workflow-gallery-state.ts +206 -0
  300. package/src/features/workflow/pages/workflow-gallery/use-workflow-gallery.ts +14 -0
  301. package/src/features/workflow/pages/workflow-gallery/workflow-card-size.ts +8 -0
  302. package/src/features/workflow/pages/workflow-gallery/workflow-card.tsx +327 -0
  303. package/src/features/workflow/pages/workflow-gallery/workflow-gallery-tabs.tsx +173 -0
  304. package/src/features/workflow/pages/workflow-gallery.tsx +96 -0
  305. package/src/features/workflow/pages/workflow.tsx +119 -0
  306. package/src/features/workflow/types/credential-vault.ts +52 -0
  307. package/src/hooks/browser-context-provider.tsx +19 -0
  308. package/src/hooks/use-browser-context.ts +188 -0
  309. package/src/hooks/use-color-scheme.ts +77 -0
  310. package/src/hooks/use-credential-vault.ts +442 -0
  311. package/src/hooks/use-page-context.ts +39 -0
  312. package/src/hooks/use-toast.ts +182 -0
  313. package/src/hooks/use-uploads-allowed.ts +28 -0
  314. package/src/index.css +95 -0
  315. package/src/lib/api.ts +445 -0
  316. package/src/lib/auth-fetch.ts +35 -0
  317. package/src/lib/config.ts +102 -0
  318. package/src/lib/theme.ts +109 -0
  319. package/src/lib/utils.ts +6 -0
  320. package/src/lib/workspace-routing.ts +67 -0
  321. package/src/lib/workspace-session.ts +66 -0
  322. package/src/lib/workspace-slug.ts +10 -0
  323. package/src/main.tsx +28 -0
  324. package/src/vite-env.d.ts +17 -0
  325. package/tailwind.config.js +153 -0
  326. package/tsconfig.app.json +30 -0
  327. package/tsconfig.json +16 -0
  328. package/tsconfig.node.json +21 -0
  329. package/vite.config.ts +122 -0
@@ -0,0 +1,80 @@
1
+ import type { TraceSpanStatus } from "@evilmartians/agent-prism-types";
2
+ import type { ComponentPropsWithRef } from "react";
3
+
4
+ import cn from "classnames";
5
+ import { Check, Ellipsis, Info, TriangleAlert } from "lucide-react";
6
+
7
+ type StatusVariant = "dot" | "badge";
8
+
9
+ export type StatusProps = ComponentPropsWithRef<"div"> & {
10
+ status: TraceSpanStatus;
11
+ variant?: StatusVariant;
12
+ };
13
+
14
+ const STATUS_COLORS_DOT: Record<TraceSpanStatus, string> = {
15
+ success: "bg-agentprism-success",
16
+ error: "bg-agentprism-error",
17
+ pending: "bg-agentprism-pending",
18
+ warning: "bg-agentprism-warning",
19
+ };
20
+
21
+ const STATUS_COLORS_BADGE: Record<TraceSpanStatus, string> = {
22
+ success:
23
+ "bg-agentprism-success-muted text-agentprism-success-muted-foreground",
24
+ error: "bg-agentprism-error-muted text-agentprism-error-muted-foreground",
25
+ pending:
26
+ "bg-agentprism-pending-muted text-agentprism-pending-muted-foreground",
27
+ warning:
28
+ "bg-agentprism-warning-muted text-agentprism-warning-muted-foreground",
29
+ };
30
+
31
+ export const SpanStatus = ({
32
+ status,
33
+ variant = "dot",
34
+ ...rest
35
+ }: StatusProps) => {
36
+ const title = `Status: ${status}`;
37
+
38
+ return (
39
+ <div className="flex size-4 items-center justify-center" {...rest}>
40
+ {variant === "dot" ? (
41
+ <SpanStatusDot status={status} title={title} />
42
+ ) : (
43
+ <SpanStatusBadge status={status} title={title} />
44
+ )}
45
+ </div>
46
+ );
47
+ };
48
+
49
+ interface StatusWithTitleProps extends StatusProps {
50
+ title: string;
51
+ }
52
+
53
+ const SpanStatusDot = ({ status, title }: StatusWithTitleProps) => {
54
+ return (
55
+ <span
56
+ className={cn("block size-1.5 rounded-full", STATUS_COLORS_DOT[status])}
57
+ aria-label={title}
58
+ title={title}
59
+ />
60
+ );
61
+ };
62
+
63
+ const SpanStatusBadge = ({ status, title }: StatusWithTitleProps) => {
64
+ return (
65
+ <span
66
+ className={cn(
67
+ "inline-flex items-center justify-center",
68
+ "h-3.5 w-4 rounded",
69
+ STATUS_COLORS_BADGE[status],
70
+ )}
71
+ aria-label={title}
72
+ title={title}
73
+ >
74
+ {status === "success" && <Check className="size-2.5" aria-hidden />}
75
+ {status === "error" && <TriangleAlert className="size-2.5" aria-hidden />}
76
+ {status === "warning" && <Info className="size-2.5" aria-hidden />}
77
+ {status === "pending" && <Ellipsis className="size-2.5" aria-hidden />}
78
+ </span>
79
+ );
80
+ };
@@ -0,0 +1,35 @@
1
+ import { type ReactElement } from "react";
2
+
3
+ import { type TabItem, Tabs } from "./Tabs";
4
+
5
+ export interface TabSelectorProps<T extends string> {
6
+ items: TabItem<T>[];
7
+ value: T;
8
+ onValueChange: (value: T) => void;
9
+ defaultValue?: T;
10
+ theme?: "underline" | "pill";
11
+ className?: string;
12
+ onClick?: (event: React.MouseEvent) => void;
13
+ }
14
+
15
+ export const TabSelector = <T extends string>({
16
+ items,
17
+ value,
18
+ onValueChange,
19
+ defaultValue,
20
+ theme = "underline",
21
+ className,
22
+ onClick,
23
+ }: TabSelectorProps<T>): ReactElement => {
24
+ return (
25
+ <Tabs<T>
26
+ items={items}
27
+ value={value}
28
+ onValueChange={onValueChange}
29
+ defaultValue={defaultValue}
30
+ theme={theme}
31
+ className={className}
32
+ onClick={onClick}
33
+ />
34
+ );
35
+ };
@@ -0,0 +1,140 @@
1
+ import type { ComponentPropsWithRef } from "react";
2
+
3
+ import * as RadixTabs from "@radix-ui/react-tabs";
4
+ import cn from "classnames";
5
+ import * as React from "react";
6
+
7
+ export interface TabItem<T extends string = string> {
8
+ value: T;
9
+ label: string;
10
+ icon?: React.ReactNode;
11
+ disabled?: boolean;
12
+ }
13
+
14
+ export type TabTheme = "underline" | "pill";
15
+
16
+ const BASE_TRIGGER =
17
+ "text-sm font-medium transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed";
18
+
19
+ const THEMES = {
20
+ underline: {
21
+ list: "h-9 flex border-b border-agentprism-border",
22
+ trigger: `w-full justify-center px-3 ${BASE_TRIGGER}
23
+ text-agentprism-secondary-foreground data-[state=active]:text-agentprism-foreground
24
+ border-b-2 border-transparent data-[state=active]:border-agentprism-border-inverse
25
+ -mb-[2px]
26
+ data-[state=inactive]:[&:not(:disabled)]:hover:border-agentprism-border-inverse/20
27
+ data-[state=inactive]:[&:not(:disabled)]:hover:text-agentprism-muted-foreground`,
28
+ },
29
+ pill: {
30
+ list: "h-9 inline-flex gap-1 p-1 bg-agentprism-secondary rounded-lg",
31
+ trigger: `px-3 ${BASE_TRIGGER} rounded-md
32
+ text-agentprism-muted-foreground data-[state=active]:text-agentprism-foreground
33
+ data-[state=inactive]:[&:not(:disabled)]:hover:bg-agentprism-background/50 data-[state=active]:bg-agentprism-background data-[state=active]:shadow-sm
34
+ dark:data-[state=active]:shadow-none`,
35
+ },
36
+ } as const;
37
+
38
+ export type TabsProps<T extends string = string> = Omit<
39
+ ComponentPropsWithRef<"div">,
40
+ "dir"
41
+ > & {
42
+ /**
43
+ * Array of tab items to display
44
+ */
45
+ items: TabItem<T>[];
46
+
47
+ /**
48
+ * The initially selected tab value (uncontrolled)
49
+ */
50
+ defaultValue?: T;
51
+
52
+ /**
53
+ * The currently selected tab value (controlled)
54
+ */
55
+ value?: T;
56
+
57
+ /**
58
+ * Callback fired when the selected tab changes
59
+ */
60
+ onValueChange?: (value: T) => void;
61
+
62
+ /**
63
+ * Visual theme variant for the tabs
64
+ * @default "underline"
65
+ */
66
+ theme?: TabTheme;
67
+
68
+ /**
69
+ * Optional className for the root container
70
+ */
71
+ className?: string;
72
+
73
+ /**
74
+ * Optional className for the tabs list container
75
+ */
76
+ tabsListClassName?: string;
77
+
78
+ /**
79
+ * Optional className for individual tab triggers
80
+ */
81
+ triggerClassName?: string;
82
+
83
+ /**
84
+ * The direction of the content of the tabs
85
+ */
86
+ dir?: "ltr" | "rtl";
87
+ };
88
+
89
+ export const Tabs = <T extends string = string>({
90
+ items,
91
+ defaultValue,
92
+ value,
93
+ onValueChange,
94
+ theme = "underline",
95
+ className = "",
96
+ tabsListClassName = "",
97
+ triggerClassName = "",
98
+ dir,
99
+ ...rest
100
+ }: TabsProps<T>) => {
101
+ const defaultTab = defaultValue || items[0]?.value;
102
+
103
+ const currentTheme = THEMES[theme];
104
+
105
+ return (
106
+ <RadixTabs.Root
107
+ className={className}
108
+ defaultValue={!value ? defaultTab : undefined}
109
+ value={value}
110
+ onValueChange={onValueChange as (value: string) => void}
111
+ dir={dir}
112
+ {...rest}
113
+ >
114
+ <RadixTabs.List
115
+ className={cn(currentTheme.list, tabsListClassName)}
116
+ aria-label="Navigation tabs"
117
+ >
118
+ {items.map((item: TabItem) => (
119
+ <RadixTabs.Trigger
120
+ key={item.value}
121
+ value={item.value}
122
+ disabled={item.disabled}
123
+ className={cn(
124
+ "group flex items-center overflow-hidden",
125
+ currentTheme.trigger,
126
+ triggerClassName,
127
+ )}
128
+ >
129
+ {item.icon && (
130
+ <span className="text-agentprism-secondary-foreground mr-2 group-data-[state=active]:text-current">
131
+ {item.icon}
132
+ </span>
133
+ )}
134
+ <span className="truncate text-sm font-medium">{item.label}</span>
135
+ </RadixTabs.Trigger>
136
+ ))}
137
+ </RadixTabs.List>
138
+ </RadixTabs.Root>
139
+ );
140
+ };
@@ -0,0 +1,143 @@
1
+ import cn from "classnames";
2
+ import { X } from "lucide-react";
3
+ import {
4
+ useRef,
5
+ type ChangeEvent,
6
+ type ComponentPropsWithRef,
7
+ type ReactNode,
8
+ type RefObject,
9
+ } from "react";
10
+
11
+ export type TextInputProps = ComponentPropsWithRef<"input"> & {
12
+ /**
13
+ * Callback fired when the input value changes
14
+ */
15
+ onValueChange?: (value: string) => void;
16
+
17
+ /**
18
+ * Icon to display at the start of the input
19
+ */
20
+ startIcon?: ReactNode;
21
+
22
+ /**
23
+ * Callback fired when the clear button is clicked. If this callback is provided,
24
+ * the clear button will be shown.
25
+ */
26
+ onClear?: () => void;
27
+
28
+ /**
29
+ * Ref to the input element
30
+ */
31
+ ref?: RefObject<HTMLInputElement | null>;
32
+
33
+ /**
34
+ * Optional className for the input element
35
+ */
36
+ inputClassName?: string;
37
+
38
+ /**
39
+ * Unique identifier for the input (required)
40
+ */
41
+ id: string;
42
+
43
+ /**
44
+ * Label text for the input
45
+ */
46
+ label?: string;
47
+
48
+ /**
49
+ * Whether to visually hide the label while keeping it for screen readers
50
+ * @default false
51
+ */
52
+ hideLabel?: boolean;
53
+ };
54
+
55
+ const iconBaseClassName =
56
+ "absolute top-1/2 -translate-y-1/2 flex items-center justify-center text-agentprism-muted-foreground";
57
+
58
+ export const TextInput = ({
59
+ className,
60
+ onChange,
61
+ onValueChange,
62
+ startIcon,
63
+ onClear,
64
+ ref,
65
+ inputClassName,
66
+ label,
67
+ hideLabel = false,
68
+ id,
69
+ ...rest
70
+ }: TextInputProps) => {
71
+ const inputRef = useRef<HTMLInputElement>(null);
72
+
73
+ const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
74
+ onChange?.(e);
75
+ onValueChange?.(e.target.value);
76
+ };
77
+
78
+ const handleClear = () => {
79
+ onClear?.();
80
+
81
+ if (ref) {
82
+ ref.current?.focus();
83
+ return;
84
+ }
85
+
86
+ inputRef.current?.focus();
87
+ };
88
+
89
+ return (
90
+ <div className={cn("w-full", className)}>
91
+ {label && (
92
+ <label
93
+ htmlFor={id}
94
+ className={cn(
95
+ "text-agentprism-foreground block text-sm font-medium",
96
+ hideLabel && "sr-only",
97
+ )}
98
+ >
99
+ {label}
100
+ </label>
101
+ )}
102
+ <div
103
+ className={cn(
104
+ "relative flex w-full items-center justify-center",
105
+ label && !hideLabel && "mt-1",
106
+ )}
107
+ >
108
+ <input
109
+ id={id}
110
+ ref={ref || inputRef}
111
+ onChange={handleChange}
112
+ className={cn(
113
+ inputClassName,
114
+ "flex h-7 items-center truncate",
115
+ "w-full px-2",
116
+ !!startIcon && "pl-8",
117
+ !!onClear && "pr-8",
118
+ "border-agentprism-border rounded border bg-transparent",
119
+ "text-agentprism-foreground placeholder:text-agentprism-foreground/50",
120
+ "hover:border-agentprism-border-strong",
121
+ "disabled:cursor-not-allowed disabled:opacity-50",
122
+ )}
123
+ {...rest}
124
+ />
125
+ {startIcon && (
126
+ <div className={cn(iconBaseClassName, "left-2")} aria-hidden>
127
+ {startIcon}
128
+ </div>
129
+ )}
130
+ {onClear && rest.value && (
131
+ <button
132
+ className={cn(iconBaseClassName, "right-2")}
133
+ aria-label="Clear input value"
134
+ onClick={handleClear}
135
+ type="button"
136
+ >
137
+ <X className="size-4" />
138
+ </button>
139
+ )}
140
+ </div>
141
+ </div>
142
+ );
143
+ };
@@ -0,0 +1,22 @@
1
+ import type { ComponentPropsWithRef } from "react";
2
+
3
+ import type { BadgeProps } from "./Badge";
4
+
5
+ import { Badge } from "./Badge";
6
+
7
+ export type TimestampBadgeProps = ComponentPropsWithRef<"span"> & {
8
+ timestamp: number;
9
+ size?: BadgeProps["size"];
10
+ };
11
+
12
+ export const TimestampBadge = ({
13
+ timestamp,
14
+ size,
15
+ ...rest
16
+ }: TimestampBadgeProps) => {
17
+ return <Badge size={size} {...rest} label={formatTimestamp(timestamp)} />;
18
+ };
19
+
20
+ function formatTimestamp(timestamp: number): string {
21
+ return new Date(timestamp).toLocaleString();
22
+ }
@@ -0,0 +1,27 @@
1
+ import type { ComponentPropsWithRef } from "react";
2
+
3
+ import { Coins } from "lucide-react";
4
+
5
+ import type { BadgeProps } from "./Badge";
6
+
7
+ import { Badge } from "./Badge";
8
+
9
+ export type TokensBadgeProps = ComponentPropsWithRef<"span"> & {
10
+ tokensCount: number;
11
+ size?: BadgeProps["size"];
12
+ };
13
+
14
+ export const TokensBadge = ({
15
+ tokensCount,
16
+ size,
17
+ ...rest
18
+ }: TokensBadgeProps) => {
19
+ return (
20
+ <Badge
21
+ iconStart={<Coins className="size-2.5" />}
22
+ size={size}
23
+ {...rest}
24
+ label={tokensCount}
25
+ />
26
+ );
27
+ };
@@ -0,0 +1,123 @@
1
+ import type { TraceRecord } from "@evilmartians/agent-prism-types";
2
+
3
+ import cn from "classnames";
4
+ import { ArrowLeft } from "lucide-react";
5
+ import { useEffect, useState } from "react";
6
+
7
+ import type { BadgeProps } from "../Badge";
8
+
9
+ import { Badge } from "../Badge";
10
+ import { Button } from "../Button";
11
+ import { IconButton } from "../IconButton";
12
+ import { TraceListItem } from "./TraceListItem";
13
+
14
+ const INITIAL_VISIBLE_TRACE_COUNT = 20;
15
+
16
+ type TraceRecordWithBadges = TraceRecord & {
17
+ badges?: Array<BadgeProps>;
18
+ };
19
+
20
+ type TraceListProps = {
21
+ traces: TraceRecordWithBadges[];
22
+ expanded: boolean;
23
+ onExpandStateChange: (expanded: boolean) => void;
24
+ className?: string;
25
+ onTraceSelect?: (trace: TraceRecord) => void;
26
+ selectedTrace?: TraceRecord;
27
+ };
28
+
29
+ export const TraceList = ({
30
+ traces,
31
+ expanded,
32
+ onExpandStateChange,
33
+ className,
34
+ onTraceSelect,
35
+ selectedTrace,
36
+ }: TraceListProps) => {
37
+ const [visibleTraceCount, setVisibleTraceCount] = useState(
38
+ INITIAL_VISIBLE_TRACE_COUNT,
39
+ );
40
+ const traceIdsSignature = traces.map((trace) => trace.id).join("|");
41
+
42
+ useEffect(() => {
43
+ setVisibleTraceCount(Math.min(INITIAL_VISIBLE_TRACE_COUNT, traces.length));
44
+ }, [traceIdsSignature, traces.length]);
45
+
46
+ const visibleTraces = traces.slice(0, visibleTraceCount);
47
+ const hasMoreTraces = traces.length > visibleTraceCount;
48
+
49
+ return (
50
+ <div
51
+ className={cn(
52
+ "flex min-w-0 flex-col",
53
+ expanded ? "h-full w-full gap-3" : "h-auto w-fit gap-1",
54
+ className,
55
+ )}
56
+ >
57
+ <header className="flex min-h-6 shrink-0 items-center justify-between gap-2">
58
+ <div
59
+ className={cn(
60
+ "flex items-center gap-2",
61
+ expanded ? "opacity-100" : "hidden opacity-0",
62
+ )}
63
+ >
64
+ <h2 className="text-agentprism-muted-foreground">Traces</h2>
65
+
66
+ <Badge
67
+ size="5"
68
+ aria-label={`Total number of traces: ${traces.length}`}
69
+ label={traces.length}
70
+ />
71
+ </div>
72
+
73
+ <IconButton
74
+ aria-label={expanded ? "Collapse Trace List" : "Expand Trace List"}
75
+ onClick={() => onExpandStateChange(!expanded)}
76
+ >
77
+ <ArrowLeft className={cn("size-3", expanded ? "" : "rotate-180")} />
78
+ </IconButton>
79
+ </header>
80
+
81
+ {expanded && (
82
+ <div className="border-agentprism-border flex min-h-0 flex-1 flex-col overflow-hidden rounded-md border">
83
+ <ul className="flex-1 overflow-y-auto">
84
+ {visibleTraces.map((trace) => (
85
+ <li
86
+ className="border-agentprism-border w-full list-none border-b [&:not(:last-child)]:border-b"
87
+ key={trace.id}
88
+ >
89
+ <TraceListItem
90
+ showDescription={false}
91
+ trace={trace}
92
+ onClick={() => onTraceSelect?.(trace)}
93
+ isSelected={selectedTrace?.id === trace.id}
94
+ badges={trace.badges}
95
+ />
96
+ </li>
97
+ ))}
98
+ </ul>
99
+
100
+ {hasMoreTraces && (
101
+ <div className="border-agentprism-border shrink-0 border-t p-2">
102
+ <Button
103
+ fullWidth
104
+ size="8"
105
+ variant="ghost"
106
+ onClick={() => {
107
+ setVisibleTraceCount((current) =>
108
+ Math.min(
109
+ current + INITIAL_VISIBLE_TRACE_COUNT,
110
+ traces.length,
111
+ ),
112
+ );
113
+ }}
114
+ >
115
+ Load more
116
+ </Button>
117
+ </div>
118
+ )}
119
+ </div>
120
+ )}
121
+ </div>
122
+ );
123
+ };
@@ -0,0 +1,86 @@
1
+ import type { TraceRecord } from "@evilmartians/agent-prism-types";
2
+ import type { KeyboardEvent } from "react";
3
+
4
+ import cn from "classnames";
5
+ import { useCallback } from "react";
6
+
7
+ import type { AvatarProps } from "../Avatar";
8
+ import type { BadgeProps } from "../Badge";
9
+
10
+ import { Badge } from "../Badge";
11
+ import { PriceBadge } from "../PriceBadge";
12
+ import { TimestampBadge } from "../TimestampBadge";
13
+ import { TokensBadge } from "../TokensBadge";
14
+ import { TraceListItemHeader } from "./TraceListItemHeader";
15
+
16
+ interface TraceListItemProps {
17
+ trace: TraceRecord;
18
+ badges?: Array<BadgeProps>;
19
+ avatar?: AvatarProps;
20
+ onClick?: () => void;
21
+ isSelected?: boolean;
22
+ showDescription?: boolean;
23
+ }
24
+
25
+ export const TraceListItem = ({
26
+ trace,
27
+ avatar,
28
+ onClick,
29
+ badges,
30
+ isSelected,
31
+ showDescription = true,
32
+ }: TraceListItemProps) => {
33
+ const handleKeyDown = useCallback(
34
+ (e: KeyboardEvent): void => {
35
+ if (e.key === "Enter" || e.key === " ") {
36
+ e.preventDefault();
37
+ onClick?.();
38
+ }
39
+ },
40
+ [onClick],
41
+ );
42
+
43
+ const { name, agentDescription, totalCost, totalTokens, startTime } = trace;
44
+
45
+ return (
46
+ <div
47
+ className={cn(
48
+ "group w-full",
49
+ "flex flex-col gap-2 p-4",
50
+ "cursor-pointer",
51
+ isSelected
52
+ ? "bg-agentprism-secondary/75 dark:bg-agentprism-muted/80"
53
+ : "bg-agentprism-background hover:bg-agentprism-secondary/45 dark:hover:bg-agentprism-muted/70",
54
+ )}
55
+ role="button"
56
+ tabIndex={0}
57
+ onClick={onClick}
58
+ onKeyDown={handleKeyDown}
59
+ aria-label={`Select trace ${name}`}
60
+ >
61
+ <TraceListItemHeader trace={trace} avatar={avatar} />
62
+
63
+ <div className="flex flex-wrap items-center gap-2">
64
+ {showDescription && (
65
+ <span className="text-agentprism-muted-foreground mr-4 max-w-full truncate text-sm">
66
+ {agentDescription}
67
+ </span>
68
+ )}
69
+
70
+ {typeof totalCost === "number" && <PriceBadge cost={totalCost} />}
71
+
72
+ {typeof totalTokens === "number" && (
73
+ <TokensBadge tokensCount={totalTokens} />
74
+ )}
75
+
76
+ {badges?.map((badge, index) => (
77
+ <Badge key={index} size="4" label={badge.label} />
78
+ ))}
79
+
80
+ {typeof startTime === "number" && (
81
+ <TimestampBadge timestamp={startTime} />
82
+ )}
83
+ </div>
84
+ </div>
85
+ );
86
+ };
@@ -0,0 +1,37 @@
1
+ import type { TraceRecord } from "@evilmartians/agent-prism-types";
2
+
3
+ import type { AvatarProps } from "../Avatar";
4
+
5
+ import { Avatar } from "../Avatar";
6
+ import { Badge } from "../Badge";
7
+
8
+ interface TraceListItemHeaderProps {
9
+ trace: TraceRecord;
10
+ avatar?: AvatarProps;
11
+ }
12
+
13
+ export const TraceListItemHeader = ({
14
+ trace,
15
+ avatar,
16
+ }: TraceListItemHeaderProps) => {
17
+ return (
18
+ <header className="flex w-full min-w-0 flex-wrap items-center justify-between gap-2">
19
+ <div className="flex min-w-0 items-center gap-1.5 overflow-hidden">
20
+ {avatar && <Avatar size="4" {...avatar} />}
21
+
22
+ <h3 className="text-agentprism-muted-foreground max-w-full truncate text-sm">
23
+ {trace.name}
24
+ </h3>
25
+ </div>
26
+
27
+ <div className="flex items-center gap-2">
28
+ <Badge
29
+ size="4"
30
+ label={
31
+ trace.spansCount === 1 ? "1 span" : `${trace.spansCount} spans`
32
+ }
33
+ />
34
+ </div>
35
+ </header>
36
+ );
37
+ };