Create.tsx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. import { makeStyles, Theme } from '@material-ui/core';
  2. import { FC, useContext, useMemo, useState } from 'react';
  3. import { useTranslation } from 'react-i18next';
  4. import DialogTemplate from '../../components/customDialog/DialogTemplate';
  5. import CustomInput from '../../components/customInput/CustomInput';
  6. import CustomSelector from '../../components/customSelector/CustomSelector';
  7. import { ITextfieldConfig } from '../../components/customInput/Types';
  8. import { rootContext } from '../../context/Root';
  9. import { useFormValidation } from '../../hooks/Form';
  10. import { formatForm } from '../../utils/Form';
  11. import { TypeEnum } from '../../utils/Validation';
  12. import CreateFields from './CreateFields';
  13. import {
  14. CollectionCreateParam,
  15. CollectionCreateProps,
  16. DataTypeEnum,
  17. ConsistencyLevelEnum,
  18. Field,
  19. } from './Types';
  20. import { CONSISTENCY_LEVEL_OPTIONS } from './Constants';
  21. const useStyles = makeStyles((theme: Theme) => ({
  22. fieldset: {
  23. width: '100%',
  24. display: 'flex',
  25. justifyContent: 'space-between',
  26. alignItems: 'center',
  27. '&:nth-last-child(2)': {
  28. flexDirection: 'column',
  29. alignItems: 'flex-start',
  30. },
  31. '& legend': {
  32. marginBottom: theme.spacing(2),
  33. color: `#82838e`,
  34. lineHeight: '20px',
  35. fontSize: '14px',
  36. },
  37. },
  38. input: {
  39. width: '48%',
  40. },
  41. select: {
  42. width: '160px',
  43. marginBottom: '22px',
  44. '&:first-child': {
  45. marginLeft: 0,
  46. },
  47. },
  48. }));
  49. const CreateCollection: FC<CollectionCreateProps> = ({ handleCreate }) => {
  50. const classes = useStyles();
  51. const { handleCloseDialog } = useContext(rootContext);
  52. const { t: collectionTrans } = useTranslation('collection');
  53. const { t: btnTrans } = useTranslation('btn');
  54. const { t: warningTrans } = useTranslation('warning');
  55. const [form, setForm] = useState({
  56. collection_name: '',
  57. description: '',
  58. autoID: true,
  59. });
  60. const [consistencyLevel, setConsistencyLevel] =
  61. useState<ConsistencyLevelEnum>(ConsistencyLevelEnum.Session); // Session is the default value of consistency level
  62. const [fields, setFields] = useState<Field[]>([
  63. {
  64. data_type: DataTypeEnum.Int64,
  65. is_primary_key: true,
  66. name: null, // we need hide helpertext at first time, so we use null to detect user enter input or not.
  67. description: '',
  68. isDefault: true,
  69. id: '1',
  70. },
  71. {
  72. data_type: DataTypeEnum.FloatVector,
  73. is_primary_key: false,
  74. name: null,
  75. dimension: '128',
  76. description: '',
  77. isDefault: true,
  78. id: '2',
  79. },
  80. ]);
  81. const [fieldsValidation, setFieldsValidation] = useState<
  82. {
  83. [x: string]: string | boolean;
  84. }[]
  85. >([
  86. { id: '1', name: false },
  87. { id: '2', name: false, dimension: true },
  88. ]);
  89. const allFieldsValid = useMemo(() => {
  90. return fieldsValidation.every(v => Object.keys(v).every(key => !!v[key]));
  91. }, [fieldsValidation]);
  92. const checkedForm = useMemo(() => {
  93. const { collection_name } = form;
  94. return formatForm({ collection_name });
  95. }, [form]);
  96. const { validation, checkIsValid, disabled } = useFormValidation(checkedForm);
  97. const changeIsAutoID = (value: boolean) => {
  98. setForm({
  99. ...form,
  100. autoID: value,
  101. });
  102. };
  103. const handleInputChange = (key: string, value: string) => {
  104. setForm(v => ({ ...v, [key]: value }));
  105. };
  106. const generalInfoConfigs: ITextfieldConfig[] = [
  107. {
  108. label: collectionTrans('name'),
  109. key: 'collection_name',
  110. value: form.collection_name,
  111. onChange: (value: string) => handleInputChange('collection_name', value),
  112. variant: 'filled',
  113. validations: [
  114. // cannot be empty
  115. {
  116. rule: 'require',
  117. errorText: warningTrans('required', {
  118. name: collectionTrans('name'),
  119. }),
  120. },
  121. // length <= 255
  122. {
  123. rule: 'range',
  124. extraParam: {
  125. max: 255,
  126. type: 'string',
  127. },
  128. errorText: collectionTrans('nameLengthWarning'),
  129. },
  130. // name can only be combined with letters, number or underscores
  131. {
  132. rule: 'collectionName',
  133. errorText: collectionTrans('nameContentWarning'),
  134. },
  135. // name can not start with number
  136. {
  137. rule: 'firstCharacter',
  138. extraParam: {
  139. invalidTypes: [TypeEnum.number],
  140. },
  141. errorText: collectionTrans('nameFirstLetterWarning'),
  142. },
  143. ],
  144. className: classes.input,
  145. },
  146. {
  147. label: collectionTrans('description'),
  148. key: 'description',
  149. value: form.description,
  150. onChange: (value: string) => handleInputChange('description', value),
  151. variant: 'filled',
  152. validations: [],
  153. className: classes.input,
  154. },
  155. ];
  156. const handleCreateCollection = () => {
  157. const vectorType = [DataTypeEnum.BinaryVector, DataTypeEnum.FloatVector];
  158. const param: CollectionCreateParam = {
  159. ...form,
  160. fields: fields.map(v => {
  161. const data: any = {
  162. name: v.name,
  163. description: v.description,
  164. is_primary_key: v.is_primary_key,
  165. data_type: v.data_type,
  166. dimension: vectorType.includes(v.data_type) ? v.dimension : undefined,
  167. };
  168. v.is_primary_key && (data.autoID = form.autoID);
  169. return data;
  170. }),
  171. consistency_level: consistencyLevel,
  172. };
  173. handleCreate(param);
  174. };
  175. return (
  176. <DialogTemplate
  177. title={collectionTrans('createTitle')}
  178. handleClose={handleCloseDialog}
  179. confirmLabel={btnTrans('create')}
  180. handleConfirm={handleCreateCollection}
  181. confirmDisabled={disabled || !allFieldsValid}
  182. >
  183. <form>
  184. <fieldset className={classes.fieldset}>
  185. <legend>{collectionTrans('general')}</legend>
  186. {generalInfoConfigs.map(config => (
  187. <CustomInput
  188. key={config.key}
  189. type="text"
  190. textConfig={config}
  191. checkValid={checkIsValid}
  192. validInfo={validation}
  193. />
  194. ))}
  195. </fieldset>
  196. <fieldset className={classes.fieldset}>
  197. <legend>{collectionTrans('schema')}</legend>
  198. <CreateFields
  199. fields={fields}
  200. setFields={setFields}
  201. setFieldsValidation={setFieldsValidation}
  202. autoID={form.autoID}
  203. setAutoID={changeIsAutoID}
  204. />
  205. </fieldset>
  206. <fieldset className={classes.fieldset}>
  207. <legend>{collectionTrans('consistency')}</legend>
  208. <CustomSelector
  209. wrapperClass={classes.select}
  210. options={CONSISTENCY_LEVEL_OPTIONS}
  211. onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
  212. setConsistencyLevel(e.target.value as ConsistencyLevelEnum);
  213. }}
  214. value={consistencyLevel}
  215. variant="filled"
  216. label={'Consistency'}
  217. />
  218. </fieldset>
  219. </form>
  220. </DialogTemplate>
  221. );
  222. };
  223. export default CreateCollection;