ImportSampleDialog.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import { makeStyles, Theme, Typography, Chip } from '@material-ui/core';
  2. import { FC, useState, useContext } from 'react';
  3. import { useTranslation } from 'react-i18next';
  4. import { saveAs } from 'file-saver';
  5. import DialogTemplate from '@/components/customDialog/DialogTemplate';
  6. import CustomSelector from '@/components/customSelector/CustomSelector';
  7. import { rootContext } from '@/context';
  8. import { InsertStatusEnum } from './insert/Types';
  9. import { DataService } from '@/http';
  10. import { LoadSampleParam } from './Types';
  11. import icons from '@/components/icons/Icons';
  12. const DownloadIcon = icons.download;
  13. const getStyles = makeStyles((theme: Theme) => {
  14. return {
  15. icon: {
  16. fontSize: '16px',
  17. },
  18. downloadBtn: {
  19. maxWidth: '240px',
  20. margin: theme.spacing(1.5, 1.5, 0, 0),
  21. },
  22. selectors: {
  23. '& .selectorWrapper': {
  24. display: 'flex',
  25. flexDirection: 'column',
  26. marginBottom: theme.spacing(2),
  27. '& .selectLabel': {
  28. fontSize: '14px',
  29. lineHeight: '20px',
  30. color: theme.palette.attuDark.main,
  31. },
  32. '& .description': {
  33. color: theme.palette.attuGrey.dark,
  34. marginBottom: theme.spacing(2),
  35. fontSize: 13,
  36. lineHeight: 1.5,
  37. width: '35vw',
  38. },
  39. },
  40. '& .actions': {
  41. display: 'flex',
  42. flexDirection: 'column',
  43. },
  44. '& .download-actions': {
  45. display: 'flex',
  46. flexDirection: 'row',
  47. },
  48. '& .selector': {
  49. maxWidth: '35vw',
  50. },
  51. },
  52. };
  53. });
  54. const sizeOptions = [
  55. {
  56. label: '100',
  57. value: '100',
  58. },
  59. {
  60. label: '1000',
  61. value: '1000',
  62. },
  63. {
  64. label: '5000',
  65. value: '5000',
  66. },
  67. {
  68. label: '10k',
  69. value: '10000',
  70. },
  71. ];
  72. const ImportSampleDialog: FC<{ collection: string }> = props => {
  73. const classes = getStyles();
  74. const { collection } = props;
  75. const [size, setSize] = useState<string>(sizeOptions[0].value);
  76. const [csvFileName, setCsvFileName] = useState<string>(
  77. `${collection}.sample.${size}.csv`
  78. );
  79. const [jsonFileName, setJsonFileName] = useState<string>(
  80. `${collection}.sample.${size}.json`
  81. );
  82. const [insertStatus, setInsertStatus] = useState<InsertStatusEnum>(
  83. InsertStatusEnum.init
  84. );
  85. const { t: insertTrans } = useTranslation('insert');
  86. const { t: btnTrans } = useTranslation('btn');
  87. const { handleCloseDialog, openSnackBar } = useContext(rootContext);
  88. // selected collection name
  89. const handleImportSample = async (
  90. collectionName: string,
  91. size: string,
  92. download: boolean = false,
  93. format: 'csv' | 'json' = 'csv'
  94. ): Promise<{ result: string | boolean; msg: string }> => {
  95. const param: LoadSampleParam = {
  96. collection_name: collectionName,
  97. size: size,
  98. download,
  99. format: format,
  100. };
  101. try {
  102. const res = await DataService.importSample(collectionName, param);
  103. if (download) {
  104. const fileName = format === 'csv' ? csvFileName : jsonFileName;
  105. const type =
  106. format === 'csv' ? 'text/csv;charset=utf-8;' : 'application/json';
  107. const blob = new Blob([res.sampleFile], { type });
  108. saveAs(blob, fileName);
  109. return { result: res.sampleFile, msg: '' };
  110. }
  111. await DataService.flush(collectionName);
  112. return { result: true, msg: '' };
  113. } catch (err: any) {
  114. const {
  115. response: {
  116. data: { message },
  117. },
  118. } = err;
  119. return { result: false, msg: message || '' };
  120. }
  121. };
  122. const onDownloadCSVClicked = async () => {
  123. return await handleImportSample(collection, size, true, 'csv');
  124. };
  125. const onDownloadJSONClicked = async () => {
  126. return await handleImportSample(collection, size, true, 'json');
  127. };
  128. const importData = async () => {
  129. if (insertStatus === InsertStatusEnum.success) {
  130. handleCloseDialog();
  131. return;
  132. }
  133. // start loading
  134. setInsertStatus(InsertStatusEnum.loading);
  135. const { result, msg } = await handleImportSample(collection, size);
  136. if (!result) {
  137. openSnackBar(msg, 'error');
  138. setInsertStatus(InsertStatusEnum.init);
  139. return;
  140. }
  141. setInsertStatus(InsertStatusEnum.success);
  142. // hide dialog
  143. handleCloseDialog();
  144. };
  145. return (
  146. <DialogTemplate
  147. title={insertTrans('importSampleData', {
  148. collection,
  149. })}
  150. handleClose={handleCloseDialog}
  151. confirmLabel={
  152. insertStatus === InsertStatusEnum.init
  153. ? btnTrans('import')
  154. : insertStatus === InsertStatusEnum.loading
  155. ? btnTrans('importing')
  156. : insertStatus === InsertStatusEnum.success
  157. ? btnTrans('done')
  158. : insertStatus
  159. }
  160. handleConfirm={importData}
  161. confirmDisabled={insertStatus === InsertStatusEnum.loading}
  162. showActions={true}
  163. showCancel={false}
  164. // don't show close icon when insert not finish
  165. // showCloseIcon={insertStatus !== InsertStatusEnum.loading}
  166. >
  167. <form className={classes.selectors}>
  168. <div className="selectorWrapper">
  169. <div className="description">
  170. <Typography variant="inherit" component="p">
  171. {insertTrans('importSampleDataDesc')}
  172. </Typography>
  173. </div>
  174. <div className="actions">
  175. <CustomSelector
  176. label={insertTrans('sampleDataSize')}
  177. options={sizeOptions}
  178. wrapperClass="selector"
  179. labelClass="selectLabel"
  180. value={size}
  181. variant="filled"
  182. onChange={(e: { target: { value: unknown } }) => {
  183. const size = e.target.value;
  184. setSize(size as string);
  185. setCsvFileName(`${collection}.sample.${size}.csv`);
  186. setJsonFileName(`${collection}.sample.${size}.json`);
  187. }}
  188. />
  189. </div>
  190. <div className="download-actions">
  191. <Chip
  192. className={classes.downloadBtn}
  193. icon={<DownloadIcon />}
  194. label={csvFileName}
  195. title={csvFileName}
  196. variant="outlined"
  197. size="small"
  198. onClick={onDownloadCSVClicked}
  199. />
  200. <Chip
  201. className={classes.downloadBtn}
  202. icon={<DownloadIcon />}
  203. label={jsonFileName}
  204. title={jsonFileName}
  205. variant="outlined"
  206. size="small"
  207. onClick={onDownloadJSONClicked}
  208. />
  209. </div>
  210. </div>
  211. </form>
  212. </DialogTemplate>
  213. );
  214. };
  215. export default ImportSampleDialog;