@loopstack/loopstack-studio 0.25.2 → 0.26.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.
Files changed (96) hide show
  1. package/dist/api/environments.js +4 -0
  2. package/dist/api/index.js +13 -9
  3. package/dist/app/EnvironmentEmbedRoot.js +29 -19
  4. package/dist/components/data-table/DataList.js +93 -91
  5. package/dist/components/data-table/DataTable.js +128 -126
  6. package/dist/components/feedback/Snackbar.js +1 -1
  7. package/dist/components/layout/StudioSidebar.js +124 -131
  8. package/dist/components/ui/sidebar.js +2 -2
  9. package/dist/components/ui/slider.js +37 -26
  10. package/dist/components/ui-widgets/widgets/SandboxRun.js +16 -14
  11. package/dist/features/code-explorer/components/CodeExplorerTree.js +1 -0
  12. package/dist/features/code-explorer/components/FileContentViewer.js +1 -1
  13. package/dist/features/dashboard/RunItem.js +39 -37
  14. package/dist/features/debug/lib/flow-utils.js +1 -1
  15. package/dist/features/documents/DocumentRenderer.js +59 -58
  16. package/dist/features/documents/renderers/useDocumentTransition.js +29 -24
  17. package/dist/features/feature-registry/FeatureRegistryProvider.js +17 -0
  18. package/dist/features/feature-registry/index.js +1 -0
  19. package/dist/features/file-explorer/api/files.js +7 -0
  20. package/dist/features/file-explorer/components/FileExplorerPanel.js +95 -0
  21. package/dist/features/{workbench/components/RemoteFileTabsBar.js → file-explorer/components/FileTabsBar.js} +4 -4
  22. package/dist/features/{workbench/components/RemoteFileTree.js → file-explorer/components/FileTree.js} +6 -6
  23. package/dist/features/file-explorer/file-explorer-feature.js +12 -0
  24. package/dist/features/file-explorer/hooks/useFileExplorer.js +44 -0
  25. package/dist/features/file-explorer/index.js +2 -0
  26. package/dist/features/file-explorer/providers/FileExplorerProvider.js +112 -0
  27. package/dist/features/oauth/OAuthPromptRenderer.js +162 -132
  28. package/dist/features/runs/Runs.js +1 -1
  29. package/dist/features/secrets/components/WorkbenchSecretsPanel.js +178 -0
  30. package/dist/features/secrets/index.js +1 -0
  31. package/dist/features/{documents → secrets}/renderers/SecretInputRenderer.js +17 -17
  32. package/dist/features/secrets/secrets-feature.js +14 -0
  33. package/dist/features/workbench/Workbench.js +32 -82
  34. package/dist/features/workbench/WorkflowList.js +109 -46
  35. package/dist/features/workbench/components/SidebarPanel.js +155 -0
  36. package/dist/features/workbench/components/WorkbenchEnvironmentPanel.js +82 -0
  37. package/dist/features/workbench/components/WorkbenchIconSidebar.js +128 -60
  38. package/dist/features/workbench/components/WorkbenchPreviewPanel.js +127 -114
  39. package/dist/features/workbench/components/WorkbenchRunsPanel.js +32 -0
  40. package/dist/features/workbench/components/WorkbenchSidebarShell.js +80 -0
  41. package/dist/features/workbench/hooks/useWorkflowData.js +3 -3
  42. package/dist/features/workbench/index.js +3 -2
  43. package/dist/features/workbench/providers/WorkbenchLayoutProvider.js +60 -62
  44. package/dist/features/workspaces/Workspaces.js +1 -1
  45. package/dist/features/workspaces/components/EnvironmentSlotSelector.js +68 -51
  46. package/dist/features/workspaces/components/WorkflowRunForm.js +1 -1
  47. package/dist/features/workspaces/components/WorkspaceHomePage.js +1 -1
  48. package/dist/hooks/useEnvironmentPreviewUrl.js +13 -0
  49. package/dist/hooks/useEnvironments.js +8 -0
  50. package/dist/hooks/useWorkflows.js +28 -26
  51. package/dist/hooks/useWorkspaces.js +28 -26
  52. package/dist/index.d.ts +98 -7
  53. package/dist/index.js +8 -1
  54. package/dist/loopstack-studio.css +1 -1
  55. package/dist/node_modules/@shikijs/core/dist/index.js +105 -643
  56. package/dist/node_modules/@shikijs/engine-oniguruma/dist/index.js +135 -122
  57. package/dist/node_modules/@shikijs/langs/dist/bird2.js +1 -1
  58. package/dist/node_modules/@shikijs/langs/dist/cobol.js +1 -1
  59. package/dist/node_modules/@shikijs/langs/dist/css.js +1 -1
  60. package/dist/node_modules/@shikijs/langs/dist/dart.js +1 -1
  61. package/dist/node_modules/@shikijs/langs/dist/emacs-lisp.js +1 -1
  62. package/dist/node_modules/@shikijs/langs/dist/es-tag-sql.js +1 -1
  63. package/dist/node_modules/@shikijs/langs/dist/go.js +1 -1
  64. package/dist/node_modules/@shikijs/langs/dist/kusto.js +1 -1
  65. package/dist/node_modules/@shikijs/langs/dist/nextflow-groovy.js +1 -1
  66. package/dist/node_modules/@shikijs/langs/dist/php.js +1 -1
  67. package/dist/node_modules/@shikijs/langs/dist/ruby.js +1 -1
  68. package/dist/node_modules/@shikijs/langs/dist/typespec.js +1 -1
  69. package/dist/node_modules/@shikijs/primitive/dist/index.js +538 -0
  70. package/dist/node_modules/@shikijs/themes/dist/horizon-bright.js +1 -1
  71. package/dist/node_modules/@xyflow/react/dist/esm/index.js +1 -1
  72. package/dist/node_modules/shiki/dist/bundle-full.js +6 -5
  73. package/dist/node_modules/shiki/dist/chunk-CtajNgzt.js +15 -0
  74. package/dist/node_modules/shiki/dist/engine-oniguruma.js +5 -0
  75. package/dist/node_modules/shiki/dist/{langs.js → langs-bundle-full-DfKZStlK.js} +1 -1
  76. package/dist/node_modules/shiki/dist/themes.js +1 -1
  77. package/dist/pages/DashboardPage.js +54 -79
  78. package/dist/pages/DebugWorkflowDetailsPage.js +41 -55
  79. package/dist/pages/DebugWorkflowsPage.js +151 -112
  80. package/dist/pages/EmbedWorkbenchPage.js +2 -1
  81. package/dist/pages/PreviewWorkbenchPage.js +77 -59
  82. package/dist/pages/RunsListPage.js +27 -41
  83. package/dist/pages/RunsPage.js +21 -36
  84. package/dist/pages/WorkbenchPage.js +48 -70
  85. package/dist/pages/WorkflowDebugPage.js +65 -79
  86. package/dist/pages/WorkspacePage.js +59 -86
  87. package/dist/pages/WorkspaceRunsPage.js +59 -54
  88. package/dist/pages/WorkspacesPage.js +11 -27
  89. package/dist/providers/StudioPreferencesProvider.js +54 -0
  90. package/package.json +29 -29
  91. package/dist/features/workbench/components/WorkbenchFilesPanel.js +0 -67
  92. package/dist/features/workbench/components/WorkbenchFloatingPanel.js +0 -57
  93. package/dist/features/workbench/components/WorkbenchFlowPanel.js +0 -47
  94. package/dist/features/workbench/components/WorkbenchSecretsPanel.js +0 -182
  95. package/dist/features/workbench/providers/RemoteFileExplorerProvider.js +0 -160
  96. /package/dist/{node_modules → frontend/studio/node_modules}/@dagrejs/dagre/dist/dagre.esm.js +0 -0
