More template work & configure backend URL
This commit is contained in:
@@ -22,7 +22,7 @@ import type ComfyGraphNode from "$lib/nodes/ComfyGraphNode";
|
||||
import { ComfyComboNode } from "$lib/nodes/widgets";
|
||||
import notify from "$lib/notify";
|
||||
import parseA1111, { type A1111ParsedInfotext } from "$lib/parseA1111";
|
||||
import configState from "$lib/stores/configState";
|
||||
import configState, { type ConfigState } from "$lib/stores/configState";
|
||||
import layoutStates, { defaultWorkflowAttributes, type SerializedLayoutState } from "$lib/stores/layoutStates";
|
||||
import modalState from "$lib/stores/modalState";
|
||||
import queueState from "$lib/stores/queueState";
|
||||
@@ -192,6 +192,11 @@ export default class ComfyApp {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.loadConfig();
|
||||
|
||||
this.api.hostname = get(configState).comfyUIHostname
|
||||
this.api.port = get(configState).comfyUIPort
|
||||
|
||||
this.setupColorScheme()
|
||||
|
||||
this.rootEl = document.getElementById("app-root") as HTMLDivElement;
|
||||
@@ -252,6 +257,20 @@ export default class ComfyApp {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO
|
||||
*/
|
||||
async loadConfig() {
|
||||
try {
|
||||
const config = await fetch(`/config.json`);
|
||||
const state = await config.json() as ConfigState;
|
||||
configState.set(state);
|
||||
}
|
||||
catch (error) {
|
||||
console.error(`Failed to load config`, error)
|
||||
}
|
||||
}
|
||||
|
||||
resizeCanvas() {
|
||||
this.canvasEl.width = this.canvasEl.parentElement.offsetWidth;
|
||||
this.canvasEl.height = this.canvasEl.parentElement.offsetHeight;
|
||||
@@ -282,7 +301,7 @@ export default class ComfyApp {
|
||||
|
||||
saveStateToLocalStorage() {
|
||||
try {
|
||||
uiState.update(s => { s.isSavingToLocalStorage = true; return s; })
|
||||
uiState.update(s => { s.forceSaveUserState = true; return s; })
|
||||
const state = get(workflowState)
|
||||
const workflows = state.openedWorkflows
|
||||
const savedWorkflows = workflows.map(w => this.serialize(w));
|
||||
@@ -298,7 +317,7 @@ export default class ComfyApp {
|
||||
notify(`Failed saving to local storage:\n${err}`, { type: "error" })
|
||||
}
|
||||
finally {
|
||||
uiState.update(s => { s.isSavingToLocalStorage = false; return s; })
|
||||
uiState.update(s => { s.forceSaveUserState = null; return s; })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1007,6 +1026,21 @@ export default class ComfyApp {
|
||||
reader.readAsText(file);
|
||||
} else if (file.type === "image/svg+xml" || file.name.endsWith(".svg")) {
|
||||
const templateAndSvg = await deserializeTemplateFromSVG(file);
|
||||
|
||||
const importTemplate = () => {
|
||||
try {
|
||||
if (templateState.add(templateAndSvg)) {
|
||||
notify("Template imported successfully!", { type: "success" })
|
||||
}
|
||||
else {
|
||||
notify("Template already exists in saved list.", { type: "warning" })
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
notify(`Error importing template: ${error}`, { type: "error", timeout: 10000 })
|
||||
}
|
||||
}
|
||||
|
||||
modalState.pushModal({
|
||||
title: "ComfyBox Template Preview",
|
||||
svelteComponent: EditTemplateModal,
|
||||
@@ -1017,6 +1051,11 @@ export default class ComfyApp {
|
||||
editable: false
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
name: "Import",
|
||||
variant: "primary",
|
||||
onClick: importTemplate
|
||||
},
|
||||
{
|
||||
name: "Close",
|
||||
variant: "secondary",
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
$: rebuildTemplates($templateState.templates);
|
||||
|
||||
function rebuildTemplates(templates: SerializedComfyBoxTemplate[]) {
|
||||
console.error("recreate");
|
||||
_sorted = Array.from(templates).map(t => {
|
||||
return {
|
||||
type: "template", id: uuidv4(), template: t, attrs: {...defaultWidgetAttributes}, attrsChanged: writable(0)
|
||||
@@ -76,6 +75,9 @@
|
||||
}
|
||||
|
||||
function handleClick(layout: TemplateLayout) {
|
||||
if ($uiState.uiUnlocked)
|
||||
return;
|
||||
|
||||
const updateTemplate = (modal: ModalData) => {
|
||||
const state = get(modal.state);
|
||||
layout.template.metadata.title = state.name || layout.template.metadata.title
|
||||
@@ -94,6 +96,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
const deleteTemplate = (modal: ModalData) => {
|
||||
if (!confirm("Are you sure you want to delete this template?"))
|
||||
return false;
|
||||
|
||||
try {
|
||||
if (templateState.remove(layout.template.id)) {
|
||||
notify("Template deleted!", { type: "success" })
|
||||
}
|
||||
else {
|
||||
notify("Failed to delete template: not saved to local storage.", { type: "warning" })
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
notify(`Failed to delete template: ${error}`, { type: "error", timeout: 10000 })
|
||||
}
|
||||
}
|
||||
|
||||
const downloadTemplate = (modal: ModalData) => {
|
||||
updateTemplate(modal);
|
||||
const svg = embedTemplateInSvg(layout.template);
|
||||
@@ -120,6 +139,11 @@
|
||||
onClick: downloadTemplate,
|
||||
closeOnClick: false
|
||||
},
|
||||
{
|
||||
name: "Delete",
|
||||
variant: "secondary",
|
||||
onClick: deleteTemplate
|
||||
},
|
||||
{
|
||||
name: "Close",
|
||||
variant: "secondary",
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
}
|
||||
|
||||
function onButtonClicked(modal: ModalData, button: ModalButton, closeDialog: Function) {
|
||||
button.onClick(modal);
|
||||
if (button.onClick(modal) === false)
|
||||
return
|
||||
|
||||
if (button.closeOnClick !== false) {
|
||||
closeDialog()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import UploadText from "$lib/components/gradio/app/UploadText.svelte";
|
||||
import type { ComfyImageLocation } from "$lib/nodes/ComfyWidgetNodes";
|
||||
import notify from "$lib/notify";
|
||||
import configState from "$lib/stores/configState";
|
||||
import { convertComfyOutputEntryToGradio, convertComfyOutputToComfyURL, type ComfyUploadImageAPIResponse } from "$lib/utils";
|
||||
import { Block, BlockLabel } from "@gradio/atoms";
|
||||
import { File as FileIcon } from "@gradio/icons";
|
||||
@@ -68,7 +69,7 @@
|
||||
|
||||
dispatch("uploading")
|
||||
|
||||
const url = `http://${location.hostname}:8188` // TODO make configurable
|
||||
const url = configState.getBackendURL();
|
||||
|
||||
const requests = files.map(async (file) => {
|
||||
const formData = new FormData();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type ComfyGraphCanvas from "$lib/ComfyGraphCanvas";
|
||||
import { type ContainerLayout, type IDragItem, type TemplateLayout, type WritableLayoutStateStore } from "$lib/stores/layoutStates"
|
||||
import type { LGraphCanvas } from "@litegraph-ts/core";
|
||||
import type { LGraphCanvas, Vector2 } from "@litegraph-ts/core";
|
||||
import { get } from "svelte/store";
|
||||
|
||||
export function handleContainerConsider(layoutState: WritableLayoutStateStore, container: ContainerLayout, evt: CustomEvent<DndEvent<IDragItem>>): IDragItem[] {
|
||||
@@ -39,12 +39,9 @@ function doInsertTemplate(layoutState: WritableLayoutStateStore, droppedTemplate
|
||||
|
||||
layoutState.updateChildren(container, newChildren);
|
||||
|
||||
const rect = canvas.ds.element.getBoundingClientRect();
|
||||
const width = rect?.width || 1;
|
||||
const height = rect?.height || 1;
|
||||
const center = canvas.convertOffsetToCanvas([width * 0.5, height * 0.5]);
|
||||
const newPos: Vector2 = [canvas.visible_area[0] + canvas.visible_area[2] / 2, canvas.visible_area[1] + canvas.visible_area[3] / 2]
|
||||
|
||||
canvas.insertTemplate(droppedTemplate.template, center, container, templateItemIndex);
|
||||
canvas.insertTemplate(droppedTemplate.template, newPos, container, templateItemIndex);
|
||||
|
||||
return get(layoutState).allItems[container.id].children;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user