1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-19 18:29:23 +00:00
Files
seahub/frontend/src/components/dir-view/dir-view.js

626 lines
19 KiB
JavaScript
Raw Normal View History

2018-12-22 15:18:53 +08:00
import React, { Fragment } from 'react';
2018-11-29 17:55:14 +08:00
import PropTypes from 'prop-types';
2019-01-05 11:43:33 +08:00
import moment from 'moment';
2018-11-29 17:55:14 +08:00
import { siteRoot } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
import { gettext } from '../../utils/constants';
2018-12-18 17:32:00 +08:00
import collabServer from '../../utils/collab-server';
2018-12-07 14:58:37 +08:00
import toaster from '../toast';
2018-11-29 17:55:14 +08:00
import DirPanel from './dir-panel';
import Dirent from '../../models/dirent';
import FileTag from '../../models/file-tag';
import RepoTag from '../../models/repo-tag';
2018-12-18 17:21:01 +08:00
import RepoInfo from '../../models/repo-info';
2018-11-29 17:55:14 +08:00
const propTypes = {
2018-12-13 14:40:09 +08:00
pathPrefix: PropTypes.array.isRequired,
onTabNavClick: PropTypes.func.isRequired,
2018-11-29 17:55:14 +08:00
onMenuClick: PropTypes.func.isRequired,
};
class DirView extends React.Component {
constructor(props) {
super(props);
this.state = {
path: '/',
2018-12-22 15:18:53 +08:00
pathExist: true,
2018-11-29 17:55:14 +08:00
repoName: '',
repoID: '',
permission: true,
2018-12-13 09:53:39 +00:00
libNeedDecrypt: false,
2018-11-29 17:55:14 +08:00
isDirentSelected: false,
isAllDirentSelected: false,
isDirentListLoading: true,
2018-12-18 17:21:01 +08:00
currentRepoInfo: null,
sortBy: 'name', // 'name' or 'time'
sortOrder: 'asc', // 'asc' or 'desc'
2018-11-29 17:55:14 +08:00
direntList: [],
selectedDirentList: [],
2018-12-12 21:42:23 +08:00
dirID: '',
2018-12-22 15:18:53 +08:00
errorMsg: '',
usedRepoTags: [],
2018-11-29 17:55:14 +08:00
};
window.onpopstate = this.onpopstate;
this.lastModifyTime = new Date();
2018-11-29 17:55:14 +08:00
}
onpopstate = (event) => {
if (event.state && event.state.path) {
this.updateDirentList(event.state.path);
this.setState({path: event.state.path});
}
}
componentDidMount() {
2018-12-13 12:25:08 +08:00
// eg: http://127.0.0.1:8000/library/repo_id/repo_name/**/**/\
2018-12-12 22:58:58 +08:00
let location = decodeURIComponent(window.location.href);
2018-11-29 17:55:14 +08:00
let repoID = this.props.repoID;
2018-12-20 17:48:27 +08:00
collabServer.watchRepo(repoID, this.onRepoUpdateEvent);
seafileAPI.listRepoTags(repoID).then(res => {
let usedRepoTags = [];
res.data.repo_tags.forEach(item => {
let usedRepoTag = new RepoTag(item);
if (usedRepoTag.fileCount > 0) {
usedRepoTags.push(usedRepoTag);
}
});
this.setState({usedRepoTags: usedRepoTags});
});
2018-11-29 17:55:14 +08:00
seafileAPI.getRepoInfo(repoID).then(res => {
2018-12-18 17:21:01 +08:00
let repoInfo = new RepoInfo(res.data);
2018-11-29 17:55:14 +08:00
this.setState({
2018-12-18 17:21:01 +08:00
currentRepoInfo: repoInfo,
repoID: repoInfo.repo_id,
repoName: repoInfo.repo_name,
permission: repoInfo.permission === 'rw',
2018-12-13 09:53:39 +00:00
libNeedDecrypt: res.data.lib_need_decrypt,
2018-11-29 17:55:14 +08:00
});
2018-12-13 09:53:39 +00:00
2018-12-18 17:21:01 +08:00
let repoName = repoInfo.repo_name;
2018-12-22 16:30:54 +08:00
let repoID = repoInfo.repo_id;
let path = location.slice(location.indexOf(repoID) + repoID.length); // get the string after repoID
path = path.slice(path.indexOf(repoName) + repoName.length); // get current path
2018-12-12 22:58:58 +08:00
this.setState({path: path});
2018-12-13 09:53:39 +00:00
if (!res.data.lib_need_decrypt) {
this.updateDirentList(path);
let fileUrl = siteRoot + 'library/' + repoInfo.repo_id + '/' + encodeURIComponent(repoInfo.repo_name) + Utils.encodePath(path);
window.history.pushState({url: fileUrl, path: path}, path, fileUrl);
2018-12-13 09:53:39 +00:00
}
2018-12-22 15:18:53 +08:00
}).catch(error => {
if (error.response) {
if (error.response.status == 403) {
this.setState({
isDirentListLoading: false,
errorMsg: gettext('Permission denied')
});
} else {
this.setState({
isDirentListLoading: false,
errorMsg: gettext('Error')
});
}
} else {
this.setState({
isDirentListLoading: false,
errorMsg: gettext('Please check the network.')
});
}
2018-12-11 17:52:19 +08:00
});
2018-11-29 17:55:14 +08:00
}
2018-12-20 17:48:27 +08:00
componentWillUnmount() {
collabServer.unwatchRepo(this.props.repoID, this.onRepoUpdateEvent);
2018-12-20 17:48:27 +08:00
}
componentDidUpdate() {
this.lastModifyTime = new Date();
}
2018-12-20 17:48:27 +08:00
onRepoUpdateEvent = () => {
let currentTime = new Date();
if ((parseFloat(currentTime - this.lastModifyTime)/1000) <= 5) {
return;
}
2018-12-20 17:48:27 +08:00
let repoID = this.props.repoID;
let { path, dirID } = this.state;
seafileAPI.dirMetaData(repoID, path).then((res) => {
if (res.data.id !== dirID) {
toaster.notify(
<span>
{gettext('This folder has been updated. ')}
<a href='' >{gettext('Refresh')}</a>
</span>,
{id: 'repo_updated', duration: 3600}
2018-12-20 17:48:27 +08:00
);
}
})
}
updateUsedRepoTags = (newUsedRepoTags) => {
this.setState({usedRepoTags: newUsedRepoTags});
}
2018-11-29 17:55:14 +08:00
updateDirentList = (filePath) => {
let repoID = this.state.repoID;
this.setState({isDirentListLoading: true});
2018-12-13 12:25:08 +08:00
seafileAPI.listDir(repoID, filePath).then(res => {
2018-12-13 11:15:20 +08:00
let direntList = res.data.map(item => {
2018-11-29 17:55:14 +08:00
return new Dirent(item);
});
this.setState({
isDirentListLoading: false,
2018-12-22 15:18:53 +08:00
pathExist: true,
direntList: Utils.sortDirents(direntList, this.state.sortBy, this.state.sortOrder),
2018-12-13 11:15:20 +08:00
dirID: res.headers.oid,
2018-11-29 17:55:14 +08:00
});
}).catch(() => {
2018-12-22 15:18:53 +08:00
this.setState({
isDirentListLoading: false,
pathExist: false
});
2018-11-29 17:55:14 +08:00
});
}
onItemClick = (dirent) => {
this.resetSelected();
let direntPath = Utils.joinPath(this.state.path, dirent.name);
if (dirent.isDir()) {
this.updateDirentList(direntPath);
this.setState({path: direntPath});
let fileUrl = siteRoot + 'library/' + this.state.repoID + '/' + encodeURIComponent(this.state.repoName) + Utils.encodePath(direntPath);
2018-11-29 17:55:14 +08:00
window.history.pushState({url: fileUrl, path: direntPath}, direntPath, fileUrl);
} else {
const w=window.open('about:blank');
2018-12-14 21:52:54 +08:00
const url = siteRoot + 'lib/' + this.state.repoID + '/file' + Utils.encodePath(direntPath);
2018-11-29 17:55:14 +08:00
w.location.href = url;
}
}
onAddFolder = (dirPath) => {
let repoID = this.state.repoID;
seafileAPI.createDir(repoID, dirPath).then(() => {
let name = Utils.getFileName(dirPath);
let dirent = this.createDirent(name, 'dir');
let direntList = this.addItem(dirent, 'dir');
this.setState({direntList: direntList});
});
}
onAddFile = (filePath, isDraft) => {
let repoID = this.state.repoID;
2018-12-21 18:36:46 +08:00
seafileAPI.createFile(repoID, filePath, isDraft).then(res => {
2018-11-29 17:55:14 +08:00
let name = Utils.getFileName(filePath);
2018-12-21 18:36:46 +08:00
let dirent = this.createDirent(name, 'file', res.data);
2018-11-29 17:55:14 +08:00
let direntList = this.addItem(dirent, 'file');
this.setState({direntList: direntList});
});
}
onItemDelete = (dirent) => {
let repoID = this.state.repoID;
let direntPath = Utils.joinPath(this.state.path, dirent.name);
if (dirent.isDir()) {
seafileAPI.deleteDir(repoID, direntPath).then(() => {
let direntList = this.deleteItem(dirent);
this.setState({direntList: direntList});
}).catch(() => {
// todo
})
} else {
seafileAPI.deleteFile(repoID, direntPath).then(() => {
let direntList = this.deleteItem(dirent);
this.setState({direntList: direntList});
}).catch(() => {
// todo
})
}
}
onItemRename = (dirent, newName) => {
let repoID = this.state.repoID;
let direntPath = Utils.joinPath(this.state.path, dirent.name);
if (dirent.isDir()) {
seafileAPI.renameDir(repoID, direntPath, newName).then(() => {
let direntList = this.renameItem(dirent, newName);
this.setState({direntList: direntList});
}).catch(() => {
//todo
});
} else {
seafileAPI.renameFile(repoID, direntPath, newName).then(() => {
let direntList = this.renameItem(dirent, newName);
this.setState({direntList: direntList});
}).catch(() => {
//todo
});
}
}
onItemMove = (destRepo, dirent, moveToDirentPath) => {
let dirName = dirent.name;
let repoID = this.state.repoID;
seafileAPI.moveDir(repoID, destRepo.repo_id, moveToDirentPath, this.state.path, dirName).then(() => {
let direntList = this.deleteItem(dirent);
2018-12-21 15:40:59 +08:00
this.setState({direntList: direntList});
2018-11-29 17:55:14 +08:00
let message = gettext('Successfully moved %(name)s.');
message = message.replace('%(name)s', dirName);
2018-12-07 14:58:37 +08:00
toaster.success(message);
2018-11-29 17:55:14 +08:00
}).catch(() => {
let message = gettext('Failed to move %(name)s');
message = message.replace('%(name)s', dirName);
2018-12-07 14:58:37 +08:00
toaster.danger(message);
2018-11-29 17:55:14 +08:00
});
}
onItemCopy = (destRepo, dirent, copyToDirentPath) => {
let dirName = dirent.name;
let repoID = this.state.repoID;
seafileAPI.copyDir(repoID, destRepo.repo_id, copyToDirentPath, this.state.path, dirName).then(() => {
let message = gettext('Successfully copied %(name)s.');
message = message.replace('%(name)s', dirName);
2018-12-07 14:58:37 +08:00
toaster.success(message);
2018-11-29 17:55:14 +08:00
}).catch(() => {
let message = gettext('Failed to copy %(name)s');
message = message.replace('%(name)s', dirName);
2018-12-07 14:58:37 +08:00
toaster.danger(message);
2018-11-29 17:55:14 +08:00
});
}
onItemSelected = (dirent) => {
let direntList = this.state.direntList.map(item => {
if (item.name === dirent.name) {
item.isSelected = !item.isSelected;
}
return item;
});
let selectedDirentList = direntList.filter(item => {
return item.isSelected;
});
if (selectedDirentList.length) {
this.setState({isDirentSelected: true});
if (selectedDirentList.length === direntList.length) {
this.setState({
isAllDirentSelected: true,
direntList: direntList,
selectedDirentList: selectedDirentList,
});
} else {
this.setState({
isAllDirentSelected: false,
direntList: direntList,
selectedDirentList: selectedDirentList
});
}
} else {
this.setState({
isDirentSelected: false,
isAllDirentSelected: false,
direntList: direntList,
selectedDirentList: []
});
}
}
onItemsMove = (destRepo, destDirentPath) => {
let dirNames = this.getSelectedDirentNames();
let repoID = this.state.repoID;
seafileAPI.moveDir(repoID, destRepo.repo_id, destDirentPath, this.state.path, dirNames).then(() => {
let direntList = this.deleteItems(dirNames);
2018-12-18 17:21:01 +08:00
this.setState({
direntList: direntList,
isDirentSelected: false,
selectedDirentList: [],
});
2018-11-29 17:55:14 +08:00
let message = gettext('Successfully moved %(name)s.');
message = message.replace('%(name)s', dirNames);
2018-12-07 14:58:37 +08:00
toaster.success(message);
2018-11-29 17:55:14 +08:00
}).catch(() => {
let message = gettext('Failed to move %(name)s');
message = message.replace('%(name)s', dirNames);
2018-12-07 14:58:37 +08:00
toaster.danger(message);
2018-11-29 17:55:14 +08:00
});
}
onItemsCopy = (destRepo, destDirentPath) => {
let dirNames = this.getSelectedDirentNames();
let repoID = this.state.repoID;
seafileAPI.copyDir(repoID, destRepo.repo_id, destDirentPath, this.state.path, dirNames).then(() => {
let message = gettext('Successfully copied %(name)s.');
message = message.replace('%(name)s', dirNames);
2018-12-07 14:58:37 +08:00
toaster.success(message);
2018-11-29 17:55:14 +08:00
}).catch(() => {
let message = gettext('Failed to copy %(name)s');
message = message.replace('%(name)s', dirNames);
2018-12-07 14:58:37 +08:00
toaster.danger(message);
2018-11-29 17:55:14 +08:00
});
}
onItemsDelete = () => {
let dirNames = this.getSelectedDirentNames();
let repoID = this.state.repoID;
seafileAPI.deleteMutipleDirents(repoID, this.state.path, dirNames).then(res => {
let direntList = this.deleteItems(dirNames);
2018-12-18 17:21:01 +08:00
this.setState({
direntList: direntList,
isDirentSelected: false,
selectedDirentList: [],
});
2018-11-29 17:55:14 +08:00
});
}
onAllItemSelected = () => {
if (this.state.isAllDirentSelected) {
let direntList = this.state.direntList.map(item => {
item.isSelected = false;
return item;
});
this.setState({
isDirentSelected: false,
isAllDirentSelected: false,
direntList: direntList,
selectedDirentList: [],
});
} else {
let direntList = this.state.direntList.map(item => {
item.isSelected = true;
return item;
});
this.setState({
isDirentSelected: true,
isAllDirentSelected: true,
direntList: direntList,
selectedDirentList: direntList,
});
}
}
onFileTagChanged = (dirent, direntPath) => {
let repoID = this.state.repoID;
seafileAPI.listFileTags(repoID, direntPath).then(res => {
let fileTags = res.data.file_tags.map(item => {
return new FileTag(item);
});
this.updateDirent(dirent, 'file_tags', fileTags);
});
seafileAPI.listRepoTags(repoID).then(res => {
let usedRepoTags = [];
res.data.repo_tags.forEach(item => {
let usedRepoTag = new RepoTag(item);
if (usedRepoTag.fileCount > 0) {
usedRepoTags.push(usedRepoTag);
}
});
this.updateUsedRepoTags(usedRepoTags);
});
2018-11-29 17:55:14 +08:00
}
onMenuClick = () => {
this.props.onMenuClick();
}
onPathClick = (path) => {
this.updateDirentList(path);
this.setState({path: path});
let fileUrl = siteRoot + 'library/' + this.state.repoID + '/' + encodeURIComponent(this.state.repoName) + Utils.encodePath(path);
2018-11-29 17:55:14 +08:00
window.history.pushState({url: fileUrl, path: path}, path, fileUrl);
}
updateDirent = (dirent, paramKey, paramValue) => {
let newDirentList = this.state.direntList.map(item => {
if (item.name === dirent.name) {
item[paramKey] = paramValue;
}
return item;
});
this.setState({direntList: newDirentList});
}
2019-01-05 11:43:33 +08:00
onFileUploadSuccess = (direntObject) => {
let isExist = this.state.direntList.some(item => {
return item.name === direntObject.name && item.type === direntObject.type;
});
if (isExist) {
let direntList = this.state.direntList;
for (let i = 0; i < direntList.length; i++) {
let dirent = direntList[i];
if (dirent.name === direntObject.name && dirent.type === direntObject.type) {
let mtime = moment.unix(direntObject.mtime).fromNow();
this.updateDirent(dirent, 'mtime', mtime); // todo file size is need update too, api is not return;
break;
}
}
} else {
direntObject.permission = 'rw';
let dirent = new Dirent(direntObject);
if (direntObject.type === 'dir') {
this.setState({direntList: [dirent, ...this.state.direntList]});
} else {
this.setState({direntList: [...this.state.direntList, dirent]});
}
}
2018-11-29 17:55:14 +08:00
}
2018-12-13 20:42:51 +08:00
onSearchedClick = (selectedItem) => {
if (selectedItem.is_dir === true) {
this.setState({path: selectedItem.path});
} else {
let url = siteRoot + 'lib/' + selectedItem.repo_id + '/file' + selectedItem.path;
let newWindow = window.open('about:blank');
newWindow.location.href = url;
}
2018-11-29 17:55:14 +08:00
}
resetSelected = () => {
this.setState({isDirentSelected: false, isAllDirentSelected: false});
}
addItem = (dirent, type) => {
let direntList = this.state.direntList.map(item => {return item}); //clone
if (type === 'dir') {
direntList.unshift(dirent);
return direntList;
}
direntList.push(dirent);
return direntList;
}
deleteItem = (dirent) => {
return this.state.direntList.filter(item => {
return item.name !== dirent.name;
});
}
renameItem = (dirent, newName) => {
return this.state.direntList.map(item => {
if (item.name === dirent.name) {
item.name = newName;
}
return item;
});
}
deleteItems = (dirNames) => {
let direntList = this.state.direntList.map(item => {return item}); //clone
while (dirNames.length) {
for (let i = 0; i < direntList.length; i++) {
if (direntList[i].name === dirNames[0]) {
direntList.splice(i, 1);
break;
}
}
dirNames.shift();
}
return direntList;
}
2018-12-21 18:36:46 +08:00
createDirent(name, type, direntInfo) {
2018-11-29 17:55:14 +08:00
let data = new Date().getTime()/1000;
let dirent = null;
if (type === 'dir') {
dirent = new Dirent({
id: '000000000000000000',
name: name,
type: type,
mtime: data,
permission: 'rw',
});
} else {
dirent = new Dirent({
id: '000000000000000000',
name: name,
type: type,
mtime: data,
permission: 'rw',
2018-12-21 18:36:46 +08:00
size: direntInfo.size,
2018-11-29 17:55:14 +08:00
starred: false,
is_locked: false,
lock_time: '',
lock_owner: null,
locked_by_me: false,
modifier_name: '',
modifier_email: '',
modifier_contact_email: '',
file_tags: []
});
}
return dirent;
}
getSelectedDirentNames = () => {
let names = [];
this.state.selectedDirentList.forEach(selectedDirent => {
names.push(selectedDirent.name);
});
return names;
}
isMarkdownFile(filePath) {
let index = filePath.lastIndexOf('.');
if (index === -1) {
return false;
} else {
let type = filePath.substring(index).toLowerCase();
if (type === '.md' || type === '.markdown') {
return true;
} else {
return false;
}
}
}
2018-12-13 09:53:39 +00:00
onLibDecryptDialog = () => {
this.setState({
libNeedDecrypt: !this.state.libNeedDecrypt
})
this.updateDirentList(this.state.path);
}
sortItems = (sortBy, sortOrder) => {
this.setState({
sortBy: sortBy,
sortOrder: sortOrder,
items: Utils.sortDirents(this.state.direntList, sortBy, sortOrder)
})
}
2018-11-29 17:55:14 +08:00
render() {
return (
<DirPanel
2018-12-11 17:52:19 +08:00
pathPrefix={this.props.pathPrefix}
2018-12-18 17:21:01 +08:00
currentRepoInfo={this.state.currentRepoInfo}
2018-11-29 17:55:14 +08:00
path={this.state.path}
2018-12-22 15:18:53 +08:00
pathExist={this.state.pathExist}
errorMsg={this.state.errorMsg}
2018-11-29 17:55:14 +08:00
repoID={this.state.repoID}
repoName={this.state.repoName}
permission={this.state.permission}
isDirentListLoading={this.state.isDirentListLoading}
isDirentSelected={this.state.isDirentSelected}
isAllDirentSelected={this.state.isAllDirentSelected}
direntList={this.state.direntList}
sortBy={this.state.sortBy}
sortOrder={this.state.sortOrder}
sortItems={this.sortItems}
2018-12-22 11:17:03 +08:00
selectedDirentList={this.state.selectedDirentList}
2018-11-29 17:55:14 +08:00
onItemClick={this.onItemClick}
onAddFile={this.onAddFile}
onAddFolder={this.onAddFolder}
onItemMove={this.onItemMove}
onItemCopy={this.onItemCopy}
onItemRename={this.onItemRename}
onItemDelete={this.onItemDelete}
onItemSelected={this.onItemSelected}
onItemsMove={this.onItemsMove}
onItemsCopy={this.onItemsCopy}
onItemsDelete={this.onItemsDelete}
onAllItemSelected={this.onAllItemSelected}
onFileTagChanged={this.onFileTagChanged}
onMenuClick={this.onMenuClick}
onPathClick={this.onPathClick}
2018-12-13 14:40:09 +08:00
onTabNavClick={this.props.onTabNavClick}
2018-11-29 17:55:14 +08:00
updateDirent={this.updateDirent}
switchViewMode={this.switchViewMode}
onSearchedClick={this.onSearchedClick}
onFileUploadSuccess={this.onFileUploadSuccess}
2018-12-13 09:53:39 +00:00
libNeedDecrypt={this.state.libNeedDecrypt}
onLibDecryptDialog={this.onLibDecryptDialog}
usedRepoTags={this.state.usedRepoTags}
2018-11-29 17:55:14 +08:00
/>
);
}
}
DirView.propTypes = propTypes;
export default DirView;