@dong-victor/dsh-better-sidebar-starter 0.1.7 → 0.1.9
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/lib/client.js +40 -75
- package/lib/client.js.map +1 -1
- package/lib/index.js +48 -1
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -161,7 +161,7 @@ window.__ModuleLoader__.load({
|
|
|
161
161
|
}
|
|
162
162
|
/** The config tree component. */
|
|
163
163
|
function ConfigTree(props) {
|
|
164
|
-
const { configs, instances, selectedInstanceId, selectedConfigId, onSelectConfig, onSelectInstance, onStartConfig, onStopInstance, onEditConfig, onDuplicateConfig } = props;
|
|
164
|
+
const { configs, instances, selectedInstanceId, selectedConfigId, onSelectConfig, onSelectInstance, onStartConfig, onStopInstance, onEditConfig, onDuplicateConfig, onDeleteConfig } = props;
|
|
165
165
|
const [collapsed, setCollapsed] = (0, react.useState)(/* @__PURE__ */ new Set());
|
|
166
166
|
const toggleGroup = (type) => {
|
|
167
167
|
setCollapsed((prev) => {
|
|
@@ -228,7 +228,14 @@ window.__ModuleLoader__.load({
|
|
|
228
228
|
e.stopPropagation();
|
|
229
229
|
onDuplicateConfig(config.id);
|
|
230
230
|
}
|
|
231
|
-
}, CopyIcon({ size: 12 })))
|
|
231
|
+
}, CopyIcon({ size: 12 })), (0, react.createElement)("button", {
|
|
232
|
+
className: "sts-icon-btn trash",
|
|
233
|
+
title: "删除配置",
|
|
234
|
+
onClick: (e) => {
|
|
235
|
+
e.stopPropagation();
|
|
236
|
+
onDeleteConfig(config.id);
|
|
237
|
+
}
|
|
238
|
+
}, TrashIcon({ size: 12 }))))];
|
|
232
239
|
for (const inst of configInstances) {
|
|
233
240
|
const instSelected = selectedInstanceId === inst.id;
|
|
234
241
|
rows.push((0, react.createElement)("div", {
|
|
@@ -1082,29 +1089,28 @@ window.__ModuleLoader__.load({
|
|
|
1082
1089
|
//#endregion
|
|
1083
1090
|
//#region src/client/DirChooser.tsx
|
|
1084
1091
|
/**
|
|
1085
|
-
* Shared directory chooser: a filesystem folder tree (backed by the
|
|
1086
|
-
*
|
|
1087
|
-
*
|
|
1088
|
-
*
|
|
1089
|
-
*
|
|
1092
|
+
* Shared directory chooser: a filesystem folder tree (backed by the starter
|
|
1093
|
+
* plugin's own fs-dirs host route) plus a browse button that opens a modal
|
|
1094
|
+
* popup. Browsing starts at the user's home directory and can navigate up to
|
|
1095
|
+
* any drive/root, so runtime tool paths (JDK/Maven/...) that live outside the
|
|
1096
|
+
* workspace can be selected. The sidebar fs.tree API cannot be used here — it
|
|
1097
|
+
* is workspace-confined since dsh-better-sidebar 0.16 (403 outside the
|
|
1098
|
+
* session workspace).
|
|
1090
1099
|
* @module dsh-better-sidebar-starter/client/DirChooser
|
|
1091
1100
|
*/
|
|
1092
|
-
/** Call the
|
|
1093
|
-
async function fsTree
|
|
1094
|
-
const
|
|
1095
|
-
sessionId: scope.sessionId,
|
|
1096
|
-
path
|
|
1097
|
-
};
|
|
1098
|
-
if (scope.cwd !== void 0 && scope.cwd !== "") payload.cwd = scope.cwd;
|
|
1099
|
-
const resp = await fetch("/sidebar/api/fs.tree", {
|
|
1101
|
+
/** Call the starter fs-dirs host route via fetch. Returns directories only. */
|
|
1102
|
+
async function fsTree(scope, path) {
|
|
1103
|
+
const resp = await fetch("/api/dsh-better-sidebar-starter/fs-dirs", {
|
|
1100
1104
|
method: "POST",
|
|
1101
1105
|
headers: { "content-type": "application/json" },
|
|
1102
|
-
body: JSON.stringify(
|
|
1106
|
+
body: JSON.stringify({
|
|
1107
|
+
sessionId: scope.sessionId,
|
|
1108
|
+
path
|
|
1109
|
+
})
|
|
1103
1110
|
});
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
return parsed.value.entries.filter((e) => e.isDir && !e.hidden);
|
|
1111
|
+
const parsed = await resp.json().catch(() => void 0);
|
|
1112
|
+
if (!resp.ok) throw new Error(`fs-dirs ${path}: ${parsed?.error ?? resp.status}`);
|
|
1113
|
+
return (parsed?.entries ?? []).filter((e) => e.isDir && !e.hidden);
|
|
1108
1114
|
}
|
|
1109
1115
|
/** Fetch the user's home directory from the host. Falls back to cwd. */
|
|
1110
1116
|
async function fetchHomeDefault(scope) {
|
|
@@ -1156,7 +1162,7 @@ window.__ModuleLoader__.load({
|
|
|
1156
1162
|
const loadDir = (s, path) => {
|
|
1157
1163
|
setLoading(true);
|
|
1158
1164
|
setError(null);
|
|
1159
|
-
fsTree
|
|
1165
|
+
fsTree(s, path).then((dirs) => {
|
|
1160
1166
|
setEntries(dirs);
|
|
1161
1167
|
setLoading(false);
|
|
1162
1168
|
}).catch((err) => {
|
|
@@ -1237,7 +1243,7 @@ window.__ModuleLoader__.load({
|
|
|
1237
1243
|
onToggleExpand(entry.path);
|
|
1238
1244
|
if (children === null) {
|
|
1239
1245
|
setLoading(true);
|
|
1240
|
-
fsTree
|
|
1246
|
+
fsTree(scope, entry.path).then((dirs) => {
|
|
1241
1247
|
setChildren(dirs);
|
|
1242
1248
|
setLoading(false);
|
|
1243
1249
|
}).catch(() => {
|
|
@@ -1349,23 +1355,6 @@ window.__ModuleLoader__.load({
|
|
|
1349
1355
|
* and environment variables.
|
|
1350
1356
|
* @module dsh-better-sidebar-starter/client/ConfigEditorModal
|
|
1351
1357
|
*/
|
|
1352
|
-
/** Call the sidebar fs.tree API directly via fetch. Returns directories only.
|
|
1353
|
-
* If path is omitted, the server uses the session cwd (root listing).
|
|
1354
|
-
* The sidebar API wraps responses in { ok: true, value: ... } envelope. */
|
|
1355
|
-
async function fsTree(scope, path) {
|
|
1356
|
-
const payload = { sessionId: scope.sessionId };
|
|
1357
|
-
if (scope.cwd !== void 0 && scope.cwd !== "") payload.cwd = scope.cwd;
|
|
1358
|
-
if (path !== void 0) payload.path = path;
|
|
1359
|
-
const resp = await fetch("/sidebar/api/fs.tree", {
|
|
1360
|
-
method: "POST",
|
|
1361
|
-
headers: { "content-type": "application/json" },
|
|
1362
|
-
body: JSON.stringify(payload)
|
|
1363
|
-
});
|
|
1364
|
-
if (!resp.ok) throw new Error(`fs.tree ${path ?? "(root)"}: ${resp.status}`);
|
|
1365
|
-
const parsed = await resp.json();
|
|
1366
|
-
if (!parsed.ok || parsed.value === void 0) throw new Error(`fs.tree ${path ?? "(root)"}: ${parsed.error?.message ?? "unknown error"}`);
|
|
1367
|
-
return parsed.value.entries.filter((e) => e.isDir && !e.hidden);
|
|
1368
|
-
}
|
|
1369
1358
|
/** Recursive tree node: loads its own children on expand. */
|
|
1370
1359
|
function TreeNode(props) {
|
|
1371
1360
|
const { scope, entry, depth, selectedPath, onSelect } = props;
|
|
@@ -1419,7 +1408,8 @@ window.__ModuleLoader__.load({
|
|
|
1419
1408
|
if (!expanded && children === null) {
|
|
1420
1409
|
setLoading(true);
|
|
1421
1410
|
setError(null);
|
|
1422
|
-
|
|
1411
|
+
const root = scope.cwd ?? "";
|
|
1412
|
+
(root === "" ? Promise.reject(/* @__PURE__ */ new Error("fs-dirs: 会话工作目录不可用")) : fsTree(scope, root)).then((dirs) => {
|
|
1423
1413
|
setChildren(dirs);
|
|
1424
1414
|
setLoading(false);
|
|
1425
1415
|
}).catch((err) => {
|
|
@@ -2851,7 +2841,10 @@ window.__ModuleLoader__.load({
|
|
|
2851
2841
|
}
|
|
2852
2842
|
} catch {}
|
|
2853
2843
|
}, [sessionQuery, fetchConfigs]);
|
|
2854
|
-
|
|
2844
|
+
/** Delete a config. */
|
|
2845
|
+
const handleDeleteConfig = (0, react.useCallback)(async (configId) => {
|
|
2846
|
+
const target = configs.find((c) => c.id === configId);
|
|
2847
|
+
if (!globalThis.confirm(`确定删除配置「${target?.name ?? configId}」?运行中的实例将被一并停止。`)) return;
|
|
2855
2848
|
for (const inst of instances) if (inst.configId === configId && inst.status === "running") await handleStop(inst.id);
|
|
2856
2849
|
try {
|
|
2857
2850
|
if ((await fetch(`${API_BASE}/configs?${sessionQuery()}&id=${encodeURIComponent(configId)}`, { method: "DELETE" })).ok) {
|
|
@@ -2861,6 +2854,7 @@ window.__ModuleLoader__.load({
|
|
|
2861
2854
|
}
|
|
2862
2855
|
} catch {}
|
|
2863
2856
|
}, [
|
|
2857
|
+
configs,
|
|
2864
2858
|
instances,
|
|
2865
2859
|
handleStop,
|
|
2866
2860
|
sessionQuery,
|
|
@@ -2929,7 +2923,10 @@ window.__ModuleLoader__.load({
|
|
|
2929
2923
|
handleStop(id);
|
|
2930
2924
|
},
|
|
2931
2925
|
onEditConfig: handleEditConfig,
|
|
2932
|
-
onDuplicateConfig: handleDuplicateConfig
|
|
2926
|
+
onDuplicateConfig: handleDuplicateConfig,
|
|
2927
|
+
onDeleteConfig: (id) => {
|
|
2928
|
+
handleDeleteConfig(id);
|
|
2929
|
+
}
|
|
2933
2930
|
})), (0, react.createElement)("div", {
|
|
2934
2931
|
className: `sts-split-gutter${dragging ? " dragging" : ""}${isHorizontal ? "" : " sts-split-gutter-v"}`,
|
|
2935
2932
|
onMouseDown: handleMouseDown
|
|
@@ -3090,39 +3087,7 @@ window.__ModuleLoader__.load({
|
|
|
3090
3087
|
icon: (size) => (0, react.createElement)(RocketIcon, { size }),
|
|
3091
3088
|
order: 50,
|
|
3092
3089
|
single: true,
|
|
3093
|
-
settings: {
|
|
3094
|
-
pluginToggles: [
|
|
3095
|
-
{
|
|
3096
|
-
key: "autoSelectOnStart",
|
|
3097
|
-
type: "switch",
|
|
3098
|
-
title: "启动后自动选中日志"
|
|
3099
|
-
},
|
|
3100
|
-
{
|
|
3101
|
-
key: "autoScroll",
|
|
3102
|
-
type: "switch",
|
|
3103
|
-
title: "自动滚动到最新日志"
|
|
3104
|
-
},
|
|
3105
|
-
{
|
|
3106
|
-
key: "javaHome",
|
|
3107
|
-
type: "text",
|
|
3108
|
-
title: "Java 主目录 (JAVA_HOME)",
|
|
3109
|
-
desc: "Spring Boot 用的 JDK 路径,留空则自动查找"
|
|
3110
|
-
},
|
|
3111
|
-
{
|
|
3112
|
-
key: "nodePath",
|
|
3113
|
-
type: "text",
|
|
3114
|
-
title: "Node.js 路径",
|
|
3115
|
-
desc: "npm 命令用的 Node 路径,留空则用系统默认"
|
|
3116
|
-
},
|
|
3117
|
-
{
|
|
3118
|
-
key: "pythonPath",
|
|
3119
|
-
type: "text",
|
|
3120
|
-
title: "Python 路径",
|
|
3121
|
-
desc: "Python 命令用的解释器路径,留空则用系统默认"
|
|
3122
|
-
}
|
|
3123
|
-
],
|
|
3124
|
-
render: (props) => (0, react.createElement)(SettingsPanel, props)
|
|
3125
|
-
},
|
|
3090
|
+
settings: { render: (props) => (0, react.createElement)(SettingsPanel, props) },
|
|
3126
3091
|
component: (props) => (0, react.createElement)(ServicesTab, props)
|
|
3127
3092
|
}), "dsh-better-sidebar-starter: services tab");
|
|
3128
3093
|
}
|