@tangle-network/sandbox-ui 0.48.0 → 0.50.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/WorkflowGraph-4JREVTSK.js +295 -0
- package/dist/{chunk-SUC6ZJZW.js → chunk-46VFHJPQ.js} +33 -0
- package/dist/{chunk-4HLWA2VN.js → chunk-MGIOO3RL.js} +1 -1
- package/dist/{chunk-3WUSPCPC.js → chunk-RT4MLYYM.js} +57 -21
- package/dist/dashboard.d.ts +3 -0
- package/dist/dashboard.js +1 -1
- package/dist/globals.css +39 -0
- package/dist/index.js +2 -2
- package/dist/integrations.d.ts +19 -1
- package/dist/integrations.js +111 -40
- package/dist/pages.d.ts +1 -1
- package/dist/styles.css +39 -0
- package/dist/workbench.js +2 -2
- package/dist/workflows.d.ts +53 -1
- package/dist/workflows.js +2 -2
- package/package.json +1 -1
- package/dist/WorkflowGraph-EOV2P5AM.js +0 -184
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ProviderIcon
|
|
3
|
+
} from "./chunk-GTJ5PSK5.js";
|
|
4
|
+
import {
|
|
5
|
+
buildWorkflowGraph
|
|
6
|
+
} from "./chunk-46VFHJPQ.js";
|
|
7
|
+
import {
|
|
8
|
+
providerLabel
|
|
9
|
+
} from "./chunk-7JLB7UZ3.js";
|
|
10
|
+
import "./chunk-U67V476Y.js";
|
|
11
|
+
|
|
12
|
+
// src/workflows/WorkflowGraph.tsx
|
|
13
|
+
import {
|
|
14
|
+
Background,
|
|
15
|
+
Controls,
|
|
16
|
+
Handle,
|
|
17
|
+
Position,
|
|
18
|
+
ReactFlow
|
|
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
|
+
return {
|
|
32
|
+
error: graph.error,
|
|
33
|
+
nodes: graph.nodes.map(
|
|
34
|
+
(n) => ({
|
|
35
|
+
id: n.id,
|
|
36
|
+
type: "wfNode",
|
|
37
|
+
position: n.position,
|
|
38
|
+
data: nodeState?.[n.id] ? { ...n.data, state: nodeState[n.id] } : n.data
|
|
39
|
+
})
|
|
40
|
+
),
|
|
41
|
+
edges: graph.edges.map((e) => ({
|
|
42
|
+
id: e.id,
|
|
43
|
+
source: e.source,
|
|
44
|
+
target: e.target,
|
|
45
|
+
sourceHandle: e.sourceHandle,
|
|
46
|
+
type: "smoothstep"
|
|
47
|
+
}))
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/workflows/format.ts
|
|
52
|
+
function fmtDuration(ms) {
|
|
53
|
+
if (ms === void 0 || !Number.isFinite(ms) || ms < 0) return void 0;
|
|
54
|
+
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
55
|
+
const s = ms / 1e3;
|
|
56
|
+
if (s < 60) return `${s.toFixed(1)}s`;
|
|
57
|
+
const totalSeconds = Math.round(s);
|
|
58
|
+
return `${Math.floor(totalSeconds / 60)}m${totalSeconds % 60}s`;
|
|
59
|
+
}
|
|
60
|
+
function fmtCost(usd) {
|
|
61
|
+
if (usd === void 0 || !Number.isFinite(usd) || usd < 0) return void 0;
|
|
62
|
+
if (usd === 0) return "$0";
|
|
63
|
+
return usd < 0.01 ? `$${usd.toFixed(4)}` : `$${usd.toFixed(2)}`;
|
|
64
|
+
}
|
|
65
|
+
function clampPreview(text, max = 200) {
|
|
66
|
+
return text.length > max ? `${text.slice(0, max)}\u2026` : text;
|
|
67
|
+
}
|
|
68
|
+
function fmtTokens(input, output) {
|
|
69
|
+
const valid = (n) => n !== void 0 && Number.isFinite(n) && n >= 0 ? n : void 0;
|
|
70
|
+
const i = valid(input);
|
|
71
|
+
const o = valid(output);
|
|
72
|
+
if (i === void 0 && o === void 0) return void 0;
|
|
73
|
+
return `${i ?? 0}/${o ?? 0} tok`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// src/workflows/WorkflowGraph.tsx
|
|
77
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
78
|
+
function useColorMode() {
|
|
79
|
+
const [mode, setMode] = useState(
|
|
80
|
+
() => typeof document !== "undefined" && document.documentElement.classList.contains("dark") ? "dark" : "light"
|
|
81
|
+
);
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
const el = document.documentElement;
|
|
84
|
+
const update = () => setMode(el.classList.contains("dark") ? "dark" : "light");
|
|
85
|
+
update();
|
|
86
|
+
const observer = new MutationObserver(update);
|
|
87
|
+
observer.observe(el, { attributes: true, attributeFilter: ["class"] });
|
|
88
|
+
return () => observer.disconnect();
|
|
89
|
+
}, []);
|
|
90
|
+
return mode;
|
|
91
|
+
}
|
|
92
|
+
var TONE_CARD = {
|
|
93
|
+
trigger: "border-primary/60 bg-primary/5",
|
|
94
|
+
structural: "border-accent-yellow/50 bg-accent-yellow/5",
|
|
95
|
+
action: "border-border bg-card"
|
|
96
|
+
};
|
|
97
|
+
var TONE_DOT = {
|
|
98
|
+
trigger: "bg-primary",
|
|
99
|
+
structural: "bg-accent-yellow",
|
|
100
|
+
action: "bg-text-muted"
|
|
101
|
+
};
|
|
102
|
+
var HANDLE_CLASS = "!h-2 !w-2 !min-w-0 !border-0 !bg-transparent opacity-0";
|
|
103
|
+
var STATUS_LABEL = {
|
|
104
|
+
queued: "Queued",
|
|
105
|
+
running: "Running",
|
|
106
|
+
succeeded: "Done",
|
|
107
|
+
failed: "Failed"
|
|
108
|
+
};
|
|
109
|
+
var STATUS_BADGE = {
|
|
110
|
+
queued: "bg-background-tertiary text-text-muted",
|
|
111
|
+
running: "bg-primary/15 text-primary",
|
|
112
|
+
succeeded: "bg-green-600/10 text-green-600",
|
|
113
|
+
failed: "bg-red-500/10 text-red-400"
|
|
114
|
+
};
|
|
115
|
+
function statusBorder(status) {
|
|
116
|
+
switch (status) {
|
|
117
|
+
case "running":
|
|
118
|
+
return "border-primary ring-2 ring-primary/40 animate-pulse";
|
|
119
|
+
case "succeeded":
|
|
120
|
+
return "border-green-500";
|
|
121
|
+
case "failed":
|
|
122
|
+
return "border-red-500";
|
|
123
|
+
default:
|
|
124
|
+
return "opacity-70";
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function MetaChip({ children }) {
|
|
128
|
+
return /* @__PURE__ */ jsx("span", { className: "rounded bg-background-tertiary px-1.5 py-0.5 text-[10px] text-text-muted", children });
|
|
129
|
+
}
|
|
130
|
+
function WorkflowNode({ data }) {
|
|
131
|
+
const d = data;
|
|
132
|
+
const state = d.state;
|
|
133
|
+
const model = state?.model ?? d.model;
|
|
134
|
+
const duration = fmtDuration(state?.durationMs);
|
|
135
|
+
const cost = fmtCost(state?.costUsd);
|
|
136
|
+
const tokens = fmtTokens(state?.inputTokens, state?.outputTokens);
|
|
137
|
+
const errorText = state?.error ? clampPreview(state.error) : void 0;
|
|
138
|
+
const outputText = state?.outputPreview ? clampPreview(state.outputPreview) : void 0;
|
|
139
|
+
return /* @__PURE__ */ jsxs(
|
|
140
|
+
"div",
|
|
141
|
+
{
|
|
142
|
+
className: `relative w-[240px] rounded-lg border px-3 py-2 shadow-sm transition-colors ${TONE_CARD[d.tone]} ${state ? statusBorder(state.status) : ""}`,
|
|
143
|
+
children: [
|
|
144
|
+
!d.isRoot && /* @__PURE__ */ jsx(
|
|
145
|
+
Handle,
|
|
146
|
+
{
|
|
147
|
+
type: "target",
|
|
148
|
+
position: Position.Top,
|
|
149
|
+
className: HANDLE_CLASS
|
|
150
|
+
}
|
|
151
|
+
),
|
|
152
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
153
|
+
/* @__PURE__ */ jsx(
|
|
154
|
+
"span",
|
|
155
|
+
{
|
|
156
|
+
"aria-hidden": "true",
|
|
157
|
+
className: `h-2 w-2 shrink-0 rounded-full ${TONE_DOT[d.tone]}`
|
|
158
|
+
}
|
|
159
|
+
),
|
|
160
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-[12px] text-text", children: d.title }),
|
|
161
|
+
state ? /* @__PURE__ */ jsx(
|
|
162
|
+
"span",
|
|
163
|
+
{
|
|
164
|
+
className: `ml-auto rounded px-1.5 py-0.5 text-[10px] ${STATUS_BADGE[state.status]}`,
|
|
165
|
+
children: STATUS_LABEL[state.status]
|
|
166
|
+
}
|
|
167
|
+
) : 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 })
|
|
168
|
+
] }),
|
|
169
|
+
d.subtitle && /* @__PURE__ */ jsx(
|
|
170
|
+
"p",
|
|
171
|
+
{
|
|
172
|
+
className: "mt-1 truncate text-[11px] text-text-muted",
|
|
173
|
+
title: d.subtitle,
|
|
174
|
+
children: d.subtitle
|
|
175
|
+
}
|
|
176
|
+
),
|
|
177
|
+
(model || cost || duration || tokens || state) && /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex flex-wrap items-center gap-1", children: [
|
|
178
|
+
d.kind && d.tone === "action" && /* @__PURE__ */ jsx(MetaChip, { children: d.kind }),
|
|
179
|
+
model && /* @__PURE__ */ jsx(MetaChip, { children: model }),
|
|
180
|
+
cost && /* @__PURE__ */ jsx(MetaChip, { children: cost }),
|
|
181
|
+
duration && /* @__PURE__ */ jsx(MetaChip, { children: duration }),
|
|
182
|
+
tokens && /* @__PURE__ */ jsx(MetaChip, { children: tokens })
|
|
183
|
+
] }),
|
|
184
|
+
state?.status === "failed" && errorText && /* @__PURE__ */ jsx(
|
|
185
|
+
"p",
|
|
186
|
+
{
|
|
187
|
+
className: "mt-1.5 line-clamp-2 text-[10px] text-red-400",
|
|
188
|
+
title: errorText,
|
|
189
|
+
children: errorText
|
|
190
|
+
}
|
|
191
|
+
),
|
|
192
|
+
outputText && state?.status !== "failed" && /* @__PURE__ */ jsx(
|
|
193
|
+
"p",
|
|
194
|
+
{
|
|
195
|
+
className: "mt-1.5 line-clamp-2 text-[10px] text-text-muted",
|
|
196
|
+
title: outputText,
|
|
197
|
+
children: outputText
|
|
198
|
+
}
|
|
199
|
+
),
|
|
200
|
+
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: [
|
|
201
|
+
/* @__PURE__ */ jsx(
|
|
202
|
+
ProviderIcon,
|
|
203
|
+
{
|
|
204
|
+
id: d.provider,
|
|
205
|
+
displayName: providerLabel(d.provider),
|
|
206
|
+
size: 12,
|
|
207
|
+
className: "rounded-[2px]"
|
|
208
|
+
}
|
|
209
|
+
),
|
|
210
|
+
providerLabel(d.provider)
|
|
211
|
+
] }),
|
|
212
|
+
/* @__PURE__ */ jsx(
|
|
213
|
+
Handle,
|
|
214
|
+
{
|
|
215
|
+
type: "source",
|
|
216
|
+
id: "out",
|
|
217
|
+
position: Position.Bottom,
|
|
218
|
+
className: HANDLE_CLASS
|
|
219
|
+
}
|
|
220
|
+
),
|
|
221
|
+
d.hasBranches && /* @__PURE__ */ jsx(
|
|
222
|
+
Handle,
|
|
223
|
+
{
|
|
224
|
+
type: "source",
|
|
225
|
+
id: "branch",
|
|
226
|
+
position: Position.Right,
|
|
227
|
+
className: HANDLE_CLASS
|
|
228
|
+
}
|
|
229
|
+
)
|
|
230
|
+
]
|
|
231
|
+
}
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
var NODE_TYPES = { wfNode: WorkflowNode };
|
|
235
|
+
function WorkflowGraph({
|
|
236
|
+
yaml,
|
|
237
|
+
variant = "full",
|
|
238
|
+
className,
|
|
239
|
+
nodeState,
|
|
240
|
+
onNodeClick
|
|
241
|
+
}) {
|
|
242
|
+
const colorMode = useColorMode();
|
|
243
|
+
const { nodes, edges, error } = useMemo(
|
|
244
|
+
() => buildFlowGraph(yaml, nodeState),
|
|
245
|
+
[yaml, nodeState]
|
|
246
|
+
);
|
|
247
|
+
const handleNodeClick = useCallback(
|
|
248
|
+
(_event, node) => {
|
|
249
|
+
onNodeClick?.(node.id, node.data);
|
|
250
|
+
},
|
|
251
|
+
[onNodeClick]
|
|
252
|
+
);
|
|
253
|
+
if (error || nodes.length === 0) {
|
|
254
|
+
return /* @__PURE__ */ jsx(
|
|
255
|
+
"div",
|
|
256
|
+
{
|
|
257
|
+
className: `flex items-center justify-center rounded-lg border border-border border-dashed p-4 text-center text-text-muted text-xs ${className ?? ""}`,
|
|
258
|
+
children: error ?? "Nothing to show"
|
|
259
|
+
}
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
const isPreview = variant === "preview";
|
|
263
|
+
return /* @__PURE__ */ jsx("div", { className: `wf-graph ${className ?? ""}`, children: /* @__PURE__ */ jsxs(
|
|
264
|
+
ReactFlow,
|
|
265
|
+
{
|
|
266
|
+
nodes,
|
|
267
|
+
edges,
|
|
268
|
+
nodeTypes: NODE_TYPES,
|
|
269
|
+
colorMode,
|
|
270
|
+
onNodeClick: onNodeClick ? handleNodeClick : void 0,
|
|
271
|
+
fitView: true,
|
|
272
|
+
fitViewOptions: { padding: 0.2 },
|
|
273
|
+
proOptions: { hideAttribution: true },
|
|
274
|
+
nodesDraggable: !isPreview,
|
|
275
|
+
nodesConnectable: false,
|
|
276
|
+
elementsSelectable: !isPreview,
|
|
277
|
+
edgesFocusable: false,
|
|
278
|
+
zoomOnScroll: false,
|
|
279
|
+
zoomOnPinch: true,
|
|
280
|
+
zoomOnDoubleClick: !isPreview,
|
|
281
|
+
panOnDrag: true,
|
|
282
|
+
preventScrolling: false,
|
|
283
|
+
minZoom: 0.2,
|
|
284
|
+
maxZoom: 1.5,
|
|
285
|
+
children: [
|
|
286
|
+
/* @__PURE__ */ jsx(Background, { gap: 16 }),
|
|
287
|
+
/* @__PURE__ */ jsx(Controls, { showInteractive: false, position: "bottom-right" })
|
|
288
|
+
]
|
|
289
|
+
}
|
|
290
|
+
) });
|
|
291
|
+
}
|
|
292
|
+
export {
|
|
293
|
+
WorkflowGraph,
|
|
294
|
+
WorkflowNode
|
|
295
|
+
};
|
|
@@ -21,6 +21,16 @@ function urlHost(url) {
|
|
|
21
21
|
return url;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
function pickDetail(cfg, keys) {
|
|
25
|
+
const out = {};
|
|
26
|
+
for (const key of keys) {
|
|
27
|
+
const v = cfg[key];
|
|
28
|
+
if (v === void 0 || v === null) continue;
|
|
29
|
+
const text = typeof v === "string" ? v : typeof v === "number" || typeof v === "boolean" ? String(v) : Array.isArray(v) ? `${v.length} item${v.length === 1 ? "" : "s"}` : "\u2026";
|
|
30
|
+
out[key] = text.length > 200 ? `${text.slice(0, 200)}\u2026` : text;
|
|
31
|
+
}
|
|
32
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
33
|
+
}
|
|
24
34
|
function describeAction(action) {
|
|
25
35
|
const rec = asRecord(action);
|
|
26
36
|
const [kind] = Object.keys(rec);
|
|
@@ -29,7 +39,9 @@ function describeAction(action) {
|
|
|
29
39
|
case "sandbox.spawn":
|
|
30
40
|
return {
|
|
31
41
|
title: "Spawn sandbox",
|
|
42
|
+
kind,
|
|
32
43
|
subtitle: str(cfg.template),
|
|
44
|
+
detail: pickDetail(cfg, ["template", "size", "region"]),
|
|
33
45
|
hasBranches: false,
|
|
34
46
|
isRoot: false,
|
|
35
47
|
tone: "action"
|
|
@@ -38,8 +50,11 @@ function describeAction(action) {
|
|
|
38
50
|
const path = str(cfg.path);
|
|
39
51
|
return {
|
|
40
52
|
title: "Integration",
|
|
53
|
+
kind,
|
|
41
54
|
subtitle: path,
|
|
55
|
+
path,
|
|
42
56
|
provider: path?.split(".")[0],
|
|
57
|
+
detail: pickDetail(cfg, ["path"]),
|
|
43
58
|
hasBranches: false,
|
|
44
59
|
isRoot: false,
|
|
45
60
|
tone: "action"
|
|
@@ -49,7 +64,9 @@ function describeAction(action) {
|
|
|
49
64
|
const url = str(cfg.url);
|
|
50
65
|
return {
|
|
51
66
|
title: "Notify",
|
|
67
|
+
kind,
|
|
52
68
|
subtitle: url ? urlHost(url) : void 0,
|
|
69
|
+
detail: pickDetail(cfg, ["url"]),
|
|
53
70
|
hasBranches: false,
|
|
54
71
|
isRoot: false,
|
|
55
72
|
tone: "action"
|
|
@@ -58,7 +75,16 @@ function describeAction(action) {
|
|
|
58
75
|
case "agent.run":
|
|
59
76
|
return {
|
|
60
77
|
title: "Run agent",
|
|
78
|
+
kind,
|
|
61
79
|
subtitle: str(cfg.model) ?? str(cfg.profile) ?? str(cfg.prompt),
|
|
80
|
+
model: str(cfg.model),
|
|
81
|
+
detail: pickDetail(cfg, [
|
|
82
|
+
"profile",
|
|
83
|
+
"model",
|
|
84
|
+
"maxRounds",
|
|
85
|
+
"size",
|
|
86
|
+
"prompt"
|
|
87
|
+
]),
|
|
62
88
|
hasBranches: false,
|
|
63
89
|
isRoot: false,
|
|
64
90
|
tone: "action"
|
|
@@ -67,6 +93,7 @@ function describeAction(action) {
|
|
|
67
93
|
const branches = Array.isArray(cfg.branches) ? cfg.branches : [];
|
|
68
94
|
return {
|
|
69
95
|
title: "Parallel",
|
|
96
|
+
kind,
|
|
70
97
|
subtitle: `${branches.length} branch${branches.length === 1 ? "" : "es"}`,
|
|
71
98
|
badge: branches.length > 0 ? `\xD7${branches.length}` : void 0,
|
|
72
99
|
hasBranches: branches.length > 0,
|
|
@@ -77,7 +104,9 @@ function describeAction(action) {
|
|
|
77
104
|
case "foreach":
|
|
78
105
|
return {
|
|
79
106
|
title: "For each",
|
|
107
|
+
kind,
|
|
80
108
|
subtitle: typeof cfg.items === "string" ? cfg.items : "list",
|
|
109
|
+
detail: pickDetail(cfg, ["items"]),
|
|
81
110
|
// Only fans out when a `do` template is actually present.
|
|
82
111
|
hasBranches: Boolean(cfg.do),
|
|
83
112
|
isRoot: false,
|
|
@@ -86,6 +115,7 @@ function describeAction(action) {
|
|
|
86
115
|
default:
|
|
87
116
|
return {
|
|
88
117
|
title: kind ? kind : "Action",
|
|
118
|
+
kind: kind ?? "action",
|
|
89
119
|
hasBranches: false,
|
|
90
120
|
isRoot: false,
|
|
91
121
|
tone: "action"
|
|
@@ -106,6 +136,7 @@ function describeTrigger(on) {
|
|
|
106
136
|
if (repo) subtitle += ` on ${repo}`;
|
|
107
137
|
return {
|
|
108
138
|
title: "Trigger",
|
|
139
|
+
kind: "provider_event",
|
|
109
140
|
subtitle,
|
|
110
141
|
provider: connection,
|
|
111
142
|
hasBranches: false,
|
|
@@ -119,6 +150,7 @@ function describeTrigger(on) {
|
|
|
119
150
|
const tz = str(sch.timezone);
|
|
120
151
|
return {
|
|
121
152
|
title: "Schedule",
|
|
153
|
+
kind: "schedule",
|
|
122
154
|
subtitle: cron ? tz ? `${cron} (${tz})` : cron : void 0,
|
|
123
155
|
hasBranches: false,
|
|
124
156
|
isRoot: true,
|
|
@@ -127,6 +159,7 @@ function describeTrigger(on) {
|
|
|
127
159
|
}
|
|
128
160
|
return {
|
|
129
161
|
title: "Trigger",
|
|
162
|
+
kind: "trigger",
|
|
130
163
|
hasBranches: false,
|
|
131
164
|
isRoot: true,
|
|
132
165
|
tone: "trigger"
|
|
@@ -1516,7 +1516,7 @@ function PlanCards({ plans, className }) {
|
|
|
1516
1516
|
|
|
1517
1517
|
// src/dashboard/dashboard-layout.tsx
|
|
1518
1518
|
import * as React7 from "react";
|
|
1519
|
-
import { Plus as Plus2, Bell } from "lucide-react";
|
|
1519
|
+
import { Plus as Plus2, Bell, ChevronsLeft, ChevronsRight } from "lucide-react";
|
|
1520
1520
|
import { Fragment as Fragment9, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1521
1521
|
function SettingsIconSmall({ className }) {
|
|
1522
1522
|
return /* @__PURE__ */ jsxs13("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
@@ -1571,6 +1571,7 @@ function DashboardLayoutInner({
|
|
|
1571
1571
|
contentClassName,
|
|
1572
1572
|
topNavLinks,
|
|
1573
1573
|
activeTopNavHref,
|
|
1574
|
+
topBarLeading,
|
|
1574
1575
|
LinkComponent = DefaultLink2,
|
|
1575
1576
|
logoHref = "/",
|
|
1576
1577
|
onLogoClick,
|
|
@@ -1621,16 +1622,29 @@ function DashboardLayoutInner({
|
|
|
1621
1622
|
className: "p-1 rounded-md transition-colors hover:bg-surface-container-high",
|
|
1622
1623
|
children: /* @__PURE__ */ jsx14(Logo, { variant, size: "sm", iconOnly: true })
|
|
1623
1624
|
}
|
|
1624
|
-
) :
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1625
|
+
) : allowCollapse ? (
|
|
1626
|
+
// The logo IS the collapse/expand control on the desktop rail
|
|
1627
|
+
// (allowCollapse). The mobile drawer never collapses, so it falls
|
|
1628
|
+
// through to the plain logo link. Expanded: full logotype with a
|
|
1629
|
+
// collapse chevron that fades in on hover. Collapsed: the mark,
|
|
1630
|
+
// with an expand chevron overlay on hover.
|
|
1631
|
+
/* @__PURE__ */ jsxs13(
|
|
1632
|
+
"button",
|
|
1633
|
+
{
|
|
1634
|
+
type: "button",
|
|
1635
|
+
onClick: toggleRail,
|
|
1636
|
+
"aria-label": railCollapsed ? "Expand navigation" : "Collapse navigation",
|
|
1637
|
+
"aria-expanded": !railCollapsed,
|
|
1638
|
+
className: cn(
|
|
1639
|
+
"group/logo relative flex items-center gap-2 rounded-md p-1 transition-colors hover:bg-surface-container-high",
|
|
1640
|
+
showLabels && "w-full"
|
|
1641
|
+
),
|
|
1642
|
+
children: [
|
|
1643
|
+
/* @__PURE__ */ jsx14(Logo, { variant, size: "sm", iconOnly: !showLabels }),
|
|
1644
|
+
showLabels ? /* @__PURE__ */ jsx14(ChevronsLeft, { className: "ml-auto h-4 w-4 shrink-0 text-muted-foreground opacity-0 transition-opacity group-hover/logo:opacity-100" }) : /* @__PURE__ */ jsx14("span", { className: "absolute inset-0 flex items-center justify-center rounded-md bg-surface-container-high opacity-0 transition-opacity group-hover/logo:opacity-100", children: /* @__PURE__ */ jsx14(ChevronsRight, { className: "h-4 w-4 text-foreground" }) })
|
|
1645
|
+
]
|
|
1646
|
+
}
|
|
1647
|
+
)
|
|
1634
1648
|
) : /* @__PURE__ */ jsx14(
|
|
1635
1649
|
Link,
|
|
1636
1650
|
{
|
|
@@ -1674,18 +1688,39 @@ function DashboardLayoutInner({
|
|
|
1674
1688
|
] }, item.id);
|
|
1675
1689
|
}) }),
|
|
1676
1690
|
/* @__PURE__ */ jsxs13(SidebarRailFooter, { className: cn(showLabels && "items-stretch px-2"), children: [
|
|
1677
|
-
allowCollapse && /* @__PURE__ */ jsx14(
|
|
1678
|
-
RailCollapseToggle,
|
|
1679
|
-
{
|
|
1680
|
-
collapsed: railCollapsed,
|
|
1681
|
-
showLabel: showLabels,
|
|
1682
|
-
onToggle: toggleRail
|
|
1683
|
-
}
|
|
1684
|
-
),
|
|
1685
1691
|
onSettingsClick ? /* @__PURE__ */ jsx14(RailButton, { icon: SettingsIconSmall, label: "Settings", onClick: onSettingsClick, showLabel: showLabels }) : /* @__PURE__ */ jsx14(RailButton, { icon: SettingsIconSmall, label: "Settings", showLabel: showLabels, asChild: true, children: /* @__PURE__ */ jsx14(Link, { href: settingsHref, to: settingsHref }) }),
|
|
1686
|
-
railFooter,
|
|
1687
1692
|
/* @__PURE__ */ jsx14(RailSeparator, { className: showLabels ? "w-full" : void 0 }),
|
|
1688
|
-
/* @__PURE__ */
|
|
1693
|
+
railFooter !== void 0 ? showLabels ? /* @__PURE__ */ jsxs13("div", { className: "flex w-full items-center gap-1", children: [
|
|
1694
|
+
/* @__PURE__ */ jsx14("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx14(
|
|
1695
|
+
ProfileAvatar,
|
|
1696
|
+
{
|
|
1697
|
+
user: sidebarUser,
|
|
1698
|
+
isLoading,
|
|
1699
|
+
onLogout,
|
|
1700
|
+
onSettingsClick,
|
|
1701
|
+
settingsHref,
|
|
1702
|
+
showDetails: showLabels,
|
|
1703
|
+
LinkComponent,
|
|
1704
|
+
children: profileMenuItems
|
|
1705
|
+
}
|
|
1706
|
+
) }),
|
|
1707
|
+
/* @__PURE__ */ jsx14("div", { className: "shrink-0", children: railFooter })
|
|
1708
|
+
] }) : /* @__PURE__ */ jsxs13("div", { className: "flex flex-col items-center gap-1", children: [
|
|
1709
|
+
railFooter,
|
|
1710
|
+
/* @__PURE__ */ jsx14(
|
|
1711
|
+
ProfileAvatar,
|
|
1712
|
+
{
|
|
1713
|
+
user: sidebarUser,
|
|
1714
|
+
isLoading,
|
|
1715
|
+
onLogout,
|
|
1716
|
+
onSettingsClick,
|
|
1717
|
+
settingsHref,
|
|
1718
|
+
showDetails: showLabels,
|
|
1719
|
+
LinkComponent,
|
|
1720
|
+
children: profileMenuItems
|
|
1721
|
+
}
|
|
1722
|
+
)
|
|
1723
|
+
] }) : /* @__PURE__ */ jsx14(
|
|
1689
1724
|
ProfileAvatar,
|
|
1690
1725
|
{
|
|
1691
1726
|
user: sidebarUser,
|
|
@@ -1748,6 +1783,7 @@ function DashboardLayoutInner({
|
|
|
1748
1783
|
children: [
|
|
1749
1784
|
/* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-8", children: [
|
|
1750
1785
|
/* @__PURE__ */ jsx14(Link, { href: logoHref, to: logoHref, className: "lg:hidden flex items-center p-1 rounded-md hover:bg-surface-container-high transition-colors", children: /* @__PURE__ */ jsx14(Logo, { variant, size: "sm", iconOnly: true }) }),
|
|
1786
|
+
topBarLeading,
|
|
1751
1787
|
topNavLinks && topNavLinks.length > 0 && /* @__PURE__ */ jsx14("div", { className: "hidden md:flex gap-6", children: topNavLinks.map((link) => /* @__PURE__ */ jsx14(
|
|
1752
1788
|
Link,
|
|
1753
1789
|
{
|
package/dist/dashboard.d.ts
CHANGED
|
@@ -688,6 +688,9 @@ interface DashboardLayoutProps {
|
|
|
688
688
|
contentClassName?: string;
|
|
689
689
|
topNavLinks?: TopNavLink[];
|
|
690
690
|
activeTopNavHref?: string;
|
|
691
|
+
/** Arbitrary content rendered at the leading (left) edge of the top bar —
|
|
692
|
+
* e.g. a workspace/team switcher — so consumers don't need a second bar. */
|
|
693
|
+
topBarLeading?: React.ReactNode;
|
|
691
694
|
LinkComponent?: React.ComponentType<any>;
|
|
692
695
|
/**
|
|
693
696
|
* Where the in-app logo links. Defaults to "/" (backward compatible);
|
package/dist/dashboard.js
CHANGED
package/dist/globals.css
CHANGED
|
@@ -392,6 +392,9 @@
|
|
|
392
392
|
.bottom-1 {
|
|
393
393
|
bottom: calc(var(--spacing) * 1);
|
|
394
394
|
}
|
|
395
|
+
.bottom-1\.5 {
|
|
396
|
+
bottom: calc(var(--spacing) * 1.5);
|
|
397
|
+
}
|
|
395
398
|
.bottom-2 {
|
|
396
399
|
bottom: calc(var(--spacing) * 2);
|
|
397
400
|
}
|
|
@@ -437,6 +440,9 @@
|
|
|
437
440
|
.z-10 {
|
|
438
441
|
z-index: 10;
|
|
439
442
|
}
|
|
443
|
+
.z-20 {
|
|
444
|
+
z-index: 20;
|
|
445
|
+
}
|
|
440
446
|
.z-30 {
|
|
441
447
|
z-index: 30;
|
|
442
448
|
}
|
|
@@ -1915,6 +1921,9 @@
|
|
|
1915
1921
|
.border-foreground {
|
|
1916
1922
|
border-color: var(--color-foreground);
|
|
1917
1923
|
}
|
|
1924
|
+
.border-green-500 {
|
|
1925
|
+
border-color: var(--color-green-500);
|
|
1926
|
+
}
|
|
1918
1927
|
.border-green-500\/30 {
|
|
1919
1928
|
border-color: color-mix(in srgb, oklch(72.3% 0.219 149.579) 30%, transparent);
|
|
1920
1929
|
@supports (color: color-mix(in lab, red, red)) {
|
|
@@ -1960,6 +1969,9 @@
|
|
|
1960
1969
|
border-color: color-mix(in oklab, var(--color-primary) 60%, transparent);
|
|
1961
1970
|
}
|
|
1962
1971
|
}
|
|
1972
|
+
.border-red-500 {
|
|
1973
|
+
border-color: var(--color-red-500);
|
|
1974
|
+
}
|
|
1963
1975
|
.border-red-500\/20 {
|
|
1964
1976
|
border-color: color-mix(in srgb, oklch(63.7% 0.237 25.331) 20%, transparent);
|
|
1965
1977
|
@supports (color: color-mix(in lab, red, red)) {
|
|
@@ -2275,6 +2287,12 @@
|
|
|
2275
2287
|
.bg-green-500 {
|
|
2276
2288
|
background-color: var(--color-green-500);
|
|
2277
2289
|
}
|
|
2290
|
+
.bg-green-600\/10 {
|
|
2291
|
+
background-color: color-mix(in srgb, oklch(62.7% 0.194 149.214) 10%, transparent);
|
|
2292
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
2293
|
+
background-color: color-mix(in oklab, var(--color-green-600) 10%, transparent);
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2278
2296
|
.bg-green-600\/20 {
|
|
2279
2297
|
background-color: color-mix(in srgb, oklch(62.7% 0.194 149.214) 20%, transparent);
|
|
2280
2298
|
@supports (color: color-mix(in lab, red, red)) {
|
|
@@ -3202,6 +3220,9 @@
|
|
|
3202
3220
|
.text-green-400 {
|
|
3203
3221
|
color: var(--color-green-400);
|
|
3204
3222
|
}
|
|
3223
|
+
.text-green-600 {
|
|
3224
|
+
color: var(--color-green-600);
|
|
3225
|
+
}
|
|
3205
3226
|
.text-muted-foreground {
|
|
3206
3227
|
color: var(--color-muted-foreground);
|
|
3207
3228
|
}
|
|
@@ -3455,6 +3476,12 @@
|
|
|
3455
3476
|
--tw-ring-color: color-mix(in oklab, var(--color-primary) 25%, transparent);
|
|
3456
3477
|
}
|
|
3457
3478
|
}
|
|
3479
|
+
.ring-primary\/40 {
|
|
3480
|
+
--tw-ring-color: color-mix(in srgb, hsl(var(--primary)) 40%, transparent);
|
|
3481
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
3482
|
+
--tw-ring-color: color-mix(in oklab, var(--color-primary) 40%, transparent);
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3458
3485
|
.ring-offset-background {
|
|
3459
3486
|
--tw-ring-offset-color: var(--color-background);
|
|
3460
3487
|
}
|
|
@@ -3605,6 +3632,11 @@
|
|
|
3605
3632
|
rotate: 180deg;
|
|
3606
3633
|
}
|
|
3607
3634
|
}
|
|
3635
|
+
.group-focus-within\:opacity-100 {
|
|
3636
|
+
&:is(:where(.group):focus-within *) {
|
|
3637
|
+
opacity: 100%;
|
|
3638
|
+
}
|
|
3639
|
+
}
|
|
3608
3640
|
.group-focus-within\/tip\:translate-x-0 {
|
|
3609
3641
|
&:is(:where(.group\/tip):focus-within *) {
|
|
3610
3642
|
--tw-translate-x: calc(var(--spacing) * 0);
|
|
@@ -3655,6 +3687,13 @@
|
|
|
3655
3687
|
}
|
|
3656
3688
|
}
|
|
3657
3689
|
}
|
|
3690
|
+
.group-hover\/logo\:opacity-100 {
|
|
3691
|
+
&:is(:where(.group\/logo):hover *) {
|
|
3692
|
+
@media (hover: hover) {
|
|
3693
|
+
opacity: 100%;
|
|
3694
|
+
}
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3658
3697
|
.group-hover\/tip\:translate-x-0 {
|
|
3659
3698
|
&:is(:where(.group\/tip):hover *) {
|
|
3660
3699
|
@media (hover: hover) {
|
package/dist/index.js
CHANGED
|
@@ -148,7 +148,7 @@ import {
|
|
|
148
148
|
buildUnifiedPatch,
|
|
149
149
|
computeDiffStats,
|
|
150
150
|
resolveLanguage
|
|
151
|
-
} from "./chunk-
|
|
151
|
+
} from "./chunk-MGIOO3RL.js";
|
|
152
152
|
import {
|
|
153
153
|
FileArtifactPane,
|
|
154
154
|
FilePreview,
|
|
@@ -211,7 +211,7 @@ import {
|
|
|
211
211
|
canAdminSandbox,
|
|
212
212
|
parseInsufficientBalance,
|
|
213
213
|
useSidebar
|
|
214
|
-
} from "./chunk-
|
|
214
|
+
} from "./chunk-RT4MLYYM.js";
|
|
215
215
|
import {
|
|
216
216
|
BillingDashboard,
|
|
217
217
|
InfoPanel,
|
package/dist/integrations.d.ts
CHANGED
|
@@ -60,6 +60,24 @@ interface IntegrationsPanelProps {
|
|
|
60
60
|
* thrown error inline.
|
|
61
61
|
*/
|
|
62
62
|
onDisconnect: (connectionId: string) => void | Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Resolver for a connected app's management page URL. When it returns a URL,
|
|
65
|
+
* the connected tile's body and the overflow menu's "Manage" item become a
|
|
66
|
+
* real link opened in a new tab (so cmd/middle-click and "open in new tab"
|
|
67
|
+
* work). Return undefined to omit Manage for a given connection. Preferred
|
|
68
|
+
* over `onManage` — only fall back to the callback when the URL must be minted
|
|
69
|
+
* imperatively on click (e.g. a one-time token).
|
|
70
|
+
*/
|
|
71
|
+
getManageHref?: (connection: IntegrationConnection) => string | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* Imperative fallback for opening a connected app's management page, used only
|
|
74
|
+
* when `getManageHref` is not supplied (or returns undefined). The consumer is
|
|
75
|
+
* responsible for opening the page (e.g. `window.open(...)`).
|
|
76
|
+
*/
|
|
77
|
+
onManage?: (input: {
|
|
78
|
+
connectionId: string;
|
|
79
|
+
providerId: string;
|
|
80
|
+
}) => void | Promise<void>;
|
|
63
81
|
/** Empty-state message when the catalog hasn't loaded any providers. */
|
|
64
82
|
emptyCatalogLabel?: string;
|
|
65
83
|
/**
|
|
@@ -72,7 +90,7 @@ interface IntegrationsPanelProps {
|
|
|
72
90
|
defaultSort?: IntegrationSort;
|
|
73
91
|
className?: string;
|
|
74
92
|
}
|
|
75
|
-
declare function IntegrationsPanel({ catalog, connections, healthByConnectionId, isLoading, error, onConnect, onDisconnect, emptyCatalogLabel, featuredIds, defaultSort, className, }: IntegrationsPanelProps): react_jsx_runtime.JSX.Element;
|
|
93
|
+
declare function IntegrationsPanel({ catalog, connections, healthByConnectionId, isLoading, error, onConnect, onDisconnect, getManageHref, onManage, emptyCatalogLabel, featuredIds, defaultSort, className, }: IntegrationsPanelProps): react_jsx_runtime.JSX.Element;
|
|
76
94
|
|
|
77
95
|
/**
|
|
78
96
|
* Endpoint contract expected on the consumer app's server (which
|
package/dist/integrations.js
CHANGED
|
@@ -16,10 +16,15 @@ import {
|
|
|
16
16
|
DialogFooter,
|
|
17
17
|
DialogHeader,
|
|
18
18
|
DialogTitle,
|
|
19
|
+
DropdownMenu,
|
|
20
|
+
DropdownMenuContent,
|
|
21
|
+
DropdownMenuItem,
|
|
22
|
+
DropdownMenuSeparator,
|
|
23
|
+
DropdownMenuTrigger,
|
|
19
24
|
EmptyState
|
|
20
25
|
} from "@tangle-network/ui/primitives";
|
|
21
26
|
import { cn } from "@tangle-network/ui/utils";
|
|
22
|
-
import { Check, Search, Unplug } from "lucide-react";
|
|
27
|
+
import { Check, ExternalLink, MoreVertical, Search, Unplug } from "lucide-react";
|
|
23
28
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
24
29
|
var DEFAULT_FEATURED_IDS = [
|
|
25
30
|
"gmail",
|
|
@@ -99,6 +104,8 @@ function IntegrationsPanel({
|
|
|
99
104
|
error,
|
|
100
105
|
onConnect,
|
|
101
106
|
onDisconnect,
|
|
107
|
+
getManageHref,
|
|
108
|
+
onManage,
|
|
102
109
|
emptyCatalogLabel = "No integrations available yet.",
|
|
103
110
|
featuredIds = DEFAULT_FEATURED_IDS,
|
|
104
111
|
defaultSort = "featured",
|
|
@@ -252,6 +259,8 @@ function IntegrationsPanel({
|
|
|
252
259
|
const name = displayNameOf(provider);
|
|
253
260
|
const connected = Boolean(live);
|
|
254
261
|
if (connected && live) {
|
|
262
|
+
const manageHref = getManageHref?.(live);
|
|
263
|
+
const canManage = Boolean(manageHref) || Boolean(onManage);
|
|
255
264
|
return /* @__PURE__ */ jsxs(
|
|
256
265
|
"div",
|
|
257
266
|
{
|
|
@@ -259,56 +268,118 @@ function IntegrationsPanel({
|
|
|
259
268
|
"data-connected": "true",
|
|
260
269
|
title: live.accountDisplay ? `${name} \u2014 ${live.accountDisplay}` : name,
|
|
261
270
|
className: cn(
|
|
262
|
-
"relative flex aspect-square flex-col items-center justify-center gap-2 rounded-xl border p-3 text-center",
|
|
271
|
+
"group relative flex aspect-square flex-col items-center justify-center gap-2 rounded-xl border p-3 text-center",
|
|
263
272
|
"border-[var(--surface-success-border)] bg-[var(--surface-success-bg)]"
|
|
264
273
|
),
|
|
265
274
|
children: [
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
"button",
|
|
275
|
+
manageHref ? /* @__PURE__ */ jsx(
|
|
276
|
+
"a",
|
|
269
277
|
{
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
"data-testid": `disconnect-${provider.providerId}`,
|
|
277
|
-
"aria-label": `Disconnect ${name}`,
|
|
278
|
-
title: "Disconnect",
|
|
279
|
-
className: "absolute right-1.5 top-1.5 flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground/70 transition-colors hover:bg-background hover:text-foreground focus-visible:bg-background focus-visible:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40",
|
|
280
|
-
children: /* @__PURE__ */ jsx(Unplug, { className: "h-3.5 w-3.5" })
|
|
278
|
+
href: manageHref,
|
|
279
|
+
target: "_blank",
|
|
280
|
+
rel: "noopener noreferrer",
|
|
281
|
+
"aria-label": `Manage ${name} (opens in new window)`,
|
|
282
|
+
"data-testid": `manage-${provider.providerId}`,
|
|
283
|
+
className: "absolute inset-0 z-10 rounded-xl focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/40"
|
|
281
284
|
}
|
|
282
|
-
),
|
|
283
|
-
/* @__PURE__ */ jsx(
|
|
284
|
-
|
|
285
|
-
{
|
|
286
|
-
id: provider.providerId,
|
|
287
|
-
iconUrl: provider.iconUrl,
|
|
288
|
-
displayName: provider.displayName,
|
|
289
|
-
size: LOGO_SIZE,
|
|
290
|
-
className: "rounded-2xl"
|
|
291
|
-
}
|
|
292
|
-
),
|
|
293
|
-
/* @__PURE__ */ jsxs("div", { className: "flex h-8 w-full flex-col justify-center leading-4", children: [
|
|
285
|
+
) : null,
|
|
286
|
+
/* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute left-2 top-2 flex h-4 w-4 items-center justify-center rounded-full bg-[var(--surface-success-text)] text-white", children: /* @__PURE__ */ jsx(Check, { className: "h-3 w-3", strokeWidth: 3 }) }),
|
|
287
|
+
/* @__PURE__ */ jsxs("div", { className: "pointer-events-none flex flex-col items-center gap-2", children: [
|
|
294
288
|
/* @__PURE__ */ jsx(
|
|
295
|
-
|
|
289
|
+
ProviderIcon,
|
|
296
290
|
{
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
291
|
+
id: provider.providerId,
|
|
292
|
+
iconUrl: provider.iconUrl,
|
|
293
|
+
displayName: provider.displayName,
|
|
294
|
+
size: LOGO_SIZE,
|
|
295
|
+
className: "rounded-2xl"
|
|
302
296
|
}
|
|
303
297
|
),
|
|
304
|
-
|
|
305
|
-
|
|
298
|
+
/* @__PURE__ */ jsxs("div", { className: "flex h-8 w-full flex-col justify-center leading-4", children: [
|
|
299
|
+
/* @__PURE__ */ jsx(
|
|
300
|
+
"span",
|
|
301
|
+
{
|
|
302
|
+
className: cn(
|
|
303
|
+
"w-full text-xs font-medium text-foreground",
|
|
304
|
+
live.accountDisplay ? "truncate" : "line-clamp-2"
|
|
305
|
+
),
|
|
306
|
+
children: name
|
|
307
|
+
}
|
|
308
|
+
),
|
|
309
|
+
live.accountDisplay ? /* @__PURE__ */ jsx(
|
|
310
|
+
"span",
|
|
311
|
+
{
|
|
312
|
+
className: "w-full truncate text-[11px] leading-4 text-muted-foreground",
|
|
313
|
+
"data-testid": `account-${provider.providerId}`,
|
|
314
|
+
children: live.accountDisplay
|
|
315
|
+
}
|
|
316
|
+
) : null
|
|
317
|
+
] })
|
|
318
|
+
] }),
|
|
319
|
+
manageHref ? /* @__PURE__ */ jsx(
|
|
320
|
+
ExternalLink,
|
|
321
|
+
{
|
|
322
|
+
"aria-hidden": true,
|
|
323
|
+
className: "pointer-events-none absolute bottom-1.5 right-1.5 h-3.5 w-3.5 text-muted-foreground/70 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100"
|
|
324
|
+
}
|
|
325
|
+
) : null,
|
|
326
|
+
/* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
327
|
+
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
328
|
+
"button",
|
|
306
329
|
{
|
|
307
|
-
|
|
308
|
-
"data-testid": `
|
|
309
|
-
|
|
330
|
+
type: "button",
|
|
331
|
+
"data-testid": `menu-${provider.providerId}`,
|
|
332
|
+
"aria-label": `More actions for ${name}`,
|
|
333
|
+
title: "More actions",
|
|
334
|
+
className: "absolute right-1.5 top-1.5 z-20 flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground/70 transition-colors hover:bg-background hover:text-foreground focus-visible:bg-background focus-visible:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40",
|
|
335
|
+
children: /* @__PURE__ */ jsx(MoreVertical, { className: "h-3.5 w-3.5" })
|
|
310
336
|
}
|
|
311
|
-
)
|
|
337
|
+
) }),
|
|
338
|
+
/* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "min-w-[160px]", children: [
|
|
339
|
+
manageHref ? /* @__PURE__ */ jsx(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
340
|
+
"a",
|
|
341
|
+
{
|
|
342
|
+
href: manageHref,
|
|
343
|
+
target: "_blank",
|
|
344
|
+
rel: "noopener noreferrer",
|
|
345
|
+
"data-testid": `manage-item-${provider.providerId}`,
|
|
346
|
+
children: [
|
|
347
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "mr-2 h-4 w-4" }),
|
|
348
|
+
" Manage"
|
|
349
|
+
]
|
|
350
|
+
}
|
|
351
|
+
) }) : onManage ? /* @__PURE__ */ jsxs(
|
|
352
|
+
DropdownMenuItem,
|
|
353
|
+
{
|
|
354
|
+
"data-testid": `manage-item-${provider.providerId}`,
|
|
355
|
+
onClick: () => onManage({
|
|
356
|
+
connectionId: live.id,
|
|
357
|
+
providerId: provider.providerId
|
|
358
|
+
}),
|
|
359
|
+
children: [
|
|
360
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "mr-2 h-4 w-4" }),
|
|
361
|
+
" Manage"
|
|
362
|
+
]
|
|
363
|
+
}
|
|
364
|
+
) : null,
|
|
365
|
+
canManage ? /* @__PURE__ */ jsx(DropdownMenuSeparator, {}) : null,
|
|
366
|
+
/* @__PURE__ */ jsxs(
|
|
367
|
+
DropdownMenuItem,
|
|
368
|
+
{
|
|
369
|
+
"data-testid": `disconnect-${provider.providerId}`,
|
|
370
|
+
className: "text-destructive focus:text-destructive",
|
|
371
|
+
onClick: () => setDisconnectTarget({
|
|
372
|
+
connectionId: live.id,
|
|
373
|
+
name,
|
|
374
|
+
accountDisplay: live.accountDisplay
|
|
375
|
+
}),
|
|
376
|
+
children: [
|
|
377
|
+
/* @__PURE__ */ jsx(Unplug, { className: "mr-2 h-4 w-4" }),
|
|
378
|
+
" Disconnect"
|
|
379
|
+
]
|
|
380
|
+
}
|
|
381
|
+
)
|
|
382
|
+
] })
|
|
312
383
|
] })
|
|
313
384
|
]
|
|
314
385
|
},
|
package/dist/pages.d.ts
CHANGED
|
@@ -202,7 +202,7 @@ interface ProvisioningConfig {
|
|
|
202
202
|
key: string;
|
|
203
203
|
value: string;
|
|
204
204
|
}[];
|
|
205
|
-
driver: "docker" | "firecracker" | "host-agent
|
|
205
|
+
driver: "docker" | "firecracker" | "host-agent" | "tangle";
|
|
206
206
|
bare: boolean;
|
|
207
207
|
startupScriptIds?: string[];
|
|
208
208
|
}
|
package/dist/styles.css
CHANGED
|
@@ -392,6 +392,9 @@
|
|
|
392
392
|
.bottom-1 {
|
|
393
393
|
bottom: calc(var(--spacing) * 1);
|
|
394
394
|
}
|
|
395
|
+
.bottom-1\.5 {
|
|
396
|
+
bottom: calc(var(--spacing) * 1.5);
|
|
397
|
+
}
|
|
395
398
|
.bottom-2 {
|
|
396
399
|
bottom: calc(var(--spacing) * 2);
|
|
397
400
|
}
|
|
@@ -437,6 +440,9 @@
|
|
|
437
440
|
.z-10 {
|
|
438
441
|
z-index: 10;
|
|
439
442
|
}
|
|
443
|
+
.z-20 {
|
|
444
|
+
z-index: 20;
|
|
445
|
+
}
|
|
440
446
|
.z-30 {
|
|
441
447
|
z-index: 30;
|
|
442
448
|
}
|
|
@@ -1915,6 +1921,9 @@
|
|
|
1915
1921
|
.border-foreground {
|
|
1916
1922
|
border-color: var(--color-foreground);
|
|
1917
1923
|
}
|
|
1924
|
+
.border-green-500 {
|
|
1925
|
+
border-color: var(--color-green-500);
|
|
1926
|
+
}
|
|
1918
1927
|
.border-green-500\/30 {
|
|
1919
1928
|
border-color: color-mix(in srgb, oklch(72.3% 0.219 149.579) 30%, transparent);
|
|
1920
1929
|
@supports (color: color-mix(in lab, red, red)) {
|
|
@@ -1960,6 +1969,9 @@
|
|
|
1960
1969
|
border-color: color-mix(in oklab, var(--color-primary) 60%, transparent);
|
|
1961
1970
|
}
|
|
1962
1971
|
}
|
|
1972
|
+
.border-red-500 {
|
|
1973
|
+
border-color: var(--color-red-500);
|
|
1974
|
+
}
|
|
1963
1975
|
.border-red-500\/20 {
|
|
1964
1976
|
border-color: color-mix(in srgb, oklch(63.7% 0.237 25.331) 20%, transparent);
|
|
1965
1977
|
@supports (color: color-mix(in lab, red, red)) {
|
|
@@ -2275,6 +2287,12 @@
|
|
|
2275
2287
|
.bg-green-500 {
|
|
2276
2288
|
background-color: var(--color-green-500);
|
|
2277
2289
|
}
|
|
2290
|
+
.bg-green-600\/10 {
|
|
2291
|
+
background-color: color-mix(in srgb, oklch(62.7% 0.194 149.214) 10%, transparent);
|
|
2292
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
2293
|
+
background-color: color-mix(in oklab, var(--color-green-600) 10%, transparent);
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2278
2296
|
.bg-green-600\/20 {
|
|
2279
2297
|
background-color: color-mix(in srgb, oklch(62.7% 0.194 149.214) 20%, transparent);
|
|
2280
2298
|
@supports (color: color-mix(in lab, red, red)) {
|
|
@@ -3202,6 +3220,9 @@
|
|
|
3202
3220
|
.text-green-400 {
|
|
3203
3221
|
color: var(--color-green-400);
|
|
3204
3222
|
}
|
|
3223
|
+
.text-green-600 {
|
|
3224
|
+
color: var(--color-green-600);
|
|
3225
|
+
}
|
|
3205
3226
|
.text-muted-foreground {
|
|
3206
3227
|
color: var(--color-muted-foreground);
|
|
3207
3228
|
}
|
|
@@ -3455,6 +3476,12 @@
|
|
|
3455
3476
|
--tw-ring-color: color-mix(in oklab, var(--color-primary) 25%, transparent);
|
|
3456
3477
|
}
|
|
3457
3478
|
}
|
|
3479
|
+
.ring-primary\/40 {
|
|
3480
|
+
--tw-ring-color: color-mix(in srgb, hsl(var(--primary)) 40%, transparent);
|
|
3481
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
3482
|
+
--tw-ring-color: color-mix(in oklab, var(--color-primary) 40%, transparent);
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3458
3485
|
.ring-offset-background {
|
|
3459
3486
|
--tw-ring-offset-color: var(--color-background);
|
|
3460
3487
|
}
|
|
@@ -3605,6 +3632,11 @@
|
|
|
3605
3632
|
rotate: 180deg;
|
|
3606
3633
|
}
|
|
3607
3634
|
}
|
|
3635
|
+
.group-focus-within\:opacity-100 {
|
|
3636
|
+
&:is(:where(.group):focus-within *) {
|
|
3637
|
+
opacity: 100%;
|
|
3638
|
+
}
|
|
3639
|
+
}
|
|
3608
3640
|
.group-focus-within\/tip\:translate-x-0 {
|
|
3609
3641
|
&:is(:where(.group\/tip):focus-within *) {
|
|
3610
3642
|
--tw-translate-x: calc(var(--spacing) * 0);
|
|
@@ -3655,6 +3687,13 @@
|
|
|
3655
3687
|
}
|
|
3656
3688
|
}
|
|
3657
3689
|
}
|
|
3690
|
+
.group-hover\/logo\:opacity-100 {
|
|
3691
|
+
&:is(:where(.group\/logo):hover *) {
|
|
3692
|
+
@media (hover: hover) {
|
|
3693
|
+
opacity: 100%;
|
|
3694
|
+
}
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3658
3697
|
.group-hover\/tip\:translate-x-0 {
|
|
3659
3698
|
&:is(:where(.group\/tip):hover *) {
|
|
3660
3699
|
@media (hover: hover) {
|
package/dist/workbench.js
CHANGED
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
buildUnifiedPatch,
|
|
13
13
|
computeDiffStats,
|
|
14
14
|
resolveLanguage
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-MGIOO3RL.js";
|
|
16
16
|
import "./chunk-3J6FG3FJ.js";
|
|
17
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-RT4MLYYM.js";
|
|
18
18
|
import "./chunk-OMUIPJQZ.js";
|
|
19
19
|
import "./chunk-VIREDUBF.js";
|
|
20
20
|
import "./chunk-77WVVJA4.js";
|
package/dist/workflows.d.ts
CHANGED
|
@@ -12,11 +12,46 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
12
12
|
* so the spine stays a single readable column.
|
|
13
13
|
*/
|
|
14
14
|
type WfNodeTone = "trigger" | "structural" | "action";
|
|
15
|
+
type WfNodeStatus = "queued" | "running" | "succeeded" | "failed";
|
|
16
|
+
/**
|
|
17
|
+
* Live RUN state for one node, supplied by the host (keyed by node id) and
|
|
18
|
+
* merged onto {@link WfNodeData.state} at render time. Absent ⇒ the graph shows
|
|
19
|
+
* the static definition only (the assistant-proposal preview path). Driven from
|
|
20
|
+
* a workflow run's per-action results so the graph animates as the run executes.
|
|
21
|
+
*/
|
|
22
|
+
interface WfNodeState {
|
|
23
|
+
status: WfNodeStatus;
|
|
24
|
+
/** Amount booked for this action, USD. */
|
|
25
|
+
costUsd?: number;
|
|
26
|
+
/** Wall-clock the action took, ms. */
|
|
27
|
+
durationMs?: number;
|
|
28
|
+
/** Model the action actually used (may differ from the requested model). */
|
|
29
|
+
model?: string;
|
|
30
|
+
/** Failure message, when the node failed. */
|
|
31
|
+
error?: string;
|
|
32
|
+
/** Short preview of the action's output (or a failure's partial text). */
|
|
33
|
+
outputPreview?: string;
|
|
34
|
+
/** Input/output token usage, when known. */
|
|
35
|
+
inputTokens?: number;
|
|
36
|
+
outputTokens?: number;
|
|
37
|
+
}
|
|
15
38
|
interface WfNodeData extends Record<string, unknown> {
|
|
16
39
|
/** Headline for the node, e.g. "Run agent". */
|
|
17
40
|
title: string;
|
|
41
|
+
/** The action/trigger kind verbatim, e.g. "agent.run", "schedule". Set on every
|
|
42
|
+
* node `buildWorkflowGraph` produces so a card can label what it is regardless
|
|
43
|
+
* of which subtitle it shows; optional on the type so external consumers
|
|
44
|
+
* constructing `WfNodeData` directly aren't forced to supply it (the render
|
|
45
|
+
* guards its usage). */
|
|
46
|
+
kind?: string;
|
|
18
47
|
/** Secondary detail, e.g. an integration path or a cron expression. */
|
|
19
48
|
subtitle?: string;
|
|
49
|
+
/** Requested model (agent.run), shown as a chip even before a run. */
|
|
50
|
+
model?: string;
|
|
51
|
+
/** `integration.invoke` provider.method path. */
|
|
52
|
+
path?: string;
|
|
53
|
+
/** Notable config fields for the expand drawer (kept small + stringified). */
|
|
54
|
+
detail?: Record<string, string>;
|
|
20
55
|
/** Connector slug (e.g. `github`) for the provider chip, when one applies. */
|
|
21
56
|
provider?: string;
|
|
22
57
|
/** Small corner tag, e.g. "×3" for a parallel fan-out. */
|
|
@@ -26,6 +61,8 @@ interface WfNodeData extends Record<string, unknown> {
|
|
|
26
61
|
/** Whether this node is the spine root (no incoming/target handle). */
|
|
27
62
|
isRoot: boolean;
|
|
28
63
|
tone: WfNodeTone;
|
|
64
|
+
/** Live run state, merged in by the host at render time (never from YAML). */
|
|
65
|
+
state?: WfNodeState;
|
|
29
66
|
}
|
|
30
67
|
interface WfNode {
|
|
31
68
|
id: string;
|
|
@@ -60,8 +97,23 @@ interface WorkflowGraphProps {
|
|
|
60
97
|
variant?: "full" | "preview";
|
|
61
98
|
/** Sizing for the wrapper; the caller controls height. */
|
|
62
99
|
className?: string;
|
|
100
|
+
/**
|
|
101
|
+
* Live per-node run state, keyed by graph node id (`trigger`, `a0`, `a0-b1`).
|
|
102
|
+
* Absent ⇒ the static definition view (the proposal-card preview passes
|
|
103
|
+
* nothing). When present, each node shows its status/cost/duration/output and
|
|
104
|
+
* the running node pulses.
|
|
105
|
+
*
|
|
106
|
+
* Immutability contract: the node memo keys on this object's reference, so the
|
|
107
|
+
* host MUST pass a NEW top-level `nodeState` object whenever any node's state
|
|
108
|
+
* changes (mutating a nested entry in place will not re-render). Building a
|
|
109
|
+
* fresh record each update — e.g. from a poll/SSE tick — satisfies this.
|
|
110
|
+
*/
|
|
111
|
+
nodeState?: Record<string, WfNodeState>;
|
|
112
|
+
/** Click handler for a node (e.g. open a detail drawer). Absent ⇒ nodes are
|
|
113
|
+
* non-interactive on click. */
|
|
114
|
+
onNodeClick?: (nodeId: string, data: WfNodeData) => void;
|
|
63
115
|
}
|
|
64
116
|
|
|
65
117
|
declare function WorkflowGraph(props: WorkflowGraphProps): react_jsx_runtime.JSX.Element;
|
|
66
118
|
|
|
67
|
-
export { type WfEdge, type WfGraph, type WfNode, type WfNodeData, type WfNodeTone, WorkflowGraph as WorkflowGraphLazy, type WorkflowGraphProps, buildWorkflowGraph };
|
|
119
|
+
export { type WfEdge, type WfGraph, type WfNode, type WfNodeData, type WfNodeState, type WfNodeStatus, type WfNodeTone, WorkflowGraph as WorkflowGraphLazy, type WorkflowGraphProps, buildWorkflowGraph };
|
package/dist/workflows.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildWorkflowGraph
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-46VFHJPQ.js";
|
|
4
4
|
import "./chunk-7JLB7UZ3.js";
|
|
5
5
|
import "./chunk-U67V476Y.js";
|
|
6
6
|
|
|
@@ -27,7 +27,7 @@ function retryImport(factory, retries = 2, delayMs = 350) {
|
|
|
27
27
|
function lazyWorkflowGraph() {
|
|
28
28
|
return lazy(
|
|
29
29
|
() => retryImport(
|
|
30
|
-
() => import("./WorkflowGraph-
|
|
30
|
+
() => import("./WorkflowGraph-4JREVTSK.js").then((m) => ({ default: m.WorkflowGraph }))
|
|
31
31
|
)
|
|
32
32
|
);
|
|
33
33
|
}
|
package/package.json
CHANGED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ProviderIcon
|
|
3
|
-
} from "./chunk-GTJ5PSK5.js";
|
|
4
|
-
import {
|
|
5
|
-
buildWorkflowGraph
|
|
6
|
-
} from "./chunk-SUC6ZJZW.js";
|
|
7
|
-
import {
|
|
8
|
-
providerLabel
|
|
9
|
-
} from "./chunk-7JLB7UZ3.js";
|
|
10
|
-
import "./chunk-U67V476Y.js";
|
|
11
|
-
|
|
12
|
-
// src/workflows/WorkflowGraph.tsx
|
|
13
|
-
import {
|
|
14
|
-
Background,
|
|
15
|
-
Controls,
|
|
16
|
-
Handle,
|
|
17
|
-
Position,
|
|
18
|
-
ReactFlow
|
|
19
|
-
} from "@xyflow/react";
|
|
20
|
-
import "@xyflow/react/dist/style.css";
|
|
21
|
-
import { useEffect, useMemo, useState } from "react";
|
|
22
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
23
|
-
function useColorMode() {
|
|
24
|
-
const [mode, setMode] = useState(
|
|
25
|
-
() => typeof document !== "undefined" && document.documentElement.classList.contains("dark") ? "dark" : "light"
|
|
26
|
-
);
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
const el = document.documentElement;
|
|
29
|
-
const update = () => setMode(el.classList.contains("dark") ? "dark" : "light");
|
|
30
|
-
update();
|
|
31
|
-
const observer = new MutationObserver(update);
|
|
32
|
-
observer.observe(el, { attributes: true, attributeFilter: ["class"] });
|
|
33
|
-
return () => observer.disconnect();
|
|
34
|
-
}, []);
|
|
35
|
-
return mode;
|
|
36
|
-
}
|
|
37
|
-
var TONE_CARD = {
|
|
38
|
-
trigger: "border-primary/60 bg-primary/5",
|
|
39
|
-
structural: "border-accent-yellow/50 bg-accent-yellow/5",
|
|
40
|
-
action: "border-border bg-card"
|
|
41
|
-
};
|
|
42
|
-
var TONE_DOT = {
|
|
43
|
-
trigger: "bg-primary",
|
|
44
|
-
structural: "bg-accent-yellow",
|
|
45
|
-
action: "bg-text-muted"
|
|
46
|
-
};
|
|
47
|
-
var HANDLE_CLASS = "!h-2 !w-2 !min-w-0 !border-0 !bg-transparent opacity-0";
|
|
48
|
-
function WorkflowNode({ data }) {
|
|
49
|
-
const d = data;
|
|
50
|
-
return /* @__PURE__ */ jsxs(
|
|
51
|
-
"div",
|
|
52
|
-
{
|
|
53
|
-
className: `relative w-[240px] rounded-lg border px-3 py-2 shadow-sm ${TONE_CARD[d.tone]}`,
|
|
54
|
-
children: [
|
|
55
|
-
!d.isRoot && /* @__PURE__ */ jsx(
|
|
56
|
-
Handle,
|
|
57
|
-
{
|
|
58
|
-
type: "target",
|
|
59
|
-
position: Position.Top,
|
|
60
|
-
className: HANDLE_CLASS
|
|
61
|
-
}
|
|
62
|
-
),
|
|
63
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
64
|
-
/* @__PURE__ */ jsx(
|
|
65
|
-
"span",
|
|
66
|
-
{
|
|
67
|
-
"aria-hidden": "true",
|
|
68
|
-
className: `h-2 w-2 shrink-0 rounded-full ${TONE_DOT[d.tone]}`
|
|
69
|
-
}
|
|
70
|
-
),
|
|
71
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-[12px] text-text", children: d.title }),
|
|
72
|
-
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 })
|
|
73
|
-
] }),
|
|
74
|
-
d.subtitle && /* @__PURE__ */ jsx(
|
|
75
|
-
"p",
|
|
76
|
-
{
|
|
77
|
-
className: "mt-1 truncate text-[11px] text-text-muted",
|
|
78
|
-
title: d.subtitle,
|
|
79
|
-
children: d.subtitle
|
|
80
|
-
}
|
|
81
|
-
),
|
|
82
|
-
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: [
|
|
83
|
-
/* @__PURE__ */ jsx(
|
|
84
|
-
ProviderIcon,
|
|
85
|
-
{
|
|
86
|
-
id: d.provider,
|
|
87
|
-
displayName: providerLabel(d.provider),
|
|
88
|
-
size: 12,
|
|
89
|
-
className: "rounded-[2px]"
|
|
90
|
-
}
|
|
91
|
-
),
|
|
92
|
-
providerLabel(d.provider)
|
|
93
|
-
] }),
|
|
94
|
-
/* @__PURE__ */ jsx(
|
|
95
|
-
Handle,
|
|
96
|
-
{
|
|
97
|
-
type: "source",
|
|
98
|
-
id: "out",
|
|
99
|
-
position: Position.Bottom,
|
|
100
|
-
className: HANDLE_CLASS
|
|
101
|
-
}
|
|
102
|
-
),
|
|
103
|
-
d.hasBranches && /* @__PURE__ */ jsx(
|
|
104
|
-
Handle,
|
|
105
|
-
{
|
|
106
|
-
type: "source",
|
|
107
|
-
id: "branch",
|
|
108
|
-
position: Position.Right,
|
|
109
|
-
className: HANDLE_CLASS
|
|
110
|
-
}
|
|
111
|
-
)
|
|
112
|
-
]
|
|
113
|
-
}
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
var NODE_TYPES = { wfNode: WorkflowNode };
|
|
117
|
-
function WorkflowGraph({
|
|
118
|
-
yaml,
|
|
119
|
-
variant = "full",
|
|
120
|
-
className
|
|
121
|
-
}) {
|
|
122
|
-
const colorMode = useColorMode();
|
|
123
|
-
const { nodes, edges, error } = useMemo(() => {
|
|
124
|
-
const graph = buildWorkflowGraph(yaml);
|
|
125
|
-
return {
|
|
126
|
-
error: graph.error,
|
|
127
|
-
nodes: graph.nodes.map(
|
|
128
|
-
(n) => ({
|
|
129
|
-
id: n.id,
|
|
130
|
-
type: "wfNode",
|
|
131
|
-
position: n.position,
|
|
132
|
-
data: n.data
|
|
133
|
-
})
|
|
134
|
-
),
|
|
135
|
-
edges: graph.edges.map((e) => ({
|
|
136
|
-
id: e.id,
|
|
137
|
-
source: e.source,
|
|
138
|
-
target: e.target,
|
|
139
|
-
sourceHandle: e.sourceHandle,
|
|
140
|
-
type: "smoothstep"
|
|
141
|
-
}))
|
|
142
|
-
};
|
|
143
|
-
}, [yaml]);
|
|
144
|
-
if (error || nodes.length === 0) {
|
|
145
|
-
return /* @__PURE__ */ jsx(
|
|
146
|
-
"div",
|
|
147
|
-
{
|
|
148
|
-
className: `flex items-center justify-center rounded-lg border border-border border-dashed p-4 text-center text-text-muted text-xs ${className ?? ""}`,
|
|
149
|
-
children: error ?? "Nothing to show"
|
|
150
|
-
}
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
const isPreview = variant === "preview";
|
|
154
|
-
return /* @__PURE__ */ jsx("div", { className: `wf-graph ${className ?? ""}`, children: /* @__PURE__ */ jsxs(
|
|
155
|
-
ReactFlow,
|
|
156
|
-
{
|
|
157
|
-
nodes,
|
|
158
|
-
edges,
|
|
159
|
-
nodeTypes: NODE_TYPES,
|
|
160
|
-
colorMode,
|
|
161
|
-
fitView: true,
|
|
162
|
-
fitViewOptions: { padding: 0.2 },
|
|
163
|
-
proOptions: { hideAttribution: true },
|
|
164
|
-
nodesDraggable: !isPreview,
|
|
165
|
-
nodesConnectable: false,
|
|
166
|
-
elementsSelectable: !isPreview,
|
|
167
|
-
edgesFocusable: false,
|
|
168
|
-
zoomOnScroll: false,
|
|
169
|
-
zoomOnPinch: true,
|
|
170
|
-
zoomOnDoubleClick: !isPreview,
|
|
171
|
-
panOnDrag: true,
|
|
172
|
-
preventScrolling: false,
|
|
173
|
-
minZoom: 0.2,
|
|
174
|
-
maxZoom: 1.5,
|
|
175
|
-
children: [
|
|
176
|
-
/* @__PURE__ */ jsx(Background, { gap: 16 }),
|
|
177
|
-
/* @__PURE__ */ jsx(Controls, { showInteractive: false, position: "bottom-right" })
|
|
178
|
-
]
|
|
179
|
-
}
|
|
180
|
-
) });
|
|
181
|
-
}
|
|
182
|
-
export {
|
|
183
|
-
WorkflowGraph
|
|
184
|
-
};
|