@loopstack/loopstack-studio 0.23.0 → 0.23.1

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 (35) hide show
  1. package/dist/components/dynamic-form/Form.js +50 -27
  2. package/dist/components/dynamic-form/InputController.js +3 -1
  3. package/dist/components/dynamic-form/fields/MarkdownViewField.js +20 -0
  4. package/dist/features/code-explorer/components/CodeExplorerTreeNode.js +80 -4
  5. package/dist/features/code-explorer/components/FileTabsBar.js +3 -190
  6. package/dist/features/code-explorer/components/FileTabsBarBase.js +190 -0
  7. package/dist/features/code-explorer/index.js +2 -2
  8. package/dist/features/code-explorer/providers/CodeExplorerProvider.js +2 -162
  9. package/dist/features/code-explorer/utils/fileIcons.js +7 -4
  10. package/dist/features/debug/components/PipelineFlowViewer.js +46 -45
  11. package/dist/features/debug/components/pipeline-flow/WorkflowGraph.js +19 -19
  12. package/dist/features/documents/DocumentRenderer.js +20 -15
  13. package/dist/features/documents/renderers/ClaudeMessage.js +96 -0
  14. package/dist/features/workbench/Workbench.js +64 -80
  15. package/dist/features/workbench/WorkflowItem.js +5 -5
  16. package/dist/features/workbench/components/RemoteFileTabsBar.js +18 -0
  17. package/dist/features/workbench/components/RemoteFileTree.js +90 -0
  18. package/dist/features/workbench/components/WorkbenchFilesPanel.js +60 -0
  19. package/dist/features/workbench/components/WorkbenchFlowPanel.js +2 -2
  20. package/dist/features/workbench/components/WorkbenchIconSidebar.js +37 -29
  21. package/dist/features/workbench/hooks/useWorkflowData.js +4 -4
  22. package/dist/features/workbench/providers/RemoteFileExplorerProvider.js +145 -0
  23. package/dist/features/workbench/providers/WorkbenchLayoutProvider.js +46 -43
  24. package/dist/features/workspaces/components/PipelineForm.js +1 -1
  25. package/dist/features/workspaces/components/WorkspaceHomePage.js +93 -0
  26. package/dist/hooks/useFiles.js +1 -43
  27. package/dist/index.d.ts +6 -0
  28. package/dist/index.js +2 -1
  29. package/dist/node_modules/@xyflow/react/dist/esm/index.js +1 -1
  30. package/dist/pages/PipelineDebugPage.js +1 -1
  31. package/dist/pages/PreviewWorkbenchPage.js +167 -70
  32. package/dist/pages/WorkspacePage.js +102 -50
  33. package/dist/pages/WorkspaceRunsPage.js +71 -0
  34. package/dist/routing/LocalRouter.js +6 -0
  35. package/package.json +2 -2
@@ -7,12 +7,12 @@ import { SidebarMenu, SidebarProvider } from "../components/ui/sidebar.js";
7
7
  import LoadingCentered_default from "../components/feedback/LoadingCentered.js";
8
8
  import ErrorSnackbar_default from "../components/feedback/ErrorSnackbar.js";
9
9
  import { require_enums } from "../packages/contracts/dist/enums/index.js";
10
- import { ReactFlowProvider } from "../node_modules/@xyflow/react/dist/esm/index.js";
11
10
  import { useFetchWorkflowsByPipeline } from "../hooks/useWorkflows.js";
12
- import PipelineFlowViewer_default from "../features/debug/components/PipelineFlowViewer.js";
13
- import "../features/debug/index.js";
14
11
  import WorkflowItem_default from "../features/workbench/WorkflowItem.js";
15
12
  import WorkflowButtons_default from "../features/workbench/components/buttons/WorkflowButtons.js";
13
+ import { ReactFlowProvider } from "../node_modules/@xyflow/react/dist/esm/index.js";
14
+ import PipelineFlowViewer_default from "../features/debug/components/PipelineFlowViewer.js";
15
+ import "../features/debug/index.js";
16
16
  import { useNamespaceTree } from "../hooks/useNamespaceTree.js";
17
17
  import WorkbenchNavigation_default from "../features/workbench/WorkbenchNavigation.js";
18
18
  import PipelineHistoryList_default from "../features/workbench/components/PipelineHistoryList.js";
@@ -21,8 +21,9 @@ import "../features/workbench/index.js";
21
21
  import { c } from "react/compiler-runtime";
22
22
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
23
23
  import { jsx, jsxs } from "react/jsx-runtime";
24
+ import { useQuery } from "@tanstack/react-query";
24
25
  import { useNavigate, useParams } from "react-router-dom";
25
- import { ChevronDown, ChevronRight, ListOrdered, Loader2, Navigation, Play, ScrollText, Workflow } from "lucide-react";
26
+ import { ChevronDown, ChevronRight, ListOrdered, Loader2, Navigation, Play, RefreshCw, ScrollText, Workflow } from "lucide-react";
26
27
  import { formatDistanceToNow } from "date-fns";
27
28
  var import_enums = require_enums(), EMBED_MESSAGE_TYPE = "loopstack:embed:workflow-completed", EMBED_RESIZE_MESSAGE_TYPE = "loopstack:embed:resize", EMBED_NEW_RUN_MESSAGE_TYPE = "loopstack:embed:new-run";
28
29
  function PreviewWorkbenchPage() {
@@ -49,17 +50,17 @@ function PreviewWorkbenchPage() {
49
50
  }), e[3] = t, e[4] = o), o;
