mirror of
https://github.com/storytold/storyteller-ml.git
synced 2026-10-17 00:23:14 +00:00
more extensions
This commit is contained in:
@@ -65,6 +65,15 @@ Note, you can right-click on a bunch of the rgthree-comfy nodes and select `🛟
|
||||
> 
|
||||
> </details>
|
||||
|
||||
## Bookmark (🔖)
|
||||
> Place the bookmark node anywhere on screen to quickly navigate to that with a shortcut key.
|
||||
> <details>
|
||||
> <summary>ℹ️ <i>See More Information</i></summary>
|
||||
>
|
||||
> - Define the `sahortvut_key` to press to go right to that bookmark node, anchored in the top left
|
||||
> - You can also define the zoom level as well!
|
||||
> </details>
|
||||
|
||||
|
||||
## Context / Context Big
|
||||
> Pass along in general flow properties, and merge in new data. Similar to some other node suites "pipes" but easier merging, is more easily interoperable with standard nodes by both combining and exploding all in a single node.
|
||||
@@ -78,6 +87,21 @@ Note, you can right-click on a bunch of the rgthree-comfy nodes and select `🛟
|
||||
> 
|
||||
> </details>
|
||||
|
||||
## Image Comparer
|
||||
> The Image Comparer node compares two images on top of each other.
|
||||
> <details>
|
||||
> <summary>ℹ️ <i>More Information</i></summary>
|
||||
>
|
||||
> - **Note:** The right-click menu may show image options (Open Image, Save Image, etc.) which will correspond to the first image (image_a) if clicked on the left-half of the node, or the second image if on the right half of the node.
|
||||
> - **Inputs:**
|
||||
> - `image_a` _Required._ The first image to use to compare. If image_b is not supplied and image_a is a batch, the comparer will use the first two images of image_a.
|
||||
> - `image_b` _Optional._ The second image to use to compare. Optional only if image_a is a batch with two images.
|
||||
> - **Properties:** You can change the following properties (by right-clicking on the node, and select "Properties" or "Properties Panel" from the menu):
|
||||
> - `comparer_mode` - Choose between "Slide" and "Click". Defaults to "Slide".
|
||||
|
||||
|
||||
## Image Inset Crop
|
||||
> The node that lets you crop an input image by either pixel value, or percentage value.
|
||||
|
||||
|
||||
## Display Any
|
||||
@@ -99,11 +123,9 @@ Note, you can right-click on a bunch of the rgthree-comfy nodes and select `🛟
|
||||
> needing a separate Lora Loaders
|
||||
> </details>
|
||||
|
||||
|
||||
## Power Prompt - Simple
|
||||
> Same as Power Prompt above, but without LORA support; made for a slightly cleaner negative prompt _(since negative prompts do not support loras)_.
|
||||
|
||||
|
||||
## SDXL Power Prompt - Positive
|
||||
> The SDXL sibling to the Power Prompt above. It contains the text_g and text_l as separate text inputs, as well a couple more input slots necessary to ensure proper clipe encoding. Combine with
|
||||
|
||||
@@ -119,13 +141,49 @@ Note, you can right-click on a bunch of the rgthree-comfy nodes and select `🛟
|
||||
> <summary>ℹ️ <i>More Information</i></summary>
|
||||
>
|
||||
> - Pass in several context nodes and the Context Switch will automatically choose the first non-null context to continue onward with.
|
||||
> - Wondering how to toggle contexts to null? Use in conjuction with the **Fast Muter**
|
||||
> - Wondering how to toggle contexts to null? Use in conjuction with the **Fast Muter** or **Fast Groups Muter**
|
||||
>
|
||||
> </details>
|
||||
|
||||
## Any Switch
|
||||
> A powerful node to similar to the Context Switch above, that chooses the first input that is not null/empty.
|
||||
> <details>
|
||||
> <summary>ℹ️ <i>More Information</i></summary>
|
||||
>
|
||||
> - Pass in several inmputs of the same type and the Any Switch will automatically choose the first non-null value to continue onward with.
|
||||
> - Wondering how to toggle contexts to null? Use in conjuction with the **Fast Muter** or **Fast Groups Muter**
|
||||
>
|
||||
> </details>
|
||||
|
||||
|
||||
## Fast Groups Muter
|
||||
> The Fast Groups Muter is an input-less node that automatically collects all groups in your current workflow and allows you to quickly mute and unmute all nodes within the group.
|
||||
> <details>
|
||||
> <summary>ℹ️ <i>More Information</i></summary>
|
||||
>
|
||||
> - Groups will automatically be shown, though you can filter, sort and more from the **node Properties** _(by right-clicking on the node, and select "Properties" or "Properties Panel" from the menu)_. Properties include:
|
||||
> - `matchColors` - Only add groups that match the provided colors. Can be ComfyUI colors (red, pale_blue) or hex codes (#a4d399). Multiple can be added, comma delimited.
|
||||
> - `matchTitle` - Filter the list of toggles by title match (string match, or regular expression).
|
||||
> - `showNav` - Add / remove a quick navigation arrow to take you to the group. (default: true)
|
||||
> - `sort` - Sort the toggles' order by "alphanumeric", graph "position", or "custom alphabet". (default: "position")
|
||||
> - `customSortAlphabet` - When the sort property is "custom alphabet" you can define the alphabet to use here, which will match the beginning of each group name and sort against it. If group titles do not match any custom alphabet entry, then they will be put after groups that do, ordered alphanumerically.
|
||||
>
|
||||
> This can be a list of single characters, like "zyxw..." or comma delimited strings for more control, like "sdxl,pro,sd,n,p".
|
||||
>
|
||||
> Note, when two group title match the same custom alphabet entry, the normal alphanumeric alphabet breaks the tie. For instance, a custom alphabet of "e,s,d" will order groups names like "SDXL, SEGS, Detailer" eventhough the custom alphabet has an "e" before "d" (where one may expect "SE" to be before "SD").
|
||||
>
|
||||
> To have "SEGS" appear before "SDXL" you can use longer strings. For instance, the custom alphabet value of "se,s,f" would work here.
|
||||
> - `toggleRestriction` - Optionally, attempt to restrict the number of widgets that can be enabled to a maximum of one, or always one.
|
||||
>
|
||||
> _Note: If using "max one" or "always one" then this is only enforced when clicking a toggle on this node; if nodes within groups are changed outside of the initial toggle click, then these restriction will not be enforced, and could result in a state where more than one toggle is enabled. This could also happen if nodes are overlapped with multiple groups._
|
||||
> </details>
|
||||
|
||||
## Fast Groups Bypasser
|
||||
> _Same as **Fast Groups Muter** above, but sets the connected nodes to "Bypass" instead of "Mute"_
|
||||
|
||||
|
||||
## Fast Muter
|
||||
> A powerful 'control panel' node to quickly toggle connected node allowing it to quickly be muted or enabled
|
||||
> A powerful 'control panel' node to quickly toggle connected nodes allowing them to quickly be muted or enabled
|
||||
> <details>
|
||||
> <summary>ℹ️ <i>More Information</i></summary>
|
||||
>
|
||||
@@ -137,7 +195,7 @@ Note, you can right-click on a bunch of the rgthree-comfy nodes and select `🛟
|
||||
> Same as Fast Muter but sets the connected nodes to "Bypass"
|
||||
|
||||
## Fast Actions Button
|
||||
> Oh boy, this node allows you to semi-automate connected nodes and/ror ConfyUI.
|
||||
> Oh boy, this node allows you to semi-automate connected nodes and/or ConfyUI.
|
||||
> <details>
|
||||
> <summary>ℹ️ <i>More Information</i></summary>
|
||||
>
|
||||
@@ -172,6 +230,14 @@ Note, you can right-click on a bunch of the rgthree-comfy nodes and select `🛟
|
||||
> </details>
|
||||
|
||||
|
||||
## Random Unmuter
|
||||
> An advanced node used to unmute one of its inputs randomly when the graph is queued (and, immediately mute it back).
|
||||
> <details>
|
||||
> <summary>ℹ️ <i>More Information</i></summary>
|
||||
>
|
||||
> - **Note:** All input nodes MUST be muted to start; if not this node will not randomly unmute another. (This is powerful, as the generated image can be dragged in and the chosen input will already by unmuted and work w/o any further action.)
|
||||
> - **Tip:** Connect a Repeater's output to this nodes input and place that Repeater on a group without any other inputs, and it will mute/unmute the entire group.
|
||||
> </details>
|
||||
|
||||
|
||||
# Advanced Techniques
|
||||
@@ -236,19 +302,28 @@ rgthree-comfy adds several improvements, features, and optimizations to ComfyUI
|
||||
> </details>
|
||||
|
||||
|
||||
## "Queue Node" in right-click menu for output nodes
|
||||
> Sometimes you want to just equeue a single node, without executing the entire workflow. Well, now you can do just that by right-clicking on an output node and selecting `Queue Node (rgthree)`.
|
||||
## "Queue Selected Output Nodes" in right-click menu
|
||||
> Sometimes you want to just queue one or two paths to specific output node(s) without executing the entire workflow. Well, now you can do just that by right-clicking on an output node and selecting `Queue Selected Output Nodes (rgthree)`.
|
||||
>
|
||||
> <details>
|
||||
> <summary>ℹ️ <i>More Information</i></summary>
|
||||
>
|
||||
> - Note that this can have side-effects on the entire workflow.
|
||||
> - Select the _output_ nodes you want to execute.
|
||||
>
|
||||
> - The whole workflow is serialized, and then we trim what we don't want for the backend. So things like all seed random/increment/decrement will run even if that node isn't being sent in the end, etc.
|
||||
> - Note: Only output nodes are captured and traversed, not all selected nodes. So if you select an output AND a node from a different path, only the path connected to the output will be executed and not non-output nodes, even if they were selected.
|
||||
>
|
||||
> - Note: The whole workflow is serialized, and then we trim what we don't want for the backend. So things like all seed random/increment/decrement will run even if that node isn't being sent in the end, etc.
|
||||
>
|
||||
> </details>
|
||||
|
||||
|
||||
## Auto-Nest Subdirectories in long Combos
|
||||
> _(Off by default while experimenting, turn on in rgthree-comfy settings)_.
|
||||
>
|
||||
> Automatically detect top-level subdirectories in long combo lists (like, Load Checkpoint) and break out into sub directories.
|
||||
|
||||
|
||||
|
||||
## "Copy Image" in right-click menu
|
||||
> Right clicking on a node that has an image should have a context-menu item of "Copy Image" will allow you to copy the image right to your clipboard
|
||||
>
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
// COPY THIS FILE BEFORE MAKING CHANGES TO: rgthree_config.json
|
||||
{
|
||||
"log_level": "WARN",
|
||||
"features": {
|
||||
"patch_recursive_execution": true,
|
||||
"show_alerts_for_corrupt_workflows": false,
|
||||
"monitor_for_corrupt_links": false,
|
||||
"menu_queue_selected_nodes": true,
|
||||
"menu_auto_nest": {
|
||||
"subdirs": null,
|
||||
"threshold": 20
|
||||
},
|
||||
"progress_bar": {
|
||||
"enabled": true,
|
||||
"height": 16
|
||||
"height": 16,
|
||||
"position": "top"
|
||||
}
|
||||
},
|
||||
"nodes": {
|
||||
|
||||
@@ -25,6 +25,7 @@ type ConfigurationSchema = {
|
||||
key: string;
|
||||
type: ConfigType;
|
||||
label: string;
|
||||
options?: string[] | number[];
|
||||
description?: string;
|
||||
subconfig?: ConfigurationSchema[];
|
||||
};
|
||||
@@ -53,8 +54,30 @@ const CONFIGURABLE: { features: ConfigurationSchema[] } = {
|
||||
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.menu_queue_selected_nodes",
|
||||
type: ConfigType.BOOLEAN,
|
||||
label: "(Menu) 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: "(Menu) Auto Nest Subdirectories",
|
||||
description:
|
||||
"When a large, flat list of values contain sub-directories, auto nest them. (Like, for " +
|
||||
"a large list of checkpoints).",
|
||||
},
|
||||
{
|
||||
key: "features.show_alerts_for_corrupt_workflows",
|
||||
type: ConfigType.BOOLEAN,
|
||||
@@ -66,7 +89,6 @@ const CONFIGURABLE: { features: ConfigurationSchema[] } = {
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new fieldrow for main or sub configuration items.
|
||||
*/
|
||||
@@ -89,16 +111,26 @@ function fieldrow(item: ConfigurationSchema) {
|
||||
});
|
||||
|
||||
let input;
|
||||
if (item.type === ConfigType.BOOLEAN) {
|
||||
if (item.options?.length) {
|
||||
input = $el<HTMLSelectElement>(`select[id="${item.key}"]`, {
|
||||
parent: container,
|
||||
children: item.options.map((o) => {
|
||||
return $el<HTMLOptionElement>(`option[value="${String(o)}"]`, {
|
||||
text: String(o),
|
||||
selected: o === initialValue,
|
||||
});
|
||||
}),
|
||||
});
|
||||
} else if (item.type === ConfigType.BOOLEAN) {
|
||||
container.classList.toggle("-checked", initialValue);
|
||||
input = $el<HTMLInputElement>(`input[type="checkbox"][id="${item.key}"]`, {
|
||||
checked: initialValue,
|
||||
parent: container,
|
||||
checked: initialValue,
|
||||
});
|
||||
} else {
|
||||
input = $el(`input[id="${item.key}"]`, {
|
||||
value: initialValue,
|
||||
parent: container,
|
||||
value: initialValue,
|
||||
});
|
||||
}
|
||||
$el("div.fieldrow-value", { children: [input], parent: container });
|
||||
@@ -184,7 +216,7 @@ export class RgthreeConfigDialog extends RgthreeDialog {
|
||||
const name = el.dataset["name"]!;
|
||||
const type = el.dataset["type"]!;
|
||||
const initialValue = CONFIG_SERVICE.getConfigValue(name);
|
||||
let currentValueEl = $$("input, textarea", el)[0] as HTMLInputElement;
|
||||
let currentValueEl = $$("input, textarea, select", el)[0] as HTMLInputElement;
|
||||
let currentValue: any = null;
|
||||
if (type === String(ConfigType.BOOLEAN)) {
|
||||
currentValue = currentValueEl.checked;
|
||||
|
||||
+65
-19
@@ -1,8 +1,54 @@
|
||||
// @ts-ignore
|
||||
import { app } from "../../scripts/app.js";
|
||||
import type { LGraphCanvas, ContextMenuItem } from "typings/litegraph.js";
|
||||
import type {
|
||||
LGraphCanvas as TLGraphCanvas,
|
||||
ContextMenuItem,
|
||||
LGraphNode,
|
||||
LiteGraph as TLiteGraph,
|
||||
} from "typings/litegraph.js";
|
||||
import type { ComfyNodeConstructor, ComfyObjectInfo } from "typings/comfy.js";
|
||||
import { rgthree } from "./rgthree.js";
|
||||
import { SERVICE as CONFIG_SERVICE } from "./config_service.js";
|
||||
|
||||
declare const LiteGraph: typeof TLiteGraph;
|
||||
declare const LGraphCanvas: typeof TLGraphCanvas;
|
||||
|
||||
function getOutputNodesFromSelected(canvas: TLGraphCanvas) {
|
||||
return (
|
||||
(canvas.selected_nodes &&
|
||||
Object.values(canvas.selected_nodes).filter((n) => {
|
||||
return (
|
||||
n.mode != LiteGraph.NEVER &&
|
||||
((n.constructor as any).nodeData as ComfyObjectInfo)?.output_node
|
||||
);
|
||||
})) ||
|
||||
[]
|
||||
);
|
||||
}
|
||||
|
||||
function showQueueNodesMenuIfOutputNodesAreSelected(
|
||||
existingOptions: ContextMenuItem[],
|
||||
node?: LGraphNode,
|
||||
) {
|
||||
if (CONFIG_SERVICE.getConfigValue("features.menu_queue_selected_nodes") != false) {
|
||||
const canvas = app.canvas as TLGraphCanvas;
|
||||
const outputNodes = getOutputNodesFromSelected(canvas);
|
||||
const menuItem = {
|
||||
content: `Queue Selected Output Nodes (rgthree) `,
|
||||
className: "rgthree-contextmenu-item",
|
||||
callback: () => {
|
||||
rgthree.queueOutputNodes(outputNodes.map((n) => n.id));
|
||||
},
|
||||
disabled: !outputNodes.length,
|
||||
};
|
||||
|
||||
let idx = existingOptions.findIndex((o) => o?.content === "Outputs") + 1;
|
||||
idx = idx || existingOptions.findIndex((o) => o?.content === "Align") + 1;
|
||||
idx = idx || 3;
|
||||
existingOptions.splice(idx, 0, menuItem);
|
||||
}
|
||||
return existingOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a "Queue Node" menu item to all output nodes, working with `rgthree.queueOutputNode` to
|
||||
@@ -11,24 +57,24 @@ import { rgthree } from "./rgthree.js";
|
||||
app.registerExtension({
|
||||
name: "rgthree.QueueNode",
|
||||
async beforeRegisterNodeDef(nodeType: ComfyNodeConstructor, nodeData: ComfyObjectInfo) {
|
||||
if (nodeData.output_node == true) {
|
||||
const getExtraMenuOptions = nodeType.prototype.getExtraMenuOptions;
|
||||
nodeType.prototype.getExtraMenuOptions = function (
|
||||
canvas: LGraphCanvas,
|
||||
options: ContextMenuItem[],
|
||||
) {
|
||||
getExtraMenuOptions ? getExtraMenuOptions.apply(this, arguments) : undefined;
|
||||
const getExtraMenuOptions = nodeType.prototype.getExtraMenuOptions;
|
||||
nodeType.prototype.getExtraMenuOptions = function (
|
||||
canvas: TLGraphCanvas,
|
||||
options: ContextMenuItem[],
|
||||
) {
|
||||
getExtraMenuOptions ? getExtraMenuOptions.apply(this, arguments) : undefined;
|
||||
showQueueNodesMenuIfOutputNodesAreSelected(options, this);
|
||||
};
|
||||
},
|
||||
|
||||
const menuItem: ContextMenuItem = {
|
||||
content: `Queue Node (rgthree)`,
|
||||
className: "rgthree-contextmenu-item",
|
||||
callback: () => {
|
||||
rgthree.queueOutputNode(this.id);
|
||||
},
|
||||
};
|
||||
const idx = options.findIndex(o => o?.content === "Outputs") + 1 || options.length - 1;
|
||||
options.splice(idx, 0, menuItem);
|
||||
};
|
||||
}
|
||||
async setup() {
|
||||
console.log("rgthree-menu-setup");
|
||||
|
||||
const getCanvasMenuOptions = LGraphCanvas.prototype.getCanvasMenuOptions;
|
||||
LGraphCanvas.prototype.getCanvasMenuOptions = function (...args: any[]) {
|
||||
const options = getCanvasMenuOptions.apply(this, [...args] as any);
|
||||
showQueueNodesMenuIfOutputNodesAreSelected(options);
|
||||
return options;
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -221,10 +221,6 @@
|
||||
@import '../common/css/buttons.scss';
|
||||
@import '../common/css/dialog.scss';
|
||||
|
||||
body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-container) {
|
||||
filter: blur(5px);
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -271,7 +267,7 @@ body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-cont
|
||||
.rgthree-dialog.-settings .fieldrow ~ .fieldrow label {
|
||||
padding-left: 28px;
|
||||
}
|
||||
.rgthree-dialog.-settings .fieldrow:not(.-checked) ~ .fieldrow {
|
||||
.rgthree-dialog.-settings .fieldrow:first-child:not(.-checked) ~ .fieldrow {
|
||||
display: none;
|
||||
}
|
||||
.rgthree-dialog.-settings .fieldrow:hover {
|
||||
|
||||
@@ -32,6 +32,14 @@ export enum LogLevel {
|
||||
DEBUG,
|
||||
}
|
||||
|
||||
const LogLevelKeyToLogLevel: { [key: string]: LogLevel } = {
|
||||
IMPORTANT: LogLevel.IMPORTANT,
|
||||
ERROR: LogLevel.ERROR,
|
||||
WARN: LogLevel.WARN,
|
||||
INFO: LogLevel.INFO,
|
||||
DEBUG: LogLevel.DEBUG,
|
||||
};
|
||||
|
||||
type ConsoleLogFns = "log" | "error" | "warn" | "debug" | "info";
|
||||
const LogLevelToMethod: { [key in LogLevel]: ConsoleLogFns } = {
|
||||
[LogLevel.IMPORTANT]: "log",
|
||||
@@ -41,14 +49,14 @@ const LogLevelToMethod: { [key in LogLevel]: ConsoleLogFns } = {
|
||||
[LogLevel.DEBUG]: "debug",
|
||||
};
|
||||
const LogLevelToCSS: { [key in LogLevel]: string } = {
|
||||
[LogLevel.IMPORTANT]: "font-weight:bold; color:blue;",
|
||||
[LogLevel.IMPORTANT]: "font-weight: bold; color: blue;",
|
||||
[LogLevel.ERROR]: "",
|
||||
[LogLevel.WARN]: "",
|
||||
[LogLevel.INFO]: "",
|
||||
[LogLevel.DEBUG]: "font-style: italic;",
|
||||
[LogLevel.INFO]: "font-style: italic; color: blue;",
|
||||
[LogLevel.DEBUG]: "font-style: italic; color: #333;",
|
||||
};
|
||||
|
||||
let GLOBAL_LOG_LEVEL = LogLevel.DEBUG;
|
||||
let GLOBAL_LOG_LEVEL = LogLevel.ERROR;
|
||||
|
||||
/** A basic wrapper around logger. */
|
||||
class Logger {
|
||||
@@ -113,6 +121,10 @@ class LogSession {
|
||||
this.log(LogLevel.INFO, message, ...args);
|
||||
}
|
||||
|
||||
infoParts(message?: string, ...args: any[]) {
|
||||
return this.logParts(LogLevel.INFO, message, ...args);
|
||||
}
|
||||
|
||||
error(message?: string, ...args: any[]) {
|
||||
this.log(LogLevel.ERROR, message, ...args);
|
||||
}
|
||||
@@ -145,7 +157,7 @@ class Rgthree extends EventTarget {
|
||||
private progressBarEl: RgthreeProgressBar | null = null;
|
||||
|
||||
/** Stores a node id that we will use to queu only that output node (with `queueOutputNode`). */
|
||||
private queueNodeId: number | null = null;
|
||||
private queueNodeIds: number[] | null = null;
|
||||
|
||||
/** Are any functional keys pressed in this given moment? */
|
||||
ctrlKey = false;
|
||||
@@ -170,6 +182,11 @@ class Rgthree extends EventTarget {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
const logLevel =
|
||||
LogLevelKeyToLogLevel[CONFIG_SERVICE.getConfigValue("log_level")] ?? GLOBAL_LOG_LEVEL;
|
||||
this.setLogLevel(logLevel);
|
||||
|
||||
window.addEventListener("keydown", (e) => {
|
||||
this.handleKeydown(e);
|
||||
});
|
||||
@@ -246,6 +263,13 @@ class Rgthree extends EventTarget {
|
||||
const fontSize = Math.max(10, Number(height) - 10);
|
||||
this.progressBarEl.style.fontSize = `${fontSize}px`;
|
||||
this.progressBarEl.style.fontWeight = fontSize <= 12 ? "bold" : "normal";
|
||||
if (CONFIG_SERVICE.getConfigValue("features.progress_bar.position") === "bottom") {
|
||||
this.progressBarEl.style.bottom = `0px`;
|
||||
this.progressBarEl.style.top = `auto`;
|
||||
} else {
|
||||
this.progressBarEl.style.top = `0px`;
|
||||
this.progressBarEl.style.bottom = `auto`;
|
||||
}
|
||||
} else {
|
||||
this.progressBarEl?.remove();
|
||||
}
|
||||
@@ -393,17 +417,21 @@ class Rgthree extends EventTarget {
|
||||
|
||||
/**
|
||||
* Wraps an `app.queuePrompt` call setting a specific node id that we will inspect and change the
|
||||
* serialized graph when set (below, in our `graphToPrompt` override).
|
||||
* serialized graph right before being sent (below, in our `api.queuePrompt` override).
|
||||
*/
|
||||
async queueOutputNode(nodeId: number) {
|
||||
async queueOutputNodes(nodeIds: number[]) {
|
||||
try {
|
||||
this.queueNodeId = nodeId;
|
||||
this.queueNodeIds = nodeIds;
|
||||
await app.queuePrompt();
|
||||
} catch(e) {
|
||||
const [n, v] = this.logParts(LogLevel.ERROR, `There was an error queuing node #${nodeId}`, e);
|
||||
} catch (e) {
|
||||
const [n, v] = this.logParts(
|
||||
LogLevel.ERROR,
|
||||
`There was an error queuing nodes ${nodeIds}`,
|
||||
e,
|
||||
);
|
||||
console[n]?.(...v);
|
||||
} finally {
|
||||
this.queueNodeId = null;
|
||||
this.queueNodeIds = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,7 +452,6 @@ class Rgthree extends EventTarget {
|
||||
return newOutput;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a bunch of hooks into ComfyUI and/or LiteGraph itself so we can either keep state or
|
||||
* context on what's happening so nodes can respond appropriately. This is usually to fix broken
|
||||
@@ -464,18 +491,27 @@ class Rgthree extends EventTarget {
|
||||
app.graphToPrompt = async function () {
|
||||
rgthree.dispatchEvent(new CustomEvent("graph-to-prompt"));
|
||||
let promise = graphToPrompt.apply(app, [...arguments]);
|
||||
const result = (await promise as ComfyApiPrompt);
|
||||
// If queueNodeId is set, then we wonly want to queue one node. We'll capture that and rewrite
|
||||
// the api format, 'output' field.
|
||||
if (rgthree.queueNodeId != null) {
|
||||
const oldOutput = result.output;
|
||||
const newOutput = rgthree.recursiveAddNodes(String(rgthree.queueNodeId), oldOutput, {});
|
||||
result.output = newOutput;
|
||||
}
|
||||
await promise;
|
||||
rgthree.dispatchEvent(new CustomEvent("graph-to-prompt-end"));
|
||||
return promise;
|
||||
};
|
||||
|
||||
// Override the queuePrompt for api to intercept the prompt output and, if queueNodeIds is set,
|
||||
// then we only want to queue those nodes, by rewriting the api format (prompt 'output' field)
|
||||
// so only those are evaluated.
|
||||
const apiQueuePrompt = api.queuePrompt as Function;
|
||||
api.queuePrompt = async function (index: number, prompt: ComfyApiPrompt) {
|
||||
if (rgthree.queueNodeIds?.length && prompt.output) {
|
||||
const oldOutput = prompt.output;
|
||||
let newOutput = {};
|
||||
for (const queueNodeId of rgthree.queueNodeIds) {
|
||||
rgthree.recursiveAddNodes(String(queueNodeId), oldOutput, newOutput);
|
||||
}
|
||||
prompt.output = newOutput;
|
||||
}
|
||||
return apiQueuePrompt.apply(app, [index, prompt]);
|
||||
};
|
||||
|
||||
// Hook into a clean call; allow us to clear and rgthree messages.
|
||||
const clean = app.clean;
|
||||
app.clean = function () {
|
||||
|
||||
@@ -113,80 +113,3 @@ body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-cont
|
||||
filter: blur(5px);
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings {
|
||||
width: 100%;
|
||||
}
|
||||
.rgthree-dialog.-settings fieldset {
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
padding: 0 12px 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.rgthree-dialog.-settings fieldset > legend {
|
||||
margin-left: 8px;
|
||||
padding: 0 8px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.rgthree-dialog.-settings .formrow {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.rgthree-dialog.-settings .formrow + .formrow {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
.rgthree-dialog.-settings .fieldrow {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.rgthree-dialog.-settings .fieldrow > label {
|
||||
flex: 1 1 auto;
|
||||
user-select: none;
|
||||
padding: 8px 12px 12px;
|
||||
}
|
||||
.rgthree-dialog.-settings .fieldrow > label span {
|
||||
font-weight: bold;
|
||||
}
|
||||
.rgthree-dialog.-settings .fieldrow > label small {
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
font-size: calc(11rem / 16);
|
||||
opacity: 0.75;
|
||||
padding-left: 16px;
|
||||
}
|
||||
.rgthree-dialog.-settings .fieldrow ~ .fieldrow {
|
||||
font-size: 0.9rem;
|
||||
border-top: 1px dotted rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
.rgthree-dialog.-settings .fieldrow ~ .fieldrow label {
|
||||
padding-left: 28px;
|
||||
}
|
||||
.rgthree-dialog.-settings .fieldrow:not(.-checked) ~ .fieldrow {
|
||||
display: none;
|
||||
}
|
||||
.rgthree-dialog.-settings .fieldrow:hover {
|
||||
background: rgba(255,255,255,0.1);
|
||||
}
|
||||
.rgthree-dialog.-settings .fieldrow ~ .fieldrow span {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow > .fieldrow-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
flex: 0 0 auto;
|
||||
width: 50%;
|
||||
max-width: 230px;
|
||||
}
|
||||
.rgthree-dialog.-settings .fieldrow.-type-boolean > .fieldrow-value {
|
||||
max-width: 64px;
|
||||
}
|
||||
.rgthree-dialog.-settings .fieldrow.-type-number input {
|
||||
width: 48px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow input[type="checkbox"] {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ function getChild(value: any) : HTMLElement|DocumentFragment|Text|null {
|
||||
|
||||
|
||||
export function setAttribute(element: HTMLElement, attribute: string, value: any) {
|
||||
const isRemoving = value == null;
|
||||
let isRemoving = value == null;
|
||||
|
||||
if (attribute === 'default') {
|
||||
attribute = RGX_DEFAULT_VALUE_PROP.test(element.nodeName) ? 'value' : 'text';
|
||||
@@ -227,8 +227,13 @@ export function setAttribute(element: HTMLElement, attribute: string, value: any
|
||||
}
|
||||
|
||||
} else if (['checked', 'disabled', 'readonly', 'required', 'selected'].includes(attribute)) {
|
||||
// Could be input, button, etc. We are not discriminate.
|
||||
(element as HTMLInputElement)[attribute as 'checked'] = !!value;
|
||||
// Could be input, button, etc. We are not discriminate.
|
||||
(element as HTMLInputElement)[attribute as 'checked'] = !!value;
|
||||
if (!value) {
|
||||
(element as HTMLInputElement).removeAttribute(attribute);
|
||||
} else {
|
||||
(element as HTMLInputElement).setAttribute(attribute, attribute);
|
||||
}
|
||||
|
||||
} else if (DIRECT_ATTRIBUTE_MAP.hasOwnProperty(attribute)) {
|
||||
if (isRemoving) {
|
||||
|
||||
@@ -37,8 +37,28 @@ const CONFIGURABLE = {
|
||||
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.menu_queue_selected_nodes",
|
||||
type: ConfigType.BOOLEAN,
|
||||
label: "(Menu) 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: "(Menu) Auto Nest Subdirectories",
|
||||
description: "When a large, flat list of values contain sub-directories, auto nest them. (Like, for " +
|
||||
"a large list of checkpoints).",
|
||||
},
|
||||
{
|
||||
key: "features.show_alerts_for_corrupt_workflows",
|
||||
type: ConfigType.BOOLEAN,
|
||||
@@ -49,6 +69,7 @@ const CONFIGURABLE = {
|
||||
],
|
||||
};
|
||||
function fieldrow(item) {
|
||||
var _a;
|
||||
const initialValue = CONFIG_SERVICE.getConfigValue(item.key);
|
||||
const container = $el(`div.fieldrow.-type-${TYPE_TO_STRING[item.type]}`, {
|
||||
dataset: {
|
||||
@@ -65,17 +86,28 @@ function fieldrow(item) {
|
||||
parent: container,
|
||||
});
|
||||
let input;
|
||||
if (item.type === ConfigType.BOOLEAN) {
|
||||
if ((_a = item.options) === null || _a === void 0 ? void 0 : _a.length) {
|
||||
input = $el(`select[id="${item.key}"]`, {
|
||||
parent: container,
|
||||
children: item.options.map((o) => {
|
||||
return $el(`option[value="${String(o)}"]`, {
|
||||
text: String(o),
|
||||
selected: o === initialValue,
|
||||
});
|
||||
}),
|
||||
});
|
||||
}
|
||||
else if (item.type === ConfigType.BOOLEAN) {
|
||||
container.classList.toggle("-checked", initialValue);
|
||||
input = $el(`input[type="checkbox"][id="${item.key}"]`, {
|
||||
checked: initialValue,
|
||||
parent: container,
|
||||
checked: initialValue,
|
||||
});
|
||||
}
|
||||
else {
|
||||
input = $el(`input[id="${item.key}"]`, {
|
||||
value: initialValue,
|
||||
parent: container,
|
||||
value: initialValue,
|
||||
});
|
||||
}
|
||||
$el("div.fieldrow-value", { children: [input], parent: container });
|
||||
@@ -152,7 +184,7 @@ export class RgthreeConfigDialog extends RgthreeDialog {
|
||||
const name = el.dataset["name"];
|
||||
const type = el.dataset["type"];
|
||||
const initialValue = CONFIG_SERVICE.getConfigValue(name);
|
||||
let currentValueEl = $$("input, textarea", el)[0];
|
||||
let currentValueEl = $$("input, textarea, select", el)[0];
|
||||
let currentValue = null;
|
||||
if (type === String(ConfigType.BOOLEAN)) {
|
||||
currentValue = currentValueEl.checked;
|
||||
|
||||
@@ -1,22 +1,50 @@
|
||||
import { app } from "../../scripts/app.js";
|
||||
import { rgthree } from "./rgthree.js";
|
||||
import { SERVICE as CONFIG_SERVICE } from "./config_service.js";
|
||||
function getOutputNodesFromSelected(canvas) {
|
||||
return ((canvas.selected_nodes &&
|
||||
Object.values(canvas.selected_nodes).filter((n) => {
|
||||
var _a;
|
||||
return (n.mode != LiteGraph.NEVER &&
|
||||
((_a = n.constructor.nodeData) === null || _a === void 0 ? void 0 : _a.output_node));
|
||||
})) ||
|
||||
[]);
|
||||
}
|
||||
function showQueueNodesMenuIfOutputNodesAreSelected(existingOptions, node) {
|
||||
if (CONFIG_SERVICE.getConfigValue("features.menu_queue_selected_nodes") != false) {
|
||||
const canvas = app.canvas;
|
||||
const outputNodes = getOutputNodesFromSelected(canvas);
|
||||
const menuItem = {
|
||||
content: `Queue Selected Output Nodes (rgthree) `,
|
||||
className: "rgthree-contextmenu-item",
|
||||
callback: () => {
|
||||
rgthree.queueOutputNodes(outputNodes.map((n) => n.id));
|
||||
},
|
||||
disabled: !outputNodes.length,
|
||||
};
|
||||
let idx = existingOptions.findIndex((o) => (o === null || o === void 0 ? void 0 : o.content) === "Outputs") + 1;
|
||||
idx = idx || existingOptions.findIndex((o) => (o === null || o === void 0 ? void 0 : o.content) === "Align") + 1;
|
||||
idx = idx || 3;
|
||||
existingOptions.splice(idx, 0, menuItem);
|
||||
}
|
||||
return existingOptions;
|
||||
}
|
||||
app.registerExtension({
|
||||
name: "rgthree.QueueNode",
|
||||
async beforeRegisterNodeDef(nodeType, nodeData) {
|
||||
if (nodeData.output_node == true) {
|
||||
const getExtraMenuOptions = nodeType.prototype.getExtraMenuOptions;
|
||||
nodeType.prototype.getExtraMenuOptions = function (canvas, options) {
|
||||
getExtraMenuOptions ? getExtraMenuOptions.apply(this, arguments) : undefined;
|
||||
const menuItem = {
|
||||
content: `Queue Node (rgthree)`,
|
||||
className: "rgthree-contextmenu-item",
|
||||
callback: () => {
|
||||
rgthree.queueOutputNode(this.id);
|
||||
},
|
||||
};
|
||||
const idx = options.findIndex(o => (o === null || o === void 0 ? void 0 : o.content) === "Outputs") + 1 || options.length - 1;
|
||||
options.splice(idx, 0, menuItem);
|
||||
};
|
||||
}
|
||||
const getExtraMenuOptions = nodeType.prototype.getExtraMenuOptions;
|
||||
nodeType.prototype.getExtraMenuOptions = function (canvas, options) {
|
||||
getExtraMenuOptions ? getExtraMenuOptions.apply(this, arguments) : undefined;
|
||||
showQueueNodesMenuIfOutputNodesAreSelected(options, this);
|
||||
};
|
||||
},
|
||||
async setup() {
|
||||
console.log("rgthree-menu-setup");
|
||||
const getCanvasMenuOptions = LGraphCanvas.prototype.getCanvasMenuOptions;
|
||||
LGraphCanvas.prototype.getCanvasMenuOptions = function (...args) {
|
||||
const options = getCanvasMenuOptions.apply(this, [...args]);
|
||||
showQueueNodesMenuIfOutputNodesAreSelected(options);
|
||||
return options;
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -481,104 +481,7 @@ body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-cont
|
||||
padding-left: 28px;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow:not(.-checked) ~ .fieldrow {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow ~ .fieldrow span {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow > .fieldrow-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
flex: 0 0 auto;
|
||||
width: 50%;
|
||||
max-width: 230px;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow.-type-boolean > .fieldrow-value {
|
||||
max-width: 64px;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow.-type-number input {
|
||||
width: 48px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow input[type=checkbox] {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-container) {
|
||||
filter: blur(5px);
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings fieldset {
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
padding: 0 12px 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings fieldset > legend {
|
||||
margin-left: 8px;
|
||||
padding: 0 8px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .formrow {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .formrow + .formrow {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow > label {
|
||||
flex: 1 1 auto;
|
||||
user-select: none;
|
||||
padding: 8px 12px 12px;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow > label span {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow > label small {
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
font-size: 0.6875rem;
|
||||
opacity: 0.75;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow ~ .fieldrow {
|
||||
font-size: 0.9rem;
|
||||
border-top: 1px dotted rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow ~ .fieldrow label {
|
||||
padding-left: 28px;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow:not(.-checked) ~ .fieldrow {
|
||||
.rgthree-dialog.-settings .fieldrow:first-child:not(.-checked) ~ .fieldrow {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,13 @@ export var LogLevel;
|
||||
LogLevel[LogLevel["INFO"] = 4] = "INFO";
|
||||
LogLevel[LogLevel["DEBUG"] = 5] = "DEBUG";
|
||||
})(LogLevel || (LogLevel = {}));
|
||||
const LogLevelKeyToLogLevel = {
|
||||
IMPORTANT: LogLevel.IMPORTANT,
|
||||
ERROR: LogLevel.ERROR,
|
||||
WARN: LogLevel.WARN,
|
||||
INFO: LogLevel.INFO,
|
||||
DEBUG: LogLevel.DEBUG,
|
||||
};
|
||||
const LogLevelToMethod = {
|
||||
[LogLevel.IMPORTANT]: "log",
|
||||
[LogLevel.ERROR]: "error",
|
||||
@@ -24,13 +31,13 @@ const LogLevelToMethod = {
|
||||
[LogLevel.DEBUG]: "debug",
|
||||
};
|
||||
const LogLevelToCSS = {
|
||||
[LogLevel.IMPORTANT]: "font-weight:bold; color:blue;",
|
||||
[LogLevel.IMPORTANT]: "font-weight: bold; color: blue;",
|
||||
[LogLevel.ERROR]: "",
|
||||
[LogLevel.WARN]: "",
|
||||
[LogLevel.INFO]: "",
|
||||
[LogLevel.DEBUG]: "font-style: italic;",
|
||||
[LogLevel.INFO]: "font-style: italic; color: blue;",
|
||||
[LogLevel.DEBUG]: "font-style: italic; color: #333;",
|
||||
};
|
||||
let GLOBAL_LOG_LEVEL = LogLevel.DEBUG;
|
||||
let GLOBAL_LOG_LEVEL = LogLevel.ERROR;
|
||||
class Logger {
|
||||
log(level, message, ...args) {
|
||||
var _a;
|
||||
@@ -69,6 +76,9 @@ class LogSession {
|
||||
info(message, ...args) {
|
||||
this.log(LogLevel.INFO, message, ...args);
|
||||
}
|
||||
infoParts(message, ...args) {
|
||||
return this.logParts(LogLevel.INFO, message, ...args);
|
||||
}
|
||||
error(message, ...args) {
|
||||
this.log(LogLevel.ERROR, message, ...args);
|
||||
}
|
||||
@@ -78,11 +88,12 @@ class LogSession {
|
||||
}
|
||||
class Rgthree extends EventTarget {
|
||||
constructor() {
|
||||
var _a;
|
||||
super();
|
||||
this.api = api;
|
||||
this.settingsDialog = null;
|
||||
this.progressBarEl = null;
|
||||
this.queueNodeId = null;
|
||||
this.queueNodeIds = null;
|
||||
this.ctrlKey = false;
|
||||
this.altKey = false;
|
||||
this.metaKey = false;
|
||||
@@ -97,6 +108,8 @@ class Rgthree extends EventTarget {
|
||||
this.canvasCurrentlyCopyingToClipboard = false;
|
||||
this.canvasCurrentlyCopyingToClipboardWithMultipleNodes = false;
|
||||
this.initialGraphToPromptSerializedWorkflowBecauseComfyUIBrokeStuff = null;
|
||||
const logLevel = (_a = LogLevelKeyToLogLevel[CONFIG_SERVICE.getConfigValue("log_level")]) !== null && _a !== void 0 ? _a : GLOBAL_LOG_LEVEL;
|
||||
this.setLogLevel(logLevel);
|
||||
window.addEventListener("keydown", (e) => {
|
||||
this.handleKeydown(e);
|
||||
});
|
||||
@@ -161,6 +174,14 @@ class Rgthree extends EventTarget {
|
||||
const fontSize = Math.max(10, Number(height) - 10);
|
||||
this.progressBarEl.style.fontSize = `${fontSize}px`;
|
||||
this.progressBarEl.style.fontWeight = fontSize <= 12 ? "bold" : "normal";
|
||||
if (CONFIG_SERVICE.getConfigValue("features.progress_bar.position") === "bottom") {
|
||||
this.progressBarEl.style.bottom = `0px`;
|
||||
this.progressBarEl.style.top = `auto`;
|
||||
}
|
||||
else {
|
||||
this.progressBarEl.style.top = `0px`;
|
||||
this.progressBarEl.style.bottom = `auto`;
|
||||
}
|
||||
}
|
||||
else {
|
||||
(_a = this.progressBarEl) === null || _a === void 0 ? void 0 : _a.remove();
|
||||
@@ -270,18 +291,18 @@ class Rgthree extends EventTarget {
|
||||
},
|
||||
];
|
||||
}
|
||||
async queueOutputNode(nodeId) {
|
||||
async queueOutputNodes(nodeIds) {
|
||||
var _a;
|
||||
try {
|
||||
this.queueNodeId = nodeId;
|
||||
this.queueNodeIds = nodeIds;
|
||||
await app.queuePrompt();
|
||||
}
|
||||
catch (e) {
|
||||
const [n, v] = this.logParts(LogLevel.ERROR, `There was an error queuing node #${nodeId}`, e);
|
||||
const [n, v] = this.logParts(LogLevel.ERROR, `There was an error queuing nodes ${nodeIds}`, e);
|
||||
(_a = console[n]) === null || _a === void 0 ? void 0 : _a.call(console, ...v);
|
||||
}
|
||||
finally {
|
||||
this.queueNodeId = null;
|
||||
this.queueNodeIds = null;
|
||||
}
|
||||
}
|
||||
recursiveAddNodes(nodeId, oldOutput, newOutput) {
|
||||
@@ -325,15 +346,23 @@ class Rgthree extends EventTarget {
|
||||
app.graphToPrompt = async function () {
|
||||
rgthree.dispatchEvent(new CustomEvent("graph-to-prompt"));
|
||||
let promise = graphToPrompt.apply(app, [...arguments]);
|
||||
const result = await promise;
|
||||
if (rgthree.queueNodeId != null) {
|
||||
const oldOutput = result.output;
|
||||
const newOutput = rgthree.recursiveAddNodes(String(rgthree.queueNodeId), oldOutput, {});
|
||||
result.output = newOutput;
|
||||
}
|
||||
await promise;
|
||||
rgthree.dispatchEvent(new CustomEvent("graph-to-prompt-end"));
|
||||
return promise;
|
||||
};
|
||||
const apiQueuePrompt = api.queuePrompt;
|
||||
api.queuePrompt = async function (index, prompt) {
|
||||
var _a;
|
||||
if (((_a = rgthree.queueNodeIds) === null || _a === void 0 ? void 0 : _a.length) && prompt.output) {
|
||||
const oldOutput = prompt.output;
|
||||
let newOutput = {};
|
||||
for (const queueNodeId of rgthree.queueNodeIds) {
|
||||
rgthree.recursiveAddNodes(String(queueNodeId), oldOutput, newOutput);
|
||||
}
|
||||
prompt.output = newOutput;
|
||||
}
|
||||
return apiQueuePrompt.apply(app, [index, prompt]);
|
||||
};
|
||||
const clean = app.clean;
|
||||
app.clean = function () {
|
||||
rgthree.clearAllMessages();
|
||||
|
||||
@@ -114,96 +114,3 @@
|
||||
body.rgthree-dialog-open > *:not(.rgthree-dialog):not(.rgthree-top-messages-container) {
|
||||
filter: blur(5px);
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings fieldset {
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
padding: 0 12px 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings fieldset > legend {
|
||||
margin-left: 8px;
|
||||
padding: 0 8px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .formrow {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .formrow + .formrow {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow > label {
|
||||
flex: 1 1 auto;
|
||||
user-select: none;
|
||||
padding: 8px 12px 12px;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow > label span {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow > label small {
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
font-size: 0.6875rem;
|
||||
opacity: 0.75;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow ~ .fieldrow {
|
||||
font-size: 0.9rem;
|
||||
border-top: 1px dotted rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow ~ .fieldrow label {
|
||||
padding-left: 28px;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow:not(.-checked) ~ .fieldrow {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow ~ .fieldrow span {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow > .fieldrow-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
flex: 0 0 auto;
|
||||
width: 50%;
|
||||
max-width: 230px;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow.-type-boolean > .fieldrow-value {
|
||||
max-width: 64px;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow.-type-number input {
|
||||
width: 48px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.rgthree-dialog.-settings .fieldrow input[type=checkbox] {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ function getChild(value) {
|
||||
return null;
|
||||
}
|
||||
export function setAttribute(element, attribute, value) {
|
||||
const isRemoving = value == null;
|
||||
let isRemoving = value == null;
|
||||
if (attribute === 'default') {
|
||||
attribute = RGX_DEFAULT_VALUE_PROP.test(element.nodeName) ? 'value' : 'text';
|
||||
}
|
||||
@@ -205,6 +205,12 @@ export function setAttribute(element, attribute, value) {
|
||||
}
|
||||
else if (['checked', 'disabled', 'readonly', 'required', 'selected'].includes(attribute)) {
|
||||
element[attribute] = !!value;
|
||||
if (!value) {
|
||||
element.removeAttribute(attribute);
|
||||
}
|
||||
else {
|
||||
element.setAttribute(attribute, attribute);
|
||||
}
|
||||
}
|
||||
else if (DIRECT_ATTRIBUTE_MAP.hasOwnProperty(attribute)) {
|
||||
if (isRemoving) {
|
||||
|
||||
Reference in New Issue
Block a user