new list utility nodes (#13)
* add List-related nodes for Checkpoints / LoRAs / Samplers/ Schedulers * wiki: reorg XY Plot 3rd tutorial and add example * bump version
This commit is contained in:
Vendored
+30
-25
@@ -82,6 +82,16 @@ const customLabels = {
|
||||
nb_elements: 'nb of elements',
|
||||
},
|
||||
},
|
||||
ListCheckpoints: {
|
||||
widget: {
|
||||
with_extension: 'with file extension?',
|
||||
},
|
||||
},
|
||||
ListLoras: {
|
||||
widget: {
|
||||
with_extension: 'with file extension?',
|
||||
},
|
||||
},
|
||||
OutputConfigBackend: {
|
||||
widget: {
|
||||
file_path: 'JSON or YAML file (backend)',
|
||||
@@ -95,31 +105,6 @@ const customLabels = {
|
||||
show_config: 'show config',
|
||||
},
|
||||
},
|
||||
OutputConfigAuto: {
|
||||
widget: {
|
||||
auto_connect: 'auto-connect?',
|
||||
multi_nodes: 'if multiple nodes found',
|
||||
error_display: 'display errors',
|
||||
show_config: 'show config',
|
||||
},
|
||||
},
|
||||
NodeConfigApplyLocal: {
|
||||
widget: {
|
||||
error_display: 'display errors',
|
||||
check_level: 'reject on',
|
||||
},
|
||||
},
|
||||
MultiConfigFetch: {
|
||||
widget: {
|
||||
node_by: 'identify nodes by',
|
||||
},
|
||||
},
|
||||
MultiConfigApplyLocal: {
|
||||
widget: {
|
||||
error_display: 'display errors',
|
||||
check_level: 'reject on',
|
||||
},
|
||||
},
|
||||
GenericQueue: {
|
||||
input: {
|
||||
input_list: 'input list',
|
||||
@@ -238,6 +223,26 @@ const customLooks = {
|
||||
list: { shape: 'grid' },
|
||||
},
|
||||
},
|
||||
ListCheckpoints: {
|
||||
output: {
|
||||
list: { shape: 'grid' },
|
||||
},
|
||||
},
|
||||
ListLoras: {
|
||||
output: {
|
||||
list: { shape: 'grid' },
|
||||
},
|
||||
},
|
||||
ListSamplers: {
|
||||
output: {
|
||||
list: { shape: 'grid' },
|
||||
},
|
||||
},
|
||||
ListSchedulers: {
|
||||
output: {
|
||||
list: { shape: 'grid' },
|
||||
},
|
||||
},
|
||||
};
|
||||
function setNodeLabels(nodeType, nodeData) {
|
||||
const nodeName = nodeData.name;
|
||||
|
||||
Vendored
+76
@@ -1,4 +1,5 @@
|
||||
import { findWidget, loadTextFile } from '../shared/utils.js';
|
||||
import { makeComboWidget } from '../widgets/factories.js';
|
||||
export function ListFromMultiline(nodeType) {
|
||||
const original_onNodeCreated = nodeType.prototype.onNodeCreated;
|
||||
nodeType.prototype.onNodeCreated = function (...args) {
|
||||
@@ -13,3 +14,78 @@ export function ListFromMultiline(nodeType) {
|
||||
};
|
||||
};
|
||||
}
|
||||
export function ListFromSelection(nodeType, selection_type) {
|
||||
const isCombo = (widget) => widget.name.startsWith(`${selection_type}_`.toLowerCase());
|
||||
const findCombos = (node) => node.widgets.filter((w) => isCombo(w));
|
||||
const addCombo = (node, selectionWidget) => {
|
||||
const index = findCombos(node).length;
|
||||
const width = node.size[0];
|
||||
const widget = makeComboWidget(node, `${selection_type}_${index}`.toLowerCase(), ['none', ...selectionWidget.all], 0);
|
||||
node.setSize([width, node.size[1]]);
|
||||
widget.label = `${selection_type} #${index + 1}`;
|
||||
widget.options.serialize = false;
|
||||
return widget;
|
||||
};
|
||||
const refreshSelection = (node, selectionWidget) => {
|
||||
const selected = [];
|
||||
let widgetIndex = 0;
|
||||
let comboIndex = 0;
|
||||
while (widgetIndex < node.widgets.length) {
|
||||
const widget = node.widgets[widgetIndex];
|
||||
if (!isCombo(widget)) {
|
||||
widgetIndex += 1;
|
||||
continue;
|
||||
}
|
||||
if (widget.selected === 0) {
|
||||
node.widgets.splice(widgetIndex, 1);
|
||||
continue;
|
||||
}
|
||||
widget.name = `${selection_type}_${comboIndex}`.toLowerCase();
|
||||
widget.label = `${selection_type} #${comboIndex + 1}`;
|
||||
selected.push(widget.value);
|
||||
widgetIndex += 1;
|
||||
comboIndex += 1;
|
||||
}
|
||||
const last = addCombo(node, selectionWidget);
|
||||
last.onSelected = () => {
|
||||
refreshSelection(node, selectionWidget);
|
||||
};
|
||||
selectionWidget.value = { selected };
|
||||
};
|
||||
const refreshFromSelection = (node, selectionWidget) => {
|
||||
let widgetIndex = 0;
|
||||
while (widgetIndex < node.widgets.length) {
|
||||
const widget = node.widgets[widgetIndex];
|
||||
if (isCombo(widget)) {
|
||||
node.widgets.splice(widgetIndex, 1);
|
||||
continue;
|
||||
}
|
||||
widgetIndex += 1;
|
||||
}
|
||||
const selected = selectionWidget.value.selected;
|
||||
for (const value of selected) {
|
||||
const widget = addCombo(node, selectionWidget);
|
||||
widget.value = value;
|
||||
widget.callback(widget.value);
|
||||
widget.onSelected = () => {
|
||||
refreshSelection(node, selectionWidget);
|
||||
};
|
||||
}
|
||||
const last = addCombo(node, selectionWidget);
|
||||
last.onSelected = () => {
|
||||
refreshSelection(node, selectionWidget);
|
||||
};
|
||||
};
|
||||
const original_onNodeCreated = nodeType.prototype.onNodeCreated;
|
||||
nodeType.prototype.onNodeCreated = function (...args) {
|
||||
original_onNodeCreated?.apply(this, ...args);
|
||||
const selectionWidget = findWidget(this, 'selection');
|
||||
refreshFromSelection(this, selectionWidget);
|
||||
};
|
||||
const original_onConfigure = nodeType.prototype.onConfigure;
|
||||
nodeType.prototype.onConfigure = function (...args) {
|
||||
original_onConfigure?.apply(this, ...args);
|
||||
const selectionWidget = findWidget(this, 'selection');
|
||||
refreshFromSelection(this, selectionWidget);
|
||||
};
|
||||
}
|
||||
|
||||
Vendored
+18
-5
@@ -3,9 +3,9 @@ import { CATEGORY } from './shared/common.js';
|
||||
import { customizeNode } from './custom.js';
|
||||
import { setupDynamicConnections } from './shared/dynamic_connections.js';
|
||||
import { QUEUE_STATUS } from './widgets/queue.js';
|
||||
import { HIDDEN, BTN, ERROR_DISPLAY } from './widgets/misc.js';
|
||||
import { HIDDEN, BTN, ERROR_DISPLAY, SELECTION_LIST } from './widgets/misc.js';
|
||||
import { OutputConfigBackend, OutputConfigLocal } from './nodes/config.js';
|
||||
import { ListFromMultiline } from './nodes/list.js';
|
||||
import { ListFromMultiline, ListFromSelection } from './nodes/list.js';
|
||||
import { InputMultiline } from './nodes/input.js';
|
||||
import { DebugJSONYAML, DebugWidgetVisibility } from './nodes/debug.js';
|
||||
globalThis[CATEGORY] = { log: 'debug' };
|
||||
@@ -28,6 +28,21 @@ app.registerExtension({
|
||||
start_index: 1,
|
||||
});
|
||||
break;
|
||||
case 'ListFromMultiline':
|
||||
ListFromMultiline(nodeType);
|
||||
break;
|
||||
case 'ListCheckpoints':
|
||||
ListFromSelection(nodeType, 'checkpoint');
|
||||
break;
|
||||
case 'ListLoras':
|
||||
ListFromSelection(nodeType, 'LoRA');
|
||||
break;
|
||||
case 'ListSamplers':
|
||||
ListFromSelection(nodeType, 'sampler');
|
||||
break;
|
||||
case 'ListSchedulers':
|
||||
ListFromSelection(nodeType, 'scheduler');
|
||||
break;
|
||||
case 'InputMultiline':
|
||||
InputMultiline(nodeType);
|
||||
break;
|
||||
@@ -38,9 +53,6 @@ app.registerExtension({
|
||||
start_index: 0,
|
||||
});
|
||||
break;
|
||||
case 'ListFromMultiline':
|
||||
ListFromMultiline(nodeType);
|
||||
break;
|
||||
case 'DebugJSONYAML':
|
||||
DebugJSONYAML(nodeType);
|
||||
break;
|
||||
@@ -63,6 +75,7 @@ app.registerExtension({
|
||||
HIDDEN,
|
||||
BTN,
|
||||
ERROR_DISPLAY,
|
||||
SELECTION_LIST,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
Vendored
+12
-1
@@ -1,6 +1,7 @@
|
||||
import { makeButtonWidget, makeComboWidget, } from '../widgets/factories.js';
|
||||
import { makeWidgetAsync } from '../shared/utils.js';
|
||||
export function HIDDEN(node, inputName, inputData, _app) {
|
||||
import { log } from '../shared/common.js';
|
||||
export function HIDDEN(node, inputName, inputData) {
|
||||
const initialValue = inputData[1].value;
|
||||
const widget = {
|
||||
type: 'HIDDEN',
|
||||
@@ -69,3 +70,13 @@ export function ERROR_DISPLAY(node, name = 'error_display') {
|
||||
const widget = makeComboWidget(node, name, ERROR_DISPLAY_CHOICES, 'dialog', () => { }, 'how to display detected errors');
|
||||
return widget;
|
||||
}
|
||||
export function SELECTION_LIST(node, inputName, inputData) {
|
||||
inputData[1].value = { selected: [] };
|
||||
if (!Array.isArray(inputData[1].all) || !inputData[1].all) {
|
||||
log.error("SELECTION_LIST: 'all is invalid");
|
||||
inputData[1].all = [];
|
||||
}
|
||||
const widget = HIDDEN(node, inputName, inputData);
|
||||
widget.all = inputData[1].all;
|
||||
return widget;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user