ui : rename models-hub namespace to models-discover

Rename the browse store folder (stores/models-hub -> stores/models-discover),
its ModelsDiscoverStore class and modelsDiscoverStore instance, the
ModelsDiscoverSizeRange type, and the related local state and prose, so the
discover feature uses one consistent namespace.

Assisted-by: llama-ui:Qwen3.8-Flash-Next
This commit is contained in:
Aleksander Grygier
2026-09-04 20:07:38 +02:00
parent 9ec63c5db1
commit aef40b5927
11 changed files with 48 additions and 48 deletions
@@ -65,7 +65,7 @@
let loadTitle = $derived(modelLoadProgressText(loadProgress));
let modalities = $derived(option.modalities);
// Avatar: with showBaseModelAvatar the original base model's org is the main
// image and the repo (quantizer) org the corner badge, as in the models hub
// image and the repo (quantizer) org the corner badge, as in the discover
// list. Loaded models usually carry the `base_model` tag on the option; GGUF
// repos only known to HF are resolved lazily via the cached getBaseModel
// lookup.
@@ -5,7 +5,7 @@
ModelsDiscoverListSearch
} from '$lib/components/app/models/discover';
import { HuggingFaceService } from '$lib/services';
import { modelsHubStore } from '$lib/stores';
import { modelsDiscoverStore } from '$lib/stores';
import type { HfModelDetailInfo, HfModelSibling } from '$lib/types';
let selectedId = $state<string | null>(null);
@@ -21,13 +21,13 @@
// Load the sidebar list on mount (the component is mounted when the dialog opens).
$effect(() => {
void modelsHubStore.fetch();
void modelsHubStore.search('');
void modelsDiscoverStore.fetch();
void modelsDiscoverStore.search('');
});
// Auto-select the first model.
$effect(() => {
const first = modelsHubStore.firstModel;
const first = modelsDiscoverStore.firstModel;
if (!selectedId && first) {
selectedId = first.id;
@@ -40,7 +40,7 @@
if (searchTimeout) clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
void modelsHubStore.search(value);
void modelsDiscoverStore.search(value);
}, 300);
}
@@ -101,15 +101,15 @@
<!-- One list instance, so the rows keep their state across search round trips;
skeleton rows replace them while the initial catalog or a query loads. -->
<div>
{#if modelsHubStore.error}
<p class="p-4 text-sm text-destructive">{modelsHubStore.error}</p>
{:else if !modelsHubStore.loading && !modelsHubStore.searching && modelsHubStore.models.length === 0}
{#if modelsDiscoverStore.error}
<p class="p-4 text-sm text-destructive">{modelsDiscoverStore.error}</p>
{:else if !modelsDiscoverStore.loading && !modelsDiscoverStore.searching && modelsDiscoverStore.models.length === 0}
<p class="p-4 text-sm text-muted-foreground">No models found</p>
{:else}
<ModelsDiscoverList
activeId={selectedId}
loading={modelsHubStore.loading || modelsHubStore.searching}
models={modelsHubStore.models}
loading={modelsDiscoverStore.loading || modelsDiscoverStore.searching}
models={modelsDiscoverStore.models}
onSelect={(id) => (selectedId = id)}
showBaseModelAvatar
/>
@@ -2,7 +2,7 @@
import ModelsDiscoverChatTemplateDialog from './ModelsDiscoverChatTemplateDialog.svelte';
import ModelsDiscoverDetailsMetadataItem from './ModelsDiscoverDetailsMetadataItem.svelte';
import { MessageSquareCode } from '@lucide/svelte';
import { modelsHubStore } from '$lib/stores';
import { modelsDiscoverStore } from '$lib/stores';
import type { HfModelDetailInfo, HfModelGguf } from '$lib/types/huggingface';
import { formatParameters } from '$lib/utils';
@@ -18,7 +18,7 @@
// Catalog family description when curated, else the HF card description.
let description = $derived(
modelsHubStore.descriptionFor(modelId) ?? details.cardData?.description
modelsDiscoverStore.descriptionFor(modelId) ?? details.cardData?.description
);
let chatTemplateOpen = $state(false);
@@ -2,7 +2,7 @@
*
* MODELS DISCOVER — DETAILS
*
* The right-hand detail pane of the hub: header (avatar, name, stats, metadata
* The right-hand detail pane of the discover view: header (avatar, name, stats, metadata
* chips, capability badges), the download options area and the model-card README.
*
*/
@@ -9,8 +9,8 @@
type ModelSidecar
} from '$lib/constants';
import { HuggingFaceService } from '$lib/services';
import { modelsHubStore } from '$lib/stores';
import type { ModelsHubSizeRange } from '$lib/stores/models-hub/index.svelte';
import { modelsDiscoverStore } from '$lib/stores';
import type { ModelsDiscoverSizeRange } from '$lib/stores/models-discover/index.svelte';
import type { HfModelInfo } from '$lib/types/huggingface';
import type { ModelModalities } from '$lib/types/models';
import { detectThinkingSupport, detectToolUseSupport } from '$lib/utils';
@@ -79,17 +79,17 @@
// Min/max size across the repo's quants, draft sidecars included. The store
// has catalog rows covered already; any other row (a search hit) measures
// its repo once here and the result is cached per repo.
let measuredSize = $state<ModelsHubSizeRange | null>(null);
let sizeRange = $derived(modelsHubStore.cachedSizeRangeFor(model.id) ?? measuredSize);
let measuredSize = $state<ModelsDiscoverSizeRange | null>(null);
let sizeRange = $derived(modelsDiscoverStore.cachedSizeRangeFor(model.id) ?? measuredSize);
$effect(() => {
const id = model.id;
if (modelsHubStore.cachedSizeRangeFor(id)) return;
if (modelsDiscoverStore.cachedSizeRangeFor(id)) return;
let cancelled = false;
void modelsHubStore.sizeRange(id).then((range) => {
void modelsDiscoverStore.sizeRange(id).then((range) => {
if (!cancelled) measuredSize = range ?? null;
});
@@ -2,7 +2,7 @@
*
* MODELS DISCOVER — LIST
*
* The hub's sidebar column: a debounced search field above a navigable list of
* The discover sidebar column: a debounced search field above a navigable list of
* HuggingFace GGUF models, with skeleton rows while loading.
*
*/
@@ -10,8 +10,8 @@
/**
* **ModelsDiscoverList** - Sidebar model list
*
* Renders the hub's model list as a navigable column. Each row links to the
* model's detail route and highlights the active one.
* Renders the discover model list as a navigable column. Each row links to the
* model's detail and highlights the active one.
*/
export { default as ModelsDiscoverList } from './ModelsDiscoverList.svelte';
@@ -25,7 +25,7 @@ export { default as ModelsDiscoverListSearch } from './ModelsDiscoverListSearch.
/**
* **ModelsDiscoverListItem** - Single sidebar row
*
* One model entry in the sidebar list. Links to `/models-hub/[org]/[model]`.
* One model entry in the discover sidebar list, selectable via `onSelect`.
*/
export { default as ModelsDiscoverListItem } from './ModelsDiscoverListItem.svelte';
@@ -2,7 +2,7 @@
*
* MODELS DISCOVER
*
* Components for the Models Discover hub: a sidebar search + list of
* Components for the Models Discover view: a sidebar search + list of
* HuggingFace GGUF models and a detail view for the selected model, used as the
* body of the discovery dialog. The list and detail trees live in their own
* subfolders; this barrel re-exports them alongside the shared leaves.
@@ -10,7 +10,7 @@
*/
/**
* **ModelsDiscover** - Models hub explorer
* **ModelsDiscover** - Models discover explorer
*
* The complete discovery layout: a sidebar search + model list on the left and a
* detail view for the selected model on the right. Used as the body of the
@@ -94,7 +94,7 @@
let renameDialogOpen = $state(false);
let settingsDialogOpen = $state(false);
let modelsHubOpen = $state(false);
let modelsDiscoverOpen = $state(false);
let renameTargetConversationId = $state<string | null>(null);
let renameDraft = $state('');
let renameOriginalTitle = $state('');
@@ -391,7 +391,7 @@
bind:searchQuery
class="px-2"
isExpandedMode={innerWidth > 768 ? uiStore.isSidebarExpanded : true}
onDiscoverModelsClick={() => (modelsHubOpen = true)}
onDiscoverModelsClick={() => (modelsDiscoverOpen = true)}
onNewChat={() => {
if (deviceStore.isMobile) {
scheduleMobileCollapse();
@@ -455,7 +455,7 @@
<DialogSettingsChat bind:open={settingsDialogOpen} />
<DialogModelsDiscover bind:open={modelsHubOpen} />
<DialogModelsDiscover bind:open={modelsDiscoverOpen} />
<style>
aside {
+2 -2
View File
@@ -40,8 +40,8 @@ export { mcpStore } from './mcp/index.svelte';
// MODELS
export { modelsStore } from './models/index.svelte';
// MODELS HUB (HuggingFace browse state for the discover dialog)
export { modelsHubStore } from './models-hub/index.svelte';
// MODELS DISCOVER (HuggingFace browse state for the discover dialog)
export { modelsDiscoverStore } from './models-discover/index.svelte';
// SERVER
export { serverStore } from './server.svelte';
@@ -1,8 +1,8 @@
/**
* modelsHubStore - Model Hub browse state
* modelsDiscoverStore - Models Discover browse state
*
* Owns the HuggingFace GGUF model list shown in the hub sidebar
* (DialogModelsDiscover). The hub has no "nothing selected" screen: it always opens
* Owns the HuggingFace GGUF model list shown in the discover sidebar
* (DialogModelsDiscover). The discover view has no "nothing selected" screen: it always opens
* a model, so `firstModel` drives the initial selection. By default the list
* shows a curated set of GGUF models in catalog order; search replaces the list
* with matching models across all of HuggingFace. Both paths fetch the same
@@ -22,15 +22,15 @@ import type {
import { SvelteMap } from 'svelte/reactivity';
/** Min/max GGUF file size (bytes) across the quants of one repo. */
export interface ModelsHubSizeRange {
export interface ModelsDiscoverSizeRange {
max: number;
min: number;
}
class ModelsHubStore {
class ModelsDiscoverStore {
error = $state<string | null>(null);
models = $state<HfModelInfo[]>([]);
/** First model in the list - the hub auto-opens this one. */
/** First model in the list - discover auto-opens this one. */
firstModel = $derived(this.models[0] ?? null);
loading = $state(false);
@@ -43,18 +43,18 @@ class ModelsHubStore {
private catalog: HfCatalogEntry[] = [];
/** Repo id -> size range, for catalog rows and lazily measured search rows. */
private catalogSizeRanges = new SvelteMap<string, ModelsHubSizeRange>();
private catalogSizeRanges = new SvelteMap<string, ModelsDiscoverSizeRange>();
private defaultModels: HfModelInfo[] = [];
private fetched = false;
private searchRequestId = 0;
/** In-flight `sizeRange()` lookups, keyed by repo id. */
private sizeRangePending = new Map<string, Promise<ModelsHubSizeRange | undefined>>();
private sizeRangePending = new Map<string, Promise<ModelsDiscoverSizeRange | undefined>>();
/**
* Cached size range for a repo, without measuring: the synchronous part of
* `sizeRange()`, for rendering a row before its measurement resolves.
*/
cachedSizeRangeFor(modelId: string): ModelsHubSizeRange | undefined {
cachedSizeRangeFor(modelId: string): ModelsDiscoverSizeRange | undefined {
return this.catalogSizeRanges.get(modelId);
}
@@ -164,7 +164,7 @@ class ModelsHubStore {
* repo whose tree came back empty. Fetches the file tree once per repo and
* caches it, so remounting a row (scrolling, searching back) is free.
*/
sizeRange(modelId: string): Promise<ModelsHubSizeRange | undefined> {
sizeRange(modelId: string): Promise<ModelsDiscoverSizeRange | undefined> {
const cached = this.catalogSizeRanges.get(modelId);
if (cached) return Promise.resolve(cached);
@@ -242,7 +242,7 @@ class ModelsHubStore {
* model fits within the range. Falls back to the catalog `size` / `sizeBytes`
* strings when the tree yielded nothing (partial fetch, sharded-only repo).
*/
private sizeRangeFor(build: HfCatalogBuild, tree: HfModelSibling[]): ModelsHubSizeRange {
private sizeRangeFor(build: HfCatalogBuild, tree: HfModelSibling[]): ModelsDiscoverSizeRange {
const quantSizes = this.quantSizesOf(tree);
if (quantSizes.length === 0) {
@@ -271,7 +271,7 @@ class ModelsHubStore {
* Size range across the main-model quants of a file tree, draft sidecars
* excluded (they only widen the range when a row advertises them).
*/
private sizeRangeOfMainQuants(tree: HfModelSibling[]): ModelsHubSizeRange | undefined {
private sizeRangeOfMainQuants(tree: HfModelSibling[]): ModelsDiscoverSizeRange | undefined {
const sizes = this.quantSizesOf(tree);
if (sizes.length === 0) return undefined;
@@ -280,4 +280,4 @@ class ModelsHubStore {
}
}
export const modelsHubStore = new ModelsHubStore();
export const modelsDiscoverStore = new ModelsDiscoverStore();
@@ -4,7 +4,7 @@
import DialogModelsDiscover from '$lib/components/app/dialogs/DialogModelsDiscover.svelte';
import DownloadProgressBar from '$lib/components/app/models/discover/DownloadProgressBar.svelte';
import ModelsDiscover from '$lib/components/app/models/discover/ModelsDiscover.svelte';
import { modelsHubStore } from '$lib/stores';
import { modelsDiscoverStore } from '$lib/stores';
const { Story } = defineMeta({
tags: ['autodocs'],
@@ -12,9 +12,9 @@
});
// Wire the hub store singleton with fixtures so the container renders data.
modelsHubStore.models = mockListModels;
modelsHubStore.loading = false;
modelsHubStore.error = null;
modelsDiscoverStore.models = mockListModels;
modelsDiscoverStore.loading = false;
modelsDiscoverStore.error = null;
</script>
<Story name="Progress bar">