2019-03-19 10:20:45 +00:00
|
|
|
import React from 'react';
|
2019-02-20 03:54:25 +00:00
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
import cookie from 'react-cookies';
|
|
|
|
import moment from 'moment';
|
2019-04-17 05:08:47 +00:00
|
|
|
import { gettext, siteRoot, username, canGenerateShareLink, canGenerateUploadLink, isDocs } from '../../utils/constants';
|
2019-02-20 03:54:25 +00:00
|
|
|
import { seafileAPI } from '../../utils/seafile-api';
|
|
|
|
import { Utils } from '../../utils/utils';
|
|
|
|
import collabServer from '../../utils/collab-server';
|
|
|
|
import Dirent from '../../models/dirent';
|
|
|
|
import FileTag from '../../models/file-tag';
|
|
|
|
import RepoTag from '../../models/repo-tag';
|
|
|
|
import RepoInfo from '../../models/repo-info';
|
|
|
|
import TreeNode from '../../components/tree-view/tree-node';
|
|
|
|
import treeHelper from '../../components/tree-view/tree-helper';
|
|
|
|
import toaster from '../../components/toast';
|
|
|
|
import ModalPortal from '../../components/modal-portal';
|
|
|
|
import LibDecryptDialog from '../../components/dialog/lib-decrypt-dialog';
|
2019-02-21 09:37:04 +00:00
|
|
|
import LibContentToolbar from './lib-content-toolbar';
|
|
|
|
import LibContentContainer from './lib-content-container';
|
|
|
|
import FileUploader from '../../components/file-uploader/file-uploader';
|
2019-02-20 03:54:25 +00:00
|
|
|
|
|
|
|
const propTypes = {
|
|
|
|
pathPrefix: PropTypes.array.isRequired,
|
|
|
|
onTabNavClick: PropTypes.func.isRequired,
|
|
|
|
onMenuClick: PropTypes.func.isRequired,
|
2019-02-21 09:37:04 +00:00
|
|
|
repoID: PropTypes.string,
|
2019-02-20 03:54:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class LibContentView extends React.Component {
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
2019-04-13 03:56:44 +00:00
|
|
|
currentMode: cookie.load('seafile_view_mode') || 'list',
|
2019-02-20 03:54:25 +00:00
|
|
|
path: '',
|
|
|
|
pathExist: true,
|
|
|
|
isViewFile: false,
|
|
|
|
hash: '',
|
|
|
|
currentRepoInfo: null,
|
|
|
|
repoName: '',
|
|
|
|
repoPermission: true,
|
|
|
|
repoEncrypted: false,
|
|
|
|
libNeedDecrypt: false,
|
|
|
|
isGroupOwnedRepo: false,
|
|
|
|
userPerm: '',
|
|
|
|
selectedDirentList: [],
|
|
|
|
isDraft: false,
|
|
|
|
hasDraft: false,
|
2019-03-15 02:10:24 +00:00
|
|
|
fileTags: [],
|
|
|
|
relatedFiles: [],
|
2019-03-05 07:37:51 +00:00
|
|
|
draftID: '',
|
2019-02-20 03:54:25 +00:00
|
|
|
draftCounts: 0,
|
|
|
|
usedRepoTags: [],
|
|
|
|
readmeMarkdown: null,
|
|
|
|
isTreeDataLoading: true,
|
|
|
|
treeData: treeHelper.buildTree(),
|
|
|
|
currentNode: null,
|
|
|
|
isFileLoading: true,
|
2019-02-21 09:37:04 +00:00
|
|
|
isFileLoadedErr: false,
|
2019-04-19 07:50:27 +00:00
|
|
|
filePermission: '',
|
2019-02-20 03:54:25 +00:00
|
|
|
content: '',
|
|
|
|
lastModified: '',
|
|
|
|
latestContributor: '',
|
|
|
|
isDirentListLoading: true,
|
|
|
|
direntList: [],
|
|
|
|
isDirentSelected: false,
|
2019-04-12 06:30:08 +00:00
|
|
|
sortBy: cookie.load('seafile-repo-dir-sort-by') || 'name', // 'name' or 'time'
|
|
|
|
sortOrder: cookie.load('seafile-repo-dir-sort-order') || 'asc', // 'asc' or 'desc'
|
2019-02-20 03:54:25 +00:00
|
|
|
isAllDirentSelected: false,
|
2019-02-21 09:37:04 +00:00
|
|
|
dirID: '', // for update dir list
|
2019-02-20 03:54:25 +00:00
|
|
|
errorMsg: '',
|
2019-03-18 09:32:49 +00:00
|
|
|
isDirentDetailShow: false,
|
2019-04-18 05:39:42 +00:00
|
|
|
updateDetail: false,
|
2019-04-24 05:37:48 +00:00
|
|
|
itemsShowLength: 100,
|
2019-02-20 03:54:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
window.onpopstate = this.onpopstate;
|
|
|
|
this.lastModifyTime = new Date();
|
2019-02-23 03:59:26 +00:00
|
|
|
this.isNeedUpdateHistoryState = true; // Load, refresh page, switch mode for the first time, no need to set historyState
|
2019-02-20 03:54:25 +00:00
|
|
|
}
|
|
|
|
|
2019-03-18 09:32:49 +00:00
|
|
|
showDirentDetail = () => {
|
2019-04-12 12:21:54 +00:00
|
|
|
this.setState({isDirentDetailShow: true});
|
2019-03-18 09:32:49 +00:00
|
|
|
}
|
|
|
|
|
2019-04-10 08:04:26 +00:00
|
|
|
toggleDirentDetail = () => {
|
|
|
|
this.setState({ isDirentDetailShow: !this.state.isDirentDetailShow });
|
|
|
|
}
|
|
|
|
|
2019-03-19 10:20:45 +00:00
|
|
|
closeDirentDetail = () => {
|
|
|
|
this.setState({ isDirentDetailShow: false });
|
|
|
|
}
|
|
|
|
|
2019-02-20 03:54:25 +00:00
|
|
|
componentWillMount() {
|
|
|
|
const hash = window.location.hash;
|
|
|
|
if (hash.slice(0, 1) === '#') {
|
2019-02-21 09:37:04 +00:00
|
|
|
this.setState({hash: hash});
|
2019-02-20 03:54:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
// eg: http://127.0.0.1:8000/library/repo_id/repo_name/**/**/\
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
let location = window.location.href.split('#')[0];
|
|
|
|
location = decodeURIComponent(location);
|
|
|
|
seafileAPI.getRepoInfo(repoID).then(res => {
|
|
|
|
let repoInfo = new RepoInfo(res.data);
|
|
|
|
this.setState({
|
|
|
|
currentRepoInfo: repoInfo,
|
|
|
|
repoName: repoInfo.repo_name,
|
2019-02-27 05:53:36 +00:00
|
|
|
libNeedDecrypt: repoInfo.lib_need_decrypt,
|
2019-02-20 03:54:25 +00:00
|
|
|
repoEncrypted: repoInfo.encrypted,
|
|
|
|
repoPermission: repoInfo.permission === 'rw'
|
|
|
|
});
|
|
|
|
|
|
|
|
let repoID = repoInfo.repo_id;
|
|
|
|
let path = location.slice(location.indexOf(repoID) + repoID.length + 1); // get the string after repoID
|
|
|
|
path = path.slice(path.indexOf('/')); // get current path
|
|
|
|
|
2019-02-23 03:59:26 +00:00
|
|
|
this.isNeedUpdateHistoryState = false;
|
|
|
|
|
2019-02-20 03:54:25 +00:00
|
|
|
this.setState({path: path});
|
|
|
|
|
2019-02-27 05:53:36 +00:00
|
|
|
if (!repoInfo.lib_need_decrypt) {
|
2019-02-20 03:54:25 +00:00
|
|
|
this.loadDirData(path);
|
|
|
|
}
|
|
|
|
}).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.')
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
collabServer.unwatchRepo(this.props.repoID, this.onRepoUpdateEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate() {
|
|
|
|
this.lastModifyTime = new Date();
|
|
|
|
}
|
|
|
|
|
|
|
|
onpopstate = (event) => {
|
2019-03-29 10:27:43 +00:00
|
|
|
if (event.state && event.state.key) { // root path
|
|
|
|
if (this.state.path === '/') {
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
let path = '/';
|
|
|
|
this.loadDirentList(path);
|
|
|
|
this.setState({
|
|
|
|
path: path,
|
|
|
|
isViewFile: false
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else if (event.state && event.state.path) { // file path
|
2019-02-20 03:54:25 +00:00
|
|
|
let path = event.state.path;
|
|
|
|
if (this.state.currentMode === 'column') {
|
|
|
|
if (Utils.isMarkdownFile(path)) { // Judging not strict
|
|
|
|
this.showFile(path);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.loadDirentList(path);
|
|
|
|
this.setState({
|
|
|
|
path: path,
|
|
|
|
isViewFile: false
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onRepoUpdateEvent = () => {
|
|
|
|
let currentTime = new Date();
|
|
|
|
if ((parseFloat(currentTime - this.lastModifyTime)/1000) <= 5) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
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}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
updateUsedRepoTags = () => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
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});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
updateReadmeMarkdown = (direntList) => {
|
|
|
|
this.setState({readmeMarkdown: null});
|
|
|
|
direntList.some(item => {
|
|
|
|
let fileName = item.name.toLowerCase();
|
|
|
|
if (fileName === 'readme.md' || fileName === 'readme.markdown') {
|
|
|
|
this.setState({readmeMarkdown: item});
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// load data
|
|
|
|
loadDirData = (path) => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
|
|
|
|
// listen current repo
|
|
|
|
collabServer.watchRepo(repoID, this.onRepoUpdateEvent);
|
|
|
|
|
|
|
|
// list used FileTags
|
|
|
|
this.updateUsedRepoTags();
|
|
|
|
|
|
|
|
// list draft counts and revierw counts
|
2019-04-17 05:08:47 +00:00
|
|
|
if (isDocs) {
|
|
|
|
seafileAPI.getRepoDraftCounts(repoID).then(res => {
|
|
|
|
this.setState({
|
|
|
|
draftCounts: res.data.draft_counts,
|
|
|
|
});
|
2019-02-20 03:54:25 +00:00
|
|
|
});
|
2019-04-17 05:08:47 +00:00
|
|
|
}
|
2019-04-13 03:56:44 +00:00
|
|
|
|
2019-02-28 07:36:14 +00:00
|
|
|
if (Utils.isMarkdownFile(path)) {
|
|
|
|
seafileAPI.getFileInfo(this.props.repoID, path).then(() => {
|
|
|
|
if (this.state.currentMode !== 'column') {
|
2019-04-13 03:56:44 +00:00
|
|
|
cookie.save('seafile_view_mode', 'column');
|
2019-02-28 07:36:14 +00:00
|
|
|
this.setState({currentMode: 'column'});
|
|
|
|
}
|
|
|
|
this.loadSidePanel(path);
|
|
|
|
this.showFile(path);
|
|
|
|
}).catch(() => {
|
|
|
|
if (this.state.currentMode === 'column') { // After an error occurs, follow dir
|
|
|
|
this.loadSidePanel(path);
|
|
|
|
this.showDir(path);
|
|
|
|
} else {
|
|
|
|
this.showDir(path);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
if (this.state.currentMode === 'column') {
|
|
|
|
this.loadSidePanel(path);
|
|
|
|
this.showDir(path);
|
2019-02-20 03:54:25 +00:00
|
|
|
} else {
|
|
|
|
this.showDir(path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
loadSidePanel = (path) => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
if (path === '/') {
|
|
|
|
seafileAPI.listDir(repoID, '/').then(res => {
|
|
|
|
let tree = this.state.treeData;
|
|
|
|
this.addResponseListToNode(res.data.dirent_list, tree.root);
|
|
|
|
this.setState({
|
|
|
|
isTreeDataLoading: false,
|
|
|
|
treeData: tree
|
|
|
|
});
|
|
|
|
}).catch(() => {
|
|
|
|
this.setState({isTreeDataLoading: false});
|
|
|
|
// todo show error message
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.loadNodeAndParentsByPath(path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
showDir = (path) => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
|
|
|
|
// update stste
|
|
|
|
this.setState({
|
|
|
|
isDirentListLoading: true,
|
|
|
|
path: path,
|
2019-04-11 13:04:47 +00:00
|
|
|
isViewFile: false,
|
|
|
|
selectedDirentList: [],
|
2019-02-20 03:54:25 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// update data
|
2019-02-23 03:59:26 +00:00
|
|
|
this.loadDirentList(path);
|
2019-02-20 03:54:25 +00:00
|
|
|
|
2019-02-23 03:59:26 +00:00
|
|
|
if (!this.isNeedUpdateHistoryState) {
|
|
|
|
this.isNeedUpdateHistoryState = true;
|
|
|
|
return;
|
|
|
|
}
|
2019-02-20 03:54:25 +00:00
|
|
|
// update location
|
|
|
|
let repoInfo = this.state.currentRepoInfo;
|
|
|
|
let url = siteRoot + 'library/' + repoID + '/' + encodeURIComponent(repoInfo.repo_name) + Utils.encodePath(path);
|
|
|
|
window.history.pushState({url: url, path: path}, path, url);
|
|
|
|
}
|
|
|
|
|
|
|
|
showFile = (filePath) => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
|
2019-03-15 02:10:24 +00:00
|
|
|
if (this.state.currentMode === 'column') {
|
|
|
|
seafileAPI.listFileTags(repoID, filePath).then(res => {
|
|
|
|
let fileTags = res.data.file_tags.map(item => {
|
|
|
|
return new FileTag(item);
|
|
|
|
});
|
|
|
|
|
|
|
|
this.setState({fileTags: fileTags});
|
|
|
|
});
|
|
|
|
|
|
|
|
seafileAPI.listRelatedFiles(repoID, filePath).then(res => {
|
|
|
|
let relatedFiles = res.data.related_files.map((relatedFile) => {
|
|
|
|
return relatedFile;
|
|
|
|
});
|
|
|
|
this.setState({relatedFiles: relatedFiles});
|
|
|
|
}).catch((error) => {
|
|
|
|
if (error.response.status === 500) {
|
|
|
|
this.setState({relatedFiles: []});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-02-20 03:54:25 +00:00
|
|
|
// update state
|
|
|
|
this.setState({
|
|
|
|
isFileLoading: true,
|
|
|
|
path: filePath,
|
|
|
|
isViewFile: true
|
|
|
|
});
|
|
|
|
|
|
|
|
// update data
|
|
|
|
seafileAPI.getFileInfo(repoID, filePath).then((res) => {
|
2019-03-05 07:37:51 +00:00
|
|
|
let { mtime, permission, last_modifier_name, is_draft, has_draft, draft_id } = res.data;
|
2019-02-20 03:54:25 +00:00
|
|
|
seafileAPI.getFileDownloadLink(repoID, filePath).then((res) => {
|
|
|
|
seafileAPI.getFileContent(res.data).then((res) => {
|
|
|
|
this.setState({
|
|
|
|
content: res.data,
|
2019-04-19 07:50:27 +00:00
|
|
|
filePermission: permission,
|
2019-02-20 03:54:25 +00:00
|
|
|
latestContributor: last_modifier_name,
|
|
|
|
lastModified: moment.unix(mtime).fromNow(),
|
|
|
|
isFileLoading: false,
|
2019-02-21 09:37:04 +00:00
|
|
|
isFileLoadedErr: false,
|
2019-02-20 03:54:25 +00:00
|
|
|
isDraft: is_draft,
|
|
|
|
hasDraft: has_draft,
|
2019-03-05 07:37:51 +00:00
|
|
|
draftID: draft_id
|
2019-02-20 03:54:25 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2019-02-21 09:37:04 +00:00
|
|
|
}).catch(() => {
|
|
|
|
this.setState({
|
|
|
|
isFileLoading: false,
|
|
|
|
isFileLoadedErr: true,
|
|
|
|
});
|
2019-02-20 03:54:25 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// update location
|
|
|
|
let repoInfo = this.state.currentRepoInfo;
|
|
|
|
let url = siteRoot + 'library/' + repoID + '/' + encodeURIComponent(repoInfo.repo_name) + Utils.encodePath(filePath);
|
|
|
|
window.history.pushState({url: url, path: filePath}, filePath, url);
|
|
|
|
}
|
|
|
|
|
2019-02-23 03:59:26 +00:00
|
|
|
loadDirentList = (path) => {
|
2019-03-19 10:20:45 +00:00
|
|
|
let repoID = this.props.repoID;
|
2019-02-20 03:54:25 +00:00
|
|
|
seafileAPI.listDir(repoID, path, {'with_thumbnail': true}).then(res => {
|
|
|
|
let direntList = [];
|
|
|
|
let markdownItem = null;
|
|
|
|
res.data.dirent_list.forEach(item => {
|
|
|
|
let fileName = item.name.toLowerCase();
|
|
|
|
if (fileName === 'readme.md' || fileName === 'readme.markdown') {
|
|
|
|
markdownItem = item;
|
|
|
|
}
|
|
|
|
let dirent = new Dirent(item);
|
|
|
|
direntList.push(dirent);
|
|
|
|
});
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
pathExist: true,
|
|
|
|
userPerm: res.data.user_perm,
|
|
|
|
isDirentListLoading: false,
|
|
|
|
direntList: Utils.sortDirents(direntList, this.state.sortBy, this.state.sortOrder),
|
2019-03-06 06:59:24 +00:00
|
|
|
dirID: res.data.dir_id,
|
2019-02-20 03:54:25 +00:00
|
|
|
readmeMarkdown: markdownItem,
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!this.state.repoEncrypted && direntList.length) {
|
|
|
|
this.getThumbnails(repoID, path, this.state.direntList);
|
|
|
|
}
|
2019-04-23 08:50:17 +00:00
|
|
|
this.onSwitchPage();
|
2019-02-20 03:54:25 +00:00
|
|
|
}).catch(() => {
|
|
|
|
this.setState({
|
|
|
|
isDirentListLoading: false,
|
|
|
|
pathExist: false,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-04-23 08:50:17 +00:00
|
|
|
onPageScroll = () => {
|
2019-04-24 05:37:48 +00:00
|
|
|
let itemsShowLength = this.state.itemsShowLength;
|
|
|
|
itemsShowLength += 100;
|
|
|
|
this.setState({itemsShowLength: itemsShowLength});
|
2019-04-23 06:43:47 +00:00
|
|
|
}
|
|
|
|
|
2019-04-23 08:50:17 +00:00
|
|
|
onSwitchPage = () => {
|
2019-04-24 05:37:48 +00:00
|
|
|
this.setState({itemsShowLength: 100});
|
2019-04-23 06:43:47 +00:00
|
|
|
}
|
|
|
|
|
2019-02-20 03:54:25 +00:00
|
|
|
getThumbnails = (repoID, path, direntList) => {
|
|
|
|
let items = direntList.filter((item) => {
|
|
|
|
return Utils.imageCheck(item.name) && !item.encoded_thumbnail_src;
|
|
|
|
});
|
|
|
|
if (items.length == 0) {
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
const _this = this;
|
|
|
|
const len = items.length;
|
|
|
|
const thumbnailSize = 48;
|
|
|
|
let getThumbnail = (i) => {
|
|
|
|
const curItem = items[i];
|
|
|
|
const curItemPath = [path, curItem.name].join('/');
|
|
|
|
seafileAPI.createThumbnail(repoID, curItemPath, thumbnailSize).then((res) => {
|
|
|
|
curItem.encoded_thumbnail_src = res.data.encoded_thumbnail_src;
|
|
|
|
}).catch((error) => {
|
|
|
|
// do nothing
|
|
|
|
}).then(() => {
|
|
|
|
if (i < len - 1) {
|
|
|
|
getThumbnail(++i);
|
|
|
|
} else {
|
|
|
|
_this.setState({
|
|
|
|
direntList: direntList
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
getThumbnail(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// toolbar operations
|
|
|
|
onMoveItems = (destRepo, destDirentPath) => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
let direntPaths = this.getSelectedDirentPaths();
|
|
|
|
let dirNames = this.getSelectedDirentNames();
|
|
|
|
|
|
|
|
seafileAPI.moveDir(repoID, destRepo.repo_id, destDirentPath, this.state.path, dirNames).then(res => {
|
|
|
|
let names = res.data.map(item => {
|
|
|
|
return item.obj_name;
|
|
|
|
});
|
|
|
|
direntPaths.forEach((direntPath, index) => {
|
|
|
|
if (this.state.currentMode === 'column') {
|
|
|
|
this.moveTreeNode(direntPath, destDirentPath, destRepo, names[index]);
|
|
|
|
}
|
|
|
|
this.moveDirent(direntPath);
|
|
|
|
});
|
2019-04-11 03:07:31 +00:00
|
|
|
let message = Utils.getMoveSuccessMessage(dirNames);
|
2019-02-20 03:54:25 +00:00
|
|
|
toaster.success(message);
|
|
|
|
}).catch(() => {
|
2019-04-11 03:07:31 +00:00
|
|
|
let message = Utils.getMoveFailedMessage(dirNames);
|
2019-02-20 03:54:25 +00:00
|
|
|
toaster.danger(message);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onCopyItems = (destRepo, destDirentPath) => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
let direntPaths = this.getSelectedDirentPaths();
|
|
|
|
let dirNames = this.getSelectedDirentNames();
|
|
|
|
|
|
|
|
seafileAPI.copyDir(repoID, destRepo.repo_id, destDirentPath, this.state.path, dirNames).then(res => {
|
|
|
|
let names = res.data.map(item => {
|
|
|
|
return item.obj_name;
|
|
|
|
});
|
|
|
|
if (this.state.currentMode === 'column') {
|
|
|
|
direntPaths.forEach((direntPath, index) => {
|
|
|
|
this.copyTreeNode(direntPath, destDirentPath, destRepo, names[index]);
|
|
|
|
});
|
|
|
|
}
|
2019-04-11 03:07:31 +00:00
|
|
|
let message = Utils.getCopySuccessfulMessage(dirNames);
|
2019-02-20 03:54:25 +00:00
|
|
|
toaster.success(message);
|
|
|
|
}).catch(() => {
|
2019-04-11 03:07:31 +00:00
|
|
|
let message = Utils.getCopyFailedMessage(dirNames);
|
2019-02-20 03:54:25 +00:00
|
|
|
toaster.danger(message);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onDeleteItems = () => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
let direntPaths = this.getSelectedDirentPaths();
|
|
|
|
let dirNames = this.getSelectedDirentNames();
|
|
|
|
|
2019-04-18 05:39:42 +00:00
|
|
|
this.setState({updateDetail: !this.state.updateDetail});
|
2019-02-20 03:54:25 +00:00
|
|
|
seafileAPI.deleteMutipleDirents(repoID, this.state.path, dirNames).then(res => {
|
|
|
|
direntPaths.forEach(direntPath => {
|
|
|
|
if (this.state.currentMode === 'column') {
|
|
|
|
this.deleteTreeNode(direntPath);
|
|
|
|
}
|
|
|
|
this.deleteDirent(direntPath);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onAddFolder = (dirPath) => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
seafileAPI.createDir(repoID, dirPath).then(() => {
|
|
|
|
let name = Utils.getFileName(dirPath);
|
|
|
|
let parentPath = Utils.getDirName(dirPath);
|
|
|
|
|
|
|
|
if (this.state.currentMode === 'column') {
|
|
|
|
this.addNodeToTree(name, parentPath, 'dir');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parentPath === this.state.path && !this.state.isViewFile) {
|
|
|
|
this.addDirent(name, 'dir');
|
|
|
|
}
|
|
|
|
}).catch(() => {
|
|
|
|
// return error message
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onAddFile = (filePath, isDraft) => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
seafileAPI.createFile(repoID, filePath, isDraft).then(res => {
|
|
|
|
let name = Utils.getFileName(filePath);
|
|
|
|
let parentPath = Utils.getDirName(filePath);
|
|
|
|
if (this.state.currentMode === 'column') {
|
|
|
|
this.addNodeToTree(name, parentPath, 'file');
|
|
|
|
}
|
|
|
|
if (parentPath === this.state.path && !this.state.isViewFile) {
|
|
|
|
this.addDirent(name, 'file', res.data.size);
|
|
|
|
}
|
|
|
|
}).catch(() => {
|
|
|
|
// todo
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
switchViewMode = (mode) => {
|
|
|
|
if (mode === this.state.currentMode) {
|
|
|
|
return;
|
|
|
|
}
|
2019-04-10 08:04:26 +00:00
|
|
|
if (mode === 'detail') {
|
|
|
|
this.toggleDirentDetail();
|
|
|
|
return;
|
|
|
|
}
|
2019-04-13 03:56:44 +00:00
|
|
|
cookie.save('seafile_view_mode', mode);
|
2019-02-20 03:54:25 +00:00
|
|
|
let path = this.state.path;
|
|
|
|
if (this.state.currentMode === 'column' && this.state.isViewFile) {
|
|
|
|
path = Utils.getDirName(path);
|
|
|
|
this.setState({
|
|
|
|
path: path,
|
|
|
|
isViewFile: false,
|
|
|
|
});
|
|
|
|
let repoInfo = this.state.currentRepoInfo;
|
|
|
|
|
|
|
|
let url = siteRoot + 'library/' + repoInfo.repo_id + '/' + encodeURIComponent(repoInfo.repo_name) + Utils.encodePath(path);
|
|
|
|
window.history.pushState({url: url, path: path}, path, url);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode === 'column') {
|
|
|
|
this.loadSidePanel(this.state.path);
|
|
|
|
}
|
2019-02-23 03:59:26 +00:00
|
|
|
this.isNeedUpdateHistoryState = false;
|
2019-02-20 03:54:25 +00:00
|
|
|
this.setState({currentMode: mode});
|
2019-02-21 10:09:17 +00:00
|
|
|
this.showDir(path);
|
2019-02-20 03:54:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
onSearchedClick = (item) => {
|
|
|
|
let path = item.is_dir ? item.path.slice(0, item.path.length - 1) : item.path;
|
|
|
|
if (this.state.currentPath === path) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (this.state.currentMode === 'column') {
|
|
|
|
// load sidePanel
|
|
|
|
let index = -1;
|
|
|
|
let paths = Utils.getPaths(path);
|
|
|
|
for (let i = 0; i < paths.length; i++) {
|
|
|
|
let node = this.state.treeData.getNodeByPath(node);
|
|
|
|
if (!node) {
|
|
|
|
index = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (index === -1) { // all the data has been loaded already.
|
|
|
|
let node = this.state.treeData.getNodeByPath(path);
|
|
|
|
this.setState({currentNode: node});
|
|
|
|
} else {
|
|
|
|
this.loadNodeAndParentsByPath(path);
|
|
|
|
}
|
|
|
|
|
2019-04-13 03:56:44 +00:00
|
|
|
// load mainPanel
|
|
|
|
if (item.is_dir) {
|
|
|
|
this.showDir(path);
|
|
|
|
} else {
|
|
|
|
if (Utils.isMarkdownFile(path)) {
|
|
|
|
this.showFile(path);
|
|
|
|
} else {
|
|
|
|
let url = siteRoot + 'lib/' + item.repo_id + '/file' + Utils.encodePath(path);
|
|
|
|
let newWindow = window.open('about:blank');
|
|
|
|
newWindow.location.href = url;
|
|
|
|
}
|
|
|
|
}
|
2019-02-20 03:54:25 +00:00
|
|
|
} else {
|
2019-04-13 03:56:44 +00:00
|
|
|
if (item.is_dir) {
|
|
|
|
this.showDir(path);
|
2019-02-20 03:54:25 +00:00
|
|
|
} else {
|
|
|
|
let url = siteRoot + 'lib/' + item.repo_id + '/file' + Utils.encodePath(path);
|
|
|
|
let newWindow = window.open('about:blank');
|
|
|
|
newWindow.location.href = url;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onMainNavBarClick = (nodePath) => {
|
|
|
|
//just for dir
|
|
|
|
this.resetSelected();
|
|
|
|
if (this.state.currentMode === 'column') {
|
|
|
|
let tree = this.state.treeData.clone();
|
|
|
|
let node = tree.getNodeByPath(nodePath);
|
|
|
|
tree.expandNode(node);
|
|
|
|
this.setState({treeData: tree, currentNode: node});
|
|
|
|
}
|
|
|
|
|
|
|
|
this.showDir(nodePath);
|
|
|
|
}
|
|
|
|
|
|
|
|
onLinkClick = (link) => {
|
|
|
|
const url = link;
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
if (Utils.isInternalMarkdownLink(url, repoID)) {
|
|
|
|
let path = Utils.getPathFromInternalMarkdownLink(url, repoID);
|
|
|
|
this.showFile(path);
|
|
|
|
} else if (Utils.isInternalDirLink(url, repoID)) {
|
|
|
|
let path = Utils.getPathFromInternalDirLink(url, repoID);
|
|
|
|
this.showDir(path);
|
|
|
|
} else {
|
|
|
|
window.open(url);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// list&tree operations
|
|
|
|
onMainPanelItemRename = (dirent, newName) => {
|
|
|
|
let path = Utils.joinPath(this.state.path, dirent.name);
|
|
|
|
this.renameItem(path, dirent.isDir(), newName);
|
|
|
|
}
|
|
|
|
|
|
|
|
onMainPanelItemDelete = (dirent) => {
|
|
|
|
let path = Utils.joinPath(this.state.path, dirent.name);
|
|
|
|
this.deleteItem(path, dirent.isDir());
|
|
|
|
}
|
|
|
|
|
|
|
|
onRenameTreeNode = (node, newName) => {
|
|
|
|
this.renameItem(node.path, node.object.isDir(), newName);
|
|
|
|
}
|
|
|
|
|
|
|
|
onDeleteTreeNode = (node) => {
|
|
|
|
this.deleteItem(node.path, node.object.isDir());
|
|
|
|
}
|
|
|
|
|
|
|
|
renameItem = (path, isDir, newName) => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
if (isDir) {
|
|
|
|
seafileAPI.renameDir(repoID, path, newName).then(() => {
|
|
|
|
this.renameItemAjaxCallback(path, newName);
|
|
|
|
}).catch(() => {
|
|
|
|
// todo
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
seafileAPI.renameFile(repoID, path, newName).then(() => {
|
|
|
|
this.renameItemAjaxCallback(path, newName);
|
|
|
|
}).catch(() => {
|
|
|
|
// todo
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
renameItemAjaxCallback(path, newName) {
|
|
|
|
if (this.state.currentMode === 'column') {
|
|
|
|
this.renameTreeNode(path, newName);
|
|
|
|
}
|
|
|
|
this.renameDirent(path, newName);
|
|
|
|
}
|
|
|
|
|
|
|
|
deleteItem(path, isDir) {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
if (isDir) {
|
|
|
|
seafileAPI.deleteDir(repoID, path).then(() => {
|
|
|
|
this.deleteItemAjaxCallback(path, isDir);
|
|
|
|
}).catch(() => {
|
|
|
|
// todo
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
seafileAPI.deleteFile(repoID, path).then(() => {
|
|
|
|
this.deleteItemAjaxCallback(path, isDir);
|
|
|
|
}).catch(() => {
|
|
|
|
// todo
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
deleteItemAjaxCallback(path) {
|
|
|
|
if (this.state.currentMode === 'column') {
|
|
|
|
this.deleteTreeNode(path);
|
|
|
|
}
|
|
|
|
this.deleteDirent(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
// list operations
|
2019-03-20 03:04:36 +00:00
|
|
|
onMoveItem = (destRepo, dirent, moveToDirentPath, nodeParentPath) => {
|
2019-02-20 03:54:25 +00:00
|
|
|
let repoID = this.props.repoID;
|
|
|
|
//just for view list state
|
|
|
|
let dirName = dirent.name;
|
2019-03-20 03:04:36 +00:00
|
|
|
if (!nodeParentPath) {
|
|
|
|
nodeParentPath = this.state.path;
|
|
|
|
}
|
|
|
|
let direntPath = Utils.joinPath(nodeParentPath, dirName);
|
|
|
|
seafileAPI.moveDir(repoID, destRepo.repo_id,moveToDirentPath, nodeParentPath, dirName).then(res => {
|
2019-02-20 03:54:25 +00:00
|
|
|
let nodeName = res.data[0].obj_name;
|
|
|
|
if (this.state.currentMode === 'column') {
|
|
|
|
this.moveTreeNode(direntPath, moveToDirentPath, destRepo, nodeName);
|
|
|
|
}
|
|
|
|
this.moveDirent(direntPath);
|
|
|
|
|
|
|
|
let message = gettext('Successfully moved %(name)s.');
|
|
|
|
message = message.replace('%(name)s', dirName);
|
|
|
|
toaster.success(message);
|
|
|
|
}).catch(() => {
|
|
|
|
let message = gettext('Failed to move %(name)s');
|
|
|
|
message = message.replace('%(name)s', dirName);
|
|
|
|
toaster.danger(message);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-03-20 03:04:36 +00:00
|
|
|
onCopyItem = (destRepo, dirent, copyToDirentPath, nodeParentPath) => {
|
2019-02-20 03:54:25 +00:00
|
|
|
let repoID = this.props.repoID;
|
|
|
|
//just for view list state
|
|
|
|
let dirName = dirent.name;
|
2019-03-20 03:04:36 +00:00
|
|
|
if (!nodeParentPath) {
|
|
|
|
nodeParentPath = this.state.path;
|
|
|
|
}
|
|
|
|
let direntPath = Utils.joinPath(nodeParentPath, dirName);
|
|
|
|
seafileAPI.copyDir(repoID, destRepo.repo_id, copyToDirentPath, nodeParentPath, dirName).then(res => {
|
2019-02-20 03:54:25 +00:00
|
|
|
let nodeName = res.data[0].obj_name;
|
|
|
|
if (this.state.currentMode === 'column') {
|
|
|
|
this.copyTreeNode(direntPath, copyToDirentPath, destRepo, nodeName);
|
|
|
|
}
|
|
|
|
let message = gettext('Successfully copied %(name)s.');
|
|
|
|
message = message.replace('%(name)s', dirName);
|
|
|
|
toaster.success(message);
|
|
|
|
}).catch(() => {
|
|
|
|
let message = gettext('Failed to copy %(name)s');
|
|
|
|
message = message.replace('%(name)s', dirName);
|
|
|
|
toaster.danger(message);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onDirentClick = (dirent) => {
|
2019-04-12 12:21:54 +00:00
|
|
|
let direntList = this.state.direntList.map(dirent => {
|
|
|
|
dirent.isSelected = false;
|
|
|
|
return dirent;
|
|
|
|
});
|
2019-04-13 01:57:44 +00:00
|
|
|
if (dirent) {
|
2019-04-13 02:45:11 +00:00
|
|
|
// dirent.isSelected = true;
|
2019-04-13 01:57:44 +00:00
|
|
|
this.setState({
|
|
|
|
direntList: direntList,
|
|
|
|
isDirentSelected: true,
|
|
|
|
selectedDirentList: [dirent],
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.setState({
|
|
|
|
direntList: direntList,
|
|
|
|
isDirentSelected: false,
|
|
|
|
selectedDirentList: [],
|
|
|
|
});
|
|
|
|
}
|
2019-04-12 12:21:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
onItemClick = (dirent) => {
|
2019-02-20 03:54:25 +00:00
|
|
|
this.resetSelected();
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
let direntPath = Utils.joinPath(this.state.path, dirent.name);
|
|
|
|
if (dirent.isDir()) { // is dir
|
|
|
|
if (this.state.currentMode === 'column') {
|
|
|
|
this.loadTreeNodeByPath(direntPath);
|
|
|
|
}
|
|
|
|
this.showDir(direntPath);
|
|
|
|
} else { // is file
|
|
|
|
if (this.state.currentMode === 'column' && Utils.isMarkdownFile(direntPath)) {
|
|
|
|
this.showFile(direntPath);
|
|
|
|
} else {
|
|
|
|
const w=window.open('about:blank');
|
|
|
|
const url = siteRoot + 'lib/' + repoID + '/file' + Utils.encodePath(direntPath);
|
|
|
|
w.location.href = url;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onDirentSelected = (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: []
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onAllDirentSelected = () => {
|
|
|
|
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.props.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);
|
|
|
|
});
|
|
|
|
|
|
|
|
this.updateUsedRepoTags();
|
|
|
|
}
|
|
|
|
|
|
|
|
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 (this.state.currentMode === 'column') {
|
|
|
|
this.addNodeToTree(dirent.name, this.state.path, dirent.type);
|
|
|
|
}
|
|
|
|
if (direntObject.type === 'dir') {
|
|
|
|
this.setState({direntList: [dirent, ...this.state.direntList]});
|
|
|
|
} else {
|
|
|
|
this.setState({direntList: [...this.state.direntList, dirent]});
|
|
|
|
this.updateReadmeMarkdown(this.state.direntList);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
addDirent = (name, type, size) => {
|
|
|
|
let item = this.createDirent(name, type, size);
|
|
|
|
let direntList = this.state.direntList;
|
|
|
|
if (type === 'dir') {
|
|
|
|
direntList.unshift(item);
|
|
|
|
} else {
|
|
|
|
// there will be there conditions;
|
|
|
|
// first: direntList.length === 0;
|
|
|
|
// second: all the direntList's items are dir;
|
|
|
|
// third: direntList has dir and file;
|
|
|
|
let length = direntList.length;
|
|
|
|
if (length === 0 || direntList[length - 1].type === 'dir') {
|
|
|
|
direntList.push(item);
|
|
|
|
} else {
|
|
|
|
let index = 0;
|
|
|
|
for (let i = 0; i <= length; i++) {
|
|
|
|
if (direntList[i].type === 'file') {
|
|
|
|
index = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
direntList.splice(index, 0, item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.setState({direntList: direntList});
|
|
|
|
this.updateReadmeMarkdown(direntList);
|
|
|
|
}
|
|
|
|
|
|
|
|
renameDirent = (direntPath, newName) => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
let parentPath = Utils.getDirName(direntPath);
|
|
|
|
let newDirentPath = Utils.joinPath(parentPath, newName);
|
|
|
|
if (direntPath === this.state.path) {
|
|
|
|
// the renamed item is current viewed item
|
|
|
|
// example: direntPath = /A/B/C, state.path = /A/B/C
|
|
|
|
|
|
|
|
this.setState({ path: newDirentPath });
|
2019-03-05 05:36:31 +00:00
|
|
|
let repoInfo = this.state.currentRepoInfo;
|
|
|
|
let url = siteRoot + 'library/' + repoID + '/' + encodeURIComponent(repoInfo.repo_name) + newDirentPath;
|
2019-02-20 03:54:25 +00:00
|
|
|
window.history.replaceState({ url: url, path: newDirentPath}, newDirentPath, url);
|
|
|
|
} else if (Utils.isChildPath(direntPath, this.state.path)) {
|
|
|
|
// example: direntPath = /A/B/C/D, state.path = /A/B/C
|
|
|
|
let oldName = Utils.getFileName(direntPath);
|
|
|
|
let direntList = this.state.direntList.map(item => {
|
|
|
|
if (item.name === oldName) {
|
|
|
|
item.name = newName;
|
|
|
|
}
|
|
|
|
return item;
|
|
|
|
});
|
|
|
|
this.setState({ direntList: direntList });
|
|
|
|
this.updateReadmeMarkdown(direntList);
|
|
|
|
} else if (Utils.isAncestorPath(direntPath, this.state.path)) {
|
|
|
|
// example: direntPath = /A/B, state.path = /A/B/C
|
|
|
|
let newPath = Utils.renameAncestorPath(this.state.path, direntPath, newDirentPath);
|
|
|
|
this.setState({ path: newPath });
|
|
|
|
|
2019-03-05 05:36:31 +00:00
|
|
|
let repoInfo = this.state.currentRepoInfo;
|
|
|
|
let url = siteRoot + 'library/' + repoID + '/' + encodeURIComponent(repoInfo.repo_name) + newPath;
|
2019-02-20 03:54:25 +00:00
|
|
|
window.history.replaceState({ url: url, path: newPath}, newPath, url);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
deleteDirent(direntPath) {
|
|
|
|
if (direntPath === this.state.path) {
|
|
|
|
// The deleted item is current item
|
|
|
|
let parentPath = Utils.getDirName(direntPath);
|
|
|
|
this.showDir(parentPath);
|
|
|
|
} else if (Utils.isChildPath(direntPath, this.state.path)) {
|
|
|
|
// The deleted item is inside current path
|
|
|
|
let name = Utils.getFileName(direntPath);
|
|
|
|
let direntList = this.state.direntList.filter(item => {
|
|
|
|
return item.name !== name;
|
|
|
|
});
|
|
|
|
this.setState({ direntList: direntList });
|
|
|
|
this.updateReadmeMarkdown(direntList);
|
|
|
|
} else if (Utils.isAncestorPath(direntPath, this.state.path)) {
|
|
|
|
// the deleted item is ancester of the current item
|
|
|
|
let parentPath = Utils.getDirName(direntPath);
|
|
|
|
this.showDir(parentPath);
|
|
|
|
}
|
|
|
|
// else do nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
moveDirent = (direntPath) => {
|
|
|
|
let name = direntPath.slice(direntPath.lastIndexOf('/') + 1);
|
|
|
|
let direntList = this.state.direntList.filter(item => {
|
|
|
|
return item.name !== name;
|
|
|
|
});
|
|
|
|
this.setState({direntList: direntList});
|
|
|
|
this.updateReadmeMarkdown(direntList);
|
|
|
|
}
|
|
|
|
|
|
|
|
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});
|
|
|
|
}
|
|
|
|
|
|
|
|
// tree operations
|
|
|
|
loadTreeNodeByPath = (path) => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
let tree = this.state.treeData.clone();
|
|
|
|
let node = tree.getNodeByPath(path);
|
|
|
|
if (!node.isLoaded) {
|
|
|
|
seafileAPI.listDir(repoID, node.path).then(res => {
|
|
|
|
this.addResponseListToNode(res.data.dirent_list, node);
|
|
|
|
let parentNode = tree.getNodeByPath(node.parentNode.path);
|
|
|
|
parentNode.isExpanded = true;
|
|
|
|
this.setState({
|
|
|
|
treeData: tree,
|
|
|
|
currentNode: node
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
let parentNode = tree.getNodeByPath(node.parentNode.path);
|
|
|
|
parentNode.isExpanded = true;
|
|
|
|
this.setState({treeData: tree, currentNode: node}); //tree
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
loadNodeAndParentsByPath = (path) => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
let tree = this.state.treeData.clone();
|
|
|
|
if (Utils.isMarkdownFile(path)) {
|
|
|
|
path = Utils.getDirName(path);
|
|
|
|
}
|
|
|
|
seafileAPI.listDir(repoID, path, {with_parents: true}).then(res => {
|
|
|
|
let direntList = res.data.dirent_list;
|
|
|
|
let results = {};
|
|
|
|
for (let i = 0; i < direntList.length; i++) {
|
|
|
|
let object = direntList[i];
|
2019-04-17 02:48:44 +00:00
|
|
|
let parentDir = object.parent_dir;
|
|
|
|
let key = parentDir === '/' ? '/' : parentDir.slice(0, parentDir.length - 1);
|
2019-02-20 03:54:25 +00:00
|
|
|
if (!results[key]) {
|
|
|
|
results[key] = [];
|
|
|
|
}
|
|
|
|
results[key].push(object);
|
|
|
|
}
|
|
|
|
for (let key in results) {
|
|
|
|
let node = tree.getNodeByPath(key);
|
|
|
|
if (!node.isLoaded) {
|
|
|
|
this.addResponseListToNode(results[key], node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.setState({
|
|
|
|
isTreeDataLoading: false,
|
|
|
|
treeData: tree
|
|
|
|
});
|
|
|
|
}).catch(() => {
|
|
|
|
this.setState({isLoadFailed: true});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onTreeNodeClick = (node) => {
|
|
|
|
this.resetSelected();
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
if (!this.state.pathExist) {
|
|
|
|
this.setState({pathExist: true});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node.object.isDir()) {
|
2019-02-21 09:37:04 +00:00
|
|
|
let isLoaded = node.isLoaded;
|
2019-02-20 03:54:25 +00:00
|
|
|
if (!node.isLoaded) {
|
|
|
|
let tree = this.state.treeData.clone();
|
|
|
|
node = tree.getNodeByPath(node.path);
|
|
|
|
seafileAPI.listDir(repoID, node.path).then(res => {
|
|
|
|
this.addResponseListToNode(res.data.dirent_list, node);
|
|
|
|
tree.collapseNode(node);
|
|
|
|
this.setState({treeData: tree});
|
|
|
|
});
|
|
|
|
}
|
2019-02-21 09:37:04 +00:00
|
|
|
if (isLoaded && node.path === this.state.path) {
|
2019-02-20 03:54:25 +00:00
|
|
|
if (node.isExpanded) {
|
|
|
|
let tree = treeHelper.collapseNode(this.state.treeData, node);
|
|
|
|
this.setState({treeData: tree});
|
|
|
|
} else {
|
|
|
|
let tree = this.state.treeData.clone();
|
|
|
|
node = tree.getNodeByPath(node.path);
|
|
|
|
tree.expandNode(node);
|
|
|
|
this.setState({treeData: tree});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node.path === this.state.path ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node.object.isDir()) { // isDir
|
|
|
|
this.showDir(node.path);
|
|
|
|
} else {
|
|
|
|
if (Utils.isMarkdownFile(node.path)) {
|
|
|
|
if (node.path !== this.state.path) {
|
|
|
|
this.showFile(node.path);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const w = window.open('about:blank');
|
|
|
|
const url = siteRoot + 'lib/' + repoID + '/file' + Utils.encodePath(node.path);
|
|
|
|
w.location.href = url;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onTreeNodeCollapse = (node) => {
|
|
|
|
let tree = treeHelper.collapseNode(this.state.treeData, node);
|
|
|
|
this.setState({treeData: tree});
|
|
|
|
}
|
|
|
|
|
|
|
|
onTreeNodeExpanded = (node) => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
let tree = this.state.treeData.clone();
|
|
|
|
node = tree.getNodeByPath(node.path);
|
|
|
|
if (!node.isLoaded) {
|
|
|
|
seafileAPI.listDir(repoID, node.path).then(res => {
|
|
|
|
this.addResponseListToNode(res.data.dirent_list, node);
|
|
|
|
this.setState({treeData: tree});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
tree.expandNode(node);
|
|
|
|
this.setState({treeData: tree});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
addNodeToTree = (name, parentPath, type) => {
|
|
|
|
let node = this.createTreeNode(name, type);
|
|
|
|
let tree = treeHelper.addNodeToParentByPath(this.state.treeData, node, parentPath);
|
|
|
|
this.setState({treeData: tree});
|
|
|
|
}
|
|
|
|
|
|
|
|
renameTreeNode = (path, newName) => {
|
|
|
|
let tree = treeHelper.renameNodeByPath(this.state.treeData, path, newName);
|
|
|
|
this.setState({treeData: tree});
|
|
|
|
}
|
|
|
|
|
|
|
|
deleteTreeNode = (path) => {
|
|
|
|
let tree = treeHelper.deleteNodeByPath(this.state.treeData, path);
|
|
|
|
this.setState({treeData: tree});
|
|
|
|
}
|
|
|
|
|
|
|
|
moveTreeNode = (nodePath, moveToPath, moveToRepo, nodeName) => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
if (repoID !== moveToRepo.repo_id) {
|
|
|
|
let tree = treeHelper.deleteNodeByPath(this.state.treeData, nodePath);
|
|
|
|
this.setState({treeData: tree});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let tree = treeHelper.moveNodeByPath(this.state.treeData, nodePath, moveToPath, nodeName);
|
|
|
|
this.setState({treeData: tree});
|
|
|
|
}
|
|
|
|
|
|
|
|
copyTreeNode = (nodePath, copyToPath, destRepo, nodeName) => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
if (repoID !== destRepo.repo_id) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let tree = treeHelper.copyNodeByPath(this.state.treeData, nodePath, copyToPath, nodeName);
|
|
|
|
this.setState({treeData: tree});
|
|
|
|
}
|
|
|
|
|
|
|
|
createTreeNode(name, type) {
|
|
|
|
let object = this.createDirent(name, type);
|
|
|
|
return new TreeNode({object});
|
|
|
|
}
|
|
|
|
|
|
|
|
createDirent(name, type, size) {
|
|
|
|
let mtime = new Date().getTime()/1000;
|
|
|
|
let dirent = new Dirent({name, type, mtime, size});
|
|
|
|
return dirent;
|
|
|
|
}
|
|
|
|
|
|
|
|
addResponseListToNode = (list, node) => {
|
|
|
|
node.isLoaded = true;
|
|
|
|
node.isExpanded = true;
|
|
|
|
let direntList = list.map(item => {
|
|
|
|
return new Dirent(item);
|
|
|
|
});
|
|
|
|
direntList = Utils.sortDirents(direntList, 'name', 'asc');
|
|
|
|
|
|
|
|
let nodeList = direntList.map(object => {
|
|
|
|
return new TreeNode({object});
|
|
|
|
});
|
|
|
|
node.addChildren(nodeList);
|
|
|
|
}
|
|
|
|
|
|
|
|
getSelectedDirentPaths = () => {
|
|
|
|
let paths = [];
|
|
|
|
this.state.selectedDirentList.forEach(selectedDirent => {
|
|
|
|
paths.push(Utils.joinPath(this.state.path, selectedDirent.name));
|
|
|
|
});
|
|
|
|
return paths;
|
|
|
|
}
|
|
|
|
|
|
|
|
getSelectedDirentNames = () => {
|
|
|
|
let names = [];
|
|
|
|
this.state.selectedDirentList.forEach(selectedDirent => {
|
|
|
|
names.push(selectedDirent.name);
|
|
|
|
});
|
|
|
|
return names;
|
|
|
|
}
|
|
|
|
|
|
|
|
resetSelected = () => {
|
|
|
|
this.setState({
|
|
|
|
isDirentSelected: false,
|
|
|
|
isAllDirentSelected: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onLibDecryptDialog = () => {
|
|
|
|
this.setState({libNeedDecrypt: false});
|
|
|
|
this.loadDirData(this.state.path);
|
|
|
|
}
|
|
|
|
|
|
|
|
goDraftPage = () => {
|
2019-03-05 07:37:51 +00:00
|
|
|
window.location.href = siteRoot + 'drafts/' + this.state.draftID + '/';
|
2019-02-20 03:54:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sortItems = (sortBy, sortOrder) => {
|
2019-04-12 06:30:08 +00:00
|
|
|
cookie.save('seafile-repo-dir-sort-by', sortBy);
|
|
|
|
cookie.save('seafile-repo-dir-sort-order', sortOrder);
|
2019-02-20 03:54:25 +00:00
|
|
|
this.setState({
|
|
|
|
sortBy: sortBy,
|
|
|
|
sortOrder: sortOrder,
|
|
|
|
items: Utils.sortDirents(this.state.direntList, sortBy, sortOrder)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-02-21 09:37:04 +00:00
|
|
|
onUploadFile = (e) => {
|
|
|
|
e.nativeEvent.stopImmediatePropagation();
|
|
|
|
this.uploader.onFileUpload();
|
|
|
|
}
|
|
|
|
|
|
|
|
onUploadFolder = (e) => {
|
|
|
|
e.nativeEvent.stopImmediatePropagation();
|
|
|
|
this.uploader.onFolderUpload();
|
|
|
|
}
|
|
|
|
|
2019-03-15 02:10:24 +00:00
|
|
|
onToolbarFileTagChanged = () => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
let filePath = this.state.path;
|
|
|
|
seafileAPI.listFileTags(repoID, filePath).then(res => {
|
|
|
|
let fileTags = res.data.file_tags.map(item => {
|
|
|
|
return new FileTag(item);
|
|
|
|
});
|
|
|
|
|
|
|
|
this.setState({fileTags: fileTags});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onToolbarRelatedFileChange = () => {
|
|
|
|
let repoID = this.props.repoID;
|
|
|
|
let filePath = this.state.path;
|
|
|
|
|
|
|
|
seafileAPI.listRelatedFiles(repoID, filePath).then(res => {
|
|
|
|
let relatedFiles = res.data.related_files.map((relatedFile) => {
|
|
|
|
return relatedFile;
|
|
|
|
});
|
|
|
|
this.setState({relatedFiles: relatedFiles});
|
|
|
|
}).catch((error) => {
|
|
|
|
if (error.response.status === 500) {
|
|
|
|
this.setState({relatedFiles: []});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-03-18 09:32:49 +00:00
|
|
|
unSelectDirent = () => {
|
|
|
|
this.setState({
|
|
|
|
isDirentSelected: false,
|
|
|
|
selectedDirentList: []
|
|
|
|
});
|
|
|
|
const dirent = {};
|
|
|
|
this.onDirentSelected(dirent);
|
|
|
|
}
|
|
|
|
|
2019-03-25 07:23:37 +00:00
|
|
|
onDeleteRepoTag = (deletedTagID) => {
|
|
|
|
let direntList = this.state.direntList.map(dirent => {
|
|
|
|
if (dirent.file_tags) {
|
|
|
|
let fileTags = dirent.file_tags.filter(item => {
|
|
|
|
return item.repo_tag_id !== deletedTagID;
|
|
|
|
});
|
|
|
|
dirent.file_tags = fileTags;
|
|
|
|
}
|
|
|
|
return dirent;
|
|
|
|
});
|
|
|
|
this.setState({direntList: direntList});
|
|
|
|
this.updateUsedRepoTags();
|
|
|
|
}
|
|
|
|
|
2019-02-20 03:54:25 +00:00
|
|
|
render() {
|
|
|
|
if (this.state.libNeedDecrypt) {
|
|
|
|
return (
|
|
|
|
<ModalPortal>
|
|
|
|
<LibDecryptDialog
|
|
|
|
repoID={this.props.repoID}
|
|
|
|
onLibDecryptDialog={this.onLibDecryptDialog}
|
|
|
|
/>
|
|
|
|
</ModalPortal>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-02-21 09:37:04 +00:00
|
|
|
if (!this.state.currentRepoInfo) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
2019-02-20 03:54:25 +00:00
|
|
|
let showShareBtn = false;
|
|
|
|
let enableDirPrivateShare = false;
|
2019-02-27 05:53:36 +00:00
|
|
|
let { currentRepoInfo, repoEncrypted, userPerm } = this.state;
|
|
|
|
let isAdmin = currentRepoInfo.is_admin;
|
|
|
|
let isVirtual = currentRepoInfo.is_virtual;
|
|
|
|
let isRepoOwner = currentRepoInfo.owner_email === username;
|
|
|
|
|
2019-02-20 03:54:25 +00:00
|
|
|
if (!repoEncrypted) {
|
2019-02-27 05:53:36 +00:00
|
|
|
let showGenerateShareLinkTab = false;
|
|
|
|
if (canGenerateShareLink && (userPerm == 'rw' || userPerm == 'r')) {
|
|
|
|
showGenerateShareLinkTab = true;
|
|
|
|
}
|
|
|
|
let showGenerateUploadLinkTab = false;
|
|
|
|
if (canGenerateUploadLink && (userPerm == 'rw')) {
|
|
|
|
showGenerateUploadLinkTab = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isVirtual && (isRepoOwner || isAdmin)) {
|
|
|
|
enableDirPrivateShare = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (showGenerateShareLinkTab || showGenerateUploadLinkTab || enableDirPrivateShare) {
|
2019-02-20 03:54:25 +00:00
|
|
|
showShareBtn = true;
|
|
|
|
}
|
2019-02-27 05:53:36 +00:00
|
|
|
|
2019-02-20 03:54:25 +00:00
|
|
|
}
|
|
|
|
|
2019-04-24 05:52:09 +00:00
|
|
|
let direntItemsList = this.state.direntList.filter((item, index) => {
|
|
|
|
return index < this.state.itemsShowLength;
|
|
|
|
})
|
|
|
|
|
2019-02-20 03:54:25 +00:00
|
|
|
return (
|
2019-02-21 09:37:04 +00:00
|
|
|
<div className="main-panel o-hidden">
|
|
|
|
<div className="main-panel-north border-left-show">
|
|
|
|
<LibContentToolbar
|
|
|
|
isViewFile={this.state.isViewFile}
|
|
|
|
filePermission={this.state.filePermission}
|
2019-02-20 03:54:25 +00:00
|
|
|
isDraft={this.state.isDraft}
|
|
|
|
hasDraft={this.state.hasDraft}
|
2019-03-15 02:10:24 +00:00
|
|
|
fileTags={this.state.fileTags}
|
|
|
|
relatedFiles={this.state.relatedFiles}
|
|
|
|
onFileTagChanged={this.onToolbarFileTagChanged}
|
|
|
|
onRelatedFileChange={this.onToolbarRelatedFileChange}
|
2019-02-21 09:37:04 +00:00
|
|
|
onSideNavMenuClick={this.props.onMenuClick}
|
|
|
|
repoID={this.props.repoID}
|
|
|
|
path={this.state.path}
|
|
|
|
isDirentSelected={this.state.isDirentSelected}
|
|
|
|
selectedDirentList={this.state.selectedDirentList}
|
|
|
|
onItemsMove={this.onMoveItems}
|
|
|
|
onItemsCopy={this.onCopyItems}
|
|
|
|
onItemsDelete={this.onDeleteItems}
|
|
|
|
direntList={this.state.direntList}
|
|
|
|
repoName={this.state.repoName}
|
|
|
|
repoEncrypted={this.state.repoEncrypted}
|
|
|
|
isGroupOwnedRepo={this.state.isGroupOwnedRepo}
|
|
|
|
userPerm={this.state.userPerm}
|
|
|
|
showShareBtn={showShareBtn}
|
|
|
|
enableDirPrivateShare={enableDirPrivateShare}
|
|
|
|
onAddFile={this.onAddFile}
|
|
|
|
onAddFolder={this.onAddFolder}
|
|
|
|
onUploadFile={this.onUploadFile}
|
|
|
|
onUploadFolder={this.onUploadFolder}
|
|
|
|
currentMode={this.state.currentMode}
|
|
|
|
switchViewMode={this.switchViewMode}
|
|
|
|
onSearchedClick={this.onSearchedClick}
|
2019-03-18 09:32:49 +00:00
|
|
|
isRepoOwner={isRepoOwner}
|
|
|
|
currentRepoInfo={this.state.currentRepoInfo}
|
|
|
|
updateDirent={this.updateDirent}
|
|
|
|
onDirentSelected={this.onDirentSelected}
|
|
|
|
showDirentDetail={this.showDirentDetail}
|
|
|
|
listRelatedFiles={this.listRelatedFiles}
|
|
|
|
unSelectDirent={this.unSelectDirent}
|
|
|
|
onFilesTagChanged={this.onFileTagChanged}
|
2019-02-20 03:54:25 +00:00
|
|
|
/>
|
2019-02-21 09:37:04 +00:00
|
|
|
</div>
|
|
|
|
<div className="main-panel-center flex-row">
|
|
|
|
<LibContentContainer
|
2019-02-20 03:54:25 +00:00
|
|
|
pathPrefix={this.props.pathPrefix}
|
|
|
|
currentMode={this.state.currentMode}
|
|
|
|
path={this.state.path}
|
|
|
|
pathExist={this.state.pathExist}
|
|
|
|
currentRepoInfo={this.state.currentRepoInfo}
|
|
|
|
repoID={this.props.repoID}
|
|
|
|
repoPermission={this.state.repoPermission}
|
|
|
|
enableDirPrivateShare={enableDirPrivateShare}
|
|
|
|
userPerm={userPerm}
|
|
|
|
isGroupOwnedRepo={this.state.isGroupOwnedRepo}
|
|
|
|
onTabNavClick={this.props.onTabNavClick}
|
|
|
|
onMainNavBarClick={this.onMainNavBarClick}
|
2019-02-21 09:37:04 +00:00
|
|
|
isViewFile={this.state.isViewFile}
|
|
|
|
hash={this.state.hash}
|
|
|
|
isDraft={this.state.isDraft}
|
|
|
|
hasDraft={this.state.hasDraft}
|
2019-03-15 02:10:24 +00:00
|
|
|
fileTags={this.state.fileTags}
|
|
|
|
relatedFiles={this.state.relatedFiles}
|
2019-02-21 09:37:04 +00:00
|
|
|
goDraftPage={this.goDraftPage}
|
|
|
|
isFileLoading={this.state.isFileLoading}
|
|
|
|
isFileLoadedErr={this.state.isFileLoadedErr}
|
|
|
|
filePermission={this.state.filePermission}
|
|
|
|
content={this.state.content}
|
|
|
|
lastModified={this.state.lastModified}
|
|
|
|
latestContributor={this.state.latestContributor}
|
|
|
|
onLinkClick={this.onLinkClick}
|
|
|
|
isTreeDataLoading={this.state.isTreeDataLoading}
|
|
|
|
treeData={this.state.treeData}
|
|
|
|
currentNode={this.state.currentNode}
|
|
|
|
onNodeClick={this.onTreeNodeClick}
|
|
|
|
onNodeCollapse={this.onTreeNodeCollapse}
|
|
|
|
onNodeExpanded={this.onTreeNodeExpanded}
|
|
|
|
onAddFolderNode={this.onAddFolder}
|
|
|
|
onAddFileNode={this.onAddFile}
|
|
|
|
onRenameNode={this.onRenameTreeNode}
|
|
|
|
onDeleteNode={this.onDeleteTreeNode}
|
2019-02-20 03:54:25 +00:00
|
|
|
draftCounts={this.state.draftCounts}
|
|
|
|
usedRepoTags={this.state.usedRepoTags}
|
|
|
|
readmeMarkdown={this.state.readmeMarkdown}
|
|
|
|
updateUsedRepoTags={this.updateUsedRepoTags}
|
|
|
|
isDirentListLoading={this.state.isDirentListLoading}
|
2019-04-24 05:52:09 +00:00
|
|
|
direntList={direntItemsList}
|
2019-04-11 13:04:47 +00:00
|
|
|
showShareBtn={showShareBtn}
|
2019-02-20 03:54:25 +00:00
|
|
|
sortBy={this.state.sortBy}
|
|
|
|
sortOrder={this.state.sortOrder}
|
|
|
|
sortItems={this.sortItems}
|
|
|
|
updateDirent={this.updateDirent}
|
2019-04-12 12:21:54 +00:00
|
|
|
onDirentClick={this.onDirentClick}
|
|
|
|
onItemClick={this.onItemClick}
|
2019-02-20 03:54:25 +00:00
|
|
|
onItemSelected={this.onDirentSelected}
|
|
|
|
onItemDelete={this.onMainPanelItemDelete}
|
|
|
|
onItemRename={this.onMainPanelItemRename}
|
|
|
|
onItemMove={this.onMoveItem}
|
|
|
|
onItemCopy={this.onCopyItem}
|
|
|
|
onAddFolder={this.onAddFolder}
|
|
|
|
onAddFile={this.onAddFile}
|
|
|
|
onFileTagChanged={this.onFileTagChanged}
|
|
|
|
isDirentSelected={this.state.isDirentSelected}
|
|
|
|
isAllDirentSelected={this.state.isAllDirentSelected}
|
|
|
|
onAllDirentSelected={this.onAllDirentSelected}
|
2019-03-18 09:32:49 +00:00
|
|
|
isDirentDetailShow={this.state.isDirentDetailShow}
|
|
|
|
selectedDirent={this.state.selectedDirentList && this.state.selectedDirentList[0]}
|
2019-04-11 13:04:47 +00:00
|
|
|
selectedDirentList={this.state.selectedDirentList}
|
|
|
|
onItemsMove={this.onMoveItems}
|
|
|
|
onItemsCopy={this.onCopyItems}
|
|
|
|
onItemsDelete={this.onDeleteItems}
|
2019-03-19 10:20:45 +00:00
|
|
|
closeDirentDetail={this.closeDirentDetail}
|
|
|
|
showDirentDetail={this.showDirentDetail}
|
2019-03-25 07:23:37 +00:00
|
|
|
onDeleteRepoTag={this.onDeleteRepoTag}
|
2019-04-17 02:48:44 +00:00
|
|
|
onToolbarFileTagChanged={this.onToolbarFileTagChanged}
|
2019-04-18 05:39:42 +00:00
|
|
|
updateDetail={this.state.updateDetail}
|
2019-04-23 08:50:17 +00:00
|
|
|
onPageScroll={this.onPageScroll}
|
2019-02-20 03:54:25 +00:00
|
|
|
/>
|
2019-02-21 09:37:04 +00:00
|
|
|
{this.state.pathExist && !this.state.isViewFile && (
|
|
|
|
<FileUploader
|
|
|
|
ref={uploader => this.uploader = uploader}
|
|
|
|
dragAndDrop={true}
|
|
|
|
path={this.state.path}
|
|
|
|
repoID={this.props.repoID}
|
|
|
|
direntList={this.state.direntList}
|
|
|
|
onFileUploadSuccess={this.onFileUploadSuccess}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</div>
|
2019-02-20 03:54:25 +00:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LibContentView.propTypes = propTypes;
|
|
|
|
|
2019-02-21 09:37:04 +00:00
|
|
|
export default LibContentView;
|