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
+
@@ -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 || [];