diff --git a/packages/files-ui/cypress/fixtures/filesTestData.ts b/packages/files-ui/cypress/fixtures/filesTestData.ts index 4b21f7812e..df4bec6e18 100644 --- a/packages/files-ui/cypress/fixtures/filesTestData.ts +++ b/packages/files-ui/cypress/fixtures/filesTestData.ts @@ -1,2 +1,3 @@ export const folderName = "Group" -export const folderPath = `/${folderName}` \ No newline at end of file +export const folderPath = `/${folderName}` +export const profileCreatedDate = "2021-05-20T21:26:36.598924Z" diff --git a/packages/files-ui/cypress/support/index.ts b/packages/files-ui/cypress/support/index.ts index cb8233c617..f0febdb6c2 100644 --- a/packages/files-ui/cypress/support/index.ts +++ b/packages/files-ui/cypress/support/index.ts @@ -28,5 +28,19 @@ Cypress.on("uncaught:exception", (err) => { } }) +// Hide fetch/XHR requests +// interim solution until cypress adds configuration support +// source https://gist.github.com/simenbrekken/3d2248f9e50c1143bf9dbe02e67f5399 +const app = window.top + +if(app != null && !app.document.head.querySelector("[data-hide-command-log-request]")) { + const style = app.document.createElement("style") + style.innerHTML = + ".command-name-request, .command-name-xhr { display: none }" + style.setAttribute("data-hide-command-log-request", "") + + app.document.head.appendChild(style) +} + // Alternatively you can use CommonJS syntax: // require('./commands') diff --git a/packages/files-ui/cypress/support/page-objects/homePage.ts b/packages/files-ui/cypress/support/page-objects/homePage.ts index cbfd7d260c..337e56f6a4 100644 --- a/packages/files-ui/cypress/support/page-objects/homePage.ts +++ b/packages/files-ui/cypress/support/page-objects/homePage.ts @@ -8,6 +8,8 @@ export const homePage = { ...fileBrowser, // home page specific file browser elements + closeBannerButton: () => cy.get("[data-cy=button-close-banner"), + surveyBanner: () => cy.get("[data-cy=banner-survey]"), newFolderButton: () => cy.get("[data-cy=button-new-folder]"), uploadButton: () => cy.get("[data-cy=button-upload-file]"), moveSelectedButton: () => cy.get("[data-testId=button-move-selected-file]"), diff --git a/packages/files-ui/cypress/support/page-objects/toasts/recoverSuccessToast.ts b/packages/files-ui/cypress/support/page-objects/toasts/recoverSuccessToast.ts new file mode 100644 index 0000000000..19a1815be4 --- /dev/null +++ b/packages/files-ui/cypress/support/page-objects/toasts/recoverSuccessToast.ts @@ -0,0 +1,4 @@ +export const recoverSuccessToast = { + body: () => cy.get("[data-testId=toast-recover-success]", { timeout: 10000 }), + closeButton: () => cy.get("[data-testid=button-close-toast-recover-success]") +} diff --git a/packages/files-ui/cypress/tests/file-management-spec.ts b/packages/files-ui/cypress/tests/file-management-spec.ts index 67025b40c9..24ebd14914 100644 --- a/packages/files-ui/cypress/tests/file-management-spec.ts +++ b/packages/files-ui/cypress/tests/file-management-spec.ts @@ -11,6 +11,7 @@ import { moveItemModal } from "../support/page-objects/modals/moveItemModal" import { recoverItemModal } from "../support/page-objects/modals/recoverItemModal" import { deleteSuccessToast } from "../support/page-objects/toasts/deleteSuccessToast" import { moveSuccessToast } from "../support/page-objects/toasts/moveSuccessToast" +import { recoverSuccessToast } from "../support/page-objects/toasts/recoverSuccessToast" import { uploadCompleteToast } from "../support/page-objects/toasts/uploadCompleteToast" describe("File management", () => { @@ -89,12 +90,16 @@ describe("File management", () => { // ensure the home root now has the folder and file navigationMenu.homeNavButton().click() - homePage.fileItemRow().should("have.length", 2) + homePage.fileItemRow() + .should("be.visible") + .should("have.length", 2) homePage.fileItemName().should("contain.text", folderName) homePage.fileItemName().should("contain.text", $fileName) - // ensure folder already in the root cannot be moved to Home - homePage.fileItemName().contains(`${$fileName}`).click() + // ensure file already in the root cannot be moved to Home + homePage.fileItemName().contains(`${$fileName}`) + .should("be.visible") + .click() homePage.moveSelectedButton().click() moveItemModal.folderList().contains("Home").click() moveItemModal.errorLabel().should("be.visible") @@ -112,8 +117,10 @@ describe("File management", () => { // select a parent folder and initiate move action homePage.fileItemName().contains("Parent").click() homePage.moveSelectedButton().click() + moveItemModal.body().should("be.visible") // ensure folder already in the root cannot be moved to Home + moveItemModal.folderList().should("be.visible") moveItemModal.folderList().contains("Home").click() moveItemModal.body().should("be.visible") moveItemModal.errorLabel().should("be.visible") @@ -259,6 +266,8 @@ describe("File management", () => { recoverItemModal.folderList().contains("Home").click() recoverItemModal.recoverButton().safeClick() binPage.fileItemRow().should("not.exist") + recoverSuccessToast.body().should("be.visible") + recoverSuccessToast.closeButton().click() // ensure recovered file is correct navigationMenu.homeNavButton().click() diff --git a/packages/files-ui/cypress/tests/file-preview-spec.ts b/packages/files-ui/cypress/tests/file-preview-spec.ts index d20d5b53bf..ffe19a8ba7 100644 --- a/packages/files-ui/cypress/tests/file-preview-spec.ts +++ b/packages/files-ui/cypress/tests/file-preview-spec.ts @@ -11,6 +11,7 @@ describe("File Preview", () => { // add files homePage.uploadFile("../fixtures/uploadedFiles/logo.png") homePage.uploadFile("../fixtures/uploadedFiles/text-file.txt") + homePage.fileItemRow().should("have.length", 2) // store their file names as cypress aliases for later comparison homePage.fileItemName().eq(0).invoke("text").as("fileNameA") @@ -72,13 +73,22 @@ describe("File Preview", () => { homePage.fileItemName().dblclick() previewModal.unsupportedFileLabel().should("exist") previewModal.downloadUnsupportedFileButton().should("be.visible") + // ensure that the file download does not start until the download button is clicked + cy.get("@downloadRequest").then(($request) => { + // retrieving the alias (spy) should yield null because posts should not have been made yet + expect($request).to.be.null + }) + + // begin the file download + previewModal.downloadUnsupportedFileButton().click() + // ensure the download request contains the correct file - cy.get("@downloadRequest").its("request.body").should("contain", { + cy.wait("@downloadRequest").its("request.body").should("contain", { path: "/file.zip" }) }) - // return to the home and ensure preview menu option is not shown for unsupported file + // return to home, ensure the preview menu option is not shown for an unsupported file previewModal.closeButton().click() homePage.fileItemKebabButton().click() homePage.previewMenuOption().should("not.exist") diff --git a/packages/files-ui/cypress/tests/survey-banner-spec.ts b/packages/files-ui/cypress/tests/survey-banner-spec.ts new file mode 100644 index 0000000000..ba13369114 --- /dev/null +++ b/packages/files-ui/cypress/tests/survey-banner-spec.ts @@ -0,0 +1,72 @@ +import { profileCreatedDate } from "../fixtures/filesTestData" +import { homePage } from "../support/page-objects/homePage" + +describe("Survey Banner", () => { + + context("desktop", () => { + + it("User can view and dismiss the survey banner", () => { + // intercept and stub the account creation date to be > 7 days + cy.intercept("GET", "https://stage.imploy.site/api/v1/user/profile", (req) => { + req.on("response", (res) => { + res.body.created_at = profileCreatedDate + }) + }) + + // intercept and stub the response to ensure the banner is displayed + cy.intercept("GET", "https://stage.imploy.site/api/v1/user/store", { + body: [{ "csf.dismissedSurveyBannerV3": "false" }] + }) + + cy.web3Login() + homePage.surveyBanner().should("be.visible") + + // set up a spy for the POST response + cy.intercept("POST", "https://stage.imploy.site/api/v1/user/store").as("storePost").then(() => { + + // dismiss the survey banner + homePage.closeBannerButton().click() + homePage.surveyBanner().should("not.exist") + + // intercept POST to ensure the key was updated after the banner is dismissed + cy.wait("@storePost").its("request.body").should("contain", { + "csf.dismissedSurveyBannerV3": "true" + }) + }) + }) + + it("User should not see the survey banner if previously dismissed", () => { + cy.intercept("GET", "https://stage.imploy.site/api/v1/user/store", { + body: [{ "csf.dismissedSurveyBannerV3": "true" }] + }) + + cy.web3Login() + homePage.surveyBanner().should("not.exist") + }) + + it("User should see banner if account age is greater than 7 days and api response is empty", () => { + cy.intercept("GET", "https://stage.imploy.site/api/v1/user/store", { + body: [{}] + }) + + cy.web3Login() + homePage.surveyBanner().should("be.visible") + }) + + it("User should not see banner if account age is less than 7 days and api response is empty", () => { + // intercept and stub the account creation date to make it less than 7 days + cy.intercept("GET", "https://stage.imploy.site/api/v1/user/profile", (req) => { + req.on("response", (res) => { + res.body.created_at = res.body.updated_at + }) + }) + + cy.intercept("GET", "https://stage.imploy.site/api/v1/user/store", { + body: [{}] + }) + + cy.web3Login() + homePage.surveyBanner().should("not.exist") + }) + }) +}) diff --git a/packages/files-ui/package.json b/packages/files-ui/package.json index 28ef7dc032..47de55c414 100644 --- a/packages/files-ui/package.json +++ b/packages/files-ui/package.json @@ -6,7 +6,7 @@ "@babel/core": "^7.12.10", "@babel/runtime": "^7.0.0", "@chainsafe/browser-storage-hooks": "^1.0.1", - "@chainsafe/files-api-client": "^1.18.14", + "@chainsafe/files-api-client": "1.18.15", "@chainsafe/web3-context": "1.1.4", "@lingui/core": "^3.7.2", "@lingui/react": "^3.7.2", @@ -33,6 +33,7 @@ "formik": "^2.2.5", "jsrsasign": "^10.4.1", "key-encoder": "^2.0.3", + "heic-convert": "^1.2.4", "mime-matcher": "^1.0.5", "posthog-js": "^1.13.10", "react": "^16.14.0", @@ -80,7 +81,7 @@ "scripts": { "postinstall": "yarn compile", "start": "yarn compile && craco --max_old_space_size=4096 start", - "build": "craco --max_old_space_size=4096 build", + "build": "craco --max_old_space_size=4096 --openssl-legacy-provider build ", "sentry": "(export REACT_APP_SENTRY_RELEASE=$(sentry-cli releases propose-version); node scripts/sentry.js)", "release": "(export REACT_APP_SENTRY_RELEASE=$(sentry-cli releases propose-version); yarn compile && yarn build && node scripts/sentry.js)", "test": "cypress open", diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/BinFileBrowser.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/BinFileBrowser.tsx index 516c3a6e19..ffc630d104 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/BinFileBrowser.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/BinFileBrowser.tsx @@ -93,7 +93,8 @@ const BinFileBrowser: React.FC = ({ controls = false }: ).then(() => { addToast({ title: t`Data restored successfully`, - type: "success" + type: "success", + testId: "recover-success" }) }).catch((error) => { console.error("Error recovering:", error) diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/CSFFileBrowser.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/CSFFileBrowser.tsx index 0627a1663e..37c0e02aa3 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/CSFFileBrowser.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/CSFFileBrowser.tsx @@ -34,6 +34,8 @@ const CSFFileBrowser: React.FC = () => { const { pathname } = useLocation() const currentPath = useMemo(() => extractFileBrowserPathFromURL(pathname, ROUTE_LINKS.Drive("")), [pathname]) const bucket = useMemo(() => buckets.find(b => b.type === "csf"), [buckets]) + const { profile, localStore } = useUser() + const [showSurvey, setShowSurvey] = useState(false) const refreshContents = useCallback((showLoading?: boolean) => { if (!bucket) return @@ -50,10 +52,6 @@ const CSFFileBrowser: React.FC = () => { }).finally(() => showLoading && setLoadingCurrentPath(false)) }, [bucket, filesApiClient, currentPath]) - const { profile, localStore, setLocalStore } = useUser() - - const showSurvey = localStore && localStore[DISMISSED_SURVEY_KEY] === "false" - const olderThanOneWeek = useMemo( () => profile?.createdAt ? dayjs(Date.now()).diff(profile.createdAt, "day") > 7 @@ -62,11 +60,14 @@ const CSFFileBrowser: React.FC = () => { ) useEffect(() => { - const dismissedFlag = localStore && localStore[DISMISSED_SURVEY_KEY] - if (dismissedFlag === undefined || dismissedFlag === null) { - setLocalStore({ [DISMISSED_SURVEY_KEY]: "false" }, "update") + if (!localStore) { + return + } + + if (localStore[DISMISSED_SURVEY_KEY] === "false"){ + setShowSurvey(true) } - }, [localStore, setLocalStore]) + }, [localStore]) useEffect(() => { refreshContents(true) diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/CreateFolderModal.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/CreateFolderModal.tsx index d23fcd5d2e..5ab03207c5 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/CreateFolderModal.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/CreateFolderModal.tsx @@ -99,12 +99,12 @@ const CreateFolderModal = ({ modalOpen, close }: ICreateFolderModalProps) => { setCreatingFolder(false) helpers.resetForm() onCancel() - } catch (errors: any) { + } catch (error: any) { setCreatingFolder(false) - if (errors[0].message.includes("Entry with such name can")) { + if (error?.error?.code === 409) { helpers.setFieldError("name", t`Folder name is already in use`) } else { - helpers.setFieldError("name", errors[0].message) + helpers.setFieldError("name", t`There was an error creating the folder ${error?.message}`) } helpers.setSubmitting(false) } diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/SearchFileBrowser.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/SearchFileBrowser.tsx index 3fc8cd8c90..392ecc47e3 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/SearchFileBrowser.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/SearchFileBrowser.tsx @@ -84,7 +84,7 @@ const SearchFileBrowser: React.FC = ({ controls = false const getPath = useCallback((cid: string): string => { const searchEntry = getSearchEntry(cid) // Set like this as look ups should always be using available cids - return searchEntry ? searchEntry.path : "" + return searchEntry ? searchEntry.path.replace(searchEntry.content.name, "") : "" }, [getSearchEntry]) const pathContents: FileSystemItem[] = useMemo(() => diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFoldersOverview.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFoldersOverview.tsx index 6e2d473f88..2bc948f9dd 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFoldersOverview.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFoldersOverview.tsx @@ -268,7 +268,7 @@ const SharedFolderOverview = () => { )} { }) refreshContents && refreshContents() helpers.resetForm() - } catch (errors: any) { - if (errors[0].message.includes("conflict with existing")) { - helpers.setFieldError("files", "File/Folder exists") - } else { - helpers.setFieldError("files", errors[0].message) - } + } catch (error: any) { + console.error(error) } helpers.setSubmitting(false) }, [close, currentPath, uploadFiles, refreshContents, bucket]) diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/hooks/useGetFile.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/hooks/useGetFile.tsx index 83890133eb..4f3b9363de 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/hooks/useGetFile.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/hooks/useGetFile.tsx @@ -40,7 +40,6 @@ export const useGetFile = () => { setError("") try { - const content = await getFileContent( id, { @@ -69,8 +68,6 @@ export const useGetFile = () => { setError(t`There was an error getting the preview.`) } } - - }, [bucket, getFileContent]) return { getFile, isDownloading, error, downloadProgress } diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/hooks/useSharingExplainerModalFlag.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/hooks/useSharingExplainerModalFlag.tsx index 99d4ea335f..964eb36a3d 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/hooks/useSharingExplainerModalFlag.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/hooks/useSharingExplainerModalFlag.tsx @@ -6,22 +6,20 @@ export const DISMISSED_SHARING_EXPLAINER_KEY = "csf.dismissedSharingExplainer" export const useSharingExplainerModalFlag = () => { const { localStore, setLocalStore } = useUser() - const [hasSeenSharingExplainerModal, setHasSeenSharingExplainerModal] = useState(false) - const dismissedFlag = localStore ? localStore[DISMISSED_SHARING_EXPLAINER_KEY] : null - + const [hasSeenSharingExplainerModal, setHasSeenSharingExplainerModal] = useState(true) useEffect(() => { - if (dismissedFlag === "false"){ - setHasSeenSharingExplainerModal(true) - } else if (dismissedFlag === null) { - // the dismiss flag was never set - setLocalStore({ [DISMISSED_SHARING_EXPLAINER_KEY]: "false" }, "update") - setHasSeenSharingExplainerModal(true) + if (!localStore) { + return + } + + if (localStore[DISMISSED_SHARING_EXPLAINER_KEY] === "false"){ + setHasSeenSharingExplainerModal(false) } - }, [dismissedFlag, setLocalStore]) + }, [localStore, setLocalStore]) const hideModal = useCallback(() => { setLocalStore({ [DISMISSED_SHARING_EXPLAINER_KEY]: "true" }, "update") - setHasSeenSharingExplainerModal(false) + setHasSeenSharingExplainerModal(true) }, [setLocalStore]) return { hasSeenSharingExplainerModal, hideModal } diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/views/FilesList.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/views/FilesList.tsx index eb5f982beb..e2588b2091 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/views/FilesList.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/views/FilesList.tsx @@ -43,7 +43,6 @@ import { CONTENT_TYPES } from "../../../../Utils/Constants" import { CSFTheme } from "../../../../Themes/types" import MimeMatcher from "../../../../Utils/MimeMatcher" import { useLanguageContext } from "../../../../Contexts/LanguageContext" -import { getPathWithFile } from "../../../../Utils/pathUtils" import SurveyBanner from "../../../SurveyBanner" import { DragPreviewLayer } from "./DragPreviewLayer" import { useFileBrowser } from "../../../../Contexts/FileBrowserContext" @@ -348,7 +347,7 @@ const FilesList = ({ isShared = false }: Props) => { const { hasSeenSharingExplainerModal, hideModal } = useSharingExplainerModalFlag() const [hasClickedShare, setClickedShare] = useState(false) const showExplainerBeforeShare = useMemo(() => - hasSeenSharingExplainerModal && hasClickedShare + !hasSeenSharingExplainerModal && hasClickedShare , [hasClickedShare, hasSeenSharingExplainerModal] ) const items: FileSystemItemType[] = useMemo(() => { @@ -616,9 +615,10 @@ const FilesList = ({ isShared = false }: Props) => { setIsDeleteModalOpen(true) }, []) - const handleOpenShareDialog = useCallback((e: React.MouseEvent) => { - e.preventDefault() - e.stopPropagation() + const handleOpenShareDialog = useCallback((e?: React.MouseEvent) => { + e?.preventDefault() + e?.stopPropagation() + setClickedShare(true) setIsShareModalOpen(true) }, []) @@ -649,13 +649,9 @@ const FilesList = ({ isShared = false }: Props) => { [classes.menuIcon]) const onShare = useCallback((fileSystemItem: FileSystemItemType) => { - if(hasSeenSharingExplainerModal) { - setClickedShare(true) - } - setSelectedItems([fileSystemItem]) - setIsShareModalOpen(true) - }, [hasSeenSharingExplainerModal]) + handleOpenShareDialog() + }, [handleOpenShareDialog]) return (
{ closePreview={closePreview} nextFile={fileIndex < files.length - 1 ? setNextPreview : undefined} previousFile={fileIndex > 0 ? setPreviousPreview : undefined} - filePath={isSearch && getPath ? getPath(files[fileIndex].cid) : getPathWithFile(currentPath, files[fileIndex].name)} + filePath={isSearch && getPath ? getPath(files[fileIndex].cid) : currentPath} /> )} { filePath && isReportFileModalOpen && diff --git a/packages/files-ui/src/Components/Modules/FilePreviewModal.tsx b/packages/files-ui/src/Components/Modules/FilePreviewModal.tsx index cf8fac1a96..708a6c1493 100644 --- a/packages/files-ui/src/Components/Modules/FilePreviewModal.tsx +++ b/packages/files-ui/src/Components/Modules/FilePreviewModal.tsx @@ -27,9 +27,11 @@ import { useFileBrowser } from "../../Contexts/FileBrowserContext" import { useGetFile } from "./FileBrowsers/hooks/useGetFile" import { useMemo } from "react" import Menu from "../../UI-components/Menu" +import { getPathWithFile } from "../../Utils/pathUtils" export interface IPreviewRendererProps { contents: Blob + contentType?: string } const SUPPORTED_FILE_TYPES: Record> = { @@ -196,6 +198,13 @@ const FilePreviewModal = ({ file, nextFile, previousFile, closePreview, filePath delta: 20 }) + const previewRendererKey = useMemo(() => content_type && + Object.keys(SUPPORTED_FILE_TYPES).find((type) => { + const matcher = new MimeMatcher(type) + + return matcher.match(content_type) + }), [content_type]) + useEffect(() => { let bucketId // Handle preview in Search where a Bucket is not available, but can be assumed to be a `CSF` bucket @@ -205,24 +214,24 @@ const FilePreviewModal = ({ file, nextFile, previousFile, closePreview, filePath } else { bucketId = bucket.id } - getFile({ file, filePath, bucketId }) - .then(setFileContent) - .catch(console.error) - }, [file, filePath, getFile, bucket, buckets]) - const validRendererMimeType = - content_type && - Object.keys(SUPPORTED_FILE_TYPES).find((type) => { - const matcher = new MimeMatcher(type) + if (previewRendererKey) { + setFileContent(undefined) + getFile({ file, filePath: getPathWithFile(filePath, file.name), bucketId }) + .then((content) => { + setFileContent(content) + }) + .catch(console.error) + } + }, [file, filePath, getFile, bucket, buckets, previewRendererKey]) + - return matcher.match(content_type) - }) const PreviewComponent = - content_type && - fileContent && - validRendererMimeType && - SUPPORTED_FILE_TYPES[validRendererMimeType] + !!content_type && + !!fileContent && + !!previewRendererKey && + SUPPORTED_FILE_TYPES[previewRendererKey] useHotkeys("Esc,Escape", () => { if (file) { @@ -231,15 +240,11 @@ const FilePreviewModal = ({ file, nextFile, previousFile, closePreview, filePath }) useHotkeys("Left,ArrowLeft", () => { - if (file && previousFile) { - previousFile() - } + previousFile && previousFile() }) useHotkeys("Right,ArrowRight", () => { - if (file && nextFile) { - nextFile() - } + nextFile && nextFile() }) const handleDownload = useCallback(() => { @@ -389,7 +394,11 @@ const FilePreviewModal = ({ file, nextFile, previousFile, closePreview, filePath !error && compatibleFilesMatcher.match(content_type) && fileContent && - PreviewComponent && } + PreviewComponent && + + } {desktop && ( diff --git a/packages/files-ui/src/Components/Modules/LoginModule/InitialScreen.tsx b/packages/files-ui/src/Components/Modules/LoginModule/InitialScreen.tsx index 5e2c27b009..3dc697007d 100644 --- a/packages/files-ui/src/Components/Modules/LoginModule/InitialScreen.tsx +++ b/packages/files-ui/src/Components/Modules/LoginModule/InitialScreen.tsx @@ -208,27 +208,23 @@ const InitialScreen = ({ className }: IInitialScreen) => { setLoginMode(loginType) try { await login(loginType) - } catch (error) { + } catch (error: any) { let errorMessage = t`There was an error authenticating` - console.log(error) - if (Array.isArray(error) && error[0]) { - if ( - error[0].type === "signature" && - error[0].message === "Invalid signature" - ) { - errorMessage = t`Failed to validate signature. + // Invalid signature, or contract wallet not deployed + if (error?.error?.code === 403 && error?.error?.message?.includes("Invalid signature")) { + errorMessage = t`Failed to validate signature. If you are using a contract wallet, please make sure you have activated your wallet.` - } } - // WalletConnect be sassy - if ((error instanceof Error && error.message === "Just nope") || ((error as any).code === 4001)) { + // User rejected the signature request (WalletConnect be sassy) + if (error?.message === "Just nope" || error?.code === 4001) { errorMessage = t`Failed to get signature` } - if (error instanceof Error && error?.message === "user closed popup") { + // DirectAuth popup was closed + if (error?.message === "user closed popup") { errorMessage = t`The authentication popup was closed` } diff --git a/packages/files-ui/src/Components/Modules/PreviewRenderers/ImagePreview.tsx b/packages/files-ui/src/Components/Modules/PreviewRenderers/ImagePreview.tsx index 997a693218..a2217961b1 100644 --- a/packages/files-ui/src/Components/Modules/PreviewRenderers/ImagePreview.tsx +++ b/packages/files-ui/src/Components/Modules/PreviewRenderers/ImagePreview.tsx @@ -1,6 +1,8 @@ import React, { useEffect, useState } from "react" import { IPreviewRendererProps } from "../FilePreviewModal" import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch" +import heicConvert from "heic-convert" + import { makeStyles, ITheme, @@ -11,7 +13,8 @@ import { Button, ZoomInIcon, ZoomOutIcon, - FullscreenIcon + FullscreenIcon, + Loading } from "@chainsafe/common-components" const useStyles = makeStyles( @@ -41,67 +44,82 @@ const useStyles = makeStyles( }) ) -const ImagePreview: React.FC = ({ contents }) => { +const ImagePreview: React.FC = ({ contents, contentType }) => { const [imageUrl, setImageUrl] = useState() - + const [loading, setLoading] = useState(false) useEffect(() => { - setImageUrl(URL.createObjectURL(contents)) - - return () => { - imageUrl && URL.revokeObjectURL(imageUrl) + if (contentType !== "image/heic") { + setImageUrl(URL.createObjectURL(contents)) + } else { + setLoading(true) + contents.arrayBuffer() + .then(b => heicConvert({ + buffer: Buffer.from(b), + format: "JPEG", + quality: 0.5 + })) + .catch(console.error) + .then(c => setImageUrl(URL.createObjectURL(new Blob([c])))) + .finally(() => setLoading(false)) } - // eslint-disable-next-line - }, [contents]) + }, [contents, contentType]) + const classes = useStyles() const { desktop } = useThemeSwitcher() return (
- - { + {loading + ? + : + { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - ({ zoomIn, zoomOut, resetTransform }) => ( - <> - {desktop && ( -
- - - -
- )} - - - - - ) - } -
+ ({ zoomIn, zoomOut, resetTransform }) => ( + <> + {desktop && ( +
+ + + +
+ )} + + imageUrl && URL.revokeObjectURL(imageUrl)} /> + + + ) + } +
+ }
) } diff --git a/packages/files-ui/src/Components/SharingExplainerModal.tsx b/packages/files-ui/src/Components/SharingExplainerModal.tsx index 4061e965dd..d6ae80a5b8 100644 --- a/packages/files-ui/src/Components/SharingExplainerModal.tsx +++ b/packages/files-ui/src/Components/SharingExplainerModal.tsx @@ -132,9 +132,9 @@ const SharingExplainerModal = ({ showModal, onHide }: Props) => { return } else { switch (next) { - case 3: + case STEP_NUMBER: setLocalStore({ [DISMISSED_SHARING_EXPLAINER_KEY]: "true" }, "update") - setStep(3) + setStep(STEP_NUMBER) break case STEP_NUMBER + 1: onHide() diff --git a/packages/files-ui/src/Components/SurveyBanner.tsx b/packages/files-ui/src/Components/SurveyBanner.tsx index 8a08f3a066..07ec39da8b 100644 --- a/packages/files-ui/src/Components/SurveyBanner.tsx +++ b/packages/files-ui/src/Components/SurveyBanner.tsx @@ -62,13 +62,16 @@ const SurveyBanner = ({ onHide }: Props) => { setLocalStore({ [DISMISSED_SURVEY_KEY]: "true" }, "update") }, [setLocalStore, onHide]) - const onOpen = useCallback(() => { + const onOpenLink = useCallback(() => { onClose() window.open(ROUTE_LINKS.UserSurvey, "_blank") }, [onClose]) return ( -
+
@@ -77,7 +80,7 @@ const SurveyBanner = ({ onHide }: Props) => { Schedule a 15 min call @@ -85,6 +88,7 @@ const SurveyBanner = ({ onHide }: Props) => {
{ setUploadsInProgress(false) // setting error let errorMessage = t`Something went wrong. We couldn't upload your file` - // uploads cancelled through button if (axios.isCancel(error)) { errorMessage = t`Uploads cancelled` } // we will need a method to parse server errors - if (Array.isArray(error) && error[0].message.includes("conflict")) { + if (error?.error?.code === 409) { errorMessage = t`A file with the same name already exists` } updateToast(toastId, { @@ -663,7 +662,7 @@ const FilesProvider = ({ children }: FilesContextProps) => { return Promise.resolve() } catch (error: any) { console.error(error) - let errorMessage = `${t`An error occurred: `} ${typeof(error) === "string" ? error : error.length ? error[0].message : ""}` + let errorMessage = `${t`An error occurred: `} ${typeof(error) === "string" ? error : error.error.message ? error.error.message : ""}` if (axios.isCancel(error)) { errorMessage = t`Downloads cancelled` } @@ -868,6 +867,8 @@ const FilesProvider = ({ children }: FilesContextProps) => { } }).catch((error) => { console.error(error) + }).finally(() => { + refreshBuckets() }) }, [getFileContent, encryptAndUploadFiles, filesApiClient, refreshBuckets, addToast, updateToast, getFileList]) diff --git a/packages/files-ui/src/Contexts/UserContext.tsx b/packages/files-ui/src/Contexts/UserContext.tsx index 3250078193..058edf38ce 100644 --- a/packages/files-ui/src/Contexts/UserContext.tsx +++ b/packages/files-ui/src/Contexts/UserContext.tsx @@ -3,6 +3,9 @@ import { useCallback, useEffect } from "react" import { useFilesApi } from "./FilesApiContext" import { useState } from "react" import { t } from "@lingui/macro" +import { DISMISSED_SHARING_EXPLAINER_KEY } from "../Components/Modules/FileBrowsers/hooks/useSharingExplainerModalFlag" +import { DISMISSED_SURVEY_KEY } from "../Components/SurveyBanner" +import { Details } from "@chainsafe/files-api-client" type UserContextProps = { children: React.ReactNode | React.ReactNode[] @@ -43,23 +46,20 @@ const UserContext = React.createContext(undefined) const UserProvider = ({ children }: UserContextProps) => { const { filesApiClient, isLoggedIn } = useFilesApi() - const [profile, setProfile] = useState(undefined) const [localStore, _setLocalStore] = useState() const setLocalStore = useCallback((newData: ILocalStore, method: "update" | "overwrite" = "update") => { - switch (method) { - case "update": - _setLocalStore({ - ...localStore, - ...newData - }) - break - case "overwrite": - _setLocalStore(newData) - break - } - }, [localStore]) + + const toStore = method === "update" + ? { ...localStore, ...newData } + : newData + + filesApiClient.updateUserLocalStore(toStore) + .then(_setLocalStore) + .catch(console.error) + + }, [filesApiClient, localStore]) const refreshProfile = useCallback(async () => { try { @@ -77,40 +77,48 @@ const UserProvider = ({ children }: UserContextProps) => { setProfile(profileState) return Promise.resolve() } catch (error) { + console.error(error) return Promise.reject("There was an error getting profile.") } }, [filesApiClient]) - useEffect(() => { - const manageAsync = async () => { - if (!localStore) { - // Fetch - try { - const fetched = await filesApiClient.getUserLocalStore() - if (!fetched) { - _setLocalStore({}) - } else { - _setLocalStore(fetched) - } - } catch(error) { - console.error(error) - _setLocalStore({}) - } - } else { - // Store - await filesApiClient.updateUserLocalStore(localStore) - } + const initLocalStore = useCallback((apiStore: ILocalStore | undefined) => { + let initStore = apiStore || {} + + if (apiStore?.[DISMISSED_SHARING_EXPLAINER_KEY] === undefined) { + initStore = { ...initStore, [DISMISSED_SHARING_EXPLAINER_KEY]: "false" } } - if (isLoggedIn) { - manageAsync() + + if (apiStore?.[DISMISSED_SURVEY_KEY] === undefined) { + initStore = { ...initStore, [DISMISSED_SURVEY_KEY]: "false" } } - }, [isLoggedIn, localStore, filesApiClient]) + + _setLocalStore(initStore) + }, []) useEffect(() => { - if (isLoggedIn) { - refreshProfile() - .catch(console.error) + if (!isLoggedIn) { + return } + + filesApiClient.getUserLocalStore() + .then((apiStore) => { + initLocalStore(apiStore) + }) + .catch((e) => { + console.error(e) + initLocalStore({}) + }) + }, [isLoggedIn, filesApiClient, initLocalStore]) + + useEffect(() => { + if (!isLoggedIn) { + return + } + + refreshProfile() + .catch(console.error) + }, [isLoggedIn, refreshProfile]) const updateProfile = async (firstName?: string, lastName?: string) => { @@ -133,10 +141,11 @@ const UserProvider = ({ children }: UserContextProps) => { }) return Promise.resolve() } catch (error: any) { + console.error(error) return Promise.reject( - Array.isArray(error) && error[0] - ? error[0].message - : "There was an error updating profile." + Array.isArray(error.error.details) + ? error.error.details.map((e: Details) => e.message).join(",") + : t`There was an error when setting username.` ) } } @@ -160,9 +169,10 @@ const UserProvider = ({ children }: UserContextProps) => { }) return Promise.resolve() } catch (error: any) { + console.error(error) return Promise.reject( - Array.isArray(error) && error[0] - ? error[0].message + Array.isArray(error.error.details) + ? error.error.details.map((e: Details) => e.message).join(",") : t`There was an error when setting username.` ) } diff --git a/packages/files-ui/src/Utils/contentTypeGuesser.ts b/packages/files-ui/src/Utils/contentTypeGuesser.ts index ae7b19cdd3..49ccbe92f7 100644 --- a/packages/files-ui/src/Utils/contentTypeGuesser.ts +++ b/packages/files-ui/src/Utils/contentTypeGuesser.ts @@ -1,7 +1,7 @@ const guessContentType = (fileName: string) => { const { length, [length - 1]: ext } = fileName.split(".") - switch (ext) { + switch (ext.toLowerCase()) { case "pdf": return "application/pdf" case "jpg": @@ -9,7 +9,8 @@ const guessContentType = (fileName: string) => { case "png": case "gif": case "bmp": - return `image/${ext}` + case "heic": + return `image/${ext.toLowerCase()}` case "mp3": case "m4a": return `audio/${ext}` diff --git a/packages/files-ui/src/locales/de/messages.po b/packages/files-ui/src/locales/de/messages.po index c43be37da0..e05e0f362d 100644 --- a/packages/files-ui/src/locales/de/messages.po +++ b/packages/files-ui/src/locales/de/messages.po @@ -155,7 +155,7 @@ msgid "Create" msgstr "Erstellen" msgid "Create Folder" -msgstr "Ordner erstellen" +msgstr "" msgid "Create Shared Folder" msgstr "" @@ -458,7 +458,7 @@ msgid "Number of copies (Replication Factor)" msgstr "Anzahl der Kopien (Replikationsfaktor)" msgid "OK" -msgstr "OK" +msgstr "" msgid "One sec, getting files ready…" msgstr "Eine Sekunde, die Dateien werden vorbereitet …" @@ -733,6 +733,9 @@ msgstr "Es gab einen Fehler bei der Authentifizierung" msgid "There was an error connecting your wallet" msgstr "" +msgid "There was an error creating the folder {0}" +msgstr "" + msgid "There was an error deleting your data" msgstr "" diff --git a/packages/files-ui/src/locales/en/messages.po b/packages/files-ui/src/locales/en/messages.po index 965d382ceb..04a0eccd69 100644 --- a/packages/files-ui/src/locales/en/messages.po +++ b/packages/files-ui/src/locales/en/messages.po @@ -736,6 +736,9 @@ msgstr "There was an error authenticating" msgid "There was an error connecting your wallet" msgstr "There was an error connecting your wallet" +msgid "There was an error creating the folder {0}" +msgstr "There was an error creating the folder {0}" + msgid "There was an error deleting your data" msgstr "There was an error deleting your data" diff --git a/packages/files-ui/src/locales/es/messages.po b/packages/files-ui/src/locales/es/messages.po index 4c08b1acd4..98cde9765d 100644 --- a/packages/files-ui/src/locales/es/messages.po +++ b/packages/files-ui/src/locales/es/messages.po @@ -156,7 +156,7 @@ msgid "Create" msgstr "Crear" msgid "Create Folder" -msgstr "Crear Carpeta" +msgstr "" msgid "Create Shared Folder" msgstr "" @@ -462,7 +462,7 @@ msgid "Number of copies (Replication Factor)" msgstr "Número de copias (factor de replicación)" msgid "OK" -msgstr "OK" +msgstr "" msgid "One sec, getting files ready…" msgstr "" @@ -737,6 +737,9 @@ msgstr "Hubo un error de autenticación." msgid "There was an error connecting your wallet" msgstr "Hubo un error al conectar su billetera" +msgid "There was an error creating the folder {0}" +msgstr "" + msgid "There was an error deleting your data" msgstr "" diff --git a/packages/files-ui/src/locales/fr/messages.po b/packages/files-ui/src/locales/fr/messages.po index d339172c59..c271d9b08a 100644 --- a/packages/files-ui/src/locales/fr/messages.po +++ b/packages/files-ui/src/locales/fr/messages.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-04-23 11:05+0200\n" -"PO-Revision-Date: 2021-10-09 17:23+0000\n" +"PO-Revision-Date: 2021-10-20 00:49+0000\n" "Last-Translator: J. Lavoie \n" "Language-Team: French \n" "Language: fr\n" @@ -737,6 +737,9 @@ msgstr "Une erreur s’est produite lors de l’authentification" msgid "There was an error connecting your wallet" msgstr "Une erreur s’est produite lors de la connexion de votre wallet" +msgid "There was an error creating the folder {0}" +msgstr "Il y a eu une erreur lors de la création du dossier {0}" + msgid "There was an error deleting your data" msgstr "Une erreur s'est produite lors de la suppression de vos données" diff --git a/packages/files-ui/src/locales/no/messages.po b/packages/files-ui/src/locales/no/messages.po index 4de081cbdd..d2f340a862 100644 --- a/packages/files-ui/src/locales/no/messages.po +++ b/packages/files-ui/src/locales/no/messages.po @@ -155,7 +155,7 @@ msgid "Create" msgstr "Opprett" msgid "Create Folder" -msgstr "Opprett mappe" +msgstr "" msgid "Create Shared Folder" msgstr "" @@ -458,7 +458,7 @@ msgid "Number of copies (Replication Factor)" msgstr "" msgid "OK" -msgstr "OK" +msgstr "" msgid "One sec, getting files ready…" msgstr "" @@ -733,6 +733,9 @@ msgstr "" msgid "There was an error connecting your wallet" msgstr "" +msgid "There was an error creating the folder {0}" +msgstr "" + msgid "There was an error deleting your data" msgstr "" diff --git a/packages/files-ui/src/types.d.ts b/packages/files-ui/src/types.d.ts new file mode 100644 index 0000000000..86a0e1233b --- /dev/null +++ b/packages/files-ui/src/types.d.ts @@ -0,0 +1 @@ +declare module "heic-convert"; \ No newline at end of file diff --git a/packages/gaming-ui/package.json b/packages/gaming-ui/package.json index 8e8d741a72..275518b256 100644 --- a/packages/gaming-ui/package.json +++ b/packages/gaming-ui/package.json @@ -6,7 +6,7 @@ "@babel/core": "^7.12.10", "@babel/runtime": "^7.0.0", "@chainsafe/browser-storage-hooks": "^1.0.1", - "@chainsafe/files-api-client": "^1.18.14", + "@chainsafe/files-api-client": "1.18.15", "@chainsafe/web3-context": "1.1.4", "@lingui/core": "^3.7.2", "@lingui/react": "^3.7.2", @@ -63,7 +63,7 @@ "scripts": { "postinstall": "yarn compile", "start": "yarn compile && craco --max_old_space_size=4096 start", - "build": "craco --max_old_space_size=4096 build", + "build": "craco --max_old_space_size=4096 --openssl-legacy-provider build ", "sentry": "(export REACT_APP_SENTRY_RELEASE=$(sentry-cli releases propose-version); node scripts/sentry.js)", "release": "(export REACT_APP_SENTRY_RELEASE=$(sentry-cli releases propose-version); yarn compile && yarn build && node scripts/sentry.js)", "test": "cypress open", diff --git a/packages/gaming-ui/src/Components/Modules/LoginModule.tsx b/packages/gaming-ui/src/Components/Modules/LoginModule.tsx index 85faf0bba4..c4268a24c0 100644 --- a/packages/gaming-ui/src/Components/Modules/LoginModule.tsx +++ b/packages/gaming-ui/src/Components/Modules/LoginModule.tsx @@ -176,21 +176,20 @@ const LoginModule = ({ className }: IInitialScreen) => { await login(loginType) } catch (error: any) { let errorMessage = t`There was an error authenticating` - console.log(error) - if (Array.isArray(error) && error[0]) { - if ( - error[0].type === "signature" && - error[0].message === "Invalid signature" - ) { - errorMessage = t`Failed to validate signature. + + // Invalid signature, or contract wallet not deployed + if (error?.error?.code === 403 && error?.error?.message?.includes("Invalid signature")) { + errorMessage = t`Failed to validate signature. If you are using a contract wallet, please make sure you have activated your wallet.` - } } - // WalletConnect be sassy + + // User rejected the signature request (WalletConnect be sassy) if (error?.message === "Just nope" || error?.code === 4001) { errorMessage = t`Failed to get signature` } + + // DirectAuth popup was closed if (error?.message === "user closed popup") { errorMessage = t`The authentication popup was closed` } diff --git a/packages/storage-ui/package.json b/packages/storage-ui/package.json index 8ca5506ca1..d55c71882d 100644 --- a/packages/storage-ui/package.json +++ b/packages/storage-ui/package.json @@ -6,7 +6,7 @@ "@babel/core": "^7.12.10", "@babel/runtime": "^7.0.0", "@chainsafe/browser-storage-hooks": "^1.0.1", - "@chainsafe/files-api-client": "^1.18.14", + "@chainsafe/files-api-client": "1.18.15", "@chainsafe/web3-context": "1.1.4", "@lingui/core": "^3.7.2", "@lingui/react": "^3.7.2", @@ -71,7 +71,7 @@ "scripts": { "postinstall": "yarn compile", "start": "yarn compile && craco --max_old_space_size=4096 start", - "build": "craco --max_old_space_size=4096 build", + "build": "craco --max_old_space_size=4096 --openssl-legacy-provider build ", "sentry": "(export REACT_APP_SENTRY_RELEASE=$(sentry-cli releases propose-version); node scripts/sentry.js)", "release": "(export REACT_APP_SENTRY_RELEASE=$(sentry-cli releases propose-version); yarn compile && yarn build && node scripts/sentry.js)", "test": "cypress open", diff --git a/packages/storage-ui/src/Components/Modules/CreateFolderModal/CreateFolderModal.tsx b/packages/storage-ui/src/Components/Modules/CreateFolderModal/CreateFolderModal.tsx index 6b245096ec..3cfadf65c8 100644 --- a/packages/storage-ui/src/Components/Modules/CreateFolderModal/CreateFolderModal.tsx +++ b/packages/storage-ui/src/Components/Modules/CreateFolderModal/CreateFolderModal.tsx @@ -110,13 +110,14 @@ const CreateFolderModal = ({ modalOpen, close }: ICreateFolderModalProps) => { setCreatingFolder(false) helpers.resetForm() close() - } catch (errors: any) { + } catch (error: any) { setCreatingFolder(false) - if (errors[0].message.includes("Entry with such name can")) { + if (error?.error?.code === 409) { helpers.setFieldError("name", t`Folder name is already in use`) } else { - helpers.setFieldError("name", errors[0].message) + helpers.setFieldError("name", t`There was an error creating the folder ${error?.message}`) } + helpers.setSubmitting(false) } helpers.setSubmitting(false) }} diff --git a/packages/storage-ui/src/Components/Modules/LoginModule.tsx b/packages/storage-ui/src/Components/Modules/LoginModule.tsx index 42bc1eb818..6cafd0cb3a 100644 --- a/packages/storage-ui/src/Components/Modules/LoginModule.tsx +++ b/packages/storage-ui/src/Components/Modules/LoginModule.tsx @@ -203,26 +203,26 @@ const LoginModule = ({ className }: IInitialScreen) => { setLoginMode(loginType) try { await login(loginType) - } catch (error) { + } catch (error: any) { let errorMessage = t`There was an error authenticating` - console.log(error) - if (Array.isArray(error) && error[0]) { - if ( - error[0].type === "signature" && - error[0].message === "Invalid signature" - ) { - errorMessage = t`Failed to validate signature. + + // Invalid signature, or contract wallet not deployed + if (error?.error?.code === 403 && error?.error?.message?.includes("Invalid signature")) { + errorMessage = t`Failed to validate signature. If you are using a contract wallet, please make sure you have activated your wallet.` - } } - // WalletConnect be sassy - if ((error instanceof Error && error.message === "Just nope") || ((error as any).code === 4001)) { + + // User rejected the signature request (WalletConnect be sassy) + if (error?.message === "Just nope" || error?.code === 4001) { errorMessage = t`Failed to get signature` } - if (error instanceof Error && error.message === "user closed popup") { + + // DirectAuth popup was closed + if (error?.message === "user closed popup") { errorMessage = t`The authentication popup was closed` } + setError(errorMessage) } setIsConnecting(false) diff --git a/packages/storage-ui/src/Components/Modules/UploadFileModal/UploadFileModal.tsx b/packages/storage-ui/src/Components/Modules/UploadFileModal/UploadFileModal.tsx index 0280a90e83..6a6a203f63 100644 --- a/packages/storage-ui/src/Components/Modules/UploadFileModal/UploadFileModal.tsx +++ b/packages/storage-ui/src/Components/Modules/UploadFileModal/UploadFileModal.tsx @@ -94,12 +94,8 @@ const UploadFileModal = ({ modalOpen, close }: IUploadFileModuleProps) => { await uploadFiles(bucket.id, values.files, currentPath) refreshContents && refreshContents() helpers.resetForm() - } catch (errors: any) { - if (errors[0].message.includes("conflict with existing")) { - helpers.setFieldError("files", t`File/Folder already exists`) - } else { - helpers.setFieldError("files", errors[0].message) - } + } catch (error: any) { + console.error(error) } helpers.setSubmitting(false) }, [close, currentPath, uploadFiles, refreshContents, bucket]) diff --git a/packages/storage-ui/src/Contexts/StorageContext.tsx b/packages/storage-ui/src/Contexts/StorageContext.tsx index 057c500387..1b64d05c54 100644 --- a/packages/storage-ui/src/Contexts/StorageContext.tsx +++ b/packages/storage-ui/src/Contexts/StorageContext.tsx @@ -248,13 +248,12 @@ const StorageProvider = ({ children }: StorageContextProps) => { }, REMOVE_UPLOAD_PROGRESS_DELAY) return Promise.resolve() - } catch (error) { - console.error(error) + } catch (error: any) { // setting error let errorMessage = t`Something went wrong. We couldn't upload your file` // we will need a method to parse server errors - if (Array.isArray(error) && error[0].message.includes("conflict")) { + if (error?.error?.code === 409) { errorMessage = t`A file with the same name already exists` } dispatchUploadsInProgress({ diff --git a/packages/storage-ui/src/locales/en/messages.po b/packages/storage-ui/src/locales/en/messages.po index 3f2656b39a..9cdeb3934e 100644 --- a/packages/storage-ui/src/locales/en/messages.po +++ b/packages/storage-ui/src/locales/en/messages.po @@ -178,9 +178,6 @@ msgstr "" msgid "File" msgstr "File" -msgid "File/Folder already exists" -msgstr "File/Folder already exists" - msgid "Folder" msgstr "Folder" @@ -361,6 +358,9 @@ msgstr "There was an error authenticating" msgid "There was an error connecting your wallet" msgstr "There was an error connecting your wallet" +msgid "There was an error creating the folder {0}" +msgstr "There was an error creating the folder {0}" + msgid "There was an error deleting this item" msgstr "There was an error deleting this item" diff --git a/yarn.lock b/yarn.lock index 023a9ef631..ab35e87884 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1925,10 +1925,10 @@ resolved "https://registry.yarnpkg.com/@chainsafe/browser-storage-hooks/-/browser-storage-hooks-1.0.1.tgz#26d32cde1999914db755a631e2643823c54959f7" integrity sha512-Q4b5gQAZnsRXKeADspd5isqfwwhhXjDk70y++YadufA6EZ3tf340oW0OVszp74KaGEw+CAYFGQR4X7bzpZ3x9Q== -"@chainsafe/files-api-client@^1.18.14": - version "1.18.14" - resolved "https://registry.yarnpkg.com/@chainsafe/files-api-client/-/files-api-client-1.18.14.tgz#5ec9aba082e884974448e395b7fbbdbfb28b68eb" - integrity sha512-4WDvVOvWxhquAzVzKyGaGqyA13ijWK0jKT5cwgS4cwPGXjPoAB95pjGe6Eo4MWN//p/dSX3qLIPAsMo2n0ZTqQ== +"@chainsafe/files-api-client@1.18.15": + version "1.18.15" + resolved "https://registry.yarnpkg.com/@chainsafe/files-api-client/-/files-api-client-1.18.15.tgz#452572eb0ecb8178617d9faa37b7866bcfeeb4ec" + integrity sha512-W7MkZnK44dV1JixPavKKppi8KVhBk60uHoaDv/zRH0WVXT5QsWjQuCLpeWv9NcytHezsOv+5AAbovnjaZFwjpA== dependencies: "@redocly/openapi-cli" "^1.0.0-beta.58" "@redocly/openapi-core" "^1.0.0-beta.58" @@ -14276,6 +14276,22 @@ he@^1.1.0, he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +heic-convert@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/heic-convert/-/heic-convert-1.2.4.tgz#605820f98ace3949a40fc7b263ee0bc573a0176b" + integrity sha512-klJHyv+BqbgKiCQvCqI9IKIvweCcohDuDl0Jphearj8+16+v8eff2piVevHqq4dW9TK0r1onTR6PKHP1I4hdbA== + dependencies: + heic-decode "^1.1.2" + jpeg-js "^0.4.1" + pngjs "^3.4.0" + +heic-decode@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/heic-decode/-/heic-decode-1.1.2.tgz#974701666432e31ed64b2263a1ece7cff5218209" + integrity sha512-UF8teegxvzQPdSTcx5frIUhitNDliz/9Pui0JFdIqVRE00spVE33DcCYtZqaLNyd4y5RP/QQWZFIc1YWVKKm2A== + dependencies: + libheif-js "^1.10.0" + hex-color-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" @@ -15996,6 +16012,11 @@ jest@24.9.0: import-local "^2.0.0" jest-cli "^24.9.0" +jpeg-js@^0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.3.tgz#6158e09f1983ad773813704be80680550eff977b" + integrity sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q== + js-levenshtein@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" @@ -16659,6 +16680,11 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +libheif-js@^1.10.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/libheif-js/-/libheif-js-1.12.0.tgz#9ad1ed16a8e6412b4d3d83565d285465a00e7305" + integrity sha512-hDs6xQ7028VOwAFwEtM0Q+B2x2NW69Jb2MhQFUbk3rUrHzz4qo5mqS8VrqNgYnSc8TiUGnR691LnO4uIfEE23w== + lines-and-columns@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" @@ -19070,7 +19096,7 @@ pn@^1.1.0: resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== -pngjs@^3.3.0: +pngjs@^3.3.0, pngjs@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==