fix(client): persist workspace drag order

This commit is contained in:
_Kerman
2026-08-11 15:57:43 +08:00
parent 31768a348e
commit 2ad471123d
4 changed files with 84 additions and 21 deletions

View File

@@ -200,9 +200,10 @@ function SessionTree({
const [drag, setDrag] = useState<DragState | null>(null)
const sessionDropCommitted = useRef(false)
const [workspaceDrag, setWorkspaceDrag] = useState<WorkspaceDragState | null>(null)
const sessionDragging = drag !== null
const workspaceDropCommitted = useRef(false)
const nativeDragActive = drag !== null || workspaceDrag !== null
useEffect(() => {
if (!sessionDragging) return
if (!nativeDragActive) return
// Row hover still owns the insertion marker. Accept the native drag at
// document level so releasing outside the list is not rendered as a
// rejected drop before dragend commits that last marker.
@@ -217,7 +218,7 @@ function SessionTree({
document.removeEventListener('dragover', acceptDrag)
document.removeEventListener('drop', acceptDrop)
}
}, [sessionDragging])
}, [nativeDragActive])
const currentGroup = current === undefined
? undefined
: (workspaces.find(w => w.sessionIds.includes(current))?.workspaceId as string | undefined)
@@ -310,6 +311,26 @@ function SessionTree({
console.warn('session reorder rejected:', reason)
})
}
const commitWorkspaceDrag = (
activeDrag: WorkspaceDragState,
over: NonNullable<WorkspaceDragState['over']>,
): void => {
if (workspaceDropCommitted.current) return
workspaceDropCommitted.current = true
setWorkspaceDrag(null)
const rowIndex = workspaces.findIndex(workspace => workspace.workspaceId === over.id)
if (rowIndex === -1) return
const anchor = over.half === 'before' ? over.id : workspaces[rowIndex + 1]?.workspaceId
if (anchor === activeDrag.workspaceId) return
const sourceIndex = workspaces.findIndex(workspace => workspace.workspaceId === activeDrag.workspaceId)
const anchorIndex = anchor === undefined
? workspaces.length
: workspaces.findIndex(workspace => workspace.workspaceId === anchor)
if (sourceIndex !== -1 && (anchorIndex === sourceIndex || anchorIndex === sourceIndex + 1)) return
insertWorkspaceBefore(activeDrag.workspaceId, anchor).catch((reason: unknown) => {
console.warn('workspace reorder rejected:', reason)
})
}
return (
<div className={clsx(css.treeBody, css.wide)}>
@@ -323,8 +344,18 @@ function SessionTree({
? workspaceDrag.over.half
: null
const workspaceDragProps = workspaceId === undefined ? undefined : {
start: () => { setWorkspaceDrag({ workspaceId, over: null }) },
end: () => { setWorkspaceDrag(null) },
start: () => {
workspaceDropCommitted.current = false
setWorkspaceDrag({ workspaceId, over: null })
},
end: () => {
if (workspaceDrag?.over !== null && workspaceDrag?.over !== undefined) {
commitWorkspaceDrag(workspaceDrag, workspaceDrag.over)
} else {
setWorkspaceDrag(null)
}
workspaceDropCommitted.current = false
},
}
const hoverWorkspace = workspaceId === undefined
? undefined
@@ -337,18 +368,7 @@ function SessionTree({
? undefined
: (half: 'before' | 'after') => {
if (workspaceDrag === null) return
const rowIndex = workspaces.findIndex(workspace => workspace.workspaceId === workspaceId)
const anchor = half === 'before' ? workspaceId : workspaces[rowIndex + 1]?.workspaceId
setWorkspaceDrag(null)
if (anchor === workspaceDrag.workspaceId) return
const sourceIndex = workspaces.findIndex(workspace => workspace.workspaceId === workspaceDrag.workspaceId)
const anchorIndex = anchor === undefined
? workspaces.length
: workspaces.findIndex(workspace => workspace.workspaceId === anchor)
if (sourceIndex !== -1 && (anchorIndex === sourceIndex || anchorIndex === sourceIndex + 1)) return
insertWorkspaceBefore(workspaceDrag.workspaceId, anchor).catch((reason: unknown) => {
console.warn('workspace reorder rejected:', reason)
})
commitWorkspaceDrag(workspaceDrag, { id: workspaceId, half })
}
return (
// Group section: header row + expanded top-level session rows. The