export const queueStorageMethods = { persistQueueCollapsedState(collapsed, delayMs = 250) { if (this._queueCollapsedPersistTimer) { clearTimeout(this._queueCollapsedPersistTimer); this._queueCollapsedPersistTimer = null; } const writeState = () => { this._queueCollapsedPersistTimer = null; try { localStorage.setItem('model_resolver_queue_collapsed', collapsed ? '1' : '0'); } catch (_e) { } }; const delay = Math.max(0, Number(delayMs) || 0); if (delay > 0) { this._queueCollapsedPersistTimer = setTimeout(writeState, delay); } else { writeState(); } }, persistQueueSplitWidth(width, delayMs = 250) { const nextWidth = Math.round(Number(width)); if (!Number.isFinite(nextWidth) || nextWidth <= 0) return; if (this._queueSplitPersistTimer) { clearTimeout(this._queueSplitPersistTimer); this._queueSplitPersistTimer = null; } const writeWidth = () => { this._queueSplitPersistTimer = null; try { localStorage.setItem('model_resolver_split_w', String(nextWidth)); } catch (_e) { } }; const delay = Math.max(0, Number(delayMs) || 0); if (delay > 0) { this._queueSplitPersistTimer = setTimeout(writeWidth, delay); } else { writeWidth(); } }, loadDownloadHistory() { if (this._downloadHistoryLoaded) return this.downloadHistory || []; this._downloadHistoryLoaded = true; try { const raw = localStorage.getItem(this.downloadHistoryStorageKey || 'model_resolver_download_history'); const parsed = raw ? JSON.parse(raw) : []; this.downloadHistory = Array.isArray(parsed) ? parsed.filter(item => item && typeof item === 'object') : []; } catch (error) { console.warn('Model Resolver: failed to load download history', error); this.downloadHistory = []; } return this.downloadHistory; }, getDownloadHistory() { if (!this._downloadHistoryLoaded) { this.loadDownloadHistory(); } return Array.isArray(this.downloadHistory) ? this.downloadHistory : []; }, saveDownloadHistory() { const history = this.getDownloadHistory().slice(0, this.downloadHistoryLimit || 200); this.downloadHistory = history; try { localStorage.setItem( this.downloadHistoryStorageKey || 'model_resolver_download_history', JSON.stringify(history) ); } catch (error) { console.warn('Model Resolver: failed to save download history', error); } }, getDownloadHistoryIdentity(entry = {}) { return [ entry.path || '', entry.filename || '', entry.category || '', entry.sourceUrl || '' ].map(value => String(value || '').trim().toLowerCase()).join('::'); }, addDownloadHistoryEntry(entry = {}) { if (!entry || !entry.filename) return null; const history = this.getDownloadHistory(); const identity = this.getDownloadHistoryIdentity(entry); const filtered = identity ? history.filter(item => this.getDownloadHistoryIdentity(item) !== identity) : history; const nextEntry = { ...entry, id: entry.id || `${Date.now()}-${Math.random().toString(36).slice(2)}`, completedAt: entry.completedAt || new Date().toISOString() }; this.downloadHistory = [nextEntry, ...filtered].slice(0, this.downloadHistoryLimit || 200); this.saveDownloadHistory(); this.updateQueuePanel?.(); return nextEntry; }, rememberCompletedDownloadHistory(downloadId, info = {}, progress = {}) { const missing = info?.missing || {}; const filename = progress.filename || info.filename || missing.download_source?.filename || missing.original_path?.split(/[/\\]/).pop() || ''; if (!filename) return null; const directory = progress.directory || info.downloadDirectory || ''; const path = progress.path || info.downloadPath || ''; const category = info.category || missing.category || progress.category || ''; const workflowLabel = this.getDownloadWorkflowLabel?.(info) || info.workflowLabel || ''; const nodeLabel = missing.subgraph_name || missing.node_type || (missing.subgraph_id ? 'Subgraph' : 'Node'); const status = progress.already_exists ? 'already_exists' : 'completed'; return this.addDownloadHistoryEntry({ downloadId, filename, category, categoryLabel: this.getCategoryDisplayName?.(category) || category, nodeLabel, nodeId: missing.node_id ?? '', widgetIndex: missing.widget_index ?? '', workflowLabel, workflowId: info.workflowId || info.workflow_id || this.getWorkflowContextId?.(info) || '', workflowKey: info.workflowKey || '', workflowRouteKey: info.workflowRouteKey || '', workflowSignature: info.workflowSignature || '', workflowTabId: info.workflowTabId || '', workflowTabName: info.workflowTabName || '', workflowTabAriaControls: info.workflowTabAriaControls || '', workflowTabText: info.workflowTabText || '', path, directory, sourceUrl: info.sourceUrl || missing.download_source?.url || '', totalSize: progress.total_size || progress.size || 0, status, statusLabel: status === 'already_exists' ? 'Already downloaded' : 'Downloaded', message: progress.message || '', completedAt: new Date().toISOString() }); }, formatDownloadHistoryTime(value = '') { if (!value) return ''; try { const date = new Date(value); if (Number.isNaN(date.getTime())) return ''; return date.toLocaleString(undefined, { month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }); } catch (_error) { return ''; } }, getDownloadHistoryFolderContext(entry = {}) { const filePath = entry.path || ''; const directory = entry.directory || ''; const targetPath = filePath || directory; const context = { context_scope: 'download_history', open_folder_label: targetPath ? 'Open Download Folder' : '', name: entry.filename || 'Download', path: targetPath, resolved_path: targetPath, open_path: filePath || directory, folder_path: directory || targetPath, download_directory: directory, download_path: filePath, category: entry.category || '', workflow_id: entry.workflowId || entry.workflow_id || (this.isLikelyWorkflowId?.(entry.workflowLabel) ? entry.workflowLabel : ''), workflow_label: entry.workflowLabel || '', workflow_key: entry.workflowKey || '', workflow_route_key: entry.workflowRouteKey || '', workflow_signature: entry.workflowSignature || '', workflow_tab_id: entry.workflowTabId || '', workflow_tab_name: entry.workflowTabName || '', workflow_tab_aria_controls: entry.workflowTabAriaControls || '', workflow_tab_text: entry.workflowTabText || '', node_id: entry.nodeId ?? '', widget_index: entry.widgetIndex ?? '' }; return (targetPath || this.canSwitchToDownloadWorkflow?.(context)) ? context : null; }, clearDownloadHistory() { this.downloadHistory = []; this.saveDownloadHistory(); this.updateQueuePanel(); }, removeDownloadHistoryEntry(historyId = '', fallbackIndex = -1) { const history = this.getDownloadHistory(); if (!history.length) return; const normalizedId = String(historyId || ''); let nextHistory = history; if (normalizedId) { nextHistory = history.filter(entry => String(entry?.id || '') !== normalizedId); } if (nextHistory.length === history.length && Number.isInteger(fallbackIndex) && fallbackIndex >= 0 && fallbackIndex < history.length) { nextHistory = history.filter((_, index) => index !== fallbackIndex); } if (nextHistory.length === history.length) return; this.downloadHistory = nextHistory; this.saveDownloadHistory(); this.updateQueuePanel(); }, };