mirror of
https://github.com/nexu-io/open-design.git
synced 2026-05-31 19:04:39 +07:00
Merge 16a1727ba9 into 53fb175855
This commit is contained in:
commit
4277bbc310
2 changed files with 83 additions and 2 deletions
|
|
@ -196,6 +196,7 @@ export function AmrLoginPill({
|
|||
const pollRef = useRef<number | null>(null);
|
||||
const loginStartedAtRef = useRef<number | null>(null);
|
||||
const loginPendingRef = useRef(false);
|
||||
const suppressLoginInFlightRef = useRef(false);
|
||||
|
||||
const stopPolling = useCallback(() => {
|
||||
if (pollRef.current !== null) {
|
||||
|
|
@ -215,6 +216,7 @@ export function AmrLoginPill({
|
|||
return () => {
|
||||
loginPendingRef.current = false;
|
||||
loginStartedAtRef.current = null;
|
||||
suppressLoginInFlightRef.current = false;
|
||||
stopPolling();
|
||||
};
|
||||
}, [refresh, skipInitialRefresh, stopPolling]);
|
||||
|
|
@ -245,6 +247,7 @@ export function AmrLoginPill({
|
|||
stopPolling();
|
||||
loginStartedAtRef.current = null;
|
||||
loginPendingRef.current = false;
|
||||
suppressLoginInFlightRef.current = false;
|
||||
setPending(null);
|
||||
return;
|
||||
}
|
||||
|
|
@ -257,6 +260,7 @@ export function AmrLoginPill({
|
|||
}
|
||||
loginStartedAtRef.current = null;
|
||||
loginPendingRef.current = false;
|
||||
suppressLoginInFlightRef.current = false;
|
||||
setPending(null);
|
||||
setErrorMessage(t('settings.amrLoginErrorCompact'));
|
||||
}
|
||||
|
|
@ -270,6 +274,7 @@ export function AmrLoginPill({
|
|||
const onStatusChange = (event: Event) => {
|
||||
const reason = amrLoginStatusEventReason(event);
|
||||
if (reason === 'login-started') {
|
||||
suppressLoginInFlightRef.current = false;
|
||||
const startedAt = Date.now();
|
||||
loginStartedAtRef.current = startedAt;
|
||||
setErrorMessage(null);
|
||||
|
|
@ -303,12 +308,13 @@ export function AmrLoginPill({
|
|||
stopPolling();
|
||||
loginStartedAtRef.current = null;
|
||||
loginPendingRef.current = false;
|
||||
suppressLoginInFlightRef.current = false;
|
||||
setPending(null);
|
||||
setCanceledVisible(false);
|
||||
setErrorMessage(null);
|
||||
return;
|
||||
}
|
||||
if (next.loginInFlight) {
|
||||
if (next.loginInFlight && !suppressLoginInFlightRef.current) {
|
||||
setErrorMessage(null);
|
||||
setPending('login');
|
||||
startPolling();
|
||||
|
|
@ -334,6 +340,7 @@ export function AmrLoginPill({
|
|||
async (event: MouseEvent<HTMLButtonElement>) => {
|
||||
event.stopPropagation();
|
||||
if (loginPendingRef.current) return;
|
||||
suppressLoginInFlightRef.current = false;
|
||||
loginPendingRef.current = true;
|
||||
const startedAt = Date.now();
|
||||
loginStartedAtRef.current = startedAt;
|
||||
|
|
@ -379,6 +386,7 @@ export function AmrLoginPill({
|
|||
configPath: '',
|
||||
}
|
||||
));
|
||||
suppressLoginInFlightRef.current = true;
|
||||
setPending(null);
|
||||
setCanceledVisible(true);
|
||||
notifyAmrLoginStatusChanged('login-canceled');
|
||||
|
|
@ -394,6 +402,7 @@ export function AmrLoginPill({
|
|||
const result = await velaLogout();
|
||||
loginStartedAtRef.current = null;
|
||||
loginPendingRef.current = false;
|
||||
suppressLoginInFlightRef.current = false;
|
||||
setPending(null);
|
||||
if (!result.ok) {
|
||||
setErrorMessage(t('settings.amrLoginErrorCompact'));
|
||||
|
|
@ -408,7 +417,11 @@ export function AmrLoginPill({
|
|||
const loggedIn = status?.loggedIn === true;
|
||||
const userEmail = status?.user?.email ?? '';
|
||||
const loginInFlight =
|
||||
pending === 'login' || (status?.loggedIn !== true && status?.loginInFlight === true);
|
||||
pending === 'login' || (
|
||||
status?.loggedIn !== true &&
|
||||
status?.loginInFlight === true &&
|
||||
!suppressLoginInFlightRef.current
|
||||
);
|
||||
const logoutInFlight = pending === 'logout';
|
||||
const cancelInFlight = pending === 'cancel';
|
||||
const accountStatus: AmrAccountControlStatus = errorMessage
|
||||
|
|
|
|||
|
|
@ -1812,6 +1812,74 @@ describe('SettingsDialog execution settings Local CLI interactions', () => {
|
|||
expect(screen.getByText('late@example.com')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('does not resurrect Signing in from a stale loginInFlight echo after cancel', async () => {
|
||||
let statusStage: 'pending' | 'stale-pending' | 'signed-out' = 'pending';
|
||||
const fetchMock = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
const url = input.toString();
|
||||
if (url === '/api/memory') {
|
||||
return new Response(
|
||||
JSON.stringify({ enabled: true, memories: [], extraction: null }),
|
||||
{ status: 200, headers: { 'content-type': 'application/json' } },
|
||||
);
|
||||
}
|
||||
if (url === '/api/integrations/vela/status') {
|
||||
const body =
|
||||
statusStage === 'signed-out'
|
||||
? {
|
||||
loggedIn: false,
|
||||
loginInFlight: false,
|
||||
profile: 'local',
|
||||
user: null,
|
||||
configPath: '/Users/test/.amr/config.json',
|
||||
}
|
||||
: {
|
||||
loggedIn: false,
|
||||
loginInFlight: true,
|
||||
profile: 'local',
|
||||
user: null,
|
||||
configPath: '/Users/test/.amr/config.json',
|
||||
};
|
||||
return new Response(JSON.stringify(body), {
|
||||
status: 200,
|
||||
headers: { 'content-type': 'application/json' },
|
||||
});
|
||||
}
|
||||
if (url === '/api/integrations/vela/login/cancel' && init?.method === 'POST') {
|
||||
statusStage = 'stale-pending';
|
||||
return new Response(JSON.stringify({ canceled: true }), {
|
||||
status: 200,
|
||||
headers: { 'content-type': 'application/json' },
|
||||
});
|
||||
}
|
||||
throw new Error(`Unexpected fetch: ${url}`);
|
||||
});
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
renderSettingsDialog(
|
||||
{ mode: 'daemon', agentId: 'amr' },
|
||||
{ agents: [amrAgent] },
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByRole('tab', { name: /Local CLI.*1 installed/i }));
|
||||
const amrCard = screen.getByRole('button', { name: /^Open Design AMR\b/ }).closest('.agent-card') as HTMLElement;
|
||||
expect(await screen.findByText('Signing in…')).toBeTruthy();
|
||||
|
||||
fireEvent.mouseEnter(amrCard);
|
||||
fireEvent.click(await screen.findByRole('button', { name: 'Cancel' }));
|
||||
expect(await screen.findByText('Canceled')).toBeTruthy();
|
||||
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('od:amr-login-status-change', {
|
||||
detail: { reason: 'login-canceled' },
|
||||
}),
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('Signing in…')).toBeNull();
|
||||
});
|
||||
expect(screen.getByRole('button', { name: 'Authorize' })).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders the signed-in AMR account state inside Settings without leaking vela branding', async () => {
|
||||
const fetchMock = vi.fn(async (input: RequestInfo | URL) => {
|
||||
const url = input.toString();
|
||||
|
|
|
|||
Loading…
Reference in a new issue