ui : wire the discover dialog to live data and downloads

Load the selected model's details, file tree and README via
HuggingFaceService on selection change, and expose the download
progress type globally for the status feed. The download options
already read their state from the models status store.

Assisted-by: pi
This commit is contained in:
Aleksander Grygier
2026-08-31 17:02:12 +02:00
parent 09e47cd45a
commit b5d4ab37c5
3 changed files with 74 additions and 29 deletions
+1
View File
@@ -83,6 +83,7 @@ declare global {
ApiLlamaCppServerProps,
ApiModelDataEntry,
ApiModelLoadStage,
ModelDownloadProgress,
ApiModelsSseProgress,
ApiModelsSseData,
ApiModelsSseDownloadProgressData,
@@ -1,12 +1,21 @@
<script lang="ts">
import { SearchInput } from '$lib/components/app';
import { ModelsDiscoverDetails, ModelsDiscoverList } from '$lib/components/app/models/discover';
import { HuggingFaceService } from '$lib/services';
import { modelsHubStore } from '$lib/stores';
import type { HfModelDetailInfo, HfModelSibling } from '$lib/types';
let selectedId = $state<string | null>(null);
let searchQuery = $state('');
let searchTimeout: ReturnType<typeof setTimeout> | null = null;
// Detail pane state, reloaded when the selection changes.
let details = $state<HfModelDetailInfo | null>(null);
let files = $state<HfModelSibling[]>([]);
let readme = $state<string | null>(null);
let detailLoading = $state(false);
let detailError = $state<string | null>(null);
// Load the sidebar list on mount (the component is mounted when the dialog opens).
$effect(() => {
void modelsHubStore.fetch();
@@ -31,6 +40,54 @@
void modelsHubStore.search(value);
}, 300);
}
// Load the detail pane for the selected model (component is reused across
// selections, so this re-fetches on every change).
$effect(() => {
const id = selectedId;
if (!id) return;
let cancelled = false;
detailLoading = true;
detailError = null;
void (async () => {
try {
const [info, tree, readmeText] = await Promise.all([
HuggingFaceService.getDetails(id),
HuggingFaceService.getTree(id),
HuggingFaceService.getReadme(id)
]);
if (cancelled) return;
if (!info) {
detailError = 'Model not found';
return;
}
details = info;
files = HuggingFaceService.filterByExtension(
HuggingFaceService.collapseGgufShards(tree),
'.gguf'
);
readme = readmeText;
} catch (err) {
if (cancelled) return;
detailError = err instanceof Error ? err.message : 'Failed to load model';
} finally {
if (!cancelled) detailLoading = false;
}
})();
return () => {
cancelled = true;
};
});
</script>
<aside
@@ -65,13 +122,13 @@
<main class="overflow-y-auto">
{#if selectedId}
<!-- TODO: load details/tree/readme via HuggingFaceService in the integration branch -->
<ModelsDiscoverDetails
details={null}
files={[]}
loading={true}
details={details}
error={detailError}
files={files}
loading={detailLoading}
modelId={selectedId}
readme={null}
readme={readme}
/>
{/if}
</main>
@@ -6,7 +6,8 @@
import DownloadProgressBar from '$lib/components/app/models/discover/DownloadProgressBar.svelte';
import ModelsDiscover from '$lib/components/app/models/discover/ModelsDiscover.svelte';
import { ModelDraftSidecar } from '$lib/enums';
import { modelsHubStore } from '$lib/stores';
import { modelsHubStore, modelsStore } from '$lib/stores';
import { SvelteSet } from 'svelte/reactivity';
const { Story } = defineMeta({
tags: ['autodocs'],
@@ -18,7 +19,15 @@
modelsHubStore.loading = false;
modelsHubStore.error = null;
const PROGRESS = { downloadedBytes: 3_600_000_000, totalBytes: 7_300_000_000 };
// Mark the Q4_K_M tag as failed for the previous-failure story. The status
// manager keeps this in a private SvelteSet keyed by `<repo>:<tag>`.
const FAILED_TAG = 'ggml-org/gemma-4-12b-it-GGUF:Q4_K_M';
(
modelsStore.status as unknown as { failedDownloads: Set<string> }
).failedDownloads = new SvelteSet([FAILED_TAG]);
</script>
<Story name="Progress bar">
@@ -54,9 +63,7 @@
<DialogModelDownload
filePath="Q4_K_M/gemma-4-12b-it-Q4_K_M.gguf"
formattedSize="7.3 GB"
onCancelDownload={() => {}}
onClose={() => {}}
onDownload={() => {}}
open
quant="Q4_K_M"
repoId="ggml-org/gemma-4-12b-it-GGUF"
@@ -70,31 +77,11 @@
<DialogModelDownload
filePath="Q4_K_M/gemma-4-12b-it-Q4_K_M.gguf"
formattedSize="7.3 GB"
onCancelDownload={() => {}}
onClose={() => {}}
onDownload={() => {}}
open
previousFailure
quant="Q4_K_M"
repoId="ggml-org/gemma-4-12b-it-GGUF"
sidecar={null}
/>
</div>
</Story>
<Story name="Download dialog (downloading)">
<div class="p-4">
<DialogModelDownload
filePath="Q4_K_M/gemma-4-12b-it-Q4_K_M.gguf"
inFlight
onCancelDownload={() => {}}
onClose={() => {}}
onDownload={() => {}}
open
progress={PROGRESS}
quant="Q4_K_M"
repoId="ggml-org/gemma-4-12b-it-GGUF"
sidecar={null}
/>
</div>
</Story>