Skip to content

Commit

Permalink
Implemented cancel upload (#857)
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidQuartz authored Mar 7, 2022
1 parent 3bdd58b commit 1054caa
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 49 deletions.
30 changes: 27 additions & 3 deletions geonode_mapstore_client/client/js/routes/UploadDataset.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/

import React, { useState, useEffect, useRef } from 'react';
import React, { useState, useEffect, useRef, useCallback } from 'react';
import PropTypes from 'prop-types';
import uniqBy from 'lodash/uniqBy';
import orderBy from 'lodash/orderBy';
Expand Down Expand Up @@ -88,6 +88,9 @@ function getDatasetFileType(file) {
return datasetFileType?.id;
}

const cancelTokens = {};
const sources = {};

function UploadList({
children,
onSuccess
Expand Down Expand Up @@ -183,16 +186,25 @@ function UploadList({
setUnsupported([]);
axios.all(Object.keys(readyUploads).map((baseName) => {
const readyUpload = readyUploads[baseName];
cancelTokens[baseName] = axios.CancelToken;
sources[baseName] = cancelTokens[baseName].source();
return uploadDataset({
file: readyUpload.files[readyUpload.mainExt],
ext: readyUpload.mainExt,
auxiliaryFiles: readyUpload.files,
config: {
onUploadProgress: datasetUploadProgress(baseName)
onUploadProgress: datasetUploadProgress(baseName),
cancelToken: sources[baseName].token
}
})
.then((data) => ({ status: 'success', data, baseName }))
.catch(({ data: error }) => ({ status: 'error', error, baseName }));
.catch((error) => {
if (axios.isCancel(error)) {
return { status: 'error', error: 'CANCELED', baseName };
}
const { data } = error;
return { status: 'error', error: data, baseName };
});
}))
.then((responses) => {
const successfulUploads = responses.filter(({ status }) => status === 'success');
Expand Down Expand Up @@ -230,6 +242,16 @@ function UploadList({
}
}


const handleCancelSingleUpload = useCallback((baseName) => {
setUploadContainerProgress((prevFiles) => ({ ...prevFiles, [baseName]: undefined }));
return sources[baseName].cancel();
}, []);

const handleCancelAllUploads = useCallback((files) => {
return files.forEach((file) => sources[file].cancel());
}, []);

return (
<UploadContainer
waitingUploads={waitingUploads}
Expand All @@ -242,6 +264,8 @@ function UploadList({
loading={loading}
progress={uploadContainerProgress}
type="dataset"
abort={handleCancelSingleUpload}
abortAll={handleCancelAllUploads}
>
{children}
</UploadContainer>
Expand Down
49 changes: 37 additions & 12 deletions geonode_mapstore_client/client/js/routes/UploadDocument.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/

import React, { useState } from 'react';
import React, { useState, useCallback } from 'react';
import PropTypes from 'prop-types';
import uniqBy from 'lodash/uniqBy';
import omit from 'lodash/omit';
Expand All @@ -32,6 +32,9 @@ function getFileNameParts(file) {
return { ext, baseName };
}

const cancelTokens = {};
const sources = {};

function UploadList({
children,
onChange
Expand Down Expand Up @@ -90,17 +93,26 @@ function UploadList({
setUnsupported([]);
axios.all(Object.keys(waitingUploads).map((baseName) => {
const readyUpload = waitingUploads[baseName];
cancelTokens[baseName] = axios.CancelToken;
sources[baseName] = cancelTokens[baseName].source();
const fileExt = Object.keys(readyUpload.files);
const file = readyUpload.files[fileExt[0]];
return uploadDocument({
title: file?.name,
file,
config: {
onUploadProgress: documentUploadProgress(baseName)
onUploadProgress: documentUploadProgress(baseName),
cancelToken: sources[baseName].token
}
})
.then((data) => ({ status: 'SUCCESS', data, file, baseName }))
.catch(({ data: error }) => ({ status: 'INVALID', error, file, baseName }));
.catch((error) => {
if (axios.isCancel(error)) {
return { status: 'INVALID', error: 'CANCELED', file, baseName };
}
const { data } = error;
return { status: 'INVALID', error: data, file, baseName };
});
}))
.then((responses) => {
const successfulUploads = responses.filter(({ status }) => status === 'SUCCESS');
Expand All @@ -109,15 +121,17 @@ function UploadList({
const successfulUploadsNames = successfulUploads.map(({ baseName }) => baseName);
updateWaitingUploads(omit(waitingUploads, successfulUploadsNames));
}
onChange(responses.map(({ status, file, data, error }) => ({
id: uuidv1(),
name: file?.name,
progress: 100,
state: status,
detail_url: data?.url,
create_date: Date.now(),
error
})));
onChange(responses.map(({ status, file, data, error }) => {
return {
id: uuidv1(),
name: file?.name,
progress: 100,
state: status,
detail_url: data?.url,
create_date: Date.now(),
error
};
}));
setLoading(false);
})
.catch(() => {
Expand All @@ -126,6 +140,15 @@ function UploadList({
}
}

const handleCancelSingleUpload = useCallback((baseName) => {
setUploadContainerProgress((prevFiles) => ({ ...prevFiles, [baseName]: undefined }));
return sources[baseName].cancel();
}, []);

const handleCancelAllUploads = useCallback((files) => {
return files.forEach((file) => sources[file].cancel());
}, []);

return (
<UploadContainer
waitingUploads={waitingUploads}
Expand All @@ -138,6 +161,8 @@ function UploadList({
loading={loading}
progress={uploadContainerProgress}
type="document"
abort={handleCancelSingleUpload}
abortAll={handleCancelAllUploads}
>
{children}
</UploadContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,19 @@ function PendingUploadCard({
filesExt,
loading,
progress,
size
size,
onAbort
}) {
return (
<div className="gn-upload-card">
<div className="gn-upload-card-header">
{missingExt.length > 0 ? <div className="gn-upload-card-error"><FaIcon name="exclamation"/></div> : null}
<div className="gn-upload-card-title">{baseName}</div>
{onRemove
? <Button size="xs" onClick={onRemove}>
? (!loading || !(progress?.[baseName])) ? <Button size="xs" onClick={onRemove}>
<FaIcon name="trash"/>
</Button> : <Button size="xs" onClick={() => onAbort(baseName)}>
<FaIcon name="stop"/>
</Button>
: null}
</div>
Expand All @@ -51,14 +54,14 @@ function PendingUploadCard({
})}
</ul>
{
(loading && progress) ?
(loading && progress && progress?.[baseName]) ?
<div className="gn-upload-card-progress-read">
{progress?.[baseName] ? `${progress?.[baseName]}%` : <Spinner />}
{progress[baseName] ? `${progress[baseName]}%` : <Spinner />}
</div> :
<div>{size}{' '}MB</div>
}
</div>
{loading && progress && <div style={{position: 'relative'}}>
{loading && progress && progress?.[baseName] && <div style={{position: 'relative'}}>
<div
className="gn-upload-card-progress"
style={{
Expand All @@ -68,7 +71,7 @@ function PendingUploadCard({
>
<div
style={{
width: `${progress?.[baseName]}%`,
width: `${progress[baseName]}%`,
height: 2,
transition: '0.3s all'
}}
Expand Down
32 changes: 11 additions & 21 deletions geonode_mapstore_client/client/js/routes/upload/UploadContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ function UploadContainer({
onUpload,
loading,
progress,
type
type,
abort,
abortAll
}) {

const inputFile = useRef();
Expand Down Expand Up @@ -94,7 +96,7 @@ function UploadContainer({
leftColumn={
<div className="gn-upload-list">
<div className="gn-upload-list-header">
<input ref={inputFile} value="" type="file" multiple onChange={handleFileDrop} style={{ display: 'none' }}/>
<input disabled={loading} ref={inputFile} value="" type="file" multiple onChange={handleFileDrop} style={{ display: 'none' }}/>
<Button onClick={() => inputFile?.current?.click()}>
<FaIcon name="plus"/>{' '}<Message msgId="gnviewer.selectFiles"/>
</Button>
Expand All @@ -117,6 +119,7 @@ function UploadContainer({
loading={loading}
progress={progress}
size={size}
onAbort={abort}
/>
</li>
);
Expand Down Expand Up @@ -146,32 +149,19 @@ function UploadContainer({
<ButtonWithTooltip noTooltipWhenDisabled tooltip={<Message msgId="gnviewer.exceedingFileMsg" msgParams={{limit: maxAllowedSize }} />} >
<Message msgId="gnviewer.upload" />
</ButtonWithTooltip> :
<Button
!loading ? <Button
variant="primary"
disabled={disabledUpload}
onClick={onUpload}
>
<Message msgId="gnviewer.upload"/>
</Button> : <Button
variant="primary"
onClick={() => abortAll(waitingUploadNames)}
>
<Message msgId="gnviewer.cancelUpload"/>
</Button>}
</div>
{loading && (
<div
style={{
position: 'absolute',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'flex-end',
justifyContent: 'center',
padding: '1rem',
textAlign: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.2)',
paddingBottom: '3rem'
}}
>
<Message msgId="gnviewer.transferInProgress"/>
</div>
)}
</div>
}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function UploadListContainer({

return (
<div className="gn-upload-processing">
{pendingUploads.length === 0
{pendingUploads.length === 0 || (filteredPendingUploads.every(({error}) => error === 'CANCELED'))
? (
<div className="gn-main-event-container">
<div className="gn-main-event-content">
Expand Down Expand Up @@ -72,7 +72,7 @@ function UploadListContainer({
delete_url: deleteUrl,
error
}) => {
return (
return (error !== 'CANCELED' &&
<li
key={id}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,8 @@
"transferInProgress": "Übertragung läuft",
"fileExceeds": "Die Dateigröße überschreitet {limit} MB. Bitte versuchen Sie es erneut mit einer kleineren Datei.",
"exceedingFileMsg": "Algunos de sus archivos exceden el límite de carga de {limit} MB. Por favor, elimínelos de la lista.",
"cannotPerfomAction": "Die Aktion für diese Ressource konnte nicht ausgeführt werden."
"cannotPerfomAction": "Die Aktion für diese Ressource konnte nicht ausgeführt werden.",
"cancelUpload": "Hochladen abbrechen"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,8 @@
"transferInProgress": "Transfer in progress",
"fileExceeds": "File size size exceeds {limit} MB. Please try again with a smaller file.",
"exceedingFileMsg": "Some of your files exceed the upload limit of {limit} MB. Please remove them from the list.",
"cannotPerfomAction": "Failed to perform action on this resource."
"cannotPerfomAction": "Failed to perform action on this resource.",
"cancelUpload": "Cancel upload"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,8 @@
"transferInProgress": "Transferencia en progreso",
"fileExceeds": "El tamaño del archivo supera los {limit} MB. Vuelva a intentarlo con un archivo más pequeño.",
"exceedingFileMsg": "Algunos de sus archivos exceden el límite de carga de {limit} MB. Por favor, elimínelos de la lista.",
"cannotPerfomAction": "No se pudo realizar la acción en este recurso."
"cannotPerfomAction": "No se pudo realizar la acción en este recurso.",
"cancelUpload": "Cancelar carga"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,8 @@
"transferInProgress": "Transfert en cours",
"fileExceeds": "La taille du fichier dépasse {Limit} Mo. Veuillez réessayer avec un fichier plus petit.",
"exceedingFileMsg": "Certains de vos fichiers dépassent la limite de téléchargement de {limit} Mo. Veuillez les supprimer de la liste.",
"cannotPerfomAction": "Échec de l'exécution de l'action sur cette ressource."
"cannotPerfomAction": "Échec de l'exécution de l'action sur cette ressource.",
"cancelUpload": "Annuler le téléchargement"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,8 @@
"transferInProgress": "Trasferimento in corso",
"fileExceeds": "La dimensione del file supera i {limit} MB. Riprova con un file più piccolo.",
"exceedingFileMsg": "Alcuni dei tuoi file superano il limite di caricamento di {limit} MB. Si prega di rimuoverli dall'elenco.",
"cannotPerfomAction": "Impossibile eseguire l'azione su questa risorsa."
"cannotPerfomAction": "Impossibile eseguire l'azione su questa risorsa.",
"cancelUpload": "Annulla caricamento"
}
}
}

0 comments on commit 1054caa

Please sign in to comment.