Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ee7d03937 | ||
|
|
fdf1f08d8d | ||
|
|
94a5f52b3f | ||
|
|
f91680d435 | ||
|
|
5e88e7e406 | ||
|
|
7421b2ce9e | ||
|
|
eaf55eb974 | ||
|
|
4ef8e7e12b | ||
|
|
142458994e | ||
|
|
5ac4aa98a3 |
@@ -3148,6 +3148,68 @@ async def get_workflow_proxy(request):
|
|||||||
return web.json_response({"error": str(e)}, status=500)
|
return web.json_response({"error": str(e)}, status=500)
|
||||||
|
|
||||||
|
|
||||||
|
# fetch workflow versions (infinite scroll support)
|
||||||
|
@server.PromptServer.instance.routes.get("/comfyui-deploy/workflow/versions")
|
||||||
|
async def get_workflow_versions_proxy(request):
|
||||||
|
workflow_id = request.rel_url.query.get("workflow_id")
|
||||||
|
api_url = request.rel_url.query.get("api_url", "https://api.comfydeploy.com")
|
||||||
|
search = request.rel_url.query.get("search", "")
|
||||||
|
limit = request.rel_url.query.get("limit", "20")
|
||||||
|
offset = request.rel_url.query.get("offset", "0")
|
||||||
|
auth_header = request.headers.get("Authorization")
|
||||||
|
|
||||||
|
if not auth_header:
|
||||||
|
return web.json_response(
|
||||||
|
{"error": "Authorization header is required"}, status=401
|
||||||
|
)
|
||||||
|
|
||||||
|
# Build target URL with query params
|
||||||
|
params = {"limit": limit, "offset": offset}
|
||||||
|
if search:
|
||||||
|
params["search"] = search
|
||||||
|
|
||||||
|
query = urlencode(params)
|
||||||
|
target_url = f"{api_url}/api/workflow/{workflow_id}/versions"
|
||||||
|
if query:
|
||||||
|
target_url += f"?{query}"
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
# fetch a specific workflow version json
|
||||||
|
@server.PromptServer.instance.routes.get("/comfyui-deploy/workflow/version")
|
||||||
|
async def get_workflow_version_proxy(request):
|
||||||
|
workflow_id = request.rel_url.query.get("workflow_id")
|
||||||
|
version = request.rel_url.query.get("version")
|
||||||
|
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}/version/{version}"
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
# for getting a machine by id
|
# for getting a machine by id
|
||||||
@server.PromptServer.instance.routes.get("/comfyui-deploy/machine")
|
@server.PromptServer.instance.routes.get("/comfyui-deploy/machine")
|
||||||
async def get_machine_proxy(request):
|
async def get_machine_proxy(request):
|
||||||
@@ -3290,3 +3352,292 @@ async def get_comfyui_version_proxy(request):
|
|||||||
return web.json_response(json_data, status=response.status)
|
return web.json_response(json_data, status=response.status)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return web.json_response({"error": str(e)}, status=500)
|
return web.json_response({"error": str(e)}, status=500)
|
||||||
|
|
||||||
|
|
||||||
|
# Proxy: generate single-part upload URL
|
||||||
|
@server.PromptServer.instance.routes.post(
|
||||||
|
"/comfyui-deploy/volume/file/generate-upload-url"
|
||||||
|
)
|
||||||
|
async def proxy_generate_upload_url(request):
|
||||||
|
data = await request.json()
|
||||||
|
api_url = data.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/volume/file/generate-upload-url"
|
||||||
|
|
||||||
|
try:
|
||||||
|
await ensure_client_session()
|
||||||
|
async with client_session.post(
|
||||||
|
target_url,
|
||||||
|
json={
|
||||||
|
"filename": data.get("filename"),
|
||||||
|
"contentType": data.get("contentType"),
|
||||||
|
"size": data.get("size"),
|
||||||
|
},
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
# Proxy: initiate multipart upload
|
||||||
|
@server.PromptServer.instance.routes.post(
|
||||||
|
"/comfyui-deploy/volume/file/initiate-multipart-upload"
|
||||||
|
)
|
||||||
|
async def proxy_initiate_multipart_upload(request):
|
||||||
|
data = await request.json()
|
||||||
|
api_url = data.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/volume/file/initiate-multipart-upload"
|
||||||
|
|
||||||
|
try:
|
||||||
|
await ensure_client_session()
|
||||||
|
async with client_session.post(
|
||||||
|
target_url,
|
||||||
|
json={
|
||||||
|
"filename": data.get("filename"),
|
||||||
|
"contentType": data.get("contentType"),
|
||||||
|
"size": data.get("size"),
|
||||||
|
},
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
# Proxy: generate part upload URL
|
||||||
|
@server.PromptServer.instance.routes.post(
|
||||||
|
"/comfyui-deploy/volume/file/generate-part-upload-url"
|
||||||
|
)
|
||||||
|
async def proxy_generate_part_upload_url(request):
|
||||||
|
data = await request.json()
|
||||||
|
api_url = data.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/volume/file/generate-part-upload-url"
|
||||||
|
|
||||||
|
try:
|
||||||
|
await ensure_client_session()
|
||||||
|
async with client_session.post(
|
||||||
|
target_url,
|
||||||
|
json={
|
||||||
|
"uploadId": data.get("uploadId"),
|
||||||
|
"key": data.get("key"),
|
||||||
|
"partNumber": data.get("partNumber"),
|
||||||
|
},
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
# Proxy: complete multipart upload
|
||||||
|
@server.PromptServer.instance.routes.post(
|
||||||
|
"/comfyui-deploy/volume/file/complete-multipart-upload"
|
||||||
|
)
|
||||||
|
async def proxy_complete_multipart_upload(request):
|
||||||
|
data = await request.json()
|
||||||
|
api_url = data.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/volume/file/complete-multipart-upload"
|
||||||
|
|
||||||
|
try:
|
||||||
|
await ensure_client_session()
|
||||||
|
async with client_session.post(
|
||||||
|
target_url,
|
||||||
|
json={
|
||||||
|
"uploadId": data.get("uploadId"),
|
||||||
|
"key": data.get("key"),
|
||||||
|
"parts": data.get("parts"),
|
||||||
|
},
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
# Proxy: abort multipart upload
|
||||||
|
@server.PromptServer.instance.routes.post(
|
||||||
|
"/comfyui-deploy/volume/file/abort-multipart-upload"
|
||||||
|
)
|
||||||
|
async def proxy_abort_multipart_upload(request):
|
||||||
|
data = await request.json()
|
||||||
|
api_url = data.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/volume/file/abort-multipart-upload"
|
||||||
|
|
||||||
|
try:
|
||||||
|
await ensure_client_session()
|
||||||
|
async with client_session.post(
|
||||||
|
target_url,
|
||||||
|
json={
|
||||||
|
"uploadId": data.get("uploadId"),
|
||||||
|
"key": data.get("key"),
|
||||||
|
},
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
# Proxy: add model (unified endpoint)
|
||||||
|
@server.PromptServer.instance.routes.post("/comfyui-deploy/volume/model")
|
||||||
|
async def proxy_add_model(request):
|
||||||
|
data = await request.json()
|
||||||
|
api_url = data.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/volume/model"
|
||||||
|
|
||||||
|
# pass body through but remove api_url key
|
||||||
|
forward_body = dict(data)
|
||||||
|
if "api_url" in forward_body:
|
||||||
|
forward_body.pop("api_url")
|
||||||
|
|
||||||
|
try:
|
||||||
|
await ensure_client_session()
|
||||||
|
async with client_session.post(
|
||||||
|
target_url, json=forward_body, 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)
|
||||||
|
|
||||||
|
|
||||||
|
# FS: stat file (size)
|
||||||
|
@server.PromptServer.instance.routes.get("/comfyui-deploy/fs/stat")
|
||||||
|
async def fs_stat(request):
|
||||||
|
try:
|
||||||
|
import os
|
||||||
|
|
||||||
|
file_path = request.rel_url.query.get("path")
|
||||||
|
if not file_path:
|
||||||
|
return web.json_response({"error": "path is required"}, status=400)
|
||||||
|
|
||||||
|
# Basic safeguard: ensure it's a ComfyUI models path
|
||||||
|
if "/models/" not in file_path:
|
||||||
|
return web.json_response({"error": "invalid path"}, status=400)
|
||||||
|
|
||||||
|
st = os.stat(file_path)
|
||||||
|
return web.json_response({"size": st.st_size})
|
||||||
|
except FileNotFoundError:
|
||||||
|
return web.json_response({"error": "not found"}, status=404)
|
||||||
|
except Exception as e:
|
||||||
|
return web.json_response({"error": str(e)}, status=500)
|
||||||
|
|
||||||
|
|
||||||
|
# Upload a multipart part directly from machine filesystem to S3 upload URL
|
||||||
|
@server.PromptServer.instance.routes.post(
|
||||||
|
"/comfyui-deploy/volume/file/upload-part-from-path"
|
||||||
|
)
|
||||||
|
async def upload_part_from_path(request):
|
||||||
|
try:
|
||||||
|
import os
|
||||||
|
import io
|
||||||
|
|
||||||
|
data = await request.json()
|
||||||
|
file_path = data.get("filePath")
|
||||||
|
upload_url = data.get("uploadUrl")
|
||||||
|
start = int(data.get("start", 0))
|
||||||
|
end = int(data.get("end", 0))
|
||||||
|
if not file_path or not upload_url:
|
||||||
|
return web.json_response(
|
||||||
|
{"error": "filePath and uploadUrl are required"}, status=400
|
||||||
|
)
|
||||||
|
if "/models/" not in file_path:
|
||||||
|
return web.json_response({"error": "invalid filePath"}, status=400)
|
||||||
|
if end <= start:
|
||||||
|
return web.json_response({"error": "invalid byte range"}, status=400)
|
||||||
|
|
||||||
|
size = end - start
|
||||||
|
|
||||||
|
await ensure_client_session()
|
||||||
|
|
||||||
|
# Important: S3 pre-signed part uploads do not support chunked transfer
|
||||||
|
# Buffer the exact part into memory to provide a Content-Length header
|
||||||
|
buffer = bytearray()
|
||||||
|
chunk_size = 4 * 1024 * 1024
|
||||||
|
with open(file_path, "rb") as f:
|
||||||
|
f.seek(start)
|
||||||
|
remaining = size
|
||||||
|
while remaining > 0:
|
||||||
|
to_read = chunk_size if remaining >= chunk_size else remaining
|
||||||
|
chunk = f.read(to_read)
|
||||||
|
if not chunk:
|
||||||
|
break
|
||||||
|
buffer.extend(chunk)
|
||||||
|
remaining -= len(chunk)
|
||||||
|
|
||||||
|
if len(buffer) != size:
|
||||||
|
return web.json_response(
|
||||||
|
{
|
||||||
|
"error": "read size mismatch",
|
||||||
|
"expected": size,
|
||||||
|
"actual": len(buffer),
|
||||||
|
},
|
||||||
|
status=500,
|
||||||
|
)
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Content-Length": str(size),
|
||||||
|
"Content-Type": "application/octet-stream",
|
||||||
|
}
|
||||||
|
|
||||||
|
async with client_session.put(
|
||||||
|
upload_url, data=bytes(buffer), headers=headers
|
||||||
|
) as resp:
|
||||||
|
text = await resp.text()
|
||||||
|
if resp.status < 200 or resp.status >= 300:
|
||||||
|
return web.json_response(
|
||||||
|
{"error": f"upload failed: {resp.status}", "body": text},
|
||||||
|
status=resp.status,
|
||||||
|
)
|
||||||
|
etag = resp.headers.get("ETag") or resp.headers.get("etag") or ""
|
||||||
|
etag = etag.replace('"', "")
|
||||||
|
return web.json_response({"eTag": etag, "bytesSent": size})
|
||||||
|
except Exception as e:
|
||||||
|
return web.json_response({"error": str(e)}, status=500)
|
||||||
|
|||||||
+145
-21
@@ -3,13 +3,15 @@ import { api } from "../../scripts/api.js";
|
|||||||
// import { LGraphNode } from "../../scripts/widgets.js";
|
// import { LGraphNode } from "../../scripts/widgets.js";
|
||||||
LGraphNode = LiteGraph.LGraphNode;
|
LGraphNode = LiteGraph.LGraphNode;
|
||||||
import { ComfyDialog, $el } from "../../scripts/ui.js";
|
import { ComfyDialog, $el } from "../../scripts/ui.js";
|
||||||
import { initializeWorkflowsList, addWorkflowSearch } from "./workflow-list.js";
|
import {
|
||||||
|
initializeWorkflowsList,
|
||||||
|
addWorkflowSearch,
|
||||||
|
refreshCurrentWorkflowCard,
|
||||||
|
} from "./workflow-list.js";
|
||||||
import { initializeMachineManager } from "./machine-manager.js";
|
import { initializeMachineManager } from "./machine-manager.js";
|
||||||
|
import { initializeModelManager } from "./model-manager.js";
|
||||||
import { fetchSnapshotSimple } from "./snapshot-utils.js";
|
import { fetchSnapshotSimple } from "./snapshot-utils.js";
|
||||||
|
|
||||||
import { generateDependencyGraph } from "https://esm.sh/comfyui-json@0.1.25";
|
|
||||||
// import { ComfyDeploy } from "https://esm.sh/comfydeploy@2.0.0-beta.69";
|
|
||||||
|
|
||||||
const styles = `
|
const styles = `
|
||||||
.comfydeploy-menu-item {
|
.comfydeploy-menu-item {
|
||||||
background: linear-gradient(to right, rgba(74, 144, 226, 0.9), rgba(103, 178, 111, 0.9)) !important;
|
background: linear-gradient(to right, rgba(74, 144, 226, 0.9), rgba(103, 178, 111, 0.9)) !important;
|
||||||
@@ -538,7 +540,9 @@ const ext = {
|
|||||||
}
|
}
|
||||||
if (toInput.length) {
|
if (toInput.length) {
|
||||||
if (true) {
|
if (true) {
|
||||||
let optionIndex = options.findIndex((o) => o && o.content === "Outputs");
|
let optionIndex = options.findIndex(
|
||||||
|
(o) => o && o.content === "Outputs"
|
||||||
|
);
|
||||||
if (optionIndex === -1) optionIndex = options.length;
|
if (optionIndex === -1) optionIndex = options.length;
|
||||||
else optionIndex++;
|
else optionIndex++;
|
||||||
options.splice(
|
options.splice(
|
||||||
@@ -735,7 +739,7 @@ const ext = {
|
|||||||
"string",
|
"string",
|
||||||
inputName,
|
inputName,
|
||||||
/* value=*/ "",
|
/* value=*/ "",
|
||||||
() => { },
|
() => {},
|
||||||
{ serialize: true }
|
{ serialize: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1330,6 +1334,14 @@ async function deployWorkflow() {
|
|||||||
|
|
||||||
deployMetaNode.widgets[2].value = data.version;
|
deployMetaNode.widgets[2].value = data.version;
|
||||||
graph.change();
|
graph.change();
|
||||||
|
|
||||||
|
if (window.refreshCurrentWorkflowCard) {
|
||||||
|
console.log(
|
||||||
|
"Refreshing current workflow card after version update with version",
|
||||||
|
data.version
|
||||||
|
);
|
||||||
|
window.refreshCurrentWorkflowCard(workflow_id, data.version);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
infoDialog.showError("Error", e.message);
|
infoDialog.showError("Error", e.message);
|
||||||
@@ -1424,6 +1436,20 @@ async function deployWorkflow() {
|
|||||||
|
|
||||||
if (new_version_data.status !== 200) {
|
if (new_version_data.status !== 200) {
|
||||||
throw new Error(await new_version_data.text());
|
throw new Error(await new_version_data.text());
|
||||||
|
} else {
|
||||||
|
// Parse the JSON response to get the actual version data
|
||||||
|
const versionData = await new_version_data.json();
|
||||||
|
|
||||||
|
if (window.refreshCurrentWorkflowCard) {
|
||||||
|
console.log(
|
||||||
|
"Refreshing current workflow card with new version",
|
||||||
|
versionData.version
|
||||||
|
);
|
||||||
|
window.refreshCurrentWorkflowCard(
|
||||||
|
data.workflow_id,
|
||||||
|
versionData.version
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1718,9 +1744,11 @@ export class LoadingDialog extends ComfyDialog {
|
|||||||
showLoading(title, message) {
|
showLoading(title, message) {
|
||||||
this.show(`
|
this.show(`
|
||||||
<div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
<div style="width: 400px; display: flex; gap: 18px; flex-direction: column; overflow: unset">
|
||||||
<h3 style="margin: 0px; display: flex; align-items: center; justify-content: center; gap: 12px;">${title} ${this.loadingIcon
|
<h3 style="margin: 0px; display: flex; align-items: center; justify-content: center; gap: 12px;">${title} ${
|
||||||
|
this.loadingIcon
|
||||||
}</h3>
|
}</h3>
|
||||||
${message
|
${
|
||||||
|
message
|
||||||
? `<label style="max-width: 100%; white-space: pre-wrap; word-wrap: break-word;">${message}</label>`
|
? `<label style="max-width: 100%; white-space: pre-wrap; word-wrap: break-word;">${message}</label>`
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
@@ -2308,9 +2336,11 @@ export class ConfigDialog extends ComfyDialog {
|
|||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
" onfocus="this.style.borderColor='#0ea5e9'; this.style.background='#252525'; this.style.boxShadow='0 0 0 3px rgba(14, 165, 233, 0.1)'" onblur="this.style.borderColor='#404040'; this.style.background='#1a1a1a'; this.style.boxShadow='none'" onmouseover="this.style.borderColor='#525252'" onmouseout="if(document.activeElement !== this) this.style.borderColor='#404040'">
|
" onfocus="this.style.borderColor='#0ea5e9'; this.style.background='#252525'; this.style.boxShadow='0 0 0 3px rgba(14, 165, 233, 0.1)'" onblur="this.style.borderColor='#404040'; this.style.background='#1a1a1a'; this.style.boxShadow='none'" onmouseover="this.style.borderColor='#525252'" onmouseout="if(document.activeElement !== this) this.style.borderColor='#404040'">
|
||||||
<option value="cloud" ${data.environment === "cloud" ? "selected" : ""
|
<option value="cloud" ${
|
||||||
|
data.environment === "cloud" ? "selected" : ""
|
||||||
}>☁️ Cloud Deployment</option>
|
}>☁️ Cloud Deployment</option>
|
||||||
<option value="local" ${data.environment === "local" ? "selected" : ""
|
<option value="local" ${
|
||||||
|
data.environment === "local" ? "selected" : ""
|
||||||
}>🏠 Local Development</option>
|
}>🏠 Local Development</option>
|
||||||
</select>
|
</select>
|
||||||
<div style="
|
<div style="
|
||||||
@@ -2376,7 +2406,8 @@ export class ConfigDialog extends ComfyDialog {
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
">API Key</label>
|
">API Key</label>
|
||||||
${data.displayName
|
${
|
||||||
|
data.displayName
|
||||||
? `
|
? `
|
||||||
<div style="
|
<div style="
|
||||||
background: linear-gradient(135deg, #0ea5e9, #3b82f6);
|
background: linear-gradient(135deg, #0ea5e9, #3b82f6);
|
||||||
@@ -2443,7 +2474,8 @@ export class ConfigDialog extends ComfyDialog {
|
|||||||
<polyline points="10,17 15,12 10,7"/>
|
<polyline points="10,17 15,12 10,7"/>
|
||||||
<line x1="15" y1="12" x2="3" y2="12"/>
|
<line x1="15" y1="12" x2="3" y2="12"/>
|
||||||
</svg>
|
</svg>
|
||||||
${data.apiKey
|
${
|
||||||
|
data.apiKey
|
||||||
? "Re-authenticate with ComfyDeploy"
|
? "Re-authenticate with ComfyDeploy"
|
||||||
: "Login with ComfyDeploy"
|
: "Login with ComfyDeploy"
|
||||||
}
|
}
|
||||||
@@ -2526,14 +2558,12 @@ export class ConfigDialog extends ComfyDialog {
|
|||||||
export const configDialog = new ConfigDialog();
|
export const configDialog = new ConfigDialog();
|
||||||
|
|
||||||
const currentOrigin = window.location.origin;
|
const currentOrigin = window.location.origin;
|
||||||
// const client = new ComfyDeploy({
|
const referrer = document.referrer;
|
||||||
// bearerAuth: getData().apiKey,
|
|
||||||
// serverURL: `${currentOrigin}/comfydeploy/api/`,
|
|
||||||
// });
|
|
||||||
|
|
||||||
const isComfyDeployDashboard = currentOrigin.includes("comfydeploy.com");
|
const isComfyDeployDashboard =
|
||||||
|
currentOrigin.includes("comfydeploy.com") ||
|
||||||
|
(referrer && referrer.includes("comfydeploy.com"));
|
||||||
|
|
||||||
// Only register the sidebar tab if we're on localhost
|
|
||||||
if (!isComfyDeployDashboard) {
|
if (!isComfyDeployDashboard) {
|
||||||
app.extensionManager.registerSidebarTab({
|
app.extensionManager.registerSidebarTab({
|
||||||
id: "search",
|
id: "search",
|
||||||
@@ -2547,12 +2577,68 @@ if (!isComfyDeployDashboard) {
|
|||||||
<h3>Comfy Deploy</h3>
|
<h3>Comfy Deploy</h3>
|
||||||
<div id="deploy-container" style="margin-bottom: 20px;"></div>
|
<div id="deploy-container" style="margin-bottom: 20px;"></div>
|
||||||
<div id="machine-container" style="margin-bottom: 20px;">
|
<div id="machine-container" style="margin-bottom: 20px;">
|
||||||
<h4>Serverless Machine</h4>
|
<div style="
|
||||||
|
display: flex;
|
||||||
|
border-bottom: 1px solid #333;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
position: relative;
|
||||||
|
">
|
||||||
|
<button
|
||||||
|
id="machine-tab"
|
||||||
|
onclick="switchTab('machine')"
|
||||||
|
style="
|
||||||
|
background: transparent;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 12px 16px 8px 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
border-bottom: 2px solid #3498db;
|
||||||
|
"
|
||||||
|
onmouseover="this.style.color='#fff'"
|
||||||
|
onmouseout="if(this.style.borderBottomColor !== 'rgb(52, 152, 219)') this.style.color='#999'"
|
||||||
|
>
|
||||||
|
Machine
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
id="model-tab"
|
||||||
|
onclick="switchTab('model')"
|
||||||
|
style="
|
||||||
|
background: transparent;
|
||||||
|
color: #999;
|
||||||
|
border: none;
|
||||||
|
padding: 12px 16px 8px 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
"
|
||||||
|
onmouseover="this.style.color='#fff'"
|
||||||
|
onmouseout="if(this.style.borderBottomColor !== 'rgb(52, 152, 219)') this.style.color='#999'"
|
||||||
|
>
|
||||||
|
Model
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="machine-tab-content">
|
||||||
<div id="machine-loading" style="display: flex; justify-content: center; align-items: center; height: 100px;">
|
<div id="machine-loading" style="display: flex; justify-content: center; align-items: center; height: 100px;">
|
||||||
${loadingIcon}
|
${loadingIcon}
|
||||||
</div>
|
</div>
|
||||||
<ul id="machine-list" style="list-style-type: none; padding: 0; display: none;"></ul>
|
<ul id="machine-list" style="list-style-type: none; padding: 0; display: none;"></ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="model-tab-content" style="display: none;">
|
||||||
|
<div id="model-loading" style="display: flex; justify-content: center; align-items: center; height: 100px;">
|
||||||
|
${loadingIcon}
|
||||||
|
</div>
|
||||||
|
<ul id="model-list" style="list-style-type: none; padding: 0; display: none;"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div id="workflows-container" style="display: none;">
|
<div id="workflows-container" style="display: none;">
|
||||||
<h4>Your Workflows</h4>
|
<h4>Your Workflows</h4>
|
||||||
<div id="workflows-loading" style="display: flex; justify-content: center; align-items: center; height: 100px;">
|
<div id="workflows-loading" style="display: flex; justify-content: center; align-items: center; height: 100px;">
|
||||||
@@ -2613,10 +2699,41 @@ if (!isComfyDeployDashboard) {
|
|||||||
const workflowsList = el.querySelector("#workflows-list");
|
const workflowsList = el.querySelector("#workflows-list");
|
||||||
const workflowsLoading = el.querySelector("#workflows-loading");
|
const workflowsLoading = el.querySelector("#workflows-loading");
|
||||||
|
|
||||||
// Initialize machine manager
|
// Initialize machine and model managers
|
||||||
const data = getData();
|
const data = getData();
|
||||||
if (data.apiKey) {
|
if (data.apiKey) {
|
||||||
await initializeMachineManager(el, getData);
|
await initializeMachineManager(el, getData);
|
||||||
|
await initializeModelManager(el, getData);
|
||||||
|
|
||||||
|
// Add tab switching functionality
|
||||||
|
window.switchTab = function (tabName) {
|
||||||
|
const machineTab = el.querySelector("#machine-tab");
|
||||||
|
const modelTab = el.querySelector("#model-tab");
|
||||||
|
const machineContent = el.querySelector("#machine-tab-content");
|
||||||
|
const modelContent = el.querySelector("#model-tab-content");
|
||||||
|
|
||||||
|
if (tabName === "machine") {
|
||||||
|
// Active machine tab
|
||||||
|
machineTab.style.color = "white";
|
||||||
|
machineTab.style.borderBottomColor = "#3498db";
|
||||||
|
// Inactive model tab
|
||||||
|
modelTab.style.color = "#999";
|
||||||
|
modelTab.style.borderBottomColor = "transparent";
|
||||||
|
// Show/hide content
|
||||||
|
machineContent.style.display = "block";
|
||||||
|
modelContent.style.display = "none";
|
||||||
|
} else if (tabName === "model") {
|
||||||
|
// Active model tab
|
||||||
|
modelTab.style.color = "white";
|
||||||
|
modelTab.style.borderBottomColor = "#3498db";
|
||||||
|
// Inactive machine tab
|
||||||
|
machineTab.style.color = "#999";
|
||||||
|
machineTab.style.borderBottomColor = "transparent";
|
||||||
|
// Show/hide content
|
||||||
|
modelContent.style.display = "block";
|
||||||
|
machineContent.style.display = "none";
|
||||||
|
}
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
// Hide machine container when no API key
|
// Hide machine container when no API key
|
||||||
const machineContainer = el.querySelector("#machine-container");
|
const machineContainer = el.querySelector("#machine-container");
|
||||||
@@ -2717,7 +2834,11 @@ api.fetchApi = async (route, options) => {
|
|||||||
const data = {
|
const data = {
|
||||||
prompt_id: body.prompt_id,
|
prompt_id: body.prompt_id,
|
||||||
};
|
};
|
||||||
const original_response = await orginal_fetch_api.call(api, route, options);
|
const original_response = await orginal_fetch_api.call(
|
||||||
|
api,
|
||||||
|
route,
|
||||||
|
options
|
||||||
|
);
|
||||||
await fetch("/comfyui-deploy/interrupt", {
|
await fetch("/comfyui-deploy/interrupt", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -3061,6 +3182,9 @@ async function refreshWorkflowListIfOpen() {
|
|||||||
// Reinitialize the workflow list
|
// Reinitialize the workflow list
|
||||||
await initializeWorkflowsList(document, getData, getTimeAgo);
|
await initializeWorkflowsList(document, getData, getTimeAgo);
|
||||||
|
|
||||||
|
// Also refresh the current workflow card
|
||||||
|
refreshCurrentWorkflowCard();
|
||||||
|
|
||||||
console.log("Workflow list refreshed successfully");
|
console.log("Workflow list refreshed successfully");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error refreshing workflow list:", error);
|
console.error("Error refreshing workflow list:", error);
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ function showNoMachineMessage(machineLoading, machineList) {
|
|||||||
<line x1="6" x2="6.01" y1="18" y2="18"/>
|
<line x1="6" x2="6.01" y1="18" y2="18"/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div style="font-weight: 500; margin-bottom: 12px;">No machine found</div>
|
<div style="font-weight: 500; margin-bottom: 12px; font-size: 12px;">No machine found</div>
|
||||||
<div style="display: flex; gap: 8px; justify-content: center;">
|
<div style="display: flex; gap: 8px; justify-content: center;">
|
||||||
<button
|
<button
|
||||||
onclick="showAddMachineDialog()"
|
onclick="showAddMachineDialog()"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+950
-26
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user