145 lines
5.1 KiB
JavaScript
145 lines
5.1 KiB
JavaScript
import { app } from "../../scripts/app.js";
|
|
import { api } from '../../scripts/api.js';
|
|
|
|
|
|
const cssUrl = new URL("./secrets.css", import.meta.url);
|
|
if (!document.querySelector(`link[href="${cssUrl}"]`)) {
|
|
document.head.appendChild(Object.assign(document.createElement("link"), { rel: "stylesheet", href: cssUrl }));
|
|
}
|
|
|
|
function el(tag, props, ...children) {
|
|
const node = Object.assign(document.createElement(tag), props);
|
|
node.append(...children);
|
|
return node;
|
|
}
|
|
|
|
async function refreshDropdowns() {
|
|
const resp = await api.fetchApi("/comfyui-secrets", { method: "GET" });
|
|
const data = await resp.json();
|
|
const keys = Object.keys(data);
|
|
for (const node of (app.graph._nodes ?? [])) {
|
|
if (node.comfyClass !== "Get Secret") continue;
|
|
const widget = node.widgets?.find(w => w.name === "Secret");
|
|
if (!widget) continue;
|
|
widget.options.values = keys;
|
|
if (keys.length && !keys.includes(widget.value)) {
|
|
widget.value = keys[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function buildRow(key = "", value = "", isNew = false) {
|
|
let originalKey = key;
|
|
const keyInput = el("input", { className: "csm-input", placeholder: "Key", value: key });
|
|
const valInput = el("input", { className: "csm-input", placeholder: "Value", value, type: "password" });
|
|
|
|
const toggleBtn = el("button", {
|
|
className: "csm-btn csm-toggle-btn",
|
|
textContent: "👁",
|
|
title: "Toggle visibility",
|
|
onclick: () => { valInput.type = valInput.type === "password" ? "text" : "password"; },
|
|
});
|
|
|
|
const saveBtn = el("button", { className: "csm-btn csm-save-btn", textContent: isNew ? "Add" : "Save" });
|
|
const delBtn = el("button", { className: "csm-btn csm-del-btn", textContent: "🗑", title: "Delete" });
|
|
const row = el("div", { className: "csm-row" }, keyInput, valInput, toggleBtn, saveBtn, delBtn);
|
|
|
|
saveBtn.onclick = async () => {
|
|
const k = keyInput.value.trim();
|
|
const v = valInput.value;
|
|
if (!k) { keyInput.focus(); return; }
|
|
const resp = await api.fetchApi("/comfyui-secrets", {
|
|
method: "POST",
|
|
body: JSON.stringify({ key: k, value: v }),
|
|
});
|
|
if (!resp.ok) return;
|
|
// If the key was renamed, delete the old one
|
|
if (!isNew && originalKey && originalKey !== k) {
|
|
await api.fetchApi(`/comfyui-secrets/${encodeURIComponent(originalKey)}`, { method: "DELETE" });
|
|
originalKey = k;
|
|
}
|
|
refreshDropdowns();
|
|
if (isNew) {
|
|
row.replaceWith(buildRow(k, v, false));
|
|
} else {
|
|
originalKey = k;
|
|
saveBtn.textContent = "Saved!";
|
|
setTimeout(() => saveBtn.textContent = "Save", 1200);
|
|
}
|
|
};
|
|
|
|
delBtn.onclick = async () => {
|
|
if (!originalKey) { row.remove(); return; }
|
|
const resp = await api.fetchApi(`/comfyui-secrets/${encodeURIComponent(originalKey)}`, {
|
|
method: "DELETE",
|
|
});
|
|
if (resp.ok) {
|
|
row.remove();
|
|
refreshDropdowns();
|
|
}
|
|
};
|
|
|
|
return row;
|
|
}
|
|
|
|
|
|
function createModal(secrets) {
|
|
const rowsContainer = el("div", { className: "csm-rows" },
|
|
...Object.entries(secrets).map(([k, v]) => buildRow(k, v)),
|
|
);
|
|
|
|
const addBtn = el("button", {
|
|
className: "csm-add-btn",
|
|
textContent: "+ Add Secret",
|
|
onclick: () => {
|
|
const newRow = buildRow("", "", true);
|
|
rowsContainer.appendChild(newRow);
|
|
newRow.querySelector("input").focus();
|
|
},
|
|
});
|
|
|
|
const closeBtn = el("button", { className: "csm-close-btn", textContent: "✕" });
|
|
const overlay = el("div", { className: "csm-overlay" },
|
|
el("div", { className: "csm-dialog" },
|
|
el("div", { className: "csm-header" },
|
|
el("h3", { className: "csm-title", textContent: "Secrets Manager" }),
|
|
closeBtn,
|
|
),
|
|
rowsContainer,
|
|
addBtn,
|
|
),
|
|
);
|
|
|
|
closeBtn.onclick = () => overlay.remove();
|
|
overlay.addEventListener("click", (e) => { if (e.target === overlay) overlay.remove(); });
|
|
|
|
return overlay;
|
|
}
|
|
|
|
|
|
app.registerExtension({
|
|
name: "comfyui.secrets",
|
|
async nodeCreated(node) {
|
|
if (node.comfyClass !== "Get Secret") return;
|
|
|
|
// Fetch keys and replace the STRING widget with a combo
|
|
const resp = await api.fetchApi("/comfyui-secrets", { method: "GET" });
|
|
const data = await resp.json();
|
|
const keys = Object.keys(data);
|
|
|
|
const idx = node.widgets?.findIndex(w => w.name === "Secret") ?? -1;
|
|
const savedValue = idx >= 0 ? node.widgets[idx].value : undefined;
|
|
if (idx >= 0) node.widgets.splice(idx, 1);
|
|
|
|
const defaultValue = (savedValue && keys.includes(savedValue)) ? savedValue : (keys[0] ?? "");
|
|
node.addWidget("combo", "Secret", defaultValue, () => {}, { values: keys });
|
|
|
|
node.addWidget("button", "Edit Secrets", null, async () => {
|
|
const r = await api.fetchApi("/comfyui-secrets", { method: "GET" });
|
|
const secrets = await r.json();
|
|
document.body.appendChild(createModal(secrets));
|
|
});
|
|
}
|
|
});
|