From 5984a6e654fa849e9e2470be84f255ffbdab30ac Mon Sep 17 00:00:00 2001 From: Juan Manuel Spoleti <104365141+juans-chainsafe@users.noreply.github.com> Date: Fri, 20 May 2022 10:37:01 -0300 Subject: [PATCH 01/39] add always() in Slack notification + update chrome and ff version (#2145) Co-authored-by: Michael Yankelev <12774278+FSM1@users.noreply.github.com> --- .github/workflows/test-files-on-demand.yml | 3 ++- .github/workflows/test-files.yml | 2 +- .github/workflows/test-storage-on-demand.yml | 3 ++- .github/workflows/test-storage.yml | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-files-on-demand.yml b/.github/workflows/test-files-on-demand.yml index 5e5093284e..af3c30302b 100644 --- a/.github/workflows/test-files-on-demand.yml +++ b/.github/workflows/test-files-on-demand.yml @@ -3,7 +3,7 @@ on: [workflow_dispatch] jobs: cypress-run: runs-on: ubuntu-latest - container: cypress/browsers:node14.17.0-chrome91-ff89 + container: cypress/browsers:node14.17.6-chrome100-ff98 steps: - name: Checkout uses: actions/checkout@v2 @@ -53,6 +53,7 @@ jobs: - name: Slack Notification uses: rtCamp/action-slack-notify@v2.2.0 + if: always() env: SLACK_TITLE: 'Files UI Test Suite On-Demand Result:' SLACK_MESSAGE: ${{ job.status }} diff --git a/.github/workflows/test-files.yml b/.github/workflows/test-files.yml index f90cbac1c2..99af8ac002 100644 --- a/.github/workflows/test-files.yml +++ b/.github/workflows/test-files.yml @@ -12,7 +12,7 @@ on: jobs: cypress-run: runs-on: ubuntu-latest - container: cypress/browsers:node14.17.0-chrome91-ff89 + container: cypress/browsers:node14.17.6-chrome100-ff98 steps: - name: Checkout uses: actions/checkout@v2 diff --git a/.github/workflows/test-storage-on-demand.yml b/.github/workflows/test-storage-on-demand.yml index da4cd43584..520e153ec2 100644 --- a/.github/workflows/test-storage-on-demand.yml +++ b/.github/workflows/test-storage-on-demand.yml @@ -3,7 +3,7 @@ on: [workflow_dispatch] jobs: cypress-run: runs-on: ubuntu-latest - container: cypress/browsers:node14.17.0-chrome91-ff89 + container: cypress/browsers:node14.17.6-chrome100-ff98 steps: - name: Checkout uses: actions/checkout@v2 @@ -52,6 +52,7 @@ jobs: - name: Slack Notification uses: rtCamp/action-slack-notify@v2.2.0 + if: always() env: SLACK_TITLE: 'Storage UI Test Suite On-Demand Result:' SLACK_MESSAGE: ${{ job.status }} diff --git a/.github/workflows/test-storage.yml b/.github/workflows/test-storage.yml index dbf77b10b8..c3204e5967 100644 --- a/.github/workflows/test-storage.yml +++ b/.github/workflows/test-storage.yml @@ -12,7 +12,7 @@ on: jobs: cypress-run: runs-on: ubuntu-latest - container: cypress/browsers:node14.17.0-chrome91-ff89 + container: cypress/browsers:node14.17.6-chrome100-ff98 steps: - name: Checkout uses: actions/checkout@v2 From 707134847ac1f15376054ad65376d018874a3547 Mon Sep 17 00:00:00 2001 From: Juan Manuel Spoleti <104365141+juans-chainsafe@users.noreply.github.com> Date: Mon, 23 May 2022 10:43:05 -0300 Subject: [PATCH 02/39] [Files] Add download file test (#2139) * files - download file from file browser TEST done * remove ; * add file content validation * remove ; * fixes from PR comment * simplifying remove only and lint Co-authored-by: Michael Yankelev <12774278+FSM1@users.noreply.github.com> Co-authored-by: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com> Co-authored-by: Thibaut Sardan --- .../toasts/downloadCompleteToast.ts | 4 ++ .../cypress/tests/file-management-spec.ts | 48 +++++++++++++++++-- .../files-ui/src/Contexts/FilesContext.tsx | 4 +- 3 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 packages/files-ui/cypress/support/page-objects/toasts/downloadCompleteToast.ts diff --git a/packages/files-ui/cypress/support/page-objects/toasts/downloadCompleteToast.ts b/packages/files-ui/cypress/support/page-objects/toasts/downloadCompleteToast.ts new file mode 100644 index 0000000000..b60227f978 --- /dev/null +++ b/packages/files-ui/cypress/support/page-objects/toasts/downloadCompleteToast.ts @@ -0,0 +1,4 @@ +export const downloadCompleteToast = { + body: () => cy.get("[data-testid=toast-download-complete]", { timeout: 10000 }), + closeButton: () => cy.get("[data-testid=button-close-toast-download-complete]") +} diff --git a/packages/files-ui/cypress/tests/file-management-spec.ts b/packages/files-ui/cypress/tests/file-management-spec.ts index a95a153c73..499f575862 100644 --- a/packages/files-ui/cypress/tests/file-management-spec.ts +++ b/packages/files-ui/cypress/tests/file-management-spec.ts @@ -13,6 +13,7 @@ import { deleteSuccessToast } from "../support/page-objects/toasts/deleteSuccess import { moveSuccessToast } from "../support/page-objects/toasts/moveSuccessToast" import { recoverSuccessToast } from "../support/page-objects/toasts/recoverSuccessToast" import { uploadCompleteToast } from "../support/page-objects/toasts/uploadCompleteToast" +import { downloadCompleteToast } from "../support/page-objects/toasts/downloadCompleteToast" import { fileInfoModal } from "../support/page-objects/modals/fileInfoModal" describe("File management", () => { @@ -467,25 +468,25 @@ describe("File management", () => { it("can view file information via modal option", () => { cy.web3Login({ clearCSFBucket: true }) - + // upload a file homePage.uploadFile("../fixtures/uploadedFiles/text-file.txt") homePage.fileItemRow().should("have.length", 1) - + // store file name as cypress aliases for later comparison homePage.fileItemName().eq(0).invoke("text").as("fileNameA") - + // navigate to the info modal for the file homePage.fileItemKebabButton().first().click() homePage.infoMenuOption().eq(0).click() - + // ensure all labels on the modal are visible fileInfoModal.nameLabel().should("be.visible") fileInfoModal.fileSizeLabel().should("be.visible") fileInfoModal.dateUploadedLabel().should("be.visible") fileInfoModal.cidLabel().should("be.visible") fileInfoModal.decryptionKeyLabel().should("be.visible") - + // ensure the correct file name is being displayed fileInfoModal.body().should("be.visible") cy.get("@fileNameA").then((fileNameA) => { @@ -502,5 +503,42 @@ describe("File management", () => { fileInfoModal.closeButton().click() fileInfoModal.body().should("not.exist") }) + + it("can download a file from file browser", () => { + const fileName = "text-file.txt" + const downloadsFolder = Cypress.config("downloadsFolder") + const fileFixturePath = `uploadedFiles/${fileName}` + + cy.web3Login({ clearCSFBucket: true }) + + // upload a file and store file content + homePage.uploadFile(fileFixturePath) + cy.fixture(fileFixturePath).as("fileContent") + homePage.fileItemRow().should("have.length", 1) + + // download file from kebab menu + homePage.fileItemKebabButton().first().click() + + // intercept POST to ensure the request was successful + cy.intercept("POST", "**/bucket/*/download") + .as("downloadRequest") + .then(() => { + homePage.downloadMenuOption().eq(0).click() + + cy.wait("@downloadRequest").should((download) => { + expect(download.response).to.have.property("statusCode", 200) + }) + }) + + // ensure the file was downloaded + downloadCompleteToast.body().should("be.visible") + downloadCompleteToast.closeButton().click() + cy.get("@fileContent").then((fileContent) => { + cy.readFile(`${downloadsFolder}/${fileName}`) + .should("exist") + .should("eq", fileContent) + }) + + }) }) }) diff --git a/packages/files-ui/src/Contexts/FilesContext.tsx b/packages/files-ui/src/Contexts/FilesContext.tsx index 58f6dbb9ba..e2722bdf5f 100644 --- a/packages/files-ui/src/Contexts/FilesContext.tsx +++ b/packages/files-ui/src/Contexts/FilesContext.tsx @@ -633,6 +633,7 @@ const FilesProvider = ({ children }: FilesContextProps) => { type: "success", progress: 0, isClosable: false, + testId: "downloading-file", onProgressCancel: cancelSource.cancel } const toastId = addToast(toastParams) @@ -663,7 +664,8 @@ const FilesProvider = ({ children }: FilesContextProps) => { type: "success", progress: undefined, onProgressCancel: undefined, - isClosable: true + isClosable: true, + testId: "download-complete" }, true) URL.revokeObjectURL(link.href) setDownloadsInProgress(false) From c67ac4ff5e2ee30a4e0fc4e4b3b9a1f392f34ba8 Mon Sep 17 00:00:00 2001 From: Tanmoy Basak Anjan Date: Wed, 25 May 2022 20:56:34 +0600 Subject: [PATCH 03/39] Right click context menu (#2134) * rearranged menu * in progress * mooving items * item selected menu restructure * bulk operations added * anchor menu * right click implementated * console and comments * catering for bin view * storagee re factored * added to browser * refactor files further * anchor position update * re arrange and names * lingui extract * types for position * Update packages/files-ui/src/Components/Modules/FileBrowsers/views/FileSystemItem/FileSystemItem.tsx Co-authored-by: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com> * Update packages/storage-ui/src/Components/Modules/FileSystemItem/itemOperations.tsx Co-authored-by: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com> * Update packages/files-ui/src/UI-components/AnchorMenu.tsx Co-authored-by: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com> * Update packages/files-ui/src/Components/Modules/FileBrowsers/views/FilesList.tsx Co-authored-by: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com> * resolving comments * anchor menu changes * applied suggestions * theme vars Co-authored-by: GitHub Actions Co-authored-by: Thibaut Sardan <33178835+Tbaut@users.noreply.github.com> --- .../src/MenuDropdown/MenuDropdown.tsx | 6 +- .../FileSystemItem/FileSystemGridItem.tsx | 13 +- .../views/FileSystemItem/FileSystemItem.tsx | 230 ++++---------- .../FileSystemItem/FileSystemTableItem.tsx | 13 +- .../views/FileSystemItem/itemOperations.tsx | 173 +++++++++++ .../Modules/FileBrowsers/views/FilesList.tsx | 238 +++++++++----- .../files-ui/src/UI-components/AnchorMenu.tsx | 115 +++++++ .../FileSystemItem/FileSystemGridItem.tsx | 13 +- .../Modules/FileSystemItem/FileSystemItem.tsx | 201 +++--------- .../FileSystemItem/FileSystemTableItem.tsx | 15 +- .../Modules/FileSystemItem/itemOperations.tsx | 152 +++++++++ .../Modules/FilesList/FilesList.tsx | 290 ++++++++++++------ .../Components/UI-components/AnchorMenu.tsx | 115 +++++++ packages/storage-ui/src/Themes/Constants.ts | 5 + packages/storage-ui/src/Themes/DarkTheme.ts | 5 + packages/storage-ui/src/Themes/LightTheme.ts | 5 + .../storage-ui/src/locales/en/messages.po | 3 - 17 files changed, 1062 insertions(+), 530 deletions(-) create mode 100644 packages/files-ui/src/Components/Modules/FileBrowsers/views/FileSystemItem/itemOperations.tsx create mode 100644 packages/files-ui/src/UI-components/AnchorMenu.tsx create mode 100644 packages/storage-ui/src/Components/Modules/FileSystemItem/itemOperations.tsx create mode 100644 packages/storage-ui/src/Components/UI-components/AnchorMenu.tsx diff --git a/packages/common-components/src/MenuDropdown/MenuDropdown.tsx b/packages/common-components/src/MenuDropdown/MenuDropdown.tsx index 9797b635c1..84c386e13b 100644 --- a/packages/common-components/src/MenuDropdown/MenuDropdown.tsx +++ b/packages/common-components/src/MenuDropdown/MenuDropdown.tsx @@ -181,7 +181,7 @@ const useStyles = makeStyles( interface IMenuItem { contents: ReactNode | ReactNode[] - onClick?: () => void + onClick?: (e: React.MouseEvent) => void } interface IMenuDropdownProps { @@ -304,9 +304,9 @@ const MenuDropdown = ({ data-testid={`dropdown-item-${testId}`} key={`menu-${index}`} className={clsx(classes.item, classNames?.item)} - onClick={() => { + onClick={(e) => { autoclose && handleClose() - item.onClick && item.onClick() + item.onClick && item.onClick(e) }} > {item.contents} diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/views/FileSystemItem/FileSystemGridItem.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/views/FileSystemItem/FileSystemGridItem.tsx index 47ef11e7e9..35ca5dab82 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/views/FileSystemItem/FileSystemGridItem.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/views/FileSystemItem/FileSystemGridItem.tsx @@ -138,12 +138,13 @@ interface IFileSystemTableItemProps { onFolderOrFileClicks: (e?: React.MouseEvent) => void icon: React.ReactNode preview: ConnectDragPreview - setEditing: (editing: string | undefined) => void + editFile: (file: FileSystemItem | undefined) => void handleRename?: (path: string, newPath: string) => Promise | undefined currentPath: string | undefined menuItems: IMenuItem[] resetSelectedFiles: () => void longPressEvents?: LongPressEvents + handleContextMenuOnItem?: (e: React.MouseEvent) => void } const FileSystemGridItem = React.forwardRef( @@ -156,12 +157,13 @@ const FileSystemGridItem = React.forwardRef( editing, onFolderOrFileClicks, icon, - setEditing, + editFile, handleRename, menuItems, resetSelectedFiles, preview, - longPressEvents + longPressEvents, + handleContextMenuOnItem }: IFileSystemTableItemProps, forwardedRef: any) => { const classes = useStyles() const { name, cid } = file @@ -216,9 +218,9 @@ const FileSystemGridItem = React.forwardRef( }, [handleClickOutside]) const stopEditing = useCallback(() => { - setEditing(undefined) + editFile(undefined) formik.resetForm() - }, [formik, setEditing]) + }, [formik, editFile]) useOnClickOutside(formRef, formik.submitForm) @@ -238,6 +240,7 @@ const FileSystemGridItem = React.forwardRef( e.preventDefault() e.stopPropagation() }} + onContextMenu={handleContextMenuOnItem} >
{ return createStyles({ @@ -103,54 +93,55 @@ const useStyles = makeStyles(({ breakpoints, constants }: CSFTheme) => { interface IFileSystemItemProps { file: FileSystemItemType - files: FileSystemItemType[] selectedCids: string[] owners?: BucketUser[] handleSelectItem(selectedItem: FileSystemItemType): void handleAddToSelectedItems(selectedItems: FileSystemItemType): void handleSelectItemWithShift(selectedItems: FileSystemItemType): void editing: string | undefined - setEditing(editing: string | undefined): void handleRename?: (cid: string, newName: string) => Promise | undefined - handleMove?: (cid: string, newPath: string) => Promise - deleteFile?: () => void - recoverFile?: () => void - viewFolder?: (cid: string) => void - moveFile?: () => void itemOperations: FileOperation[] resetSelectedFiles: () => void browserView: BrowserView - reportFile?: (path: string) => void - showFileInfo?: (path: string) => void + editFile(file: FileSystemItemType | undefined): void + downloadFile?: (file: FileSystemItemType) => void + deleteFile?: (file: FileSystemItemType) => void handleShare?: (file: FileSystemItemType) => void - showPreview?: (fileIndex: number) => void + moveFile?: (file: FileSystemItemType) => void + recoverFile?: (file: FileSystemItemType) => void + reportFile?: (file: FileSystemItemType) => void + previewFile?: (file: FileSystemItemType) => void + viewFolder?: (file: FileSystemItemType) => void + showFileInfo?: (file: FileSystemItemType) => void + handleContextMenuOnItem? : (e: React.MouseEvent, file: FileSystemItemType) => void } + const FileSystemItem = ({ file, - files, selectedCids, owners, editing, - setEditing, handleRename, deleteFile, recoverFile, viewFolder, moveFile, + downloadFile, handleSelectItem, handleAddToSelectedItems, handleSelectItemWithShift, itemOperations, browserView, + editFile, resetSelectedFiles, reportFile, showFileInfo, handleShare, - showPreview + previewFile, + handleContextMenuOnItem }: IFileSystemItemProps) => { - const { bucket, downloadFile, currentPath, handleUploadOnDrop, moveItems } = useFileBrowser() - const { downloadMultipleFiles } = useFiles() + const { bucket, currentPath, handleUploadOnDrop, moveItems } = useFileBrowser() const { cid, name, isFolder } = file const inSharedFolder = useMemo(() => bucket?.type === "share", [bucket]) @@ -176,164 +167,46 @@ const FileSystemItem = ({ }) const stopEditing = useCallback(() => { - setEditing(undefined) + editFile(undefined) formik.resetForm() - }, [formik, setEditing]) + }, [formik, editFile]) const { desktop } = useThemeSwitcher() const classes = useStyles() - const filePath = useMemo(() => getPathWithFile(currentPath, name), [currentPath, name]) - const onFilePreview = useCallback(() => { - showPreview && showPreview(files.indexOf(file)) - }, [file, files, showPreview]) + const menuItems = useMemo(() => getItemMenuOptions({ + menuIconClass: classes.menuIcon, + file, + inSharedFolder, + viewFolder, + reportFile, + previewFile, + recoverFile, + showFileInfo, + deleteFile, + handleShare, + moveFile, + downloadFile, + editFile, + itemOperations - const allMenuItems: Record = useMemo(() => ({ - rename: { - contents: ( - <> - - - Rename - - - ), - onClick: () => setEditing(cid) - }, - delete: { - contents: ( - <> - - - Delete - - - ), - onClick: () => deleteFile && deleteFile() - }, - download: { - contents: ( - <> - - - {file.isFolder ? Download as zip : Download} - - - ), - onClick: () => { - if (file.isFolder) { - bucket && downloadMultipleFiles([file], currentPath, bucket.id) - } else { - downloadFile && downloadFile(cid) - } - } - }, - move: { - contents: ( - <> - - - Move - - - ), - onClick: () => moveFile && moveFile() - }, - share: { - contents: ( - <> - - - {inSharedFolder - ? t`Copy to` - : t`Share` - } - - - ), - onClick: () => handleShare && handleShare(file) - }, - info: { - contents: ( - <> - - - Info - - - ), - onClick: () => showFileInfo && showFileInfo(filePath) - }, - recover: { - contents: ( - <> - - - Recover - - - ), - onClick: () => recoverFile && recoverFile() - }, - preview: { - contents: ( - <> - - - Preview - - - ), - onClick: () => onFilePreview() - }, - view_folder: { - contents: ( - <> - - - View folder - - - ), - onClick: () => viewFolder && viewFolder(cid) - }, - report: { - contents: ( - <> - - - Report - - - ), - onClick: () => reportFile && reportFile(filePath) - } - }), - [ + }), [ classes.menuIcon, file, - setEditing, - cid, - deleteFile, - bucket, - downloadMultipleFiles, - currentPath, + editFile, + previewFile, + itemOperations, downloadFile, + deleteFile, moveFile, handleShare, - filePath, showFileInfo, recoverFile, - onFilePreview, viewFolder, reportFile, inSharedFolder ]) - const menuItems: IMenuItem[] = itemOperations.map( - (itemOperation) => allMenuItems[itemOperation] - ) - const [, dragMoveRef, preview] = useDrag({ type: DragTypes.MOVABLE_FILE, canDrag: !editing, @@ -428,9 +301,9 @@ const FileSystemItem = ({ handleAddToSelectedItems(file) } else { if (isFolder) { - viewFolder && viewFolder(file.cid) + viewFolder && viewFolder(file) } else { - onFilePreview() + previewFile && previewFile(file) } } } @@ -440,11 +313,11 @@ const FileSystemItem = ({ file, isFolder, viewFolder, - onFilePreview, selectedCids.length, handleAddToSelectedItems, handleSelectItemWithShift, - handleSelectItem + handleSelectItem, + previewFile ] ) @@ -453,16 +326,16 @@ const FileSystemItem = ({ if (desktop) { // on desktop if (isFolder) { - viewFolder && viewFolder(file.cid) + viewFolder && viewFolder(file) } else { - onFilePreview() + previewFile && previewFile(file) } } else { // on mobile return } }, - [desktop, viewFolder, file, onFilePreview, isFolder] + [desktop, viewFolder, file, previewFile, isFolder] ) const { click } = useDoubleClick(onSingleClick, onDoubleClick) @@ -496,8 +369,11 @@ const FileSystemItem = ({ onFolderOrFileClicks, preview, selectedCids, - setEditing, + editFile, resetSelectedFiles, + handleContextMenuOnItem: (e: React.MouseEvent) => { + handleContextMenuOnItem && handleContextMenuOnItem(e, file) + }, handleItemSelectOnCheck, longPressEvents: !desktop ? longPressEvents : undefined } @@ -551,7 +427,7 @@ const FileSystemItem = ({