diff --git a/portal-ui/src/screens/Console/Buckets/ViewBucket/SetRetentionConfig.tsx b/portal-ui/src/screens/Console/Buckets/ViewBucket/SetRetentionConfig.tsx new file mode 100644 index 000000000..4618d6298 --- /dev/null +++ b/portal-ui/src/screens/Console/Buckets/ViewBucket/SetRetentionConfig.tsx @@ -0,0 +1,173 @@ +// This file is part of MinIO Console Server +// Copyright (c) 2020 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React, { useEffect, useState } from "react"; +import Grid from "@material-ui/core/Grid"; +import { Button, LinearProgress } from "@material-ui/core"; +import { createStyles, Theme, withStyles } from "@material-ui/core/styles"; +import { modalBasic } from "../../Common/FormComponents/common/styleLibrary"; +import api from "../../../../common/api"; +import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper"; +import ErrorBlock from "../../../shared/ErrorBlock"; +import RadioGroupSelector from "../../Common/FormComponents/RadioGroupSelector/RadioGroupSelector"; +import InputBoxWrapper from "../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper"; + +const styles = (theme: Theme) => + createStyles({ + ...modalBasic, + }); + +interface ISetRetentionConfigProps { + classes: any; + open: boolean; + bucketName: string; + closeModalAndRefresh: () => void; +} + +const SetRetentionConfig = ({ + classes, + open, + bucketName, + closeModalAndRefresh, +}: ISetRetentionConfigProps) => { + const [addLoading, setAddLoading] = useState(false); + const [error, setError] = useState(""); + const [retentionMode, setRetentionMode] = useState("compliance"); + const [retentionUnit, setRetentionUnit] = useState("days"); + const [retentionValidity, setRetentionValidity] = useState(1); + const [valid, setValid] = useState(false); + + const setRetention = (event: React.FormEvent) => { + event.preventDefault(); + if (addLoading) { + return; + } + setAddLoading(true); + api + .invoke("PUT", `/api/v1/buckets/${bucketName}/retention`, { + mode: retentionMode, + unit: retentionUnit, + validity: retentionValidity, + }) + .then((res) => { + setAddLoading(false); + setError(""); + closeModalAndRefresh(); + }) + .catch((err) => { + setAddLoading(false); + setError(err); + }); + }; + + useEffect(() => { + if (Number.isNaN(retentionValidity) || retentionValidity < 1) { + setValid(false); + return; + } + setValid(true); + }, [retentionValidity]); + + return ( + { + setError(""); + closeModalAndRefresh(); + }} + > + ) => { + setRetention(e); + }} + > + + + {error !== "" && ( + + + + )} + + ) => { + setRetentionMode(e.target.value as string); + }} + selectorOptions={[ + { value: "compliance", label: "Compliance" }, + { value: "governance", label: "Governance" }, + ]} + /> + + + ) => { + setRetentionUnit(e.target.value as string); + }} + selectorOptions={[ + { value: "days", label: "Days" }, + { value: "years", label: "Years" }, + ]} + /> + + + ) => { + setRetentionValidity(e.target.valueAsNumber); + }} + label="Retention Validity" + value={String(retentionValidity)} + required + min="1" + /> + + + + + Set + + + {addLoading && ( + + + + )} + + + + ); +}; + +export default withStyles(styles)(SetRetentionConfig); diff --git a/portal-ui/src/screens/Console/Buckets/ViewBucket/ViewBucket.tsx b/portal-ui/src/screens/Console/Buckets/ViewBucket/ViewBucket.tsx index d74e0b867..223b50923 100644 --- a/portal-ui/src/screens/Console/Buckets/ViewBucket/ViewBucket.tsx +++ b/portal-ui/src/screens/Console/Buckets/ViewBucket/ViewBucket.tsx @@ -37,6 +37,7 @@ import { } from "../types"; import { Button } from "@material-ui/core"; import SetAccessPolicy from "./SetAccessPolicy"; +import SetRetentionConfig from "./SetRetentionConfig"; import { CreateIcon } from "../../../../icons"; import AddEvent from "./AddEvent"; import DeleteEvent from "./DeleteEvent"; @@ -215,10 +216,9 @@ const ViewBucket = ({ classes, match }: IViewBucketProps) => { ); const [curTab, setCurTab] = useState(0); const [addScreenOpen, setAddScreenOpen] = useState(false); - const [ - enableEncryptionScreenOpen, - setEnableEncryptionScreenOpen, - ] = useState(false); + const [enableEncryptionScreenOpen, setEnableEncryptionScreenOpen] = useState< + boolean + >(false); const [deleteOpen, setDeleteOpen] = useState(false); const [selectedEvent, setSelectedEvent] = useState(null); const [bucketSize, setBucketSize] = useState("0"); @@ -226,6 +226,9 @@ const ViewBucket = ({ classes, match }: IViewBucketProps) => { const [openSetReplication, setOpenSetReplication] = useState(false); const [isVersioned, setIsVersioned] = useState(false); const [encryptionEnabled, setEncryptionEnabled] = useState(false); + const [retentionConfigOpen, setRetentionConfigOpen] = useState( + false + ); const fetchEvents = useCallback(() => { setLoadingBucket(true); @@ -319,6 +322,7 @@ const ViewBucket = ({ classes, match }: IViewBucketProps) => { const closeAddModalAndRefresh = () => { setAccessPolicyScreenOpen(false); + setRetentionConfigOpen(false); loadInfo(); }; @@ -420,6 +424,15 @@ const ViewBucket = ({ classes, match }: IViewBucketProps) => { }} /> )} + {retentionConfigOpen && ( + { + closeAddModalAndRefresh(); + }} + /> + )} {openSetReplication && ( { @@ -511,6 +524,19 @@ const ViewBucket = ({ classes, match }: IViewBucketProps) => { Change Access Policy + + { + setRetentionConfigOpen(true); + }} + > + Set Retention Configuration + +