dsh-sessions-manager 3.5.1 → 3.5.2
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/README.en.md +10 -0
- package/README.md +10 -0
- package/lib/client.js +112 -88
- package/lib/client.js.map +2 -2
- package/lib/index.js +820 -220
- package/lib/index.js.map +4 -4
- package/package.json +1 -1
- package/src/client/index.jsx +138 -83
- package/src/client/logic.js +5 -1
- package/src/compat/capabilities.js +64 -8
- package/src/compat/persistence.js +137 -18
- package/src/handle-era-ops.js +185 -0
- package/src/handle-era-paths.js +126 -0
- package/src/index.js +347 -91
- package/src/markdown.js +122 -71
- package/src/path-guard.js +59 -0
- package/src/session-meta-cache.js +40 -13
- package/src/title-persist-index.js +6 -1
package/README.en.md
CHANGED
|
@@ -162,6 +162,16 @@ lib/client.js pre-built client (ModuleLoader CJS handshake)
|
|
|
162
162
|
- `0.1.3-alpha.1`: snapshot lists and read-only `SessionHandle` flows are supported. Permanent purge and cross-workspace move are disabled when no verified safe path is available; other management functions continue to work. The panel shows the effective capabilities.
|
|
163
163
|
- Unverified future runtimes expose only capabilities the plugin can safely identify; method presence alone is not presented as behavioral compatibility.
|
|
164
164
|
|
|
165
|
+
### Behavior differences and degradations under `0.1.3-alpha.1`
|
|
166
|
+
|
|
167
|
+
- **Recycle-bin restore is verified**: before restoring, the plugin confirms the underlying stored session still exists (live / `stat` / listing, in that order). It returns accurate errors when the session is gone (`DSM_SESSION_MISSING`), was permanently purged (`DSM_SESSION_PURGED`), or the index still lists it but the log file has vanished (`DSM_SESSION_LOG_MISSING`); when the log location cannot be verified the entry is honestly reported as `unverified` instead of silently passing. Restoring a session whose workspace was deleted succeeds and notes that it now lives under "未分组" (ungrouped).
|
|
168
|
+
- **Permanent purge / empty recycle bin / automatic physical cleanup**: the official public contract offers no delete API, so the plugin keeps the legacy-era semi-official approach — a **three-layer guarded path derivation** starting from the backend instance's storage-root field (root → session directory structure → session-id ownership check), followed by a whole-directory removal verified with the official `stat`. Sessions with an active writer are refused (409). When the derivation fails (e.g. the storage root is unavailable), the actions degrade to disabled with an explicit reason instead of deleting blindly.
|
|
169
|
+
- **Cross-workspace move**: the primary path replays events through the official `create` + `append` (writer-ownership probe refuses active sessions, before/after `revision` checks guard against concurrent writes, backup + rollback guarantees no half-moved state on failure); when the backend holds a ghost record for the same id it falls back to relocating the log with a frame0 cwd rewrite (frame count and content verified byte-for-byte). Paths come from the same guarded derivation; the workspace grouping index is rebuilt automatically after the move — no restart needed.
|
|
170
|
+
- **Purge tombstones never suppress new sessions**: if a session with the same id is recreated later, the tombstone yields automatically and the new session appears normally in lists and the sidebar.
|
|
171
|
+
- **Metadata-cache change tokens**: on the new runtime the plugin prefers the official `stat`/`list` snapshot `revision` (comparable only within one service instance and one session id) to detect changes; legacy runtimes keep the `(mtime, size)` file fingerprint. Revisions are never persisted into the cross-process title index. List metadata comes straight from `snapshot.header` and titles from the batch projection — a missing title does **not** trigger a full-log decode, avoiding amplification of the known historical-session loading regression in alpha.
|
|
172
|
+
- **Auto-archive**: the new runtime exposes no reliable "last activity" timestamp; the sweep skips (`no-activity-data`) when idleness cannot be proven, and never archives on a guess.
|
|
173
|
+
- **Sidebar injection**: DOM / React fiber recognition is centralized in a versioned adapter; when the upstream sidebar shape is no longer recognized, all injections degrade safely and the official sidebar is left untouched. While recognition works, updates are driven incrementally by a MutationObserver with only a low-frequency fallback check.
|
|
174
|
+
|
|
165
175
|
## License
|
|
166
176
|
|
|
167
177
|
[MIT](./LICENSE) © TOBYCAI
|
package/README.md
CHANGED
|
@@ -162,6 +162,16 @@ lib/client.js 预构建 client(ModuleLoader CJS handshake)
|
|
|
162
162
|
- `0.1.3-alpha.1`:支持 snapshot 列表和 `SessionHandle` 只读流程;永久删除与跨工作区移动在缺少已验证安全路径时自动禁用,其余管理能力继续工作。能力以面板实际提示为准。
|
|
163
163
|
- 未经验证的未来 Runtime 默认只开放能够识别的安全能力;插件不会用方法存在与否冒充行为兼容。
|
|
164
164
|
|
|
165
|
+
### `0.1.3-alpha.1` 下的行为差异与降级说明
|
|
166
|
+
|
|
167
|
+
- **回收站恢复需要校验**:恢复前会确认底层会话仍存在(live / `stat` / 列表三级判定)。底层会话已不存在(`DSM_SESSION_MISSING`)、已被彻底删除(`DSM_SESSION_PURGED`)或索引仍在但日志文件消失(`DSM_SESSION_LOG_MISSING`)时返回准确错误;无法核验日志位置时如实标注 `unverified`,不会假装校验通过。恢复到「工作区已删除」的会话会成功并提示其暂归「未分组」。
|
|
168
|
+
- **彻底删除 / 清空回收站 / 自动物理清理**:官方公共契约未提供删除 API,插件沿用 legacy 时代的半官方路线——从后端实例的存储根目录字段出发做**三层守卫式路径推导**(根目录 → 会话目录结构 → 会话 ID 归属校验),通过后整目录删除并以官方 `stat` 复核;存在活跃写入的会话会被拒绝(409)。推导失败(如无法确认存储根目录)时自动禁用并说明原因,绝不盲删。
|
|
169
|
+
- **跨工作区移动**:主路径为官方 `create` + `append` 事件重放(写所有权探测拒绝活跃会话、revision 前后校验防并发写入、备份回滚保证失败不留半移动状态);后端存在同 ID 幽灵记录时回退到 frame0 cwd 改写搬运(帧数与内容逐位校验)。路径同样来自守卫式推导;移动后自动重建工作区分组索引,无需重启。
|
|
170
|
+
- **彻底删除墓碑不压制新会话**:若同 ID 会话被重新创建,墓碑自动让位,新会话正常出现在列表与侧栏。
|
|
171
|
+
- **元数据缓存的变更令牌**:新 Runtime 优先使用官方 `stat`/`list` 快照的 `revision`(仅同一 service 实例、同一会话内可比较)判断会话是否变化,旧 Runtime 继续使用 `(mtime, size)` 文件指纹;`revision` 绝不写入跨进程持久索引。列表元数据直接取自 `snapshot.header`,标题走批量投影——没有标题时**不会**自动解码整本日志,避免放大 alpha 已知的历史会话加载性能回退。
|
|
172
|
+
- **自动归档**:新 Runtime 不提供可靠的「最后活跃时间」,无法证明会话闲置时检查会跳过(`no-activity-data`),绝不基于猜测归档。
|
|
173
|
+
- **侧栏注入**:DOM / React fiber 识别收敛为可版本化的 adapter;上游侧栏结构不被识别时整体安全停用,不影响官方侧栏本身。识别正常时以 MutationObserver 增量驱动为主,仅保留低频兜底检查。
|
|
174
|
+
|
|
165
175
|
## License
|
|
166
176
|
|
|
167
177
|
[MIT](./LICENSE) © TOBYCAI
|
package/lib/client.js
CHANGED
|
@@ -44,6 +44,8 @@ function dotStateFor({ manualUnread = false, dataState = "", isActive = false }
|
|
|
44
44
|
case "running":
|
|
45
45
|
return "running";
|
|
46
46
|
case "warning":
|
|
47
|
+
case "waiting":
|
|
48
|
+
case "needs-attention":
|
|
47
49
|
return "feedback";
|
|
48
50
|
case "error":
|
|
49
51
|
return "error";
|
|
@@ -96,12 +98,12 @@ function loadPanelPrefs() {
|
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
100
|
var CSS = `
|
|
99
|
-
.archv{--dsm-radius-tag:4px;display:flex;flex-direction:column;gap:4px;max-width:800px;padding:8px 2px 28px}
|
|
101
|
+
.archv{--dsm-radius-tag:4px;--dsm-radius-ctl:9px;--dsm-radius-sheet:10px;--dsm-radius-card:12px;display:flex;flex-direction:column;gap:4px;max-width:800px;padding:8px 2px 28px}
|
|
100
102
|
.archv-head{display:flex;align-items:center;gap:10px;margin:0 0 2px}
|
|
101
103
|
.archv-title{font-size:16px;font-weight:650;color:var(--dsw-alias-label-primary);letter-spacing:-0.01em;margin:0}
|
|
102
104
|
.archv-count{font-size:11px;font-weight:600;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-fill-subtle);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;padding:1px 8px;flex:none}
|
|
103
105
|
.archv-sub{font-size:12px;line-height:1.55;color:var(--dsw-alias-label-tertiary);margin:0 0 12px;max-width:64ch}
|
|
104
|
-
.archv-err{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:9px 12px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-error-primary) 40%,transparent);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 8%,transparent);border-radius:
|
|
106
|
+
.archv-err{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:9px 12px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-error-primary) 40%,transparent);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 8%,transparent);border-radius:var(--dsm-radius-sheet);color:var(--dsw-alias-state-error-primary);font-size:12px;margin-bottom:10px}
|
|
105
107
|
.archv-errretry{appearance:none;border:1px solid color-mix(in srgb,var(--dsw-alias-state-error-primary) 45%,transparent);background:transparent;color:inherit;border-radius:8px;padding:4px 10px;font-size:11px;cursor:pointer;flex:none}
|
|
106
108
|
.sess-filter{display:flex;align-items:center;gap:6px;margin:0 0 12px}
|
|
107
109
|
.sess-fbtn{appearance:none;min-height:30px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-fill-subtle);color:var(--dsw-alias-label-secondary);border-radius:999px;font-size:12px;font-weight:500;cursor:pointer}
|
|
@@ -110,13 +112,13 @@ var CSS = `
|
|
|
110
112
|
.sess-tools{display:grid;grid-template-columns:minmax(180px,1fr) minmax(140px,.7fr) minmax(130px,.55fr);gap:8px;margin:0 0 8px}
|
|
111
113
|
.sess-field{display:flex;flex-direction:column;gap:5px;min-width:0}
|
|
112
114
|
.sess-field label{font-size:11px;font-weight:600;color:var(--dsw-alias-label-secondary)}
|
|
113
|
-
.sess-field input,.sess-field select{box-sizing:border-box;width:100%;min-height:36px;padding:0 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:
|
|
115
|
+
.sess-field input,.sess-field select{box-sizing:border-box;width:100%;min-height:36px;padding:0 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsm-radius-ctl);background:var(--dsw-alias-fill-elevated);color:var(--dsw-alias-label-primary);font:inherit;font-size:12px}
|
|
114
116
|
.sess-results{font-size:11px;color:var(--dsw-alias-label-tertiary);margin:0 0 4px}
|
|
115
117
|
.archv button:focus-visible,.archv input:focus-visible,.archv select:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}
|
|
116
118
|
.sess-batch{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 2px 4px;margin-bottom:4px}
|
|
117
119
|
.sess-btntext{font-size:12px;color:var(--dsw-alias-label-tertiary);flex:none}
|
|
118
120
|
.archv-list{display:flex;flex-direction:column;gap:8px}
|
|
119
|
-
.archv-card{display:flex;flex-direction:column;align-items:stretch;gap:0;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:
|
|
121
|
+
.archv-card{display:flex;flex-direction:column;align-items:stretch;gap:0;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsm-radius-card);background:var(--dsw-alias-fill-elevated);transition:border-color .15s ease,background-color .15s ease}
|
|
120
122
|
.archv-card:hover{border-color:var(--dsw-alias-border-l4)}
|
|
121
123
|
.archv-card-exp{border-color:var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1)}
|
|
122
124
|
.archv-row{display:flex;align-items:center;gap:14px;width:100%;min-width:0}
|
|
@@ -137,16 +139,16 @@ var CSS = `
|
|
|
137
139
|
.archv-star-on svg{fill:currentColor}
|
|
138
140
|
.archv-body{flex:1;min-width:0;display:flex;align-items:center;gap:12px}
|
|
139
141
|
.archv-actions{display:flex;gap:8px;flex:none;flex-wrap:nowrap;justify-content:flex-end}
|
|
140
|
-
.archv-btn{appearance:none;min-height:32px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-fill-subtle);color:var(--dsw-alias-label-secondary);border-radius:
|
|
142
|
+
.archv-btn{appearance:none;min-height:32px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-fill-subtle);color:var(--dsw-alias-label-secondary);border-radius:var(--dsm-radius-ctl);font-size:12px;font-weight:500;cursor:pointer;white-space:nowrap;display:inline-flex;align-items:center;justify-content:center;gap:6px;text-align:center;transition:background-color .15s ease,border-color .15s ease,color .15s ease}
|
|
141
143
|
.archv-btn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
|
|
142
144
|
.archv-btn:disabled{opacity:.5;cursor:default}
|
|
143
145
|
.archv-del{color:var(--dsw-alias-state-error-primary);border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary) 45%,transparent)}
|
|
144
146
|
.archv-del:hover:not(:disabled){background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
|
|
145
147
|
.archv-go{color:var(--dsw-alias-state-business-primary);border-color:color-mix(in srgb,var(--dsw-alias-state-business-primary) 45%,transparent)}
|
|
146
148
|
.archv-go:hover:not(:disabled){background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 10%,transparent);color:var(--dsw-alias-state-business-primary)}
|
|
147
|
-
.archv-empty{display:flex;align-items:center;gap:10px;padding:20px 14px;border:1px dashed var(--dsw-alias-border-l3);border-radius:
|
|
149
|
+
.archv-empty{display:flex;align-items:center;gap:10px;padding:20px 14px;border:1px dashed var(--dsw-alias-border-l3);border-radius:var(--dsm-radius-card);color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}
|
|
148
150
|
.archv-skel{display:flex;flex-direction:column;gap:8px}
|
|
149
|
-
.archv-skel-card{height:58px;border-radius:
|
|
151
|
+
.archv-skel-card{height:58px;border-radius:var(--dsm-radius-card);background:var(--dsw-alias-fill-subtle);position:relative;overflow:hidden}
|
|
150
152
|
.archv-skel-card::after{content:'';position:absolute;inset:0;transform:translateX(-100%);background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--dsw-alias-fill-elevated) 75%,transparent),transparent);animation:archv-shimmer 1.4s infinite}
|
|
151
153
|
.archv-status{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);z-index:60;background:var(--dsw-alias-fill-elevated);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);padding:9px 16px;border-radius:999px;font-size:12px;box-shadow:0 8px 24px rgb(0 0 0/.18);display:flex;align-items:center;gap:8px;animation:archv-pop .18s ease-out;max-width:min(90vw,420px)}
|
|
152
154
|
.archv-spin{width:12px;height:12px;border:2px solid color-mix(in srgb,var(--dsw-alias-label-secondary) 35%,transparent);border-top-color:var(--dsw-alias-label-secondary);border-radius:50%;animation:archv-rot .8s linear infinite;flex:none}
|
|
@@ -155,24 +157,24 @@ var CSS = `
|
|
|
155
157
|
@keyframes archv-pop{from{opacity:0;transform:translateX(-50%) translateY(10px)}}
|
|
156
158
|
@media (prefers-reduced-motion:reduce){.archv-skel-card::after{animation:none}.archv-card,.archv-btn{transition:none}.archv-status,.archv-spin{animation:none}}
|
|
157
159
|
@media (max-width:640px){.archv-card{flex-direction:column;align-items:stretch;gap:10px}.archv-actions{justify-content:flex-end}.sess-tools{grid-template-columns:1fr}.sess-fbtn,.archv-btn{min-height:40px}}
|
|
158
|
-
.mv-sheet{width:100%;box-sizing:border-box;display:flex;flex-direction:column;gap:12px;margin-top:12px;padding:14px;border:1px solid var(--dsw-alias-border-l2);border-radius:
|
|
160
|
+
.mv-sheet{width:100%;box-sizing:border-box;display:flex;flex-direction:column;gap:12px;margin-top:12px;padding:14px;border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsm-radius-sheet);background:var(--dsw-alias-fill-subtle)}
|
|
159
161
|
.mv-sheet-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
|
|
160
162
|
.mv-sheet-title{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary);margin:0}
|
|
161
163
|
.mv-sheet-close{appearance:none;width:26px;height:26px;color:var(--dsw-alias-label-secondary);background:0 0;border:none;border-radius:7px;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-size:16px;line-height:1}
|
|
162
164
|
.mv-sheet-close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
|
|
163
|
-
.mv-seg{display:flex;gap:2px;padding:2px;background:var(--dsw-alias-fill-elevated);border:1px solid var(--dsw-alias-border-l2);border-radius:
|
|
165
|
+
.mv-seg{display:flex;gap:2px;padding:2px;background:var(--dsw-alias-fill-elevated);border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsm-radius-sheet);width:100%}
|
|
164
166
|
.mv-segbtn{appearance:none;flex:1;min-height:30px;padding:0 12px;border:none;background:transparent;color:var(--dsw-alias-label-secondary);border-radius:8px;font-size:12px;font-weight:500;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;gap:6px}
|
|
165
167
|
.mv-segbtn:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
|
|
166
168
|
.mv-segbtn-on{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);box-shadow:0 1px 2px rgb(0 0 0/.08)}
|
|
167
169
|
.mv-field{display:flex;flex-direction:column;gap:6px}
|
|
168
170
|
.mv-field label.mv-field-label{font-size:12px;font-weight:500;color:var(--dsw-alias-label-secondary)}
|
|
169
|
-
.mv-field select,.mv-field input[type=text]{box-sizing:border-box;appearance:none;width:100%;min-height:34px;padding:0 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:
|
|
171
|
+
.mv-field select,.mv-field input[type=text]{box-sizing:border-box;appearance:none;width:100%;min-height:34px;padding:0 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsm-radius-ctl);background:var(--dsw-alias-fill-elevated);color:var(--dsw-alias-label-primary);font-size:12px;font-family:inherit}
|
|
170
172
|
.mv-field select:focus-visible,.mv-field input[type=text]:focus-visible,.mv-sheet-close:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}
|
|
171
173
|
.mv-browse-row{display:flex;align-items:center;gap:8px}
|
|
172
174
|
.mv-browse-row input[type=text]{flex:1;min-width:0}
|
|
173
175
|
.mv-foot{display:flex;justify-content:flex-end;align-items:center;gap:8px;margin-top:2px}
|
|
174
176
|
@media (max-width:640px){.archv-row{flex-wrap:wrap}.mv-sheet{padding:12px}}
|
|
175
|
-
.dtl-sheet{margin-top:12px;padding:14px;border:1px solid var(--dsw-alias-border-l2);border-radius:
|
|
177
|
+
.dtl-sheet{margin-top:12px;padding:14px;border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsm-radius-sheet);background:var(--dsw-alias-fill-subtle)}
|
|
176
178
|
.dtl-sheet-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
|
|
177
179
|
.dtl-sheet-title{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary);margin:0}
|
|
178
180
|
.dtl-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(130px,1fr));gap:8px;margin-top:10px}
|
|
@@ -193,7 +195,7 @@ var CSS = `
|
|
|
193
195
|
.more-wrap{position:relative;flex:none}
|
|
194
196
|
.more-btn{appearance:none;width:28px;height:28px;border:none;border-radius:8px;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;line-height:1}
|
|
195
197
|
.more-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
|
|
196
|
-
.more-menu{position:absolute;top:calc(100% + 4px);right:0;z-index:60;min-width:160px;padding:5px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l3);border-radius:
|
|
198
|
+
.more-menu{position:absolute;top:calc(100% + 4px);right:0;z-index:60;min-width:160px;padding:5px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l3);border-radius:var(--dsm-radius-sheet);box-shadow:0 10px 32px rgb(0 0 0/.24);display:flex;flex-direction:column;gap:1px}
|
|
197
199
|
.more-item{appearance:none;display:flex;align-items:center;gap:8px;width:100%;padding:7px 10px;border:none;background:transparent;color:var(--dsw-alias-label-primary);border-radius:7px;font-size:12.5px;cursor:pointer;white-space:nowrap;text-align:left}
|
|
198
200
|
.more-item:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
199
201
|
.more-item-danger{color:var(--dsw-alias-state-error-primary)}
|
|
@@ -436,9 +438,13 @@ function SessionPanel({ workspacesSvc }) {
|
|
|
436
438
|
const w = workspaces.find((x) => x.workspaceId === id);
|
|
437
439
|
return w ? w.path : "";
|
|
438
440
|
};
|
|
439
|
-
const actionCapability = (name) =>
|
|
440
|
-
|
|
441
|
-
|
|
441
|
+
const actionCapability = (name, legacy) => {
|
|
442
|
+
const source = capabilities && capabilities.actions;
|
|
443
|
+
return source && (source[name] || legacy && source[legacy]) || { available: false, reason: "\u6B63\u5728\u68C0\u67E5\u5F53\u524D DSH \u7684\u517C\u5BB9\u80FD\u529B\u2026" };
|
|
444
|
+
};
|
|
445
|
+
const canPurge = actionCapability("physicalPurge", "purge");
|
|
446
|
+
const canMove = actionCapability("relocateSession", "move");
|
|
447
|
+
const canRestoreTrash = actionCapability("restoreIndexedSession", "restoreTrash");
|
|
442
448
|
const archivedList = sessions ? sessions.filter((x) => x.archived) : [];
|
|
443
449
|
const activeList = sessions ? sessions.filter((x) => !x.archived) : [];
|
|
444
450
|
const starredList = starredOf(sessions);
|
|
@@ -579,9 +585,9 @@ function SessionPanel({ workspacesSvc }) {
|
|
|
579
585
|
const restoreTrash = (sid) => {
|
|
580
586
|
if (trashBusy) return;
|
|
581
587
|
setTrashBusy(sid);
|
|
582
|
-
postJSON("/archived-sessions/trash/restore", { sessionId: sid }).then(() => {
|
|
588
|
+
postJSON("/archived-sessions/trash/restore", { sessionId: sid }).then((r) => {
|
|
583
589
|
setTrashBusy(null);
|
|
584
|
-
showToast("\u5DF2\u6062\u590D\u4F1A\u8BDD");
|
|
590
|
+
showToast(r && r.workspaceGone ? "\u5DF2\u6062\u590D\u4F1A\u8BDD\uFF08\u539F\u5DE5\u4F5C\u533A\u5DF2\u5220\u9664\uFF0C\u4F1A\u8BDD\u6682\u5F52\u300C\u672A\u5206\u7EC4\u300D\uFF09" : "\u5DF2\u6062\u590D\u4F1A\u8BDD");
|
|
585
591
|
loadTrash();
|
|
586
592
|
refresh();
|
|
587
593
|
}).catch((e) => {
|
|
@@ -1217,10 +1223,16 @@ function SessionPanel({ workspacesSvc }) {
|
|
|
1217
1223
|
] }),
|
|
1218
1224
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "sess-field", children: [
|
|
1219
1225
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { children: "\u6C38\u4E45\u6E05\u7406" }),
|
|
1220
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn archv-del", disabled: trashBusy !== null || !trash.length || !canPurge.available, title: !canPurge.available ? canPurge.reason :
|
|
1226
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn archv-del", disabled: trashBusy !== null || !trash.length || !canPurge.available, "aria-disabled": !canPurge.available, title: !canPurge.available ? canPurge.reason : "\u7269\u7406\u5220\u9664\u8FD9\u4E9B\u65E5\u5FD7\uFF0C\u91CA\u653E\u78C1\u76D8\u7A7A\u95F4", onClick: () => setPurgeTarget("__all"), children: "\u6E05\u7A7A\u56DE\u6536\u7AD9" })
|
|
1221
1227
|
] })
|
|
1222
1228
|
] }),
|
|
1223
|
-
!canPurge.available && /* @__PURE__ */ (0, import_jsx_runtime.
|
|
1229
|
+
!canPurge.available && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "archv-empty", role: "status", children: [
|
|
1230
|
+
canPurge.reason,
|
|
1231
|
+
"\u3002\u56DE\u6536\u7AD9\u6761\u76EE\u4F1A\u4E00\u76F4\u4FDD\u7559\uFF0C\u53EF\u968F\u65F6\u6062\u590D\uFF1B\u5F53\u524D DSH \u7248\u672C\u4E0B\u79FB\u5165\u56DE\u6536\u7AD9",
|
|
1232
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: "\u4E0D\u4F1A\u91CA\u653E\u78C1\u76D8\u7A7A\u95F4" }),
|
|
1233
|
+
"\uFF0C\u4F1A\u8BDD\u65E5\u5FD7\u4ECD\u5B8C\u6574\u4FDD\u7559\u5728\u539F\u5DE5\u4F5C\u533A\u76EE\u5F55\u3002"
|
|
1234
|
+
] }),
|
|
1235
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dtl-note", children: "\u56DE\u6536\u7AD9\u662F\u8F6F\u5220\u9664\uFF1A\u65E5\u5FD7\u4ECD\u7559\u5728\u539F\u5DE5\u4F5C\u533A\u76EE\u5F55\uFF0C\u300C\u5F7B\u5E95\u5220\u9664\u300D\u624D\u662F\u771F\u6B63\u91CA\u653E\u78C1\u76D8\u7A7A\u95F4\u7684\u4E00\u6B65\uFF08\u5F53\u524D\u7248\u672C\u672A\u652F\u6301\u65F6\u4F1A\u4FDD\u6301\u7981\u7528\uFF09\u3002" }),
|
|
1224
1236
|
trashCheck && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: trashCheck.missing ? "archv-err" : "archv-empty", role: "status", children: [
|
|
1225
1237
|
"\u6821\u9A8C\u5B8C\u6210\uFF1A",
|
|
1226
1238
|
trashCheck.healthy,
|
|
@@ -1234,7 +1246,7 @@ function SessionPanel({ workspacesSvc }) {
|
|
|
1234
1246
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsm-trash-name", title: t.sessionId, children: t.title || t.sessionId }),
|
|
1235
1247
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsm-trash-date", children: fmtDate(t.deletedAt) }),
|
|
1236
1248
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dsm-trash-actions", children: [
|
|
1237
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", disabled: trashBusy !== null, onClick: () => restoreTrash(t.sessionId), children: "\u6062\u590D" }),
|
|
1249
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", disabled: trashBusy !== null || !canRestoreTrash.available, title: !canRestoreTrash.available ? canRestoreTrash.reason : "\u6062\u590D\u5230\u5220\u9664\u524D\u7684\u4F4D\u7F6E\u4E0E\u5F52\u6863\u72B6\u6001", onClick: () => restoreTrash(t.sessionId), children: "\u6062\u590D" }),
|
|
1238
1250
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn archv-del", disabled: trashBusy !== null || !canPurge.available, title: !canPurge.available ? canPurge.reason : void 0, onClick: () => setPurgeTarget(t.sessionId), children: "\u5F7B\u5E95\u5220\u9664" })
|
|
1239
1251
|
] })
|
|
1240
1252
|
] }, t.sessionId)) })
|
|
@@ -1245,7 +1257,7 @@ function SessionPanel({ workspacesSvc }) {
|
|
|
1245
1257
|
purgeTarget === "__all" ? "\u5168\u90E8\u56DE\u6536\u7AD9\u4F1A\u8BDD" : "\u8FD9\u4E2A\u4F1A\u8BDD",
|
|
1246
1258
|
"\uFF1F"
|
|
1247
1259
|
] }),
|
|
1248
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dlg-text", children: "\u6B64\u64CD\u4F5C\u4F1A\u7269\u7406\u5220\u9664\u65E5\u5FD7\uFF0C\u65E0\u6CD5\u6062\u590D\u3002\u5F52\u6863\u3001\u7B5B\u9009\u548C\u91CD\u65B0\u5B89\u88C5\u63D2\u4EF6\u90FD\u4E0D\u80FD\u627E\u56DE\u8FD9\u4E9B\u6570\u636E\u3002" }),
|
|
1260
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dlg-text", children: "\u6B64\u64CD\u4F5C\u4F1A\u7269\u7406\u5220\u9664\u65E5\u5FD7\u5E76\u91CA\u653E\u78C1\u76D8\u7A7A\u95F4\uFF0C\u65E0\u6CD5\u6062\u590D\u3002\u5F52\u6863\u3001\u7B5B\u9009\u548C\u91CD\u65B0\u5B89\u88C5\u63D2\u4EF6\u90FD\u4E0D\u80FD\u627E\u56DE\u8FD9\u4E9B\u6570\u636E\u3002" }),
|
|
1249
1261
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dlg-actions", children: [
|
|
1250
1262
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn", onClick: () => setPurgeTarget(null), children: "\u53D6\u6D88" }),
|
|
1251
1263
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "archv-btn archv-del", onClick: () => {
|
|
@@ -1356,57 +1368,83 @@ async function dsmLoadCapabilities() {
|
|
|
1356
1368
|
}
|
|
1357
1369
|
return dsmCapabilities;
|
|
1358
1370
|
}
|
|
1359
|
-
function dsmActionCapability(name) {
|
|
1360
|
-
|
|
1371
|
+
function dsmActionCapability(name, legacy) {
|
|
1372
|
+
const source = dsmCapabilities && dsmCapabilities.actions;
|
|
1373
|
+
return source ? source[name] || legacy && source[legacy] || null : null;
|
|
1361
1374
|
}
|
|
1362
1375
|
async function dsmLoadTrashIds() {
|
|
1363
1376
|
try {
|
|
1364
1377
|
const r = await postJSON("/archived-sessions/sidebar-state", {});
|
|
1365
1378
|
dsmTrashIds = new Set((r && r.trashedSessionIds || []).map(String));
|
|
1366
1379
|
dsmServerPurgedIds = new Set((r && r.purgedSessionIds || []).map(String));
|
|
1380
|
+
for (const id of [...dsmPendingPurged]) {
|
|
1381
|
+
if (dsmServerPurgedIds.has(id)) dsmPendingPurged.delete(id);
|
|
1382
|
+
}
|
|
1367
1383
|
dsmAuthoritativeTitles = new Map(Object.entries(r && r.titles || {}).map(([id, title]) => [String(id), String(title)]));
|
|
1368
1384
|
if (dsmRepaintDots) dsmRepaintDots();
|
|
1369
1385
|
} catch (e) {
|
|
1370
1386
|
}
|
|
1371
1387
|
return dsmTrashIds;
|
|
1372
1388
|
}
|
|
1373
|
-
var
|
|
1374
|
-
var dsmPurgedIds = null;
|
|
1389
|
+
var dsmPendingPurged = /* @__PURE__ */ new Set();
|
|
1375
1390
|
function dsmLoadPurged() {
|
|
1376
|
-
|
|
1377
|
-
try {
|
|
1378
|
-
dsmPurgedIds = new Set(JSON.parse(localStorage.getItem(DSM_KEY_PURGED) || "[]"));
|
|
1379
|
-
} catch (e) {
|
|
1380
|
-
dsmPurgedIds = /* @__PURE__ */ new Set();
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1383
|
-
dsmServerPurgedIds.forEach((id) => dsmPurgedIds.add(id));
|
|
1384
|
-
return dsmPurgedIds;
|
|
1385
|
-
}
|
|
1386
|
-
function dsmSavePurged() {
|
|
1387
|
-
try {
|
|
1388
|
-
localStorage.setItem(DSM_KEY_PURGED, JSON.stringify([...dsmLoadPurged()]));
|
|
1389
|
-
} catch (e) {
|
|
1390
|
-
}
|
|
1391
|
+
return /* @__PURE__ */ new Set([...dsmServerPurgedIds, ...dsmPendingPurged]);
|
|
1391
1392
|
}
|
|
1392
1393
|
function dsmMarkPurged(ids) {
|
|
1393
|
-
|
|
1394
|
-
ids.forEach((id) => s.add(String(id)));
|
|
1395
|
-
dsmSavePurged();
|
|
1394
|
+
ids.forEach((id) => dsmPendingPurged.add(String(id)));
|
|
1396
1395
|
if (dsmRepaintDots) dsmRepaintDots();
|
|
1397
1396
|
}
|
|
1397
|
+
var SIDEBAR_ADAPTER_VERSION = 3;
|
|
1398
|
+
var SIDEBAR_ADAPTER_MAX_MISSES = 200;
|
|
1399
|
+
function createSidebarAdapter() {
|
|
1400
|
+
let disabled = false;
|
|
1401
|
+
let misses = 0;
|
|
1402
|
+
const findFiber = (el) => {
|
|
1403
|
+
const k = Object.keys(el).find((kk) => kk.startsWith("__reactFiber") || kk.startsWith("__reactInternalInstance"));
|
|
1404
|
+
return k ? el[k] : null;
|
|
1405
|
+
};
|
|
1406
|
+
const recognize = (row) => {
|
|
1407
|
+
const out = { node: null, group: null };
|
|
1408
|
+
if (disabled || !row || typeof row !== "object") return out;
|
|
1409
|
+
let f = findFiber(row);
|
|
1410
|
+
let guard = 0;
|
|
1411
|
+
while (f && guard++ < 300) {
|
|
1412
|
+
const props = f.memoizedProps;
|
|
1413
|
+
if (props && props.node && typeof props.node === "object") out.node = props.node;
|
|
1414
|
+
if (props && props.group && typeof props.group === "object") out.group = props.group;
|
|
1415
|
+
f = f.return;
|
|
1416
|
+
}
|
|
1417
|
+
if (!out.node && !out.group) {
|
|
1418
|
+
if (++misses >= SIDEBAR_ADAPTER_MAX_MISSES) {
|
|
1419
|
+
disabled = true;
|
|
1420
|
+
try {
|
|
1421
|
+
console.warn("[dsh-sessions-manager] \u4FA7\u680F\u6CE8\u5165 adapter v" + SIDEBAR_ADAPTER_VERSION + " \u5DF2\u505C\u7528\uFF1A\u672A\u8BC6\u522B\u5230\u5DF2\u77E5\u7684 DSH \u4FA7\u680F\u8282\u70B9\u7ED3\u6784\uFF08\u4E0A\u6E38\u53EF\u80FD\u5DF2\u6539\u7248\uFF09");
|
|
1422
|
+
} catch (e) {
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
} else if (misses > 0) {
|
|
1426
|
+
misses = 0;
|
|
1427
|
+
}
|
|
1428
|
+
return out;
|
|
1429
|
+
};
|
|
1430
|
+
return {
|
|
1431
|
+
version: SIDEBAR_ADAPTER_VERSION,
|
|
1432
|
+
get disabled() {
|
|
1433
|
+
return disabled;
|
|
1434
|
+
},
|
|
1435
|
+
findFiber,
|
|
1436
|
+
recognize
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
var sidebarAdapter = createSidebarAdapter();
|
|
1398
1440
|
function installSidebarSessionMenuAug() {
|
|
1399
1441
|
if (typeof document === "undefined") return;
|
|
1400
1442
|
const AUG = "data-dsm-aug";
|
|
1401
1443
|
let styleInjected = false;
|
|
1402
1444
|
let activeSubClose = null;
|
|
1403
1445
|
let hoverTimer = null;
|
|
1404
|
-
const findFiber = (el) => {
|
|
1405
|
-
const k = Object.keys(el).find((kk) => kk.startsWith("__reactFiber") || kk.startsWith("__reactInternalInstance"));
|
|
1406
|
-
return k ? el[k] : null;
|
|
1407
|
-
};
|
|
1408
1446
|
const sessionInfoFromMenu = (menuEl) => {
|
|
1409
|
-
let f = findFiber(menuEl);
|
|
1447
|
+
let f = sidebarAdapter.findFiber(menuEl);
|
|
1410
1448
|
let guard = 0;
|
|
1411
1449
|
while (f && guard++ < 300) {
|
|
1412
1450
|
const p = f.memoizedProps;
|
|
@@ -1589,7 +1627,7 @@ function installSidebarSessionMenuAug() {
|
|
|
1589
1627
|
const move = mk("\u79FB\u52A8\u4F1A\u8BDD", ICON_MOVE, false);
|
|
1590
1628
|
const del = mk("\u5220\u9664\u4F1A\u8BDD", ICON_DEL, true);
|
|
1591
1629
|
const mark = mk(dsmLoadManual().has(info.id) ? "\u6807\u8BB0\u5DF2\u8BFB" : "\u6807\u8BB0\u672A\u8BFB", ICON_UNREAD, false);
|
|
1592
|
-
const moveCapability = dsmActionCapability("move");
|
|
1630
|
+
const moveCapability = dsmActionCapability("relocateSession") || dsmActionCapability("move");
|
|
1593
1631
|
if (!moveCapability || !moveCapability.available) {
|
|
1594
1632
|
move.btn.disabled = true;
|
|
1595
1633
|
move.btn.title = moveCapability && moveCapability.reason || "\u6B63\u5728\u68C0\u67E5\u5F53\u524D\u7248\u672C\u7684\u79FB\u52A8\u80FD\u529B";
|
|
@@ -1628,6 +1666,7 @@ function installSidebarSessionMenuAug() {
|
|
|
1628
1666
|
};
|
|
1629
1667
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
1630
1668
|
const obs = new MutationObserver(() => {
|
|
1669
|
+
if (sidebarAdapter.disabled) return;
|
|
1631
1670
|
const menus = document.querySelectorAll('body > [role="menu"]');
|
|
1632
1671
|
menus.forEach((menuEl) => {
|
|
1633
1672
|
if (seen.has(menuEl)) return;
|
|
@@ -1651,21 +1690,7 @@ function installSidebarStatusDots() {
|
|
|
1651
1690
|
s.textContent = SIDEBAR_AUG_CSS;
|
|
1652
1691
|
document.head.appendChild(s);
|
|
1653
1692
|
}
|
|
1654
|
-
const
|
|
1655
|
-
const k = Object.keys(el).find((kk) => kk.startsWith("__reactFiber") || kk.startsWith("__reactInternalInstance"));
|
|
1656
|
-
return k ? el[k] : null;
|
|
1657
|
-
};
|
|
1658
|
-
const fiberProp = (el, pred) => {
|
|
1659
|
-
let f = findFiber(el);
|
|
1660
|
-
let g = 0;
|
|
1661
|
-
while (f && g++ < 300) {
|
|
1662
|
-
const p = f.memoizedProps;
|
|
1663
|
-
if (p && pred(p)) return pred(p);
|
|
1664
|
-
f = f.return;
|
|
1665
|
-
}
|
|
1666
|
-
return null;
|
|
1667
|
-
};
|
|
1668
|
-
const rowNode = (row) => fiberProp(row, (p) => p.node && typeof p.node.id === "string" && p.node.id ? p.node : null);
|
|
1693
|
+
const rowNode = (row) => sidebarAdapter.recognize(row).node;
|
|
1669
1694
|
const rowId = (row) => {
|
|
1670
1695
|
const node = rowNode(row);
|
|
1671
1696
|
return node ? node.id : null;
|
|
@@ -1690,6 +1715,7 @@ function installSidebarStatusDots() {
|
|
|
1690
1715
|
const manualUnread = dsmLoadManual();
|
|
1691
1716
|
const titleInitializedRows = /* @__PURE__ */ new WeakSet();
|
|
1692
1717
|
const paint = () => {
|
|
1718
|
+
if (sidebarAdapter.disabled) return;
|
|
1693
1719
|
const activeId = activeRowId();
|
|
1694
1720
|
if (activeId !== curActive && activeId && manualUnread.has(activeId)) {
|
|
1695
1721
|
manualUnread.delete(activeId);
|
|
@@ -1752,10 +1778,6 @@ function installSidebarStatusDots() {
|
|
|
1752
1778
|
});
|
|
1753
1779
|
};
|
|
1754
1780
|
dsmRepaintDots = paint;
|
|
1755
|
-
const tick = () => {
|
|
1756
|
-
if (++dsmTrashTick % 8 === 0) dsmLoadTrashIds();
|
|
1757
|
-
paint();
|
|
1758
|
-
};
|
|
1759
1781
|
let raf = 0;
|
|
1760
1782
|
const schedulePaint = () => {
|
|
1761
1783
|
if (raf) return;
|
|
@@ -1764,38 +1786,38 @@ function installSidebarStatusDots() {
|
|
|
1764
1786
|
paint();
|
|
1765
1787
|
});
|
|
1766
1788
|
};
|
|
1789
|
+
const FALLBACK_TICK_MS = 4e3;
|
|
1790
|
+
const tick = () => {
|
|
1791
|
+
if (typeof document !== "undefined" && document.hidden) return;
|
|
1792
|
+
if (++dsmTrashTick % 8 === 0) dsmLoadTrashIds();
|
|
1793
|
+
paint();
|
|
1794
|
+
};
|
|
1767
1795
|
tick();
|
|
1768
1796
|
dsmLoadTrashIds();
|
|
1769
1797
|
paint();
|
|
1770
1798
|
const obs = new MutationObserver(schedulePaint);
|
|
1771
|
-
obs.observe(document.body, {
|
|
1772
|
-
|
|
1799
|
+
obs.observe(document.body, {
|
|
1800
|
+
childList: true,
|
|
1801
|
+
subtree: true,
|
|
1802
|
+
attributes: true,
|
|
1803
|
+
attributeFilter: ["data-state", "aria-selected", "class", "style"],
|
|
1804
|
+
characterData: true
|
|
1805
|
+
});
|
|
1806
|
+
setInterval(tick, FALLBACK_TICK_MS);
|
|
1773
1807
|
}
|
|
1774
1808
|
function installSidebarWorkspaceDrag() {
|
|
1775
1809
|
if (typeof document === "undefined") return;
|
|
1776
1810
|
let sessions = /* @__PURE__ */ new Map();
|
|
1777
1811
|
let dragging = null;
|
|
1778
1812
|
let moving = false;
|
|
1779
|
-
const
|
|
1780
|
-
const
|
|
1781
|
-
return
|
|
1782
|
-
};
|
|
1783
|
-
const fiberNodes = (el) => {
|
|
1784
|
-
const out = [];
|
|
1785
|
-
let fiber = findFiber(el);
|
|
1786
|
-
let guard = 0;
|
|
1787
|
-
while (fiber && guard++ < 300) {
|
|
1788
|
-
const props = fiber.memoizedProps;
|
|
1789
|
-
if (props && props.node && typeof props.node === "object") out.push(props.node);
|
|
1790
|
-
if (props && props.group && typeof props.group === "object") out.push(props.group);
|
|
1791
|
-
fiber = fiber.return;
|
|
1792
|
-
}
|
|
1793
|
-
return out;
|
|
1813
|
+
const sessionForRow = (row) => {
|
|
1814
|
+
const { node, group } = sidebarAdapter.recognize(row);
|
|
1815
|
+
return sessionForNodes(group ? [node, group].filter(Boolean) : [node], sessions);
|
|
1794
1816
|
};
|
|
1795
|
-
const sessionForRow = (row) => sessionForNodes(fiberNodes(row), sessions);
|
|
1796
1817
|
const workspaceForRow = (row) => {
|
|
1797
1818
|
if (sessionForRow(row)) return null;
|
|
1798
|
-
|
|
1819
|
+
const { group } = sidebarAdapter.recognize(row);
|
|
1820
|
+
return group ? workspaceForNodes([group]) : null;
|
|
1799
1821
|
};
|
|
1800
1822
|
const eventRow = (event) => {
|
|
1801
1823
|
for (const item of event.composedPath ? event.composedPath() : []) {
|
|
@@ -1815,6 +1837,7 @@ function installSidebarWorkspaceDrag() {
|
|
|
1815
1837
|
document.querySelectorAll(".dsm-drag-source,.dsm-drop-target").forEach((el) => el.classList.remove("dsm-drag-source", "dsm-drop-target"));
|
|
1816
1838
|
};
|
|
1817
1839
|
const decorateRows = () => {
|
|
1840
|
+
if (sidebarAdapter.disabled) return;
|
|
1818
1841
|
document.querySelectorAll('[role="treeitem"]').forEach((row) => {
|
|
1819
1842
|
const session = sessionForRow(row);
|
|
1820
1843
|
const ws = workspaceForRow(row);
|
|
@@ -1839,7 +1862,8 @@ function installSidebarWorkspaceDrag() {
|
|
|
1839
1862
|
maybeRefresh();
|
|
1840
1863
|
}, true);
|
|
1841
1864
|
document.addEventListener("dragstart", (event) => {
|
|
1842
|
-
|
|
1865
|
+
if (sidebarAdapter.disabled) return;
|
|
1866
|
+
const moveCapability = dsmActionCapability("relocateSession") || dsmActionCapability("move");
|
|
1843
1867
|
if (!moveCapability || !moveCapability.available) return;
|
|
1844
1868
|
const row = eventRow(event);
|
|
1845
1869
|
const item = row && sessionForRow(row);
|