From 57568f1d0fb2459348f960fa4ebe3c90040360af Mon Sep 17 00:00:00 2001 From: Dariusz L Date: Thu, 6 Aug 2026 23:13:10 +0200 Subject: [PATCH] refactor: unify local model context menus --- tests/test_downloads_tab_workflow_route.mjs | 54 ++++++++++++++++++++ web/resolver/views/options_methods.js | 56 ++++++++++----------- 2 files changed, 80 insertions(+), 30 deletions(-) diff --git a/tests/test_downloads_tab_workflow_route.mjs b/tests/test_downloads_tab_workflow_route.mjs index bad3fec..bc13326 100644 --- a/tests/test_downloads_tab_workflow_route.mjs +++ b/tests/test_downloads_tab_workflow_route.mjs @@ -2965,6 +2965,60 @@ test('download result context menu offers subfolder suggestions only for CivitAI assert.match(resolverDialogSource, /textContent: "Suggest Subfolder"/); }); +test('metadata audit context menus preserve the local model context contract', () => { + const item = { + filename: 'model.safetensors', + relative_path: 'checkpoints/model.safetensors', + model_path: 'C:/models/checkpoints/model.safetensors', + base_directory: 'C:/models', + category: 'checkpoints', + metadata_path: 'C:/models/checkpoints/model.safetensors.modelresolver.json', + actual_size: 2048, + metadata_size: 512, + size: 2048, + sha256: 'a'.repeat(64), + }; + const buildLocalModelContext = eval( + `(${extractMethod(optionsMethodsSource, 'buildLocalModelContext')})` + ); + const auditContext = buildLocalModelContext.call(item, item, 'metadata_size_audit', { + size: item.actual_size, + file_size: item.actual_size, + metadata_size: item.metadata_size, + }); + const buildContext = buildLocalModelContext.call(item, item, 'metadata_builder', { + size: item.size, + file_size: item.size, + sha256: item.sha256, + }); + assert.equal(buildLocalModelContext({ filename: 'missing.safetensors' }, 'metadata_builder'), null); + + const sharedFields = [ + 'context_scope', + 'open_folder_label', + 'name', + 'filename', + 'relative_path', + 'path', + 'resolved_path', + 'open_path', + 'folder_path', + 'category', + 'metadata_path', + ]; + for (const field of sharedFields) { + assert.equal(auditContext[field], buildContext[field], field); + } + assert.equal(auditContext.context_source, 'metadata_size_audit'); + assert.equal(buildContext.context_source, 'metadata_builder'); + assert.equal(auditContext.size, item.actual_size); + assert.equal(auditContext.file_size, item.actual_size); + assert.equal(auditContext.metadata_size, item.metadata_size); + assert.equal(buildContext.size, item.size); + assert.equal(buildContext.file_size, item.size); + assert.equal(buildContext.sha256, item.sha256); +}); + test('download result context menu reuses the existing forced subfolder suggestion', async () => { const getContextMenuDownloadMissing = eval(`(${extractMethod(downloadTargetMethodsSource, 'getContextMenuDownloadMissing')})`); const suggestDownloadSubfolderFromContextMenu = eval(`(${extractMethod(downloadTargetMethodsSource, 'suggestDownloadSubfolderFromContextMenu')})`); diff --git a/web/resolver/views/options_methods.js b/web/resolver/views/options_methods.js index b5ba785..35165c9 100644 --- a/web/resolver/views/options_methods.js +++ b/web/resolver/views/options_methods.js @@ -7,6 +7,26 @@ export const optionsMethods = { escapeHtml(value) { return escapeHtml(value); }, + buildLocalModelContext(item = {}, contextSource = '', extraFields = {}) { + const modelLabel = item.relative_path || item.filename || item.model_path || 'Model'; + const modelPath = item.model_path || ''; + if (!modelPath) return null; + return { + context_scope: 'local_model', + open_folder_label: 'Show File in Folder', + name: item.filename || modelLabel, + filename: item.filename || modelLabel, + relative_path: item.relative_path || modelLabel, + path: modelPath, + resolved_path: modelPath, + open_path: modelPath, + folder_path: item.base_directory || '', + category: item.category || '', + metadata_path: item.metadata_path || '', + ...extraFields, + context_source: contextSource + }; + }, displayOptions() { if (!this.contentElement) return; this.contentElement.style.overflowY = 'hidden'; @@ -1279,23 +1299,11 @@ export const optionsMethods = { const differenceClass = difference > 0 ? 'is-positive' : (difference < 0 ? 'is-negative' : ''); const differenceLabel = item.difference_label || `${difference >= 0 ? '+' : '-'}${this.formatBytes(Math.abs(difference))}`; const sizeField = item.size_field || 'size'; - const auditContext = modelPath ? { - context_scope: 'local_model', - open_folder_label: 'Show File in Folder', - name: item.filename || modelLabel, - filename: item.filename || modelLabel, - relative_path: item.relative_path || modelLabel, - path: modelPath, - resolved_path: modelPath, - open_path: modelPath, - folder_path: item.base_directory || '', - category: item.category || '', - metadata_path: metadataPath, + const auditContext = this.buildLocalModelContext(item, 'metadata_size_audit', { size: item.actual_size || 0, file_size: item.actual_size || 0, - metadata_size: item.metadata_size || 0, - context_source: 'metadata_size_audit' - } : null; + metadata_size: item.metadata_size || 0 + }); const contextAttrs = auditContext ? this.getContextMenuAttrs(auditContext, 'Right-click for model options') : ''; @@ -1891,23 +1899,11 @@ export const optionsMethods = { const actionClass = actionValue.replace(/[^a-z0-9_-]+/g, '-'); const message = item.message || changedFieldsSummary; const rowMatchesFilter = metadataBuildHistoryActionMatchesFilter(actionValue, activeHistoryFilter); - const buildContext = modelPath ? { - context_scope: 'local_model', - open_folder_label: 'Show File in Folder', - name: item.filename || modelLabel, - filename: item.filename || modelLabel, - relative_path: item.relative_path || modelLabel, - path: modelPath, - resolved_path: modelPath, - open_path: modelPath, - folder_path: item.base_directory || '', - category: item.category || '', - metadata_path: metadataPath, + const buildContext = this.buildLocalModelContext(item, 'metadata_builder', { size: item.size || 0, file_size: item.size || 0, - sha256: item.sha256 || '', - context_source: 'metadata_builder' - } : null; + sha256: item.sha256 || '' + }); const contextAttrs = buildContext ? this.getContextMenuAttrs(buildContext, 'Right-click for model options') : '';