fix(accounts): show OAuth results in notifications

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Zyy
2026-11-03 15:55:56 +08:00
co-authored by Codex
parent 12c32fcdec
commit 317c05c74a
5 changed files with 25 additions and 32 deletions
@@ -304,7 +304,6 @@
"fileReadingFailedTryAgain": "File reading failed, please try again",
"uploadFiles": "Upload files",
"authorizationExpired": "Authorization expired, start again or check whether authorization completed",
"pollingPaused": "Polling paused, check the authorization result to continue",
"regenerateAuthorizationLink": "Regenerate authorization link",
"generateAuthorizationLink": "Generate authorization link",
"authorizationLink": "Authorization link",
@@ -304,7 +304,6 @@
"fileReadingFailedTryAgain": "文件读取失败,请重新选择",
"uploadFiles": "上传文件",
"authorizationExpired": "授权已过期,可重新开始或检查已完成的授权结果",
"pollingPaused": "查询已暂停,可检查授权结果后继续",
"regenerateAuthorizationLink": "重新生成授权链接",
"generateAuthorizationLink": "生成授权链接",
"authorizationLink": "授权链接",
@@ -304,7 +304,6 @@
"fileReadingFailedTryAgain": "文件讀取失敗,請重新選擇",
"uploadFiles": "上傳文件",
"authorizationExpired": "授權已過期,可重新開始或檢查已完成的授權結果",
"pollingPaused": "查詢已暫停,可檢查授權結果後繼續",
"regenerateAuthorizationLink": "重新生成授權鏈接",
"generateAuthorizationLink": "生成授權鏈接",
"authorizationLink": "授權鏈接",
@@ -3,11 +3,10 @@ import type { AccountAuthorizationView } from '../../composables/useAccountAutho
import { ZButton, ZForm, ZFormItem, ZIconButton, ZScrollbar, ZTextarea } from '@codex-proxy/ui'
import { Copy, KeyRound } from '@lucide/vue'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useCopyText } from '@/composables/useCopyText'
const props = defineProps<{
defineProps<{
authUrl: string
panelTitle: string
panelDescription: string
@@ -25,13 +24,6 @@ const { t } = useI18n({ useScope: 'global' })
const callback = defineModel<string>({ required: true })
const copyWithToast = useCopyText()
const statusText = computed(() => {
if (props.authorization.status === 'expired')
return t('accounts.onboarding.authorizationExpired')
if (props.authorization.status === 'paused')
return t('accounts.onboarding.pollingPaused')
return ''
})
</script>
<template>
@@ -89,13 +81,6 @@ const statusText = computed(() => {
</ZFormItem>
</ZForm>
<p v-if="statusText" class="m-0 text-z-sm text-z-text-secondary" role="status">
{{ statusText }}
</p>
<p v-if="authorization.error" class="m-0 text-z-sm text-z-error" role="alert">
{{ authorization.error }}
</p>
<ZForm v-if="authorization.flow">
<ZFormItem :label="callbackLabel" required>
<ZTextarea
@@ -1,15 +1,16 @@
import type { AccountImportSettings, AccountOAuthStartResponse } from '@/api'
import { computed, onScopeDispose, shallowRef } from 'vue'
import { completeAccountOAuth, startAccountOAuth } from '@/api'
import { ApiError } from '@/api/request'
import { t } from '@/i18n'
import { notification as ZNotification } from '@/utils/notification'
import { errorMessage } from '@/utils/operation'
type Status = 'idle' | 'starting' | 'waiting' | 'paused' | 'expired' | 'completing'
type Status = 'idle' | 'starting' | 'waiting' | 'expired' | 'completing'
export interface AccountAuthorizationView {
flow: AccountOAuthStartResponse | null
status: Status
error: string
}
interface AuthorizationRequest {
@@ -20,13 +21,11 @@ interface AuthorizationRequest {
export function useAccountAuthorization(onComplete: () => Promise<void>) {
const flow = shallowRef<AccountOAuthStartResponse | null>(null)
const status = shallowRef<Status>('idle')
const error = shallowRef('')
const callback = shallowRef('')
const busy = computed(() => status.value === 'starting' || status.value === 'completing')
const view = computed<AccountAuthorizationView>(() => ({
flow: flow.value,
status: status.value,
error: error.value,
}))
let context: { provider: string, settings?: AccountImportSettings } | undefined
let controller: AbortController | undefined
@@ -48,7 +47,6 @@ export function useAccountAuthorization(onComplete: () => Promise<void>) {
cancel()
flow.value = null
status.value = 'idle'
error.value = ''
callback.value = ''
}
@@ -62,7 +60,7 @@ export function useAccountAuthorization(onComplete: () => Promise<void>) {
controller = current
status.value = 'starting'
try {
const result = await startAccountOAuth(request.start, { signal: current.signal, silent: true })
const result = await startAccountOAuth(request.start, { signal: current.signal })
if (current.signal.aborted)
return
const expiresAt = Date.parse(result.expiresAt)
@@ -75,14 +73,22 @@ export function useAccountAuthorization(onComplete: () => Promise<void>) {
: 'waiting'
expiryTimer = setTimeout(() => {
// 不取消正在确认的提交,过期后仍接收服务端已经提交的结果。
if (status.value !== 'completing')
if (status.value !== 'completing') {
status.value = 'expired'
ZNotification.warning({
message: t('accounts.onboarding.authorizationExpired'),
})
}
}, Math.max(0, Math.min(expiresAt - Date.now(), 2_147_483_647)))
}
catch (cause) {
if (!current.signal.aborted) {
error.value = errorMessage(cause, t('accounts.onboarding.linkFailed'))
status.value = 'idle'
if (!(cause instanceof ApiError)) {
ZNotification.error({
message: errorMessage(cause, t('accounts.onboarding.linkFailed')),
})
}
}
}
}
@@ -93,17 +99,18 @@ export function useAccountAuthorization(onComplete: () => Promise<void>) {
if (!current || !currentFlow || !context || busy.value)
return
if (!callback.value.trim()) {
error.value = t('accounts.onboarding.callbackRequired')
ZNotification.warning({
message: t('accounts.onboarding.callbackRequired'),
})
return
}
status.value = 'completing'
error.value = ''
try {
await completeAccountOAuth({
...context,
flowId: currentFlow.flowId,
callbackUrl: callback.value.trim(),
}, { signal: current.signal, silent: true })
}, { signal: current.signal })
if (!current.signal.aborted) {
clearTimers()
await onComplete()
@@ -113,8 +120,12 @@ export function useAccountAuthorization(onComplete: () => Promise<void>) {
if (!current.signal.aborted) {
status.value = expired()
? 'expired'
: 'paused'
error.value = errorMessage(cause, t('accounts.onboarding.authorizationFailed'))
: 'waiting'
if (!(cause instanceof ApiError)) {
ZNotification.error({
message: errorMessage(cause, t('accounts.onboarding.authorizationFailed')),
})
}
}
}
}