refactor(chat): remove manual view switching#16739
Conversation
…ePage - Changed session layout preference from 'agent.layout' to 'agent.session.display_mode' in AgentPage. - Updated related tests to reflect the new session display mode. - Refactored Sessions component to remove unused session display options and history button. - Adjusted HomePage to use 'topic.tab.display_mode' instead of 'topic.layout' for topic display preferences. - Removed manual chat layout switches from CommonSettings. - Updated tests across various components to ensure consistency with the new display mode preferences.
…or for right panel
…o ResourceEntityRail test
… related tests to maintain sidebar behavior
…sourceList, and AssistantResourceList components
… enhance ConversationPickerDialog styling
…aderNavbar components
…hancing avatar display options
Signed-off-by: kangfenmao <kangfenmao@qq.com>
There was a problem hiding this comment.
This review was translated automatically.
Findings:
- Important:
src/renderer/pages/agents/AgentPage.tsx:467andsrc/renderer/pages/agents/AgentPage.tsx:894can both create a new blank agent session without a single-flight guard. The picker path closes the dialog before awaiting, but the composer path remains clickable, and either path can be triggered again before the firstPOST /agent-sessionsresult is reflected inclassicLayoutSessions. Because both code paths only callfindReusableEmptySessionagainst that stale list, rapid repeated actions can create duplicate empty sessions for the same agent/workspace. Home already guards the analogous classic topic paths withisCreatingTopicRef; please add the same protection for classic agent session creation and cover the rapid double-click/re-entry case.
Open questions:
- None.
Summary:
Requesting changes for the duplicate blank-session creation path in the new classic agent flow.
Verification:
- Reviewed PR #16739 at head
5e45378eeb71749758607bd8f7db2ce285427175in/Users/cherryai004/Documents/Cherry_Studio_Dev/cherry-studio-pr-review/.codex-tmp/pr-review-sweep-16739-20260704T090238Z. - Inspected the preference/display-mode migration, resource rail/menu changes, shell/pane/composer changes, edit dialog changes, docs, i18n, and related tests.
- Checked GitHub CI via
gh; latest relevant checks were successful or skipped by change gating. - Did not run local
pnpm lint/test/format, per repository PR review instructions.
After fixing, please request eeee0717 for further review.
Original Content
Findings:
- Important:
src/renderer/pages/agents/AgentPage.tsx:467andsrc/renderer/pages/agents/AgentPage.tsx:894can both create a new blank agent session without a single-flight guard. The picker path closes the dialog before awaiting, but the composer path remains clickable, and either path can be triggered again before the firstPOST /agent-sessionsresult is reflected inclassicLayoutSessions. Because both code paths only callfindReusableEmptySessionagainst that stale list, rapid repeated actions can create duplicate empty sessions for the same agent/workspace. Home already guards the analogous classic topic paths withisCreatingTopicRef; please add the same protection for classic agent session creation and cover the rapid double-click/re-entry case.
Open questions:
- None.
Summary:
Requesting changes for the duplicate blank-session creation path in the new classic agent flow.
Verification:
- Reviewed PR #16739 at head
5e45378eeb71749758607bd8f7db2ce285427175in/Users/cherryai004/Documents/Cherry_Studio_Dev/cherry-studio-pr-review/.codex-tmp/pr-review-sweep-16739-20260704T090238Z. - Inspected the preference/display-mode migration, resource rail/menu changes, shell/pane/composer changes, edit dialog changes, docs, i18n, and related tests.
- Checked GitHub CI via
gh; latest relevant checks were successful or skipped by change gating. - Did not run local
pnpm lint/test/format, per repository PR review instructions.
修复后请 request eeee0717 再进行后续 review。
AtomsH4
left a comment
There was a problem hiding this comment.
Reviewed the resource menu/layout preference refactor. The preference/source-of-truth migration is mostly consistent, but I left two warnings: one real deletion-guard race in the new classic rail clear-topics path, and one missing v2 breaking-changes entry for the user-visible layout behavior change.
0c90da6 to
5e45378
Compare
…-layout interactions
…en no assistant is selected
…ment after clearing assistant topics
zhangjiadi225
left a comment
There was a problem hiding this comment.
Findings:
-
Blocking:
src/renderer/pages/agents/AgentPage.tsx:90/src/renderer/pages/home/HomePage.tsx:128— Agent session pane position is stored intopic.tab.position. Moving the session list in Agent therefore also changes the Home topic pane position, andsessionItemActions.tsx:116also reusessettings.topic.position.*copy for the session menu. This mixes two product surfaces behind a topic-scoped preference. Please either split this into an Agent-specific key such asagent.session.position, or rename/migrate it to a genuinely shared resource pane position key and update the type/i18n/migration naming accordingly. -
Blocking:
src/renderer/components/chat/resourceList/ResourceEntityRail.tsx:141— tag grouping enables drag reorder while persistence still writes the global assistantorderKey.AssistantResourceList.tsx:437passesgroupByTag, and the rail only restricts drops to the same rendered tag group, butuseResourceEntityRailstill builds a global id order and PATCHes/assistants/:id/order. Reordering within one tag can therefore move the assistant across unrelated tags in the global order when switching back to list view or when sections are recomputed. Please keep reorder disabled whilegroupByTagis active unless there is a tag-scoped ordering model. -
Blocking:
src/renderer/pages/home/Tabs/components/Topics.tsx:804— the new assistant-group delete path callsdataApiService.delete('/assistants/:id')directly instead of usinguseAssistantMutations().deleteAssistant(). The shared hook refreshes/pinsand/topicsfordeleteTopics: true; this path manually refreshes assistants/topics only, which can leave stale assistant/topic pins in pin-aware UI and duplicates the assistant deletion workflow in a topic component. Please reusedeleteAssistant(assistantId, { deleteTopics: true })here. -
Follow-up:
src/renderer/components/chat/resourceList/ResourceEntityRail.tsx:147—selectedClickId/onSelectedClickonly runs through row click. Keyboard Enter/Space goes throughResourceListVirtual.tsx:372->actions.selectItem(activeId), so keyboard users cannot trigger the new “select the already selected entity to open/toggle the pane” behavior. Please wireResourceList.Provider.onSelectItemto find the item and reusehandleItemClick(item). -
Follow-up:
src/renderer/components/chat/resourceList/AgentResourceList.tsx:67/src/renderer/pages/agents/components/Sessions.tsx:282— Agent icon display uses an Agent-labeled menu but still reads/writesassistant.icon_type, with option labels coming fromsettings.assistant.icon.type.*. If this is intended to be shared, the preference should be migrated/renamed to a neutral resource icon key; otherwise Agent needs its ownagent.icon_type.
Verification:
- Reviewed PR #16739 at head
6569aba82902c70dd1a0e5b98b8707ec9df6e6f2. - Checked GitHub CI via
gh; current checks are green. - Did not run local
pnpm lint/test/format, per repository PR review rules.
zhangjiadi225
left a comment
There was a problem hiding this comment.
Additional finding:
Follow-up: src/renderer/pages/home/Tabs/components/Topics.tsx:509 / src/renderer/pages/agents/components/Sessions.tsx:590 / src/renderer/pages/agents/components/Sessions.tsx:634 — the fallback selection after deleting the active topic/session is not aligned between Assistant and Agent, and it also does not consistently match the current display grouping. Initial classic entry selects the globally latest topic/session (findLatestUpdated), and clicking an assistant/agent rail entity enters that entity's first resource by pinned/time order. But deleting the active row uses a different set of rules: the topic right panel picks the neighbouring topic scoped to the current assistant, while the session right panel does the same for the current agent; the session sidebar then falls back to sessionItems.find((s) => s.id !== id), which is the raw API/orderKey order rather than the visible group order or latest updated session.
Please extract/centralize this selection policy and make it explicit: either always choose the next visible row according to the current display list, or choose the latest remaining row within the relevant assistant/agent/workdir scope. As written, deleting a session from the Agent sidebar can jump to an unexpected session that is neither the nearest visible item nor the latest item.
Verification:
- Rechecked this behavior on PR #16739 head
6569aba82902c70dd1a0e5b98b8707ec9df6e6f2. - Did not run local
pnpm lint/test/format, per repository PR review rules.
The classic-rail "clear assistant topics" entry only checked the topic snapshot captured before the confirm dialog opened, then called deleteTopicsByAssistantId() unconditionally. TopicService.deleteByAssistantId() has no at-least-one guard of its own, so if the topic list changed while the dialog was open the rail could bypass the guard the modern grouping enforces. Mirror the modern grouping (Topics.tsx): track the latest topics in a ref and re-validate the target set after confirm returns, bailing out when nothing is left to clear. Adds a regression test covering the drain-during-confirm case. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: jd <59188306+zhangjiadi225@users.noreply.github.com>
Tag grouping only scopes drag drops to the same rendered tag, but reorder persistence still writes the global assistant `orderKey` via PATCH /assistants/:id/order. Dragging within a tag could therefore move the assistant across unrelated tags once the global order is recomputed. Gate `onReorder` on `isTagGrouping` so reorder stays disabled while grouping by tag, until a tag-scoped ordering model exists. Adds a rail-props test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: jd <59188306+zhangjiadi225@users.noreply.github.com>
The topic-group assistant delete called dataApiService.delete('/assistants/:id')
directly and refreshed only assistants/topics. The shared
useAssistantMutations().deleteAssistant() also refreshes /pins (and /topics when
deleteTopics is set), so the direct call could leave stale assistant/topic pins
in pin-aware UI and duplicated the deletion workflow inside a topic component.
Route deletion through the hook.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: jd <59188306+zhangjiadi225@users.noreply.github.com>
…rence The Agent session pane position read/wrote topic.tab.position, so moving the Agent session list also moved the Home topic pane, and the session position menu reused settings.topic.position.* copy — mixing two surfaces behind a topic-scoped key. Add a v2-only agent.session.position preference (default left, generated from target-key-definitions.json) and point AgentPage, Sessions, and the session position menu at it, with dedicated settings.agent.position.* i18n. Home keeps topic.tab.position. Both default to left, so existing behavior is preserved and no migration is needed (v2-only key, no v1 source). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: jd <59188306+zhangjiadi225@users.noreply.github.com>
Signed-off-by: kangfenmao <kangfenmao@qq.com>
Keyboard activation (Enter/Space at the listbox level) goes through the list's selectItem action, which the rail never wired to onSelectItem — so keyboard users could neither select an entity nor trigger the "activate the already-selected entity to toggle its pane" behavior. Wire onSelectItem to reuse handleItemClick, and drop the row's now-redundant onClick so mouse click, row-focused Enter/Space, and listbox-level keyboard all funnel through selectItem -> onSelectItem -> handleItemClick exactly once. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: jd <59188306+zhangjiadi225@users.noreply.github.com>
The classic agent rail and agent session sidebar read/wrote assistant.icon_type, so changing the agent entity icon style also changed the assistant's (and vice versa). Add a v2-only agent.icon_type preference (default emoji, generated from target-key-definitions.json) and point AgentResourceList and Sessions at it. The icon-style option labels (emoji/model/none) stay shared: the text is surface-agnostic and already routed through the neutral RESOURCE_ICON_TYPE_* helpers, and the parent menu label is already agent-scoped (agent.icon.type). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: jd <59188306+zhangjiadi225@users.noreply.github.com>
…stub The keyboard-navigation test stubs scrollToIndex on the mocked virtual list's ref node; the ref callback param is typed HTMLDivElement, so assign through a narrowed cast to keep tsgo happy (the pre-commit hook does not run typecheck). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: jd <59188306+zhangjiadi225@users.noreply.github.com>
…tion After deleting the active topic/session the two surfaces disagreed: topic and classic-session deletes picked the neighbour in the scoped visible list, but the modern session sidebar fell back to sessionItems.find(s => s.id !== id) — the raw API/orderKey head, which could jump to an unexpected session that is neither the nearest visible row nor the latest. Extract pickNeighbourAfterRemoval(orderedList, id) (next row, or previous when the deleted row was last) and route topic deletion and both session paths through it, using each surface's display-ordered visible list (filteredGroupedSessions, which equals the full grouped list in modern mode). Both surfaces now follow one explicit "next visible row" policy. Adds helper unit tests and a modern-sidebar delete test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: jd <59188306+zhangjiadi225@users.noreply.github.com>
Signed-off-by: jd <59188306+zhangjiadi225@users.noreply.github.com>
There was a problem hiding this comment.
This review was translated automatically.
Findings:
-
Important:
src/renderer/utils/sidebar.ts:270/src/shared/data/preference/preferenceSchemas.ts:482changeui.sidebar.favoritesfrom a bare app-id array to taggedSidebarFavoriteItem[], but existing preference DB rows are loaded as-is and the seeder only inserts missing rows. A saved value like['assistants','agents','translate','mini_app']now reachesnormalizeSidebarFavoriteItem, has notype, is dropped, and the sidebar falls back to only the requiredassistantsitem. Please add a one-time preference data migration or storage-boundary normalization that rewrites legacy strings to{ type: 'app', id }, and cover this existing-row case in tests. -
Important:
src/renderer/components/chat/resourceList/AssistantResourceList.tsx:440andsrc/renderer/components/chat/resourceList/AgentResourceList.tsx:276consumeresourceMenuItemsfor the new options menu but no longer pass them through toResourceEntityRail.ResourceEntityRailstill relies on activeresourceMenuItemsto clear row selection and disable the selected-row repeat-click path (ResourceEntityRail.tsx:144). In classic layout, opening the Assistant/Agent/Skill resource catalog leaves the current rail entity visually selected, and clicking that selected row runsonSelected*Clickinstead of normal selection, so it toggles the right resource pane rather than closing the catalog and returning to the conversation. Please forward the menu state, or otherwise give the rail the same active-resource-view signal, so active catalog views suppress entity selection/repeat-click behavior. -
Important:
src/renderer/pages/home/HomePage.tsx:523can fall back into a draft for the assistant that was just deleted.Topics.tsx:804callsdeleteAssistant(assistantId, { deleteTopics: true }), then invokesonActiveAssistantDeletedbefore refreshing assistants/topics. When there is no remaining topic to select,handleActiveAssistantDeletedcallsstartDraftAssistantSelection()with no payload;resolveDraftAssistantTargetstill sees the stale assistant list and stalelastUsedAssistantId, so it can resolve back todeletedAssistantId. The UI can then show a draft bound to a non-existent assistant, and creating/sending from it can fail. Please make this fallback exclude the deleted assistant or refresh/update the assistant source before starting the fallback draft, and cover the "delete active assistant with no remaining topics" case. -
Important:
src/renderer/pages/agents/AgentPage.tsx:126auto-opens the classic Agent session pane on every fresh mount when the stored display mode isagentand the session position isright. The effect always callssetSessionPaneOpen(true)after remount, so a user who manually closes the right session pane hasui.agent.right_pane_open=falseoverwritten the next time the Agent page/app is re-entered. Please preserve explicit storedfalsevalues and only default-open when the setting is genuinely unset/being initialized; add a remount/restart-style test for the manual-close case. -
Important:
src/renderer/i18n/locales/en-us.json:1099and the matchingzh-cn/zh-twentries regress the assistant clear flow back to "topics" while the surrounding UI labels it as conversations. The dialog title remains "Clear conversations", but the content/menu/success copy now says "topics", producing mixed user-visible terminology for the same action. Please keep these strings consistent with the conversation wording, e.g. "Clear conversations", "Clearing conversations will delete…", and "Cleared {{count}} conversations" with matching Chinese translations.
Manual intervention:
- Required: Preference/data migration and chat/agent UI runtime behavior changed; please manually verify upgraded sidebar favorites, classic resource rail/catalog switching, active-assistant deletion fallback, and right-position Agent session pane close persistence.
Verification:
- Reviewed PR #16739 at head
98d4935806c6a355bdfa2162cc7e93fb7024ce48in the pinned worktree. - Checked existing reviews/comments and did not repeat previously addressed feedback.
- Checked GitHub CI via
gh; current checks are passing or skipped. - Did not run local
pnpm lint/test/format, per repository PR review rules.
After the fix, please request eeee0717 for further review.
Original Content
Findings:
-
Important:
src/renderer/utils/sidebar.ts:270/src/shared/data/preference/preferenceSchemas.ts:482changeui.sidebar.favoritesfrom a bare app-id array to taggedSidebarFavoriteItem[], but existing preference DB rows are loaded as-is and the seeder only inserts missing rows. A saved value like['assistants','agents','translate','mini_app']now reachesnormalizeSidebarFavoriteItem, has notype, is dropped, and the sidebar falls back to only the requiredassistantsitem. Please add a one-time preference data migration or storage-boundary normalization that rewrites legacy strings to{ type: 'app', id }, and cover this existing-row case in tests. -
Important:
src/renderer/components/chat/resourceList/AssistantResourceList.tsx:440andsrc/renderer/components/chat/resourceList/AgentResourceList.tsx:276consumeresourceMenuItemsfor the new options menu but no longer pass them through toResourceEntityRail.ResourceEntityRailstill relies on activeresourceMenuItemsto clear row selection and disable the selected-row repeat-click path (ResourceEntityRail.tsx:144). In classic layout, opening the Assistant/Agent/Skill resource catalog leaves the current rail entity visually selected, and clicking that selected row runsonSelected*Clickinstead of normal selection, so it toggles the right resource pane rather than closing the catalog and returning to the conversation. Please forward the menu state, or otherwise give the rail the same active-resource-view signal, so active catalog views suppress entity selection/repeat-click behavior. -
Important:
src/renderer/pages/home/HomePage.tsx:523can fall back into a draft for the assistant that was just deleted.Topics.tsx:804callsdeleteAssistant(assistantId, { deleteTopics: true }), then invokesonActiveAssistantDeletedbefore refreshing assistants/topics. When there is no remaining topic to select,handleActiveAssistantDeletedcallsstartDraftAssistantSelection()with no payload;resolveDraftAssistantTargetstill sees the stale assistant list and stalelastUsedAssistantId, so it can resolve back todeletedAssistantId. The UI can then show a draft bound to a non-existent assistant, and creating/sending from it can fail. Please make this fallback exclude the deleted assistant or refresh/update the assistant source before starting the fallback draft, and cover the "delete active assistant with no remaining topics" case. -
Important:
src/renderer/pages/agents/AgentPage.tsx:126auto-opens the classic Agent session pane on every fresh mount when the stored display mode isagentand the session position isright. The effect always callssetSessionPaneOpen(true)after remount, so a user who manually closes the right session pane hasui.agent.right_pane_open=falseoverwritten the next time the Agent page/app is re-entered. Please preserve explicit storedfalsevalues and only default-open when the setting is genuinely unset/being initialized; add a remount/restart-style test for the manual-close case. -
Important:
src/renderer/i18n/locales/en-us.json:1099and the matchingzh-cn/zh-twentries regress the assistant clear flow back to "topics" while the surrounding UI labels it as conversations. The dialog title remains "Clear conversations", but the content/menu/success copy now says "topics", producing mixed user-visible terminology for the same action. Please keep these strings consistent with the conversation wording, e.g. "Clear conversations", "Clearing conversations will delete…", and "Cleared {{count}} conversations" with matching Chinese translations.
Manual intervention:
- 需要:Preference/data migration and chat/agent UI runtime behavior changed; please manually verify upgraded sidebar favorites, classic resource rail/catalog switching, active-assistant deletion fallback, and right-position Agent session pane close persistence.
Verification:
- Reviewed PR #16739 at head
98d4935806c6a355bdfa2162cc7e93fb7024ce48in the pinned worktree. - Checked existing reviews/comments and did not repeat previously addressed feedback.
- Checked GitHub CI via
gh; current checks are passing or skipped. - Did not run local
pnpm lint/test/format, per repository PR review rules.
修复后请 request eeee0717 再进行后续 review。
Signed-off-by: jd <59188306+zhangjiadi225@users.noreply.github.com>
Signed-off-by: jd <59188306+zhangjiadi225@users.noreply.github.com>
Signed-off-by: kangfenmao <kangfenmao@qq.com>
Signed-off-by: kangfenmao <kangfenmao@qq.com>
@eeee0717 has re-checked and handled these items:
Synced with latest Original Content@eeee0717 已对这几项重新检查并处理:
已同步最新 |
…e resource menu items
What this PR does
Before this PR:
Session/topic view switching and resource actions were spread across settings, sidebar behavior, and grouped menu surfaces. Agent and assistant resource controls also had inconsistent labels and nested edit-dialog tool tabs.
After this PR:
Session/topic display mode controls live with the relevant resource menus, legacy layout preferences are removed, resource list interactions are simplified, and Agent/Assistant edit tool tabs are shown directly. The related i18n strings, docs, preference schema, and tests are updated.
Fixes #N/A
Why we need it and why it was done in this way
The following tradeoffs were made:
The change keeps the behavior scoped to the existing chat and agent resource surfaces instead of adding another settings-level abstraction.
The following alternatives were considered:
Keeping the old settings switches was considered, but that would preserve duplicated layout controls and make the resource menu behavior harder to reason about.
Links to places where the discussion took place: N/A
Breaking changes
N/A
Special notes for your reviewer
This PR includes UI behavior changes in chat resource lists, AgentPage/HomePage display mode handling, and Agent/Assistant edit dialog tab presentation.
Checklist
This checklist is not enforcing, but it's a reminder of items that could be relevant to every PR.
Approvers are expected to review this list.
mainfor active development,v1for v1 maintenance fixes/gh-pr-review,gh pr diff, or GitHub UI) before requesting review from othersRelease note