github.com/minio/console@v1.4.1/web-app/src/screens/Console/Account/EditServiceAccount.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, { useEffect, useState, Fragment } from "react"; 18 import { 19 Box, 20 Button, 21 ChangeAccessPolicyIcon, 22 DateTimeInput, 23 Grid, 24 InputBox, 25 Switch, 26 } from "mds"; 27 import { api } from "api"; 28 import { errorToHandler } from "api/errors"; 29 import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper"; 30 import { ApiError } from "api/consoleApi"; 31 import { useAppDispatch } from "store"; 32 import { encodeURLString } from "common/utils"; 33 import { setErrorSnackMessage, setModalErrorSnackMessage } from "systemSlice"; 34 import ModalWrapper from "../Common/ModalWrapper/ModalWrapper"; 35 import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary"; 36 import { DateTime } from "luxon"; 37 38 interface IServiceAccountPolicyProps { 39 open: boolean; 40 selectedAccessKey: string | null; 41 closeModalAndRefresh: () => void; 42 } 43 44 const EditServiceAccount = ({ 45 open, 46 selectedAccessKey, 47 closeModalAndRefresh, 48 }: IServiceAccountPolicyProps) => { 49 const dispatch = useAppDispatch(); 50 const [loading, setLoading] = useState<boolean>(false); 51 const [policyDefinition, setPolicyDefinition] = useState<any>(""); 52 53 const [name, setName] = useState<string>(""); 54 const [description, setDescription] = useState<string>(""); 55 const [expiry, setExpiry] = useState<any>(); 56 const [status, setStatus] = useState<string | undefined>("enabled"); 57 58 useEffect(() => { 59 if (!loading && selectedAccessKey !== "") { 60 const sourceAccKey = encodeURLString(selectedAccessKey); 61 setLoading(true); 62 api.serviceAccounts 63 .getServiceAccount(sourceAccKey) 64 .then((res) => { 65 setLoading(false); 66 const saInfo = res.data; 67 68 setName(saInfo?.name || ""); 69 70 if (saInfo?.expiration) { 71 setExpiry(DateTime.fromISO(saInfo?.expiration)); 72 } 73 74 setDescription(saInfo?.description || ""); 75 setStatus(saInfo.accountStatus); 76 77 setPolicyDefinition(saInfo.policy || ""); 78 }) 79 .catch((err) => { 80 setLoading(false); 81 dispatch(setModalErrorSnackMessage(errorToHandler(err))); 82 }); 83 } 84 // eslint-disable-next-line react-hooks/exhaustive-deps 85 }, [selectedAccessKey]); 86 87 const setPolicy = (event: React.FormEvent, newPolicy: string) => { 88 event.preventDefault(); 89 api.serviceAccounts 90 .updateServiceAccount(encodeURLString(selectedAccessKey), { 91 policy: newPolicy, 92 description: description, 93 expiry: expiry, 94 name: name, 95 status: status, 96 }) 97 .then(() => { 98 closeModalAndRefresh(); 99 }) 100 .catch(async (res) => { 101 const err = (await res.json()) as ApiError; 102 dispatch(setErrorSnackMessage(errorToHandler(err))); 103 }); 104 }; 105 106 return ( 107 <ModalWrapper 108 title={`Edit details of - ${selectedAccessKey}`} 109 modalOpen={open} 110 onClose={() => { 111 closeModalAndRefresh(); 112 }} 113 titleIcon={<ChangeAccessPolicyIcon />} 114 > 115 <form 116 noValidate 117 autoComplete="off" 118 onSubmit={(e: React.FormEvent<HTMLFormElement>) => { 119 setPolicy(e, policyDefinition); 120 }} 121 > 122 <Grid container> 123 <Grid item xs={12}> 124 <CodeMirrorWrapper 125 label={`Access Key Policy`} 126 value={policyDefinition} 127 onChange={(value) => { 128 setPolicyDefinition(value); 129 }} 130 editorHeight={"350px"} 131 helptip={ 132 <Fragment> 133 <a 134 target="blank" 135 href="https://min.io/docs/minio/kubernetes/upstream/administration/identity-access-management/policy-based-access-control.html#policy-document-structure" 136 > 137 Guide to access policy structure 138 </a> 139 </Fragment> 140 } 141 /> 142 </Grid> 143 <Box 144 sx={{ 145 marginBottom: "15px", 146 marginTop: "15px", 147 display: "flex", 148 width: "100%", 149 "& label": { width: "195px" }, 150 }} 151 > 152 <DateTimeInput 153 noLabelMinWidth 154 value={expiry} 155 onChange={(e) => { 156 setExpiry(e); 157 }} 158 id="expiryTime" 159 label={"Expiry"} 160 timeFormat={"24h"} 161 secondsSelector={false} 162 /> 163 </Box> 164 <Grid 165 xs={12} 166 sx={{ 167 marginBottom: "15px", 168 }} 169 > 170 <InputBox 171 value={name} 172 size={120} 173 label={"Name"} 174 id={"name"} 175 name={"name"} 176 type={"text"} 177 placeholder={"Enter a name"} 178 onChange={(e) => { 179 setName(e.target.value); 180 }} 181 /> 182 </Grid> 183 <Grid 184 xs={12} 185 sx={{ 186 marginBottom: "15px", 187 }} 188 > 189 <InputBox 190 size={120} 191 value={description} 192 label={"Description"} 193 id={"description"} 194 name={"description"} 195 type={"text"} 196 placeholder={"Enter a description"} 197 onChange={(e) => { 198 setDescription(e.target.value); 199 }} 200 /> 201 </Grid> 202 <Grid 203 xs={12} 204 sx={{ 205 display: "flex", 206 alignItems: "center", 207 justifyContent: "start", 208 fontWeight: 600, 209 color: "rgb(7, 25, 62)", 210 gap: 2, 211 marginBottom: "15px", 212 }} 213 > 214 <label style={{ width: "150px" }}>Status</label> 215 <Box 216 sx={{ 217 padding: "2px", 218 }} 219 > 220 <Switch 221 style={{ 222 gap: "115px", 223 }} 224 indicatorLabels={["Enabled", "Disabled"]} 225 checked={status === "on"} 226 id="saStatus" 227 name="saStatus" 228 label="" 229 onChange={(e) => { 230 setStatus(e.target.checked ? "on" : "off"); 231 }} 232 value="yes" 233 /> 234 </Box> 235 </Grid> 236 <Grid item xs={12} sx={modalStyleUtils.modalButtonBar}> 237 <Button 238 id={"cancel-sa-policy"} 239 type="button" 240 variant="regular" 241 onClick={() => { 242 closeModalAndRefresh(); 243 }} 244 disabled={loading} 245 label={"Cancel"} 246 /> 247 <Button 248 id={"save-sa-policy"} 249 type="submit" 250 variant="callAction" 251 color="primary" 252 disabled={loading} 253 label={"Update"} 254 /> 255 </Grid> 256 </Grid> 257 </form> 258 </ModalWrapper> 259 ); 260 }; 261 262 export default EditServiceAccount;