@zhangfengshun/dsh-remote-ssh 2.3.1 → 2.3.3
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 +9 -0
- package/lib/client.js +62 -2
- package/lib/index.js +8 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
本文件的版本号与 `package.json` 的 `version` 保持一致。每个版本对应一个 Cordis Package 快照(`pkg-N`)。
|
|
4
4
|
|
|
5
|
+
## [2.3.3] — 修复工作区图标替换不生效
|
|
6
|
+
### 修复
|
|
7
|
+
- 2.3.2 的图标替换向上爬找「直接子级含 svg 的祖先」,但壳层工作区行的文件夹 svg 位于标题的**前兄弟槽位**(`projectRow > [slot.folder(svg), …, projectText > title]`),不是任何祖先的直接子级 → 匹配后静默跳过、图标从未被替换。改为:从标题向上最多 4 层,取每层容器的**第一个子元素**,首个含 svg 的即行首文件夹槽位;并将「插入新节点」改为**原位改写**该 svg 的 viewBox/尺寸/内容(不插入/删除节点,避免 React 对账风险;展开态切换重建 svg 后由观察器 500ms 内自动重刷)。
|
|
8
|
+
|
|
9
|
+
## [2.3.2] — 远程工作区图标改为单个「地球角标文件夹」
|
|
10
|
+
### 变更
|
|
11
|
+
- **工作区标题去掉 🌐 前缀**:新建远程工作区的原生标题不再带 🌐(此前标题 emoji + 壳层文件夹图标造成「文件夹 + 地球」双重标识);启动自愈同步剥掉既有工作区标题中的旧 🌐 前缀(仅限已知旧形态,不覆盖自定义标题)。
|
|
12
|
+
- **客户端图标替换**:按工作区标题文本定位侧边栏工作区行,隐藏壳层默认纯文件夹 svg,插入内联「地球角标文件夹」SVG(文件夹描边 + 主题色圆形地球角标,跟随明暗主题);复用 2.3.1 的增量观察器(只扫新增子树、30s 刷新标题集、data 标记防重入),稳态成本≈0。
|
|
13
|
+
|
|
5
14
|
## [2.3.1] — 修复 2.3.0 上线后的界面卡顿(GC 压力 + 客户端全页扫描)
|
|
6
15
|
### 修复
|
|
7
16
|
- **读缓存字节预算(review m1)**:单条结果 >1MiB 不再缓存(结果照常返回),缓存总量上限 32MB 超限逐出最旧条目——消除大文件驻留字符串造成的 GC 压力(最坏 ~270MB → ≤32MB)。
|
package/lib/client.js
CHANGED
|
@@ -1136,9 +1136,67 @@ window.__ModuleLoader__.load({
|
|
|
1136
1136
|
for (var i = 0; i < buttons.length; i++) checkCell(buttons[i]);
|
|
1137
1137
|
} catch (e) {}
|
|
1138
1138
|
}
|
|
1139
|
+
// ---- 远程工作区图标:单个「地球角标文件夹」SVG 替换壳层默认纯文件夹图标 ----
|
|
1140
|
+
// 壳层工作区行的文件夹图标是固定原语(IconFolderOpen16/Close16),无 per-workspace
|
|
1141
|
+
// 图标 API;旧方案在标题里塞 🌐 emoji 造成「文件夹 + 地球」双重标识。现按标题文本
|
|
1142
|
+
// 定位远程工作区行,找到行首 slot.folder 槽位(标题的前兄弟),把其中的 svg
|
|
1143
|
+
// 原位改写为「地球角标文件夹」内容 —— 不插入/删除节点,避免 React 对账风险。
|
|
1144
|
+
var remoteTitles = new Set();
|
|
1145
|
+
function refreshRemoteTitles() {
|
|
1146
|
+
api("listWorkspaces").then(function (r) {
|
|
1147
|
+
if (!(r && r.ok && Array.isArray(r.workspaces))) return;
|
|
1148
|
+
var next = new Set();
|
|
1149
|
+
for (var i = 0; i < r.workspaces.length; i++) {
|
|
1150
|
+
var t = String(r.workspaces[i].title || "").trim();
|
|
1151
|
+
if (t) { next.add(t); next.add("🌐 " + t); } // 兼容自愈前的旧前缀标题
|
|
1152
|
+
}
|
|
1153
|
+
remoteTitles = next;
|
|
1154
|
+
swapWorkspaceIconsIn(document.body); // 标题集就绪后补一次全量替换
|
|
1155
|
+
}).catch(function () {});
|
|
1156
|
+
}
|
|
1157
|
+
var FOLDER_GLOBE_INNER =
|
|
1158
|
+
'<path d="M2.4 4.2c0-1.05.85-1.9 1.9-1.9h3.1c.52 0 1.02.21 1.39.58l1.05 1.05c.28.28.66.44 1.06.44h6.3c1.05 0 1.9.85 1.9 1.9v6.53c0 1.05-.85 1.9-1.9 1.9H4.3c-1.05 0-1.9-.85-1.9-1.9V4.2z" fill="none" stroke="currentColor" stroke-width="1.2"/>' +
|
|
1159
|
+
'<circle cx="6.3" cy="12.1" r="3.1" fill="var(--dsw-alias-state-business-primary, #4c6ef5)" stroke="var(--dsw-alias-bg-layer-1, #1b1b1b)" stroke-width="0.8"/>' +
|
|
1160
|
+
'<g fill="none" stroke="#ffffff" stroke-width="0.75"><circle cx="6.3" cy="12.1" r="1.95"/><ellipse cx="6.3" cy="12.1" rx="0.95" ry="1.95"/><path d="M4.35 12.1h3.9"/></g>';
|
|
1161
|
+
function swapWorkspaceIconsIn(root) {
|
|
1162
|
+
if (!remoteTitles.size) return;
|
|
1163
|
+
try {
|
|
1164
|
+
var nodes = root.querySelectorAll("span,div,button,a,p");
|
|
1165
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
1166
|
+
var el = nodes[i];
|
|
1167
|
+
if (el.getAttribute && el.getAttribute("data-rssh-title-scan") === "1") continue;
|
|
1168
|
+
var t = (el.textContent || "").trim();
|
|
1169
|
+
if (!t || !remoteTitles.has(t) || el.childElementCount > 2) continue;
|
|
1170
|
+
el.setAttribute("data-rssh-title-scan", "1");
|
|
1171
|
+
// 行结构:projectRow > [slot.folder(svg), slot.chevron(svg), projectText > span.title, ...]
|
|
1172
|
+
// 从标题元素向上最多 4 层,取每层容器的第一个子元素——首个含 svg 的即行首
|
|
1173
|
+
// 文件夹槽位;将其 svg 原位改写为地球角标文件夹(React 复用同一节点,
|
|
1174
|
+
// 展开态切换会重建 svg,观察器 500ms 内自动重刷)。
|
|
1175
|
+
var holder = el;
|
|
1176
|
+
for (var hop = 0; hop < 4 && holder && holder.parentElement; hop++) {
|
|
1177
|
+
var row = holder.parentElement;
|
|
1178
|
+
var first = row.children && row.children[0];
|
|
1179
|
+
if (first && first.querySelector && first.querySelector("svg")) {
|
|
1180
|
+
var oldSvg = first.querySelector("svg");
|
|
1181
|
+
if (oldSvg.getAttribute("data-rssh-folder-globe") !== "1") {
|
|
1182
|
+
oldSvg.setAttribute("data-rssh-folder-globe", "1");
|
|
1183
|
+
oldSvg.setAttribute("viewBox", "0 0 20 16");
|
|
1184
|
+
oldSvg.setAttribute("width", "16");
|
|
1185
|
+
oldSvg.setAttribute("height", "16");
|
|
1186
|
+
oldSvg.innerHTML = FOLDER_GLOBE_INNER;
|
|
1187
|
+
}
|
|
1188
|
+
break;
|
|
1189
|
+
}
|
|
1190
|
+
holder = row;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
} catch (e) {}
|
|
1194
|
+
}
|
|
1139
1195
|
ctx.effect(function () {
|
|
1140
1196
|
if (typeof document === "undefined") return;
|
|
1141
1197
|
hideRemoteGearIcon();
|
|
1198
|
+
refreshRemoteTitles();
|
|
1199
|
+
var titleTimer = setInterval(refreshRemoteTitles, 30000);
|
|
1142
1200
|
var timer = null;
|
|
1143
1201
|
var pendingRoots = null;
|
|
1144
1202
|
var schedule = function (root) {
|
|
@@ -1152,10 +1210,11 @@ window.__ModuleLoader__.load({
|
|
|
1152
1210
|
if (roots && roots.length) {
|
|
1153
1211
|
// 只扫新增子树:流式聊天期间不做全文档扫描(稳态成本≈0)
|
|
1154
1212
|
for (var i = 0; i < roots.length; i++) {
|
|
1155
|
-
if (roots[i].isConnected) checkCellIn(roots[i]);
|
|
1213
|
+
if (roots[i].isConnected) { checkCellIn(roots[i]); swapWorkspaceIconsIn(roots[i]); }
|
|
1156
1214
|
}
|
|
1157
1215
|
} else {
|
|
1158
1216
|
hideRemoteGearIcon(); // 语言切换等无根场景全量扫一次
|
|
1217
|
+
swapWorkspaceIconsIn(document.body);
|
|
1159
1218
|
}
|
|
1160
1219
|
}, 500);
|
|
1161
1220
|
};
|
|
@@ -1171,8 +1230,9 @@ window.__ModuleLoader__.load({
|
|
|
1171
1230
|
mo.disconnect();
|
|
1172
1231
|
if (off) off();
|
|
1173
1232
|
if (timer) clearTimeout(timer);
|
|
1233
|
+
clearInterval(titleTimer);
|
|
1174
1234
|
};
|
|
1175
|
-
}, "dsh-remote-ssh: hide
|
|
1235
|
+
}, "dsh-remote-ssh: settings gear hide + remote workspace folder-globe icon");
|
|
1176
1236
|
}
|
|
1177
1237
|
|
|
1178
1238
|
// better-sidebar 0.15+ 的文件上传 UI 把原始字节流 POST 到 /sidebar/upload。
|
package/lib/index.js
CHANGED
|
@@ -1273,7 +1273,7 @@ function apply(ctx, config) {
|
|
|
1273
1273
|
let workspaceId = null;
|
|
1274
1274
|
if (workspaceRegistry) {
|
|
1275
1275
|
try {
|
|
1276
|
-
const wsTitle =
|
|
1276
|
+
const wsTitle = title; // 图标语义由客户端「地球角标文件夹」图标承担,标题不再带 🌐 前缀
|
|
1277
1277
|
const native = await workspaceRegistry.create(mirrorDir, wsTitle);
|
|
1278
1278
|
workspaceId = native.id;
|
|
1279
1279
|
// workspaceRegistry.create 仅首次创建时应用 title;已存在的旧工作区
|
|
@@ -1856,10 +1856,11 @@ function apply(ctx, config) {
|
|
|
1856
1856
|
}
|
|
1857
1857
|
})();
|
|
1858
1858
|
|
|
1859
|
-
// ----
|
|
1859
|
+
// ---- 启动自愈:把既有远程工作区的原生标题统一为「远程路径最后一段」----
|
|
1860
1860
|
// 早期版本 create 工作区时未传 title,DSH 用镜像目录 basename(wsId,如 wmt3tev5cdfge)
|
|
1861
1861
|
// 作标题;workspaceRegistry.create 只对新建记录应用 title,旧记录会被原样返回。
|
|
1862
|
-
//
|
|
1862
|
+
// 2.3.2 起标题不再带 🌐 前缀(图标由客户端地球角标文件夹 SVG 承担),自愈同时剥掉
|
|
1863
|
+
// 旧版遗留的 🌐 前缀。仅在标题等于已知旧形态时修复,不覆盖用户自定义标题。
|
|
1863
1864
|
function healWorkspaceTitles() {
|
|
1864
1865
|
const reg = workspaceRegistry;
|
|
1865
1866
|
if (!reg || typeof reg.resolveByPath !== "function") return;
|
|
@@ -1868,13 +1869,14 @@ function apply(ctx, config) {
|
|
|
1868
1869
|
if (!w || !w.mirrorPath || !w.remotePath) continue;
|
|
1869
1870
|
const lastSeg = String(w.remotePath).replace(/\/+$/, "").split("/").pop();
|
|
1870
1871
|
if (!lastSeg || lastSeg === "~" || lastSeg === ".") continue;
|
|
1871
|
-
const desired =
|
|
1872
|
+
const desired = lastSeg;
|
|
1872
1873
|
const base = String(w.mirrorPath).split(/[\\/]/).filter(Boolean).pop();
|
|
1874
|
+
const legacy = new Set([base, "🌐 " + base, desired, "🌐 " + desired, "🌐 " + w.title]);
|
|
1873
1875
|
(async () => {
|
|
1874
1876
|
try {
|
|
1875
1877
|
const ent = await reg.resolveByPath(w.mirrorPath);
|
|
1876
|
-
//
|
|
1877
|
-
if (ent && typeof ent.setTitle === "function" && (ent.title
|
|
1878
|
+
// 只在标题仍是已知旧形态(镜像目录名旧 bug / 🌐 前缀旧版)时修复,尊重自定义标题。
|
|
1879
|
+
if (ent && typeof ent.setTitle === "function" && legacy.has(ent.title)) {
|
|
1878
1880
|
await ent.setTitle(desired);
|
|
1879
1881
|
}
|
|
1880
1882
|
} catch (e) {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhangfengshun/dsh-remote-ssh",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.3",
|
|
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",
|