@zhangfengshun/dsh-remote-ssh 1.3.1 → 1.4.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/CHANGELOG.md +4 -0
- package/lib/client.js +76 -26
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
本文件的版本号与 `package.json` 的 `version` 保持一致。每个版本对应一个 Cordis Package 快照(`pkg-N`)。
|
|
4
4
|
|
|
5
|
+
## [1.4.0] — 远程文件单开一栏预览
|
|
6
|
+
### 新增
|
|
7
|
+
- 点击「远程文件」文件树中的文件,改为在 better-sidebar 中**单开一栏(独立页签)预览/编辑**,与内置「文件」页签一致,不再在文件树下方内嵌预览。新增隐藏页签类型 `remssh:editor`,同一远程文件按 (profileId, path) 去重复用。
|
|
8
|
+
|
|
5
9
|
## [1.3.1] — 修复远程文件树滚动
|
|
6
10
|
### 修复
|
|
7
11
|
- 「远程文件」页签改为 flex 布局:文件树在文件很多时占据剩余高度并内部滚动(`flex:1; overflow-y:auto`),不再因父容器 `overflow:hidden` 而无法往下拉。
|
package/lib/client.js
CHANGED
|
@@ -96,6 +96,7 @@ window.__ModuleLoader__.load({
|
|
|
96
96
|
"files.errRead": "读取失败",
|
|
97
97
|
"files.errSave": "保存失败",
|
|
98
98
|
"files.errSaveDefaultDir": "保存默认目录失败",
|
|
99
|
+
"files.binary": "二进制文件,无法预览",
|
|
99
100
|
"term.title": "终端 {id}",
|
|
100
101
|
"term.exited": " (已退出)",
|
|
101
102
|
"term.connecting": "正在连接…",
|
|
@@ -160,6 +161,7 @@ window.__ModuleLoader__.load({
|
|
|
160
161
|
"files.errRead": "Failed to read",
|
|
161
162
|
"files.errSave": "Failed to save",
|
|
162
163
|
"files.errSaveDefaultDir": "Failed to save default directory",
|
|
164
|
+
"files.binary": "Binary file — preview not available",
|
|
163
165
|
"term.title": "Terminal {id}",
|
|
164
166
|
"term.exited": " (exited)",
|
|
165
167
|
"term.connecting": "Connecting…",
|
|
@@ -255,6 +257,7 @@ window.__ModuleLoader__.load({
|
|
|
255
257
|
function FilesTab(props) {
|
|
256
258
|
var t = useT();
|
|
257
259
|
var sessionId = props.sessionId;
|
|
260
|
+
var betterSidebar = props.betterSidebar;
|
|
258
261
|
var [workspaces, setWorkspaces] = React.useState([]);
|
|
259
262
|
var profiles = useProfiles();
|
|
260
263
|
var [wsId, setWsId] = useSessionMemory(sessionId, "wsId", sel.workspaceId);
|
|
@@ -263,7 +266,6 @@ window.__ModuleLoader__.load({
|
|
|
263
266
|
var [entries, setEntries] = useSessionMemory(sessionId, "entries", []);
|
|
264
267
|
var [err, setErr] = React.useState(null);
|
|
265
268
|
var [loading, setLoading] = React.useState(false);
|
|
266
|
-
var [openFile, setOpenFile] = useSessionMemory(sessionId, "openFile", null);
|
|
267
269
|
var [defaultDir, setDefaultDir] = useSessionMemory(sessionId, "defaultDir", "");
|
|
268
270
|
|
|
269
271
|
React.useEffect(function () {
|
|
@@ -316,11 +318,16 @@ window.__ModuleLoader__.load({
|
|
|
316
318
|
setPath(base);
|
|
317
319
|
load(profileId, base);
|
|
318
320
|
} else {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
321
|
+
// 用独立页签预览远程文件(与内置「文件」页签一致),而非在文件树下方预览。
|
|
322
|
+
if (betterSidebar && betterSidebar.openTab) {
|
|
323
|
+
betterSidebar.openTab({
|
|
324
|
+
type: "remssh:editor",
|
|
325
|
+
id: "remssh:editor:" + profileId + ":" + base,
|
|
326
|
+
title: e.name,
|
|
327
|
+
path: base,
|
|
328
|
+
meta: { profileId: profileId, remotePath: base }
|
|
329
|
+
}, { sessionId: sessionId });
|
|
330
|
+
}
|
|
324
331
|
}
|
|
325
332
|
}
|
|
326
333
|
|
|
@@ -333,14 +340,6 @@ window.__ModuleLoader__.load({
|
|
|
333
340
|
load(profileId, up);
|
|
334
341
|
}
|
|
335
342
|
|
|
336
|
-
function saveFile() {
|
|
337
|
-
if (!openFile) return;
|
|
338
|
-
api("writeFile", { profileId: profileId, path: openFile.path, content: openFile.content }).then(function (r) {
|
|
339
|
-
if (r && r.ok) setOpenFile(Object.assign({}, openFile, { dirty: false }));
|
|
340
|
-
else setErr((r && r.error) || t("files.errSave"));
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
|
|
344
343
|
return h("div", { style: { display: "flex", flexDirection: "column", flex: 1, minHeight: 0, overflow: "hidden" } },
|
|
345
344
|
h("div", { style: { flex: "none" } },
|
|
346
345
|
h("div", { className: "rssh-row" },
|
|
@@ -379,18 +378,56 @@ window.__ModuleLoader__.load({
|
|
|
379
378
|
e.type === "file" ? h("span", { className: "rssh-tree-size" }, String(e.size)) : null
|
|
380
379
|
);
|
|
381
380
|
})
|
|
381
|
+
)
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// ======================================================================
|
|
386
|
+
// 远程文件编辑器页签:点击文件树中的文件后单开一栏预览/编辑(与内置「文件」页签一致)
|
|
387
|
+
// ======================================================================
|
|
388
|
+
function RemoteEditor(props) {
|
|
389
|
+
var t = useT();
|
|
390
|
+
var tab = props.tab || {};
|
|
391
|
+
var ctx = props.ctx;
|
|
392
|
+
var meta = tab.meta || {};
|
|
393
|
+
var profileId = meta.profileId || "";
|
|
394
|
+
var remotePath = tab.path || meta.remotePath || "";
|
|
395
|
+
var [data, setData] = React.useState({ loading: true, content: "", binary: false, dirty: false, error: null });
|
|
396
|
+
|
|
397
|
+
React.useEffect(function () {
|
|
398
|
+
var alive = true;
|
|
399
|
+
setData({ loading: true, content: "", binary: false, dirty: false, error: null });
|
|
400
|
+
api("readFile", { profileId: profileId, path: remotePath }).then(function (r) {
|
|
401
|
+
if (!alive) return;
|
|
402
|
+
if (r && r.ok) setData({ loading: false, content: r.content || "", binary: !!r.binary, dirty: false, error: null });
|
|
403
|
+
else setData({ loading: false, content: "", binary: false, dirty: false, error: (r && r.error) || t("files.errRead") });
|
|
404
|
+
});
|
|
405
|
+
return function () { alive = false; };
|
|
406
|
+
}, [profileId, remotePath]);
|
|
407
|
+
|
|
408
|
+
function save() {
|
|
409
|
+
api("writeFile", { profileId: profileId, path: remotePath, content: data.content }).then(function (r) {
|
|
410
|
+
if (r && r.ok) setData(Object.assign({}, data, { dirty: false, error: null }));
|
|
411
|
+
else setData(Object.assign({}, data, { error: (r && r.error) || t("files.errSave") }));
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function close() {
|
|
416
|
+
if (ctx && ctx.betterSidebar && tab.id) ctx.betterSidebar.closeTab(tab.id);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (data.loading) return h("div", { className: "rssh-muted", style: { padding: 8 } }, t("files.reading"));
|
|
420
|
+
if (data.error) return h("div", { className: "rssh-err", style: { padding: 8, whiteSpace: "pre-wrap" } }, data.error);
|
|
421
|
+
if (data.binary) return h("div", { className: "rssh-muted", style: { padding: 8 } }, t("files.binary"));
|
|
422
|
+
|
|
423
|
+
return h("div", { style: { display: "flex", flexDirection: "column", flex: 1, minHeight: 0, padding: 8, overflow: "hidden" } },
|
|
424
|
+
h("div", { className: "rssh-pathbar", style: { flex: "none" } },
|
|
425
|
+
h("span", { className: "rssh-title", style: { flex: 1, wordBreak: "break-all" } }, remotePath),
|
|
426
|
+
h("button", { className: "rssh-btn", onClick: save }, t("common.save")),
|
|
427
|
+
h("button", { className: "rssh-btn", onClick: close }, t("common.close"))
|
|
382
428
|
),
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
h("span", { className: "rssh-title", style: { flex: 1, wordBreak: "break-all" } }, openFile.path),
|
|
386
|
-
h("button", { className: "rssh-btn", onClick: saveFile }, t("common.save")),
|
|
387
|
-
h("button", { className: "rssh-btn", onClick: function () { setOpenFile(null); } }, t("common.close"))
|
|
388
|
-
),
|
|
389
|
-
openFile.loading ? h("div", { className: "rssh-muted" }, t("files.reading")) :
|
|
390
|
-
openFile.error ? h("div", { className: "rssh-err" }, openFile.error) :
|
|
391
|
-
h("textarea", { className: "rssh-content", style: { width: "100%", boxSizing: "border-box", minHeight: 200, background: "var(--dsw-alias-markdown-code-block)", color: "var(--dsw-alias-label-primary)", border: "1px solid var(--dsw-alias-border-l2)" },
|
|
392
|
-
value: openFile.content, onChange: function (e) { setOpenFile(Object.assign({}, openFile, { content: e.target.value, dirty: true })); } })
|
|
393
|
-
) : null
|
|
429
|
+
h("textarea", { className: "rssh-content", style: { flex: 1, minHeight: 0, maxHeight: "none", width: "100%", boxSizing: "border-box", background: "var(--dsw-alias-markdown-code-block)", color: "var(--dsw-alias-label-primary)", border: "1px solid var(--dsw-alias-border-l2)" },
|
|
430
|
+
value: data.content, onChange: function (e) { setData(Object.assign({}, data, { content: e.target.value, dirty: true })); } })
|
|
394
431
|
);
|
|
395
432
|
}
|
|
396
433
|
|
|
@@ -728,7 +765,20 @@ window.__ModuleLoader__.load({
|
|
|
728
765
|
icon: function () { return h("span", null, "🗂️"); },
|
|
729
766
|
component: function (props) {
|
|
730
767
|
var sid = props && props.scope ? props.scope.sessionId : null;
|
|
731
|
-
return h(FilesTab, { key: "files:" + (sid || "global"), sessionId: sid });
|
|
768
|
+
return h(FilesTab, { key: "files:" + (sid || "global"), sessionId: sid, betterSidebar: props && props.ctx ? props.ctx.betterSidebar : null });
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
});
|
|
772
|
+
// 远程文件编辑器页签(隐藏页签,仅由文件树点击打开,每个远程文件单开一栏)。
|
|
773
|
+
ctx.effect(function () {
|
|
774
|
+
return betterSidebar.registerTab({
|
|
775
|
+
id: "remssh:editor",
|
|
776
|
+
title: function () { return i18n.t("tabs.files"); },
|
|
777
|
+
hidden: true,
|
|
778
|
+
dedupeKey: function (tab) { return (tab && tab.meta && tab.meta.profileId || "") + "\u0000" + (tab && tab.path || ""); },
|
|
779
|
+
icon: function () { return h("span", null, "📄"); },
|
|
780
|
+
component: function (props) {
|
|
781
|
+
return h(RemoteEditor, { tab: props && props.tab, ctx: props && props.ctx, scope: props && props.scope });
|
|
732
782
|
}
|
|
733
783
|
});
|
|
734
784
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhangfengshun/dsh-remote-ssh",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "DSH web plugin: VSCode Remote-SSH-like remote development (SSH to supercomputers/servers, remote workspace, file explorer, integrated terminal), integrated with dsh-better-sidebar and DSH settings.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|