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

     1  // This file is part of MinIO Console Server
     2  // Copyright (c) 2021 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 { ErrorResponseHandler } from "../../../../../../common/types";
    19  import { decodeURLString } from "../../../../../../common/utils";
    20  import ConfirmDialog from "../../../../Common/ModalWrapper/ConfirmDialog";
    21  import useApi from "../../../../Common/Hooks/useApi";
    22  import { ConfirmDeleteIcon, Switch } from "mds";
    23  import { setErrorSnackMessage } from "../../../../../../systemSlice";
    24  import { AppState, useAppDispatch } from "../../../../../../store";
    25  import { hasPermission } from "../../../../../../common/SecureComponent";
    26  import { IAM_SCOPES } from "../../../../../../common/SecureComponent/permissions";
    27  import { useSelector } from "react-redux";
    28  import { isVersionedMode } from "../../../../../../utils/validationFunctions";
    29  import { BucketVersioningResponse } from "api/consoleApi";
    30  
    31  interface IDeleteObjectProps {
    32    closeDeleteModalAndRefresh: (refresh: boolean) => void;
    33    deleteOpen: boolean;
    34    selectedObject: string;
    35    selectedBucket: string;
    36  
    37    versioningInfo: BucketVersioningResponse | undefined;
    38    selectedVersion?: string;
    39  }
    40  
    41  const DeleteObject = ({
    42    closeDeleteModalAndRefresh,
    43    deleteOpen,
    44    selectedBucket,
    45    selectedObject,
    46    versioningInfo,
    47    selectedVersion = "",
    48  }: IDeleteObjectProps) => {
    49    const dispatch = useAppDispatch();
    50    const onDelSuccess = () => closeDeleteModalAndRefresh(true);
    51    const onDelError = (err: ErrorResponseHandler) => {
    52      dispatch(setErrorSnackMessage(err));
    53  
    54      // We close the modal box on access denied.
    55      if (err.detailedError === "Access Denied.") {
    56        closeDeleteModalAndRefresh(true);
    57      }
    58    };
    59    const onClose = () => closeDeleteModalAndRefresh(false);
    60  
    61    const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
    62    const [deleteVersions, setDeleteVersions] = useState<boolean>(false);
    63    const [bypassGovernance, setBypassGovernance] = useState<boolean>(false);
    64  
    65    const retentionConfig = useSelector(
    66      (state: AppState) => state.objectBrowser.retentionConfig,
    67    );
    68  
    69    const canBypass =
    70      hasPermission(
    71        [selectedBucket],
    72        [IAM_SCOPES.S3_BYPASS_GOVERNANCE_RETENTION],
    73      ) && retentionConfig?.mode === "governance";
    74  
    75    if (!selectedObject) {
    76      return null;
    77    }
    78    const onConfirmDelete = () => {
    79      const decodedSelectedObject = decodeURLString(selectedObject);
    80      const recursive = decodedSelectedObject.endsWith("/");
    81      invokeDeleteApi(
    82        "DELETE",
    83        `/api/v1/buckets/${selectedBucket}/objects?prefix=${selectedObject}${
    84          selectedVersion !== ""
    85            ? `&version_id=${selectedVersion}`
    86            : `&recursive=${recursive}&all_versions=${deleteVersions}`
    87        }${bypassGovernance ? "&bypass=true" : ""}`,
    88      );
    89    };
    90  
    91    return (
    92      <ConfirmDialog
    93        title={`Delete Object`}
    94        confirmText={"Delete"}
    95        isOpen={deleteOpen}
    96        titleIcon={<ConfirmDeleteIcon />}
    97        isLoading={deleteLoading}
    98        onConfirm={onConfirmDelete}
    99        onClose={onClose}
   100        confirmationContent={
   101          <Fragment>
   102            Are you sure you want to delete: <br />
   103            <b>{decodeURLString(selectedObject)}</b>{" "}
   104            {selectedVersion !== "" ? (
   105              <Fragment>
   106                <br />
   107                <br />
   108                Version ID:
   109                <br />
   110                <strong>{selectedVersion}</strong>
   111              </Fragment>
   112            ) : (
   113              ""
   114            )}
   115            ? <br />
   116            <br />
   117            {isVersionedMode(versioningInfo?.status) &&
   118              selectedVersion === "" && (
   119                <Fragment>
   120                  <Switch
   121                    label={"Delete All Versions"}
   122                    indicatorLabels={["Yes", "No"]}
   123                    checked={deleteVersions}
   124                    value={"delete_versions"}
   125                    id="delete-versions"
   126                    name="delete-versions"
   127                    onChange={(e) => {
   128                      setDeleteVersions(!deleteVersions);
   129                    }}
   130                    description=""
   131                  />
   132                </Fragment>
   133              )}
   134            {canBypass && (deleteVersions || selectedVersion !== "") && (
   135              <Fragment>
   136                <div
   137                  style={{
   138                    marginTop: 10,
   139                  }}
   140                >
   141                  <Switch
   142                    label={"Bypass Governance Mode"}
   143                    indicatorLabels={["Yes", "No"]}
   144                    checked={bypassGovernance}
   145                    value={"bypass_governance"}
   146                    id="bypass_governance"
   147                    name="bypass_governance"
   148                    onChange={(e) => {
   149                      setBypassGovernance(!bypassGovernance);
   150                    }}
   151                    description=""
   152                  />
   153                </div>
   154              </Fragment>
   155            )}
   156            {deleteVersions && (
   157              <Fragment>
   158                <div
   159                  style={{
   160                    marginTop: 10,
   161                    border: "#c83b51 1px solid",
   162                    borderRadius: 3,
   163                    padding: 5,
   164                    backgroundColor: "#c83b5120",
   165                    color: "#c83b51",
   166                  }}
   167                >
   168                  This will remove the object as well as all of its versions,{" "}
   169                  <br />
   170                  This action is irreversible.
   171                </div>
   172                <br />
   173                Are you sure you want to continue?
   174              </Fragment>
   175            )}
   176          </Fragment>
   177        }
   178      />
   179    );
   180  };
   181  
   182  export default DeleteObject;