github.com/minio/console@v1.4.1/web-app/src/screens/Console/EventDestinations/CustomForms/ConfMySql.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, { useCallback, useEffect, useState } from "react"; 18 import { IElementValue } from "../../Configurations/types"; 19 import { 20 Box, 21 CommentBox, 22 FormLayout, 23 Grid, 24 InputBox, 25 RadioGroup, 26 ReadBox, 27 Switch, 28 } from "mds"; 29 30 interface IConfMySqlProps { 31 onChange: (newValue: IElementValue[]) => void; 32 } 33 34 const ConfMySql = ({ onChange }: IConfMySqlProps) => { 35 //Local States 36 const [useDsnString, setUseDsnString] = useState<boolean>(false); 37 const [dsnString, setDsnString] = useState<string>(""); 38 const [host, setHostname] = useState<string>(""); 39 const [dbName, setDbName] = useState<string>(""); 40 const [port, setPort] = useState<string>(""); 41 const [user, setUser] = useState<string>(""); 42 const [password, setPassword] = useState<string>(""); 43 44 const [table, setTable] = useState<string>(""); 45 const [format, setFormat] = useState<string>("namespace"); 46 const [queueDir, setQueueDir] = useState<string>(""); 47 const [queueLimit, setQueueLimit] = useState<string>(""); 48 const [comment, setComment] = useState<string>(""); 49 50 // dsn_string* (string) MySQL data-source-name connection string e.g. "<user>:<password>@tcp(<host>:<port>)/<database>" 51 // table* (string) DB table name to store/update events, table is auto-created 52 // format* (namespace*|access) 'namespace' reflects current bucket/object list and 'access' reflects a journal of object operations, defaults to 'namespace' 53 // queue_dir (path) staging dir for undelivered messages e.g. '/home/events' 54 // queue_limit (number) maximum limit for undelivered messages, defaults to '100000' 55 // comment (sentence) optionally add a comment to this setting 56 57 const parseDsnString = ( 58 input: string, 59 keys: string[], 60 ): Map<string, string> => { 61 let kvFields: Map<string, string> = new Map(); 62 const regex = /(.*?):(.*?)@tcp\((.*?):(.*?)\)\/(.*?)$/gm; 63 let m; 64 65 while ((m = regex.exec(input)) !== null) { 66 // This is necessary to avoid infinite loops with zero-width matches 67 if (m.index === regex.lastIndex) { 68 regex.lastIndex++; 69 } 70 71 kvFields.set("user", m[1]); 72 kvFields.set("password", m[2]); 73 kvFields.set("host", m[3]); 74 kvFields.set("port", m[4]); 75 kvFields.set("dbname", m[5]); 76 } 77 78 return kvFields; 79 }; 80 81 const configToDsnString = useCallback((): string => { 82 return `${user}:${password}@tcp(${host}:${port})/${dbName}`; 83 }, [user, password, host, port, dbName]); 84 85 useEffect(() => { 86 if (dsnString !== "") { 87 const formValues = [ 88 { key: "dsn_string", value: dsnString }, 89 { key: "table", value: table }, 90 { key: "format", value: format }, 91 { key: "queue_dir", value: queueDir }, 92 { key: "queue_limit", value: queueLimit }, 93 { key: "comment", value: comment }, 94 ]; 95 96 onChange(formValues); 97 } 98 }, [dsnString, table, format, queueDir, queueLimit, comment, onChange]); 99 100 useEffect(() => { 101 const cs = configToDsnString(); 102 setDsnString(cs); 103 }, [user, dbName, password, port, host, setDsnString, configToDsnString]); 104 105 const switcherChangeEvt = (event: React.ChangeEvent<HTMLInputElement>) => { 106 if (event.target.checked) { 107 // build dsn_string 108 const cs = configToDsnString(); 109 setDsnString(cs); 110 } else { 111 // parse dsn_string 112 const kv = parseDsnString(dsnString, [ 113 "host", 114 "port", 115 "dbname", 116 "user", 117 "password", 118 ]); 119 setHostname(kv.get("host") ? kv.get("host") + "" : ""); 120 setPort(kv.get("port") ? kv.get("port") + "" : ""); 121 setDbName(kv.get("dbname") ? kv.get("dbname") + "" : ""); 122 setUser(kv.get("user") ? kv.get("user") + "" : ""); 123 setPassword(kv.get("password") ? kv.get("password") + "" : ""); 124 } 125 126 setUseDsnString(event.target.checked); 127 }; 128 129 return ( 130 <FormLayout withBorders={false} containerPadding={false}> 131 <Switch 132 label={"Enter DNS String"} 133 checked={useDsnString} 134 id="checkedB" 135 name="checkedB" 136 onChange={switcherChangeEvt} 137 value={"dnsString"} 138 /> 139 {useDsnString ? ( 140 <React.Fragment> 141 <Box className={"inputItem"}> 142 <InputBox 143 id="dsn-string" 144 name="dsn_string" 145 label="DSN String" 146 value={dsnString} 147 onChange={(e: React.ChangeEvent<HTMLInputElement>) => { 148 setDsnString(e.target.value); 149 }} 150 /> 151 </Box> 152 </React.Fragment> 153 ) : ( 154 <React.Fragment> 155 <Box> 156 <Box 157 withBorders 158 useBackground 159 sx={{ 160 overflowY: "auto", 161 height: 170, 162 marginBottom: 12, 163 }} 164 > 165 <InputBox 166 id="host" 167 name="host" 168 label="" 169 placeholder="Enter Host" 170 value={host} 171 onChange={(e: React.ChangeEvent<HTMLInputElement>) => { 172 setHostname(e.target.value); 173 }} 174 /> 175 <InputBox 176 id="db-name" 177 name="db-name" 178 label="" 179 placeholder="Enter DB Name" 180 value={dbName} 181 onChange={(e: React.ChangeEvent<HTMLInputElement>) => { 182 setDbName(e.target.value); 183 }} 184 /> 185 <InputBox 186 id="port" 187 name="port" 188 label="" 189 placeholder="Enter Port" 190 value={port} 191 onChange={(e: React.ChangeEvent<HTMLInputElement>) => { 192 setPort(e.target.value); 193 }} 194 /> 195 <InputBox 196 id="user" 197 name="user" 198 label="" 199 placeholder="Enter User" 200 value={user} 201 onChange={(e: React.ChangeEvent<HTMLInputElement>) => { 202 setUser(e.target.value); 203 }} 204 /> 205 <InputBox 206 id="password" 207 name="password" 208 label="" 209 placeholder="Enter Password" 210 type="password" 211 value={password} 212 onChange={(e: React.ChangeEvent<HTMLInputElement>) => { 213 setPassword(e.target.value); 214 }} 215 /> 216 </Box> 217 </Box> 218 <Grid item xs={12} sx={{ margin: "12px 0" }}> 219 <ReadBox label={"Connection String"} multiLine> 220 {dsnString} 221 </ReadBox> 222 </Grid> 223 </React.Fragment> 224 )} 225 <InputBox 226 id="table" 227 name="table" 228 label="Table" 229 placeholder="Enter Table Name" 230 value={table} 231 tooltip="DB table name to store/update events, table is auto-created" 232 onChange={(e: React.ChangeEvent<HTMLInputElement>) => { 233 setTable(e.target.value); 234 }} 235 /> 236 <RadioGroup 237 currentValue={format} 238 id="format" 239 name="format" 240 label="Format" 241 onChange={(e) => { 242 setFormat(e.target.value); 243 }} 244 tooltip="'namespace' reflects current bucket/object list and 'access' reflects a journal of object operations, defaults to 'namespace'" 245 selectorOptions={[ 246 { label: "Namespace", value: "namespace" }, 247 { label: "Access", value: "access" }, 248 ]} 249 /> 250 <InputBox 251 id="queue-dir" 252 name="queue_dir" 253 label="Queue Dir" 254 placeholder="Enter Queue Dir" 255 value={queueDir} 256 tooltip="Staging directory for undelivered messages e.g. '/home/events'" 257 onChange={(e: React.ChangeEvent<HTMLInputElement>) => { 258 setQueueDir(e.target.value); 259 }} 260 /> 261 <InputBox 262 id="queue-limit" 263 name="queue_limit" 264 label="Queue Limit" 265 placeholder="Enter Queue Limit" 266 type="number" 267 value={queueLimit} 268 tooltip="Maximum limit for undelivered messages, defaults to '10000'" 269 onChange={(e: React.ChangeEvent<HTMLInputElement>) => { 270 setQueueLimit(e.target.value); 271 }} 272 /> 273 <CommentBox 274 id="comment" 275 name="comment" 276 label="Comment" 277 placeholder="Enter custom notes if any" 278 value={comment} 279 onChange={(e) => { 280 setComment(e.target.value); 281 }} 282 /> 283 </FormLayout> 284 ); 285 }; 286 287 export default ConfMySql;