Files
llama.cpp/tools/ui/src/lib/components/app/models/ModelLoadControl.svelte
T
Aleksander Grygier d789d02899 ui : show every provider's models in the manager
The table grows a section per enabled provider, each with its own mark,
error and loading state, and a provider filter with live repo counts.
Rows gain their capability gates back, the draft column with its
use-as-draft action, and the quant badge names the provider on its rows.

Assisted-by: pi:llama.cpp/DeepSeek-V4.1-Flash
2026-10-01 16:51:16 +02:00

140 lines
4.2 KiB
Svelte

<script lang="ts">
import { ActionIcon } from '$lib/components/app';
import { BackendIcon } from '$lib/components/app/backends';
import { ICON_CLASS_DEFAULT, MODEL_LOAD_ICONS } from '$lib/constants';
import { backendsModelsStore, modelsStore } from '$lib/stores';
import type { ModelOption } from '$lib/types/models';
import { getBackend } from '$lib/utils/api-base';
interface Props {
/** Backend can load and unload models, llama-compat servers only. */
canLoad: boolean;
class?: string;
isFailed?: boolean;
isLoaded: boolean;
isLoading?: boolean;
isSleeping?: boolean;
option: ModelOption;
/** Table rows keep the load action visible, selector rows reveal it on hover. */
revealOnHover?: boolean;
/** Renders the state alone, for a caller that moves load and unload elsewhere. */
showAction?: boolean;
/** Non-loadable rows show the provider mark, which identifies them in a flat list. */
showBackendMark?: boolean;
/** Table rows mark a remote provider, which this UI cannot load or unload. */
showRemoteMark?: boolean;
}
let {
canLoad,
class: className = '',
isFailed = false,
isLoaded,
isLoading = false,
isSleeping = false,
option,
revealOnHover = true,
showAction = true,
showBackendMark = false,
showRemoteMark = false
}: Props = $props();
let backendName = $derived(getBackend(option.backendId)?.name ?? 'Remote provider');
/** The provider's listing failed, so nothing it serves is selectable right now. */
let isBackendFailed = $derived(
Boolean(option.backendId && backendsModelsStore.get(option.backendId).error)
);
</script>
<div class={['flex w-5 shrink-0 items-center justify-center', className]}>
{#if !canLoad}
{#if showBackendMark}
<BackendIcon backend={getBackend(option.backendId)} class="h-3.5 w-3.5" />
{:else if showRemoteMark}
<span
class="flex items-center gap-1 {isBackendFailed ? 'opacity-50 grayscale' : ''}"
title={isBackendFailed ? `${backendName} is unavailable` : backendName}
>
<BackendIcon backend={getBackend(option.backendId)} class="h-3.5 w-3.5" />
{#if isBackendFailed}
<MODEL_LOAD_ICONS.failed class="h-3 w-3 text-destructive" />
{/if}
</span>
{/if}
{:else if isLoading}
<MODEL_LOAD_ICONS.loading class="{ICON_CLASS_DEFAULT} animate-spin text-muted-foreground" />
{:else}
<!-- the state dot is what the row shows at rest; the action takes its place on hover -->
{#if showAction && revealOnHover}
{#if isFailed}
<MODEL_LOAD_ICONS.failed
class="h-3.5 w-3.5 text-red-500 group-hover:hidden [@media(pointer:coarse)]:hidden"
/>
{:else}
<span
class="h-2 w-2 rounded-full group-hover:hidden [@media(pointer:coarse)]:hidden {isSleeping
? 'bg-orange-400'
: isLoaded
? 'bg-green-500'
: 'bg-muted-foreground/50'}"
></span>
{/if}
{:else}
{#if isFailed}
<MODEL_LOAD_ICONS.failed class="h-3.5 w-3.5 text-red-500" />
{:else}
<span
class="h-2 w-2 rounded-full {isSleeping
? 'bg-orange-400'
: isLoaded
? 'bg-green-500'
: 'bg-muted-foreground/50'}"
></span>
{/if}
{/if}
<!-- the wrapper has to pick one display value: flex and hidden together
leave the winner to stylesheet order -->
<div
class={!showAction
? 'hidden'
: revealOnHover
? 'hidden group-hover:flex [@media(pointer:coarse)]:flex'
: 'flex'}
>
{#if isFailed}
<ActionIcon
class="h-5 w-5 text-red-500 hover:text-foreground"
icon={MODEL_LOAD_ICONS.retry}
iconSize="h-4 w-4"
onclick={() => modelsStore.status.load(option.model)}
stopPropagationOnClick
tooltip="Retry loading model"
tooltipAsTitle
/>
{:else if isLoaded || isSleeping}
<ActionIcon
class="h-5 w-5 hover:text-foreground"
icon={MODEL_LOAD_ICONS.unload}
iconSize="h-4 w-4"
onclick={() => modelsStore.status.unload(option.model)}
stopPropagationOnClick
tooltip="Unload model"
tooltipAsTitle
/>
{:else}
<ActionIcon
class="h-5 w-5 hover:text-foreground"
icon={MODEL_LOAD_ICONS.load}
iconSize="h-4 w-4"
onclick={() => modelsStore.status.load(option.model)}
stopPropagationOnClick
tooltip="Load model"
tooltipAsTitle
/>
{/if}
</div>
{/if}
</div>