orcheo-studio 0.24.4 → 0.24.5

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 (77) hide show
  1. package/.bumpversion.cfg +1 -1
  2. package/dist/assets/{arc-99TH-Koz.js → arc-C-7b0zH4.js} +1 -1
  3. package/dist/assets/{architectureDiagram-VXUJARFQ-DugaTSY2.js → architectureDiagram-VXUJARFQ-Ciy8lV6J.js} +1 -1
  4. package/dist/assets/{blockDiagram-VD42YOAC-BH68wVtD.js → blockDiagram-VD42YOAC-dC88adQ_.js} +1 -1
  5. package/dist/assets/{c4Diagram-YG6GDRKO-V6Vqtp7B.js → c4Diagram-YG6GDRKO-BiHVvXEu.js} +1 -1
  6. package/dist/assets/channel-pJdT5i-M.js +1 -0
  7. package/dist/assets/{chunk-4BX2VUAB-CvbCAMNv.js → chunk-4BX2VUAB-C6V7Huup.js} +1 -1
  8. package/dist/assets/{chunk-55IACEB6-h_T3kQh7.js → chunk-55IACEB6-DRmZnlbz.js} +1 -1
  9. package/dist/assets/{chunk-B4BG7PRW-Dm6dgbGh.js → chunk-B4BG7PRW-DwV5xRJr.js} +1 -1
  10. package/dist/assets/{chunk-DI55MBZ5-DSXFA4Fi.js → chunk-DI55MBZ5-BHsUZ0IJ.js} +1 -1
  11. package/dist/assets/{chunk-FMBD7UC4-DJDlfjt1.js → chunk-FMBD7UC4-6Q-Lz0AM.js} +1 -1
  12. package/dist/assets/{chunk-QN33PNHL-BnjUGeBL.js → chunk-QN33PNHL-BFy_ml8O.js} +1 -1
  13. package/dist/assets/{chunk-QZHKN3VN-BRudOghZ.js → chunk-QZHKN3VN-C1fN91FN.js} +1 -1
  14. package/dist/assets/{chunk-TZMSLE5B-CpxSpvqK.js → chunk-TZMSLE5B-FLRSQ_Fi.js} +1 -1
  15. package/dist/assets/classDiagram-2ON5EDUG-CNT-EGNU.js +1 -0
  16. package/dist/assets/classDiagram-v2-WZHVMYZB-CNT-EGNU.js +1 -0
  17. package/dist/assets/clone-BCi0j082.js +1 -0
  18. package/dist/assets/{cose-bilkent-S5V4N54A-Dl80WZ_a.js → cose-bilkent-S5V4N54A-BSWP1X1D.js} +1 -1
  19. package/dist/assets/{dagre-6UL2VRFP-vw-vkw78.js → dagre-6UL2VRFP-CYoZFlcz.js} +1 -1
  20. package/dist/assets/{diagram-PSM6KHXK-B4MT5Nvf.js → diagram-PSM6KHXK-B8RGX0YL.js} +1 -1
  21. package/dist/assets/{diagram-QEK2KX5R-CMioZnRI.js → diagram-QEK2KX5R-ChWXJ8p_.js} +1 -1
  22. package/dist/assets/{diagram-S2PKOQOG-PJAE8YS0.js → diagram-S2PKOQOG-Dwic0Fjn.js} +1 -1
  23. package/dist/assets/{erDiagram-Q2GNP2WA-DCd-WouG.js → erDiagram-Q2GNP2WA-0NSDB0DX.js} +1 -1
  24. package/dist/assets/{flowDiagram-NV44I4VS-DS__-WT4.js → flowDiagram-NV44I4VS-DEoGWs9L.js} +1 -1
  25. package/dist/assets/{ganttDiagram-JELNMOA3-Btifh-31.js → ganttDiagram-JELNMOA3-DqzV4S6l.js} +1 -1
  26. package/dist/assets/{gitGraphDiagram-V2S2FVAM-BCyjopey.js → gitGraphDiagram-V2S2FVAM-B-EIQM_H.js} +1 -1
  27. package/dist/assets/{graph-6YBx8iQ0.js → graph-Ha1DTJNG.js} +1 -1
  28. package/dist/assets/{index-lkycEDHM.js → index-DTxvVcXp.js} +61 -61
  29. package/dist/assets/{infoDiagram-HS3SLOUP-CAsJ2eU1.js → infoDiagram-HS3SLOUP-C4_vpEkn.js} +1 -1
  30. package/dist/assets/{isUndefined-CcAlyXn3.js → isUndefined-DkuoqItu.js} +1 -1
  31. package/dist/assets/{journeyDiagram-XKPGCS4Q-Bi8XsX15.js → journeyDiagram-XKPGCS4Q-BxY4e6OZ.js} +1 -1
  32. package/dist/assets/{kanban-definition-3W4ZIXB7-PTAFVsDn.js → kanban-definition-3W4ZIXB7-BTX3_Q7O.js} +1 -1
  33. package/dist/assets/{layout-Do-GOFdW.js → layout-Dt1W0fl0.js} +1 -1
  34. package/dist/assets/{linear-CZlgolw0.js → linear-CjywSMUX.js} +1 -1
  35. package/dist/assets/{min-N15IYW1Y.js → min-Dblq6bty.js} +1 -1
  36. package/dist/assets/{mindmap-definition-VGOIOE7T-Dlgxv6Jo.js → mindmap-definition-VGOIOE7T-C5P7bAFm.js} +1 -1
  37. package/dist/assets/{pieDiagram-ADFJNKIX-Dr2AfIw5.js → pieDiagram-ADFJNKIX-BSMylwok.js} +1 -1
  38. package/dist/assets/{quadrantDiagram-AYHSOK5B-B8TPuvW6.js → quadrantDiagram-AYHSOK5B-C74B7bqa.js} +1 -1
  39. package/dist/assets/{requirementDiagram-UZGBJVZJ-CdD2oP1N.js → requirementDiagram-UZGBJVZJ-CvPzL8Le.js} +1 -1
  40. package/dist/assets/{sankeyDiagram-TZEHDZUN-XEMX6l5k.js → sankeyDiagram-TZEHDZUN-BFHm6g6t.js} +1 -1
  41. package/dist/assets/{sequenceDiagram-WL72ISMW-BlIKpBev.js → sequenceDiagram-WL72ISMW-e74mJ0xk.js} +1 -1
  42. package/dist/assets/{stateDiagram-FKZM4ZOC-D3KGQY6v.js → stateDiagram-FKZM4ZOC-VLQxNVA7.js} +1 -1
  43. package/dist/assets/stateDiagram-v2-4FDKWEC3-Bbpq2t6B.js +1 -0
  44. package/dist/assets/{timeline-definition-IT6M3QCI-TkL4mz_f.js → timeline-definition-IT6M3QCI-oveNP_QD.js} +1 -1
  45. package/dist/assets/{treemap-GDKQZRPO-BDp_c1Vc.js → treemap-GDKQZRPO-Cowimd29.js} +1 -1
  46. package/dist/assets/{xychartDiagram-PRI3JC2R-D0dNQImL.js → xychartDiagram-PRI3JC2R-CP9Fm_aO.js} +1 -1
  47. package/dist/index.html +1 -1
  48. package/package.json +1 -1
  49. package/src/App.tsx +48 -44
  50. package/src/features/account/pages/workspace-members.tsx +58 -62
  51. package/src/features/auth/pages/login.tsx +3 -1
  52. package/src/features/chatkit/lib/public-chat-access.ts +13 -0
  53. package/src/features/chatkit/pages/public-chat.tsx +1 -12
  54. package/src/features/shared/components/chat-interface.types.ts +1 -5
  55. package/src/features/shared/components/top-navigation/version-status.tsx +27 -31
  56. package/src/features/workflow/components/panels/rjsf-cron-widget.tsx +35 -10
  57. package/src/features/workflow/components/trace/agent-prism/SpanCard/SpanCardConnector.tsx +1 -5
  58. package/src/features/workflow/components/trace/agent-prism/shared.ts +1 -10
  59. package/src/features/workflow/lib/workflow-execution-builders.ts +4 -4
  60. package/src/features/workflow/lib/workflow-execution.types.ts +2 -9
  61. package/src/features/workflow/lib/workflow-frontmatter.ts +3 -1
  62. package/src/features/workflow/lib/workflow-storage-api.ts +5 -9
  63. package/src/features/workflow/lib/workflow-storage-helpers.ts +2 -4
  64. package/src/features/workflow/lib/workflow-storage.ts +6 -2
  65. package/src/features/workflow/lib/workflow-storage.types.ts +1 -6
  66. package/src/features/workflow/lib/workflow-upload-errors.ts +6 -2
  67. package/src/features/workflow/pages/workflow/components/workflow-tab-content.tsx +3 -1
  68. package/src/features/workflow/pages/workflow/hooks/controller/use-workflow-execution-controller.ts +4 -1
  69. package/src/features/workflow/pages/workflow/hooks/use-execution-updates.ts +4 -2
  70. package/src/features/workflow/pages/workflow-gallery/create-team-dialog.tsx +2 -6
  71. package/src/lib/api.ts +7 -2
  72. package/src/lib/workspace-routing.ts +1 -3
  73. package/dist/assets/channel-D562bZxL.js +0 -1
  74. package/dist/assets/classDiagram-2ON5EDUG-Dix_KnuM.js +0 -1
  75. package/dist/assets/classDiagram-v2-WZHVMYZB-Dix_KnuM.js +0 -1
  76. package/dist/assets/clone-0c2Tu-SH.js +0 -1
  77. package/dist/assets/stateDiagram-v2-4FDKWEC3-Di3Nkv2n.js +0 -1
@@ -282,69 +282,65 @@ export default function WorkspaceMembers() {
282
282
  </div>
283
283
  )}
284
284
 
285
- {canManage &&
286
- invitations.some((i) => i.status === "pending") && (
287
- <div className="rounded-lg border">
288
- <div className="border-b px-4 py-3">
289
- <h3 className="text-sm font-medium">Pending Invitations</h3>
290
- </div>
291
- <Table>
292
- <TableHeader>
293
- <TableRow>
294
- <TableHead>Email</TableHead>
295
- <TableHead>Role</TableHead>
296
- <TableHead>Expires</TableHead>
297
- <TableHead className="text-right">Actions</TableHead>
298
- </TableRow>
299
- </TableHeader>
300
- <TableBody>
301
- {invitations
302
- .filter((i) => i.status === "pending")
303
- .map((invitation) => {
304
- const isRevoking =
305
- revokingInvitationId === invitation.id;
306
- const isExpired =
307
- new Date(invitation.expires_at) < new Date();
308
- return (
309
- <TableRow
310
- key={invitation.id}
311
- className={isExpired ? "opacity-60" : undefined}
312
- >
313
- <TableCell className="text-sm">
314
- {invitation.email}
315
- </TableCell>
316
- <TableCell className="capitalize">
317
- {invitation.role}
318
- </TableCell>
319
- <TableCell className="text-sm text-muted-foreground">
320
- {isExpired ? (
321
- <span className="text-destructive">Expired</span>
322
- ) : (
323
- new Date(
324
- invitation.expires_at,
325
- ).toLocaleDateString()
326
- )}
327
- </TableCell>
328
- <TableCell className="text-right">
329
- <Button
330
- variant="ghost"
331
- size="sm"
332
- className="text-destructive hover:text-destructive"
333
- onClick={() =>
334
- void handleRevokeInvitation(invitation.id)
335
- }
336
- disabled={isRevoking}
337
- >
338
- {isRevoking ? "Revoking..." : "Revoke"}
339
- </Button>
340
- </TableCell>
341
- </TableRow>
342
- );
343
- })}
344
- </TableBody>
345
- </Table>
285
+ {canManage && invitations.some((i) => i.status === "pending") && (
286
+ <div className="rounded-lg border">
287
+ <div className="border-b px-4 py-3">
288
+ <h3 className="text-sm font-medium">Pending Invitations</h3>
346
289
  </div>
347
- )}
290
+ <Table>
291
+ <TableHeader>
292
+ <TableRow>
293
+ <TableHead>Email</TableHead>
294
+ <TableHead>Role</TableHead>
295
+ <TableHead>Expires</TableHead>
296
+ <TableHead className="text-right">Actions</TableHead>
297
+ </TableRow>
298
+ </TableHeader>
299
+ <TableBody>
300
+ {invitations
301
+ .filter((i) => i.status === "pending")
302
+ .map((invitation) => {
303
+ const isRevoking = revokingInvitationId === invitation.id;
304
+ const isExpired =
305
+ new Date(invitation.expires_at) < new Date();
306
+ return (
307
+ <TableRow
308
+ key={invitation.id}
309
+ className={isExpired ? "opacity-60" : undefined}
310
+ >
311
+ <TableCell className="text-sm">
312
+ {invitation.email}
313
+ </TableCell>
314
+ <TableCell className="capitalize">
315
+ {invitation.role}
316
+ </TableCell>
317
+ <TableCell className="text-sm text-muted-foreground">
318
+ {isExpired ? (
319
+ <span className="text-destructive">Expired</span>
320
+ ) : (
321
+ new Date(invitation.expires_at).toLocaleDateString()
322
+ )}
323
+ </TableCell>
324
+ <TableCell className="text-right">
325
+ <Button
326
+ variant="ghost"
327
+ size="sm"
328
+ className="text-destructive hover:text-destructive"
329
+ onClick={() =>
330
+ void handleRevokeInvitation(invitation.id)
331
+ }
332
+ disabled={isRevoking}
333
+ >
334
+ {isRevoking ? "Revoking..." : "Revoke"}
335
+ </Button>
336
+ </TableCell>
337
+ </TableRow>
338
+ );
339
+ })}
340
+ </TableBody>
341
+ </Table>
342
+ </div>
343
+ )}
348
344
 
