WOrkflow/layout fixes

This commit is contained in:
space-nuko
2023-05-10 21:49:46 -05:00
parent c0bd46b079
commit 48923ec60f
11 changed files with 933 additions and 42 deletions

View File

@@ -816,11 +816,11 @@
"multiline": false "multiline": false
}, },
"widgets_values": [ "widgets_values": [
"cached" "none"
], ],
"color": "#223", "color": "#223",
"bgColor": "#335", "bgColor": "#335",
"comfyValue": "cached", "comfyValue": "none",
"shownOutputProperties": {}, "shownOutputProperties": {},
"saveUserState": true "saveUserState": true
}, },
@@ -1275,11 +1275,11 @@
"multiline": false "multiline": false
}, },
"widgets_values": [ "widgets_values": [
"2240" "2"
], ],
"color": "#223", "color": "#223",
"bgColor": "#335", "bgColor": "#335",
"comfyValue": "2240", "comfyValue": "2",
"shownOutputProperties": {}, "shownOutputProperties": {},
"saveUserState": true "saveUserState": true
}, },
@@ -1370,11 +1370,11 @@
"multiline": false "multiline": false
}, },
"widgets_values": [ "widgets_values": [
"2240" "2"
], ],
"color": "#223", "color": "#223",
"bgColor": "#335", "bgColor": "#335",
"comfyValue": "2240", "comfyValue": "2",
"shownOutputProperties": {}, "shownOutputProperties": {},
"saveUserState": true "saveUserState": true
}, },
@@ -3203,7 +3203,7 @@
"outputs": [ "outputs": [
{ {
"name": "", "name": "",
"type": "number", "type": "*",
"links": [ "links": [
299 299
], ],
@@ -3374,7 +3374,7 @@
"outputs": [ "outputs": [
{ {
"name": "", "name": "",
"type": "*", "type": "string",
"links": [ "links": [
310, 310,
311 311
@@ -4161,7 +4161,7 @@
"title": "Operation", "title": "Operation",
"properties": { "properties": {
"A": 2, "A": 2,
"B": 1120, "B": 1,
"OP": "*", "OP": "*",
"tags": [] "tags": []
} }
@@ -4207,7 +4207,7 @@
"title": "Operation", "title": "Operation",
"properties": { "properties": {
"A": 2, "A": 2,
"B": 1120, "B": 1,
"OP": "*", "OP": "*",
"tags": [] "tags": []
} }
@@ -12370,7 +12370,7 @@
"properties": { "properties": {
"tags": [], "tags": [],
"defaultValue": null, "defaultValue": null,
"index": 0, "index": null,
"updateMode": "append", "updateMode": "append",
"values": [] "values": []
}, },
@@ -13051,7 +13051,7 @@
"properties": { "properties": {
"tags": [], "tags": [],
"defaultValue": null, "defaultValue": null,
"index": 5, "index": null,
"updateMode": "append", "updateMode": "append",
"values": [] "values": []
}, },
@@ -19697,6 +19697,7 @@
"currentId": 223, "currentId": 223,
"attrs": { "attrs": {
"queuePromptButtonName": "Queue txt2img", "queuePromptButtonName": "Queue txt2img",
"queuePromptButtonRunWorkflow": false,
"defaultSubgraph": "txt2img" "defaultSubgraph": "txt2img"
} }
}, },

View File

@@ -0,0 +1,838 @@
{
"createdBy": "ComfyBox",
"version": 1,
"workflow": {
"last_node_id": 13,
"last_link_id": 11,
"nodes": [
{
"id": 2,
"type": "ui/combo",
"pos": [
1957.9086484470572,
1203.438046544425
],
"size": [
210,
78
],
"flags": {
"collapsed": true
},
"order": 0,
"mode": 0,
"inputs": [
{
"name": "value",
"type": "string",
"link": null
},
{
"name": "store",
"type": -1,
"link": null,
"shape": 1
}
],
"outputs": [
{
"name": "value",
"type": "string",
"links": [
1
]
},
{
"name": "changed",
"type": -2,
"links": null,
"shape": 1
}
],
"title": "UI.Combo",
"properties": {
"tags": [],
"defaultValue": null,
"values": [],
"convertValueToLabelCode": ""
},
"widgets_values": [],
"color": "#223",
"bgColor": "#335",
"comfyValue": "A",
"shownOutputProperties": {},
"saveUserState": false
},
{
"id": 3,
"type": "ui/image_upload",
"pos": [
1925.8925619834713,
1247.7851239669424
],
"size": [
210,
138
],
"flags": {},
"order": 1,
"mode": 0,
"inputs": [
{
"name": "store",
"type": -1,
"link": null,
"shape": 1
}
],
"outputs": [
{
"name": "filename",
"type": "string",
"links": [
4
]
},
{
"name": "width",
"type": "number",
"links": null
},
{
"name": "height",
"type": "number",
"links": null
},
{
"name": "image_count",
"type": "number",
"links": null
},
{
"name": "changed",
"type": -2,
"links": null,
"shape": 1
}
],
"title": "UI.ImageUpload",
"properties": {
"defaultValue": null,
"tags": [],
"fileCount": "single"
},
"widgets_values": [],
"color": "#223",
"bgColor": "#335",
"comfyValue": [],
"shownOutputProperties": {},
"saveUserState": false
},
{
"id": 5,
"type": "ImageUpscaleWithModel",
"pos": [
2322,
1204
],
"size": [
176.4,
46
],
"flags": {},
"order": 6,
"mode": 0,
"inputs": [
{
"name": "upscale_model",
"type": "UPSCALE_MODEL",
"link": 2,
"config": {}
},
{
"name": "image",
"type": "IMAGE",
"link": 5,
"config": {}
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
7
],
"slot_index": 0
}
],
"title": "ImageUpscaleWithModel",
"properties": {
"tags": []
},
"color": "#432",
"bgColor": "#653",
"saveUserState": true
},
{
"id": 10,
"type": "ui/button",
"pos": [
2657,
1335
],
"size": [
210,
78
],
"flags": {
"collapsed": true
},
"order": 2,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "clicked",
"type": -2,
"links": [
9
],
"shape": 1,
"slot_index": 0
},
{
"name": "isClicked",
"type": "boolean",
"links": null
}
],
"title": "UI.Button",
"properties": {
"tags": [],
"defaultValue": false,
"param": "bang"
},
"widgets_values": [
"false"
],
"color": "#223",
"bgColor": "#335",
"comfyValue": false,
"shownOutputProperties": {},
"saveUserState": true
},
{
"id": 8,
"type": "SaveImage",
"pos": [
2542,
1254
],
"size": [
220,
46
],
"flags": {},
"order": 7,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 7,
"config": {}
},
{
"name": "filename_prefix",
"type": "string",
"link": 11,
"config": {},
"defaultWidgetNode": null,
"widgetNodeType": "ui/text",
"serialize": true
}
],
"outputs": [
{
"name": "onExecuted",
"type": -2,
"links": [
8
],
"color_off": "rebeccapurple",
"color_on": "rebeccapurple",
"shape": 1,
"slot_index": 0
}
],
"title": "SaveImage",
"properties": {
"tags": []
},
"color": "#432",
"bgColor": "#653",
"saveUserState": true
},
{
"id": 6,
"type": "LoadImage",
"pos": [
2160,
1264
],
"size": [
140,
46
],
"flags": {},
"order": 5,
"mode": 0,
"inputs": [
{
"name": "image",
"type": "string",
"link": 4,
"config": {},
"defaultWidgetNode": null,
"widgetNodeType": "ui/combo",
"serialize": true,
"slot_index": 0
}
],
"outputs": [
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
5
],
"slot_index": 0
},
{
"name": "MASK",
"type": "MASK",
"links": null
}
],
"title": "LoadImage",
"properties": {
"tags": []
},
"color": "#432",
"bgColor": "#653",
"saveUserState": true
},
{
"id": 9,
"type": "ui/text",
"pos": [
2445,
1300
],
"size": [
210,
78
],
"flags": {
"collapsed": true
},
"order": 3,
"mode": 0,
"inputs": [
{
"name": "value",
"type": "string",
"link": null
},
{
"name": "store",
"type": -1,
"link": null,
"shape": 1
}
],
"outputs": [
{
"name": "value",
"type": "string",
"links": [
11
],
"slot_index": 0
},
{
"name": "changed",
"type": -2,
"links": null,
"shape": 1
}
],
"title": "UI.Text",
"properties": {
"tags": [],
"defaultValue": "ComfyUI",
"multiline": false
},
"widgets_values": [
"ComfyUI"
],
"color": "#223",
"bgColor": "#335",
"comfyValue": "ComfyUI",
"shownOutputProperties": {},
"saveUserState": true
},
{
"id": 4,
"type": "ui/gallery",
"pos": [
2819,
1259
],
"size": [
210,
166
],
"flags": {},
"order": 8,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "OUTPUT",
"link": null,
"slot_index": 0
},
{
"name": "store",
"type": -1,
"link": 8,
"color_off": "rebeccapurple",
"color_on": "rebeccapurple",
"shape": 1
},
{
"name": "clear",
"type": -1,
"link": 9,
"shape": 1
}
],
"outputs": [
{
"name": "selected_index",
"type": "number",
"links": null
},
{
"name": "width",
"type": "number",
"links": null
},
{
"name": "height",
"type": "number",
"links": null
},
{
"name": "filename",
"type": "string",
"links": null
}
],
"title": "UI.Gallery",
"properties": {
"tags": [],
"defaultValue": null,
"index": 0,
"updateMode": "replace"
},
"widgets_values": [],
"color": "#223",
"bgColor": "#335",
"comfyValue": [],
"shownOutputProperties": {},
"saveUserState": false
},
{
"id": 1,
"type": "UpscaleModelLoader",
"pos": [
2088,
1179
],
"size": [
203.2,
26
],
"flags": {},
"order": 4,
"mode": 0,
"inputs": [
{
"name": "model_name",
"type": "string",
"link": 1,
"config": {},
"defaultWidgetNode": null,
"widgetNodeType": "ui/combo",
"serialize": true
}
],
"outputs": [
{
"name": "UPSCALE_MODEL",
"type": "UPSCALE_MODEL",
"links": [
2
],
"slot_index": 0
}
],
"title": "UpscaleModelLoader",
"properties": {
"tags": []
},
"color": "#432",
"bgColor": "#653",
"saveUserState": true
}
],
"links": [
[
1,
2,
0,
1,
0,
"string"
],
[
2,
1,
0,
5,
0,
"UPSCALE_MODEL"
],
[
4,
3,
0,
6,
0,
"string"
],
[
5,
6,
0,
5,
1,
"IMAGE"
],
[
7,
5,
0,
8,
0,
"IMAGE"
],
[
8,
8,
0,
4,
1,
-1
],
[
9,
10,
0,
4,
2,
-1
],
[
11,
9,
0,
8,
1,
"string"
]
],
"groups": [],
"config": {},
"extra": {},
"version": 10
},
"layout": {
"root": "0",
"allItems": {
"0": {
"dragItem": {
"type": "container",
"id": "0",
"attrs": {
"title": "",
"hidden": false,
"disabled": false,
"direction": "horizontal",
"classes": "",
"style": "",
"nodeDisabledState": "disabled",
"variant": "gallery",
"containerVariant": "block",
"openOnStartup": false,
"buttonVariant": "primary",
"buttonSize": "large",
"tags": []
}
},
"children": [
"1",
"2"
]
},
"1": {
"dragItem": {
"type": "container",
"id": "1",
"attrs": {
"title": "",
"hidden": false,
"disabled": false,
"direction": "vertical",
"classes": "",
"style": "",
"nodeDisabledState": "disabled",
"variant": "gallery",
"containerVariant": "block",
"openOnStartup": false,
"buttonVariant": "primary",
"buttonSize": "large",
"tags": []
}
},
"children": [
"5",
"4"
],
"parent": "0"
},
"2": {
"dragItem": {
"type": "container",
"id": "2",
"attrs": {
"title": "",
"hidden": false,
"disabled": false,
"direction": "vertical",
"classes": "",
"style": "",
"nodeDisabledState": "disabled",
"variant": "gallery",
"containerVariant": "block",
"openOnStartup": false,
"buttonVariant": "primary",
"buttonSize": "large",
"tags": []
}
},
"children": [
"6",
"12"
],
"parent": "0"
},
"3": {
"dragItem": {
"type": "widget",
"id": "3",
"nodeId": 2,
"attrs": {
"title": "Model Name",
"hidden": false,
"disabled": false,
"direction": "vertical",
"classes": "",
"style": "",
"nodeDisabledState": "disabled",
"variant": "gallery",
"containerVariant": "block",
"openOnStartup": false,
"buttonVariant": "primary",
"buttonSize": "large",
"tags": []
}
},
"children": [],
"parent": "4"
},
"4": {
"dragItem": {
"type": "container",
"id": "4",
"attrs": {
"title": "UpscaleModelLoader",
"hidden": false,
"disabled": false,
"direction": "vertical",
"classes": "",
"style": "",
"nodeDisabledState": "disabled",
"variant": "gallery",
"containerVariant": "block",
"openOnStartup": false,
"buttonVariant": "primary",
"buttonSize": "large",
"tags": []
}
},
"children": [
"3"
],
"parent": "1"
},
"5": {
"dragItem": {
"type": "widget",
"id": "5",
"nodeId": 3,
"attrs": {
"title": "Image",
"hidden": false,
"disabled": false,
"direction": "vertical",
"classes": "",
"style": "",
"nodeDisabledState": "disabled",
"variant": "gallery",
"containerVariant": "block",
"openOnStartup": false,
"buttonVariant": "primary",
"buttonSize": "large",
"tags": []
}
},
"children": [],
"parent": "1"
},
"6": {
"dragItem": {
"type": "widget",
"id": "6",
"nodeId": 4,
"attrs": {
"title": "Result",
"hidden": false,
"disabled": false,
"direction": "vertical",
"classes": "",
"style": "",
"nodeDisabledState": "disabled",
"variant": "gallery",
"containerVariant": "block",
"openOnStartup": false,
"buttonVariant": "primary",
"buttonSize": "large",
"tags": []
}
},
"children": [],
"parent": "2"
},
"9": {
"dragItem": {
"type": "widget",
"id": "9",
"nodeId": 9,
"attrs": {
"title": "Filename Prefix",
"hidden": false,
"disabled": false,
"direction": "vertical",
"classes": "",
"style": "",
"nodeDisabledState": "disabled",
"variant": "gallery",
"containerVariant": "block",
"openOnStartup": false,
"buttonVariant": "primary",
"buttonSize": "large",
"tags": []
}
},
"children": [],
"parent": "12"
},
"11": {
"dragItem": {
"type": "widget",
"id": "11",
"nodeId": 10,
"attrs": {
"title": "Clear Outputs",
"hidden": false,
"disabled": false,
"direction": "vertical",
"classes": "",
"style": "",
"nodeDisabledState": "disabled",
"variant": "gallery",
"containerVariant": "block",
"openOnStartup": false,
"buttonVariant": "secondary",
"buttonSize": "large",
"tags": []
}
},
"children": [],
"parent": "12"
},
"12": {
"dragItem": {
"type": "container",
"id": "12",
"attrs": {
"title": "",
"hidden": false,
"disabled": false,
"direction": "horizontal",
"classes": "",
"style": "",
"nodeDisabledState": "disabled",
"variant": "gallery",
"containerVariant": "block",
"openOnStartup": false,
"buttonVariant": "primary",
"buttonSize": "large",
"tags": []
}
},
"children": [
"9",
"11"
],
"parent": "2"
}
},
"currentId": 15,
"attrs": {
"queuePromptButtonName": "Queue Prompt",
"queuePromptButtonRunWorkflow": true
}
},
"canvas": {
"offset": [
-1717.3714583644114,
-1017.6529225774816
],
"scale": 1
}
}

