Files
olivv-cs-ComfyUI-FunPack/app/legacy/git_actions.js
T
digital-garbageandClaude Sonnet 5 29ac44ffcd feat: v4 UI port Phase A start -- module categories, legacy frontend served live
Two pieces of the "port v4's exact UI onto v5's backend" plan:

- core/contract.py: new optional ModuleSpec.category field (closed set:
  continuity, guidance, conditioning, sampling, post, system), validated in
  core/schema.py, threaded through core/registry.py's FIELDS and
  to_manifest(). Presentation grouping, independent of STAGE (execution
  order) -- a module can be stage="sampling" and category="guidance" at
  once. Only the 4 existing modules that actually render a settings panel
  (alg, sharpen, appearance, full_control) got a category assigned; the
  other 12 have none to categorize (no SETTINGS block) and stay
  uncategorised, which is valid.

- v4's frontend (movie_editor/frontend/*, ~29k lines, 61 files) copied
  verbatim into app/legacy/. core/routes.py's "/" route now serves
  legacy/index.html instead of the composer entry point; a <base> tag in
  that file resolves its own relative script/link tags against
  /funpack/app/legacy/ regardless of what URL it's served at, so every
  file moved as a unit with zero per-file path edits. Verified live: all
  61 assets load 200 OK, the real v4 onboarding screen renders pixel-for-
  pixel (it's the actual DOM/CSS, not a reimplementation), and several v4
  API calls (/api/media, /api/projects, /api/git/status) already succeed
  against v5's real backend by coincidence of shared route naming -- the
  rest 404/405 as expected, since api.js's ~90 functions haven't been
  rewired to v5's actual routes yet (next piece of this plan).

The old composer entry point (app/index.html, app/composer/**) stays in
the tree, unreferenced, until a later cleanup pass once nothing imports it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 23:58:51 +03:00

213 lines
9.1 KiB
JavaScript

// Shared FunPack git actions (Switch branch / Update + reload). Used by both the
// FunPack menu and the welcome screen so neither has to duplicate the flow — or force
// the user to load a project first just to switch branches.
(function () {
const API = () => window.MovieEditorAPI;
let _status = null; // cached git status (branch, dirty, behind, branches)
async function refresh() {
try { _status = await API().gitStatus(); }
catch (_) { _status = { ok: false }; }
return _status;
}
function get() { return _status; }
// Ensure we have a usable status; surface the same alerts the menu used to.
async function _ensureStatus() {
let gs = _status;
if (!gs?.ok) {
try { gs = await API().gitStatus(); _status = gs; }
catch (e) { alert(String(e.message || e)); return null; }
}
if (!gs?.ok) { alert(gs?.detail || "Git status unavailable for this install."); return null; }
return gs;
}
function _restartOverlay(message) {
return window.FunPackRestart?.showOverlay?.(message);
}
function _waitForComfyReload(msgEl, startMs) {
window.FunPackRestart?.waitForReload?.(msgEl, startMs);
}
// All three actions below end in a restart and a page reload, so anything the store is
// still holding has to reach disk first. flushSave() ignores the suspension for this.
async function _flushPendingEdits() {
try { await window.Store?.flushSave?.(); } catch (_) {}
}
async function update() {
const gs = await _ensureStatus();
if (!gs) return;
if (gs.dirty) {
alert("Local changes detected in the FunPack folder.\nCommit or stash them before updating from git.");
return;
}
const branch = gs.branch || "dev";
const behind = gs.behind > 0 ? `\n\n${gs.behind} commit(s) available on origin/${branch}.` : "";
if (!confirm(`Pull latest "${branch}" from origin and restart ComfyUI?\n\nAny running generation will be lost.${behind}`)) return;
await _flushPendingEdits();
const msg = _restartOverlay(`Pulling origin/${branch}…\nComfyUI will restart when the pull finishes.`);
try {
const res = await API().gitUpdate(branch);
const deps = _reportRequirements(res);
msg.textContent = (res.updated
? `Updated ${res.before} → ${res.after}.${deps}\nRestarting ComfyUI…`
: "Already up to date.\nRestarting ComfyUI…");
} catch (e) {
window.FunPackRestart?.removeOverlay?.();
alert("Update failed: " + (e.message || e));
return;
}
_waitForComfyReload(msg, Date.now());
}
// An update that changed requirements.txt installs them before restarting. A FAILED
// install is the one outcome the user has to act on — the code is updated and the node
// pack will not import — so it interrupts rather than scrolling past in an overlay.
function _reportRequirements(res) {
const r = res && res.requirements;
if (!r || !r.ran) return "";
if (r.ok) return "\nDependencies installed.";
alert("FunPack updated, but installing its dependencies failed.\n\n"
+ (r.detail || "")
+ "\n\nFunPack may not load until this is run.");
return "\nDependency install FAILED — see the message above.";
}
async function switchBranch() {
const gs = await _ensureStatus();
if (!gs) return;
if (gs.dirty) {
alert("Local changes detected in the FunPack folder.\nCommit or stash them before switching branches.");
return;
}
const branches = gs.branches || [];
if (!branches.length) { alert("No git branches found."); return; }
const cur = gs.branch;
if (!window.SlotPicker) return;
window.SlotPicker.open({
title: "Switch FunPack branch",
options: branches.map((b) => ({ value: b, label: b, hint: b === cur ? "current" : "" })),
onPick: async (branch) => {
if (branch === cur) return;
if (!confirm(`Switch to "${branch}", pull from origin, and restart ComfyUI?\n\nAny running generation will be lost.`)) return;
await _flushPendingEdits();
const msg = _restartOverlay(`Switching to ${branch}…\nComfyUI will restart when ready.`);
try {
const res = await API().gitCheckout(branch);
const deps = _reportRequirements(res);
msg.textContent = (res.updated
? `Switched to ${branch} (${res.before} → ${res.after}).${deps}\nRestarting ComfyUI…`
: `On ${branch}, already up to date.\nRestarting ComfyUI…`);
} catch (e) {
window.FunPackRestart?.removeOverlay?.();
alert("Branch switch failed: " + (e.message || e));
return;
}
_waitForComfyReload(msg, Date.now());
},
});
}
// Undoes the most recent Update or Switch branch — git's own reflog remembers where HEAD
// was before that move, so there is no separate "before" state to keep in sync here.
async function rollback() {
const gs = await _ensureStatus();
if (!gs) return;
const target = gs.rollback_target;
if (!target) { alert("Nothing to roll back to — no update or branch switch on record."); return; }
if (gs.dirty) {
alert("Local changes detected in the FunPack folder.\nCommit or stash them before rolling back.");
return;
}
const subject = target.subject ? `\n"${target.subject}"` : "";
if (!confirm(`Roll back to ${target.commit}?${subject}\n\nAny running generation will be `
+ "lost. If the update you're undoing changed requirements.txt, dependencies are NOT "
+ "reinstalled automatically — run pip install by hand after if things don't load.")) return;
await _flushPendingEdits();
const msg = _restartOverlay(`Rolling back to ${target.commit}…\nComfyUI will restart when ready.`);
try {
const res = await API().gitRollback();
msg.textContent = `Rolled back ${res.before} → ${res.after}.\nRestarting ComfyUI…`;
} catch (e) {
window.FunPackRestart?.removeOverlay?.();
alert("Rollback failed: " + (e.message || e));
return;
}
_waitForComfyReload(msg, Date.now());
}
async function restartComfy() {
if (!confirm(
"Restart ComfyUI now?\n\nThe server will be down for ~10-40s and any running generation "
+ "will be lost. This page reloads automatically when it's back."
)) return;
await _flushPendingEdits();
const msg = _restartOverlay("Restarting ComfyUI…\nThis page will reload when it's back.");
if (!msg) return;
try { await API().restart(); } catch (_) { /* the connection drops as it execv's */ }
_waitForComfyReload(msg, Date.now());
}
// The three maintenance actions every FunPack splash screen offers. Shared because
// they are the actions you need BEFORE opening a project — a branch swap should not
// require first loading a montage you did not want.
function maintenanceRow(cls) {
const { el } = window.dom;
const row = el("div", "maint-row" + (cls ? " " + cls : ""));
const mk = (label, hint, fn) => {
const b = el("button", "maint-btn");
b.type = "button";
b.append(el("span", "maint-btn-label", label));
b.append(el("span", "maint-btn-hint", hint));
b.onclick = fn;
return b;
};
const updateBtn = mk("Update", "Checking…", () => update());
const switchBtn = mk("Switch branch", "Checking…", () => switchBranch());
const restartBtn = mk("Restart ComfyUI", "Reload the server without updating", () => restartComfy());
const rollbackBtn = mk("Rollback update", "Checking…", () => rollback());
row.append(updateBtn, switchBtn, restartBtn, rollbackBtn);
const hint = (b) => b.querySelector(".maint-btn-hint");
// No isConnected guard: callers build the row before appending their overlay, so
// status can land while the row is still detached — bailing there would leave the
// hints reading "Checking…" for good. Writing into a discarded row is harmless.
refresh().then((gs) => {
if (!gs?.ok) {
updateBtn.classList.add("disabled");
switchBtn.classList.add("disabled");
rollbackBtn.classList.add("disabled");
hint(updateBtn).textContent = "Git unavailable for this install";
hint(switchBtn).textContent = "Git unavailable for this install";
hint(rollbackBtn).textContent = "Git unavailable for this install";
return;
}
hint(updateBtn).textContent = gs.dirty
? "Local changes — commit first"
: (gs.behind > 0 ? `${gs.behind} commit(s) behind origin/${gs.branch}` : `origin/${gs.branch} up to date`);
hint(switchBtn).textContent = gs.dirty
? `On ${gs.branch} · local changes — commit first`
: `On ${gs.branch} · pick another`;
// Only meaningful right after an Update/Switch branch -- most sessions have nothing
// to undo, so the button reads that plainly instead of just sitting disabled unlabelled.
if (gs.rollback_target) {
hint(rollbackBtn).textContent = `Undo last update — back to ${gs.rollback_target.commit}`;
} else {
rollbackBtn.classList.add("disabled");
hint(rollbackBtn).textContent = "Nothing to undo yet";
}
});
return row;
}
window.FunPackGit = { refresh, get, update, switchBranch, restartComfy, rollback, maintenanceRow };
})();