diff --git a/ts/rgthree.ts b/ts/rgthree.ts
index bc1c160..6f8a957 100644
--- a/ts/rgthree.ts
+++ b/ts/rgthree.ts
@@ -74,7 +74,18 @@ class LogSession {
}
}
-
+export type RgthreeUiMessage = {
+ id: string;
+ message: string;
+ type?: 'warn'|null;
+ timeout?: number;
+ // closeable?: boolean; // TODO
+ actions?: Array<{
+ label: string;
+ href?: string;
+ callback?: (event: MouseEvent) => void;
+ }>;
+}
/**
* A global class as 'rgthree'; exposed on wiindow. Lots can go in here.
@@ -91,6 +102,77 @@ class Rgthree {
monitorBadLinksAlerted = false;
monitorLinkTimeout: number|null = null;
+ async clearAllMessages() {
+ let container = document.querySelector('.rgthree-top-messages-container');
+ container && (container.innerHTML = '');
+ }
+
+ async showMessage(data: RgthreeUiMessage) {
+ let container = document.querySelector('.rgthree-top-messages-container');
+ if (!container) {
+ container = document.createElement('div');
+ container.classList.add('rgthree-top-messages-container');
+ document.body.appendChild(container);
+ }
+ // Hide if we exist.
+ await this.hideMessage(data.id);
+
+ const messageContainer = document.createElement('div');
+ messageContainer.setAttribute('type', data.type || 'info');
+
+ const message = document.createElement('span');
+ message.innerText = data.message;
+ messageContainer.appendChild(message);
+
+ for (let a = 0; a < (data.actions || []).length; a++) {
+ const action = data.actions![a]!;
+ if (a > 0) {
+ const sep = document.createElement('span');
+ sep.innerHTML = ' | ';
+ messageContainer.appendChild(sep);
+ }
+
+ const actionEl = document.createElement('a');
+ actionEl.innerText = action.label;
+ if (action.href) {
+ actionEl.target = '_blank';
+ actionEl.href = action.href;
+ }
+ if (action.callback) {
+ actionEl.onclick = (e) => {
+ return action.callback!(e);
+ }
+ }
+ messageContainer.appendChild(actionEl);
+ }
+
+ const messageAnimContainer = document.createElement('div');
+ messageAnimContainer.setAttribute('msg-id', data.id);
+ messageAnimContainer.appendChild(messageContainer);
+ container.appendChild(messageAnimContainer);
+
+ // Add. Wait. Measure. Wait. Anim.
+ await wait(64);
+ messageAnimContainer.style.marginTop = `-${messageAnimContainer.offsetHeight}px`;
+ await wait(64);
+ messageAnimContainer.classList.add('-show');
+
+ if (data.timeout) {
+ await wait(data.timeout);
+ this.hideMessage(data.id);
+ }
+
+ }
+
+ async hideMessage(id: string) {
+ const msg = document.querySelector(`.rgthree-top-messages-container > [msg-id="${id}"]`);
+ if (msg?.classList.contains('-show')) {
+ msg.classList.remove('-show');
+ await wait(750);
+ }
+ msg && msg.remove();
+ }
+
constructor() {
window.addEventListener("keydown", (e) => {
this.ctrlKey = !!e.ctrlKey;
@@ -128,17 +210,17 @@ class Rgthree {
const clean = app.clean;
app.clean = function() {
- document.querySelector('.rgthree-bad-links-alerts-container')?.remove();
+ that.clearAllMessages();
clean && clean.call(app, ...arguments);
};
const loadGraphData = app.loadGraphData;
app.loadGraphData = function(graph: serializedLGraph) {
- if (this.monitorLinkTimeout) {
- clearTimeout(this.monitorLinkTimeout);
- this.monitorLinkTimeout = null;
+ if (that.monitorLinkTimeout) {
+ clearTimeout(that.monitorLinkTimeout);
+ that.monitorLinkTimeout = null;
}
- document.querySelector('.rgthree-bad-links-alerts-container')?.remove();
+ that.clearAllMessages();
// Try to make a copy to use, because ComfyUI's loadGraphData will modify it.
let graphCopy: serializedLGraph|null;
try {
@@ -151,71 +233,38 @@ class Rgthree {
const graphToUse = wasLoadingAborted ? (graphCopy || graph) : app.graph
const fixBadLinksResult = fixBadLinks(graphToUse);
if (fixBadLinksResult.hasBadLinks) {
- const div = document.createElement('div');
- div.classList.add('rgthree-bad-links-alerts');
- div.innerHTML = `
- ⚠️
-
- The workflow you've loaded may have connection/linking data that could be fixed.
-
- Open fixer
- |
- Fix in place
- `;
- div.style.background = '#353535';
- div.style.color = '#fff';
- div.style.display = 'flex';
- div.style.flexDirection = 'row';
- div.style.alignItems = 'center';
- div.style.justifyContent = 'center';
- div.style.height = 'fit-content';
- div.style.boxShadow = '0 0 10px rgba(0,0,0,0.88)';
- div.style.padding = '6px 12px';
- div.style.borderRadius = '0 0 4px 4px';
- div.style.fontFamily = 'Arial, sans-serif';
- div.style.fontSize = '14px';
- div.style.transform = 'translateY(-100%)';
- div.style.transition = 'transform 0.5s ease-in-out';
- const container = document.createElement('div');
- container.classList.add('rgthree-bad-links-alerts-container');
- container.appendChild(div);
- container.style.position = 'fixed';
- container.style.zIndex = '9999';
- container.style.top = '0';
- container.style.left = '0';
- container.style.width = '100%';
- container.style.height = '0';
- container.style.display = 'flex';
- container.style.justifyContent = 'center';
- document.body.appendChild(container);
-
- div.querySelector('.fix-in-place')?.addEventListener('click', (event) => {
- event.stopPropagation();
- event.preventDefault();
- if (confirm('This will attempt to fix in place. Please make sure to have a saved copy of your workflow.')) {
- const fixBadLinksResult = fixBadLinks(graphToUse, true);
- if (!fixBadLinksResult.hasBadLinks) {
- alert('Success! It\'s possible some valid links may have been affected. Please check and verify your workflow.');
- wasLoadingAborted && app.loadGraphData(fixBadLinksResult.graph);
- container.remove();
- if (rgthreeConfig['monitor_bad_links']) {
- that.monitorLinkTimeout = setTimeout(() => {
- that.monitorBadLinks();
- }, 5000);
+ that.showMessage({
+ id: 'bad-links',
+ type: 'warn',
+ message: 'The workflow you\'ve loaded may have connection/linking data that could be fixed.',
+ actions: [
+ {
+ label: 'Open fixer',
+ href: '/extensions/rgthree-comfy/html/links.html',
+ },
+ {
+ label: 'Fix in place',
+ href: '/extensions/rgthree-comfy/html/links.html',
+ callback: (event) => {
+ event.stopPropagation();
+ event.preventDefault();
+ if (confirm('This will attempt to fix in place. Please make sure to have a saved copy of your workflow.')) {
+ const fixBadLinksResult = fixBadLinks(graphToUse, true);
+ if (!fixBadLinksResult.hasBadLinks) {
+ that.hideMessage('bad-links');
+ alert('Success! It\'s possible some valid links may have been affected. Please check and verify your workflow.');
+ wasLoadingAborted && app.loadGraphData(fixBadLinksResult.graph);
+ if (rgthreeConfig['monitor_bad_links']) {
+ that.monitorLinkTimeout = setTimeout(() => {
+ that.monitorBadLinks();
+ }, 5000);
+ }
+ }
+ }
}
- }
- }
-
+ },
+ ]
});
-
- setTimeout(() => {
- const container = document.querySelector('.rgthree-bad-links-alerts') as HTMLElement;
- container && (container.style.transform = 'translateY(0%)');
- }, 500);
} else if (rgthreeConfig['monitor_bad_links']) {
that.monitorLinkTimeout = setTimeout(() => {
that.monitorBadLinks();
diff --git a/web/rgthree.css b/web/rgthree.css
index ac920b0..3489de3 100644
--- a/web/rgthree.css
+++ b/web/rgthree.css
@@ -1,4 +1,82 @@
+.rgthree-top-messages-container {
+ position: fixed;
+ z-index: 9999;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: start;
+}
+
+.rgthree-top-messages-container > div {
+ position: relative;
+ height: fit-content;
+ padding: 4px;
+ margin-top: -100px; /* re-set by JS */
+ opacity: 0;
+ transition: all 0.33s ease-in-out;
+ z-index: 3;
+}
+.rgthree-top-messages-container > div:last-child {
+ z-index: 2;
+}
+.rgthree-top-messages-container > div:not(.-show) {
+ z-index: 1;
+}
+
+.rgthree-top-messages-container > div.-show {
+ opacity: 1;
+ margin-top: 0px !important;
+}
+
+.rgthree-top-messages-container > div.-show {
+ opacity: 1;
+ transform: translateY(0%);
+}
+
+.rgthree-top-messages-container > div > div {
+ position: relative;
+ background: #353535;
+ color: #fff;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ height: fit-content;
+ box-shadow: 0 0 10px rgba(0,0,0,0.88);
+ padding: 6px 12px;
+ border-radius: 4px;
+ font-family: Arial, sans-serif;
+ font-size: 14px;
+}
+
+.rgthree-top-messages-container [type="warn"]::before {
+ content: '⚠️';
+ display: inline-block;
+ flex: 0 0 auto;
+ font-size: 18px;
+ margin-right: 4px;
+ line-height: 1;
+}
+
+.rgthree-top-messages-container a {
+ cursor: pointer;
+ text-decoration: underline;
+ color: #fc0;
+ margin-left: 4px;
+ display: inline-block;
+ line-height: 1;
+}
+
+.rgthree-top-messages-container a:hover {
+ color: #fc0;
+ text-decoration: none;
+}
+
/* Fix node selector being crazy long b/c of array types. */
.litegraph.litesearchbox input,
.litegraph.litesearchbox select {
diff --git a/web/rgthree.js b/web/rgthree.js
index 189d861..178b7eb 100644
--- a/web/rgthree.js
+++ b/web/rgthree.js
@@ -59,6 +59,64 @@ class LogSession {
}
}
class Rgthree {
+ async clearAllMessages() {
+ let container = document.querySelector('.rgthree-top-messages-container');
+ container && (container.innerHTML = '');
+ }
+ async showMessage(data) {
+ let container = document.querySelector('.rgthree-top-messages-container');
+ if (!container) {
+ container = document.createElement('div');
+ container.classList.add('rgthree-top-messages-container');
+ document.body.appendChild(container);
+ }
+ await this.hideMessage(data.id);
+ const messageContainer = document.createElement('div');
+ messageContainer.setAttribute('type', data.type || 'info');
+ const message = document.createElement('span');
+ message.innerText = data.message;
+ messageContainer.appendChild(message);
+ for (let a = 0; a < (data.actions || []).length; a++) {
+ const action = data.actions[a];
+ if (a > 0) {
+ const sep = document.createElement('span');
+ sep.innerHTML = ' | ';
+ messageContainer.appendChild(sep);
+ }
+ const actionEl = document.createElement('a');
+ actionEl.innerText = action.label;
+ if (action.href) {
+ actionEl.target = '_blank';
+ actionEl.href = action.href;
+ }
+ if (action.callback) {
+ actionEl.onclick = (e) => {
+ return action.callback(e);
+ };
+ }
+ messageContainer.appendChild(actionEl);
+ }
+ const messageAnimContainer = document.createElement('div');
+ messageAnimContainer.setAttribute('msg-id', data.id);
+ messageAnimContainer.appendChild(messageContainer);
+ container.appendChild(messageAnimContainer);
+ await wait(64);
+ messageAnimContainer.style.marginTop = `-${messageAnimContainer.offsetHeight}px`;
+ await wait(64);
+ messageAnimContainer.classList.add('-show');
+ if (data.timeout) {
+ await wait(data.timeout);
+ this.hideMessage(data.id);
+ }
+ }
+ async hideMessage(id) {
+ const msg = document.querySelector(`.rgthree-top-messages-container > [msg-id="${id}"]`);
+ if (msg === null || msg === void 0 ? void 0 : msg.classList.contains('-show')) {
+ msg.classList.remove('-show');
+ await wait(750);
+ }
+ msg && msg.remove();
+ }
constructor() {
this.ctrlKey = false;
this.altKey = false;
@@ -98,18 +156,16 @@ class Rgthree {
};
const clean = app.clean;
app.clean = function () {
- var _a;
- (_a = document.querySelector('.rgthree-bad-links-alerts-container')) === null || _a === void 0 ? void 0 : _a.remove();
+ that.clearAllMessages();
clean && clean.call(app, ...arguments);
};
const loadGraphData = app.loadGraphData;
app.loadGraphData = function (graph) {
- var _a;
- if (this.monitorLinkTimeout) {
- clearTimeout(this.monitorLinkTimeout);
- this.monitorLinkTimeout = null;
+ if (that.monitorLinkTimeout) {
+ clearTimeout(that.monitorLinkTimeout);
+ that.monitorLinkTimeout = null;
}
- (_a = document.querySelector('.rgthree-bad-links-alerts-container')) === null || _a === void 0 ? void 0 : _a.remove();
+ that.clearAllMessages();
let graphCopy;
try {
graphCopy = JSON.parse(JSON.stringify(graph));
@@ -118,73 +174,43 @@ class Rgthree {
graphCopy = null;
}
setTimeout(() => {
- var _a, _b, _c;
+ var _a, _b;
const wasLoadingAborted = (_b = (_a = document.querySelector('.comfy-modal-content')) === null || _a === void 0 ? void 0 : _a.textContent) === null || _b === void 0 ? void 0 : _b.includes('Loading aborted due');
const graphToUse = wasLoadingAborted ? (graphCopy || graph) : app.graph;
const fixBadLinksResult = fixBadLinks(graphToUse);
if (fixBadLinksResult.hasBadLinks) {
- const div = document.createElement('div');
- div.classList.add('rgthree-bad-links-alerts');
- div.innerHTML = `
- ⚠️
-
- The workflow you've loaded may have connection/linking data that could be fixed.
-
- Open fixer
- |
- Fix in place
- `;
- div.style.background = '#353535';
- div.style.color = '#fff';
- div.style.display = 'flex';
- div.style.flexDirection = 'row';
- div.style.alignItems = 'center';
- div.style.justifyContent = 'center';
- div.style.height = 'fit-content';
- div.style.boxShadow = '0 0 10px rgba(0,0,0,0.88)';
- div.style.padding = '6px 12px';
- div.style.borderRadius = '0 0 4px 4px';
- div.style.fontFamily = 'Arial, sans-serif';
- div.style.fontSize = '14px';
- div.style.transform = 'translateY(-100%)';
- div.style.transition = 'transform 0.5s ease-in-out';
- const container = document.createElement('div');
- container.classList.add('rgthree-bad-links-alerts-container');
- container.appendChild(div);
- container.style.position = 'fixed';
- container.style.zIndex = '9999';
- container.style.top = '0';
- container.style.left = '0';
- container.style.width = '100%';
- container.style.height = '0';
- container.style.display = 'flex';
- container.style.justifyContent = 'center';
- document.body.appendChild(container);
- (_c = div.querySelector('.fix-in-place')) === null || _c === void 0 ? void 0 : _c.addEventListener('click', (event) => {
- event.stopPropagation();
- event.preventDefault();
- if (confirm('This will attempt to fix in place. Please make sure to have a saved copy of your workflow.')) {
- const fixBadLinksResult = fixBadLinks(graphToUse, true);
- if (!fixBadLinksResult.hasBadLinks) {
- alert('Success! It\'s possible some valid links may have been affected. Please check and verify your workflow.');
- wasLoadingAborted && app.loadGraphData(fixBadLinksResult.graph);
- container.remove();
- if (rgthreeConfig['monitor_bad_links']) {
- that.monitorLinkTimeout = setTimeout(() => {
- that.monitorBadLinks();
- }, 5000);
+ that.showMessage({
+ id: 'bad-links',
+ type: 'warn',
+ message: 'The workflow you\'ve loaded may have connection/linking data that could be fixed.',
+ actions: [
+ {
+ label: 'Open fixer',
+ href: '/extensions/rgthree-comfy/html/links.html',
+ },
+ {
+ label: 'Fix in place',
+ href: '/extensions/rgthree-comfy/html/links.html',
+ callback: (event) => {
+ event.stopPropagation();
+ event.preventDefault();
+ if (confirm('This will attempt to fix in place. Please make sure to have a saved copy of your workflow.')) {
+ const fixBadLinksResult = fixBadLinks(graphToUse, true);
+ if (!fixBadLinksResult.hasBadLinks) {
+ that.hideMessage('bad-links');
+ alert('Success! It\'s possible some valid links may have been affected. Please check and verify your workflow.');
+ wasLoadingAborted && app.loadGraphData(fixBadLinksResult.graph);
+ if (rgthreeConfig['monitor_bad_links']) {
+ that.monitorLinkTimeout = setTimeout(() => {
+ that.monitorBadLinks();
+ }, 5000);
+ }
+ }
+ }
}
- }
- }
+ },
+ ]
});
- setTimeout(() => {
- const container = document.querySelector('.rgthree-bad-links-alerts');
- container && (container.style.transform = 'translateY(0%)');
- }, 500);
}
else if (rgthreeConfig['monitor_bad_links']) {
that.monitorLinkTimeout = setTimeout(() => {