LoadCollectionDialog.tsx 6.3 KB

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