diff --git a/web/css/resolver-main.css b/web/css/resolver-main.css index 26cf36a..78d643c 100644 --- a/web/css/resolver-main.css +++ b/web/css/resolver-main.css @@ -537,6 +537,24 @@ gap: 6px; flex-wrap: wrap; } +.mr-missing-list-tools { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 8px; + flex-wrap: wrap; +} +.mr-missing-refresh-btn, +#model-resolver-modal .mr-missing-refresh-btn { + min-height: 26px; + padding: 0 8px; + gap: 5px; + font-size: 11px; +} +.mr-missing-refresh-btn svg { + width: 13px; + height: 13px; +} .mr-missing-stat { display: inline-flex; align-items: center; diff --git a/web/resolver/views/missing_browser_methods.js b/web/resolver/views/missing_browser_methods.js index 3ab74fd..9d5dbe1 100644 --- a/web/resolver/views/missing_browser_methods.js +++ b/web/resolver/views/missing_browser_methods.js @@ -215,10 +215,15 @@ export const missingBrowserMethods = {
${totalMissing} missing model${totalMissing === 1 ? '' : 's'}
${this.escapeHtml(activeHint)}
-
- ${stats.exact} exact - ${stats.partial} partial - ${stats.none} no match +
+
+ ${stats.exact} exact + ${stats.partial} partial + ${stats.none} no match +
+
@@ -293,6 +298,12 @@ export const missingBrowserMethods = { wireMissingModelsBrowser(container, data, sortedMissingModels) { this.wireMissingBrowserSplitter(container); + const refreshBtn = container.querySelector('#mr-refresh-missing-analysis'); + if (refreshBtn && refreshBtn.dataset.mlRefreshBound !== 'true') { + refreshBtn.dataset.mlRefreshBound = 'true'; + refreshBtn.addEventListener('click', () => this.refreshMissingAnalysis(refreshBtn)); + } + const selectRow = (row) => { const key = row.dataset.missingKey; if (!key || key === this.selectedMissingModelKey) return; @@ -729,6 +740,30 @@ export const missingBrowserMethods = { this.updateBatchFooterButtons(); }, + async refreshMissingAnalysis(button = null) { + if (button?.disabled) return; + + try { + if (button) { + button.disabled = true; + button.classList.add('mr-btn-is-disabled'); + } + + this.showNotification('Refreshing missing models and local matches...', 'info'); + this.allModels = null; + this.invalidateLoadedModelsCacheForActiveWorkflow?.(); + await this.loadWorkflowData(null, { force: true }); + } catch (error) { + console.error('Model Resolver: missing analysis refresh failed:', error); + this.showNotification('Refresh failed: ' + error.message, 'error'); + } finally { + if (button) { + button.disabled = false; + button.classList.remove('mr-btn-is-disabled'); + } + } + }, + renderMissingModel(missing, missingIndex = 0) { const allMatches = missing.matches || [];