@@ -1,5 +1,5 @@
1
1
  import { MarkerType, Position } from "../../../node_modules/@xyflow/system/dist/esm/index.js";
2
- import dagre_esm_default from "../../../node_modules/@dagrejs/dagre/dist/dagre.esm.js";
2
+ import dagre_esm_default from "../../../frontend/studio/node_modules/@dagrejs/dagre/dist/dagre.esm.js";
3
3
  var NODE_WIDTH = 130, NODE_HEIGHT = 70, CONDITION_OPERATORS = {
4
4
  gt: ">",
5
5
  lt: "<",
@@ -1,4 +1,6 @@
1
1
  import CompletionMessagePaper_default from "../../components/messages/CompletionMessagePaper.js";
2
+ import { useFeatureRegistry } from "../feature-registry/FeatureRegistryProvider.js";
3
+ import "../feature-registry/index.js";
2
4
  import OAuthPromptRenderer_default from "../oauth/OAuthPromptRenderer.js";
3
5
  import "../oauth/index.js";
4
6
  import AiMessage_default from "./renderers/AiMessage.js";
@@ -12,83 +14,82 @@ import ErrorMessageRenderer_default from "./renderers/ErrorMessageRenderer.js";
12
14
  import LinkMessageRenderer_default from "./renderers/LinkMessageRenderer.js";
13
15
  import MarkdownMessageRenderer_default from "./renderers/MarkdownMessageRenderer.js";
14
16
  import PlainMessageRenderer_default from "./renderers/PlainMessageRenderer.js";
15
- import SecretInputRenderer_default from "./renderers/SecretInputRenderer.js";
16
17
  import TextPromptRenderer_default from "./renderers/TextPromptRenderer.js";
17
18
  import { c } from "react/compiler-runtime";
18
- import React from "react";
19
+ import React, { useMemo } from "react";
19
20
  import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
20
- var rendererRegistry = new Map([
21
- ["ai-message", ({ document: t, isLastItem: v }) => /* @__PURE__ */ jsx(AiMessage_default, {
22
- document: t,
23
- isLastItem: v
21
+ var coreRendererRegistry = new Map([
22
+ ["ai-message", ({ document: e, isLastItem: _ }) => /* @__PURE__ */ jsx(AiMessage_default, {
23
+ document: e,
24
+ isLastItem: _
24
25
  })],
25
- ["claude-message", ({ document: t, isLastItem: v }) => /* @__PURE__ */ jsx(ClaudeMessage_default, {
26
- document: t,
27
- isLastItem: v
26
+ ["claude-message", ({ document: e, isLastItem: _ }) => /* @__PURE__ */ jsx(ClaudeMessage_default, {
27
+ document: e,
28
+ isLastItem: _
28
29
  })],
29
- ["debug", ({ document: t }) => /* @__PURE__ */ jsx("div", {
30
+ ["debug", ({ document: e }) => /* @__PURE__ */ jsx("div", {
30
31
  className: "mb-4 flex",
31
- children: /* @__PURE__ */ jsx(DocumentDebugRenderer_default, { document: t })
32
+ children: /* @__PURE__ */ jsx(DocumentDebugRenderer_default, { document: e })
32
33
  })],
33
- ["form", ({ parentWorkflow: v, workflow: y, document: b, isActive: x }) => /* @__PURE__ */ jsx(CompletionMessagePaper_default, {
34
+ ["form", ({ parentWorkflow: _, workflow: v, document: y, isActive: b }) => /* @__PURE__ */ jsx(CompletionMessagePaper_default, {
34
35
  role: "document",
35
36
  fullWidth: !0,
36
- timestamp: new Date(b.createdAt),
37
+ timestamp: new Date(y.createdAt),
37
38
  children: /* @__PURE__ */ jsx(DocumentFormRenderer_default, {
38
- parentWorkflow: v,
39
- workflow: y,
40
- document: b,
41
- enabled: x,
42
- viewOnly: !x
39
+ parentWorkflow: _,
40
+ workflow: v,
41
+ document: y,
42
+ enabled: b,
43
+ viewOnly: !b
43
44
  })
44
45
  })],
45
- ["message", ({ document: t }) => /* @__PURE__ */ jsx(DocumentMessageRenderer_default, { document: t })],
46
- ["error", ({ document: t }) => /* @__PURE__ */ jsx(ErrorMessageRenderer_default, { document: t })],
47
- ["plain", ({ document: t }) => /* @__PURE__ */ jsx(PlainMessageRenderer_default, { document: t })],
48
- ["markdown", ({ document: t }) => /* @__PURE__ */ jsx(MarkdownMessageRenderer_default, { document: t })],
49
- ["link", ({ document: t }) => /* @__PURE__ */ jsx(LinkMessageRenderer_default, { document: t })],
50
- ["oauth-prompt", ({ parentWorkflow: t, workflow: y, document: b, isActive: x }) => /* @__PURE__ */ jsx(OAuthPromptRenderer_default, {
51
- parentWorkflow: t,
52
- workflow: y,
53
- document: b,
54
- isActive: x
55
- })],
56
- ["text-prompt", ({ parentWorkflow: t, workflow: v, document: y, isActive: b }) => /* @__PURE__ */ jsx(TextPromptRenderer_default, {
57
- parentWorkflow: t,
58
- workflow: v,
46
+ ["message", ({ document: e }) => /* @__PURE__ */ jsx(DocumentMessageRenderer_default, { document: e })],
47
+ ["error", ({ document: e }) => /* @__PURE__ */ jsx(ErrorMessageRenderer_default, { document: e })],
48
+ ["plain", ({ document: e }) => /* @__PURE__ */ jsx(PlainMessageRenderer_default, { document: e })],
49
+ ["markdown", ({ document: e }) => /* @__PURE__ */ jsx(MarkdownMessageRenderer_default, { document: e })],
50
+ ["link", ({ document: e }) => /* @__PURE__ */ jsx(LinkMessageRenderer_default, { document: e })],
51
+ ["oauth-prompt", ({ parentWorkflow: e, workflow: _, document: y, isActive: b }) => /* @__PURE__ */ jsx(OAuthPromptRenderer_default, {
52
+ parentWorkflow: e,
53
+ workflow: _,
59
54
  document: y,
60
55
  isActive: b
61
56
  })],
62
- ["choices", ({ parentWorkflow: t, workflow: v, document: y, isActive: x }) => /* @__PURE__ */ jsx(ChoicesRenderer_default, {
63
- parentWorkflow: t,
64
- workflow: v,
65
- document: y,
66
- isActive: x
57
+ ["text-prompt", ({ parentWorkflow: e, workflow: _, document: v, isActive: y }) => /* @__PURE__ */ jsx(TextPromptRenderer_default, {
58
+ parentWorkflow: e,
59
+ workflow: _,
60
+ document: v,
61
+ isActive: y
67
62
  })],
68
- ["confirm-prompt", ({ parentWorkflow: t, workflow: v, document: y, isActive: b }) => /* @__PURE__ */ jsx(ConfirmPromptRenderer_default, {
69
- parentWorkflow: t,
70
- workflow: v,
71
- document: y,
72
- isActive: b
63
+ ["choices", ({ parentWorkflow: e, workflow: _, document: v, isActive: y }) => /* @__PURE__ */ jsx(ChoicesRenderer_default, {
64
+ parentWorkflow: e,
65
+ workflow: _,
66
+ document: v,
67
+ isActive: y
73
68
  })],
74
- ["secret-input", ({ parentWorkflow: t, workflow: v, document: y, isActive: b }) => /* @__PURE__ */ jsx(SecretInputRenderer_default, {
75
- parentWorkflow: t,
76
- workflow: v,
77
- document: y,
78
- isActive: b
69
+ ["confirm-prompt", ({ parentWorkflow: e, workflow: _, document: v, isActive: y }) => /* @__PURE__ */ jsx(ConfirmPromptRenderer_default, {
70
+ parentWorkflow: e,
71
+ workflow: _,
72
+ document: v,
73
+ isActive: y
79
74
  })]
80
75
  ]);
81
- function resolveDocumentWidget(t) {
82
- let v = t;
83
- return v?.widgets?.[0]?.widget ? v.widgets[0].widget : v?.form?.widget ? v.form.widget : "form";
76
+ function resolveDocumentWidget(e) {
77
+ let _ = e;
78
+ return _?.widgets?.[0]?.widget ? _.widgets[0].widget : _?.form?.widget ? _.form.widget : "form";
84
79
  }
85
- var DocumentRenderer_default = (t) => {
86
- let v = c(5), y = t.document, b;
87
- if (v[0] !== y.ui) {
88
- let t = resolveDocumentWidget(y.ui);
89
- b = rendererRegistry.get(t), v[0] = y.ui, v[1] = b;
90
- } else b = v[1];
91
- let x = b, S;
92
- return v[2] !== x || v[3] !== t ? (S = /* @__PURE__ */ jsx("div", { children: x ? /* @__PURE__ */ jsx(x, { ...t }) : /* @__PURE__ */ jsx(Fragment$1, { children: "unknown document type" }) }), v[2] = x, v[3] = t, v[4] = S) : S = v[4], S;
80
+ var DocumentRenderer_default = (e) => {
81
+ let v = c(8), y = useFeatureRegistry(), b = e.document, x;
82
+ if (v[0] !== b.ui || v[1] !== y) {
83
+ let e = resolveDocumentWidget(b.ui), _;
84
+ if (v[3] !== y) {
85
+ _ = /* @__PURE__ */ new Map();
86
+ for (let e of y) if (e.documentRenderers) for (let [v, y] of Object.entries(e.documentRenderers)) _.set(v, y);
87
+ v[3] = y, v[4] = _;
88
+ } else _ = v[4];
89
+ let S = _;
90
+ x = coreRendererRegistry.get(e) ?? S.get(e), v[0] = b.ui, v[1] = y, v[2] = x;
91
+ } else x = v[2];
92
+ let S = x, C;
93
+ return v[5] !== S || v[6] !== e ? (C = /* @__PURE__ */ jsx("div", { children: S ? /* @__PURE__ */ jsx(S, { ...e }) : /* @__PURE__ */ jsx(Fragment$1, { children: "unknown document type" }) }), v[5] = S, v[6] = e, v[7] = C) : C = v[7], C;
93
94
  };
94
95
  export { DocumentRenderer_default as default };
@@ -1,30 +1,35 @@
1
1
  import { useRunWorkflow } from "../../../hooks/useProcessor.js";
2
+ import { c } from "react/compiler-runtime";
2
3
  import { useCallback } from "react";
3
4
  function resolveTransition(e) {
4
- let t = e, n = t?.widgets;
5
- return n?.[0]?.options?.transition ? n[0].options.transition : (t?.actions)?.map((e) => e.options?.transition).find((e) => !!e);
5
+ let r = e, i = r?.widgets;
6
+ return i?.[0]?.options?.transition ? i[0].options.transition : (r?.actions)?.map((e) => e.options?.transition).find((e) => !!e);
6
7
  }
7
- function useDocumentTransition(r, i, a) {
8
- let o = useRunWorkflow(), s = i.availableTransitions?.map((e) => e.id) ?? [], c = resolveTransition(a), l = !!c && s.includes(c);
9
- return {
10
- submit: useCallback((e) => {
11
- !c || !l || o.mutate({
12
- workflowId: r.id,
13
- runWorkflowPayloadDto: { transition: {
14
- id: c,
15
- workflowId: i.id,
16
- payload: e
17
- } }
18
- });
19
- }, [
20
- c,
21
- l,
22
- o,
23
- r.id,
24
- i.id
25
- ]),
26
- canSubmit: l,
27
- isLoading: o.isPending
28
- };
8
+ function useDocumentTransition(i, a, o) {
9
+ let s = c(14), l = useRunWorkflow(), u, d;
10
+ if (s[0] !== o || s[1] !== a.availableTransitions) {
11
+ let e = a.availableTransitions?.map(_temp) ?? [];
12
+ d = resolveTransition(o), u = !!d && e.includes(d), s[0] = o, s[1] = a.availableTransitions, s[2] = u, s[3] = d;
13
+ } else u = s[2], d = s[3];
14
+ let f = u, p;
15
+ s[4] !== f || s[5] !== i.id || s[6] !== l || s[7] !== d || s[8] !== a.id ? (p = (e) => {
16
+ !d || !f || l.mutate({
17
+ workflowId: i.id,
18
+ runWorkflowPayloadDto: { transition: {
19
+ id: d,
20
+ workflowId: a.id,
21
+ payload: e
22
+ } }
23
+ });
24
+ }, s[4] = f, s[5] = i.id, s[6] = l, s[7] = d, s[8] = a.id, s[9] = p) : p = s[9];
25
+ let m = p, h;
26
+ return s[10] !== f || s[11] !== l.isPending || s[12] !== m ? (h = {
27
+ submit: m,
28
+ canSubmit: f,
29
+ isLoading: l.isPending
30
+ }, s[10] = f, s[11] = l.isPending, s[12] = m, s[13] = h) : h = s[13], h;
31
+ }
32
+ function _temp(e) {
33
+ return e.id;
29
34
  }
30
35
  export { useDocumentTransition };
@@ -0,0 +1,17 @@
1
+ import { c } from "react/compiler-runtime";
2
+ import { createContext, useContext, useMemo } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ var FeatureRegistryContext = createContext([]);
5
+ function FeatureRegistryProvider(r) {
6
+ let i = c(5), { features: a, children: o } = r, s;
7
+ i[0] === a ? s = i[1] : (s = a === void 0 ? [] : a, i[0] = a, i[1] = s);
8
+ let l = s, u;
9
+ return i[2] !== o || i[3] !== l ? (u = /* @__PURE__ */ jsx(FeatureRegistryContext.Provider, {
10
+ value: l,
11
+ children: o
12
+ }), i[2] = o, i[3] = l, i[4] = u) : u = i[4], u;
13
+ }
14
+ function useFeatureRegistry() {
15
+ return useContext(FeatureRegistryContext);
16
+ }
17
+ export { FeatureRegistryProvider, useFeatureRegistry };
@@ -0,0 +1 @@
1
+ import { FeatureRegistryProvider, useFeatureRegistry } from "./FeatureRegistryProvider.js";
@@ -0,0 +1,7 @@
1
+ function createFilesApi(e) {
2
+ return {
3
+ getTree: (t) => e.get(`/api/v1/workspaces/${t.workspaceId}/files/tree`, { params: t.path ? { path: t.path } : void 0 }).then((e) => e.data),
4
+ readFile: (t) => e.get(`/api/v1/workspaces/${t.workspaceId}/files/read`, { params: { path: t.path } }).then((e) => e.data)
5
+ };
6
+ }
7
+ export { createFilesApi };
@@ -0,0 +1,95 @@
1
+ import { useWorkbenchLayout } from "../../workbench/providers/WorkbenchLayoutProvider.js";
2
+ import { SidebarPanel } from "../../workbench/components/SidebarPanel.js";
3
+ import "../../workbench/index.js";
4
+ import { FileContentViewer } from "../../code-explorer/components/FileContentViewer.js";
5
+ import "../../code-explorer/index.js";
6
+ import { FileExplorerProvider, useOptionalFileExplorer } from "../providers/FileExplorerProvider.js";
7
+ import { FileTabsBar } from "./FileTabsBar.js";
8
+ import { FileTree } from "./FileTree.js";
9
+ import { c } from "react/compiler-runtime";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ import { Files } from "lucide-react";
12
+ function FileExplorerContent() {
13
+ let e = c(7), r = useOptionalFileExplorer();
14
+ if (!r) {
15
+ let r;
16
+ return e[0] === Symbol.for("react.memo_cache_sentinel") ? (r = /* @__PURE__ */ jsx("div", {
17
+ className: "flex flex-1 items-center justify-center p-4",
18
+ children: /* @__PURE__ */ jsx("p", {
19
+ className: "text-muted-foreground text-sm",
20
+ children: "File explorer is not available for this workspace."
21
+ })
22
+ }), e[0] = r) : r = e[0], r;
23
+ }
24
+ let a;
25
+ e[1] === Symbol.for("react.memo_cache_sentinel") ? (a = /* @__PURE__ */ jsx("div", {
26
+ className: "w-52 shrink-0 overflow-auto border-r bg-muted/40",
27
+ children: /* @__PURE__ */ jsx(FileTree, {})
28
+ }), e[1] = a) : a = e[1];
29
+ let d;
30
+ e[2] === Symbol.for("react.memo_cache_sentinel") ? (d = /* @__PURE__ */ jsx(FileTabsBar, {}), e[2] = d) : d = e[2];
31
+ let f;
32
+ return e[3] !== r.fileContent || e[4] !== r.isContentLoading || e[5] !== r.selectedFile ? (f = /* @__PURE__ */ jsxs("div", {
33
+ className: "flex h-full",
34
+ children: [a, /* @__PURE__ */ jsxs("div", {
35
+ className: "flex min-w-0 flex-1 flex-col",
36
+ children: [d, /* @__PURE__ */ jsx("div", {
37
+ className: "flex-1 overflow-hidden p-3 pt-2",
38
+ children: /* @__PURE__ */ jsx(FileContentViewer, {
39
+ selectedFile: r.selectedFile,
40
+ content: r.fileContent,
41
+ isLoading: r.isContentLoading,
42
+ className: "h-full"
43
+ })
44
+ })]
45
+ })]
46
+ }), e[3] = r.fileContent, e[4] = r.isContentLoading, e[5] = r.selectedFile, e[6] = f) : f = e[6], f;
47
+ }
48
+ function FileExplorerPanel(i) {
49
+ let o = c(20), { workspaceId: s } = i, { closePanel: l, panelSize: u, setPanelSize: p, workspaceConfig: m, environments: h } = useWorkbenchLayout(), g;
50
+ o[0] !== h?.[0]?.slotId || o[1] !== m?.features?.fileExplorer?.enabled || o[2] !== m?.features?.fileExplorer?.environments ? (g = (m?.features?.fileExplorer?.enabled && m?.features?.fileExplorer?.environments?.includes(h?.[0]?.slotId ?? "")) ?? !1, o[0] = h?.[0]?.slotId, o[1] = m?.features?.fileExplorer?.enabled, o[2] = m?.features?.fileExplorer?.environments, o[3] = g) : g = o[3];
51
+ let _ = g;
52
+ if (!_) {
53
+ let e;
54
+ o[4] === Symbol.for("react.memo_cache_sentinel") ? (e = /* @__PURE__ */ jsx(Files, { className: "h-4 w-4" }), o[4] = e) : e = o[4];
55
+ let i;
56
+ o[5] === Symbol.for("react.memo_cache_sentinel") ? (i = /* @__PURE__ */ jsx("div", {
57
+ className: "flex flex-1 items-center justify-center p-4",
58
+ children: /* @__PURE__ */ jsx("p", {
59
+ className: "text-muted-foreground text-sm",
60
+ children: "File explorer is not available for this environment."
61
+ })
62
+ }), o[5] = i) : i = o[5];
63
+ let a;
64
+ return o[6] !== l || o[7] !== u || o[8] !== p ? (a = /* @__PURE__ */ jsx(SidebarPanel, {
65
+ icon: e,
66
+ title: "Files",
67
+ description: "Browse remote files.",
68
+ size: u,
69
+ onSizeChange: p,
70
+ onClose: l,
71
+ children: i
72
+ }), o[6] = l, o[7] = u, o[8] = p, o[9] = a) : a = o[9], a;
73
+ }
74
+ let v;
75
+ o[10] === Symbol.for("react.memo_cache_sentinel") ? (v = /* @__PURE__ */ jsx(Files, { className: "h-4 w-4" }), o[10] = v) : v = o[10];
76
+ let y;
77
+ o[11] === Symbol.for("react.memo_cache_sentinel") ? (y = /* @__PURE__ */ jsx(FileExplorerContent, {}), o[11] = y) : y = o[11];
78
+ let b;
79
+ o[12] !== _ || o[13] !== s ? (b = /* @__PURE__ */ jsx(FileExplorerProvider, {
80
+ workspaceId: s,
81
+ enabled: _,
82
+ children: y
83
+ }), o[12] = _, o[13] = s, o[14] = b) : b = o[14];
84
+ let x;
85
+ return o[15] !== l || o[16] !== u || o[17] !== p || o[18] !== b ? (x = /* @__PURE__ */ jsx(SidebarPanel, {
86
+ icon: v,
87
+ title: "Files",
88
+ description: "Browse and view files.",
89
+ size: u,
90
+ onSizeChange: p,
91
+ onClose: l,
92
+ children: b
93
+ }), o[15] = l, o[16] = u, o[17] = p, o[18] = b, o[19] = x) : x = o[19], x;
94
+ }
95
+ export { FileExplorerPanel };
@@ -1,9 +1,9 @@
1
1
  import { FileTabsBarBase } from "../../code-explorer/components/FileTabsBarBase.js";
2
- import { useRemoteFileExplorer } from "../providers/RemoteFileExplorerProvider.js";
2
+ import { useFileExplorer } from "../providers/FileExplorerProvider.js";
3
3
  import { c } from "react/compiler-runtime";
4
4
  import { jsx } from "react/jsx-runtime";
5
- function RemoteFileTabsBar() {
6
- let i = c(9), { openFiles: a, selectedFile: o, selectFile: s, closeFile: l, closeAll: u, closeOthers: d, closeToLeft: f, closeToRight: p } = useRemoteFileExplorer(), m;
5
+ function FileTabsBar() {
6
+ let i = c(9), { openFiles: a, selectedFile: o, selectFile: s, closeFile: l, closeAll: u, closeOthers: d, closeToLeft: f, closeToRight: p } = useFileExplorer(), m;
7
7
  return i[0] !== u || i[1] !== l || i[2] !== d || i[3] !== f || i[4] !== p || i[5] !== a || i[6] !== s || i[7] !== o ? (m = /* @__PURE__ */ jsx(FileTabsBarBase, {
8
8
  openFiles: a,
9
9
  selectedFile: o,
@@ -15,4 +15,4 @@ function RemoteFileTabsBar() {
15
15
  closeToRight: p
16
16
  }), i[0] = u, i[1] = l, i[2] = d, i[3] = f, i[4] = p, i[5] = a, i[6] = s, i[7] = o, i[8] = m) : m = i[8], m;
17
17
  }
18
- export { RemoteFileTabsBar };
18
+ export { FileTabsBar };
@@ -1,12 +1,12 @@
1
1
  import { Button } from "../../../components/ui/button.js";
2
2
  import { ScrollArea } from "../../../components/ui/scroll-area.js";
3
3
  import { CodeExplorerTreeNode } from "../../code-explorer/components/CodeExplorerTreeNode.js";
4
- import { useRemoteFileExplorer } from "../providers/RemoteFileExplorerProvider.js";
4
+ import { useFileExplorer } from "../providers/FileExplorerProvider.js";
5
5
  import { c } from "react/compiler-runtime";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { AlertCircle, Loader2, RefreshCw } from "lucide-react";
8
- var RemoteFileTree_default = () => {
9
- let d = c(35), { nodes: f, isTreeLoading: p, treeError: m, isFetchingTree: h, expandedFolders: g, toggleFolder: _, selectFile: v, closeFile: y, selectedFile: b, refreshTree: x } = useRemoteFileExplorer();
8
+ function FileTree() {
9
+ let d = c(35), { nodes: f, isTreeLoading: p, treeError: m, isFetchingTree: h, expandedFolders: g, toggleFolder: _, selectFile: v, closeFile: y, selectedFile: b, refreshTree: x } = useFileExplorer();
10
10
  if (p) {
11
11
  let e;
12
12
  return d[0] === Symbol.for("react.memo_cache_sentinel") ? (e = /* @__PURE__ */ jsxs("div", {
@@ -77,7 +77,7 @@ var RemoteFileTree_default = () => {
77
77
  children: /* @__PURE__ */ jsx("div", {
78
78
  className: "w-full py-1",
79
79
  role: "tree",
80
- "aria-label": "Remote file tree",
80
+ "aria-label": "File tree",
81
81
  children: T
82
82
  })
83
83
  }), d[30] = T, d[31] = E);
@@ -86,5 +86,5 @@ var RemoteFileTree_default = () => {
86
86
  className: "flex h-full flex-col gap-1.5",
87
87
  children: [w, E]
88
88
  }), d[32] = w, d[33] = E, d[34] = D) : D = d[34], D;
89
- };
90
- export { RemoteFileTree_default as default };
89
+ }
90
+ export { FileTree };
@@ -0,0 +1,12 @@
1
+ import { FileExplorerPanel } from "./components/FileExplorerPanel.js";
2
+ import { Files } from "lucide-react";
3
+ const fileExplorerFeature = {
4
+ id: "file-explorer",
5
+ sidebarPanel: {
6
+ id: "files",
7
+ label: "Files",
8
+ icon: Files,
9
+ component: FileExplorerPanel
10
+ }
11
+ };
12
+ export { fileExplorerFeature };
@@ -0,0 +1,44 @@
1
+ import { useApiClient } from "../../../hooks/useApi.js";
2
+ import { c } from "react/compiler-runtime";
3
+ import { useQuery } from "@tanstack/react-query";
4
+ function useFileTree(r, i) {
5
+ let a = c(10), o = i === void 0 ? !0 : i, { envKey: s, api: l } = useApiClient(), u;
6
+ a[0] !== s || a[1] !== r ? (u = [
7
+ "file-explorer-tree",
8
+ s,
9
+ r
10
+ ], a[0] = s, a[1] = r, a[2] = u) : u = a[2];
11
+ let d;
12
+ a[3] !== l || a[4] !== r ? (d = () => l.files.getTree({ workspaceId: r }), a[3] = l, a[4] = r, a[5] = d) : d = a[5];
13
+ let f = !!r && o, p;
14
+ return a[6] !== u || a[7] !== d || a[8] !== f ? (p = {
15
+ queryKey: u,
16
+ queryFn: d,
17
+ enabled: f,
18
+ staleTime: 3e4,
19
+ retry: !1
20
+ }, a[6] = u, a[7] = d, a[8] = f, a[9] = p) : p = a[9], useQuery(p);
21
+ }
22
+ function useFileContent(r, i, a) {
23
+ let o = c(12), s = a === void 0 ? !0 : a, { envKey: l, api: u } = useApiClient(), d;
24
+ o[0] !== l || o[1] !== i || o[2] !== r ? (d = [
25
+ "file-explorer-content",
26
+ l,
27
+ r,
28
+ i
29
+ ], o[0] = l, o[1] = i, o[2] = r, o[3] = d) : d = o[3];
30
+ let f;
31
+ o[4] !== u || o[5] !== i || o[6] !== r ? (f = () => u.files.readFile({
32
+ workspaceId: r,
33
+ path: i
34
+ }), o[4] = u, o[5] = i, o[6] = r, o[7] = f) : f = o[7];
35
+ let p = !!r && !!i && s, m;
36
+ return o[8] !== d || o[9] !== f || o[10] !== p ? (m = {
37
+ queryKey: d,
38
+ queryFn: f,
39
+ enabled: p,
40
+ staleTime: 15e3,
41
+ retry: !1
42
+ }, o[8] = d, o[9] = f, o[10] = p, o[11] = m) : m = o[11], useQuery(m);
43
+ }
44
+ export { useFileContent, useFileTree };
@@ -0,0 +1,2 @@
1
+ import { FileExplorerProvider, useFileExplorer, useOptionalFileExplorer } from "./providers/FileExplorerProvider.js";
2
+ import { fileExplorerFeature } from "./file-explorer-feature.js";
@@ -0,0 +1,112 @@
1
+ import { useFileContent, useFileTree } from "../hooks/useFileExplorer.js";
2
+ import { c } from "react/compiler-runtime";
3
+ import { createContext, useCallback, useContext, useMemo, useState } from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { useQueryClient } from "@tanstack/react-query";
6
+ var FileExplorerContext = createContext(null);
7
+ function FileExplorerProvider(s) {
8
+ let l = c(36), { workspaceId: u, enabled: d, children: f } = s, p = d === void 0 ? !0 : d, m = useQueryClient(), h;
9
+ l[0] === Symbol.for("react.memo_cache_sentinel") ? (h = /* @__PURE__ */ new Set(), l[0] = h) : h = l[0];
10
+ let [g, _] = useState(h), v;
11
+ l[1] === Symbol.for("react.memo_cache_sentinel") ? (v = [], l[1] = v) : v = l[1];
12
+ let [y, b] = useState(v), [x, S] = useState(null), C = useFileTree(u, p), w = useFileContent(u, x?.type === "file" ? x.path : void 0, p), T;
13
+ l[2] === Symbol.for("react.memo_cache_sentinel") ? (T = (e) => {
14
+ _((a) => {
15
+ let o = new Set(a);
16
+ return o.has(e) ? o.delete(e) : o.add(e), o;
17
+ });
18
+ }, l[2] = T) : T = l[2];
19
+ let E = T, D;
20
+ l[3] === Symbol.for("react.memo_cache_sentinel") ? (D = (e) => {
21
+ e.type === "file" && (S(e), b((a) => a.some((a) => a.path === e.path) ? a : [...a, e]));
22
+ }, l[3] = D) : D = l[3];
23
+ let O = D, k;
24
+ l[4] === x?.path ? k = l[5] : (k = (e) => {
25
+ b((a) => {
26
+ let o = a.filter((a) => a.path !== e.path);
27
+ if (x?.path === e.path) if (o.length > 0) {
28
+ let s = a.findIndex((a) => a.path === e.path);
29
+ S(o[Math.max(0, s - 1)]);
30
+ } else S(null);
31
+ return o;
32
+ });
33
+ }, l[4] = x?.path, l[5] = k);
34
+ let A = k, j;
35
+ l[6] === x ? j = l[7] : (j = () => {
36
+ x && b((e) => {
37
+ let a = e.filter((e) => e.path !== x.path);
38
+ if (a.length > 0) {
39
+ let o = e.findIndex((e) => e.path === x.path);
40
+ S(a[Math.max(0, o - 1)]);
41
+ } else S(null);
42
+ return a;
43
+ });
44
+ }, l[6] = x, l[7] = j);
45
+ let M = j, N;
46
+ l[8] === Symbol.for("react.memo_cache_sentinel") ? (N = () => {
47
+ b([]), S(null);
48
+ }, l[8] = N) : N = l[8];
49
+ let P = N, F;
50
+ l[9] === Symbol.for("react.memo_cache_sentinel") ? (F = (e) => {
51
+ b([e]), S(e);
52
+ }, l[9] = F) : F = l[9];
53
+ let I = F, L;
54
+ l[10] === x ? L = l[11] : (L = (e) => {
55
+ b((a) => {
56
+ let o = a.findIndex((a) => a.path === e.path);
57
+ if (o <= 0) return a;
58
+ let s = a.slice(o);
59
+ return x && a.findIndex((e) => e.path === x.path) < o && S(e), s;
60
+ });
61
+ }, l[10] = x, l[11] = L);
62
+ let R = L, z;
63
+ l[12] === x ? z = l[13] : (z = (e) => {
64
+ b((a) => {
65
+ let o = a.findIndex((a) => a.path === e.path);
66
+ if (o < 0 || o >= a.length - 1) return a;
67
+ let s = a.slice(0, o + 1);
68
+ return x && a.findIndex((e) => e.path === x.path) > o && S(e), s;
69
+ });
70
+ }, l[12] = x, l[13] = z);
71
+ let B = z, V;
72
+ l[14] === m ? V = l[15] : (V = () => {
73
+ m.invalidateQueries({ queryKey: ["file-explorer-tree"] });
74
+ }, l[14] = m, l[15] = V);
75
+ let H = V, U;
76
+ l[16] === C.data ? U = l[17] : (U = C.data ?? [], l[16] = C.data, l[17] = U);
77
+ let W = C.isLoading && !C.data, G = w.data?.content ?? null, K = w.isLoading && !!x, q;
78
+ l[18] !== M || l[19] !== A || l[20] !== R || l[21] !== B || l[22] !== g || l[23] !== y || l[24] !== H || l[25] !== x || l[26] !== U || l[27] !== W || l[28] !== G || l[29] !== K || l[30] !== C.error || l[31] !== C.isFetching ? (q = {
79
+ nodes: U,
80
+ isTreeLoading: W,
81
+ treeError: C.error,
82
+ isFetchingTree: C.isFetching,
83
+ openFiles: y,
84
+ selectedFile: x,
85
+ fileContent: G,
86
+ isContentLoading: K,
87
+ expandedFolders: g,
88
+ toggleFolder: E,
89
+ selectFile: O,
90
+ closeFile: A,
91
+ closeAll: P,
92
+ closeOthers: I,
93
+ closeToLeft: R,
94
+ closeToRight: B,
95
+ clearSelection: M,
96
+ refreshTree: H
97
+ }, l[18] = M, l[19] = A, l[20] = R, l[21] = B, l[22] = g, l[23] = y, l[24] = H, l[25] = x, l[26] = U, l[27] = W, l[28] = G, l[29] = K, l[30] = C.error, l[31] = C.isFetching, l[32] = q) : q = l[32];
98
+ let J = q, Y;
99
+ return l[33] !== f || l[34] !== J ? (Y = /* @__PURE__ */ jsx(FileExplorerContext.Provider, {
100
+ value: J,
101
+ children: f
102
+ }), l[33] = f, l[34] = J, l[35] = Y) : Y = l[35], Y;
103
+ }
104
+ function useFileExplorer() {
105
+ let e = useContext(FileExplorerContext);
106
+ if (!e) throw Error("useFileExplorer must be used within FileExplorerProvider");
107
+ return e;
108
+ }
109
+ function useOptionalFileExplorer() {
110
+ return useContext(FileExplorerContext);
111
+ }
112
+ export { FileExplorerProvider, useFileExplorer, useOptionalFileExplorer };