mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-29 04:01:24 +00:00
463 lines
15 KiB
JavaScript
463 lines
15 KiB
JavaScript
import React, { Fragment } from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import { gettext, siteRoot, name, fileServerRoot, useGoFileserver } from '../../utils/constants';
|
|
import { Utils } from '../../utils/utils';
|
|
import { seafileAPI } from '../../utils/seafile-api';
|
|
import URLDecorator from '../../utils/url-decorator';
|
|
import MoveDirentDialog from '../dialog/move-dirent-dialog';
|
|
import CopyDirentDialog from '../dialog/copy-dirent-dialog';
|
|
import EditFileTagDialog from '../dialog/edit-filetag-dialog';
|
|
import ZipDownloadDialog from '../dialog/zip-download-dialog';
|
|
import ShareDialog from '../dialog/share-dialog';
|
|
import Rename from '../dialog/rename-dirent';
|
|
import LibSubFolderPermissionDialog from '../dialog/lib-sub-folder-permission-dialog';
|
|
import ModalPortal from '../modal-portal';
|
|
import ItemDropdownMenu from '../dropdown-menu/item-dropdown-menu';
|
|
import toaster from '../toast';
|
|
import '../../css/selected-dirents-toolbar.css';
|
|
|
|
const propTypes = {
|
|
path: PropTypes.string.isRequired,
|
|
userPerm: PropTypes.string.isRequired,
|
|
repoID: PropTypes.string.isRequired,
|
|
repoEncrypted: PropTypes.bool.isRequired,
|
|
repoTags: PropTypes.array.isRequired,
|
|
selectedDirentList: PropTypes.array.isRequired,
|
|
onItemsMove: PropTypes.func.isRequired,
|
|
onItemsCopy: PropTypes.func.isRequired,
|
|
onItemsDelete: PropTypes.func.isRequired,
|
|
isRepoOwner: PropTypes.bool.isRequired,
|
|
enableDirPrivateShare: PropTypes.bool.isRequired,
|
|
currentRepoInfo: PropTypes.object.isRequired,
|
|
onFilesTagChanged: PropTypes.func.isRequired,
|
|
unSelectDirent: PropTypes.func.isRequired,
|
|
updateDirent: PropTypes.func.isRequired,
|
|
currentMode: PropTypes.string.isRequired,
|
|
switchViewMode: PropTypes.func.isRequired,
|
|
direntList: PropTypes.array.isRequired,
|
|
onItemRename: PropTypes.func.isRequired,
|
|
showDirentDetail: PropTypes.func.isRequired,
|
|
isGroupOwnedRepo: PropTypes.bool.isRequired,
|
|
};
|
|
|
|
class MultipleDirOperationToolbar extends React.Component {
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
this.state = {
|
|
isZipDialogOpen: false,
|
|
isMoveDialogShow: false,
|
|
isCopyDialogShow: false,
|
|
isMultipleOperation: true,
|
|
showLibContentViewDialogs: false,
|
|
showShareDialog: false,
|
|
showEditFileTagDialog: false,
|
|
fileTagList: [],
|
|
multiFileTagList: [],
|
|
isRenameDialogOpen: false,
|
|
isPermissionDialogOpen: false
|
|
};
|
|
}
|
|
|
|
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;
|
|
}
|
|
if (!useGoFileserver) {
|
|
this.setState({
|
|
isZipDialogOpen: true
|
|
});
|
|
} else {
|
|
const target = this.props.selectedDirentList.map(dirent => dirent.name);
|
|
seafileAPI.zipDownload(repoID, path, target).then((res) => {
|
|
const zipToken = res.data['zip_token'];
|
|
location.href = `${fileServerRoot}zip/${zipToken}`;
|
|
}).catch((error) => {
|
|
let errorMsg = Utils.getErrorMsg(error);
|
|
this.setState({
|
|
isLoading: false,
|
|
errorMsg: errorMsg
|
|
});
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
closeZipDialog = () => {
|
|
this.setState({
|
|
isZipDialogOpen: false
|
|
});
|
|
};
|
|
|
|
checkDuplicatedName = (newName) => {
|
|
return Utils.checkDuplicatedNameInList(this.props.direntList, newName);
|
|
};
|
|
|
|
onItemRename = (newName) => {
|
|
const dirent = this.props.selectedDirentList[0];
|
|
this.props.onItemRename(dirent, newName);
|
|
};
|
|
|
|
onPermissionItem = () => {
|
|
this.setState({
|
|
showLibContentViewDialogs: !this.state.showLibContentViewDialogs,
|
|
isPermissionDialogOpen: !this.state.isPermissionDialogOpen
|
|
});
|
|
};
|
|
|
|
onStartRevise = (dirent) => {
|
|
let repoID = this.props.repoID;
|
|
let filePath = this.getDirentPath(dirent);
|
|
seafileAPI.sdocStartRevise(repoID, filePath).then((res) => {
|
|
let url = siteRoot + 'lib/' + repoID + '/file' + Utils.encodePath(res.data.file_path);
|
|
window.open(url);
|
|
}).catch(error => {
|
|
let errMessage = Utils.getErrorMsg(error);
|
|
toaster.danger(errMessage);
|
|
});
|
|
};
|
|
|
|
getDirentMenuList = (dirent) => {
|
|
const isRepoOwner = this.props.isRepoOwner;
|
|
const currentRepoInfo = this.props.currentRepoInfo;
|
|
const isContextmenu = true;
|
|
let opList = Utils.getDirentOperationList(isRepoOwner, currentRepoInfo, dirent, isContextmenu);
|
|
const list = ['Move', 'Copy', 'Delete', 'Download'];
|
|
if (dirent.type == 'dir') {
|
|
opList = opList.filter((item, index) => {
|
|
return list.indexOf(item.key) == -1 && item != 'Divider';
|
|
});
|
|
} else {
|
|
opList = opList.filter((item, index) => {
|
|
return list.indexOf(item.key) == -1;
|
|
});
|
|
}
|
|
return opList;
|
|
};
|
|
|
|
onMenuItemClick = (operation) => {
|
|
const dirents = this.props.selectedDirentList;
|
|
const dirent = dirents[0];
|
|
switch (operation) {
|
|
case 'Share':
|
|
this.setState({
|
|
showLibContentViewDialogs: true,
|
|
showShareDialog: true,
|
|
});
|
|
break;
|
|
case 'Rename':
|
|
this.setState({
|
|
showLibContentViewDialogs: true,
|
|
isRenameDialogOpen: true
|
|
});
|
|
break;
|
|
case 'Permission':
|
|
this.onPermissionItem();
|
|
break;
|
|
case 'Tags':
|
|
this.listFileTags(dirent);
|
|
break;
|
|
case 'Lock':
|
|
this.lockFile(dirent);
|
|
break;
|
|
case 'Unlock':
|
|
this.unlockFile(dirent);
|
|
break;
|
|
case 'History':
|
|
this.onHistory(dirent);
|
|
break;
|
|
case 'Access Log':
|
|
this.onAccessLog(dirent);
|
|
break;
|
|
case 'Properties':
|
|
this.props.showDirentDetail('info');
|
|
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.updateDirent(dirent, 'lock_owner_name', name);
|
|
this.props.unSelectDirent();
|
|
}
|
|
}).catch(error => {
|
|
let errMessage = Utils.getErrorMsg(error);
|
|
toaster.danger(errMessage);
|
|
});
|
|
};
|
|
|
|
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.updateDirent(dirent, 'lock_owner_name', '');
|
|
this.props.unSelectDirent();
|
|
}
|
|
}).catch(error => {
|
|
let errMessage = Utils.getErrorMsg(error);
|
|
toaster.danger(errMessage);
|
|
});
|
|
};
|
|
|
|
onOpenViaClient = (dirent) => {
|
|
const filePath = this.getDirentPath(dirent);
|
|
let url = URLDecorator.getUrl({
|
|
type: 'open_via_client',
|
|
repoID: this.props.repoID,
|
|
filePath: filePath
|
|
});
|
|
location.href = url;
|
|
};
|
|
|
|
onHistory = (dirent) => {
|
|
let filePath = this.getDirentPath(dirent);
|
|
let url = URLDecorator.getUrl({
|
|
type: 'file_revisions',
|
|
repoID: this.props.repoID,
|
|
filePath: filePath
|
|
});
|
|
location.href = url;
|
|
};
|
|
|
|
onAccessLog = (dirent) => {
|
|
let filePath = this.getDirentPath(dirent);
|
|
let path = siteRoot + 'repo/file-access/' + this.props.repoID + '/?p=' + encodeURIComponent(filePath) ;
|
|
window.open(path);
|
|
};
|
|
|
|
toggleCancel = () => {
|
|
this.setState({
|
|
showLibContentViewDialogs: false,
|
|
showShareDialog: false,
|
|
showEditFileTagDialog: false,
|
|
isRenameDialogOpen: false,
|
|
isPermissionDialogOpen: false,
|
|
});
|
|
};
|
|
|
|
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({
|
|
fileTagList: fileTagList,
|
|
showLibContentViewDialogs: true,
|
|
showEditFileTagDialog: true,
|
|
});
|
|
}).catch(error => {
|
|
let errMessage = Utils.getErrorMsg(error);
|
|
toaster.danger(errMessage);
|
|
});
|
|
};
|
|
|
|
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);
|
|
this.props.onFilesTagChanged(dirent, direntPath);
|
|
}
|
|
};
|
|
|
|
getDirentPath = (dirent) => {
|
|
if (dirent) return Utils.joinPath(this.props.path, dirent.name);
|
|
};
|
|
|
|
render() {
|
|
const { repoID, repoTags, userPerm, selectedDirentList } = this.props;
|
|
const dirent = selectedDirentList[0];
|
|
const selectedLen = selectedDirentList.length;
|
|
const direntPath = this.getDirentPath(dirent);
|
|
const { isCustomPermission, customPermission } = Utils.getUserPermission(userPerm);
|
|
|
|
let canModify = false;
|
|
let canCopy = false;
|
|
let canDelete = false;
|
|
let canDownload = false;
|
|
switch (userPerm) {
|
|
case 'rw':
|
|
case 'admin':
|
|
canModify = true;
|
|
canCopy = true;
|
|
canDelete = true;
|
|
canDownload = true;
|
|
break;
|
|
case 'cloud-edit':
|
|
canModify = true;
|
|
canCopy = true;
|
|
canDelete = true;
|
|
break;
|
|
case 'r':
|
|
canCopy = true;
|
|
canDownload = true;
|
|
break;
|
|
}
|
|
if (isCustomPermission) {
|
|
const { permission } = customPermission;
|
|
canModify = permission.modify;
|
|
canCopy = permission.copy;
|
|
canDownload = permission.download;
|
|
canDelete = permission.delete;
|
|
}
|
|
|
|
return (
|
|
<Fragment>
|
|
<div className="selected-dirents-toolbar">
|
|
<span className="cur-view-path-btn px-2" onClick={this.props.unSelectDirent}>
|
|
<span className="sf3-font-x-01 sf3-font mr-2" aria-label={gettext('Unselect')} title={gettext('Unselect')}></span>
|
|
<span>{selectedLen}{' '}{gettext('selected')}</span>
|
|
</span>
|
|
{canModify &&
|
|
<span className="cur-view-path-btn" onClick={this.onMoveToggle}>
|
|
<span className="sf3-font-move1 sf3-font" aria-label={gettext('Move')} title={gettext('Move')}></span>
|
|
</span>
|
|
}
|
|
{canCopy &&
|
|
<span className="cur-view-path-btn" onClick={this.onCopyToggle}>
|
|
<span className="sf3-font-copy1 sf3-font" aria-label={gettext('Copy')} title={gettext('Copy')}></span>
|
|
</span>
|
|
}
|
|
{canDelete &&
|
|
<span className="cur-view-path-btn" onClick={this.onItemsDelete}>
|
|
<span className="sf3-font-delete1 sf3-font" aria-label={gettext('Delete')} title={gettext('Delete')}></span>
|
|
</span>
|
|
}
|
|
{canDownload &&
|
|
<span className="cur-view-path-btn" onClick={this.onItemsDownload}>
|
|
<span className="sf3-font-download1 sf3-font" aria-label={gettext('Download')} title={gettext('Download')}></span>
|
|
</span>
|
|
}
|
|
{selectedLen === 1 &&
|
|
<ItemDropdownMenu
|
|
item={this.props.selectedDirentList[0]}
|
|
toggleClass={'cur-view-path-btn sf3-font-more-vertical sf3-font'}
|
|
onMenuItemClick={this.onMenuItemClick}
|
|
getMenuList={this.getDirentMenuList}
|
|
/>
|
|
}
|
|
</div>
|
|
{this.state.isMoveDialogShow &&
|
|
<MoveDirentDialog
|
|
path={this.props.path}
|
|
repoID={this.props.repoID}
|
|
repoEncrypted={this.props.repoEncrypted}
|
|
isMultipleOperation={this.state.isMultipleOperation}
|
|
selectedDirentList={this.props.selectedDirentList}
|
|
onItemsMove={this.props.onItemsMove}
|
|
onCancelMove={this.onMoveToggle}
|
|
/>
|
|
}
|
|
{this.state.isCopyDialogShow &&
|
|
<CopyDirentDialog
|
|
path={this.props.path}
|
|
repoID={this.props.repoID}
|
|
repoEncrypted={this.props.repoEncrypted}
|
|
selectedDirentList={this.props.selectedDirentList}
|
|
isMultipleOperation={this.state.isMultipleOperation}
|
|
onItemsCopy={this.props.onItemsCopy}
|
|
onCancelCopy={this.onCopyToggle}
|
|
/>
|
|
}
|
|
{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>
|
|
{this.state.showShareDialog &&
|
|
<ModalPortal>
|
|
<ShareDialog
|
|
itemType={dirent.type}
|
|
itemName={dirent.name}
|
|
itemPath={direntPath}
|
|
userPerm={dirent.permission}
|
|
repoID={repoID}
|
|
repoEncrypted={this.props.repoEncrypted}
|
|
enableDirPrivateShare={this.props.enableDirPrivateShare}
|
|
isGroupOwnedRepo={this.props.isGroupOwnedRepo}
|
|
toggleDialog={this.toggleCancel}
|
|
/>
|
|
</ModalPortal>
|
|
}
|
|
{this.state.isRenameDialogOpen &&
|
|
<ModalPortal>
|
|
<Rename
|
|
dirent={dirent}
|
|
onRename={this.onItemRename}
|
|
checkDuplicatedName={this.checkDuplicatedName}
|
|
toggleCancel={this.toggleCancel}
|
|
/>
|
|
</ModalPortal>
|
|
}
|
|
{this.state.isPermissionDialogOpen &&
|
|
<ModalPortal>
|
|
<LibSubFolderPermissionDialog
|
|
toggleDialog={this.toggleCancel}
|
|
repoID={repoID}
|
|
folderPath={direntPath}
|
|
folderName={dirent.name}
|
|
isDepartmentRepo={this.props.isGroupOwnedRepo}
|
|
/>
|
|
</ModalPortal>
|
|
}
|
|
{this.state.showEditFileTagDialog &&
|
|
<ModalPortal>
|
|
<EditFileTagDialog
|
|
repoID={repoID}
|
|
repoTags={repoTags}
|
|
filePath={direntPath}
|
|
fileTagList={this.state.fileTagList}
|
|
toggleCancel={this.toggleCancel}
|
|
onFileTagChanged={this.onMenuFileTagChanged}
|
|
/>
|
|
</ModalPortal>
|
|
}
|
|
</Fragment>
|
|
)}
|
|
</Fragment>
|
|
);
|
|
}
|
|
}
|
|
|
|
MultipleDirOperationToolbar.propTypes = propTypes;
|
|
|
|
export default MultipleDirOperationToolbar;
|