7
7
8
8
import {
9
9
downloadCase ,
10
- exportCase ,
10
+ fetchConvertedCase ,
11
11
getCaseOriginalName ,
12
12
} from '../../utils/rest-api' ;
13
13
import { useIntl } from 'react-intl' ;
14
14
import { ElementType , useSnackMessage } from '@gridsuite/commons-ui' ;
15
+ import { useCallback , useState } from 'react' ;
15
16
16
17
const downloadCases = async ( uuids : string [ ] ) => {
17
18
for ( const uuid of uuids ) {
@@ -31,48 +32,55 @@ const downloadCases = async (uuids: string[]) => {
31
32
}
32
33
} ;
33
34
34
- const exportCases = async (
35
- cases : any [ ] ,
36
- format : string ,
37
- formatParameters : {
38
- [ parameterName : string ] : any ;
39
- } ,
40
- onError ?: ( caseElement : any , errorMsg : string ) => void
41
- ) : Promise < void > => {
42
- const files : { name : string ; blob : Blob } [ ] = [ ] ;
43
- for ( const c of cases ) {
35
+ export function useDownloadUtils ( ) {
36
+ const intl = useIntl ( ) ;
37
+ const { snackError, snackInfo } = useSnackMessage ( ) ;
38
+ const capitalizeFirstLetter = ( string : string ) =>
39
+ `${ string . charAt ( 0 ) . toUpperCase ( ) } ${ string . slice ( 1 ) } ` ;
40
+ const [ abortController , setAbortController ] = useState < AbortController > ( ) ;
41
+
42
+ const handleCaseExportError = ( caseElement : any , errorMsg : string ) =>
43
+ snackError ( {
44
+ headerId : 'download.error' ,
45
+ headerValues : { caseName : caseElement . elementName } ,
46
+ messageTxt : errorMsg ,
47
+ } ) ;
48
+
49
+ const exportCase = async (
50
+ caseElement : any ,
51
+ format : string ,
52
+ formatParameters : {
53
+ [ parameterName : string ] : any ;
54
+ } ,
55
+ abortController : AbortController
56
+ ) : Promise < void > => {
44
57
try {
45
- const result = await exportCase (
46
- c . elementUuid ,
58
+ const result = await fetchConvertedCase (
59
+ caseElement . elementUuid ,
47
60
format ,
48
- formatParameters
61
+ formatParameters ,
62
+ abortController
49
63
) ;
50
64
let filename = result . headers
51
65
. get ( 'Content-Disposition' )
52
66
. split ( 'filename=' ) [ 1 ] ;
53
67
filename = filename . substring ( 1 , filename . length - 1 ) ; // We remove quotes
54
68
const blob = await result . blob ( ) ;
55
- files . push ( { name : filename , blob } ) ;
56
- } catch ( e : any ) {
57
- onError ?.( c , e ) ;
58
- }
59
- }
60
- for ( const file of files ) {
61
- const href = window . URL . createObjectURL ( file . blob ) ;
62
- const link = document . createElement ( 'a' ) ;
63
- link . href = href ;
64
- link . setAttribute ( 'download' , file . name ) ;
65
- document . body . appendChild ( link ) ;
66
- link . click ( ) ;
67
- document . body . removeChild ( link ) ;
68
- }
69
- } ;
70
69
71
- export function useDownloadUtils ( ) {
72
- const intl = useIntl ( ) ;
73
- const { snackError, snackInfo } = useSnackMessage ( ) ;
74
- const capitalizeFirstLetter = ( string : string ) =>
75
- `${ string . charAt ( 0 ) . toUpperCase ( ) } ${ string . slice ( 1 ) } ` ;
70
+ const href = window . URL . createObjectURL ( blob ) ;
71
+ const link = document . createElement ( 'a' ) ;
72
+ link . href = href ;
73
+ link . setAttribute ( 'download' , filename ) ;
74
+ document . body . appendChild ( link ) ;
75
+ link . click ( ) ;
76
+ document . body . removeChild ( link ) ;
77
+ } catch ( error : any ) {
78
+ if ( error . name === 'AbortError' ) {
79
+ throw error ;
80
+ }
81
+ handleCaseExportError ( caseElement , error ) ;
82
+ }
83
+ } ;
76
84
77
85
const buildPartialDownloadMessage = (
78
86
numberOfDownloadedCases : number ,
@@ -183,13 +191,13 @@ export function useDownloadUtils() {
183
191
) ;
184
192
} ;
185
193
186
- const handleCaseExportError = ( caseElement : any , errorMsg : string ) =>
187
- snackError ( {
188
- headerId : 'download.error' ,
189
- headerValues : { caseName : caseElement . elementName } ,
190
- messageTxt : errorMsg ,
191
- } ) ;
194
+ const stopCasesExports = useCallback ( ( ) => {
195
+ if ( abortController ) {
196
+ abortController . abort ( ) ;
197
+ }
198
+ } , [ abortController ] ) ;
192
199
200
+ // downloads converted files one after another. The downloading may be interrupted midterm with a few files downloaded already.
193
201
const handleConvertCases = async (
194
202
selectedElements : any [ ] ,
195
203
format : string ,
@@ -200,19 +208,38 @@ export function useDownloadUtils() {
200
208
const cases = selectedElements . filter (
201
209
( element ) => element . type === ElementType . CASE
202
210
) ;
203
- await exportCases (
204
- cases ,
205
- format ,
206
- formatParameters ,
207
- handleCaseExportError
208
- ) ;
209
- if ( cases . length !== selectedElements . length ) {
210
- snackInfo ( {
211
- messageTxt : buildPartialDownloadMessage (
211
+ let message : string = '' ;
212
+
213
+ try {
214
+ const controller = new AbortController ( ) ;
215
+ setAbortController ( controller ) ;
216
+
217
+ for ( const c of cases ) {
218
+ await exportCase ( c , format , formatParameters , controller ) ;
219
+ }
220
+ } catch ( error : any ) {
221
+ if ( error . name === 'AbortError' ) {
222
+ message = intl . formatMessage ( {
223
+ id : 'download.stopped' ,
224
+ } ) ;
225
+ }
226
+ } finally {
227
+ setAbortController ( undefined ) ;
228
+
229
+ if (
230
+ message . length === 0 &&
231
+ cases . length !== selectedElements . length
232
+ ) {
233
+ message += buildPartialDownloadMessage (
212
234
cases . length ,
213
235
selectedElements
214
- ) ,
215
- } ) ;
236
+ ) ;
237
+ }
238
+ if ( message . length > 0 ) {
239
+ snackInfo ( {
240
+ messageTxt : message ,
241
+ } ) ;
242
+ }
216
243
}
217
244
} ;
218
245
@@ -231,5 +258,5 @@ export function useDownloadUtils() {
231
258
}
232
259
} ;
233
260
234
- return { handleDownloadCases, handleConvertCases } ;
261
+ return { handleDownloadCases, handleConvertCases, stopCasesExports } ;
235
262
}
0 commit comments