Prompt travel

This commit is contained in:
space-nuko
2023-06-03 00:38:09 -05:00
parent ab6266704c
commit b3f2f9093f
22 changed files with 187 additions and 69 deletions

View File

@@ -40,6 +40,7 @@ import { deserializeTemplateFromSVG, type SerializedComfyBoxTemplate } from "$li
import templateState from "$lib/stores/templateState"; import templateState from "$lib/stores/templateState";
import { formatValidationError, type ComfyAPIPromptErrorResponse, formatExecutionError, type ComfyExecutionError } from "$lib/apiErrors"; import { formatValidationError, type ComfyAPIPromptErrorResponse, formatExecutionError, type ComfyExecutionError } from "$lib/apiErrors";
import systemState from "$lib/stores/systemState"; import systemState from "$lib/stores/systemState";
import type { JourneyNode } from "$lib/stores/journeyStates";
export const COMFYBOX_SERIAL_VERSION = 1; export const COMFYBOX_SERIAL_VERSION = 1;
@@ -610,6 +611,7 @@ export default class ComfyApp {
if (node?.onExecuted) { if (node?.onExecuted) {
node.onExecuted(output); node.onExecuted(output);
} }
workflow.journey.onExecuted(promptID, nodeID, output, queueEntry);
} }
} }
}); });
@@ -1028,6 +1030,15 @@ export default class ComfyApp {
notify("Prompt queued.", { type: "info", showOn: "web" }); notify("Prompt queued.", { type: "info", showOn: "web" });
} }
let journeyNode: JourneyNode | null;
if (get(uiState).autoPushJourney) {
const activeNode = targetWorkflow.journey.getActiveNode();
if (activeNode != null) {
journeyNode = targetWorkflow.journey.pushPatchOntoActive(targetWorkflow, activeNode);
}
}
this.processingQueue = true; this.processingQueue = true;
let workflow: ComfyBoxWorkflow; let workflow: ComfyBoxWorkflow;
@@ -1097,6 +1108,9 @@ export default class ComfyApp {
else { else {
queueState.afterQueued(workflow.id, response.promptID, response.number, p.output, extraData) queueState.afterQueued(workflow.id, response.promptID, response.number, p.output, extraData)
workflowState.afterQueued(workflow.id, response.promptID) workflowState.afterQueued(workflow.id, response.promptID)
if (journeyNode != null) {
journeyNode.promptID = response.promptID;
}
} }
} catch (err) { } catch (err) {
errorMes = err?.toString(); errorMes = err?.toString();

View File

@@ -7,12 +7,14 @@
import type ComfyApp from './ComfyApp'; import type ComfyApp from './ComfyApp';
import type { ComfyBoxWorkflow } from '$lib/stores/workflowState'; import type { ComfyBoxWorkflow } from '$lib/stores/workflowState';
import workflowState from '$lib/stores/workflowState'; import workflowState from '$lib/stores/workflowState';
import { calculateWorkflowParamsPatch, resolvePatch, type JourneyPatchNode, type WritableJourneyStateStore } from '$lib/stores/journeyStates'; import uiState from '$lib/stores/uiState';
import { calculateWorkflowParamsPatch, resolvePatch, type JourneyPatchNode, type WritableJourneyStateStore, diffParams } from '$lib/stores/journeyStates';
import JourneyRenderer from './JourneyRenderer.svelte'; import JourneyRenderer from './JourneyRenderer.svelte';
import { Plus } from "svelte-bootstrap-icons"; import { Plus } from "svelte-bootstrap-icons";
import { getWorkflowRestoreParams, getWorkflowRestoreParamsFromWorkflow } from '$lib/restoreParameters'; import { getWorkflowRestoreParams, getWorkflowRestoreParamsFromWorkflow } from '$lib/restoreParameters';
import notify from '$lib/notify'; import notify from '$lib/notify';
import selectionState from '$lib/stores/selectionState'; import selectionState from '$lib/stores/selectionState';
import { Checkbox } from '@gradio/form';
export let app: ComfyApp; export let app: ComfyApp;
@@ -30,32 +32,7 @@
const workflowParams = getWorkflowRestoreParamsFromWorkflow(workflow) const workflowParams = getWorkflowRestoreParamsFromWorkflow(workflow)
const activeNode = journey.getActiveNode(); const activeNode = journey.getActiveNode();
journey.pushPatchOntoActive(workflow, activeNode, true)
let journeyNode
if (activeNode == null) {
// add root node
if ($journey.root != null) {
return;
}
journeyNode = journey.addNode(workflowParams, null);
notify("Pushed a new base workflow state.", { type: "info" })
}
else {
// add patch node
const patch = calculateWorkflowParamsPatch(activeNode, workflowParams);
const patchedCount = Object.keys(patch).length;
if (patchedCount === 0) {
notify("No changes were made to active parameters yet.", { type: "warning" })
return;
}
journeyNode = journey.addNode(patch, activeNode);
notify(`Pushed new state with ${patchedCount} changes.`, { type: "info" })
}
if (journeyNode != null) {
journey.selectNode(journeyNode);
}
} }
function onSelectNode(e: CustomEvent<{ cyto: cytoscape.Core, node: cytoscape.NodeSingular }>) { function onSelectNode(e: CustomEvent<{ cyto: cytoscape.Core, node: cytoscape.NodeSingular }>) {
@@ -85,12 +62,11 @@
return; return;
} }
if (journeyNode.type === "patch") { const patch = resolvePatch(journeyNode);
$selectionState.currentPatchHoveredNodes = new Set(Object.keys((journeyNode as JourneyPatchNode).patch)) const workflowParams = getWorkflowRestoreParamsFromWorkflow(workflow);
} const diff = diffParams(patch, workflowParams);
else {
$selectionState.currentPatchHoveredNodes = new Set(); $selectionState.currentPatchHoveredNodes = new Set(Object.keys(diff));
}
} }
function onHoverNodeOut(e: CustomEvent<{ cyto: cytoscape.Core, node: cytoscape.NodeSingular }>) { function onHoverNodeOut(e: CustomEvent<{ cyto: cytoscape.Core, node: cytoscape.NodeSingular }>) {
@@ -104,6 +80,9 @@
on:hover_node={onHoverNode} on:hover_node={onHoverNode}
on:hover_node_out={onHoverNodeOut} on:hover_node_out={onHoverNodeOut}
/> />
<div class="bottom" style:border-top="1px solid var(--panel-border-color)">
<Checkbox label="Auto-Push" disabled={$journey.root == null} bind:value={$uiState.autoPushJourney}/>
</div>
<div class="bottom"> <div class="bottom">
<button class="mode-button ternary" <button class="mode-button ternary"
title={"Add new"} title={"Add new"}
@@ -119,7 +98,7 @@
.journey-view { .journey-view {
width: 100%; width: 100%;
height: calc(100% - $button-height); height: calc(100% - $button-height * 2);
} }
.bottom { .bottom {
@@ -127,6 +106,7 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
color: var(--comfy-accent-soft); color: var(--comfy-accent-soft);
justify-content: center;
.mode-button { .mode-button {
height: 100%; height: 100%;

View File

@@ -6,6 +6,7 @@
import type { NodeDataDefinition, EdgeDataDefinition } from 'cytoscape'; import type { NodeDataDefinition, EdgeDataDefinition } from 'cytoscape';
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import selectionState from '$lib/stores/selectionState'; import selectionState from '$lib/stores/selectionState';
import uiQueueState from '$lib/stores/uiQueueState';
export let workflow: ComfyBoxWorkflow | null = null export let workflow: ComfyBoxWorkflow | null = null
export let journey: WritableJourneyStateStore | null = null export let journey: WritableJourneyStateStore | null = null
@@ -52,7 +53,7 @@
const patchNode = node as JourneyPatchNode; const patchNode = node as JourneyPatchNode;
nodes.push({ nodes.push({
id: patchNode.id, id: patchNode.id,
label: "N", label: "P",
selected: node.id === journeyState.activeNodeID, selected: node.id === journeyState.activeNodeID,
locked: true locked: true
@@ -101,9 +102,22 @@
const { cyto } = e.detail; const { cyto } = e.detail;
for (const node of cyto.nodes().components()) { for (const node of cyto.nodes().components()) {
if (node.id() === lastSelected) { const nodeID = node.id()
if (nodeID === lastSelected) {
// why doesn't passing `selected` work in the ctor? // why doesn't passing `selected` work in the ctor?
node.select(); node.select();
cyto.zoom(1.25);
cyto.center(node)
}
const journeyNode = $journey.nodesByID[nodeID]
if (journeyNode) {
if (journeyNode.promptID != null) {
const queueEntry = $uiQueueState.historyUIEntries.find(e => e.entry.promptID === journeyNode.promptID)
if (queueEntry != null && queueEntry.images) {
node.data("bgImage", queueEntry.images[0]);
}
}
} }
} }
@@ -114,13 +128,6 @@
.on("select", onNodeSelected) .on("select", onNodeSelected)
.on("mouseover", onNodeHovered) .on("mouseover", onNodeHovered)
.on("mouseout", onNodeHoveredOut) .on("mouseout", onNodeHoveredOut)
const nodes = Array.from(journey.iterateBreadthFirst());
if (nodes.length > 0) {
const lastNode = nodes[nodes.length - 1]
const start = cyto.$(`#${lastNode.id}`)
cyto.center(start)
}
} }
</script> </script>

View File

@@ -37,7 +37,7 @@
container: refElement, container: refElement,
style: GraphStyles, style: GraphStyles,
wheelSensitivity: 0.1, wheelSensitivity: 0.1,
maxZoom: 1, maxZoom: 3,
minZoom: 0.5, minZoom: 0.5,
}) })

View File

@@ -18,8 +18,9 @@ const styles: Stylesheet[] = [
{ {
selector: "node", selector: "node",
style: { style: {
"width": "50", "width": "100",
"height": "50", "height": "100",
"shape": "round-rectangle",
"font-family": "Arial", "font-family": "Arial",
"font-size": "18", "font-size": "18",
"font-weight": "normal", "font-weight": "normal",
@@ -33,6 +34,16 @@ const styles: Stylesheet[] = [
"color": "#1d3660" "color": "#1d3660"
} }
}, },
{
selector: "node[bgImage]",
style: {
"label": "",
"background-image": "data(bgImage)",
"background-image-containment": "over",
"background-fit": "cover",
"color": "transparent"
}
},
{ {
selector: "node:selected", selector: "node:selected",
style: { style: {

View File

@@ -11,6 +11,7 @@ export default class ComfyButtonNode extends ComfyWidgetNode<boolean> {
override properties: ComfyButtonProperties = { override properties: ComfyButtonProperties = {
tags: [], tags: [],
defaultValue: false, defaultValue: false,
excludeFromJourney: true,
param: "bang" param: "bang"
} }

View File

@@ -11,6 +11,7 @@ export default class ComfyCheckboxNode extends ComfyWidgetNode<boolean> {
override properties: ComfyCheckboxProperties = { override properties: ComfyCheckboxProperties = {
tags: [], tags: [],
defaultValue: false, defaultValue: false,
excludeFromJourney: false,
} }
static slotLayout: SlotLayout = { static slotLayout: SlotLayout = {

View File

@@ -19,7 +19,8 @@ export default class ComfyComboNode extends ComfyWidgetNode<string> {
tags: [], tags: [],
defaultValue: "A", defaultValue: "A",
values: ["A", "B", "C", "D"], values: ["A", "B", "C", "D"],
convertValueToLabelCode: "" convertValueToLabelCode: "",
excludeFromJourney: false,
} }
static slotLayout: SlotLayout = { static slotLayout: SlotLayout = {

View File

@@ -18,7 +18,8 @@ export default class ComfyGalleryNode extends ComfyWidgetNode<ComfyBoxImageMetad
defaultValue: [], defaultValue: [],
index: 0, index: 0,
updateMode: "replace", updateMode: "replace",
autoSelectOnUpdate: true autoSelectOnUpdate: true,
excludeFromJourney: true,
} }
static slotLayout: SlotLayout = { static slotLayout: SlotLayout = {
@@ -130,8 +131,6 @@ export default class ComfyGalleryNode extends ComfyWidgetNode<ComfyBoxImageMetad
const meta = parseWhateverIntoImageMetadata(param) || []; const meta = parseWhateverIntoImageMetadata(param) || [];
console.debug("[ComfyGalleryNode] Received output!", param)
if (updateMode === "append") { if (updateMode === "append") {
const currentValue = get(this.value) const currentValue = get(this.value)
if (meta.length > 0 && (selectedIndex != null || this.properties.autoSelectOnUpdate)) { if (meta.length > 0 && (selectedIndex != null || this.properties.autoSelectOnUpdate)) {

View File

@@ -6,7 +6,6 @@ import ImageUploadWidget from "$lib/widgets/ImageUploadWidget.svelte";
import type { ComfyWidgetProperties } from "./ComfyWidgetNode"; import type { ComfyWidgetProperties } from "./ComfyWidgetNode";
import ComfyWidgetNode from "./ComfyWidgetNode"; import ComfyWidgetNode from "./ComfyWidgetNode";
import { get, writable, type Writable } from "svelte/store"; import { get, writable, type Writable } from "svelte/store";
import { type LineGroup } from "$lib/components/MaskCanvas.svelte"
export interface ComfyImageUploadNodeProperties extends ComfyWidgetProperties { export interface ComfyImageUploadNodeProperties extends ComfyWidgetProperties {
maskCount: number maskCount: number
@@ -16,7 +15,8 @@ export default class ComfyImageUploadNode extends ComfyWidgetNode<ComfyBoxImageM
properties: ComfyImageUploadNodeProperties = { properties: ComfyImageUploadNodeProperties = {
defaultValue: [], defaultValue: [],
tags: [], tags: [],
maskCount: 0 maskCount: 0,
excludeFromJourney: true,
} }
static slotLayout: SlotLayout = { static slotLayout: SlotLayout = {

View File

@@ -10,6 +10,7 @@ export default class ComfyMarkdownNode extends ComfyWidgetNode<string> {
override properties: ComfyMarkdownProperties = { override properties: ComfyMarkdownProperties = {
tags: [], tags: [],
defaultValue: false, defaultValue: false,
excludeFromJourney: true,
} }
static slotLayout: SlotLayout = { static slotLayout: SlotLayout = {

View File

@@ -30,7 +30,8 @@ export default class ComfyMultiRegionNode extends ComfyWidgetNode<BoundingBox[]>
canvasWidth: 512, canvasWidth: 512,
canvasHeight: 512, canvasHeight: 512,
canvasImageURL: null, canvasImageURL: null,
inputType: "size" inputType: "size",
excludeFromJourney: false,
} }
static slotLayout: SlotLayout = { static slotLayout: SlotLayout = {

View File

@@ -20,7 +20,8 @@ export default class ComfyNumberNode extends ComfyWidgetNode<number> {
min: 0, min: 0,
max: 10, max: 10,
step: 1, step: 1,
precision: 1 precision: 1,
excludeFromJourney: false,
} }
override svelteComponentType = NumberWidget override svelteComponentType = NumberWidget

View File

@@ -16,6 +16,7 @@ export default class ComfyRadioNode extends ComfyWidgetNode<string> {
tags: [], tags: [],
choices: ["Choice A", "Choice B", "Choice C"], choices: ["Choice A", "Choice B", "Choice C"],
defaultValue: "Choice A", defaultValue: "Choice A",
excludeFromJourney: false,
} }
static slotLayout: SlotLayout = { static slotLayout: SlotLayout = {

View File

@@ -16,6 +16,7 @@ export default class ComfyTextNode extends ComfyWidgetNode<string> {
multiline: false, multiline: false,
lines: 5, lines: 5,
maxLines: 5, maxLines: 5,
excludeFromJourney: false,
} }
static slotLayout: SlotLayout = { static slotLayout: SlotLayout = {

View File

@@ -37,7 +37,8 @@ export type SerializedComfyWidgetNode = {
*/ */
export interface ComfyWidgetProperties extends ComfyGraphNodeProperties { export interface ComfyWidgetProperties extends ComfyGraphNodeProperties {
defaultValue: any defaultValue: any,
excludeFromJourney: boolean
} }
export type ShownOutputProperty = { export type ShownOutputProperty = {

View File

@@ -162,13 +162,16 @@ export function concatRestoreParams2(a: RestoreParamTargets, b: RestoreParamTarg
/* /*
* Like getWorkflowRestoreParams but applies to an instanced (non-serialized) workflow * Like getWorkflowRestoreParams but applies to an instanced (non-serialized) workflow
*/ */
export function getWorkflowRestoreParamsFromWorkflow(workflow: ComfyBoxWorkflow): RestoreParamWorkflowNodeTargets { export function getWorkflowRestoreParamsFromWorkflow(workflow: ComfyBoxWorkflow, noExclude: boolean = false): RestoreParamWorkflowNodeTargets {
const result = {} const result = {}
for (const node of workflow.graph.iterateNodesInOrderRecursive()) { for (const node of workflow.graph.iterateNodesInOrderRecursive()) {
if (!isComfyWidgetNode(node)) if (!isComfyWidgetNode(node))
continue; continue;
if (!noExclude && node.properties.excludeFromJourney)
continue;
const finalValue = node.getValue(); const finalValue = node.getValue();
if (finalValue != null) { if (finalValue != null) {
const source: RestoreParamSourceWorkflowNode = { const source: RestoreParamSourceWorkflowNode = {

View File

@@ -1,11 +1,16 @@
import { get, writable } from 'svelte/store'; import { get, writable } from 'svelte/store';
import type { Readable, Writable } from 'svelte/store'; import type { Readable, Writable } from 'svelte/store';
import type { DragItemID, IDragItem } from './layoutStates'; import { isComfyWidgetNode, type DragItemID, type IDragItem } from './layoutStates';
import { LiteGraph, type LGraphNode, type NodeID, type UUID } from '@litegraph-ts/core'; import { LiteGraph, type LGraphNode, type NodeID, type UUID } from '@litegraph-ts/core';
import type { SerializedAppState } from '$lib/components/ComfyApp'; import type { SerializedAppState } from '$lib/components/ComfyApp';
import type { RestoreParamTargets, RestoreParamWorkflowNodeTargets } from '$lib/restoreParameters'; import { getWorkflowRestoreParamsFromWorkflow, type RestoreParamSourceWorkflowNode, type RestoreParamTargets, type RestoreParamWorkflowNodeTargets } from '$lib/restoreParameters';
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import deepEqual from "deep-equal"; import deepEqual from "deep-equal";
import notify from '$lib/notify';
import type { ComfyBoxWorkflow } from './workflowState';
import type { ComfyNodeID, PromptID } from '$lib/api';
import type { SerializedPromptOutput } from '$lib/utils';
import type { QueueEntry } from './queueState';
export type JourneyNodeType = "root" | "patch"; export type JourneyNodeType = "root" | "patch";
@@ -14,7 +19,9 @@ export type JourneyNodeID = UUID;
export interface JourneyNode { export interface JourneyNode {
id: JourneyNodeID, id: JourneyNodeID,
type: JourneyNodeType, type: JourneyNodeType,
children: JourneyPatchNode[] children: JourneyPatchNode[],
promptID?: PromptID,
images?: string[]
} }
export interface JourneyRootNode extends JourneyNode { export interface JourneyRootNode extends JourneyNode {
@@ -52,7 +59,7 @@ export function resolvePatch(node: JourneyNode): RestoreParamWorkflowNodeTargets
return base; return base;
} }
function diffParams(base: RestoreParamWorkflowNodeTargets, updated: RestoreParamWorkflowNodeTargets): RestoreParamWorkflowNodeTargets { export function diffParams(base: RestoreParamWorkflowNodeTargets, updated: RestoreParamWorkflowNodeTargets): RestoreParamWorkflowNodeTargets {
const result = {} const result = {}
for (const [k, v] of Object.entries(updated)) { for (const [k, v] of Object.entries(updated)) {
@@ -89,9 +96,11 @@ export type JourneyState = {
type JourneyStateOps = { type JourneyStateOps = {
clear: () => void, clear: () => void,
getActiveNode: () => JourneyNode | null, getActiveNode: () => JourneyNode | null,
addNode: (params: RestoreParamWorkflowNodeTargets, parent?: JourneyNodeID | JourneyNode) => JourneyNode, // addNode: (params: RestoreParamWorkflowNodeTargets, parent?: JourneyNodeID | JourneyNode) => JourneyNode,
selectNode: (id?: JourneyNodeID | JourneyNode) => void, selectNode: (id?: JourneyNodeID | JourneyNode) => void,
iterateBreadthFirst: (id?: JourneyNodeID | null) => Iterable<JourneyNode> iterateBreadthFirst: (id?: JourneyNodeID | null) => Iterable<JourneyNode>,
pushPatchOntoActive: (workflow: ComfyBoxWorkflow, activeNode?: JourneyNode, showNotification?: boolean) => JourneyNode | null
onExecuted: (promptID: PromptID, nodeID: ComfyNodeID, output: SerializedPromptOutput, queueEntry: QueueEntry) => void
} }
export type WritableJourneyStateStore = Writable<JourneyState> & JourneyStateOps; export type WritableJourneyStateStore = Writable<JourneyState> & JourneyStateOps;
@@ -131,6 +140,7 @@ function create() {
*/ */
function addNode(params: RestoreParamWorkflowNodeTargets, parent?: JourneyNodeID | JourneyNode): JourneyNode { function addNode(params: RestoreParamWorkflowNodeTargets, parent?: JourneyNodeID | JourneyNode): JourneyNode {
let _node: JourneyRootNode | JourneyPatchNode; let _node: JourneyRootNode | JourneyPatchNode;
store.update(s => { store.update(s => {
let parentNode: JourneyNode | null = null let parentNode: JourneyNode | null = null
if (parent != null) { if (parent != null) {
@@ -167,6 +177,41 @@ function create() {
return _node; return _node;
} }
function pushPatchOntoActive(workflow: ComfyBoxWorkflow, activeNode?: JourneyNode, showNotification: boolean = false): JourneyNode | null {
const workflowParams = getWorkflowRestoreParamsFromWorkflow(workflow)
let journeyNode
if (activeNode == null) {
// add root node
if (get(store).root != null) {
return;
}
journeyNode = addNode(workflowParams, null);
if (showNotification)
notify("Pushed a new base workflow state.", { type: "info" })
}
else {
// add patch node
const patch = calculateWorkflowParamsPatch(activeNode, workflowParams);
const patchedCount = Object.keys(patch).length;
if (patchedCount === 0) {
if (showNotification)
notify("No changes were made to active parameters yet.", { type: "warning" })
return;
}
journeyNode = addNode(patch, activeNode);
if (showNotification)
notify(`Pushed new state with ${patchedCount} changes.`, { type: "info" })
}
if (journeyNode != null) {
selectNode(journeyNode);
}
return journeyNode;
}
function selectNode(obj?: JourneyNodeID | JourneyNode) { function selectNode(obj?: JourneyNodeID | JourneyNode) {
store.update(s => { store.update(s => {
if (typeof obj === "string") if (typeof obj === "string")
@@ -217,13 +262,23 @@ function create() {
} }
} }
function onExecuted(promptID: PromptID, nodeID: ComfyNodeID, output: SerializedPromptOutput, queueEntry: QueueEntry) {
const journeyNode = Array.from(iterateBreadthFirst()).find(j => j.promptID === promptID);
if (journeyNode === null)
return;
// TODO
}
return { return {
...store, ...store,
getActiveNode, getActiveNode,
clear, clear,
addNode, // addNode,
pushPatchOntoActive,
selectNode, selectNode,
iterateBreadthFirst iterateBreadthFirst,
onExecuted
} }
} }

View File

@@ -512,6 +512,14 @@ const ALL_ATTRIBUTES: AttributesSpecList = [
serialize: serializeStringArray, serialize: serializeStringArray,
deserialize: deserializeStringArray deserialize: deserializeStringArray
}, },
{
name: "excludeFromJourney",
type: "boolean",
location: "nodeProps",
editable: true,
defaultValue: false,
canShow: isComfyWidgetNode
},
// Container tags are contained in the widget attributes // Container tags are contained in the widget attributes
{ {

View File

@@ -15,6 +15,8 @@ export type UIState = {
forceSaveUserState: boolean | null, forceSaveUserState: boolean | null,
activeError: PromptID | null activeError: PromptID | null
autoPushJourney: boolean
} }
type UIStateOps = { type UIStateOps = {
@@ -34,7 +36,9 @@ const store: Writable<UIState> = writable(
reconnecting: false, reconnecting: false,
forceSaveUserState: null, forceSaveUserState: null,
activeError: null activeError: null,
autoPushJourney: true
}) })
function reconnecting() { function reconnecting() {

View File

@@ -224,7 +224,7 @@ export class ComfyBoxWorkflow {
console.error("[applyParamsPatch] Node was not ComfyWidgetNode!!", nodeId, source) console.error("[applyParamsPatch] Node was not ComfyWidgetNode!!", nodeId, source)
continue; continue;
} }
node.setValue(source.finalValue); node.value.set(source.finalValue);
} }
} }

View File

@@ -68,4 +68,32 @@ export default class journeyStateTests extends UnitTest {
} }
}) })
} }
test__patches_exclusions() {
const [workflow, layoutState] = ComfyBoxWorkflow.create()
const { graph, journey } = workflow;
layoutState.initDefaultLayout() // adds 3 containers
const widget1 = LiteGraph.createNode(ComfyNumberNode);
const widget2 = LiteGraph.createNode(ComfyNumberNode);
const watch1 = LiteGraph.createNode(Watch);
const watch2 = LiteGraph.createNode(Watch);
graph.add(widget1)
graph.add(watch1)
widget1.properties.excludeFromJourney = true;
widget1.connect(0, watch1, 0);
widget1.setValue(0)
let workflowParams = getWorkflowRestoreParamsFromWorkflow(workflow)
const root = journey.addNode(workflowParams, null);
expect(root).toEqual({
id: root.id,
type: "root",
children: [],
base: {}
});
}
} }