85 lines
5.2 KiB
TypeScript
85 lines
5.2 KiB
TypeScript
import { StrictMode, useRef, useState } from 'react';
|
|
import { createRoot } from 'react-dom/client';
|
|
import { mockIPC } from '@tauri-apps/api/mocks';
|
|
import { I18nProvider } from '../../src/i18n';
|
|
import { FloatingNotice, MessageNotice, useAppNotice } from '../../src/appNotice';
|
|
import { UsageRecordsPage } from '../../src/pages/UsageRecordsPage';
|
|
import { AgentConfigurationFeedback } from '../../src/pages/AgentControls';
|
|
import { useConfirmation } from '../../src/components/ConfirmationDialog';
|
|
import { QuotaActionFeedback } from '../../src/components/QuotaActionFeedback';
|
|
import '../../src/styles/index.css';
|
|
|
|
const params = new URLSearchParams(location.search);
|
|
localStorage.setItem('easy-cli-proxy-api.locale', params.get('locale') ?? 'zh-CN');
|
|
localStorage.setItem('cpa-gui.usage-records-tab.v1', 'pricing');
|
|
document.documentElement.dataset.theme = params.get('theme') ?? 'light';
|
|
const fixture = window as typeof window & { feedbackFixture: { failSync: boolean } };
|
|
fixture.feedbackFixture = { failSync: false };
|
|
mockIPC(async (cmd) => {
|
|
if (cmd === 'set_app_locale') return null;
|
|
if (cmd === 'get_usage_collector_status') return { state: 'collecting', totalRecords: 1 };
|
|
if (cmd === 'get_usage_analysis') return { models: [], providers: [], sources: [], apiKeys: [] };
|
|
if (cmd === 'get_usage_pricing') return {
|
|
rows: [{ model: 'test-model', requests: 1, totalTokens: 100, estimatedCost: 0, price: null }],
|
|
totalCost: 0, totalRequests: 1, pricedRequests: 0, savedPrices: 0,
|
|
};
|
|
if (cmd === 'preview_usage_model_prices') {
|
|
if (fixture.feedbackFixture.failSync) throw new Error('price sync failed');
|
|
return {
|
|
source: 'Models.dev', sourceUrl: 'https://models.dev/api.json', unmatched: [],
|
|
matches: [{ model: 'test-model', prompt: 2, completion: 6, cache: 0, cacheRead: 0, cacheCreation: 0,
|
|
promptConfigured: true, completionConfigured: true, cacheReadConfigured: false, cacheCreationConfigured: false,
|
|
source: 'models.dev', sourceModelId: 'openai/test-model', updatedAtMs: 0 }],
|
|
};
|
|
}
|
|
if (cmd === 'apply_usage_model_prices') return { imported: 1 };
|
|
if (cmd === 'save_usage_model_price' || cmd === 'delete_usage_model_price') return null;
|
|
throw new Error('Unexpected fixture command: ' + cmd);
|
|
}, { shouldMockEvents: true });
|
|
|
|
function Fixture() {
|
|
const first = useAppNotice();
|
|
const second = useAppNotice();
|
|
const [agent, setAgent] = useState(false);
|
|
const [quota, setQuota] = useState(false);
|
|
const [nativeError, setNativeError] = useState('');
|
|
const { askConfirmation, confirmationDialog } = useConfirmation();
|
|
const [mounted, setMounted] = useState(true);
|
|
const dialog = useRef<HTMLDialogElement>(null);
|
|
return <main style={{ padding: 24 }}>
|
|
<div data-testid="toolbar" style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
|
|
<button onClick={() => first.showNotice('Saved', 'success')}>Success</button>
|
|
<button onClick={() => first.showNotice('Failure '.repeat(120), 'error')}>Error</button>
|
|
<button onClick={() => second.showNotice('Second result', 'info')}>Second</button>
|
|
<button onClick={() => { first.clearNotice(); second.clearNotice(); setAgent(false); setQuota(false); }}>Clear</button>
|
|
<button onClick={() => setAgent(true)}>Agent result</button>
|
|
<button onClick={() => setQuota(true)}>Quota result</button>
|
|
<button onClick={() => dialog.current?.showModal()}>Native dialog</button>
|
|
<button onClick={() => void askConfirmation({ title: "Confirm test", message: "Confirm the operation", confirmText: "Confirm" })}>Confirmation dialog</button>
|
|
<button onClick={() => setMounted(value => !value)}>Toggle source</button>
|
|
</div>
|
|
<section data-testid="panel" style={{ transform: 'translateZ(0)', overflow: 'hidden', height: 210, marginTop: 16, border: '1px solid gray' }}>
|
|
{mounted && <><FloatingNotice key={first.revision} notice={first.notice} onDismiss={first.clearNotice} />
|
|
<FloatingNotice key={second.revision} notice={second.notice} onDismiss={second.clearNotice} /></>}
|
|
<div data-testid="before">Existing form</div>
|
|
<div className="agent-save-bar">
|
|
<AgentConfigurationFeedback pending={agent} description="" />
|
|
<div className="agent-save-actions"><button>Apply agent</button></div>
|
|
</div>
|
|
<MessageNotice tone="success" message={agent ? 'Agent saved' : ''} />
|
|
{quota && <QuotaActionFeedback name="test.json" quota={{ status: 'success', rows: [], actionResult: { action: 'reset', status: 'refresh-error', error: 'query failed' } }} />}
|
|
<input data-testid="after" defaultValue="Keep focus" />
|
|
</section>
|
|
{confirmationDialog}
|
|
<dialog ref={dialog} className="agent-backup-modal" style={{ width: 400, height: 'calc(100vh - 48px)' }}>
|
|
<h2>Native backup dialog</h2>
|
|
<button onClick={() => setNativeError('Native modal error')}>Native error</button>
|
|
<MessageNotice message={nativeError} onDismiss={() => setNativeError('')} />
|
|
<button data-testid="native-footer" style={{ position: 'absolute', right: 20, bottom: 20 }} onClick={() => dialog.current?.close()}>Close dialog</button>
|
|
</dialog>
|
|
</main>;
|
|
}
|
|
createRoot(document.getElementById('root')!).render(<StrictMode><I18nProvider>
|
|
{params.get('scenario') === 'pricing' ? <UsageRecordsPage /> : <Fixture />}
|
|
</I18nProvider></StrictMode>);
|