Files

153 lines
4.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { COLORS, EMPTY_VALUE } from "./constants.js";
import { flashButton, patchFileDropdown } from "./utils.js";
import { ButtonRowWidget } from "./widgets/button_row_widget.js";
export const createLoaderCrud = (
node,
fileWidget,
{
baseEndpoint,
nodeLabel = "Node",
buildJson,
pushJson,
template,
newPlaceholder = "New file name:",
clonePlaceholder = "Clone to new file:",
onChange,
},
) => {
const handleNew = async () => {
const name = prompt(newPlaceholder);
if (!name?.trim()) return;
const res = await fetch(`${baseEndpoint}/new`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ file: name.trim() }),
});
const data = await res.json();
if (data.ok) {
patchFileDropdown(fileWidget, EMPTY_VALUE, data.file);
pushJson(node, JSON.parse(data.content));
onChange?.();
if (node.graph) node.graph.setDirtyCanvas(true, true);
} else {
alert(`[${nodeLabel}] ${data.error}`);
}
};
const handleSave = async () => {
const file = fileWidget.value;
if (!file || file === EMPTY_VALUE) {
alert(`[${nodeLabel}] No file selected.`);
return;
}
const content = buildJson(node);
const res = await fetch(`${baseEndpoint}/save`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ file, content }),
});
const data = await res.json();
if (data.ok) {
flashButton(node, 1, "✅ Saved!");
onChange?.();
} else {
alert(`[${nodeLabel}] Save failed: ${data.error}`);
}
};
const handleClone = async () => {
const name = prompt(clonePlaceholder);
if (!name?.trim()) return;
const content = buildJson(node);
const file = name.trim().endsWith(".json")
? name.trim()
: `${name.trim()}.json`;
const res = await fetch(`${baseEndpoint}/save`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ file, content }),
});
const data = await res.json();
if (data.ok) {
patchFileDropdown(fileWidget, EMPTY_VALUE, file);
onChange?.();
if (node.graph) node.graph.setDirtyCanvas(true, true);
} else {
alert(`[${nodeLabel}] Clone failed: ${data.error}`);
}
};
const handleDelete = async () => {
const file = fileWidget.value;
if (!file || file === EMPTY_VALUE) {
alert(`[${nodeLabel}] No file selected.`);
return;
}
if (!confirm(`Delete "${file}"? This cannot be undone.`)) return;
const res = await fetch(`${baseEndpoint}/delete`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ file }),
});
const data = await res.json();
if (data.ok) {
const values = fileWidget.options?.values ?? [];
const idx = values.indexOf(file);
if (idx !== -1) values.splice(idx, 1);
if (!values.length) values.push(EMPTY_VALUE);
fileWidget.options.values = values;
fileWidget.value = values[0];
fileWidget.callback?.(values[0]);
if (values[0] === EMPTY_VALUE) pushJson(node, template);
onChange?.();
if (node.graph) node.graph.setDirtyCanvas(true, true);
} else {
alert(`[${nodeLabel}] Delete failed: ${data.error}`);
}
};
const loadFileIntoWidgets = async (file) => {
if (!file || file === EMPTY_VALUE) return;
try {
const res = await fetch(
`${baseEndpoint}/load?file=${encodeURIComponent(file)}`,
);
const data = await res.json();
if (data.error) {
console.warn(`[${nodeLabel}] Load error:`, data.error);
return;
}
pushJson(node, JSON.parse(data.content));
} catch (e) {
console.warn(`[${nodeLabel}] Failed to load or parse file:`, e);
}
};
node.widgets.push(
new ButtonRowWidget("action_buttons", [
{ label: "➕ New", onClick: handleNew },
{ label: "💾 Save", onClick: handleSave },
{ label: "📋 Clone", onClick: handleClone },
{
label: "🗑️ Delete",
color: COLORS.dark_red,
onClick: handleDelete,
},
]),
);
return { loadFileIntoWidgets };
};