feat(agents): convert codex auth method selector to segmented radio buttons

This commit is contained in:
lzt404 committed 2026-09-15 17:15:21 +08:00
1 parent e25da0c517
commit 76da9b9944
4 files changed
+110 -10

No files matched your search

+1 -1
View File
@@ -1086,7 +1086,7 @@ export const zhCN = {
"agents.modify.connectionRepair": "当前接入:CPA 配置需要修复",
"agents.modify.authMethod": "接入方式",
"agents.modify.authApiKey": "API 密钥",
"agents.modify.authOAuth": "OAuth配置方式",
"agents.modify.authOAuth": "OAuth 登录方式",
"agents.modify.matches": "已保存",
"agents.modify.pending": "待应用",
"agents.modify.checking": "正在读取配置…",
+53 -7
View File
@@ -1904,19 +1904,65 @@ export function AgentsPage({ embedded = false, onConfigurationApplied }: AgentsP
{selected === 'codex' ? (
<div className="agent-codex-options">
<div className="agent-auth-method">
<div className="agent-signin-label"><label htmlFor="agent-connection-method">{t('agents.modify.authMethod')}</label>
<div className="agent-signin-label">
<span id="agent-connection-method-label" className="agent-signin-label-title">{t('agents.modify.authMethod')}</span>
<button type="button" className="agent-signin-help-toggle" aria-expanded={connectionHelpOpen} aria-controls="agent-signin-hint"
onClick={() => updateViewState({ connectionHelpOpen: !connectionHelpOpen })}>
{t(connectionHelpOpen ? 'agents.modify.authHelpHide' : 'agents.modify.authHelpShow')}
<ChevronDown size={14} aria-hidden="true" />
</button>
</div>
<select id="agent-connection-method" aria-label={t('agents.modify.authMethod')} aria-describedby={connectionHelpOpen ? "agent-signin-hint" : undefined} value={oauthConfiguration ? 'oauth' : 'apikey'}
onChange={(event) => void changeOauthConfiguration(event.currentTarget.value === 'oauth')}
disabled={busy || loading || modelLoading}>
<option value="apikey">{t('agents.modify.authApiKey')}</option>
<option value="oauth">{t('agents.modify.authOAuth')}</option>
</select>
<div
id="agent-connection-method"
className="agent-auth-segmented"
role="radiogroup"
aria-labelledby="agent-connection-method-label"
aria-describedby={connectionHelpOpen ? "agent-signin-hint" : undefined}
onKeyDown={(event) => {
if (busy || loading || modelLoading) return;
if (event.key === 'ArrowRight' || event.key === 'ArrowDown') {
event.preventDefault();
if (!oauthConfiguration) void changeOauthConfiguration(true);
} else if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') {
event.preventDefault();
if (oauthConfiguration) void changeOauthConfiguration(false);
}
}}
>
<button
type="button"
role="radio"
className={`agent-auth-segmented-button${!oauthConfiguration ? ' active' : ''}`}
aria-checked={!oauthConfiguration}
tabIndex={!oauthConfiguration ? 0 : -1}
disabled={busy || loading || modelLoading}
data-value="apikey"
onClick={() => {
if (oauthConfiguration) {
void changeOauthConfiguration(false);
}
}}
>
{t('agents.modify.authApiKey')}
</button>
<button
type="button"
role="radio"
className={`agent-auth-segmented-button${oauthConfiguration ? ' active' : ''}`}
aria-checked={Boolean(oauthConfiguration)}
tabIndex={oauthConfiguration ? 0 : -1}
disabled={busy || loading || modelLoading}
data-value="oauth"
onClick={() => {
if (!oauthConfiguration) {
void changeOauthConfiguration(true);
}
}}
>
{busyAction === 'oauth-check' ? <LoaderCircle size={14} className="spin" /> : null}
{t('agents.modify.authOAuth')}
</button>
</div>
</div>
{codexCatalogButton}
+54
View File
@@ -14268,6 +14268,59 @@ body.table-col-resizing * {
/* Configuration form and explicit write actions. */
.agent-auth-method { display: grid; gap: 6px; flex: 1; min-width: 0; font-size: var(--font-size-meta); }
.agent-auth-method select { width: 100%; min-height: 38px; padding: 8px 10px; border: 1px solid var(--theme-e3e1db); border-radius: 8px; color: var(--theme-2d2a26); background: var(--theme-fffdf8); }
.agent-auth-segmented {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
align-items: center;
gap: 3px;
min-height: 38px;
height: 38px;
padding: 3px;
border: 1px solid var(--theme-e3e1db);
border-radius: 8px;
background: var(--theme-eeece6);
box-sizing: border-box;
}
.agent-auth-segmented-button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
height: 100%;
min-width: 0;
padding: 0 10px;
border: 0;
border-radius: 5px;
background: transparent;
color: var(--theme-7a746c);
font-size: var(--font-size-meta);
font-weight: 600;
font-family: inherit;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
cursor: pointer;
user-select: none;
transition: background 140ms ease, color 140ms ease, box-shadow 140ms ease;
}
.agent-auth-segmented-button:hover:not(:disabled) {
background: var(--theme-e8e5dc);
color: var(--theme-2d2a26);
}
.agent-auth-segmented-button.active {
background: var(--theme-fffdf8);
color: var(--theme-2d2a26);
font-weight: 700;
box-shadow: 0 1px 3px rgba(45, 42, 38, 0.12);
}
.agent-auth-segmented-button:disabled {
cursor: not-allowed;
opacity: 0.55;
}
.agent-auth-segmented-button:focus-visible {
outline: 2px solid var(--theme-2d2a26);
outline-offset: -1px;
}
.agent-model-section .agent-codex-options { margin-top: 16px; align-items: end; }
.agent-model-section .agent-codex-catalog-button { min-height: 38px; height: 38px; padding: 8px 10px; }
.agent-write-state { margin: 0; font-size: var(--font-size-meta); color: var(--theme-7a746c); }
@@ -14307,6 +14360,7 @@ body.table-col-resizing * {
.agent-run-controls .agent-launch-button { flex: 0 1 auto; width: auto; min-width: 0; max-width: 100%; }
}
.agent-signin-label { display: flex; align-items: center; gap: 8px; }
.agent-signin-label-title { font-weight: 600; color: var(--theme-2d2a26); }
.agent-signin-help-toggle { display: inline-flex; align-items: center; gap: 4px; min-height: 30px; padding: 3px 6px; border: 0; border-radius: 4px; background: transparent; color: var(--theme-7a746c); font: inherit; cursor: pointer; }
.agent-signin-help-toggle:hover { color: var(--theme-2d2a26); background: var(--theme-fffdf8); }
.agent-signin-help-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
+2 -2
View File
@@ -78,10 +78,10 @@ const assert = require('node:assert/strict');
await page.locator('.agent-list-items button').filter({ hasText: 'Codex' }).click();
await ready(); await expectPending(true);
await selectModel('gpt-one'); await expectPending(false);
await page.locator('#agent-connection-method').selectOption('oauth');
await page.locator('#agent-connection-method [data-value="oauth"]').click();
await expectPending(true);
await selectModel('gpt-two');
await page.locator('#agent-connection-method').selectOption('apikey');
await page.locator('#agent-connection-method [data-value="apikey"]').click();
await expectPending(true);
await selectModel('gpt-one'); await expectPending(false);