From 4cbd2a822591288a13de9e49757b7ffc812d03bb Mon Sep 17 00:00:00 2001 From: KarrixLee Date: Mon, 16 Jun 2025 21:01:43 +0800 Subject: [PATCH] Add workflow retrieval functionality and enhance UI interaction - Introduced a new endpoint in custom_routes.py for fetching workflows by ID, including authorization checks and error handling. - Updated workflow-list.js to support fetching and displaying workflow data upon user interaction, including loading indicators and error handling. - Enhanced the createWorkflowItem function to accept additional parameters for improved data handling and user feedback. These changes improve the user experience by enabling seamless workflow retrieval and interaction within the application. --- custom_routes.py | 25 +++++++ web-plugin/workflow-list.js | 129 +++++++++++++++++++++++++++++------- 2 files changed, 129 insertions(+), 25 deletions(-) diff --git a/custom_routes.py b/custom_routes.py index 849fc92..5fc6d80 100644 --- a/custom_routes.py +++ b/custom_routes.py @@ -3035,3 +3035,28 @@ async def get_workflows_proxy(request): return web.json_response(json_data, status=response.status) except Exception as e: return web.json_response({"error": str(e)}, status=500) + + +# for getting a workflow by id +@server.PromptServer.instance.routes.get("/comfyui-deploy/workflow") +async def get_workflow_proxy(request): + workflow_id = request.rel_url.query.get("workflow_id") + api_url = request.rel_url.query.get("api_url", "https://api.comfydeploy.com") + auth_header = request.headers.get("Authorization") + + if not auth_header: + return web.json_response( + {"error": "Authorization header is required"}, status=401 + ) + + target_url = f"{api_url}/api/workflow/{workflow_id}" + + try: + await ensure_client_session() + async with client_session.get( + target_url, headers={"Authorization": auth_header} + ) as response: + json_data = await response.json() + return web.json_response(json_data, status=response.status) + except Exception as e: + return web.json_response({"error": str(e)}, status=500) diff --git a/web-plugin/workflow-list.js b/web-plugin/workflow-list.js index 46ce5a2..cd1cf83 100644 --- a/web-plugin/workflow-list.js +++ b/web-plugin/workflow-list.js @@ -44,7 +44,7 @@ async function fetchWorkflows(getData, offset = 0, limit = 20, search = "") { } } -function createWorkflowItem(workflow, getTimeAgo) { +function createWorkflowItem(workflow, getTimeAgo, getData) { const li = document.createElement("li"); li.style.cssText = ` border-bottom: 1px solid #444; @@ -61,6 +61,73 @@ function createWorkflowItem(workflow, getTimeAgo) { li.style.background = "transparent"; }); + // Add click handler to fetch and load workflow data + li.addEventListener("click", async () => { + try { + const data = getData(); + if (!data.apiKey) { + console.error("No API key configured"); + return; + } + + // Show loading toast + const loadingToast = window.app.extensionManager.toast.add({ + severity: "info", + summary: "Loading workflow...", + detail: `Loading "${workflow.name}"`, + life: 3000, + }); + + const params = new URLSearchParams({ + workflow_id: workflow.id, + api_url: data.apiUrl || "https://api.comfydeploy.com", + }); + + const response = await fetch(`/comfyui-deploy/workflow?${params}`, { + method: "GET", + headers: { + Authorization: `Bearer ${data.apiKey}`, + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + throw new Error(`Failed to fetch workflow: ${response.status}`); + } + + const workflowData = await response.json(); + console.log("Workflow data:", workflowData); + + // Load the workflow into the graph + if (workflowData.versions && workflowData.versions.length > 0) { + const latestVersion = workflowData.versions[0]; + if (latestVersion.workflow && window.app) { + // Load the workflow + window.app.loadGraphData(latestVersion.workflow); + + // Show success toast + window.app.extensionManager.toast.add({ + severity: "success", + summary: "Workflow loaded successfully", + detail: `Loaded "${workflow.name}" v${latestVersion.version}`, + life: 3000, + }); + } + } + } catch (error) { + console.error("Error loading workflow:", error); + // Show error toast + window.app.extensionManager.toast.add({ + severity: "error", + summary: "Failed to load workflow", + detail: error.message, + life: 5000, + }); + } finally { + loadingToast.close(); + } + }); + const updatedDate = new Date(workflow.updated_at); const timeAgo = getTimeAgo(updatedDate); @@ -69,39 +136,40 @@ function createWorkflowItem(workflow, getTimeAgo) {
${ workflow.cover_image - ? ` -
- Workflow cover -
- 📄 -
-
- ` - : ` -
- 📄 -
- ` + ? `` + : `
+ ${workflow.name.charAt(0).toUpperCase()} +
` }
-
+

${workflow.name} -

+ ${ workflow.pinned - ? '📌' + ? `📌` : "" }
-
+ ${ + workflow.description + ? `

+ ${workflow.description} +

` + : "" + } + +
+ - Updated ${timeAgo} + ${workflow.user_name} • Updated ${timeAgo}
@@ -139,7 +207,7 @@ async function loadMoreWorkflows(element, getData, getTimeAgo) { // Render new workflow items newWorkflows.forEach((workflow) => { - const workflowItem = createWorkflowItem(workflow, getTimeAgo); + const workflowItem = createWorkflowItem(workflow, getTimeAgo, getData); workflowsList.appendChild(workflowItem); }); } @@ -174,10 +242,16 @@ async function initializeWorkflowsList(element, getData, getTimeAgo) { const workflowsList = element.querySelector("#workflows-list"); const workflowsLoading = element.querySelector("#workflows-loading"); - if (workflowsState.initialized) return; + // Check if already initialized AND the DOM elements still exist + if ( + workflowsState.initialized && + workflowsList && + workflowsList.children.length > 0 + ) + return; try { - // Reset state + // Reset state (always reset when reinitializing) workflowsState = { workflows: [], offset: 0, @@ -188,6 +262,11 @@ async function initializeWorkflowsList(element, getData, getTimeAgo) { currentSearch: "", }; + // Clear existing content in case of reinitialization + if (workflowsList) { + workflowsList.innerHTML = ""; + } + // Show container and loading workflowsContainer.style.display = "block"; workflowsLoading.style.display = "flex";