ui : match the backend list to the MCP server cards

Assisted-by: pi:llama.cpp/DeepSeek-V4.1-Flash
This commit is contained in:
Aleksander Grygier
2026-09-28 12:10:11 +02:00
parent 44117d64d7
commit 092f302529
4 changed files with 26 additions and 25 deletions
@@ -3,10 +3,10 @@
import { Pencil, Server, Trash2 } from '@lucide/svelte';
import { DialogConfirmation } from '$lib/components/app/dialogs';
import Logo from '$lib/components/app/misc/Logo.svelte';
import { Badge } from '$lib/components/ui/badge';
import { Button } from '$lib/components/ui/button';
import * as Card from '$lib/components/ui/card';
import { Switch } from '$lib/components/ui/switch';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import type { Backend, BackendProtocol } from '$lib/types';
const PROTOCOL_LABELS: Record<BackendProtocol, string> = {
@@ -14,6 +14,8 @@
openai: 'OpenAI'
};
const CARD_ICON_CLASS = 'h-5 w-5';
interface Props {
backend: Backend;
isLocal?: boolean;
@@ -32,37 +34,33 @@
<Card.Root class="!gap-3 bg-muted/30 p-4">
<div class="flex items-start justify-between gap-3">
<div class="flex min-w-0 items-center gap-2">
<BackendIcon {backend} class={ICON_CLASS_DEFAULT}>
<BackendIcon {backend} class={CARD_ICON_CLASS}>
{#snippet fallback()}
{#if isLocal}
<Logo class={ICON_CLASS_DEFAULT} style="--size: 1rem" />
<Logo class={CARD_ICON_CLASS} style="--size: 1.25rem" />
{:else}
<Server class={ICON_CLASS_DEFAULT} />
<Server class={CARD_ICON_CLASS} />
{/if}
{/snippet}
</BackendIcon>
<div class="min-w-0">
<p class="truncate text-sm font-medium">{backend.name}</p>
<p class="truncate leading-5 font-medium">{backend.name}</p>
<p class="truncate text-xs text-muted-foreground">{displayUrl}</p>
</div>
</div>
<div class="flex shrink-0 items-center gap-1">
<div class="flex shrink-0 items-center gap-1.5">
{#if isLocal}
<span class="rounded-md border px-2 py-0.5 text-[0.7rem] text-muted-foreground">
Built-in
</span>
<Badge class="h-5 px-1.5 text-[10px]" variant="outline">Built-in</Badge>
{/if}
<span class="rounded-md border px-2 py-0.5 text-[0.7rem] text-muted-foreground">
{protocolLabel}
</span>
<Badge class="h-5 px-1.5 text-[10px]" variant="outline">{protocolLabel}</Badge>
</div>
</div>
<div class="flex items-center justify-between gap-2">
<div class="mt-auto flex items-center justify-between gap-4">
<div class="flex items-center gap-2">
<Switch checked={backend.enabled} onCheckedChange={(value) => onToggle?.(value)} />
@@ -72,15 +70,22 @@
</div>
{#if !isLocal}
<div class="flex items-center gap-1">
<Button aria-label="Edit backend" onclick={() => onEdit?.()} size="sm" variant="ghost">
<div class="flex shrink-0 items-center gap-1">
<Button
aria-label="Edit backend"
class="h-7 w-7"
onclick={() => onEdit?.()}
size="icon"
variant="ghost"
>
<Pencil class="h-3.5 w-3.5" />
</Button>
<Button
aria-label="Delete backend"
class="hover:text-destructive-foreground h-7 w-7 text-destructive hover:bg-destructive/10"
onclick={() => (showDelete = true)}
size="sm"
size="icon"
variant="ghost"
>
<Trash2 class="h-3.5 w-3.5" />
@@ -21,7 +21,7 @@
</script>
<Card.Root
class={`relative gap-3! select-none bg-muted/30 p-4 transition-all ${interactive ? 'cursor-pointer hover:bg-muted/50 hover:opacity-100' : ''} ${selected && !added ? 'bg-muted/30 ring-1 ring-primary/40' : ''} ${dimmed || added ? 'opacity-50' : ''}`}
class={`relative gap-3! select-none bg-muted/30 p-4 transition-[background-color,opacity,transform] duration-150 ${interactive ? 'cursor-pointer hover:bg-muted/50 hover:opacity-100 active:scale-[0.99]' : ''} ${selected && !added ? 'bg-muted/30 ring-1 ring-primary/40' : ''} ${dimmed || added ? 'opacity-50' : ''}`}
onclick={interactive ? onClick : undefined}
>
{#if added}
@@ -40,7 +40,7 @@
}
</script>
<div in:fade={{ duration: 150 }} class={['flex flex-col gap-4', className]}>
<div in:fade={{ duration: 150 }} class={['grid gap-4', className]}>
<DialogBackendForm
bind:open={isAdding}
backend={editing}
@@ -26,9 +26,7 @@
</script>
<Dialog.Root onOpenChange={handleOpenChange} {open}>
<Dialog.Content
class="flex flex-col gap-2 md:max-h-[80vh]! md:w-[calc(100vw-4rem)]! md:max-w-164!"
>
<Dialog.Content class="flex flex-col md:max-h-[80vh]! md:w-[calc(100vw-4rem)]! md:max-w-164!">
<Dialog.Header>
<Dialog.Title class="flex items-center gap-2">
<Logo class="h-5 w-5" style="--size: 1.25rem" />
@@ -36,13 +34,11 @@
<span>Backends</span>
</Dialog.Title>
<Dialog.Description>
Endpoints this UI can talk to. The built-in backend is the llama.cpp server serving it.
</Dialog.Description>
<Dialog.Description>Endpoints this UI can talk to.</Dialog.Description>
</Dialog.Header>
<Tabs.Root
class="min-h-0 flex-1"
class="min-h-0 flex-1 gap-3"
onValueChange={(value) => (protocol = value as BackendProtocol)}
value={protocol}
>