-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(renterd): bulk move files via multiselect drag interaction
- Loading branch information
1 parent
be794d5
commit 2ab2ae8
Showing
24 changed files
with
590 additions
and
162 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@siafoundation/e2e': minor | ||
--- | ||
|
||
Added methods for mouse move and hover behaviours. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'renterd': minor | ||
--- | ||
|
||
Files and directories can now be selected and moved in bulk to a destination folder via drag and drop or the multi-select actions menu. This works even when selecting files (and entire directories) from across multiple different origin directories. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@siafoundation/design-system': minor | ||
--- | ||
|
||
The table now supports multiple dragging datums. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
import { test } from '@playwright/test' | ||
import { navigateToBuckets } from '../fixtures/navigate' | ||
import { createBucket, openBucket } from '../fixtures/buckets' | ||
import { | ||
getFileRowById, | ||
openDirectory, | ||
createFilesMap, | ||
expectFilesMap, | ||
navigateToParentDirectory, | ||
} from '../fixtures/files' | ||
import { afterTest, beforeTest } from '../fixtures/beforeTest' | ||
import { hoverMouseOver, moveMouseOver } from '@siafoundation/e2e' | ||
|
||
test.beforeEach(async ({ page }) => { | ||
await beforeTest(page, { | ||
hostdCount: 3, | ||
}) | ||
}) | ||
|
||
test.afterEach(async () => { | ||
await afterTest() | ||
}) | ||
|
||
test('move two files by selecting and dragging from one directory out to another', async ({ | ||
page, | ||
}) => { | ||
test.setTimeout(120_000) | ||
const bucketName = 'bucket1' | ||
await navigateToBuckets({ page }) | ||
await createBucket(page, bucketName) | ||
await createFilesMap(page, bucketName, { | ||
'file1.txt': null, | ||
dir1: { | ||
'file2.txt': null, | ||
}, | ||
dir2: { | ||
'file3.txt': null, | ||
'file4.txt': null, | ||
dir3: { | ||
'file5.txt': null, | ||
'file6.txt': null, | ||
}, | ||
}, | ||
}) | ||
await navigateToBuckets({ page }) | ||
await openBucket(page, bucketName) | ||
|
||
await openDirectory(page, 'bucket1/dir2/') | ||
|
||
// Select file3 and entire dir3. | ||
const file3 = await getFileRowById(page, 'bucket1/dir2/file3.txt', true) | ||
await file3.click() | ||
const dir3 = await getFileRowById(page, 'bucket1/dir2/dir3/', true) | ||
await dir3.click() | ||
|
||
// Move all selected files by dragging one of them. | ||
await moveMouseOver(page, file3) | ||
await page.mouse.down() | ||
|
||
const parentDir = await getFileRowById(page, '..', true) | ||
await hoverMouseOver(page, parentDir) | ||
|
||
const file1 = await getFileRowById(page, 'bucket1/file1.txt', true) | ||
await moveMouseOver(page, file1) | ||
await page.mouse.up() | ||
|
||
await expectFilesMap(page, bucketName, { | ||
'file1.txt': 'visible', | ||
'file3.txt': 'visible', | ||
dir3: { | ||
'file5.txt': 'visible', | ||
'file6.txt': 'visible', | ||
}, | ||
dir1: { | ||
'file2.txt': 'visible', | ||
}, | ||
dir2: { | ||
'file3.txt': 'hidden', | ||
'file4.txt': 'visible', | ||
dir3: 'hidden', | ||
}, | ||
}) | ||
}) | ||
|
||
test('move a file via drag and drop while leaving a separate set of selected files in place', async ({ | ||
page, | ||
}) => { | ||
test.setTimeout(120_000) | ||
const bucketName = 'bucket1' | ||
await navigateToBuckets({ page }) | ||
await createBucket(page, bucketName) | ||
await createFilesMap(page, bucketName, { | ||
'file1.txt': null, | ||
dir1: { | ||
'file2.txt': null, | ||
}, | ||
dir2: { | ||
'file3.txt': null, | ||
'file4.txt': null, | ||
'file5.txt': null, | ||
}, | ||
}) | ||
await navigateToBuckets({ page }) | ||
await openBucket(page, bucketName) | ||
|
||
await openDirectory(page, 'bucket1/dir2/') | ||
|
||
// Select file3 and file4. | ||
const file3 = await getFileRowById(page, 'bucket1/dir2/file3.txt', true) | ||
await file3.click() | ||
const file4 = await getFileRowById(page, 'bucket1/dir2/file4.txt', true) | ||
await file4.click() | ||
|
||
// Move file5 which is not in the selection. | ||
const file5 = await getFileRowById(page, 'bucket1/dir2/file5.txt', true) | ||
await moveMouseOver(page, file5) | ||
await page.mouse.down() | ||
|
||
const parentDir = await getFileRowById(page, '..', true) | ||
await hoverMouseOver(page, parentDir) | ||
|
||
const file1 = await getFileRowById(page, 'bucket1/file1.txt', true) | ||
await moveMouseOver(page, file1) | ||
await page.mouse.up() | ||
|
||
await expectFilesMap(page, bucketName, { | ||
'file1.txt': 'visible', | ||
'file5.txt': 'visible', | ||
dir1: { | ||
'file2.txt': 'visible', | ||
}, | ||
dir2: { | ||
'file3.txt': 'hidden', | ||
'file4.txt': 'hidden', | ||
}, | ||
}) | ||
}) | ||
|
||
test('move files by selecting and using the docked menu batch action', async ({ | ||
page, | ||
}) => { | ||
test.setTimeout(120_000) | ||
const bucketName = 'bucket1' | ||
await navigateToBuckets({ page }) | ||
await createBucket(page, bucketName) | ||
await createFilesMap(page, bucketName, { | ||
'file1.txt': null, | ||
dir1: { | ||
'file2.txt': null, | ||
}, | ||
dir2: { | ||
'file3.txt': null, | ||
'file4.txt': null, | ||
dir3: { | ||
'file5.txt': null, | ||
'file6.txt': null, | ||
}, | ||
}, | ||
}) | ||
await navigateToBuckets({ page }) | ||
await openBucket(page, bucketName) | ||
|
||
await openDirectory(page, 'bucket1/dir2/') | ||
|
||
// Select file3 and entire dir3. | ||
const file3 = await getFileRowById(page, 'bucket1/dir2/file3.txt', true) | ||
await file3.click() | ||
const dir3 = await getFileRowById(page, 'bucket1/dir2/dir3/', true) | ||
await dir3.click() | ||
|
||
await navigateToParentDirectory(page) | ||
|
||
const menu = page.getByLabel('file multi-select menu') | ||
|
||
// Delete selected files. | ||
await menu.getByLabel('move selected files to the current directory').click() | ||
const dialog = page.getByRole('dialog') | ||
await dialog.getByRole('button', { name: 'Move' }).click() | ||
|
||
await expectFilesMap(page, bucketName, { | ||
'file1.txt': 'visible', | ||
'file3.txt': 'visible', | ||
dir3: { | ||
'file5.txt': 'visible', | ||
'file6.txt': 'visible', | ||
}, | ||
dir1: { | ||
'file2.txt': 'visible', | ||
}, | ||
dir2: { | ||
'file3.txt': 'hidden', | ||
'file4.txt': 'visible', | ||
dir3: 'hidden', | ||
}, | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
apps/renterd/components/FilesDirectory/FilesDirectoryDockedControls/FilesBatchMove.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { Button, Paragraph } from '@siafoundation/design-system' | ||
import { FolderMoveTo16 } from '@siafoundation/react-icons' | ||
import { useFilesDirectory } from '../../../contexts/filesDirectory' | ||
import { useDialog } from '../../../contexts/dialog' | ||
|
||
export function FilesBatchMove() { | ||
const { openConfirmDialog } = useDialog() | ||
const { multiSelect, moveSelectedFiles, moveSelectedFilesOperationCount } = | ||
useFilesDirectory() | ||
|
||
return ( | ||
<Button | ||
disabled={moveSelectedFilesOperationCount === 0} | ||
aria-label="move selected files to the current directory" | ||
tip="Move selected files to the current directory" | ||
onClick={() => { | ||
openConfirmDialog({ | ||
title: `Move files`, | ||
action: 'Move', | ||
variant: 'accent', | ||
body: ( | ||
<div className="flex flex-col gap-1"> | ||
<Paragraph size="14"> | ||
Are you sure you would like to move the{' '} | ||
{multiSelect.selectionCount.toLocaleString()} selected files to | ||
the current directory? | ||
</Paragraph> | ||
</div> | ||
), | ||
onConfirm: async () => { | ||
moveSelectedFiles() | ||
}, | ||
}) | ||
}} | ||
> | ||
<FolderMoveTo16 /> | ||
</Button> | ||
) | ||
} |
4 changes: 3 additions & 1 deletion
4
...enterd/components/FilesDirectory/FilesDirectoryDockedControls/FilesDirectoryBatchMenu.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,15 @@ | ||
import { MultiSelectionMenu } from '@siafoundation/design-system' | ||
import { FilesBatchDelete } from '../../Files/batchActions/FilesBatchDelete' | ||
import { useFilesDirectory } from '../../../contexts/filesDirectory' | ||
import { FilesBatchMove } from './FilesBatchMove' | ||
|
||
export function FilesDirectoryBatchMenu() { | ||
const { multiSelect } = useFilesDirectory() | ||
|
||
return ( | ||
<MultiSelectionMenu multiSelect={multiSelect} entityWord="file"> | ||
<FilesBatchDelete multiSelect={multiSelect} /> | ||
<FilesBatchMove /> | ||
<FilesBatchDelete /> | ||
</MultiSelectionMenu> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.