Browse Source

refac: tools styling

Timothy Jaeryang Baek 3 months ago
parent
commit
cb94a87cb0

+ 26 - 75
src/lib/components/chat/MessageInput.svelte

@@ -52,6 +52,7 @@
 	import CommandLine from '../icons/CommandLine.svelte';
 	import { KokoroWorker } from '$lib/workers/KokoroWorker';
 	import ToolServersModal from './ToolServersModal.svelte';
+	import Wrench from '../icons/Wrench.svelte';
 
 	const i18n = getContext('i18n');
 
@@ -90,7 +91,7 @@
 		webSearchEnabled
 	});
 
-	let showToolServers = false;
+	let showTools = false;
 
 	let loaded = false;
 	let recording = false;
@@ -353,7 +354,7 @@
 
 <FilesOverlay show={dragged} />
 
-<ToolServersModal bind:show={showToolServers} />
+<ToolServersModal bind:show={showTools} {selectedToolIds} />
 
 {#if loaded}
 	<div class="w-full font-primary">
@@ -397,38 +398,6 @@
 						<div
 							class="px-3 pb-0.5 pt-1.5 text-left w-full flex flex-col absolute bottom-0 left-0 right-0 bg-linear-to-t from-white dark:from-gray-900 z-10"
 						>
-							{#if selectedToolIds.length > 0}
-								<div class="flex items-center justify-between w-full">
-									<div class="flex items-center gap-2.5 text-sm dark:text-gray-500">
-										<div class="pl-1">
-											<span class="relative flex size-2">
-												<span
-													class="animate-ping absolute inline-flex h-full w-full rounded-full bg-yellow-400 opacity-75"
-												/>
-												<span class="relative inline-flex rounded-full size-2 bg-yellow-500" />
-											</span>
-										</div>
-										<div class="  text-ellipsis line-clamp-1 flex">
-											{#each selectedToolIds.map((id) => {
-												return $tools ? $tools.find((t) => t.id === id) : { id: id, name: id };
-											}) as tool, toolIdx (toolIdx)}
-												<Tooltip
-													content={tool?.meta?.description ?? ''}
-													className=" {toolIdx !== 0 ? 'pl-0.5' : ''} shrink-0"
-													placement="top"
-												>
-													{tool.name}
-												</Tooltip>
-
-												{#if toolIdx !== selectedToolIds.length - 1}
-													<span>, </span>
-												{/if}
-											{/each}
-										</div>
-									</div>
-								</div>
-							{/if}
-
 							{#if atSelectedModel !== undefined}
 								<div class="flex items-center justify-between w-full">
 									<div class="pl-[1px] flex items-center gap-2 text-sm dark:text-gray-500">
@@ -1133,6 +1102,29 @@
 										</InputMenu>
 
 										<div class="flex gap-0.5 items-center overflow-x-auto scrollbar-none flex-1">
+											{#if toolServers.length + selectedToolIds.length > 0}
+												<Tooltip
+													content={$i18n.t('{{COUNT}} Available Tools', {
+														COUNT: toolServers.length + selectedToolIds.length
+													})}
+												>
+													<button
+														class="translate-y-[0.5px] flex gap-1 items-center text-gray-600 dark:text-gray-300 hover:text-gray-700 dark:hover:text-gray-200 rounded-lg p-1 mr-0.5 self-center transition"
+														aria-label="Available Tools"
+														type="button"
+														on:click={() => {
+															showTools = !showTools;
+														}}
+													>
+														<Wrench className="size-4" strokeWidth="1.75" />
+
+														<span class="text-sm font-medium text-gray-600 dark:text-gray-300">
+															{toolServers.length + selectedToolIds.length}
+														</span>
+													</button>
+												</Tooltip>
+											{/if}
+
 											{#if $_user}
 												{#if $config?.features?.enable_web_search && ($_user.role === 'admin' || $_user?.permissions?.features?.web_search)}
 													<Tooltip content={$i18n.t('Search the internet')} placement="top">
@@ -1195,47 +1187,6 @@
 									</div>
 
 									<div class="self-end flex space-x-1 mr-1 shrink-0">
-										{#if toolServers.length > 0}
-											<Tooltip
-												content={$i18n.t('{{COUNT}} Available Tool Servers', {
-													COUNT: toolServers.length
-												})}
-											>
-												<button
-													class="translate-y-[1.5px] flex gap-1 items-center text-gray-600 dark:text-gray-300 hover:text-gray-700 dark:hover:text-gray-200 rounded-lg px-1.5 py-0.5 mr-0.5 self-center border border-gray-100 dark:border-gray-800 transition"
-													aria-label="Available Tool Servers"
-													type="button"
-													on:click={() => {
-														showToolServers = !showToolServers;
-													}}
-												>
-													<svg
-														xmlns="http://www.w3.org/2000/svg"
-														fill="none"
-														viewBox="0 0 24 24"
-														stroke-width="1.5"
-														stroke="currentColor"
-														class="size-3"
-													>
-														<path
-															stroke-linecap="round"
-															stroke-linejoin="round"
-															d="M21.75 6.75a4.5 4.5 0 0 1-4.884 4.484c-1.076-.091-2.264.071-2.95.904l-7.152 8.684a2.548 2.548 0 1 1-3.586-3.586l8.684-7.152c.833-.686.995-1.874.904-2.95a4.5 4.5 0 0 1 6.336-4.486l-3.276 3.276a3.004 3.004 0 0 0 2.25 2.25l3.276-3.276c.256.565.398 1.192.398 1.852Z"
-														/>
-														<path
-															stroke-linecap="round"
-															stroke-linejoin="round"
-															d="M4.867 19.125h.008v.008h-.008v-.008Z"
-														/>
-													</svg>
-
-													<span class="text-xs">
-														{toolServers.length}
-													</span>
-												</button>
-											</Tooltip>
-										{/if}
-
 										{#if !history?.currentId || history.messages[history.currentId]?.done == true}
 											<Tooltip content={$i18n.t('Record voice')}>
 												<button

+ 79 - 36
src/lib/components/chat/ToolServersModal.svelte

@@ -1,6 +1,6 @@
 <script lang="ts">
 	import { getContext, onMount } from 'svelte';
-	import { models, config, toolServers } from '$lib/stores';
+	import { models, config, toolServers, tools } from '$lib/stores';
 
 	import { toast } from 'svelte-sonner';
 	import { deleteSharedChatById, getChatById, shareChatById } from '$lib/apis/chats';
@@ -11,6 +11,11 @@
 	import Collapsible from '../common/Collapsible.svelte';
 
 	export let show = false;
+	export let selectedToolIds = [];
+
+	let selectedTools = [];
+
+	$: selectedTools = $tools.filter((tool) => selectedToolIds.includes(tool.id));
 
 	const i18n = getContext('i18n');
 </script>
@@ -18,7 +23,7 @@
 <Modal bind:show size="md">
 	<div>
 		<div class=" flex justify-between dark:text-gray-300 px-5 pt-4 pb-0.5">
-			<div class=" text-lg font-medium self-center">{$i18n.t('Available Tool Servers')}</div>
+			<div class=" text-lg font-medium self-center">{$i18n.t('Available Tools')}</div>
 			<button
 				class="self-center"
 				on:click={() => {
@@ -38,47 +43,85 @@
 			</button>
 		</div>
 
-		<div class="px-5 pb-5 w-full flex flex-col justify-center">
-			<div class=" text-sm dark:text-gray-300 mb-2">
-				Open WebUI can use tools provided by any OpenAPI server. <br /><a
-					class="underline"
-					href="https://github.com/open-webui/openapi-servers"
-					target="_blank">Learn more about OpenAPI tool servers.</a
-				>
-			</div>
-			<div class=" text-sm dark:text-gray-300 mb-1">
-				{#each $toolServers as toolServer}
-					<Collapsible buttonClassName="w-full" chevron>
-						<div>
-							<div class="text-base font-medium dark:text-gray-100 text-gray-800">
-								{toolServer?.openapi?.info?.title} - v{toolServer?.openapi?.info?.version}
-							</div>
+		{#if selectedTools.length > 0}
+			{#if $toolServers.length > 0}
+				<div class=" flex justify-between dark:text-gray-300 px-5 pb-1">
+					<div class=" text-base font-medium self-center">{$i18n.t('Tools')}</div>
+				</div>
+			{/if}
 
-							<div class="text-sm text-gray-500">
-								{toolServer?.openapi?.info?.description}
+			<div class="px-5 pb-3 w-full flex flex-col justify-center">
+				<div class=" text-sm dark:text-gray-300 mb-1">
+					{#each selectedTools as tool}
+						<Collapsible buttonClassName="w-full mb-0.5">
+							<div>
+								<div class="text-sm font-medium dark:text-gray-100 text-gray-800">
+									{tool?.name}
+								</div>
+
+								{#if tool?.meta?.description}
+									<div class="text-xs text-gray-500">
+										{tool?.meta?.description}
+									</div>
+								{/if}
 							</div>
 
-							<div class="text-sm text-gray-500">
-								{toolServer?.url}
+							<!-- <div slot="content">
+							{JSON.stringify(tool, null, 2)}
+						</div> -->
+						</Collapsible>
+					{/each}
+				</div>
+			</div>
+		{/if}
+
+		{#if $toolServers.length > 0}
+			<div class=" flex justify-between dark:text-gray-300 px-5 pb-0.5">
+				<div class=" text-base font-medium self-center">{$i18n.t('Tool Servers')}</div>
+			</div>
+
+			<div class="px-5 pb-5 w-full flex flex-col justify-center">
+				<div class=" text-xs text-gray-600 dark:text-gray-300 mb-2">
+					Open WebUI can use tools provided by any OpenAPI server. <br /><a
+						class="underline"
+						href="https://github.com/open-webui/openapi-servers"
+						target="_blank">Learn more about OpenAPI tool servers.</a
+					>
+				</div>
+				<div class=" text-sm dark:text-gray-300 mb-1">
+					{#each $toolServers as toolServer}
+						<Collapsible buttonClassName="w-full" chevron>
+							<div>
+								<div class="text-sm font-medium dark:text-gray-100 text-gray-800">
+									{toolServer?.openapi?.info?.title} - v{toolServer?.openapi?.info?.version}
+								</div>
+
+								<div class="text-xs text-gray-500">
+									{toolServer?.openapi?.info?.description}
+								</div>
+
+								<div class="text-xs text-gray-500">
+									{toolServer?.url}
+								</div>
 							</div>
-						</div>
 
-						<div slot="content">
-							{#each toolServer?.specs ?? [] as tool_spec}
-								<div class="my-1">
-									<div class="font-medium text-gray-800 dark:text-gray-100">
-										{tool_spec?.name}
-									</div>
+							<div slot="content">
+								{#each toolServer?.specs ?? [] as tool_spec}
+									<div class="my-1">
+										<div class="font-medium text-gray-800 dark:text-gray-100">
+											{tool_spec?.name}
+										</div>
 
-									<div>
-										{tool_spec?.description}
+										<div>
+											{tool_spec?.description}
+										</div>
 									</div>
-								</div>
-							{/each}
-						</div>
-					</Collapsible>
-				{/each}
+								{/each}
+							</div>
+						</Collapsible>
+					{/each}
+				</div>
 			</div>
-		</div>
+		{/if}
 	</div>
 </Modal>