mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-09-20 18:51:26 -03:00
fix(move): recalculate sub_type when moving models across roots
Moving a checkpoint into a unet root (or vice versa) moved the file and updated the in-memory cache, but three stale spots survived until a manual cache rebuild: - The moved .metadata.json kept the old sub_type, and the opportunistic sync_cache_from_metadata path (fired by get_model_metadata and example image metadata updates) trusted it, reverting the cache entry and the SQLite snapshot to the pre-move sub_type. Loader nodes filter strictly on sub_type, so the model stayed listed under the old type. - The manager page discarded the move response's cache_entry, so the card badge (CKPT/DM) and context menu label kept showing the old type. Fixes: - move_model now re-resolves sub_type from the target location (new resolve_sub_type_for_path hook) and persists it into the moved .metadata.json. - _sync_cache_from_metadata_impl runs desired entries through adjust_cached_entry so location-derived fields cannot be re-poisoned by stale metadata snapshots. - MoveManager carries cache_entry.sub_type into the in-place card update so badge and context menu reflect the new type immediately.
This commit is contained in:
@@ -17,7 +17,8 @@ vi.mock('../../../static/js/state/index.js', () => ({
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getCurrentPageState: vi.fn(() => ({ activeFolder: null, searchOptions: {} }))
|
||||
}));
|
||||
|
||||
vi.mock('../../../static/js/managers/ModalManager.js', () => ({
|
||||
@@ -162,4 +163,75 @@ describe('MoveManager', () => {
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should propagate the recalculated sub_type from the move response to the card', async () => {
|
||||
// Setup state: moving a checkpoint into the unet root
|
||||
moveManager.useDefaultPath = false;
|
||||
moveManager.bulkFilePaths = null;
|
||||
moveManager.currentFilePath = '/models/checkpoints/model.safetensors';
|
||||
moveManager.modelRoots = ['/models/checkpoints', '/models/unet'];
|
||||
document.getElementById('moveModelRoot').innerHTML = '<option value="/models/unet">/models/unet</option>';
|
||||
document.getElementById('moveModelRoot').value = '/models/unet';
|
||||
moveManager.folderTreeManager.selectedPath = '';
|
||||
|
||||
const updateSingleItem = vi.fn();
|
||||
state.virtualScroller = {
|
||||
updateSingleItem,
|
||||
removeMultipleItemsByFilePath: vi.fn()
|
||||
};
|
||||
|
||||
mockApiClient.moveSingleModel = vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
original_file_path: '/models/checkpoints/model.safetensors',
|
||||
new_file_path: '/models/unet/model.safetensors',
|
||||
cache_entry: { sub_type: 'diffusion_model' }
|
||||
});
|
||||
|
||||
try {
|
||||
await moveManager.moveModel();
|
||||
|
||||
expect(updateSingleItem).toHaveBeenCalledWith(
|
||||
'/models/checkpoints/model.safetensors',
|
||||
expect.objectContaining({
|
||||
file_path: '/models/unet/model.safetensors',
|
||||
sub_type: 'diffusion_model'
|
||||
})
|
||||
);
|
||||
} finally {
|
||||
delete state.virtualScroller;
|
||||
}
|
||||
});
|
||||
|
||||
it('should omit sub_type from the card update when the response has no cache entry', async () => {
|
||||
moveManager.useDefaultPath = false;
|
||||
moveManager.bulkFilePaths = null;
|
||||
moveManager.currentFilePath = '/models/loras/a.safetensors';
|
||||
moveManager.modelRoots = ['/models/loras'];
|
||||
document.getElementById('moveModelRoot').innerHTML = '<option value="/models/loras">/models/loras</option>';
|
||||
document.getElementById('moveModelRoot').value = '/models/loras';
|
||||
moveManager.folderTreeManager.selectedPath = '';
|
||||
|
||||
const updateSingleItem = vi.fn();
|
||||
state.virtualScroller = {
|
||||
updateSingleItem,
|
||||
removeMultipleItemsByFilePath: vi.fn()
|
||||
};
|
||||
|
||||
mockApiClient.moveSingleModel = vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
original_file_path: '/models/loras/a.safetensors',
|
||||
new_file_path: '/models/loras/b/a.safetensors'
|
||||
});
|
||||
|
||||
try {
|
||||
await moveManager.moveModel();
|
||||
|
||||
expect(updateSingleItem).toHaveBeenCalledWith(
|
||||
'/models/loras/a.safetensors',
|
||||
expect.not.objectContaining({ sub_type: expect.anything() })
|
||||
);
|
||||
} finally {
|
||||
delete state.virtualScroller;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user