Files
nathannlu-ComfyUI-Cloud/js/node/workflows.ui.js
T
2024-03-13 13:10:20 -07:00

188 lines
5.3 KiB
JavaScript

import { headerHtml } from '../ui.js';
import { ComfyDialog, $el } from '../comfy/comfy.js';
import { getCloudWorkflow, getWorkflowRunOutput } from '../client.js';
class WorkflowTableDialog extends ComfyDialog {
container = null;
constructor() {
super();
this.element.classList.add("comfy-normal-modal");
this.element.style.paddingBottom = "20px";
this.element.style.overflowY = "auto";
this.container = document.createElement("div");
this.container.style.color = "white";
this.container.style.width = "720px";
this.container.style.minHeight = "540px";
this.header = document.createElement("div");
this.header.innerHTML = headerHtml
this.element.querySelector(".comfy-modal-content").prepend(this.container);
this.element.querySelector(".comfy-modal-content").prepend(this.header);
}
createButtons() {
return [
$el(
"div",
[
$el("button", {
type: "button",
textContent: "Close",
onclick: () => this.close(),
}),
],
),
];
}
close() {
this.element.style.display = "none";
}
async show() {
await this.showWorkflowsTable();
}
async showWorkflowDetails(id) {
const data = await getWorkflowRunOutput(id)
this.container.innerHTML = workflowDetailsHtml(data);
const link = this.container.querySelector("#back-button");
link.onclick = async () => {
await this.showWorkflowsTable()
};
this.element.style.display = "flex";
this.element.style.zIndex = 1001;
}
async showWorkflowsTable() {
// @todo - call api to set data
const workflow = await getCloudWorkflow()
this.runs = workflow.runs || [];
this.container.innerHTML = tableHtml(this.runs);
const workflowRows = this.container.querySelectorAll(".workflow-row");
workflowRows.forEach((row, i) => {
row.onclick = async () => {
const rowId = this.runs[i].id
await this.showWorkflowDetails(rowId)
}
});
this.element.style.display = "flex";
this.element.style.zIndex = 1001;
}
}
export const workflowTableDialog = new WorkflowTableDialog()
// Function to handle row click
const workflowDetailsHtml = (rowDetails) => {
//const imageData = rowDetails.outputs[0]?.data.images[0].filename;
return`
<div style="padding: 20px; border: 1px solid #ddd; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);">
<h2>Row Details</h2>
<p><strong>Status:</strong> <span style="color: ${rowDetails.status === 'success' ? '#4CAF50' : '#FFC107'};">${rowDetails.status}</span></p>
${generateOutputs(rowDetails.outputs)}
<button id="back-button">Back</button>
</div>
`;
}
const generateOutputs = (outputs) => {
return outputs?.map((run) => {
const fileName = run.data.images?.[0].filename ||
run.data.files?.[0].filename ||
run.data.gifs?.[0].filename;
if (!fileName) {
return`
<TableRow key={run.id}>
<TableCell>Output</TableCell>
<TableCell className="">
<CodeBlock
code={JSON.stringify(run.data, null, 2)}
lang="json"
/>
</TableCell>
</TableRow>
`;
}
// const filePath
return `
<tr key={run.id}>
<TableCell className="break-words">${fileName}</TableCell>
<TableCell>
${generateOutputDisplay(run.run_id, fileName)}
</TableCell>
</TableRow>
`;
}).join('');
}
const generateOutputDisplay = (run_id, filename) => {
const url = `https://comfyui-output.nyc3.digitaloceanspaces.com/comfyui-output/outputs/runs/${run_id}/${filename}`
if (filename.endsWith(".mp4") || filename.endsWith(".webm")) {
return`
<video controls autoPlay className="w-[400px]">
<source src="${url}" type="video/mp4" />
<source src="${url}" type="video/webm" />
Your browser does not support the video tag.
</video>
`;
}
if (
filename.endsWith(".png") ||
filename.endsWith(".gif") ||
filename.endsWith(".jpg") ||
filename.endsWith(".jpeg")
) {
return `<img className="max-w-[200px]" alt="${filename}" src="${url}" />`;
} else {
return `<a download href="${url}">${filename}</a>`;
}
}
// Function to generate HTML rows based on the array of objects
function generateRows(data) {
return data.map((item, i) => `
<tr class="workflow-row" style="border-bottom: 1px solid #ddd; cursor: pointer;">
<td style="padding: 12px;">${i+1}</td>
<td style="padding: 12px;">${item.created_at}</td>
<td style="padding: 12px;">0.0s</td>
<td style="padding: 12px; color: ${item.status === 'success' ? '#4CAF50' : '#FFC107'};">${item.status}</td>
</tr>
`).join('');
}
// Generate the table HTML with dynamic rows
const tableHtml = (data) => {
return`
<table style="border-collapse: collapse; width: 100%; font-family: Arial, sans-serif; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);">
<thead>
<tr style="background-color: #f4f4f4; color: #333; border-bottom: 2px solid #ddd; text-align: left;">
<th style="padding: 12px;">Number</th>
<th style="padding: 12px;">Time</th>
<th style="padding: 12px;">Duration</th>
<th style="padding: 12px;">Status</th>
</tr>
</thead>
<tbody>
${generateRows(data)}
</tbody>
</table>
`;
}