orcheo-studio 0.24.4 → 0.24.6

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 (103) hide show
  1. package/.bumpversion.cfg +1 -1
  2. package/dist/assets/{arc-99TH-Koz.js → arc-CJePtrV4.js} +1 -1
  3. package/dist/assets/{architectureDiagram-VXUJARFQ-DugaTSY2.js → architectureDiagram-VXUJARFQ-BavAz0jp.js} +1 -1
  4. package/dist/assets/{blockDiagram-VD42YOAC-BH68wVtD.js → blockDiagram-VD42YOAC-Bx1XAydH.js} +1 -1
  5. package/dist/assets/{c4Diagram-YG6GDRKO-V6Vqtp7B.js → c4Diagram-YG6GDRKO-B2LhByin.js} +1 -1
  6. package/dist/assets/channel-BuDj-lWJ.js +1 -0
  7. package/dist/assets/{chunk-4BX2VUAB-CvbCAMNv.js → chunk-4BX2VUAB-UqiH5dLp.js} +1 -1
  8. package/dist/assets/{chunk-55IACEB6-h_T3kQh7.js → chunk-55IACEB6-ChxTr_6v.js} +1 -1
  9. package/dist/assets/{chunk-B4BG7PRW-Dm6dgbGh.js → chunk-B4BG7PRW-2ETw-eA1.js} +1 -1
  10. package/dist/assets/{chunk-DI55MBZ5-DSXFA4Fi.js → chunk-DI55MBZ5-BdxVSKej.js} +1 -1
  11. package/dist/assets/{chunk-FMBD7UC4-DJDlfjt1.js → chunk-FMBD7UC4-BJF2M5iQ.js} +1 -1
  12. package/dist/assets/{chunk-QN33PNHL-BnjUGeBL.js → chunk-QN33PNHL-DI9t3nKL.js} +1 -1
  13. package/dist/assets/{chunk-QZHKN3VN-BRudOghZ.js → chunk-QZHKN3VN-DsbUIBgB.js} +1 -1
  14. package/dist/assets/{chunk-TZMSLE5B-CpxSpvqK.js → chunk-TZMSLE5B-DzMhWfBV.js} +1 -1
  15. package/dist/assets/classDiagram-2ON5EDUG-Bc5AzWzU.js +1 -0
  16. package/dist/assets/classDiagram-v2-WZHVMYZB-Bc5AzWzU.js +1 -0
  17. package/dist/assets/clone-CtxIENQC.js +1 -0
  18. package/dist/assets/{cose-bilkent-S5V4N54A-Dl80WZ_a.js → cose-bilkent-S5V4N54A-BcKKbLWz.js} +1 -1
  19. package/dist/assets/{dagre-6UL2VRFP-vw-vkw78.js → dagre-6UL2VRFP-CERJ9KSL.js} +1 -1
  20. package/dist/assets/{diagram-PSM6KHXK-B4MT5Nvf.js → diagram-PSM6KHXK-DGl--Cyq.js} +1 -1
  21. package/dist/assets/{diagram-QEK2KX5R-CMioZnRI.js → diagram-QEK2KX5R-DbfdELCd.js} +1 -1
  22. package/dist/assets/{diagram-S2PKOQOG-PJAE8YS0.js → diagram-S2PKOQOG-CsR4YAm5.js} +1 -1
  23. package/dist/assets/{erDiagram-Q2GNP2WA-DCd-WouG.js → erDiagram-Q2GNP2WA-BlOr_gpI.js} +1 -1
  24. package/dist/assets/{flowDiagram-NV44I4VS-DS__-WT4.js → flowDiagram-NV44I4VS-BAyDXjxF.js} +1 -1
  25. package/dist/assets/{ganttDiagram-JELNMOA3-Btifh-31.js → ganttDiagram-JELNMOA3-b2ntam6s.js} +1 -1
  26. package/dist/assets/{gitGraphDiagram-V2S2FVAM-BCyjopey.js → gitGraphDiagram-V2S2FVAM-BvdeZrga.js} +1 -1
  27. package/dist/assets/{graph-6YBx8iQ0.js → graph-DMrtDwYQ.js} +1 -1
  28. package/dist/assets/{index-lkycEDHM.js → index-CaWVBOSf.js} +204 -189
  29. package/dist/assets/index-CbLxL6va.css +1 -0
  30. package/dist/assets/{infoDiagram-HS3SLOUP-CAsJ2eU1.js → infoDiagram-HS3SLOUP-CFO6LsEb.js} +1 -1
  31. package/dist/assets/{isUndefined-CcAlyXn3.js → isUndefined-DE2VOYrW.js} +1 -1
  32. package/dist/assets/{journeyDiagram-XKPGCS4Q-Bi8XsX15.js → journeyDiagram-XKPGCS4Q-Svi8cltR.js} +1 -1
  33. package/dist/assets/{kanban-definition-3W4ZIXB7-PTAFVsDn.js → kanban-definition-3W4ZIXB7-C7uds03_.js} +1 -1
  34. package/dist/assets/{layout-Do-GOFdW.js → layout-D5N_DnHw.js} +1 -1
  35. package/dist/assets/{linear-CZlgolw0.js → linear-h9-K1RBq.js} +1 -1
  36. package/dist/assets/{min-N15IYW1Y.js → min-CjtZYucR.js} +1 -1
  37. package/dist/assets/{mindmap-definition-VGOIOE7T-Dlgxv6Jo.js → mindmap-definition-VGOIOE7T-Bw80_6TW.js} +1 -1
  38. package/dist/assets/{pieDiagram-ADFJNKIX-Dr2AfIw5.js → pieDiagram-ADFJNKIX-DGukFJSP.js} +1 -1
  39. package/dist/assets/{quadrantDiagram-AYHSOK5B-B8TPuvW6.js → quadrantDiagram-AYHSOK5B-CU7GPi0P.js} +1 -1
  40. package/dist/assets/{requirementDiagram-UZGBJVZJ-CdD2oP1N.js → requirementDiagram-UZGBJVZJ-D_aCZrji.js} +1 -1
  41. package/dist/assets/{sankeyDiagram-TZEHDZUN-XEMX6l5k.js → sankeyDiagram-TZEHDZUN-Wgtprjih.js} +1 -1
  42. package/dist/assets/{sequenceDiagram-WL72ISMW-BlIKpBev.js → sequenceDiagram-WL72ISMW-BCOCCVxS.js} +1 -1
  43. package/dist/assets/{stateDiagram-FKZM4ZOC-D3KGQY6v.js → stateDiagram-FKZM4ZOC-DHVe22f9.js} +1 -1
  44. package/dist/assets/stateDiagram-v2-4FDKWEC3-Bq9eQr8D.js +1 -0
  45. package/dist/assets/{timeline-definition-IT6M3QCI-TkL4mz_f.js → timeline-definition-IT6M3QCI-Cm4CAEQk.js} +1 -1
  46. package/dist/assets/{treemap-GDKQZRPO-BDp_c1Vc.js → treemap-GDKQZRPO-DvLhDp9r.js} +1 -1
  47. package/dist/assets/{xychartDiagram-PRI3JC2R-D0dNQImL.js → xychartDiagram-PRI3JC2R-BtcJYIPe.js} +1 -1
  48. package/dist/index.html +8 -2
  49. package/index.html +6 -0
  50. package/package.json +1 -1
  51. package/src/App.tsx +48 -44
  52. package/src/design-system/ui/button.tsx +1 -1
  53. package/src/features/account/components/settings/appearance-settings-tab.tsx +1 -1
  54. package/src/features/account/pages/profile/components/profile-general-tab.tsx +1 -1
  55. package/src/features/account/pages/workspace-members.tsx +58 -62
  56. package/src/features/auth/pages/login.tsx +4 -2
  57. package/src/features/auth/pages/verify.tsx +1 -1
  58. package/src/features/chatkit/components/public-chat-error-boundary.tsx +1 -1
  59. package/src/features/chatkit/components/public-chat-widget.tsx +2 -3
  60. package/src/features/chatkit/lib/chatkit-theme.ts +3 -2
  61. package/src/features/chatkit/lib/public-chat-access.ts +13 -0
  62. package/src/features/chatkit/pages/public-chat.tsx +18 -27
  63. package/src/features/shared/components/chat-interface.types.ts +1 -5
  64. package/src/features/shared/components/top-navigation/studio-brand.tsx +1 -1
  65. package/src/features/shared/components/top-navigation/version-status.tsx +27 -31
  66. package/src/features/shared/components/workspace-bootstrap-gate.tsx +4 -4
  67. package/src/features/workflow/components/dialogs/credential-access-badge.tsx +2 -2
  68. package/src/features/workflow/components/dialogs/credential-status-badge.tsx +2 -2
  69. package/src/features/workflow/components/dialogs/credentials-table.tsx +1 -1
  70. package/src/features/workflow/components/dialogs/update-workflow-dialog.tsx +34 -78
  71. package/src/features/workflow/components/dialogs/upload-workflow-dialog.tsx +40 -136
  72. package/src/features/workflow/components/dialogs/workflow-folder-picker.tsx +178 -0
  73. package/src/features/workflow/components/panels/rjsf-cron-widget.tsx +35 -10
  74. package/src/features/workflow/components/panels/workflow-diff-dialog.tsx +5 -5
  75. package/src/features/workflow/components/panels/workflow-history-table.tsx +3 -4
  76. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardConnector.tsx +1 -5
  77. package/src/features/workflow/components/trace/agent-prism/shared.ts +1 -10
  78. package/src/features/workflow/components/trace/agent-prism/theme/theme.css +74 -74
  79. package/src/features/workflow/lib/workflow-execution-builders.ts +4 -4
  80. package/src/features/workflow/lib/workflow-execution.types.ts +2 -9
  81. package/src/features/workflow/lib/workflow-folder-selection.ts +239 -0
  82. package/src/features/workflow/lib/workflow-frontmatter.ts +3 -1
  83. package/src/features/workflow/lib/workflow-storage-api.ts +5 -9
  84. package/src/features/workflow/lib/workflow-storage-helpers.ts +2 -4
  85. package/src/features/workflow/lib/workflow-storage.ts +6 -2
  86. package/src/features/workflow/lib/workflow-storage.types.ts +1 -6
  87. package/src/features/workflow/lib/workflow-upload-errors.ts +6 -2
  88. package/src/features/workflow/pages/workflow/components/settings-tab-content.tsx +24 -9
  89. package/src/features/workflow/pages/workflow/components/workflow-tab-content.tsx +6 -4
  90. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-execution-controller.ts +4 -1
  91. package/src/features/workflow/pages/workflow/hooks/use-execution-updates.ts +4 -2
  92. package/src/features/workflow/pages/workflow-gallery/create-team-dialog.tsx +2 -6
  93. package/src/features/workflow/pages/workflow-gallery/workflow-card.tsx +16 -16
  94. package/src/index.css +101 -59
  95. package/src/lib/api.ts +7 -2
  96. package/src/lib/workspace-routing.ts +1 -3
  97. package/tailwind.config.js +47 -2
  98. package/dist/assets/channel-D562bZxL.js +0 -1
  99. package/dist/assets/classDiagram-2ON5EDUG-Dix_KnuM.js +0 -1
  100. package/dist/assets/classDiagram-v2-WZHVMYZB-Dix_KnuM.js +0 -1
  101. package/dist/assets/clone-0c2Tu-SH.js +0 -1
  102. package/dist/assets/index-Df4jFRhd.css +0 -1
  103. package/dist/assets/stateDiagram-v2-4FDKWEC3-Di3Nkv2n.js +0 -1
