feat: add bulk file actions (#7827)
* fixed styling * Enabled header checkbox selection * Changed styling of selection * Implemented bulk downloading and deleting * Added delete bulk hook * Added download bulk hook * Fix backend to send extension in download single file * Fix hook to download single file directly * Added header and selection handling * Added delete confirmation * [autofix.ci] apply automated fixes * Fixed selection with shift * Show disabled files * Show disabled files as not clickable * Changed color of icon when disabled * Implemented pressed shift handling * Fixed shift selection and disabled text selection when holding shift * Created test for bulk selection on files modal * add test of disabled components in file component * Fixed files page test to include bulk editing test * removed ring on focus visible * Changed delete files having the right select --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
596a219de3
commit
a72995c408
11 changed files with 1244 additions and 235 deletions
|
|
@ -318,3 +318,148 @@ test(
|
|||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
"should handle bulk actions for multiple files",
|
||||
{ tag: ["@release", "@files"] },
|
||||
async ({ page }) => {
|
||||
const fileNames = {
|
||||
txt: generateRandomFilename(),
|
||||
json: generateRandomFilename(),
|
||||
py: generateRandomFilename(),
|
||||
};
|
||||
|
||||
const testFiles = [
|
||||
path.join(__dirname, "../../assets/test-file.txt"),
|
||||
path.join(__dirname, "../../assets/test-file.json"),
|
||||
path.join(__dirname, "../../assets/test-file.py"),
|
||||
];
|
||||
|
||||
const fileContents = testFiles.map((file) => fs.readFileSync(file));
|
||||
|
||||
await awaitBootstrapTest(page, { skipModal: true });
|
||||
|
||||
const firstRunLangflow = await page
|
||||
.getByTestId("empty-project-description")
|
||||
.count();
|
||||
|
||||
if (firstRunLangflow > 0) {
|
||||
await addFlowToTestOnEmptyLangflow(page);
|
||||
}
|
||||
|
||||
await page.waitForSelector('[data-testid="mainpage_title"]', {
|
||||
timeout: 30000,
|
||||
});
|
||||
|
||||
await page.getByText("My Files").first().click();
|
||||
const fileChooserPromise = page.waitForEvent("filechooser");
|
||||
await page.getByTestId("upload-file-btn").click();
|
||||
|
||||
const fileChooser = await fileChooserPromise;
|
||||
await fileChooser.setFiles([
|
||||
{
|
||||
name: `${fileNames.txt}.txt`,
|
||||
mimeType: "text/plain",
|
||||
buffer: fileContents[0],
|
||||
},
|
||||
{
|
||||
name: `${fileNames.json}.json`,
|
||||
mimeType: "application/json",
|
||||
buffer: fileContents[1],
|
||||
},
|
||||
{
|
||||
name: `${fileNames.py}.py`,
|
||||
mimeType: "text/x-python",
|
||||
buffer: fileContents[2],
|
||||
},
|
||||
]);
|
||||
|
||||
// Wait for upload success message
|
||||
const successMessage = await page.getByText("Files uploaded successfully");
|
||||
expect(successMessage).toBeTruthy();
|
||||
|
||||
// Verify all files appear in the list
|
||||
for (const name of Object.values(fileNames)) {
|
||||
const file = await page.getByText(name).last();
|
||||
await expect(file).toBeVisible({
|
||||
timeout: 1000,
|
||||
});
|
||||
}
|
||||
|
||||
// Select files with shift (checkbox on the grid)
|
||||
|
||||
await page.keyboard.down("Shift");
|
||||
await page.locator('input[data-ref="eInput"]').nth(5).click();
|
||||
await page.locator('input[data-ref="eInput"]').nth(7).click();
|
||||
await page.keyboard.up("Shift");
|
||||
|
||||
expect(
|
||||
await page.locator('input[data-ref="eInput"]').nth(5).isChecked(),
|
||||
).toBe(true);
|
||||
expect(
|
||||
await page.locator('input[data-ref="eInput"]').nth(6).isChecked(),
|
||||
).toBe(true);
|
||||
expect(
|
||||
await page.locator('input[data-ref="eInput"]').nth(7).isChecked(),
|
||||
).toBe(true);
|
||||
|
||||
// Check if the bulk actions toolbar appears
|
||||
const selectedCountText = await page.getByText("3 selected");
|
||||
await expect(selectedCountText).toBeVisible();
|
||||
|
||||
// Check if download button is visible
|
||||
const downloadButton = await page.getByTestId("bulk-download-btn");
|
||||
await expect(downloadButton).toBeVisible();
|
||||
|
||||
// Set up download listener
|
||||
const downloadPromise = page.waitForEvent("download");
|
||||
|
||||
// Click download button
|
||||
await downloadButton.click();
|
||||
|
||||
// Wait for download to start
|
||||
const download = await downloadPromise;
|
||||
|
||||
// Verify the download was initiated
|
||||
expect(download).toBeTruthy();
|
||||
|
||||
// Check for success message
|
||||
const downloadSuccessMessage = await page.getByText(
|
||||
/Files? downloaded successfully/,
|
||||
);
|
||||
expect(downloadSuccessMessage).toBeTruthy();
|
||||
|
||||
// Select both files (checkbox on the grid)
|
||||
|
||||
await page.locator('input[data-ref="eInput"]').nth(7).click();
|
||||
|
||||
// Check if the bulk actions toolbar appears
|
||||
const selectedCountTextDelete = await page.getByText("2 selected");
|
||||
await expect(selectedCountTextDelete).toBeVisible();
|
||||
|
||||
const deleteButton = await page.getByTestId("bulk-delete-btn");
|
||||
await expect(deleteButton).toBeVisible();
|
||||
|
||||
// Test delete functionality
|
||||
await deleteButton.click();
|
||||
|
||||
// Confirm the delete in the modal
|
||||
const confirmDeleteButton = await page.getByRole("button", {
|
||||
name: "Delete",
|
||||
});
|
||||
await confirmDeleteButton.click();
|
||||
|
||||
// Check for success message
|
||||
const deleteSuccessMessage = await page.getByText(
|
||||
"Files deleted successfully",
|
||||
);
|
||||
expect(deleteSuccessMessage).toBeTruthy();
|
||||
|
||||
// Verify the deleted files are no longer visible
|
||||
const remainingFileCount =
|
||||
(await page.getByText(fileNames.py + ".py").count()) +
|
||||
(await page.getByText(fileNames.txt + ".txt").count()) +
|
||||
(await page.getByText(fileNames.json + ".json").count());
|
||||
expect(remainingFileCount).toBe(1);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue