Skip to content

Commit 67b902e

Browse files
[ui-sb] feat: disable drag and drop for root paths (#4240)
1 parent 7aec1e9 commit 67b902e

File tree

12 files changed

+187
-67
lines changed

12 files changed

+187
-67
lines changed

desktop/core/src/desktop/js/apps/storageBrowser/StorageBrowserTab/StorageBrowserTab.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import {
3636
getLastDirOrFileNameFromPath,
3737
getFileSystemAndPath
3838
} from '../../../reactComponents/PathBrowser/PathBrowser.util';
39-
import { inTrash } from '../../../utils/storageBrowserUtils';
39+
import { inTrash } from '../utils/utils';
4040

4141
import './StorageBrowserTab.scss';
4242

desktop/core/src/desktop/js/apps/storageBrowser/StorageDirectoryPage/StorageDirectoryActions/CreateAndUpload/CreateAndUploadAction.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import userEvent from '@testing-library/user-event';
2020
import '@testing-library/jest-dom';
2121
import CreateAndUploadAction from './CreateAndUploadAction';
2222
import { CREATE_DIRECTORY_API_URL, CREATE_FILE_API_URL } from '../../../api';
23-
import * as storageUtils from '../../../../../utils/storageBrowserUtils';
23+
import * as storageUtils from '../../../utils/utils';
2424

2525
const mockSave = jest.fn();
2626
jest.mock('../../../../../utils/hooks/useSaveData/useSaveData', () => ({

desktop/core/src/desktop/js/apps/storageBrowser/StorageDirectoryPage/StorageDirectoryActions/CreateAndUpload/CreateAndUploadAction.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ import {
3434
isOFSServiceID,
3535
isOFSVol,
3636
isS3Root,
37-
isFileSystemRoot
38-
} from '../../../../../utils/storageBrowserUtils';
37+
isFileSystemNonRoot
38+
} from '../../../utils/utils';
3939
import { FileStats } from '../../../types';
4040
import useSaveData from '../../../../../utils/hooks/useSaveData/useSaveData';
4141
import InputModal from '../../../../../reactComponents/InputModal/InputModal';
@@ -78,15 +78,15 @@ const getActionConfig = (t: TFunction): Record<ActionType, ActionItem> => ({
7878
modal: { title: t('Create File'), label: t('File name') },
7979
api: CREATE_FILE_API_URL,
8080
group: 'create',
81-
visible: path => isFileSystemRoot(path)
81+
visible: path => isFileSystemNonRoot(path)
8282
},
8383
[ActionType.createFolder]: {
8484
icon: <FolderIcon />,
8585
label: t('New Folder'),
8686
modal: { title: t('Create Folder'), label: t('Folder name') },
8787
api: CREATE_DIRECTORY_API_URL,
8888
group: 'create',
89-
visible: path => isFileSystemRoot(path)
89+
visible: path => isFileSystemNonRoot(path)
9090
},
9191
[ActionType.createBucket]: {
9292
icon: <BucketIcon />,
@@ -116,7 +116,7 @@ const getActionConfig = (t: TFunction): Record<ActionType, ActionItem> => ({
116116
icon: <ImportIcon />,
117117
label: t('Upload File'),
118118
group: 'upload',
119-
visible: path => isFileSystemRoot(path)
119+
visible: path => isFileSystemNonRoot(path)
120120
}
121121
});
122122

desktop/core/src/desktop/js/apps/storageBrowser/StorageDirectoryPage/StorageDirectoryActions/FileAndFolder/FileAndFolderActions.util.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {
2929
isS3,
3030
isOFSRoot,
3131
inTrash
32-
} from '../../../../../utils/storageBrowserUtils';
32+
} from '../../../utils/utils';
3333
import { SupportedFileTypes } from '../../../../../utils/constants/storageBrowser';
3434
import { TFunction } from 'i18next';
3535
import { getFileType } from '../../../StorageFilePage/StorageFilePage.util';

desktop/core/src/desktop/js/apps/storageBrowser/StorageDirectoryPage/StorageDirectoryActions/StorageDirectoryActions.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// limitations under the License.
1616

1717
import React from 'react';
18-
import { inTrash } from '../../../../utils/storageBrowserUtils';
18+
import { inTrash } from '../../utils/utils';
1919
import CreateAndUploadAction from './CreateAndUpload/CreateAndUploadAction';
2020
import TrashActions from './Trash/TrashActions';
2121
import FileAndFolderActions from './FileAndFolder/FileAndFolderActions';

desktop/core/src/desktop/js/apps/storageBrowser/StorageDirectoryPage/StorageDirectoryActions/Trash/TrashActions.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { i18nReact } from '../../../../../utils/i18nReact';
2222
import { FileStats, StorageDirectoryTableData } from '../../../types';
2323
import useSaveData from '../../../../../utils/hooks/useSaveData/useSaveData';
2424
import { TRASH_PURGE, TRASH_RESTORE_BULK } from '../../../api';
25-
import { inRestorableTrash } from '../../../../../utils/storageBrowserUtils';
25+
import { inRestorableTrash } from '../../../utils/utils';
2626

2727
interface TrashActionsProps {
2828
selectedFiles: StorageDirectoryTableData[];

desktop/core/src/desktop/js/apps/storageBrowser/StorageDirectoryPage/StorageDirectoryPage.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import {
5151
FILE_UPLOAD_START_EVENT,
5252
FILE_UPLOAD_SUCCESS_EVENT
5353
} from '../../../reactComponents/FileUploadQueue/event';
54+
import { isFileSystemNonRoot } from '../utils/utils';
5455

5556
import './StorageDirectoryPage.scss';
5657

@@ -127,7 +128,16 @@ const StorageDirectoryPage = ({
127128

128129
const onRowClicked = (record: StorageDirectoryTableData) => {
129130
return {
130-
onClick: () => {
131+
onClick: (event: React.MouseEvent) => {
132+
// Handle CTRL+click to open in new tab
133+
if (event.ctrlKey || event.metaKey) {
134+
const currentUrl = new URL(window.location.href);
135+
currentUrl.searchParams.set('path', record.path);
136+
window.open(currentUrl.toString(), '_blank');
137+
return;
138+
}
139+
140+
// Normal click behavior
131141
if (selectedFiles.length === 0) {
132142
onFilePathChange(record.path);
133143
if (record.type === 'dir') {
@@ -258,7 +268,7 @@ const StorageDirectoryPage = ({
258268
</div>
259269
</div>
260270

261-
<DragAndDrop onDrop={onFilesDrop}>
271+
<DragAndDrop onDrop={onFilesDrop} disabled={!isFileSystemNonRoot(fileStats.path)}>
262272
<LoadingErrorWrapper errors={errorConfig}>
263273
<PaginatedTable<StorageDirectoryTableData>
264274
loading={listDirectoryLoading && !polling}

desktop/core/src/desktop/js/apps/storageBrowser/StorageFilePage/StorageFilePage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {
3232
import useLoadData from '../../../utils/hooks/useLoadData/useLoadData';
3333
import { getLastKnownConfig } from '../../../config/hueConfig';
3434
import LoadingErrorWrapper from '../../../reactComponents/LoadingErrorWrapper/LoadingErrorWrapper';
35-
import { inTrash } from '../../../utils/storageBrowserUtils';
35+
import { inTrash } from '../utils/utils';
3636
import { getLastDirOrFileNameFromPath } from '../../../reactComponents/PathBrowser/PathBrowser.util';
3737

3838
interface StorageFilePageProps {

desktop/core/src/desktop/js/utils/storageBrowserUtils.test.ts renamed to desktop/core/src/desktop/js/apps/storageBrowser/utils/utils.test.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ import {
2828
isOFSVol,
2929
inTrash,
3030
inRestorableTrash,
31-
isFileSystemRoot
32-
} from './storageBrowserUtils';
31+
isFileSystemNonRoot
32+
} from './utils';
3333

3434
describe('isHDFS function', () => {
3535
test('returns true for paths starting with "/"', () => {
@@ -225,49 +225,49 @@ describe('inRestorableTrash function', () => {
225225
});
226226
});
227227

228-
describe('isFileSystemRoot', () => {
228+
describe('isFileSystemNonRoot', () => {
229229
beforeEach(() => {
230230
jest.resetAllMocks();
231231
});
232232

233233
it('returns true for non-root S3 path', () => {
234-
expect(isFileSystemRoot('s3a://bucket/folder')).toBe(true);
234+
expect(isFileSystemNonRoot('s3a://bucket/folder')).toBe(true);
235235
});
236236

237237
it('returns false for S3 root path', () => {
238-
expect(isFileSystemRoot('s3a://')).toBe(false);
238+
expect(isFileSystemNonRoot('s3a://')).toBe(false);
239239
});
240240

241241
it('returns true for non-root GS path', () => {
242-
expect(isFileSystemRoot('gs://folder')).toBe(true);
242+
expect(isFileSystemNonRoot('gs://folder')).toBe(true);
243243
});
244244

245245
it('returns false for GS root path', () => {
246-
expect(isFileSystemRoot('gs://')).toBe(false);
246+
expect(isFileSystemNonRoot('gs://')).toBe(false);
247247
});
248248

249249
it('returns true for non-root ABFS path', () => {
250-
expect(isFileSystemRoot('abfs://folder')).toBe(true);
250+
expect(isFileSystemNonRoot('abfs://folder')).toBe(true);
251251
});
252252

253253
it('returns false for ABFS root path', () => {
254-
expect(isFileSystemRoot('abfs://')).toBe(false);
254+
expect(isFileSystemNonRoot('abfs://')).toBe(false);
255255
});
256256

257257
it('returns true for OFS when not serviceID or volume', () => {
258-
expect(isFileSystemRoot('ofs://service/volume/folder')).toBe(true);
258+
expect(isFileSystemNonRoot('ofs://service/volume/folder')).toBe(true);
259259
});
260260

261261
it('returns false for OFS serviceID', () => {
262-
expect(isFileSystemRoot('ofs://service')).toBe(false);
262+
expect(isFileSystemNonRoot('ofs://service')).toBe(false);
263263
});
264264

265265
it('returns false for OFS volume', () => {
266-
expect(isFileSystemRoot('ofs://service/vol')).toBe(false);
266+
expect(isFileSystemNonRoot('ofs://service/vol')).toBe(false);
267267
});
268268

269269
it('returns true for HDFS (default case)', () => {
270-
expect(isFileSystemRoot('/hdfs')).toBe(true);
271-
expect(isFileSystemRoot('/')).toBe(true);
270+
expect(isFileSystemNonRoot('/hdfs')).toBe(true);
271+
expect(isFileSystemNonRoot('/')).toBe(true);
272272
});
273273
});

desktop/core/src/desktop/js/utils/storageBrowserUtils.ts renamed to desktop/core/src/desktop/js/apps/storageBrowser/utils/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export const inRestorableTrash = (path: string): boolean => {
8484
return path.match(/^\/user\/.+?\/\.Trash\/.+?/) !== null;
8585
};
8686

87-
export const isFileSystemRoot = (path: string): boolean => {
87+
export const isFileSystemNonRoot = (path: string): boolean => {
8888
if (isS3(path)) {
8989
return !isS3Root(path);
9090
}

0 commit comments

Comments
 (0)