View File

@@ -8,7 +8,7 @@ import { get } from "svelte/store";
import type ComfyGraphNode from "./nodes/ComfyGraphNode"; import type ComfyGraphNode from "./nodes/ComfyGraphNode";
import type IComfyInputSlot from "./IComfyInputSlot"; import type IComfyInputSlot from "./IComfyInputSlot";
import type { ComfyBackendNode } from "./nodes/ComfyBackendNode"; import type { ComfyBackendNode } from "./nodes/ComfyBackendNode";
import type { ComfyWidgetNode } from "./nodes"; import type { ComfyComboNode, ComfyWidgetNode } from "./nodes";
type ComfyGraphEvents = { type ComfyGraphEvents = {
configured: (graph: LGraph) => void configured: (graph: LGraph) => void
@@ -108,6 +108,11 @@ export default class ComfyGraph extends LGraph {
widgetNode.collapse(); widgetNode.collapse();
widgetNode.pos = [inputPos[0] - 140, inputPos[1] + LiteGraph.NODE_SLOT_HEIGHT / 2]; widgetNode.pos = [inputPos[0] - 140, inputPos[1] + LiteGraph.NODE_SLOT_HEIGHT / 2];
widgetNodesAdded.push(widgetNode) widgetNodesAdded.push(widgetNode)
// Set combo box as loaded
if (widgetNode.type === "ui/combo" && widgetNode.properties.values != null) {
(widgetNode as ComfyComboNode).formatValues(widgetNode.properties.values);
}
} }
} }
} }

