Sync login status between different windows. [INS-2537] (#9908)

* feat: add revalidation on user login event in Root component

* Sync login status between different windows.

* Fix review issues.
This commit is contained in:
yaoweiprc authored and GitHub committed 2026-05-28 04:00:28 +00:00
1 parent 637ae78d43
commit bee65d402c
5 files changed
+30 -16

No files matched your search

@@ -93,10 +93,11 @@ describe('absorbKey', () => {
expect(session.encPrivateKey).toEqual(MOCK_ENC_PRIVATE_KEY);
});
it('triggers loginStateChange after storing session', async () => {
it('triggers loginStateChange with true after storing session', async () => {
await absorbKey(SESSION_ID, RAW_KEY);
expect(getWindowMain().loginStateChange).toHaveBeenCalledOnce();
expect(getWindowMain().loginStateChange).toHaveBeenCalledWith(true);
});
it('falls back to current session id when none is provided', async () => {
@@ -189,7 +190,7 @@ describe('logout', () => {
expect(insomniaApi.logout).toHaveBeenCalledWith({ sessionId: SESSION_ID });
});
it('triggers loginStateChange', async () => {
it('triggers loginStateChange with false', async () => {
await setSessionData(
SESSION_ID,
'acct',
@@ -204,6 +205,7 @@ describe('logout', () => {
await logout();
expect(getWindowMain().loginStateChange).toHaveBeenCalledOnce();
expect(getWindowMain().loginStateChange).toHaveBeenCalledWith(false);
});
it('does not throw if the API call fails', async () => {
+2 -2
View File
@@ -42,7 +42,7 @@ export async function absorbKey(sessionId: string, key: string) {
JSON.parse(encPrivateKey),
);
window.main.loginStateChange();
window.main.loginStateChange(true);
}
export async function getPrivateKey() {
@@ -93,7 +93,7 @@ export async function logout(clearCredentials = false) {
if (clearCredentials) {
await _removeAllCredentials();
}
window.main.loginStateChange();
window.main.loginStateChange(false);
}
/** Set data for the new session and store it encrypted with the sessionId */
+1 -1
View File
@@ -258,7 +258,7 @@ const main: Window['main'] = {
completeExecutionStep: options => ipcRenderer.send('completeExecutionStep', options),
updateLatestStepName: options => ipcRenderer.send('updateLatestStepName', options),
getExecution: options => invokeWithNormalizedError('getExecution', options),
loginStateChange: () => ipcRenderer.send('loginStateChange'),
loginStateChange: options => ipcRenderer.send('loginStateChange', options),
restart: () => ipcRenderer.send('restart'),
openInBrowser: options => ipcRenderer.send('openInBrowser', options),
openDeepLink: options => ipcRenderer.send('openDeepLink', options),
+7 -9
View File
@@ -136,8 +136,7 @@ const writeResponseBodyToFile = async (
}
};
const getResponsesDir = () =>
path.join(process.env.INSOMNIA_DATA_PATH || app.getPath('userData'), 'responses');
const getResponsesDir = () => path.join(process.env.INSOMNIA_DATA_PATH || app.getPath('userData'), 'responses');
const responsesDirCreated = new Set<string>();
@@ -151,10 +150,7 @@ const getTimelinePath = (_: unknown, responseId: string) => {
return target;
};
const appendToTimeline = async (
_: unknown,
options: { timelinePath: string; data: string },
) => {
const appendToTimeline = async (_: unknown, options: { timelinePath: string; data: string }) => {
const allowedResponsesDir = getResponsesDir();
const resolvedPath = path.resolve(options.timelinePath);
if (!resolvedPath.startsWith(path.resolve(allowedResponsesDir) + path.sep) || !resolvedPath.endsWith('.timeline')) {
@@ -171,7 +167,7 @@ const appendToTimeline = async (
};
export interface RendererToMainBridgeAPI {
loginStateChange: () => void;
loginStateChange: (isLoggedIn: boolean) => void;
openInBrowser: (url: string) => void;
restart: () => void;
halfSecondAfterAppStart: () => void;
@@ -325,9 +321,11 @@ export function registerMainHandlers() {
ipcMainHandle('multipartBufferToArray', async (_, options) => {
return multipartBufferToArray(options);
});
ipcMainOn('loginStateChange', async () => {
ipcMainOn('loginStateChange', async (event, isLoggedIn: boolean) => {
BrowserWindow.getAllWindows().forEach(w => {
w.webContents.send('loggedIn');
if (w.webContents !== event.sender) {
w.webContents.send('loggedIn', isLoggedIn);
}
});
});
ipcMainHandle('backup', async () => {
+16 -2
View File
@@ -335,12 +335,26 @@ const Root = () => {
const latestInSubmission = useLatest(ifInSubmission);
useEffect(() => {
return window.main.on('git.db-synced', () => {
const unsubLoggedIn = window.main.on('loggedIn', (_, isLoggedIn: boolean) => {
if (!latestInSubmission.current) {
if (!isLoggedIn) {
// If the user just logged out, navigate to the login page
navigate(href('/auth/login'));
} else {
navigate(href('/organization'));
}
}
});
const unsubGitDbSynced = window.main.on('git.db-synced', () => {
if (!latestInSubmission.current) {
revalidate();
}
});
}, [latestInSubmission, revalidate]);
return () => {
unsubLoggedIn();
unsubGitDbSynced();
};
}, [latestInSubmission, revalidate, navigate]);
useEffect(() => {
return window.main.on('shell:open', async (_: IpcRendererEvent, url: string) => {