dsh-better-workspace 0.17.0 → 0.17.1

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/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-external/dsh-better-workspace",
3
- "version": "0.17.0",
3
+ "version": "0.17.1",
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.",
6
6
  "engines": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-better-workspace",
3
- "version": "0.17.0",
3
+ "version": "0.17.1",
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); add-workspace rides the official directory flow.",
5
5
  "type": "module",
6
6
  "repository": {
package/src/client.js CHANGED
@@ -3294,6 +3294,11 @@ window.__ModuleLoader__.load({
3294
3294
  '.bw-seg-btn-on{background:var(--dsw-alias-bg-layer-2,rgba(127,127,127,.16));color:var(--dsw-alias-label-primary,#e6e6e6);font-weight:500}',
3295
3295
  '.bw-seg-btn+.bw-seg-btn{border-left:1px solid var(--dsw-alias-border-l1,rgba(127,127,127,.25))}',
3296
3296
  '.bw-gn-hint{font-size:12px;color:var(--dsw-alias-label-tertiary,#9a9a9a)}',
3297
+ // A container-only node (a workspace name-group in the session layer):
3298
+ // still expandable, but it carries no workspaceId to file against.
3299
+ '.bw-gn-row-hold{cursor:default}',
3300
+ '.bw-gn-row-hold:hover{background:transparent}',
3301
+ '.bw-gn-row-hold .bw-gn-label{color:var(--dsw-alias-label-secondary,#b8b8b8)}',
3297
3302
  '.bw-gn-empty{font-size:12px;color:var(--dsw-alias-label-tertiary,#9a9a9a);padding:10px 8px;text-align:center}',
3298
3303
  '.bw-gn-tree{max-height:250px;overflow:auto;padding:4px;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1,rgba(127,127,127,.22));border-radius:8px;background:var(--dsw-alias-bg-layer-2,rgba(127,127,127,.06))}',
3299
3304
  '.bw-gn-row{display:flex;align-items:center;gap:6px;min-height:26px;padding-right:8px;border-radius:6px;cursor:pointer;user-select:none}',
@@ -3837,7 +3842,7 @@ window.__ModuleLoader__.load({
3837
3842
  const [error, setError] = React.useState('')
3838
3843
  const plan = treeOf(kind)
3839
3844
  const toggle = (id) => setOpenKeys((prev) => ({ ...prev, [id]: !prev[id] }))
3840
- const pick = (node) => { setPicked(node); setError('') }
3845
+ const pick = (node) => { if (node.pickable === false) return; setPicked(node); setError('') }
3841
3846
  const submit = () => {
3842
3847
  const clean = String(name).split('/').filter((s) => s !== '').join('/')
3843
3848
  if (clean === '') { setError(t('group.new.empty')); return }
@@ -3854,7 +3859,7 @@ window.__ModuleLoader__.load({
3854
3859
  const expanded = openKeys[node.id] === true || (depth === 0 && openKeys[node.id] !== false)
3855
3860
  out.push(E('div', {
3856
3861
  key: 'n-' + node.id,
3857
- className: cls('bw-gn-row', picked && picked.id === node.id && 'bw-gn-row-on'),
3862
+ className: cls('bw-gn-row', node.pickable === false && 'bw-gn-row-hold', picked && picked.id === node.id && 'bw-gn-row-on'),
3858
3863
  style: { paddingLeft: 6 + depth * 14 },
3859
3864
  role: 'treeitem',
3860
3865
  'aria-selected': picked && picked.id === node.id ? 'true' : 'false',
@@ -5384,22 +5389,60 @@ window.__ModuleLoader__.load({
5384
5389
  children: sessGroupNodesOf(g, workspaceId),
5385
5390
  }))
5386
5391
  const newGroupTreeOf = (kind) => {
5392
+ // The container tree MIRRORS the sidebar's current view mode (v0.17.1):
5393
+ // "workspace tree" offers the real hierarchy (disk nesting + name
5394
+ // groups); the one-level modes ("workspaces" / "flat") render no
5395
+ // hierarchy to mirror, so they fall back to a flat workspace list.
5396
+ // Offering a nesting the sidebar is not showing would be a lie about
5397
+ // where the new group lands.
5398
+ const treeView = groupBy === 'workspace-tree'
5387
5399
  if (kind === 'workspace') {
5388
5400
  // "Top level" IS a real target here (a group at the root of the
5389
5401
  // workspace tree), so it is a node like any other.
5390
- return { hint: null, nodes: [{ id: '|', scope: '', path: '', label: t('group.new.root'), kind: 'folder', children: wsGroupNodesOf(tree) }] }
5402
+ return {
5403
+ hint: null,
5404
+ nodes: [{
5405
+ id: '|', scope: '', path: '', label: t('group.new.root'), kind: 'folder',
5406
+ children: treeView ? wsGroupNodesOf(tree) : [],
5407
+ }],
5408
+ }
5391
5409
  }
5392
5410
  // A session group lives INSIDE one workspace (folders.sess is keyed by
5393
- // workspaceId), so there is no "top level" to declare into: the
5394
- // workspace list is the top level itself, introduced by a plain HINT
5395
- // rather than wrapped in a fake root node (v0.17.1 — a header row that
5396
- // looked like a tree node read as a container you could pick).
5397
- const nodes = []
5411
+ // workspaceId), so there is no "top level" to declare into the
5412
+ // workspace tree IS the top level, introduced by a plain hint rather
5413
+ // than wrapped in a fake root node (a header row that looked like a
5414
+ // tree node read as a container you could pick).
5415
+ //
5416
+ // The walk follows the SAME tree the sidebar renders (disk nesting
5417
+ // included), not the flat registry list: a child workspace must appear
5418
+ // nested under its parent exactly as it does in "workspace tree" view.
5419
+ // Name-group folders are containers here — a session group cannot be
5420
+ // filed against one (they carry no workspaceId) — so they expand but
5421
+ // refuse selection.
5422
+ const sessNodesOf = (node) => {
5423
+ const out = []
5424
+ for (const f of node.folders || []) {
5425
+ out.push({ id: f.scope + '|' + f.path, scope: '', path: '', label: f.name, kind: 'folder', pickable: false, children: sessNodesOf(f) })
5426
+ }
5427
+ for (const w of node.workspaces || []) {
5428
+ const inner = sessGroupNodesOf(buildSessionTree(sessionsOf(w), sessionSlash, sessFolders, w.workspaceId), w.workspaceId)
5429
+ const subNodes = w.sub ? sessNodesOf(w.sub) : []
5430
+ out.push({
5431
+ id: w.workspaceId + '|', scope: w.workspaceId, path: '', label: w.leaf || w.title, kind: 'ws',
5432
+ children: [...inner, ...subNodes],
5433
+ })
5434
+ }
5435
+ return out
5436
+ }
5437
+ if (treeView) return { hint: t('group.new.pickWorkspace'), nodes: sessNodesOf(tree) }
5438
+ // One-level modes: every workspace sits at the root, exactly as the
5439
+ // sidebar draws it (raw items — there is no .sub level to nest here).
5440
+ const flat = []
5398
5441
  for (const w of items) {
5399
5442
  const inner = sessGroupNodesOf(buildSessionTree(sessionsOf(w), sessionSlash, sessFolders, w.workspaceId), w.workspaceId)
5400
- nodes.push({ id: w.workspaceId + '|', scope: w.workspaceId, path: '', label: w.leaf || w.title, kind: 'ws', children: inner })
5443
+ flat.push({ id: w.workspaceId + '|', scope: w.workspaceId, path: '', label: w.leaf || w.title, kind: 'ws', children: inner })
5401
5444
  }
5402
- return { hint: t('group.new.pickWorkspace'), nodes }
5445
+ return { hint: t('group.new.pickWorkspace'), nodes: flat }
5403
5446
  }
5404
5447
  /**
5405
5448
  * Picker entries for the header button: every workspace, then its