Skip to content

Commit d3b1e3f

Browse files
feat(portable): update management with per-track caching and flash-free detail refresh
- Full update system for Portable installs using update.py (pygit2-based) - Two update tracks: Stable (--stable flag, latest tag) and Latest on GitHub (master HEAD) - Check for Update fetches GitHub Releases/Commits API, stores results per-track in updateInfoByTrack - Switching tracks instantly shows cached check results without re-fetching - Update execution with 3-step progress, handles updater self-update flow - Detail view uses targeted section refresh (replaceWith) instead of full page rebuild - Extract _renderSection, _refreshSection, _refreshAllSections for flash-free updates - List view shows amber update badge via getStatusTag() - Modal messages linkify URLs (open in system browser) and are selectable with scroll - Migrate legacy updateInfo to updateInfoByTrack on startup - button.loading CSS class for inline check spinner Amp-Thread-ID: https://ampcode.com/threads/T-019c6f48-6409-738c-8e1d-5bf37f16859e Co-authored-by: Amp <amp@ampcode.com>
1 parent a7ad556 commit d3b1e3f

7 files changed

Lines changed: 501 additions & 136 deletions

File tree

lib/ipc.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ async function migrateDefaults() {
9696
changed = true;
9797
}
9898
}
99+
// Migrate legacy updateInfo → updateInfoByTrack
100+
if (inst.updateInfo && !inst.updateInfoByTrack) {
101+
const track = inst.updateInfo.track || inst.updateTrack || "stable";
102+
const { track: _t, ...rest } = inst.updateInfo;
103+
inst.updateInfoByTrack = { [track]: rest };
104+
delete inst.updateInfo;
105+
changed = true;
106+
}
99107
}
100108
if (changed) {
101109
for (const inst of all) await installations.update(inst.id, inst);
@@ -163,7 +171,9 @@ function register({ onLaunch, onStop, onComfyExited, onComfyRestarted } = {}) {
163171
const source = sourceMap[inst.sourceId];
164172
if (!source) return inst;
165173
const listPreview = source.getListPreview ? source.getListPreview(inst) : undefined;
166-
const statusTag = inst.status === "failed" ? { label: "Install Failed", style: "danger" } : undefined;
174+
const statusTag = inst.status === "failed"
175+
? { label: "Install Failed", style: "danger" }
176+
: (source.getStatusTag ? source.getStatusTag(inst) : undefined);
167177
return { ...inst, sourceLabel: source.label, ...(listPreview != null ? { listPreview } : {}), ...(statusTag ? { statusTag } : {}) };
168178
});
169179
});
@@ -647,9 +657,14 @@ function register({ onLaunch, onStop, onComfyExited, onComfyRestarted } = {}) {
647657
sender.send("install-progress", { installationId, phase, ...detail });
648658
}
649659
};
660+
const sendOutput = (text) => {
661+
if (!sender.isDestroyed()) {
662+
sender.send("comfy-output", { installationId, text });
663+
}
664+
};
650665
const update = (data) => installations.update(installationId, data);
651666
try {
652-
return await resolveSource(inst.sourceId).handleAction(actionId, inst, actionData, { update, sendProgress });
667+
return await resolveSource(inst.sourceId).handleAction(actionId, inst, actionData, { update, sendProgress, sendOutput });
653668
} catch (err) {
654669
return { ok: false, message: err.message };
655670
}

locales/en.json

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
"openDirectory": "Open Directory",
135135
"checkForUpdate": "Check for Update",
136136
"featureNotImplemented": "This feature is not yet implemented.",
137+
"updateAvailable": "Update Available",
137138
"delete": "Delete Installation",
138139
"deleteConfirmTitle": "Delete Installation",
139140
"deleteConfirmMessage": "This will permanently delete the installation and all its files. This cannot be undone.",
@@ -170,7 +171,29 @@
170171
"label": "Portable",
171172
"package": "Portable Package",
172173
"version": "Version",
173-
"packageLabel": "Package"
174+
"packageLabel": "Package",
175+
"updates": "Updates",
176+
"updateTrack": "Update Track",
177+
"trackStable": "Stable",
178+
"trackLatest": "Latest on GitHub",
179+
"installedVersion": "Installed Version",
180+
"latestVersion": "Latest Version",
181+
"lastChecked": "Last Checked",
182+
"updateStatus": "Status",
183+
"updateAvailableTag": "Update: {version}",
184+
"updateAvailable": "Update available",
185+
"upToDate": "Up to date",
186+
"updateNow": "Update Now",
187+
"updateConfirmTitle": "Update ComfyUI",
188+
"updateConfirmMessage": "Update from {installed} to {latest}?\n\nLocal changes will be stashed and a backup branch created.\n\nRelease notes:\n{notes}",
189+
"updateConfirmMessageLatest": "Update from {installed} to latest on master ({latest})?\n\nThis will pull the newest commits from the master branch. Local changes will be stashed and a backup branch created.\n\nLatest commit: {commit}",
190+
"updatingTitle": "Updating to {version}…",
191+
"updatePrepare": "Prepare",
192+
"updateRun": "Update",
193+
"updateDeps": "Dependencies",
194+
"updateFailed": "Update process failed with exit code {code}.",
195+
"checkingForUpdate": "Checking for update…",
196+
"noUpdateDir": "No update directory found in this portable installation."
174197
},
175198

176199
"installer": {

0 commit comments

Comments
 (0)