fix(cli-status): refresh auth after terminal close

This commit is contained in:
777genius 2026-05-27 21:53:47 +03:00
parent 877a81439b
commit 46a525aea1
4 changed files with 140 additions and 26 deletions

View file

@ -1759,9 +1759,6 @@ export const CliStatusBanner = (): React.JSX.Element | null => {
setProviderTerminal(null);
recheckAuthState();
}}
onExit={() => {
recheckAuthState();
}}
autoCloseOnSuccessMs={3000}
successMessage={
providerTerminal.action === 'login'
@ -2367,21 +2364,6 @@ export const CliStatusBanner = (): React.JSX.Element | null => {
}
})();
}}
onExit={() => {
setIsVerifyingAuth(true);
void (async () => {
try {
await invalidateCliStatus();
if (multimodelEnabled) {
await bootstrapCliStatus({ multimodelEnabled: true });
} else {
await fetchCliStatus();
}
} finally {
setIsVerifyingAuth(false);
}
})();
}}
autoCloseOnSuccessMs={4000}
successMessage={t('cliStatus.labels.loginComplete')}
failureMessage={t('cliStatus.labels.loginFailed')}

View file

@ -862,9 +862,6 @@ export const CliStatusSection = (): React.JSX.Element | null => {
setProviderTerminal(null);
recheckStatus();
}}
onExit={() => {
recheckStatus();
}}
autoCloseOnSuccessMs={3000}
successMessage={
providerTerminal.action === 'login'

View file

@ -180,10 +180,6 @@ export const ProvisioningProviderRuntimeSettingsDialog = ({
onProviderRuntimeChanged?.(providerTerminal.providerId);
refreshRuntimeAfterTerminal();
}}
onExit={() => {
onProviderRuntimeChanged?.(providerTerminal.providerId);
refreshRuntimeAfterTerminal();
}}
autoCloseOnSuccessMs={3000}
successMessage={
providerTerminal.action === 'login' ? 'Authentication updated' : 'Provider logged out'

View file

@ -70,6 +70,10 @@ let providerRuntimeSettingsDialogProps: {
open?: boolean;
initialProviderId?: string;
} | null = null;
let terminalModalProps: {
onClose?: () => void;
onExit?: (exitCode: number) => void;
} | null = null;
const codexAccountHookState = {
snapshot: null as CodexAccountSnapshotDto | null,
loading: false,
@ -160,7 +164,23 @@ vi.mock('@renderer/components/terminal/TerminalLogPanel', () => ({
}));
vi.mock('@renderer/components/terminal/TerminalModal', () => ({
TerminalModal: () => React.createElement('div', { 'data-testid': 'terminal-modal' }, 'terminal'),
TerminalModal: (props: { onClose?: () => void; onExit?: (exitCode: number) => void }) => {
terminalModalProps = props;
return React.createElement(
'div',
{ 'data-testid': 'terminal-modal' },
React.createElement(
'button',
{ 'data-testid': 'terminal-exit', onClick: () => props.onExit?.(0) },
'exit'
),
React.createElement(
'button',
{ 'data-testid': 'terminal-close', onClick: () => props.onClose?.() },
'close'
)
);
},
}));
vi.mock('@renderer/store', () => {
@ -345,6 +365,7 @@ describe('CLI status visibility during completed install state', () => {
beforeEach(() => {
providerRuntimeSettingsDialogProps = null;
terminalModalProps = null;
codexAccountHookState.snapshot = null;
codexAccountHookState.loading = false;
codexAccountHookState.rateLimitsLoading = false;
@ -518,6 +539,50 @@ describe('CLI status visibility during completed install state', () => {
});
});
it('waits until the runtime login modal closes before refreshing auth status', async () => {
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
storeState.cliStatus = createInstalledCliStatus({
authLoggedIn: false,
});
const host = document.createElement('div');
document.body.appendChild(host);
const root = createRoot(host);
await act(async () => {
root.render(React.createElement(CliStatusBanner));
await flushLazyImports();
});
const loginButton = Array.from(host.querySelectorAll('button')).find(
(button) => button.textContent?.trim() === 'Login'
);
await act(async () => {
loginButton?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
await flushLazyImports();
});
expect(host.querySelector('[data-testid="terminal-modal"]')).not.toBeNull();
expect(terminalModalProps?.onExit).toBeUndefined();
storeState.invalidateCliStatus.mockClear();
storeState.bootstrapCliStatus.mockClear();
await act(async () => {
terminalModalProps?.onClose?.();
await flushLazyImports();
});
expect(storeState.invalidateCliStatus).toHaveBeenCalledTimes(1);
expect(storeState.bootstrapCliStatus).toHaveBeenCalledTimes(1);
await act(async () => {
root.unmount();
await flushLazyImports();
});
});
it('loads the installer terminal log only while installation is active', async () => {
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
storeState.cliInstallerState = 'installing';
@ -1427,6 +1492,80 @@ describe('CLI status visibility during completed install state', () => {
});
});
it('waits until the provider login modal closes before refreshing provider auth status', async () => {
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
storeState.cliInstallerState = 'idle';
storeState.cliStatus = createInstalledCliStatus({
flavor: 'agent_teams_orchestrator',
authLoggedIn: false,
providers: [
{
providerId: 'anthropic',
displayName: 'Anthropic',
supported: true,
authenticated: false,
authMethod: null,
verificationState: 'verified',
statusMessage: 'Not connected',
models: [],
canLoginFromUi: true,
capabilities: {
teamLaunch: true,
oneShot: true,
},
connection: {
supportsOAuth: true,
supportsApiKey: true,
configurableAuthModes: ['auto', 'oauth', 'api_key'],
configuredAuthMode: 'auto',
apiKeyConfigured: false,
apiKeySource: null,
apiKeySourceLabel: null,
},
backend: null,
},
],
});
const host = document.createElement('div');
document.body.appendChild(host);
const root = createRoot(host);
await act(async () => {
root.render(React.createElement(CliStatusBanner));
await flushLazyImports();
});
const connectButton = Array.from(host.querySelectorAll('button')).find((button) =>
button.textContent?.includes('Connect Anthropic')
);
expect(connectButton).not.toBeUndefined();
await act(async () => {
connectButton?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
await flushLazyImports();
});
expect(host.querySelector('[data-testid="terminal-modal"]')).not.toBeNull();
expect(terminalModalProps?.onExit).toBeUndefined();
storeState.invalidateCliStatus.mockClear();
storeState.bootstrapCliStatus.mockClear();
await act(async () => {
terminalModalProps?.onClose?.();
await flushLazyImports();
});
expect(storeState.invalidateCliStatus).toHaveBeenCalledTimes(1);
expect(storeState.bootstrapCliStatus).toHaveBeenCalledTimes(1);
await act(async () => {
root.unmount();
await flushLazyImports();
});
});
it('shows subscription limit placeholders while an Anthropic subscription provider is checking', async () => {
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
storeState.cliInstallerState = 'idle';