浏览代码

fix: spinner

Timothy J. Baek 11 月之前
父节点
当前提交
b7fc37d992
共有 1 个文件被更改,包括 197 次插入179 次删除
  1. 197 179
      src/lib/components/chat/Settings/Connections.svelte

+ 197 - 179
src/lib/components/chat/Settings/Connections.svelte

@@ -20,6 +20,7 @@
 	} from '$lib/apis/openai';
 	import { toast } from 'svelte-sonner';
 	import Switch from '$lib/components/common/Switch.svelte';
+	import Spinner from '$lib/components/common/Spinner.svelte';
 
 	const i18n = getContext('i18n');
 
@@ -31,8 +32,8 @@
 	let OPENAI_API_KEYS = [''];
 	let OPENAI_API_BASE_URLS = [''];
 
-	let ENABLE_OPENAI_API = false;
-	let ENABLE_OLLAMA_API = false;
+	let ENABLE_OPENAI_API = null;
+	let ENABLE_OLLAMA_API = null;
 
 	const updateOpenAIHandler = async () => {
 		OPENAI_API_BASE_URLS = await updateOpenAIUrls(localStorage.token, OPENAI_API_BASE_URLS);
@@ -57,16 +58,23 @@
 
 	onMount(async () => {
 		if ($user.role === 'admin') {
+			await Promise.all([
+				(async () => {
+					OLLAMA_BASE_URLS = await getOllamaUrls(localStorage.token);
+				})(),
+				(async () => {
+					OPENAI_API_BASE_URLS = await getOpenAIUrls(localStorage.token);
+				})(),
+				(async () => {
+					OPENAI_API_KEYS = await getOpenAIKeys(localStorage.token);
+				})()
+			]);
+
 			const ollamaConfig = await getOllamaConfig(localStorage.token);
 			const openaiConfig = await getOpenAIConfig(localStorage.token);
 
 			ENABLE_OPENAI_API = openaiConfig.ENABLE_OPENAI_API;
 			ENABLE_OLLAMA_API = ollamaConfig.ENABLE_OLLAMA_API;
-
-			OLLAMA_BASE_URLS = await getOllamaUrls(localStorage.token);
-
-			OPENAI_API_BASE_URLS = await getOpenAIUrls(localStorage.token);
-			OPENAI_API_KEYS = await getOpenAIKeys(localStorage.token);
 		}
 	});
 </script>
@@ -79,201 +87,211 @@
 	}}
 >
 	<div class="  pr-1.5 overflow-y-scroll max-h-[25rem] space-y-3">
