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,29 @@
1
+ type ChatTelemetryEvent =
2
+ | "studio.chat.open"
3
+ | "studio.chat.close"
4
+ | "studio.chat.session.success"
5
+ | "studio.chat.session.failure";
6
+
7
+ const buildDetail = (detail?: Record<string, unknown>) => ({
8
+ timestamp: new Date().toISOString(),
9
+ ...(detail ?? {}),
10
+ });
11
+
12
+ export function recordChatTelemetry(
13
+ event: ChatTelemetryEvent,
14
+ detail?: Record<string, unknown>,
15
+ ) {
16
+ if (typeof window !== "undefined") {
17
+ window.dispatchEvent(
18
+ new CustomEvent("chatkit:telemetry", {
19
+ detail: { event, ...buildDetail(detail) },
20
+ }),
21
+ );
22
+ }
23
+
24
+ if (process.env.NODE_ENV !== "production") {
25
+ console.info(`[telemetry] ${event}`, buildDetail(detail));
26
+ }
27
+ }
28
+
29
+ export type { ChatTelemetryEvent };
@@ -0,0 +1,70 @@
1
+ import { authFetch } from "@/lib/auth-fetch";
2
+ import { buildBackendHttpUrl } from "@/lib/config";
3
+
4
+ interface WorkflowSessionResponse {
5
+ client_secret?: string;
6
+ clientSecret?: string;
7
+ expires_at?: string;
8
+ expiresAt?: string;
9
+ }
10
+
11
+ export interface WorkflowChatSession {
12
+ clientSecret: string;
13
+ expiresAt: number | null;
14
+ }
15
+
16
+ const parseErrorDetail = async (response: Response): Promise<string> => {
17
+ try {
18
+ const payload = (await response.json()) as Record<string, unknown>;
19
+ if (typeof payload?.detail === "object" && payload.detail !== null) {
20
+ const detail = payload.detail as Record<string, unknown>;
21
+ const message =
22
+ typeof detail.message === "string" ? detail.message : null;
23
+ if (message) {
24
+ return message;
25
+ }
26
+ }
27
+ if (typeof payload.message === "string") {
28
+ return payload.message;
29
+ }
30
+ } catch {
31
+ // Ignore JSON parse errors and fall through to status text.
32
+ }
33
+ return response.statusText || "ChatKit session request failed.";
34
+ };
35
+
36
+ export async function requestWorkflowChatSession(
37
+ workflowId: string,
38
+ backendBaseUrl?: string | null,
39
+ ): Promise<WorkflowChatSession> {
40
+ const url = buildBackendHttpUrl(
41
+ `/api/workflows/${workflowId}/chatkit/session`,
42
+ backendBaseUrl ?? undefined,
43
+ );
44
+ const response = await authFetch(url, {
45
+ method: "POST",
46
+ headers: {
47
+ "Content-Type": "application/json",
48
+ },
49
+ credentials: "include",
50
+ });
51
+
52
+ if (!response.ok) {
53
+ const message = await parseErrorDetail(response);
54
+ throw new Error(message);
55
+ }
56
+
57
+ const payload = (await response.json()) as WorkflowSessionResponse;
58
+ const secret = payload.client_secret ?? payload.clientSecret;
59
+ if (!secret) {
60
+ throw new Error("ChatKit session response missing client secret.");
61
+ }
62
+
63
+ const expiresRaw = payload.expires_at ?? payload.expiresAt;
64
+ const expiresAt = expiresRaw ? new Date(expiresRaw).getTime() : null;
65
+
66
+ return {
67
+ clientSecret: secret,
68
+ expiresAt,
69
+ };
70
+ }
@@ -0,0 +1,445 @@
1
+ import { useCallback, useEffect, useMemo, useState } from "react";
2
+ import type { ReactNode } from "react";
3
+ import { Monitor, Moon, Sun } from "lucide-react";
4
+ import { Link, useLocation, useParams } from "react-router-dom";
5
+ import { Alert, AlertDescription, AlertTitle } from "@/design-system/ui/alert";
6
+ import { Button } from "@/design-system/ui/button";
7
+ import { Skeleton } from "@/design-system/ui/skeleton";
8
+ import { ToggleGroup, ToggleGroupItem } from "@/design-system/ui/toggle-group";
9
+ import { getBackendBaseUrl } from "@/lib/config";
10
+ import { cn } from "@/lib/utils";
11
+ import type { Theme } from "@/lib/theme";
12
+ import { useThemePreferences } from "@features/account/components/use-theme-preferences";
13
+ import { isAuthenticated } from "@features/auth/lib/auth-session";
14
+ import {
15
+ ApiRequestError,
16
+ fetchPublicWorkflow,
17
+ } from "@features/workflow/lib/workflow-storage-api";
18
+ import type { PublicWorkflowMetadata } from "@features/workflow/lib/workflow-storage.types";
19
+ import { PublicChatWidget } from "@features/chatkit/components/public-chat-widget";
20
+ import { PublicChatErrorBoundary } from "@features/chatkit/components/public-chat-error-boundary";
21
+ import type { PublicChatHttpError } from "@features/chatkit/lib/chatkit-client";
22
+
23
+ type ColorScheme = "light" | "dark";
24
+
25
+ type WorkflowState =
26
+ | { status: "loading" }
27
+ | { status: "error"; message: string }
28
+ | { status: "ready"; workflow: PublicWorkflowMetadata };
29
+
30
+ const sanitizeWorkflowNameForEmail = (value: string): string =>
31
+ value
32
+ .replace(/[\r\n]+/g, " ")
33
+ .replace(/[<>]/g, "")
34
+ .trim();
35
+
36
+ export default function PublicChatPage() {
37
+ const { workflowId } = useParams<{ workflowId: string }>();
38
+ const location = useLocation();
39
+ const [workflowState, setWorkflowState] = useState<WorkflowState>({
40
+ status: workflowId ? "loading" : "error",
41
+ ...(workflowId ? {} : { message: "Workflow identifier missing from URL." }),
42
+ });
43
+ const [chatError, setChatError] = useState<PublicChatHttpError | null>(null);
44
+ const [rateLimitError, setRateLimitError] =
45
+ useState<PublicChatHttpError | null>(null);
46
+ const [isChatReady, setIsChatReady] = useState(false);
47
+ const [systemColorScheme, setSystemColorScheme] = useState<ColorScheme>(() =>
48
+ typeof window !== "undefined" &&
49
+ window.matchMedia("(prefers-color-scheme: dark)").matches
50
+ ? "dark"
51
+ : "light",
52
+ );
53
+ const { theme, setTheme } = useThemePreferences({});
54
+ const backendBaseUrl = useMemo(() => getBackendBaseUrl(), []);
55
+ const redirectTo = `${location.pathname}${location.search}${location.hash}`;
56
+
57
+ useEffect(() => {
58
+ setChatError(null);
59
+ setRateLimitError(null);
60
+ setIsChatReady(false);
61
+ }, [workflowId]);
62
+
63
+ useEffect(() => {
64
+ if (!workflowId) {
65
+ return;
66
+ }
67
+ let cancelled = false;
68
+ setWorkflowState({ status: "loading" });
69
+
70
+ fetchPublicWorkflow(workflowId)
71
+ .then((workflow) => {
72
+ if (cancelled) {
73
+ return;
74
+ }
75
+ if (!workflow) {
76
+ setWorkflowState({
77
+ status: "error",
78
+ message: "This workflow does not exist or is no longer available.",
79
+ });
80
+ return;
81
+ }
82
+ if (!workflow.is_public) {
83
+ setWorkflowState({
84
+ status: "error",
85
+ message:
86
+ "This workflow is private. Ask the owner to republish it before trying again.",
87
+ });
88
+ return;
89
+ }
90
+ setWorkflowState({ status: "ready", workflow });
91
+ })
92
+ .catch((error: unknown) => {
93
+ if (cancelled) {
94
+ return;
95
+ }
96
+ if (error instanceof ApiRequestError) {
97
+ if (error.status === 403) {
98
+ setWorkflowState({
99
+ status: "error",
100
+ message:
101
+ "This workflow is private. Ask the owner to republish it before trying again.",
102
+ });
103
+ return;
104
+ }
105
+ const message =
106
+ error.status >= 500
107
+ ? "The workflow service is unavailable. Please try again later."
108
+ : "Unable to load workflow metadata.";
109
+ setWorkflowState({ status: "error", message });
110
+ return;
111
+ }
112
+ setWorkflowState({
113
+ status: "error",
114
+ message: "Unexpected error while loading workflow metadata.",
115
+ });
116
+ });
117
+
118
+ return () => {
119
+ cancelled = true;
120
+ };
121
+ }, [workflowId]);
122
+
123
+ const contactHref = useMemo(() => {
124
+ if (workflowState.status !== "ready") {
125
+ return "mailto:?subject=Orcheo%20workflow%20access";
126
+ }
127
+ const sanitizedName = sanitizeWorkflowNameForEmail(
128
+ workflowState.workflow.name,
129
+ );
130
+ const subject = encodeURIComponent(`Request access to ${sanitizedName}`);
131
+ const link = typeof window !== "undefined" ? window.location.href : "";
132
+ const body = encodeURIComponent(
133
+ `Hi,%0A%0ACould you confirm access for workflow "${sanitizedName}" (handle: ${workflowState.workflow.handle ?? "n/a"}, id: ${workflowState.workflow.id})?%0A%0ALink: ${link}%0A`,
134
+ );
135
+ return `mailto:?subject=${subject}&body=${body}`;
136
+ }, [workflowState]);
137
+
138
+ const handleErrorBoundaryReset = useCallback(() => {
139
+ setChatError(null);
140
+ setRateLimitError(null);
141
+ setIsChatReady(false);
142
+ }, []);
143
+
144
+ const handleChatHttpError = (error: PublicChatHttpError) => {
145
+ if (error.status === 429 || error.code?.startsWith("chatkit.rate_limit")) {
146
+ setRateLimitError(error);
147
+ return;
148
+ }
149
+ if (error.code === "chatkit.auth.oauth_required") {
150
+ setChatError({
151
+ ...error,
152
+ message:
153
+ "OAuth login is required before this workflow can be used. Sign in and try again.",
154
+ });
155
+ setIsChatReady(false);
156
+ return;
157
+ }
158
+ if (error.status === 401 || error.status === 403) {
159
+ setChatError({
160
+ ...error,
161
+ message:
162
+ "You do not have access to this workflow yet. Ask the owner to confirm it is still published.",
163
+ });
164
+ setIsChatReady(false);
165
+ return;
166
+ }
167
+ setChatError({
168
+ ...error,
169
+ message:
170
+ error.message ||
171
+ "ChatKit could not start this conversation. Please try again shortly.",
172
+ });
173
+ setIsChatReady(false);
174
+ };
175
+
176
+ const resolvedColorScheme: ColorScheme =
177
+ theme === "system" ? systemColorScheme : theme;
178
+
179
+ useEffect(() => {
180
+ if (typeof window === "undefined") {
181
+ return;
182
+ }
183
+ const media = window.matchMedia("(prefers-color-scheme: dark)");
184
+ const handleChange = (event: MediaQueryListEvent) => {
185
+ setSystemColorScheme(event.matches ? "dark" : "light");
186
+ };
187
+ if (typeof media.addEventListener === "function") {
188
+ media.addEventListener("change", handleChange);
189
+ } else {
190
+ media.addListener(handleChange);
191
+ }
192
+ return () => {
193
+ if (typeof media.removeEventListener === "function") {
194
+ media.removeEventListener("change", handleChange);
195
+ } else {
196
+ media.removeListener(handleChange);
197
+ }
198
+ };
199
+ }, []);
200
+
201
+ const handleThemeRequest = useCallback(
202
+ (requestedScheme: ColorScheme) => {
203
+ setTheme(requestedScheme);
204
+ },
205
+ [setTheme],
206
+ );
207
+
208
+ const renderChatColumn = () => {
209
+ const currentWorkflowName =
210
+ workflowState.status === "ready"
211
+ ? workflowState.workflow.name
212
+ : "this workflow";
213
+
214
+ const renderBody = () => {
215
+ if (workflowState.status === "loading") {
216
+ return (
217
+ <div className="space-y-4">
218
+ <Skeleton className="h-10 w-40 rounded-full" />
219
+ <Skeleton className="h-[520px] w-full rounded-3xl" />
220
+ </div>
221
+ );
222
+ }
223
+
224
+ if (workflowState.status === "error") {
225
+ return (
226
+ <div className="rounded-3xl border border-slate-200/80 bg-white/70 p-6 text-slate-900 shadow-sm dark:border-slate-800/60 dark:bg-slate-950/40 dark:text-white">
227
+ <p className="text-lg font-semibold">Chat unavailable</p>
228
+ <p className="mt-2 text-sm text-slate-600 dark:text-slate-300">
229
+ We cannot open a ChatKit session until the workflow loads.
230
+ </p>
231
+ <Button asChild variant="secondary" className="mt-4">
232
+ <Link to="/">Return home</Link>
233
+ </Button>
234
+ </div>
235
+ );
236
+ }
237
+
238
+ if (
239
+ workflowState.status === "ready" &&
240
+ workflowState.workflow.require_login &&
241
+ !isAuthenticated()
242
+ ) {
243
+ return (
244
+ <div className="rounded-3xl border border-slate-200/80 bg-white/70 p-6 text-slate-900 shadow-sm dark:border-slate-800/60 dark:bg-slate-950/40 dark:text-white">
245
+ <p className="text-lg font-semibold">Login required</p>
246
+ <p className="mt-2 text-sm text-slate-600 dark:text-slate-300">
247
+ The owner requires OAuth login before this chat can start.
248
+ </p>
249
+ <div className="mt-4 flex flex-wrap gap-3">
250
+ <Button asChild>
251
+ <Link to="/login" state={{ from: redirectTo }}>
252
+ Sign in to continue
253
+ </Link>
254
+ </Button>
255
+ <Button asChild variant="outline">
256
+ <a href={contactHref}>Contact owner</a>
257
+ </Button>
258
+ </div>
259
+ </div>
260
+ );
261
+ }
262
+
263
+ return (
264
+ <div className="space-y-4">
265
+ {rateLimitError && (
266
+ <Alert className="border-amber-500/50 bg-amber-500/[0.08] text-amber-100">
267
+ <AlertTitle>Slow down for a moment</AlertTitle>
268
+ <AlertDescription>
269
+ {rateLimitError.message ||
270
+ "Too many requests were sent for this workflow. Please wait before retrying."}
271
+ </AlertDescription>
272
+ <div className="mt-3">
273
+ <Button
274
+ size="sm"
275
+ variant="outline"
276
+ className="border-amber-400/60 text-amber-100"
277
+ onClick={() => setRateLimitError(null)}
278
+ >
279
+ Dismiss
280
+ </Button>
281
+ </div>
282
+ </Alert>
283
+ )}
284
+
285
+ {chatError ? (
286
+ <div className="space-y-4 rounded-3xl border border-red-500/40 bg-red-500/10 p-6 text-center">
287
+ <p className="font-medium text-red-100">{chatError.message}</p>
288
+ <div className="flex flex-wrap justify-center gap-3">
289
+ <Button asChild variant="outline">
290
+ <a href={contactHref}>Contact owner</a>
291
+ </Button>
292
+ </div>
293
+ </div>
294
+ ) : (
295
+ <div className="relative min-h-[520px]">
296
+ {!isChatReady && (
297
+ <div className="absolute inset-0 flex flex-col gap-4 rounded-3xl bg-white/90 p-6 shadow-sm dark:bg-slate-950/80">
298
+ <Skeleton className="h-10 w-1/2 self-center" />
299
+ <Skeleton className="h-full w-full" />
300
+ </div>
301
+ )}
302
+ <div
303
+ className={cn(
304
+ "h-[520px] w-full",
305
+ isChatReady ? "opacity-100" : "opacity-0",
306
+ "transition-opacity duration-200",
307
+ )}
308
+ >
309
+ <PublicChatWidget
310
+ key={workflowState.workflow.id}
311
+ workflowId={workflowState.workflow.id}
312
+ workflowName={workflowState.workflow.name}
313
+ startScreenPrompts={
314
+ workflowState.workflow.chatkit?.start_screen_prompts
315
+ }
316
+ supportedModels={
317
+ workflowState.workflow.chatkit?.supported_models
318
+ }
319
+ backendBaseUrl={backendBaseUrl}
320
+ onHttpError={handleChatHttpError}
321
+ onReady={() => setIsChatReady(true)}
322
+ colorScheme={resolvedColorScheme}
323
+ onThemeRequest={handleThemeRequest}
324
+ />
325
+ </div>
326
+ </div>
327
+ )}
328
+ </div>
329
+ );
330
+ };
331
+
332
+ return (
333
+ <div className="space-y-6">
334
+ <div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
335
+ <div className="space-y-2">
336
+ <p className="text-3xl font-semibold text-slate-900 dark:text-white">
337
+ Chat with “{currentWorkflowName}”
338
+ </p>
339
+ <p className="text-base text-slate-600 dark:text-slate-300">
340
+ Chat sessions open automatically for published workflows unless
341
+ the owner requires OAuth login.
342
+ </p>
343
+ {workflowState.status === "ready" && (
344
+ <div className="flex flex-wrap gap-2 text-xs text-slate-500 dark:text-slate-400">
345
+ {workflowState.workflow.handle && (
346
+ <code className="rounded bg-slate-100 px-2 py-1 dark:bg-slate-900">
347
+ handle: {workflowState.workflow.handle}
348
+ </code>
349
+ )}
350
+ <code className="rounded bg-slate-100 px-2 py-1 dark:bg-slate-900">
351
+ id: {workflowState.workflow.id}
352
+ </code>
353
+ </div>
354
+ )}
355
+ </div>
356
+ <ThemeToggleButtonGroup value={theme} onChange={setTheme} />
357
+ </div>
358
+ {renderBody()}
359
+ </div>
360
+ );
361
+ };
362
+
363
+ return (
364
+ <PublicChatErrorBoundary onReset={handleErrorBoundaryReset}>
365
+ <div className="h-screen overflow-hidden bg-white text-slate-900 dark:bg-slate-950 dark:text-white">
366
+ <div className="mx-auto flex h-full max-w-6xl flex-col px-4 py-6 lg:py-8">
367
+ <div className="flex flex-1 items-center justify-center">
368
+ <div className="w-full max-w-3xl">{renderChatColumn()}</div>
369
+ </div>
370
+ </div>
371
+ </div>
372
+ </PublicChatErrorBoundary>
373
+ );
374
+ }
375
+
376
+ const THEME_OPTIONS: Array<{
377
+ icon: ReactNode;
378
+ label: string;
379
+ value: Theme;
380
+ }> = [
381
+ {
382
+ value: "light",
383
+ label: "Light",
384
+ icon: <Sun className="h-4 w-4" />,
385
+ },
386
+ {
387
+ value: "dark",
388
+ label: "Dark",
389
+ icon: <Moon className="h-4 w-4" />,
390
+ },
391
+ {
392
+ value: "system",
393
+ label: "System",
394
+ icon: <Monitor className="h-4 w-4" />,
395
+ },
396
+ ];
397
+
398
+ const isThemeValue = (value: string): value is Theme =>
399
+ THEME_OPTIONS.some((option) => option.value === value);
400
+
401
+ interface ThemeToggleButtonGroupProps {
402
+ className?: string;
403
+ value: Theme;
404
+ onChange: (theme: Theme) => void;
405
+ }
406
+
407
+ function ThemeToggleButtonGroup({
408
+ className,
409
+ value,
410
+ onChange,
411
+ }: ThemeToggleButtonGroupProps) {
412
+ const handleThemeChange = (value: string) => {
413
+ if (!value || !isThemeValue(value)) {
414
+ return;
415
+ }
416
+ onChange(value);
417
+ };
418
+
419
+ return (
420
+ <ToggleGroup
421
+ type="single"
422
+ value={value}
423
+ onValueChange={handleThemeChange}
424
+ aria-label="Select display theme"
425
+ className={cn(
426
+ "rounded-full border border-slate-200 bg-white/90 px-1 py-1 shadow-[inset_0_-1px_4px_rgba(15,23,42,0.12)] backdrop-blur-sm dark:border-slate-800 dark:bg-slate-950/70",
427
+ className,
428
+ )}
429
+ variant="default"
430
+ size="default"
431
+ >
432
+ {THEME_OPTIONS.map((option) => (
433
+ <ToggleGroupItem
434
+ key={option.value}
435
+ value={option.value}
436
+ aria-label={`Use ${option.label.toLowerCase()} theme`}
437
+ className="h-9 w-9 rounded-full border border-transparent p-0 text-slate-400 transition-all hover:bg-transparent hover:text-slate-900 dark:text-slate-400 dark:hover:text-white data-[state=on]:border-slate-900/20 data-[state=on]:bg-slate-900 data-[state=on]:text-white data-[state=on]:shadow-[0_4px_12px_rgba(15,23,42,0.3)] dark:data-[state=on]:border-white/30 dark:data-[state=on]:bg-white dark:data-[state=on]:text-slate-900"
438
+ >
439
+ {option.icon}
440
+ <span className="sr-only">{option.label}</span>
441
+ </ToggleGroupItem>
442
+ ))}
443
+ </ToggleGroup>
444
+ );
445
+ }