Files
DemonGatanjieu-Anomalous_Mo…/web/modules/ui_recipe_flow_inspect.js
T
DemonGatanjieuandClaude Opus 5.5 186f5467b0 Lay a workflow's details out as flow, preset tabs and the preset shown
The left column is gone. The details are one column: the flow, a row of
tabs under it (the workflow's own values, each preset with how many
values it changes, + to save the canvas or copy the one shown, all
pictures and versions at the end; it stays in view while the panel
scrolls) and the tab chosen in a panel joined to it.

The flow is small and shows only the structure: the stages in the order
they run, then the finishing nodes and the saves; above them one lane
each for the model files, the LoRAs and the control models, each a bar
over the stages it feeds (recipe_flow.flowLanes, tested). Steps, splits
and strengths moved into the boxes' tooltips; the legend and the hint
line are gone. What the preset shown changes from the workflow's own is
orange, and its head says how many values that is. A box's values open
under the flow only once one is picked, with x to close.

The set rows' key-value chips went with the column; the tabs count the
differences with ui_param_set_keys.setDifferences. Remaining "方案"
labels in the preset menus now say 预设.

Checked on the isolated test ComfyUI with the two-pass Anima card: each
preset marks the right boxes, the inspector, the + menu and its editor,
all pictures, versions, sticky tabs, and the narrow (docked) layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 20:05:38 +08:00

83 lines
4.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* The box picked in a workflow's flow, under it (ui_recipe_flow.js), nothing while none is: what it
* is with its full file name, whether it runs with the values shown, × to close, and every value of
* its node, a value the preset changed struck out as the workflow's own with the preset's after it
* (both orange). A stage that runs names its
* other nodes that changed (its model, a LoRA), each a button to that one; a box unused with these
* values names the presets that use it, each a button to that preset.
*/
import { translate as t } from './locales.js';
import { appendText, button, displayValue } from './ui_recipe_detail_dom.js';
import { nodeValues, sameValue, stageMark, usedIn } from './recipe_flow.js';
const nodeIn = (workflow, id) => (workflow?.nodes || []).find(node => String(node.id) === id) || null;
/** What a box of the flow is: a stage by its number and job, anything else by its role. */
export const roleOf = item => (item.sampler ? `${stageMark(item.n)} ${t(`workflowFlow_${item.kind}`)}` : t(`workflowFlowRole_${item.kind}`));
function stateKey(item, used) {
if (used) return 'workflowFlowRuns';
if (item.state === 'off') return 'workflowFlowOff';
return item.state === 'skipped' ? 'workflowFlowSkipped' : 'workflowFlowUnused';
}
/** A line of buttons after `label`. */
function links(card, label, entries) {
const line = appendText(card, 'div', '', 'anomalous-wfd-flow-links');
appendText(line, 'span', label);
for (const [text, run] of entries) button(line, text, 'anomalous-wfd-flow-link').onclick = run;
}
/**
* Draws the picked box's card into `panel`. view: flow (shown), shown (its workflow), changed (node
* ids unlike the workflow's own), current (the preset shown, null for the own values), presets()
* ([{label, filename, flow}], the own values first), pick(id).
*/
export function renderInspector(panel, ctx, { flow, shown, changed, current, presets, pick }) {
const id = ctx.parameterState.flowPick;
const item = id && (flow.stages.find(stage => stage.sampler === id) || flow.parts.find(part => part.ids.includes(id)));
if (!item) return;
const card = appendText(panel, 'div', '', 'anomalous-wfd-flow-inspect');
const node = nodeIn(shown, id);
const used = usedIn(flow, id);
const head = appendText(card, 'div', '', 'anomalous-wfd-flow-inspect-head');
const titles = appendText(head, 'div', '');
appendText(titles, 'strong', roleOf(item), 'anomalous-wfd-flow-inspect-title');
appendText(titles, 'div', item.file || node?.title || node?.type || '', 'anomalous-wfd-flow-inspect-file');
appendText(head, 'span', t(stateKey(item, used)), `anomalous-wfd-flow-state${used ? ' is-on' : ''}`);
const close = button(head, '×', 'anomalous-wf-icon-btn');
close.title = t('workflowFlowClose');
close.onclick = () => pick(id);
if (item.ids?.length > 1) appendText(card, 'small', t('workflowFlowNodes', { count: item.ids.length, ids: item.ids.map(other => `#${other}`).join(' ') }), 'anomalous-wfd-muted');
if (!used) {
const where = presets().filter(preset => preset.filename !== current && usedIn(preset.flow, id));
links(card, t(where.length ? 'workflowFlowRunsIn' : 'workflowFlowRunsNowhere'), where.map(preset => [preset.label, () => {
ctx.parameterState.editor = null;
ctx.select('set', preset.filename);
}]));
}
const others = item.sampler && used ? [...item.nodes].filter(other => other !== id && changed.has(other)) : [];
if (others.length) {
links(card, t('workflowFlowChangedHere'), others.map((other) => {
const part = flow.parts.find(entry => entry.ids.includes(other));
const otherNode = nodeIn(shown, other);
return [part ? `${roleOf(part)} ${part.name}` : `${otherNode?.title || otherNode?.type || ''} #${other}`, () => pick(other)];
}));
}
const own = changed.has(id) ? nodeValues(nodeIn(ctx.recipe.workflow, id)) : null;
if (own) appendText(card, 'small', t('workflowFlowDiffNote'), 'anomalous-wfd-muted');
const grid = appendText(card, 'div', '', 'anomalous-wfd-flow-values');
nodeValues(node).forEach(({ name, value }, at) => {
const was = own && !sameValue(own[at]?.value, value) ? own[at] : null;
const cell = appendText(grid, 'div', '', `anomalous-wfd-flow-value${was ? ' is-changed' : ''}`);
appendText(cell, 'span', name);
const text = appendText(cell, 'strong', '');
if (was) {
appendText(text, 'span', displayValue(was.value), 'anomalous-wfd-flow-was');
text.append(' → ');
}
text.append(displayValue(value));
});
}