2018-12-19 03:41:45 +00:00
|
|
|
import React, { Fragment } from 'react';
|
2018-10-13 09:07:54 +00:00
|
|
|
import PropTypes from 'prop-types';
|
2019-04-25 07:09:28 +00:00
|
|
|
import { siteRoot, gettext, thumbnailSizeForOriginal, username, isPro, enableFileComment, fileAuditEnabled, folderPermEnabled, canGenerateShareLink } from '../../utils/constants';
|
2019-01-16 09:45:46 +00:00
|
|
|
import { Utils } from '../../utils/utils';
|
2019-04-11 13:04:47 +00:00
|
|
|
import TextTranslation from '../../utils/text-translation';
|
|
|
|
import { seafileAPI } from '../../utils/seafile-api';
|
|
|
|
import URLDecorator from '../../utils/url-decorator';
|
2018-10-25 05:36:06 +00:00
|
|
|
import Loading from '../loading';
|
2019-01-25 07:44:04 +00:00
|
|
|
import toaster from '../toast';
|
2019-04-11 13:04:47 +00:00
|
|
|
import ModalPortal from '../modal-portal';
|
|
|
|
import CreateFile from '../dialog/create-file-dialog';
|
|
|
|
import CreateFolder from '../dialog/create-folder-dialog';
|
|
|
|
import ImageDialog from '../dialog/image-dialog';
|
|
|
|
import ZipDownloadDialog from '../dialog/zip-download-dialog';
|
|
|
|
import MoveDirentDialog from '../dialog/move-dirent-dialog';
|
|
|
|
import CopyDirentDialog from '../dialog/copy-dirent-dialog';
|
|
|
|
import DirentListItem from './dirent-list-item';
|
|
|
|
import ContextMenu from '../context-menu/context-menu';
|
|
|
|
import { hideMenu, showMenu } from '../context-menu/actions';
|
2018-10-13 09:07:54 +00:00
|
|
|
|
|
|
|
const propTypes = {
|
2018-11-22 03:26:00 +00:00
|
|
|
path: PropTypes.string.isRequired,
|
2018-11-28 04:41:49 +00:00
|
|
|
repoID: PropTypes.string.isRequired,
|
2018-12-18 09:21:01 +00:00
|
|
|
currentRepoInfo: PropTypes.object,
|
2018-11-28 04:41:49 +00:00
|
|
|
isAllItemSelected: PropTypes.bool.isRequired,
|
|
|
|
isDirentListLoading: PropTypes.bool.isRequired,
|
2018-10-13 09:07:54 +00:00
|
|
|
direntList: PropTypes.array.isRequired,
|
2019-04-11 13:04:47 +00:00
|
|
|
showShareBtn: PropTypes.bool.isRequired,
|
2019-01-04 09:15:15 +00:00
|
|
|
sortBy: PropTypes.string.isRequired,
|
|
|
|
sortOrder: PropTypes.string.isRequired,
|
|
|
|
sortItems: PropTypes.func.isRequired,
|
2018-12-19 03:41:45 +00:00
|
|
|
onAddFile: PropTypes.func.isRequired,
|
2019-04-11 13:04:47 +00:00
|
|
|
onAddFolder: PropTypes.func.isRequired,
|
2018-10-13 09:07:54 +00:00
|
|
|
onItemDelete: PropTypes.func.isRequired,
|
2018-11-23 12:19:42 +00:00
|
|
|
onAllItemSelected: PropTypes.func.isRequired,
|
|
|
|
onItemSelected: PropTypes.func.isRequired,
|
2018-10-25 05:36:06 +00:00
|
|
|
onItemRename: PropTypes.func.isRequired,
|
2018-10-13 09:07:54 +00:00
|
|
|
onItemClick: PropTypes.func.isRequired,
|
2018-11-27 06:47:19 +00:00
|
|
|
onItemMove: PropTypes.func.isRequired,
|
|
|
|
onItemCopy: PropTypes.func.isRequired,
|
2019-01-17 09:05:08 +00:00
|
|
|
onDirentClick: PropTypes.func.isRequired,
|
2018-11-22 03:26:00 +00:00
|
|
|
updateDirent: PropTypes.func.isRequired,
|
2019-04-11 13:04:47 +00:00
|
|
|
selectedDirentList: PropTypes.array.isRequired,
|
|
|
|
onItemsMove: PropTypes.func.isRequired,
|
|
|
|
onItemsCopy: PropTypes.func.isRequired,
|
|
|
|
onItemsDelete: PropTypes.func.isRequired,
|
2019-04-17 02:48:44 +00:00
|
|
|
onFileTagChanged: PropTypes.func,
|
2018-10-13 09:07:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class DirentListView extends React.Component {
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
isItemFreezed: false,
|
2019-01-16 09:45:46 +00:00
|
|
|
isImagePopupOpen: false,
|
|
|
|
imageItems: [],
|
|
|
|
imageIndex: 0,
|
2019-04-08 03:35:46 +00:00
|
|
|
fileType: '',
|
2019-04-11 13:04:47 +00:00
|
|
|
isCreateFileDialogShow: false,
|
|
|
|
isCreateFolderDialogShow: false,
|
|
|
|
isMoveDialogShow: false,
|
|
|
|
isCopyDialogShow: false,
|
|
|
|
isProgressDialogShow: false,
|
|
|
|
progress: 0,
|
|
|
|
isMutipleOperation: true,
|
2019-04-13 02:45:11 +00:00
|
|
|
activeDirent: null,
|
2018-10-13 09:07:54 +00:00
|
|
|
};
|
2019-02-27 05:53:36 +00:00
|
|
|
|
|
|
|
this.isRepoOwner = props.currentRepoInfo.owner_email === username;
|
|
|
|
this.isAdmin = props.currentRepoInfo.is_admin;
|
|
|
|
this.repoEncrypted = props.currentRepoInfo.encrypted;
|
2018-10-13 09:07:54 +00:00
|
|
|
|
2019-04-11 13:04:47 +00:00
|
|
|
this.clickedDirent = null;
|
|
|
|
this.direntItems = [];
|
|
|
|
this.currentItemRef = null;
|
2019-04-08 03:35:46 +00:00
|
|
|
|
2019-04-11 13:04:47 +00:00
|
|
|
this.zipToken = null;
|
2019-04-08 03:35:46 +00:00
|
|
|
}
|
|
|
|
|
2019-04-22 04:18:35 +00:00
|
|
|
freezeItem = () => {
|
2018-10-13 09:07:54 +00:00
|
|
|
this.setState({isItemFreezed: true});
|
|
|
|
}
|
2018-11-22 03:26:00 +00:00
|
|
|
|
2019-04-22 04:18:35 +00:00
|
|
|
unfreezeItem = () => {
|
2018-10-13 09:07:54 +00:00
|
|
|
this.setState({isItemFreezed: false});
|
|
|
|
}
|
|
|
|
|
2019-01-25 07:44:04 +00:00
|
|
|
onItemRename = (dirent, newName) => {
|
|
|
|
let isDuplicated = this.props.direntList.some(item => {
|
|
|
|
return item.name === newName;
|
|
|
|
});
|
|
|
|
if (isDuplicated) {
|
2019-01-29 03:32:54 +00:00
|
|
|
let errMessage = gettext('The name "{name}" is already taken. Please choose a different name.');
|
2019-01-25 07:44:04 +00:00
|
|
|
errMessage = errMessage.replace('{name}', Utils.HTMLescape(newName));
|
|
|
|
toaster.danger(errMessage);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
this.props.onItemRename(dirent, newName);
|
|
|
|
}
|
|
|
|
|
2018-11-23 12:19:42 +00:00
|
|
|
onItemRenameToggle = () => {
|
2019-04-22 04:18:35 +00:00
|
|
|
this.freezeItem();
|
2018-10-13 09:07:54 +00:00
|
|
|
}
|
|
|
|
|
2019-04-13 02:45:11 +00:00
|
|
|
onItemSelected = (dirent) => {
|
|
|
|
this.setState({activeDirent: null});
|
|
|
|
this.props.onItemSelected(dirent);
|
|
|
|
}
|
|
|
|
|
|
|
|
onDirentClick = (dirent) => {
|
|
|
|
if (this.props.selectedDirentList.length > 0 && !this.state.activeDirent ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.setState({activeDirent: dirent});
|
|
|
|
this.props.onDirentClick(dirent);
|
|
|
|
}
|
|
|
|
|
2019-01-04 07:06:27 +00:00
|
|
|
sortByName = (e) => {
|
|
|
|
e.preventDefault();
|
|
|
|
const sortBy = 'name';
|
|
|
|
const sortOrder = this.props.sortOrder == 'asc' ? 'desc' : 'asc';
|
|
|
|
this.props.sortItems(sortBy, sortOrder);
|
|
|
|
}
|
|
|
|
|
|
|
|
sortByTime = (e) => {
|
|
|
|
e.preventDefault();
|
|
|
|
const sortBy = 'time';
|
|
|
|
const sortOrder = this.props.sortOrder == 'asc' ? 'desc' : 'asc';
|
|
|
|
this.props.sortItems(sortBy, sortOrder);
|
|
|
|
}
|
|
|
|
|
2019-01-16 09:45:46 +00:00
|
|
|
// for image popup
|
2019-04-09 09:24:44 +00:00
|
|
|
prepareImageItem = (item) => {
|
2019-02-27 05:53:36 +00:00
|
|
|
const useThumbnail = !this.repoEncrypted;
|
2019-04-09 09:24:44 +00:00
|
|
|
const name = item.name;
|
|
|
|
|
|
|
|
const fileExt = name.substr(name.lastIndexOf('.') + 1).toLowerCase();
|
|
|
|
const isGIF = fileExt == 'gif';
|
|
|
|
|
|
|
|
const path = Utils.encodePath(Utils.joinPath(this.props.path, name));
|
|
|
|
const repoID = this.props.repoID;
|
|
|
|
let src;
|
|
|
|
if (useThumbnail && !isGIF) {
|
|
|
|
src = `${siteRoot}thumbnail/${repoID}/${thumbnailSizeForOriginal}${path}`;
|
|
|
|
} else {
|
|
|
|
src = `${siteRoot}repo/${repoID}/raw${path}`;
|
|
|
|
}
|
2019-01-16 09:45:46 +00:00
|
|
|
|
2019-04-09 09:24:44 +00:00
|
|
|
return {
|
|
|
|
'name': name,
|
|
|
|
'url': `${siteRoot}lib/${repoID}/file${path}`,
|
|
|
|
'src': src
|
|
|
|
};
|
2019-01-16 09:45:46 +00:00
|
|
|
}
|
|
|
|
|
2019-04-09 09:24:44 +00:00
|
|
|
showImagePopup = (curItem) => {
|
2019-01-16 09:45:46 +00:00
|
|
|
let items = this.props.direntList.filter((item) => {
|
|
|
|
return Utils.imageCheck(item.name);
|
|
|
|
});
|
2019-04-09 09:24:44 +00:00
|
|
|
|
|
|
|
const imageItems = items.map((item) => {
|
|
|
|
return this.prepareImageItem(item);
|
|
|
|
});
|
|
|
|
|
2019-01-16 09:45:46 +00:00
|
|
|
this.setState({
|
|
|
|
isImagePopupOpen: true,
|
2019-04-09 09:24:44 +00:00
|
|
|
imageItems: imageItems,
|
|
|
|
imageIndex: items.indexOf(curItem)
|
2019-01-16 09:45:46 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
moveToPrevImage = () => {
|
|
|
|
const imageItemsLength = this.state.imageItems.length;
|
|
|
|
this.setState((prevState) => ({
|
|
|
|
imageIndex: (prevState.imageIndex + imageItemsLength - 1) % imageItemsLength
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
moveToNextImage = () => {
|
|
|
|
const imageItemsLength = this.state.imageItems.length;
|
|
|
|
this.setState((prevState) => ({
|
|
|
|
imageIndex: (prevState.imageIndex + 1) % imageItemsLength
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
closeImagePopup = () => {
|
2019-04-12 12:21:54 +00:00
|
|
|
this.setState({isImagePopupOpen: false});
|
2019-01-16 09:45:46 +00:00
|
|
|
}
|
|
|
|
|
2019-04-11 13:04:47 +00:00
|
|
|
onCreateFileToggle = () => {
|
|
|
|
this.setState({isCreateFileDialogShow: !this.state.isCreateFileDialogShow});
|
|
|
|
}
|
|
|
|
|
|
|
|
onCreateFolderToggle = () => {
|
|
|
|
this.setState({isCreateFolderDialogShow: !this.state.isCreateFolderDialogShow});
|
|
|
|
}
|
|
|
|
|
|
|
|
onAddFile = (filePath, isDraft) => {
|
|
|
|
this.setState({isCreateFileDialogShow: false});
|
|
|
|
this.props.onAddFile(filePath, isDraft);
|
|
|
|
}
|
|
|
|
|
|
|
|
onAddFolder = (dirPath) => {
|
|
|
|
this.setState({isCreateFolderDialogShow: false});
|
|
|
|
this.props.onAddFolder(dirPath);
|
|
|
|
}
|
|
|
|
|
2019-01-31 03:32:10 +00:00
|
|
|
checkDuplicatedName = (newName) => {
|
|
|
|
let direntList = this.props.direntList;
|
|
|
|
let isDuplicated = direntList.some(object => {
|
|
|
|
return object.name === newName;
|
|
|
|
});
|
|
|
|
return isDuplicated;
|
|
|
|
}
|
|
|
|
|
2019-04-11 13:04:47 +00:00
|
|
|
onMoveToggle = () => {
|
|
|
|
this.setState({isMoveDialogShow: !this.state.isMoveDialogShow});
|
|
|
|
}
|
|
|
|
|
|
|
|
onCopyToggle = () => {
|
|
|
|
this.setState({isCopyDialogShow: !this.state.isCopyDialogShow});
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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(() => {
|
|
|
|
this.setState({isProgressDialogShow: false});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// common contextmenu handle
|
|
|
|
onMouseDown = (event) => {
|
|
|
|
event.stopPropagation();
|
|
|
|
if (event.button === 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
handleContextClick = (event, id, menuList, currentObject = null) => {
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
|
2019-04-18 09:32:34 +00:00
|
|
|
let currentRepoInfo = this.props.currentRepoInfo;
|
|
|
|
|
|
|
|
if (currentRepoInfo.permission === 'cloud-edit' || currentRepoInfo.permission === 'preview') {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
2019-04-11 13:04:47 +00:00
|
|
|
let x = event.clientX || (event.touches && event.touches[0].pageX);
|
|
|
|
let y = event.clientY || (event.touches && event.touches[0].pageY);
|
|
|
|
|
|
|
|
if (this.props.posX) {
|
|
|
|
x -= this.props.posX;
|
|
|
|
}
|
|
|
|
if (this.props.posY) {
|
|
|
|
y -= this.props.posY;
|
|
|
|
}
|
|
|
|
|
|
|
|
hideMenu();
|
|
|
|
|
|
|
|
let showMenuConfig = {
|
|
|
|
id: id,
|
|
|
|
position: { x, y },
|
|
|
|
target: event.target,
|
|
|
|
currentObject: currentObject,
|
|
|
|
menuList: menuList,
|
|
|
|
};
|
|
|
|
|
|
|
|
showMenu(showMenuConfig);
|
|
|
|
}
|
|
|
|
|
|
|
|
// table-container contextmenu handle
|
2019-04-13 05:35:33 +00:00
|
|
|
onContainerClick = () => {
|
|
|
|
if (this.state.activeDirent) {
|
|
|
|
this.onDirentClick(null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-11 13:04:47 +00:00
|
|
|
onContainerMouseDown = (event) => {
|
|
|
|
this.onMouseDown(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
onContainerContextMenu = (event) => {
|
|
|
|
if (this.props.selectedDirentList.length === 0) {
|
|
|
|
let id = "dirent-container-menu"
|
|
|
|
let menuList = [TextTranslation.NEW_FOLDER, TextTranslation.NEW_FILE];
|
|
|
|
this.handleContextClick(event, id, menuList);
|
|
|
|
} else {
|
|
|
|
if (this.props.selectedDirentList.length === 1) {
|
2019-04-13 02:45:11 +00:00
|
|
|
if (!this.state.activeDirent) {
|
|
|
|
let id = 'dirent-item-menu';
|
|
|
|
let dirent = this.props.selectedDirentList[0];
|
|
|
|
let menuList = this.getDirentItemMenuList(dirent, true);
|
|
|
|
this.handleContextClick(event, id, menuList, dirent);
|
|
|
|
} else {
|
|
|
|
this.onDirentClick(null);
|
|
|
|
event.preventDefault();
|
|
|
|
event.persist();
|
|
|
|
setTimeout(() => {
|
|
|
|
let id = "dirent-container-menu"
|
|
|
|
let menuList = [TextTranslation.NEW_FOLDER, TextTranslation.NEW_FILE];
|
|
|
|
this.handleContextClick(event, id, menuList);
|
|
|
|
}, 0);
|
|
|
|
}
|
2019-04-11 13:04:47 +00:00
|
|
|
} else {
|
|
|
|
let id = 'dirents-menu';
|
|
|
|
let menuList = [TextTranslation.MOVE, TextTranslation.COPY, TextTranslation.DOWNLOAD, TextTranslation.DELETE];
|
|
|
|
this.handleContextClick(event, id, menuList);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onContainerMenuItemClick = (operation) => {
|
|
|
|
switch(operation) {
|
|
|
|
case 'New Folder':
|
|
|
|
this.onCreateFolderToggle();
|
|
|
|
break;
|
|
|
|
case 'New File':
|
|
|
|
this.onCreateFileToggle();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
hideMenu();
|
|
|
|
}
|
|
|
|
|
|
|
|
onDirentsMenuItemClick = (operation) => {
|
|
|
|
switch(operation) {
|
|
|
|
case 'Move':
|
|
|
|
this.onMoveToggle();
|
|
|
|
break;
|
|
|
|
case 'Copy':
|
|
|
|
this.onCopyToggle();
|
|
|
|
break;
|
|
|
|
case 'Download':
|
|
|
|
this.onItemsDownload();
|
|
|
|
break;
|
|
|
|
case 'Delete':
|
|
|
|
this.props.onItemsDelete();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
hideMenu();
|
|
|
|
}
|
|
|
|
|
|
|
|
// table-thread contextmenu handle -- Shield event
|
|
|
|
onThreadMouseDown = (event) => {
|
|
|
|
this.onMouseDown(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
onThreadContextMenu = (event) => {
|
|
|
|
event.stopPropagation();
|
|
|
|
}
|
|
|
|
|
|
|
|
// table-dirent-item contextmenu handle
|
|
|
|
onItemMouseDown = (event) => {
|
|
|
|
this.onMouseDown(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
onItemContextMenu = (event, dirent) => {
|
2019-04-13 02:45:11 +00:00
|
|
|
if (this.props.selectedDirentList.length > 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.onDirentClick(dirent);
|
2019-04-13 01:57:44 +00:00
|
|
|
let id = 'dirent-item-menu';
|
|
|
|
let menuList = this.getDirentItemMenuList(dirent, true);
|
|
|
|
this.handleContextClick(event, id, menuList, dirent);
|
2019-04-11 13:04:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
setDirentItemRef = (index) => item => {
|
|
|
|
this.direntItems[index] = item;
|
|
|
|
}
|
|
|
|
|
|
|
|
onMenuItemClick = (operation, currentObject, event) => {
|
|
|
|
let index = this.getDirentIndex(currentObject);
|
|
|
|
this.direntItems[index].onMenuItemClick(operation, event);
|
|
|
|
|
|
|
|
hideMenu();
|
|
|
|
}
|
|
|
|
|
|
|
|
onShowMenu = (e) => {
|
2019-04-22 04:18:35 +00:00
|
|
|
this.freezeItem();
|
2019-04-11 13:04:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
onHideMenu = (e) => {
|
2019-04-22 04:18:35 +00:00
|
|
|
this.unfreezeItem();
|
2019-04-11 13:04:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// contextmenu utils
|
|
|
|
getDirentIndex = (dirent) => {
|
|
|
|
let direntList = this.props.direntList;
|
|
|
|
let index = 0;
|
|
|
|
for (let i = 0; i < direntList.length; i++) {
|
|
|
|
if (direntList[i].name === dirent.name) {
|
|
|
|
index = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
getDirentItemMenuList = (dirent, isContextmenu) => {
|
|
|
|
|
|
|
|
let isRepoOwner = this.isRepoOwner;
|
|
|
|
let currentRepoInfo = this.props.currentRepoInfo;
|
|
|
|
let can_set_folder_perm = folderPermEnabled && ((isRepoOwner && currentRepoInfo.has_been_shared_out) || currentRepoInfo.is_admin);
|
|
|
|
|
|
|
|
let type = dirent.type;
|
|
|
|
let permission = dirent.permission;
|
|
|
|
|
|
|
|
let menuList = [];
|
|
|
|
let contextmenuList = [];
|
|
|
|
if (isContextmenu) {
|
|
|
|
let { SHARE, DOWNLOAD, DELETE } = TextTranslation;
|
|
|
|
contextmenuList = this.props.showShareBtn ? [SHARE, DOWNLOAD, DELETE, 'Divider'] : [DOWNLOAD, DELETE, 'Divider'];
|
2019-04-25 07:09:28 +00:00
|
|
|
|
|
|
|
if (dirent.type === 'file') {
|
2019-04-25 08:29:41 +00:00
|
|
|
contextmenuList = canGenerateShareLink ? [SHARE, DOWNLOAD, DELETE, 'Divider'] : [DOWNLOAD, DELETE, 'Divider'];
|
2019-04-25 07:09:28 +00:00
|
|
|
}
|
2019-04-11 13:04:47 +00:00
|
|
|
}
|
|
|
|
|
2019-04-17 02:48:44 +00:00
|
|
|
let { RENAME, MOVE, COPY, PERMISSION, OPEN_VIA_CLIENT, LOCK, UNLOCK, COMMENT, HISTORY, ACCESS_LOG, TAGS } = TextTranslation;
|
2019-04-11 13:04:47 +00:00
|
|
|
if (type === 'dir' && permission === 'rw') {
|
|
|
|
if (can_set_folder_perm) {
|
2019-04-13 05:35:33 +00:00
|
|
|
menuList = [...contextmenuList, RENAME, MOVE, COPY, 'Divider', PERMISSION, 'Divider', OPEN_VIA_CLIENT];
|
2019-04-11 13:04:47 +00:00
|
|
|
} else {
|
2019-04-13 05:35:33 +00:00
|
|
|
menuList = [...contextmenuList, RENAME, MOVE, COPY, 'Divider', OPEN_VIA_CLIENT];
|
2019-04-11 13:04:47 +00:00
|
|
|
}
|
|
|
|
return menuList;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type === 'dir' && permission === 'r') {
|
2019-04-13 05:35:33 +00:00
|
|
|
menuList = currentRepoInfo.encrypted ? [...contextmenuList, COPY] : [];
|
2019-04-11 13:04:47 +00:00
|
|
|
return menuList;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type === 'file' && permission === 'rw') {
|
|
|
|
menuList = [...contextmenuList];
|
|
|
|
if (!dirent.is_locked || (dirent.is_locked && dirent.locked_by_me)) {
|
|
|
|
menuList.push(RENAME);
|
|
|
|
menuList.push(MOVE);
|
|
|
|
}
|
|
|
|
menuList.push(COPY);
|
2019-04-17 02:48:44 +00:00
|
|
|
menuList.push(TAGS);
|
2019-04-11 13:04:47 +00:00
|
|
|
if (isPro) {
|
|
|
|
if (dirent.is_locked) {
|
|
|
|
if (dirent.locked_by_me || (dirent.lock_owner === 'OnlineOffice' && permission === 'rw')) {
|
|
|
|
menuList.push(UNLOCK);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
menuList.push(LOCK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
menuList.push('Divider');
|
|
|
|
if (enableFileComment) {
|
|
|
|
menuList.push(COMMENT);
|
|
|
|
}
|
|
|
|
menuList.push(HISTORY);
|
|
|
|
if (fileAuditEnabled) {
|
|
|
|
menuList.push(ACCESS_LOG);
|
|
|
|
}
|
|
|
|
menuList.push('Divider');
|
|
|
|
menuList.push(OPEN_VIA_CLIENT);
|
|
|
|
return menuList;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type === 'file' && permission === 'r') {
|
|
|
|
menuList = [...contextmenuList];
|
|
|
|
if (!currentRepoInfo.encrypted) {
|
|
|
|
menuList.push(COPY);
|
|
|
|
}
|
|
|
|
if (enableFileComment) {
|
|
|
|
menuList.push(COMMENT);
|
|
|
|
}
|
|
|
|
menuList.push(HISTORY);
|
|
|
|
return menuList;
|
|
|
|
}
|
2019-04-18 09:32:34 +00:00
|
|
|
|
|
|
|
return [];
|
2019-04-11 13:04:47 +00:00
|
|
|
}
|
|
|
|
|
2018-10-13 09:07:54 +00:00
|
|
|
render() {
|
2019-01-04 07:06:27 +00:00
|
|
|
const { direntList, sortBy, sortOrder } = this.props;
|
2018-10-25 05:36:06 +00:00
|
|
|
|
|
|
|
if (this.props.isDirentListLoading) {
|
|
|
|
return (<Loading />);
|
|
|
|
}
|
|
|
|
|
2019-01-04 07:06:27 +00:00
|
|
|
// sort
|
|
|
|
const sortByName = sortBy == 'name';
|
|
|
|
const sortByTime = sortBy == 'time';
|
|
|
|
const sortIcon = sortOrder == 'asc' ? <span className="fas fa-caret-up"></span> : <span className="fas fa-caret-down"></span>;
|
|
|
|
|
2018-10-13 09:07:54 +00:00
|
|
|
return (
|
2019-04-13 05:35:33 +00:00
|
|
|
<div className="table-container" onMouseDown={this.onContainerMouseDown} onContextMenu={this.onContainerContextMenu} onClick={this.onContainerClick}>
|
2019-01-31 09:37:02 +00:00
|
|
|
<table>
|
2019-04-11 13:04:47 +00:00
|
|
|
<thead onMouseDown={this.onThreadMouseDown} onContextMenu={this.onThreadContextMenu}>
|
2019-01-31 09:37:02 +00:00
|
|
|
<tr>
|
2019-04-08 03:35:46 +00:00
|
|
|
<th width="3%" className="pl10">
|
2019-01-31 09:37:02 +00:00
|
|
|
<input type="checkbox" className="vam" onChange={this.props.onAllItemSelected} checked={this.props.isAllItemSelected}/>
|
|
|
|
</th>
|
2019-03-28 05:32:22 +00:00
|
|
|
<th width="3%" className="pl10">{/*icon */}</th>
|
|
|
|
<th width="5%" className="pl10">{/*star */}</th>
|
2019-01-31 09:37:02 +00:00
|
|
|
<th width="39%"><a className="d-block table-sort-op" href="#" onClick={this.sortByName}>{gettext('Name')} {sortByName && sortIcon}</a></th>
|
|
|
|
<th width="6%">{/*tag */}</th>
|
2019-02-20 09:08:00 +00:00
|
|
|
<th width="18%">{/*operation */}</th>
|
2019-01-31 09:37:02 +00:00
|
|
|
<th width="11%">{gettext('Size')}</th>
|
2019-02-20 09:08:00 +00:00
|
|
|
<th width="15%"><a className="d-block table-sort-op" href="#" onClick={this.sortByTime}>{gettext('Last Update')} {sortByTime && sortIcon}</a></th>
|
2019-01-31 09:37:02 +00:00
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
2019-04-11 13:04:47 +00:00
|
|
|
{direntList.map((dirent, index) => {
|
|
|
|
return (
|
|
|
|
<DirentListItem
|
|
|
|
ref={this.setDirentItemRef(index)}
|
|
|
|
key={index}
|
|
|
|
dirent={dirent}
|
|
|
|
path={this.props.path}
|
|
|
|
repoID={this.props.repoID}
|
|
|
|
currentRepoInfo={this.props.currentRepoInfo}
|
|
|
|
isAdmin={this.isAdmin}
|
|
|
|
isRepoOwner={this.isRepoOwner}
|
|
|
|
repoEncrypted={this.repoEncrypted}
|
|
|
|
enableDirPrivateShare={this.props.enableDirPrivateShare}
|
|
|
|
isGroupOwnedRepo={this.props.isGroupOwnedRepo}
|
|
|
|
showShareBtn={this.props.showShareBtn}
|
|
|
|
onItemClick={this.props.onItemClick}
|
|
|
|
onItemRenameToggle={this.onItemRenameToggle}
|
2019-04-13 02:45:11 +00:00
|
|
|
onItemSelected={this.onItemSelected}
|
2019-04-11 13:04:47 +00:00
|
|
|
onItemDelete={this.props.onItemDelete}
|
|
|
|
onItemRename={this.onItemRename}
|
|
|
|
onItemMove={this.props.onItemMove}
|
|
|
|
onItemCopy={this.props.onItemCopy}
|
|
|
|
updateDirent={this.props.updateDirent}
|
|
|
|
isItemFreezed={this.state.isItemFreezed}
|
2019-04-22 04:18:35 +00:00
|
|
|
freezeItem={this.freezeItem}
|
|
|
|
unfreezeItem={this.unfreezeItem}
|
2019-04-13 02:45:11 +00:00
|
|
|
onDirentClick={this.onDirentClick}
|
2019-04-11 13:04:47 +00:00
|
|
|
showImagePopup={this.showImagePopup}
|
|
|
|
onItemMouseDown={this.onItemMouseDown}
|
|
|
|
onItemContextMenu={this.onItemContextMenu}
|
2019-04-12 12:21:54 +00:00
|
|
|
selectedDirentList={this.props.selectedDirentList}
|
2019-04-13 02:45:11 +00:00
|
|
|
activeDirent={this.state.activeDirent}
|
2019-04-17 02:48:44 +00:00
|
|
|
onFileTagChanged={this.props.onFileTagChanged}
|
2019-04-21 02:43:34 +00:00
|
|
|
getDirentItemMenuList={this.getDirentItemMenuList}
|
2019-04-11 13:04:47 +00:00
|
|
|
/>
|
|
|
|
);
|
|
|
|
})}
|
2019-01-31 09:37:02 +00:00
|
|
|
</tbody>
|
|
|
|
</table>
|
2019-04-11 13:04:47 +00:00
|
|
|
<Fragment>
|
|
|
|
<ContextMenu
|
|
|
|
id={'dirent-container-menu'}
|
|
|
|
onMenuItemClick={this.onContainerMenuItemClick}
|
|
|
|
/>
|
|
|
|
<ContextMenu
|
|
|
|
id={'dirent-item-menu'}
|
|
|
|
onMenuItemClick={this.onMenuItemClick}
|
|
|
|
onShowMenu={this.onShowMenu}
|
|
|
|
onHideMenu={this.onHideMenu}
|
|
|
|
/>
|
|
|
|
<ContextMenu
|
|
|
|
id={'dirents-menu'}
|
|
|
|
onMenuItemClick={this.onDirentsMenuItemClick}
|
|
|
|
/>
|
|
|
|
{this.state.isImagePopupOpen && (
|
|
|
|
<ModalPortal>
|
|
|
|
<ImageDialog
|
|
|
|
imageItems={this.state.imageItems}
|
|
|
|
imageIndex={this.state.imageIndex}
|
|
|
|
closeImagePopup={this.closeImagePopup}
|
|
|
|
moveToPrevImage={this.moveToPrevImage}
|
|
|
|
moveToNextImage={this.moveToNextImage}
|
|
|
|
/>
|
|
|
|
</ModalPortal>
|
|
|
|
)}
|
|
|
|
{this.state.isCreateFolderDialogShow && (
|
|
|
|
<ModalPortal>
|
|
|
|
<CreateFolder
|
|
|
|
parentPath={this.props.path}
|
|
|
|
onAddFolder={this.onAddFolder}
|
|
|
|
checkDuplicatedName={this.checkDuplicatedName}
|
|
|
|
addFolderCancel={this.onCreateFolderToggle}
|
|
|
|
/>
|
|
|
|
</ModalPortal>
|
|
|
|
)}
|
|
|
|
{this.state.isCreateFileDialogShow && (
|
|
|
|
<ModalPortal>
|
|
|
|
<CreateFile
|
|
|
|
parentPath={this.props.path}
|
|
|
|
fileType={this.state.fileType}
|
|
|
|
onAddFile={this.onAddFile}
|
|
|
|
checkDuplicatedName={this.checkDuplicatedName}
|
|
|
|
addFileCancel={this.onCreateFileToggle}
|
|
|
|
/>
|
|
|
|
</ModalPortal>
|
|
|
|
)}
|
|
|
|
{this.state.isMoveDialogShow &&
|
|
|
|
<MoveDirentDialog
|
|
|
|
path={this.props.path}
|
|
|
|
repoID={this.props.repoID}
|
|
|
|
repoEncrypted={this.props.currentRepoInfo.encrypted}
|
|
|
|
isMutipleOperation={this.state.isMutipleOperation}
|
|
|
|
selectedDirentList={this.props.selectedDirentList}
|
|
|
|
onItemsMove={this.props.onItemsMove}
|
|
|
|
onCancelMove={this.onMoveToggle}
|
2019-04-09 09:24:44 +00:00
|
|
|
/>
|
2019-04-11 13:04:47 +00:00
|
|
|
}
|
|
|
|
{this.state.isCopyDialogShow &&
|
|
|
|
<CopyDirentDialog
|
|
|
|
path={this.props.path}
|
|
|
|
repoID={this.props.repoID}
|
|
|
|
repoEncrypted={this.props.currentRepoInfo.encrypted}
|
|
|
|
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} />
|
|
|
|
}
|
|
|
|
</Fragment>
|
|
|
|
</div>
|
2018-10-13 09:07:54 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DirentListView.propTypes = propTypes;
|
|
|
|
|
|
|
|
export default DirentListView;
|