Fix stale LoRA closure, variant fit budget, and hidden dataset remove button

The generate callback omitted loraCapable from its dependencies, so when
an auto-compile flips supports_lora off mid-session the memoized handler
still sent the previously selected adapters and the next generation
failed with the backend's LoRA-not-supported error instead of omitting
adapters the UI had already hidden.

HubModelPicker's GGUF variant expanders, format lists and Hub row fit
hints measured against the summed multi-GPU total. When the picker is
task-scoped (Images/Video) the loaders place the whole pipeline on one
device, so a variant could be recommended as fitting and then OOM at
load; those sites now share the single-device budget the group fit gate
already uses, while chat pickers keep the summed total since llama.cpp
splits layers across devices.

The dataset labeling grid's Remove button relied on group-hover with no
group parent, leaving it permanently invisible to mouse users; the image
wrapper now carries the group class.
This commit is contained in:
Daniel Han 2026-07-11 17:31:59 +00:00
commit cece544fd9
3 changed files with 18 additions and 7 deletions

View file

@ -2085,6 +2085,17 @@ export function HubModelPicker({
}),
[gpu],
);
// Variant expanders and format lists follow the same single-device budget as
// deviceBudget when this picker is task-scoped (Images/Video): the diffusion
// and video loaders place the whole pipeline on one device, so sorting and
// recommending quants against the summed multi-GPU total would mark variants
// as fitting that OOM at load. Chat pickers keep the summed total, where
// llama.cpp can split layers across devices.
const expanderGpuGb = gpu.available
? task
? gpu.maxDeviceMemoryGb
: gpu.memoryTotalGb
: undefined;
const routedArtifactFor = useCallback(
(group: CatalogGroup): ModelArtifact => {
// Honor the format filter when routing a bare group click. A group is only
@ -3092,7 +3103,7 @@ export function HubModelPicker({
parentOptionKey={optionKey}
onNavigatePastStart={() => hubModelList.focusOption(optionKey)}
onNavigatePastEnd={() => hubModelList.moveFocus(optionKey, "next")}
gpuGb={gpu.available ? gpu.memoryTotalGb : undefined}
gpuGb={expanderGpuGb}
systemRamGb={gpu.systemRamAvailableGb || undefined}
variantActions={{
onUpdate: (quant, expectedBytes) =>
@ -3191,7 +3202,7 @@ export function HubModelPicker({
optionProps={hubModelList.getOptionProps(optionKey, selected)}
onClick={() => void routeGroupClick(group, expandKey)}
vramStatus={null}
gpuGb={gpu.available ? gpu.memoryTotalGb : undefined}
gpuGb={expanderGpuGb}
className={downloadedRowButtonClassName}
/>
</div>
@ -3220,7 +3231,7 @@ export function HubModelPicker({
recommendedArtifactId={routed.repoId}
isRepoDownloaded={isRepoDownloaded}
onSelect={onSelect}
gpuGb={gpu.available ? gpu.memoryTotalGb : undefined}
gpuGb={expanderGpuGb}
systemRamGb={gpu.systemRamAvailableGb || undefined}
hfToken={hfToken || undefined}
parentOptionKey={optionKey}
@ -4192,7 +4203,7 @@ export function HubModelPicker({
value === m.id,
)}
onClick={() => handleModelClick(m.id)}
gpuGb={gpu.available ? gpu.memoryTotalGb : undefined}
gpuGb={expanderGpuGb}
/>
</div>
);
@ -4341,7 +4352,7 @@ export function HubModelPicker({
isKnownGgufRepo(id) ? null : (vram?.status ?? null)
}
vramEst={isKnownGgufRepo(id) ? undefined : vram?.est}
gpuGb={gpu.available ? gpu.memoryTotalGb : undefined}
gpuGb={expanderGpuGb}
onArrowDownIntoChildren={
expandedGguf === id
? () => {

View file

@ -1992,7 +1992,7 @@ export function ImagesPage({ active = true }: { active?: boolean }) {
setGenDone(null);
setGenStep(null);
}
}, [prompt, negativePrompt, width, height, steps, guidance, seed, batchSize, count, workflow, initImage, maskImage, strength, extendPct, extendSides, upscaleFactor, upscaleStrength, referenceImages, loras, controlnetCapable, controlnetId, controlImage, controlType, controlStrength, ensureSrc, refreshStatus]);
}, [prompt, negativePrompt, width, height, steps, guidance, seed, batchSize, count, workflow, initImage, maskImage, strength, extendPct, extendSides, upscaleFactor, upscaleStrength, referenceImages, loras, loraCapable, controlnetCapable, controlnetId, controlImage, controlType, controlStrength, ensureSrc, refreshStatus]);
// Keep the active workflow valid for the loaded model: an edit-only model (Qwen-Image-
// Edit) has no Create/Transform tabs, a base model has no Edit tab. Snap to the first

View file

@ -106,7 +106,7 @@ function LabelTile({
uncaptioned ? "border-amber-500/60 bg-amber-500/5" : "border-border",
)}
>
<div className="relative aspect-square w-full overflow-hidden rounded-md bg-muted">
<div className="group relative aspect-square w-full overflow-hidden rounded-md bg-muted">
{thumb ? (
<img src={thumb} alt={record.filename} className="size-full object-cover" />
) : (