-		<div class=" space-y-3">
-			<div class="mt-2 space-y-2 pr-1.5">
+		{#if ENABLE_OPENAI_API !== null && ENABLE_OLLAMA_API !== null}
+			<div class=" space-y-3">
+				<div class="mt-2 space-y-2 pr-1.5">
+					<div class="flex justify-between items-center text-sm">
+						<div class="  font-medium">{$i18n.t('OpenAI API')}</div>
+
+						<div class="mt-1">
+							<Switch
+								bind:state={ENABLE_OPENAI_API}
+								on:change={async () => {
+									updateOpenAIConfig(localStorage.token, ENABLE_OPENAI_API);
+								}}
+							/>
+						</div>
+					</div>
+
+					{#if ENABLE_OPENAI_API}
+						<div class="flex flex-col gap-1">
+							{#each OPENAI_API_BASE_URLS as url, idx}
+								<div class="flex w-full gap-2">
+									<div class="flex-1">
+										<input
+											class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
+											placeholder={$i18n.t('API Base URL')}
+											bind:value={url}
+											autocomplete="off"
+										/>
+									</div>
+
+									<div class="flex-1">
+										<input
+											class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
+											placeholder={$i18n.t('API Key')}
+											bind:value={OPENAI_API_KEYS[idx]}
+											autocomplete="off"
+										/>
+									</div>
+									<div class="self-center flex items-center">
+										{#if idx === 0}
+											<button
+												class="px-1"
+												on:click={() => {
+													OPENAI_API_BASE_URLS = [...OPENAI_API_BASE_URLS, ''];
+													OPENAI_API_KEYS = [...OPENAI_API_KEYS, ''];
+												}}
+												type="button"
+											>
+												<svg
+													xmlns="http://www.w3.org/2000/svg"
+													viewBox="0 0 16 16"
+													fill="currentColor"
+													class="w-4 h-4"
+												>
+													<path
+														d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z"
+													/>
+												</svg>
+											</button>
+										{:else}
+											<button
+												class="px-1"
+												on:click={() => {
+													OPENAI_API_BASE_URLS = OPENAI_API_BASE_URLS.filter(
+														(url, urlIdx) => idx !== urlIdx
+													);
+													OPENAI_API_KEYS = OPENAI_API_KEYS.filter((key, keyIdx) => idx !== keyIdx);
+												}}
+												type="button"
+											>
+												<svg
+													xmlns="http://www.w3.org/2000/svg"
+													viewBox="0 0 16 16"
+													fill="currentColor"
+													class="w-4 h-4"
+												>
+													<path d="M3.75 7.25a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-8.5Z" />
+												</svg>
+											</button>
+										{/if}
+									</div>
+								</div>
+								<div class=" mb-1 text-xs text-gray-400 dark:text-gray-500">
+									{$i18n.t('WebUI will make requests to')}
+									<span class=" text-gray-200">'{url}/models'</span>
+								</div>
+							{/each}
+						</div>
+					{/if}
+				</div>
+			</div>
+
+			<hr class=" dark:border-gray-700" />
+
+			<div class="pr-1.5 space-y-2">
 				<div class="flex justify-between items-center text-sm">
-					<div class="  font-medium">{$i18n.t('OpenAI API')}</div>
+					<div class="  font-medium">{$i18n.t('Ollama API')}</div>
 
 					<div class="mt-1">
 						<Switch
-							bind:state={ENABLE_OPENAI_API}
+							bind:state={ENABLE_OLLAMA_API}
 							on:change={async () => {
-								updateOpenAIConfig(localStorage.token, ENABLE_OPENAI_API);
+								updateOllamaConfig(localStorage.token, ENABLE_OLLAMA_API);
 							}}
 						/>
 					</div>
 				</div>
-
-				{#if ENABLE_OPENAI_API}
-					<div class="flex flex-col gap-1">
-						{#each OPENAI_API_BASE_URLS as url, idx}
-							<div class="flex w-full gap-2">
-								<div class="flex-1">
+				{#if ENABLE_OLLAMA_API}
+					<div class="flex w-full gap-1.5">
+						<div class="flex-1 flex flex-col gap-2">
+							{#each OLLAMA_BASE_URLS as url, idx}
+								<div class="flex gap-1.5">
 									<input
 										class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
-										placeholder={$i18n.t('API Base URL')}
+										placeholder={$i18n.t('Enter URL (e.g. http://localhost:11434)')}
 										bind:value={url}
-										autocomplete="off"
 									/>
-								</div>
 
-								<div class="flex-1">
-									<input
-										class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
-										placeholder={$i18n.t('API Key')}
-										bind:value={OPENAI_API_KEYS[idx]}
-										autocomplete="off"
-									/>
-								</div>
-								<div class="self-center flex items-center">
-									{#if idx === 0}
-										<button
-											class="px-1"
-											on:click={() => {
-												OPENAI_API_BASE_URLS = [...OPENAI_API_BASE_URLS, ''];
-												OPENAI_API_KEYS = [...OPENAI_API_KEYS, ''];
-											}}
-											type="button"
-										>
-											<svg
-												xmlns="http://www.w3.org/2000/svg"
-												viewBox="0 0 16 16"
-												fill="currentColor"
-												class="w-4 h-4"
+									<div class="self-center flex items-center">
+										{#if idx === 0}
+											<button
+												class="px-1"
+												on:click={() => {
+													OLLAMA_BASE_URLS = [...OLLAMA_BASE_URLS, ''];
+												}}
+												type="button"
 											>
-												<path
-													d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z"
-												/>
-											</svg>
-										</button>
-									{:else}
-										<button
-											class="px-1"
-											on:click={() => {
-												OPENAI_API_BASE_URLS = OPENAI_API_BASE_URLS.filter(
-													(url, urlIdx) => idx !== urlIdx
-												);
-												OPENAI_API_KEYS = OPENAI_API_KEYS.filter((key, keyIdx) => idx !== keyIdx);
-											}}
-											type="button"
-										>
-											<svg
-												xmlns="http://www.w3.org/2000/svg"
-												viewBox="0 0 16 16"
-												fill="currentColor"
-												class="w-4 h-4"
+												<svg
+													xmlns="http://www.w3.org/2000/svg"
+													viewBox="0 0 16 16"
+													fill="currentColor"
+													class="w-4 h-4"
+												>
+													<path
+														d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z"
+													/>
+												</svg>
+											</button>
+										{:else}
+											<button
+												class="px-1"
+												on:click={() => {
+													OLLAMA_BASE_URLS = OLLAMA_BASE_URLS.filter(
+														(url, urlIdx) => idx !== urlIdx
+													);
+												}}
+												type="button"
 											>
-												<path d="M3.75 7.25a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-8.5Z" />
-											</svg>
-										</button>
-									{/if}
+												<svg
+													xmlns="http://www.w3.org/2000/svg"
+													viewBox="0 0 16 16"
+													fill="currentColor"
+													class="w-4 h-4"
+												>
+													<path d="M3.75 7.25a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-8.5Z" />
+												</svg>
+											</button>
+										{/if}
+									</div>
 								</div>
-							</div>
-							<div class=" mb-1 text-xs text-gray-400 dark:text-gray-500">
-								{$i18n.t('WebUI will make requests to')}
-								<span class=" text-gray-200">'{url}/models'</span>
-							</div>
-						{/each}
-					</div>
-				{/if}
-			</div>
-		</div>
-
-		<hr class=" dark:border-gray-700" />
-
-		<div class="pr-1.5 space-y-2">
-			<div class="flex justify-between items-center text-sm">
-				<div class="  font-medium">{$i18n.t('Ollama API')}</div>
+							{/each}
+						</div>
 
-				<div class="mt-1">
-					<Switch
-						bind:state={ENABLE_OLLAMA_API}
-						on:change={async () => {
-							updateOllamaConfig(localStorage.token, ENABLE_OLLAMA_API);
-						}}
-					/>
-				</div>
-			</div>
-			{#if ENABLE_OLLAMA_API}
-				<div class="flex w-full gap-1.5">
-					<div class="flex-1 flex flex-col gap-2">
-						{#each OLLAMA_BASE_URLS as url, idx}
-							<div class="flex gap-1.5">
-								<input
-									class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
-									placeholder={$i18n.t('Enter URL (e.g. http://localhost:11434)')}
-									bind:value={url}
-								/>
-
-								<div class="self-center flex items-center">
-									{#if idx === 0}
-										<button
-											class="px-1"
-											on:click={() => {
-												OLLAMA_BASE_URLS = [...OLLAMA_BASE_URLS, ''];
-											}}
-											type="button"
-										>
-											<svg
-												xmlns="http://www.w3.org/2000/svg"
-												viewBox="0 0 16 16"
-												fill="currentColor"
-												class="w-4 h-4"
-											>
-												<path
-													d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z"
-												/>
-											</svg>
-										</button>
-									{:else}
-										<button
-											class="px-1"
-											on:click={() => {
-												OLLAMA_BASE_URLS = OLLAMA_BASE_URLS.filter((url, urlIdx) => idx !== urlIdx);
-											}}
-											type="button"
-										>
-											<svg
-												xmlns="http://www.w3.org/2000/svg"
-												viewBox="0 0 16 16"
-												fill="currentColor"
-												class="w-4 h-4"
-											>
-												<path d="M3.75 7.25a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-8.5Z" />
-											</svg>
-										</button>
-									{/if}
-								</div>
-							</div>
-						{/each}
+						<div class="flex">
+							<button
+								class="self-center p-2 bg-gray-200 hover:bg-gray-300 dark:bg-gray-900 dark:hover:bg-gray-850 rounded-lg transition"
+								on:click={() => {
+									updateOllamaUrlsHandler();
+								}}
+								type="button"
+							>
+								<svg
+									xmlns="http://www.w3.org/2000/svg"
+									viewBox="0 0 20 20"
+									fill="currentColor"
+									class="w-4 h-4"
+								>
+									<path
+										fill-rule="evenodd"
+										d="M15.312 11.424a5.5 5.5 0 01-9.201 2.466l-.312-.311h2.433a.75.75 0 000-1.5H3.989a.75.75 0 00-.75.75v4.242a.75.75 0 001.5 0v-2.43l.31.31a7 7 0 0011.712-3.138.75.75 0 00-1.449-.39zm1.23-3.723a.75.75 0 00.219-.53V2.929a.75.75 0 00-1.5 0V5.36l-.31-.31A7 7 0 003.239 8.188a.75.75 0 101.448.389A5.5 5.5 0 0113.89 6.11l.311.31h-2.432a.75.75 0 000 1.5h4.243a.75.75 0 00.53-.219z"
+										clip-rule="evenodd"
+									/>
+								</svg>
+							</button>
+						</div>
 					</div>
 
-					<div class="flex">
-						<button
-							class="self-center p-2 bg-gray-200 hover:bg-gray-300 dark:bg-gray-900 dark:hover:bg-gray-850 rounded-lg transition"
-							on:click={() => {
-								updateOllamaUrlsHandler();
-							}}
-							type="button"
+					<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
+						{$i18n.t('Trouble accessing Ollama?')}
+						<a
+							class=" text-gray-300 font-medium underline"
+							href="https://github.com/open-webui/open-webui#troubleshooting"
+							target="_blank"
 						>
-							<svg
-								xmlns="http://www.w3.org/2000/svg"
-								viewBox="0 0 20 20"
-								fill="currentColor"
-								class="w-4 h-4"
-							>
-								<path
-									fill-rule="evenodd"
-									d="M15.312 11.424a5.5 5.5 0 01-9.201 2.466l-.312-.311h2.433a.75.75 0 000-1.5H3.989a.75.75 0 00-.75.75v4.242a.75.75 0 001.5 0v-2.43l.31.31a7 7 0 0011.712-3.138.75.75 0 00-1.449-.39zm1.23-3.723a.75.75 0 00.219-.53V2.929a.75.75 0 00-1.5 0V5.36l-.31-.31A7 7 0 003.239 8.188a.75.75 0 101.448.389A5.5 5.5 0 0113.89 6.11l.311.31h-2.432a.75.75 0 000 1.5h4.243a.75.75 0 00.53-.219z"
-									clip-rule="evenodd"
-								/>
-							</svg>
-						</button>
+							{$i18n.t('Click here for help.')}
+						</a>
 					</div>
+				{/if}
+			</div>
+		{:else}
+			<div class="flex h-full justify-center">
+				<div class="my-auto">
+					<Spinner className="size-6" />
 				</div>
-
-				<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
-					{$i18n.t('Trouble accessing Ollama?')}
-					<a
-						class=" text-gray-300 font-medium underline"
-						href="https://github.com/open-webui/open-webui#troubleshooting"
-						target="_blank"
-					>
-						{$i18n.t('Click here for help.')}
-					</a>
-				</div>
-			{/if}
-		</div>
+			</div>
+		{/if}
 	</div>
 
 	<div class="flex justify-end pt-3 text-sm font-medium">