Add accumulator preview reorder diagnostics

This commit is contained in:
2026-06-25 11:00:32 +02:00
parent c22c440d01
commit de7ca38a65
3 changed files with 151 additions and 8 deletions
+115 -3
View File
@@ -4,6 +4,7 @@ import { api } from "../../scripts/api.js";
const EXTENSION = "ethanfel.prompt_builder.accumulator_preview";
const NODE_NAME = "SxCPAccumulatorPreview";
const STYLE_ID = "sxcp-accumulator-preview-styles";
const DEBUG_STORAGE_KEY = "sxcpAccumulatorPreviewDebug";
const MIN_CELL_W = 180;
const GAP = 6;
@@ -33,6 +34,62 @@ function getNodeById(id) {
return app.graph?.getNodeById?.(Number(id)) || app.graph?._nodes_by_id?.[id] || app.graph?._nodes_by_id?.[Number(id)];
}
function debugEnabled() {
try {
return window.SXCP_ACCUMULATOR_PREVIEW_DEBUG === true || localStorage.getItem(DEBUG_STORAGE_KEY) === "1";
} catch (_err) {
return window.SXCP_ACCUMULATOR_PREVIEW_DEBUG === true;
}
}
function debugLog(...args) {
if (debugEnabled()) console.log(`[${EXTENSION}]`, ...args);
}
function debugWarn(...args) {
console.warn(`[${EXTENSION}]`, ...args);
}
function nodeSummaries() {
return (app.graph?._nodes || [])
.filter(isAccumulatorPreviewNode)
.map((node) => ({
id: node.id,
store_key: storeKey(node),
entries: (node._sxapEntries || []).map((entry, index) => ({
index: entry.index,
id: entry.id,
preview_key: entry.preview_key,
has_image: entry.has_image,
has_preview_image: !!entry.preview_image,
image_ref: imageParamsForEntry(node, entry, index),
})),
images: node._sxapImages || [],
status: node._sxapStatus || "",
}));
}
function installDebugHelpers() {
if (window.sxcpAccumulatorPreviewDebug) return;
window.sxcpAccumulatorPreviewDebug = {
enable() {
localStorage.setItem(DEBUG_STORAGE_KEY, "1");
window.SXCP_ACCUMULATOR_PREVIEW_DEBUG = true;
console.log(`[${EXTENSION}] debug enabled`);
},
disable() {
localStorage.removeItem(DEBUG_STORAGE_KEY);
window.SXCP_ACCUMULATOR_PREVIEW_DEBUG = false;
console.log(`[${EXTENSION}] debug disabled`);
},
dump() {
const data = nodeSummaries();
console.log(`[${EXTENSION}] dump`, data);
return data;
},
};
}
function asArray(value) {
if (!value) return [];
return Array.isArray(value) ? value : [value];
@@ -93,6 +150,9 @@ function entryKey(entry) {
function buildImageMap(entries, images, previous = new Map()) {
const next = new Map(previous);
const imageEntries = asArray(entries).filter((entry) => entry?.has_image);
imageEntries.forEach((entry) => {
if (entry.preview_image) next.set(entryKey(entry), entry.preview_image);
});
asArray(images).filter(Boolean).forEach((image, index) => {
const directKey = String(image?.preview_key || "").trim();
if (directKey) {
@@ -111,6 +171,7 @@ function buildImageMap(entries, images, previous = new Map()) {
}
function imageParamsForEntry(node, entry, fallbackIndex) {
if (entry?.preview_image) return entry.preview_image;
const keyed = node._sxapImageByKey?.get(entryKey(entry));
if (keyed) return keyed;
return (node._sxapImages || [])[fallbackIndex];
@@ -137,12 +198,14 @@ function entryTitle(entry) {
}
async function postJson(path, payload) {
debugLog("POST", path, payload);
const response = await api.fetchApi(path, {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(payload),
});
const data = await response.json();
debugLog("POST response", path, data);
if (!response.ok) throw new Error(data?.error || response.statusText);
return data;
}
@@ -299,17 +362,37 @@ function renderCell(node, entry, imageParams, displayIndex) {
const source = node._sxapDragEntry;
node._sxapDragEntry = null;
if (source.index === entry.index) return;
debugLog("drop", {
source_index: source.index,
source_key: entryKey(source),
target_index: entry.index,
target_key: entryKey(entry),
});
await moveEntryToIndex(node, source, entry.index);
};
const thumb = document.createElement("img");
thumb.className = "sxap-thumb";
thumb.style.height = `${Math.max(48, Math.round(cellW * entryAspect(entry)))}px`;
if (imageParams) thumb.src = imageUrl(imageParams);
if (imageParams) {
const url = imageUrl(imageParams);
thumb.src = url;
thumb.onerror = () => debugWarn("image load failed", {
entry: {index: entry.index, id: entry.id, preview_key: entry.preview_key},
imageParams,
url,
});
} else {
debugWarn("missing image params for entry", {
entry: {index: entry.index, id: entry.id, preview_key: entry.preview_key},
displayIndex,
});
}
thumb.draggable = true;
thumb.onclick = () => markSelected(node, entry.index);
thumb.ondragstart = (event) => {
node._sxapDragEntry = entry;
debugLog("dragstart", {index: entry.index, key: entryKey(entry), id: entry.id});
if (event.dataTransfer) {
event.dataTransfer.effectAllowed = "move";
event.dataTransfer.setData("text/plain", String(entry.id || entry.index || ""));
@@ -364,6 +447,12 @@ function renderGrid(node) {
empty.textContent = storeKey(node) ? "No accumulator images." : "Run once or set an explicit store_key.";
grid.appendChild(empty);
} else {
debugLog("renderGrid", entries.map((entry, index) => ({
index: entry.index,
key: entryKey(entry),
has_preview_image: !!entry.preview_image,
has_image_params: !!imageParamsForEntry(node, entry, index),
})));
entries.forEach((entry, index) => {
grid.appendChild(renderCell(node, entry, imageParamsForEntry(node, entry, index), index));
});
@@ -428,8 +517,9 @@ async function deleteEntry(node, entry) {
try {
const data = await postJson("/sxcp/accumulator/delete", actionPayload(node, {
store_key: key,
preview_key: entry.preview_key || "",
entry_id: entry.id || "",
index: entry.id ? 0 : entry.index,
index: entry.preview_key || entry.id ? 0 : entry.index,
clear: false,
}));
applyData(node, data, `${data.status || ""}; deleted=${data.removed || 0}`);
@@ -447,12 +537,33 @@ async function moveEntryToIndex(node, entry, targetIndex) {
}
if (!entry) return;
try {
debugLog("move request", {
entry: {index: entry.index, id: entry.id, preview_key: entry.preview_key},
targetIndex,
});
const data = await postJson("/sxcp/accumulator/move", actionPayload(node, {
store_key: key,
preview_key: entry.preview_key || "",
entry_id: entry.id || "",
index: entry.id ? 0 : entry.index,
index: entry.preview_key || entry.id ? 0 : entry.index,
target_index: targetIndex,
}));
debugLog("move response summary", {
moved: data.moved,
from_index: data.from_index,
to_index: data.to_index,
entries: asArray(data.entries).map((item) => ({
index: item.index,
id: item.id,
preview_key: item.preview_key,
has_preview_image: !!item.preview_image,
})),
images: asArray(data.images).map((item) => ({
filename: item.filename,
preview_key: item.preview_key,
entry_id: item.entry_id,
})),
});
applyData(node, data, `${data.status || ""}; moved=${data.moved ? "yes" : "no"}`);
} catch (err) {
console.error(`[${EXTENSION}] drag move failed`, err);
@@ -599,6 +710,7 @@ app.registerExtension({
name: EXTENSION,
async setup() {
installDebugHelpers();
api.addEventListener("executed", ({detail}) => {
const node = getNodeById(detail?.display_node ?? detail?.node);
if (!isAccumulatorPreviewNode(node)) return;