50
51
  }
51
52
  function PreviewWorkbenchContent(e) {
52
- let t = c(57), { pipelineId: o, onNewRunSuccess: s } = e, l = useRef(null), [u, d] = useState("output"), [m, y] = useState(!1), b = usePipeline(o), x = useFetchWorkflowsByPipeline(o), C;
53
+ let t = c(61), { pipelineId: o, onNewRunSuccess: s } = e, l = useRef(null), [u, d] = useState("output"), [m, _] = useState(!1), b = usePipeline(o), x = useFetchWorkflowsByPipeline(o), C;
53
54
  t[0] === x.data ? C = t[1] : (C = x.data ?? [], t[0] = x.data, t[1] = C);
54
- let T = C, E = useRef(!1), D = b.data?.workspaceId, ge = useWorkspace(D).data?.blockName, _e = b.data?.blockName, O = usePipelineConfigByName(ge, _e), k, A;
55
- t[2] !== x.data || t[3] !== o ? (k = () => {
55
+ let T = C, E = useRef(!1), _e = b.data?.workspaceId, ve = useWorkspace(_e).data?.blockName, ye = b.data?.blockName, D = usePipelineConfigByName(ve, ye), O, k;
56
+ t[2] !== x.data || t[3] !== o ? (O = () => {
56
57
  !x.data || E.current || x.data.length > 0 && x.data.every(_temp) && window.parent !== window && (E.current = !0, window.parent.postMessage({
57
58
  type: EMBED_MESSAGE_TYPE,
58
59
  pipelineId: o
59
60
  }, window.location.origin));
60
- }, A = [x.data, o], t[2] = x.data, t[3] = o, t[4] = k, t[5] = A) : (k = t[4], A = t[5]), useEffect(k, A);
61
- let j, M;
62
- t[6] === o ? (j = t[7], M = t[8]) : (j = () => {
61
+ }, k = [x.data, o], t[2] = x.data, t[3] = o, t[4] = O, t[5] = k) : (O = t[4], k = t[5]), useEffect(O, k);
62
+ let A, j;
63
+ t[6] === o ? (A = t[7], j = t[8]) : (A = () => {
63
64
  if (window.parent === window || !l.current) return;
64
65
  let e = new ResizeObserver(() => {
65
66
  if (!l.current) return;
@@ -71,66 +72,73 @@ function PreviewWorkbenchContent(e) {
71
72
  }, window.location.origin);
72
73
  });
73
74
  return e.observe(l.current), () => e.disconnect();
74
- }, M = [o], t[6] = o, t[7] = j, t[8] = M), useEffect(j, M);
75
- let N;
76
- t[9] === s ? N = t[10] : (N = (e) => {
77
- y(!1), s(e);
78
- }, t[9] = s, t[10] = N);
79
- let P = N, F = _temp2, I;
80
- t[11] === Symbol.for("react.memo_cache_sentinel") ? (I = {
75
+ }, j = [o], t[6] = o, t[7] = A, t[8] = j), useEffect(A, j);
76
+ let M;
77
+ t[9] === s ? M = t[10] : (M = (e) => {
78
+ _(!1), s(e);
79
+ }, t[9] = s, t[10] = M);
80
+ let N = M, P = _temp2, F;
81
+ t[11] === Symbol.for("react.memo_cache_sentinel") ? (F = {
81
82
  enableDebugMode: !1,
82
83
  showFullMessageHistory: !1
83
- }, t[11] = I) : I = t[11];
84
- let L = I, R;
85
- t[12] === Symbol.for("react.memo_cache_sentinel") ? (R = {
84
+ }, t[11] = F) : F = t[11];
85
+ let I = F, L;
86
+ t[12] === Symbol.for("react.memo_cache_sentinel") ? (L = {
86
87
  value: "output",
87
88
  label: "Output",
88
89
  icon: /* @__PURE__ */ jsx(ScrollText, { className: "h-3.5 w-3.5" })
89
- }, t[12] = R) : R = t[12];
90
- let z;
91
- t[13] === Symbol.for("react.memo_cache_sentinel") ? (z = {
90
+ }, t[12] = L) : L = t[12];
91
+ let R;
92
+ t[13] === Symbol.for("react.memo_cache_sentinel") ? (R = {
92
93
  value: "graph",
93
94
  label: "Graph",
94
95
  icon: /* @__PURE__ */ jsx(Workflow, { className: "h-3.5 w-3.5" })
95
- }, t[13] = z) : z = t[13];
96
+ }, t[13] = R) : R = t[13];
97
+ let z;
98
+ t[14] === Symbol.for("react.memo_cache_sentinel") ? (z = {
99
+ value: "run-log",
100
+ label: "Run Log",
101
+ icon: /* @__PURE__ */ jsx(ListOrdered, { className: "h-3.5 w-3.5" })
102
+ }, t[14] = z) : z = t[14];
96
103
  let B;
