Replaced most $el buttons with ComfyButtons.

This commit is contained in:
Christian Bastian
2024-07-23 22:39:02 -04:00
parent eade5b27d8
commit 85a8f5f427
2 changed files with 198 additions and 139 deletions

View File

@@ -149,7 +149,6 @@
} }
.model-manager .icon-button { .model-manager .icon-button {
padding: 0;
height: 40px; height: 40px;
width: 40px; width: 40px;
line-height: 1.15; line-height: 1.15;
@@ -173,12 +172,12 @@
min-width: 0; min-width: 0;
} }
.model-manager .button-success { .model-manager .comfy-button-success {
color: green; color: green;
border-color: green; border-color: green;
} }
.model-manager .button-failure { .model-manager .comfy-button-failure {
color: darkred; color: darkred;
border-color: darkred; border-color: darkred;
} }
@@ -633,6 +632,7 @@
.model-manager .model-manager-settings button { .model-manager .model-manager-settings button {
height: 40px; height: 40px;
width: 120px; width: 120px;
justify-content: center;
} }
.model-manager .model-manager-settings input[type="number"], .model-manager .model-manager-settings input[type="number"],

View File

@@ -169,26 +169,55 @@ function debounce(callback, delay) {
/** /**
* @param {HTMLButtonElement} element * @param {HTMLButtonElement} element
* @param {boolean} success * @param {boolean} success
* @param {string} [successText=""] * @param {string} successClassName
* @param {string} [failureText=""] * @param {string} failureClassName
* @param {string} [resetText=""]
*/ */
function buttonAlert(element, success, successText = "", failureText = "", resetText = "") { function comfyButtonAlert(element, success, successClassName = undefined, failureClassName = undefined) {
if (element === undefined || element === null) { if (element === undefined || element === null) { return; }
const nodeName = element.nodeName.toLowerCase();
let button = undefined;
let icon = undefined;
if (nodeName === "button") {
button = element;
icon = button.getElementsByTagName("i")[0];
}
else if (nodeName === "i") {
icon = element;
button = element.parentElement;
}
else if (nodeName === "span") {
button = element.parentElement;
icon = button.getElementsByTagName("i")[0];
}
if (button === undefined) {
console.warn("Unable to find button element!");
console.warn(element);
return; return;
} }
const name = success ? "button-success" : "button-failure";
element.classList.add(name); // TODO: debounce would be nice, but needs some sort of "global" to avoid creating/destroying many objects
if (successText != "" && failureText != "") {
element.innerHTML = success ? successText : failureText; const colorClassName = success ? "comfy-button-success" : "comfy-button-failure";
}
// TODO: debounce would be nice to get working... if (icon) {
window.setTimeout((element, name, innerHTML) => { const iconClassName = (success ? successClassName : failureClassName) ?? "";
element.classList.remove(name); if (iconClassName !== "") {
if (innerHTML != "") { icon.classList.add(iconClassName);
element.innerHTML = innerHTML;
} }
}, 1000, element, name, resetText); icon.classList.add(colorClassName);
window.setTimeout((element, iconClassName, colorClassName) => {
if (iconClassName !== "") {
element.classList.remove(iconClassName);
}
element.classList.remove(colorClassName);
}, 1000, icon, iconClassName, colorClassName);
}
button.classList.add(colorClassName);
window.setTimeout((element, colorClassName) => {
element.classList.remove(colorClassName);
}, 1000, button, colorClassName);
} }
/** /**
@@ -701,15 +730,17 @@ class ImageSelect {
style: { display: "none" }, style: { display: "none" },
}, [ }, [
el_customUrl, el_customUrl,
$el("button.icon-button", { new ComfyButton({
textContent: "🔍︎", icon: "magnify",
onclick: async (e) => { tooltip: "Search models",
classList: "comfyui-button icon-button",
action: async (e) => {
const value = el_customUrl.value; const value = el_customUrl.value;
el_customUrlPreview.src = await getCustomPreviewUrl(value); el_customUrlPreview.src = await getCustomPreviewUrl(value);
e.stopPropagation(); e.stopPropagation();
el_customUrl.blur(); el_customUrl.blur();
}, },
}), }).element,
]); ]);
const el_previewButtons = $el("div.model-preview-overlay", { const el_previewButtons = $el("div.model-preview-overlay", {
@@ -717,14 +748,18 @@ class ImageSelect {
display: el_defaultPreviews.children.length > 1 ? "block" : "none", display: el_defaultPreviews.children.length > 1 ? "block" : "none",
}, },
}, [ }, [
$el("button.icon-button.model-preview-button-left", { new ComfyButton({
textContent: "←", icon: "arrow-left",
onclick: () => this.stepDefaultPreviews(-1), tooltip: "Previous image",
}), classList: "comfyui-button icon-button model-preview-button-left",
$el("button.icon-button.model-preview-button-right", { action: () => this.stepDefaultPreviews(-1),
textContent: "→", }).element,
onclick: () => this.stepDefaultPreviews(1), new ComfyButton({
}), icon: "arrow-right",
tooltip: "Next image",
classList: "comfyui-button icon-button model-preview-button-right",
action: () => this.stepDefaultPreviews(1),
}).element,
]); ]);
const el_previews = $el("div.item", { const el_previews = $el("div.item", {
$: (el) => (this.elements.previews = el), $: (el) => (this.elements.previews = el),
@@ -1570,7 +1605,7 @@ class ModelGrid {
} }
event.stopPropagation(); event.stopPropagation();
} }
buttonAlert(event.target, success, "✔", "✖", "✚"); comfyButtonAlert(event.target, success, "mdi-check-bold", "mdi-close-thick");
} }
static #getWidgetComboIndices(node, value) { static #getWidgetComboIndices(node, value) {
@@ -1686,7 +1721,7 @@ class ModelGrid {
else { else {
console.warn(`Unable to copy unknown model type '${modelType}.`); console.warn(`Unable to copy unknown model type '${modelType}.`);
} }
buttonAlert(event.target, success, "✔", "✖", "⧉︎"); comfyButtonAlert(event.target, success, "mdi-check-bold", "mdi-close-thick");
} }
/** /**
@@ -1730,41 +1765,42 @@ class ModelGrid {
let actionButtons = []; let actionButtons = [];
if (showAddButton && !(modelType === "embeddings" && !navigator.clipboard)) { if (showAddButton && !(modelType === "embeddings" && !navigator.clipboard)) {
actionButtons.push( actionButtons.push(
$el("button.icon-button.model-button", { new ComfyButton({
type: "button", icon: "content-copy",
textContent: "⧉︎", tooltip: "Copy model to clipboard",
onclick: (e) => ModelGrid.#copyModelToClipboard( classList: "comfyui-button icon-button model-button",
e, action: (e) => ModelGrid.#copyModelToClipboard(
modelType,
path,
removeEmbeddingExtension
),
draggable: false,
})
);
}
if (showCopyButton) {
actionButtons.push(
$el("button.icon-button.model-button", {
type: "button",
textContent: "✚",
onclick: (e) => ModelGrid.#addModel(
e, e,
modelType, modelType,
path, path,
removeEmbeddingExtension, removeEmbeddingExtension,
addOffset
), ),
draggable: false, }).element,
}) );
}
if (showCopyButton) {
actionButtons.push(
new ComfyButton({
icon: "plus-box-outline",
tooltip: "Add model to node grid",
classList: "comfyui-button icon-button model-button",
action: (e) => ModelGrid.#addModel(
e,
modelType,
path,
removeEmbeddingExtension,
addOffset,
),
}).element,
); );
} }
if (showLoadWorkflowButton) { if (showLoadWorkflowButton) {
actionButtons.push( actionButtons.push(
$el("button.icon-button.model-button", { new ComfyButton({
type: "button", icon: "arrow-bottom-left-bold-box-outline",
textContent: "↙︎", tooltip: "Load preview workflow",
onclick: async (e) => { classList: "comfyui-button icon-button model-button",
action: async (e) => {
const urlString = previewThumbnail.src; const urlString = previewThumbnail.src;
const url = new URL(urlString); const url = new URL(urlString);
const urlSearchParams = url.searchParams; const urlSearchParams = url.searchParams;
@@ -1773,16 +1809,16 @@ class ModelGrid {
const urlFull = urlString.substring(0, urlString.indexOf("?")) + "?uri=" + uri + "&v=" + v; const urlFull = urlString.substring(0, urlString.indexOf("?")) + "?uri=" + uri + "&v=" + v;
load_workflow(urlFull); load_workflow(urlFull);
}, },
}), }).element,
); );
} }
const infoButtons = [ const infoButtons = [
$el("button.icon-button.model-button", { new ComfyButton({
type: "button", icon: "information-outline",
textContent: "ⓘ", tooltip: "View model information",
onclick: async() => { await showModelInfo(searchPath) }, classList: "comfyui-button icon-button model-button",
draggable: false, action: async() => { await showModelInfo(searchPath) },
}), }).element,
]; ];
const dragAdd = (e) => ModelGrid.#dragAddModel( const dragAdd = (e) => ModelGrid.#dragAddModel(
e, e,
@@ -1925,10 +1961,10 @@ class ModelInfo {
this.previewSelect = previewSelect; this.previewSelect = previewSelect;
previewSelect.elements.previews.style.display = "flex"; previewSelect.elements.previews.style.display = "flex";
const setPreviewButton = $el("button", { const setPreviewButton = new ComfyButton({
$: (el) => (this.elements.setPreviewButton = el), tooltip: "Overwrite currrent preview with selected image",
textContent: "Set as Preview", content: "Set as Preview",
onclick: async(e) => { action: async(e) => {
const confirmation = window.confirm("Change preview image(s) PERMANENTLY?"); const confirmation = window.confirm("Change preview image(s) PERMANENTLY?");
let updatedPreview = false; let updatedPreview = false;
if (confirmation) { if (confirmation) {
@@ -1989,9 +2025,10 @@ class ModelInfo {
e.target.disabled = false; e.target.disabled = false;
} }
buttonAlert(e.target, updatedPreview); comfyButtonAlert(e.target, updatedPreview);
}, },
}); }).element;
this.elements.setPreviewButton = setPreviewButton;
previewSelect.elements.radioButtons.addEventListener("change", (e) => { previewSelect.elements.radioButtons.addEventListener("change", (e) => {
setPreviewButton.style.display = previewSelect.defaultIsChecked() ? "none" : "block"; setPreviewButton.style.display = previewSelect.defaultIsChecked() ? "none" : "block";
}); });
@@ -2003,9 +2040,11 @@ class ModelInfo {
display: "block", display: "block",
}, [ }, [
$el("div.row.tab-header-flex-block", [ $el("div.row.tab-header-flex-block", [
$el("button.icon-button", { new ComfyButton({
textContent: "🗑︎", icon: "trash-can-outline",
onclick: async(e) => { tooltip: "Delete model FOREVER",
classList: "comfyui-button icon-button",
action: async(e) => {
const affirmation = "delete"; const affirmation = "delete";
const confirmation = window.prompt("Type \"" + affirmation + "\" to delete the model PERMANENTLY.\n\nThis includes all image or text files."); const confirmation = window.prompt("Type \"" + affirmation + "\" to delete the model PERMANENTLY.\n\nThis includes all image or text files.");
let deleted = false; let deleted = false;
@@ -2037,17 +2076,18 @@ class ModelInfo {
}); });
} }
if (!deleted) { if (!deleted) {
buttonAlert(e.target, false); comfyButtonAlert(e.target, false);
} }
}, },
}), }).element,
$el("div.search-models", [ $el("div.search-models", [
moveDestinationInput, moveDestinationInput,
searchDropdown.element, searchDropdown.element,
]), ]),
$el("button", { new ComfyButton({
textContent: "Move", icon: "file-move-outline",
onclick: async(e) => { tooltip: "Move file",
action: async(e) => {
const confirmation = window.confirm("Move this file?"); const confirmation = window.confirm("Move this file?");
let moved = false; let moved = false;
if (confirmation) { if (confirmation) {
@@ -2088,9 +2128,9 @@ class ModelInfo {
return false; return false;
}); });
} }
buttonAlert(e.target, moved); comfyButtonAlert(e.target, moved);
}, },
}), }).element,
]), ]),
]), ]),
$el("div.model-info-container", { $el("div.model-info-container", {
@@ -2215,9 +2255,11 @@ class ModelInfo {
filename, filename,
]), ]),
$el("div", [ $el("div", [
$el("button.icon-button", { new ComfyButton({
textContent: "", icon: "pencil",
onclick: async(e) => { tooltip: "Change file name",
classList: "comfyui-button icon-button",
action: async(e) => {
const container = this.elements.info; const container = this.elements.info;
const oldFile = container.dataset.path; const oldFile = container.dataset.path;
const [oldFilePath, oldFileName] = SearchPath.split(oldFile); const [oldFilePath, oldFileName] = SearchPath.split(oldFile);
@@ -2260,9 +2302,9 @@ class ModelInfo {
return false; return false;
}); });
} }
buttonAlert(e.target, renamed); comfyButtonAlert(e.target, renamed);
}, },
}), }).element,
]), ]),
]), ]),
); );
@@ -2296,12 +2338,11 @@ class ModelInfo {
previewSelect.elements.previews, previewSelect.elements.previews,
$el("div.row.tab-header", [ $el("div.row.tab-header", [
$el("div", [ $el("div", [
$el("button", { new ComfyButton({
textContent: "Load Workflow", content: "Load Workflow",
onclick: async (e) => { tooltip: "Attempt to load preview image workflow",
load_workflow(previewSelect.elements.defaultPreviews.children[0].src); action: () => load_workflow(previewSelect.elements.defaultPreviews.children[0].src),
}, }).element,
}),
]), ]),
$el("div.row.tab-header-flex-block", [ $el("div.row.tab-header-flex-block", [
previewSelect.elements.radioGroup, previewSelect.elements.radioGroup,
@@ -2453,10 +2494,10 @@ class ModelInfo {
]), ]),
]), ]),
tagGeneratorRandomizedOutput, tagGeneratorRandomizedOutput,
$el("button", { new ComfyButton({
textContent: "Randomize", content: "Randomize",
style: { width: "100%" }, tooltip: "Randomly generate subset of tags",
onclick: (e) => { action: () => {
const samplerName = document.querySelector(`input[name="${TAG_GENERATOR_SAMPLER_NAME}"]:checked`).value; const samplerName = document.querySelector(`input[name="${TAG_GENERATOR_SAMPLER_NAME}"]:checked`).value;
const sampler = samplerName === "Frequency" ? ModelInfo.ProbabilisticTagSampling : ModelInfo.UniformTagSampling; const sampler = samplerName === "Frequency" ? ModelInfo.ProbabilisticTagSampling : ModelInfo.UniformTagSampling;
const sampleCount = tagGenerationCount.value; const sampleCount = tagGenerationCount.value;
@@ -2465,7 +2506,7 @@ class ModelInfo {
const sampledTags = sampler(tags, sampleCount, frequencyThreshold); const sampledTags = sampler(tags, sampleCount, frequencyThreshold);
tagGeneratorRandomizedOutput.value = sampledTags.join(", "); tagGeneratorRandomizedOutput.value = sampledTags.join(", ");
}, },
}), }).element,
]), ]),
$el("h2", ["Training Tags"]), $el("h2", ["Training Tags"]),
tagsParagraph, tagsParagraph,
@@ -2489,13 +2530,15 @@ class ModelInfo {
style: { margin: "0px 0px 16px" }, style: { margin: "0px 0px 16px" },
}, [ }, [
$el("h1", { style: { "margin-top": "0px", "margin-bottom": "0px" } }, ["Notes"]), $el("h1", { style: { "margin-top": "0px", "margin-bottom": "0px" } }, ["Notes"]),
$el("button.icon-button", { new ComfyButton({
textContent: "💾", icon: "content-save",
onclick: async (e) => { tooltip: "Save note",
classList: "comfyui-button icon-button",
action: async (e) => {
const saved = await this.trySave(false); const saved = await this.trySave(false);
buttonAlert(e.target, saved); comfyButtonAlert(e.target, saved);
}, },
}), }).element,
]), ]),
$el("div", { $el("div", {
style: { "display": "flex", "height": "100%", "min-height": "60px" }, style: { "display": "flex", "height": "100%", "min-height": "60px" },
@@ -3010,10 +3053,12 @@ class DownloadView {
} }
}, },
}), }),
$el("button.icon-button", { new ComfyButton({
onclick: async () => { await update(); }, icon: "magnify",
textContent: "🔍︎", tooltip: "Search url",
}), classList: "comfyui-button icon-button",
action: async() => await update(),
}).element,
]), ]),
$el("div.download-model-infos", { $el("div.download-model-infos", {
$: (el) => (this.elements.infos = el), $: (el) => (this.elements.infos = el),
@@ -3125,9 +3170,11 @@ class DownloadView {
downloadPreviewSelect.elements.previews, downloadPreviewSelect.elements.previews,
$el("div.download-settings-wrapper", [ $el("div.download-settings-wrapper", [
$el("div.download-settings", [ $el("div.download-settings", [
$el("button.icon-button", { new ComfyButton({
textContent: "📥︎", icon: "download",
onclick: async (e) => { tooltip: "Download model",
classList: "comfyui-button icon-button",
action: async (e) => {
const pathDirectory = el_saveDirectoryPath.value; const pathDirectory = el_saveDirectoryPath.value;
const modelName = (() => { const modelName = (() => {
const filename = info["fileName"]; const filename = info["fileName"];
@@ -3175,10 +3222,10 @@ class DownloadView {
} }
this.#updateModels(); this.#updateModels();
} }
buttonAlert(e.target, success, "✔", "✖", resultText); comfyButtonAlert(e.target, success, "mdi-check-bold", "mdi-close-thick");
e.target.disabled = success; e.target.disabled = success;
}, },
}), }).element,
$el("div.row.tab-header-flex-block", [ $el("div.row.tab-header-flex-block", [
el_saveDirectoryPath, el_saveDirectoryPath,
searchDropdown.element, searchDropdown.element,
@@ -3342,11 +3389,12 @@ class BrowseView {
this.element = $el("div", [ this.element = $el("div", [
$el("div.row.tab-header", [ $el("div.row.tab-header", [
$el("div.row.tab-header-flex-block", [ $el("div.row.tab-header-flex-block", [
$el("button.icon-button", { new ComfyButton({
type: "button", icon: "reload",
textContent: "⟳", tooltip: "Reload model grid",
onclick: () => updateModels(), classList: "comfyui-button icon-button",
}), action: async() => updateModels(),
}).element,
$el("select.model-select-dropdown", { $el("select.model-select-dropdown", {
$: (el) => (this.elements.modelTypeSelect = el), $: (el) => (this.elements.modelTypeSelect = el),
name: "model-type", name: "model-type",
@@ -3375,11 +3423,12 @@ class BrowseView {
searchInput, searchInput,
searchDropdown.element, searchDropdown.element,
]), ]),
$el("button.icon-button", { new ComfyButton({
type: "button", icon: "magnify",
textContent: "🔍︎", tooltip: "Search models",
onclick: () => updateModelGrid(), classList: "comfyui-button icon-button",
}), action: () => updateModelGrid(),
}).element,
]), ]),
]), ]),
modelGrid, modelGrid,
@@ -3461,7 +3510,7 @@ class SettingsView {
const data = await request("/model-manager/settings/load"); const data = await request("/model-manager/settings/load");
const settingsData = data["settings"]; const settingsData = data["settings"];
this.#setSettings(settingsData, updateModels); this.#setSettings(settingsData, updateModels);
buttonAlert(this.elements.reloadButton, true); comfyButtonAlert(this.elements.reloadButton, true);
} }
/** @returns {Promise<void>} */ /** @returns {Promise<void>} */
@@ -3496,7 +3545,7 @@ class SettingsView {
const settingsData = data["settings"]; const settingsData = data["settings"];
this.#setSettings(settingsData, true); this.#setSettings(settingsData, true);
} }
buttonAlert(this.elements.saveButton, success); comfyButtonAlert(this.elements.saveButton, success);
} }
/** /**
@@ -3515,23 +3564,27 @@ class SettingsView {
updateSidebarButtons(); updateSidebarButtons();
}); });
const reloadButton = new ComfyButton({
content: "Reload",
tooltip: "Reload settings and model manager files",
action: async() => await this.reload(true),
}).element;
this.elements.reloadButton = reloadButton;
const saveButton = new ComfyButton({
content: "Save",
tooltip: "Save settings and reload model manager",
action: async() => await this.save(),
}).element;
this.elements.saveButton = saveButton;
$el("div.model-manager-settings", { $el("div.model-manager-settings", {
$: (el) => (this.element = el), $: (el) => (this.element = el),
}, [ }, [
$el("h1", ["Settings"]), $el("h1", ["Settings"]),
$el("div", [ $el("div", [
$el("button", { reloadButton,
$: (el) => (this.elements.reloadButton = el), saveButton,
type: "button",
textContent: "Reload", // ⟳
onclick: async () => { await this.reload(true); },
}),
$el("button", {
$: (el) => (this.elements.saveButton = el),
type: "button",
textContent: "Save", // 💾︎
onclick: async () => { await this.save(); },
}),
]), ]),
$el("a", { $el("a", {
style: { color: "var(--fg-color)" }, style: { color: "var(--fg-color)" },
@@ -3937,6 +3990,15 @@ class ModelManager extends ComfyDialog {
sidebarButtonGroupChildren[i].classList.add("icon-button"); sidebarButtonGroupChildren[i].classList.add("icon-button");
} }
const closeModelInfoButton = new ComfyButton({
icon: "arrow-left",
tooltip: "Close model info",
classList: "comfyui-button icon-button",
action: async() => await this.#tryHideModelInfo(true),
}).element;
this.#closeModelInfoButton = closeModelInfoButton;
closeModelInfoButton.style.display = "none";
const modelManager = $el( const modelManager = $el(
"div.comfy-modal.model-manager", "div.comfy-modal.model-manager",
{ {
@@ -3951,21 +4013,18 @@ class ModelManager extends ComfyDialog {
$el("div.topbar-right", { $el("div.topbar-right", {
$: (el) => (this.#topbarRight = el), $: (el) => (this.#topbarRight = el),
}, [ }, [
$el("button.icon-button", { new ComfyButton({
textContent: "✖", icon: "window-close",
onclick: async() => { tooltip: "Close model manager",
classList: "comfyui-button icon-button",
action: async() => {
const saved = await this.#modelInfo.trySave(true); const saved = await this.#modelInfo.trySave(true);
if (saved) { if (saved) {
this.close(); this.close();
} }
} },
}), }).element,
$el("button.icon-button", { closeModelInfoButton,
$: (el) => (this.#closeModelInfoButton = el),
style: { display: "none" },
textContent: "⬅",
onclick: async() => { await this.#tryHideModelInfo(true); },
}),
sidebarSelect, sidebarSelect,
sidebarButtonGroup, sidebarButtonGroup,
]), ]),