diff --git a/static/js/managers/MoveManager.js b/static/js/managers/MoveManager.js
index 4ffad779..4a7cc856 100644
--- a/static/js/managers/MoveManager.js
+++ b/static/js/managers/MoveManager.js
@@ -88,6 +88,11 @@ class MoveManager {
folderPathInput.value = '';
}
+ // Reset folder tree selection
+ if (this.folderTreeManager) {
+ this.folderTreeManager.clearSelection();
+ }
+
try {
// Fetch model roots
const modelRootSelect = document.getElementById('moveModelRoot');
@@ -308,7 +313,7 @@ class MoveManager {
}
// Get selected folder path from folder tree manager
- const targetFolder = this.folderTreeManager.getSelectedPath();
+ const targetFolder = this.useDefaultPath ? '' : this.folderTreeManager.getSelectedPath();
let targetPath = selectedRoot;
if (targetFolder) {
diff --git a/tests/frontend/managers/MoveManager.test.js b/tests/frontend/managers/MoveManager.test.js
new file mode 100644
index 00000000..ab829493
--- /dev/null
+++ b/tests/frontend/managers/MoveManager.test.js
@@ -0,0 +1,159 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+import { moveManager } from '../../../static/js/managers/MoveManager.js';
+import { state } from '../../../static/js/state/index.js';
+import { modalManager } from '../../../static/js/managers/ModalManager.js';
+import { getModelApiClient } from '../../../static/js/api/modelApiFactory.js';
+import * as storageHelpers from '../../../static/js/utils/storageHelpers.js';
+
+// Mock dependencies
+vi.mock('../../../static/js/state/index.js', () => ({
+ state: {
+ currentPageType: 'loras',
+ selectedModels: new Set(),
+ global: {
+ settings: {
+ download_path_templates: {
+ lora: '{base_model}/unstaged'
+ }
+ }
+ }
+ }
+}));
+
+vi.mock('../../../static/js/managers/ModalManager.js', () => ({
+ modalManager: {
+ showModal: vi.fn(),
+ closeModal: vi.fn()
+ }
+}));
+
+vi.mock('../../../static/js/api/modelApiFactory.js', () => ({
+ getModelApiClient: vi.fn()
+}));
+
+vi.mock('../../../static/js/utils/storageHelpers.js', () => ({
+ getStorageItem: vi.fn(),
+ setStorageItem: vi.fn()
+}));
+
+vi.mock('../../../static/js/utils/uiHelpers.js', () => ({
+ showToast: vi.fn()
+}));
+
+vi.mock('../../../static/js/utils/i18nHelpers.js', () => ({
+ translate: vi.fn(key => key)
+}));
+
+describe('MoveManager', () => {
+ let mockApiClient;
+
+ beforeEach(() => {
+ vi.clearAllMocks();
+
+ // Setup DOM
+ document.body.innerHTML = `
+
+ `;
+
+ mockApiClient = {
+ apiConfig: {
+ config: {
+ displayName: 'LoRA',
+ supportsMove: true
+ },
+ endpoints: {
+ moveModel: '/api/move'
+ }
+ },
+ modelType: 'loras',
+ fetchModelRoots: vi.fn().mockResolvedValue({ roots: ['/models/loras'] }),
+ fetchUnifiedFolderTree: vi.fn().mockResolvedValue({ success: true, tree: {} }),
+ moveSingleModel: vi.fn().mockResolvedValue({ success: true })
+ };
+ getModelApiClient.mockReturnValue(mockApiClient);
+ });
+
+ it('should reset folder selection when showing move modal', async () => {
+ // Manually set a selected path in folderTreeManager
+ moveManager.folderTreeManager.selectedPath = 'previous/path';
+
+ await moveManager.showMoveModal('some/file.safetensors');
+
+ expect(moveManager.folderTreeManager.getSelectedPath()).toBe('');
+ });
+
+ it('should ignore manual folder selection when useDefaultPath is true', async () => {
+ // Setup state
+ moveManager.useDefaultPath = true;
+ moveManager.currentFilePath = '/models/loras/flux/my-lora.safetensors';
+ document.getElementById('moveModelRoot').innerHTML = '';
+ document.getElementById('moveModelRoot').value = '/models/loras';
+
+ // Manually set a selected path despite useDefaultPath being true
+ moveManager.folderTreeManager.selectedPath = 'wrong/folder';
+
+ await moveManager.moveModel();
+
+ // Should call moveSingleModel with the root path, NOT including the 'wrong/folder'
+ expect(mockApiClient.moveSingleModel).toHaveBeenCalledWith(
+ '/models/loras/flux/my-lora.safetensors',
+ '/models/loras',
+ true
+ );
+ });
+
+ it('should include manual folder selection when useDefaultPath is false', async () => {
+ // Setup state
+ moveManager.useDefaultPath = false;
+ moveManager.currentFilePath = '/models/loras/flux/my-lora.safetensors';
+ document.getElementById('moveModelRoot').innerHTML = '';
+ document.getElementById('moveModelRoot').value = '/models/loras';
+
+ // Set a selected path
+ moveManager.folderTreeManager.selectedPath = 'my/organized/folder';
+
+ await moveManager.moveModel();
+
+ // Should call moveSingleModel with root + selected folder
+ expect(mockApiClient.moveSingleModel).toHaveBeenCalledWith(
+ '/models/loras/flux/my-lora.safetensors',
+ '/models/loras/my/organized/folder',
+ false
+ );
+ });
+
+ it('should handle bulk move and ignore manual folder selection when useDefaultPath is true', async () => {
+ // Setup state
+ moveManager.useDefaultPath = true;
+ moveManager.bulkFilePaths = [
+ '/models/loras/flux/lora1.safetensors',
+ '/models/loras/flux/lora2.safetensors'
+ ];
+ document.getElementById('moveModelRoot').innerHTML = '';
+ document.getElementById('moveModelRoot').value = '/models/loras';
+
+ // Manually set a selected path
+ moveManager.folderTreeManager.selectedPath = 'wrong/folder';
+
+ mockApiClient.moveBulkModels = vi.fn().mockResolvedValue({ success: true });
+
+ await moveManager.moveModel();
+
+ // Should call moveBulkModels with the root path, NOT including the 'wrong/folder'
+ expect(mockApiClient.moveBulkModels).toHaveBeenCalledWith(
+ moveManager.bulkFilePaths,
+ '/models/loras',
+ true
+ );
+ });
+});