Improve combo refresh logic
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { Block, BlockTitle } from "@gradio/atoms";
|
||||
import { Accordion } from "@gradio/accordion";
|
||||
import Accordion from "$lib/components/gradio/app/Accordion.svelte";
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import WidgetContainer from "./WidgetContainer.svelte"
|
||||
|
||||
@@ -50,6 +50,10 @@
|
||||
children = layoutState.updateChildren(container, evt.detail.items)
|
||||
// Ensure dragging is stopped on drag finish
|
||||
};
|
||||
|
||||
function handleClick({ clicked }: CustomEvent<boolean>) {
|
||||
navigator.vibrate(20)
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if container && children}
|
||||
@@ -100,7 +104,7 @@
|
||||
</Block>
|
||||
{:else}
|
||||
<Block elem_classes={["gradio-accordion"]}>
|
||||
<Accordion label={container.attrs.title} bind:open={container.isOpen}>
|
||||
<Accordion label={container.attrs.title} bind:open={container.isOpen} on:click={handleClick}>
|
||||
{#each children.filter(item => item.id !== SHADOW_PLACEHOLDER_ITEM_ID) as item(item.id)}
|
||||
<WidgetContainer dragItem={item} zIndex={zIndex+1} {isMobile} />
|
||||
{/each}
|
||||
|
||||
@@ -19,7 +19,7 @@ import ComfyGraphCanvas, { type SerializedGraphCanvasState } from "$lib/ComfyGra
|
||||
import type ComfyGraphNode from "$lib/nodes/ComfyGraphNode";
|
||||
import * as widgets from "$lib/widgets/index"
|
||||
import queueState from "$lib/stores/queueState";
|
||||
import type { SvelteComponentDev } from "svelte/internal";
|
||||
import { type SvelteComponentDev } from "svelte/internal";
|
||||
import type IComfyInputSlot from "$lib/IComfyInputSlot";
|
||||
import type { SerializedLayoutState } from "$lib/stores/layoutState";
|
||||
import layoutState from "$lib/stores/layoutState";
|
||||
@@ -27,8 +27,9 @@ import { toast } from '@zerodevx/svelte-toast'
|
||||
import ComfyGraph from "$lib/ComfyGraph";
|
||||
import { ComfyBackendNode } from "$lib/nodes/ComfyBackendNode";
|
||||
import { get } from "svelte/store";
|
||||
import { tick } from "svelte";
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import { download, jsonToJsObject, promptToGraphVis, workflowToGraphVis } from "$lib/utils";
|
||||
import { download, jsonToJsObject, promptToGraphVis, range, workflowToGraphVis } from "$lib/utils";
|
||||
import notify from "$lib/notify";
|
||||
import configState from "$lib/stores/configState";
|
||||
|
||||
@@ -72,6 +73,12 @@ export type Progress = {
|
||||
max: number
|
||||
}
|
||||
|
||||
type BackendComboNode = {
|
||||
comboNode: nodes.ComfyComboNode
|
||||
inputSlot: IComfyInputSlot,
|
||||
backendNode: ComfyBackendNode
|
||||
}
|
||||
|
||||
function isActiveBackendNode(node: ComfyGraphNode, tag: string | null): boolean {
|
||||
if (!node.isBackendNode)
|
||||
return false;
|
||||
@@ -764,47 +771,78 @@ export default class ComfyApp {
|
||||
async refreshComboInNodes(flashUI: boolean = false) {
|
||||
const defs = await this.api.getNodeDefs();
|
||||
|
||||
for (let nodeNum in this.lGraph._nodes) {
|
||||
const node = this.lGraph._nodes[nodeNum];
|
||||
if (node.type === "ui/combo") {
|
||||
(node as nodes.ComfyComboNode).valuesForCombo = null;
|
||||
(node as nodes.ComfyComboNode).comboRefreshed.set(true);
|
||||
const toUpdate: BackendComboNode[] = []
|
||||
|
||||
const isComfyComboNode = (node: LGraphNode): boolean => {
|
||||
return node
|
||||
&& node.type === "ui/combo"
|
||||
&& "doAutoConfig" in node;
|
||||
}
|
||||
|
||||
// Node IDs of combo widgets attached to a backend node
|
||||
let backendCombos: Set<number> = new Set()
|
||||
|
||||
console.debug("[refreshComboInNodes] start")
|
||||
|
||||
// Figure out which combo nodes to update. They need to be connected to
|
||||
// an input slot on a backend node with a backend config in the input
|
||||
// slot connected to.
|
||||
for (const node of this.lGraph.iterateNodesInOrder()) {
|
||||
if (!(node as any).isBackendNode)
|
||||
continue;
|
||||
|
||||
const backendNode = (node as ComfyBackendNode)
|
||||
const inputIndex = range(backendNode.inputs.length)
|
||||
.find(i => {
|
||||
const input = backendNode.inputs[i]
|
||||
const inputNode = backendNode.getInputNode(i)
|
||||
|
||||
// Does this input autocreate a combo box on creation?
|
||||
const isComfyInput = "config" in input
|
||||
&& "widgetNodeType" in input
|
||||
&& input.widgetNodeType === "ui/combo";
|
||||
|
||||
return isComfyComboNode(inputNode) && isComfyInput
|
||||
});
|
||||
|
||||
if (inputIndex != null) {
|
||||
const comboNode = backendNode.getInputNode(inputIndex) as nodes.ComfyComboNode
|
||||
const inputSlot = backendNode.inputs[inputIndex] as IComfyInputSlot;
|
||||
const def = defs[backendNode.type];
|
||||
|
||||
const hasBackendConfig = def["input"]["required"][inputSlot.name] !== undefined
|
||||
console.log("hasBackendConfig", node.title, inputSlot.name, hasBackendConfig)
|
||||
|
||||
if (hasBackendConfig) {
|
||||
backendCombos.add(comboNode.id)
|
||||
toUpdate.push({ comboNode, inputSlot, backendNode })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let seen = new Set()
|
||||
console.debug("[refreshComboInNodes] found:", toUpdate.length, toUpdate)
|
||||
|
||||
for (let nodeNum in this.lGraph._nodes) {
|
||||
const node = this.lGraph._nodes[nodeNum];
|
||||
// Mark combo nodes without backend configs as being loaded already.
|
||||
for (const node of this.lGraph.iterateNodesInOrder()) {
|
||||
if (isComfyComboNode(node) && !backendCombos.has(node.id)) {
|
||||
const comboNode = node as nodes.ComfyComboNode;
|
||||
comboNode.formatValues(comboNode.properties.values);
|
||||
}
|
||||
}
|
||||
|
||||
const def = defs[node.type];
|
||||
await tick();
|
||||
|
||||
for (let index = 0; index < node.inputs.length; index++) {
|
||||
const input = node.inputs[index];
|
||||
if ("config" in input) {
|
||||
const comfyInput = input as IComfyInputSlot;
|
||||
// Load definitions from the backend.
|
||||
for (const { comboNode, inputSlot, backendNode } of toUpdate) {
|
||||
const def = defs[backendNode.type];
|
||||
const rawValues = def["input"]["required"][inputSlot.name][0];
|
||||
|
||||
if (comfyInput.defaultWidgetNode == nodes.ComfyComboNode && def["input"]["required"][comfyInput.name] !== undefined) {
|
||||
const rawValues = def["input"]["required"][comfyInput.name][0];
|
||||
console.warn("[ComfyApp] Reconfiguring combo widget", backendNode.type, "=>", comboNode.type, inputSlot.config.values.length)
|
||||
comboNode.doAutoConfig(inputSlot, { includeProperties: new Set(["values"]), setWidgetTitle: false })
|
||||
|
||||
comfyInput.config.values = rawValues;
|
||||
const inputNode = node.getInputNode(index)
|
||||
|
||||
if (inputNode && "doAutoConfig" in inputNode && comfyInput.widgetNodeType === inputNode.type && !seen.has(inputNode.id)) {
|
||||
seen.add(inputNode.id)
|
||||
console.warn("[ComfyApp] Reconfiguring combo widget", inputNode.type, comfyInput.config.values.length)
|
||||
const comfyComboNode = inputNode as nodes.ComfyComboNode;
|
||||
comfyComboNode.doAutoConfig(comfyInput, { includeProperties: new Set(["values"]), setWidgetTitle: false })
|
||||
|
||||
comfyComboNode.formatValues(rawValues)
|
||||
if (!comfyInput.config.values.includes(get(comfyComboNode.value))) {
|
||||
comfyComboNode.setValue(comfyInput.config.defaultValue || comfyInput.config.values[0])
|
||||
}
|
||||
if (flashUI)
|
||||
comfyComboNode.comboRefreshed.set(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
comboNode.formatValues(rawValues)
|
||||
if (!inputSlot.config.values.includes(get(comboNode.value))) {
|
||||
comboNode.setValue(inputSlot.config.defaultValue || inputSlot.config.values[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,10 @@
|
||||
|
||||
return tabName
|
||||
}
|
||||
|
||||
function handleSelect() {
|
||||
navigator.vibrate(20)
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if container && children}
|
||||
@@ -113,7 +117,7 @@
|
||||
{/if}
|
||||
</Block>
|
||||
{:else}
|
||||
<Tabs elem_classes={["gradio-tabs"]}>
|
||||
<Tabs elem_classes={["gradio-tabs"]} on:select={handleSelect}>
|
||||
{#each children.filter(item => item.id !== SHADOW_PLACEHOLDER_ITEM_ID) as item, i(item.id)}
|
||||
{@const tabName = getTabName(container, i)}
|
||||
<TabItem name={tabName}>
|
||||
|
||||
44
src/lib/components/gradio/app/Accordion.svelte
Normal file
44
src/lib/components/gradio/app/Accordion.svelte
Normal file
@@ -0,0 +1,44 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from "svelte";
|
||||
export let label: string = "";
|
||||
export let open: boolean = true;
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
click: boolean;
|
||||
}>();
|
||||
|
||||
function handleClick() {
|
||||
open = !open;
|
||||
dispatch("click", open);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div on:click={handleClick} class="label-wrap" class:open>
|
||||
<span>{label}</span>
|
||||
<span style:transform={open ? "rotate(0)" : "rotate(90deg)"} class="icon">
|
||||
▼
|
||||
</span>
|
||||
</div>
|
||||
<div style:display={open ? "block" : "none"}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
span {
|
||||
font-weight: var(--section-header-text-weight);
|
||||
font-size: var(--section-header-text-size);
|
||||
}
|
||||
.label-wrap {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
width: var(--size-full);
|
||||
}
|
||||
.label-wrap.open {
|
||||
margin-bottom: var(--size-2);
|
||||
}
|
||||
|
||||
.icon {
|
||||
transition: 150ms;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user