orcheo-studio 0.24.1 → 0.24.2

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 (73) hide show
  1. package/.bumpversion.cfg +1 -1
  2. package/dist/assets/{arc-DhTjQsml.js → arc-B5ofENSG.js} +1 -1
  3. package/dist/assets/{architectureDiagram-VXUJARFQ-CGDm4iVL.js → architectureDiagram-VXUJARFQ-DxYHdW7c.js} +1 -1
  4. package/dist/assets/{blockDiagram-VD42YOAC-B5xlwwyL.js → blockDiagram-VD42YOAC-DJFNLztP.js} +1 -1
  5. package/dist/assets/{c4Diagram-YG6GDRKO-DtVXFxFX.js → c4Diagram-YG6GDRKO-i42OpjrQ.js} +1 -1
  6. package/dist/assets/channel-D4idvlBv.js +1 -0
  7. package/dist/assets/{chunk-4BX2VUAB-CA8vZ6Tb.js → chunk-4BX2VUAB-BP38Jeu1.js} +1 -1
  8. package/dist/assets/{chunk-55IACEB6-CxNWLhGM.js → chunk-55IACEB6-DgOteLeo.js} +1 -1
  9. package/dist/assets/{chunk-B4BG7PRW-BW8UEmwi.js → chunk-B4BG7PRW-DSFMHhnv.js} +1 -1
  10. package/dist/assets/{chunk-DI55MBZ5-_6YQcHqR.js → chunk-DI55MBZ5-houO_rDU.js} +1 -1
  11. package/dist/assets/{chunk-FMBD7UC4-L-9FXYi4.js → chunk-FMBD7UC4-2uWxVMuK.js} +1 -1
  12. package/dist/assets/{chunk-QN33PNHL-DZtaWvmZ.js → chunk-QN33PNHL-CNE7iDzV.js} +1 -1
  13. package/dist/assets/{chunk-QZHKN3VN-B3c4-un7.js → chunk-QZHKN3VN-CuJasZjZ.js} +1 -1
  14. package/dist/assets/{chunk-TZMSLE5B-DmyAt3KD.js → chunk-TZMSLE5B-DdOfh1YS.js} +1 -1
  15. package/dist/assets/classDiagram-2ON5EDUG-BbsIqyB3.js +1 -0
  16. package/dist/assets/classDiagram-v2-WZHVMYZB-BbsIqyB3.js +1 -0
  17. package/dist/assets/clone-BtsJ7Mgy.js +1 -0
  18. package/dist/assets/{cose-bilkent-S5V4N54A-r3dremCG.js → cose-bilkent-S5V4N54A-n5L5u7aX.js} +1 -1
  19. package/dist/assets/{dagre-6UL2VRFP-C6AizynV.js → dagre-6UL2VRFP-DA0iPKXN.js} +1 -1
  20. package/dist/assets/{diagram-PSM6KHXK-CKTAJrFm.js → diagram-PSM6KHXK-3FRZnvw9.js} +1 -1
  21. package/dist/assets/{diagram-QEK2KX5R-B4BLbqZ6.js → diagram-QEK2KX5R-ePGkAGnY.js} +1 -1
  22. package/dist/assets/{diagram-S2PKOQOG-CLy2S4hE.js → diagram-S2PKOQOG-FYWv9iIE.js} +1 -1
  23. package/dist/assets/{erDiagram-Q2GNP2WA-DlemVcfS.js → erDiagram-Q2GNP2WA-2la-V9DA.js} +1 -1
  24. package/dist/assets/{flowDiagram-NV44I4VS-CpBPPeuN.js → flowDiagram-NV44I4VS-Cv-HCQV2.js} +1 -1
  25. package/dist/assets/{ganttDiagram-JELNMOA3-BY4cJPdg.js → ganttDiagram-JELNMOA3-DZhWBmY1.js} +1 -1
  26. package/dist/assets/{gitGraphDiagram-V2S2FVAM-D7RJFr3i.js → gitGraphDiagram-V2S2FVAM-CBfpN1uw.js} +1 -1
  27. package/dist/assets/{graph-CJZvtDnb.js → graph-D6aI-bPq.js} +1 -1
  28. package/dist/assets/{index-CARUdnbv.js → index-D8PZ9Puu.js} +185 -185
  29. package/dist/assets/{index-DcCYJX3c.css → index-Df4jFRhd.css} +1 -1
  30. package/dist/assets/{infoDiagram-HS3SLOUP-CcSzbqKG.js → infoDiagram-HS3SLOUP-Lvd-vDDU.js} +1 -1
  31. package/dist/assets/{isUndefined-BbMiFvTc.js → isUndefined-DLcwy6eJ.js} +1 -1
  32. package/dist/assets/{journeyDiagram-XKPGCS4Q-DTmP5k2H.js → journeyDiagram-XKPGCS4Q-rVvUlw1X.js} +1 -1
  33. package/dist/assets/{kanban-definition-3W4ZIXB7-BSA4gDhk.js → kanban-definition-3W4ZIXB7-Dg-tIUSI.js} +1 -1
  34. package/dist/assets/{layout-D3BxIqM1.js → layout-CYgJ9n1K.js} +1 -1
  35. package/dist/assets/{linear-CemsbS51.js → linear-CfAw1dgz.js} +1 -1
  36. package/dist/assets/{min-DkRMnH62.js → min-BBMETs6R.js} +1 -1
  37. package/dist/assets/{mindmap-definition-VGOIOE7T-CNj0QY6e.js → mindmap-definition-VGOIOE7T-DY__eUNT.js} +1 -1
  38. package/dist/assets/{pieDiagram-ADFJNKIX-CPQsqbb4.js → pieDiagram-ADFJNKIX-Nr7ukKrm.js} +1 -1
  39. package/dist/assets/{quadrantDiagram-AYHSOK5B-CPX25nd3.js → quadrantDiagram-AYHSOK5B-Bb54Oaa_.js} +1 -1
  40. package/dist/assets/{requirementDiagram-UZGBJVZJ-7mxxRNiB.js → requirementDiagram-UZGBJVZJ-BtLViRZC.js} +1 -1
  41. package/dist/assets/{sankeyDiagram-TZEHDZUN-CPhitUZ9.js → sankeyDiagram-TZEHDZUN-COqbhL3I.js} +1 -1
  42. package/dist/assets/{sequenceDiagram-WL72ISMW-BwLMsC7F.js → sequenceDiagram-WL72ISMW-DHKy94Yw.js} +1 -1
  43. package/dist/assets/{stateDiagram-FKZM4ZOC-Crx9CUqD.js → stateDiagram-FKZM4ZOC-8dJVXo1X.js} +1 -1
  44. package/dist/assets/stateDiagram-v2-4FDKWEC3-_96AsFOw.js +1 -0
  45. package/dist/assets/{timeline-definition-IT6M3QCI-DDh1Iim0.js → timeline-definition-IT6M3QCI-CyS6rBy_.js} +1 -1
  46. package/dist/assets/{treemap-GDKQZRPO-Bc6lNY0z.js → treemap-GDKQZRPO-CUM9baT2.js} +1 -1
  47. package/dist/assets/{xychartDiagram-PRI3JC2R-BAGZwI3e.js → xychartDiagram-PRI3JC2R-BztiRmM1.js} +1 -1
  48. package/dist/index.html +2 -2
  49. package/package.json +1 -1
  50. package/src/features/auth/pages/login.tsx +8 -1
  51. package/src/features/workflow/components/dialogs/update-workflow-dialog.tsx +1 -1
  52. package/src/features/workflow/components/dialogs/upload-workflow-dialog.tsx +14 -2
  53. package/src/features/workflow/data/workflow-types.ts +5 -0
  54. package/src/features/workflow/lib/workflow-storage-helpers.ts +21 -0
  55. package/src/features/workflow/lib/workflow-storage.ts +58 -31
  56. package/src/features/workflow/lib/workflow-storage.types.ts +11 -0
  57. package/src/features/workflow/lib/workflow-upload-errors.ts +81 -0
  58. package/src/features/workflow/pages/workflow/components/workflow-layout.tsx +4 -1
  59. package/src/features/workflow/pages/workflow/components/workflow-tab-content.tsx +108 -7
  60. package/src/features/workflow/pages/workflow/hooks/controller/build-layout-props.ts +3 -0
  61. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-lifecycle.ts +6 -0
  62. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-resources.ts +2 -0
  63. package/src/features/workflow/pages/workflow/hooks/execution-runtime-updates.ts +1 -1
  64. package/src/features/workflow/pages/workflow/hooks/use-workflow-loader.ts +22 -0
  65. package/src/features/workflow/pages/workflow/hooks/use-workflow-metadata-state.ts +11 -0
  66. package/src/features/workflow/pages/workflow/hooks/use-workflow-saver.ts +8 -0
  67. package/src/features/workflow/pages/workflow/hooks/use-workflow-storage-listener.ts +14 -0
  68. package/src/features/workflow/pages/workflow-gallery/workflow-card.tsx +26 -4
  69. package/dist/assets/channel-CeR8j9Si.js +0 -1
  70. package/dist/assets/classDiagram-2ON5EDUG-B2tKUrqn.js +0 -1
  71. package/dist/assets/classDiagram-v2-WZHVMYZB-B2tKUrqn.js +0 -1
  72. package/dist/assets/clone-BN-HxSe-.js +0 -1
  73. package/dist/assets/stateDiagram-v2-4FDKWEC3-elh6u9Fl.js +0 -1
