fix(settings): 处理 PR 审核意见 — 验证失败文案 / 切换回滚 / 计时器依赖
- ProvidersSection: 验证失败时显示 validateFailed 文案,不再对 result.ok=false 误报「连接检查通过」 - ProvidersSection: LLM/ASR 切换失败时下拉框回滚到 committed provider,避免 UI 停在新选项而后端仍是旧 provider;去掉 handler 末尾的 rethrow —— 作为 SelectLite onChange 是即发即忘调用,rethrow 会变成未处理的 promise rejection - CheckUpdateButton: 自动收起计时器只依赖 status,不再因 useAutoUpdate 每次渲染 返回新 updater 对象而被反复 clear/reset - 新增 i18n key settings.providers.validateFailed(zh-CN/zh-TW/en/ja/ko)
This commit is contained in:
1 parent
52c49fcfad
commit
7dc1600c4c
7 files changed
+24
-9
No files matched your search
@@ -660,6 +660,7 @@ export const en: typeof zhCN = {
|
||||
selectModel: 'Select a model to fill the field above',
|
||||
modelSaved: 'Saved model {{model}}.',
|
||||
validateSuccess: 'Connection check passed.',
|
||||
validateFailed: 'Connection check failed.',
|
||||
providerHttpStatus: 'Provider returned HTTP {{status}}. Check the API key permissions or endpoint.',
|
||||
endpointMustUseHttps: 'Endpoint must use HTTPS (localhost/127.0.0.1 are allowed for local testing).',
|
||||
endpointInvalid: 'Endpoint format is invalid.',
|
||||
|
||||
@@ -662,6 +662,7 @@ export const ja: typeof zhCN = {
|
||||
selectModel: 'モデルを選んで上記欄に入力',
|
||||
modelSaved: 'モデル {{model}} を保存しました。',
|
||||
validateSuccess: '接続チェックに合格しました。',
|
||||
validateFailed: '接続チェックに失敗しました。',
|
||||
providerHttpStatus: 'サプライヤーが {{status}} を返しました。API Key 権限またはエンドポイントを確認してください。',
|
||||
endpointMustUseHttps: 'Endpoint は HTTPS を使用する必要があります(localhost/127.0.0.1 を除く)。',
|
||||
endpointInvalid: 'Endpoint の形式が無効です。',
|
||||
|
||||
@@ -662,6 +662,7 @@ export const ko: typeof zhCN = {
|
||||
selectModel: '모델을 선택해 위 필드에 입력',
|
||||
modelSaved: '모델 {{model}} 을(를) 저장했습니다.',
|
||||
validateSuccess: '연결 확인을 통과했습니다.',
|
||||
validateFailed: '연결 확인에 실패했습니다.',
|
||||
providerHttpStatus: '공급자가 {{status}} 를 반환했습니다. API Key 권한 또는 Endpoint 를 확인해 주세요.',
|
||||
endpointMustUseHttps: 'Endpoint 는 HTTPS 를 사용해야 합니다(localhost/127.0.0.1 제외).',
|
||||
endpointInvalid: 'Endpoint 형식이 올바르지 않습니다.',
|
||||
|
||||
@@ -658,6 +658,7 @@ export const zhCN = {
|
||||
selectModel: '选择一个模型写入上方字段',
|
||||
modelSaved: '已保存模型 {{model}}。',
|
||||
validateSuccess: '连接检查通过。',
|
||||
validateFailed: '连接检查未通过。',
|
||||
providerHttpStatus: '供应商接口返回 {{status}},请检查 API Key 权限或 Endpoint。',
|
||||
endpointMustUseHttps: 'Endpoint 必须使用 HTTPS(本地 localhost/127.0.0.1 测试除外)。',
|
||||
endpointInvalid: 'Endpoint 格式不合法。',
|
||||
|
||||
@@ -660,6 +660,7 @@ export const zhTW: typeof zhCN = {
|
||||
selectModel: '選擇一個模型寫入上方字段',
|
||||
modelSaved: '已保存模型 {{model}}。',
|
||||
validateSuccess: '連接檢查通過。',
|
||||
validateFailed: '連接檢查未通過。',
|
||||
providerHttpStatus: '供應商接口返回 {{status}},請檢查 API Key 權限或 Endpoint。',
|
||||
endpointMustUseHttps: 'Endpoint 必須使用 HTTPS(本地 localhost/127.0.0.1 測試除外)。',
|
||||
endpointInvalid: 'Endpoint 格式不合法。',
|
||||
|
||||
@@ -22,7 +22,10 @@ export function CheckUpdateButton({ channel }: { channel: UpdateChannel }) {
|
||||
return () => window.clearTimeout(id);
|
||||
}
|
||||
return undefined;
|
||||
}, [status, updater]);
|
||||
// 只按 status 触发:useAutoUpdate 每次渲染都返回新 updater 对象,把它放进
|
||||
// 依赖会让父组件每次重渲染都把 2.5s 自动收起计时器清掉重置。
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [status]);
|
||||
|
||||
const upToDate = status === 'none';
|
||||
const failed = status === 'error';
|
||||
|
||||
@@ -224,13 +224,17 @@ export function ProvidersSection() {
|
||||
setCommittedLlmProvider(id);
|
||||
emitSaved('saved', t('common.saved'));
|
||||
} catch (err) {
|
||||
// seq 守卫:只有当前 call 还是最新时才把 saving 翻成 failed;
|
||||
// 旧 call 早被 newer call 的 emitSaved('saving') 覆盖,再叠 failed 会
|
||||
// 把 newer 正在跑的 saving 假伪成失败。
|
||||
// seq 守卫:只有当前 call 还是最新时才翻 failed + 回滚下拉框;旧 call 早被
|
||||
// newer call 的 emitSaved('saving') 覆盖,不要插手。
|
||||
if (seq === llmSwitchSeqRef.current) {
|
||||
emitSaved('failed', t('common.operationFailed'));
|
||||
// 后端切换失败 → 下拉框退回真实生效的 committed provider,免得 UI 停在
|
||||
// 新选项、实际 provider 仍是旧的,造成显示与后端不一致。
|
||||
setLlmProvider(committedLlmProvider);
|
||||
}
|
||||
throw err;
|
||||
// 不再 rethrow:本 handler 作为 SelectLite onChange 是即发即忘调用,
|
||||
// rethrow 会变成未处理的 promise rejection。错误已 emitSaved + 记日志。
|
||||
console.error('[settings] switch LLM provider failed', err);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -277,12 +281,12 @@ export function ProvidersSection() {
|
||||
setCommittedAsrProvider(id);
|
||||
emitSaved('saved', t('common.saved'));
|
||||
} catch (err) {
|
||||
// seq 守卫同上 onLlmProviderChange:旧 call 不要把 newer call 的 saving
|
||||
// 伪造成 failed。
|
||||
// seq 守卫 + 回滚 + 不 rethrow,同 onLlmProviderChange。
|
||||
if (seq === asrSwitchSeqRef.current) {
|
||||
emitSaved('failed', t('common.operationFailed'));
|
||||
setAsrProvider(committedAsrProvider);
|
||||
}
|
||||
throw err;
|
||||
console.error('[settings] switch ASR provider failed', err);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -473,7 +477,10 @@ function ProviderTools({ kind, modelAccount, onModelSelected }: { kind: 'llm' |
|
||||
setResult('loading', t('settings.providers.validating'));
|
||||
try {
|
||||
const result = await validateProviderCredentials(kind);
|
||||
setResult(result.ok ? 'success' : 'error', t('settings.providers.validateSuccess'));
|
||||
setResult(
|
||||
result.ok ? 'success' : 'error',
|
||||
t(result.ok ? 'settings.providers.validateSuccess' : 'settings.providers.validateFailed'),
|
||||
);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
if ((kind === 'llm' && message === 'llmModelMissing') || (kind === 'asr' && message === 'asrModelMissing')) {
|
||||
|
||||
Reference in new issue
Block a user