mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-03 11:20:50 +08:00
feat: improve iFlow cookie auth UX with duplicate config handling
- Add 409 conflict handling for duplicate iFlow config files - Add key creation hint in cookie login section - Move extra actions button after delete button for consistency - Improve OAuth status badge display logic (hide when idle) - Add config toggle enable/disable i18n translations - Adjust item-actions spacing from sm to md
This commit is contained in:
@@ -447,10 +447,13 @@
|
|||||||
"iflow_cookie_label": "Cookie Value:",
|
"iflow_cookie_label": "Cookie Value:",
|
||||||
"iflow_cookie_placeholder": "Paste browser cookie, e.g. sessionid=...;",
|
"iflow_cookie_placeholder": "Paste browser cookie, e.g. sessionid=...;",
|
||||||
"iflow_cookie_hint": "Submit an existing cookie to finish login without opening the authorization link; the credential file will be saved automatically.",
|
"iflow_cookie_hint": "Submit an existing cookie to finish login without opening the authorization link; the credential file will be saved automatically.",
|
||||||
|
"iflow_cookie_key_hint": "Note: Create a key on the platform first.",
|
||||||
"iflow_cookie_button": "Submit Cookie Login",
|
"iflow_cookie_button": "Submit Cookie Login",
|
||||||
"iflow_cookie_status_success": "Cookie login succeeded and credentials are saved.",
|
"iflow_cookie_status_success": "Cookie login succeeded and credentials are saved.",
|
||||||
"iflow_cookie_status_error": "Cookie login failed:",
|
"iflow_cookie_status_error": "Cookie login failed:",
|
||||||
|
"iflow_cookie_status_duplicate": "Duplicate config:",
|
||||||
"iflow_cookie_start_error": "Failed to submit cookie login:",
|
"iflow_cookie_start_error": "Failed to submit cookie login:",
|
||||||
|
"iflow_cookie_config_duplicate": "A config file already exists (duplicate). Remove the existing file and try again if you want to re-save it.",
|
||||||
"iflow_cookie_required": "Please provide the Cookie value first.",
|
"iflow_cookie_required": "Please provide the Cookie value first.",
|
||||||
"iflow_cookie_result_title": "Cookie Login Result",
|
"iflow_cookie_result_title": "Cookie Login Result",
|
||||||
"iflow_cookie_result_email": "Account",
|
"iflow_cookie_result_email": "Account",
|
||||||
|
|||||||
@@ -148,6 +148,8 @@
|
|||||||
"excluded_models_placeholder": "用逗号或换行分隔,例如: gemini-1.5-pro, gemini-1.5-flash",
|
"excluded_models_placeholder": "用逗号或换行分隔,例如: gemini-1.5-pro, gemini-1.5-flash",
|
||||||
"excluded_models_hint": "留空表示不过滤;保存时会自动去重并忽略空白。",
|
"excluded_models_hint": "留空表示不过滤;保存时会自动去重并忽略空白。",
|
||||||
"excluded_models_count": "排除 {{count}} 个模型",
|
"excluded_models_count": "排除 {{count}} 个模型",
|
||||||
|
"config_toggle_label": "启用",
|
||||||
|
"config_disabled_badge": "已停用",
|
||||||
"codex_title": "Codex API 配置",
|
"codex_title": "Codex API 配置",
|
||||||
"codex_add_button": "添加配置",
|
"codex_add_button": "添加配置",
|
||||||
"codex_empty_title": "暂无Codex配置",
|
"codex_empty_title": "暂无Codex配置",
|
||||||
@@ -445,10 +447,13 @@
|
|||||||
"iflow_cookie_label": "Cookie 内容:",
|
"iflow_cookie_label": "Cookie 内容:",
|
||||||
"iflow_cookie_placeholder": "粘贴浏览器中的 Cookie,例如 sessionid=...;",
|
"iflow_cookie_placeholder": "粘贴浏览器中的 Cookie,例如 sessionid=...;",
|
||||||
"iflow_cookie_hint": "直接提交 Cookie 以完成登录(无需打开授权链接),服务端将自动保存凭据。",
|
"iflow_cookie_hint": "直接提交 Cookie 以完成登录(无需打开授权链接),服务端将自动保存凭据。",
|
||||||
|
"iflow_cookie_key_hint": "提示:需在平台上先创建 Key。",
|
||||||
"iflow_cookie_button": "提交 Cookie 登录",
|
"iflow_cookie_button": "提交 Cookie 登录",
|
||||||
"iflow_cookie_status_success": "Cookie 登录成功,凭据已保存。",
|
"iflow_cookie_status_success": "Cookie 登录成功,凭据已保存。",
|
||||||
"iflow_cookie_status_error": "Cookie 登录失败:",
|
"iflow_cookie_status_error": "Cookie 登录失败:",
|
||||||
|
"iflow_cookie_status_duplicate": "配置文件重复:",
|
||||||
"iflow_cookie_start_error": "提交 Cookie 登录失败:",
|
"iflow_cookie_start_error": "提交 Cookie 登录失败:",
|
||||||
|
"iflow_cookie_config_duplicate": "检测到配置文件已存在(重复),如需重新保存请先删除原文件后重试。",
|
||||||
"iflow_cookie_required": "请先填写 Cookie 内容",
|
"iflow_cookie_required": "请先填写 Cookie 内容",
|
||||||
"iflow_cookie_result_title": "Cookie 登录结果",
|
"iflow_cookie_result_title": "Cookie 登录结果",
|
||||||
"iflow_cookie_result_email": "账号",
|
"iflow_cookie_result_email": "账号",
|
||||||
@@ -636,6 +641,8 @@
|
|||||||
"claude_config_added": "Claude配置添加成功",
|
"claude_config_added": "Claude配置添加成功",
|
||||||
"claude_config_updated": "Claude配置更新成功",
|
"claude_config_updated": "Claude配置更新成功",
|
||||||
"claude_config_deleted": "Claude配置删除成功",
|
"claude_config_deleted": "Claude配置删除成功",
|
||||||
|
"config_enabled": "配置已启用",
|
||||||
|
"config_disabled": "配置已停用",
|
||||||
"field_required": "必填字段不能为空",
|
"field_required": "必填字段不能为空",
|
||||||
"openai_provider_required": "请填写提供商名称和Base URL",
|
"openai_provider_required": "请填写提供商名称和Base URL",
|
||||||
"openai_provider_added": "OpenAI提供商添加成功",
|
"openai_provider_added": "OpenAI提供商添加成功",
|
||||||
|
|||||||
@@ -1046,7 +1046,6 @@ export function AiProvidersPage() {
|
|||||||
<div key={keyField(item)} className="item-row" style={rowDisabled ? { opacity: 0.6 } : undefined}>
|
<div key={keyField(item)} className="item-row" style={rowDisabled ? { opacity: 0.6 } : undefined}>
|
||||||
<div className="item-meta">{renderContent(item, index)}</div>
|
<div className="item-meta">{renderContent(item, index)}</div>
|
||||||
<div className="item-actions">
|
<div className="item-actions">
|
||||||
{options?.renderExtraActions ? options.renderExtraActions(item, index) : null}
|
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
size="sm"
|
size="sm"
|
||||||
@@ -1063,6 +1062,7 @@ export function AiProvidersPage() {
|
|||||||
>
|
>
|
||||||
{deleteLabel || t('common.delete')}
|
{deleteLabel || t('common.delete')}
|
||||||
</Button>
|
</Button>
|
||||||
|
{options?.renderExtraActions ? options.renderExtraActions(item, index) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ interface IFlowCookieState {
|
|||||||
loading: boolean;
|
loading: boolean;
|
||||||
result?: IFlowCookieAuthResponse;
|
result?: IFlowCookieAuthResponse;
|
||||||
error?: string;
|
error?: string;
|
||||||
|
errorType?: 'error' | 'warning';
|
||||||
}
|
}
|
||||||
|
|
||||||
const PROVIDERS: { id: OAuthProvider; titleKey: string; hintKey: string; urlLabelKey: string }[] = [
|
const PROVIDERS: { id: OAuthProvider; titleKey: string; hintKey: string; urlLabelKey: string }[] = [
|
||||||
@@ -122,18 +123,35 @@ export function OAuthPage() {
|
|||||||
showNotification(t('auth_login.iflow_cookie_required'), 'warning');
|
showNotification(t('auth_login.iflow_cookie_required'), 'warning');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setIflowCookie((prev) => ({ ...prev, loading: true, error: undefined, result: undefined }));
|
setIflowCookie((prev) => ({
|
||||||
|
...prev,
|
||||||
|
loading: true,
|
||||||
|
error: undefined,
|
||||||
|
errorType: undefined,
|
||||||
|
result: undefined
|
||||||
|
}));
|
||||||
try {
|
try {
|
||||||
const res = await oauthApi.iflowCookieAuth(cookie);
|
const res = await oauthApi.iflowCookieAuth(cookie);
|
||||||
if (res.status === 'ok') {
|
if (res.status === 'ok') {
|
||||||
setIflowCookie((prev) => ({ ...prev, loading: false, result: res }));
|
setIflowCookie((prev) => ({ ...prev, loading: false, result: res }));
|
||||||
showNotification(t('auth_login.iflow_cookie_status_success'), 'success');
|
showNotification(t('auth_login.iflow_cookie_status_success'), 'success');
|
||||||
} else {
|
} else {
|
||||||
setIflowCookie((prev) => ({ ...prev, loading: false, error: res.error }));
|
setIflowCookie((prev) => ({
|
||||||
|
...prev,
|
||||||
|
loading: false,
|
||||||
|
error: res.error,
|
||||||
|
errorType: 'error'
|
||||||
|
}));
|
||||||
showNotification(`${t('auth_login.iflow_cookie_status_error')} ${res.error || ''}`, 'error');
|
showNotification(`${t('auth_login.iflow_cookie_status_error')} ${res.error || ''}`, 'error');
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
setIflowCookie((prev) => ({ ...prev, loading: false, error: err?.message }));
|
if (err?.status === 409) {
|
||||||
|
const message = t('auth_login.iflow_cookie_config_duplicate');
|
||||||
|
setIflowCookie((prev) => ({ ...prev, loading: false, error: message, errorType: 'warning' }));
|
||||||
|
showNotification(message, 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setIflowCookie((prev) => ({ ...prev, loading: false, error: err?.message, errorType: 'error' }));
|
||||||
showNotification(`${t('auth_login.iflow_cookie_start_error')} ${err?.message || ''}`, 'error');
|
showNotification(`${t('auth_login.iflow_cookie_start_error')} ${err?.message || ''}`, 'error');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -185,15 +203,13 @@ export function OAuthPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!isDisabled && (
|
{!isDisabled && state.status && state.status !== 'idle' && (
|
||||||
<div className="status-badge" style={{ marginTop: 8 }}>
|
<div className="status-badge" style={{ marginTop: 8 }}>
|
||||||
{state.status === 'success'
|
{state.status === 'success'
|
||||||
? t('auth_login.codex_oauth_status_success')
|
? t('auth_login.codex_oauth_status_success')
|
||||||
: state.status === 'error'
|
: state.status === 'error'
|
||||||
? `${t('auth_login.codex_oauth_status_error')} ${state.error || ''}`
|
? `${t('auth_login.codex_oauth_status_error')} ${state.error || ''}`
|
||||||
: state.status === 'waiting'
|
: t('auth_login.codex_oauth_status_waiting')}
|
||||||
? t('auth_login.codex_oauth_status_waiting')
|
|
||||||
: t('common.info')}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
@@ -211,6 +227,9 @@ export function OAuthPage() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="hint">{t('auth_login.iflow_cookie_hint')}</div>
|
<div className="hint">{t('auth_login.iflow_cookie_hint')}</div>
|
||||||
|
<div className="hint" style={{ marginTop: 4 }}>
|
||||||
|
{t('auth_login.iflow_cookie_key_hint')}
|
||||||
|
</div>
|
||||||
<div className="form-item" style={{ marginTop: 12 }}>
|
<div className="form-item" style={{ marginTop: 12 }}>
|
||||||
<label className="label">{t('auth_login.iflow_cookie_label')}</label>
|
<label className="label">{t('auth_login.iflow_cookie_label')}</label>
|
||||||
<Input
|
<Input
|
||||||
@@ -220,8 +239,14 @@ export function OAuthPage() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{iflowCookie.error && (
|
{iflowCookie.error && (
|
||||||
<div className="status-badge error" style={{ marginTop: 8 }}>
|
<div
|
||||||
{t('auth_login.iflow_cookie_status_error')} {iflowCookie.error}
|
className={`status-badge ${iflowCookie.errorType === 'warning' ? 'warning' : 'error'}`}
|
||||||
|
style={{ marginTop: 8 }}
|
||||||
|
>
|
||||||
|
{iflowCookie.errorType === 'warning'
|
||||||
|
? t('auth_login.iflow_cookie_status_duplicate')
|
||||||
|
: t('auth_login.iflow_cookie_status_error')}{' '}
|
||||||
|
{iflowCookie.error}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{iflowCookie.result && iflowCookie.result.status === 'ok' && (
|
{iflowCookie.result && iflowCookie.result.status === 'ok' && (
|
||||||
|
|||||||
@@ -407,7 +407,7 @@
|
|||||||
|
|
||||||
.item-actions {
|
.item-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: $spacing-sm;
|
gap: $spacing-md;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user