LoadCollectionDialog.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import { useEffect, useState, useContext, useMemo } from 'react';
  2. import {
  3. Typography,
  4. makeStyles,
  5. Theme,
  6. Switch,
  7. FormControlLabel,
  8. } from '@material-ui/core';
  9. import { useTranslation } from 'react-i18next';
  10. import { authContext } from '@/context/Auth';
  11. import { CollectionHttp } from '@/http/Collection';
  12. import { rootContext } from '@/context/Root';
  13. import { useFormValidation } from '@/hooks/Form';
  14. import { formatForm } from '@/utils/Form';
  15. import { parseJson, getNode } from '@/utils/Metric';
  16. import CustomInput from '@/components/customInput/CustomInput';
  17. import { ITextfieldConfig } from '@/components/customInput/Types';
  18. import DialogTemplate from '@/components/customDialog/DialogTemplate';
  19. import { MilvusHttp } from '@/http/Milvus';
  20. import CustomToolTip from '@/components/customToolTip/CustomToolTip';
  21. import { MILVUS_NODE_TYPE, MILVUS_DEPLOY_MODE } from '../../consts/Milvus';
  22. import icons from '@/components/icons/Icons';
  23. const useStyles = makeStyles((theme: Theme) => ({
  24. desc: {
  25. marginBottom: theme.spacing(2),
  26. maxWidth: 480,
  27. },
  28. replicaDesc: {
  29. marginBottom: theme.spacing(2),
  30. maxWidth: 480,
  31. },
  32. toggle: {
  33. marginBottom: theme.spacing(2),
  34. },
  35. icon: {
  36. fontSize: '20px',
  37. marginLeft: theme.spacing(0.5),
  38. },
  39. }));
  40. const LoadCollectionDialog = (props: any) => {
  41. const classes = useStyles();
  42. const { collection, onLoad } = props;
  43. const { t: dialogTrans } = useTranslation('dialog');
  44. const { t: collectionTrans } = useTranslation('collection');
  45. const { t: btnTrans } = useTranslation('btn');
  46. const { t: warningTrans } = useTranslation('warning');
  47. const { handleCloseDialog } = useContext(rootContext);
  48. const [form, setForm] = useState({
  49. replica: 1,
  50. });
  51. const { isManaged } = useContext(authContext);
  52. const [enableRelica, setEnableRelica] = useState(false);
  53. const [replicaToggle, setReplicaToggle] = useState(false);
  54. const [maxQueryNode, setMaxQueryNode] = useState(1);
  55. // check if it is cluster
  56. useEffect(() => {
  57. async function fetchData() {
  58. const res = await MilvusHttp.getMetrics();
  59. const parsedJson = parseJson(res);
  60. // get root cord
  61. const rootCoords = getNode(
  62. parsedJson.workingNodes,
  63. MILVUS_NODE_TYPE.ROOTCOORD
  64. );
  65. // get query nodes
  66. const queryNodes = getNode(
  67. parsedJson.workingNodes,
  68. MILVUS_NODE_TYPE.QUERYNODE
  69. );
  70. const rootCoord = rootCoords[0];
  71. // should we show replic toggle
  72. const enableRelica =
  73. rootCoord.infos.system_info.deploy_mode ===
  74. MILVUS_DEPLOY_MODE.DISTRIBUTED;
  75. // only show replica toggle in distributed mode && query node > 1
  76. if (enableRelica && queryNodes.length > 1 && !isManaged) {
  77. setMaxQueryNode(queryNodes.length);
  78. setEnableRelica(enableRelica);
  79. }
  80. }
  81. fetchData();
  82. }, []);
  83. // input state change
  84. const handleInputChange = (value: number) => {
  85. setForm({ replica: value });
  86. };
  87. // confirm action
  88. const handleConfirm = async () => {
  89. let params;
  90. if (enableRelica) {
  91. params = { replica_number: Number(form.replica) };
  92. }
  93. // load collection request
  94. await CollectionHttp.loadCollection(collection, params);
  95. // callback
  96. onLoad && onLoad();
  97. // close dialog
  98. handleCloseDialog();
  99. };
  100. // validator
  101. const checkedForm = useMemo(() => {
  102. return enableRelica ? [] : formatForm(form);
  103. }, [form, enableRelica]);
  104. // validate
  105. const { validation, checkIsValid, disabled } = useFormValidation(checkedForm);
  106. // input config
  107. const inputConfig: ITextfieldConfig = {
  108. label: collectionTrans('replicaNum'),
  109. type: 'number',
  110. key: 'replica',
  111. onChange: handleInputChange,
  112. variant: 'filled',
  113. placeholder: collectionTrans('replicaNum'),
  114. fullWidth: true,
  115. validations: [],
  116. required: enableRelica,
  117. defaultValue: form.replica,
  118. };
  119. // if replica is enabled, add validation
  120. if (enableRelica) {
  121. inputConfig.validations?.push(
  122. {
  123. rule: 'require',
  124. errorText: warningTrans('required', {
  125. name: collectionTrans('replicaNum'),
  126. }),
  127. },
  128. {
  129. rule: 'range',
  130. errorText: warningTrans('range', { min: 1, max: maxQueryNode }),
  131. extraParam: {
  132. min: 1,
  133. max: maxQueryNode,
  134. type: 'number',
  135. },
  136. }
  137. );
  138. }
  139. // toggle enbale replica
  140. const handleChange = () => {
  141. setReplicaToggle(!replicaToggle);
  142. if (!replicaToggle === false) {
  143. setForm({ replica: 1 });
  144. }
  145. };
  146. const InfoIcon = icons.info;
  147. return (
  148. <DialogTemplate
  149. title={dialogTrans('loadTitle', {
  150. type: collection,
  151. })}
  152. handleClose={handleCloseDialog}
  153. children={
  154. <>
  155. <Typography variant="body1" component="p" className={classes.desc}>
  156. {collectionTrans('loadContent')}
  157. </Typography>
  158. {enableRelica ? (
  159. <>
  160. <FormControlLabel
  161. control={
  162. <Switch checked={replicaToggle} onChange={handleChange} />
  163. }
  164. label={
  165. <CustomToolTip title={collectionTrans('replicaDes')}>
  166. <>
  167. {collectionTrans('enableRepica')}
  168. <InfoIcon classes={{ root: classes.icon }} />
  169. </>
  170. </CustomToolTip>
  171. }
  172. className={classes.toggle}
  173. />
  174. </>
  175. ) : null}
  176. {replicaToggle ? (
  177. <>
  178. <CustomInput
  179. type="text"
  180. textConfig={inputConfig}
  181. checkValid={checkIsValid}
  182. validInfo={validation}
  183. />
  184. </>
  185. ) : null}
  186. </>
  187. }
  188. confirmLabel={btnTrans('load')}
  189. handleConfirm={handleConfirm}
  190. confirmDisabled={replicaToggle ? disabled : false}
  191. />
  192. );
  193. };
  194. export default LoadCollectionDialog;