1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-02 15:38:15 +00:00

Zip download (#3252)

* [dir view] rewrote 'zip download'

* renamed component 'ShareLinkZipDownloadDialog' to 'ZipDownloadDialog'

* [zip download] show specific error msg
This commit is contained in:
llj
2019-04-12 15:54:05 +08:00
committed by Daniel Pan
parent f721ecb0a0
commit 655e951214
7 changed files with 149 additions and 238 deletions

View File

@@ -1,127 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Modal, ModalHeader, ModalBody } from 'reactstrap';
import { gettext, fileServerRoot } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import Loading from '../loading';
const propTypes = {
token: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
toggleDialog: PropTypes.func.isRequired
};
let interval;
class ShareLinkZipDownloadDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
errorMsg: '',
zipProgress: null
};
}
componentDidMount() {
const { token, path } = this.props;
seafileAPI.getShareLinkZipTask(token, path).then((res) => {
const zipToken = res.data['zip_token'];
this.setState({
isLoading: false,
errorMsg: '',
zipToken: zipToken
});
this.queryZipProgress();
interval = setInterval(this.queryZipProgress, 1000);
}).catch((error) => {
let errorMsg = '';
if (error.response) {
errorMsg = gettext('Error');
} else {
errorMsg = gettext('Please check the network.');
}
this.setState({
isLoading: false,
errorMsg: errorMsg
});
});
}
queryZipProgress = () => {
const zipToken = this.state.zipToken;
seafileAPI.queryZipProgress(zipToken).then((res) => {
const data = res.data;
this.setState({
zipProgress: data.total == 0 ? '100%' : (data.zipped/data.total*100).toFixed(2) + '%'
});
if (data['total'] == data['zipped']) {
clearInterval(interval);
this.props.toggleDialog();
location.href = `${fileServerRoot}zip/${zipToken}`;
}
}).catch((error) => {
clearInterval(interval);
let errorMsg = '';
if (error.response) {
errorMsg = gettext('Error');
} else {
errorMsg = gettext('Please check the network.');
}
this.setState({
isLoading: false,
errorMsg: errorMsg
});
});
}
cancelZipTask = () => {
const zipToken = this.state.zipToken;
seafileAPI.cancelZipTask(zipToken).then((res) => {
// do nothing
}).catch((error) => {
// do nothing
});
}
toggleDialog = () => {
const zipProgress = this.state.zipProgress;
if (zipProgress && zipProgress != '100%') {
clearInterval(interval);
this.cancelZipTask();
}
this.props.toggleDialog();
}
render() {
return (
<Modal isOpen={true} centered={true} toggle={this.toggleDialog}>
<ModalHeader toggle={this.toggleDialog}>{gettext('Download')}</ModalHeader>
<ModalBody>
<Content data={this.state} />
</ModalBody>
</Modal>
);
}
}
class Content extends React.Component {
render() {
const {isLoading, errorMsg, zipProgress} = this.props.data;
if (isLoading) {
return <Loading />;
}
if (errorMsg) {
return <p className="error mt-4 text-center">{errorMsg}</p>;
}
return <p className="mt-4 text-center">{`${gettext('Packaging...')} ${zipProgress}`}</p>;
}
}
ShareLinkZipDownloadDialog.propTypes = propTypes;
export default ShareLinkZipDownloadDialog;

View File

@@ -1,30 +1,135 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Modal, ModalHeader, ModalBody } from 'reactstrap';
import { gettext, fileServerRoot } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import Loading from '../loading';
const propTypes = {
onCancelDownload: PropTypes.func.isRequired,
progress: PropTypes.number.isRequired,
token: PropTypes.string,
path: PropTypes.string.isRequired,
repoID: PropTypes.string,
target: PropTypes.oneOfType([
PropTypes.string,
PropTypes.array
]),
toggleDialog: PropTypes.func.isRequired
};
class ZipDownloadDialog extends React.Component {
let interval;
toggle = () => {
this.props.onCancelDownload();
class ZipDownloadDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
errorMsg: '',
zipProgress: null
};
}
componentDidMount() {
const { token, path, repoID, target } = this.props;
const getZipTask = token ?
seafileAPI.getShareLinkZipTask(token, path) :
seafileAPI.zipDownload(repoID, path, target);
getZipTask.then((res) => {
const zipToken = res.data['zip_token'];
this.setState({
isLoading: false,
errorMsg: '',
zipToken: zipToken
});
this.queryZipProgress();
interval = setInterval(this.queryZipProgress, 1000);
}).catch((error) => {
let errorMsg = '';
if (error.response) {
errorMsg = error.response.data.error_msg || gettext('Error');
} else {
errorMsg = gettext('Please check the network.');
}
this.setState({
isLoading: false,
errorMsg: errorMsg
});
});
}
queryZipProgress = () => {
const zipToken = this.state.zipToken;
seafileAPI.queryZipProgress(zipToken).then((res) => {
const data = res.data;
this.setState({
zipProgress: data.total == 0 ? '100%' : (data.zipped/data.total*100).toFixed(2) + '%'
});
if (data['total'] == data['zipped']) {
clearInterval(interval);
this.props.toggleDialog();
location.href = `${fileServerRoot}zip/${zipToken}`;
}
}).catch((error) => {
clearInterval(interval);
let errorMsg = '';
if (error.response) {
errorMsg = gettext('Error');
} else {
errorMsg = gettext('Please check the network.');
}
this.setState({
isLoading: false,
errorMsg: errorMsg
});
});
}
cancelZipTask = () => {
const zipToken = this.state.zipToken;
seafileAPI.cancelZipTask(zipToken).then((res) => {
// do nothing
}).catch((error) => {
// do nothing
});
}
toggleDialog = () => {
const zipProgress = this.state.zipProgress;
if (zipProgress && zipProgress != '100%') {
clearInterval(interval);
this.cancelZipTask();
}
this.props.toggleDialog();
}
render() {
return (
<Modal isOpen={true} toggle={this.toggle}>
<ModalHeader toggle={this.toggle}></ModalHeader>
<Modal isOpen={true} centered={true} toggle={this.toggleDialog}>
<ModalHeader toggle={this.toggleDialog}>{gettext('Download')}</ModalHeader>
<ModalBody>
<div>{this.props.progress + '%'}</div>
<Content data={this.state} />
</ModalBody>
</Modal>
);
}
}
class Content extends React.Component {
render() {
const {isLoading, errorMsg, zipProgress} = this.props.data;
if (isLoading) {
return <Loading />;
}
if (errorMsg) {
return <p className="error mt-4 text-center">{errorMsg}</p>;
}
return <p className="mt-4 text-center">{`${gettext('Packaging...')} ${zipProgress}`}</p>;
}
}
ZipDownloadDialog.propTypes = propTypes;
export default ZipDownloadDialog;

View File

@@ -9,11 +9,10 @@ import URLDecorator from '../../utils/url-decorator';
import DirentMenu from './dirent-menu';
import Rename from '../rename';
import ModalPortal from '../modal-portal';
import ZipDownloadDialog from '../dialog/zip-download-dialog';
import MoveDirentDialog from '../dialog/move-dirent-dialog';
import CopyDirentDialog from '../dialog/copy-dirent-dialog';
import ShareDialog from '../dialog/share-dialog';
import toaster from '../toast';
import ZipDownloadDialog from '../dialog/zip-download-dialog';
import '../../css/dirent-list-item.css';
@@ -51,8 +50,7 @@ class DirentListItem extends React.Component {
this.state = {
isOperationShow: false,
highlight: false,
progress: 0,
isProgressDialogShow: false,
isZipDialogOpen: false,
isMoveDialogShow: false,
isCopyDialogShow: false,
isShareDialogShow: false,
@@ -61,7 +59,6 @@ class DirentListItem extends React.Component {
isDragTipShow: false,
isDropTipshow: false,
};
this.zipToken = null;
}
componentWillReceiveProps(nextProps) {
@@ -296,16 +293,8 @@ class DirentListItem extends React.Component {
let repoID = this.props.repoID;
let direntPath = this.getDirentPath(dirent);
if (dirent.type === 'dir') {
this.setState({isProgressDialogShow: true, progress: 0});
seafileAPI.zipDownload(repoID, this.props.path, dirent.name).then(res => {
this.zipToken = res.data['zip_token'];
this.addDownloadAnimation();
this.interval = setInterval(this.addDownloadAnimation, 1000);
}).catch((error) => {
clearInterval(this.interval);
this.setState({isProgressDialogShow: false});
let errorMessage = error.response.data.error_msg;
toaster.danger(errorMessage);
this.setState({
isZipDialogOpen: true
});
} else {
let url = URLDecorator.getUrl({type: 'download_file_url', repoID: repoID, filePath: direntPath});
@@ -313,34 +302,9 @@ class DirentListItem extends React.Component {
}
}
addDownloadAnimation = () => {
let _this = this;
let token = this.zipToken;
seafileAPI.queryZipProgress(token).then(res => {
let data = res.data;
let progress = data.total === 0 ? 100 : (data.zipped / data.total * 100).toFixed(0);
this.setState({progress: parseInt(progress)});
if (data['total'] === data['zipped']) {
this.setState({
progress: 100
});
clearInterval(this.interval);
location.href = URLDecorator.getUrl({type: 'download_dir_zip_url', token: token});
setTimeout(function() {
_this.setState({isProgressDialogShow: false});
}, 500);
}
});
}
onCancelDownload = () => {
let zipToken = this.zipToken;
seafileAPI.cancelZipTask(zipToken).then(res => {
clearInterval(this.interval);
this.setState({
isProgressDialogShow: false,
});
closeZipDialog = () => {
this.setState({
isZipDialogOpen: false
});
}
@@ -364,7 +328,7 @@ class DirentListItem extends React.Component {
let dragStartItemData = {nodeDirent: this.props.dirent, nodeParentPath: this.props.path, nodeRootPath: nodeRootPath};
dragStartItemData = JSON.stringify(dragStartItemData);
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setDragImage(this.refs.drag_icon, 15, 15);
e.dataTransfer.setData('applicaiton/drag-item-info', dragStartItemData);
}
@@ -560,11 +524,13 @@ class DirentListItem extends React.Component {
/>
</ModalPortal>
}
{this.state.isProgressDialogShow &&
{this.state.isZipDialogOpen &&
<ModalPortal>
<ZipDownloadDialog
progress={this.state.progress}
onCancelDownload={this.onCancelDownload}
repoID={this.props.repoID}
path={this.props.path}
target={this.props.dirent.name}
toggleDialog={this.closeZipDialog}
/>
</ModalPortal>
}

View File

@@ -1,18 +1,17 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { Button , ButtonGroup , Modal } from 'reactstrap';
import { Button, ButtonGroup } from 'reactstrap';
import { gettext } from '../../utils/constants';
import { Utils } from '../../utils/utils';
import { seafileAPI } from '../../utils/seafile-api';
import URLDecorator from '../../utils/url-decorator';
import ZipDownloadDialog from '../dialog/zip-download-dialog';
import MoveDirentDialog from '../dialog/move-dirent-dialog';
import CopyDirentDialog from '../dialog/copy-dirent-dialog';
import DirentsMenu from '../dirent-list-view/dirents-menu';
import ShareDialog from '../dialog/share-dialog';
import RelatedFileDialogs from '../dialog/related-file-dialogs';
import EditFileTagDialog from '../dialog/edit-filetag-dialog';
import toaster from '../toast';
import ZipDownloadDialog from '../dialog/zip-download-dialog';
import ModalPortal from '../modal-portal';
const propTypes = {
@@ -37,8 +36,7 @@ class MutipleDirOperationToolbar extends React.Component {
constructor(props) {
super(props);
this.state = {
progress: 0,
isProgressDialogShow: false,
isZipDialogOpen: false,
isMoveDialogShow: false,
isCopyDialogShow: false,
isMutipleOperation: true,
@@ -50,7 +48,6 @@ class MutipleDirOperationToolbar extends React.Component {
showRelatedFileDialog: false,
viewMode: 'list_related_file',
};
this.zipToken = null;
}
onMoveToggle = () => {
@@ -74,49 +71,15 @@ class MutipleDirOperationToolbar extends React.Component {
location.href= url;
return;
}
let selectedDirentNames = selectedDirentList.map(dirent => {
return dirent.name;
});
this.setState({isProgressDialogShow: true, progress: 0});
seafileAPI.zipDownload(repoID, path, selectedDirentNames).then(res => {
this.zipToken = res.data['zip_token'];
this.addDownloadAnimation();
this.interval = setInterval(this.addDownloadAnimation, 1000);
}).catch((error) => {
clearInterval(this.interval);
this.setState({isProgressDialogShow: false});
let errorMessage = error.response.data.error_msg;
toaster.danger(errorMessage);
this.setState({
isZipDialogOpen: true
});
}
}
addDownloadAnimation = () => {
let _this = this;
let token = this.zipToken;
seafileAPI.queryZipProgress(token).then(res => {
let data = res.data;
let progress = data.total === 0 ? 100 : (data.zipped / data.total * 100).toFixed(0);
this.setState({progress: parseInt(progress)});
if (data['total'] === data['zipped']) {
this.setState({
progress: 100
});
clearInterval(this.interval);
location.href = URLDecorator.getUrl({type: 'download_dir_zip_url', token: token});
setTimeout(function() {
_this.setState({isProgressDialogShow: false});
}, 500);
}
});
}
onCancelDownload = () => {
seafileAPI.cancelZipTask(this.zipToken).then(() => {
clearInterval(this.interval);
this.setState({isProgressDialogShow: false});
closeZipDialog = () => {
this.setState({
isZipDialogOpen: false
});
}
@@ -315,8 +278,15 @@ class MutipleDirOperationToolbar extends React.Component {
onCancelCopy={this.onCopyToggle}
/>
}
{this.state.isProgressDialogShow &&
<ZipDownloadDialog progress={this.state.progress} onCancelDownload={this.onCancelDownload} />
{this.state.isZipDialogOpen &&
<ModalPortal>
<ZipDownloadDialog
repoID={this.props.repoID}
path={this.props.path}
target={this.props.selectedDirentList.map(dirent => dirent.name)}
toggleDialog={this.closeZipDialog}
/>
</ModalPortal>
}
{this.state.showLibContentViewDialogs && (
<Fragment>

View File

@@ -9,7 +9,7 @@ import { seafileAPI } from './utils/seafile-api';
import Loading from './components/loading';
import toaster from './components/toast';
import ModalPortal from './components/modal-portal';
import ShareLinkZipDownloadDialog from './components/dialog/share-link-zip-download-dialog';
import ZipDownloadDialog from './components/dialog/zip-download-dialog';
import ImageDialog from './components/dialog/image-dialog';
import './css/shared-dir-view.css';
@@ -228,7 +228,7 @@ class SharedDirView extends React.Component {
</div>
{this.state.isZipDialogOpen &&
<ModalPortal>
<ShareLinkZipDownloadDialog
<ZipDownloadDialog
token={token}
path={this.state.zipFolderPath}
toggleDialog={this.closeZipDialog}

View File

@@ -10,9 +10,6 @@ class URLDecorator {
params = 'p=' + options.filePath;
url = siteRoot + 'repo/' + historyRepoID + '/' + options.objID + '/download?' + params;
break;
case 'download_dir_zip_url':
url = fileServerRoot + 'zip/' + options.token;
break;
case 'download_file_url':
url = siteRoot + 'lib/' + options.repoID + '/file' + Utils.encodePath(options.filePath) + '?dl=1';
break;

View File

@@ -94,7 +94,7 @@ class ZipTaskView(APIView):
repo.store_id, repo.version, dir_id)
if dir_size > seaserv.MAX_DOWNLOAD_DIR_SIZE:
error_msg = 'Unable to download directory "%s": size is too large.' % dir_name
error_msg = _('Unable to download directory "%s": size is too large.') % dir_name
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
fake_obj_id = {