From a0fdf03340e8f2194bd13e66531a2f2309ea2a54 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Sun, 15 Mar 2026 06:59:31 +0000 Subject: [PATCH] studio: add Cancel button to model loading toast popup Replace toast.promise with a manual toast.loading that includes a Cancel action button. Users can now cancel model downloads/loads from the toast notification itself, not just from the header bar spinner. --- .../chat/hooks/use-chat-model-runtime.ts | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts b/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts index 3f8d41d743..c775ace084 100644 --- a/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts +++ b/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts @@ -280,18 +280,37 @@ export function useChatModelRuntime() { } } - const loadPromise = performLoad().finally(() => { - setLoadingModel(null); - setLoadAbortController(null); + const toastId = toast.loading("Loading model…", { + description: loadingDescription, + action: { + label: "Cancel", + onClick: () => { + abortCtrl.abort(); + setLoadingModel(null); + setLoadAbortController(null); + unloadModel({ model_path: modelId }).catch(() => {}); + clearCheckpoint(); + toast.dismiss(toastId); + toast.info("Model loading cancelled"); + }, + }, }); - await toast.promise(loadPromise, { - loading: "Loading model…", - success: `${displayName} loaded`, - error: (err) => - err instanceof Error ? err.message : "Failed to load model", - description: loadingDescription, - }); + try { + await performLoad(); + toast.success(`${displayName} loaded`, { id: toastId }); + } catch (err) { + if (!abortCtrl.signal.aborted) { + toast.error( + err instanceof Error ? err.message : "Failed to load model", + { id: toastId }, + ); + } + throw err; + } finally { + setLoadingModel(null); + setLoadAbortController(null); + } } catch (error) { setLoadingModel(null); const message =