349
345
  {isForbidden ? null : isLoading ? (
350
346
  <p className="text-sm text-muted-foreground">Loading members...</p>
@@ -73,7 +73,9 @@ export default function Login() {
73
73
  setStage("sent");
74
74
  } catch (err) {
75
75
  setError(
76
- err instanceof Error ? err.message : "Unable to send the sign-in email.",
76
+ err instanceof Error
77
+ ? err.message
78
+ : "Unable to send the sign-in email.",
77
79
  );
78
80
  } finally {
79
81
  setBusy(false);
@@ -0,0 +1,13 @@
1
+ import type { PublicChatHttpError } from "@features/chatkit/lib/chatkit-client";
2
+
3
+ export const getPublicChatAccessErrorMessage = (
4
+ error: Pick<PublicChatHttpError, "status" | "code">,
5
+ ): string => {
6
+ if (error.code === "chatkit.auth.workspace_mismatch") {
7
+ return "Your account is signed in, but it is not a member of this workflow workspace. Switch workspaces or ask the owner to add you.";
8
+ }
9
+ if (error.status === 403) {
10
+ return "You do not have permission to use this workflow. Ask the owner to confirm your workspace access.";
11
+ }
12
+ return "You do not have access to this workflow yet. Ask the owner to confirm it is still published.";
13
+ };
@@ -19,6 +19,7 @@ import type { PublicWorkflowMetadata } from "@features/workflow/lib/workflow-sto
19
19
  import { PublicChatWidget } from "@features/chatkit/components/public-chat-widget";
20
20
  import { PublicChatErrorBoundary } from "@features/chatkit/components/public-chat-error-boundary";
21
21
  import type { PublicChatHttpError } from "@features/chatkit/lib/chatkit-client";
22
+ import { getPublicChatAccessErrorMessage } from "@features/chatkit/lib/public-chat-access";
22
23
 
23
24
  type ColorScheme = "light" | "dark";
24
25
 
@@ -27,18 +28,6 @@ type WorkflowState =
27
28
  | { status: "error"; message: string }
28
29
  | { status: "ready"; workflow: PublicWorkflowMetadata };
29
30
 
30
- export const getPublicChatAccessErrorMessage = (
31
- error: Pick<PublicChatHttpError, "status" | "code">,
32
- ): string => {
33
- if (error.code === "chatkit.auth.workspace_mismatch") {
34
- return "Your account is signed in, but it is not a member of this workflow workspace. Switch workspaces or ask the owner to add you.";
35
- }
36
- if (error.status === 403) {
37
- return "You do not have permission to use this workflow. Ask the owner to confirm your workspace access.";
38
- }
39
- return "You do not have access to this workflow yet. Ask the owner to confirm it is still published.";
40
- };
41
-
42
31
  const sanitizeWorkflowNameForEmail = (value: string): string =>
43
32
  value
44
33
  .replace(/[\r\n]+/g, " ")
@@ -27,11 +27,7 @@ export interface ChatInterfaceProps {
27
27
  isMinimizable?: boolean;
28
28
  isClosable?: boolean;
29
29
  position?:
30
- | "bottom-right"
31
- | "bottom-left"
32
- | "top-right"
33
- | "top-left"
34
- | "center";
30
+ "bottom-right" | "bottom-left" | "top-right" | "top-left" | "center";
35
31
  triggerButton?: React.ReactNode;
36
32
  user: ChatParticipant;
37
33
  ai: ChatParticipant;
@@ -44,17 +44,6 @@ const parseCache = (raw: string | null): SystemInfoCachePayload | null => {
44
44
  }
45
45
  };
46
46
 
47
- const shouldRefresh = (cache: SystemInfoCachePayload | null): boolean => {
48
- if (!cache) {
49
- return true;
50
- }
51
- const lastCheckedAt = Date.parse(cache.checkedAt);
52
- if (Number.isNaN(lastCheckedAt)) {
53
- return true;
54
- }
55
- return Date.now() - lastCheckedAt >= UPDATE_CHECK_TTL_MS;
56
- };
57
-
58
47
  const parseSemver = (value: string | null | undefined): ParsedSemver | null => {
59
48
  if (!value) {
60
49
  return null;
@@ -152,7 +141,10 @@ const isDismissed = (): boolean => {
152
141
  };
153
142
 
154
143
  export default function VersionStatus() {
155
- const [systemInfo, setSystemInfo] = useState<SystemInfoResponse | null>(null);
144
+ const [cachedInfo, setCachedInfo] = useState<SystemInfoResponse | null>(null);
145
+ const [liveBackendVersion, setLiveBackendVersion] = useState<string | null>(
146
+ null,
147
+ );
156
148
  const [dismissedReminder, setDismissedReminder] = useState<boolean>(() =>
157
149
  isDismissed(),
158
150
  );
@@ -163,11 +155,12 @@ export default function VersionStatus() {
163
155
  window.localStorage.getItem(UPDATE_CHECK_CACHE_KEY),
164
156
  );
165
157
  if (cache) {
166
- setSystemInfo(cache.payload);
167
- }
168
-
169
- if (!shouldRefresh(cache)) {
170
- return;
158
+ setCachedInfo(cache.payload);
159
+ setLiveBackendVersion(cache.payload.backend.current_version);
160
+ const cacheAge = Date.now() - Date.parse(cache.checkedAt);
161
+ if (cacheAge < UPDATE_CHECK_TTL_MS) {
162
+ return;
163
+ }
171
164
  }
172
165
 
173
166
  let active = true;
@@ -176,7 +169,8 @@ export default function VersionStatus() {
176
169
  if (!active) {
177
170
  return;
178
171
  }
179
- setSystemInfo(payload);
172
+ setLiveBackendVersion(payload.backend.current_version);
173
+ setCachedInfo(payload);
180
174
  const cachePayload: SystemInfoCachePayload = {
181
175
  checkedAt: new Date().toISOString(),
182
176
  payload,
@@ -196,39 +190,41 @@ export default function VersionStatus() {
196
190
  }, []);
197
191
 
198
192
  const studioUpdateAvailable = useMemo(() => {
199
- if (!systemInfo) {
193
+ if (!cachedInfo) {
200
194
  return false;
201
195
  }
202
- if (systemInfo.studio.update_available) {
196
+ if (cachedInfo.studio.update_available) {
203
197
  return true;
204
198
  }
205
- return compareSemver(studioVersion, systemInfo.studio.latest_version) < 0;
206
- }, [studioVersion, systemInfo]);
199
+ return compareSemver(studioVersion, cachedInfo.studio.latest_version) < 0;
200
+ }, [studioVersion, cachedInfo]);
207
201
 
208
202
  const showReminder =
209
- ((systemInfo?.backend.update_available ?? false) ||
203
+ ((cachedInfo?.backend.update_available ?? false) ||
210
204
  studioUpdateAvailable) &&
211
205
  !dismissedReminder;
212
206
 
213
207
  const versionSummary = useMemo(() => {
214
- const backend = systemInfo?.backend.current_version ?? "unknown";
208
+ const backend = liveBackendVersion ?? "unknown";
215
209
  return `Orcheo ${studioVersion} · Backend ${backend}`;
216
- }, [studioVersion, systemInfo]);
210
+ }, [studioVersion, liveBackendVersion]);
217
211
 
218
212
  const updateLines = useMemo(() => {
219
- if (!systemInfo) return [];
213
+ if (!cachedInfo) return [];
220
214
  const lines: string[] = [];
221
- if (systemInfo.backend.update_available) {
215
+ if (cachedInfo.backend.update_available) {
222
216
  lines.push(
223
- `Backend: ${systemInfo.backend.current_version} → ${systemInfo.backend.latest_version}`,
217
+ `Backend: ${cachedInfo.backend.current_version} → ${cachedInfo.backend.latest_version}`,
224
218
  );
225
219
  }
226
220
  if (studioUpdateAvailable) {
227
- const studioCurrent = systemInfo.studio.current_version ?? studioVersion;
228
- lines.push(`Orcheo: ${studioCurrent} → ${systemInfo.studio.latest_version}`);
221
+ const studioCurrent = cachedInfo.studio.current_version ?? studioVersion;
222
+ lines.push(
223
+ `Orcheo: ${studioCurrent} → ${cachedInfo.studio.latest_version}`,
224
+ );
229
225
  }
230
226
  return lines;
231
- }, [studioUpdateAvailable, studioVersion, systemInfo]);
227
+ }, [studioUpdateAvailable, studioVersion, cachedInfo]);
232
228
 
233
229
  const dismissUpdateReminder = () => {
234
230
  if (typeof window === "undefined") {
@@ -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" />
@@ -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
 
@@ -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;
@@ -22,7 +22,9 @@ const parseTomlString = (value: string): string | undefined => {
22
22
  if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
23
23
  try {
24
24
  const parsed = JSON.parse(trimmed) as unknown;
25
- return typeof parsed === "string" && parsed.trim() ? parsed.trim() : undefined;
25
+ return typeof parsed === "string" && parsed.trim()
26
+ ? parsed.trim()
27
+ : undefined;
26
28
  } catch {
27
29
  return undefined;
28
30
  }
@@ -498,7 +498,8 @@ export const extractCronConfigFromVersionGraph = (
498
498
 
499
499
  // Matches a value that is exactly a single `{{config.configurable.<name>}}`
500
500
  // placeholder, optionally padded with whitespace inside the braces.
501
- const CONFIGURABLE_TEMPLATE = /^\{\{\s*config\.configurable\.([^}\s.]+)\s*\}\}$/;
501
+ const CONFIGURABLE_TEMPLATE =
502
+ /^\{\{\s*config\.configurable\.([^}\s.]+)\s*\}\}$/;
502
503
 
503
504
  const resolveConfigurableTemplate = (
504
505
  value: string | null | undefined,
@@ -539,16 +540,11 @@ const resolveConfigurableCronConfig = (
539
540
  resolveConfigurableTemplate(config.expression, configurable) ??
540
541
  config.expression,
541
542
  timezone: resolveConfigurableTemplate(config.timezone, configurable) as
542
- | string
543
- | undefined,
543
+ string | undefined,
544
544
  start_at: resolveConfigurableTemplate(config.start_at, configurable) as
545
- | string
546
- | null
547
- | undefined,
545
+ string | null | undefined,
548
546
  end_at: resolveConfigurableTemplate(config.end_at, configurable) as
549
- | string
550
- | null
551
- | undefined,
547
+ string | null | undefined,
552
548
  };
553
549
  };
554
550
 
@@ -281,11 +281,9 @@ const parseWorkflowMetadata = (
281
281
 
282
282
  const workflowRecord = workflowMetadata as Record<string, unknown>;
283
283
  const snapshotPayload = workflowRecord.snapshot as
284
- | WorkflowSnapshot
285
- | undefined;
284
+ WorkflowSnapshot | undefined;
286
285
  const summaryPayload = workflowRecord.summary as
287
- | WorkflowDiffResult["summary"]
288
- | undefined;
286
+ WorkflowDiffResult["summary"] | undefined;
289
287
  const messagePayload = workflowRecord.message as string | undefined;
290
288
  const workflowToGraph = (workflowRecord.workflowToGraph ??
291
289
  workflowRecord.canvasToGraph) as Record<string, string> | undefined;
@@ -399,7 +399,9 @@ export const uploadWorkflowFromFiles = async (
399
399
  });
400
400
  } catch (error) {
401
401
  const message =
402
- error instanceof Error ? error.message : "Upload failed. Please try again.";
402
+ error instanceof Error
403
+ ? error.message
404
+ : "Upload failed. Please try again.";
403
405
  const uploadError = saveWorkflowUploadError(created.id, message);
404
406
  const stored = await ensureWorkflow(created.id);
405
407
  invalidateWorkflowListCache();
@@ -453,7 +455,9 @@ export const updateWorkflowFromFiles = async (
453
455
  });
454
456
  } catch (error) {
455
457
  const message =
456
- error instanceof Error ? error.message : "Update failed. Please try again.";
458
+ error instanceof Error
459
+ ? error.message
460
+ : "Update failed. Please try again.";
457
461
  saveWorkflowUploadError(workflowId, message);
458
462
  invalidateWorkflowListCache();
459
463
  invalidateWorkflowCache(workflowId);
@@ -161,12 +161,7 @@ export interface WorkflowListenerHealth {
161
161
  last_event_at?: string | null;
162
162
  last_error?: string | null;
163
163
  runtime_status:
164
- | "starting"
165
- | "healthy"
166
- | "backoff"
167
- | "stopped"
168
- | "error"
169
- | "unknown";
164
+ "starting" | "healthy" | "backoff" | "stopped" | "error" | "unknown";
170
165
  runtime_detail?: string | null;
171
166
  last_polled_at?: string | null;
172
167
  consecutive_failures: number;
@@ -7,7 +7,8 @@ export interface WorkflowUploadError {
7
7
 
8
8
  const STORAGE_PREFIX = "orcheo.workflowUploadError.";
9
9
 
10
- const storageKey = (workflowId: string): string => `${STORAGE_PREFIX}${workflowId}`;
10
+ const storageKey = (workflowId: string): string =>
11
+ `${STORAGE_PREFIX}${workflowId}`;
11
12
 
12
13
  const canUseSessionStorage = (): boolean =>
13
14
  typeof window !== "undefined" && Boolean(window.sessionStorage);
@@ -26,7 +27,10 @@ export const saveWorkflowUploadError = (
26
27
  }
27
28
 
28
29
  try {
29
- window.sessionStorage.setItem(storageKey(workflowId), JSON.stringify(error));
30
+ window.sessionStorage.setItem(
31
+ storageKey(workflowId),
32
+ JSON.stringify(error),
33
+ );
30
34
  } catch {
31
35
  // Upload failure rendering should not depend on storage availability.
32
36
  }
@@ -752,7 +752,9 @@ export function WorkflowTabContent({
752
752
  void handleScheduleToggle(checked)
753
753
  }
754
754
  disabled={
755
- isSchedulePending || !canToggleSchedule || uploadBlocksWorkflow
755
+ isSchedulePending ||
756
+ !canToggleSchedule ||
757
+ uploadBlocksWorkflow
756
758
  }
757
759
  />
758
760
  </div>
@@ -92,7 +92,10 @@ export function useWorkflowExecutionController(
92
92
 
93
93
  const graphToWorkflow = latestVersionRecord?.graphToWorkflow ?? {};
94
94
  const executionId = generateRandomId("run");
95
- const executionRecord = createExecutionRecord(executionId, graphToWorkflow);
95
+ const executionRecord = createExecutionRecord(
96
+ executionId,
97
+ graphToWorkflow,
98
+ );
96
99
 
97
100
  if (core.websocketRef.current) {
98
101
  core.websocketRef.current.close();
@@ -48,8 +48,10 @@ export function useExecutionUpdates({
48
48
  );
49
49
 
50
50
  const describePayload = useCallback(
51
- (payload: Record<string, unknown>, graphToWorkflow: Record<string, string>) =>
52
- describePayloadRaw(payload, graphToWorkflow, (id) => id),
51
+ (
52
+ payload: Record<string, unknown>,
53
+ graphToWorkflow: Record<string, string>,
54
+ ) => describePayloadRaw(payload, graphToWorkflow, (id) => id),
53
55
  [],
54
56
  );
55
57
 
@@ -70,9 +70,7 @@ export const CreateTeamDialog = ({
70
70
  await onCreate(trimmedName, trimmedSlug);
71
71
  onOpenChange(false);
72
72
  } catch (err) {
73
- setError(
74
- err instanceof Error ? err.message : "Failed to create team.",
75
- );
73
+ setError(err instanceof Error ? err.message : "Failed to create team.");
76
74
  } finally {
77
75
  setIsSubmitting(false);
78
76
  }
@@ -118,9 +116,7 @@ export const CreateTeamDialog = ({
118
116
  underscores only.
119
117
  </p>
120
118
  </div>
121
- {error ? (
122
- <p className="text-sm text-destructive">{error}</p>
123
- ) : null}
119
+ {error ? <p className="text-sm text-destructive">{error}</p> : null}
124
120
  </div>
125
121
 
126
122
  <DialogFooter>