Compare commits

..
1 Commits
Author SHA1 Message Date
adachi af3de6eafb Deduplicate replayed comparison previews 2026-10-16 13:44:26 +08:00
7 changed files with 43 additions and 12 deletions
+5
View File
@@ -1,5 +1,10 @@
# Changelog
## 0.5.8
- Count each comparison preview file once, even when cached execution notifications replay it; keep the selected result on replay.
- Remove duplicate preview entries when reloading older saved comparison histories.
## 0.5.7
- Accumulate comparison results across runs, select the newest result and preserve each result's matching original, including after workflow reload.
+5 -4
View File
@@ -1,10 +1,11 @@
# Git versions and rollback
The current local version is **v0.5.7**. Both the installed plugin and the source repository retain local commits and tags. This update is also pushed to the GitHub main branch.
The current local version is **v0.5.8**. Both the installed plugin and the source repository retain local commits and tags. This update is also pushed to the GitHub main branch.
| Tag | Contents |
|---|---|
| `v0.5.7` | Fixed comparison images; wheel navigates the workflow; retain result history across runs |
| `v0.5.8` | Deduplicate replayed comparison previews and repair duplicate saved history |
| `v0.5.7` / `local-before-v0.5.8` | Fixed comparison images; wheel navigates the workflow; retain result history across runs |
| `v0.5.6` / `local-before-v0.5.7` | Exclusive selector follows Get/Set and virtual routes correctly |
| `v0.5.5` / `local-before-v0.5.6` | Bind canvas/panel widths to node geometry and retain vertical resizing |
| `v0.5.4` / `local-before-v0.5.5` | Isolate Fit clicks and refresh editor assets on upgrade |
@@ -19,13 +20,13 @@ To undo only this update, run in the plugin folder:
```powershell
git status --short
git switch --detach local-before-v0.5.7
git switch --detach local-before-v0.5.8
```
Return to this version with:
```powershell
git switch --detach v0.5.7
git switch --detach v0.5.8
```
Restart ComfyUI and hard-refresh the browser (`Ctrl+F5`) after switching versions.
+1
View File
@@ -49,6 +49,7 @@ Environment: Windows, local ComfyUI 0.19.3, ComfyUI frontend 1.42.11, PyTorch 2.
- 0.5.7: actual browser wheel events over a real queued comparison image change workflow navigation while the comparison transform stays fitted and centered. Verified on frontends 1.42.11 and 1.52.7 in classic nodes and Nodes 2.0, with left-result/right-original pixels, hover/leave behavior, batch selection, adoption preserving mask/history, workflow reload, rejected mismatched adoption and ordinary-upload mask reset.
- 0.5.7: three real queued two-image batches accumulate 2, 4 and 6 results and select the newest result. After adoption, old results retain their old original and new results use the adopted original; all six results survive workflow reload in both frontend versions/renderers. Dependency-free tests additionally cover legacy batch mapping, empty outputs and immutable appending.
- 0.5.8: real single-image queues on frontend 1.52.7 in classic nodes and Nodes 2.0 show 1/1 then 2/2. Replaying the same execution output twice does not increase the count or reset a manually selected result. Reloading a workflow containing duplicate preview references removes duplicates. Unit checks distinguish filenames, subfolders and file types.
The sampling path was also checked for noise-schedule continuity against the real `common_ksampler`/`KSampler` functions in the local ComfyUI; an actual checkpoint has not been loaded to test GPU image quality or every model family, so CPU/interface tests must not be treated as model-quality verification.
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "adachi-inpaint-workbench"
version = "0.5.7"
version = "0.5.8"
description = "Inline mask painting and WebUI-style inpainting nodes for ComfyUI"
requires-python = ">=3.10"
license = { file = "LICENSE" }
+8 -1
View File
@@ -12,5 +12,12 @@ assert.deepEqual(appendComparison(legacy, {originals: ["c"], results: [5]}), {
assert.deepEqual(appendComparison(undefined, first), first);
assert.deepEqual(appendComparison(first, {}), first);
assert.deepEqual(appendComparison({}, {results: ["orphan"]}), {originals: [], results: []});
assert.deepEqual(appendComparison(JSON.parse(JSON.stringify(second)), first).results, ["result-a", "result-b", "result-c", "result-a"]);
assert.deepEqual(appendComparison(JSON.parse(JSON.stringify(second)), first).results, ["result-a", "result-b", "result-c"], "Cached execution replay must not count twice");
const preview = {filename: "preview_001.png", subfolder: "", type: "temp"};
const one = {originals: ["source-a"], results: [preview]};
assert.equal(appendComparison(one, {originals: ["source-a"], results: [{...preview}]}).results.length, 1);
assert.equal(appendComparison(one, {originals: ["source-a"], results: [{...preview, filename: "preview_002.png"}]}).results.length, 2);
assert.equal(appendComparison(one, {originals: ["source-a"], results: [{...preview, subfolder: "other"}]}).results.length, 2);
assert.equal(appendComparison(one, {originals: ["source-a"], results: [{...preview, type: "output"}]}).results.length, 2);
assert.deepEqual(appendComparison({originals: ["source-a", "source-a"], results: [preview, {...preview}]}), one, "Repair duplicates already saved in workflows");
console.log("Comparison history checks passed");
+12 -1
View File
@@ -11,5 +11,16 @@ export function appendComparison(previous, incoming) {
};
};
const before = pairs(previous), next = pairs(incoming);
return { originals: [...before.originals, ...next.originals], results: [...before.results, ...next.results] };
const history = { originals: [], results: [] }, seen = new Set();
for (const data of [before, next]) data.results.forEach((result, index) => {
// Cached execution notifications can replay the same preview. Its file
// identity is stable, while a genuinely new generation gets a new file.
const key = typeof result === "object" && result !== null
? JSON.stringify([result.type || "temp", result.subfolder || "", result.filename])
: JSON.stringify(result);
if (seen.has(key)) return;
seen.add(key);
history.originals.push(data.originals[index]); history.results.push(result);
});
return history;
}
+11 -5
View File
@@ -1,7 +1,7 @@
import { app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js";
import { ImageCompareView } from "./compare.js?v=0.5.7";
import { appendComparison } from "./compare_history.js?v=0.5.7";
import { ImageCompareView } from "./compare.js?v=0.5.8";
import { appendComparison } from "./compare_history.js?v=0.5.8";
import { routeWheelOutsideImage } from "./wheel_routing.js";
import { T } from "./i18n.js";
import { bindWidgetToNodeWidth } from "./widget_layout.js?v=0.5.5";
@@ -62,18 +62,24 @@ app.registerExtension({
node.onExecuted = function (output) {
const result = executed?.apply(this, arguments);
if (!output?.adachi_originals?.length || !output?.adachi_results?.length) return result;
const data = appendComparison(node.properties.adachi_compare, {
const previous = appendComparison(node.properties.adachi_compare);
const data = appendComparison(previous, {
originals: output.adachi_originals, results: output.adachi_results,
});
node.properties.adachi_compare = data;
node.properties.adachi_result_index = data.results.length - 1;
node.properties.adachi_result_index = data.results.length > previous.results.length
? data.results.length - 1 : Math.max(0, Math.min(data.results.length - 1, node.properties.adachi_result_index || 0));
compare.setData(data, node.properties.adachi_result_index);
return result;
};
const configured = node.onConfigure;
node.onConfigure = function () {
const result = configured?.apply(this, arguments);
if (node.properties.adachi_compare) compare.setData(node.properties.adachi_compare, node.properties.adachi_result_index || 0);
if (node.properties.adachi_compare) {
node.properties.adachi_compare = appendComparison(node.properties.adachi_compare);
node.properties.adachi_result_index = Math.max(0, Math.min(node.properties.adachi_compare.results.length - 1, node.properties.adachi_result_index || 0));
compare.setData(node.properties.adachi_compare, node.properties.adachi_result_index);
}
return result;
};
const removed = node.onRemoved;