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