Skip to content

feat(chat): dedupe workspace labels, split sidebar - #2142

Merged
zhangmo8 merged 5 commits into
devfrom
feat/sidebar-workspace-labels
Aug 12, 2026
Merged

feat(chat): dedupe workspace labels, split sidebar#2142
zhangmo8 merged 5 commits into
devfrom
feat/sidebar-workspace-labels

Conversation

@zhangmo8

@zhangmo8 zhangmo8 commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Closes [feature] Disambiguate duplicate workspace names in the sidebar #2121 — duplicate workspace basenames in the sidebar now get the shortest parent suffix that makes them unique (app · team-a / app · archive), computed reactively over the currently visible group set (session groups and environment-only groups). Unique basenames keep their compact label; when a colliding workspace is archived/removed, the survivor shrinks back automatically. The full normalized path is exposed on the group header via title and an sr-only span for keyboard/AT users.
  • Visual separation of Chat vs Workspace — the chat section gets a subtle bg-muted/30 rounded card and the workspace title a hairline top divider (shown only when there is content above), so the two identical-looking lists read as separate zones. Class-only change, no DOM restructuring.
  • Refactor: WindowSideBar.vue 2513 → 1199 lines — the script is split into seven focused composables under composables/sidebar/; raw window.* / document.* usage is replaced with VueUse primitives (useEventListener, useDocumentVisibility, useResizeObserver, useTimeoutFn, usePreferredReducedMotion, tryOnScopeDispose). Template and DOM structure are unchanged.

BEFORE / AFTER (sidebar layout)

BEFORE                              AFTER
──────────────────────────         ──────────────────────────
📌 Pinned                          📌 Pinned
   session row                        session row
Chats                    [+]       ╭────────────────────────╮
   session row                     │ Chats              [+] │  ← bg-muted/30 card
Workspace          [📁+] [⊞]       │   session row          │
  📂 app                 [+]       ╰────────────────────────╯
   session row                     ──────────────────────────  ← divider
  📂 app                 [+]       Workspace          [📁+] [⊞]
   session row                       📂 app · team-a       [+]
       ↑ indistinguishable            session row
                                     📂 app · archive      [+]
                                       session row

New composables

