fix(context): align first-visit switch state
This commit is contained in:
parent
e46868b6d7
commit
255fa5aa47
2 changed files with 63 additions and 0 deletions
|
|
@ -356,6 +356,13 @@ export const createContextSlice: StateCreator<AppState, [], [], ContextSlice> =
|
||||||
isContextSwitching: false,
|
isContextSwitching: false,
|
||||||
targetContextId: null,
|
targetContextId: null,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
set({
|
||||||
|
...getEmptyContextState(),
|
||||||
|
activeContextId: targetContextId,
|
||||||
|
isContextSwitching: true,
|
||||||
|
targetContextId,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3: Fetch fresh data in background (slow over SSH)
|
// Step 3: Fetch fresh data in background (slow over SSH)
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,17 @@ function targetSnapshot() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deferred<T>(): {
|
||||||
|
promise: Promise<T>;
|
||||||
|
resolve: (value: T) => void;
|
||||||
|
} {
|
||||||
|
let resolve!: (value: T) => void;
|
||||||
|
const promise = new Promise<T>((innerResolve) => {
|
||||||
|
resolve = innerResolve;
|
||||||
|
});
|
||||||
|
return { promise, resolve };
|
||||||
|
}
|
||||||
|
|
||||||
describe('context slice team/task reset', () => {
|
describe('context slice team/task reset', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
|
@ -169,6 +180,51 @@ describe('context slice team/task reset', () => {
|
||||||
expect(apiMock.teams.getAllTasks).toHaveBeenCalledTimes(1);
|
expect(apiMock.teams.getAllTasks).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('updates the active context before slow first-visit project scans can trigger team refreshes', async () => {
|
||||||
|
contextStorageMock.loadSnapshot.mockResolvedValue(null);
|
||||||
|
const projectScan = deferred<unknown[]>();
|
||||||
|
apiMock.getProjects.mockReturnValue(projectScan.promise);
|
||||||
|
apiMock.getRepositoryGroups.mockResolvedValue([]);
|
||||||
|
const store = createTestStore();
|
||||||
|
store.setState({
|
||||||
|
activeContextId: 'local',
|
||||||
|
teams: [
|
||||||
|
{
|
||||||
|
teamName: 'local-team',
|
||||||
|
displayName: 'Local Team',
|
||||||
|
projectPath: '/local/project',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
globalTasks: [
|
||||||
|
{
|
||||||
|
id: 'local-task',
|
||||||
|
subject: 'Local task',
|
||||||
|
status: 'todo',
|
||||||
|
teamName: 'local-team',
|
||||||
|
teamDisplayName: 'Local Team',
|
||||||
|
projectPath: '/local/project',
|
||||||
|
comments: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
globalTasksInitialized: true,
|
||||||
|
} as never);
|
||||||
|
|
||||||
|
const switchPromise = store.getState().switchContext('ssh-dev');
|
||||||
|
await Promise.resolve();
|
||||||
|
await Promise.resolve();
|
||||||
|
|
||||||
|
expect(store.getState().activeContextId).toBe('ssh-dev');
|
||||||
|
expect(store.getState().isContextSwitching).toBe(true);
|
||||||
|
expect(store.getState().teams).toEqual([]);
|
||||||
|
expect(store.getState().globalTasks).toEqual([]);
|
||||||
|
|
||||||
|
projectScan.resolve(targetSnapshot().projects);
|
||||||
|
await switchPromise;
|
||||||
|
|
||||||
|
expect(store.getState().activeContextId).toBe('ssh-dev');
|
||||||
|
expect(store.getState().isContextSwitching).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
it('drops previous-context team and task caches when lazy context initialization changes context', async () => {
|
it('drops previous-context team and task caches when lazy context initialization changes context', async () => {
|
||||||
apiMock.context.getActive.mockResolvedValue('ssh-dev');
|
apiMock.context.getActive.mockResolvedValue('ssh-dev');
|
||||||
const store = createTestStore();
|
const store = createTestStore();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue