🐛 fix(sidebar): 修复侧边栏拖拽顺序重启后丢失

- 保留启动恢复阶段未回填连接时的 sidebarRootOrder
- 避免 hydration 过早裁剪连接根节点排序 token
- 补充重启后连接回填场景回归测试
This commit is contained in:
Syngnat
2026-07-03 21:39:40 +08:00
parent 29ee21e9d7
commit 3bf42a169c
2 changed files with 81 additions and 6 deletions

View File

@@ -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: {

View File

@@ -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<AppState>()(
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<AppState>()(
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,