From 3bf42a169cd90da7d92d8dad177a237349fbcfb8 Mon Sep 17 00:00:00 2001 From: Syngnat Date: Fri, 3 Jul 2026 21:39:40 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(sidebar):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E4=BE=A7=E8=BE=B9=E6=A0=8F=E6=8B=96=E6=8B=BD=E9=A1=BA?= =?UTF-8?q?=E5=BA=8F=E9=87=8D=E5=90=AF=E5=90=8E=E4=B8=A2=E5=A4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 保留启动恢复阶段未回填连接时的 sidebarRootOrder - 避免 hydration 过早裁剪连接根节点排序 token - 补充重启后连接回填场景回归测试 --- frontend/src/store.test.ts | 61 ++++++++++++++++++++++++++++++++++++++ frontend/src/store.ts | 26 ++++++++++++---- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/frontend/src/store.test.ts b/frontend/src/store.test.ts index 2fd7b942..831c77f2 100644 --- a/frontend/src/store.test.ts +++ b/frontend/src/store.test.ts @@ -1051,6 +1051,67 @@ describe('store appearance persistence', () => { ]); }); + it('keeps persisted sidebar root order until backend connections reload on startup', async () => { + storage.setItem('lite-db-storage', JSON.stringify({ + state: { + connectionTags: [ + { + id: 'tag-redis', + name: 'Redis', + connectionIds: ['conn-b'], + }, + ], + sidebarRootOrder: [ + 'connection:conn-a', + 'connection:conn-c', + 'tag:tag-redis', + ], + }, + version: 13, + })); + + const { + buildSidebarRootConnectionToken, + buildSidebarRootTagToken, + resolveSidebarRootOrderTokens, + useStore, + } = await importStore(); + + expect(useStore.getState().sidebarRootOrder).toEqual([ + buildSidebarRootConnectionToken('conn-a'), + buildSidebarRootConnectionToken('conn-c'), + buildSidebarRootTagToken('tag-redis'), + ]); + + useStore.getState().replaceConnections([ + { + id: 'conn-a', + name: 'A', + config: { id: 'conn-a', type: 'mysql', host: 'a.local', port: 3306, user: 'root' }, + }, + { + id: 'conn-b', + name: 'B', + config: { id: 'conn-b', type: 'redis', host: 'b.local', port: 6379, user: 'default' }, + }, + { + id: 'conn-c', + name: 'C', + config: { id: 'conn-c', type: 'mysql', host: 'c.local', port: 3306, user: 'root' }, + }, + ]); + + expect(resolveSidebarRootOrderTokens( + useStore.getState().sidebarRootOrder, + useStore.getState().connectionTags, + useStore.getState().connections, + )).toEqual([ + buildSidebarRootConnectionToken('conn-a'), + buildSidebarRootConnectionToken('conn-c'), + buildSidebarRootTagToken('tag-redis'), + ]); + }); + it('keeps legacy global proxy password during hydration until explicit cleanup', async () => { storage.setItem('lite-db-storage', JSON.stringify({ state: { diff --git a/frontend/src/store.ts b/frontend/src/store.ts index fb7275f8..1809c862 100644 --- a/frontend/src/store.ts +++ b/frontend/src/store.ts @@ -1176,6 +1176,18 @@ export const resolveSidebarRootOrderTokens = ( return result; }; +const resolveHydratedSidebarRootOrderTokens = ( + sidebarRootOrder: unknown, + connectionTags?: ConnectionTag[], + connections?: SavedConnection[], +): string[] => { + const sanitized = sanitizeSidebarRootOrder(sidebarRootOrder); + if (!connectionTags || !connections) { + return sanitized; + } + return resolveSidebarRootOrderTokens(sanitized, connectionTags, connections); +}; + const insertSidebarRootTokenBeforeUngrouped = ( sidebarRootOrder: string[], token: string, @@ -3834,10 +3846,10 @@ export const useStore = create()( state.connectionTags, ); } - nextState.sidebarRootOrder = resolveSidebarRootOrderTokens( + nextState.sidebarRootOrder = resolveHydratedSidebarRootOrderTokens( state.sidebarRootOrder, - nextState.connectionTags, - nextState.connections, + state.connectionTags === undefined ? undefined : nextState.connectionTags, + state.connections === undefined ? undefined : nextState.connections, ); delete nextState.savedQueries; nextState.externalSQLDirectories = sanitizeExternalSQLDirectories( @@ -3931,10 +3943,12 @@ export const useStore = create()( const persistedSidebarRootOrder = state.sidebarRootOrder === undefined ? currentState.sidebarRootOrder - : resolveSidebarRootOrderTokens( + : resolveHydratedSidebarRootOrderTokens( state.sidebarRootOrder, - persistedConnectionTags, - persistedConnections, + state.connectionTags === undefined + ? undefined + : persistedConnectionTags, + state.connections === undefined ? undefined : persistedConnections, ); return { ...currentState,