feat: refine usage views and add Codex system prompt editing

- Brighten usage subpages with consistent surfaces and text contrast
- Show reasoning effort by default and migrate saved column settings
- Hide HTTP method prefixes and tighten request table spacing
- Support custom Codex system prompts and synchronize instruction templates
- Add a clear button to plugin search
- Update localization, mocks, and regression tests
This commit is contained in:
lzt404 committed 2026-10-04 17:31:52 +08:00
1 parent dfba9b019f
commit 2b49fe6a25
19 files changed
+233 -23

No files matched your search

+9
View File
@@ -12,6 +12,7 @@ import {
const configuration = (): CodexModelConfiguration => ({
display_name: 'Third Party',
description: null,
base_instructions: 'You are a helpful coding assistant.',
context_window: 128_000,
max_context_window: 128_000,
effective_context_window_percent: 95,
@@ -28,6 +29,14 @@ const configuration = (): CodexModelConfiguration => ({
});
describe('Codex 模型列表编辑', () => {
test('识别系统提示词修改并拒绝空提示词', () => {
const original = configuration();
const edited = { ...original, base_instructions: '请用中文回答。\n保留换行。' };
expect(sameCodexModelConfiguration(original, edited)).toBeFalse();
expect(validateCodexModelConfiguration(edited)).toBeNull();
expect(validateCodexModelConfiguration({ ...original, base_instructions: ' \n ' }))
.toBe('agents.catalog.invalidPrompt');
});
test("区分 Codex 客户端 API、模板后备与自定义上下文", () => {
const model: CodexCatalogEditorModel = {
slug: "model-a", hasOfficialTemplate: true, customized: false,
+4 -2
View File
@@ -9,11 +9,13 @@ const params = new URLSearchParams(location.search);
localStorage.setItem('easy-cli-proxy-api.locale', params.get('locale') || 'zh-CN');
// Keep the model column visible even if a previous fixture changed the user's layout.
localStorage.setItem('cpa-gui.usage-events-visible-cols.v3', JSON.stringify([
'time', 'key', 'source', 'model', 'effort', 'result', 'request', 'latency', 'speed', 'total', 'cache', 'provider',
'time', 'key', 'source', 'model', 'result', 'request', 'latency', 'speed', 'total', 'cache', 'provider',
]));
localStorage.removeItem('cpa-gui.usage-events-visible-cols.v2');
localStorage.removeItem('cpa-gui.usage-events-visible-cols.v4');
localStorage.removeItem('cpa-gui.usage-events-visible-cols.v5');
localStorage.removeItem('cpa-gui.usage-events-col-widths.v2');
localStorage.removeItem('cpa-gui.usage-events-col-widths.v3');
document.documentElement.dataset.theme = params.get('theme') || 'light';
const tokens = {
@@ -44,7 +46,7 @@ const record = (id: string, model: string, alias: string, response_model?: strin
alias,
...(response_model === undefined ? {} : { response_model }),
reasoning_effort: 'high',
endpoint: '/v1/responses',
endpoint: 'POST /v1/responses',
api_key_hash: 'ui-key',
api_key_display: 'sk-ui',
api_key_remark: 'UI fixture',
+20
View File
@@ -49,6 +49,23 @@ const fs = require('node:fs');
assert.equal(await page.evaluate(() => window.pluginsFixture.commands.some(call => call.command === 'open_core_logs_directory')), true);
await noOverflow();
const searchInput = page.getByRole('searchbox');
await searchInput.fill('qoder');
const focusedSearch = await searchInput.evaluate(input => ({
outline: getComputedStyle(input).outlineStyle,
shadow: getComputedStyle(input).boxShadow,
containerShadow: getComputedStyle(input.parentElement).boxShadow,
}));
assert.equal(focusedSearch.outline, 'none', 'the input must not draw a second focus ring inside the search field');
assert.equal(focusedSearch.shadow, 'none');
assert.notEqual(focusedSearch.containerShadow, 'none', 'the outer search field retains a visible focus indicator');
await page.keyboard.press('Tab');
assert.equal(await page.locator('.plugin-search-clear').evaluate(button => button === document.activeElement), true);
await page.keyboard.press('Enter');
assert.equal(await searchInput.inputValue(), '');
assert.equal(await searchInput.evaluate(input => input === document.activeElement), true, 'clearing returns focus to search');
assert.equal(await page.locator('.plugin-card').count(), 4, 'clearing restores the unfiltered list');
await card('kiro').getByRole('button', { name: 'Find in store', exact: true }).click();
await card('Kiro').getByRole('button', { name: 'Install', exact: true }).waitFor();
assert.equal(await tab('Plugin store').getAttribute('aria-current'), 'page');
@@ -177,6 +194,9 @@ const fs = require('node:fs');
if (process.env.PLUGIN_SCREENSHOT_DIR) {
fs.mkdirSync(process.env.PLUGIN_SCREENSHOT_DIR, { recursive: true });
await page.screenshot({ path: path.join(process.env.PLUGIN_SCREENSHOT_DIR, `plugins-${locale}-${width}.png`), fullPage: true });
await page.getByRole('searchbox').fill('qoder');
await page.screenshot({ path: path.join(process.env.PLUGIN_SCREENSHOT_DIR, `plugins-search-${locale}-${width}.png`), fullPage: true });
await page.locator('.plugin-search-clear').click();
}
await card('Community analytics').getByRole('button', { name: locale === 'en' ? 'Install' : '安装', exact: true }).click();
await dialog().waitFor();
+3
View File
@@ -89,6 +89,9 @@ function parseCsv(text) {
await open('zh-CN');
assert.equal(await modelCells().count(), 9, 'Every fixture record renders a model cell');
const zhDetails = await modelDetails();
assert.equal(await page.locator('.usage-th-effort').count(), 1, 'Migration enables reasoning effort for existing layouts');
assert.equal(await page.locator('.usage-td-request').first().textContent(), '/v1/responses');
assert.equal(await page.locator('.usage-td-request').first().getAttribute('title'), '/v1/responses');
assert.match(await modelCells().first().getAttribute('title'), /response_model.*上游声明/);
assert.deepEqual(await page.locator('.usage-events-table th').evaluateAll(cells => cells.slice(0, 2).map(cell => cell.className.split(' ')[0])), ['usage-th-time', 'usage-th-provider']);
assert.equal(await page.locator('.usage-td-provider strong').first().textContent(), 'Codex');