github.com/minio/console@v1.4.1/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetRetention.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, { useEffect, useRef, useState } from "react";
    18  import { Box, Button, FormLayout, Grid, RadioGroup, Switch } from "mds";
    19  import { useSelector } from "react-redux";
    20  import { BucketObject, ObjectRetentionMode } from "api/consoleApi";
    21  import { api } from "api";
    22  import { errorToHandler } from "api/errors";
    23  import { encodeURLString } from "common/utils";
    24  import { modalStyleUtils } from "../../../../Common/FormComponents/common/styleLibrary";
    25  import { twoDigitDate } from "../../../../Common/FormComponents/DateSelector/utils";
    26  import { setModalErrorSnackMessage } from "../../../../../../systemSlice";
    27  import { AppState, useAppDispatch } from "../../../../../../store";
    28  import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper";
    29  import DateSelector from "../../../../Common/FormComponents/DateSelector/DateSelector";
    30  
    31  interface ISetRetentionProps {
    32    open: boolean;
    33    closeModalAndRefresh: (updateInfo: boolean) => void;
    34    objectName: string;
    35    bucketName: string;
    36    objectInfo: BucketObject;
    37  }
    38  
    39  interface IRefObject {
    40    resetDate: () => void;
    41  }
    42  
    43  const SetRetention = ({
    44    open,
    45    closeModalAndRefresh,
    46    objectName,
    47    objectInfo,
    48    bucketName,
    49  }: ISetRetentionProps) => {
    50    const dispatch = useAppDispatch();
    51    const retentionConfig = useSelector(
    52      (state: AppState) => state.objectBrowser.retentionConfig,
    53    );
    54  
    55    const [statusEnabled, setStatusEnabled] = useState<boolean>(true);
    56    const [type, setType] = useState<ObjectRetentionMode | "">("");
    57    const [date, setDate] = useState<string>("");
    58    const [isDateValid, setIsDateValid] = useState<boolean>(false);
    59    const [isSaving, setIsSaving] = useState<boolean>(false);
    60    const [alreadyConfigured, setAlreadyConfigured] = useState<boolean>(false);
    61  
    62    useEffect(() => {
    63      if (objectInfo.retention_mode) {
    64        setType(retentionConfig?.mode || ObjectRetentionMode.Governance);
    65        setAlreadyConfigured(true);
    66      }
    67      // get retention_until_date if defined
    68      if (objectInfo.retention_until_date) {
    69        const valueDate = new Date(objectInfo.retention_until_date);
    70        if (valueDate.toString() !== "Invalid Date") {
    71          const year = valueDate.getFullYear();
    72          const month = twoDigitDate(valueDate.getMonth() + 1);
    73          const day = valueDate.getDate();
    74          if (!isNaN(day) && month !== "NaN" && !isNaN(year)) {
    75            setDate(`${year}-${month}-${day}`);
    76          }
    77        }
    78        setAlreadyConfigured(true);
    79      }
    80    }, [objectInfo, retentionConfig?.mode]);
    81  
    82    const dateElement = useRef<IRefObject>(null);
    83  
    84    const dateFieldDisabled = () => {
    85      return !(statusEnabled && (type === "governance" || type === "compliance"));
    86    };
    87  
    88    const onSubmit = (e: React.FormEvent) => {
    89      e.preventDefault();
    90    };
    91  
    92    const resetForm = () => {
    93      setStatusEnabled(false);
    94      setType(ObjectRetentionMode.Governance);
    95      if (dateElement.current) {
    96        dateElement.current.resetDate();
    97      }
    98    };
    99  
   100    const addRetention = (
   101      selectedObject: string,
   102      versionId: string | null,
   103      expireDate: string,
   104    ) => {
   105      api.buckets
   106        .putObjectRetention(
   107          bucketName,
   108          {
   109            prefix: encodeURLString(selectedObject),
   110            version_id: versionId || "",
   111          },
   112          {
   113            expires: expireDate,
   114            mode: type as ObjectRetentionMode,
   115          },
   116        )
   117        .then(() => {
   118          setIsSaving(false);
   119          closeModalAndRefresh(true);
   120        })
   121        .catch((err) => {
   122          dispatch(setModalErrorSnackMessage(errorToHandler(err.error)));
   123          setIsSaving(false);
   124        });
   125    };
   126  
   127    const disableRetention = (
   128      selectedObject: string,
   129      versionId: string | null,
   130    ) => {
   131      api.buckets
   132        .deleteObjectRetention(bucketName, {
   133          prefix: encodeURLString(selectedObject),
   134          version_id: versionId || "",
   135        })
   136        .then(() => {
   137          setIsSaving(false);
   138          closeModalAndRefresh(true);
   139        })
   140        .catch((err) => {
   141          dispatch(setModalErrorSnackMessage(errorToHandler(err.error)));
   142          setIsSaving(false);
   143        });
   144    };
   145  
   146    const saveNewRetentionPolicy = () => {
   147      setIsSaving(true);
   148      const selectedObject = objectInfo.name || "";
   149      const versionId = objectInfo.version_id || null;
   150  
   151      const expireDate =
   152        !statusEnabled && type === "governance" ? "" : `${date}T23:59:59Z`;
   153  
   154      if (!statusEnabled && type === "governance") {
   155        disableRetention(selectedObject, versionId);
   156  
   157        return;
   158      }
   159  
   160      addRetention(selectedObject, versionId, expireDate);
   161    };
   162  
   163    const showSwitcher =
   164      alreadyConfigured && (type === "governance" || type === "");
   165  
   166    return (
   167      <ModalWrapper
   168        title="Set Retention Policy"
   169        modalOpen={open}
   170        onClose={() => {
   171          resetForm();
   172          closeModalAndRefresh(false);
   173        }}
   174      >
   175        <form
   176          noValidate
   177          autoComplete="off"
   178          onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
   179            onSubmit(e);
   180          }}
   181        >
   182          <FormLayout withBorders={false} containerPadding={false}>
   183            <Box className={"inputItem"}>
   184              <strong>Selected Object</strong>: {objectName}
   185            </Box>
   186            {showSwitcher && (
   187              <Switch
   188                value="status"
   189                id="status"
   190                name="status"
   191                checked={statusEnabled}
   192                onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
   193                  setStatusEnabled(!statusEnabled);
   194                }}
   195                label={"Status"}
   196                indicatorLabels={["Enabled", "Disabled"]}
   197              />
   198            )}
   199            <RadioGroup
   200              currentValue={type}
   201              id="type"
   202              name="type"
   203              label="Type"
   204              disableOptions={
   205                !statusEnabled || (alreadyConfigured && type !== "")
   206              }
   207              onChange={(e) => {
   208                setType(e.target.value as ObjectRetentionMode);
   209              }}
   210              selectorOptions={[
   211                { label: "Governance", value: ObjectRetentionMode.Governance },
   212                { label: "Compliance", value: ObjectRetentionMode.Compliance },
   213              ]}
   214            />
   215            <DateSelector
   216              id="date"
   217              label="Date"
   218              disableOptions={dateFieldDisabled()}
   219              ref={dateElement}
   220              value={date}
   221              borderBottom={true}
   222              onDateChange={(date: string, isValid: boolean) => {
   223                setIsDateValid(isValid);
   224                if (isValid) {
   225                  setDate(date);
   226                }
   227              }}
   228            />
   229            <Grid item xs={12} sx={modalStyleUtils.modalButtonBar}>
   230              <Button
   231                id={"reset"}
   232                type="button"
   233                variant="regular"
   234                onClick={resetForm}
   235                label={"Reset"}
   236              />
   237              <Button
   238                id={"save"}
   239                type="submit"
   240                variant="callAction"
   241                disabled={
   242                  (statusEnabled && type === "") ||
   243                  (statusEnabled && !isDateValid) ||
   244                  isSaving
   245                }
   246                onClick={saveNewRetentionPolicy}
   247                label={"Save"}
   248              />
   249            </Grid>
   250          </FormLayout>
   251        </form>
   252      </ModalWrapper>
   253    );
   254  };
   255  
   256  export default SetRetention;