diff --git a/web/resolver/actions/queue_methods.js b/web/resolver/actions/queue_methods.js index 06f4646..89a3b9e 100644 --- a/web/resolver/actions/queue_methods.js +++ b/web/resolver/actions/queue_methods.js @@ -1795,15 +1795,10 @@ export const queueMethods = { return; } - const response = await api.fetchApi('/model_resolver/resolve', { + const data = await this.fetchJson('/model_resolver/resolve', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ workflow, resolutions: applyResolutions }) - }); - - if (!response.ok) throw new Error(`API error: ${response.status}`); - - const data = await response.json(); + }, 'Apply resolutions'); if (data.success) { const optimisticData = this.getOptimisticAnalysisDataAfterApply(appliedSelections); await this.refreshComfyModelCatalogAfterApply?.(data.workflow, applyResolutions); @@ -2168,34 +2163,30 @@ export const queueMethods = { return true; }, - refreshAnalysisInBackground(workflow, expectedSignature = null) { + async 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.applyResolvedSelectionAliasesToAnalysisData(data); - this.cachedWorkflowSignature = signature || this.cachedWorkflowSignature; - this.cachedAnalysisData = data; - this.saveAnalysisCacheForActiveWorkflow?.(); + try { + const data = await this.fetchJson('/model_resolver/analyze', { + method: 'POST', + body: JSON.stringify({ workflow }), + silent: true + }, 'Background analysis'); - 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); - }); + if (signature && this.activeWorkflowSignature !== signature) return; + this.applyResolvedSelectionAliasesToAnalysisData(data); + 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 = []) { diff --git a/web/resolver/actions/resolve_download_methods.js b/web/resolver/actions/resolve_download_methods.js index 0309202..08f5ff1 100644 --- a/web/resolver/actions/resolve_download_methods.js +++ b/web/resolver/actions/resolve_download_methods.js @@ -41,20 +41,13 @@ export const resolveDownloadMethods = { original_lora_name: ref.name || ref.original_path })); - const response = await api.fetchApi('/model_resolver/resolve', { + const data = await this.fetchJson('/model_resolver/resolve', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ workflow, resolutions: resolutions }) - }); - - if (!response.ok) { - throw new Error(`API error: ${response.status}`); - } - - const data = await response.json(); + }, 'Resolve model'); log.debug('Resolve response: success=', data.success, ' missing count:', data.workflow?.nodes?.length); if (data.success) { @@ -95,17 +88,10 @@ export const resolveDownloadMethods = { } // Analyze workflow first - const analyzeResponse = await api.fetchApi('/model_resolver/analyze', { + const analyzeData = await this.fetchJson('/model_resolver/analyze', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ workflow }) - }); - - if (!analyzeResponse.ok) { - throw new Error(`API error: ${analyzeResponse.status}`); - } - - const analyzeData = await analyzeResponse.json(); + }, 'Analyze workflow'); const missingModels = analyzeData.missing_models || []; // Collect all 100% matches @@ -135,20 +121,13 @@ export const resolveDownloadMethods = { } // Apply resolutions - const resolveResponse = await api.fetchApi('/model_resolver/resolve', { + const resolveData = await this.fetchJson('/model_resolver/resolve', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ workflow, resolutions }) - }); - - if (!resolveResponse.ok) { - throw new Error(`API error: ${resolveResponse.status}`); - } - - const resolveData = await resolveResponse.json(); + }, 'Resolve models'); if (resolveData.success) { await this.refreshComfyModelCatalogAfterApply?.(resolveData.workflow, resolutions); @@ -195,17 +174,10 @@ export const resolveDownloadMethods = { } // Analyze workflow first - const analyzeResponse = await api.fetchApi('/model_resolver/analyze', { + const analyzeData = await this.fetchJson('/model_resolver/analyze', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ workflow }) - }); - - if (!analyzeResponse.ok) { - throw new Error(`API error: ${analyzeResponse.status}`); - } - - const analyzeData = await analyzeResponse.json(); + }, 'Analyze workflow'); const missingModels = analyzeData.missing_models || []; // Collect models that need downloading: @@ -1241,9 +1213,8 @@ export const resolveDownloadMethods = { } // Start download - const response = await api.fetchApi('/model_resolver/download', { + const data = await this.fetchJson('/model_resolver/download', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url, filename, @@ -1255,13 +1226,8 @@ export const resolveDownloadMethods = { hf_token: tokens.hf_token, civitai_key: tokens.civitai_key }) - }); + }, 'Start download'); - if (!response.ok) { - throw new Error(`Download failed: ${response.status}`); - } - - const data = await response.json(); if (!data.success) { throw new Error(data.error || 'Download failed'); } @@ -1398,12 +1364,7 @@ export const resolveDownloadMethods = { if (!info) return; try { - const response = await api.fetchApi(`/model_resolver/progress/${downloadId}`); - if (!response.ok) { - throw new Error('Failed to get progress'); - } - - const progress = await response.json(); + const progress = await this.fetchJson(`/model_resolver/progress/${downloadId}`, { silent: true }, 'Get download progress'); const snapshot = this.rememberDownloadUiState(downloadId, info, progress, { isActive: true }); const { progressDiv, downloadBtn } = this.resolveDownloadUiElements(info); const { missing, category } = info; @@ -1523,13 +1484,9 @@ export const resolveDownloadMethods = { */ async cancelDownload(downloadId) { try { - const response = await api.fetchApi(`/model_resolver/cancel/${downloadId}`, { + await this.fetchJson(`/model_resolver/cancel/${downloadId}`, { method: 'POST' - }); - - if (!response.ok) { - throw new Error('Failed to cancel download'); - } + }, 'Cancel download'); const info = this.activeDownloads[downloadId]; if (info) { @@ -1727,22 +1684,12 @@ export const resolveDownloadMethods = { log.debug('Model Resolver: Search request:', JSON.stringify(searchData)); - const requestOptions = { + const data = await this.fetchJson('/model_resolver/search', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(searchData) - }; - if (sourceController) { - requestOptions.signal = sourceController.signal; - } - - const response = await api.fetchApi('/model_resolver/search', requestOptions); - - if (!response.ok) { - throw new Error(`Search failed: ${response.status}`); - } - - const data = await response.json(); + body: JSON.stringify(searchData), + signal: sourceController?.signal, + silent: true + }, 'Search source'); log.debug('Model Resolver: Search response:', JSON.stringify(data)); if (!this.isBackgroundSearchRunActive(workflowKey, missingSearchKey, searchRunId)) { @@ -1948,17 +1895,12 @@ export const resolveDownloadMethods = { }; log.debug('resolveUrnAsync payload:', JSON.stringify(payload)); - const response = await api.fetchApi('/model_resolver/search', { + data = await this.fetchJson('/model_resolver/search', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload) - }); - - log.debug('resolveUrnAsync response status:', response.status); - if (!response.ok) { - throw new Error(`URN resolve failed: ${response.status}`); - } - data = await response.json(); + body: JSON.stringify(payload), + silent: true + }, 'Resolve URN'); + log.debug('resolveUrnAsync search completed'); } if (data) { @@ -2490,20 +2432,13 @@ export const resolveDownloadMethods = { }, async fetchLocalMatches(filename, category = '', forceRescan = false) { - const response = await api.fetchApi('/model_resolver/local-matches', { + return await this.fetchJson('/model_resolver/local-matches', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ filename, category: category || '', force_rescan: Boolean(forceRescan) }) - }); - - if (!response.ok) { - throw new Error(`Local match search failed: ${response.status}`); - } - - return await response.json(); + }, 'Fetch local matches'); } }; diff --git a/web/resolver/model_resolver.js b/web/resolver/model_resolver.js index 10886f7..9d86e25 100644 --- a/web/resolver/model_resolver.js +++ b/web/resolver/model_resolver.js @@ -659,18 +659,17 @@ export class ModelResolver { this.lastCheckedWorkflow = workflowHash; // Call analyze endpoint to check for missing models - const response = await api.fetchApi('/model_resolver/analyze', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ workflow }) - }); - - if (!response.ok) { + let data; + try { + data = await this.dialog.fetchJson('/model_resolver/analyze', { + method: 'POST', + body: JSON.stringify({ workflow }), + silent: true + }, 'Analyze workflow'); + } catch (error) { console.warn('Model Resolver: Failed to analyze workflow for missing models'); return; } - - const data = await response.json(); // Auto-open dialog if there are missing models if (data.total_missing > 0) { diff --git a/web/resolver/resolver_dialog.js b/web/resolver/resolver_dialog.js index 3eb419c..e003ffb 100644 --- a/web/resolver/resolver_dialog.js +++ b/web/resolver/resolver_dialog.js @@ -222,7 +222,14 @@ export class ResolverManagerDialog extends ComfyDialog { }; const response = await api.fetchApi(endpoint, fetchOptions); if (!response.ok) { - throw new Error(`Server returned ${response.status}: ${response.statusText}`); + let errorMsg = `Server returned ${response.status}: ${response.statusText}`; + try { + const errData = await response.json(); + if (errData && errData.error) { + errorMsg = errData.error; + } + } catch (_) {} + throw new Error(errorMsg); } if (response.status === 204) { return null; @@ -230,7 +237,7 @@ export class ResolverManagerDialog extends ComfyDialog { return await response.json(); } catch (error) { console.error(`Model Resolver: ${errorContext} failed:`, error); - if (typeof this.showNotification === 'function') { + if (!options.silent && typeof this.showNotification === 'function') { this.showNotification(error.message || 'API request failed', 'error'); } throw error; diff --git a/web/resolver/search/download_target_methods.js b/web/resolver/search/download_target_methods.js index 760f9b5..c49f136 100644 --- a/web/resolver/search/download_target_methods.js +++ b/web/resolver/search/download_target_methods.js @@ -11,9 +11,7 @@ export const downloadTargetMethods = { const force = options === true || Boolean(options?.force); if (!force && this.allModels && this.allModels.length) return; try { - const resp = await api.fetchApi(`/model_resolver/models${force ? '?force=1' : ''}`); - if (!resp.ok) throw new Error(`HTTP ${resp.status}`); - const models = await resp.json(); + const models = await this.fetchJson(`/model_resolver/models${force ? '?force=1' : ''}`, {}, 'Load all models'); const list = Array.isArray(models) ? models : []; // Build labels and sort alphabetically this.allModels = list.map((m) => ({ @@ -29,9 +27,7 @@ export const downloadTargetMethods = { async ensureDownloadDirectoriesLoaded() { if (this.downloadDirectories) return; try { - const resp = await api.fetchApi('/model_resolver/directories'); - if (!resp.ok) throw new Error(`HTTP ${resp.status}`); - const directories = await resp.json(); + const directories = await this.fetchJson('/model_resolver/directories', {}, 'Load download directories'); if (directories && typeof directories === 'object') { this.downloadDirectories = Object.entries(directories).reduce((acc, [key, value]) => { const normalizedKey = this.normalizeDownloadCategory(key); @@ -52,9 +48,7 @@ export const downloadTargetMethods = { async ensureCapabilitiesLoaded() { if (this.capabilities) return; try { - const resp = await api.fetchApi('/model_resolver/capabilities'); - if (!resp.ok) throw new Error(`HTTP ${resp.status}`); - const data = await resp.json(); + const data = await this.fetchJson('/model_resolver/capabilities', {}, 'Load capabilities'); this.capabilities = data && typeof data === 'object' ? data : { sources: {} }; } catch (e) { console.warn('Model Resolver: could not load capabilities', e); @@ -65,9 +59,7 @@ export const downloadTargetMethods = { async ensureDownloadRootDirectoriesLoaded() { if (this.downloadRootDirectories) return this.downloadRootDirectories; try { - const resp = await api.fetchApi('/model_resolver/root-directories'); - if (!resp.ok) throw new Error(`HTTP ${resp.status}`); - const data = await resp.json(); + const data = await this.fetchJson('/model_resolver/root-directories', {}, 'Load root directories'); this.downloadRootDirectories = data && typeof data === 'object' ? data : {}; } catch (e) { console.warn('Model Resolver: could not load root directories', e); @@ -79,9 +71,7 @@ export const downloadTargetMethods = { async ensureBaseModelsLoaded() { if (this.baseModels) return; try { - const resp = await api.fetchApi('/model_resolver/base-models'); - if (!resp.ok) throw new Error(`HTTP ${resp.status}`); - const data = await resp.json(); + const data = await this.fetchJson('/model_resolver/base-models', {}, 'Load base models config'); this.baseModels = data && typeof data === 'object' ? data : {}; } catch (e) { console.warn('Model Resolver: could not load base-models config', e); @@ -1500,9 +1490,7 @@ export const downloadTargetMethods = { } try { - const resp = await api.fetchApi(`/model_resolver/subfolders/${encodeURIComponent(key)}`); - if (!resp.ok) throw new Error(`HTTP ${resp.status}`); - const subfolders = await resp.json(); + const subfolders = await this.fetchJson(`/model_resolver/subfolders/${encodeURIComponent(key)}`, {}, 'Load subfolders'); const list = Array.isArray(subfolders) ? subfolders : []; this.downloadSubfolders.set(key, list); return list; @@ -2300,12 +2288,9 @@ export const downloadTargetMethods = { async clearBackendSearchCaches({ throwOnError = false } = {}) { try { - const response = await api.fetchApi('/model_resolver/clear-search-cache', { + await this.fetchJson('/model_resolver/clear-search-cache', { method: 'POST' - }); - if (!response.ok) { - throw new Error('Failed to clear backend search cache'); - } + }, 'Clear search cache'); return true; } catch (error) { console.error('Model Resolver: Clear search cache error:', error); diff --git a/web/resolver/search/search_panel.js b/web/resolver/search/search_panel.js index a742e76..6830ebb 100644 --- a/web/resolver/search/search_panel.js +++ b/web/resolver/search/search_panel.js @@ -992,9 +992,10 @@ export const searchPanelMethods = { timerRecord.inFlight = true; try { - const response = await api.fetchApi(`/model_resolver/search-progress/${encodeURIComponent(progressId)}`); - if (!response.ok) return; - const progress = await response.json(); + const progress = await this.fetchJson(`/model_resolver/search-progress/${encodeURIComponent(progressId)}`, { + silent: true + }, 'Poll search progress'); + if (!progress) return; if (!progress?.exists) return; const latestProgress = state.sourceProgress?.[source]; if (!latestProgress || (latestProgress.status !== 'pending' && latestProgress.status !== 'running')) { @@ -2096,17 +2097,10 @@ export const searchPanelMethods = { civitai_candidate_limit: tokens.civitai_candidate_limit }; - const response = await api.fetchApi('/model_resolver/search', { + const data = await this.fetchJson('/model_resolver/search', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) - }); - - if (!response.ok) { - throw new Error(`URN resolve failed: ${response.status}`); - } - - const data = await response.json(); + }, 'Resolve URN'); if (data.civitai) { this.applyCivitaiUrnResult(missing, data.civitai); } diff --git a/web/resolver/shell/lifecycle_graph_methods.js b/web/resolver/shell/lifecycle_graph_methods.js index fe12f1a..9685e76 100644 --- a/web/resolver/shell/lifecycle_graph_methods.js +++ b/web/resolver/shell/lifecycle_graph_methods.js @@ -198,21 +198,18 @@ export const lifecycleGraphMethods = { // Call analyze endpoint const progressPromise = this.pollAnalysisProgress(analysisId, analysisId); - const response = await api.fetchApi('/model_resolver/analyze', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ workflow, analysis_id: analysisId, force_rescan: Boolean(forceRescan) }) - }); - if (this._analysisProgressToken === analysisId) { - this._analysisProgressToken = null; + let data; + try { + data = await this.fetchJson('/model_resolver/analyze', { + method: 'POST', + body: JSON.stringify({ workflow, analysis_id: analysisId, force_rescan: Boolean(forceRescan) }) + }, 'Analyze workflow'); + } finally { + if (this._analysisProgressToken === analysisId) { + this._analysisProgressToken = null; + } + await progressPromise; } - await progressPromise; - - if (!response.ok) { - throw new Error(`API error: ${response.status}`); - } - - const data = await response.json(); if (this._workflowDataLoadToken === loadToken) { this.cachedWorkflowSignature = workflowSignature; this.cachedAnalysisData = data; diff --git a/web/resolver/shell/workflow_update_methods.js b/web/resolver/shell/workflow_update_methods.js index 03a0419..ea1a462 100644 --- a/web/resolver/shell/workflow_update_methods.js +++ b/web/resolver/shell/workflow_update_methods.js @@ -1,4 +1,4 @@ -import { app } from "../../../../../scripts/app.js"; +import { app } from "../../../../../scripts/app.js"; import { api } from "../../../../../scripts/api.js"; import { $el } from "../../../../../scripts/ui.js"; import { getSvgIcon } from "../../utils/icon_utils.js"; @@ -45,12 +45,7 @@ export const workflowUpdateMethods = { }, async fetchComfyNodeDefs() { - const response = await api.fetchApi(`/object_info?model_resolver_refresh=${Date.now()}`); - if (!response.ok) { - throw new Error(`object_info refresh failed: ${response.status}`); - } - - return await response.json(); + return await this.fetchJson(`/object_info?model_resolver_refresh=${Date.now()}`, {}, 'Fetch ComfyUI node definitions'); }, shouldRefreshComfyModelCatalogForApply(workflow = null, resolutions = []) { diff --git a/web/resolver/utils/render_format_methods.js b/web/resolver/utils/render_format_methods.js index b98d5e6..4b566fa 100644 --- a/web/resolver/utils/render_format_methods.js +++ b/web/resolver/utils/render_format_methods.js @@ -220,14 +220,15 @@ export const renderFormatMethods = { async pollAnalysisProgress(analysisId, token) { while (this._analysisProgressToken === token) { try { - const response = await api.fetchApi(`/model_resolver/analyze-progress/${analysisId}`); + const progress = await this.fetchJson(`/model_resolver/analyze-progress/${analysisId}`, { + silent: true + }, 'Poll analysis progress'); if ( - response.ok && + progress && this.contentElement && this._analysisProgressToken === token && this.activeTab === 'missing' ) { - const progress = await response.json(); this.contentElement.innerHTML = this.renderAnalysisProgress(progress); if (progress.status === 'completed' || progress.status === 'error') { if (this._analysisProgressToken === token) { diff --git a/web/resolver/views/model_info_methods.js b/web/resolver/views/model_info_methods.js index 424e978..2050026 100644 --- a/web/resolver/views/model_info_methods.js +++ b/web/resolver/views/model_info_methods.js @@ -831,25 +831,17 @@ export const modelInfoMethods = { || modelData?.folder_path || modelData?.download_directory || ''; - const response = await api.fetchApi('/model_resolver/civitai-search', { + const data = await this.fetchJson('/model_resolver/civitai-search', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ filename: loraName, category: modelData?.category || '', resolved_path: resolvedPath }) - }); - - if (response.ok) { - const data = await response.json(); - this.updateInfoDialogWithData(dialog, data); - } else { - this.updateInfoDialogError(dialog, 'Model not found on CivitAI'); - } + }, 'Fetch CivitAI model info'); + this.updateInfoDialogWithData(dialog, data); } catch (e) { - console.error('Model Resolver: Error fetching model info:', e); - this.updateInfoDialogError(dialog, 'Error fetching info'); + this.updateInfoDialogError(dialog, 'Error fetching info from CivitAI'); } }, @@ -1415,22 +1407,15 @@ export const modelInfoMethods = { try { const tokens = this.getStoredTokens?.() || {}; - const response = await api.fetchApi('/model_resolver/model-details', { + const data = await this.fetchJson('/model_resolver/model-details', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ source: model.details_source || model.source, model_id: model.model_id || model.modelId, version_id: model.version_id || model.versionId, civitai_key: tokens.civitai_key || '' }) - }); - - if (!response.ok) { - throw new Error(`Details request failed: ${response.status}`); - } - - const data = await response.json(); + }, 'Fetch model details'); details._detailsData = data; details._selectedVersionId = String(data.selected_version?.id || data.version_id || ''); details.innerHTML = this.renderSourceModelDetails(data, model); @@ -1486,22 +1471,15 @@ export const modelInfoMethods = { try { const data = details._detailsData; const tokens = this.getStoredTokens?.() || {}; - const response = await api.fetchApi('/model_resolver/model-details', { + const fresh = await this.fetchJson('/model_resolver/model-details', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ source: data.source || details._sourceModel?.details_source || details._sourceModel?.source, model_id: data.model_id || details._sourceModel?.model_id || details._sourceModel?.modelId, version_id: versionId, civitai_key: tokens.civitai_key || '' }) - }); - - if (!response.ok) { - throw new Error(`Version details request failed: ${response.status}`); - } - - const fresh = await response.json(); + }, 'Fetch model version details'); const freshVersion = fresh.selected_version; if (!freshVersion?.id) return; diff --git a/web/resolver/views/options_methods.js b/web/resolver/views/options_methods.js index 62b33b7..7f6c743 100644 --- a/web/resolver/views/options_methods.js +++ b/web/resolver/views/options_methods.js @@ -731,15 +731,10 @@ export const optionsMethods = { try { if (button) button.disabled = true; setTokenCheckStatus(statusEl, 'Checking...', 'is-pending'); - const response = await api.fetchApi(endpoint, { + const data = await this.fetchJson(endpoint, { method: 'POST', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ [payloadKey]: value }) - }); - const data = await response.json(); - if (!response.ok) { - throw new Error(data.error || `Check failed: ${response.status}`); - } + }, 'Check credential'); setTokenCheckStatus( statusEl, data.message || (data.valid ? 'Valid' : 'Invalid'), @@ -794,11 +789,7 @@ export const optionsMethods = { if (modelListStateEl) { modelListStateEl.textContent = checkRemote ? 'Checking GitHub...' : 'Loading...'; } - const response = await api.fetchApi(`/model_resolver/model-list/status${checkRemote ? '?check_remote=1' : ''}`); - if (!response.ok) { - throw new Error(`Status failed: ${response.status}`); - } - const data = await response.json(); + const data = await this.fetchJson(`/model_resolver/model-list/status${checkRemote ? '?check_remote=1' : ''}`, {}, 'Load model list status'); renderModelListStatus(data, checkRemote); return data; } catch (error) { @@ -816,13 +807,9 @@ export const optionsMethods = { setModelListBusy(true); if (modelListStateEl) modelListStateEl.textContent = 'Updating...'; if (modelListMessageEl) modelListMessageEl.textContent = 'Downloading latest ComfyUI-Manager model-list.json...'; - const response = await api.fetchApi('/model_resolver/model-list/update', { + const data = await this.fetchJson('/model_resolver/model-list/update', { method: 'POST' - }); - const data = await response.json(); - if (!response.ok) { - throw new Error(data.error || `Update failed: ${response.status}`); - } + }, 'Update model list'); await this.clearSearchCaches(); renderModelListStatus(data, false); if (modelListStateEl) modelListStateEl.textContent = 'Updated'; @@ -873,11 +860,7 @@ export const optionsMethods = { if (baseModelsStateEl) { baseModelsStateEl.textContent = checkRemote ? 'Checking CivitAI...' : 'Loading...'; } - const response = await api.fetchApi(`/model_resolver/base-models/status${checkRemote ? '?check_remote=1' : ''}`); - if (!response.ok) { - throw new Error(`Status failed: ${response.status}`); - } - const data = await response.json(); + const data = await this.fetchJson(`/model_resolver/base-models/status${checkRemote ? '?check_remote=1' : ''}`, {}, 'Load base models status'); renderBaseModelsStatus(data, checkRemote); return data; } catch (error) { @@ -907,13 +890,9 @@ export const optionsMethods = { setBaseModelsBusy(true); if (baseModelsStateEl) baseModelsStateEl.textContent = 'Updating...'; if (baseModelsMessageEl) baseModelsMessageEl.textContent = 'Downloading latest base models from CivitAI...'; - const response = await api.fetchApi('/model_resolver/base-models/update', { + const data = await this.fetchJson('/model_resolver/base-models/update', { method: 'POST' - }); - const data = await response.json(); - if (!response.ok) { - throw new Error(data.error || `Update failed: ${response.status}`); - } + }, 'Update base models'); await this.clearSearchCaches(); // Invalidate the in-memory cache so the base model dropdown // reloads fresh data from the server next time it is opened. @@ -978,11 +957,7 @@ export const optionsMethods = { try { setHfIndexBusy(true); if (hfIndexStateEl) hfIndexStateEl.textContent = 'Loading...'; - const response = await api.fetchApi('/model_resolver/huggingface/author-index/status'); - if (!response.ok) { - throw new Error(`Status failed: ${response.status}`); - } - const data = await response.json(); + const data = await this.fetchJson('/model_resolver/huggingface/author-index/status', {}, 'Load HuggingFace index status'); renderHfIndexStatus(data); return data; } catch (error) { @@ -1000,14 +975,12 @@ export const optionsMethods = { setHfIndexBusy(true); if (hfIndexStateEl) hfIndexStateEl.textContent = 'Refreshing...'; if (hfIndexMessageEl) hfIndexMessageEl.textContent = 'Downloading Comfy-Org file index from HuggingFace...'; - const response = await api.fetchApi('/model_resolver/huggingface/author-index/refresh', { + const data = await this.fetchJson('/model_resolver/huggingface/author-index/refresh', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ hf_token: hfInput?.value || '' }) - }); - const data = await response.json(); - if (!response.ok || data.success === false) { - throw new Error(data.error || `Refresh failed: ${response.status}`); + }, 'Refresh HuggingFace index'); + if (data?.success === false) { + throw new Error(data.error || 'Refresh failed'); } await this.clearSearchCaches(); renderHfIndexStatus(data); @@ -1328,9 +1301,7 @@ export const optionsMethods = { setTemplateDetectStatus('Scanning existing model folders...', 'is-pending'); try { - const resp = await api.fetchApi('/model_resolver/path-template-suggestions?force=1'); - if (!resp.ok) throw new Error(`HTTP ${resp.status}`); - const data = await resp.json(); + const data = await this.fetchJson('/model_resolver/path-template-suggestions?force=1', {}, 'Detect path templates'); const categories = data?.categories && typeof data.categories === 'object' ? data.categories : {}; @@ -1675,12 +1646,10 @@ export const optionsMethods = { // 2. Persist to server (survives new browsers / profiles) try { setStatus('Saving…', ''); - const resp = await api.fetchApi('/model_resolver/settings', { + await this.fetchJson('/model_resolver/settings', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(newSettings), - }); - if (!resp.ok) throw new Error(`HTTP ${resp.status}`); + body: JSON.stringify(newSettings) + }, 'Save settings'); setStatus('Saved on this machine (all browsers).', 'is-saved'); this.showNotification('Options saved', 'success'); } catch (err) { @@ -1750,13 +1719,7 @@ export const optionsMethods = { */ async loadSettingsFromServer() { try { - const resp = await api.fetchApi('/model_resolver/settings'); - if (!resp.ok) { - const tokens = this.getStoredTokens(); - this.applyFrontendLoggingPreference(tokens.frontend_logs_enabled, tokens.frontend_log_level); - return; - } - const data = await resp.json(); + const data = await this.fetchJson('/model_resolver/settings', { silent: true }, 'Load settings from server'); if (!data || typeof data !== 'object') { const tokens = this.getStoredTokens(); this.applyFrontendLoggingPreference(tokens.frontend_logs_enabled, tokens.frontend_log_level); diff --git a/web/resolver/views/tabs_loaded_methods.js b/web/resolver/views/tabs_loaded_methods.js index 372ace0..fade9f9 100644 --- a/web/resolver/views/tabs_loaded_methods.js +++ b/web/resolver/views/tabs_loaded_methods.js @@ -1,4 +1,4 @@ -import { app } from "../../../../../scripts/app.js"; +import { app } from "../../../../../scripts/app.js"; import { api } from "../../../../../scripts/api.js"; import { $el } from "../../../../../scripts/ui.js"; import { getSvgIcon } from "../../utils/icon_utils.js"; @@ -114,17 +114,10 @@ export const tabsLoadedMethods = { this.contentElement.innerHTML = '
Loading loaded models...
'; } - const response = await api.fetchApi('/model_resolver/loaded', { + const data = await this.fetchJson('/model_resolver/loaded', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ workflow }) - }); - - if (!response.ok) { - throw new Error(`API error: ${response.status}`); - } - - const data = await response.json(); + }, 'Fetch loaded models'); if (this._loadedModelsLoadToken === loadToken) { this.cachedLoadedModelsSignature = workflowSignature; this.cachedLoadedModelsData = data;