From ddb1c69fc99e40aa63ff73bf9b3b183286f15ab7 Mon Sep 17 00:00:00 2001 From: naman-bruno Date: Thu, 12 Mar 2026 18:40:52 +0530 Subject: [PATCH] Revert "workspace renaming with path update (#7437)" (#7455) This reverts commit e7c2c7c8722169407d98b8152ed55b3d13f85376. --- .../ReduxStore/slices/workspaces/actions.js | 33 ++--- packages/bruno-electron/src/ipc/workspace.js | 19 +-- .../src/utils/workspace-config.js | 43 +----- .../tests/utils/workspace-config.spec.js | 135 +----------------- 4 files changed, 14 insertions(+), 216 deletions(-) diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js index 15dd0adf7..5761d605d 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js @@ -524,38 +524,21 @@ const handleWorkspaceAction = async (action, workspaceUid, ...args) => { export const renameWorkspaceAction = (workspaceUid, newName) => { return async (dispatch, getState) => { try { - const { workspaces, activeWorkspaceUid } = getState().workspaces; + const { workspaces } = getState().workspaces; const workspace = workspaces.find((w) => w.uid === workspaceUid); if (!workspace) { throw new Error('Workspace not found'); } - const result = await ipcRenderer.invoke('renderer:rename-workspace', workspace.pathname, newName); + await handleWorkspaceAction((...args) => ipcRenderer.invoke('renderer:rename-workspace', ...args), + workspace.pathname, + newName); - if (result.newWorkspacePath) { - const { generateUidBasedOnHash } = await import('utils/common'); - const newWorkspaceUid = generateUidBasedOnHash(result.newWorkspacePath); - const wasActive = activeWorkspaceUid === workspaceUid; - - dispatch(removeWorkspace(workspaceUid)); - - dispatch(createWorkspace({ - ...workspace, - uid: newWorkspaceUid, - name: newName, - pathname: result.newWorkspacePath - })); - - if (wasActive) { - dispatch(setActiveWorkspace(newWorkspaceUid)); - } - } else { - dispatch(updateWorkspace({ - uid: workspaceUid, - name: newName - })); - } + dispatch(updateWorkspace({ + uid: workspaceUid, + name: newName + })); } catch (error) { throw error; } diff --git a/packages/bruno-electron/src/ipc/workspace.js b/packages/bruno-electron/src/ipc/workspace.js index 130c1234d..a896a2a09 100644 --- a/packages/bruno-electron/src/ipc/workspace.js +++ b/packages/bruno-electron/src/ipc/workspace.js @@ -16,6 +16,7 @@ const { readWorkspaceConfig, writeWorkspaceConfig, validateWorkspaceConfig, + updateWorkspaceName, updateWorkspaceDocs, addCollectionToWorkspace, removeCollectionFromWorkspace, @@ -24,8 +25,7 @@ const { normalizeCollectionEntry, validateWorkspacePath, validateWorkspaceDirectory, - getWorkspaceUid, - renameWorkspace + getWorkspaceUid } = require('../utils/workspace-config'); const { isValidCollectionDirectory } = require('../utils/filesystem'); @@ -270,20 +270,7 @@ const registerWorkspaceIpc = (mainWindow, workspaceWatcher) => { ipcMain.handle('renderer:rename-workspace', async (event, workspacePath, newName) => { try { - const result = await renameWorkspace(workspacePath, newName); - - if (result.newWorkspacePath) { - if (workspaceWatcher) { - workspaceWatcher.removeWatcher(workspacePath); - workspaceWatcher.addWatcher(mainWindow, result.newWorkspacePath); - } - - lastOpenedWorkspaces.remove(workspacePath); - lastOpenedWorkspaces.add(result.newWorkspacePath); - - return { success: true, newWorkspacePath: result.newWorkspacePath }; - } - + await updateWorkspaceName(workspacePath, newName); return { success: true }; } catch (error) { throw error; diff --git a/packages/bruno-electron/src/utils/workspace-config.js b/packages/bruno-electron/src/utils/workspace-config.js index 165cab409..7e0c6d900 100644 --- a/packages/bruno-electron/src/utils/workspace-config.js +++ b/packages/bruno-electron/src/utils/workspace-config.js @@ -1,7 +1,7 @@ const fs = require('fs'); const path = require('path'); const yaml = require('js-yaml'); -const { writeFile, validateName, isValidCollectionDirectory, sanitizeName } = require('./filesystem'); +const { writeFile, validateName, isValidCollectionDirectory } = require('./filesystem'); const { generateUidBasedOnHash } = require('./common'); const { withLock, getWorkspaceLockKey } = require('./workspace-lock'); @@ -563,44 +563,6 @@ const getWorkspaceUid = (workspacePath) => { return generateUidBasedOnHash(workspacePath); }; -/** - * Renames a workspace folder and updates the workspace.yml config. - * @param {string} workspacePath - Current absolute path to the workspace folder - * @param {string} newName - New name for the workspace - * @returns {Promise<{newWorkspacePath: string|null}>} - New path if folder was renamed, null otherwise - */ -const renameWorkspace = async (workspacePath, newName) => { - const parentDir = path.dirname(workspacePath); - const newFolderName = sanitizeName(newName); - const newWorkspacePath = path.join(parentDir, newFolderName); - - const pathsAreSame = path.normalize(workspacePath).toLowerCase() === path.normalize(newWorkspacePath).toLowerCase(); - - if (!pathsAreSame) { - if (fs.existsSync(newWorkspacePath)) { - throw new Error(`A folder named "${newFolderName}" already exists at this location`); - } - - fs.renameSync(workspacePath, newWorkspacePath); - - try { - await updateWorkspaceName(newWorkspacePath, newName); - } catch (error) { - try { - fs.renameSync(newWorkspacePath, workspacePath); - } catch (rollbackError) { - console.error('Failed to rollback workspace folder rename:', rollbackError); - } - throw error; - } - - return { newWorkspacePath }; - } - - await updateWorkspaceName(workspacePath, newName); - return { newWorkspacePath: null }; -}; - module.exports = { makeRelativePath, normalizeCollectionEntry, @@ -623,6 +585,5 @@ module.exports = { getWorkspaceUid, writeWorkspaceFileAtomic, isValidCollectionEntry, - isValidSpecEntry, - renameWorkspace + isValidSpecEntry }; diff --git a/packages/bruno-electron/tests/utils/workspace-config.spec.js b/packages/bruno-electron/tests/utils/workspace-config.spec.js index 55851070c..e70637214 100644 --- a/packages/bruno-electron/tests/utils/workspace-config.spec.js +++ b/packages/bruno-electron/tests/utils/workspace-config.spec.js @@ -2,7 +2,7 @@ const path = require('path'); const fs = require('fs'); const os = require('os'); const yaml = require('js-yaml'); -const { reorderWorkspaceCollections, renameWorkspace } = require('../../src/utils/workspace-config'); +const { reorderWorkspaceCollections } = require('../../src/utils/workspace-config'); const collection = (name, pathSegment) => ({ name, path: pathSegment }); @@ -74,136 +74,3 @@ describe('reorderWorkspaceCollections', () => { expect(getCollectionPathsFromYml()).toEqual(['collections/api', 'collections/backend']); }); }); - -describe('renameWorkspace', () => { - let parentDir; - let workspacePath; - - /** Creates a workspace directory with workspace.yml */ - const createWorkspace = (folderName, workspaceName) => { - const wsPath = path.join(parentDir, folderName); - fs.mkdirSync(wsPath, { recursive: true }); - const content = [ - 'opencollection: 1.0.0', - 'info:', - ` name: "${workspaceName}"`, - ' type: workspace', - 'collections:', - 'specs:', - 'docs: \'\'' - ].join('\n'); - fs.writeFileSync(path.join(wsPath, 'workspace.yml'), content); - return wsPath; - }; - - /** Gets the workspace name from workspace.yml */ - const getWorkspaceName = (wsPath) => { - const raw = fs.readFileSync(path.join(wsPath, 'workspace.yml'), 'utf8'); - const config = yaml.load(raw); - return config.info?.name; - }; - - beforeEach(() => { - parentDir = fs.mkdtempSync(path.join(os.tmpdir(), 'bruno-ws-parent-')); - workspacePath = createWorkspace('Untitled Workspace', 'Untitled Workspace'); - }); - - afterEach(() => { - fs.rmSync(parentDir, { recursive: true, force: true }); - }); - - test('renames workspace folder and updates config', async () => { - const result = await renameWorkspace(workspacePath, 'My API Project'); - - expect(result.newWorkspacePath).toBe(path.join(parentDir, 'My API Project')); - expect(fs.existsSync(path.join(parentDir, 'Untitled Workspace'))).toBe(false); - expect(fs.existsSync(path.join(parentDir, 'My API Project'))).toBe(true); - expect(getWorkspaceName(result.newWorkspacePath)).toBe('My API Project'); - }); - - test('only updates config when folder name stays the same', async () => { - // Create workspace where folder name matches sanitized target but display name differs - const sameFolderPath = createWorkspace('My-Project', 'Old Name'); - - // Rename to name that sanitizes to same folder name - const result = await renameWorkspace(sameFolderPath, 'My:Project'); - - expect(result.newWorkspacePath).toBeNull(); - expect(fs.existsSync(sameFolderPath)).toBe(true); - // Verify config was actually updated - expect(getWorkspaceName(sameFolderPath)).toBe('My:Project'); - }); - - test('sanitizes special characters in folder name', async () => { - const result = await renameWorkspace(workspacePath, 'My:API/Project'); - - expect(result.newWorkspacePath).toBe(path.join(parentDir, 'My-API-Project-Test-')); - expect(fs.existsSync(result.newWorkspacePath)).toBe(true); - expect(getWorkspaceName(result.newWorkspacePath)).toBe('My:API/Project'); - }); - - test('throws error when target folder already exists', async () => { - // Create another workspace with the target name - createWorkspace('Existing Project', 'Existing Project'); - - await expect(renameWorkspace(workspacePath, 'Existing Project')) - .rejects.toThrow('A folder named "Existing Project" already exists at this location'); - - // Original workspace should still exist - expect(fs.existsSync(workspacePath)).toBe(true); - }); - - test('handles case-only rename by updating config without renaming folder', async () => { - // Create workspace with lowercase name - const lowerPath = createWorkspace('myworkspace', 'myworkspace'); - - // Rename to different case - code uses case-insensitive comparison - // so this only updates config, doesn't rename folder (cross-platform safety) - const result = await renameWorkspace(lowerPath, 'MyWorkspace'); - - expect(result.newWorkspacePath).toBeNull(); - expect(fs.existsSync(lowerPath)).toBe(true); - expect(getWorkspaceName(lowerPath)).toBe('MyWorkspace'); - }); - - test('preserves workspace.yml content after rename', async () => { - // Add collections, specs, and other fields to the workspace - const configPath = path.join(workspacePath, 'workspace.yml'); - const content = [ - 'opencollection: 1.0.0', - 'info:', - ' name: "Untitled Workspace"', - ' type: workspace', - 'collections:', - ' - name: "API"', - ' path: "collections/api"', - ' remote: "https://github.com/example/api"', - 'specs:', - ' - name: "OpenAPI"', - ' path: "specs/openapi.yaml"', - 'docs: \'Some documentation\'', - '', - 'activeEnvironmentUid: env_123' - ].join('\n'); - fs.writeFileSync(configPath, content); - - const result = await renameWorkspace(workspacePath, 'My Project'); - - const newConfigPath = path.join(result.newWorkspacePath, 'workspace.yml'); - const newContent = fs.readFileSync(newConfigPath, 'utf8'); - const config = yaml.load(newContent); - - // Verify all fields are preserved - expect(config.opencollection).toBe('1.0.0'); - expect(config.info.name).toBe('My Project'); - expect(config.info.type).toBe('workspace'); - expect(config.collections).toHaveLength(1); - expect(config.collections[0].name).toBe('API'); - expect(config.collections[0].path).toBe('collections/api'); - expect(config.collections[0].remote).toBe('https://github.com/example/api'); - expect(config.specs).toHaveLength(1); - expect(config.specs[0]).toEqual({ name: 'OpenAPI', path: 'specs/openapi.yaml' }); - expect(config.docs).toBe('Some documentation'); - expect(config.activeEnvironmentUid).toBe('env_123'); - }); -});