fix(sidebar): key parent-expansion per render context (#1302)
The same session can appear in two render contexts at once — most visibly under "Recent" and under its project's root group. Expansion state was keyed by bare session id, so toggling the chevron in one context flipped it in the other; the user clicked one row and a duplicate elsewhere expanded/collapsed in sync. Switch the expansion set to composite keys of the form `<renderContext>:<active|archived>:<sessionId>`. SessionNodeItem already computes this exact shape for its menu instance key (menuInstanceKey); reuse it as expansionKey so the two render-time instances of one session keep independent expand state. Updated: - isExpanded reads `expandedParents.has(expansionKey)`. - Chevron click / Enter / Space pass `expansionKey` to toggleParent instead of session.id. - The memo-equality check compares the same composite key on both sides so it correctly re-renders when only one context's state changes. - toggleParent's parameter is renamed `expansionKey` to reflect the new shape; the implementation is unchanged. - The auto-expand-parent-on-subagent-navigation effect doesn't know which context the user will look at the parent in, so it fans the parentID out to all four (project|recent) × (active|archived) combinations. Storage is bumped to `oc.sessions.expandedParents.v2`. Existing v1 data (bare session ids) is one-shot migrated by fanning each id across all four contexts and rewritten under the v2 key; the v1 key is then removed so a downgrade-then-reupgrade doesn't re-migrate. Co-authored-by: vhqtvn <8930337+vhqtvn@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
co-authored by
vhqtvn
parent
7582db6df6
commit
9ab90d4f1a
@@ -81,7 +81,13 @@ const PROJECT_COLLAPSE_STORAGE_KEY = 'oc.sessions.projectCollapse';
|
||||
const GROUP_ORDER_STORAGE_KEY = 'oc.sessions.groupOrder';
|
||||
const GROUP_COLLAPSE_STORAGE_KEY = 'oc.sessions.groupCollapse';
|
||||
const PROJECT_ACTIVE_SESSION_STORAGE_KEY = 'oc.sessions.activeSessionByProject';
|
||||
const SESSION_EXPANDED_STORAGE_KEY = 'oc.sessions.expandedParents';
|
||||
// v2 key holds composite "${renderContext}:${active|archived}:${sessionId}"
|
||||
// entries so the same session in different render contexts (e.g. "Recent"
|
||||
// and a project's root) has independent expand state. v1 held bare session
|
||||
// ids; useSidebarPersistence migrates v1 data on first read by fanning each
|
||||
// id into all four context combinations.
|
||||
const SESSION_EXPANDED_STORAGE_KEY = 'oc.sessions.expandedParents.v2';
|
||||
const LEGACY_SESSION_EXPANDED_STORAGE_KEY = 'oc.sessions.expandedParents';
|
||||
const SESSION_PINNED_STORAGE_KEY = 'oc.sessions.pinned';
|
||||
|
||||
type PrVisualState = 'draft' | 'open' | 'blocked' | 'merged' | 'closed';
|
||||
@@ -521,6 +527,7 @@ export const SessionSidebar: React.FC<SessionSidebarProps> = ({
|
||||
safeStorage,
|
||||
keys: {
|
||||
sessionExpanded: SESSION_EXPANDED_STORAGE_KEY,
|
||||
sessionExpandedLegacy: LEGACY_SESSION_EXPANDED_STORAGE_KEY,
|
||||
projectCollapse: PROJECT_COLLAPSE_STORAGE_KEY,
|
||||
sessionPinned: SESSION_PINNED_STORAGE_KEY,
|
||||
groupOrder: GROUP_ORDER_STORAGE_KEY,
|
||||
@@ -677,16 +684,25 @@ export const SessionSidebar: React.FC<SessionSidebarProps> = ({
|
||||
sessionEvents.requestDirectoryDialog();
|
||||
}, []);
|
||||
|
||||
// Auto-expand parent session when navigating to a subagent (child) session
|
||||
// Auto-expand parent session when navigating to a subagent (child) session.
|
||||
// We don't know which render context the user will look at the parent in
|
||||
// (Recent, project root, archived bucket, ...), so fan out across all
|
||||
// four combinations to ensure it's expanded wherever it appears.
|
||||
React.useEffect(() => {
|
||||
if (!currentSessionId) return;
|
||||
const current = sessions.find((s) => s.id === currentSessionId);
|
||||
const parentID = (current as Session & { parentID?: string | null })?.parentID;
|
||||
if (!parentID) return;
|
||||
const keysToAdd = [
|
||||
`project:active:${parentID}`,
|
||||
`project:archived:${parentID}`,
|
||||
`recent:active:${parentID}`,
|
||||
`recent:archived:${parentID}`,
|
||||
];
|
||||
setExpandedParents((prev) => {
|
||||
if (prev.has(parentID)) return prev;
|
||||
if (keysToAdd.every((k) => prev.has(k))) return prev;
|
||||
const next = new Set(prev);
|
||||
next.add(parentID);
|
||||
keysToAdd.forEach((k) => next.add(k));
|
||||
try {
|
||||
safeStorage.setItem(SESSION_EXPANDED_STORAGE_KEY, JSON.stringify(Array.from(next)));
|
||||
} catch { /* ignored */ }
|
||||
@@ -694,13 +710,13 @@ export const SessionSidebar: React.FC<SessionSidebarProps> = ({
|
||||
});
|
||||
}, [currentSessionId, sessions, safeStorage]);
|
||||
|
||||
const toggleParent = React.useCallback((sessionId: string) => {
|
||||
const toggleParent = React.useCallback((expansionKey: string) => {
|
||||
setExpandedParents((prev) => {
|
||||
const next = new Set(prev);
|
||||
if (next.has(sessionId)) {
|
||||
next.delete(sessionId);
|
||||
if (next.has(expansionKey)) {
|
||||
next.delete(expansionKey);
|
||||
} else {
|
||||
next.add(sessionId);
|
||||
next.add(expansionKey);
|
||||
}
|
||||
try {
|
||||
safeStorage.setItem(SESSION_EXPANDED_STORAGE_KEY, JSON.stringify(Array.from(next)));
|
||||
|
||||
Reference in New Issue
Block a user