Move state management into svelte store

This commit is contained in:
space-nuko
2023-04-05 11:10:03 -05:00
parent dbe65fa98c
commit b754243d27
5 changed files with 154 additions and 144 deletions

View File

@@ -5,6 +5,7 @@
import { Backpack, Gear } from 'radix-icons-svelte'; import { Backpack, Gear } from 'radix-icons-svelte';
import ComfyUIPane from "./ComfyUIPane.svelte"; import ComfyUIPane from "./ComfyUIPane.svelte";
import ComfyApp from "./ComfyApp"; import ComfyApp from "./ComfyApp";
import widgetState from "$lib/stores/widgetState";
import { LGraphNode } from "litegraph.js"; import { LGraphNode } from "litegraph.js";
@@ -36,21 +37,10 @@
onMount(async () => { onMount(async () => {
app = new ComfyApp(); app = new ComfyApp();
app.eventBus.on("nodeAdded", (node: LGraphNode) => { app.eventBus.on("nodeAdded", widgetState.nodeAdded);
uiPane.addNodeUI(node); app.eventBus.on("nodeRemoved", widgetState.nodeRemoved);
}); app.eventBus.on("configured", widgetState.configureFinished);
app.eventBus.on("cleared", widgetState.clear);
app.eventBus.on("nodeRemoved", (node: LGraphNode) => {
uiPane.removeNodeUI(node);
});
app.eventBus.on("configured", (graph: LGraph) => {
uiPane.configureFinished(graph);
});
app.eventBus.on("cleared", () => {
uiPane.clear();
});
await app.setup(); await app.setup();
refreshView(); refreshView();

View File

@@ -1,13 +1,11 @@
<script lang="ts"> <script lang="ts">
import { Button } from "@gradio/button"; import { onDestroy } from "svelte";
import { Block, BlockTitle } from "@gradio/atoms"; import { Block, BlockTitle } from "@gradio/atoms";
import { Dropdown, Range, TextBox } from "@gradio/form"; import { Dropdown, Range, TextBox } from "@gradio/form";
import widgetState from "$lib/stores/widgetState";
import { dndzone } from 'svelte-dnd-action'; import { dndzone } from 'svelte-dnd-action';
import { flip } from 'svelte/animate'; import {flip} from 'svelte/animate';
export let state: Record<number, any[]> = {};
export let items: Record<number, { node: LGraphNode, widget: IWidget }[]> = {};
export let dragItems = []; export let dragItems = [];
let dragDisabled = true; let dragDisabled = true;
@@ -29,6 +27,12 @@
const stopDrag = () => { const stopDrag = () => {
dragDisabled = true; dragDisabled = true;
}; };
const unsubscribe = widgetState.subscribe(state => {
dragItems = dragItems.filter(item => item.node.id in state);
});
onDestroy(unsubscribe);
</script> </script>
@@ -40,16 +44,17 @@
{#each dragItems as dragItem(dragItem.id)} {#each dragItems as dragItem(dragItem.id)}
{@const node = dragItem.node} {@const node = dragItem.node}
{@const id = node.id} {@const id = node.id}
<div class="animation-wrapper" animate:flip={{duration:flipDurationMs}}>
<Block> <Block>
<div class="handle" on:mousedown={startDrag} on:touchstart={startDrag} on:mouseup={stopDrag} on:touchend={stopDrag}/> <div class="handle" on:mousedown={startDrag} on:touchstart={startDrag} on:mouseup={stopDrag} on:touchend={stopDrag}/>
<label for={id}> <label for={id}>
<BlockTitle>{node.title}</BlockTitle> <BlockTitle>{node.title}</BlockTitle>
</label> </label>
{#each items[id] as item, i} {#each $widgetState[id] as item, i}
{#if item.widget.type == "combo"} {#if item.widget.type == "combo"}
<div class="wrapper"> <div class="wrapper">
<Dropdown <Dropdown
bind:value={state[id][i]} bind:value={item.value}
choices={item.widget.options.values} choices={item.widget.options.values}
multiselect={false} multiselect={false}
max_choices={1}, max_choices={1},
@@ -64,7 +69,7 @@
{:else if item.widget.type == "number"} {:else if item.widget.type == "number"}
<div class="wrapper"> <div class="wrapper">
<Range <Range
bind:value={state[id][i]} bind:value={item.value}
minimum={item.widget.options.min} minimum={item.widget.options.min}
maximum={item.widget.options.max} maximum={item.widget.options.max}
step={item.widget.options.step} step={item.widget.options.step}
@@ -77,9 +82,10 @@
{:else if item.widget.type == "text"} {:else if item.widget.type == "text"}
<div class="wrapper"> <div class="wrapper">
<TextBox <TextBox
bind:value={state[id][i]} bind:value={item.value}
label={item.widget.name} label={item.widget.name}
lines={item.widget.options.multiline ? 5 : 1} lines={item.widget.options.multiline ? 5 : 1}
max_lines={item.widget.options.multiline ? 5 : 1}
show_label={true} show_label={true}
on:change on:change
on:submit on:submit
@@ -90,6 +96,7 @@
{/if} {/if}
{/each} {/each}
</Block> </Block>
</div>
{/each} {/each}
</div> </div>

View File

@@ -3,86 +3,26 @@
import type { IWidget } from "litegraph.js"; import type { IWidget } from "litegraph.js";
import ComfyApp from "./ComfyApp"; import ComfyApp from "./ComfyApp";
import ComfyPane from "./ComfyPane.svelte"; import ComfyPane from "./ComfyPane.svelte";
import widgetState from "$lib/stores/widgetState";
export let app: ComfyApp; export let app: ComfyApp;
let dragConfigured: boolean = false;
export let dragItemss: any[][] = []
let dragItems = []; export let totalId = 0;
export function clear() { $: if(app && !dragConfigured) {
nodes = {}; dragConfigured = true;
items = {}; app.eventBus.on("nodeAdded", (node: LGraphNode) => {
state = {}; dragItemss[0].push({ id: totalId++, node: node });
dragItems = [] });
} }
export function addNodeUI(node: LGraphNode) {
if (node.widgets) {
for (const [i, widget] of node.widgets.entries()) {
if (!nodes[node.id]) {
dragItems.push({ id: node.id, node: node })
}
nodes[node.id] = node;
node.onPropertyChanged = (k, v) => {
console.log("PROPCHANGE", k, v)
};
if (!items[node.id]) {
items[node.id] = []
}
items[node.id].push({ node, widget })
if (!state[node.id]) {
state[node.id] = []
}
state[node.id].push(widget.value);
}
}
nodes = nodes;
items = items;
state = state;
}
export function removeNodeUI(node: LGraphNode) {
delete nodes[node.id]
delete state[node.id]
delete items[node.id]
dragItems = Array.from(dragItems.filter(e => e.id != node.id));
console.log("REM", node.id, dragItems)
nodes = nodes;
items = items;
state = state;
}
export function configureFinished(graph: LGraph) {
for (const node of graph.computeExecutionOrder(false, null)) {
if (node.widgets_values) {
for (const [j, value] of node.widgets_values.entries()) {
state[node.id][j] = value;
}
}
}
nodes = nodes;
state = state;
}
export function getState() {
return state;
}
let nodes: Record<number, LGraphNode> = {};
let items: Record<number, { node: LGraphNode, widget: IWidget }[]> = {};
let state: Record<number, any[]> = {};
</script> </script>
<div id="comfy-ui-panes" > <div id="comfy-ui-panes" >
<ComfyPane {dragItems} {items} {state} /> <ComfyPane bind:dragItems={dragItemss[0]} />
<ComfyPane {items} {state} /> <ComfyPane bind:dragItems={dragItemss[1]} />
<ComfyPane {items} {state} /> <ComfyPane bind:dragItems={dragItemss[2]} />
</div> </div>
<style> <style>
@@ -105,7 +45,7 @@
position: absolute; position: absolute;
right: 0; right: 0;
width: 1em; width: 1em;
height: 0.5em; height: 1em;
background-color: grey; background-color: grey;
} }

View File

@@ -0,0 +1,73 @@
import { writable, get } from 'svelte/store';
import type { LGraph, LGraphNode, IWidget } from "litegraph.js";
import type { Readable, Writable } from 'svelte/store';
export type WidgetUIState = {
node: LGraphNode,
widget: IWidget,
value: any
}
type NodeID = number;
type WidgetStateOps = {
nodeAdded: (node: LGraphNode) => void,
nodeRemoved: (node: LGraphNode) => void,
configureFinished: (graph: LGraph) => void,
clear: () => void,
}
type WidgetStateStore = Writable<Record<NodeID, WidgetUIState[]>> & WidgetStateOps;
const store: Writable<Record<NodeID, WidgetUIState[]>> = writable({})
function clear() {
store.set({})
}
function nodeAdded(node: LGraphNode) {
if (node.widgets) {
let state = get(store)
for (const widget of node.widgets) {
if (!state[node.id])
state[node.id] = []
state[node.id].push({ node, widget, value: widget.value })
}
store.set(state);
}
}
function nodeRemoved(node: LGraphNode) {
let state = get(store)
delete state[node.id]
store.set(state)
}
function configureFinished(graph: LGraph) {
let state = get(store);
for (const node of graph.computeExecutionOrder(false, null)) {
if (node.widgets_values) {
for (const [i, value] of node.widgets_values.entries()) {
if (i < state[node.id].length) {
state[node.id][i].value = value;
}
else {
console.error("Mismatch in widgets_values!", state[node.id].map(i => i.value), node.widgets_values)
break;
}
}
}
}
store.set(state)
}
export default
{
...store,
nodeAdded,
nodeRemoved,
configureFinished,
clear
} as WidgetStateStore;

View File

@@ -4,7 +4,7 @@ import FullReload from 'vite-plugin-full-reload'
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [
sveltekit() sveltekit(),
FullReload(["src/**/*.{js,ts,svelte}"]) FullReload(["src/**/*.{js,ts,svelte}"])
], ],
build: { build: {