Skip to content

Commit f9689fe

Browse files
authored
Merge pull request #3455 from kammeows/Branch_Kamakshi
Fix: Prevent duplicate file renaming in sidebar
2 parents d2b769e + 2c5cf88 commit f9689fe

File tree

2 files changed

+68
-4
lines changed

2 files changed

+68
-4
lines changed

client/modules/IDE/components/FileNode.jsx

+28-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import classNames from 'classnames';
33
import React, { useState, useRef } from 'react';
44
import { connect } from 'react-redux';
55
import { useTranslation } from 'react-i18next';
6+
import { useSelector } from 'react-redux';
67

78
import * as IDEActions from '../actions/ide';
89
import * as FileActions from '../actions/files';
@@ -88,6 +89,24 @@ const FileNode = ({
8889
const [isDeleting, setIsDeleting] = useState(false);
8990
const [updatedName, setUpdatedName] = useState(name);
9091

92+
const files = useSelector((state) => state.files);
93+
94+
const checkDuplicate = (newName) => {
95+
const parentFolder = files.find((f) => f.id === parentId);
96+
if (!parentFolder) return false;
97+
98+
const siblingFiles = parentFolder.children
99+
.map((childId) => files.find((f) => f.id === childId))
100+
.filter(Boolean)
101+
.filter((file) => file.id !== id);
102+
103+
const isDuplicate = siblingFiles.some(
104+
(f) => f.name.trim().toLowerCase() === newName.trim().toLowerCase()
105+
);
106+
107+
return isDuplicate;
108+
};
109+
91110
const { t } = useTranslation();
92111
const fileNameInput = useRef(null);
93112
const fileOptionsRef = useRef(null);
@@ -157,7 +176,7 @@ const FileNode = ({
157176
};
158177

159178
const saveUpdatedFileName = () => {
160-
if (updatedName !== name) {
179+
if (!checkDuplicate(updatedName) && updatedName !== name) {
161180
updateFileName(id, updatedName);
162181
}
163182
};
@@ -198,8 +217,13 @@ const FileNode = ({
198217
};
199218

200219
const handleFileNameBlur = () => {
201-
validateFileName();
202-
hideEditFileName();
220+
if (!checkDuplicate(updatedName)) {
221+
validateFileName();
222+
hideEditFileName();
223+
} else {
224+
setUpdatedName(name);
225+
hideEditFileName();
226+
}
203227
};
204228

205229
const toggleFileOptions = (event) => {
@@ -271,6 +295,7 @@ const FileNode = ({
271295
aria-label={updatedName}
272296
className="sidebar__file-item-name"
273297
onClick={handleFileClick}
298+
onDoubleClick={handleClickRename}
274299
data-testid="file-name"
275300
>
276301
<FileName name={updatedName} />

client/modules/IDE/components/FileNode.unit.test.jsx

+40-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import React from 'react';
2+
import { Provider } from 'react-redux';
3+
import configureStore from 'redux-mock-store';
4+
import thunk from 'redux-thunk';
25

36
import {
47
fireEvent,
@@ -9,6 +12,8 @@ import {
912
} from '../../../test-utils';
1013
import { FileNode } from './FileNode';
1114

15+
const mockStore = configureStore([thunk]);
16+
1217
describe('<FileNode />', () => {
1318
const changeName = (newFileName) => {
1419
const renameButton = screen.getByText(/Rename/i);
@@ -32,6 +37,7 @@ describe('<FileNode />', () => {
3237
fileType,
3338
canEdit: true,
3439
children: [],
40+
parentId: 'parent-folder-id',
3541
authenticated: false,
3642
setSelectedFile: jest.fn(),
3743
deleteFile: jest.fn(),
@@ -45,7 +51,40 @@ describe('<FileNode />', () => {
4551
setProjectName: jest.fn()
4652
};
4753

48-
render(<FileNode {...props} />);
54+
const mockFiles = [
55+
{
56+
id: '0',
57+
name: props.name,
58+
parentId: 'parent-folder-id'
59+
},
60+
{
61+
id: '1',
62+
name: 'sketch.js',
63+
parentId: '0',
64+
isSelectedFile: true
65+
},
66+
{
67+
id: 'parent-folder-id',
68+
name: 'parent',
69+
parentId: null,
70+
children: ['0', 'some-other-file-id']
71+
},
72+
{
73+
id: 'some-other-file-id',
74+
name: 'duplicate.js',
75+
parentId: 'parent-folder-id'
76+
}
77+
];
78+
79+
const store = mockStore({
80+
files: mockFiles
81+
});
82+
83+
render(
84+
<Provider store={store}>
85+
<FileNode {...props} />
86+
</Provider>
87+
);
4988

5089
return props;
5190
};

0 commit comments

Comments
 (0)