ImportSampleDialog.tsx 7.1 KB

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