diff --git a/packages/common-components/src/Table/Table.tsx b/packages/common-components/src/Table/Table.tsx index d9cbb913dd..43ff504ca6 100644 --- a/packages/common-components/src/Table/Table.tsx +++ b/packages/common-components/src/Table/Table.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode } from "react" +import React, { ReactNode, TableHTMLAttributes } from "react" import { ITheme, makeStyles, createStyles } from "@chainsafe/common-theme" import clsx from "clsx" @@ -57,7 +57,7 @@ const useStyles = makeStyles( }) ) -export interface ITableProps { +export interface ITableProps extends TableHTMLAttributes { className?: string children: ReactNode | ReactNode[] striped?: boolean diff --git a/packages/common-components/src/Table/TableHead.tsx b/packages/common-components/src/Table/TableHead.tsx index 60a3ce9f72..aeec4fe9e5 100644 --- a/packages/common-components/src/Table/TableHead.tsx +++ b/packages/common-components/src/Table/TableHead.tsx @@ -17,7 +17,7 @@ const useStyles = makeStyles(({ palette, typography, overrides }: ITheme) => }) ) -export interface ITableHeadProps { +export interface ITableHeadProps extends React.HTMLAttributes{ className?: string children: ReactNode | ReactNode[] } diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFoldersOverview.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFoldersOverview.tsx index 859cbf0a87..b4bcf06a73 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFoldersOverview.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFoldersOverview.tsx @@ -11,7 +11,9 @@ import { Button, PlusIcon, useHistory, - Dialog + Dialog, + IMenuItem, + PlusSvg } from "@chainsafe/common-components" import { BucketKeyPermission, useFiles } from "../../../Contexts/FilesContext" import { t, Trans } from "@lingui/macro" @@ -28,6 +30,7 @@ import clsx from "clsx" import CreateSharedFolderModal from "./CreateSharedFolderModal" import CreateOrManageSharedFolderModal from "./ManageSharedFolderModal" import { useLanguageContext } from "../../../Contexts/LanguageContext" +import AnchorMenu, { AnchoreMenuPosition } from "../../../UI-components/AnchorMenu" export const desktopSharedGridSettings = "50px 3fr 90px 140px 140px 45px !important" export const mobileSharedGridSettings = "3fr 80px 45px !important" @@ -112,6 +115,14 @@ const useStyles = makeStyles( }, buttonWrap: { whiteSpace: "nowrap" + }, + menuIcon: { + display: "flex", + justifyContent: "center", + alignItems: "center", + width: 20, + marginRight: constants.generalUnit * 1.5, + fill: constants.previewModal.menuItemIconColor } }) } @@ -135,6 +146,22 @@ const SharedFolderOverview = () => { const [isSharedFolderCreationModalOpen, setIsSharedFolderCreationModalOpen] = useState(false) const [bucketToEdit, setBucketToEdit] = useState(undefined) const { selectedLocale } = useLanguageContext() + const [contextMenuPosition, setContextMenuPosition] = useState(null) + const [contextMenuOptions, setContextMenuOptions] = useState([]) + const generalContextMenuOptions: IMenuItem[] = useMemo(() => [ + { + contents: ( + <> + + + Create + + + ), + onClick: () => setIsSharedFolderCreationModalOpen(true) + } + ], [classes]) + const sortedBuckets = useMemo(() => { let temp: BucketKeyPermission[] @@ -202,6 +229,20 @@ const SharedFolderOverview = () => { const openSharedFolder = useCallback((bucketId: string) => { redirect(ROUTE_LINKS.SharedFolderExplorer(bucketId, "/")) }, [redirect]) + + const handleContextMenu = useCallback((e: React.MouseEvent, options?: IMenuItem[]) => { + e.preventDefault() + if(options){ + setContextMenuOptions(options) + } else { + setContextMenuOptions(generalContextMenuOptions) + } + setContextMenuPosition({ + left: e.clientX - 2, + top: e.clientY - 4 + }) + }, [generalContextMenuOptions]) + return ( <>
{ bottomBanner: accountRestricted })} > -
+
{
+ {contextMenuPosition && ( + setContextMenuPosition(null)} + anchorPosition={contextMenuPosition} + /> + )} {isLoadingBuckets && (
{ striped={true} hover={true} > - + { setBucketToDelete(bucket) setIsDeleteBucketModalOpen(true) }} + handleContextMenu={handleContextMenu} /> )} diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/views/FileSystemItem/SharedFolderRow.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/views/FileSystemItem/SharedFolderRow.tsx index 79049486dc..a7f532b1e8 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/views/FileSystemItem/SharedFolderRow.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/views/FileSystemItem/SharedFolderRow.tsx @@ -154,9 +154,17 @@ interface Props { openSharedFolder: (bucketId: string) => void onEditSharedFolder: () => void handleDeleteSharedFolder: () => void + handleContextMenu: (e: React.MouseEvent, items?: IMenuItem[]) => void } -const SharedFolderRow = ({ bucket, handleRename, openSharedFolder, handleDeleteSharedFolder, onEditSharedFolder }: Props) => { +const SharedFolderRow = ({ + bucket, + handleRename, + openSharedFolder, + handleDeleteSharedFolder, + handleContextMenu, + onEditSharedFolder +}: Props) => { const classes = useStyles() const { name, size } = bucket const { desktop } = useThemeSwitcher() @@ -290,6 +298,7 @@ const SharedFolderRow = ({ bucket, handleRename, openSharedFolder, handleDeleteS data-cy="row-shared-folder-item" className={classes.tableRow} type="grid" + onContextMenu={(e) => handleContextMenu(e, menuItems)} > {desktop && void } -const BucketRow = ({ bucket }: Props) => { +const BucketRow = ({ bucket, handleContextMenu }: Props) => { const classes = useStyles() const { removeBucket } = useStorage() const { redirect } = useHistory() + const menuItems = useMemo(() => [{ + contents: ( + <> + + + Delete bucket + + + ), + onClick: () => removeBucket(bucket.id) + }], [bucket, classes, removeBucket]) + return ( { deleting: bucket.status === "deleting" })} data-cy="row-bucket-item" + onContextMenu={(e) => handleContextMenu(e, menuItems)} > { testId='bucket-kebab' animation="none" anchor={"bottom-right"} - menuItems={[{ - contents: ( - <> - - - Delete bucket - - - ), - onClick: () => removeBucket(bucket.id) - }]} + menuItems={menuItems} classNames={{ icon: classes.dropdownIcon, options: classes.dropdownOptions, diff --git a/packages/storage-ui/src/Components/Pages/BucketsPage.tsx b/packages/storage-ui/src/Components/Pages/BucketsPage.tsx index c4e25725cf..15e3a297d7 100644 --- a/packages/storage-ui/src/Components/Pages/BucketsPage.tsx +++ b/packages/storage-ui/src/Components/Pages/BucketsPage.tsx @@ -5,7 +5,9 @@ import { FormikRadioInput, FormikTextInput, Grid, + IMenuItem, PlusIcon, + PlusSvg, Table, TableBody, TableHead, @@ -26,6 +28,7 @@ import { useStorageApi } from "../../Contexts/StorageApiContext" import { usePageTrack } from "../../Contexts/PosthogContext" import { FileSystemType } from "@chainsafe/files-api-client" import { Helmet } from "react-helmet-async" +import AnchorMenu, { AnchoreMenuPosition } from "../UI-components/AnchorMenu" export const desktopGridSettings = "3fr 110px 150px 70px !important" export const mobileGridSettings = "3fr 100px 100px 70px !important" @@ -105,6 +108,14 @@ const useStyles = makeStyles(({ breakpoints, animation, constants, typography }: display: "flex", flexDirection: "row" } + }, + menuIcon: { + display: "flex", + justifyContent: "center", + alignItems: "center", + width: 20, + marginRight: constants.generalUnit * 1.5, + fill: constants.previewModal.menuItemIconColor } }) ) @@ -115,6 +126,22 @@ const BucketsPage = () => { const { accountRestricted } = useStorageApi() const [isCreateBucketModalOpen, setIsCreateBucketModalOpen] = useState(false) const bucketsToShow = useMemo(() => storageBuckets.filter(b => b.status === "created"), [storageBuckets]) + const [contextMenuPosition, setContextMenuPosition] = useState(null) + const [contextMenuOptions, setContextMenuOptions] = useState([]) + const generalContextMenuOptions: IMenuItem[] = useMemo(() => [ + { + contents: ( + <> + + + Create Bucket + + + ), + onClick: () => setIsCreateBucketModalOpen(true) + } + ], [classes]) + const bucketNameValidationSchema = useMemo( () => bucketNameValidator(bucketsToShow.map(b => b.name)) , [bucketsToShow] @@ -153,6 +180,19 @@ const BucketsPage = () => { setIsCreateBucketModalOpen(false) }, [formik]) + const handleContextMenu = useCallback((e: React.MouseEvent, options?: IMenuItem[]) => { + e.preventDefault() + if(options){ + setContextMenuOptions(options) + } else { + setContextMenuOptions(generalContextMenuOptions) + } + setContextMenuPosition({ + left: e.clientX - 2, + top: e.clientY - 4 + }) + }, [generalContextMenuOptions]) + return (
@@ -161,6 +201,7 @@ const BucketsPage = () => {
@@ -179,12 +220,22 @@ const BucketsPage = () => {
+ {contextMenuPosition && ( + setContextMenuPosition(null)} + anchorPosition={contextMenuPosition} + /> + )} - + { )}