Files
olivv-cs-ComfyUI-FunPack/app/ui/features/settings/modules.js
T

69 lines
5.0 KiB
JavaScript

// Modules: what could be installed, what is in use, and what is off (for this project, after a failure, or by choice).
import { composer as c } from "../../composer/composer.js";
import { RESTART_HINT } from "../addons/index.js";
const CATEGORIES = [["continuity", "Continuity"], ["guidance", "Guidance"], ["conditioning", "Conditioning"], ["sampling", "Sampling"], ["post", "Post"], ["system", "System"], ["", "Other"]];
export const modules = (app) => function mount() {
const ps = app.pipeline;
const page = c.region.stack({ gap: "md" });
let addons = [];
const loadAddons = () => app.api.addons().then((a) => { addons = a; draw(); }).catch(() => {});
// The project remembers which add-ons it uses, so a new rental can offer them again on load.
const remember = (id, on) => { const now = app.project.pref("addons", []) || [], next = on ? [...new Set([...now, id])] : now.filter((i) => i !== id); app.project.setPref("addons", next); };
const flip = async (a, on) => {
try {
addons = await app.api.setAddon(a.id, on); remember(a.id, on);
if (on && addons.some((x) => x.id === a.id && x.state === "pending")) c.toast.info({ text: `${a.title} is not installed yet: restart ComfyUI to download and install it.`, duration: 10000 });
} catch (err) { c.toast.warn({ text: `Could not change ${a.title}: ${err.message}` }); }
draw();
};
const addonRow = (a) => {
const pending = a.state === "pending";
const hint = [a.hint, pending ? RESTART_HINT : null, a.failed ? `Could not install: ${a.failed}\nSwitch it on to try again.` : null].filter(Boolean).join("\n");
return c.toggle.default({ label: a.title, hint, checked: a.state === "installed" || pending, onChange: (on) => flip(a, on) });
};
function draw() {
if (ps.loading()) return page.set([c.hint.default({ text: "Loading…" })]);
if (ps.loadError()) return page.set([c.banner.warn({ text: `Could not load: ${ps.loadError()}` })]);
const control = ps.control();
const ok = ps.usefulness(), mine = Object.values(ps.modulesById()).filter((m) => control[m.id] && control[m.id].controllable && (control[m.id].quarantine || ok(m)));
const offered = addons.filter((a) => a.state === "available" || a.state === "pending"), onAddons = addons.filter((a) => a.state === "installed"), offAddons = addons.filter((a) => a.state === "disabled");
if (!mine.length && !addons.length) return page.set([c.emptyState.default({ icon: "☷", title: "Nothing to switch", hint: "No installed module can be switched off." })]);
const name = (m) => m.title || m.id;
const row = (m) => {
const held = control[m.id].quarantine;
if (held) {
return c.settingsRow.default({ label: `${name(m)} — failed`, hint: `Off since ${held.when || "a failure"}: ${held.reason || "an error"}`,
control: c.button.sm({ label: "Turn back on", tone: "ghost", onClick: async () => {
try { await app.api.releaseModule(m.id); } catch (err) { c.toast.warn({ text: `Could not turn ${name(m)} back on: ${err.message}` }); }
await ps.refreshControl(); draw();
} }) });
}
return c.toggle.default({ label: name(m), hint: ps.allOff() ? "Off: all enhancements are disabled" : ps.isOff(m.id) ? "Off for this project" : undefined, checked: !ps.allOff() && !ps.isOff(m.id), disabled: ps.allOff(),
onChange: (on) => ps.setOff(m.id, !on).then(draw) });
};
const isOff = (m) => control[m.id].quarantine || ps.isOff(m.id);
const notes = ps.saveNotes();
const master = c.toggle.default({ label: "Disable all enhancements", hint: "Switches every feature above off at once, so you can compare with and without them. Your choices are kept; switch it back off to restore them.",
checked: ps.allOff(), onChange: (on) => ps.setAllOff(on).then(draw) });
const section = (label, rows) => rows.length ? [c.label.section({ text: label }), ...rows] : [];
const installed = mine.filter((m) => !isOff(m));
const waiting = addons.filter((a) => a.state === "pending");
page.set([notes.length ? c.banner.warn({ text: notes.join(" ") }) : null,
waiting.length ? c.banner.info({ text: `Restart ComfyUI to finish installing ${waiting.map((a) => a.title).join(", ")}.`, action: { label: "Restart ComfyUI", onClick: () => app.maintenance.restart() } }) : null,
...section("Available modules", offered.map(addonRow)),
...section("Installed modules", [...onAddons.map(addonRow), ...CATEGORIES.flatMap(([key]) => installed.filter((m) => (m.category || "") === key).map(row))]),
...section("Disabled modules", [...offAddons.map(addonRow), ...mine.filter(isOff).map(row)]),
c.hint.default({ text: "A module turned off here is off for this project only. One that failed while generating is off everywhere until you turn it back on." }),
master].filter(Boolean));
}
draw();
loadAddons();
ps.ensureLoaded().then(() => ps.refreshControl()).then(draw);
const off = ps.subscribe(draw);
return { node: page.node, destroy: () => { off(); page.node.remove(); } };
};