LoadCollectionDialog.tsx 5.7 KB

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