mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-01 15:09:14 +00:00
Merge branch '7.0'
This commit is contained in:
@@ -64,11 +64,6 @@ module.exports = {
|
||||
require.resolve('react-dev-utils/webpackHotDevClient'),
|
||||
paths.appSrc + "/wiki.js",
|
||||
],
|
||||
repoview: [
|
||||
require.resolve('./polyfills'),
|
||||
require.resolve('react-dev-utils/webpackHotDevClient'),
|
||||
paths.appSrc + "/repo-wiki-mode.js",
|
||||
],
|
||||
fileHistory: [
|
||||
require.resolve('./polyfills'),
|
||||
require.resolve('react-dev-utils/webpackHotDevClient'),
|
||||
|
@@ -61,7 +61,6 @@ module.exports = {
|
||||
markdownEditor: [require.resolve('./polyfills'), paths.appIndexJs],
|
||||
TCAccept: [require.resolve('./polyfills'), paths.appSrc + "/tc-accept.js"],
|
||||
wiki: [require.resolve('./polyfills'), paths.appSrc + "/wiki.js"],
|
||||
repoview: [require.resolve('./polyfills'), paths.appSrc + "/repo-wiki-mode.js"],
|
||||
fileHistory: [require.resolve('./polyfills'), paths.appSrc + "/file-history.js"],
|
||||
fileHistoryOld: [require.resolve('./polyfills'), paths.appSrc + "/file-history-old.js"],
|
||||
app: [require.resolve('./polyfills'), paths.appSrc + "/app.js"],
|
||||
|
@@ -494,13 +494,10 @@ class DirentListItem extends React.Component {
|
||||
}
|
||||
|
||||
renderItemOperation = () => {
|
||||
let { dirent, selectedDirentList } = this.props;
|
||||
let { dirent, currentRepoInfo, selectedDirentList } = this.props;
|
||||
|
||||
// no need to check whether show shareBtn or not.
|
||||
// according to specification below, shareBtn aways show.
|
||||
// check for "generate uploadlink" or other tabs should put inside the shareDialog.
|
||||
// https://dev.seafile.com/seahub/lib/d6f300e7-bb2b-4722-b83e-cf45e370bfbc/file/seaf-server%20%E5%8A%9F%E8%83%BD%E8%AE%BE%E8%AE%A1/%E6%9D%83%E9%99%90%E7%9B%B8%E5%85%B3/%E8%B5%84%E6%96%99%E5%BA%93%E6%9D%83%E9%99%90%E8%A7%84%E8%8C%83.md
|
||||
// let showShareBtn = Utils.isHasPermissionToShare(currentRepoInfo, dirent.permission, dirent);
|
||||
let showShareBtn = Utils.isHasPermissionToShare(currentRepoInfo, dirent.permission, dirent);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
@@ -514,9 +511,11 @@ class DirentListItem extends React.Component {
|
||||
<i className="op-icon sf2-icon-download" title={gettext('Download')} onClick={this.onItemDownload}></i>
|
||||
</li>
|
||||
)}
|
||||
<li className="operation-group-item">
|
||||
<i className="op-icon sf2-icon-share" title={gettext('Share')} onClick={this.onItemShare}></i>
|
||||
</li>
|
||||
{showShareBtn && (
|
||||
<li className="operation-group-item">
|
||||
<i className="op-icon sf2-icon-share" title={gettext('Share')} onClick={this.onItemShare}></i>
|
||||
</li>
|
||||
)}
|
||||
{dirent.permission === 'rw' && (
|
||||
<li className="operation-group-item">
|
||||
<i className="op-icon sf2-icon-delete" title={gettext('Delete')} onClick={this.onItemDelete}></i>
|
||||
@@ -546,7 +545,7 @@ class DirentListItem extends React.Component {
|
||||
<i className="op-icon sf2-icon-download" title={gettext('Download')} onClick={this.onItemDownload}></i>
|
||||
</li>
|
||||
)}
|
||||
{(
|
||||
{showShareBtn && (
|
||||
<li className="operation-group-item">
|
||||
<i className="op-icon sf2-icon-share" title={gettext('Share')} onClick={this.onItemShare}></i>
|
||||
</li>
|
||||
|
@@ -2,7 +2,7 @@ import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Resumablejs from '@seafile/resumablejs';
|
||||
import MD5 from 'MD5';
|
||||
import { enableResumableFileUpload, resumableUploadFileBlockSize } from '../../utils/constants';
|
||||
import { enableResumableFileUpload, resumableUploadFileBlockSize, maxUploadFileSize } from '../../utils/constants';
|
||||
import { seafileAPI } from '../../utils/seafile-api';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import { gettext } from '../../utils/constants';
|
||||
@@ -18,13 +18,11 @@ const propTypes = {
|
||||
chunkSize: PropTypes.number,
|
||||
withCredentials: PropTypes.bool,
|
||||
maxFiles: PropTypes.number,
|
||||
maxFileSize: PropTypes.number,
|
||||
testMethod: PropTypes.string,
|
||||
testChunks: PropTypes.number,
|
||||
simultaneousUploads: PropTypes.number,
|
||||
fileParameterName: PropTypes.string,
|
||||
maxFilesErrorCallback: PropTypes.func,
|
||||
maxFileSizeErrorCallback: PropTypes.func,
|
||||
minFileSizeErrorCallback: PropTypes.func,
|
||||
fileTypeErrorCallback: PropTypes.func,
|
||||
dragAndDrop: PropTypes.bool.isRequired,
|
||||
@@ -39,6 +37,7 @@ class FileUploader extends React.Component {
|
||||
this.state = {
|
||||
retryFileList: [],
|
||||
uploadFileList: [],
|
||||
forbidUploadFileList: [],
|
||||
totalProgress: 0,
|
||||
isUploadProgressDialogShow: false,
|
||||
isUploadRemindDialogShow: false,
|
||||
@@ -64,7 +63,7 @@ class FileUploader extends React.Component {
|
||||
query: this.setQuery || {},
|
||||
fileType: this.props.filetypes,
|
||||
maxFiles: this.props.maxFiles,
|
||||
maxFileSize: this.props.maxFileSize,
|
||||
maxFileSize: maxUploadFileSize * 1000 * 1000 || undefined,
|
||||
testMethod: this.props.testMethod || 'post',
|
||||
testChunks: this.props.testChunks || false,
|
||||
headers: this.setHeaders || {},
|
||||
@@ -105,7 +104,7 @@ class FileUploader extends React.Component {
|
||||
}
|
||||
|
||||
bindCallbackHandler = () => {
|
||||
let {maxFilesErrorCallback, minFileSizeErrorCallback, maxFileSizeErrorCallback, fileTypeErrorCallback } = this.props;
|
||||
let {maxFilesErrorCallback, minFileSizeErrorCallback, fileTypeErrorCallback } = this.props;
|
||||
|
||||
if (maxFilesErrorCallback) {
|
||||
this.resumable.opts.maxFilesErrorCallback = this.props.maxFilesErrorCallback;
|
||||
@@ -115,8 +114,8 @@ class FileUploader extends React.Component {
|
||||
this.resumable.opts.minFileSizeErrorCallback = this.props.minFileSizeErrorCallback;
|
||||
}
|
||||
|
||||
if (maxFileSizeErrorCallback) {
|
||||
this.resumable.opts.maxFileSizeErrorCallback = this.props.maxFileSizeErrorCallback;
|
||||
if (this.maxFileSizeErrorCallback) {
|
||||
this.resumable.opts.maxFileSizeErrorCallback = this.maxFileSizeErrorCallback;
|
||||
}
|
||||
|
||||
if (fileTypeErrorCallback) {
|
||||
@@ -142,6 +141,12 @@ class FileUploader extends React.Component {
|
||||
this.resumable.on('dragstart', this.onDragStart.bind(this));
|
||||
}
|
||||
|
||||
maxFileSizeErrorCallback = (file) => {
|
||||
let { forbidUploadFileList } = this.state;
|
||||
forbidUploadFileList.push(file);
|
||||
this.setState({forbidUploadFileList: forbidUploadFileList});
|
||||
}
|
||||
|
||||
onChunkingComplete = (resumableFile) => {
|
||||
|
||||
let allFilesUploaded = this.state.allFilesUploaded;
|
||||
@@ -229,7 +234,13 @@ class FileUploader extends React.Component {
|
||||
}
|
||||
|
||||
filesAddedComplete = (resumable, files) => {
|
||||
// single file uploading can check repetition, because custom dialog conn't prevent program execution;
|
||||
let { forbidUploadFileList } = this.state;
|
||||
if (forbidUploadFileList.length > 0 && files.length === 0) {
|
||||
this.setState({
|
||||
isUploadProgressDialogShow: true,
|
||||
totalProgress: 100
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setUploadFileList = () => {
|
||||
@@ -377,7 +388,16 @@ class FileUploader extends React.Component {
|
||||
if (!message) {
|
||||
error = gettext('Network error');
|
||||
} else {
|
||||
error = message;
|
||||
// eg: '{"error": "Internal error" \n }'
|
||||
let errorMessage = message.replace(/\n/g, '');
|
||||
errorMessage = JSON.parse(errorMessage);
|
||||
error = errorMessage.error;
|
||||
if (error === 'File locked by others.') {
|
||||
error = gettext('File Locked by others.');
|
||||
}
|
||||
if (error === 'Internal error.') {
|
||||
error = gettext('Internal error.');
|
||||
}
|
||||
}
|
||||
|
||||
let uploadFileList = this.state.uploadFileList.map(item => {
|
||||
@@ -481,7 +501,7 @@ class FileUploader extends React.Component {
|
||||
this.resumable.files = [];
|
||||
// reset upload link loaded
|
||||
this.isUploadLinkLoaded = false;
|
||||
this.setState({isUploadProgressDialogShow: false, uploadFileList: []});
|
||||
this.setState({isUploadProgressDialogShow: false, uploadFileList: [], forbidUploadFileList: []});
|
||||
Utils.registerGlobalVariable('uploader', 'isUploadProgressDialogShow', false);
|
||||
}
|
||||
|
||||
@@ -667,6 +687,7 @@ class FileUploader extends React.Component {
|
||||
<UploadProgressDialog
|
||||
retryFileList={this.state.retryFileList}
|
||||
uploadFileList={this.state.uploadFileList}
|
||||
forbidUploadFileList={this.state.forbidUploadFileList}
|
||||
totalProgress={this.state.totalProgress}
|
||||
uploadBitrate={this.state.uploadBitrate}
|
||||
allFilesUploaded={this.state.allFilesUploaded}
|
||||
|
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { gettext, maxUploadFileSize } from '../../utils/constants';
|
||||
|
||||
const propTypes = {
|
||||
file: PropTypes.object,
|
||||
};
|
||||
|
||||
class ForbidUploadListItem extends React.Component {
|
||||
|
||||
render() {
|
||||
let { file } = this.props;
|
||||
let msg = gettext('Please upload files less than {placeholder}M').replace('{placeholder}', maxUploadFileSize);
|
||||
return (
|
||||
<tr className="file-upload-item">
|
||||
<td className="upload-name">
|
||||
<div className="ellipsis">{file.name}</div>
|
||||
</td>
|
||||
|
||||
<td colSpan={3} className="error">{msg}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ForbidUploadListItem.propTypes = propTypes;
|
||||
|
||||
export default ForbidUploadListItem;
|
@@ -1,14 +1,16 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { gettext } from '../../utils/constants';
|
||||
import UploadListItem from './upload-list-item';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import UploadListItem from './upload-list-item';
|
||||
import ForbidUploadListItem from './forbid-upload-list-item';
|
||||
|
||||
const propTypes = {
|
||||
uploadBitrate: PropTypes.number.isRequired,
|
||||
totalProgress: PropTypes.number.isRequired,
|
||||
retryFileList: PropTypes.array.isRequired,
|
||||
uploadFileList: PropTypes.array.isRequired,
|
||||
forbidUploadFileList: PropTypes.array.isRequired,
|
||||
onCloseUploadDialog: PropTypes.func.isRequired,
|
||||
onCancelAllUploading: PropTypes.func.isRequired,
|
||||
onUploadCancel: PropTypes.func.isRequired,
|
||||
@@ -94,6 +96,11 @@ class UploadProgressDialog extends React.Component {
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
{
|
||||
this.props.forbidUploadFileList.map((file, index) => {
|
||||
return (<ForbidUploadListItem key={index} file={file} />);
|
||||
})
|
||||
}
|
||||
{
|
||||
this.props.uploadFileList.map((resumableFile, index) => {
|
||||
return (
|
||||
|
@@ -1264,7 +1264,11 @@ class LibContentView extends React.Component {
|
||||
let direntList = this.state.direntList.filter(item => {
|
||||
return item.name !== name;
|
||||
});
|
||||
this.setState({ direntList: direntList });
|
||||
|
||||
// Recalculate the state of the selection
|
||||
this.recaculateSelectedStateAfterDirentDeleted(name, direntList);
|
||||
|
||||
this.setState({direntList: direntList});
|
||||
this.updateReadmeMarkdown(direntList);
|
||||
} else if (Utils.isAncestorPath(direntPath, this.state.path)) {
|
||||
// the deleted item is ancester of the current item
|
||||
@@ -1283,6 +1287,10 @@ class LibContentView extends React.Component {
|
||||
let direntList = this.state.direntList.filter(item => {
|
||||
return item.name !== name;
|
||||
});
|
||||
|
||||
// Recalculate the state of the selection
|
||||
this.recaculateSelectedStateAfterDirentDeleted(name, direntList);
|
||||
|
||||
this.setState({direntList: direntList});
|
||||
this.updateReadmeMarkdown(direntList);
|
||||
}
|
||||
@@ -1531,6 +1539,20 @@ class LibContentView extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
recaculateSelectedStateAfterDirentDeleted = (name, newDirentList) => {
|
||||
let selectedDirentList = this.state.selectedDirentList.slice(0);
|
||||
if (selectedDirentList.length > 0) {
|
||||
selectedDirentList = selectedDirentList.filter(item => {
|
||||
return item.name !== name;
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
selectedDirentList: selectedDirentList,
|
||||
isDirentSelected: selectedDirentList.length > 0,
|
||||
isAllDirentSelected: selectedDirentList.length === newDirentList.length,
|
||||
});
|
||||
}
|
||||
|
||||
onLibDecryptDialog = () => {
|
||||
this.setState({libNeedDecrypt: false});
|
||||
this.loadDirData(this.state.path);
|
||||
|
@@ -1,315 +0,0 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cookie from 'react-cookies';
|
||||
import { gettext, repoID, siteRoot, permission } from '../../utils/constants';
|
||||
import { seafileAPI } from '../../utils/seafile-api';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import RepoInfo from '../../models/repo-info';
|
||||
import CommonToolbar from '../../components/toolbar/common-toolbar';
|
||||
import ViewModeToolbar from '../../components/toolbar/view-mode-toolbar';
|
||||
import DirOperationToolBar from '../../components/toolbar/dir-operation-toolbar';
|
||||
import MultipleDirOperationToolbar from '../../components/toolbar/multiple-dir-operation-toolbar';
|
||||
import CurDirPath from '../../components/cur-dir-path';
|
||||
import WikiMarkdownViewer from '../../components/wiki-markdown-viewer';
|
||||
import DirentListView from '../../components/dirent-list-view/dirent-list-view';
|
||||
import DirentDetail from '../../components/dirent-detail/dirent-details';
|
||||
import FileUploader from '../../components/file-uploader/file-uploader';
|
||||
import RepoInfoBar from '../../components/repo-info-bar';
|
||||
|
||||
const propTypes = {
|
||||
content: PropTypes.string,
|
||||
lastModified: PropTypes.string,
|
||||
latestContributor: PropTypes.string,
|
||||
permission: PropTypes.string,
|
||||
hash: PropTypes.string,
|
||||
path: PropTypes.string.isRequired,
|
||||
repoName: PropTypes.string.isRequired,
|
||||
repoEncrypted: PropTypes.bool.isRequired,
|
||||
showShareBtn: PropTypes.bool.isRequired,
|
||||
enableDirPrivateShare: PropTypes.bool.isRequired,
|
||||
userPerm: PropTypes.string.isRequired,
|
||||
isAdmin: PropTypes.bool.isRequired,
|
||||
isGroupOwnedRepo: PropTypes.bool.isRequired,
|
||||
// whether the file or dir corresponding to the path exist
|
||||
pathExist: PropTypes.bool.isRequired,
|
||||
isFileLoading: PropTypes.bool.isRequired,
|
||||
isViewFile: PropTypes.bool.isRequired,
|
||||
isDirentListLoading: PropTypes.bool.isRequired,
|
||||
isDirentSelected: PropTypes.bool.isRequired,
|
||||
isAllDirentSelected: PropTypes.bool.isRequired,
|
||||
direntList: PropTypes.array.isRequired,
|
||||
sortBy: PropTypes.string.isRequired,
|
||||
sortOrder: PropTypes.string.isRequired,
|
||||
sortItems: PropTypes.func.isRequired,
|
||||
selectedDirentList: PropTypes.array.isRequired,
|
||||
updateDirent: PropTypes.func.isRequired,
|
||||
onSideNavMenuClick: PropTypes.func.isRequired,
|
||||
onSearchedClick: PropTypes.func.isRequired,
|
||||
onMainNavBarClick: PropTypes.func.isRequired,
|
||||
onItemClick: PropTypes.func.isRequired,
|
||||
onAllDirentSelected: PropTypes.func.isRequired,
|
||||
onItemSelected: PropTypes.func.isRequired,
|
||||
onItemDelete: PropTypes.func.isRequired,
|
||||
onItemRename: PropTypes.func.isRequired,
|
||||
onItemMove: PropTypes.func.isRequired,
|
||||
onItemCopy: PropTypes.func.isRequired,
|
||||
onAddFile: PropTypes.func.isRequired,
|
||||
onAddFolder: PropTypes.func.isRequired,
|
||||
onFileTagChanged: PropTypes.func.isRequired,
|
||||
onItemsMove: PropTypes.func.isRequired,
|
||||
onItemsCopy: PropTypes.func.isRequired,
|
||||
onItemsDelete: PropTypes.func.isRequired,
|
||||
onLinkClick: PropTypes.func.isRequired,
|
||||
onFileUploadSuccess: PropTypes.func.isRequired,
|
||||
isDraft: PropTypes.bool,
|
||||
hasDraft: PropTypes.bool,
|
||||
goDraftPage: PropTypes.func,
|
||||
usedRepoTags: PropTypes.array.isRequired,
|
||||
readmeMarkdown: PropTypes.object,
|
||||
draftCounts: PropTypes.number,
|
||||
updateUsedRepoTags: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
class MainPanel extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
currentMode: 'wiki',
|
||||
isDirentDetailShow: false,
|
||||
currentDirent: null,
|
||||
direntPath: '',
|
||||
currentRepoInfo: null,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
seafileAPI.getRepoInfo(repoID).then(res => {
|
||||
let repoInfo = new RepoInfo(res.data);
|
||||
this.setState({
|
||||
currentRepoInfo: repoInfo,
|
||||
});
|
||||
});
|
||||
if (this.props.hash) {
|
||||
let hash = this.props.hash;
|
||||
setTimeout(function() {
|
||||
window.location.hash = hash;
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
switchViewMode = (mode) => {
|
||||
cookie.save('view_mode', mode, { path: '/' });
|
||||
let repoName = this.state.currentRepoInfo.repo_name;
|
||||
let dirPath = this.props.isViewFile ? Utils.getDirName(this.props.path) : this.props.path;
|
||||
window.location.href = siteRoot + 'library/' + repoID + '/' + repoName + dirPath;
|
||||
}
|
||||
|
||||
onSideNavMenuClick = () => {
|
||||
this.props.onSideNavMenuClick();
|
||||
}
|
||||
|
||||
onItemClick = (dirent) => {
|
||||
this.setState({isDirentDetailShow: false});
|
||||
this.props.onItemClick(dirent);
|
||||
}
|
||||
|
||||
|
||||
onMainNavBarClick = (path) => {
|
||||
this.setState({isDirentDetailShow: false});
|
||||
this.props.onMainNavBarClick(path);
|
||||
}
|
||||
|
||||
// on '<tr>'
|
||||
onDirentClick = (dirent) => {
|
||||
if (this.state.isDirentDetailShow) {
|
||||
this.onItemDetails(dirent);
|
||||
}
|
||||
}
|
||||
|
||||
onItemDetails = (dirent) => {
|
||||
this.setState({
|
||||
currentDirent: dirent,
|
||||
isDirentDetailShow: true,
|
||||
});
|
||||
}
|
||||
|
||||
onItemDetailsClose = () => {
|
||||
this.setState({isDirentDetailShow: false});
|
||||
}
|
||||
|
||||
onFileTagChanged = (dirent, direntPath) => {
|
||||
this.props.onFileTagChanged(dirent, direntPath);
|
||||
}
|
||||
|
||||
onUploadFile = (e) => {
|
||||
e.nativeEvent.stopImmediatePropagation();
|
||||
this.uploader.onFileUpload();
|
||||
}
|
||||
|
||||
onUploadFolder = (e) => {
|
||||
e.nativeEvent.stopImmediatePropagation();
|
||||
this.uploader.onFolderUpload();
|
||||
}
|
||||
|
||||
onFileUploadSuccess = (direntObject) => {
|
||||
this.props.onFileUploadSuccess(direntObject);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const ErrMessage = (<div className="message err-tip">{gettext('Folder does not exist.')}</div>);
|
||||
const showRepoInfoBar = this.props.path === '/' && (
|
||||
this.props.usedRepoTags.length != 0 || this.props.readmeMarkdown != null ||
|
||||
this.props.draftCounts != 0);
|
||||
|
||||
return (
|
||||
<div className="main-panel wiki-main-panel o-hidden">
|
||||
<div className="main-panel-north border-left-show">
|
||||
<div className="cur-view-toolbar">
|
||||
<span className="sf2-icon-menu hidden-md-up d-md-none side-nav-toggle" title={gettext('Side Nav Menu')} onClick={this.onSideNavMenuClick}></span>
|
||||
<div className="dir-operation">
|
||||
{this.props.isDirentSelected ?
|
||||
<MultipleDirOperationToolbar
|
||||
repoID={repoID}
|
||||
path={this.props.path}
|
||||
selectedDirentList={this.props.selectedDirentList}
|
||||
onItemsMove={this.props.onItemsMove}
|
||||
onItemsCopy={this.props.onItemsCopy}
|
||||
onItemsDelete={this.props.onItemsDelete}
|
||||
/> :
|
||||
<DirOperationToolBar
|
||||
path={this.props.path}
|
||||
repoID={repoID}
|
||||
repoName={this.props.repoName}
|
||||
repoEncrypted={this.props.repoEncrypted}
|
||||
isDraft={this.props.isDraft}
|
||||
hasDraft={this.props.hasDraft}
|
||||
direntList={this.props.direntList}
|
||||
permission={this.props.permission}
|
||||
isViewFile={this.props.isViewFile}
|
||||
showShareBtn={this.props.showShareBtn}
|
||||
enableDirPrivateShare={this.props.enableDirPrivateShare}
|
||||
userPerm={this.props.userPerm}
|
||||
isAdmin={this.props.isAdmin}
|
||||
isGroupOwnedRepo={this.props.isGroupOwnedRepo}
|
||||
onAddFile={this.props.onAddFile}
|
||||
onAddFolder={this.props.onAddFolder}
|
||||
onUploadFile={this.onUploadFile}
|
||||
onUploadFolder={this.onUploadFolder}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
<ViewModeToolbar currentMode={this.state.currentMode} switchViewMode={this.switchViewMode}/>
|
||||
</div>
|
||||
<CommonToolbar repoID={repoID} onSearchedClick={this.props.onSearchedClick} searchPlaceholder={gettext('Search files in this library')}/>
|
||||
</div>
|
||||
<div className="main-panel-center flex-row">
|
||||
<div className="cur-view-container">
|
||||
<div className="cur-view-path">
|
||||
{this.state.currentRepoInfo && (
|
||||
<CurDirPath
|
||||
repoID={repoID}
|
||||
repoName={this.state.currentRepoInfo.repo_name}
|
||||
currentPath={this.props.path}
|
||||
permission={permission}
|
||||
onPathClick={this.onMainNavBarClick}
|
||||
isViewFile={this.props.isViewFile}
|
||||
updateUsedRepoTags={this.props.updateUsedRepoTags}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="cur-view-content">
|
||||
{!this.props.pathExist && ErrMessage }
|
||||
{(this.props.pathExist && this.props.isViewFile) && (
|
||||
<WikiMarkdownViewer
|
||||
isFileLoading={this.props.isFileLoading}
|
||||
markdownContent={this.props.content}
|
||||
latestContributor={this.props.latestContributor}
|
||||
lastModified = {this.props.lastModified}
|
||||
onLinkClick={this.props.onLinkClick}
|
||||
>
|
||||
<Fragment>
|
||||
{(!this.props.isDraft && this.props.hasDraft) &&
|
||||
<div className='seafile-btn-view-review text-center'>
|
||||
<div className='tag tag-green'>
|
||||
{gettext('This file is in draft stage.')}
|
||||
<a className="ml-2" onMouseDown={this.props.goDraftPage}>{gettext('View Draft')}</a>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</Fragment>
|
||||
</WikiMarkdownViewer>
|
||||
)}
|
||||
{(this.props.pathExist && !this.props.isViewFile) && (
|
||||
<Fragment>
|
||||
{showRepoInfoBar && (
|
||||
<RepoInfoBar
|
||||
repoID={repoID}
|
||||
currentPath={this.props.path}
|
||||
usedRepoTags={this.props.usedRepoTags}
|
||||
readmeMarkdown={this.props.readmeMarkdown}
|
||||
draftCounts={this.props.draftCounts}
|
||||
updateUsedRepoTags={this.props.updateUsedRepoTags}
|
||||
/>
|
||||
)}
|
||||
<DirentListView
|
||||
path={this.props.path}
|
||||
repoID={repoID}
|
||||
repoEncrypted={this.props.repoEncrypted}
|
||||
isRepoOwner={this.props.isRepoOwner}
|
||||
isAdmin={this.props.isAdmin}
|
||||
isGroupOwnedRepo={this.props.isGroupOwnedRepo}
|
||||
enableDirPrivateShare={this.props.enableDirPrivateShare}
|
||||
direntList={this.props.direntList}
|
||||
sortBy={this.props.sortBy}
|
||||
sortOrder={this.props.sortOrder}
|
||||
sortItems={this.props.sortItems}
|
||||
onAddFile={this.props.onAddFile}
|
||||
onItemClick={this.onItemClick}
|
||||
onItemDelete={this.props.onItemDelete}
|
||||
onItemRename={this.props.onItemRename}
|
||||
onItemMove={this.props.onItemMove}
|
||||
onItemCopy={this.props.onItemCopy}
|
||||
onDirentClick={this.onDirentClick}
|
||||
onItemDetails={this.onItemDetails}
|
||||
isDirentListLoading={this.props.isDirentListLoading}
|
||||
updateDirent={this.props.updateDirent}
|
||||
currentRepoInfo={this.state.currentRepoInfo}
|
||||
isAllItemSelected={this.props.isAllDirentSelected}
|
||||
onAllItemSelected={this.props.onAllDirentSelected}
|
||||
onItemSelected={this.props.onItemSelected}
|
||||
/>
|
||||
<FileUploader
|
||||
ref={uploader => this.uploader = uploader}
|
||||
dragAndDrop={true}
|
||||
path={this.props.path}
|
||||
repoID={repoID}
|
||||
direntList={this.props.direntList}
|
||||
onFileUploadSuccess={this.onFileUploadSuccess}
|
||||
/>
|
||||
</Fragment>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{this.state.isDirentDetailShow && (
|
||||
<div className="cur-view-detail">
|
||||
<DirentDetail
|
||||
repoID={repoID}
|
||||
path={this.props.path}
|
||||
dirent={this.state.currentDirent}
|
||||
direntPath={this.state.direntPath}
|
||||
onItemDetailsClose={this.onItemDetailsClose}
|
||||
onFileTagChanged={this.onFileTagChanged}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MainPanel.propTypes = propTypes;
|
||||
|
||||
export default MainPanel;
|
File diff suppressed because it is too large
Load Diff
@@ -58,6 +58,7 @@ export const canAddPublicRepo = window.app.pageOptions.canAddPublicRepo;
|
||||
export const canInvitePeople = window.app.pageOptions.canInvitePeople;
|
||||
export const canLockUnlockFile = window.app.pageOptions.canLockUnlockFile;
|
||||
export const customNavItems = window.app.pageOptions.customNavItems;
|
||||
export const maxUploadFileSize = window.app.pageOptions.maxUploadFileSize;
|
||||
|
||||
export const curNoteMsg = window.app.pageOptions.curNoteMsg;
|
||||
export const curNoteID = window.app.pageOptions.curNoteID;
|
||||
|
@@ -92,7 +92,7 @@ class Groups(APIView):
|
||||
username = request.user.username
|
||||
if is_org_context(request):
|
||||
org_id = request.user.org.org_id
|
||||
user_groups = seaserv.get_org_groups_by_user(org_id, username)
|
||||
user_groups = seaserv.get_org_groups_by_user(org_id, username, return_ancestors=True)
|
||||
else:
|
||||
user_groups = ccnet_api.get_groups(username, return_ancestors=True)
|
||||
|
||||
|
@@ -96,6 +96,9 @@
|
||||
canAddPublicRepo: {% if can_add_public_repo %} true {% else %} false {% endif %},
|
||||
canInvitePeople: {% if enable_guest_invitation and user.permissions.can_invite_guest %} true {% else %} false {% endif %},
|
||||
customNavItems: {% if custom_nav_items %} JSON.parse('{{ custom_nav_items | escapejs }}') {% else %} {{'[]'}} {% endif %},
|
||||
{% if max_upload_file_size > 0 %}
|
||||
maxUploadFileSize: {{ max_upload_file_size }},
|
||||
{% endif %}
|
||||
|
||||
{% if request.user.is_authenticated and request.cur_note %}
|
||||
curNoteMsg: '{{ request.cur_note.message|urlize|escapejs }}',
|
||||
|
@@ -81,7 +81,6 @@ $('#signup-form').on('submit', function(){
|
||||
var email = $.trim($('input[name="email"]').val()),
|
||||
pwd1 = $.trim($('input[name="password1"]').val()),
|
||||
pwd2 = $.trim($('input[name="password2"]').val());
|
||||
level = getStrengthLevel(pwd1);
|
||||
|
||||
if (!email) {
|
||||
$('.error').html("{% trans "Email cannot be blank" %}").removeClass('hide');
|
||||
@@ -100,6 +99,7 @@ $('#signup-form').on('submit', function(){
|
||||
return false;
|
||||
}
|
||||
{% if strong_pwd_required %}
|
||||
var level = getStrengthLevel(pwd1);
|
||||
if (level < {{level}}) {
|
||||
$('.error').html(passwd_tip).removeClass('hide');
|
||||
return false;
|
||||
|
@@ -1,22 +0,0 @@
|
||||
{% extends "base_for_react.html" %}
|
||||
{% load render_bundle from webpack_loader %}
|
||||
{% block extra_style %}
|
||||
{% render_bundle 'repoview' 'css' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_script %}
|
||||
<script type="text/javascript">
|
||||
window.wiki = {
|
||||
config: {
|
||||
repoId: "{{ repo_id }}",
|
||||
serviceUrl: "{{ service_url}}",
|
||||
initial_path: "{{ initial_path|escapejs }}",
|
||||
slug: "{{ repo_name }}",
|
||||
isDir: "{{ is_dir }}",
|
||||
permission: "{{ permission }}"
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
{% render_bundle 'repoview' 'js' %}
|
||||
{% endblock %}
|
@@ -1131,10 +1131,17 @@ def react_fake_view(request, **kwargs):
|
||||
|
||||
folder_perm_enabled = True if is_pro_version() and ENABLE_FOLDER_PERM else False
|
||||
|
||||
try:
|
||||
max_upload_file_size = seafile_api.get_server_config_int('fileserver', 'max_upload_size')
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
max_upload_file_size = -1
|
||||
|
||||
return render(request, "react_app.html", {
|
||||
"guide_enabled": guide_enabled,
|
||||
'trash_repos_expire_days': expire_days if expire_days > 0 else 30,
|
||||
'dtable_web_server': DTABLE_WEB_SERVER,
|
||||
'max_upload_file_size': max_upload_file_size,
|
||||
'seafile_collab_server': SEAFILE_COLLAB_SERVER,
|
||||
'storages': get_library_storages(request),
|
||||
'enable_repo_snapshot_label': settings.ENABLE_REPO_SNAPSHOT_LABEL,
|
||||
|
@@ -1,6 +1,7 @@
|
||||
from django.conf import settings
|
||||
from django.db import connection
|
||||
|
||||
from seaserv import ccnet_api
|
||||
from seahub.auth.backends import RemoteUserBackend
|
||||
from seahub.base.accounts import User
|
||||
from registration.models import (
|
||||
@@ -43,9 +44,12 @@ class ShibbolethRemoteUserBackend(RemoteUserBackend):
|
||||
return
|
||||
|
||||
username = self.clean_username(remote_user)
|
||||
try:
|
||||
user = User.objects.get(email=username)
|
||||
except User.DoesNotExist:
|
||||
|
||||
local_ccnet_users = ccnet_api.search_emailusers('DB', username, -1, -1)
|
||||
if not local_ccnet_users:
|
||||
local_ccnet_users = ccnet_api.search_emailusers('LDAP', username, -1, -1)
|
||||
|
||||
if not local_ccnet_users:
|
||||
if self.create_unknown_user:
|
||||
user = User.objects.create_user(
|
||||
email=username, is_active=self.activate_after_creation)
|
||||
|
Reference in New Issue
Block a user