2
0

AuthForm.tsx 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. import React, { useContext, useMemo, useState } from 'react';
  2. import { makeStyles, Theme, Typography } from '@material-ui/core';
  3. import { useTranslation } from 'react-i18next';
  4. import CustomButton from '@/components/customButton/CustomButton';
  5. import CustomInput from '@/components/customInput/CustomInput';
  6. import { useFormValidation } from '@/hooks';
  7. import { formatForm } from '@/utils';
  8. import { useNavigate } from 'react-router-dom';
  9. import { rootContext, authContext, dataContext } from '@/context';
  10. import { MILVUS_CLIENT_ID } from '@/consts';
  11. import { CustomRadio } from '@/components/customRadio/CustomRadio';
  12. import Icons from '@/components/icons/Icons';
  13. import CustomToolTip from '@/components/customToolTip/CustomToolTip';
  14. const useStyles = makeStyles((theme: Theme) => ({
  15. wrapper: {
  16. display: 'flex',
  17. flexDirection: 'column',
  18. alignItems: 'flex-end',
  19. padding: theme.spacing(0, 3),
  20. position: 'relative',
  21. },
  22. titleWrapper: {
  23. textAlign: 'left',
  24. alignSelf: 'flex-start',
  25. padding: theme.spacing(3, 0),
  26. '& svg': {
  27. fontSize: 15,
  28. marginLeft: theme.spacing(0.5),
  29. },
  30. },
  31. input: {
  32. margin: theme.spacing(0.5, 0, 0),
  33. },
  34. toggle: {
  35. display: 'flex',
  36. width: '100%',
  37. justifyContent: 'flex-start',
  38. },
  39. star: {
  40. position: 'absolute',
  41. top: -48,
  42. right: -8,
  43. marginTop: theme.spacing(1),
  44. alignItems: 'center',
  45. height: '32px',
  46. lineHeight: '32px',
  47. color: '#333',
  48. background: '#f1f1f1',
  49. padding: theme.spacing(0.5, 0, 0.5, 1),
  50. fontSize: 13,
  51. display: 'block',
  52. width: '132px',
  53. textDecoration: 'none',
  54. marginRight: theme.spacing(1),
  55. fontWeight: 500,
  56. '&:hover': {
  57. fontWeight: 'bold',
  58. },
  59. },
  60. icon: {
  61. verticalAlign: '-5px',
  62. marginRight: theme.spacing(1),
  63. },
  64. }));
  65. export const AuthForm = (props: any) => {
  66. // styles
  67. const classes = useStyles();
  68. // context
  69. const { openSnackBar } = useContext(rootContext);
  70. const { authReq, setAuthReq, login } = useContext(authContext);
  71. const { setDatabase } = useContext(dataContext);
  72. // i18n
  73. const { t: commonTrans } = useTranslation();
  74. const attuTrans = commonTrans('attu');
  75. const { t: btnTrans } = useTranslation('btn');
  76. const { t: warningTrans } = useTranslation('warning');
  77. const { t: successTrans } = useTranslation('success');
  78. const { t: dbTrans } = useTranslation('database');
  79. // hooks
  80. const navigate = useNavigate();
  81. // UI states
  82. const [withPass, setWithPass] = useState(authReq.username.length > 0);
  83. // form validation
  84. const checkedForm = useMemo(() => {
  85. return formatForm(authReq);
  86. }, [authReq]);
  87. const { validation, checkIsValid } = useFormValidation(checkedForm);
  88. // handle input change
  89. const handleInputChange = (
  90. key: 'address' | 'username' | 'password' | 'database' | 'token',
  91. value: string | boolean
  92. ) => {
  93. setAuthReq(v => ({ ...v, [key]: value }));
  94. };
  95. // const {
  96. // withPrometheus,
  97. // setWithPrometheus,
  98. // prometheusAddress,
  99. // prometheusInstance,
  100. // prometheusNamespace,
  101. // setPrometheusAddress,
  102. // setPrometheusInstance,
  103. // setPrometheusNamespace,
  104. // } = useContext(prometheusContext);
  105. // const prometheusConfigs: ITextfieldConfig[] = useMemo(
  106. // () => [
  107. // {
  108. // label: `${attuTrans.prometheusAddress}`,
  109. // key: 'prometheus_address',
  110. // onChange: setPrometheusAddress,
  111. // variant: 'filled',
  112. // className: classes.input,
  113. // placeholder: attuTrans.prometheusAddress,
  114. // fullWidth: true,
  115. // defaultValue: prometheusAddress,
  116. // },
  117. // {
  118. // label: `${attuTrans.prometheusNamespace}`,
  119. // key: 'prometheus_namespace',
  120. // onChange: setPrometheusNamespace,
  121. // variant: 'filled',
  122. // className: classes.input,
  123. // placeholder: attuTrans.prometheusNamespace,
  124. // fullWidth: true,
  125. // defaultValue: prometheusNamespace,
  126. // },
  127. // {
  128. // label: `${attuTrans.prometheusInstance}`,
  129. // key: 'prometheus_instance',
  130. // onChange: setPrometheusInstance,
  131. // variant: 'filled',
  132. // className: classes.input,
  133. // placeholder: attuTrans.prometheusInstance,
  134. // fullWidth: true,
  135. // defaultValue: prometheusInstance,
  136. // },
  137. // ],
  138. // []
  139. // );
  140. const handleConnect = async (event: React.FormEvent) => {
  141. event.preventDefault();
  142. try {
  143. // login
  144. const result = await login(authReq);
  145. // set database
  146. setDatabase(authReq.database);
  147. // success message
  148. openSnackBar(successTrans('connect'));
  149. // save clientId to local storage
  150. window.localStorage.setItem(MILVUS_CLIENT_ID, result.clientId);
  151. // redirect to homepage
  152. navigate('/');
  153. } catch (error: any) {
  154. // if not authorized, show auth inputs
  155. if (error.response.data.message.includes('UNAUTHENTICATED')) {
  156. handleEnableAuth(true);
  157. }
  158. }
  159. };
  160. const btnDisabled = useMemo(() => {
  161. return authReq.address.trim().length === 0;
  162. }, [authReq.address]);
  163. // handle auth toggle
  164. const handleEnableAuth = (val: boolean) => {
  165. setWithPass(val);
  166. };
  167. return (
  168. <form onSubmit={handleConnect}>
  169. <section className={classes.wrapper}>
  170. <div className={classes.titleWrapper}>
  171. <Typography variant="h4" component="h4">
  172. {attuTrans.connectTitle}
  173. <CustomToolTip title={attuTrans.connectionTip}>
  174. <Icons.info />
  175. </CustomToolTip>
  176. </Typography>
  177. </div>
  178. {/* address */}
  179. <CustomInput
  180. type="text"
  181. textConfig={{
  182. label: attuTrans.address,
  183. key: 'address',
  184. onChange: (val: string) => handleInputChange('address', val),
  185. variant: 'filled',
  186. className: classes.input,
  187. placeholder: attuTrans.address,
  188. fullWidth: true,
  189. validations: [
  190. {
  191. rule: 'require',
  192. errorText: warningTrans('required', {
  193. name: attuTrans.address,
  194. }),
  195. },
  196. ],
  197. defaultValue: authReq.address,
  198. }}
  199. checkValid={checkIsValid}
  200. validInfo={validation}
  201. key={attuTrans.address}
  202. />
  203. {/* db */}
  204. <CustomInput
  205. type="text"
  206. textConfig={{
  207. label: `Milvus ${dbTrans('database')} ${attuTrans.optional}`,
  208. key: 'database',
  209. onChange: (value: string) => handleInputChange('database', value),
  210. variant: 'filled',
  211. className: classes.input,
  212. placeholder: dbTrans('database'),
  213. fullWidth: true,
  214. defaultValue: authReq.database,
  215. }}
  216. checkValid={checkIsValid}
  217. validInfo={validation}
  218. key={attuTrans.database}
  219. />
  220. {/* toggle auth */}
  221. <div className={classes.toggle}>
  222. <CustomRadio
  223. checked={withPass}
  224. label={attuTrans.authentication}
  225. handleChange={handleEnableAuth}
  226. />
  227. </div>
  228. {/* token */}
  229. {withPass && (
  230. <>
  231. <CustomInput
  232. type="text"
  233. textConfig={{
  234. label: `${attuTrans.token} ${attuTrans.optional} `,
  235. key: 'token',
  236. onChange: (val: string) => handleInputChange('token', val),
  237. variant: 'filled',
  238. className: classes.input,
  239. placeholder: attuTrans.token,
  240. fullWidth: true,
  241. defaultValue: authReq.token,
  242. }}
  243. checkValid={checkIsValid}
  244. validInfo={validation}
  245. key={attuTrans.token}
  246. />
  247. {/* user */}
  248. <CustomInput
  249. type="text"
  250. textConfig={{
  251. label: `${attuTrans.username} ${attuTrans.optional}`,
  252. key: 'username',
  253. onChange: (value: string) =>
  254. handleInputChange('username', value),
  255. variant: 'filled',
  256. className: classes.input,
  257. placeholder: attuTrans.username,
  258. fullWidth: true,
  259. defaultValue: authReq.username,
  260. }}
  261. checkValid={checkIsValid}
  262. validInfo={validation}
  263. key={attuTrans.username}
  264. />
  265. {/* pass */}
  266. <CustomInput
  267. type="text"
  268. textConfig={{
  269. label: `${attuTrans.password} ${attuTrans.optional}`,
  270. key: 'password',
  271. onChange: (value: string) =>
  272. handleInputChange('password', value),
  273. variant: 'filled',
  274. className: classes.input,
  275. placeholder: attuTrans.password,
  276. fullWidth: true,
  277. type: 'password',
  278. defaultValue: authReq.password,
  279. }}
  280. checkValid={checkIsValid}
  281. validInfo={validation}
  282. key={attuTrans.password}
  283. />
  284. </>
  285. )}
  286. {/* <div className={classes.toggle}>
  287. <CustomRadio
  288. defaultChecked={withPrometheus}
  289. label={attuTrans.prometheus}
  290. handleChange={setWithPrometheus}
  291. />
  292. </div>
  293. {withPrometheus &&
  294. prometheusConfigs.map(v => (
  295. <CustomInput
  296. type="text"
  297. textConfig={v}
  298. checkValid={checkIsValid}
  299. validInfo={validation}
  300. key={v.label}
  301. />
  302. ))} */}
  303. <CustomButton type="submit" variant="contained" disabled={btnDisabled}>
  304. {btnTrans('connect')}
  305. </CustomButton>
  306. </section>
  307. </form>
  308. );
  309. };