@@ -20,6 +20,7 @@ const { t } = useI18n()
2020const router = useRouter ()
2121const providersStore = useProvidersStore ()
2222const { providers } = storeToRefs (providersStore ) as { providers: RemovableRef <Record <string , any >> }
23+ const loading = ref (0 )
2324
2425// Get provider metadata
2526const providerId = ' ollama'
@@ -74,6 +75,11 @@ watch(headers, (headers) => {
7475})
7576
7677async function refetch() {
78+ loading .value ++
79+ // service startup time
80+ const startValidationTimestamp = performance .now ()
81+ let finalValidationMessage = ' '
82+
7783 try {
7884 const validationResult = await providerMetadata .value .validators .validateProviderConfig ({
7985 baseUrl: baseUrl .value ,
@@ -84,16 +90,25 @@ async function refetch() {
8490 })
8591
8692 if (! validationResult .valid ) {
87- validationMessage . value = t (' settings.dialogs.onboarding.validationError' , {
93+ finalValidationMessage = t (' settings.dialogs.onboarding.validationError' , {
8894 error: validationResult .reason ,
8995 })
9096 }
97+ else {
98+ finalValidationMessage = ' '
99+ }
91100 }
92101 catch (error ) {
93- validationMessage . value = t (' settings.dialogs.onboarding.validationError' , {
102+ finalValidationMessage = t (' settings.dialogs.onboarding.validationError' , {
94103 error: error instanceof Error ? error .message : String (error ),
95104 })
96105 }
106+ finally {
107+ setTimeout (() => {
108+ loading .value --
109+ validationMessage .value = finalValidationMessage
110+ }, 500 - (performance .now () - startValidationTimestamp ))
111+ }
97112}
98113
99114watch ([baseUrl , headers ], refetch , { immediate: true })
@@ -122,47 +137,59 @@ function handleResetSettings() {
122137 </script >
123138
124139<template >
125- <Alert v-if =" validationMessage" type =" error" >
126- <template #title >
127- {{ t('settings.dialogs.onboarding.validationFailed') }}
128- </template >
129- <template v-if =" validationMessage " #content >
130- <div class =" whitespace-pre-wrap break-all" >
131- {{ validationMessage }}
132- </div >
133- </template >
134- </Alert >
135- <ProviderSettingsLayout
136- :provider-name =" providerMetadata?.localizedName"
137- :provider-icon =" providerMetadata?.icon"
138- :on-back =" () => router.back()"
139- >
140- <ProviderSettingsContainer >
141- <ProviderBasicSettings
142- :title =" t('settings.pages.providers.common.section.basic.title')"
143- :description =" t('settings.pages.providers.common.section.basic.description')"
144- :on-reset =" handleResetSettings"
145- >
146- <ProviderBaseUrlInput
147- v-model =" baseUrl"
148- :placeholder =" providerMetadata?.defaultOptions?.().baseUrl as string || ''"
149- required
150- />
151- </ProviderBasicSettings >
152-
153- <ProviderAdvancedSettings :title =" t('settings.pages.providers.common.section.advanced.title')" >
154- <FieldKeyValues
155- v-model =" headers"
156- :label =" t('settings.pages.providers.common.section.advanced.fields.field.headers.label')"
157- :description =" t('settings.pages.providers.common.section.advanced.fields.field.headers.description')"
158- :key-placeholder =" t('settings.pages.providers.common.section.advanced.fields.field.headers.key.placeholder')"
159- :value-placeholder =" t('settings.pages.providers.common.section.advanced.fields.field.headers.value.placeholder')"
160- @add =" (key: string, value: string) => addKeyValue(headers, key, value)"
161- @remove =" (index: number) => removeKeyValue(index, headers)"
162- />
163- </ProviderAdvancedSettings >
164- </ProviderSettingsContainer >
165- </ProviderSettingsLayout >
140+ <div class =" flex flex-col gap-4" >
141+ <Alert v-if =" !!loading" type =" loading" >
142+ <template #title >
143+ {{ t('settings.pages.providers.provider.common.status.validating') }}
144+ </template >
145+ </Alert >
146+ <Alert v-else-if =" !validationMessage" type =" success" >
147+ <template #title >
148+ {{ t('settings.pages.providers.provider.common.status.valid') }}
149+ </template >
150+ </Alert >
151+ <Alert v-else-if =" validationMessage" type =" error" >
152+ <template #title >
153+ {{ t('settings.dialogs.onboarding.validationFailed') }}
154+ </template >
155+ <template v-if =" validationMessage " #content >
156+ <div class =" whitespace-pre-wrap break-all" >
157+ {{ validationMessage }}
158+ </div >
159+ </template >
160+ </Alert >
161+ <ProviderSettingsLayout
162+ :provider-name =" providerMetadata?.localizedName"
163+ :provider-icon =" providerMetadata?.icon"
164+ :on-back =" () => router.back()"
165+ >
166+ <ProviderSettingsContainer >
167+ <ProviderBasicSettings
168+ :title =" t('settings.pages.providers.common.section.basic.title')"
169+ :description =" t('settings.pages.providers.common.section.basic.description')"
170+ :on-reset =" handleResetSettings"
171+ >
172+ <ProviderBaseUrlInput
173+ v-model =" baseUrl"
174+ :placeholder =" providerMetadata?.defaultOptions?.().baseUrl as string || ''"
175+ required
176+ />
177+ </ProviderBasicSettings >
178+
179+ <ProviderAdvancedSettings :title =" t('settings.pages.providers.common.section.advanced.title')" >
180+ <FieldKeyValues
181+ v-model =" headers"
182+ :label =" t('settings.pages.providers.common.section.advanced.fields.field.headers.label')"
183+ :description =" t('settings.pages.providers.common.section.advanced.fields.field.headers.description')"
184+ :key-placeholder =" t('settings.pages.providers.common.section.advanced.fields.field.headers.key.placeholder')"
185+ :value-placeholder =" t('settings.pages.providers.common.section.advanced.fields.field.headers.value.placeholder')"
186+ @add =" (key: string, value: string) => addKeyValue(headers, key, value)"
187+ @remove =" (index: number) => removeKeyValue(index, headers)"
188+ />
189+ </ProviderAdvancedSettings >
190+ </ProviderSettingsContainer >
191+ </ProviderSettingsLayout >
192+ </div >
166193</template >
167194
168195<route lang="yaml">
0 commit comments