Add per-item Apply button to queued resolution selected bar
Refactor queue_methods.js to split applyPendingResolutions into applyQueuedByKey (per-item) and applyPendingResolutionList (shared implementation). Add an Apply button alongside the Remove button in the selected resolution bar, wired to applyQueuedByKey with loading state. Update CSS for .mr-selected-actions layout and .mr-btn-primary styling in the detail pane.
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
<img src="https://api.visitorbadge.io/api/combined?path=https%3A%2F%2Fgithub.com%2FAzornes%2FComfyui-Model-Resolver&countColor=%2337d67a&style=for-the-badge&labelStyle=none&labelColor=111827" /></a>
|
||||
<img alt="Python 3.10+" src="https://img.shields.io/badge/Python-3.10+-4B8BBE?labelColor=111827&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMTAiIGhlaWdodD0iMTEwIiB2aWV3Qm94PSIwLjIxIC0wLjA3NyAxMTAgMTEwIj48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImEiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iNjMuODE1OSIgeTE9IjU2LjY4MjkiIHgyPSIxMTguNDkzNCIgeTI9IjEuODIyNSIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxIDAgMCAtMSAtNTMuMjk3NCA2Ni40MzIxKSI%2BPHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjMzg3RUI4Ii8%2BPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMzY2OTk0Ii8%2BPC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImIiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iOTcuMDQ0NCIgeTE9IjIxLjYzMjEiIHgyPSIxNTUuNjY2NSIgeTI9Ii0zNC41MzA4IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEgMCAwIC0xIC01My4yOTc0IDY2LjQzMjEpIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNGRkUwNTIiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNGRkMzMzEiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48cGF0aCBmaWxsPSJ1cmwoI2EpIiBkPSJNNTUuMDIzLTAuMDc3Yy0yNS45NzEsMC0yNi4yNSwxMC4wODEtMjYuMjUsMTIuMTU2djEyLjU5NGgyNi43NXYzLjc4MUgxOC4xNDhjLTcuOTQ5LDAtMTcuOTM4LDQuODMzLTE3LjkzOCwyNi4yNSwwLDE5LjY3Myw3Ljc5MiwyNy4yODEsMTUuNjU2LDI3LjI4MWg5LjM0NFY2OC44NmMwLTUuNDkxLDIuNzIxLTE1LjY1NiwxNS40MDYtMTUuNjU2aDI2LjUzMWMzLjkwMiwwLDE0LjkwNi0xLjY5NiwxNC45MDYtMTQuNDA2VjE0LjU3OWMuMDAxLTMuMTUzLS41MzgtMTQuNjU2LTI3LjAzLTE0LjY1NnpNNDAuMjczLDguMzkyYzIuNjYyLDAsNC44MTMsMi4xNSw0LjgxMyw0LjgxMywwLDIuNjYxLTIuMTUxLDQuODEzLTQuODEzLDQuODEzcy00LjgxMy0yLjE1MS00LjgxMy00LjgxM2MwLTIuNjYzLDIuMTUxLTQuODEzLDQuODEzLTQuODEzeiIvPjxwYXRoIGZpbGw9InVybCgjYikiIGQ9Ik01NS4zOTcsMTA5LjkyM2MyNS45NTksMCwyNi4yODItMTAuMjcxLDI2LjI4Mi0xMi4xNTZWODUuMTczSDU0Ljg5N3YtMy43ODFoMzcuMzc1YzguMDA5LDAsMTcuOTM4LTQuOTU0LDE3LjkzOC0yNi4yNSwwLTIzLjMyMi0xMC41MzgtMjcuMjgxLTE1LjY1Ni0yNy4yODFIODUuMjF2MTMuMTI1YzAsNS40OTEtMi42MzEsMTUuNjU2LTE1LjQwNiwxNS42NTZINDMuMjcyYy0zLjg5MiwwLTE0LjkwNiwxLjg5Ni0xNC45MDYsMTQuNDA2djI0LjIxOWMwLDUuMjMsMy4xOTYsMTQuNjU2LDI3LjAzMSwxNC42NTZ6TTcwLjE0OCwxMDEuNDU0Yy0yLjY2MiwwLTQuODEzLTIuMTUxLTQuODEzLTQuODEzczIuMTUtNC44MTMsNC44MTMtNC44MTNjMi42NjEsMCw0LjgxMywyLjE1MSw0LjgxMyw0LjgxM3MtMi4xNTIsNC44MTMtNC44MTMsNC44MTN6Ii8%2BPC9zdmc%2B&style=for-the-badge">
|
||||
<img alt="JavaScript" src="https://img.shields.io/badge/-JavaScript-000000?logo=javascript&logoColor=F7DF1E&style=for-the-badge&logoWidth=20">
|
||||
<a href="https://github.com/sponsors/Azornes"><img src="https://img.shields.io/badge/Sponsor-EA4AAA?style=for-the-badge&logo=githubsponsors&logoColor=white&labelColor=111827" alt="Sponsor"><img src="https://img.shields.io/badge/-%20-181717?style=for-the-badge&logo=github&logoColor=white" alt="GitHub"></a>
|
||||
<a href="https://github.com/sponsors/Azornes"><img src="https://img.shields.io/badge/Sponsor-EA4AAA?style=for-the-badge&logo=githubsponsors&logoColor=rede&labelColor=111827" alt="Sponsor"><img src="https://img.shields.io/badge/-%20-181717?style=for-the-badge&logo=github&logoColor=white" alt="GitHub"></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<strong>🔹 <a href="#%EF%B8%8F-installation">Quick Start</a></strong>
|
||||
|
||||
@@ -5390,11 +5390,15 @@
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#model-resolver-modal .mr-missing-detail-pane .mr-selected-actions {
|
||||
gap: 8px;
|
||||
margin-left: auto;
|
||||
}
|
||||
#model-resolver-modal .mr-missing-detail-pane .model-resolver-selected .mr-btn {
|
||||
min-height: var(--mr-missing-search-button-height, 34px);
|
||||
height: var(--mr-missing-search-button-height, 34px);
|
||||
padding: 0 12px;
|
||||
margin-left: auto;
|
||||
margin-left: 0;
|
||||
background: var(--mr-missing-control-bg, rgba(255,255,255,0.035));
|
||||
border-color: var(--mr-missing-control-border, rgba(255,255,255,0.105));
|
||||
border-radius: var(--mr-missing-control-radius, 7px);
|
||||
@@ -5408,6 +5412,16 @@
|
||||
border-color: var(--mr-missing-control-border-hover, rgba(255,255,255,0.17));
|
||||
color: var(--mr-text);
|
||||
}
|
||||
#model-resolver-modal .mr-missing-detail-pane .model-resolver-selected .mr-btn-primary {
|
||||
background: rgba(47, 128, 237, 0.18);
|
||||
border-color: rgba(47, 128, 237, 0.34);
|
||||
color: #dbeafe;
|
||||
}
|
||||
#model-resolver-modal .mr-missing-detail-pane .model-resolver-selected .mr-btn-primary:hover:not(:disabled) {
|
||||
background: rgba(47, 128, 237, 0.26);
|
||||
border-color: rgba(47, 128, 237, 0.48);
|
||||
color: #ffffff;
|
||||
}
|
||||
#model-resolver-modal .mr-missing-detail-pane .mr-search-progress-list-compact {
|
||||
gap: 7px;
|
||||
margin: 10px 0 8px;
|
||||
|
||||
@@ -523,6 +523,14 @@
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.mr-selected-actions {
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
align-items: center;
|
||||
gap: var(--mr-spacing-8);
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.mr-inline-note-link {
|
||||
cursor: pointer;
|
||||
color: var(--mr-accent-blue);
|
||||
|
||||
@@ -343,17 +343,28 @@ export const queueMethods = {
|
||||
|
||||
// Build selected bar content
|
||||
const label = selection.resolved_model?.relative_path || selection.resolved_model?.filename || selection.resolved_path || '';
|
||||
const resolveBtnId = `selected-remove-${nodeId}-${widgetIndex}`;
|
||||
const applyBtnId = `selected-apply-${nodeId}-${widgetIndex}`;
|
||||
const removeBtnId = `selected-remove-${nodeId}-${widgetIndex}`;
|
||||
|
||||
selectedBar.innerHTML = `<div class="mr-selected-bar-inner">`;
|
||||
selectedBar.innerHTML += `<span class="mr-selected-label">✓ Selected:</span>`;
|
||||
selectedBar.innerHTML += `<code class="mr-selected-code">${label}</code>`;
|
||||
selectedBar.innerHTML += `<button id="${resolveBtnId}" class="mr-btn mr-btn-secondary mr-btn-sm">Remove</button>`;
|
||||
selectedBar.innerHTML += `<span class="mr-selected-actions">`;
|
||||
selectedBar.innerHTML += `<button id="${applyBtnId}" class="mr-btn mr-btn-primary mr-btn-sm" data-tooltip="Apply this selected local match to the workflow.">Apply</button>`;
|
||||
selectedBar.innerHTML += `<button id="${removeBtnId}" class="mr-btn mr-btn-secondary mr-btn-sm">Remove</button>`;
|
||||
selectedBar.innerHTML += `</span>`;
|
||||
selectedBar.innerHTML += `</div>`;
|
||||
selectedBar.style.display = 'block';
|
||||
|
||||
const applyBtn = selectedBar.querySelector(`#${applyBtnId}`);
|
||||
if (applyBtn) {
|
||||
applyBtn.addEventListener('click', () => {
|
||||
this.applyQueuedByKey(key, applyBtn);
|
||||
});
|
||||
}
|
||||
|
||||
// Wire remove button - use key-based removal
|
||||
const removeBtn = selectedBar.querySelector(`#${resolveBtnId}`);
|
||||
const removeBtn = selectedBar.querySelector(`#${removeBtnId}`);
|
||||
if (removeBtn) {
|
||||
removeBtn.addEventListener('click', () => {
|
||||
this.removeQueuedByKey(key);
|
||||
@@ -725,10 +736,39 @@ export const queueMethods = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Apply all pending resolutions in batch
|
||||
* Apply one queued resolution from the selected bar.
|
||||
*/
|
||||
async applyPendingResolutions() {
|
||||
const list = this.pendingResolutions || [];
|
||||
async applyQueuedByKey(key, button = null) {
|
||||
if (!key || !this.pendingIndex.has(key)) {
|
||||
this.showNotification('Selected match is no longer queued.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const idx = this.pendingIndex.get(key);
|
||||
const selection = this.pendingResolutions?.[idx];
|
||||
if (!selection) {
|
||||
this.showNotification('Selected match is no longer queued.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (button) {
|
||||
button.disabled = true;
|
||||
button.classList.add('mr-btn-is-disabled');
|
||||
button.textContent = 'Applying...';
|
||||
}
|
||||
|
||||
try {
|
||||
await this.applyPendingResolutionList([selection], { clearAll: false });
|
||||
} finally {
|
||||
if (button?.isConnected) {
|
||||
button.disabled = false;
|
||||
button.classList.remove('mr-btn-is-disabled');
|
||||
button.textContent = 'Apply';
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async applyPendingResolutionList(list, { clearAll = false } = {}) {
|
||||
if (!list.length) {
|
||||
this.showNotification('No selections queued', 'error');
|
||||
return;
|
||||
@@ -760,11 +800,19 @@ export const queueMethods = {
|
||||
const optimisticData = this.getOptimisticAnalysisDataAfterApply(appliedSelections);
|
||||
await this.updateWorkflowInComfyUI(data.workflow);
|
||||
|
||||
this.pendingResolutions = [];
|
||||
this.pendingIndex = new Map();
|
||||
const appliedKeys = new Set(appliedSelections.map(selection => this.getResolutionQueueKey(selection)));
|
||||
const remainingSelections = clearAll
|
||||
? []
|
||||
: (this.pendingResolutions || []).filter(selection => !appliedKeys.has(this.getResolutionQueueKey(selection)));
|
||||
|
||||
this.pendingResolutions = remainingSelections;
|
||||
this.rebuildPendingIndex();
|
||||
this.savePendingQueueForActiveWorkflow();
|
||||
this.syncWorkflowScopedQueue?.(data.workflow);
|
||||
|
||||
this.pendingResolutions = remainingSelections;
|
||||
this.rebuildPendingIndex();
|
||||
this.savePendingQueueForActiveWorkflow();
|
||||
this.updateApplyPendingButton();
|
||||
this.updateQueuePanel();
|
||||
|
||||
@@ -785,6 +833,14 @@ export const queueMethods = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Apply all pending resolutions in batch
|
||||
*/
|
||||
async applyPendingResolutions() {
|
||||
const list = this.pendingResolutions || [];
|
||||
await this.applyPendingResolutionList(list, { clearAll: true });
|
||||
},
|
||||
|
||||
updateApplyPendingButton() {
|
||||
if (!this.applyPendingBtn) return;
|
||||
const count = this.pendingResolutions?.length || 0;
|
||||
|
||||
Reference in New Issue
Block a user