mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-11 09:51:30 +00:00
This reverts commit e7c2c7c872.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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<Test>');
|
||||
|
||||
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>');
|
||||
});
|
||||
|
||||
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');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user