feat: expand multi-ref pending resolutions and fix race conditions in loaded/missing tabs
- Add getResolutionQueueKey, getResolutionNodeRefs, and expandPendingResolutionsForApply helpers in queue_methods.js so each queued resolution can carry multiple node refs and be fully resolved before apply. - Store node_refs, is_lora_v2, original_lora_name, and nested_key on pending resolutions; expand them during apply, with a guard for empty selections. - Introduce optimistic analysis updates (applyOptimisticAnalysisData + getOptimisticAnalysisDataAfterApply) so the missing/loaded views refresh immediately after apply, then refresh in the background via refreshAnalysisInBackground. - Update notification messaging to reflect expanded reference counts. - Fix race conditions in lifecycle_graph_methods.js and tabs_loaded_methods.js by assigning load tokens only after the async workflow-load path begins, so early returns no longer clobber the token and stale panels are suppressed. - Minor README badge styling fixes: add labelColor=111827 and update the Python badge to an SVG-based asset.
This commit is contained in:
@@ -8,14 +8,13 @@
|
||||
|
||||
<p align="center">
|
||||
<img alt="ComfyUI" src="https://img.shields.io/badge/ComfyUI-1a1a1a?style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAASFBMVEVHcEwYLtsYLtkXLtkXLdkYLtkWLdcFIdoAD95uerfI1XLR3mq3xIP8/yj0/zvw/0FSYMP5/zKMmKQtPNOuuozj8FOhrZW7x4FMWFFbAAAABnRSTlMAUrPX87KxijklAAAA00lEQVR4AX3SBw6DMAxA0UzbrIzO+9+02GkEpoWP9hPZZs06Hw75aI3k4W/+wkQtnGZNhF1I34BzalQcxkmasY0b9raklNcvLYU1GNiiOeVWauOa/XS526gRyzpV/7HeUOG9Jp6vcsvUrCPeKg/3KBKBQhoTD1dQggPWzPVfFOIgo85/kR4y6oB/8SlIEh7wvmTuKd3wgLVW1sTfRBoR7oWVqy/U2NcrWDYMINE7NUuJuoV+2fhaWmnbjzcOWnRv7XbiLh/Y9dNUqk2y0QcNwTu7wgf+/BhsPUhf4QAAAABJRU5ErkJggg==" />
|
||||
<img alt='GitHub Clones' src='https://img.shields.io/badge/dynamic/json?color=2F80ED&label=Clone&query=count&url=https://gist.githubusercontent.com/Azornes/2730ed6bbf240f06efd0c183bddd3d6c/raw/clone.json&logo=github&style=for-the-badge'></a>
|
||||
<img alt='GitHub Clones' src='https://img.shields.io/badge/dynamic/json?color=2F80ED&label=Clone&query=count&url=https://gist.githubusercontent.com/Azornes/2730ed6bbf240f06efd0c183bddd3d6c/raw/clone.json&logo=github&style=for-the-badge&labelColor=111827'></a>
|
||||
<a href="https://visitorbadge.io/status?path=https%3A%2F%2Fgithub.com%2FAzornes%2FComfyui-Resolution-Master">
|
||||
<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" /></a>
|
||||
<img alt="Python 3.10+" src="https://img.shields.io/badge/-Python_3.10+-4B8BBE?logo=python&logoColor=FFFFFF&style=for-the-badge&logoWidth=20">
|
||||
<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" 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=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>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<strong>🔹 <a href="#%EF%B8%8F-installation">Quick Start</a></strong>
|
||||
|
|
||||
|
||||
@@ -387,7 +387,7 @@ export const queueMethods = {
|
||||
this.pendingIndex = new Map();
|
||||
for (let i = 0; i < this.pendingResolutions.length; i++) {
|
||||
const r = this.pendingResolutions[i];
|
||||
const key = `${r.node_id}:${r.widget_index}:${r.subgraph_id || ''}:${r.is_top_level ? 'T' : 'F'}`;
|
||||
const key = this.getResolutionQueueKey(r);
|
||||
this.pendingIndex.set(key, i);
|
||||
}
|
||||
},
|
||||
@@ -408,6 +408,77 @@ export const queueMethods = {
|
||||
this.updateQueuePanel();
|
||||
},
|
||||
|
||||
getResolutionQueueKey(resolution = {}) {
|
||||
const nodeId = resolution.node_id ?? '';
|
||||
const widgetIndex = resolution.widget_index ?? '';
|
||||
const subgraphId = resolution.subgraph_id || '';
|
||||
const scope = resolution.is_top_level !== false ? 'T' : 'F';
|
||||
return `${nodeId}:${widgetIndex}:${subgraphId}:${scope}`;
|
||||
},
|
||||
|
||||
getResolutionNodeRefs(missing = {}) {
|
||||
const refs = Array.isArray(missing.all_node_refs) && missing.all_node_refs.length
|
||||
? missing.all_node_refs
|
||||
: [missing];
|
||||
|
||||
return refs.map(ref => ({
|
||||
node_id: ref.node_id,
|
||||
node_type: ref.node_type,
|
||||
node_title: ref.node_title,
|
||||
widget_index: ref.widget_index,
|
||||
original_path: ref.original_path,
|
||||
name: ref.name,
|
||||
category: ref.category,
|
||||
subgraph_id: ref.subgraph_id,
|
||||
subgraph_name: ref.subgraph_name,
|
||||
is_top_level: ref.is_top_level,
|
||||
is_lora_v2: ref.is_lora_v2,
|
||||
nested_key: ref.nested_key
|
||||
}));
|
||||
},
|
||||
|
||||
expandPendingResolutionsForApply(list = this.pendingResolutions || []) {
|
||||
const expanded = [];
|
||||
const seen = new Set();
|
||||
|
||||
for (const resolution of Array.isArray(list) ? list : []) {
|
||||
const { node_refs, all_node_refs, ...baseResolution } = resolution || {};
|
||||
const refs = Array.isArray(node_refs) && node_refs.length
|
||||
? node_refs
|
||||
: (Array.isArray(all_node_refs) && all_node_refs.length ? all_node_refs : [resolution]);
|
||||
|
||||
for (const ref of refs.filter(Boolean)) {
|
||||
const item = {
|
||||
...baseResolution,
|
||||
node_id: ref.node_id ?? baseResolution.node_id,
|
||||
widget_index: ref.widget_index ?? baseResolution.widget_index,
|
||||
category: ref.category || baseResolution.category,
|
||||
subgraph_id: ref.subgraph_id ?? baseResolution.subgraph_id,
|
||||
is_top_level: ref.is_top_level ?? baseResolution.is_top_level,
|
||||
is_lora_v2: ref.is_lora_v2 ?? baseResolution.is_lora_v2,
|
||||
original_lora_name: ref.name || ref.original_path || baseResolution.original_lora_name || baseResolution.name || baseResolution.original_path,
|
||||
nested_key: ref.nested_key ?? baseResolution.nested_key,
|
||||
original_path: ref.original_path || baseResolution.original_path,
|
||||
node_type: ref.node_type || baseResolution.node_type,
|
||||
node_label: ref.subgraph_name || ref.node_type || baseResolution.node_label
|
||||
};
|
||||
const itemKey = [
|
||||
item.node_id ?? '',
|
||||
item.widget_index ?? '',
|
||||
item.subgraph_id || '',
|
||||
item.is_top_level !== false ? 'T' : 'F',
|
||||
item.nested_key || '',
|
||||
item.original_lora_name || item.original_path || ''
|
||||
].join(':');
|
||||
if (seen.has(itemKey)) continue;
|
||||
seen.add(itemKey);
|
||||
expanded.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return expanded;
|
||||
},
|
||||
|
||||
updateQueueVisibility() {
|
||||
const isMissingTab = this.activeTab === 'missing';
|
||||
const showQueuePanel = isMissingTab && !this.queueCollapsed;
|
||||
@@ -628,11 +699,15 @@ export const queueMethods = {
|
||||
original_path: missing.original_path,
|
||||
subgraph_id: missing.subgraph_id,
|
||||
is_top_level: missing.is_top_level,
|
||||
is_lora_v2: missing.is_lora_v2,
|
||||
original_lora_name: missing.name || missing.original_path,
|
||||
nested_key: missing.nested_key,
|
||||
node_refs: this.getResolutionNodeRefs(missing),
|
||||
node_type: missing.node_type,
|
||||
node_label: missing.subgraph_name || missing.node_type
|
||||
};
|
||||
|
||||
const key = `${resolution.node_id}:${resolution.widget_index}:${resolution.subgraph_id || ''}:${resolution.is_top_level ? 'T' : 'F'}`;
|
||||
const key = this.getResolutionQueueKey(resolution);
|
||||
if (this.pendingIndex.has(key)) {
|
||||
// replace existing selection for this slot
|
||||
const idx = this.pendingIndex.get(key);
|
||||
@@ -660,6 +735,12 @@ export const queueMethods = {
|
||||
}
|
||||
|
||||
try {
|
||||
const appliedSelections = this.clonePendingResolutions?.(list) || JSON.parse(JSON.stringify(list));
|
||||
const applyResolutions = this.expandPendingResolutionsForApply(appliedSelections);
|
||||
if (!applyResolutions.length) {
|
||||
this.showNotification('No valid selections to apply', 'error');
|
||||
return;
|
||||
}
|
||||
const workflow = this.getCurrentWorkflow();
|
||||
if (!workflow) {
|
||||
this.showNotification('No workflow loaded', 'error');
|
||||
@@ -669,22 +750,32 @@ export const queueMethods = {
|
||||
const response = await api.fetchApi('/model_resolver/resolve', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ workflow, resolutions: list })
|
||||
body: JSON.stringify({ workflow, resolutions: applyResolutions })
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error(`API error: ${response.status}`);
|
||||
|
||||
const data = await response.json();
|
||||
if (data.success) {
|
||||
const optimisticData = this.getOptimisticAnalysisDataAfterApply(appliedSelections);
|
||||
await this.updateWorkflowInComfyUI(data.workflow);
|
||||
this.showNotification(`✓ Linked ${list.length} selection${list.length>1?'s':''}`, 'success');
|
||||
// Clear queue and refresh analysis
|
||||
|
||||
this.pendingResolutions = [];
|
||||
this.pendingIndex = new Map();
|
||||
this.savePendingQueueForActiveWorkflow();
|
||||
this.syncWorkflowScopedQueue?.(data.workflow);
|
||||
|
||||
this.updateApplyPendingButton();
|
||||
this.updateQueuePanel();
|
||||
await this.loadWorkflowData(data.workflow, { force: true });
|
||||
|
||||
this.applyOptimisticAnalysisData(optimisticData, data.workflow);
|
||||
|
||||
const selectionCount = appliedSelections.length;
|
||||
const refText = applyResolutions.length > selectionCount
|
||||
? ` (${applyResolutions.length} references)`
|
||||
: '';
|
||||
this.showNotification(`✓ Linked ${selectionCount} selection${selectionCount > 1 ? 's' : ''}${refText}`, 'success');
|
||||
this.refreshAnalysisInBackground(data.workflow, this.getWorkflowSignature(data.workflow));
|
||||
} else {
|
||||
this.showNotification('Failed to apply selections: ' + (data.error || 'Unknown error'), 'error');
|
||||
}
|
||||
@@ -754,7 +845,7 @@ export const queueMethods = {
|
||||
const pending = Array.isArray(this.pendingResolutions) ? this.pendingResolutions : [];
|
||||
if (!pending.length) return [];
|
||||
|
||||
const pendingKeys = new Set(pending.map(resolution => this.getMissingModelKey(resolution)));
|
||||
const pendingKeys = new Set(pending.map(resolution => this.getResolutionQueueKey(resolution)));
|
||||
return (this.missingModels || []).filter(missing => pendingKeys.has(this.getMissingModelKey(missing)));
|
||||
},
|
||||
|
||||
@@ -787,6 +878,80 @@ export const queueMethods = {
|
||||
return (this.missingModels || []).filter(missing => activeKeys.has(this.getMissingModelKey(missing)));
|
||||
},
|
||||
|
||||
getOptimisticAnalysisDataAfterApply(appliedSelections = []) {
|
||||
const missingModels = Array.isArray(this.missingModels) ? this.missingModels : [];
|
||||
const appliedKeys = new Set(
|
||||
(Array.isArray(appliedSelections) ? appliedSelections : [])
|
||||
.map(selection => this.getResolutionQueueKey(selection))
|
||||
);
|
||||
if (!appliedKeys.size) return null;
|
||||
|
||||
const sourceData = this.cachedAnalysisData || {
|
||||
missing_models: missingModels,
|
||||
total_missing: missingModels.length
|
||||
};
|
||||
const sourceMissing = Array.isArray(sourceData.missing_models)
|
||||
? sourceData.missing_models
|
||||
: missingModels;
|
||||
const nextMissing = sourceMissing.filter(missing => !appliedKeys.has(this.getMissingModelKey(missing)));
|
||||
|
||||
return {
|
||||
...sourceData,
|
||||
missing_models: nextMissing,
|
||||
total_missing: nextMissing.length
|
||||
};
|
||||
},
|
||||
|
||||
applyOptimisticAnalysisData(data, workflow = null) {
|
||||
if (!data) return false;
|
||||
|
||||
const workflowSignature = this.getWorkflowSignature(workflow || this.getCurrentWorkflow());
|
||||
if (workflowSignature) {
|
||||
this.cachedWorkflowSignature = workflowSignature;
|
||||
}
|
||||
this.cachedAnalysisData = this.cloneAnalysisData?.(data) || data;
|
||||
this.saveAnalysisCacheForActiveWorkflow?.();
|
||||
|
||||
if (this.activeTab === 'missing' && this.contentElement) {
|
||||
this.displayMissingModels(this.contentElement, data);
|
||||
this.reconnectActiveDownloads?.();
|
||||
} else {
|
||||
this.missingModels = Array.isArray(data.missing_models) ? data.missing_models : [];
|
||||
this.updateBatchFooterButtons?.();
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
refreshAnalysisInBackground(workflow, expectedSignature = null) {
|
||||
if (!workflow) return;
|
||||
|
||||
const signature = expectedSignature || this.getWorkflowSignature(workflow);
|
||||
api.fetchApi('/model_resolver/analyze', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ workflow })
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) throw new Error(`API error: ${response.status}`);
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
if (signature && this.activeWorkflowSignature !== signature) return;
|
||||
this.cachedWorkflowSignature = signature || this.cachedWorkflowSignature;
|
||||
this.cachedAnalysisData = data;
|
||||
this.saveAnalysisCacheForActiveWorkflow?.();
|
||||
|
||||
if (this.activeTab === 'missing' && this.contentElement && !this._analysisProgressToken) {
|
||||
this.displayMissingModels(this.contentElement, data);
|
||||
this.reconnectActiveDownloads?.();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.warn('Model Resolver: background analysis refresh failed:', error);
|
||||
});
|
||||
},
|
||||
|
||||
previewFooterMenuModels(models = []) {
|
||||
const keys = new Set(
|
||||
(Array.isArray(models) ? models : [])
|
||||
|
||||
@@ -116,10 +116,11 @@ export const lifecycleGraphMethods = {
|
||||
async loadWorkflowData(workflow = null, { force = false } = {}) {
|
||||
if (!this.contentElement) return;
|
||||
|
||||
const loadToken = `missing-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
||||
this._workflowDataLoadToken = loadToken;
|
||||
this._workflowDataLoadToken = null;
|
||||
let loadToken = null;
|
||||
const shouldRenderMissingModels = () => (
|
||||
this.activeTab === 'missing' &&
|
||||
loadToken &&
|
||||
this._workflowDataLoadToken === loadToken &&
|
||||
this.contentElement
|
||||
);
|
||||
@@ -132,16 +133,19 @@ export const lifecycleGraphMethods = {
|
||||
}
|
||||
|
||||
if (!workflow) {
|
||||
if (this._workflowDataLoadToken === loadToken) {
|
||||
this._analysisProgressToken = null;
|
||||
}
|
||||
this._analysisProgressToken = null;
|
||||
if (shouldRenderMissingModels()) {
|
||||
this.contentElement.innerHTML = '<p>No workflow loaded. Please load a workflow first.</p>';
|
||||
} else if (this.activeTab === 'missing' && this.contentElement) {
|
||||
this.contentElement.innerHTML = '<p>No workflow loaded. Please load a workflow first.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.syncWorkflowScopedQueue(workflow);
|
||||
|
||||
loadToken = `missing-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
||||
this._workflowDataLoadToken = loadToken;
|
||||
|
||||
const workflowSignature = this.getWorkflowSignature(workflow);
|
||||
if (force) {
|
||||
this.invalidateLoadedModelsCacheForActiveWorkflow();
|
||||
@@ -200,12 +204,14 @@ export const lifecycleGraphMethods = {
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
if (this._workflowDataLoadToken === loadToken) {
|
||||
if (!loadToken || this._workflowDataLoadToken === loadToken) {
|
||||
this._analysisProgressToken = null;
|
||||
}
|
||||
console.error('Model Resolver: Error loading workflow data:', error);
|
||||
if (shouldRenderMissingModels()) {
|
||||
this.contentElement.innerHTML = `<p class="mr-error-text">Error: ${error.message}</p>`;
|
||||
} else if (!loadToken && this.activeTab === 'missing' && this.contentElement) {
|
||||
this.contentElement.innerHTML = `<p class="mr-error-text">Error: ${error.message}</p>`;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -73,10 +73,11 @@ export const tabsLoadedMethods = {
|
||||
async loadLoadedModels(workflow = null, { force = false } = {}) {
|
||||
if (!this.contentElement) return;
|
||||
|
||||
const loadToken = `loaded-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
||||
this._loadedModelsLoadToken = loadToken;
|
||||
this._loadedModelsLoadToken = null;
|
||||
let loadToken = null;
|
||||
const shouldRenderLoadedModels = () => (
|
||||
this.activeTab === 'loaded' &&
|
||||
loadToken &&
|
||||
this._loadedModelsLoadToken === loadToken &&
|
||||
this.contentElement
|
||||
);
|
||||
@@ -86,11 +87,16 @@ export const tabsLoadedMethods = {
|
||||
if (!workflow) {
|
||||
if (shouldRenderLoadedModels()) {
|
||||
this.contentElement.innerHTML = '<p>No workflow loaded. Please load a workflow first.</p>';
|
||||
} else if (this.activeTab === 'loaded' && this.contentElement) {
|
||||
this.contentElement.innerHTML = '<p>No workflow loaded. Please load a workflow first.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.syncWorkflowScopedQueue(workflow);
|
||||
|
||||
loadToken = `loaded-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
||||
this._loadedModelsLoadToken = loadToken;
|
||||
|
||||
const workflowSignature = this.getWorkflowSignature(workflow);
|
||||
if (
|
||||
!force &&
|
||||
@@ -132,6 +138,8 @@ export const tabsLoadedMethods = {
|
||||
console.error('Model Resolver: Error loading loaded models:', error);
|
||||
if (shouldRenderLoadedModels()) {
|
||||
this.contentElement.innerHTML = `<p class="mr-error-text">Error: ${error.message}</p>`;
|
||||
} else if (!loadToken && this.activeTab === 'loaded' && this.contentElement) {
|
||||
this.contentElement.innerHTML = `<p class="mr-error-text">Error: ${error.message}</p>`;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user