Merge pull request #1663 from touwaeriol/fix/test-dialog-close-during-stream
fix(ui): allow closing test dialog during active SSE stream
This commit is contained in:
@@ -165,7 +165,6 @@
|
|||||||
<button
|
<button
|
||||||
@click="handleClose"
|
@click="handleClose"
|
||||||
class="rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-200 dark:bg-dark-600 dark:text-gray-300 dark:hover:bg-dark-500"
|
class="rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-200 dark:bg-dark-600 dark:text-gray-300 dark:hover:bg-dark-500"
|
||||||
:disabled="status === 'connecting'"
|
|
||||||
>
|
>
|
||||||
{{ t('common.close') }}
|
{{ t('common.close') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -249,7 +248,7 @@ const availableModels = ref<ClaudeModel[]>([])
|
|||||||
const selectedModelId = ref('')
|
const selectedModelId = ref('')
|
||||||
const testPrompt = ref('')
|
const testPrompt = ref('')
|
||||||
const loadingModels = ref(false)
|
const loadingModels = ref(false)
|
||||||
let eventSource: EventSource | null = null
|
let abortController: AbortController | null = null
|
||||||
const generatedImages = ref<PreviewImage[]>([])
|
const generatedImages = ref<PreviewImage[]>([])
|
||||||
const prioritizedGeminiModels = ['gemini-3.1-flash-image', 'gemini-2.5-flash-image', 'gemini-2.5-flash', 'gemini-2.5-pro', 'gemini-3-flash-preview', 'gemini-3-pro-preview', 'gemini-2.0-flash']
|
const prioritizedGeminiModels = ['gemini-3.1-flash-image', 'gemini-2.5-flash-image', 'gemini-2.5-flash', 'gemini-2.5-pro', 'gemini-3-flash-preview', 'gemini-3-pro-preview', 'gemini-2.0-flash']
|
||||||
const supportsGeminiImageTest = computed(() => {
|
const supportsGeminiImageTest = computed(() => {
|
||||||
@@ -279,7 +278,7 @@ watch(
|
|||||||
resetState()
|
resetState()
|
||||||
await loadAvailableModels()
|
await loadAvailableModels()
|
||||||
} else {
|
} else {
|
||||||
closeEventSource()
|
abortStream()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -329,18 +328,14 @@ const resetState = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
// 防止在连接测试进行中关闭对话框
|
abortStream()
|
||||||
if (status.value === 'connecting') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
closeEventSource()
|
|
||||||
emit('close')
|
emit('close')
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeEventSource = () => {
|
const abortStream = () => {
|
||||||
if (eventSource) {
|
if (abortController) {
|
||||||
eventSource.close()
|
abortController.abort()
|
||||||
eventSource = null
|
abortController = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,7 +360,9 @@ const startTest = async () => {
|
|||||||
addLine(t('admin.accounts.testAccountTypeLabel', { type: props.account.type }), 'text-gray-400')
|
addLine(t('admin.accounts.testAccountTypeLabel', { type: props.account.type }), 'text-gray-400')
|
||||||
addLine('', 'text-gray-300')
|
addLine('', 'text-gray-300')
|
||||||
|
|
||||||
closeEventSource()
|
abortStream()
|
||||||
|
|
||||||
|
abortController = new AbortController()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create EventSource for SSE
|
// Create EventSource for SSE
|
||||||
@@ -381,7 +378,8 @@ const startTest = async () => {
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
model_id: selectedModelId.value,
|
model_id: selectedModelId.value,
|
||||||
prompt: supportsGeminiImageTest.value ? testPrompt.value.trim() : ''
|
prompt: supportsGeminiImageTest.value ? testPrompt.value.trim() : ''
|
||||||
})
|
}),
|
||||||
|
signal: abortController.signal
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -418,10 +416,15 @@ const startTest = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: unknown) {
|
||||||
|
if (error instanceof DOMException && error.name === 'AbortError') {
|
||||||
|
status.value = 'idle'
|
||||||
|
return
|
||||||
|
}
|
||||||
status.value = 'error'
|
status.value = 'error'
|
||||||
errorMessage.value = error.message || 'Unknown error'
|
const msg = error instanceof Error ? error.message : 'Unknown error'
|
||||||
addLine(`Error: ${errorMessage.value}`, 'text-red-400')
|
errorMessage.value = msg
|
||||||
|
addLine(`Error: ${msg}`, 'text-red-400')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -165,7 +165,6 @@
|
|||||||
<button
|
<button
|
||||||
@click="handleClose"
|
@click="handleClose"
|
||||||
class="rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-200 dark:bg-dark-600 dark:text-gray-300 dark:hover:bg-dark-500"
|
class="rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-200 dark:bg-dark-600 dark:text-gray-300 dark:hover:bg-dark-500"
|
||||||
:disabled="status === 'connecting'"
|
|
||||||
>
|
>
|
||||||
{{ t('common.close') }}
|
{{ t('common.close') }}
|
||||||
</button>
|
</button>
|
||||||
@@ -249,7 +248,7 @@ const availableModels = ref<ClaudeModel[]>([])
|
|||||||
const selectedModelId = ref('')
|
const selectedModelId = ref('')
|
||||||
const testPrompt = ref('')
|
const testPrompt = ref('')
|
||||||
const loadingModels = ref(false)
|
const loadingModels = ref(false)
|
||||||
let eventSource: EventSource | null = null
|
let abortController: AbortController | null = null
|
||||||
const generatedImages = ref<PreviewImage[]>([])
|
const generatedImages = ref<PreviewImage[]>([])
|
||||||
const prioritizedGeminiModels = ['gemini-3.1-flash-image', 'gemini-2.5-flash-image', 'gemini-2.5-flash', 'gemini-2.5-pro', 'gemini-3-flash-preview', 'gemini-3-pro-preview', 'gemini-2.0-flash']
|
const prioritizedGeminiModels = ['gemini-3.1-flash-image', 'gemini-2.5-flash-image', 'gemini-2.5-flash', 'gemini-2.5-pro', 'gemini-3-flash-preview', 'gemini-3-pro-preview', 'gemini-2.0-flash']
|
||||||
const supportsGeminiImageTest = computed(() => {
|
const supportsGeminiImageTest = computed(() => {
|
||||||
@@ -279,7 +278,7 @@ watch(
|
|||||||
resetState()
|
resetState()
|
||||||
await loadAvailableModels()
|
await loadAvailableModels()
|
||||||
} else {
|
} else {
|
||||||
closeEventSource()
|
abortStream()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -329,18 +328,14 @@ const resetState = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
// 防止在连接测试进行中关闭对话框
|
abortStream()
|
||||||
if (status.value === 'connecting') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
closeEventSource()
|
|
||||||
emit('close')
|
emit('close')
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeEventSource = () => {
|
const abortStream = () => {
|
||||||
if (eventSource) {
|
if (abortController) {
|
||||||
eventSource.close()
|
abortController.abort()
|
||||||
eventSource = null
|
abortController = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,7 +360,9 @@ const startTest = async () => {
|
|||||||
addLine(t('admin.accounts.testAccountTypeLabel', { type: props.account.type }), 'text-gray-400')
|
addLine(t('admin.accounts.testAccountTypeLabel', { type: props.account.type }), 'text-gray-400')
|
||||||
addLine('', 'text-gray-300')
|
addLine('', 'text-gray-300')
|
||||||
|
|
||||||
closeEventSource()
|
abortStream()
|
||||||
|
|
||||||
|
abortController = new AbortController()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create EventSource for SSE
|
// Create EventSource for SSE
|
||||||
@@ -381,7 +378,8 @@ const startTest = async () => {
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
model_id: selectedModelId.value,
|
model_id: selectedModelId.value,
|
||||||
prompt: supportsGeminiImageTest.value ? testPrompt.value.trim() : ''
|
prompt: supportsGeminiImageTest.value ? testPrompt.value.trim() : ''
|
||||||
})
|
}),
|
||||||
|
signal: abortController.signal
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -418,10 +416,15 @@ const startTest = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: unknown) {
|
||||||
|
if (error instanceof DOMException && error.name === 'AbortError') {
|
||||||
|
status.value = 'idle'
|
||||||
|
return
|
||||||
|
}
|
||||||
status.value = 'error'
|
status.value = 'error'
|
||||||
errorMessage.value = error.message || 'Unknown error'
|
const msg = error instanceof Error ? error.message : 'Unknown error'
|
||||||
addLine(`Error: ${errorMessage.value}`, 'text-red-400')
|
errorMessage.value = msg
|
||||||
|
addLine(`Error: ${msg}`, 'text-red-400')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user