github.com/minio/console@v1.4.1/web-app/src/screens/Console/Buckets/ListBuckets/UploadFilesButton.tsx (about)

     1  // This file is part of MinIO Console Server
     2  // Copyright (c) 2022 MinIO, Inc.
     3  //
     4  // This program is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Affero General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // This program is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  // GNU Affero General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Affero General Public License
    15  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16  
    17  import React, { Fragment, useState } from "react";
    18  import { CSSObject } from "styled-components";
    19  import { Button, DropdownSelector, UploadFolderIcon, UploadIcon } from "mds";
    20  import {
    21    IAM_SCOPES,
    22    permissionTooltipHelper,
    23  } from "../../../../common/SecureComponent/permissions";
    24  import { hasPermission } from "../../../../common/SecureComponent";
    25  import TooltipWrapper from "../../Common/TooltipWrapper/TooltipWrapper";
    26  import { useSelector } from "react-redux";
    27  import { AppState } from "../../../../store";
    28  import { getSessionGrantsWildCard } from "./UploadPermissionUtils";
    29  
    30  interface IUploadFilesButton {
    31    uploadPath: string;
    32    bucketName: string;
    33    forceDisable?: boolean;
    34    uploadFileFunction: (closeFunction: () => void) => void;
    35    uploadFolderFunction: (closeFunction: () => void) => void;
    36    overrideStyles?: CSSObject;
    37  }
    38  
    39  const UploadFilesButton = ({
    40    uploadPath,
    41    bucketName,
    42    forceDisable = false,
    43    uploadFileFunction,
    44    uploadFolderFunction,
    45    overrideStyles = {},
    46  }: IUploadFilesButton) => {
    47    const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
    48    const [uploadOptionsOpen, uploadOptionsSetOpen] = useState<boolean>(false);
    49  
    50    const anonymousMode = useSelector(
    51      (state: AppState) => state.system.anonymousMode,
    52    );
    53  
    54    const sessionGrants = useSelector((state: AppState) =>
    55      state.console.session ? state.console.session.permissions || {} : {},
    56    );
    57  
    58    const putObjectPermScopes = [
    59      IAM_SCOPES.S3_PUT_OBJECT,
    60      IAM_SCOPES.S3_PUT_ACTIONS,
    61    ];
    62  
    63    const sessionGrantWildCards = getSessionGrantsWildCard(
    64      sessionGrants,
    65      uploadPath,
    66      putObjectPermScopes,
    67    );
    68  
    69    const openUploadMenu = Boolean(anchorEl);
    70    const handleClick = (event: React.MouseEvent<HTMLElement>) => {
    71      uploadOptionsSetOpen(!uploadOptionsOpen);
    72      setAnchorEl(event.currentTarget);
    73    };
    74    const handleCloseUpload = () => {
    75      setAnchorEl(null);
    76    };
    77  
    78    const uploadObjectAllowed =
    79      hasPermission(
    80        [uploadPath, ...sessionGrantWildCards],
    81        putObjectPermScopes,
    82      ) || anonymousMode;
    83  
    84    const uploadFolderAllowed = hasPermission(
    85      [bucketName, ...sessionGrantWildCards],
    86      putObjectPermScopes,
    87      false,
    88      true,
    89    );
    90  
    91    const uploadFolderAction = (action: string) => {
    92      if (action === "folder") {
    93        uploadFolderFunction(handleCloseUpload);
    94        return;
    95      }
    96  
    97      uploadFileFunction(handleCloseUpload);
    98    };
    99  
   100    const uploadEnabled: boolean = uploadObjectAllowed || uploadFolderAllowed;
   101  
   102    return (
   103      <Fragment>
   104        <TooltipWrapper
   105          tooltip={
   106            uploadEnabled
   107              ? "Upload Files"
   108              : permissionTooltipHelper(
   109                  [IAM_SCOPES.S3_PUT_OBJECT, IAM_SCOPES.S3_PUT_ACTIONS],
   110                  "upload files to this bucket",
   111                )
   112          }
   113        >
   114          <Button
   115            id={"upload-main"}
   116            aria-controls={`upload-main-menu`}
   117            aria-haspopup="true"
   118            aria-expanded={openUploadMenu ? "true" : undefined}
   119            onClick={handleClick}
   120            label={"Upload"}
   121            icon={<UploadIcon />}
   122            variant={"callAction"}
   123            disabled={forceDisable || !uploadEnabled}
   124            sx={overrideStyles}
   125          />
   126        </TooltipWrapper>
   127        <DropdownSelector
   128          id={"upload-main-menu"}
   129          options={[
   130            {
   131              label: "Upload File",
   132              icon: <UploadIcon />,
   133              value: "file",
   134              disabled: !uploadObjectAllowed || forceDisable,
   135            },
   136            {
   137              label: "Upload Folder",
   138              icon: <UploadFolderIcon />,
   139              value: "folder",
   140              disabled: !uploadFolderAllowed || forceDisable,
   141            },
   142          ]}
   143          selectedOption={""}
   144          onSelect={(nValue) => uploadFolderAction(nValue)}
   145          hideTriggerAction={() => {
   146            uploadOptionsSetOpen(false);
   147          }}
   148          open={uploadOptionsOpen}
   149          anchorEl={anchorEl}
   150          anchorOrigin={"end"}
   151          useAnchorWidth
   152        />
   153      </Fragment>
   154    );
   155  };
   156  
   157  export default UploadFilesButton;