github.com/minio/console@v1.4.1/web-app/src/screens/Console/Users/DeleteUser.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, useEffect, useState } from "react"; 18 import { useNavigate } from "react-router-dom"; 19 import { setErrorSnackMessage } from "../../../systemSlice"; 20 import { ConfirmDeleteIcon, DataTable, InformativeMessage, Loader } from "mds"; 21 import { encodeURLString } from "../../../common/utils"; 22 import { IAM_PAGES } from "../../../common/SecureComponent/permissions"; 23 import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog"; 24 import { useAppDispatch } from "../../../store"; 25 import { api } from "api"; 26 import { UserServiceAccountItem } from "../../../api/consoleApi"; 27 import { errorToHandler } from "../../../api/errors"; 28 29 interface IDeleteUserProps { 30 closeDeleteModalAndRefresh: (refresh: boolean) => void; 31 deleteOpen: boolean; 32 selectedUsers: string[] | null; 33 } 34 35 const DeleteUser = ({ 36 closeDeleteModalAndRefresh, 37 deleteOpen, 38 selectedUsers, 39 }: IDeleteUserProps) => { 40 const navigate = useNavigate(); 41 const dispatch = useAppDispatch(); 42 43 const onClose = () => closeDeleteModalAndRefresh(false); 44 45 const [loadingSA, setLoadingSA] = useState<boolean>(true); 46 const [hasSA, setHasSA] = useState<boolean>(false); 47 const [userSAList, setUserSAList] = useState<UserServiceAccountItem[]>([]); 48 const [deleteLoading, setDeleteLoading] = useState<boolean>(false); 49 50 const userLoggedIn = localStorage.getItem("userLoggedIn") || ""; 51 52 useEffect(() => { 53 if (selectedUsers) { 54 api.users 55 .checkUserServiceAccounts(selectedUsers) 56 .then((res) => { 57 if (res.data) { 58 setUserSAList(res.data.userServiceAccountList ?? []); 59 if (res.data.hasSA) { 60 setHasSA(true); 61 } 62 } 63 }) 64 .catch((err) => 65 dispatch(setErrorSnackMessage(errorToHandler(err.error))), 66 ) 67 .finally(() => setLoadingSA(false)); 68 } 69 }, [selectedUsers, dispatch]); 70 71 if (!selectedUsers) { 72 return null; 73 } 74 const renderUsers = selectedUsers.map((user) => ( 75 <div key={user}> 76 <b>{user}</b> 77 </div> 78 )); 79 const viewAction = (selectionElement: any): void => { 80 navigate( 81 `${IAM_PAGES.USERS}/${encodeURLString(selectionElement.userName)}`, 82 ); 83 onClose(); 84 }; 85 const tableActions = [ 86 { 87 type: "view", 88 onClick: viewAction, 89 }, 90 ]; 91 92 const onConfirmDelete = () => { 93 for (let user of selectedUsers) { 94 if (user === userLoggedIn) { 95 dispatch( 96 setErrorSnackMessage({ 97 errorMessage: "Cannot delete currently logged in user", 98 detailedError: `Cannot delete currently logged in user ${userLoggedIn}`, 99 }), 100 ); 101 closeDeleteModalAndRefresh(true); 102 } else { 103 api.user 104 .removeUser(encodeURLString(user)) 105 .then((res) => { 106 closeDeleteModalAndRefresh(true); 107 navigate(`${IAM_PAGES.USERS}`); 108 }) 109 .finally(() => setDeleteLoading(false)); 110 } 111 } 112 }; 113 114 const noSAtext = 115 "Are you sure you want to delete the following " + 116 selectedUsers.length + 117 " " + 118 "user" + 119 (selectedUsers.length > 1 ? "s?" : "?"); 120 121 return ( 122 <ConfirmDialog 123 title={`Delete User${selectedUsers.length > 1 ? "s" : ""}`} 124 confirmText={"Delete"} 125 isOpen={deleteOpen} 126 titleIcon={<ConfirmDeleteIcon />} 127 isLoading={deleteLoading} 128 onConfirm={onConfirmDelete} 129 onClose={onClose} 130 confirmationContent={ 131 loadingSA ? ( 132 <Loader /> 133 ) : ( 134 <Fragment> 135 {hasSA ? ( 136 <Fragment> 137 <InformativeMessage 138 variant={"warning"} 139 message={ 140 <Fragment> 141 Click on a user to view the full listing of associated 142 Access Keys. All Access Keys associated with a user will 143 be deleted along with the user. 144 <br /> 145 <br /> 146 <strong>Are you sure you want to continue?</strong> 147 </Fragment> 148 } 149 title="Warning: One or more users selected has associated Access Keys." 150 sx={{ margin: "15px 0" }} 151 /> 152 <DataTable 153 itemActions={tableActions} 154 columns={[ 155 { label: "Username", elementKey: "userName" }, 156 { 157 label: "# Associated Access Keys", 158 elementKey: "numSAs", 159 }, 160 ]} 161 isLoading={loadingSA} 162 records={userSAList} 163 entityName="User Access Keys" 164 idField="userName" 165 customPaperHeight="250" 166 /> 167 </Fragment> 168 ) : ( 169 <Fragment> 170 {noSAtext} 171 {renderUsers} 172 </Fragment> 173 )} 174 </Fragment> 175 ) 176 } 177 /> 178 ); 179 }; 180 181 export default DeleteUser;