@zhangfengshun/dsh-remote-ssh 2.3.2 → 2.3.4
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 +48 -28
- 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.4] — 修复点击会话后图标退化 + 角标加大
|
|
6
|
+
### 修复
|
|
7
|
+
- **图标退化**:点击会话等交互触发 React 重渲染,会把 svg 的 viewBox/children 还原成纯文件夹(属性级变化不触发 childList 观察器),而 2.3.3 的防重入守卫只认 data 标记——标记在即跳过,还原后永不重刷。改为:守卫校验**实际状态**(viewBox 是否为目标帧),不匹配即重新应用;并维护已匹配标题元素清单,**每 1s 幂等复检**(断连清理),任何还原 1 秒内自愈。
|
|
8
|
+
- **角标加大**:地球角标半径 3.1 → 5.2(渲染直径 ≈5px → ≈8.3px,视觉接近翻倍),地球线稿与描边同步放大,位置微调至文件夹左下角不越界。
|
|
9
|
+
|
|
10
|
+
## [2.3.3] — 修复工作区图标替换不生效
|
|
11
|
+
### 修复
|
|
12
|
+
- 2.3.2 的图标替换向上爬找「直接子级含 svg 的祖先」,但壳层工作区行的文件夹 svg 位于标题的**前兄弟槽位**(`projectRow > [slot.folder(svg), …, projectText > title]`),不是任何祖先的直接子级 → 匹配后静默跳过、图标从未被替换。改为:从标题向上最多 4 层,取每层容器的**第一个子元素**,首个含 svg 的即行首文件夹槽位;并将「插入新节点」改为**原位改写**该 svg 的 viewBox/尺寸/内容(不插入/删除节点,避免 React 对账风险;展开态切换重建 svg 后由观察器 500ms 内自动重刷)。
|
|
13
|
+
|
|
5
14
|
## [2.3.2] — 远程工作区图标改为单个「地球角标文件夹」
|
|
6
15
|
### 变更
|
|
7
16
|
- **工作区标题去掉 🌐 前缀**:新建远程工作区的原生标题不再带 🌐(此前标题 emoji + 壳层文件夹图标造成「文件夹 + 地球」双重标识);启动自愈同步剥掉既有工作区标题中的旧 🌐 前缀(仅限已知旧形态,不覆盖自定义标题)。
|
package/lib/client.js
CHANGED
|
@@ -1139,8 +1139,10 @@ window.__ModuleLoader__.load({
|
|
|
1139
1139
|
// ---- 远程工作区图标:单个「地球角标文件夹」SVG 替换壳层默认纯文件夹图标 ----
|
|
1140
1140
|
// 壳层工作区行的文件夹图标是固定原语(IconFolderOpen16/Close16),无 per-workspace
|
|
1141
1141
|
// 图标 API;旧方案在标题里塞 🌐 emoji 造成「文件夹 + 地球」双重标识。现按标题文本
|
|
1142
|
-
//
|
|
1142
|
+
// 定位远程工作区行,找到行首 slot.folder 槽位(标题的前兄弟),把其中的 svg
|
|
1143
|
+
// 原位改写为「地球角标文件夹」内容 —— 不插入/删除节点,避免 React 对账风险。
|
|
1143
1144
|
var remoteTitles = new Set();
|
|
1145
|
+
var watchedTitles = []; // 已匹配的标题元素:定时幂等复检,抵消 React 重渲染对图标的还原
|
|
1144
1146
|
function refreshRemoteTitles() {
|
|
1145
1147
|
api("listWorkspaces").then(function (r) {
|
|
1146
1148
|
if (!(r && r.ok && Array.isArray(r.workspaces))) return;
|
|
@@ -1153,19 +1155,48 @@ window.__ModuleLoader__.load({
|
|
|
1153
1155
|
swapWorkspaceIconsIn(document.body); // 标题集就绪后补一次全量替换
|
|
1154
1156
|
}).catch(function () {});
|
|
1155
1157
|
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1158
|
+
var FOLDER_GLOBE_VIEWBOX = "0 0 20 16";
|
|
1159
|
+
var FOLDER_GLOBE_INNER =
|
|
1160
|
+
'<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"/>' +
|
|
1161
|
+
'<circle cx="6.2" cy="10.9" r="5.2" fill="var(--dsw-alias-state-business-primary, #4c6ef5)" stroke="var(--dsw-alias-bg-layer-1, #1b1b1b)" stroke-width="1"/>' +
|
|
1162
|
+
'<g fill="none" stroke="#ffffff" stroke-width="0.9"><circle cx="6.2" cy="10.9" r="3.3"/><ellipse cx="6.2" cy="10.9" rx="1.55" ry="3.3"/><path d="M2.9 10.9h6.6"/></g>';
|
|
1163
|
+
/** 幂等应用:React 重渲染会还原 svg 属性(viewBox 回 16×16、children 回纯文件夹),
|
|
1164
|
+
* 但不感知也不清除我们的 data 标记 —— 守卫必须校验实际状态而非仅 data 标记,
|
|
1165
|
+
* 否则还原后永不重刷(2.3.3 退化 bug 根因)。 */
|
|
1166
|
+
function applyFolderGlobe(slotSvg) {
|
|
1167
|
+
if (slotSvg.getAttribute("data-rssh-folder-globe") === "1" && slotSvg.getAttribute("viewBox") === FOLDER_GLOBE_VIEWBOX) return;
|
|
1168
|
+
slotSvg.setAttribute("data-rssh-folder-globe", "1");
|
|
1169
|
+
slotSvg.setAttribute("viewBox", FOLDER_GLOBE_VIEWBOX);
|
|
1170
|
+
slotSvg.setAttribute("width", "16");
|
|
1171
|
+
slotSvg.setAttribute("height", "16");
|
|
1172
|
+
slotSvg.innerHTML = FOLDER_GLOBE_INNER;
|
|
1173
|
+
}
|
|
1174
|
+
/** 对单个标题元素做行首槽位修复:projectRow > [slot.folder(svg), …, projectText > title],
|
|
1175
|
+
* 文件夹 svg 在标题的前兄弟槽位 —— 向上 ≤4 层取每层容器第一个子元素,首个含 svg 即是。 */
|
|
1176
|
+
function fixRowIconFor(el) {
|
|
1177
|
+
var holder = el;
|
|
1178
|
+
for (var hop = 0; hop < 4 && holder && holder.parentElement; hop++) {
|
|
1179
|
+
var row = holder.parentElement;
|
|
1180
|
+
var first = row.children && row.children[0];
|
|
1181
|
+
if (first && first.querySelector && first.querySelector("svg")) {
|
|
1182
|
+
applyFolderGlobe(first.querySelector("svg"));
|
|
1183
|
+
return true;
|
|
1184
|
+
}
|
|
1185
|
+
holder = row;
|
|
1186
|
+
}
|
|
1187
|
+
return false;
|
|
1188
|
+
}
|
|
1189
|
+
function watchTitle(el) {
|
|
1190
|
+
for (var i = 0; i < watchedTitles.length; i++) { if (watchedTitles[i] === el) return; }
|
|
1191
|
+
watchedTitles.push(el);
|
|
1192
|
+
fixRowIconFor(el);
|
|
1193
|
+
}
|
|
1194
|
+
function recheckWatched() {
|
|
1195
|
+
for (var i = watchedTitles.length - 1; i >= 0; i--) {
|
|
1196
|
+
var el = watchedTitles[i];
|
|
1197
|
+
if (!el || !el.isConnected) { watchedTitles.splice(i, 1); continue; }
|
|
1198
|
+
fixRowIconFor(el);
|
|
1199
|
+
}
|
|
1169
1200
|
}
|
|
1170
1201
|
function swapWorkspaceIconsIn(root) {
|
|
1171
1202
|
if (!remoteTitles.size) return;
|
|
@@ -1173,22 +1204,9 @@ window.__ModuleLoader__.load({
|
|
|
1173
1204
|
var nodes = root.querySelectorAll("span,div,button,a,p");
|
|
1174
1205
|
for (var i = 0; i < nodes.length; i++) {
|
|
1175
1206
|
var el = nodes[i];
|
|
1176
|
-
if (el.getAttribute && el.getAttribute("data-rssh-title-scan") === "1") continue;
|
|
1177
1207
|
var t = (el.textContent || "").trim();
|
|
1178
1208
|
if (!t || !remoteTitles.has(t) || el.childElementCount > 2) continue;
|
|
1179
|
-
el
|
|
1180
|
-
// 向上找最近的「直接子级含 svg」的容器(壳层 slot.folder 槽位)
|
|
1181
|
-
var p = el, slot = null, guard = 0;
|
|
1182
|
-
while (p && p.nodeType === 1 && p !== document.body && guard++ < 6) {
|
|
1183
|
-
if (p.querySelector(":scope > svg")) { slot = p; break; }
|
|
1184
|
-
p = p.parentElement;
|
|
1185
|
-
}
|
|
1186
|
-
if (!slot) continue;
|
|
1187
|
-
var old = slot.querySelector(":scope > svg");
|
|
1188
|
-
if (old && old.getAttribute("data-rssh-folder-globe") === "1") continue;
|
|
1189
|
-
if (old) old.style.display = "none";
|
|
1190
|
-
var mine = folderGlobeSvg();
|
|
1191
|
-
if (old) slot.insertBefore(mine, old); else slot.appendChild(mine);
|
|
1209
|
+
watchTitle(el);
|
|
1192
1210
|
}
|
|
1193
1211
|
} catch (e) {}
|
|
1194
1212
|
}
|
|
@@ -1197,6 +1215,7 @@ window.__ModuleLoader__.load({
|
|
|
1197
1215
|
hideRemoteGearIcon();
|
|
1198
1216
|
refreshRemoteTitles();
|
|
1199
1217
|
var titleTimer = setInterval(refreshRemoteTitles, 30000);
|
|
1218
|
+
var recheckTimer = setInterval(recheckWatched, 1000); // 抵消 React 属性还原
|
|
1200
1219
|
var timer = null;
|
|
1201
1220
|
var pendingRoots = null;
|
|
1202
1221
|
var schedule = function (root) {
|
|
@@ -1231,6 +1250,7 @@ window.__ModuleLoader__.load({
|
|
|
1231
1250
|
if (off) off();
|
|
1232
1251
|
if (timer) clearTimeout(timer);
|
|
1233
1252
|
clearInterval(titleTimer);
|
|
1253
|
+
clearInterval(recheckTimer);
|
|
1234
1254
|
};
|
|
1235
1255
|
}, "dsh-remote-ssh: settings gear hide + remote workspace folder-globe icon");
|
|
1236
1256
|
}
|
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.4",
|
|
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",
|