Add accumulator preview reorder diagnostics
This commit is contained in:
+115
-3
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user