@@ -0,0 +1,178 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { FileJson, FileText, FolderUp, Loader2 } from "lucide-react";
3
+ import { cn } from "@/lib/utils";
4
+ import {
5
+ collectDroppedFolderFiles,
6
+ collectFolderInputFiles,
7
+ loadWorkflowFolderSelection,
8
+ WorkflowFolderSelectionError,
9
+ type WorkflowFolderSelection,
10
+ } from "@features/workflow/lib/workflow-folder-selection";
11
+
12
+ interface WorkflowFolderPickerProps {
13
+ /** Unique prefix for the input id so labels stay associated per dialog. */
14
+ idPrefix: string;
15
+ disabled?: boolean;
16
+ /** Name of the currently selected script, or "" when none is selected. */
17
+ scriptName: string;
18
+ /** Name of the currently selected config, or null when none is selected. */
19
+ configName: string | null;
20
+ onSelect: (selection: WorkflowFolderSelection) => void;
21
+ onError: (message: string) => void;
22
+ }
23
+
24
+ const READ_FOLDER_FALLBACK_ERROR =
25
+ "Could not read the selected folder. Please try again.";
26
+ const EMPTY_FOLDER_ERROR =
27
+ "No files were found in the selected folder. Add a folder containing a .py workflow script and try again.";
28
+
29
+ export function WorkflowFolderPicker({
30
+ idPrefix,
31
+ disabled = false,
32
+ scriptName,
33
+ configName,
34
+ onSelect,
35
+ onError,
36
+ }: WorkflowFolderPickerProps) {
37
+ const inputRef = useRef<HTMLInputElement>(null);
38
+ const [isDragging, setIsDragging] = useState(false);
39
+ const [isProcessing, setIsProcessing] = useState(false);
40
+ const inputId = `${idPrefix}-folder`;
41
+
42
+ // `webkitdirectory` is not part of the standard input typings, so set it
43
+ // imperatively to opt the file picker into folder selection.
44
+ useEffect(() => {
45
+ const input = inputRef.current;
46
+ if (input) {
47
+ input.setAttribute("webkitdirectory", "");
48
+ input.setAttribute("directory", "");
49
+ }
50
+ }, []);
51
+
52
+ const processFiles = useCallback(
53
+ async (files: File[]) => {
54
+ if (files.length === 0) {
55
+ onError(EMPTY_FOLDER_ERROR);
56
+ return;
57
+ }
58
+ setIsProcessing(true);
59
+ try {
60
+ const selection = await loadWorkflowFolderSelection(files);
61
+ onSelect(selection);
62
+ } catch (err) {
63
+ const message =
64
+ err instanceof WorkflowFolderSelectionError
65
+ ? err.message
66
+ : READ_FOLDER_FALLBACK_ERROR;
67
+ onError(message);
68
+ } finally {
69
+ setIsProcessing(false);
70
+ }
71
+ },
72
+ [onSelect, onError],
73
+ );
74
+
75
+ const handleInputChange = useCallback(
76
+ (event: React.ChangeEvent<HTMLInputElement>) => {
77
+ const files = collectFolderInputFiles(event.target.files);
78
+ // Allow re-selecting the same folder later.
79
+ event.target.value = "";
80
+ void processFiles(files);
81
+ },
82
+ [processFiles],
83
+ );
84
+
85
+ const handleDrop = useCallback(
86
+ (event: React.DragEvent<HTMLLabelElement>) => {
87
+ event.preventDefault();
88
+ setIsDragging(false);
89
+ if (disabled) {
90
+ return;
91
+ }
92
+ void (async () => {
93
+ try {
94
+ const files = await collectDroppedFolderFiles(event.dataTransfer);
95
+ await processFiles(files);
96
+ } catch {
97
+ onError(READ_FOLDER_FALLBACK_ERROR);
98
+ }
99
+ })();
100
+ },
101
+ [disabled, processFiles, onError],
102
+ );
103
+
104
+ const handleDragOver = useCallback(
105
+ (event: React.DragEvent<HTMLLabelElement>) => {
106
+ event.preventDefault();
107
+ if (!disabled) {
108
+ setIsDragging(true);
109
+ }
110
+ },
111
+ [disabled],
112
+ );
113
+
114
+ const handleDragLeave = useCallback(
115
+ (event: React.DragEvent<HTMLLabelElement>) => {
116
+ // Ignore drag-leave events bubbling up from child elements.
117
+ if (event.currentTarget.contains(event.relatedTarget as Node | null)) {
118
+ return;
119
+ }
120
+ setIsDragging(false);
121
+ },
122
+ [],
123
+ );
124
+
125
+ const hasSelection = scriptName.length > 0;
126
+
127
+ return (
128
+ <div className="space-y-1.5">
129
+ <label
130
+ htmlFor={inputId}
131
+ onDrop={handleDrop}
132
+ onDragOver={handleDragOver}
133
+ onDragEnter={handleDragOver}
134
+ onDragLeave={handleDragLeave}
135
+ className={cn(
136
+ "flex w-full cursor-pointer flex-col items-center justify-center gap-2 rounded-md border border-dashed border-input bg-transparent px-4 py-6 text-center transition-colors",
137
+ "hover:border-ring focus-within:outline-none focus-within:ring-1 focus-within:ring-ring",
138
+ disabled && "pointer-events-none opacity-50",
139
+ isDragging && "border-ring bg-accent",
140
+ )}
141
+ >
142
+ {isProcessing ? (
143
+ <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
144
+ ) : (
145
+ <FolderUp className="h-6 w-6 text-muted-foreground" />
146
+ )}
147
+ <span className="text-sm font-medium">
148
+ {isDragging ? "Drop folder to load" : "Drag a folder here or browse"}
149
+ </span>
150
+ <span className="text-xs text-muted-foreground">
151
+ The folder should contain one <code>.py</code> script and an optional{" "}
152
+ <code>.json</code> config.
153
+ </span>
154
+ </label>
155
+ <input
156
+ ref={inputRef}
157
+ id={inputId}
158
+ type="file"
159
+ multiple
160
+ className="sr-only"
161
+ onChange={handleInputChange}
162
+ disabled={disabled}
163
+ />
164
+ {hasSelection && (
165
+ <div className="space-y-1 rounded-md bg-muted/50 px-3 py-2 text-xs">
166
+ <p className="flex items-center gap-1.5 text-foreground">
167
+ <FileText className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
168
+ <span className="truncate">{scriptName}</span>
169
+ </p>
170
+ <p className="flex items-center gap-1.5 text-muted-foreground">
171
+ <FileJson className="h-3.5 w-3.5 shrink-0" />
172
+ <span className="truncate">{configName ?? "No config file"}</span>
173
+ </p>
174
+ </div>
175
+ )}
176
+ </div>
177
+ );
178
+ }
@@ -72,11 +72,20 @@ const clampInt = (value: string, max: number, fallback: number) => {
72
72
  };
