fix(web): show origin-blocked analyze guidance (#2568)

Co-authored-by: Gergő Magyar <gergomagyar@icloud.com>
This commit is contained in:
azizur100389 2026-07-20 08:15:16 +01:00 committed by GitHub
parent dfe271b2a9
commit c487fd1ecc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 62 additions and 2 deletions

View file

@ -29,6 +29,7 @@ import {
import { AnalyzeProgress } from './AnalyzeProgress';
import { filterRepoFiles } from '@/lib/upload-filter';
import { useTranslation } from 'react-i18next';
import { formatBackendError } from '../i18n/error-messages';
// ── Helpers ──────────────────────────────────────────────────────────────────
@ -349,7 +350,7 @@ export const RepoAnalyzer = ({ variant, onComplete, onCancel }: RepoAnalyzerProp
} catch (err) {
// Unmount aborts the controller, so this also covers the unmounted case.
if (controller.signal.aborted) return;
setValidationError(err instanceof Error ? err.message : t('errors:startAnalysisFailed'));
setValidationError(formatBackendError(err, t));
setPhase('error');
}
};
@ -430,7 +431,7 @@ export const RepoAnalyzer = ({ variant, onComplete, onCancel }: RepoAnalyzerProp
// by the server's job timeout and terminal-job TTL sweep.
if (controller.signal.aborted) return;
setUploading(false);
setValidationError(err instanceof Error ? err.message : t('errors:startAnalysisFailed'));
setValidationError(formatBackendError(err, t));
setPhase('error');
}
};

View file

@ -18,6 +18,17 @@ import {
} from '../../src/services/backend-client';
vi.mock('../../src/services/backend-client', () => ({
BackendError: class BackendError extends Error {
constructor(
message: string,
public readonly status: number,
public readonly code: string,
public readonly retryAfterMs?: number,
) {
super(message);
this.name = 'BackendError';
}
},
startAnalyze: vi.fn(),
cancelAnalyze: vi.fn(),
streamAnalyzeProgress: vi.fn(),

View file

@ -12,6 +12,7 @@ import { act, fireEvent, render, screen } from '@testing-library/react';
import { RepoAnalyzer } from '../../src/components/RepoAnalyzer';
import { i18nReady } from '../../src/i18n';
import {
BackendError,
cancelAnalyze,
startAnalyze,
streamAnalyzeProgress,
@ -19,6 +20,17 @@ import {
} from '../../src/services/backend-client';
vi.mock('../../src/services/backend-client', () => ({
BackendError: class BackendError extends Error {
constructor(
message: string,
public readonly status: number,
public readonly code: string,
public readonly retryAfterMs?: number,
) {
super(message);
this.name = 'BackendError';
}
},
startAnalyze: vi.fn(),
cancelAnalyze: vi.fn(),
streamAnalyzeProgress: vi.fn(),
@ -161,6 +173,24 @@ describe('folder upload', () => {
expect(screen.getByText('upload exploded')).toBeInTheDocument();
expect(streamAnalyzeProgress).not.toHaveBeenCalled();
});
it('formats origin-blocked upload failures with actionable guidance', async () => {
const d = deferred<typeof JOB>();
vi.mocked(uploadFolder).mockReturnValue(d.promise);
startUpload();
await act(async () => {
d.reject(
new BackendError('This endpoint is restricted to same-host origins', 403, 'origin_blocked'),
);
});
expect(screen.getByText(/Open GitNexus from the server's own address/)).toBeInTheDocument();
expect(
screen.queryByText('This endpoint is restricted to same-host origins'),
).not.toBeInTheDocument();
expect(streamAnalyzeProgress).not.toHaveBeenCalled();
});
});
describe('URL analyze', () => {
@ -215,4 +245,22 @@ describe('URL analyze', () => {
expect(vi.mocked(streamAnalyzeProgress).mock.calls[0][0]).toBe('job-3');
expect(cancelAnalyze).not.toHaveBeenCalled();
});
it('formats origin-blocked analyze failures with actionable guidance', async () => {
const d = deferred<typeof JOB>();
vi.mocked(startAnalyze).mockReturnValue(d.promise);
startGithubAnalyze();
await act(async () => {
d.reject(
new BackendError('This endpoint is restricted to same-host origins', 403, 'origin_blocked'),
);
});
expect(screen.getByText(/Open GitNexus from the server's own address/)).toBeInTheDocument();
expect(
screen.queryByText('This endpoint is restricted to same-host origins'),
).not.toBeInTheDocument();
expect(streamAnalyzeProgress).not.toHaveBeenCalled();
});
});