97
- t[14] === Symbol.for("react.memo_cache_sentinel") ? (B = [
104
+ t[15] === Symbol.for("react.memo_cache_sentinel") ? (B = [
105
+ L,
98
106
  R,
99
107
  z,
100
108
  {
101
- value: "run-log",
102
- label: "Run Log",
103
- icon: /* @__PURE__ */ jsx(ListOrdered, { className: "h-3.5 w-3.5" })
109
+ value: "logs",
110
+ label: "Logs",
111
+ icon: /* @__PURE__ */ jsx(ScrollText, { className: "h-3.5 w-3.5" })
104
112
  }
105
- ], t[14] = B) : B = t[14];
106
- let V = B, H;
107
- t[15] === u ? H = t[16] : (H = /* @__PURE__ */ jsx("div", {
113
+ ], t[15] = B) : B = t[15];
114
+ let be = B, V;
115
+ t[16] === u ? V = t[17] : (V = /* @__PURE__ */ jsx("div", {
108
116
  className: "bg-background flex items-center rounded-md border p-0.5",
109
- children: V.map((e) => /* @__PURE__ */ jsxs("button", {
117
+ children: be.map((e) => /* @__PURE__ */ jsxs("button", {
110
118
  onClick: () => d(e.value),
111
119
  className: `flex items-center gap-1.5 rounded-sm px-2.5 py-1 text-xs font-medium transition-colors ${u === e.value ? "bg-foreground text-background shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
112
120
  children: [e.icon, e.label]
113
121
  }, e.value))
114
- }), t[15] = u, t[16] = H);
115
- let U;
116
- t[17] === Symbol.for("react.memo_cache_sentinel") ? (U = /* @__PURE__ */ jsxs(Button, {
122
+ }), t[16] = u, t[17] = V);
123
+ let H;
124
+ t[18] === Symbol.for("react.memo_cache_sentinel") ? (H = /* @__PURE__ */ jsxs(Button, {
117
125
  variant: "outline",
118
126
  size: "sm",
119
127
  className: "h-7 gap-1.5",
120
- onClick: () => y(!0),
128
+ onClick: () => _(!0),
121
129
  children: [/* @__PURE__ */ jsx(Play, { className: "h-3 w-3" }), "New Run"]
122
- }), t[17] = U) : U = t[17];
123
- let W;
124
- t[18] === H ? W = t[19] : (W = /* @__PURE__ */ jsxs("div", {
130
+ }), t[18] = H) : H = t[18];
131
+ let U;
132
+ t[19] === V ? U = t[20] : (U = /* @__PURE__ */ jsxs("div", {
125
133
  className: "bg-muted/50 flex h-11 shrink-0 items-center justify-between border-b px-3",
126
- children: [H, U]
127
- }), t[18] = H, t[19] = W);
134
+ children: [V, H]
135
+ }), t[19] = V, t[20] = U);
136
+ let W;
137
+ t[21] === b.error ? W = t[22] : (W = /* @__PURE__ */ jsx(ErrorSnackbar_default, { error: b.error }), t[21] = b.error, t[22] = W);
128
138
  let G;
129
- t[20] === b.error ? G = t[21] : (G = /* @__PURE__ */ jsx(ErrorSnackbar_default, { error: b.error }), t[20] = b.error, t[21] = G);
139
+ t[23] === x.error ? G = t[24] : (G = /* @__PURE__ */ jsx(ErrorSnackbar_default, { error: x.error }), t[23] = x.error, t[24] = G);
130
140
  let K;
131
- t[22] === x.error ? K = t[23] : (K = /* @__PURE__ */ jsx(ErrorSnackbar_default, { error: x.error }), t[22] = x.error, t[23] = K);
132
- let q;
133
- t[24] !== u || t[25] !== b.data || t[26] !== b.isLoading || t[27] !== x.data || t[28] !== x.isLoading ? (q = u === "output" && /* @__PURE__ */ jsx("div", {
141
+ t[25] !== u || t[26] !== b.data || t[27] !== b.isLoading || t[28] !== x.data || t[29] !== x.isLoading ? (K = u === "output" && /* @__PURE__ */ jsx("div", {
134
142
  className: "px-4 py-3",
135
143
  children: /* @__PURE__ */ jsx(LoadingCentered_default, {
136
144
  loading: b.isLoading || x.isLoading,
@@ -141,21 +149,22 @@ function PreviewWorkbenchContent(e) {
141
149
  children: /* @__PURE__ */ jsx(WorkflowItem_default, {
142
150
  pipeline: b.data,
143
151
  workflowId: e.id,
144
- scrollTo: F,
145
- settings: L
152
+ scrollTo: P,
153
+ settings: I
146
154
  })
147
155
  }, e.id)) : null
148
156
  })
149
- }), t[24] = u, t[25] = b.data, t[26] = b.isLoading, t[27] = x.data, t[28] = x.isLoading, t[29] = q) : q = t[29];
150
- let J;
151
- t[30] !== u || t[31] !== b.isLoading || t[32] !== O || t[33] !== x.isLoading || t[34] !== o || t[35] !== T ? (J = u === "graph" && /* @__PURE__ */ jsx("div", {
157
+ }), t[25] = u, t[26] = b.data, t[27] = b.isLoading, t[28] = x.data, t[29] = x.isLoading, t[30] = K) : K = t[30];
158
+ let q;
159
+ t[31] !== u || t[32] !== b.isLoading || t[33] !== D || t[34] !== x.isLoading || t[35] !== o || t[36] !== T ? (q = u === "graph" && /* @__PURE__ */ jsx("div", {
152
160
  className: "h-full",
153
161
  children: /* @__PURE__ */ jsx(LoadingCentered_default, {
154
162
  loading: b.isLoading || x.isLoading,
155
163
  children: T.length > 0 ? /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(PipelineFlowViewer_default, {
156
164
  pipelineId: o,
157
165
  workflows: T,
158
- pipelineConfig: O.data
166
+ pipelineConfig: D.data,
167
+ direction: "TB"
159
168
  }) }) : /* @__PURE__ */ jsx("div", {
160
169
  className: "text-muted-foreground flex h-full items-center justify-center",
161
170
  children: /* @__PURE__ */ jsx("p", {
@@ -164,21 +173,24 @@ function PreviewWorkbenchContent(e) {
164
173
  })
165
174
  })
166
175
  })
167
- }), t[30] = u, t[31] = b.isLoading, t[32] = O, t[33] = x.isLoading, t[34] = o, t[35] = T, t[36] = J) : J = t[36];
168
- let Y;
169
- t[37] !== u || t[38] !== b.data ? (Y = u === "run-log" && /* @__PURE__ */ jsx("div", {
176
+ }), t[31] = u, t[32] = b.isLoading, t[33] = D, t[34] = x.isLoading, t[35] = o, t[36] = T, t[37] = q) : q = t[37];
177
+ let J;
178
+ t[38] !== u || t[39] !== b.data ? (J = u === "run-log" && /* @__PURE__ */ jsx("div", {
170
179
  className: "px-4",
171
180
  children: /* @__PURE__ */ jsx(PipelineHistoryList_default, { pipeline: b.data })
172
- }), t[37] = u, t[38] = b.data, t[39] = Y) : Y = t[39];
173
- let X;
174
- t[40] !== u || t[41] !== o ? (X = u === "navigate" && /* @__PURE__ */ jsx("div", {
181
+ }), t[38] = u, t[39] = b.data, t[40] = J) : J = t[40];
182
+ let Y;
183
+ t[41] !== u || t[42] !== o ? (Y = u === "navigate" && /* @__PURE__ */ jsx("div", {
175
184
  className: "px-4 py-2",
176
185
  children: /* @__PURE__ */ jsx(EmbedNavigationContent, { pipelineId: o })
177
- }), t[40] = u, t[41] = o, t[42] = X) : X = t[42];
186
+ }), t[41] = u, t[42] = o, t[43] = Y) : Y = t[43];
187
+ let X;
188
+ t[44] === u ? X = t[45] : (X = u === "logs" && /* @__PURE__ */ jsx(EmbedLogsContent, {}), t[44] = u, t[45] = X);
178
189
  let Z;
179
- t[43] !== G || t[44] !== K || t[45] !== q || t[46] !== J || t[47] !== Y || t[48] !== X ? (Z = /* @__PURE__ */ jsxs("div", {
190
+ t[46] !== W || t[47] !== G || t[48] !== K || t[49] !== q || t[50] !== J || t[51] !== Y || t[52] !== X ? (Z = /* @__PURE__ */ jsxs("div", {
180
191
  className: "flex-1 overflow-auto",
181
192
  children: [
193
+ W,
182
194
  G,
183
195
  K,
184
196
  q,
@@ -186,23 +198,23 @@ function PreviewWorkbenchContent(e) {
186
198
  Y,
187
199
  X
188
200
  ]
189
- }), t[43] = G, t[44] = K, t[45] = q, t[46] = J, t[47] = Y, t[48] = X, t[49] = Z) : Z = t[49];
201
+ }), t[46] = W, t[47] = G, t[48] = K, t[49] = q, t[50] = J, t[51] = Y, t[52] = X, t[53] = Z) : Z = t[53];
190
202
  let Q;
191
- t[50] !== P || t[51] !== m ? (Q = /* @__PURE__ */ jsx(NewRunDialog, {
203
+ t[54] !== N || t[55] !== m ? (Q = /* @__PURE__ */ jsx(NewRunDialog, {
192
204
  open: m,
193
- onOpenChange: y,
194
- onSuccess: P
195
- }), t[50] = P, t[51] = m, t[52] = Q) : Q = t[52];
205
+ onOpenChange: _,
206
+ onSuccess: N
207
+ }), t[54] = N, t[55] = m, t[56] = Q) : Q = t[56];
196
208
  let $;
197
- return t[53] !== W || t[54] !== Z || t[55] !== Q ? ($ = /* @__PURE__ */ jsxs("div", {
209
+ return t[57] !== U || t[58] !== Z || t[59] !== Q ? ($ = /* @__PURE__ */ jsxs("div", {
198
210
  ref: l,
199
211
  className: "flex h-screen flex-col overflow-hidden",
200
212
  children: [
201
- W,
213
+ U,
202
214
  Z,
203
215
  Q
204
216
  ]
205
- }), t[53] = W, t[54] = Z, t[55] = Q, t[56] = $) : $ = t[56], $;
217
+ }), t[57] = U, t[58] = Z, t[59] = Q, t[60] = $) : $ = t[60], $;
206
218
  }
207
219
  function _temp2() {}
208
220
  function _temp(e) {
@@ -381,12 +393,97 @@ function EmbedWorkflowSection(e) {
381
393
  className: "py-1",
382
394
  children: a
383
395
  }) }), t[24] = a, t[25] = g);
384
- let _;
385
- return t[26] !== h || t[27] !== g ? (_ = /* @__PURE__ */ jsxs(Collapsible, {
396
+ let v;
397
+ return t[26] !== h || t[27] !== g ? (v = /* @__PURE__ */ jsxs(Collapsible, {
386
398
  defaultOpen: !0,
387
399
  className: "group/collapsible",
388
400
  children: [h, g]
389
- }), t[26] = h, t[27] = g, t[28] = _) : _ = t[28], _;
401
+ }), t[26] = h, t[27] = g, t[28] = v) : v = t[28], v;
402
+ }
403
+ function stripAnsi(e) {
404
+ return e.replace(/\x1b\[[0-9;]*m/g, "");
405
+ }
406
+ function LogLine(e) {
407
+ let t = c(14), { line: n, index: r } = e, i, a, o;
408
+ if (t[0] !== n) {
409
+ i = stripAnsi(n);
410
+ let e;
411
+ t[4] === Symbol.for("react.memo_cache_sentinel") ? (e = /\bERROR\b/, t[4] = e) : e = t[4], a = e.test(i), o = /\bWARN\b/.test(i) || /\b(Warning|WARNING|DeprecationWarning)\b/.test(i), t[0] = n, t[1] = i, t[2] = a, t[3] = o;
412
+ } else i = t[1], a = t[2], o = t[3];
413
+ let s = o, l = `group flex border-b border-border/30 hover:bg-accent/30 ${a ? "bg-destructive/5" : s ? "bg-yellow-500/5" : ""}`, u = r + 1, d;
414
+ t[5] === u ? d = t[6] : (d = /* @__PURE__ */ jsx("span", {
415
+ className: "w-10 shrink-0 select-none border-r border-border/30 px-2 py-0.5 text-right text-[10px] text-muted-foreground/50",
416
+ children: u
417
+ }), t[5] = u, t[6] = d);
418
+ let f = `flex-1 px-3 py-0.5 text-[11px] leading-5 font-mono ${a ? "text-destructive" : s ? "text-yellow-600 dark:text-yellow-400" : ""}`, p;
419
+ t[7] !== i || t[8] !== f ? (p = /* @__PURE__ */ jsx("span", {
420
+ className: f,
421
+ children: i
422
+ }), t[7] = i, t[8] = f, t[9] = p) : p = t[9];
423
+ let m;
424
+ return t[10] !== l || t[11] !== d || t[12] !== p ? (m = /* @__PURE__ */ jsxs("div", {
425
+ className: l,
426
+ children: [d, p]
427
+ }), t[10] = l, t[11] = d, t[12] = p, t[13] = m) : m = t[13], m;
428
+ }
429
+ function EmbedLogsContent() {
430
+ let e = useRef(null), t = useQuery({
431
+ queryKey: ["remote-agent-app-logs"],
432
+ queryFn: async () => {
433
+ let e = await fetch("http://localhost:8000/api/v1/app/logs?lines=200", { credentials: "include" });
434
+ if (!e.ok) {
435
+ let t = await e.text();
436
+ throw Error(`Failed to fetch logs (${e.status}): ${t}`);
437
+ }
438
+ return await e.json();
439
+ },
440
+ refetchInterval: 5e3
441
+ });
442
+ useEffect(() => {
443
+ e.current?.scrollIntoView({ behavior: "smooth" });
444
+ }, [t.data]);
445
+ let n = useMemo(() => {
446
+ let e = [];
447
+ return t.data?.stdout && e.push(t.data.stdout), t.data?.stderr && e.push(t.data.stderr), e.join("\n").split("\n").filter((e) => e.length > 0);
448
+ }, [t.data]);
449
+ return /* @__PURE__ */ jsxs("div", {
450
+ className: "flex h-full flex-col",
451
+ children: [/* @__PURE__ */ jsxs("div", {
452
+ className: "flex h-9 shrink-0 items-center justify-between border-b bg-muted/30 px-3",
453
+ children: [/* @__PURE__ */ jsx("span", {
454
+ className: "text-xs font-medium text-muted-foreground",
455
+ children: "Application Logs"
456
+ }), /* @__PURE__ */ jsx("button", {
457
+ onClick: () => void t.refetch(),
458
+ className: `text-muted-foreground hover:text-foreground rounded-md p-1 transition-colors hover:cursor-pointer ${t.isFetching ? "animate-spin" : ""}`,
459
+ children: /* @__PURE__ */ jsx(RefreshCw, { className: "h-3 w-3" })
460
+ })]
461
+ }), /* @__PURE__ */ jsx("div", {
462
+ className: "flex-1 overflow-auto bg-background",
463
+ children: t.isLoading && !t.data ? /* @__PURE__ */ jsx("div", {
464
+ className: "flex justify-center py-8",
465
+ children: /* @__PURE__ */ jsx(Loader2, { className: "text-muted-foreground h-4 w-4 animate-spin" })
466
+ }) : t.error ? /* @__PURE__ */ jsx("div", {
467
+ className: "px-4 py-3",
468
+ children: /* @__PURE__ */ jsxs("p", {
469
+ className: "text-sm text-destructive",
470
+ children: ["Error: ", t.error.message]
471
+ })
472
+ }) : n.length > 0 ? /* @__PURE__ */ jsxs("div", {
473
+ className: "font-mono",
474
+ children: [n.map((e, t) => /* @__PURE__ */ jsx(LogLine, {
475
+ line: e,
476
+ index: t
477
+ }, t)), /* @__PURE__ */ jsx("div", { ref: e })]
478
+ }) : /* @__PURE__ */ jsxs("div", {
479
+ className: "flex flex-col items-center justify-center gap-2 py-8 text-muted-foreground",
480
+ children: [/* @__PURE__ */ jsx(ScrollText, { className: "h-5 w-5" }), /* @__PURE__ */ jsx("span", {
481
+ className: "text-xs",
482
+ children: "No logs available"
483
+ })]
484
+ })
485
+ })]
486
+ });
390
487
  }
391
488
  function EmbedNavigationContent(e) {
392
489
  let t = c(4), { pipelineId: n } = e, r = useNamespaceTree(n);
@@ -1,63 +1,115 @@
1
1
  import { useStudio } from "../providers/StudioProvider.js";
2
+ import { useWorkspaceConfig } from "../hooks/useConfig.js";
2
3
  import { useWorkspace } from "../hooks/useWorkspaces.js";
4
+ import { Button } from "../components/ui/button.js";
3
5
  import MainLayout_default from "../components/layout/MainLayout.js";
4
6
  import ErrorSnackbar_default from "../components/feedback/ErrorSnackbar.js";
5
- import ExecutionTimeline_default from "../features/workspaces/components/ExecutionTimeline.js";
7
+ import WorkspaceHomePage_default from "../features/workspaces/components/WorkspaceHomePage.js";
6
8
  import { c } from "react/compiler-runtime";
7
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
- import { useParams } from "react-router-dom";
9
- import { Home, Loader2 } from "lucide-react";
10
+ import { Link, useParams } from "react-router-dom";
11
+ import { ArrowRight, Home, Loader2 } from "lucide-react";
10
12
  var WorkspacePage_default = () => {
11
- let p = c(31), { router: m } = useStudio(), { workspaceId: h } = useParams(), g = useWorkspace(h), _;
12
- p[0] === m ? _ = p[1] : (_ = m.getDashboard(), p[0] = m, p[1] = _);
13
- let v;
14
- p[2] === Symbol.for("react.memo_cache_sentinel") ? (v = /* @__PURE__ */ jsx(Home, { className: "h-4 w-4" }), p[2] = v) : v = p[2];
15
- let y;
16
- p[3] === _ ? y = p[4] : (y = {
17
- label: "Dashboard",
18
- href: _,
19
- icon: v
20
- }, p[3] = _, p[4] = y);
21
- let b;
22
- p[5] === m ? b = p[6] : (b = m.getWorkspaces(), p[5] = m, p[6] = b);
23
- let x;
24
- p[7] === b ? x = p[8] : (x = {
25
- label: "Workspaces",
26
- href: b
27
- }, p[7] = b, p[8] = x);
28
- let S = g.data?.title ?? "", C;
29
- p[9] === S ? C = p[10] : (C = {
30
- label: S,
31
- current: !0
32
- }, p[9] = S, p[10] = C);
33
- let w;
34
- p[11] !== y || p[12] !== x || p[13] !== C ? (w = [
35
- y,
36
- x,
37
- C
38
- ], p[11] = y, p[12] = x, p[13] = C, p[14] = w) : w = p[14];
39
- let T = w, E = g.data?.title ?? "", D;
40
- p[15] === E ? D = p[16] : (D = /* @__PURE__ */ jsx("h1", {
41
- className: "mb-4 text-3xl font-bold tracking-tight",
42
- children: E
43
- }), p[15] = E, p[16] = D);
13
+ let v = c(49), { router: y } = useStudio(), { workspaceId: b } = useParams(), x = useWorkspace(b), S = useWorkspaceConfig(), C = x.data, w;
14
+ bb0: {
15
+ if (!C || !S.data) {
16
+ w = void 0;
17
+ break bb0;
18
+ }
19
+ let t;
20
+ if (v[0] !== S.data || v[1] !== C) {
21
+ let _;
22
+ v[3] === C ? _ = v[4] : (_ = (t) => t.blockName === C.blockName, v[3] = C, v[4] = _), t = S.data.find(_)?.ui?.actions?.find(_temp), v[0] = S.data, v[1] = C, v[2] = t;
23
+ } else t = v[2];
24
+ w = t;
25
+ }
26
+ let T = w, E;
27
+ v[5] === y ? E = v[6] : (E = y.getDashboard(), v[5] = y, v[6] = E);
28
+ let D;
29
+ v[7] === Symbol.for("react.memo_cache_sentinel") ? (D = /* @__PURE__ */ jsx(Home, { className: "h-4 w-4" }), v[7] = D) : D = v[7];
44
30
  let O;
45
- p[17] === g.isLoading ? O = p[18] : (O = g.isLoading ? /* @__PURE__ */ jsx(Loader2, { className: "h-6 w-6 animate-spin" }) : "", p[17] = g.isLoading, p[18] = O);
31
+ v[8] === E ? O = v[9] : (O = {
32
+ label: "Dashboard",
33
+ href: E,
34
+ icon: D
35
+ }, v[8] = E, v[9] = O);
46
36
  let k;
47
- p[19] === g.error ? k = p[20] : (k = /* @__PURE__ */ jsx(ErrorSnackbar_default, { error: g.error }), p[19] = g.error, p[20] = k);
37
+ v[10] === y ? k = v[11] : (k = y.getWorkspaces(), v[10] = y, v[11] = k);
48
38
  let A;
49
- p[21] === g.data ? A = p[22] : (A = g.data ? /* @__PURE__ */ jsx(ExecutionTimeline_default, { workspace: g.data }) : "", p[21] = g.data, p[22] = A);
50
- let j;
51
- p[23] !== O || p[24] !== k || p[25] !== A || p[26] !== D ? (j = /* @__PURE__ */ jsxs(Fragment, { children: [
52
- D,
39
+ v[12] === k ? A = v[13] : (A = {
40
+ label: "Workspaces",
41
+ href: k
42
+ }, v[12] = k, v[13] = A);
43
+ let j = C?.title ?? "", M;
44
+ v[14] === j ? M = v[15] : (M = {
45
+ label: j,
46
+ current: !0
47
+ }, v[14] = j, v[15] = M);
48
+ let N;
49
+ v[16] !== O || v[17] !== A || v[18] !== M ? (N = [
53
50
  O,
54
- k,
55
- A
56
- ] }), p[23] = O, p[24] = k, p[25] = A, p[26] = D, p[27] = j) : j = p[27];
57
- let M;
58
- return p[28] !== T || p[29] !== j ? (M = /* @__PURE__ */ jsx(MainLayout_default, {
59
- breadcrumbsData: T,
60
- children: j
61
- }), p[28] = T, p[29] = j, p[30] = M) : M = p[30], M;
51
+ A,
52
+ M
53
+ ], v[16] = O, v[17] = A, v[18] = M, v[19] = N) : N = v[19];
54
+ let P = N, F = x.isLoading || S.isLoading, I = C?.title ?? "", L;
55
+ v[20] === I ? L = v[21] : (L = /* @__PURE__ */ jsx("h1", {
56
+ className: "text-3xl font-bold tracking-tight",
57
+ children: I
58
+ }), v[20] = I, v[21] = L);
59
+ let R;
60
+ v[22] !== y || v[23] !== b ? (R = b && /* @__PURE__ */ jsx(Button, {
61
+ variant: "outline",
62
+ size: "sm",
63
+ asChild: !0,
64
+ children: /* @__PURE__ */ jsxs(Link, {
65
+ to: y.getWorkspaceRuns(b),
66
+ children: ["Runs", /* @__PURE__ */ jsx(ArrowRight, { className: "ml-1 h-4 w-4" })]
67
+ })
68
+ }), v[22] = y, v[23] = b, v[24] = R) : R = v[24];
69
+ let z;
70
+ v[25] !== L || v[26] !== R ? (z = /* @__PURE__ */ jsxs("div", {
71
+ className: "mb-4 flex items-center justify-between",
72
+ children: [L, R]
73
+ }), v[25] = L, v[26] = R, v[27] = z) : z = v[27];
74
+ let B;
75
+ v[28] === F ? B = v[29] : (B = F ? /* @__PURE__ */ jsx(Loader2, { className: "h-6 w-6 animate-spin" }) : "", v[28] = F, v[29] = B);
76
+ let V;
77
+ v[30] === x.error ? V = v[31] : (V = /* @__PURE__ */ jsx(ErrorSnackbar_default, { error: x.error }), v[30] = x.error, v[31] = V);
78
+ let H;
79
+ v[32] === S.error ? H = v[33] : (H = /* @__PURE__ */ jsx(ErrorSnackbar_default, { error: S.error }), v[32] = S.error, v[33] = H);
80
+ let U;
81
+ v[34] !== F || v[35] !== y || v[36] !== T || v[37] !== C || v[38] !== b ? (U = C && T ? /* @__PURE__ */ jsx(WorkspaceHomePage_default, {
82
+ workspace: C,
83
+ action: T
84
+ }) : C && !F ? /* @__PURE__ */ jsxs("div", {
85
+ className: "flex flex-col items-center justify-center py-16",
86
+ children: [/* @__PURE__ */ jsx("p", {
87
+ className: "text-muted-foreground mb-4",
88
+ children: "No home page configured for this workspace."
89
+ }), b && /* @__PURE__ */ jsx(Button, {
90
+ variant: "default",
91
+ asChild: !0,
92
+ children: /* @__PURE__ */ jsxs(Link, {
93
+ to: y.getWorkspaceRuns(b),
94
+ children: ["Go to Runs", /* @__PURE__ */ jsx(ArrowRight, { className: "ml-1 h-4 w-4" })]
95
+ })
96
+ })]
97
+ }) : null, v[34] = F, v[35] = y, v[36] = T, v[37] = C, v[38] = b, v[39] = U) : U = v[39];
98
+ let W;
99
+ v[40] !== z || v[41] !== B || v[42] !== V || v[43] !== H || v[44] !== U ? (W = /* @__PURE__ */ jsxs(Fragment, { children: [
100
+ z,
101
+ B,
102
+ V,
103
+ H,
104
+ U
105
+ ] }), v[40] = z, v[41] = B, v[42] = V, v[43] = H, v[44] = U, v[45] = W) : W = v[45];
106
+ let G;
107
+ return v[46] !== P || v[47] !== W ? (G = /* @__PURE__ */ jsx(MainLayout_default, {
108
+ breadcrumbsData: P,
109
+ children: W
110
+ }), v[46] = P, v[47] = W, v[48] = G) : G = v[48], G;
62
111
  };
112
+ function _temp(t) {
113
+ return t.widget === "start-form";
114
+ }
63
115
  export { WorkspacePage_default as default };
@@ -0,0 +1,71 @@
1
+ import { useStudio } from "../providers/StudioProvider.js";
2
+ import { useWorkspace } from "../hooks/useWorkspaces.js";
3
+ import MainLayout_default from "../components/layout/MainLayout.js";
4
+ import ErrorSnackbar_default from "../components/feedback/ErrorSnackbar.js";
5
+ import ExecutionTimeline_default from "../features/workspaces/components/ExecutionTimeline.js";
6
+ import { c } from "react/compiler-runtime";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ import { useParams } from "react-router-dom";
9
+ import { Home, Loader2 } from "lucide-react";
10
+ var WorkspaceRunsPage_default = () => {
11
+ let p = c(36), { router: m } = useStudio(), { workspaceId: h } = useParams(), g = useWorkspace(h), _;
12
+ p[0] === m ? _ = p[1] : (_ = m.getDashboard(), p[0] = m, p[1] = _);
13
+ let v;
14
+ p[2] === Symbol.for("react.memo_cache_sentinel") ? (v = /* @__PURE__ */ jsx(Home, { className: "h-4 w-4" }), p[2] = v) : v = p[2];
15
+ let y;
16
+ p[3] === _ ? y = p[4] : (y = {
17
+ label: "Dashboard",
18
+ href: _,
19
+ icon: v
20
+ }, p[3] = _, p[4] = y);
21
+ let b;
22
+ p[5] === m ? b = p[6] : (b = m.getWorkspaces(), p[5] = m, p[6] = b);
23
+ let x;
24
+ p[7] === b ? x = p[8] : (x = {
25
+ label: "Workspaces",
26
+ href: b
27
+ }, p[7] = b, p[8] = x);
28
+ let S = g.data?.title ?? "", C;
29
+ p[9] !== m || p[10] !== h ? (C = h ? m.getWorkspace(h) : void 0, p[9] = m, p[10] = h, p[11] = C) : C = p[11];
30
+ let w;
31
+ p[12] !== S || p[13] !== C ? (w = {
32
+ label: S,
33
+ href: C
34
+ }, p[12] = S, p[13] = C, p[14] = w) : w = p[14];
35
+ let T;
36
+ p[15] === Symbol.for("react.memo_cache_sentinel") ? (T = {
37
+ label: "Runs",
38
+ current: !0
39
+ }, p[15] = T) : T = p[15];
40
+ let E;
41
+ p[16] !== y || p[17] !== x || p[18] !== w ? (E = [
42
+ y,
43
+ x,
44
+ w,
45
+ T
46
+ ], p[16] = y, p[17] = x, p[18] = w, p[19] = E) : E = p[19];
47
+ let D = E, O = g.data?.title ?? "", k;
48
+ p[20] === O ? k = p[21] : (k = /* @__PURE__ */ jsxs("h1", {
49
+ className: "mb-4 text-3xl font-bold tracking-tight",
50
+ children: [O, " — Runs"]
51
+ }), p[20] = O, p[21] = k);
52
+ let A;
53
+ p[22] === g.isLoading ? A = p[23] : (A = g.isLoading ? /* @__PURE__ */ jsx(Loader2, { className: "h-6 w-6 animate-spin" }) : "", p[22] = g.isLoading, p[23] = A);
54
+ let j;
55
+ p[24] === g.error ? j = p[25] : (j = /* @__PURE__ */ jsx(ErrorSnackbar_default, { error: g.error }), p[24] = g.error, p[25] = j);
56
+ let M;
57
+ p[26] === g.data ? M = p[27] : (M = g.data ? /* @__PURE__ */ jsx(ExecutionTimeline_default, { workspace: g.data }) : "", p[26] = g.data, p[27] = M);
58
+ let N;
59
+ p[28] !== k || p[29] !== A || p[30] !== j || p[31] !== M ? (N = /* @__PURE__ */ jsxs(Fragment, { children: [
60
+ k,
61
+ A,
62
+ j,
63
+ M
64
+ ] }), p[28] = k, p[29] = A, p[30] = j, p[31] = M, p[32] = N) : N = p[32];
65
+ let P;
66
+ return p[33] !== D || p[34] !== N ? (P = /* @__PURE__ */ jsx(MainLayout_default, {
67
+ breadcrumbsData: D,
68
+ children: N
69
+ }), p[33] = D, p[34] = N, p[35] = P) : P = p[35], P;
70
+ };
71
+ export { WorkspaceRunsPage_default as default };
@@ -67,6 +67,12 @@ var LocalRouter = class {
67
67
  async navigateToPipelineNamespace(e, t, n) {
68
68
  await this.navigate(`/workspaces/${e}/pipelines/${t}/namespaces/${n}`);
69
69
  }
70
+ getWorkspaceRuns(e) {
71
+ return `/workspaces/${e}/runs`;
72
+ }
73
+ async navigateToWorkspaceRuns(e) {
74
+ await this.navigate(this.getWorkspaceRuns(e));
75
+ }
70
76
  getEmbedPipeline(e) {
71
77
  return `${this.embedPrefix}/pipelines/${e}`;
72
78
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loopstack/loopstack-studio",
3
- "version": "0.23.0",
3
+ "version": "0.23.1",
4
4
  "repository": "loopstack-ai/loopstack-studio",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -26,7 +26,7 @@
26
26
  "dependencies": {
27
27
  "@fontsource/roboto": "^5.2.10",
28
28
  "@hookform/resolvers": "^5.2.2",
29
- "@loopstack/contracts": "^0.23.0",
29
+ "@loopstack/contracts": "^0.23.1",
30
30
  "@radix-ui/react-accordion": "^1.2.12",
31
31
  "@radix-ui/react-alert-dialog": "^1.1.15",
32
32
  "@radix-ui/react-avatar": "^1.1.11",