diff --git a/js/comfy/ui.js b/js/comfy/ui.js index c6fe222..bb769b5 100644 --- a/js/comfy/ui.js +++ b/js/comfy/ui.js @@ -22,6 +22,12 @@ export class ComfyCloudPopover extends ComfyDialog { }); + // VanJS content + this.container = document.createElement("div"); + this.container.style.color = "white"; + this.container.style.overflow = "hidden"; + + // Title this.title = document.createElement("div"); this.title.style.fontSize = "18px"; @@ -38,6 +44,8 @@ export class ComfyCloudPopover extends ComfyDialog { this.collapsed = !this.collapsed; this.component.style.height = this.collapsed ? "0" : "auto"; this.collapseButton.style.transform = this.collapsed ? "rotate(180deg)" : "rotate(0deg)"; + this.container.style.overflow = this.collapsed ? "hidden" : "auto"; + this.container.style.overflowY = this.collapsed ? "hidden" : "scroll"; } // Title + collapse button wrapper @@ -50,11 +58,6 @@ export class ComfyCloudPopover extends ComfyDialog { this.header.append(this.collapseButton); - // VanJS content - this.container = document.createElement("div"); - this.container.style.color = "white"; - this.container.style.overflow = "hidden"; - this.component = null; this.ui = ui diff --git a/js/ui/uploadProgress.js b/js/ui/uploadProgress.js index 20d66fa..1b61482 100644 --- a/js/ui/uploadProgress.js +++ b/js/ui/uploadProgress.js @@ -28,9 +28,32 @@ const ProgressBar = (progress) => { export const taskId = van.state(null) export const Progress = (dialogInstance) => { - const activeTab = van.state(0) const data = van.state(local.pollUploadStatus(taskId.val)) // workflowRun data + const combineCustomNodeData = (data) => { + const result = {}; + + for (const [path, obj] of Object.entries(data)) { + if (path.includes('custom_nodes')) { + const parts = path.split('/'); + const nodeIndex = parts.indexOf('custom_nodes') + 1; + const nodePath = parts.slice(0, nodeIndex + 1).join('/'); + + if (!result[nodePath]) { + result[nodePath] = { "max": 0, "value": 0 }; + } + + result[nodePath]["max"] += obj["max"]; + result[nodePath]["value"] += obj["value"]; + + } else { + result[path] = obj; + } + } + + return result; + } + const start = () => dialogInstance.poll = dialogInstance.poll || setInterval(async () => { const res = await local.pollUploadStatus(taskId.val) @@ -45,12 +68,13 @@ export const Progress = (dialogInstance) => { dialogInstance, dialogInstance.poll = 0; } - data.val = Promise.resolve(res) - }, 1000) + const formattedData = { ...res, progress: combineCustomNodeData(res.progress)} + data.val = Promise.resolve(formattedData) + }, 2500) start() - return () => van.tags.div({style: 'width: 360px'}, + return () => div({style: 'width: 360px; overflow-y: scroll; height: 480px;'}, Await({ value: data.val, container: span, diff --git a/python/upload/__init__.py b/python/upload/__init__.py index 4075a4a..1b474b5 100644 --- a/python/upload/__init__.py +++ b/python/upload/__init__.py @@ -2,6 +2,7 @@ import io import os import asyncio import aiostream +import json from typing import List, Callable from .spec import FileSpecContextManager, serialize_spec, FileUploadSpec @@ -29,7 +30,14 @@ async def upload_file_specs( for idx, spec in enumerate(serialized_specs): spec["id"] = idx serialized_specs_dict[idx] = spec - + + # Check serialized specs + max_size = 50 * 1024 * 1024 # 50 MB in bytes + json_data = json.dumps(serialized_specs) + json_size = len(json_data.encode('utf-8')) + if json_size > max_size: + raise Exception(f'Workflow too large error. File specs size exceeds the 50MB limit: {data_size} bytes') + if hashing_complete_callback is not None: hashing_complete_callback() @@ -40,7 +48,6 @@ async def upload_file_specs( response_data = await make_post_request(url, { "specs": serialized_specs, "workflow_id": workflow_id }) upload_data = response_data["data"] - # Create the upload data # Mix the response data from the server and the file spec # and pass it to the generator diff --git a/python/upload/spec.py b/python/upload/spec.py index 9e309d2..42780cc 100644 --- a/python/upload/spec.py +++ b/python/upload/spec.py @@ -282,6 +282,10 @@ class _FileSpecContextManager: def gen(): glob = local_path.rglob("*") if recursive else local_path.glob("*") for subpath in glob: + # skip if subpath contains .git or __pycache__ + if ".git" in subpath.parts or "__pycache__" in subpath.parts: + continue + # Skip directories and unsupported file types (e.g. block devices) if subpath.is_file(): yield create_file_spec_provider(subpath)