@@ -17,6 +17,7 @@ export interface ApiWorkflow {
17
17
  id: string;
18
18
  handle?: string | null;
19
19
  team_id?: string | null;
20
+ team_slug?: string | null;
20
21
  name: string;
21
22
  slug: string;
22
23
  description: string | null;
@@ -31,10 +32,16 @@ export interface ApiWorkflow {
31
32
  updated_at: string;
32
33
  share_url?: string | null;
33
34
  chatkit?: WorkflowChatKitConfig | null;
35
+ upload_error?: ApiWorkflowUploadError | null;
34
36
  latest_version?: ApiWorkflowVersion | null;
35
37
  is_scheduled?: boolean;
36
38
  }
37
39
 
40
+ export interface ApiWorkflowUploadError {
41
+ message: string;
42
+ occurred_at: string;
43
+ }
44
+
38
45
  export interface ChatKitStartScreenPrompt {
39
46
  label: string;
40
47
  prompt: string;
@@ -262,6 +269,10 @@ export interface WorkflowVersionRecord {
262
269
  export interface StoredWorkflow extends Workflow {
263
270
  versions: WorkflowVersionRecord[];
264
271
  teamId?: string | null;
272
+ uploadError?: {
273
+ message: string;
274
+ occurredAt: string;
275
+ };
265
276
  draftAccess?: "personal" | "authenticated" | "workspace";
266
277
  isArchived?: boolean;
267
278
  isPublic?: boolean;
@@ -0,0 +1,81 @@
1
+ import type { StoredWorkflow } from "./workflow-storage.types";
2
+
3
+ export interface WorkflowUploadError {
4
+ message: string;
5
+ occurredAt: string;
6
+ }
7
+
8
+ const STORAGE_PREFIX = "orcheo.workflowUploadError.";
9
+
10
+ const storageKey = (workflowId: string): string => `${STORAGE_PREFIX}${workflowId}`;
11
+
12
+ const canUseSessionStorage = (): boolean =>
13
+ typeof window !== "undefined" && Boolean(window.sessionStorage);
14
+
15
+ export const saveWorkflowUploadError = (
16
+ workflowId: string,
17
+ message: string,
18
+ ): WorkflowUploadError => {
19
+ const error = {
20
+ message,
21
+ occurredAt: new Date().toISOString(),
22
+ };
23
+
24
+ if (!canUseSessionStorage()) {
25
+ return error;
26
+ }
27
+
28
+ try {
29
+ window.sessionStorage.setItem(storageKey(workflowId), JSON.stringify(error));
30
+ } catch {
31
+ // Upload failure rendering should not depend on storage availability.
32
+ }
33
+
34
+ return error;
35
+ };
36
+
37
+ export const readWorkflowUploadError = (
38
+ workflowId: string,
39
+ ): WorkflowUploadError | undefined => {
40
+ if (!canUseSessionStorage()) {
41
+ return undefined;
42
+ }
43
+
44
+ try {
45
+ const raw = window.sessionStorage.getItem(storageKey(workflowId));
46
+ if (!raw) {
47
+ return undefined;
48
+ }
49
+ const parsed = JSON.parse(raw) as Partial<WorkflowUploadError>;
50
+ if (
51
+ typeof parsed.message === "string" &&
52
+ parsed.message.trim().length > 0 &&
53
+ typeof parsed.occurredAt === "string"
54
+ ) {
55
+ return {
56
+ message: parsed.message,
57
+ occurredAt: parsed.occurredAt,
58
+ };
59
+ }
60
+ } catch {
61
+ return undefined;
62
+ }
63
+
64
+ return undefined;
65
+ };
66
+
67
+ export const clearWorkflowUploadError = (workflowId: string): void => {
68
+ if (!canUseSessionStorage()) {
69
+ return;
70
+ }
71
+
72
+ try {
73
+ window.sessionStorage.removeItem(storageKey(workflowId));
74
+ } catch {
75
+ // Ignore storage errors; the next successful version is authoritative.
76
+ }
77
+ };
78
+
79
+ export const getWorkflowUploadError = (
80
+ workflow: Pick<StoredWorkflow, "versions" | "uploadError">,
81
+ ): WorkflowUploadError | undefined => workflow.uploadError;
@@ -88,7 +88,10 @@ export function WorkflowLayout({
88
88
  forceMount
89
89
  className="m-0 flex min-h-0 flex-1 flex-col overflow-hidden p-0 data-[state=inactive]:hidden"
90
90
  >
91
- <WorkflowTabContent {...workflowProps} />
91
+ <WorkflowTabContent
92
+ {...workflowProps}
93
+ isActive={tabsProps.activeTab === "workflow"}
94
+ />
92
95
  </TabsContent>
93
96
 
94
97
  <TabsContent
@@ -1,4 +1,4 @@
1
- import { useEffect, useMemo, useState } from "react";
1
+ import { useEffect, useMemo, useRef, useState } from "react";
2
2
  import { useUploadsAllowed } from "@/hooks/use-uploads-allowed";
3
3
  import {
4
4
  AlertTriangle,
@@ -60,15 +60,24 @@ import { resolveWorkflowVersionMermaidSource } from "@features/workflow/lib/work
60
60
  import { WorkflowConfigSheet } from "@features/workflow/pages/workflow/components/workflow-config-sheet";
61
61
  import type { WorkflowExecutionStatus } from "@features/workflow/pages/workflow/helpers/types";
62
62
 
63
+ const RUN_RESULT_BANNER_TIMEOUT_MS = 6000;
64
+
63
65
  export interface WorkflowTabContentProps {
64
66
  workflowId: string | null;
65
67
  workflowRouteRef?: string | null;
66
68
  workflowName: string;
69
+ workflowHandle?: string | null;
70
+ workflowTeamSlug?: string | null;
67
71
  versions: WorkflowVersionRecord[];
72
+ uploadError?: {
73
+ message: string;
74
+ occurredAt: string;
75
+ } | null;
68
76
  isLoading: boolean;
69
77
  loadError: string | null;
70
78
  isRunPending: boolean;
71
79
  isRunning: boolean;
80
+ isActive?: boolean;
72
81
  lastRunStatus?: WorkflowExecutionStatus | null;
73
82
  onRunWorkflow: () => Promise<void>;
74
83
  onSaveConfig: (nextConfig: WorkflowRunnableConfig | null) => Promise<void>;
@@ -193,6 +202,29 @@ const getErrorMessage = (error: unknown, fallback: string): string => {
193
202
  return rawMessage;
194
203
  };
195
204
 
205
+ const formatWorkflowHandle = (
206
+ handle?: string | null,
207
+ teamSlug?: string | null,
208
+ ): string | null => {
209
+ const trimmedHandle = handle?.trim().replace(/^@+/, "");
210
+ if (!trimmedHandle) {
211
+ return null;
212
+ }
213
+
214
+ if (trimmedHandle.includes("/")) {
215
+ return `@${trimmedHandle}`;
216
+ }
217
+
218
+ const trimmedTeamSlug = teamSlug
219
+ ?.trim()
220
+ .replace(/^@+/, "")
221
+ .replace(/\/+$/, "");
222
+
223
+ return trimmedTeamSlug
224
+ ? `@${trimmedTeamSlug}/${trimmedHandle}`
225
+ : `@${trimmedHandle}`;
226
+ };
227
+
196
228
  interface RunResultBanner {
197
229
  Icon: typeof CheckCircle2;
198
230
  className: string;
@@ -239,11 +271,15 @@ const resolveRunResultBanner = (
239
271
  export function WorkflowTabContent({
240
272
  workflowId,
241
273
  workflowName,
274
+ workflowHandle,
275
+ workflowTeamSlug,
242
276
  versions,
277
+ uploadError,
243
278
  isLoading,
244
279
  loadError,
245
280
  isRunPending,
246
281
  isRunning,
282
+ isActive = true,
247
283
  lastRunStatus = null,
248
284
  onRunWorkflow,
249
285
  onSaveConfig,
@@ -256,6 +292,8 @@ export function WorkflowTabContent({
256
292
  const navigate = useNavigate();
257
293
  const uploadsAllowed = useUploadsAllowed();
258
294
  const latestVersion = versions.at(-1);
295
+ const workflowSubtitleLabel =
296
+ formatWorkflowHandle(workflowHandle, workflowTeamSlug) ?? workflowName;
259
297
  const [isConfigOpen, setIsConfigOpen] = useState(false);
260
298
  const [isPublished, setIsPublished] = useState(initialIsPublished);
261
299
  const [requireLogin, setRequireLogin] = useState(initialRequireLogin);
@@ -271,6 +309,10 @@ export function WorkflowTabContent({
271
309
  const [isUpdateDialogOpen, setIsUpdateDialogOpen] = useState(false);
272
310
  const [isMissingCredentialsDialogOpen, setIsMissingCredentialsDialogOpen] =
273
311
  useState(false);
312
+ const [visibleRunResultStatus, setVisibleRunResultStatus] =
313
+ useState<WorkflowExecutionStatus | null>(null);
314
+ const isRunActive = isRunPending || isRunning;
315
+ const wasRunActiveRef = useRef(isRunActive);
274
316
  const hasMissingCredentials = missingCredentials.length > 0;
275
317
  const canDeleteWorkflow = Boolean(workflowId);
276
318
 
@@ -396,6 +438,26 @@ export function WorkflowTabContent({
396
438
  };
397
439
  }, [mermaidCacheKey, mermaidRenderId, mermaidSource]);
398
440
 
441
+ useEffect(() => {
442
+ const didFinishRun =
443
+ wasRunActiveRef.current && !isRunActive && Boolean(lastRunStatus);
444
+ wasRunActiveRef.current = isRunActive;
445
+
446
+ if (!isActive || isRunActive || !didFinishRun || !lastRunStatus) {
447
+ setVisibleRunResultStatus(null);
448
+ return;
449
+ }
450
+
451
+ setVisibleRunResultStatus(lastRunStatus);
452
+ const timeoutId = window.setTimeout(() => {
453
+ setVisibleRunResultStatus(null);
454
+ }, RUN_RESULT_BANNER_TIMEOUT_MS);
455
+
456
+ return () => {
457
+ window.clearTimeout(timeoutId);
458
+ };
459
+ }, [isActive, isRunActive, lastRunStatus]);
460
+
399
461
  const diagramNodes = useMemo(() => {
400
462
  if (!diagramSvg) {
401
463
  return [] as Node[];
@@ -438,10 +500,11 @@ export function WorkflowTabContent({
438
500
  }
439
501
 
440
502
  const canConfigure = Boolean(workflowId);
441
- const isRunActive = isRunPending || isRunning;
503
+ const hasUploadError = Boolean(uploadError);
504
+ const uploadBlocksWorkflow = hasUploadError && !latestVersion;
442
505
  const runResultBanner =
443
- !isRunActive && lastRunStatus
444
- ? resolveRunResultBanner(lastRunStatus)
506
+ !isRunActive && visibleRunResultStatus
507
+ ? resolveRunResultBanner(visibleRunResultStatus)
445
508
  : null;
446
509
  const canRun = Boolean(workflowId && latestVersion);
447
510
  const runButtonDisabled = !canRun || isRunPending || isRunning;
@@ -480,6 +543,16 @@ export function WorkflowTabContent({
480
543
  return;
481
544
  }
482
545
 
546
+ if (uploadBlocksWorkflow) {
547
+ setIsPublished(false);
548
+ toast({
549
+ title: "Fix upload error first",
550
+ description: "Fix the error and upload again before publishing.",
551
+ variant: "destructive",
552
+ });
553
+ return;
554
+ }
555
+
483
556
  if (nextValue) {
484
557
  setIsPublishDialogOpen(true);
485
558
  return;
@@ -553,6 +626,16 @@ export function WorkflowTabContent({
553
626
  return;
554
627
  }
555
628
 
629
+ if (uploadBlocksWorkflow) {
630
+ setIsScheduled(false);
631
+ toast({
632
+ title: "Fix upload error first",
633
+ description: "Fix the error and upload again before scheduling.",
634
+ variant: "destructive",
635
+ });
636
+ return;
637
+ }
638
+
556
639
  setIsSchedulePending(true);
557
640
  try {
558
641
  if (nextValue) {
@@ -630,7 +713,7 @@ export function WorkflowTabContent({
630
713
  {workflowName || "Workflow"}
631
714
  </h2>
632
715
  <p className="text-sm text-muted-foreground">
633
- {workflowName}
716
+ {workflowSubtitleLabel}
634
717
  {latestVersion ? ` · ${latestVersion.version}` : ""}
635
718
  </p>
636
719
  </div>
@@ -648,7 +731,7 @@ export function WorkflowTabContent({
648
731
  onCheckedChange={(checked) =>
649
732
  void handlePublishToggle(checked)
650
733
  }
651
- disabled={isPublishPending}
734
+ disabled={isPublishPending || uploadBlocksWorkflow}
652
735
  />
653
736
  </div>
654
737
  </TooltipTrigger>
@@ -668,7 +751,9 @@ export function WorkflowTabContent({
668
751
  onCheckedChange={(checked) =>
669
752
  void handleScheduleToggle(checked)
670
753
  }
671
- disabled={isSchedulePending || !canToggleSchedule}
754
+ disabled={
755
+ isSchedulePending || !canToggleSchedule || uploadBlocksWorkflow
756
+ }
672
757
  />
673
758
  </div>
674
759
  {workflowId && uploadsAllowed === true ? (
@@ -740,6 +825,22 @@ export function WorkflowTabContent({
740
825
  </div>
741
826
  )}
742
827
 
828
+ {uploadError && (
829
+ <Alert variant="destructive">
830
+ <XCircle className="h-4 w-4" />
831
+ <AlertTitle>Workflow upload failed</AlertTitle>
832
+ <AlertDescription>
833
+ <div className="space-y-2">
834
+ <p>{uploadError.message}</p>
835
+ <p>
836
+ Fix the error in the workflow script or config, then upload
837
+ again.
838
+ </p>
839
+ </div>
840
+ </AlertDescription>
841
+ </Alert>
842
+ )}
843
+
743
844
  {isPublished && shareUrl && (
744
845
  <div className="flex items-center justify-between rounded-md border border-border/60 bg-muted/20 px-3 py-2">
745
846
  <div className="min-w-0">
@@ -83,7 +83,10 @@ export function buildWorkflowLayoutProps(
83
83
  workflowId: core.metadata.currentWorkflowId,
84
84
  workflowRouteRef: core.routeWorkflowRef,
85
85
  workflowName: core.metadata.workflowName,
86
+ workflowHandle: core.metadata.workflowHandle,
87
+ workflowTeamSlug: core.metadata.workflowTeamSlug,
86
88
  versions: core.metadata.workflowVersions ?? [],
89
+ uploadError: core.metadata.workflowUploadError,
87
90
  isLoading: core.metadata.isWorkflowLoading,
88
91
  loadError: core.metadata.workflowLoadError,
89
92
  isRunPending: execution.isRunPending,
@@ -13,8 +13,11 @@ export function useWorkflowLifecycle(
13
13
  setCurrentWorkflowId: core.metadata.setCurrentWorkflowId,
14
14
  setWorkflowName: core.metadata.setWorkflowName,
15
15
  setWorkflowDescription: core.metadata.setWorkflowDescription,
16
+ setWorkflowHandle: core.metadata.setWorkflowHandle,
17
+ setWorkflowTeamSlug: core.metadata.setWorkflowTeamSlug,
16
18
  setWorkflowTags: core.metadata.setWorkflowTags,
17
19
  setWorkflowVersions: core.metadata.setWorkflowVersions,
20
+ setWorkflowUploadError: core.metadata.setWorkflowUploadError,
18
21
  setChatkitStartScreenPrompts: core.metadata.setChatkitStartScreenPrompts,
19
22
  setChatkitSupportedModels: core.metadata.setChatkitSupportedModels,
20
23
  setIsWorkflowPublic: core.metadata.setIsWorkflowPublic,
@@ -30,7 +33,10 @@ export function useWorkflowLifecycle(
30
33
  currentWorkflowId: core.metadata.currentWorkflowId,
31
34
  setWorkflowName: core.metadata.setWorkflowName,
32
35
  setWorkflowDescription: core.metadata.setWorkflowDescription,
36
+ setWorkflowHandle: core.metadata.setWorkflowHandle,
37
+ setWorkflowTeamSlug: core.metadata.setWorkflowTeamSlug,
33
38
  setWorkflowVersions: core.metadata.setWorkflowVersions,
39
+ setWorkflowUploadError: core.metadata.setWorkflowUploadError,
34
40
  setWorkflowTags: core.metadata.setWorkflowTags,
35
41
  setChatkitStartScreenPrompts: core.metadata.setChatkitStartScreenPrompts,
36
42
  setChatkitSupportedModels: core.metadata.setChatkitSupportedModels,
@@ -40,6 +40,8 @@ export function useWorkflowResources(
40
40
  const saver = useWorkflowSaver({
41
41
  setWorkflowName: core.metadata.setWorkflowName,
42
42
  setWorkflowDescription: core.metadata.setWorkflowDescription,
43
+ setWorkflowHandle: core.metadata.setWorkflowHandle,
44
+ setWorkflowTeamSlug: core.metadata.setWorkflowTeamSlug,
43
45
  setWorkflowVersions: core.metadata.setWorkflowVersions,
44
46
  setWorkflowTags: core.metadata.setWorkflowTags,
45
47
  workflowName: core.metadata.workflowName,
@@ -43,7 +43,7 @@ export function collectRuntimeUpdates(
43
43
  return;
44
44
  }
45
45
 
46
- const resultsCandidate = value["results"];
46
+ const resultsCandidate = value["node_results"];
47
47
  let candidatePayload: unknown;
48
48
 
49
49
  if (isRecord(resultsCandidate)) {
@@ -19,8 +19,13 @@ interface UseWorkflowLoaderParams {
19
19
  setCurrentWorkflowId: Dispatch<SetStateAction<string | null>>;
20
20
  setWorkflowName: Dispatch<SetStateAction<string>>;
21
21
  setWorkflowDescription: Dispatch<SetStateAction<string>>;
22
+ setWorkflowHandle: Dispatch<SetStateAction<string | null>>;
23
+ setWorkflowTeamSlug: Dispatch<SetStateAction<string | null>>;
22
24
  setWorkflowTags: Dispatch<SetStateAction<string[]>>;
23
25
  setWorkflowVersions: Dispatch<SetStateAction<StoredWorkflow["versions"]>>;
26
+ setWorkflowUploadError: Dispatch<
27
+ SetStateAction<StoredWorkflow["uploadError"] | null>
28
+ >;
24
29
  setChatkitStartScreenPrompts: Dispatch<
25
30
  SetStateAction<ChatKitStartScreenPrompt[] | null>
26
31
  >;
@@ -42,8 +47,11 @@ export function useWorkflowLoader({
42
47
  setCurrentWorkflowId,
43
48
  setWorkflowName,
44
49
  setWorkflowDescription,
50
+ setWorkflowHandle,
51
+ setWorkflowTeamSlug,
45
52
  setWorkflowTags,
46
53
  setWorkflowVersions,
54
+ setWorkflowUploadError,
47
55
  setChatkitStartScreenPrompts,
48
56
  setChatkitSupportedModels,
49
57
  setIsWorkflowPublic,
@@ -64,8 +72,11 @@ export function useWorkflowLoader({
64
72
  setCurrentWorkflowId(null);
65
73
  setWorkflowName("New Workflow");
66
74
  setWorkflowDescription("");
75
+ setWorkflowHandle(null);
76
+ setWorkflowTeamSlug(null);
67
77
  setWorkflowTags(["draft"]);
68
78
  setWorkflowVersions([]);
79
+ setWorkflowUploadError(null);
69
80
  setChatkitStartScreenPrompts(null);
70
81
  setChatkitSupportedModels(null);
71
82
  setIsWorkflowPublic(false);
@@ -83,6 +94,9 @@ export function useWorkflowLoader({
83
94
  setActiveExecutionId(null);
84
95
  setChatkitStartScreenPrompts(null);
85
96
  setChatkitSupportedModels(null);
97
+ setWorkflowHandle(null);
98
+ setWorkflowTeamSlug(null);
99
+ setWorkflowUploadError(null);
86
100
  setIsWorkflowLoading(false);
87
101
  setWorkflowLoadError(null);
88
102
  return;
@@ -98,8 +112,11 @@ export function useWorkflowLoader({
98
112
  setCurrentWorkflowId(persisted.id);
99
113
  setWorkflowName(persisted.name);
100
114
  setWorkflowDescription(persisted.description ?? "");
115
+ setWorkflowHandle(persisted.handle ?? null);
116
+ setWorkflowTeamSlug(persisted.teamSlug ?? null);
101
117
  setWorkflowTags(persisted.tags ?? ["draft"]);
102
118
  setWorkflowVersions(persisted.versions ?? []);
119
+ setWorkflowUploadError(persisted.uploadError ?? null);
103
120
  setChatkitStartScreenPrompts(
104
121
  persisted.chatkitStartScreenPrompts ?? null,
105
122
  );
@@ -125,6 +142,7 @@ export function useWorkflowLoader({
125
142
  setWorkflowLoadError(
126
143
  error instanceof Error ? error.message : "Unknown error occurred",
127
144
  );
145
+ setWorkflowUploadError(null);
128
146
  setChatkitStartScreenPrompts(null);
129
147
  setChatkitSupportedModels(null);
130
148
  setIsWorkflowPublic(false);
@@ -163,6 +181,9 @@ export function useWorkflowLoader({
163
181
  setExecutions,
164
182
  setActiveExecutionId,
165
183
  setWorkflowDescription,
184
+ setWorkflowHandle,
185
+ setWorkflowTeamSlug,
186
+ setWorkflowUploadError,
166
187
  setChatkitStartScreenPrompts,
167
188
  setChatkitSupportedModels,
168
189
  setIsWorkflowPublic,
@@ -172,6 +193,7 @@ export function useWorkflowLoader({
172
193
  setWorkflowShareUrl,
173
194
  setWorkflowTags,
174
195
  setWorkflowVersions,
196
+ setWorkflowRequireLogin,
175
197
  workflowId,
176
198
  ]);
177
199
 
@@ -9,12 +9,17 @@ import type {
9
9
  export function useWorkflowMetadataState() {
10
10
  const [workflowName, setWorkflowName] = useState("New Workflow");
11
11
  const [workflowDescription, setWorkflowDescription] = useState("");
12
+ const [workflowHandle, setWorkflowHandle] = useState<string | null>(null);
13
+ const [workflowTeamSlug, setWorkflowTeamSlug] = useState<string | null>(null);
12
14
  const [currentWorkflowId, setCurrentWorkflowId] = useState<string | null>(
13
15
  null,
14
16
  );
15
17
  const [workflowVersions, setWorkflowVersions] = useState<
16
18
  StoredWorkflow["versions"]
17
19
  >([]);
20
+ const [workflowUploadError, setWorkflowUploadError] = useState<
21
+ StoredWorkflow["uploadError"] | null
22
+ >(null);
18
23
  const [workflowTags, setWorkflowTags] = useState<string[]>(["draft"]);
19
24
  const [isWorkflowLoading, setIsWorkflowLoading] = useState(false);
20
25
  const [workflowLoadError, setWorkflowLoadError] = useState<string | null>(
@@ -35,10 +40,16 @@ export function useWorkflowMetadataState() {
35
40
  setWorkflowName,
36
41
  workflowDescription,
37
42
  setWorkflowDescription,
43
+ workflowHandle,
44
+ setWorkflowHandle,
45
+ workflowTeamSlug,
46
+ setWorkflowTeamSlug,
38
47
  currentWorkflowId,
39
48
  setCurrentWorkflowId,
40
49
  workflowVersions,
41
50
  setWorkflowVersions,
51
+ workflowUploadError,
52
+ setWorkflowUploadError,
42
53
  workflowTags,
43
54
  setWorkflowTags,
44
55
  isWorkflowLoading,
@@ -13,6 +13,8 @@ import type { WorkflowRunnableConfig } from "@features/workflow/lib/workflow-sto
13
13
  interface WorkflowSaverOptions {
14
14
  setWorkflowName: Dispatch<SetStateAction<string>>;
15
15
  setWorkflowDescription: Dispatch<SetStateAction<string>>;
16
+ setWorkflowHandle: Dispatch<SetStateAction<string | null>>;
17
+ setWorkflowTeamSlug: Dispatch<SetStateAction<string | null>>;
16
18
  setWorkflowVersions: Dispatch<SetStateAction<StoredWorkflow["versions"]>>;
17
19
  setWorkflowTags: Dispatch<SetStateAction<string[]>>;
18
20
  workflowName: string;
@@ -37,6 +39,8 @@ export function useWorkflowSaver(
37
39
  const {
38
40
  setWorkflowName,
39
41
  setWorkflowDescription,
42
+ setWorkflowHandle,
43
+ setWorkflowTeamSlug,
40
44
  setWorkflowVersions,
41
45
  setWorkflowTags,
42
46
  workflowName,
@@ -111,6 +115,8 @@ export function useWorkflowSaver(
111
115
 
112
116
  setWorkflowName(saved.name);
113
117
  setWorkflowDescription(saved.description ?? "");
118
+ setWorkflowHandle(saved.handle ?? null);
119
+ setWorkflowTeamSlug(saved.teamSlug ?? null);
114
120
  setWorkflowTags(saved.tags ?? tagsToPersist);
115
121
  setWorkflowVersions(saved.versions ?? []);
116
122
 
@@ -131,6 +137,8 @@ export function useWorkflowSaver(
131
137
  }, [
132
138
  currentWorkflowId,
133
139
  setWorkflowDescription,
140
+ setWorkflowHandle,
141
+ setWorkflowTeamSlug,
134
142
  setWorkflowName,
135
143
  setWorkflowTags,
136
144
  setWorkflowVersions,
@@ -15,7 +15,12 @@ interface UseWorkflowStorageListenerParams {
15
15
  currentWorkflowId: string | null;
16
16
  setWorkflowName: Dispatch<SetStateAction<string>>;
17
17
  setWorkflowDescription: Dispatch<SetStateAction<string>>;
18
+ setWorkflowHandle: Dispatch<SetStateAction<string | null>>;
19
+ setWorkflowTeamSlug: Dispatch<SetStateAction<string | null>>;
18
20
  setWorkflowVersions: Dispatch<SetStateAction<StoredWorkflow["versions"]>>;
21
+ setWorkflowUploadError: Dispatch<
22
+ SetStateAction<StoredWorkflow["uploadError"] | null>
23
+ >;
19
24
  setWorkflowTags: Dispatch<SetStateAction<string[]>>;
20
25
  setChatkitStartScreenPrompts: Dispatch<
21
26
  SetStateAction<ChatKitStartScreenPrompt[] | null>
@@ -29,7 +34,10 @@ export function useWorkflowStorageListener({
29
34
  currentWorkflowId,
30
35
  setWorkflowName,
31
36
  setWorkflowDescription,
37
+ setWorkflowHandle,
38
+ setWorkflowTeamSlug,
32
39
  setWorkflowVersions,
40
+ setWorkflowUploadError,
33
41
  setWorkflowTags,
34
42
  setChatkitStartScreenPrompts,
35
43
  setChatkitSupportedModels,
@@ -50,7 +58,10 @@ export function useWorkflowStorageListener({
50
58
  if (updated) {
51
59
  setWorkflowName(updated.name);
52
60
  setWorkflowDescription(updated.description ?? "");
61
+ setWorkflowHandle(updated.handle ?? null);
62
+ setWorkflowTeamSlug(updated.teamSlug ?? null);
53
63
  setWorkflowVersions(updated.versions ?? []);
64
+ setWorkflowUploadError(updated.uploadError ?? null);
54
65
  setWorkflowTags(updated.tags ?? ["draft"]);
55
66
  setChatkitStartScreenPrompts(
56
67
  updated.chatkitStartScreenPrompts ?? null,
@@ -72,10 +83,13 @@ export function useWorkflowStorageListener({
72
83
  }, [
73
84
  currentWorkflowId,
74
85
  setWorkflowDescription,
86
+ setWorkflowHandle,
87
+ setWorkflowTeamSlug,
75
88
  setChatkitStartScreenPrompts,
76
89
  setChatkitSupportedModels,
77
90
  setWorkflowName,
78
91
  setWorkflowTags,
92
+ setWorkflowUploadError,
79
93
  setWorkflowVersions,
80
94
  ]);
81
95
  }
@@ -128,6 +128,7 @@ export const WorkflowCard = ({
128
128
  const versionToDisplay = isTemplate
129
129
  ? (candidateBadge?.version ?? null)
130
130
  : (workflow.versions?.at(-1)?.candidateSource?.candidateVersion ?? null);
131
+ const uploadError = !isTemplate ? workflow.uploadError : undefined;
131
132
  const avatarUrl = resolveAvatarUrl(
132
133
  workflow.avatarEmoji ?? getWorkflowTemplateAvatar(workflow),
133
134
  workflow.id,
@@ -309,10 +310,31 @@ export const WorkflowCard = ({
309
310
 
310
311
  <CardContent className="flex flex-1 min-h-0 flex-col items-center px-5 py-3 text-center">
311
312
  <div className="relative flex w-full shrink-0 items-start justify-center">
312
- <div className="absolute left-0 top-0 flex items-center gap-1 rounded-md border border-border/70 bg-muted/60 px-2 py-1 text-muted-foreground shadow-sm dark:bg-slate-950/20">
313
- <span className="h-1.5 w-1.5 rounded-full bg-slate-800 shadow-[0_0_6px_rgba(15,23,42,0.32)] dark:bg-slate-200 dark:shadow-[0_0_6px_rgba(226,232,240,0.28)]" />
314
- <span className="font-mono text-[9px] font-bold uppercase tracking-[0.1em] text-slate-700 dark:text-slate-300">
315
- AI
313
+ <div
314
+ className={cn(
315
+ "absolute left-0 top-0 flex items-center gap-1 rounded-md border px-2 py-1 shadow-sm",
316
+ uploadError
317
+ ? "border-red-500/40 bg-red-50 text-red-700 dark:bg-red-950/40 dark:text-red-300"
318
+ : "border-border/70 bg-muted/60 text-muted-foreground dark:bg-slate-950/20",
319
+ )}
320
+ >
321
+ <span
322
+ className={cn(
323
+ "h-1.5 w-1.5 rounded-full",
324
+ uploadError
325
+ ? "bg-red-600 shadow-[0_0_6px_rgba(220,38,38,0.45)] dark:bg-red-300"
326
+ : "bg-slate-800 shadow-[0_0_6px_rgba(15,23,42,0.32)] dark:bg-slate-200 dark:shadow-[0_0_6px_rgba(226,232,240,0.28)]",
327
+ )}
328
+ />
329
+ <span
330
+ className={cn(
331
+ "font-mono text-[9px] font-bold uppercase tracking-[0.1em]",
332
+ uploadError
333
+ ? "text-red-700 dark:text-red-300"
334
+ : "text-slate-700 dark:text-slate-300",
335
+ )}
336
+ >
337
+ {uploadError ? "Error" : "AI"}
316
338
  </span>
317
339
  </div>
318
340
 
@@ -1 +0,0 @@
1
- import{ap as o,aq as n}from"./index-CARUdnbv.js";const t=(a,r)=>o.lang.round(n.parse(a)[r]);export{t as c};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-B4BG7PRW-BW8UEmwi.js";import{_ as i}from"./index-CARUdnbv.js";import"./chunk-FMBD7UC4-L-9FXYi4.js";import"./chunk-55IACEB6-CxNWLhGM.js";import"./chunk-QN33PNHL-DZtaWvmZ.js";var p={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{p as diagram};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-B4BG7PRW-BW8UEmwi.js";import{_ as i}from"./index-CARUdnbv.js";import"./chunk-FMBD7UC4-L-9FXYi4.js";import"./chunk-55IACEB6-CxNWLhGM.js";import"./chunk-QN33PNHL-DZtaWvmZ.js";var p={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{p as diagram};
@@ -1 +0,0 @@
1
- import{ay as r}from"./index-CARUdnbv.js";var a=4;function n(o){return r(o,a)}export{n as c};
@@ -1 +0,0 @@
1
- import{s as t,b as r,a,S as s}from"./chunk-DI55MBZ5-_6YQcHqR.js";import{_ as i}from"./index-CARUdnbv.js";import"./chunk-55IACEB6-CxNWLhGM.js";import"./chunk-QN33PNHL-DZtaWvmZ.js";var l={parser:a,get db(){return new s(2)},renderer:r,styles:t,init:i(e=>{e.state||(e.state={}),e.state.arrowMarkerAbsolute=e.arrowMarkerAbsolute},"init")};export{l as diagram};