Queue/history bar

This commit is contained in:
space-nuko
2023-05-12 13:46:42 -05:00
parent 3bf774ba0c
commit f64db2035a
11 changed files with 321 additions and 166 deletions

View File

@@ -1,74 +1,113 @@
<script lang="ts">
import queueState, { type QueueEntry } from "$lib/stores/queueState";
import queueState, { type CompletedQueueEntry, type QueueEntry, type QueueEntryStatus } from "$lib/stores/queueState";
import ProgressBar from "./ProgressBar.svelte";
import { getNodeInfo } from "$lib/utils"
import type { Writable } from "svelte/store";
import Spinner from "./Spinner.svelte";
import { convertComfyOutputToComfyURL, convertFilenameToComfyURL, getNodeInfo } from "$lib/utils"
import type { Writable } from "svelte/store";
import type { QueueItemType } from "$lib/api";
let queuePending: Writable<QueueEntry[]> | null = null;
let queueRunning: Writable<QueueEntry[]> | null = null;
let queueCompleted: Writable<CompletedQueueEntry[]> | null = null;
type QueueUIEntry = {
message: string,
submessage: string,
date?: string,
status: "success" | "error" | "pending" | "running" | "all_cached",
images?: string[] // URLs
status: QueueEntryStatus | "pending" | "running",
images?: string[], // URLs
error?: string
}
$: if ($queueState) {
queuePending = $queueState.queuePending
queueRunning = $queueState.queueRunning
queueCompleted = $queueState.queueCompleted
}
let mode: QueueItemType = "queue";
function switchMode(newMode: QueueItemType) {
console.warn("SwitchMode", newMode)
const changed = mode !== newMode
mode = newMode
if (changed)
_entries = []
}
let _entries: QueueUIEntry[] = []
$: if ($queuePending && $queuePending.length != _entries.length) {
_entries = []
for (const entry of $queuePending) {
// for (const outputs of Object.values(entry.outputs)) {
// const allImages = outputs.images.map(r => {
// // TODO configure backend URL
// const url = "http://localhost:8188/view?"
// const params = new URLSearchParams(r)
// return url + params
// });
//
// _entries.push({ allImages, name: "Output" })
// }
let date = null;
if (entry.queuedAt) {
const options: Intl.DateTimeFormatOptions = {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: 'numeric',
minute: 'numeric'
};
const dateTimeFormat = new Intl.DateTimeFormat('en-US', options);
date = dateTimeFormat.format(entry.queuedAt);
}
_entries.push({
message: "Prompt",
submessage: ".......",
date,
status: "pending",
images: null
})
}
console.error("BUILDENTRIES", _entries, $queuePending)
$: if (mode === "queue" && $queuePending && $queuePending.length != _entries.length) {
updateFromQueue();
}
else if (mode === "history" && $queueCompleted && $queueCompleted.length != _entries.length) {
updateFromHistory();
}
function convertEntry(entry: QueueEntry): QueueUIEntry {
const images = Object.values(entry.outputs).flatMap(o => o.images)
.map(convertComfyOutputToComfyURL);
let date = null;
if (entry.queuedAt) {
const options: Intl.DateTimeFormatOptions = {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: 'numeric',
minute: 'numeric'
};
const dateTimeFormat = new Intl.DateTimeFormat('en-US', options);
date = dateTimeFormat.format(entry.queuedAt);
}
let message = "Prompt";
if (entry.extraData.subgraphs)
message = `Prompt: ${entry.extraData.subgraphs.join(', ')}`
let submessage = `Nodes: ${Object.keys(entry.prompt).length}`
return {
message,
submessage,
date,
status: "pending",
images
}
}
function convertCompletedEntry(entry: CompletedQueueEntry): QueueUIEntry {
const result = convertEntry(entry.entry);
result.status = entry.status;
result.error = entry.error;
return result;
}
function updateFromQueue() {
_entries = $queuePending.map(convertEntry);
console.warn("[ComfyQueue] BUILDQUEUE", _entries, $queuePending)
}
function updateFromHistory() {
_entries = $queueCompleted.map(convertCompletedEntry);
console.warn("[ComfyQueue] BUILDHISTORY", _entries, $queueCompleted)
}
let queued = false
$: queued = Boolean($queueState.runningNodeID || $queueState.progress);
let inProgress = false;
$: inProgress = typeof $queueState.queueRemaining === "number" && $queueState.queueRemaining > 0;
</script>
<div class="queue">
<div class="queue-entries">
{#each _entries as entry}
<div class="queue-entry {entry.status}">
{#if entry.images}
{#if entry.images.length > 0}
<img class="queue-entry-image" src={entry.images[0]} alt="thumbnail" />
{:else}
<div class="queue-entry-image-placeholder" />
<!-- <div class="queue-entry-image-placeholder" /> -->
{/if}
<div class="queue-entry-details">
<div class="queue-entry-message">
@@ -88,68 +127,79 @@
</div>
{/each}
</div>
<div class="mode-buttons">
<div class="mode-button"
on:click={() => switchMode("queue")}
class:mode-selected={mode === "queue"}>
Queue
</div>
<div class="mode-button"
on:click={() => switchMode("history")}
class:mode-selected={mode === "history"}>
History
</div>
</div>
<div class="bottom">
{#if $queueState.runningNodeID || $queueState.progress}
<div class="queue-remaining" class:queued class:in-progress={inProgress}>
{#if inProgress}
<Spinner />
<div class="status">
Queued prompts: {$queueState.queueRemaining}
</div>
{:else}
<div>
Nothing queued.
</div>
{/if}
</div>
{#if queued}
<div class="node-name">
<span>Node: {getNodeInfo($queueState.runningNodeID)}</span>
</div>
<div>
<ProgressBar value={$queueState.progress?.value} max={$queueState.progress?.max} styles="height: 30px;" />
</div>
{/if}
{#if typeof $queueState.queueRemaining === "number" && $queueState.queueRemaining > 0}
<div class="queue-remaining in-progress">
<div>
Queued prompts: {$queueState.queueRemaining}.
</div>
</div>
{:else}
<div class="queue-remaining done">
<div>
Nothing queued.
</div>
<ProgressBar value={$queueState.progress?.value} max={$queueState.progress?.max} />
</div>
{/if}
</div>
</div>
<style lang="scss">
$pending-height: 300px;
$pending-height: 200px;
$bottom-bar-height: 70px;
$mode-buttons-height: 30px;
$queue-height: calc(100vh - #{$pending-height} - #{$mode-buttons-height} - #{$bottom-bar-height});
.queue {
}
.queue-remaining {
height: 5em;
width: 100%;
text-align: center;
border: 5px solid #CCC;
position: relative;
display: flex;
justify-content: center;
align-items: center;
color: var(--body-text-color);
}
.queue-entries {
overflow-y: scroll;
max-height: calc(100vh - $pending-height);
height: $queue-height;
max-height: $queue-height;
}
.queue-entry {
padding: 0.5rem;
padding: 1.0rem;
display: flex;
flex-direction: row;
border-top: 2px solid var(--neutral-200);
border-bottom: 1px solid var(--neutral-400);
border-bottom: 1px solid var(--panel-border-color);
background: var(--panel-background-fill);
&.success {
background: green
/* background: green; */
}
&.error {
background: red
background: red;
}
&.cached {
background: grey
&.all_cached {
background: grey;
}
&.running {
/* background: lightblue; */
}
&.pending, &.unknown {
/* background: orange; */
}
}
@@ -174,54 +224,86 @@
display: flex;
flex-direction: column;
justify-content: center;
white-space: nowrap;
}
.queue-entry-message {
width: var(--size-20);
font-size: large;
font-size: 15px;
}
.queue-entry-submessage {
width: var(--size-20);
font-size: 12px;
}
.queue-entry-queued-at {
width: auto;
font-size: 14px;
font-size: 10px;
position:absolute;
right: 0px;
bottom:0px;
padding: 0.0rem 0.4rem;
/* color: var(--neutral-600) */
color: var(--neutral-600);
color: var(--body-text-color);
}
.node-name {
border: 5px solid #CCC;
background-color: var(--color-red-300);
padding: 0.2em;
.mode-buttons {
height: calc($mode-buttons-height);
display: flex;
flex-direction: row;
text-align: center;
justify-content: center;
align-items: center;
.mode-button {
padding: 0.2rem;
width: 100%;
height: 100%;
border: 1px solid var(--panel-border-color);
font-weight: bold;
background: var(--button-secondary-background-fill);
&:hover {
background: var(--button-secondary-background-fill-hover);
filter: brightness(120%);
}
&:active {
filter: brightness(50%)
}
&.mode-selected {
filter: brightness(150%)
}
}
}
.bottom {
width: 100%;
height: $pending-height;
height: calc($pending-height);
position: absolute;
}
border: 2px solid var(--panel-border-color);
.in-progress {
background-color: var(--secondary-300);
}
.done {
background-color: var(--color-grey-200);
}
.node-name {
background-color: var(--comfy-node-name-background);
color: var(--comfy-node-name-foreground);
padding: 0.2em;
display: flex;
justify-content: center;
align-items: center;
}
.queue-item {
height: 1.5em;
width: 10em;
text-align: center;
border: 1px solid black;
.queue-remaining {
height: calc($pending-height - $bottom-bar-height - 50px);
width: 100%;
text-align: center;
position: relative;
display: flex;
justify-content: space-evenly;
align-items: center;
background: var(--panel-background-fill);
> .status {
}
&.queued {
height: calc($pending-height - $bottom-bar-height);
}
}
}
</style>