Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
89 lines
6.2 KiB
JavaScript
89 lines
6.2 KiB
JavaScript
// Keeping the install alive: update, switch branch, roll back, restart ComfyUI. Every one ends in a restart and a page
|
||
// reload, so edits are saved first and a card holds the screen until the server answers again.
|
||
import { composer as c } from "../composer/composer.js";
|
||
|
||
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
|
||
|
||
export function createMaintenance({ api, flush }) {
|
||
const tell = (text) => c.toast.warn({ text });
|
||
|
||
// -> git status when it is usable, else says why and returns null
|
||
async function status(needClean) {
|
||
let gs;
|
||
try { gs = await api.gitFull(); } catch (err) { return tell(err.message), null; }
|
||
if (!gs || !gs.ok) return tell((gs && gs.detail) || "Git is not available for this install."), null;
|
||
if (needClean && gs.dirty) return tell("Local changes in the FunPack folder: commit or stash them first."), null;
|
||
return gs;
|
||
}
|
||
const ask = (title, message) => c.modal.dialogue({ title, message, confirmLabel: "Go ahead" }).result;
|
||
|
||
async function reloadWhenBack(card) {
|
||
const start = Date.now();
|
||
await wait(3500);
|
||
for (;;) {
|
||
try { if ((await api.health()).ok) return location.reload(); } catch { /* still down */ }
|
||
if (Date.now() - start > 90000) card.setText("Still waiting on ComfyUI… it may need a manual restart.");
|
||
await wait(2000);
|
||
}
|
||
}
|
||
async function run(message, action, said) {
|
||
try { await flush(); } catch (err) { return tell(err.message); }
|
||
const text = c.text.md({ text: message });
|
||
const card = c.modal.generic({ title: "Working", size: "sm", closeOnOutside: false, closeOnEsc: false, body: c.region.stack({ gap: "md", children: [c.progress.indeterminate({ label: "Working" }), text] }) });
|
||
card.setText = (t) => text.setText ? text.setText(t) : (text.node.textContent = t);
|
||
try {
|
||
const res = await action();
|
||
if (res && res.restarting === false) { // nothing restarted: say what is true, and stay on the page
|
||
card.close();
|
||
return c.modal.dialogue({ title: "Not restarted", message: `${res.blocked || (said ? said(res) : "Nothing changed.")} ${res.blocked ? "Restart ComfyUI yourself when the generation has finished." : ""}`.trim(), confirmLabel: "OK", cancelLabel: "Close" }).result;
|
||
}
|
||
const bad = res && res.requirements && res.requirements.ran && !res.requirements.ok;
|
||
if (bad) { await c.modal.dialogue({ title: "Dependencies failed", message: `${res.requirements.detail || ""}\n\nFunPack was updated, but installing its dependencies failed: it may not load until they are installed by hand. ComfyUI will restart now.`, confirmLabel: "Restart", cancelLabel: "Restart" }).result; }
|
||
card.setText(`${said ? said(res) : message}\nRestarting ComfyUI…`);
|
||
} catch (err) {
|
||
if (action.dropsConnection) { /* the server went down as it restarted: expected */ } else { card.close(); return tell(err.message); }
|
||
}
|
||
return reloadWhenBack(card);
|
||
}
|
||
const deps = (res) => (res && res.requirements && res.requirements.ran ? (res.requirements.ok ? " Dependencies installed." : " Dependency install FAILED: FunPack may not load until it is run by hand.") : "");
|
||
|
||
return {
|
||
/** What each action would do right now: {update, branch, rollback, ok} for the cards' hints. */
|
||
async hints() {
|
||
let gs; try { gs = await api.gitFull(); } catch { gs = null; }
|
||
if (!gs || !gs.ok) return { ok: false, update: "Git unavailable for this install", branch: "Git unavailable for this install", rollback: "Git unavailable for this install" };
|
||
return { ok: true,
|
||
update: gs.fetch_ok === false ? "Could not reach origin: update status unknown" : gs.dirty ? "Local changes — commit first" : gs.behind > 0 ? `${gs.behind} commit(s) behind origin/${gs.branch}` : `origin/${gs.branch} up to date`,
|
||
branch: `On ${gs.branch}${gs.dirty ? " · local changes — commit first" : " · pick another"}`,
|
||
rollbackOk: Boolean(gs.rollback_target),
|
||
rollback: gs.rollback_target ? `Undo last update — back to ${String(gs.rollback_target.commit).slice(0, 8)}` : "Nothing to undo yet" };
|
||
},
|
||
async update() {
|
||
const gs = await status(true); if (!gs) return;
|
||
const branch = gs.branch || "dev";
|
||
if (!(await ask("Update", `Pull the latest "${branch}" from origin and restart ComfyUI? Any running generation will be lost.${gs.behind > 0 ? ` ${gs.behind} commit(s) available.` : ""}`))) return;
|
||
return run(`Pulling origin/${branch}…`, () => api.git("update", { branch }), (r) => (r.updated ? `Updated ${r.before} → ${r.after}.${deps(r)}` : "Already up to date."));
|
||
},
|
||
async switchBranch() {
|
||
const gs = await status(true); if (!gs) return;
|
||
if (!(gs.branches || []).length) return tell("No git branches found.");
|
||
const branch = await c.modal.choice({ title: "Switch FunPack branch", items: gs.branches.map((b) => ({ id: b, label: b, hint: b === gs.branch ? "current" : "" })) }).result;
|
||
if (!branch || branch === gs.branch) return;
|
||
if (!(await ask("Switch branch", `Switch to "${branch}", pull from origin, and restart ComfyUI? Any running generation will be lost.`))) return;
|
||
return run(`Switching to ${branch}…`, () => api.git("checkout", { branch }), (r) => `On ${branch}${r.updated ? ` (${r.before} → ${r.after})` : ", already up to date"}.${deps(r)}`);
|
||
},
|
||
async rollback() {
|
||
const gs = await status(true); if (!gs) return;
|
||
const target = gs.rollback_target;
|
||
if (!target) return tell("Nothing to roll back to — no update or branch switch on record.");
|
||
if (!(await ask("Roll back", `Roll back to ${String(target.commit).slice(0, 8)}${target.subject ? ` ("${target.subject}")` : ""}? If that update changed requirements.txt, dependencies are not reinstalled: run pip by hand afterwards if things do not load.`))) return;
|
||
return run(`Rolling back to ${String(target.commit).slice(0, 8)}…`, () => api.git("rollback"), (r) => `Rolled back ${r.before} → ${r.after}.`);
|
||
},
|
||
async restart() {
|
||
if (!(await ask("Restart ComfyUI", "Restart now? The server is down for 10–40 s and any running generation is lost. This page reloads when it is back."))) return;
|
||
const action = () => api.git("restart"); action.dropsConnection = true;
|
||
return run("Restarting ComfyUI…", action);
|
||
},
|
||
};
|
||
}
|