github.com/minio/console@v1.4.1/web-app/src/screens/Console/Dashboard/DownloadWidgetDataButton.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, { Fragment } from "react"; 18 import { Box, DownloadIcon, DropdownSelector } from "mds"; 19 import { exportComponentAsPNG } from "react-component-export-image"; 20 import { ErrorResponseHandler } from "../../../common/types"; 21 import { useAppDispatch } from "../../../../src/store"; 22 import { setErrorSnackMessage } from "../../../../src/systemSlice"; 23 24 interface IDownloadWidgetDataButton { 25 title: any; 26 componentRef: any; 27 data: any; 28 } 29 30 const DownloadWidgetDataButton = ({ 31 title, 32 componentRef, 33 data, 34 }: IDownloadWidgetDataButton) => { 35 const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); 36 const openDownloadMenu = Boolean(anchorEl); 37 const handleClick = (event: React.MouseEvent<HTMLElement>) => { 38 setAnchorEl(event.currentTarget); 39 }; 40 const handleCloseDownload = () => { 41 setAnchorEl(null); 42 }; 43 const download = (filename: string, text: string) => { 44 let element = document.createElement("a"); 45 element.setAttribute("href", "data:text/plain;charset=utf-8," + text); 46 element.setAttribute("download", filename); 47 48 element.style.display = "none"; 49 document.body.appendChild(element); 50 51 element.click(); 52 document.body.removeChild(element); 53 }; 54 55 const dispatch = useAppDispatch(); 56 const onDownloadError = (err: ErrorResponseHandler) => 57 dispatch(setErrorSnackMessage(err)); 58 59 const convertToCSV = (objectToConvert: any) => { 60 const array = [Object.keys(objectToConvert[0])].concat(objectToConvert); 61 return array 62 .map((it) => { 63 return Object.values(it).toString(); 64 }) 65 .join("\n"); 66 }; 67 68 const widgetDataCSVFileName = () => { 69 if (title !== null) { 70 return (title + "_" + Date.now().toString() + ".csv") 71 .replace(/\s+/g, "") 72 .trim() 73 .toLowerCase(); 74 } else { 75 return "widgetData_" + Date.now().toString() + ".csv"; 76 } 77 }; 78 79 const downloadAsCSV = () => { 80 if (data !== null && data.length > 0) { 81 download(widgetDataCSVFileName(), convertToCSV(data)); 82 } else { 83 let err: ErrorResponseHandler; 84 err = { 85 errorMessage: "Unable to download widget data", 86 detailedError: "Unable to download widget data - data not available", 87 }; 88 onDownloadError(err); 89 } 90 }; 91 92 const downloadAsPNG = () => { 93 if (title !== null) { 94 const pngFileName = (title + "_" + Date.now().toString() + ".png") 95 .replace(/\s+/g, "") 96 .trim() 97 .toLowerCase(); 98 exportComponentAsPNG(componentRef, { fileName: pngFileName }); 99 } else { 100 const pngFileName = "widgetData_" + Date.now().toString() + ".png"; 101 exportComponentAsPNG(componentRef, { fileName: pngFileName }); 102 } 103 }; 104 105 const handleSelectedOption = (selectOption: string) => { 106 if (selectOption === "csv") { 107 downloadAsCSV(); 108 } else if (selectOption === "png") { 109 downloadAsPNG(); 110 } 111 }; 112 113 return ( 114 <Fragment> 115 <Box 116 sx={{ 117 justifyItems: "center", 118 "& .download-icon": { 119 backgroundColor: "transparent", 120 border: 0, 121 padding: 0, 122 cursor: "pointer", 123 "& svg": { 124 color: "#D0D0D0", 125 height: 16, 126 }, 127 "&:hover": { 128 "& svg": { 129 color: "#404143", 130 }, 131 }, 132 }, 133 }} 134 > 135 <button className={"download-icon"} onClick={handleClick}> 136 <DownloadIcon /> 137 </button> 138 <DropdownSelector 139 id={"download-widget-main-menu"} 140 options={[ 141 { label: "Download as CSV", value: "csv" }, 142 { label: "Download as PNG", value: "png" }, 143 ]} 144 selectedOption={""} 145 onSelect={(value) => handleSelectedOption(value)} 146 hideTriggerAction={() => { 147 handleCloseDownload(); 148 }} 149 open={openDownloadMenu} 150 anchorEl={anchorEl} 151 anchorOrigin={"end"} 152 /> 153 </Box> 154 </Fragment> 155 ); 156 }; 157 158 export default DownloadWidgetDataButton;