Merge remote-tracking branch 'origin/dev' into codex/fix-logs-filtering-to-show-dashboard-audits

This commit is contained in:
Tam Nhu Tran committed 2026-05-30 15:57:03 -04:00
commit 3d9636351e
156 files changed
+4169 -625

No files matched your search

@@ -94,6 +94,7 @@ describe('ControlPanelEmbed', () => {
const iframe = await screen.findByTitle('CLIProxy Management Panel');
expect(iframe).toHaveAttribute('src', '/api/cliproxy-local/management.html');
fireEvent.load(iframe);
await waitFor(() => {
expect(window.localStorage.removeItem).toHaveBeenCalledWith('cli-proxy-auth');
@@ -107,6 +108,7 @@ describe('ControlPanelEmbed', () => {
);
expect(window.localStorage.setItem).toHaveBeenCalledWith('managementKey', 'custom-secret');
expect(window.localStorage.setItem).toHaveBeenCalledWith('isLoggedIn', 'true');
expect(window.localStorage.removeItem).toHaveBeenCalledWith('managementKey');
});
vi.clearAllMocks();
@@ -86,6 +86,47 @@ describe('useCliproxyAuthFlow', () => {
);
});
it('includes the selected account id when reauth starts from the dashboard', async () => {
const fetchMock = vi.fn((input: RequestInfo | URL) => {
const url = String(input);
if (url.includes('/codex/start-url')) {
return Promise.resolve(
createJsonResponse({
success: true,
authUrl: 'https://auth.example.com/codex?state=codex-reauth',
state: 'codex-reauth',
})
);
}
if (url.includes('/status?state=codex-reauth')) {
return Promise.resolve(createJsonResponse({ status: 'wait' }));
}
return Promise.reject(new Error(`Unexpected fetch: ${url}`));
});
vi.stubGlobal('fetch', fetchMock);
const { result } = renderHook(() => useCliproxyAuthFlow(), { wrapper });
await act(async () => {
await result.current.startAuth('codex', {
accountId: 'existing@example.com',
startEndpoint: 'start-url',
});
});
expect(fetchMock).toHaveBeenCalledWith(
'/api/cliproxy/auth/codex/start-url',
expect.objectContaining({
method: 'POST',
body: expect.stringContaining('"accountId":"existing@example.com"'),
})
);
});
it('surfaces manual OAuth start guidance from the dashboard API', async () => {
const guidance = [
'Start local CLIProxy first: ccs cliproxy start',
@@ -141,6 +141,65 @@ describe('deriveTraceGroups', () => {
expect(result.every((r) => r.kind === 'leaf' && r.repeatCount === undefined)).toBe(true);
});
it('keeps adjacent leaves with different detail payloads as separate rows', () => {
const result = deriveTraceGroups(
leafEntries(
{
id: '1',
timestamp: 't1',
event: 'poll',
message: 'same',
latencyMs: 25,
metadata: { attempt: 1, nested: { status: 'warm' } },
context: { account: 'alpha' },
error: { code: 'E_ONE', message: 'first' },
},
{
id: '2',
timestamp: 't2',
event: 'poll',
message: 'same',
latencyMs: 50,
metadata: { attempt: 2, nested: { status: 'cold' } },
context: { account: 'beta' },
error: { code: 'E_TWO', message: 'second' },
}
)
);
expect(result).toHaveLength(2);
expect(result.every((r) => r.kind === 'leaf' && r.repeatCount === undefined)).toBe(true);
expect(result.map((r) => (r.kind === 'leaf' ? r.entry.id : 'trace'))).toEqual(['2', '1']);
});
it('coalesces leaves with semantically identical structured payloads', () => {
const result = deriveTraceGroups(
leafEntries(
{
id: '1',
timestamp: 't1',
event: 'poll',
message: 'tick',
latencyMs: 25,
metadata: { b: 2, a: 1 },
context: { nested: { b: false, a: true } },
},
{
id: '2',
timestamp: 't2',
event: 'poll',
message: 'tick',
latencyMs: 25,
metadata: { a: 1, b: 2 },
context: { nested: { a: true, b: false } },
}
)
);
expect(result).toHaveLength(1);
expect((result[0] as LeafItem).repeatCount).toBe(2);
});
it('display-sorts items reverse-chronologically', () => {
// Use distinct events so leaves don't coalesce — testing display sort,
// not coalesce.
@@ -0,0 +1,27 @@
import { render, screen } from '@tests/setup/test-utils';
import { describe, expect, it } from 'vitest';
import { LogsDetailPanel } from '@/components/logs/logs-detail-panel';
import type { LogsEntry } from '@/lib/api-client';
function buildEntry(overrides: Partial<LogsEntry> = {}): LogsEntry {
return {
id: 'entry-1',
timestamp: '2026-04-07T11:00:00.000Z',
level: 'info',
source: 'dashboard',
event: 'logs.bootstrap',
message: 'Dashboard log entry',
processId: 25582,
runId: 'run-1',
...overrides,
};
}
describe('LogsDetailPanel', () => {
it('falls back to the raw timestamp when the selected log entry has an invalid timestamp', () => {
render(<LogsDetailPanel entry={buildEntry({ timestamp: 'not-a-date' })} />);
expect(screen.getByText('not-a-date')).toBeInTheDocument();
expect(screen.getByTitle('not-a-date')).toHaveTextContent('not-a-date');
});
});
@@ -0,0 +1,98 @@
import { renderHook } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { useAuthMonitorData } from '@/components/monitoring/auth-monitor/hooks';
const { useCliproxyAuthMock, useCliproxyStatsMock, useCliproxyStatusMock } = vi.hoisted(() => ({
useCliproxyAuthMock: vi.fn(),
useCliproxyStatsMock: vi.fn(),
useCliproxyStatusMock: vi.fn(),
}));
vi.mock('@/hooks/use-cliproxy', () => ({
useCliproxyAuth: useCliproxyAuthMock,
}));
vi.mock('@/hooks/use-cliproxy-stats', () => ({
useCliproxyStats: useCliproxyStatsMock,
useCliproxyStatus: useCliproxyStatusMock,
}));
const authStatus = [
{
provider: 'codex',
displayName: 'OpenAI Codex',
accounts: [
{
id: 'codex-account',
email: 'codex@example.com',
tokenFile: '/tmp/codex.json',
provider: 'codex',
isDefault: true,
},
],
},
];
describe('useAuthMonitorData', () => {
beforeEach(() => {
vi.clearAllMocks();
useCliproxyAuthMock.mockReturnValue({
data: { authStatus },
isLoading: false,
error: null,
});
useCliproxyStatsMock.mockReturnValue({
data: undefined,
isLoading: false,
dataUpdatedAt: 0,
});
});
it('keeps account data visible without polling stats when CLIProxy is unavailable', () => {
useCliproxyStatusMock.mockReturnValue({
data: { running: false },
isLoading: false,
});
const { result } = renderHook(() => useAuthMonitorData());
expect(useCliproxyStatsMock).toHaveBeenCalledWith(false);
expect(result.current.isLoading).toBe(false);
expect(result.current.accounts).toHaveLength(1);
expect(result.current.totalRequests).toBe(0);
expect(result.current.providerStats[0]).toMatchObject({
provider: 'codex',
accountCount: 1,
totalRequests: 0,
});
});
it('enables live stats only after CLIProxy is running', () => {
useCliproxyStatusMock.mockReturnValue({
data: { running: true },
isLoading: false,
});
useCliproxyStatsMock.mockReturnValue({
data: {
accountStats: {
'codex:codex@example.com': {
source: 'codex@example.com',
successCount: 8,
failureCount: 2,
totalTokens: 100,
provider: 'codex',
},
},
},
isLoading: false,
dataUpdatedAt: Date.now(),
});
const { result } = renderHook(() => useAuthMonitorData());
expect(useCliproxyStatsMock).toHaveBeenCalledWith(true);
expect(result.current.totalSuccess).toBe(8);
expect(result.current.totalFailure).toBe(2);
expect(result.current.totalRequests).toBe(10);
});
});
@@ -191,4 +191,41 @@ describe('AuthMonitor', () => {
expect(within(getSummaryCard('Failed')).getByText('3')).toBeInTheDocument();
expect(within(getSummaryCard('Success Rate')).getByText('80%')).toBeInTheDocument();
});
it('shows CLIProxy guidance when a large account pool has a high failure rate', () => {
useAuthMonitorDataMock.mockReturnValue({
...authMonitorData,
accounts: Array.from({ length: 5 }, (_, index) => ({
id: `codex-${index}`,
email: `codex-${index}@example.com`,
tokenFile: `/tmp/codex-${index}.json`,
provider: 'codex',
displayName: 'OpenAI Codex',
isDefault: index === 0,
successCount: index === 0 ? 1 : 0,
failureCount: 5,
color: '#10a37f',
})),
totalSuccess: 1,
totalFailure: 25,
totalRequests: 26,
providerStats: [
{
provider: 'codex',
displayName: 'OpenAI Codex',
totalRequests: 26,
successCount: 1,
failureCount: 25,
accountCount: 5,
accounts: [],
},
],
overallSuccessRate: 4,
});
render(<AuthMonitor />);
expect(screen.getByText('High CLIProxy failure rate detected')).toBeInTheDocument();
expect(screen.getByText(/ccs cliproxy routing/)).toBeInTheDocument();
});
});
@@ -83,6 +83,20 @@ describe('QuotaTooltipContent', () => {
expect(screen.getByText(expectedReset)).toBeInTheDocument();
});
it('renders the Gemini tier label when entitlement evidence is absent', () => {
const quota = createGeminiQuotaResult({
entitlement: undefined,
tierLabel: 'Legacy Pro',
tierId: null,
creditBalance: null,
});
render(<QuotaTooltipContent quota={quota} resetTime={null} />);
expect(screen.getByText('Tier')).toBeInTheDocument();
expect(screen.getByText('Legacy Pro')).toBeInTheDocument();
});
it('falls back to the shared reset indicator when Gemini buckets omit reset timestamps', () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-01-29T00:00:00Z'));
@@ -68,6 +68,7 @@ describe('provider presentation metadata', () => {
'gitlab',
'codebuddy',
'kilo',
'qoder',
]);
expect(getProviderSection('gitlab')?.id).toBe('plus-extra');
expect(getProviderSection('gemini')?.id).toBe('core');
@@ -128,6 +129,7 @@ describe('provider presentation metadata', () => {
'/assets/providers/codebuddy.png',
],
['kilo', 'Kilo AI', 'Kilo AI coding assistant', '/assets/providers/kilo.png'],
['qoder', 'Qoder', 'Qoder AI coding assistant', '/assets/providers/qoder.svg'],
])('recognizes %s across dashboard display helpers', (provider, name, description, asset) => {
expect(getProviderDisplayName(provider)).toBe(name);
expect(getProviderDescription(provider)).toBe(description);