File Responsibility
useSidebarWorkspaceGroups grouping pipeline, environment merge, label disambiguation, collapse state
useSessionPinFlight pin flight animation + feedback, reduced-motion aware
useSessionListAutoFill scroll pagination + viewport auto-fill (#1762 behavior preserved)
useSidebarSessionShortcuts Cmd/Alt+digit shortcuts and badges
useProjectGroupReorder drag & menu reordering of workspace groups
useSidebarWorkspaceActions add / archive / reveal workspace
useSidebarRemoteControl remote status polling with backoff + visibility pause

Verification

  • test/main/shared/workspaceLabels.test.ts — 6 unit tests (same basename, nested duplicates, cross-platform separators, parentless paths, collision removal)
  • WindowSideBar.test.ts 65/65, WindowSideBarSessionItem + App.startup 24/24, test/main/shared 112/112; full renderer suite passes except 4 files already failing on dev (reproduced on a clean tree, unrelated)
  • Two tests that reached into component internals via wrapper.vm were rewritten against observable behavior (real window keydown, poll timer)
  • oxfmt, oxlint, typecheck:web, typecheck:node, pnpm run lint, pnpm run i18n all clean
  • Verified in the built app (Playwright _electron): disambiguated labels, sr-only paths, section separation render correctly with zero renderer console errors
  • Behavior double-checked against dev: cold-start pagination (30-per-page; sessions of later groups appear after scrolling) is identical before/after this PR — pre-existing behavior, see note below

Note for reviewers

While verifying, we confirmed a pre-existing UX quirk (unchanged by this PR): in project grouping, managed-environment group headers always render, but their sessions only appear once pagination reaches them, so a group can look temporarily empty on cold start. Worth a separate issue; happy to file it.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Reorder project workspace groups by drag-and-drop or menu actions.
    • Use keyboard shortcuts to quickly select visible sessions.
    • Add and archive workspaces directly from the sidebar.
    • Automatically load more sessions as you scroll.
  • Improvements

    • Added smoother pinning and unpinning animations.
    • Improved remote-control status updates and navigation.
    • Clarified duplicate workspace names with directory context.
    • Enhanced workspace grouping, labels, tooltips, and accessibility.
  • Tests

    • Expanded coverage for workspace labels, shortcuts, scrolling, pinning, and remote-control updates.

Duplicate workspace basenames get the shortest parent-path
suffix (app · team-a / app · archive) computed over any given
set of labels. Windows and POSIX separators are handled
consistently; unique labels keep their compact form. (#2121)
Extract the 2.5k-line WindowSideBar script into seven sidebar
composables (workspace groups, pin flight, list auto-fill,
session shortcuts, group reorder, workspace actions, remote
control) and replace raw window/document API usage with VueUse
primitives (useEventListener, useDocumentVisibility,
useResizeObserver, useTimeoutFn, usePreferredReducedMotion).

Also lands in the sidebar itself:
- duplicate workspace labels rendered with minimal parent
  context over the visible group set, full normalized path on
  the group header title and an sr-only span (#2121)
- a subtle chat-section card background plus a divider above
  the workspace section so the two lists read separately

Template and DOM structure are unchanged. The two tests that
poked component internals via wrapper.vm now go through real
window events and the poll timer instead.
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2a377a55-04fb-44b0-af91-c80b4efc9e40

📥 Commits

Reviewing files that changed from the base of the PR and between a0ea81c and d6bb505.

📒 Files selected for processing (7)
  • src/renderer/src/components/WindowSideBar.vue
  • src/renderer/src/composables/sidebar/useProjectGroupReorder.ts
  • src/renderer/src/composables/sidebar/useSessionPinFlight.ts
  • src/renderer/src/composables/sidebar/useSidebarRemoteControl.ts
  • src/shared/utils/workspaceLabels.ts
  • test/main/shared/workspaceLabels.test.ts
  • test/renderer/components/WindowSideBar.test.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/renderer/src/composables/sidebar/useSidebarRemoteControl.ts
  • src/shared/utils/workspaceLabels.ts
  • src/renderer/src/composables/sidebar/useProjectGroupReorder.ts
  • src/renderer/src/composables/sidebar/useSessionPinFlight.ts
  • src/renderer/src/components/WindowSideBar.vue

📝 Walkthrough

Walkthrough

The sidebar moves remote control, workspace grouping and actions, project reordering, session autofill, pin animations, and shortcuts into dedicated composables. Workspace labels now disambiguate duplicate names with parent paths. Tests cover these behaviors.

Changes

Sidebar modularization and workspace UX

Layer / File(s) Summary
Workspace grouping and label disambiguation
src/renderer/src/composables/sidebar/useSidebarWorkspaceGroups.ts, src/shared/utils/workspaceLabels.ts, test/main/shared/workspaceLabels.test.ts, test/renderer/components/WindowSideBar.test.ts, src/renderer/src/components/WindowSideBar.vue
Workspace groups merge active and historical environments, support collapse state, and disambiguate duplicate labels with minimal parent-path suffixes.
Workspace actions and project-group reordering
src/renderer/src/composables/sidebar/useSidebarWorkspaceActions.ts, src/renderer/src/composables/sidebar/useProjectGroupReorder.ts, src/renderer/src/components/WindowSideBar.vue
Workspace creation, archiving, highlighting, drag reordering, and menu-based moves use dedicated composables.
Session pinning, autofill, and shortcuts
src/renderer/src/composables/sidebar/useSessionPinFlight.ts, src/renderer/src/composables/sidebar/useSessionListAutoFill.ts, src/renderer/src/composables/sidebar/useSidebarSessionShortcuts.ts, test/renderer/composables/chat/chatScrollArchitecture.test.ts, test/renderer/components/WindowSideBar.test.ts
Pin transitions, session-list pagination and scroll restoration, and keyboard shortcuts move out of the component with lifecycle cleanup.
Remote-control polling
src/renderer/src/composables/sidebar/useSidebarRemoteControl.ts, src/renderer/src/components/WindowSideBar.vue, test/renderer/components/WindowSideBar.test.ts
Remote channel status, polling backoff, visibility handling, presentation, settings navigation, and stale-refresh protection use a dedicated composable.
Sidebar composition cleanup
src/renderer/src/components/WindowSideBar.vue
The component wires composable outputs, removes duplicated state and initialization, and updates workspace accessibility labels and section styling.

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested reviewers: zerob13

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR also adds unrelated sidebar composables for remote control, pinning, shortcuts, autofill, workspace actions, and reordering beyond issue #2121. Split the unrelated sidebar behavior refactors into separate pull requests or link them to issues that define their requirements.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the two primary changes: workspace-label deduplication and sidebar decomposition.
Linked Issues check ✅ Passed The workspace-label implementation and tests satisfy issue #2121 requirements for uniqueness, minimal context, cross-platform paths, accessibility, and recomputation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/sidebar-workspace-labels

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@zhangmo8
zhangmo8 requested review from yyhhyyyyyy and zerob13 and removed request for yyhhyyyyyy and zerob13 August 11, 2026 11:58
The sidebar's only scrollTop assignment moved from
WindowSideBar.vue into useSessionListAutoFill.ts during the
composable split; re-register it under the new path.
@zhangmo8
zhangmo8 marked this pull request as ready for review August 12, 2026 02:03

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (5)
src/shared/utils/workspaceLabels.ts (1)

53-61: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

The fallback branch does not normalize separators.

The doc comment states that the suffix always renders with /. The fallback uses item.id unchanged, so a Windows id renders as app · C:\work\app. The branch is reachable only when two items share the same label and the same parent chain, which implies identical paths, so impact is very low. If you keep the branch, join the split segments instead of using the raw id.

♻️ Optional normalization of the fallback path
-      const uniqueContext = contextCounts.get(context) === 1 ? context : item.id
+      const uniqueContext =
+        contextCounts.get(context) === 1
+          ? context
+          : item.id.split(/[\\/]+/).filter(Boolean).join('/')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/utils/workspaceLabels.ts` around lines 53 - 61, Normalize the
fallback suffix in the forEach block before storing the override: replace the
raw item.id used when contextCounts.get(context) is not unique with the existing
path-segment normalization so separators always render as “/”. Preserve the
unique-context branch and the `${item.label} · ${uniqueContext}` format.
src/renderer/src/components/WindowSideBar.vue (1)

424-441: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The path is exposed twice to assistive technology.

The button carries title with the normalized path, and it also contains an sr-only span with the same path. Some screen readers announce the accessible name from the content and then the title as a description, so the path can be read twice. If you want the tooltip and the announcement, keep title and give the group an aria-describedby that points at the sr-only span, or drop the sr-only span.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/src/components/WindowSideBar.vue` around lines 424 - 441, Update
the project-directory group accessibility markup around
getGroupIdentifier(group) so the normalized path is exposed only once to
assistive technology: either remove the duplicate sr-only path text or keep it
and reference it via a unique aria-describedby instead of relying on the button
title as an additional announcement. Preserve the visual title tooltip behavior.
src/renderer/src/composables/sidebar/useSidebarWorkspaceGroups.ts (1)

280-297: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Disambiguation ignores localized group labels.

disambiguateWorkspaceLabels compares group.label only. Groups that carry a labelKey are excluded by isProjectDirectoryGroup, so this is correct today. If a future workspace group gains a labelKey, two groups could still render the same translated text without an override. Consider passing the resolved display label into this computed if that case appears.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/src/composables/sidebar/useSidebarWorkspaceGroups.ts` around
lines 280 - 297, The current disambiguation uses raw group.label values, so
localized groups with labelKey could render duplicate translated names. In
workspaceGroups, resolve each group’s actual display label before passing it to
disambiguateWorkspaceLabels, while preserving the existing filtering and label
override mapping.
src/renderer/src/composables/sidebar/useSessionListAutoFill.ts (1)

100-110: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Handle a rejected loadNextPage inside the fill loop.

sessionStore.loadNextPage() is awaited without error handling. Every caller invokes ensureSessionListFilled with void (line 123 here, and useProjectGroupReorder.ts line 157). If the store rejects, the result is an unhandled promise rejection. The finally block still resets isFillingSessionList, so the loop does not lock, but the failure is silent to the log and noisy to the runtime.

Catch the rejection and stop the loop.

♻️ Proposed change
         const beforeCount = sessionStore.sessions.length
         const beforeHasMore = sessionStore.hasMore
-        await sessionStore.loadNextPage()
+        try {
+          await sessionStore.loadNextPage()
+        } catch (error) {
+          console.warn('[useSessionListAutoFill] Failed to load next session page:', error)
+          return
+        }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/src/composables/sidebar/useSessionListAutoFill.ts` around lines
100 - 110, Update ensureSessionListFilled around sessionStore.loadNextPage() to
catch rejected loads, stop the fill loop, and prevent the rejection from
escaping the void-invoked caller. Preserve the existing finally cleanup that
resets isFillingSessionList.
src/renderer/src/composables/sidebar/useSidebarSessionShortcuts.ts (1)

69-72: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Route the Alt+ badge label through vue-i18n.

Line 71 hardcodes the Alt+ prefix. This string renders in the sidebar as user-visible copy. The symbol is locale-neutral, but the Alt key name is not.

Move the modifier label to a locale key and resolve it with t().

As per coding guidelines, src/renderer/**/*.{vue,ts,tsx}: "Use vue-i18n for user-facing copy, and prefer existing shadcn-vue primitives and VueUse utilities."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/src/composables/sidebar/useSidebarSessionShortcuts.ts` around
lines 69 - 72, Update getShortcutBadgeLabelForIndex to obtain the non-Mac
modifier label through the composable’s vue-i18n t() function instead of
hardcoding “Alt+”; add or reuse the appropriate locale key for that modifier
while preserving the Mac ⌘ label and existing digit formatting.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/renderer/src/composables/sidebar/useProjectGroupReorder.ts`:
- Around line 62-88: Validate that nextVisiblePaths has the same number of
entries as previousVisiblePaths before mutating nextOrder in
commitVisibleProjectGroupOrder. If the lengths differ, return without calling
projectStore.reorderEnvironments; otherwise preserve the existing reorder logic.

In `@src/renderer/src/composables/sidebar/useSessionPinFlight.ts`:
- Around line 291-299: Guard the pinFlightSessionId reset in the finally block
of the pin-flight flow using the same session-id ownership check as
pinDockedSessionId, so an earlier flight cannot clear the ID belonging to a
later session. Keep clone.remove() unconditional.

In `@src/renderer/src/composables/sidebar/useSidebarRemoteControl.ts`:
- Around line 108-157: Add a composable-local refresh sequence token to
refreshRemoteControlStatus and increment it for each invocation, then ignore any
result whose token is no longer current before replaceRemoteSnapshot. Apply the
same supersession check in runStatusRefresh before updating statusRefreshErrors
or scheduling another poll, so stale overlapping requests cannot mutate state.

---

Nitpick comments:
In `@src/renderer/src/components/WindowSideBar.vue`:
- Around line 424-441: Update the project-directory group accessibility markup
around getGroupIdentifier(group) so the normalized path is exposed only once to
assistive technology: either remove the duplicate sr-only path text or keep it
and reference it via a unique aria-describedby instead of relying on the button
title as an additional announcement. Preserve the visual title tooltip behavior.

In `@src/renderer/src/composables/sidebar/useSessionListAutoFill.ts`:
- Around line 100-110: Update ensureSessionListFilled around
sessionStore.loadNextPage() to catch rejected loads, stop the fill loop, and
prevent the rejection from escaping the void-invoked caller. Preserve the
existing finally cleanup that resets isFillingSessionList.

In `@src/renderer/src/composables/sidebar/useSidebarSessionShortcuts.ts`:
- Around line 69-72: Update getShortcutBadgeLabelForIndex to obtain the non-Mac
modifier label through the composable’s vue-i18n t() function instead of
hardcoding “Alt+”; add or reuse the appropriate locale key for that modifier
while preserving the Mac ⌘ label and existing digit formatting.

In `@src/renderer/src/composables/sidebar/useSidebarWorkspaceGroups.ts`:
- Around line 280-297: The current disambiguation uses raw group.label values,
so localized groups with labelKey could render duplicate translated names. In
workspaceGroups, resolve each group’s actual display label before passing it to
disambiguateWorkspaceLabels, while preserving the existing filtering and label
override mapping.

In `@src/shared/utils/workspaceLabels.ts`:
- Around line 53-61: Normalize the fallback suffix in the forEach block before
storing the override: replace the raw item.id used when
contextCounts.get(context) is not unique with the existing path-segment
normalization so separators always render as “/”. Preserve the unique-context
branch and the `${item.label} · ${uniqueContext}` format.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0a7fcc12-7c2d-4a51-a0a3-c741ab5fafa5

📥 Commits

Reviewing files that changed from the base of the PR and between 5217c1c and dd088d9.

📒 Files selected for processing (12)
  • src/renderer/src/components/WindowSideBar.vue
  • src/renderer/src/composables/sidebar/useProjectGroupReorder.ts
  • src/renderer/src/composables/sidebar/useSessionListAutoFill.ts
  • src/renderer/src/composables/sidebar/useSessionPinFlight.ts
  • src/renderer/src/composables/sidebar/useSidebarRemoteControl.ts
  • src/renderer/src/composables/sidebar/useSidebarSessionShortcuts.ts
  • src/renderer/src/composables/sidebar/useSidebarWorkspaceActions.ts
  • src/renderer/src/composables/sidebar/useSidebarWorkspaceGroups.ts
  • src/shared/utils/workspaceLabels.ts
  • test/main/shared/workspaceLabels.test.ts
  • test/renderer/components/WindowSideBar.test.ts
  • test/renderer/composables/chat/chatScrollArchitecture.test.ts

Comment thread src/renderer/src/composables/sidebar/useProjectGroupReorder.ts
Comment thread src/renderer/src/composables/sidebar/useSessionPinFlight.ts Outdated
Comment thread src/renderer/src/composables/sidebar/useSidebarRemoteControl.ts Outdated
@zhangmo8
zhangmo8 requested review from yyhhyyyyyy and zerob13 August 12, 2026 03:25
- Skip the project group reorder commit when the visible path count
  mismatches, so a short list cannot persist a duplicated order
- Only clear pinFlightSessionId when still owned by the finishing
  flight, mirroring the pinDockedSessionId guards
- Drop superseded remote status refreshes so a stale overlapping
  request cannot replace a newer snapshot, count toward backoff, or
  fork the poll chain; add a regression test for the overlap

Addresses CodeRabbit review feedback on #2142.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/renderer/src/composables/sidebar/useProjectGroupReorder.ts`:
- Around line 65-68: Update the project group reorder validation in the reorder
flow around nextVisiblePaths and previousVisiblePaths to abort unless both lists
contain the same unique paths, not merely equal lengths. Verify membership and
uniqueness for each list before the persistence loop, preserving the existing
warning-and-return behavior when validation fails.

In `@src/renderer/src/composables/sidebar/useSidebarRemoteControl.ts`:
- Around line 114-126: Update refreshRemoteControlStatus to propagate the
boolean result from pluginCatalogStore.replaceRemoteSnapshot instead of always
returning true after the guarded write. Ensure runStatusRefresh handles a false
or distinct superseded outcome without clearing statusRefreshErrors or
scheduling the next poll as a successful refresh.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e8437d87-d287-4c8b-9284-23f3fe75494b

📥 Commits

Reviewing files that changed from the base of the PR and between dd088d9 and a0ea81c.

📒 Files selected for processing (4)
  • src/renderer/src/composables/sidebar/useProjectGroupReorder.ts
  • src/renderer/src/composables/sidebar/useSessionPinFlight.ts
  • src/renderer/src/composables/sidebar/useSidebarRemoteControl.ts
  • test/renderer/components/WindowSideBar.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/renderer/components/WindowSideBar.test.ts

Comment thread src/renderer/src/composables/sidebar/useProjectGroupReorder.ts Outdated
Comment thread src/renderer/src/composables/sidebar/useSidebarRemoteControl.ts Outdated

@zerob13 zerob13 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Targeted checks pass (workspaceLabels, WindowSideBar, the scroll-architecture test, both typechecks, Oxfmt, and Oxlint). I found three additional issues below. The existing unresolved threads about reorder-path membership and the guarded remote snapshot result also still need attention.

Comment thread src/shared/utils/workspaceLabels.ts Outdated
Comment thread src/renderer/src/components/WindowSideBar.vue Outdated
Comment thread src/renderer/src/composables/sidebar/useSessionPinFlight.ts
Comment thread src/shared/utils/workspaceLabels.ts Outdated
- workspaceLabels: resolve each duplicate at its own shortest unique
  parent suffix instead of one depth per collision bucket
- WindowSideBar: replace the group header title/sr-only path with a
  hover+focus tooltip associated to the button
- useSessionPinFlight: serialize pin toggles so overlapping flights
  cannot fight over the flight/docked ownership refs
- useProjectGroupReorder: reject non-permutation visible path lists,
  not just count mismatches
- useSidebarRemoteControl: distinguish applied/discarded/failed refresh
  outcomes so a discarded snapshot neither resets nor grows backoff

@yyhhyyyyyy yyhhyyyyyy left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@zhangmo8
zhangmo8 merged commit ae3f1e1 into dev Aug 12, 2026
12 checks passed
@zhangmo8
zhangmo8 deleted the feat/sidebar-workspace-labels branch August 12, 2026 09:45
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.

[feature] Disambiguate duplicate workspace names in the sidebar

3 participants