@tangle-network/sandbox-ui 0.72.0 → 0.74.0

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.
package/dist/workflows.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  buildWorkflowGraph
3
- } from "./chunk-34F66QTV.js";
3
+ } from "./chunk-VXGI2XUK.js";
4
4
  import "./chunk-U67V476Y.js";
5
5
 
6
6
  // src/workflows/WorkflowGraphLazy.tsx
@@ -26,7 +26,7 @@ function retryImport(factory, retries = 2, delayMs = 350) {
26
26
  function lazyWorkflowGraph() {
27
27
  return lazy(
28
28
  () => retryImport(
29
- () => import("./WorkflowGraph-M5ZOY43R.js").then((m) => ({ default: m.WorkflowGraph }))
29
+ () => import("./WorkflowGraph-64XJBIW2.js").then((m) => ({ default: m.WorkflowGraph }))
30
30
  )
31
31
  );
32
32
  }
@@ -50,18 +50,18 @@ function GraphFallback({
50
50
  className: `overflow-auto rounded-lg border border-border bg-background p-2 ${className ?? ""}`,
51
51
  children: [
52
52
  /* @__PURE__ */ jsxs("div", { className: "mb-1 flex items-center justify-between gap-2", children: [
53
- /* @__PURE__ */ jsx("p", { className: "text-text-muted text-xs", children: "Couldn't render the graph \u2014 showing the definition." }),
53
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-xs", children: "Couldn't render the graph \u2014 showing the definition." }),
54
54
  /* @__PURE__ */ jsx(
55
55
  "button",
56
56
  {
57
57
  type: "button",
58
58
  onClick: onRetry,
59
- className: "shrink-0 rounded border border-border px-1.5 py-0.5 text-text-muted text-xs transition hover:text-text",
59
+ className: "shrink-0 rounded border border-border px-1.5 py-0.5 text-muted-foreground text-xs transition hover:text-foreground",
60
60
  children: "Retry"
61
61
  }
62
62
  )
63
63
  ] }),
64
- /* @__PURE__ */ jsx("pre", { className: "text-text text-xs", children: /* @__PURE__ */ jsx("code", { children: yaml }) })
64
+ /* @__PURE__ */ jsx("pre", { className: "text-foreground text-xs", children: /* @__PURE__ */ jsx("code", { children: yaml }) })
65
65
  ]
66
66
  }
67
67
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox-ui",
3
- "version": "0.72.0",
3
+ "version": "0.74.0",
4
4
  "description": "Unified UI component library for Tangle Sandbox — primitives, chat, dashboard, terminal, editor, and workspace components",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,328 +0,0 @@
1
- import {
2
- ProviderIcon
3
- } from "./chunk-GTJ5PSK5.js";
4
- import {
5
- buildWorkflowGraph,
6
- providerLabel
7
- } from "./chunk-34F66QTV.js";
8
- import "./chunk-U67V476Y.js";
9
-
10
- // src/workflows/WorkflowGraph.tsx
11
- import {
12
- Background,
13
- Controls,
14
- Handle,
15
- Position,
16
- ReactFlow,
17
- useEdgesState,
18
- useNodesState
19
- } from "@xyflow/react";
20
- import "@xyflow/react/dist/style.css";
21
- import {
22
- useCallback,
23
- useEffect,
24
- useMemo,
25
- useState
26
- } from "react";
27
-
28
- // src/workflows/flow-graph.ts
29
- function buildFlowGraph(yaml, nodeState) {
30
- const graph = buildWorkflowGraph(yaml, {
31
- reserveRunState: nodeState !== void 0
32
- });
33
- return {
34
- error: graph.error,
35
- nodes: graph.nodes.map(
36
- (n) => ({
37
- id: n.id,
38
- type: "wfNode",
39
- position: n.position,
40
- data: nodeState?.[n.id] ? { ...n.data, state: nodeState[n.id] } : n.data
41
- })
42
- ),
43
- edges: graph.edges.map((e) => ({
44
- id: e.id,
45
- source: e.source,
46
- target: e.target,
47
- sourceHandle: e.sourceHandle,
48
- type: "smoothstep"
49
- }))
50
- };
51
- }
52
- function sameRunState(a, b) {
53
- if (a === b) return true;
54
- if (!a || !b) return false;
55
- const aKeys = Object.keys(a);
56
- const bKeys = Object.keys(b);
57
- if (aKeys.length !== bKeys.length) return false;
58
- return aKeys.every((k) => a[k] === b[k]);
59
- }
60
- function mergeRunState(prev, baseDataById, nodeState) {
61
- return prev.map((n) => {
62
- const base = baseDataById.get(n.id) ?? n.data;
63
- const s = nodeState?.[n.id];
64
- const nextData = s ? { ...base, state: s } : base;
65
- return sameRunState(n.data.state, nextData.state) ? n : { ...n, data: nextData };
66
- });
67
- }
68
-
69
- // src/workflows/format.ts
70
- function fmtDuration(ms) {
71
- if (ms === void 0 || !Number.isFinite(ms) || ms < 0) return void 0;
72
- if (ms < 1e3) return `${Math.round(ms)}ms`;
73
- const s = ms / 1e3;
74
- if (s < 60) return `${s.toFixed(1)}s`;
75
- const totalSeconds = Math.round(s);
76
- return `${Math.floor(totalSeconds / 60)}m${totalSeconds % 60}s`;
77
- }
78
- function fmtCost(usd) {
79
- if (usd === void 0 || !Number.isFinite(usd) || usd < 0) return void 0;
80
- if (usd === 0) return "$0";
81
- return usd < 0.01 ? `$${usd.toFixed(4)}` : `$${usd.toFixed(2)}`;
82
- }
83
- function clampPreview(text, max = 200) {
84
- return text.length > max ? `${text.slice(0, max)}\u2026` : text;
85
- }
86
- function fmtTokens(input, output) {
87
- const valid = (n) => n !== void 0 && Number.isFinite(n) && n >= 0 ? n : void 0;
88
- const i = valid(input);
89
- const o = valid(output);
90
- if (i === void 0 && o === void 0) return void 0;
91
- return `${i ?? 0}/${o ?? 0} tok`;
92
- }
93
-
94
- // src/workflows/WorkflowGraph.tsx
95
- import { jsx, jsxs } from "react/jsx-runtime";
96
- function useColorMode() {
97
- const [mode, setMode] = useState(
98
- () => typeof document !== "undefined" && document.documentElement.classList.contains("dark") ? "dark" : "light"
99
- );
100
- useEffect(() => {
101
- const el = document.documentElement;
102
- const update = () => setMode(el.classList.contains("dark") ? "dark" : "light");
103
- update();
104
- const observer = new MutationObserver(update);
105
- observer.observe(el, { attributes: true, attributeFilter: ["class"] });
106
- return () => observer.disconnect();
107
- }, []);
108
- return mode;
109
- }
110
- var TONE_CARD = {
111
- trigger: "border-primary/60 bg-primary/5",
112
- structural: "border-accent-yellow/50 bg-accent-yellow/5",
113
- action: "border-border bg-card"
114
- };
115
- var TONE_DOT = {
116
- trigger: "bg-primary",
117
- structural: "bg-accent-yellow",
118
- action: "bg-text-muted"
119
- };
120
- var HANDLE_CLASS = "!h-2 !w-2 !min-w-0 !border-0 !bg-transparent opacity-0";
121
- var STATUS_LABEL = {
122
- queued: "Queued",
123
- running: "Running",
124
- succeeded: "Done",
125
- failed: "Failed"
126
- };
127
- var STATUS_BADGE = {
128
- queued: "bg-background-tertiary text-text-muted",
129
- running: "bg-primary/15 text-primary",
130
- succeeded: "bg-green-600/10 text-green-600",
131
- failed: "bg-red-500/10 text-red-400"
132
- };
133
- function statusBorder(status) {
134
- switch (status) {
135
- case "running":
136
- return "border-primary ring-2 ring-primary/40 animate-pulse";
137
- case "succeeded":
138
- return "border-green-500";
139
- case "failed":
140
- return "border-red-500";
141
- default:
142
- return "opacity-70";
143
- }
144
- }
145
- function MetaChip({ children }) {
146
- return /* @__PURE__ */ jsx("span", { className: "rounded bg-background-tertiary px-1.5 py-0.5 text-[10px] text-text-muted", children });
147
- }
148
- function WorkflowNode({ data }) {
149
- const d = data;
150
- const state = d.state;
151
- const model = state?.model ?? d.model;
152
- const duration = fmtDuration(state?.durationMs);
153
- const cost = fmtCost(state?.costUsd);
154
- const tokens = fmtTokens(state?.inputTokens, state?.outputTokens);
155
- const errorText = state?.error ? clampPreview(state.error) : void 0;
156
- const outputText = state?.outputPreview ? clampPreview(state.outputPreview) : void 0;
157
- return /* @__PURE__ */ jsxs(
158
- "div",
159
- {
160
- className: `relative w-[240px] rounded-lg border px-3 py-2 shadow-sm transition-colors ${TONE_CARD[d.tone]} ${state ? statusBorder(state.status) : ""}`,
161
- children: [
162
- !d.isRoot && /* @__PURE__ */ jsx(
163
- Handle,
164
- {
165
- type: "target",
166
- position: Position.Top,
167
- className: HANDLE_CLASS
168
- }
169
- ),
170
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
171
- /* @__PURE__ */ jsx(
172
- "span",
173
- {
174
- "aria-hidden": "true",
175
- className: `h-2 w-2 shrink-0 rounded-full ${TONE_DOT[d.tone]}`
176
- }
177
- ),
178
- /* @__PURE__ */ jsx("span", { className: "font-medium text-[12px] text-text", children: d.title }),
179
- state ? /* @__PURE__ */ jsx(
180
- "span",
181
- {
182
- className: `ml-auto rounded px-1.5 py-0.5 text-[10px] ${STATUS_BADGE[state.status]}`,
183
- children: STATUS_LABEL[state.status]
184
- }
185
- ) : d.badge && /* @__PURE__ */ jsx("span", { className: "ml-auto rounded bg-background-tertiary px-1.5 py-0.5 text-[10px] text-text-muted", children: d.badge })
186
- ] }),
187
- d.subtitle && /* @__PURE__ */ jsx(
188
- "p",
189
- {
190
- className: "mt-1 truncate text-[11px] text-text-muted",
191
- title: d.subtitle,
192
- children: d.subtitle
193
- }
194
- ),
195
- (model || cost || duration || tokens || state) && /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex flex-wrap items-center gap-1", children: [
196
- d.kind && d.tone === "action" && /* @__PURE__ */ jsx(MetaChip, { children: d.kind }),
197
- model && /* @__PURE__ */ jsx(MetaChip, { children: model }),
198
- cost && /* @__PURE__ */ jsx(MetaChip, { children: cost }),
199
- duration && /* @__PURE__ */ jsx(MetaChip, { children: duration }),
200
- tokens && /* @__PURE__ */ jsx(MetaChip, { children: tokens })
201
- ] }),
202
- state?.status === "failed" && errorText && /* @__PURE__ */ jsx(
203
- "p",
204
- {
205
- className: "mt-1.5 line-clamp-2 text-[10px] text-red-400",
206
- title: errorText,
207
- children: errorText
208
- }
209
- ),
210
- outputText && state?.status !== "failed" && /* @__PURE__ */ jsx(
211
- "p",
212
- {
213
- className: "mt-1.5 line-clamp-2 text-[10px] text-text-muted",
214
- title: outputText,
215
- children: outputText
216
- }
217
- ),
218
- d.provider && /* @__PURE__ */ jsxs("span", { className: "mt-1.5 inline-flex items-center gap-1 rounded bg-background-tertiary px-1.5 py-0.5 text-[10px] text-text-muted", children: [
219
- /* @__PURE__ */ jsx(
220
- ProviderIcon,
221
- {
222
- id: d.provider,
223
- displayName: providerLabel(d.provider),
224
- size: 12,
225
- className: "rounded-[2px]"
226
- }
227
- ),
228
- providerLabel(d.provider)
229
- ] }),
230
- /* @__PURE__ */ jsx(
231
- Handle,
232
- {
233
- type: "source",
234
- id: "out",
235
- position: Position.Bottom,
236
- className: HANDLE_CLASS
237
- }
238
- ),
239
- d.hasBranches && /* @__PURE__ */ jsx(
240
- Handle,
241
- {
242
- type: "source",
243
- id: "branch",
244
- position: Position.Right,
245
- className: HANDLE_CLASS
246
- }
247
- )
248
- ]
249
- }
250
- );
251
- }
252
- var NODE_TYPES = { wfNode: WorkflowNode };
253
- function WorkflowGraph({
254
- yaml,
255
- variant = "full",
256
- className,
257
- nodeState,
258
- onNodeClick
259
- }) {
260
- const colorMode = useColorMode();
261
- const hasRunOverlay = nodeState !== void 0;
262
- const structural = useMemo(
263
- () => buildFlowGraph(yaml, hasRunOverlay ? {} : void 0),
264
- [yaml, hasRunOverlay]
265
- );
266
- const [nodes, setNodes, onNodesChange] = useNodesState(structural.nodes);
267
- const [edges, setEdges, onEdgesChange] = useEdgesState(structural.edges);
268
- useEffect(() => {
269
- setNodes(structural.nodes);
270
- setEdges(structural.edges);
271
- }, [structural, setNodes, setEdges]);
272
- useEffect(() => {
273
- const baseById = new Map(structural.nodes.map((n) => [n.id, n.data]));
274
- setNodes((prev) => mergeRunState(prev, baseById, nodeState));
275
- }, [nodeState, structural, setNodes]);
276
- const handleNodeClick = useCallback(
277
- (_event, node) => {
278
- onNodeClick?.(node.id, node.data);
279
- },
280
- [onNodeClick]
281
- );
282
- if (structural.error || structural.nodes.length === 0) {
283
- return /* @__PURE__ */ jsx(
284
- "div",
285
- {
286
- className: `flex items-center justify-center rounded-lg border border-border border-dashed p-4 text-center text-text-muted text-xs ${className ?? ""}`,
287
- children: structural.error ?? "Nothing to show"
288
- }
289
- );
290
- }
291
- const isPreview = variant === "preview";
292
- return /* @__PURE__ */ jsx("div", { className: `wf-graph ${className ?? ""}`, children: /* @__PURE__ */ jsxs(
293
- ReactFlow,
294
- {
295
- nodes,
296
- edges,
297
- onNodesChange,
298
- onEdgesChange,
299
- nodeTypes: NODE_TYPES,
300
- colorMode,
301
- onNodeClick: onNodeClick ? handleNodeClick : void 0,
302
- fitView: true,
303
- fitViewOptions: { padding: 0.2 },
304
- proOptions: { hideAttribution: true },
305
- nodesDraggable: !isPreview,
306
- nodesConnectable: false,
307
- deleteKeyCode: null,
308
- edgesReconnectable: false,
309
- elementsSelectable: !isPreview,
310
- edgesFocusable: false,
311
- zoomOnScroll: false,
312
- zoomOnPinch: true,
313
- zoomOnDoubleClick: !isPreview,
314
- panOnDrag: true,
315
- preventScrolling: false,
316
- minZoom: 0.2,
317
- maxZoom: 1.5,
318
- children: [
319
- /* @__PURE__ */ jsx(Background, { gap: 16 }),
320
- /* @__PURE__ */ jsx(Controls, { showInteractive: false, position: "bottom-right" })
321
- ]
322
- }
323
- ) });
324
- }
325
- export {
326
- WorkflowGraph,
327
- WorkflowNode
328
- };