The click can come before the answer to a count typed just before it, and all three Run buttons held the saves as they were drawn: a save set to 3 runs ran once. Run now waits for the counts on their way and reads the group as it stands at its turn, in one place for all of them. Tested with a real mouse on an isolated ComfyUI, the answer held back 400 ms: the bar, a part and a card each queue the new count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
60 lines
2.8 KiB
JavaScript
60 lines
2.8 KiB
JavaScript
/**
|
|
* The page's calls to api/workflow_saves.py, where every save of a workflow lives. A group is found by
|
|
* the key in the workflow's extra, or for a saved file by its path. Every change goes through here, so
|
|
* the bar under the canvas and the Saves view, which both show groups, hear of it. No DOM.
|
|
*/
|
|
|
|
import { jsonResponse } from './ui_dom.js';
|
|
|
|
const FAILED = 'The saves did not answer';
|
|
const listeners = new Set();
|
|
let counts = Promise.resolve(); // the counts sent so far, answered or not
|
|
|
|
const read = (route, query = {}) => fetch(`/anomalous/saves${route}?${new URLSearchParams(query)}`).then(response => jsonResponse(response, FAILED));
|
|
|
|
const send = (route, body) => fetch(`/anomalous/saves/${route}`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
}).then(response => jsonResponse(response, FAILED));
|
|
|
|
function changed(key, group) {
|
|
for (const listener of listeners) listener(key, group);
|
|
return group;
|
|
}
|
|
|
|
/** `listener(key, group)` hears of every change to a group: `group` as it stands, null once it is gone. */
|
|
export const onSavesChange = listener => listeners.add(listener);
|
|
|
|
/** The group of `key`, or of the workflow file `path`; null when there is none. */
|
|
export const findGroup = (key, path) => read('/group', { key, path }).then(data => data.group);
|
|
|
|
/** Group `key` read again, for those who show it: its runs may have ended. */
|
|
export const refreshGroup = key => findGroup(key, '').then(group => changed(key, group));
|
|
|
|
/** Every group, the newest first, each with what it is called and its newest picture. */
|
|
export const listGroups = () => read('').then(data => data.groups);
|
|
|
|
/** `save` of group `key`'s whole workflow. */
|
|
export const readWorkflow = (key, id) => read('/workflow', { key, id }).then(data => data.workflow);
|
|
|
|
/** Keeps a save ({key, workflow, title, path, changes}); the group as it stands then. */
|
|
export const addSave = save => send('add', save).then(data => changed(save.key, data.group));
|
|
|
|
export function setCount(key, id, count) {
|
|
const sent = send('update', { key, id, count }).then(data => changed(key, data.group));
|
|
counts = Promise.allSettled([counts, sent]);
|
|
return sent;
|
|
}
|
|
|
|
/** Settles once every count sent so far is answered, taken or not. */
|
|
export const countsAnswered = () => counts;
|
|
|
|
/** Says which runs came from save `id`, so their pictures can be found. */
|
|
export const noteRuns = (key, id, promptIds) => send('ran', { key, id, prompt_ids: promptIds }).then(data => changed(key, data.group));
|
|
|
|
/** To the Recycle Bin; the group as it stands then, null after its last save. `changes`: the next save's, from now on. */
|
|
export const removeSave = (key, id, changes) => send('remove', { key, id, changes }).then(data => changed(key, data.group));
|
|
|
|
export const removeGroup = key => send('remove_group', { key }).then(() => changed(key, null));
|