ux: ollama flow

This commit is contained in:
2026-05-07 03:03:25 -04:00
parent 3b6e3c34d5
commit 767e929bf9
3 changed files with 83 additions and 12 deletions
+57 -11
View File
@@ -52,6 +52,8 @@ let ollamaOnline = true;
let latestUpdate = null;
let currentThreadId = "default";
let currentNegotiationId = null;
let latestOllamaStatus = null;
const clickedOllamaActions = new Set();
if (window.lucide) {
window.lucide.createIcons();
@@ -585,6 +587,7 @@ async function refreshOllamaStatus() {
function renderOllamaStatus(status) {
if (!ollamaStatusEl) return;
latestOllamaStatus = status;
const models = status.models?.length ? status.models.join(", ") : "None detected";
const pillClass = status.installed && status.running && status.model_available ? "status-pill" : "status-pill warning";
ollamaStatusEl.innerHTML = `
@@ -595,14 +598,18 @@ function renderOllamaStatus(status) {
${ollamaStatusItem("Model", status.configured_model || "")}
${ollamaStatusItem("Pulled", status.model_available ? "Yes" : "No")}
${ollamaStatusItem("URL", status.base_url || "")}
${ollamaStatusItem("Auto Install", status.can_auto_install ? "Available" : "Unavailable")}
${status.can_auto_install ? ollamaStatusItem("Auto Install", "Available") : ""}
</div>
${ollamaStatusItem("Installed Models", models)}
${status.detail ? ollamaStatusItem("Detail", status.detail) : ""}
`;
if (ollamaInstallButton) ollamaInstallButton.disabled = Boolean(status.installed);
if (ollamaInstallButton) {
ollamaInstallButton.hidden = !status.can_auto_install;
ollamaInstallButton.disabled = Boolean(status.installed) || !status.can_auto_install;
}
if (ollamaLaunchButton) ollamaLaunchButton.disabled = !status.installed || Boolean(status.running);
if (ollamaPullButton) ollamaPullButton.disabled = !status.running || Boolean(status.model_available);
updateOllamaAttention(status);
}
function ollamaStatusItem(label, value) {
@@ -630,6 +637,29 @@ async function postOllamaAction(endpoint, options = {}) {
}
}
function markOllamaActionClicked(action) {
if (action) clickedOllamaActions.add(action);
updateOllamaAttention();
}
function setOllamaButtonAttention(button, action, active) {
if (!button) return;
const shouldPulse = active && !clickedOllamaActions.has(action) && !button.disabled && !button.hidden;
button.classList.toggle("attention-pulse", shouldPulse);
}
function updateOllamaAttention(status = null) {
const currentStatus = status || latestOllamaStatus;
if (!currentStatus) return;
const ready = Boolean(currentStatus.installed && currentStatus.running && currentStatus.model_available);
ollamaToggle?.classList.toggle("attention-pulse", !ready);
setOllamaButtonAttention(ollamaDownloadButton, "download", !currentStatus.installed);
setOllamaButtonAttention(ollamaInstallButton, "install", !currentStatus.installed && currentStatus.can_auto_install);
setOllamaButtonAttention(ollamaLaunchButton, "launch", currentStatus.installed && !currentStatus.running);
setOllamaButtonAttention(ollamaPullButton, "pull", currentStatus.running && !currentStatus.model_available);
if (ready) clickedOllamaActions.clear();
}
function configuredOllamaModel() {
return document.getElementById("ollama-model")?.value || "";
}
@@ -980,20 +1010,24 @@ async function checkHealth() {
ollamaOnline = Boolean(health.online);
if (!ollamaOnline) {
statusEl.textContent = "Offline";
setWarning(health.message || "Ollama is offline. Start Ollama before chatting.");
setWarning("Ollama needs attention. Open the Ollama tab and use the pulsing action button.");
ollamaToggle?.classList.add("attention-pulse");
return false;
}
if (health.model_available === false) {
setWarning(`Ollama is online, but model "${health.model}" is not pulled. Run: ollama pull ${health.model}`);
setWarning(`Ollama needs the configured model "${health.model}". Open the Ollama tab and use Install Model.`);
ollamaToggle?.classList.add("attention-pulse");
} else {
setWarning("");
ollamaToggle?.classList.remove("attention-pulse");
}
statusEl.textContent = "Ready";
return true;
} catch (error) {
ollamaOnline = false;
statusEl.textContent = "Offline";
setWarning(`Could not check Ollama health: ${error.message}`);
setWarning("Could not check Ollama health. Open the Ollama tab and use the pulsing action button.");
ollamaToggle?.classList.add("attention-pulse");
return false;
}
}
@@ -1174,10 +1208,22 @@ memoryToggle?.addEventListener("click", () => toggleSidebarPanel("memory"));
ollamaToggle?.addEventListener("click", () => toggleSidebarPanel("ollama"));
ollamaForm?.addEventListener("submit", saveOllamaConfig);
ollamaRefreshButton?.addEventListener("click", refreshOllamaStatus);
ollamaDownloadButton?.addEventListener("click", () => postOllamaAction("/api/ollama/download"));
ollamaInstallButton?.addEventListener("click", () => postOllamaAction("/api/ollama/install"));
ollamaLaunchButton?.addEventListener("click", () => postOllamaAction("/api/ollama/launch"));
ollamaPullButton?.addEventListener("click", () => postOllamaAction("/api/ollama/pull", { body: { model: configuredOllamaModel() } }));
ollamaDownloadButton?.addEventListener("click", () => {
markOllamaActionClicked("download");
postOllamaAction("/api/ollama/download");
});
ollamaInstallButton?.addEventListener("click", () => {
markOllamaActionClicked("install");
postOllamaAction("/api/ollama/install");
});
ollamaLaunchButton?.addEventListener("click", () => {
markOllamaActionClicked("launch");
postOllamaAction("/api/ollama/launch");
});
ollamaPullButton?.addEventListener("click", () => {
markOllamaActionClicked("pull");
postOllamaAction("/api/ollama/pull", { body: { model: configuredOllamaModel() } });
});
updateCheckButton?.addEventListener("click", checkForUpdate);
updateInstallButton?.addEventListener("click", installUpdate);
updateOpenReleasesButton?.addEventListener("click", openReleasesPage);
@@ -1194,7 +1240,7 @@ async function sendMessage() {
if (!message || input.disabled) return;
const healthy = await checkHealth();
if (!healthy) {
addMessage("assistant warning-message", "Ollama is offline. Start Ollama, then try again.");
addMessage("assistant warning-message", "Ollama needs attention before chat can continue. Open the Ollama tab and press the pulsing action button, then try again.");
return;
}
input.value = "";
@@ -1257,7 +1303,7 @@ async function sendMessage() {
}
} catch (error) {
const message = error.message.includes("503")
? "Ollama is offline or unreachable. Start Ollama, then try again."
? "Ollama needs attention before chat can continue. Open the Ollama tab and press the pulsing action button, then try again."
: `Chat failed: ${error.message}`;
setWarning(message);
setMessageMarkdown(assistantNode, message);