dsh-better-workspace 0.36.10 → 0.36.12
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.md +1 -1
- package/dsh.plugin.json +1 -1
- package/package.json +1 -1
- package/src/client.js +55 -12
package/README.md
CHANGED
|
@@ -129,7 +129,7 @@ DSH 的侧边栏浏览区是一个公开插槽 `sidebar.workspaces`(single),官
|
|
|
129
129
|
|
|
130
130
|
- 会话**跨工作区**拖拽仍被拒绝(会话归属工作区);同一工作区内的分组归属已随拖拽生效(v0.18.0:拖到别组的行改写前缀,拖到自己的工作区行移出分组,右键也有「移出分组」)。
|
|
131
131
|
- 搜索为本地标题过滤(两层扁平化后逐工作区匹配);宿主内容搜索(`session.search`)计划接回。
|
|
132
|
-
- flat(平铺)
|
|
132
|
+
- flat(平铺)视图未接管,层级树即视图。侧栏切到「单列表」时,新会话页的选择器退化为**一层完整标题**的工作区列表(仍可选,不再分组);切到「按工作区」时(v0.36.11 起),只要「工作区分组」开着(磁盘+名称 / 仅名称),侧栏与新会话页选择器都显示**名称树挂顶层**的结构(名称组与磁盘容器平级,切换即时生效);「工作区分组」设为「磁盘目录」时保持官方的散开平铺。
|
|
133
133
|
- 新会话页选择器里的分组开合是**选择器本地状态**(默认全展开):它不写侧栏的折叠状态,免得选工作区时被侧栏的折叠挡住目标。
|
|
134
134
|
|
|
135
135
|
## 开发
|
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-better-workspace",
|
|
3
|
-
"version": "0.36.
|
|
3
|
+
"version": "0.36.12",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"description": "侧边栏工作区树:按官方磁盘目录嵌套(官方 workspace-tree 语义),可选按名称中的 / 分组(默认关闭,设置里开启);新会话页的工作区选择器同树。Workspace tree for the DSH sidebar workspace list, nested by official disk folders with optional \"/\"-name grouping; the New Session workspace picker shows the same tree.",
|
|
6
6
|
"engines": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-better-workspace",
|
|
3
|
-
"version": "0.36.
|
|
3
|
+
"version": "0.36.12",
|
|
4
4
|
"description": "侧边栏工作区树:按官方磁盘目录嵌套(官方 workspace-tree 语义),可选按名称中的 / 分组(默认关闭,设置里开启);新会话页的工作区选择器同树(同一份视图选项即时同步);添加工作区走官方目录流。Workspace tree for the DSH sidebar: disk-path nesting (official workspace-tree semantics), with optional \"/\"-name grouping (off by default), and the same tree in the New Session workspace picker; add-workspace rides the official directory flow.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
package/src/client.js
CHANGED
|
@@ -8273,7 +8273,15 @@ window.__ModuleLoader__.load({
|
|
|
8273
8273
|
// the user report "拖拽中树会乱/落点漂移". Drop targets are now
|
|
8274
8274
|
// answered by the stable render; nothing re-flows mid-drag.
|
|
8275
8275
|
const tree = React.useMemo(() => {
|
|
8276
|
-
|
|
8276
|
+
// v0.36.11: "workspaces" (groupBy === 'workspace') turns OFF disk
|
|
8277
|
+
// nesting — official semantics — but the NAME tree stays on when the
|
|
8278
|
+
// user enabled one (workspaceGroupMode !== 'disk'). A plain buildTree
|
|
8279
|
+
// mode of 'slash' expresses exactly that: name groups at the root,
|
|
8280
|
+
// every workspace at the top, entry.sub always null.
|
|
8281
|
+
const treeMode = groupBy === 'workspace' && workspaceGroupMode !== 'disk'
|
|
8282
|
+
? 'slash'
|
|
8283
|
+
: workspaceGroupMode
|
|
8284
|
+
const built = buildTree(items, treeMode, wsFolders, folderOrderMap)
|
|
8277
8285
|
if (!compactChains) return built
|
|
8278
8286
|
const folders = built.folders.map((f) => materializeChain(compressTree(f)))
|
|
8279
8287
|
// v0.36.5: keep the MIXED root sequence across chain compression —
|
|
@@ -8285,14 +8293,21 @@ window.__ModuleLoader__.load({
|
|
|
8285
8293
|
? built.seq.map((item) => item.kind === 'folder' ? { kind: 'folder', node: byName.get(item.node.name) || item.node } : item)
|
|
8286
8294
|
: built.seq
|
|
8287
8295
|
return { ...built, folders, workspaces: built.workspaces, seq }
|
|
8288
|
-
}, [items, compactChains, workspaceGroupMode, wsFolders, folderOrderMap])
|
|
8296
|
+
}, [items, compactChains, groupBy, workspaceGroupMode, wsFolders, folderOrderMap])
|
|
8289
8297
|
// UNCOMPRESSED tree, for the new-group dialog only. compressTree merges a
|
|
8290
8298
|
// single-child chain into one row that stands for BOTH a group and the
|
|
8291
8299
|
// workspace under it — fine for drawing, useless for choosing a
|
|
8292
8300
|
// container: one half must stay unselectable and the other must be
|
|
8293
8301
|
// selectable, and a merged row cannot be both. (It also carried no
|
|
8294
8302
|
// `name`, which is how a lone "E" rendered blank.)
|
|
8295
|
-
|
|
8303
|
+
// v0.36.11: same groupBy-aware mode as the rendered tree — the
|
|
8304
|
+
// new-group dialog must mirror the hierarchy the user actually sees.
|
|
8305
|
+
const rawTree = React.useMemo(() => buildTree(
|
|
8306
|
+
items,
|
|
8307
|
+
groupBy === 'workspace' && workspaceGroupMode !== 'disk' ? 'slash' : workspaceGroupMode,
|
|
8308
|
+
wsFolders,
|
|
8309
|
+
folderOrderMap,
|
|
8310
|
+
), [items, groupBy, workspaceGroupMode, wsFolders, folderOrderMap])
|
|
8296
8311
|
// Disk-layer ancestry for drag semantics (same derivation as buildTree).
|
|
8297
8312
|
const diskParentMap = React.useMemo(() => diskParentMapOf(items), [items])
|
|
8298
8313
|
|
|
@@ -8619,7 +8634,10 @@ window.__ModuleLoader__.load({
|
|
|
8619
8634
|
// hierarchy to mirror, so they fall back to a flat workspace list.
|
|
8620
8635
|
// Offering a nesting the sidebar is not showing would be a lie about
|
|
8621
8636
|
// where the new group lands.
|
|
8637
|
+
// v0.36.11: "workspaces" + an enabled name layer shows a root-level
|
|
8638
|
+
// name tree — mirror it instead of claiming there is no hierarchy.
|
|
8622
8639
|
const treeView = groupBy === 'workspace-tree'
|
|
8640
|
+
|| (groupBy === 'workspace' && workspaceGroupMode !== 'disk')
|
|
8623
8641
|
if (kind === 'workspace') {
|
|
8624
8642
|
// "Top level" IS a real target here (a group at the root of the
|
|
8625
8643
|
// workspace tree), so it is a node like any other.
|
|
@@ -10173,6 +10191,17 @@ window.__ModuleLoader__.load({
|
|
|
10173
10191
|
}
|
|
10174
10192
|
const wsHasCurrent = (w) => !!currentId && !!w
|
|
10175
10193
|
&& ((w.sessionIds || []).includes(currentId) || subHasCurrent(w.sub))
|
|
10194
|
+
// Name groups (slash view) have no disk path to prefix-match; the
|
|
10195
|
+
// folder glyph lights up whenever its SUBTREE holds the current
|
|
10196
|
+
// session — the official ProjectRow rule, applied tree-wide.
|
|
10197
|
+
const nodeHoldsCurrent = (level) => {
|
|
10198
|
+
if (!level || !currentId) return false
|
|
10199
|
+
for (const item of levelSeqOf(level)) {
|
|
10200
|
+
if (item.kind === 'ws') { if (wsHasCurrent(item.entry)) return true }
|
|
10201
|
+
else if (nodeHoldsCurrent(item.node)) return true
|
|
10202
|
+
}
|
|
10203
|
+
return false
|
|
10204
|
+
}
|
|
10176
10205
|
const currentWsPath = currentId
|
|
10177
10206
|
? ((items || []).find((w) => (w.sessionIds || []).includes(currentId)) || {}).path
|
|
10178
10207
|
: undefined
|
|
@@ -10208,7 +10237,7 @@ window.__ModuleLoader__.load({
|
|
|
10208
10237
|
custStyle: rowStyleOf('folder:' + idPath),
|
|
10209
10238
|
iconMode: (styleEntry('folder:' + idPath) || {}).icon || 'solid',
|
|
10210
10239
|
pulse: expanded ? null : folderPulseOf(node),
|
|
10211
|
-
active: pathHoldsCurrent(currentWsPath, node.path),
|
|
10240
|
+
active: pathHoldsCurrent(currentWsPath, node.path) || nodeHoldsCurrent(node),
|
|
10212
10241
|
t,
|
|
10213
10242
|
})]
|
|
10214
10243
|
if (expanded) {
|
|
@@ -10263,14 +10292,28 @@ window.__ModuleLoader__.load({
|
|
|
10263
10292
|
} else if (groupBy === 'flat') {
|
|
10264
10293
|
bodyRows.push(...renderFlatRows())
|
|
10265
10294
|
} else if (groupBy === 'workspace') {
|
|
10266
|
-
|
|
10267
|
-
|
|
10268
|
-
|
|
10269
|
-
|
|
10270
|
-
|
|
10271
|
-
|
|
10272
|
-
|
|
10273
|
-
|
|
10295
|
+
if (workspaceGroupMode === 'disk') {
|
|
10296
|
+
// Official 'workspace' mode (v0.13): one level — every workspace at
|
|
10297
|
+
// the root, no name groups, no disk nesting, no chain compression.
|
|
10298
|
+
// Session rows keep the slash toggle; disk-nested children do not
|
|
10299
|
+
// recurse here because raw items carry no .sub level.
|
|
10300
|
+
// flatWorkspaceEntry, never the raw item: see its note — the raw
|
|
10301
|
+
// one has no `leaf` and the row would render nameless.
|
|
10302
|
+
for (const workspace of items || []) {
|
|
10303
|
+
bodyRows.push(...renderWorkspaceEntry({ workspace: flatWorkspaceEntry(workspace) }, 0, wsPulseOf(workspace)))
|
|
10304
|
+
}
|
|
10305
|
+
} else {
|
|
10306
|
+
// v0.36.11: with a NAME layer enabled (disk-slash / slash), the
|
|
10307
|
+
// official scatter contradicts the user's mental model — the name
|
|
10308
|
+
// tree the sidebar has been rendering all along should stay a tree,
|
|
10309
|
+
// just lifted to the root (disk nesting OFF = 'slash' mode in the
|
|
10310
|
+
// tree memo above). Same render loop as the tree branch below:
|
|
10311
|
+
// mixed sequence, drag events, ungrouped block all apply.
|
|
10312
|
+
for (const item of levelSeqOf(tree)) {
|
|
10313
|
+
bodyRows.push(...(item.kind === 'ws'
|
|
10314
|
+
? renderWorkspaceEntry({ workspace: item.entry }, 0, wsPulseOf(item.entry))
|
|
10315
|
+
: renderPlainFolder(item.node, 0)))
|
|
10316
|
+
}
|
|
10274
10317
|
}
|
|
10275
10318
|
bodyRows.push(...renderUngroupedBlock())
|
|
10276
10319
|
} else {
|