diff --git a/apps/desktop/src/app/chat/sidebar/index.tsx b/apps/desktop/src/app/chat/sidebar/index.tsx
index be88f05e319..472ef8fdb18 100644
--- a/apps/desktop/src/app/chat/sidebar/index.tsx
+++ b/apps/desktop/src/app/chat/sidebar/index.tsx
@@ -1458,6 +1458,20 @@ function SidebarWorkspaceGroup({
const hiddenCount = Math.max(0, totalCount - visibleSessions.length)
const nextCount = Math.min(pageStep, hiddenCount)
+ // Leading glyph: profile color dot, platform avatar, or a branch mark for a
+ // worktree. When reorderable it doubles as the drag handle (icon ↔ grabber).
+ const leadingIcon = group.color ? (
+
+ ) : isSourceGroup && group.sourceId ? (
+
+ ) : (
+
+ )
+
// Reveal already-loaded rows first; only hit the backend when the next page
// crosses what's been fetched for this profile.
const handleProfileLoadMore = () => {
@@ -1494,20 +1508,16 @@ function SidebarWorkspaceGroup({
onClick={() => setOpen(value => !value)}
type="button"
>
- {group.color ? (
-
- ) : null}
- {isSourceGroup && group.sourceId ? (
-
- ) : null}
+ ) : (
+ leadingIcon
+ )}
{group.label}
@@ -1534,23 +1544,6 @@ function SidebarWorkspaceGroup({
)}
- {reorderable && (
- event.stopPropagation()}
- >
-
-
- )}
{open && (
<>
@@ -1650,7 +1643,16 @@ function SidebarWorkspaceParent({
onClick={() => setOpen(value => !value)}
type="button"
>
-
+ {reorderable ? (
+ }
+ label={s.reorderWorkspace(parent.label)}
+ />
+ ) : (
+
+ )}
{parent.label}
{parent.sessionCount}
@@ -1672,23 +1674,6 @@ function SidebarWorkspaceParent({
)}
- {reorderable && (
- event.stopPropagation()}
- >
-
-
- )}
{open &&
(soleWorktree ? (
@@ -1757,6 +1742,48 @@ function WorkspaceShowMoreButton({ count, label, onClick }: { count: number; lab
)
}
+// Reorder handle that lives in the header's leading-icon slot: the resting icon
+// fades out and a grabber fades in on hover/drag (same swap as the session row),
+// so the drag affordance never eats header width on the right.
+function WorkspaceReorderHandle({
+ dragHandleProps,
+ dragging,
+ icon,
+ label
+}: {
+ dragHandleProps?: React.HTMLAttributes
+ dragging: boolean
+ icon: React.ReactNode
+ label: string
+}) {
+ return (
+ event.stopPropagation()}
+ >
+
+ {icon}
+
+
+
+ )
+}
+
interface SortableSessionRowProps {
session: SessionInfo
isPinned: boolean