View File

@@ -12,7 +12,7 @@
import { flip } from 'svelte/animate'; import { flip } from 'svelte/animate';
import layoutState, { type ContainerLayout, type WidgetLayout, type IDragItem } from "$lib/stores/layoutState"; import layoutState, { type ContainerLayout, type WidgetLayout, type IDragItem } from "$lib/stores/layoutState";
import { startDrag, stopDrag } from "$lib/utils" import { startDrag, stopDrag } from "$lib/utils"
import type { Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
import { isHidden } from "$lib/widgets/utils"; import { isHidden } from "$lib/widgets/utils";
export let container: ContainerLayout | null = null; export let container: ContainerLayout | null = null;
@@ -22,23 +22,27 @@
export let edit: boolean = false; export let edit: boolean = false;
export let dragDisabled: boolean = false; export let dragDisabled: boolean = false;
export let isMobile: boolean = false; export let isMobile: boolean = false;
let isOpen: Writable<boolean> | null = null;
let attrsChanged: Writable<boolean> | null = null;
let children: IDragItem[] | null = null; let children: IDragItem[] | null = null;
const flipDurationMs = 100; const flipDurationMs = 100;
let selectedIndex: number = 0; let selectedIndex: number = 0;
$: if (container) { $: if (container) {
children = $layoutState.allItems[container.id].children; setupState()
attrsChanged = container.attrsChanged
if (container.isOpen == null) {
container.isOpen = container.attrs.openOnStartup
}
} }
else { else {
children = null; children = null;
attrsChanged = null }
function setupState() {
children = $layoutState.allItems[container.id].children;
if (container.isOpen == null) {
container.isOpen = writable(container.attrs.openOnStartup)
}
isOpen = container.isOpen
console.warn("REBUILD", container.attrs.title, $isOpen)
} }
function handleConsider(evt: any) { function handleConsider(evt: any) {
@@ -51,8 +55,9 @@
// Ensure dragging is stopped on drag finish // Ensure dragging is stopped on drag finish
}; };
function handleClick({ clicked }: CustomEvent<boolean>) { function handleClick(e: CustomEvent<boolean>) {
navigator.vibrate(20) navigator.vibrate(20)
$isOpen = e.detail
} }
</script> </script>
@@ -104,7 +109,7 @@
</Block> </Block>
{:else} {:else}
<Block elem_classes={["gradio-accordion"]}> <Block elem_classes={["gradio-accordion"]}>
<Accordion label={container.attrs.title} bind:open={container.isOpen} on:click={handleClick}> <Accordion label={container.attrs.title} open={$isOpen} on:click={handleClick}>
{#each children.filter(item => item.id !== SHADOW_PLACEHOLDER_ITEM_ID) as item(item.id)} {#each children.filter(item => item.id !== SHADOW_PLACEHOLDER_ITEM_ID) as item(item.id)}
<WidgetContainer dragItem={item} zIndex={zIndex+1} {isMobile} /> <WidgetContainer dragItem={item} zIndex={zIndex+1} {isMobile} />
{/each} {/each}

View File

@@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { onMount } from "svelte"; import { onMount } from "svelte";
import { get } from "svelte/store"; import { get, writable, type Writable } from "svelte/store";
import { Pane, Splitpanes } from 'svelte-splitpanes'; import { Pane, Splitpanes } from 'svelte-splitpanes';
import { Button } from "@gradio/button"; import { Button } from "@gradio/button";
import { BlockTitle } from "@gradio/atoms"; import { BlockTitle } from "@gradio/atoms";

View File

@@ -383,7 +383,7 @@ export default class ComfyApp {
} }
// Distinguish frontend/backend connections // Distinguish frontend/backend connections
const BACKEND_TYPES = ["CLIP", "CLIP_VISION", "CLIP_VISION_OUTPUT", "CONDITIONING", "CONTROL_NET", "LATENT", "MASK", "MODEL", "STYLE_MODEL", "VAE"] const BACKEND_TYPES = ["CLIP", "CLIP_VISION", "CLIP_VISION_OUTPUT", "CONDITIONING", "CONTROL_NET", "LATENT", "MASK", "MODEL", "STYLE_MODEL", "VAE", "UPSCALE_MODEL"]
for (const type of BACKEND_TYPES) { for (const type of BACKEND_TYPES) {
setColor(type, "orange") setColor(type, "orange")
} }
@@ -497,6 +497,11 @@ export default class ComfyApp {
(node as ComfyGraphNode).onDefaultQueueAction() (node as ComfyGraphNode).onDefaultQueueAction()
} }
} }
if (get(layoutState).attrs.queuePromptButtonRunWorkflow) {
this.queuePrompt(0, 1);
notify("Prompt queued.");
}
} }
querySave() { querySave() {

View File

@@ -11,8 +11,11 @@
let target: IDragItem | null = null; let target: IDragItem | null = null;
let node: LGraphNode | null = null; let node: LGraphNode | null = null;
let attrsChanged: Writable<boolean> | null = null; let attrsChanged: Writable<number> | null = null;
let refreshPanel: Writable<number> = writable(0);
let refreshPropsPanel: Writable<number> | null
$: refreshPropsPanel = $layoutState.refreshPropsPanel;
$: if ($layoutState.currentSelection.length > 0) { $: if ($layoutState.currentSelection.length > 0) {
const targetId = $layoutState.currentSelection.slice(-1)[0] const targetId = $layoutState.currentSelection.slice(-1)[0]
@@ -50,7 +53,7 @@
let value = spec.defaultValue; let value = spec.defaultValue;
target.attrs[spec.name] = value; target.attrs[spec.name] = value;
if (spec.refreshPanelOnChange) if (spec.refreshPanelOnChange)
$refreshPanel += 1; $refreshPropsPanel += 1;
} }
} }
} }
@@ -218,9 +221,14 @@
} }
} }
function doRefreshPanel() { function getWorkflowAttribute(spec: AttributesSpec): any {
console.warn("[ComfyProperties] doRefreshPanel") let value = $layoutState.attrs[spec.name]
$refreshPanel += 1; if (value == null)
value = spec.defaultValue
else if (spec.serialize)
value = spec.serialize(value)
console.debug("[ComfyProperties] getWorkflowAttribute", spec.name, value, spec, $layoutState.attrs[spec.name])
return value
} }
function updateWorkflowAttribute(spec: AttributesSpec, value: any) { function updateWorkflowAttribute(spec: AttributesSpec, value: any) {
@@ -236,6 +244,11 @@
if (spec.refreshPanelOnChange) if (spec.refreshPanelOnChange)
doRefreshPanel() doRefreshPanel()
} }
function doRefreshPanel() {
console.warn("[ComfyProperties] doRefreshPanel")
$refreshPropsPanel += 1;
}
</script> </script>
<div class="props"> <div class="props">
@@ -251,7 +264,7 @@
</div> </div>
</div> </div>
<div class="props-entries"> <div class="props-entries">
{#key $refreshPanel} {#key $refreshPropsPanel}
{#each ALL_ATTRIBUTES as category(category.categoryName)} {#each ALL_ATTRIBUTES as category(category.categoryName)}
<div class="category-name"> <div class="category-name">
<span> <span>
@@ -379,7 +392,7 @@
<div class="props-entry"> <div class="props-entry">
{#if spec.type === "string"} {#if spec.type === "string"}
<TextBox <TextBox
value={$layoutState.attrs[spec.name] || spec.defaultValue} value={getWorkflowAttribute(spec)}
on:change={(e) => updateWorkflowAttribute(spec, e.detail)} on:change={(e) => updateWorkflowAttribute(spec, e.detail)}
on:input={(e) => updateWorkflowAttribute(spec, e.detail)} on:input={(e) => updateWorkflowAttribute(spec, e.detail)}
label={spec.name} label={spec.name}
@@ -388,7 +401,7 @@
/> />
{:else if spec.type === "boolean"} {:else if spec.type === "boolean"}
<Checkbox <Checkbox
value={$layoutState.attrs[spec.name] || spec.defaultValue} value={getWorkflowAttribute(spec)}
on:change={(e) => updateWorkflowAttribute(spec, e.detail)} on:change={(e) => updateWorkflowAttribute(spec, e.detail)}
disabled={!$uiState.uiUnlocked || !spec.editable} disabled={!$uiState.uiUnlocked || !spec.editable}
label={spec.name} label={spec.name}
@@ -396,7 +409,7 @@
{:else if spec.type === "number"} {:else if spec.type === "number"}
<ComfyNumberProperty <ComfyNumberProperty
name={spec.name} name={spec.name}
value={$layoutState.attrs[spec.name] || spec.defaultValue} value={getWorkflowAttribute(spec)}
step={spec.step || 1} step={spec.step || 1}
min={spec.min || -1024} min={spec.min || -1024}
max={spec.max || 1024} max={spec.max || 1024}
@@ -406,7 +419,7 @@
{:else if spec.type === "enum"} {:else if spec.type === "enum"}
<ComfyComboProperty <ComfyComboProperty
name={spec.name} name={spec.name}
value={$layoutState.attrs[spec.name] || spec.defaultValue} value={getWorkflowAttribute(spec)}
values={spec.values} values={spec.values}
disabled={!$uiState.uiUnlocked || !spec.editable} disabled={!$uiState.uiUnlocked || !spec.editable}
on:change={(e) => updateWorkflowAttribute(spec, e.detail)} on:change={(e) => updateWorkflowAttribute(spec, e.detail)}

View File

@@ -31,6 +31,12 @@ export type LayoutAttributes = {
* Name of the "Queue Prompt" button. Set to blank to hide the button. * Name of the "Queue Prompt" button. Set to blank to hide the button.
*/ */
queuePromptButtonName: string, queuePromptButtonName: string,
/*
* If true, clicking the "Queue Prompt" button will run the default subgraph.
* Set this to false if you need special behavior before running any subgraphs.
*/
queuePromptButtonRunWorkflow: boolean,
} }
/* /*
@@ -86,6 +92,8 @@ export type LayoutState = {
* Global workflow attributes * Global workflow attributes
*/ */
attrs: LayoutAttributes attrs: LayoutAttributes
refreshPropsPanel: Writable<number>
} }
/** /**
@@ -539,6 +547,13 @@ const ALL_ATTRIBUTES: AttributesSpecList = [
location: "workflow", location: "workflow",
editable: true, editable: true,
defaultValue: "Queue Prompt" defaultValue: "Queue Prompt"
},
{
name: "queuePromptButtonRunWorkflow",
type: "boolean",
location: "workflow",
editable: true,
defaultValue: true
} }
] ]
} }
@@ -612,7 +627,7 @@ export interface ContainerLayout extends IDragItem {
// (not serialized) // (not serialized)
// Accordion // Accordion
isOpen?: boolean, isOpen?: Writable<boolean>,
} }
/* /*
@@ -657,6 +672,7 @@ const store: Writable<LayoutState> = writable({
currentSelectionNodes: [], currentSelectionNodes: [],
isMenuOpen: false, isMenuOpen: false,
isConfiguring: true, isConfiguring: true,
refreshPropsPanel: writable(0),
attrs: { attrs: {
...defaultWorkflowAttributes ...defaultWorkflowAttributes
} }
@@ -913,6 +929,7 @@ function initDefaultLayout() {
currentSelectionNodes: [], currentSelectionNodes: [],
isMenuOpen: false, isMenuOpen: false,
isConfiguring: false, isConfiguring: false,
refreshPropsPanel: writable(0),
attrs: { attrs: {
...defaultWorkflowAttributes ...defaultWorkflowAttributes
} }
@@ -1028,12 +1045,16 @@ function deserialize(data: SerializedLayoutState, graph: LGraph) {
currentSelectionNodes: [], currentSelectionNodes: [],
isMenuOpen: false, isMenuOpen: false,
isConfiguring: false, isConfiguring: false,
refreshPropsPanel: writable(0),
attrs: { ...defaultWorkflowAttributes, ...data.attrs } attrs: { ...defaultWorkflowAttributes, ...data.attrs }
} }
console.debug("[layoutState] deserialize", data, state) console.debug("[layoutState] deserialize", data, state, defaultWorkflowAttributes)
store.set(state) store.set(state)
// Ensure properties panel is updated with new state
state.refreshPropsPanel.set(get(state.refreshPropsPanel) + 1)
} }
function onStartConfigure() { function onStartConfigure() {

View File

@@ -5,12 +5,13 @@
import { Checkbox } from "@gradio/form"; import { Checkbox } from "@gradio/form";
import { get, type Writable, writable } from "svelte/store"; import { get, type Writable, writable } from "svelte/store";
import { isDisabled } from "./utils" import { isDisabled } from "./utils"
import type { SelectData } from "@gradio/utils";
export let widget: WidgetLayout | null = null; export let widget: WidgetLayout | null = null;
export let isMobile: boolean = false; export let isMobile: boolean = false;
let node: ComfyCheckboxNode | null = null; let node: ComfyCheckboxNode | null = null;
let nodeValue: Writable<boolean> | null = null; let nodeValue: Writable<boolean> | null = null;
let attrsChanged: Writable<boolean> | null = null; let attrsChanged: Writable<number> | null = null;
$: widget && setNodeValue(widget); $: widget && setNodeValue(widget);
@@ -22,7 +23,8 @@
} }
}; };
function onSelect() { function onSelect(e: CustomEvent<SelectData>) {
$nodeValue = e.detail.selected
navigator.vibrate(20) navigator.vibrate(20)
} }
</script> </script>
@@ -35,7 +37,7 @@
<Checkbox <Checkbox
disabled={isDisabled(widget)} disabled={isDisabled(widget)}
label={widget.attrs.title} label={widget.attrs.title}
bind:value={$nodeValue} value={$nodeValue}
on:select={onSelect} on:select={onSelect}
/> />
</Block> </Block>

View File

@@ -41,6 +41,7 @@
nodeValue = node.value; nodeValue = node.value;
propsChanged = node.propsChanged; propsChanged = node.propsChanged;
valuesForCombo = node.valuesForCombo; valuesForCombo = node.valuesForCombo;
lastConfigured = $valuesForCombo
} }
} }

View File

@@ -76,7 +76,7 @@
<Toolbar bottom> <Toolbar bottom>
{#if $layoutState.attrs.queuePromptButtonName != ""} {#if $layoutState.attrs.queuePromptButtonName != ""}
<Link on:click={queuePrompt}> <Link on:click={queuePrompt}>
{$layoutState.attrs.queuePromptButtonName} {$layoutState.attrs.queuePromptButtonName}
</Link> </Link>
{/if} {/if}
<Link on:click={refreshCombos}>🔄</Link> <Link on:click={refreshCombos}>🔄</Link>