fix(context): clear project loading on ssh reset

This commit is contained in:
777genius 2026-05-26 18:47:16 +03:00
parent 2fdbf301b4
commit 1b36d1daa6
2 changed files with 80 additions and 0 deletions

View file

@ -85,7 +85,13 @@ export const createConnectionSlice: StateCreator<AppState, [], [], ConnectionSli
? {
activeContextId: `ssh-${config.host}`,
projects: [],
projectsLoading: false,
projectsInitialized: false,
projectsError: null,
repositoryGroups: [],
repositoryGroupsLoading: false,
repositoryGroupsInitialized: false,
repositoryGroupsError: null,
openTabs: [],
activeTabId: null,
selectedTabIds: [],
@ -149,7 +155,13 @@ export const createConnectionSlice: StateCreator<AppState, [], [], ConnectionSli
activeContextId: 'local',
// Clear all stale SSH data including tabs so dashboard shows fresh local data
projects: [],
projectsLoading: false,
projectsInitialized: false,
projectsError: null,
repositoryGroups: [],
repositoryGroupsLoading: false,
repositoryGroupsInitialized: false,
repositoryGroupsError: null,
openTabs: [],
activeTabId: null,
selectedTabIds: [],

View file

@ -121,6 +121,12 @@ function deferred<T>(): {
return { promise, resolve };
}
async function flushMicrotasks(): Promise<void> {
await Promise.resolve();
await Promise.resolve();
await Promise.resolve();
}
describe('context slice team/task reset', () => {
beforeEach(() => {
vi.clearAllMocks();
@ -374,6 +380,40 @@ describe('context slice team/task reset', () => {
expect(apiMock.teams.getAllTasks).toHaveBeenCalledTimes(1);
});
it('clears project and repository loading guards before direct SSH connect refetches', async () => {
const projectScan = deferred<unknown[]>();
const repositoryScan = deferred<unknown[]>();
apiMock.getProjects.mockReturnValue(projectScan.promise);
apiMock.getRepositoryGroups.mockReturnValue(repositoryScan.promise);
const store = createTestStore();
store.setState({
activeContextId: 'local',
projectsLoading: true,
repositoryGroupsLoading: true,
} as never);
await store.getState().connectSsh({
host: 'dev',
port: 22,
username: 'me',
authMethod: 'privateKey',
privateKeyPath: '/tmp/key',
});
expect(apiMock.getProjects).toHaveBeenCalledTimes(1);
expect(apiMock.getRepositoryGroups).toHaveBeenCalledTimes(1);
expect(store.getState().projectsLoading).toBe(true);
expect(store.getState().repositoryGroupsLoading).toBe(true);
projectScan.resolve([]);
repositoryScan.resolve([]);
await Promise.all([projectScan.promise, repositoryScan.promise]);
await flushMicrotasks();
expect(store.getState().projectsLoading).toBe(false);
expect(store.getState().repositoryGroupsLoading).toBe(false);
});
it('drops previous-context team and task caches on direct SSH disconnect', async () => {
const store = createTestStore();
store.setState({
@ -419,4 +459,32 @@ describe('context slice team/task reset', () => {
expect(apiMock.teams.list).toHaveBeenCalledTimes(1);
expect(apiMock.teams.getAllTasks).toHaveBeenCalledTimes(1);
});
it('clears project and repository loading guards before direct SSH disconnect refetches', async () => {
const projectScan = deferred<unknown[]>();
const repositoryScan = deferred<unknown[]>();
apiMock.getProjects.mockReturnValue(projectScan.promise);
apiMock.getRepositoryGroups.mockReturnValue(repositoryScan.promise);
const store = createTestStore();
store.setState({
activeContextId: 'ssh-dev',
projectsLoading: true,
repositoryGroupsLoading: true,
} as never);
await store.getState().disconnectSsh();
expect(apiMock.getProjects).toHaveBeenCalledTimes(1);
expect(apiMock.getRepositoryGroups).toHaveBeenCalledTimes(1);
expect(store.getState().projectsLoading).toBe(true);
expect(store.getState().repositoryGroupsLoading).toBe(true);
projectScan.resolve([]);
repositoryScan.resolve([]);
await Promise.all([projectScan.promise, repositoryScan.promise]);
await flushMicrotasks();
expect(store.getState().projectsLoading).toBe(false);
expect(store.getState().repositoryGroupsLoading).toBe(false);
});
});