github.com/minio/console@v1.4.1/web-app/src/screens/Console/KMS/ListKeys.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 } from "react"; 18 import { 19 AddIcon, 20 Button, 21 DataTable, 22 Grid, 23 PageLayout, 24 RefreshIcon, 25 UploadIcon, 26 } from "mds"; 27 import { useNavigate } from "react-router-dom"; 28 import api from "../../../common/api"; 29 import { 30 hasPermission, 31 SecureComponent, 32 } from "../../../common/SecureComponent"; 33 import { 34 CONSOLE_UI_RESOURCE, 35 IAM_PAGES, 36 IAM_SCOPES, 37 } from "../../../common/SecureComponent/permissions"; 38 import { ErrorResponseHandler } from "../../../common/types"; 39 import { useAppDispatch } from "../../../store"; 40 import { setErrorSnackMessage, setHelpName } from "../../../systemSlice"; 41 import withSuspense from "../Common/Components/withSuspense"; 42 import SearchBox from "../Common/SearchBox"; 43 import TooltipWrapper from "../Common/TooltipWrapper/TooltipWrapper"; 44 import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper"; 45 import HelpMenu from "../HelpMenu"; 46 47 const DeleteKMSModal = withSuspense( 48 React.lazy(() => import("./DeleteKMSModal")), 49 ); 50 51 const ListKeys = () => { 52 const dispatch = useAppDispatch(); 53 const navigate = useNavigate(); 54 55 const [filter, setFilter] = useState<string>(""); 56 const [deleteOpen, setDeleteOpen] = useState<boolean>(false); 57 const [selectedKey, setSelectedKey] = useState<string>(""); 58 const [loading, setLoading] = useState<boolean>(false); 59 const [records, setRecords] = useState<[]>([]); 60 61 const deleteKey = hasPermission(CONSOLE_UI_RESOURCE, [ 62 IAM_SCOPES.KMS_DELETE_KEY, 63 ]); 64 const createKey = hasPermission(CONSOLE_UI_RESOURCE, [ 65 IAM_SCOPES.KMS_CREATE_KEY, 66 ]); 67 68 const importKey = hasPermission(CONSOLE_UI_RESOURCE, [ 69 IAM_SCOPES.KMS_IMPORT_KEY, 70 ]); 71 72 const displayKeys = hasPermission(CONSOLE_UI_RESOURCE, [ 73 IAM_SCOPES.KMS_LIST_KEYS, 74 ]); 75 76 useEffect(() => { 77 fetchRecords(); 78 }, []); 79 80 useEffect(() => { 81 setLoading(true); 82 }, [filter]); 83 84 useEffect(() => { 85 if (loading) { 86 if (displayKeys) { 87 let pattern = filter.trim() === "" ? "*" : filter.trim(); 88 api 89 .invoke("GET", `/api/v1/kms/keys?pattern=${pattern}`) 90 .then((res) => { 91 setLoading(false); 92 setRecords(res.results); 93 }) 94 .catch((err: ErrorResponseHandler) => { 95 setLoading(false); 96 dispatch(setErrorSnackMessage(err)); 97 }); 98 } else { 99 setLoading(false); 100 } 101 } 102 }, [loading, setLoading, setRecords, dispatch, displayKeys, filter]); 103 104 const fetchRecords = () => { 105 setLoading(true); 106 }; 107 108 const confirmDeleteKey = (key: string) => { 109 setDeleteOpen(true); 110 setSelectedKey(key); 111 }; 112 113 const closeDeleteModalAndRefresh = (refresh: boolean) => { 114 setDeleteOpen(false); 115 116 if (refresh) { 117 fetchRecords(); 118 } 119 }; 120 121 const tableActions: any[] = []; 122 if (deleteKey) { 123 tableActions.push({ 124 type: "delete", 125 onClick: confirmDeleteKey, 126 sendOnlyId: true, 127 disableButtonFunction: () => !deleteKey, 128 }); 129 } 130 131 useEffect(() => { 132 dispatch(setHelpName("list_keys")); 133 }, [dispatch]); 134 135 return ( 136 <React.Fragment> 137 {deleteOpen && ( 138 <DeleteKMSModal 139 deleteOpen={deleteOpen} 140 selectedItem={selectedKey} 141 closeDeleteModalAndRefresh={closeDeleteModalAndRefresh} 142 /> 143 )} 144 <PageHeaderWrapper 145 label="Key Management Service Keys" 146 actions={<HelpMenu />} 147 /> 148 149 <PageLayout> 150 <Grid container> 151 <Grid 152 item 153 xs={12} 154 sx={{ 155 display: "flex", 156 alignItems: "center", 157 justifyContent: "flex-end", 158 "& button": { 159 marginLeft: "8px", 160 }, 161 }} 162 > 163 <SecureComponent 164 scopes={[IAM_SCOPES.KMS_LIST_KEYS]} 165 resource={CONSOLE_UI_RESOURCE} 166 errorProps={{ disabled: true }} 167 > 168 <SearchBox 169 onChange={setFilter} 170 placeholder="Search Keys with pattern" 171 value={filter} 172 /> 173 </SecureComponent> 174 175 <SecureComponent 176 scopes={[IAM_SCOPES.KMS_LIST_KEYS]} 177 resource={CONSOLE_UI_RESOURCE} 178 errorProps={{ disabled: true }} 179 > 180 <TooltipWrapper tooltip={"Refresh"}> 181 <Button 182 id={"refresh-keys"} 183 variant="regular" 184 icon={<RefreshIcon />} 185 onClick={() => setLoading(true)} 186 /> 187 </TooltipWrapper> 188 </SecureComponent> 189 {importKey ? ( 190 <SecureComponent 191 scopes={[IAM_SCOPES.KMS_IMPORT_KEY]} 192 resource={CONSOLE_UI_RESOURCE} 193 errorProps={{ disabled: true }} 194 > 195 <TooltipWrapper tooltip={"Import Key"}> 196 <Button 197 id={"import-key"} 198 variant={"regular"} 199 icon={<UploadIcon />} 200 onClick={() => { 201 navigate(IAM_PAGES.KMS_KEYS_IMPORT); 202 }} 203 /> 204 </TooltipWrapper> 205 </SecureComponent> 206 ) : null} 207 {createKey ? ( 208 <SecureComponent 209 scopes={[IAM_SCOPES.KMS_CREATE_KEY]} 210 resource={CONSOLE_UI_RESOURCE} 211 errorProps={{ disabled: true }} 212 > 213 <TooltipWrapper tooltip={"Create Key"}> 214 <Button 215 id={"create-key"} 216 label={"Create Key"} 217 variant={"callAction"} 218 icon={<AddIcon />} 219 onClick={() => navigate(IAM_PAGES.KMS_KEYS_ADD)} 220 /> 221 </TooltipWrapper> 222 </SecureComponent> 223 ) : null} 224 </Grid> 225 <Grid item xs={12} sx={{ marginTop: "5px" }}> 226 <SecureComponent 227 scopes={[IAM_SCOPES.KMS_LIST_KEYS]} 228 resource={CONSOLE_UI_RESOURCE} 229 errorProps={{ disabled: true }} 230 > 231 <DataTable 232 itemActions={tableActions} 233 columns={[ 234 { label: "Name", elementKey: "name" }, 235 { label: "Created By", elementKey: "createdBy" }, 236 { label: "Created At", elementKey: "createdAt" }, 237 ]} 238 isLoading={loading} 239 records={records} 240 entityName="Keys" 241 idField="name" 242 /> 243 </SecureComponent> 244 </Grid> 245 </Grid> 246 </PageLayout> 247 </React.Fragment> 248 ); 249 }; 250 251 export default ListKeys;