multimodalart's picture
Squashing commit
4450790 verified
import { app } from "../../scripts/app.js";
import { RgthreeDialog } from "../../rgthree/common/dialog.js";
import { createElement as $el, query as $$ } from "../../rgthree/common/utils_dom.js";
import { checkmark, logoRgthree } from "../../rgthree/common/media/svgs.js";
import { rgthree } from "./rgthree.js";
import { SERVICE as CONFIG_SERVICE } from "./services/config_service.js";
var ConfigType;
(function (ConfigType) {
ConfigType[ConfigType["UNKNOWN"] = 0] = "UNKNOWN";
ConfigType[ConfigType["BOOLEAN"] = 1] = "BOOLEAN";
ConfigType[ConfigType["STRING"] = 2] = "STRING";
ConfigType[ConfigType["NUMBER"] = 3] = "NUMBER";
ConfigType[ConfigType["ARRAY"] = 4] = "ARRAY";
})(ConfigType || (ConfigType = {}));
var ConfigInputType;
(function (ConfigInputType) {
ConfigInputType[ConfigInputType["UNKNOWN"] = 0] = "UNKNOWN";
ConfigInputType[ConfigInputType["CHECKLIST"] = 1] = "CHECKLIST";
})(ConfigInputType || (ConfigInputType = {}));
const TYPE_TO_STRING = {
[ConfigType.UNKNOWN]: "unknown",
[ConfigType.BOOLEAN]: "boolean",
[ConfigType.STRING]: "string",
[ConfigType.NUMBER]: "number",
[ConfigType.ARRAY]: "array",
};
const CONFIGURABLE = {
features: [
{
key: "features.progress_bar.enabled",
type: ConfigType.BOOLEAN,
label: "Prompt Progress Bar",
description: `Shows a minimal progress bar for nodes and steps at the top of the app.`,
subconfig: [
{
key: "features.progress_bar.height",
type: ConfigType.NUMBER,
label: "Height of the bar",
},
{
key: "features.progress_bar.position",
type: ConfigType.STRING,
label: "Position at top or bottom of window",
options: ["top", "bottom"],
},
],
},
{
key: "features.import_individual_nodes.enabled",
type: ConfigType.BOOLEAN,
label: "Import Individual Nodes Widgets",
description: "Dragging & Dropping a similar image/JSON workflow onto (most) current workflow nodes" +
"will allow you to import that workflow's node's widgets when it has the same " +
"id and type. This is useful when you have several images and you'd like to import just " +
"one part of a previous iteration, like a seed, or prompt.",
},
],
menus: [
{
key: "features.comfy_top_bar_menu.enabled",
type: ConfigType.BOOLEAN,
label: "Enable Top Bar Menu",
description: "Have quick access from ComfyUI's new top bar to rgthree-comfy bookmarks, settings " +
"(and more to come).",
},
{
key: "features.menu_queue_selected_nodes",
type: ConfigType.BOOLEAN,
label: "Show 'Queue Selected Output Nodes'",
description: "Will show a menu item in the right-click context menus to queue (only) the selected " +
"output nodes.",
},
{
key: "features.menu_auto_nest.subdirs",
type: ConfigType.BOOLEAN,
label: "Auto Nest Subdirectories in Menus",
description: "When a large, flat list of values contain sub-directories, auto nest them. (Like, for " +
"a large list of checkpoints).",
subconfig: [
{
key: "features.menu_auto_nest.threshold",
type: ConfigType.NUMBER,
label: "Number of items needed to trigger nesting.",
},
],
},
{
key: "features.menu_bookmarks.enabled",
type: ConfigType.BOOLEAN,
label: "Show Bookmarks in context menu",
description: "Will list bookmarks in the rgthree-comfy right-click context menu.",
},
],
groups: [
{
key: "features.group_header_fast_toggle.enabled",
type: ConfigType.BOOLEAN,
label: "Show fast toggles in Group Headers",
description: "Show quick toggles in Groups' Headers to quickly mute, bypass or queue.",
subconfig: [
{
key: "features.group_header_fast_toggle.toggles",
type: ConfigType.ARRAY,
label: "Which toggles to show.",
inputType: ConfigInputType.CHECKLIST,
options: [
{ value: "queue", label: "queue" },
{ value: "bypass", label: "bypass" },
{ value: "mute", label: "mute" },
],
},
{
key: "features.group_header_fast_toggle.show",
type: ConfigType.STRING,
label: "When to show them.",
options: [
{ value: "hover", label: "on hover" },
{ value: "always", label: "always" },
],
},
],
},
],
advanced: [
{
key: "features.show_alerts_for_corrupt_workflows",
type: ConfigType.BOOLEAN,
label: "Detect Corrupt Workflows",
description: "Will show a message at the top of the screen when loading a workflow that has " +
"corrupt linking data.",
},
{
key: "log_level",
type: ConfigType.STRING,
label: "Log level for browser dev console.",
description: "Further down the list, the more verbose logs to the console will be. For instance, " +
"selecting 'IMPORTANT' means only important message will be logged to the browser " +
"console, while selecting 'WARN' will log all messages at or higher than WARN, including " +
"'ERROR' and 'IMPORTANT' etc.",
options: ["IMPORTANT", "ERROR", "WARN", "INFO", "DEBUG", "DEV"],
isDevOnly: true,
onSave: function (value) {
rgthree.setLogLevel(value);
},
},
{
key: "features.invoke_extensions_async.node_created",
type: ConfigType.BOOLEAN,
label: "Allow other extensions to call nodeCreated on rgthree-nodes.",
isDevOnly: true,
description: "Do not disable unless you are having trouble (and then file an issue at rgthree-comfy)." +
"Prior to Apr 2024 it was not possible for other extensions to invoke their nodeCreated " +
"event on some rgthree-comfy nodes. Now it's possible and this option is only here in " +
"for easy if something is wrong.",
},
],
};
function fieldrow(item) {
var _a;
const initialValue = CONFIG_SERVICE.getConfigValue(item.key);
const container = $el(`div.fieldrow.-type-${TYPE_TO_STRING[item.type]}`, {
dataset: {
name: item.key,
initial: initialValue,
type: item.type,
},
});
$el(`label[for="${item.key}"]`, {
children: [
$el(`span[text="${item.label}"]`),
item.description ? $el("small", { html: item.description }) : null,
],
parent: container,
});
let input;
if ((_a = item.options) === null || _a === void 0 ? void 0 : _a.length) {
if (item.inputType === ConfigInputType.CHECKLIST) {
const initialValueList = initialValue || [];
input = $el(`fieldset.rgthree-checklist-group[id="${item.key}"]`, {
parent: container,
children: item.options.map((o) => {
const label = o.label || String(o);
const value = o.value || o;
const id = `${item.key}_${value}`;
return $el(`span.rgthree-checklist-item`, {
children: [
$el(`input[type="checkbox"][value="${value}"]`, {
id,
checked: initialValueList.includes(value),
}),
$el(`label`, {
for: id,
text: label,
})
]
});
}),
});
}
else {
input = $el(`select[id="${item.key}"]`, {
parent: container,
children: item.options.map((o) => {
const label = o.label || String(o);
const value = o.value || o;
const valueSerialized = JSON.stringify({ value: value });
return $el(`option[value="${valueSerialized}"]`, {
text: label,
selected: valueSerialized === JSON.stringify({ value: initialValue }),
});
}),
});
}
}
else if (item.type === ConfigType.BOOLEAN) {
container.classList.toggle("-checked", !!initialValue);
input = $el(`input[type="checkbox"][id="${item.key}"]`, {
parent: container,
checked: initialValue,
});
}
else {
input = $el(`input[id="${item.key}"]`, {
parent: container,
value: initialValue,
});
}
$el("div.fieldrow-value", { children: [input], parent: container });
return container;
}
export class RgthreeConfigDialog extends RgthreeDialog {
constructor() {
const content = $el("div");
content.appendChild(RgthreeConfigDialog.buildFieldset(CONFIGURABLE["features"], "Features"));
content.appendChild(RgthreeConfigDialog.buildFieldset(CONFIGURABLE["menus"], "Menus"));
content.appendChild(RgthreeConfigDialog.buildFieldset(CONFIGURABLE["groups"], "Groups"));
content.appendChild(RgthreeConfigDialog.buildFieldset(CONFIGURABLE["advanced"], "Advanced"));
content.addEventListener("input", (e) => {
const changed = this.getChangedFormData();
$$(".save-button", this.element)[0].disabled =
!Object.keys(changed).length;
});
content.addEventListener("change", (e) => {
const changed = this.getChangedFormData();
$$(".save-button", this.element)[0].disabled =
!Object.keys(changed).length;
});
const dialogOptions = {
class: "-iconed -settings",
title: logoRgthree + `<h2>Settings - rgthree-comfy</h2>`,
content,
onBeforeClose: () => {
const changed = this.getChangedFormData();
if (Object.keys(changed).length) {
return confirm("Looks like there are unsaved changes. Are you sure you want close?");
}
return true;
},
buttons: [
{
label: "Save",
disabled: true,
className: "rgthree-button save-button -blue",
callback: async (e) => {
var _a, _b;
const changed = this.getChangedFormData();
if (!Object.keys(changed).length) {
this.close();
return;
}
const success = await CONFIG_SERVICE.setConfigValues(changed);
if (success) {
for (const key of Object.keys(changed)) {
(_b = (_a = Object.values(CONFIGURABLE)
.flat()
.find((f) => f.key === key)) === null || _a === void 0 ? void 0 : _a.onSave) === null || _b === void 0 ? void 0 : _b.call(_a, changed[key]);
}
this.close();
rgthree.showMessage({
id: "config-success",
message: `${checkmark} Successfully saved rgthree-comfy settings!`,
timeout: 4000,
});
$$(".save-button", this.element)[0].disabled = true;
}
else {
alert("There was an error saving rgthree-comfy configuration.");
}
},
},
],
};
super(dialogOptions);
}
static buildFieldset(datas, label) {
const fieldset = $el(`fieldset`, { children: [$el(`legend[text="${label}"]`)] });
for (const data of datas) {
if (data.isDevOnly && !rgthree.isDevMode()) {
continue;
}
const container = $el("div.formrow");
container.appendChild(fieldrow(data));
if (data.subconfig) {
for (const subfeature of data.subconfig) {
container.appendChild(fieldrow(subfeature));
}
}
fieldset.appendChild(container);
}
return fieldset;
}
getChangedFormData() {
return $$("[data-name]", this.contentElement).reduce((acc, el) => {
const name = el.dataset["name"];
const type = el.dataset["type"];
const initialValue = CONFIG_SERVICE.getConfigValue(name);
let currentValueEl = $$("fieldset.rgthree-checklist-group, input, textarea, select", el)[0];
let currentValue = null;
if (type === String(ConfigType.BOOLEAN)) {
currentValue = currentValueEl.checked;
el.classList.toggle("-checked", currentValue);
}
else {
currentValue = currentValueEl === null || currentValueEl === void 0 ? void 0 : currentValueEl.value;
if (currentValueEl.nodeName === "SELECT") {
currentValue = JSON.parse(currentValue).value;
}
else if (currentValueEl.classList.contains('rgthree-checklist-group')) {
currentValue = [];
for (const check of $$('input[type="checkbox"]', currentValueEl)) {
if (check.checked) {
currentValue.push(check.value);
}
}
}
else if (type === String(ConfigType.NUMBER)) {
currentValue = Number(currentValue) || initialValue;
}
}
if (JSON.stringify(currentValue) !== JSON.stringify(initialValue)) {
acc[name] = currentValue;
}
return acc;
}, {});
}
}
app.ui.settings.addSetting({
id: "rgthree.config",
name: "Open rgthree-comfy config",
type: () => {
return $el("tr.rgthree-comfyui-settings-row", {
children: [
$el("td", {
child: `<div>${logoRgthree} [rgthree-comfy] configuration / settings</div>`,
}),
$el("td", {
child: $el('button.rgthree-button.-blue[text="rgthree-comfy settings"]', {
events: {
click: (e) => {
new RgthreeConfigDialog().show();
},
},
}),
}),
],
});
},
});