github.com/minio/console@v1.4.1/web-app/src/screens/Console/Buckets/BucketDetails/EnableQuota.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, useState } from "react"; 18 import { 19 BucketQuotaIcon, 20 Button, 21 FormLayout, 22 InputBox, 23 Switch, 24 Grid, 25 ProgressBar, 26 } from "mds"; 27 import { 28 calculateBytes, 29 getBytes, 30 k8sScalarUnitsExcluding, 31 } from "../../../../common/utils"; 32 33 import { modalStyleUtils } from "../../Common/FormComponents/common/styleLibrary"; 34 import ModalWrapper from "../../Common/ModalWrapper/ModalWrapper"; 35 import InputUnitMenu from "../../Common/FormComponents/InputUnitMenu/InputUnitMenu"; 36 37 import { setModalErrorSnackMessage } from "../../../../systemSlice"; 38 import { useAppDispatch } from "../../../../store"; 39 import { BucketQuota } from "api/consoleApi"; 40 import { api } from "api"; 41 import { errorToHandler } from "api/errors"; 42 43 interface IEnableQuotaProps { 44 open: boolean; 45 enabled: boolean; 46 cfg: BucketQuota | null; 47 selectedBucket: string; 48 closeModalAndRefresh: () => void; 49 } 50 51 const EnableQuota = ({ 52 open, 53 enabled, 54 cfg, 55 selectedBucket, 56 closeModalAndRefresh, 57 }: IEnableQuotaProps) => { 58 const dispatch = useAppDispatch(); 59 const [loading, setLoading] = useState<boolean>(false); 60 const [quotaEnabled, setQuotaEnabled] = useState<boolean>(false); 61 const [quotaSize, setQuotaSize] = useState<string>("1"); 62 const [quotaUnit, setQuotaUnit] = useState<string>("Ti"); 63 const [validInput, setValidInput] = useState<boolean>(false); 64 65 useEffect(() => { 66 if (enabled) { 67 setQuotaEnabled(true); 68 if (cfg) { 69 const unitCalc = calculateBytes(cfg.quota || 0, true, false, true); 70 71 setQuotaSize(unitCalc.total.toString()); 72 setQuotaUnit(unitCalc.unit); 73 setValidInput(true); 74 } 75 } 76 }, [enabled, cfg]); 77 78 useEffect(() => { 79 const valRegExp = /^\d*(?:\.\d{1,2})?$/; 80 81 if (!quotaEnabled) { 82 setValidInput(true); 83 return; 84 } 85 86 setValidInput(valRegExp.test(quotaSize)); 87 }, [quotaEnabled, quotaSize]); 88 89 const enableBucketEncryption = () => { 90 if (loading || !validInput) { 91 return; 92 } 93 94 api.buckets 95 .setBucketQuota(selectedBucket, { 96 enabled: quotaEnabled, 97 amount: parseInt(getBytes(quotaSize, quotaUnit, true)), 98 quota_type: "hard", 99 }) 100 .then(() => { 101 setLoading(false); 102 closeModalAndRefresh(); 103 }) 104 .catch((err) => { 105 setLoading(false); 106 dispatch(setModalErrorSnackMessage(errorToHandler(err.error))); 107 }); 108 }; 109 110 return ( 111 <ModalWrapper 112 modalOpen={open} 113 onClose={() => { 114 closeModalAndRefresh(); 115 }} 116 title="Enable Bucket Quota" 117 titleIcon={<BucketQuotaIcon />} 118 > 119 <form 120 noValidate 121 autoComplete="off" 122 onSubmit={(e: React.FormEvent<HTMLFormElement>) => { 123 e.preventDefault(); 124 enableBucketEncryption(); 125 }} 126 > 127 <FormLayout withBorders={false} containerPadding={false}> 128 <Switch 129 value="bucket_quota" 130 id="bucket_quota" 131 name="bucket_quota" 132 checked={quotaEnabled} 133 onChange={(event: React.ChangeEvent<HTMLInputElement>) => { 134 setQuotaEnabled(event.target.checked); 135 }} 136 label={"Enabled"} 137 /> 138 {quotaEnabled && ( 139 <InputBox 140 id="quota_size" 141 name="quota_size" 142 onChange={(e: React.ChangeEvent<HTMLInputElement>) => { 143 setQuotaSize(e.target.value); 144 if (!e.target.validity.valid) { 145 setValidInput(false); 146 } else { 147 setValidInput(true); 148 } 149 }} 150 label="Quota" 151 value={quotaSize} 152 required 153 min="1" 154 overlayObject={ 155 <InputUnitMenu 156 id={"quota_unit"} 157 onUnitChange={(newValue) => { 158 setQuotaUnit(newValue); 159 }} 160 unitSelected={quotaUnit} 161 unitsList={k8sScalarUnitsExcluding(["Ki"])} 162 disabled={false} 163 /> 164 } 165 error={!validInput ? "Please enter a valid quota" : ""} 166 /> 167 )} 168 <Grid item xs={12} sx={modalStyleUtils.modalButtonBar}> 169 <Button 170 id={"cancel"} 171 type="button" 172 variant="regular" 173 disabled={loading} 174 onClick={() => { 175 closeModalAndRefresh(); 176 }} 177 label={"Cancel"} 178 /> 179 180 <Button 181 id={"save"} 182 type="submit" 183 variant="callAction" 184 disabled={loading || !validInput} 185 label={"Save"} 186 /> 187 </Grid> 188 {loading && ( 189 <Grid item xs={12}> 190 <ProgressBar /> 191 </Grid> 192 )} 193 </FormLayout> 194 </form> 195 </ModalWrapper> 196 ); 197 }; 198 199 export default EnableQuota;