73
73
 
74
74
  /** Parse a single cron field's first numeric token, falling back to `fallback`. */
75
- const parseField = (field: string | undefined, max: number, fallback: number) =>
76
- field && field !== "*" ? clampInt(field.split(/[,/-]/)[0], max, fallback) : fallback;
75
+ const parseField = (
76
+ field: string | undefined,
77
+ max: number,
78
+ fallback: number,
79
+ ) =>
80
+ field && field !== "*"
81
+ ? clampInt(field.split(/[,/-]/)[0], max, fallback)
82
+ : fallback;
77
83
 
78
84
  /** Extract the step N from a `*\/N` field (clamped to `max`), or undefined if it isn't a step. */
79
- const parseStep = (field: string | undefined, max: number): number | undefined => {
85
+ const parseStep = (
86
+ field: string | undefined,
87
+ max: number,
88
+ ): number | undefined => {
80
89
  const match = /^\*\/(\d+)$/.exec(field ?? "");
81
90
  return match ? clampInt(match[1], max, 1) || 1 : undefined;
82
91
  };
@@ -98,7 +107,9 @@ const parseDaysOfWeek = (field: string | undefined): number[] => {
98
107
  return Array.from(new Set(days));
99
108
  };
100
109
 
101
- const parseCron = (value: string | undefined): { freq: Frequency; parts: CronParts } => {
110
+ const parseCron = (
111
+ value: string | undefined,
112
+ ): { freq: Frequency; parts: CronParts } => {
102
113
  const [minute, hour, dom, , dow] = (value ?? "").trim().split(/\s+/);
103
114
  const minuteStep = parseStep(minute, 59);
104
115
  const hourStep = parseStep(hour, 23);
@@ -117,13 +128,15 @@ const parseCron = (value: string | undefined): { freq: Frequency; parts: CronPar
117
128
  // `*/30 * * * *` (step) or `* * * * *` (every minute) → minute interval.
118
129
  else if (minuteStep !== undefined || minute === "*") freq = "minute";
119
130
  // `M */2 * * *` (step) or `M * * * *` (every hour) → hour interval.
120
- else if (hourStep !== undefined || hour === "*" || hour === undefined) freq = "hour";
131
+ else if (hourStep !== undefined || hour === "*" || hour === undefined)
132
+ freq = "hour";
121
133
 
122
134
  return { freq, parts };
123
135
  };
124
136
 
125
137
  const buildCron = (freq: Frequency, parts: CronParts): string => {
126
- const { interval, hourInterval, minute, hour, dayOfMonth, daysOfWeek } = parts;
138
+ const { interval, hourInterval, minute, hour, dayOfMonth, daysOfWeek } =
139
+ parts;
127
140
  switch (freq) {
128
141
  case "minute":
129
142
  // `*/1` is just "every minute"; emit the canonical wildcard form.
@@ -136,7 +149,9 @@ const buildCron = (freq: Frequency, parts: CronParts): string => {
136
149
  case "day":
137
150
  return `${minute} ${hour} * * *`;
138
151
  case "week": {
139
- const dow = daysOfWeek.length ? [...daysOfWeek].sort((a, b) => a - b).join(",") : "*";
152
+ const dow = daysOfWeek.length
153
+ ? [...daysOfWeek].sort((a, b) => a - b).join(",")
154
+ : "*";
140
155
  return `${minute} ${hour} * * ${dow}`;
141
156
  }
142
157
  case "month":
@@ -165,7 +180,11 @@ const canonicalCron = (value: string | undefined): string | null => {
165
180
  if (/[a-z]/i.test(fields.join(""))) return null;
166
181
  const days = parseDaysOfWeek(dow);
167
182
  const dowField =
168
- dow === "*" ? "*" : days.length ? [...days].sort((a, b) => a - b).join(",") : dow;
183
+ dow === "*"
184
+ ? "*"
185
+ : days.length
186
+ ? [...days].sort((a, b) => a - b).join(",")
187
+ : dow;
169
188
  return [minute, hour, dom, month, dowField].join(" ");
170
189
  };
171
190
 
@@ -292,7 +311,9 @@ function CronWidget(props: WidgetProps) {
292
311
 
293
312
  {(freq === "minute" || freq === "hour") && (
294
313
  <Select
295
- value={String(freq === "minute" ? parts.interval : parts.hourInterval)}
314
+ value={String(
315
+ freq === "minute" ? parts.interval : parts.hourInterval,
316
+ )}
296
317
  onValueChange={(v) =>
297
318
  freq === "minute"
298
319
  ? update("minute", { ...parts, interval: Number(v) })
@@ -343,7 +364,11 @@ function CronWidget(props: WidgetProps) {
343
364
  "flex h-9 min-w-[6rem] items-center justify-between gap-2 whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
344
365
  )}
345
366
  >
346
- <span className={cn(parts.daysOfWeek.length === 0 && "text-muted-foreground")}>
367
+ <span
368
+ className={cn(
369
+ parts.daysOfWeek.length === 0 && "text-muted-foreground",
370
+ )}
371
+ >
347
372
  {selectedDaysLabel}
348
373
  </span>
349
374
  <ChevronDown className="h-4 w-4 opacity-50" />
@@ -28,9 +28,9 @@ interface WorkflowDiffDialogProps {
28
28
  }
29
29
 
30
30
  const summaryBadgeClass = {
31
- added: "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400",
32
- removed: "bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400",
33
- modified: "bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400",
31
+ added: "bg-success-muted text-success-muted-foreground",
32
+ removed: "bg-destructive-muted text-destructive-muted-foreground",
33
+ modified: "bg-info-muted text-info-muted-foreground",
34
34
  };
35
35
 
36
36
  const formatValue = (value: unknown) =>
@@ -103,12 +103,12 @@ const Differences = ({
103
103
  <p className="text-muted-foreground">{entry.detail}</p>
104
104
  )}
105
105
  {entry.type !== "added" && entry.before !== undefined && (
106
- <pre className="bg-red-50 dark:bg-red-900/20 rounded-md p-2 font-mono text-xs whitespace-pre-wrap">
106
+ <pre className="bg-destructive-muted/60 rounded-md p-2 font-mono text-xs whitespace-pre-wrap">
107
107
  - {formatValue(entry.before)}
108
108
  </pre>
109
109
  )}
110
110
  {entry.type !== "removed" && entry.after !== undefined && (
111
- <pre className="bg-green-50 dark:bg-green-900/20 rounded-md p-2 font-mono text-xs whitespace-pre-wrap">
111
+ <pre className="bg-success-muted/60 rounded-md p-2 font-mono text-xs whitespace-pre-wrap">
112
112
  + {formatValue(entry.after)}
113
113
  </pre>
114
114
  )}
@@ -22,13 +22,12 @@ interface WorkflowHistoryTableProps {
22
22
  onSelectVersion: (versionId: string) => void;
23
23
  }
24
24
 
25
- const statusBadgeClass =
26
- "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400";
25
+ const statusBadgeClass = "bg-success-muted text-success-muted-foreground";
27
26
 
28
27
  const summaryBadgeClasses: Record<"added" | "removed" | "modified", string> = {
29
28
  added: statusBadgeClass,
30
- removed: "bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400",
31
- modified: "bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400",
29
+ removed: "bg-destructive-muted text-destructive-muted-foreground",
30
+ modified: "bg-info-muted text-info-muted-foreground",
32
31
  };
33
32
 
34
33
  const SummaryBadge = ({
@@ -1,9 +1,5 @@
1
1
  export type SpanCardConnectorType =
2
- | "horizontal"
3
- | "vertical"
4
- | "t-right"
5
- | "corner-top-right"
6
- | "empty";
2
+ "horizontal" | "vertical" | "t-right" | "corner-top-right" | "empty";
7
3
 
8
4
  interface SpanCardConnectorProps {
9
5
  type: SpanCardConnectorType;
@@ -31,16 +31,7 @@ export type ColorVariant =
31
31
  | "gray";
32
32
 
33
33
  export type ComponentSize =
34
- | "4"
35
- | "5"
36
- | "6"
37
- | "7"
38
- | "8"
39
- | "9"
40
- | "10"
41
- | "11"
42
- | "12"
43
- | "16";
34
+ "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12" | "16";
44
35
 
45
36
  // CONSTANTS
46
37
 
@@ -1,59 +1,61 @@
1
1
  :root {
2
- /* General purpose colors */
3
- --agentprism-background: 1 0 0; /* white */
4
- --agentprism-foreground: 21% 0.034 264.665; /* gray.900 */
5
- --agentprism-primary: 21% 0.034 264.665; /* gray.900 */
6
- --agentprism-primary-foreground: 98.5% 0.002 247.839; /* gray.50 */
7
- --agentprism-primary: 21% 0.034 264.665; /* gray.900 */
8
- --agentprism-primary-foreground: 98.5% 0.002 247.839; /* gray.50 */
9
- --agentprism-secondary: 96.7% 0.003 264.542; /* gray.100 */
10
- --agentprism-secondary-foreground: 55.1% 0.027 264.364; /* gray.500 */
11
- --agentprism-muted: 98.5% 0.002 247.839; /* gray.50 */
12
- --agentprism-muted-foreground: 44.6% 0.03 256.802; /* gray.600 */
13
- --agentprism-accent: 96.7% 0.003 264.542; /* gray.100 */
14
- --agentprism-accent-foreground: 96.7% 0.003 264.542; /* gray.100 */
2
+ /*
3
+ * General-purpose colors aligned with the Orcheo design system
4
+ * (orcheo-design-system/tokens/colors.css): warm ink neutrals,
5
+ * Orcheo orange brand, warm-harmonized status hues.
6
+ */
7
+ --agentprism-background: 97% 0.008 91.483; /* ink-50 */
8
+ --agentprism-foreground: 21.3% 0.006 91.63; /* ink-900 */
9
+ --agentprism-primary: 21.3% 0.006 91.63; /* ink-900 */
10
+ --agentprism-primary-foreground: 97% 0.008 91.483; /* ink-50 */
11
+ --agentprism-secondary: 93.4% 0.014 88.686; /* ink-100 */
12
+ --agentprism-secondary-foreground: 54.4% 0.02 84.589; /* ink-500 */
13
+ --agentprism-muted: 93.4% 0.014 88.686; /* ink-100 */
14
+ --agentprism-muted-foreground: 44.3% 0.015 86.885; /* ink-600 */
15
+ --agentprism-accent: 93.4% 0.014 88.686; /* ink-100 */
16
+ --agentprism-accent-foreground: 27.3% 0.009 88.77; /* ink-800 */
15
17
 
16
18
  /* Brand colors */
17
- --agentprism-brand: 60.6% 0.25 292.717; /* violet.500 */
19
+ --agentprism-brand: 71.1% 0.179 48.062; /* orange-500 */
18
20
  --agentprism-brand-foreground: 1 0 0; /* white */
19
- --agentprism-brand-secondary: 70.5% 0.213 47.604; /* orange.500 */
21
+ --agentprism-brand-secondary: 69.5% 0.092 72.981; /* tan-500 */
20
22
  --agentprism-brand-secondary-foreground: 1 0 0; /* white */
21
23
 
22
24
  /* Borders */
23
- --agentprism-border: 92.8% 0.006 264.531; /* gray.200 */
24
- --agentprism-border-subtle: 96.7% 0.003 264.542; /* gray.100 */
25
- --agentprism-border-strong: 87.2% 0.01 258.338; /* gray.300 */
26
- --agentprism-border-inverse: 21% 0.034 264.665; /* gray.900 */
25
+ --agentprism-border: 87.7% 0.02 87.522; /* ink-200 */
26
+ --agentprism-border-subtle: 93.4% 0.014 88.686; /* ink-100 */
27
+ --agentprism-border-strong: 78.7% 0.025 88.258; /* ink-300 */
28
+ --agentprism-border-inverse: 21.3% 0.006 91.63; /* ink-900 */
27
29
 
28
30
  /* Success status color */
29
- --agentprism-success: 69.6% 0.17 162.48; /* emerald.500 */
30
- --agentprism-success-muted: 97.9% 0.021 166.113; /* emerald.50 */
31
- --agentprism-success-muted-foreground: 50.8% 0.118 165.612; /* emerald.700 */
31
+ --agentprism-success: 52.9% 0.103 156.217; /* green-500 */
32
+ --agentprism-success-muted: 94.2% 0.018 161.108; /* green-100 */
33
+ --agentprism-success-muted-foreground: 45.8% 0.089 156.156; /* green-600 */
32
34
 
33
35
  /* Error status color */
34
- --agentprism-error: 63.7% 0.237 25.331; /* red.500 */
35
- --agentprism-error-muted: 97.1% 0.013 17.38; /* red.50 */
36
- --agentprism-error-muted-foreground: 57.7% 0.245 27.325; /* red.600 */
36
+ --agentprism-error: 57.3% 0.184 32.327; /* red-500 */
37
+ --agentprism-error-muted: 93.1% 0.029 36.154; /* red-100 */
38
+ --agentprism-error-muted-foreground: 50% 0.164 32.898; /* red-600 */
37
39
 
38
40
  /* Warning status color */
39
- --agentprism-warning: 79.5% 0.184 86.047; /* yellow.500 */
40
- --agentprism-warning-muted: 98.7% 0.026 102.212; /* yellow.50 */
41
- --agentprism-warning-muted-foreground: 55.4% 0.135 66.442; /* yellow.700 */
41
+ --agentprism-warning: 72.9% 0.147 78.341; /* amber-500 */
42
+ --agentprism-warning-muted: 95.1% 0.041 88.794; /* amber-100 */
43
+ --agentprism-warning-muted-foreground: 63.6% 0.129 77.25; /* amber-600 */
42
44
 
43
45
  /* Pending status color */
44
- --agentprism-pending: 60.6% 0.25 292.717; /* violet.500 */
45
- --agentprism-pending-muted: 94.3% 0.029 294.588; /* violet.100 */
46
- --agentprism-pending-muted-foreground: 54.1% 0.281 293.009; /* violet.600 */
46
+ --agentprism-pending: 52.2% 0.082 245.431; /* blue-500 */
47
+ --agentprism-pending-muted: 93.8% 0.014 238.015; /* blue-100 */
48
+ --agentprism-pending-muted-foreground: 44.6% 0.07 244.417; /* blue-600 */
47
49
 
48
50
  /* Code syntax highlighting */
49
- --agentprism-code-string: 57.7% 0.245 27.325; /* red.600 */
50
- --agentprism-code-number: 57.7% 0.245 27.325; /* red.600 */
51
- --agentprism-code-key: 54.6% 0.245 262.881; /* blue.600 */
52
- --agentprism-code-base: 55.1% 0.027 264.364; /* gray.500 */
51
+ --agentprism-code-string: 50% 0.164 32.898; /* red-600 */
52
+ --agentprism-code-number: 50% 0.164 32.898; /* red-600 */
53
+ --agentprism-code-key: 44.6% 0.07 244.417; /* blue-600 */
54
+ --agentprism-code-base: 54.4% 0.02 84.589; /* ink-500 */
53
55
 
54
56
  /* Generic badge colors */
55
- --agentprism-badge-default: 96.7% 0.003 264.542; /* gray.100 */
56
- --agentprism-badge-default-foreground: 44.6% 0.03 256.802; /* gray.600 */
57
+ --agentprism-badge-default: 93.4% 0.014 88.686; /* ink-100 */
58
+ --agentprism-badge-default-foreground: 44.3% 0.015 86.885; /* ink-600 */
57
59
 
58
60
  /* Trace colors (llm) */
59
61
  --agentprism-avatar-llm: 62.7% 0.265 303.9; /* purple.500 */
@@ -123,61 +125,59 @@
123
125
  }
124
126
 
125
127
  .dark {
126
- /* General purpose colors */
127
- --agentprism-background: 4% 0 0; /* align with workflow dark background */
128
- --agentprism-foreground: 96.7% 0.003 264.542; /* gray.100 */
129
- --agentprism-primary: 96.7% 0.003 264.542; /* gray.100 */
130
- --agentprism-primary-foreground: 13% 0.028 261.692; /* gray.950 */
131
- --agentprism-primary: 96.7% 0.003 264.542; /* gray.100 */
132
- --agentprism-primary-foreground: 13% 0.028 261.692; /* gray.950 */
133
- --agentprism-secondary: 27.8% 0.033 256.848; /* gray.800 */
134
- --agentprism-secondary-foreground: 55.1% 0.027 264.364; /* gray.500 */
135
- --agentprism-muted: 21% 0.034 264.665; /* gray.900 */
136
- --agentprism-muted-foreground: 70.7% 0.022 261.325; /* gray.400 */
137
- --agentprism-accent: 96.7% 0.003 264.542; /* gray.100 */
138
- --agentprism-accent-foreground: 21% 0.034 264.665; /* gray.900 */
128
+ /* General purpose colors — warm ink dark ramp (orcheo-design-system) */
129
+ --agentprism-background: 16.3% 0.004 106.847; /* ink-950 */
130
+ --agentprism-foreground: 93.4% 0.014 88.686; /* ink-100 */
131
+ --agentprism-primary: 93.4% 0.014 88.686; /* ink-100 */
132
+ --agentprism-primary-foreground: 16.3% 0.004 106.847; /* ink-950 */
133
+ --agentprism-secondary: 27.3% 0.009 88.77; /* ink-800 */
134
+ --agentprism-secondary-foreground: 66.5% 0.023 85.959; /* ink-400 */
135
+ --agentprism-muted: 21.3% 0.006 91.63; /* ink-900 */
136
+ --agentprism-muted-foreground: 66.5% 0.023 85.959; /* ink-400 */
137
+ --agentprism-accent: 27.3% 0.009 88.77; /* ink-800 */
138
+ --agentprism-accent-foreground: 93.4% 0.014 88.686; /* ink-100 */
139
139
 
140
140
  /* Brand colors */
141
- --agentprism-brand: 60.6% 0.25 292.717; /* violet.500 */
141
+ --agentprism-brand: 71.1% 0.179 48.062; /* orange-500 */
142
142
  --agentprism-brand-foreground: 1 0 0; /* white */
143
- --agentprism-brand-secondary: 70.5% 0.213 47.604; /* orange.500 */
143
+ --agentprism-brand-secondary: 69.5% 0.092 72.981; /* tan-500 */
144
144
  --agentprism-brand-secondary-foreground: 1 0 0; /* white */
145
145
 
146
146
  /* Borders */
147
- --agentprism-border: 44.6% 0.03 256.802; /* gray.600 */
148
- --agentprism-border-subtle: 37.3% 0.034 259.733; /* gray.700 */
149
- --agentprism-border-strong: 55.1% 0.027 264.364; /* gray.500 */
150
- --agentprism-border-inverse: 92.8% 0.006 264.531; /* gray.200 */
147
+ --agentprism-border: 34.9% 0.013 87.556; /* ink-700 */
148
+ --agentprism-border-subtle: 27.3% 0.009 88.77; /* ink-800 */
149
+ --agentprism-border-strong: 44.3% 0.015 86.885; /* ink-600 */
150
+ --agentprism-border-inverse: 87.7% 0.02 87.522; /* ink-200 */
151
151
 
152
152
  /* Success status color */
153
- --agentprism-success: 72.3% 0.219 149.579; /* green.500 */
154
- --agentprism-success-muted: 26.6% 0.065 152.934; /* green.950 */
155
- --agentprism-success-muted-foreground: 87.1% 0.15 154.449; /* green.300 */
153
+ --agentprism-success: 52.9% 0.103 156.217; /* green-500 */
154
+ --agentprism-success-muted: 29.7% 0.053 156.812; /* dark forest tint */
155
+ --agentprism-success-muted-foreground: 77.1% 0.081 159.669;
156
156
 
157
157
  /* Error status color */
158
- --agentprism-error: 63.7% 0.237 25.331; /* red.500 */
159
- --agentprism-error-muted: 25.8% 0.092 26.042; /* red.950 */
160
- --agentprism-error-muted-foreground: 80.8% 0.114 19.571; /* red.300 */
158
+ --agentprism-error: 57.3% 0.184 32.327; /* red-500 */
159
+ --agentprism-error-muted: 26.5% 0.076 33.199; /* dark warm-red tint */
160
+ --agentprism-error-muted-foreground: 74.1% 0.111 33.398;
161
161
 
162
162
  /* Warning status color */
163
- --agentprism-warning: 79.5% 0.184 86.047; /* yellow.500 */
164
- --agentprism-warning-muted: 28.6% 0.066 53.813; /* yellow.950 */
165
- --agentprism-warning-muted-foreground: 90.5% 0.182 98.111; /* yellow.300 */
163
+ --agentprism-warning: 72.9% 0.147 78.341; /* amber-500 */
164
+ --agentprism-warning-muted: 31.6% 0.06 79.88; /* dark ochre tint */
165
+ --agentprism-warning-muted-foreground: 81.5% 0.114 84.939;
166
166
 
167
167
  /* Pending status color */
168
- --agentprism-pending: 60.6% 0.25 292.717; /* violet.500 */
169
- --agentprism-pending-muted: 28.3% 0.141 291.089; /* violet.950 */
170
- --agentprism-pending-muted-foreground: 70.2% 0.183 293.541; /* violet.400 */
168
+ --agentprism-pending: 52.2% 0.082 245.431; /* blue-500 */
169
+ --agentprism-pending-muted: 27.9% 0.039 244.504; /* dark slate-blue tint */
170
+ --agentprism-pending-muted-foreground: 75.9% 0.061 243.329;
171
171
 
172
172
  /* Code syntax highlighting */
173
- --agentprism-code-string: 70.4% 0.191 22.216; /* red.400 */
174
- --agentprism-code-number: 70.4% 0.191 22.216; /* red.400 */
175
- --agentprism-code-key: 80.9% 0.105 251.813; /* blue.300 */
176
- --agentprism-code-base: 70.7% 0.022 261.325; /* gray.400 */
173
+ --agentprism-code-string: 74.1% 0.111 33.398; /* warm red, lightened */
174
+ --agentprism-code-number: 74.1% 0.111 33.398;
175
+ --agentprism-code-key: 75.9% 0.061 243.329; /* slate blue, lightened */
176
+ --agentprism-code-base: 66.5% 0.023 85.959; /* ink-400 */
177
177
 
178
178
  /* Generic badge colors */
179
- --agentprism-badge-default: 21% 0.034 264.665; /* gray.900 */
180
- --agentprism-badge-default-foreground: 70.7% 0.022 261.325; /* gray.400 */
179
+ --agentprism-badge-default: 21.3% 0.006 91.63; /* ink-900 */
180
+ --agentprism-badge-default-foreground: 66.5% 0.023 85.959; /* ink-400 */
181
181
 
182
182
  /* Trace colors (llm) */
183
183
  --agentprism-avatar-llm: 82.7% 0.119 306.383; /* purple.300 */
@@ -50,10 +50,10 @@ const extractVersionRecord = (
50
50
  lookup: WorkflowLookup,
51
51
  ) => {
52
52
  const inputs = history.inputs ?? {};
53
- const metadata = (inputs.metadata ?? inputs.workflow ?? inputs.canvas ?? {}) as Record<
54
- string,
55
- unknown
56
- >;
53
+ const metadata = (inputs.metadata ??
54
+ inputs.workflow ??
55
+ inputs.canvas ??
56
+ {}) as Record<string, unknown>;
57
57
  const versionIdRaw = metadata?.workflow_version_id;
58
58
  if (typeof versionIdRaw === "string" && versionIdRaw) {
59
59
  return lookup.versions.get(versionIdRaw);
@@ -31,17 +31,10 @@ export type WorkflowLookup = {
31
31
  };
32
32
 
33
33
  export type WorkflowExecutionStatus =
34
- | "running"
35
- | "success"
36
- | "failed"
37
- | "partial";
34
+ "running" | "success" | "failed" | "partial";
38
35
 
39
36
  export type WorkflowExecutionNodeStatus =
40
- | "idle"
41
- | "running"
42
- | "success"
43
- | "error"
44
- | "warning";
37
+ "idle" | "running" | "success" | "error" | "warning";
45
38
 
46
39
  export interface WorkflowExecutionNode {
47
40
  id: string;