feat: improve onboarding model selection (#416)

Merge validating & validated status into `Next` button; disable `Next` when the provider is invalid.

Co-authored-by: Neko <neko@ayaka.moe>
This commit is contained in:
Typed SIGTERM
2025-08-25 11:47:44 +08:00
committed by GitHub
co-authored by Neko
parent 5c1eb33ad8
commit 2f54547e7b
4 changed files with 22 additions and 33 deletions
+3 -3
View File
@@ -17,8 +17,6 @@ dialogs:
baseUrl: Base URL
baseUrlHelp: API endpoint URL (use default if unsure)
accountId: Account ID
validating: Validating configuration...
validationSuccess: First configuration validated successful.
validationFailed: Configuration validation failed
validationError: 'Validation error: {error}'
skipForNow: Skip for now
@@ -26,7 +24,9 @@ dialogs:
next: Next
start: Let's do it!
select-model: Choose model
language:
no-models: No available models
no-models-help: Please return to the previous step and check your API key, or check the network connection.
language:
title: Language
description: >
Change the language of the AIRI interface. This will not affect the language
@@ -17,7 +17,6 @@ dialogs:
baseUrl: URL Base
baseUrlHelp: URL del endpoint de la API (usa el predeterminado si no estás seguro)
accountId: ID de Cuenta
validating: Validando configuración...
validationFailed: La validación de la configuración falló
validationError: 'Error de validación: {error}'
skipForNow: Omitir por ahora
@@ -15,8 +15,6 @@ dialogs:
baseUrl: 基础 URL
baseUrlHelp: API 端点 URL(如果不确定请使用默认值)
accountId: 账户 ID
validating: 正在验证配置...
validationSuccess: 配置初步验证通过。
validationFailed: 配置验证失败
validationError: 验证错误:{error}
skipForNow: 暂时跳过
@@ -24,6 +22,8 @@ dialogs:
next: 下一步
start: 开始吧!
select-model: 选择模型
no-models: 找不到可用模型
no-models-help: 请返回上一步并检查您的 API Key,或检查网络连接。
language:
title: 语言
description: 切换显示界面的语言
@@ -140,7 +140,6 @@ async function validateConfiguration() {
isValidating.value++
// service startup time
const startValidationTimestamp = performance.now()
validationMessage.value = t('settings.dialogs.onboarding.validating')
let finalValidationMessage = ''
try {
@@ -160,10 +159,7 @@ async function validateConfiguration() {
isValid.value = validationResult.valid
if (isValid.value) {
finalValidationMessage = t('settings.dialogs.onboarding.validationSuccess')
}
else {
if (!isValid.value) {
finalValidationMessage = validationResult.reason
}
}
@@ -177,7 +173,7 @@ async function validateConfiguration() {
setTimeout(() => {
isValidating.value--
validationMessage.value = finalValidationMessage
}, Math.max(0, debounceTime - (performance.now() - startValidationTimestamp)))
}, debounceTime - (performance.now() - startValidationTimestamp))
}
}
@@ -413,31 +409,13 @@ onMounted(() => {
</div>
</template>
</Alert>
<div v-if="(isValid || isValidating > 0) && validationMessage" class="mt-4">
<div
class="flex items-center rounded-lg p-3" :class="[
(isValidating > 0)
? 'bg-blue-50 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300'
: 'bg-green-50 text-green-700 dark:bg-green-900/30 dark:text-green-300',
]"
>
<div
class="mr-2 text-lg" :class="[
(isValidating > 0)
? 'i-svg-spinners:3-dots-fade'
: 'i-solar:check-circle-bold-duotone',
]"
/>
{{ validationMessage }}
</div>
</div>
</div>
<!-- Action Buttons -->
<Button
:label="t('settings.dialogs.onboarding.next')"
:disabled="!selectedProviderId || (needsApiKey && apiKey.trim().length === 0)"
:loading="isLoadingActiveProviderModels"
:loading="isLoadingActiveProviderModels || isValidating > 0"
:disabled="!selectedProviderId || (needsApiKey && apiKey.trim().length === 0) || !isValid"
@click="handleFinishProviderConfiguration"
/>
</div>
@@ -459,9 +437,10 @@ onMounted(() => {
<!-- Using the new RadioCardManySelect component -->
<div flex-1>
<RadioCardManySelect
v-if="providerModels.length > 0"
v-model="activeModel"
v-model:search-query="modelSearchQuery"
:items="providerModels.sort((a, b) => a.id === activeModel ? -1 : b.id === activeModel ? 1 : 0)"
:items="providerModels.toSorted((a, b) => a.id === activeModel ? -1 : b.id === activeModel ? 1 : 0)"
:searchable="true"
:search-placeholder="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.search_placeholder')"
:search-no-results-title="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.no_search_results')"
@@ -472,6 +451,17 @@ onMounted(() => {
:collapse-button-text="t('settings.pages.modules.consciousness.sections.section.provider-model-selection.collapse')"
list-class="max-h-[calc(100dvh-17rem)] sm:max-h-120"
/>
<Alert v-else type="error">
<template #title>
{{ t('settings.dialogs.onboarding.no-models') }}
</template>
<template #content>
<div class="whitespace-pre-wrap break-all">
{{ t('settings.dialogs.onboarding.no-models-help') }}
</div>
</template>
</Alert>
</div>
<!-- Action Buttons -->