import { createContext } from 'react' ; import { observable , action , flow , computed } from 'mobx' ; import axios , { AxiosResponse } from 'axios' ; import { remove , isUndefined } from 'lodash-es' ; import { DataMapStore } from './dataMapStore' ; import { ServerDataImportStore } from './serverDataImportStore' ; import { initErrorInfo , initRequestStatus } from '../../factory/dataImportStore/dataImportRootStore' ; import { baseUrl , responseData } from '../../types/common' ; import { FileUploadResult , FileUploadTask , FileUploadQueue } from '../../types/GraphManagementStore/dataImportStore' ; import { VertexType , VertexTypeListResponse , EdgeType , EdgeTypeListResponse } from '../../types/GraphManagementStore/metadataConfigsStore' ; import { checkIfLocalNetworkOffline } from '../../utils' ; const MAX_CONCURRENT_UPLOAD = 5 ; export class DataImportRootStore { dataMapStore : DataMapStore ; serverDataImportStore : ServerDataImportStore ; constructor ( ) { this . dataMapStore = new DataMapStore ( this ) ; this . serverDataImportStore = new ServerDataImportStore ( this ) ; } @ observable currentId : number | null = null ; @ observable currentJobId : number | null = null ; @ observable currentStatus = '' ; @ observable currentStep = NaN ; @ observable requestStatus = initRequestStatus ( ) ; @ observable errorInfo = initErrorInfo ( ) ; @ observable fileList : File [ ] = [ ] ; @ observable . ref fileHashes : Record < string , string > = { } ; @ observable fileUploadTasks : FileUploadTask [ ] = [ ] ; @ observable fileUploadQueue : FileUploadQueue [ ] = [ ] ; @ observable fileRetryUploadList : string [ ] = [ ] ; @ observable . ref fileInfos : FileUploadResult [ ] = [ ] ; @ observable . ref vertexTypes : VertexType [ ] = [ ] ; @ observable . ref edgeTypes : EdgeType [ ] = [ ] ; @ computed get successFileUploadTaskNames ( ) { return this . fileUploadTasks . filter ( ( { status } ) => status === 'success' ) . map ( ( { name } ) => name ) ; } @ computed get unsuccessFileUploadTasks ( ) { return this . fileUploadTasks . filter ( ( { status } ) => status !== 'success' ) ; } @ action setCurrentId ( id ) { this . currentId = id ; } @ action setCurrentJobId ( id ) { this . currentJobId = id ; } @ action setCurrentStatus ( status ) { this . currentStatus = status ; } @ action setCurrentStep ( step ) { this . currentStep = step ; } @ action updateFileList ( files ) { this . fileList = [ ... files , ... this . fileList ] ; } @ action initFileUploadTask ( tasks ) { this . fileUploadTasks = [ tasks , ... this . fileUploadTasks ] ; } @ action addFileUploadQueue ( element ) { this . fileUploadQueue . push ( element ) ; } @ action removeFileUploadQueue ( fileName ) { remove ( this . fileUploadQueue , ( { fileName : name } ) => name === fileName ) ; } @ action mutateFileUploadQueue < T extends keyof FileUploadQueue > ( key , value , index ) { this . fileUploadQueue [ index ] [ key ] = value ; } @ action mutateFileUploadTasks < T extends keyof FileUploadTask > ( key , value , fileName ) { const fileUploadTask = this . fileUploadTasks . find ( ( { name } ) => name === fileName ) ! ; if ( ! isUndefined ( fileUploadTask ) ) { fileUploadTask [ key ] = value ; } } @ action removeFileUploadTasks ( fileName ) { remove ( this . fileUploadTasks , ( { name } ) => fileName === name ) ; } @ action addRetryFileUploadQueue ( fileName ) { this . fileRetryUploadList . push ( fileName ) ; } @ action pullRetryFileUploadQueue ( ) { return this . fileRetryUploadList . shift ( ) ; } @ action resetAllFileInfos ( ) { this . fileList = [ ] ; this . fileUploadTasks = [ ] ; this . fileUploadQueue = [ ] ; this . fileInfos = [ ] ; } @ action dispose ( ) { this . currentId = null ; this . currentJobId = null ; this . currentStatus = '' ; this . currentStep = NaN ; this . vertexTypes = [ ] ; this . edgeTypes = [ ] ; this . resetAllFileInfos ( ) ; this . requestStatus = initRequestStatus ( ) ; this . errorInfo = initErrorInfo ( ) ; } fetchFilehashes = flow ( function * fetchFilehashes ( this , fileNames ) { this . requestStatus . fetchFilehashes = 'pending' ; try { const result = yield axios . get < responseData < Record < string , string > > > ( `${ baseUrl }/${ this . currentId }/job-manager/${ this . currentJobId }/upload-file/token?${ fileNames . map ( ( name ) => `names=${ name }` ) . join ( '&' ) }` ) . catch ( checkIfLocalNetworkOffline ) ; if ( result . data . status !== 200 ) { this . errorInfo . fetchFilehashes . code = result . data . status ; throw new Error ( result . data . message ) ; } this . fileHashes = { ... this . fileHashes , ... result . data . data } ; this . requestStatus . fetchFilehashes = 'success' ; } catch ( error ) { this . requestStatus . fetchFilehashes = 'failed' ; this . errorInfo . fetchFilehashes . message = error . message ; console . error ( error . message ) ; } } ) ; uploadFiles = flow ( function * uploadFiles ( this , { fileName , fileChunkList , fileChunkTotal } ) { this . requestStatus . uploadFiles = 'pending' ; const formData = new FormData ( ) ; formData . append ( 'file' , fileChunkList . chunk ) ; if ( this . currentId === null || this . currentJobId === null ) { return ; } try { const result = yield axios . post < responseData < FileUploadResult > > ( `${ baseUrl }/${ this . currentId }/job-manager/${ this . currentJobId }/upload-file?total=${ fileChunkTotal }&index=${ fileChunkList . chunkIndex }&name=${ fileName }&token=${ this . fileHashes [ fileName ] }` , formData , { headers : { 'Content-Type' : 'multipart/form-data' } } ) . catch ( checkIfLocalNetworkOffline ) ; if ( result . data . status !== 200 ) { this . errorInfo . uploadFiles . code = result . data . status ; throw new Error ( result . data . message ) ; } this . fileInfos . push ( result . data . data ) ; this . requestStatus . uploadFiles = 'success' ; return result . data . data ; } catch ( error ) { this . requestStatus . uploadFiles = 'failed' ; this . errorInfo . uploadFiles . message = error . message ; console . error ( error . message ) ; } } ) ; deleteFiles = flow ( function * deleteFiles ( this , fileName ) { this . requestStatus . deleteFiles = 'pending' ; try { const result = yield axios . delete ( `${ baseUrl }/${ this . currentId }/job-manager/${ this . currentJobId }/upload-file?name=${ fileName }&token=${ this . fileHashes [ fileName ] }` ) . catch ( checkIfLocalNetworkOffline ) ; if ( result . data . status !== 200 ) { this . errorInfo . deleteFiles . code = result . data . status ; throw new Error ( result . data . message ) ; } this . requestStatus . deleteFiles = 'success' ; } catch ( error ) { this . requestStatus . deleteFiles = 'failed' ; this . errorInfo . deleteFiles . message = error . message ; console . error ( error . message ) ; } } ) ; sendUploadCompleteSignal = flow ( function * sendUploadCompleteSignal ( this ) { this . requestStatus . sendUploadCompleteSignal = 'pending' ; try { const result = yield axios . put ( `${ baseUrl }/${ this . currentId }/job-manager/${ this . currentJobId }/upload-file/next-step` ) . catch ( checkIfLocalNetworkOffline ) ; if ( result . data . status !== 200 ) { this . errorInfo . sendUploadCompleteSignal . code = result . data . status ; throw new Error ( result . data . message ) ; } this . requestStatus . sendUploadCompleteSignal = 'success' ; } catch ( error ) { this . requestStatus . sendUploadCompleteSignal = 'failed' ; this . errorInfo . sendUploadCompleteSignal . message = error . message ; console . error ( error . message ) ; } } ) ; sendMappingCompleteSignal = flow ( function * sendMappingCompleteSignal ( this ) { this . requestStatus . sendMappingCompleteSignal = 'pending' ; try { const result = yield axios . put ( `${ baseUrl }/${ this . currentId }/job-manager/${ this . currentJobId }/file-mappings/next-step` ) . catch ( checkIfLocalNetworkOffline ) ; if ( result . data . status !== 200 ) { this . errorInfo . sendMappingCompleteSignal . code = result . data . status ; throw new Error ( result . data . message ) ; } this . requestStatus . sendMappingCompleteSignal = 'success' ; } catch ( error ) { this . requestStatus . sendMappingCompleteSignal = 'failed' ; this . errorInfo . sendMappingCompleteSignal . message = error . message ; console . error ( error . message ) ; } } ) ; fetchVertexTypeList = flow ( function * fetchVertexTypeList ( this ) { this . requestStatus . fetchVertexTypeList = 'pending' ; try { const result = yield axios . get < responseData < VertexTypeListResponse > > ( `${ baseUrl }/${ this . currentId }/schema/vertexlabels` , { params : { page_size : - 1 } } ) . catch ( checkIfLocalNetworkOffline ) ; if ( result . data . status !== 200 ) { this . errorInfo . fetchVertexTypeList . code = result . data . status ; throw new Error ( result . data . message ) ; } this . vertexTypes = result . data . data . records ; this . requestStatus . fetchVertexTypeList = 'success' ; } catch ( error ) { this . requestStatus . fetchVertexTypeList = 'failed' ; this . errorInfo . fetchVertexTypeList . message = error . message ; } } ) ; fetchEdgeTypeList = flow ( function * fetchEdgeTypeList ( this ) { this . requestStatus . fetchEdgeTypeList = 'pending' ; try { const result = yield axios . get < responseData < EdgeTypeListResponse > > ( `${ baseUrl }/${ this . currentId }/schema/edgelabels` , { params : { page_size : - 1 } } ) . catch ( checkIfLocalNetworkOffline ) ; if ( result . data . status !== 200 ) { this . errorInfo . fetchEdgeTypeList . code = result . data . status ; throw new Error ( result . data . message ) ; } this . edgeTypes = result . data . data . records ; this . requestStatus . fetchEdgeTypeList = 'success' ; } catch ( error ) { this . requestStatus . fetchEdgeTypeList = 'failed' ; this . errorInfo . fetchEdgeTypeList . message = error . message ; } } ) ; } export default createContext ( new DataImportRootStore ( ) ) ;