diff --git a/.github/workflows/lingui-extract-files.yml b/.github/workflows/lingui-extract-files.yml deleted file mode 100644 index 4c4b28c631..0000000000 --- a/.github/workflows/lingui-extract-files.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Lingui extract - Files -on: - pull_request: - branches: - - "dev" - paths: - - "packages/files-ui/**/*" -jobs: - # extract any new translatable string - # and commit if there are new ones - # and if the user submitting the PR isn't weblate - extract: - name: lingui-extract - runs-on: ubuntu-latest - if: ${{ github.actor != 'weblate' }} - steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.event.pull_request.head.ref }} - ssh-key: ${{ secrets.LINGUI_GH_ACTION_COMMIT_KEY }} - - name: set user - run: | - git config --global user.name 'GitHub Actions' - git config --global user.email 'actions@github.com' - - # use node module caching - - uses: actions/cache@v2 - with: - path: '**/node_modules' - key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} - - - name: install packages - run: yarn install --immutable - - - name: lingui-extract and commit - run: | - (cd packages/files-ui && yarn extract --clean) - git add packages/files-ui/src/locales/* - if git commit -m "lingui extract"; then git push; else echo 'exiting successfully without commit'; fi diff --git a/.github/workflows/lingui-extract-storage.yml b/.github/workflows/lingui-extract-storage.yml deleted file mode 100644 index ada3fc6491..0000000000 --- a/.github/workflows/lingui-extract-storage.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Lingui extract - Storage -on: - pull_request: - branches: - - "dev" - paths: - - "packages/storage-ui/**/*" -jobs: - # extract any new translatable string - # and commit if there are new ones - # and if the user submitting the PR isn't weblate - extract: - name: lingui-extract - runs-on: ubuntu-latest - if: ${{ github.actor != 'weblate' }} - steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.event.pull_request.head.ref }} - ssh-key: ${{ secrets.LINGUI_GH_ACTION_COMMIT_KEY }} - - name: set user - run: | - git config --global user.name 'GitHub Actions' - git config --global user.email 'actions@github.com' - - # use node module caching - - uses: actions/cache@v2 - with: - path: '**/node_modules' - key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} - - - name: install packages - run: yarn install --immutable - - - name: lingui-extract and commit - if: ${{ github.actor != 'weblate' }} - run: | - (cd packages/storage-ui && yarn extract --clean) - git add packages/storage-ui/src/locales/* - if git commit -m "lingui extract"; then git push; else echo 'exiting successfully without commit'; fi diff --git a/packages/storage-ui/cypress/tests/api-keys-management.cy.ts b/packages/storage-ui/cypress/tests/api-keys-management.cy.ts index 926c978be1..39ed018ff3 100644 --- a/packages/storage-ui/cypress/tests/api-keys-management.cy.ts +++ b/packages/storage-ui/cypress/tests/api-keys-management.cy.ts @@ -21,7 +21,6 @@ describe("Main Navigation", () => { // ensure new key modal is closed and api key button is not enabled newKeyModal.secretLabel().should("not.exist") - apiKeysPage.addApiKeyButton().should("not.be.enabled") // ensure key id and status are correct in the table cy.get("@keyId").then((keyId) => { diff --git a/packages/storage-ui/src/Components/Elements/BlacklistedModeBanner.tsx b/packages/storage-ui/src/Components/Elements/BlacklistedModeBanner.tsx new file mode 100644 index 0000000000..f8041d9007 --- /dev/null +++ b/packages/storage-ui/src/Components/Elements/BlacklistedModeBanner.tsx @@ -0,0 +1,48 @@ +import { Typography, Button } from "@chainsafe/common-components" +import { createStyles, makeStyles, useThemeSwitcher } from "@chainsafe/common-theme" +import { Trans } from "@lingui/macro" +import React from "react" +import { CSSTheme } from "../../Themes/types" +import { ROUTE_LINKS } from "../StorageRoutes" + +const useStyles = makeStyles( + ({ breakpoints, constants, palette }: CSSTheme) => { + return createStyles({ + accountRestrictedNotification: { + position: "fixed", + bottom: 0, + backgroundColor: palette.additional["gray"][10], + color: palette.additional["gray"][1], + padding: `${constants.generalUnit * 2}px ${constants.generalUnit * 3}px`, + left: 0, + width: "100vw", + [breakpoints.up("md")]: { + left: `${constants.navWidth}px`, + width:`calc(100vw - ${constants.navWidth}px)`, + display: "flex", + justifyContent: "space-between", + alignItems: "center" + } + } + }) + } +) + +const BlacklistedModeBanner = () => { + const classes = useStyles() + const { desktop } = useThemeSwitcher() + + return ( +
+ + Your account has been blacklisted due to unusual activity + + +
) +} + +export default BlacklistedModeBanner \ No newline at end of file diff --git a/packages/storage-ui/src/Components/Elements/BucketRow.tsx b/packages/storage-ui/src/Components/Elements/BucketRow.tsx index ae341621c9..0b219c9286 100644 --- a/packages/storage-ui/src/Components/Elements/BucketRow.tsx +++ b/packages/storage-ui/src/Components/Elements/BucketRow.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useMemo, useRef, useState, useCallback } from "react" -import { makeStyles, createStyles, useOnClickOutside } from "@chainsafe/common-theme" +import { makeStyles, createStyles, useOnClickOutside, useThemeSwitcher } from "@chainsafe/common-theme" import { + CopyIcon, DeleteSvg, EditSvg, formatBytes, @@ -12,7 +13,8 @@ import { TableCell, TableRow, Typography, - useHistory + useHistory, + useToasts } from "@chainsafe/common-components" import { t, Trans } from "@lingui/macro" import { Bucket } from "@chainsafe/files-api-client" @@ -23,7 +25,7 @@ import clsx from "clsx" import { Form, FormikProvider, useFormik } from "formik" import { nameValidator } from "../../Utils/validationSchema" -const useStyles = makeStyles(({ animation, constants, breakpoints }: CSSTheme) => +const useStyles = makeStyles(({ palette, animation, constants, breakpoints }: CSSTheme) => createStyles({ dropdownIcon: { "& svg": { @@ -93,6 +95,15 @@ const useStyles = makeStyles(({ animation, constants, breakpoints }: CSSTheme) = [breakpoints.down("md")]: { margin: `${constants.generalUnit * 4.2}px 0` } + }, + idRow: { + display: "flex", + alignItems: "center" + }, + copyIcon: { + fontSize: "16px", + fill: palette.additional["gray"][8], + marginLeft: "8px" } }) ) @@ -106,6 +117,9 @@ interface Props { const BucketRow = ({ bucket, onRemoveBucket, handleContextMenu, handleRename }: Props) => { const classes = useStyles() const { redirect } = useHistory() + const { addToast } = useToasts() + const { desktop } = useThemeSwitcher() + const menuItems = useMemo(() => [ { contents: ( @@ -168,6 +182,14 @@ const BucketRow = ({ bucket, onRemoveBucket, handleContextMenu, handleRename }: useOnClickOutside(formRef, formik.submitForm) + const onCopyBucketId = () => { + navigator.clipboard.writeText(bucket.id) + addToast({ + title: t`Bucket Id copied`, + type: "success" + }) + } + return ( + {desktop && + + {bucket.id } + + + } diff --git a/packages/storage-ui/src/Components/Layouts/AppNav.tsx b/packages/storage-ui/src/Components/Layouts/AppNav.tsx index d6e3fb80d4..2e21d076cf 100644 --- a/packages/storage-ui/src/Components/Layouts/AppNav.tsx +++ b/packages/storage-ui/src/Components/Layouts/AppNav.tsx @@ -18,7 +18,6 @@ import { useLocation, KeySvg, CreditCardOutlinedSvg - // FileWithImageSvg } from "@chainsafe/common-components" import { ROUTE_LINKS } from "../StorageRoutes" import { Trans } from "@lingui/macro" diff --git a/packages/storage-ui/src/Components/Layouts/AppWrapper.tsx b/packages/storage-ui/src/Components/Layouts/AppWrapper.tsx index 01e82bdbd5..77eea750f2 100644 --- a/packages/storage-ui/src/Components/Layouts/AppWrapper.tsx +++ b/packages/storage-ui/src/Components/Layouts/AppWrapper.tsx @@ -3,7 +3,7 @@ import React, { useState } from "react" import { ReactNode } from "react" import clsx from "clsx" import { useStorageApi } from "../../Contexts/StorageApiContext" -import { CssBaseline } from "@chainsafe/common-components" +import { CssBaseline } from "@chainsafe/common-components" import AppHeader from "./AppHeader" import AppNav from "./AppNav" diff --git a/packages/storage-ui/src/Components/Modules/ApiKeys.tsx b/packages/storage-ui/src/Components/Modules/ApiKeys.tsx index 0e8dbc173b..dc9e41a4db 100644 --- a/packages/storage-ui/src/Components/Modules/ApiKeys.tsx +++ b/packages/storage-ui/src/Components/Modules/ApiKeys.tsx @@ -16,7 +16,8 @@ import { DeleteSvg, MoreIcon, CopyIcon, - Divider } from "@chainsafe/common-components" + Divider +} from "@chainsafe/common-components" import { CSSTheme } from "../../Themes/types" import { Trans } from "@lingui/macro" import dayjs from "dayjs" @@ -96,7 +97,7 @@ const useStyles = makeStyles(({ constants, breakpoints, animation, zIndex, palet color: constants.createFolder.color, [breakpoints.down("md")]: { bottom: - Number(constants?.mobileButtonHeight) + constants.generalUnit, + Number(constants?.mobileButtonHeight) + constants.generalUnit, borderTopLeftRadius: `${constants.generalUnit * 1.5}px`, borderTopRightRadius: `${constants.generalUnit * 1.5}px`, maxWidth: `${breakpoints.width("md")}px !important` @@ -226,7 +227,6 @@ const ApiKeys = () => { onClick={createStorageAccessKey} variant="outline" size="large" - disabled={keys.filter(k => k.type === "storage").length > 0} > @@ -275,7 +275,7 @@ const ApiKeys = () => { - {keys.map(k => + {keys.filter(k => k.type !== "gaming").map(k => const FilesList = () => { const { themeKey, desktop } = useThemeSwitcher() - const { accountRestricted } = useStorageApi() + const { accountRestricted, accountBlacklisted } = useStorageApi() const { heading, controls = true, @@ -1212,9 +1213,8 @@ const FilesList = () => { ) } - {accountRestricted && - - } + {accountRestricted && } + {accountBlacklisted && } ) } diff --git a/packages/storage-ui/src/Components/Pages/BucketsPage.tsx b/packages/storage-ui/src/Components/Pages/BucketsPage.tsx index 9940493378..747ebf734b 100644 --- a/packages/storage-ui/src/Components/Pages/BucketsPage.tsx +++ b/packages/storage-ui/src/Components/Pages/BucketsPage.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useMemo, useState } from "react" -import { makeStyles, createStyles } from "@chainsafe/common-theme" +import { makeStyles, createStyles, useThemeSwitcher } from "@chainsafe/common-theme" import { Button, Dialog, @@ -30,9 +30,10 @@ import { usePageTrack } from "../../Contexts/PosthogContext" import { Bucket, FileSystemType } from "@chainsafe/files-api-client" import { Helmet } from "react-helmet-async" import AnchorMenu, { AnchorMenuPosition } from "../UI-components/AnchorMenu" +import BlacklistedModeBanner from "../Elements/BlacklistedModeBanner" -export const desktopGridSettings = "3fr 150px 150px 70px !important" -export const mobileGridSettings = "3fr 100px 100px 70px !important" +export const desktopGridSettings = "2fr 5fr 150px 150px 50px !important" +export const mobileGridSettings = "1fr 150px 110px 50px !important" const useStyles = makeStyles(({ breakpoints, animation, constants, typography }: CSSTheme) => createStyles({ @@ -127,7 +128,7 @@ type SortDirection = "ascend" | "descend" const BucketsPage = () => { const classes = useStyles() const { storageBuckets, createBucket, refreshBuckets, removeBucket, editBucket } = useStorage() - const { accountRestricted } = useStorageApi() + const { accountRestricted, accountBlacklisted } = useStorageApi() const [isCreateBucketModalOpen, setIsCreateBucketModalOpen] = useState(false) const [bucketToRemove, setBucketToRemove] = useState() const [isRemovingBucket, setIsRemovingBucket] = useState(false) @@ -136,6 +137,8 @@ const BucketsPage = () => { const [sortColumn, setSortColumn] = useState(undefined) const [sortDirection, setSortDirection] = useState("descend") + const { desktop } = useThemeSwitcher() + const generalContextMenuOptions: IMenuItem[] = useMemo(() => [ { contents: ( @@ -317,6 +320,14 @@ const BucketsPage = () => { > Name + {desktop && + + Bucket Id + + } { )} - {accountRestricted && - - } + {accountRestricted && } + {accountBlacklisted && } { isLoadingPins, resetPins } = useStorage() - const { accountRestricted } = useStorageApi() + const { accountRestricted, accountBlacklisted } = useStorageApi() const [addCIDOpen, setAddCIDOpen] = useState(false) const [sortColumn, setSortColumn] = useState("date_uploaded") const [sortDirection, setSortDirection] = useState("descend") @@ -294,9 +295,8 @@ const CidsPage = () => { close={() => setAddCIDOpen(false)} modalOpen={addCIDOpen} /> - {accountRestricted && - - } + {accountRestricted && } + {accountBlacklisted && } ) } diff --git a/packages/storage-ui/src/Contexts/StorageApiContext.tsx b/packages/storage-ui/src/Contexts/StorageApiContext.tsx index 90f39a6b3a..8ac0e56bb6 100644 --- a/packages/storage-ui/src/Contexts/StorageApiContext.tsx +++ b/packages/storage-ui/src/Contexts/StorageApiContext.tsx @@ -70,6 +70,7 @@ type StorageApiContext = { status: DirectAuthContextStatus resetStatus(): void accountRestricted?: boolean + accountBlacklisted?: boolean } const StorageApiContext = React.createContext(undefined) @@ -105,6 +106,7 @@ const StorageApiProvider = ({ apiUrl, withLocalStorage = true, children }: Stora { exp: number; enckey?: string; mps?: string; uuid: string } | undefined >(undefined) const [accountRestricted, setAccountRestricted] = useState(false) + const [accountBlacklisted, setAccountBlacklisted] = useState(false) // returning user const isReturningUserLocal = localStorageGet(isReturningUserStorageKey) @@ -234,7 +236,7 @@ const StorageApiProvider = ({ apiUrl, withLocalStorage = true, children }: Stora useEffect(() => { if (accessToken && accessToken.token && storageApiClient) { storageApiClient?.setToken(accessToken.token) - const decodedAccessToken = jwtDecode<{ perm: { secured?: string; files?: string } }>( + const decodedAccessToken = jwtDecode<{ perm: { secured?: string; files?: string; storage?: string } }>( accessToken.token ) @@ -243,6 +245,12 @@ const StorageApiProvider = ({ apiUrl, withLocalStorage = true, children }: Stora } else { setAccountRestricted(false) } + + if (decodedAccessToken.perm.storage === "blacklisted") { + setAccountBlacklisted(true) + } else { + setAccountBlacklisted(false) + } } }, [accessToken, storageApiClient]) @@ -263,14 +271,14 @@ const StorageApiProvider = ({ apiUrl, withLocalStorage = true, children }: Stora } } + useEffect(() => { - if (refreshToken && refreshToken.token) { + if (refreshToken?.token) { try { - const decoded = jwtDecode<{ mps?: string; enckey?: string; exp: number; uuid: string }>( + const decodedRefresh = jwtDecode<{ mps?: string; enckey?: string; exp: number; uuid: string }>( refreshToken.token ) - - setDecodedRefreshToken(decoded) + setDecodedRefreshToken(decodedRefresh) } catch (error) { console.error("Error decoding access token") } @@ -422,7 +430,8 @@ const StorageApiProvider = ({ apiUrl, withLocalStorage = true, children }: Stora selectWallet, resetAndSelectWallet, logout, - accountRestricted + accountRestricted, + accountBlacklisted }} > {children} diff --git a/packages/storage-ui/src/locales/en/messages.po b/packages/storage-ui/src/locales/en/messages.po index 478ccd6684..373ebfd851 100644 --- a/packages/storage-ui/src/locales/en/messages.po +++ b/packages/storage-ui/src/locales/en/messages.po @@ -118,6 +118,12 @@ msgstr "Billing start time" msgid "Browse files" msgstr "Browse files" +msgid "Bucket Id" +msgstr "Bucket Id" + +msgid "Bucket Id copied" +msgstr "Bucket Id copied" + msgid "Bucket name" msgstr "Bucket name" @@ -274,6 +280,9 @@ msgstr "Destination Address" msgid "Didn't receive the email ?" msgstr "Didn't receive the email ?" +msgid "Discord support" +msgstr "Discord support" + msgid "Docs" msgstr "Docs" @@ -805,6 +814,9 @@ msgstr "You will need to sign a message in your wallet to complete sign in." msgid "You've got a payment due. Until you've settled up, we've placed your account in restricted mode" msgstr "You've got a payment due. Until you've settled up, we've placed your account in restricted mode" +msgid "Your account has been blacklisted due to unusual activity" +msgstr "Your account has been blacklisted due to unusual activity" + msgid "Your account is restricted. Until you've settled up, you can't upload any new content." msgstr "Your account is restricted. Until you've settled up, you can't upload any new content." diff --git a/yarn.lock b/yarn.lock index 3c6be51480..bfa88d87bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9929,9 +9929,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001111, caniuse-lite@^1.0.30001157, caniuse-lite@^1.0.30001251: - version "1.0.30001414" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001414.tgz" - integrity sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg== + version "1.0.30001621" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001621.tgz" + integrity sha512-+NLXZiviFFKX0fk8Piwv3PfLPGtRqJeq2TiNoUff/qB5KJgwecJTvCXDpmlyP/eCI/GUEmp/h/y5j0yckiiZrA== capture-exit@^2.0.0: version "2.0.0"