dsh-better-workspace 0.7.0 → 0.7.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/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-external/dsh-better-workspace",
3
- "version": "0.6.0",
3
+ "version": "0.7.2",
4
4
  "main": "./src/index.js",
5
5
  "description": "侧边栏工作区层级树:名称中的 / 即虚拟分组(web/前端 · web/后端),添加工作区的目录流附所属分组弹窗,重命名即时重排层级,可新建空分组。Hierarchy tree for the DSH sidebar workspace list.",
6
6
  "engines": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-better-workspace",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "DSH web plugin: a hierarchical workspace tree for the sidebar. Workspace titles containing \"/\" group into virtual folders (web/前端 · web/后端); the add-workspace directory flow gains a parent-group popup; renames re-derive the tree; a new-folder button creates empty levels.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -43,7 +43,8 @@
43
43
  "LICENSE"
44
44
  ],
45
45
  "scripts": {
46
- "test": "node --test tests/smoke.mjs"
46
+ "test": "node --test tests/smoke.mjs",
47
+ "version": "node -e \"const fs=require('fs');const m=JSON.parse(fs.readFileSync('dsh.plugin.json','utf8'));const v=JSON.parse(fs.readFileSync('package.json','utf8')).version;m.version=v;fs.writeFileSync('dsh.plugin.json',JSON.stringify(m,null,2)+'\\n')\" && git add dsh.plugin.json"
47
48
  },
48
49
  "keywords": [
49
50
  "dsh",
package/src/client.js CHANGED
@@ -1157,6 +1157,12 @@ window.__ModuleLoader__.load({
1157
1157
  const [customize, setCustomize] = React.useState(null) // { kind, entryKey, name }
1158
1158
  const [errorText, setErrorText] = React.useState(null)
1159
1159
  const [drag, setDrag] = React.useState(null) // { kind: 'workspace'|'session', source, over } | null
1160
+ // Workspace drags arm their state one frame LATE (see workspaceDragEvents):
1161
+ // arming synchronously re-renders during the dragstart dispatch, the chain
1162
+ // expansion inserts rows above the drag source, the cursor leaves the
1163
+ // source element, and Chromium cancels the whole gesture. dragEnd clears
1164
+ // the timer so a same-tick cancel never leaves a ghost drag behind.
1165
+ const wsDragArmTimer = React.useRef(null)
1160
1166
  const normalizedQuery = query.trim().toLowerCase()
1161
1167
  const now = Date.now()
1162
1168
 
@@ -1306,6 +1312,9 @@ window.__ModuleLoader__.load({
1306
1312
  }
1307
1313
  const dragMatches = (kind) => drag !== null && drag.kind === kind
1308
1314
  const canDragWorkspace = typeof insertWorkspaceBefore === 'function'
1315
+ // Session REORDER needs the host insertSessionBefore action; dragging a
1316
+ // session onto a sub-group row (a pure rename) stays available without it.
1317
+ const canReorderSessions = typeof insertSessionBefore === 'function'
1309
1318
 
1310
1319
  /* --------------------- workspace drag & drop -------------------- */
1311
1320
 
@@ -1332,9 +1341,20 @@ window.__ModuleLoader__.load({
1332
1341
  const segs = splitTitleSegs(workspace.title)
1333
1342
  const sourceLeaf = segs.length > 0 ? segs[segs.length - 1] : (workspace.leaf || String(workspace.workspaceId))
1334
1343
  const sourceFolder = segs.length > 1 ? segs.slice(0, -1).join('/') : ''
1335
- setDrag({ kind: 'workspace', source: { workspaceId: workspace.workspaceId, leaf: sourceLeaf, folderPath: sourceFolder }, over: null })
1344
+ // Deferred by one frame on purpose (Chromium cancels a just-started
1345
+ // drag whose source element is moved out from under the cursor; see
1346
+ // wsDragArmTimer above). By the next frame the gesture has settled
1347
+ // and the chain expansion is an ordinary mid-drag update.
1348
+ if (wsDragArmTimer.current !== null) clearTimeout(wsDragArmTimer.current)
1349
+ wsDragArmTimer.current = setTimeout(() => {
1350
+ wsDragArmTimer.current = null
1351
+ setDrag({ kind: 'workspace', source: { workspaceId: workspace.workspaceId, leaf: sourceLeaf, folderPath: sourceFolder }, over: null })
1352
+ }, 0)
1353
+ },
1354
+ onDragEnd: () => {
1355
+ if (wsDragArmTimer.current !== null) { clearTimeout(wsDragArmTimer.current); wsDragArmTimer.current = null }
1356
+ setDrag(null)
1336
1357
  },
1337
- onDragEnd: () => setDrag(null),
1338
1358
  onDragOver: (event) => {
1339
1359
  if (!dragMatches('workspace')) return
1340
1360
  event.preventDefault()
@@ -1426,7 +1446,7 @@ window.__ModuleLoader__.load({
1426
1446
  },
1427
1447
  onDragEnd: () => setDrag(null),
1428
1448
  onDragOver: (event) => {
1429
- if (!dragMatches('session') || drag.source.workspaceId !== workspaceId) return
1449
+ if (!dragMatches('session') || !canReorderSessions || drag.source.workspaceId !== workspaceId) return
1430
1450
  event.preventDefault()
1431
1451
  event.stopPropagation()
1432
1452
  try { event.dataTransfer.dropEffect = 'move' } catch { }
@@ -1436,7 +1456,7 @@ window.__ModuleLoader__.load({
1436
1456
  : (current ? { ...current, over: { kind: 'session', target: session.id, half } } : current))
1437
1457
  },
1438
1458
  onDrop: (event) => {
1439
- if (!dragMatches('session') || drag.source.workspaceId !== workspaceId) return
1459
+ if (!dragMatches('session') || !canReorderSessions || drag.source.workspaceId !== workspaceId) return
1440
1460
  event.preventDefault()
1441
1461
  event.stopPropagation()
1442
1462
  const half = drag.over && drag.over.kind === 'session' && drag.over.target === session.id ? drag.over.half : rowHalf(event)
@@ -1463,6 +1483,7 @@ window.__ModuleLoader__.load({
1463
1483
  const commitSessionDrop = (workspaceId, targetSessionId, half) => {
1464
1484
  const source = drag.source
1465
1485
  setDrag(null)
1486
+ if (!canReorderSessions) return
1466
1487
  if (source.sessionId === targetSessionId) return
1467
1488
  const workspace = (items || []).find(w => w.workspaceId === workspaceId)
1468
1489
  if (!workspace) return
@@ -2012,6 +2033,12 @@ window.__ModuleLoader__.load({
2012
2033
  insertWorkspaceBefore: typeof workspaces.insertBefore === 'function'
2013
2034
  ? (workspaceId, beforeWorkspaceId) => workspaces.insertBefore(workspaceId, beforeWorkspaceId)
2014
2035
  : undefined,
2036
+ // Official contract exposes session reorder through the WORKSPACES
2037
+ // service (see dsh ui-workspace client index.ts); feature-probed so
2038
+ // older hosts degrade to "group-move only" instead of a TypeError.
2039
+ insertSessionBefore: typeof workspaces.insertSessionBefore === 'function'
2040
+ ? (workspaceId, sessionId, beforeSessionId) => workspaces.insertSessionBefore(workspaceId, sessionId, beforeSessionId)
2041
+ : undefined,
2015
2042
  archiveSession: (sessionId) => uiWorkspace.archiveSession(sessionId),
2016
2043
  createWorkspace: (input) => workspaces.create(input),
2017
2044
  pickDirectory: () => uiWorkspace.pickDirectory(),