AuthForm.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. import React, { useContext, useMemo, useState } from 'react';
  2. import { makeStyles, Theme, Typography } from '@material-ui/core';
  3. import CustomButton from '../../components/customButton/CustomButton';
  4. import CustomInput from '../../components/customInput/CustomInput';
  5. import icons from '../../components/icons/Icons';
  6. import { useTranslation } from 'react-i18next';
  7. import { ITextfieldConfig } from '../../components/customInput/Types';
  8. import { useFormValidation } from '../../hooks/Form';
  9. import { formatForm } from '../../utils/Form';
  10. import { MilvusHttp } from '../../http/Milvus';
  11. import { formatAddress } from '../../utils/Format';
  12. import { useNavigate } from 'react-router-dom';
  13. import { rootContext } from '../../context/Root';
  14. import { authContext } from '../../context/Auth';
  15. import { MILVUS_ADDRESS } from '../../consts/Localstorage';
  16. import { CODE_STATUS } from '../../consts/Http';
  17. import { MILVUS_URL } from '../../consts/Milvus';
  18. import { CustomRadio } from '../../components/customRadio/CustomRadio';
  19. const useStyles = makeStyles((theme: Theme) => ({
  20. wrapper: {
  21. display: 'flex',
  22. flexDirection: 'column',
  23. alignItems: 'flex-end',
  24. padding: theme.spacing(0, 3),
  25. },
  26. titleWrapper: {
  27. display: 'flex',
  28. alignItems: 'center',
  29. padding: theme.spacing(3),
  30. margin: '0 auto',
  31. flexDirection: 'column',
  32. '& .title': {
  33. margin: 0,
  34. color: '#323232',
  35. fontWeight: 'bold',
  36. },
  37. },
  38. logo: {
  39. width: '42px',
  40. height: 'auto',
  41. marginBottom: '8px',
  42. display: 'block',
  43. },
  44. input: {
  45. margin: theme.spacing(3, 0, 0.5),
  46. },
  47. sslWrapper: {
  48. display: 'flex',
  49. width: '100%',
  50. justifyContent: 'flex-start',
  51. },
  52. }));
  53. export const AuthForm = (props: any) => {
  54. const navigate = useNavigate();
  55. const classes = useStyles();
  56. const { openSnackBar } = useContext(rootContext);
  57. const { setAddress, setIsAuth } = useContext(authContext);
  58. const Logo = icons.zilliz;
  59. const { t: commonTrans } = useTranslation();
  60. const attuTrans = commonTrans('attu');
  61. const { t: btnTrans } = useTranslation('btn');
  62. const { t: warningTrans } = useTranslation('warning');
  63. const { t: successTrans } = useTranslation('success');
  64. const [showAuthForm, setShowAuthForm] = useState(false);
  65. const [form, setForm] = useState({
  66. address: MILVUS_URL,
  67. username: '',
  68. password: '',
  69. ssl: false,
  70. });
  71. const checkedForm = useMemo(() => {
  72. return formatForm(form);
  73. }, [form]);
  74. const { validation, checkIsValid, disabled } = useFormValidation(checkedForm);
  75. const handleInputChange = (
  76. key: 'address' | 'username' | 'password' | 'ssl',
  77. value: string | boolean
  78. ) => {
  79. setForm(v => ({ ...v, [key]: value }));
  80. };
  81. const inputConfigs: ITextfieldConfig[] = useMemo(() => {
  82. const noAuthConfigs: ITextfieldConfig[] = [
  83. {
  84. label: attuTrans.address,
  85. key: 'address',
  86. onChange: (val: string) => handleInputChange('address', val),
  87. variant: 'filled',
  88. className: classes.input,
  89. placeholder: attuTrans.address,
  90. fullWidth: true,
  91. validations: [
  92. {
  93. rule: 'require',
  94. errorText: warningTrans('required', { name: attuTrans.address }),
  95. },
  96. ],
  97. defaultValue: form.address,
  98. },
  99. ];
  100. return showAuthForm
  101. ? [
  102. ...noAuthConfigs,
  103. {
  104. label: attuTrans.username,
  105. key: 'username',
  106. onChange: (value: string) => handleInputChange('username', value),
  107. variant: 'filled',
  108. className: classes.input,
  109. placeholder: attuTrans.username,
  110. fullWidth: true,
  111. validations: [
  112. {
  113. rule: 'require',
  114. errorText: warningTrans('required', {
  115. name: attuTrans.username,
  116. }),
  117. },
  118. ],
  119. defaultValue: form.username,
  120. },
  121. {
  122. label: attuTrans.password,
  123. key: 'password',
  124. onChange: (value: string) => handleInputChange('password', value),
  125. variant: 'filled',
  126. className: classes.input,
  127. placeholder: attuTrans.password,
  128. fullWidth: true,
  129. type: 'password',
  130. validations: [
  131. {
  132. rule: 'require',
  133. errorText: warningTrans('required', {
  134. name: attuTrans.password,
  135. }),
  136. },
  137. ],
  138. defaultValue: form.username,
  139. },
  140. ]
  141. : noAuthConfigs;
  142. }, [form, attuTrans, warningTrans, classes.input, showAuthForm]);
  143. const handleConnect = async () => {
  144. const address = formatAddress(form.address);
  145. try {
  146. const data = showAuthForm
  147. ? { ...form, address }
  148. : { address, ssl: form.ssl };
  149. await MilvusHttp.connect(data);
  150. setIsAuth(true);
  151. setAddress(address);
  152. openSnackBar(successTrans('connect'));
  153. window.localStorage.setItem(MILVUS_ADDRESS, address);
  154. navigate('/');
  155. } catch (error: any) {
  156. if (error?.response?.status === CODE_STATUS.UNAUTHORIZED) {
  157. showAuthForm
  158. ? openSnackBar(attuTrans.unAuth, 'error')
  159. : setShowAuthForm(true);
  160. }
  161. }
  162. };
  163. const btnDisabled = useMemo(() => {
  164. return showAuthForm ? disabled : form.address.trim().length === 0;
  165. }, [showAuthForm, disabled, form.address]);
  166. return (
  167. <section className={classes.wrapper}>
  168. <div className={classes.titleWrapper}>
  169. <Logo classes={{ root: classes.logo }} />
  170. <Typography variant="h2" className="title">
  171. {attuTrans.admin}
  172. </Typography>
  173. </div>
  174. {inputConfigs.map(v => (
  175. <CustomInput
  176. type="text"
  177. textConfig={v}
  178. checkValid={checkIsValid}
  179. validInfo={validation}
  180. key={v.label}
  181. />
  182. ))}
  183. <div className={classes.sslWrapper}>
  184. <CustomRadio
  185. label={attuTrans.ssl}
  186. handleChange={(val: boolean) => handleInputChange('ssl', val)}
  187. />
  188. </div>
  189. <CustomButton
  190. variant="contained"
  191. disabled={btnDisabled}
  192. onClick={handleConnect}
  193. >
  194. {btnTrans('connect')}
  195. </CustomButton>
  196. </section>
  197. );
  198. };