Skip to content

feat(web): stabilize and drag-reorder workspaces in the sidebar#1047

Merged
wbxl2000 merged 7 commits into
mainfrom
feat/web-draggable-workspace-order
Jun 24, 2026
Merged

feat(web): stabilize and drag-reorder workspaces in the sidebar#1047
wbxl2000 merged 7 commits into
mainfrom
feat/web-draggable-workspace-order

Conversation

@wbxl2000

Copy link
Copy Markdown
Collaborator

Related Issue

No related issue — UX polish requested directly.

Problem

The web sidebar's workspace order followed the daemon's list order, which shifts with recent activity, so workspaces kept moving around. There was no way to pin a preferred arrangement, and a page reload could reshuffle everything. Sessions within a group already reorder live by latest activity; workspaces did not have a stable equivalent.

What changed

Workspaces now keep a stable, locally-persisted order and can be reordered by dragging a group header.

  • New localStorage key kimi-web.workspace-order holds the desired workspace id order (loadWorkspaceOrder / saveWorkspaceOrder).
  • workspacesView is sorted by that order, so the sidebar, mobile switcher and sessions dialog all reflect it. A watcher reconciles the stored order with the known workspace set: removed workspaces are dropped and newly-seen ones are prepended (newest first, the closest signal to a creation time, since workspaces carry no createdAt). The watcher keys on the id set, so a pure daemon reorder of the same workspaces no longer reshuffles the UI, and a drag reorder does not re-trigger it.
  • The workspace group header is the drag handle (native HTML5 DnD); dropping on another group moves it there and persists the new order via a new reorderWorkspaces action.
  • Sessions inside a group are untouched — they still sort by updatedAt and reorder live as activity arrives.
  • Pure ordering logic (reconcileWorkspaceOrder, sortByWorkspaceOrder, moveInOrder) is factored into src/lib/workspaceOrder.ts for unit testing.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works (workspace-order.test.ts, plus storage round-trip tests).
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update. (No user-facing docs to update for this behavior.)

@changeset-bot

changeset-bot Bot commented Jun 23, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b74c3f3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jun 23, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@b74c3f3
npx https://pkg.pr.new/@moonshot-ai/kimi-code@b74c3f3

commit: b74c3f3

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3b8c92ebdc

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +1709 to +1712
() => {
const next = reconcileWorkspaceOrder(
mergedWorkspaces.value.map((w) => w.id),
workspaceOrder.value,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve empty workspaces while reconciling order

On refresh, this watcher can run after the session list is populated but before loadWorkspaces() returns, so mergedWorkspaces only contains workspaces derived from sessions. If the persisted order includes a registered workspace with no sessions, reconcileWorkspaceOrder() treats that id as deleted and saves an order without it; when the workspace API later adds it back, it is considered newly seen and is prepended, so empty workspaces jump to the front instead of preserving the user's saved drag order. Gate the drop/removal reconciliation until the real workspace list has loaded, or avoid deleting stored ids during the derived-only phase.

Useful? React with 👍 / 👎.

@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8b93aeeb4d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread apps/kimi-web/src/lib/workspaceOrder.ts Outdated
if (fromIdx === -1 || toIdx === -1 || fromIdx === toIdx) return order;
const next = [...order];
next.splice(fromIdx, 1);
next.splice(toIdx, 0, fromId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Adjust downward drops to match the insertion marker

When dragging a workspace downward, toIdx is computed before fromId is removed, so the target shifts left and this inserts the source after the highlighted target. For example, dragging a over c in [a,b,c,d] produces [b,c,a,d], while the sidebar shows .drop-before at the top of c; users cannot trust the insertion marker. Adjust the insertion index after removing the source when fromIdx < toIdx (or recompute it) so the persisted order matches the drop indicator.

Useful? React with 👍 / 👎.

@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f5d9220c4f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +574 to +575
@dragover="onGroupDragOver($event, g.workspace.id)"
@drop="onGroupDrop(g.workspace.id)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add an end-of-list drop target

With the current wiring every valid drop is tied to an existing workspace id and moveInOrder always inserts the dragged workspace before that target. In a list like [A, B, C], dragging A onto C yields [B, A, C], so there is no single drop position that can produce [B, C, A]; the new drag-reorder UI cannot move a workspace directly to the bottom. Add an after-last/bottom drop zone or distinguish before/after based on pointer position.

Useful? React with 👍 / 👎.

@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

const list = mergedWorkspaces.value;

P2 Badge Use reordered workspaces for active fallback

When rawState.activeWorkspaceId is missing or stale (for example after the active workspace is removed, or when there is no persisted active workspace), this computed still falls back to mergedWorkspaces.value[0]. The new drag order is only applied in workspacesView, so the highlighted/default workspace can differ from the first visible group; actions such as the sidebar New Chat use client.activeWorkspaceId and can create the session in the daemon's first workspace instead of the user's reordered top workspace. Drive this fallback from the ordered workspace list as well.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 85ae77cc03

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

})),
);
}));
return sortByWorkspaceOrder(views, workspaceOrder.value);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 Badge Honor drag order when selecting the next workspace

When a user has a custom order and removes the active workspace, the removal paths still choose mergedWorkspaces.value[0] rather than this sorted workspacesView. For example, with daemon order A,B,C and dragged order C,B,A, removing C makes A active even though B is now the first visible group; the next-workspace fallback should use the same ordered view (or an injected ordered helper) so deletion does not jump back to daemon order.

Useful? React with 👍 / 👎.

@wbxl2000

Copy link
Copy Markdown
Collaborator Author

@codex

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: b74c3f3267

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@wbxl2000 wbxl2000 merged commit 98d3e5b into main Jun 24, 2026
8 checks passed
@wbxl2000 wbxl2000 deleted the feat/web-draggable-workspace-order branch June 24, 2026 04:06
@github-actions github-actions Bot mentioned this pull request Jun 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant