2018-11-27 06:47:19 +00:00
|
|
|
import React, { Fragment } from 'react';
|
|
|
|
import PropTypes from 'prop-types';
|
2019-03-28 09:34:01 +00:00
|
|
|
import { Button , ButtonGroup , Modal } from 'reactstrap';
|
2018-11-27 06:47:19 +00:00
|
|
|
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';
|
2019-03-18 09:32:49 +00:00
|
|
|
import DirentsMenu from '../dirent-list-view/dirents-menu';
|
|
|
|
import ShareDialog from '../dialog/share-dialog';
|
2019-03-29 02:36:34 +00:00
|
|
|
import RelatedFileDialogs from '../dialog/related-file-dialogs';
|
2019-03-18 09:32:49 +00:00
|
|
|
import EditFileTagDialog from '../dialog/edit-filetag-dialog';
|
|
|
|
import toaster from '../toast';
|
|
|
|
import ModalPortal from '../modal-portal';
|
2018-11-27 06:47:19 +00:00
|
|
|
|
|
|
|
const propTypes = {
|
|
|
|
path: PropTypes.string.isRequired,
|
|
|
|
repoID: PropTypes.string.isRequired,
|
2019-03-11 03:14:49 +00:00
|
|
|
repoEncrypted: PropTypes.bool.isRequired,
|
2018-11-27 06:47:19 +00:00
|
|
|
selectedDirentList: PropTypes.array.isRequired,
|
|
|
|
onItemsMove: PropTypes.func.isRequired,
|
|
|
|
onItemsCopy: PropTypes.func.isRequired,
|
|
|
|
onItemsDelete: PropTypes.func.isRequired,
|
2019-03-18 09:32:49 +00:00
|
|
|
isRepoOwner: PropTypes.bool.isRequired,
|
2019-03-19 10:20:45 +00:00
|
|
|
enableDirPrivateShare: PropTypes.bool.isRequired,
|
|
|
|
currentRepoInfo: PropTypes.object.isRequired,
|
2019-03-20 03:13:32 +00:00
|
|
|
onFilesTagChanged: PropTypes.func.isRequired,
|
2019-03-19 10:20:45 +00:00
|
|
|
unSelectDirent: PropTypes.func.isRequired,
|
|
|
|
updateDirent: PropTypes.func.isRequired,
|
|
|
|
showDirentDetail: PropTypes.func.isRequired,
|
2018-11-27 06:47:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class MutipleDirOperationToolbar extends React.Component {
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
progress: 0,
|
|
|
|
isProgressDialogShow: false,
|
|
|
|
isMoveDialogShow: false,
|
|
|
|
isCopyDialogShow: false,
|
|
|
|
isMutipleOperation: true,
|
2019-03-18 09:32:49 +00:00
|
|
|
showLibContentViewDialogs: false,
|
|
|
|
showShareDialog: false,
|
|
|
|
showEditFileTagDialog: false,
|
|
|
|
fileTagList: [],
|
|
|
|
multiFileTagList: [],
|
2019-03-29 02:36:34 +00:00
|
|
|
showRelatedFileDialog: false,
|
|
|
|
viewMode: 'list_related_file',
|
2018-11-27 06:47:19 +00:00
|
|
|
};
|
|
|
|
this.zipToken = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
onMoveToggle = () => {
|
|
|
|
this.setState({isMoveDialogShow: !this.state.isMoveDialogShow});
|
|
|
|
}
|
|
|
|
|
|
|
|
onCopyToggle = () => {
|
|
|
|
this.setState({isCopyDialogShow: !this.state.isCopyDialogShow});
|
|
|
|
}
|
|
|
|
|
|
|
|
onItemsDelete = () => {
|
|
|
|
this.props.onItemsDelete();
|
|
|
|
}
|
|
|
|
|
|
|
|
onItemsDownload = () => {
|
|
|
|
let { path, repoID, selectedDirentList } = this.props;
|
|
|
|
if (selectedDirentList.length) {
|
|
|
|
if (selectedDirentList.length === 1 && !selectedDirentList[0].isDir()) {
|
|
|
|
let direntPath = Utils.joinPath(path, selectedDirentList[0].name);
|
|
|
|
let url = URLDecorator.getUrl({type: 'download_file_url', repoID: repoID, filePath: direntPath});
|
|
|
|
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);
|
2019-04-11 10:02:39 +00:00
|
|
|
}).catch((error) => {
|
|
|
|
clearInterval(this.interval);
|
|
|
|
this.setState({isProgressDialogShow: false});
|
|
|
|
let errorMessage = error.response.data.error_msg;
|
|
|
|
toaster.danger(errorMessage);
|
2018-11-27 06:47:19 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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(() => {
|
2019-04-11 10:02:39 +00:00
|
|
|
clearInterval(this.interval);
|
2018-11-27 06:47:19 +00:00
|
|
|
this.setState({isProgressDialogShow: false});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-03-18 09:32:49 +00:00
|
|
|
onMenuItemClick = (operation) => {
|
|
|
|
const dirents = this.props.selectedDirentList;
|
|
|
|
const dirent = dirents[0];
|
|
|
|
switch(operation) {
|
|
|
|
case 'Share':
|
|
|
|
this.setState({
|
|
|
|
showLibContentViewDialogs: true,
|
|
|
|
showShareDialog: true,
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
case 'Tags':
|
2019-03-19 02:38:05 +00:00
|
|
|
this.listFileTags(dirent);
|
2019-03-18 09:32:49 +00:00
|
|
|
break;
|
|
|
|
case 'Details':
|
|
|
|
this.props.showDirentDetail();
|
|
|
|
break;
|
|
|
|
case 'Lock':
|
|
|
|
this.lockFile(dirent);
|
|
|
|
break;
|
|
|
|
case 'Unlock':
|
|
|
|
this.unlockFile(dirent);
|
|
|
|
break;
|
|
|
|
case 'Related Files':
|
|
|
|
this.openRelatedFilesDialog(dirent);
|
|
|
|
break;
|
|
|
|
case 'History':
|
|
|
|
this.onHistory(dirent);
|
|
|
|
break;
|
|
|
|
case 'Open via Client':
|
|
|
|
this.onOpenViaClient(dirent);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lockFile = (dirent) => {
|
|
|
|
const filePath = this.getDirentPath(dirent);
|
|
|
|
seafileAPI.lockfile(this.props.repoID, filePath).then((res) => {
|
|
|
|
if (res.data.is_locked) {
|
|
|
|
this.props.updateDirent(dirent, 'is_locked', true);
|
|
|
|
this.props.updateDirent(dirent, 'locked_by_me', true);
|
|
|
|
this.props.unSelectDirent();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
unlockFile = (dirent) => {
|
|
|
|
const filePath = this.getDirentPath(dirent);
|
|
|
|
seafileAPI.unlockfile(this.props.repoID, filePath).then((res) => {
|
|
|
|
if (!res.data.is_locked) {
|
|
|
|
this.props.updateDirent(dirent, 'is_locked', false);
|
|
|
|
this.props.updateDirent(dirent, 'locked_by_me', false);
|
|
|
|
this.props.unSelectDirent();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onOpenViaClient = (dirent) => {
|
|
|
|
const filePath = this.getDirentPath(dirent);
|
|
|
|
let url = URLDecorator.getUrl({
|
|
|
|
type: 'open_via_client',
|
|
|
|
repoID: this.props.repoID,
|
|
|
|
filePath: filePath
|
|
|
|
});
|
|
|
|
location.href = url;
|
|
|
|
this.props.unSelectDirent();
|
|
|
|
}
|
|
|
|
|
|
|
|
onHistory = (dirent) => {
|
|
|
|
let filePath = this.getDirentPath(dirent);
|
|
|
|
let url = URLDecorator.getUrl({
|
|
|
|
type: 'file_revisions',
|
|
|
|
repoID: this.props.repoID,
|
|
|
|
filePath: filePath
|
|
|
|
});
|
|
|
|
location.href = url;
|
|
|
|
}
|
|
|
|
|
|
|
|
openRelatedFilesDialog = (dirent) => {
|
|
|
|
let filePath = this.getDirentPath(dirent);
|
|
|
|
seafileAPI.listRelatedFiles(this.props.repoID, filePath).then(res => {
|
2019-03-29 02:36:34 +00:00
|
|
|
let relatedFiles = res.data.related_files;
|
|
|
|
if (relatedFiles.length > 0) {
|
2019-03-18 09:32:49 +00:00
|
|
|
this.setState({
|
2019-03-29 02:36:34 +00:00
|
|
|
relatedFiles: relatedFiles,
|
|
|
|
showLibContentViewDialogs: true,
|
|
|
|
showRelatedFileDialog: true,
|
|
|
|
viewMode: 'list_related_file',
|
2019-03-18 09:32:49 +00:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.setState({
|
2019-03-29 02:36:34 +00:00
|
|
|
relatedFiles: relatedFiles,
|
|
|
|
showLibContentViewDialogs: true,
|
|
|
|
showRelatedFileDialog: true,
|
|
|
|
viewMode: 'add_related_file',
|
2019-03-18 09:32:49 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
toggleCancel = () => {
|
|
|
|
this.setState({
|
|
|
|
showLibContentViewDialogs: false,
|
|
|
|
showShareDialog: false,
|
|
|
|
showEditFileTagDialog: false,
|
2019-03-29 02:36:34 +00:00
|
|
|
showRelatedFileDialog: false,
|
2019-03-18 09:32:49 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
listFileTags = (dirent) => {
|
|
|
|
let filePath = this.getDirentPath(dirent);
|
|
|
|
seafileAPI.listFileTags(this.props.repoID, filePath).then(res => {
|
|
|
|
let fileTagList = res.data.file_tags;
|
|
|
|
for (let i = 0, length = fileTagList.length; i < length; i++) {
|
|
|
|
fileTagList[i].id = fileTagList[i].file_tag_id;
|
|
|
|
}
|
|
|
|
this.setState({
|
2019-03-19 02:38:05 +00:00
|
|
|
fileTagList: fileTagList,
|
|
|
|
showLibContentViewDialogs: true,
|
|
|
|
showEditFileTagDialog: true,
|
2019-03-18 09:32:49 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onMenuFileTagChanged = () => {
|
|
|
|
this.listFileTags(this.props.selectedDirentList[0]);
|
|
|
|
let length = this.props.selectedDirentList.length;
|
|
|
|
for (let i = 0; i < length; i++) {
|
|
|
|
const dirent = this.props.selectedDirentList[i];
|
|
|
|
const direntPath = this.getDirentPath(dirent);
|
2019-03-20 03:13:32 +00:00
|
|
|
this.props.onFilesTagChanged(dirent, direntPath);
|
2019-03-18 09:32:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
listRelatedFiles = (dirent) => {
|
|
|
|
let filePath = this.getDirentPath(dirent);
|
|
|
|
seafileAPI.listRelatedFiles(this.props.repoID, filePath).then(res => {
|
|
|
|
this.setState({
|
|
|
|
relatedFiles: res.data.related_files
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onRelatedFileChange = () => {
|
|
|
|
this.listRelatedFiles(this.props.selectedDirentList[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
getDirentPath = (dirent) => {
|
2019-03-18 10:09:37 +00:00
|
|
|
if (dirent) return Utils.joinPath(this.props.path, dirent.name);
|
2019-03-18 09:32:49 +00:00
|
|
|
}
|
|
|
|
|
2018-11-27 06:47:19 +00:00
|
|
|
render() {
|
2019-03-18 09:32:49 +00:00
|
|
|
const { repoID } = this.props;
|
|
|
|
let direntPath = this.getDirentPath(this.props.selectedDirentList[0]);
|
2018-11-27 06:47:19 +00:00
|
|
|
return (
|
|
|
|
<Fragment>
|
2019-03-18 09:32:49 +00:00
|
|
|
<div className="d-flex">
|
|
|
|
<ButtonGroup className="flex-row group-operations">
|
|
|
|
<Button className="secondary group-op-item action-icon sf2-icon-move" title={gettext('Move')} onClick={this.onMoveToggle}></Button>
|
|
|
|
<Button className="secondary group-op-item action-icon sf2-icon-copy" title={gettext('Copy')} onClick={this.onCopyToggle}></Button>
|
|
|
|
<Button className="secondary group-op-item action-icon sf2-icon-delete" title={gettext('Delete')} onClick={this.onItemsDelete}></Button>
|
|
|
|
<Button className="secondary group-op-item action-icon sf2-icon-download" title={gettext('Download')} onClick={this.onItemsDownload}></Button>
|
2019-03-20 06:49:16 +00:00
|
|
|
{this.props.selectedDirentList.length > 0 &&
|
|
|
|
<DirentsMenu
|
|
|
|
dirents={this.props.selectedDirentList}
|
|
|
|
currentRepoInfo={this.props.currentRepoInfo}
|
|
|
|
isRepoOwner={this.props.isRepoOwner}
|
|
|
|
onMenuItemClick={this.onMenuItemClick}
|
|
|
|
/>
|
|
|
|
}
|
2019-03-18 09:32:49 +00:00
|
|
|
</ButtonGroup>
|
|
|
|
</div>
|
2018-11-27 06:47:19 +00:00
|
|
|
{this.state.isMoveDialogShow &&
|
|
|
|
<MoveDirentDialog
|
|
|
|
path={this.props.path}
|
2018-11-28 04:41:49 +00:00
|
|
|
repoID={this.props.repoID}
|
2019-03-11 03:14:49 +00:00
|
|
|
repoEncrypted={this.props.repoEncrypted}
|
2018-11-27 06:47:19 +00:00
|
|
|
isMutipleOperation={this.state.isMutipleOperation}
|
|
|
|
selectedDirentList={this.props.selectedDirentList}
|
|
|
|
onItemsMove={this.props.onItemsMove}
|
|
|
|
onCancelMove={this.onMoveToggle}
|
|
|
|
/>
|
|
|
|
}
|
|
|
|
{this.state.isCopyDialogShow &&
|
|
|
|
<CopyDirentDialog
|
|
|
|
path={this.props.path}
|
2018-11-28 04:41:49 +00:00
|
|
|
repoID={this.props.repoID}
|
2019-03-11 03:14:49 +00:00
|
|
|
repoEncrypted={this.props.repoEncrypted}
|
2018-11-27 06:47:19 +00:00
|
|
|
selectedDirentList={this.props.selectedDirentList}
|
|
|
|
isMutipleOperation={this.state.isMutipleOperation}
|
|
|
|
onItemsCopy={this.props.onItemsCopy}
|
|
|
|
onCancelCopy={this.onCopyToggle}
|
|
|
|
/>
|
|
|
|
}
|
|
|
|
{this.state.isProgressDialogShow &&
|
|
|
|
<ZipDownloadDialog progress={this.state.progress} onCancelDownload={this.onCancelDownload} />
|
|
|
|
}
|
2019-03-18 09:32:49 +00:00
|
|
|
{this.state.showLibContentViewDialogs && (
|
|
|
|
<Fragment>
|
|
|
|
{this.state.showShareDialog &&
|
|
|
|
<ModalPortal>
|
|
|
|
<ShareDialog
|
|
|
|
itemType={this.props.selectedDirentList[0].type}
|
|
|
|
itemName={this.props.selectedDirentList[0].name}
|
|
|
|
itemPath={direntPath}
|
|
|
|
userPerm={this.props.selectedDirentList[0].permission}
|
|
|
|
repoID={repoID}
|
|
|
|
repoEncrypted={false}
|
|
|
|
enableDirPrivateShare={this.props.enableDirPrivateShare}
|
|
|
|
isGroupOwnedRepo={this.state.isGroupOwnedRepo}
|
|
|
|
toggleDialog={this.toggleCancel}
|
|
|
|
/>
|
|
|
|
</ModalPortal>
|
|
|
|
}
|
|
|
|
{this.state.showEditFileTagDialog &&
|
|
|
|
<ModalPortal>
|
|
|
|
<EditFileTagDialog
|
|
|
|
repoID={repoID}
|
|
|
|
filePath={direntPath}
|
|
|
|
fileTagList={this.state.fileTagList}
|
|
|
|
toggleCancel={this.toggleCancel}
|
|
|
|
onFileTagChanged={this.onMenuFileTagChanged}
|
|
|
|
/>
|
|
|
|
</ModalPortal>
|
|
|
|
}
|
2019-03-29 02:36:34 +00:00
|
|
|
{this.state.showRelatedFileDialog &&
|
2019-03-18 09:32:49 +00:00
|
|
|
<ModalPortal>
|
2019-03-29 02:36:34 +00:00
|
|
|
<RelatedFileDialogs
|
|
|
|
repoID={repoID}
|
|
|
|
filePath={direntPath}
|
|
|
|
relatedFiles={this.state.relatedFiles}
|
|
|
|
toggleCancel={this.toggleCancel}
|
|
|
|
onRelatedFileChange={this.onRelatedFileChange}
|
|
|
|
dirent={this.props.selectedDirentList[0]}
|
|
|
|
viewMode={this.state.viewMode}
|
|
|
|
/>
|
2019-03-18 09:32:49 +00:00
|
|
|
</ModalPortal>
|
2019-03-29 02:36:34 +00:00
|
|
|
}
|
2019-03-18 09:32:49 +00:00
|
|
|
</Fragment>
|
|
|
|
)}
|
2018-11-27 06:47:19 +00:00
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MutipleDirOperationToolbar.propTypes = propTypes;
|
|
|
|
|
|
|
|
export default MutipleDirOperationToolbar;
|