mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-09 02:42:47 +00:00
Code optimized (#2388)
This commit is contained in:
committed by
Daniel Pan
parent
6b62d3e653
commit
490a15deed
@@ -34,7 +34,7 @@ module.exports = {
|
||||
// This means they will be the "root" imports that are included in JS bundle.
|
||||
// The first two entry points enable "hot" CSS and auto-refreshes for JS.
|
||||
entry: {
|
||||
main: [
|
||||
markdownEditor: [
|
||||
// We ship a few polyfills by default:
|
||||
require.resolve('./polyfills'),
|
||||
// Include an alternative client for WebpackDevServer. A client's job is to
|
||||
@@ -59,11 +59,6 @@ module.exports = {
|
||||
require.resolve('react-dev-utils/webpackHotDevClient'),
|
||||
paths.appSrc + "/wiki.js",
|
||||
],
|
||||
dashboard: [
|
||||
require.resolve('./polyfills'),
|
||||
require.resolve('react-dev-utils/webpackHotDevClient'),
|
||||
paths.appSrc + "/dashboard.js",
|
||||
],
|
||||
repoview: [
|
||||
require.resolve('./polyfills'),
|
||||
require.resolve('react-dev-utils/webpackHotDevClient'),
|
||||
@@ -74,11 +69,11 @@ module.exports = {
|
||||
require.resolve('react-dev-utils/webpackHotDevClient'),
|
||||
paths.appSrc + "/file-history.js",
|
||||
],
|
||||
drafts: [
|
||||
app: [
|
||||
require.resolve('./polyfills'),
|
||||
require.resolve('react-dev-utils/webpackHotDevClient'),
|
||||
paths.appSrc + "/drafts.js",
|
||||
]
|
||||
paths.appSrc + "/app.js",
|
||||
]
|
||||
},
|
||||
|
||||
output: {
|
||||
|
@@ -3,6 +3,7 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@reach/router": "^1.1.1",
|
||||
"@seafile/seafile-editor": "^0.1.20",
|
||||
"autoprefixer": "7.1.6",
|
||||
"chalk": "1.1.3",
|
||||
@@ -32,7 +33,7 @@
|
||||
"raf": "3.4.0",
|
||||
"react": "^16.4.2",
|
||||
"react-cookies": "^0.1.0",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-dom": "^16.5.2",
|
||||
"react-moment": "^0.7.9",
|
||||
"react-s-alert": "^1.4.1",
|
||||
"reactstrap": "^6.4.0",
|
||||
|
49
frontend/src/app.js
Normal file
49
frontend/src/app.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import React, { Component } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Router } from '@reach/router'
|
||||
import SidePanel from './components/side-panel';
|
||||
import MainPanel from './components/main-panel';
|
||||
import DraftsView from './pages/drafts/drafts-view';
|
||||
import FilesActivities from './pages/dashboard/files-activities';
|
||||
|
||||
import 'seafile-ui';
|
||||
import './assets/css/fa-solid.css';
|
||||
import './assets/css/fa-regular.css';
|
||||
import './assets/css/fontawesome.css';
|
||||
import './css/layout.css';
|
||||
import './css/common.css';
|
||||
import './css/toolbar.css';
|
||||
import './css/search.css';
|
||||
|
||||
class App extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isOpen: false,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
let href = window.location.href.split('/');
|
||||
let currentTab = href[href.length - 2];
|
||||
|
||||
return (
|
||||
<div id="main">
|
||||
<SidePanel isOpen={this.state.isOpen} toggleClose={this.isOpen} currentTab={currentTab} />
|
||||
|
||||
<MainPanel path='/'>
|
||||
<Router>
|
||||
<FilesActivities path='dashboard' />
|
||||
<DraftsView path='drafts' />
|
||||
</Router>
|
||||
</MainPanel>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<App />,
|
||||
document.getElementById('wrapper')
|
||||
);
|
@@ -14,29 +14,31 @@ class ListView extends React.Component {
|
||||
render() {
|
||||
let drafts = this.props.draftList;
|
||||
return (
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{width: '4%'}}>{/*img*/}</th>
|
||||
<th style={{width: '46%'}}>{gettext('Name')}</th>
|
||||
<th style={{width: '20%'}}>{gettext('Owner')}</th>
|
||||
<th style={{width: '20%'}}>{gettext('Update time')}</th>
|
||||
<th style={{width: '10%'}}></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{ drafts && drafts.map((draft) => {
|
||||
return (
|
||||
<ListItem
|
||||
key={draft.id}
|
||||
draft={draft}
|
||||
onMenuToggleClick={this.props.onMenuToggleClick}
|
||||
isItemFreezed={this.props.isItemFreezed}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="table-container">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{width: '4%'}}>{/*img*/}</th>
|
||||
<th style={{width: '46%'}}>{gettext('Name')}</th>
|
||||
<th style={{width: '20%'}}>{gettext('Owner')}</th>
|
||||
<th style={{width: '20%'}}>{gettext('Update time')}</th>
|
||||
<th style={{width: '10%'}}></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{ drafts && drafts.map((draft) => {
|
||||
return (
|
||||
<ListItem
|
||||
key={draft.id}
|
||||
draft={draft}
|
||||
onMenuToggleClick={this.props.onMenuToggleClick}
|
||||
isItemFreezed={this.props.isItemFreezed}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import CommonToolbar from '../../components/toolbar/common-toolbar';
|
||||
import FilesActivities from '../../components/files-activities';
|
||||
import CommonToolbar from './toolbar/common-toolbar';
|
||||
|
||||
class MainPanel extends Component {
|
||||
constructor(props) {
|
||||
@@ -26,7 +25,7 @@ class MainPanel extends Component {
|
||||
<CommonToolbar onSearchedClick={this.onSearchedClick}/>
|
||||
</div>
|
||||
<div className="main-panel-center">
|
||||
<FilesActivities />
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Link } from '@reach/router';
|
||||
import { gettext, siteRoot } from './constants';
|
||||
import { seafileAPI } from '../utils/seafile-api';
|
||||
|
||||
@@ -134,7 +135,7 @@ class MainSideNav extends React.Component {
|
||||
</a>
|
||||
</li>
|
||||
<li className="tab" id="group-nav">
|
||||
<a className="ellipsis user-select-no" title={gettext('Shared with groups')} onClick={this.grpsExtend}>
|
||||
<a href="#" className="ellipsis user-select-no" title={gettext('Shared with groups')} onClick={this.grpsExtend}>
|
||||
<span className={`toggle-icon float-right fas ${this.state.groupsExtended ?'fa-caret-down':'fa-caret-left'}`} aria-hidden="true"></span>
|
||||
<span className="sf2-icon-group" aria-hidden="true"></span>
|
||||
{gettext('Shared with groups')}
|
||||
@@ -152,10 +153,10 @@ class MainSideNav extends React.Component {
|
||||
</a>
|
||||
</li>
|
||||
<li className={`tab ${this.state.currentTab === 'dashboard' ? 'tab-cur' : ''}`}>
|
||||
<a href={siteRoot + 'dashboard'} title={gettext('Acitivities')} onClick={() => this.tabItemClick('dashboard')}>
|
||||
<Link to={siteRoot + 'dashboard'} title={gettext('Acitivities')} onClick={() => this.tabItemClick('dashboard')}>
|
||||
<span className="sf2-icon-clock" aria-hidden="true"></span>
|
||||
{gettext('Acitivities')}
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li className={`tab ${this.state.currentTab === 'devices' ? 'tab-cur' : ''}`}>
|
||||
<a href={siteRoot + '#devices/'} className="ellipsis" title={gettext('Linked Devices')} onClick={() => this.tabItemClick('devices')}>
|
||||
@@ -164,13 +165,13 @@ class MainSideNav extends React.Component {
|
||||
</a>
|
||||
</li>
|
||||
<li className={`tab ${this.state.currentTab === 'drafts' ? 'tab-cur' : ''}`} onClick={() => this.tabItemClick('drafts')}>
|
||||
<a href={siteRoot + 'drafts/'} title={gettext('Drafts')}>
|
||||
<Link to={siteRoot + 'drafts'} title={gettext('Drafts')}>
|
||||
<span className="sf2-icon-edit" aria-hidden="true"></span>
|
||||
{gettext('Drafts')}
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="tab" id="share-admin-nav">
|
||||
<a className="ellipsis user-select-no" title={gettext('Share Admin')} onClick={this.shExtend}>
|
||||
<a href="#" className="ellipsis user-select-no" title={gettext('Share Admin')} onClick={this.shExtend}>
|
||||
<span className={`toggle-icon float-right fas ${this.state.sharedExtended ? 'fa-caret-down':'fa-caret-left'}`} aria-hidden="true"></span>
|
||||
<span aria-hidden="true" className="sf2-icon-wrench"></span>
|
||||
{gettext('Share Admin')}
|
||||
|
@@ -205,7 +205,7 @@ class Search extends Component {
|
||||
onChange={this.onChangeHandler}
|
||||
autoComplete="off"
|
||||
/>
|
||||
<i className={`search-icon-right input-icon-addon sf2-icon-close ${this.state.isCloseShow ? "" : "hide"}`} onClick={this.onCloseHandler}></i>
|
||||
<i className={`search-icon-right input-icon-addon fas fa-times ${this.state.isCloseShow ? "" : "hide"}`} onClick={this.onCloseHandler}></i>
|
||||
</div>
|
||||
<div className="search-result-container">
|
||||
{this.renderSearchResult()}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Modal, ModalHeader, ModalBody } from 'reactstrap';
|
||||
import { gettext, siteRoot } from './constants';
|
||||
import { Modal, ModalBody } from 'reactstrap';
|
||||
|
||||
class About extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -8,11 +8,9 @@ class About extends React.Component {
|
||||
this.state = {
|
||||
modal: false
|
||||
};
|
||||
|
||||
this.toggle = this.toggle.bind(this);
|
||||
}
|
||||
|
||||
toggle() {
|
||||
toggle = () => {
|
||||
this.setState({
|
||||
modal: !this.state.modal
|
||||
});
|
||||
@@ -21,14 +19,14 @@ class About extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<a href="#" className="item" onClick={this.toggle}>About</a>
|
||||
<a href="#" className="item" onClick={this.toggle}>{gettext('About')}</a>
|
||||
<Modal isOpen={this.state.modal} toggle={this.toggle} className={this.props.className}>
|
||||
<ModalBody>
|
||||
<div className="about-content">
|
||||
<p><img src="/media/img/seafile-logo.png" title="Private Seafile" alt="logo" width="128" height="32" /></p>
|
||||
<p>Server Version: 6.3.3<br /> © 2018 Seafile</p>
|
||||
<p><a href="http://seafile.com/about/" target="_blank">About Us</a></p>
|
||||
</div>
|
||||
<div className="about-content">
|
||||
<p><img src="/media/img/seafile-logo.png" title="Private Seafile" alt="logo" width="128" height="32" /></p>
|
||||
<p>{gettext('Server Version: 6.3.3')}<br />{gettext('© 2018 Seafile')}</p>
|
||||
<p><a href="http://seafile.com/about/" target="_blank">{gettext('About Us')}</a></p>
|
||||
</div>
|
||||
</ModalBody>
|
||||
</Modal>
|
||||
</div>
|
||||
@@ -40,11 +38,11 @@ class SideNavFooter extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="side-nav-footer">
|
||||
<a href="/help/" target="_blank" className="item">Help</a>
|
||||
<a href={siteRoot + 'help/'} target="_blank" className="item">{gettext('Help')}</a>
|
||||
<About />
|
||||
<a href="/download_client_program/" className="item last-item">
|
||||
<a href={siteRoot + 'download_client_program/'} className="item last-item">
|
||||
<span aria-hidden="true" className="sf2-icon-monitor vam"></span>{' '}
|
||||
<span className="vam">Clients</span>
|
||||
<span className="vam">{gettext('Clients')}</span>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
|
@@ -9,23 +9,25 @@ class TreeDirView extends React.Component {
|
||||
let children = node.hasChildren() ? node.children : null;
|
||||
|
||||
return (
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{width: "4%"}}></th>
|
||||
<th style={{width: "60%"}}>{gettext('Name')}</th>
|
||||
<th style={{width: "16%"}}>{gettext('Size')}</th>
|
||||
<th style={{width: "20%"}}>{gettext('Last Update')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{children && children.map((node, index) => {
|
||||
return (
|
||||
<TreeDirList key={index} node={node} onMainNodeClick={this.props.onMainNodeClick}></TreeDirList>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="table-container">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{width: "4%"}}></th>
|
||||
<th style={{width: "60%"}}>{gettext('Name')}</th>
|
||||
<th style={{width: "16%"}}>{gettext('Size')}</th>
|
||||
<th style={{width: "20%"}}>{gettext('Last Update')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{children && children.map((node, index) => {
|
||||
return (
|
||||
<TreeDirList key={index} node={node} onMainNodeClick={this.props.onMainNodeClick}></TreeDirList>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -68,7 +68,7 @@
|
||||
|
||||
.table-container {
|
||||
flex: 1;
|
||||
padding: 10px 1rem;
|
||||
padding: 10px 16px 20px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
/* specific handler */
|
||||
.table-container table .menu-toggle {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tr-highlight {
|
||||
@@ -127,10 +128,15 @@
|
||||
.dropdown-menu {
|
||||
min-width: 8rem;
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
/* end dropdown-menu style */
|
||||
|
||||
/* begin tip */
|
||||
.empty-tip {
|
||||
margin: auto 1rem;
|
||||
padding: 30px 40px;
|
||||
background-color: #FAFAFA;
|
||||
border: solid 1px #DDD;
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.side-panel {
|
||||
@@ -66,3 +67,46 @@
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
|
||||
.cur-view-container {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
flex:1 1 auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cur-view-path {
|
||||
flex-shrink:0;
|
||||
min-height:40px;
|
||||
padding:8px 16px 0;
|
||||
background:#f9f9f9;
|
||||
position:relative; /* for the ':after' */
|
||||
}
|
||||
|
||||
.cur-view-path:after {
|
||||
content:'';
|
||||
border-bottom:1px solid #e8e8e8;
|
||||
position:absolute;
|
||||
left:16px;
|
||||
right:16px;
|
||||
bottom:0;
|
||||
}
|
||||
|
||||
.cur-view-content {
|
||||
padding:10px 16px 20px;
|
||||
flex:1;
|
||||
height: calc(100% - 40px);
|
||||
overflow:auto;
|
||||
}
|
||||
|
||||
.cur-view-content .hd {
|
||||
padding-bottom:0;
|
||||
height:48px;
|
||||
padding:9px 10px;
|
||||
background:#f2f2f2;
|
||||
margin-bottom:.5em;
|
||||
border-radius:2px;
|
||||
}
|
||||
|
||||
[role=group] {
|
||||
display: flex;
|
||||
}
|
@@ -13,11 +13,12 @@
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.search-container .search-icon-left {
|
||||
.search-icon-left {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.search-container .search-icon-right {
|
||||
.search-icon-right {
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
pointer-events: all;
|
||||
font-style: normal;
|
||||
|
@@ -52,6 +52,13 @@ img[src=""] {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.wiki-side-panel {
|
||||
flex: 0 0 20%;
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.wiki-main-panel {
|
||||
flex: 1 0 80%;
|
||||
display:flex;
|
||||
@@ -59,37 +66,30 @@ img[src=""] {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.wiki-side-panel {
|
||||
flex: 0 0 20%;
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
overflow:hidden;
|
||||
}
|
||||
.cur-view-main {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.cur-view-container {
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.cur-view-container .markdown-container {
|
||||
.cur-view-content {
|
||||
display: flex;
|
||||
padding: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.cur-view-content .markdown-container{
|
||||
padding-left: 40px;
|
||||
padding-right: 40px;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.cur-view-container .markdown-content {
|
||||
.cur-view-content .markdown-content {
|
||||
width: calc(100% - 160px);
|
||||
padding-right: 40px;
|
||||
}
|
||||
|
||||
.cur-view-container .markdown-outline {
|
||||
.cur-view-content .markdown-outline {
|
||||
position: fixed;
|
||||
padding-right: 18px;
|
||||
top: 97px;
|
||||
@@ -103,14 +103,14 @@ img[src=""] {
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.cur-view-container .markdown-container {
|
||||
.cur-view-content .markdown-container {
|
||||
padding-right: 40px;
|
||||
}
|
||||
.cur-view-container .markdown-content {
|
||||
.cur-view-content .markdown-content {
|
||||
width: 100%;
|
||||
padding-right: 0;
|
||||
}
|
||||
.cur-view-container .markdown-outline {
|
||||
.cur-view-content .markdown-outline {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
@@ -1,54 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { siteRoot } from './components/constants';
|
||||
import SidePanel from './components/side-panel';
|
||||
import MainPanel from './pages/dashboard/main-panel';
|
||||
import 'seafile-ui';
|
||||
import './assets/css/fa-solid.css';
|
||||
import './assets/css/fa-regular.css';
|
||||
import './assets/css/fontawesome.css';
|
||||
import './css/layout.css'
|
||||
import './css/dashboard.css';
|
||||
import './css/toolbar.css';
|
||||
import './css/search.css';
|
||||
|
||||
|
||||
class DashBoard extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isOpen: false
|
||||
};
|
||||
this.currentTab = 'dashboard';
|
||||
}
|
||||
|
||||
isOpen = () => {
|
||||
this.setState({
|
||||
isOpen: !this.state.isOpen,
|
||||
});
|
||||
}
|
||||
|
||||
onSearchedClick = (item) => {
|
||||
let str = item.path.substr(item.path.length-1, 1);
|
||||
if (str === '/'){
|
||||
window.location.href= siteRoot + '#common/lib/' + item.repo_id + item.path;
|
||||
} else {
|
||||
window.location.href= siteRoot + 'lib/' + item.repo_id + '/file' + item.path;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div id="main">
|
||||
<SidePanel isOpen={this.state.isOpen} toggleClose={this.isOpen} currentTab={this.currentTab}/>
|
||||
<MainPanel isOpen={this.isOpen}></MainPanel>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<DashBoard />,
|
||||
document.getElementById('wrapper')
|
||||
);
|
@@ -1,70 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import editUtilties from './utils/editor-utilties';
|
||||
import SidePanel from './components/side-panel';
|
||||
import MainPanel from './pages/drafts/main-panel';
|
||||
|
||||
import 'seafile-ui';
|
||||
import './assets/css/fa-solid.css';
|
||||
import './assets/css/fa-regular.css';
|
||||
import './assets/css/fontawesome.css';
|
||||
import './css/layout.css';
|
||||
import './css/common.css';
|
||||
import './css/toolbar.css';
|
||||
import './css/search.css';
|
||||
|
||||
class Drafts extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
draftList: [],
|
||||
isLoadingDraft: true,
|
||||
};
|
||||
this.currentTab = 'drafts';
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.initDraftList();
|
||||
}
|
||||
|
||||
initDraftList() {
|
||||
editUtilties.listDrafts().then(res => {
|
||||
this.setState({
|
||||
draftList: res.data.data,
|
||||
isLoadingDraft: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
deleteDraft = (draft) => {
|
||||
editUtilties.deleteDraft(draft.id).then(res => {
|
||||
this.initDraftList();
|
||||
});
|
||||
}
|
||||
|
||||
publishDraft = (draft) => {
|
||||
editUtilties.publishDraft(draft.id).then(res => {
|
||||
this.initDraftList();
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div id="main">
|
||||
<SidePanel currentTab={this.currentTab}></SidePanel>
|
||||
<MainPanel
|
||||
isLoadingDraft={this.state.isLoadingDraft}
|
||||
draftList={this.state.draftList}
|
||||
deleteDraft={this.deleteDraft}
|
||||
publishDraft={this.publishDraft}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Drafts />,
|
||||
document.getElementById('wrapper')
|
||||
);
|
@@ -1,7 +1,7 @@
|
||||
// Import React!
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './App';
|
||||
import MarkdownEditor from './markdown-editor';
|
||||
import { I18nextProvider } from 'react-i18next';
|
||||
import i18n from './i18n';
|
||||
import './assets/css/fa-solid.css';
|
||||
@@ -14,7 +14,7 @@ let lang = window.app.pageOptions.lang
|
||||
|
||||
ReactDOM.render(
|
||||
<I18nextProvider i18n={ i18n } initialLanguage={ lang } >
|
||||
<App />
|
||||
<MarkdownEditor />
|
||||
</I18nextProvider>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
4
frontend/src/App.js → frontend/src/markdown-editor.js
Executable file → Normal file
4
frontend/src/App.js → frontend/src/markdown-editor.js
Executable file → Normal file
@@ -162,7 +162,7 @@ class EditorUtilities {
|
||||
|
||||
const editorUtilities = new EditorUtilities();
|
||||
|
||||
class App extends React.Component {
|
||||
class MarkdownEditor extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@@ -233,4 +233,4 @@ class App extends React.Component {
|
||||
}
|
||||
}
|
||||
}
|
||||
export default App;
|
||||
export default MarkdownEditor;
|
@@ -1,6 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import { seafileAPI } from '../utils/seafile-api';
|
||||
import { gettext, siteRoot } from './constants';
|
||||
import { seafileAPI } from '../../utils/seafile-api';
|
||||
import { gettext, siteRoot } from '../../components/constants';
|
||||
|
||||
const per_page = 25; // default
|
||||
|
||||
@@ -233,11 +233,11 @@ class FilesActivities extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="main-panel-main" id="activities">
|
||||
<div className="cur-view-container" id="activities">
|
||||
<div className="cur-view-path">
|
||||
<h3 className="sf-heading">{gettext("Activities")}</h3>
|
||||
</div>
|
||||
<div className="cur-view-main-con" onScroll={this.handleScroll}>
|
||||
<div className="cur-view-content" onScroll={this.handleScroll}>
|
||||
<FileActivitiesContent data={this.state} />
|
||||
</div>
|
||||
</div>
|
@@ -1,23 +1,17 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { gettext } from '../../components/constants';
|
||||
import CommonToolbar from '../../components/toolbar/common-toolbar';
|
||||
import editUtilties from '../../utils/editor-utilties';
|
||||
import Loading from '../../components/loading';
|
||||
import ListView from '../../components/list-view/list-view';
|
||||
import ListMenu from '../../components/list-view/list-menu';
|
||||
|
||||
const propTypes = {
|
||||
isLoadingDraft: PropTypes.bool.isRequired,
|
||||
draftList: PropTypes.array.isRequired,
|
||||
publishDraft: PropTypes.func.isRequired,
|
||||
deleteDraft: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
class MainPanel extends React.Component {
|
||||
class DraftsView extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
draftList: [],
|
||||
isLoadingDraft: true,
|
||||
isMenuShow: false,
|
||||
menuPosition: {top:'', left: ''},
|
||||
currentDraft: null,
|
||||
@@ -26,6 +20,7 @@ class MainPanel extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.initDraftList();
|
||||
document.addEventListener('click', this.onHideContextMenu);
|
||||
}
|
||||
|
||||
@@ -33,6 +28,30 @@ class MainPanel extends React.Component {
|
||||
document.removeEventListener('click', this.onHideContextMenu);
|
||||
}
|
||||
|
||||
initDraftList() {
|
||||
this.setState({isLoadingDraft: true});
|
||||
editUtilties.listDrafts().then(res => {
|
||||
this.setState({
|
||||
draftList: res.data.data,
|
||||
isLoadingDraft: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onDeleteHandler = () => {
|
||||
let draft = this.state.currentDraft;
|
||||
editUtilties.deleteDraft(draft.id).then(res => {
|
||||
this.initDraftList();
|
||||
});
|
||||
}
|
||||
|
||||
onPublishHandler = () => {
|
||||
let draft = this.state.currentDraft;
|
||||
editUtilties.publishDraft(draft.id).then(res => {
|
||||
this.initDraftList();
|
||||
});
|
||||
}
|
||||
|
||||
onMenuToggleClick = (e, draft) => {
|
||||
if (this.state.isMenuShow) {
|
||||
this.onHideContextMenu();
|
||||
@@ -60,44 +79,26 @@ class MainPanel extends React.Component {
|
||||
isItemFreezed: false
|
||||
});
|
||||
}
|
||||
|
||||
onPublishHandler = () => {
|
||||
this.props.publishDraft(this.state.currentDraft);
|
||||
}
|
||||
|
||||
onDeleteHandler = () => {
|
||||
this.props.deleteDraft(this.state.currentDraft);
|
||||
}
|
||||
|
||||
onSearchedClick = () => {
|
||||
//todos;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="main-panel">
|
||||
<div className="main-panel-north flex-right">
|
||||
<CommonToolbar onSearchedClick={this.onSearchedClick}/>
|
||||
</div>
|
||||
<div className="main-panel-center">
|
||||
<div className="panel-heading text-left">{gettext('Drafts')}</div>
|
||||
{this.props.isLoadingDraft ?
|
||||
<Loading /> :
|
||||
<div className="table-container">
|
||||
{this.props.draftList.length ?
|
||||
<ListView
|
||||
draftList={this.props.draftList}
|
||||
isItemFreezed={this.state.isItemFreezed}
|
||||
onMenuToggleClick={this.onMenuToggleClick}
|
||||
/> :
|
||||
<div className="message empty-tip">
|
||||
<h2>{gettext('There is no draft file existing')}</h2>
|
||||
</div>
|
||||
}
|
||||
<div className="cur-view-container">
|
||||
<div className="cur-view-path panel-heading text-left">{gettext('Drafts')}</div>
|
||||
<div className="cur-view-content" style={{padding: 0}}>
|
||||
{this.state.isLoadingDraft && <Loading /> }
|
||||
{(!this.state.isLoadingDraft && this.state.draftList.length !==0) &&
|
||||
<ListView
|
||||
draftList={this.state.draftList}
|
||||
isItemFreezed={this.state.isItemFreezed}
|
||||
onMenuToggleClick={this.onMenuToggleClick}
|
||||
/>
|
||||
}
|
||||
{(!this.state.isLoadingDraft && this.state.draftList.length === 0) &&
|
||||
<div className="message empty-tip">
|
||||
<h2>{gettext('There is no draft file existing')}</h2>
|
||||
</div>
|
||||
}
|
||||
{
|
||||
this.state.isMenuShow &&
|
||||
{this.state.isMenuShow &&
|
||||
<ListMenu
|
||||
isMenuShow={this.state.isMenuShow}
|
||||
currentDraft={this.state.currentDraft}
|
||||
@@ -112,6 +113,4 @@ class MainPanel extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
MainPanel.propTypes = propTypes;
|
||||
|
||||
export default MainPanel;
|
||||
export default DraftsView;
|
@@ -84,7 +84,7 @@ class MainPanel extends Component {
|
||||
</div>
|
||||
<CommonToolbar onSearchedClick={this.props.onSearchedClick} />
|
||||
</div>
|
||||
<div className="cur-view-main">
|
||||
<div className="cur-view-container">
|
||||
<div className="cur-view-path">
|
||||
<div className="path-containter">
|
||||
<a href={siteRoot + '#common/'} className="normal">{gettext("Libraries")}</a>
|
||||
@@ -94,14 +94,16 @@ class MainPanel extends Component {
|
||||
</div>
|
||||
<PathToolbar />
|
||||
</div>
|
||||
<div className="cur-view-container table-container">
|
||||
{ this.props.isViewFileState && <MarkdownViewer
|
||||
markdownContent={this.props.content}
|
||||
latestContributor={this.props.latestContributor}
|
||||
lastModified = {this.props.lastModified}
|
||||
onLinkClick={this.props.onLinkClick}
|
||||
isFileLoading={this.props.isFileLoading}
|
||||
/>}
|
||||
<div className="cur-view-content">
|
||||
{ this.props.isViewFileState &&
|
||||
<MarkdownViewer
|
||||
markdownContent={this.props.content}
|
||||
latestContributor={this.props.latestContributor}
|
||||
lastModified = {this.props.lastModified}
|
||||
onLinkClick={this.props.onLinkClick}
|
||||
isFileLoading={this.props.isFileLoading}
|
||||
/>
|
||||
}
|
||||
{ !this.props.isViewFileState &&
|
||||
<TreeDirView
|
||||
node={this.props.changedNode}
|
||||
|
@@ -60,7 +60,7 @@ class MainPanel extends Component {
|
||||
</div>
|
||||
<CommonToolbar onSearchedClick={this.props.onSearchedClick} />
|
||||
</div>
|
||||
<div className="cur-view-main">
|
||||
<div className="cur-view-container">
|
||||
<div className="cur-view-path">
|
||||
<div className="path-containter">
|
||||
<a href={siteRoot + 'wikis/'} className="normal">{gettext("Wikis")}</a>
|
||||
@@ -69,14 +69,16 @@ class MainPanel extends Component {
|
||||
{pathElem}
|
||||
</div>
|
||||
</div>
|
||||
<div className="cur-view-container table-container">
|
||||
{ this.props.isViewFileState && <MarkdownViewer
|
||||
markdownContent={this.props.content}
|
||||
latestContributor={this.props.latestContributor}
|
||||
lastModified = {this.props.lastModified}
|
||||
onLinkClick={this.props.onLinkClick}
|
||||
isFileLoading={this.props.isFileLoading}
|
||||
/>}
|
||||
<div className="cur-view-content">
|
||||
{ this.props.isViewFileState &&
|
||||
<MarkdownViewer
|
||||
markdownContent={this.props.content}
|
||||
latestContributor={this.props.latestContributor}
|
||||
lastModified = {this.props.lastModified}
|
||||
onLinkClick={this.props.onLinkClick}
|
||||
isFileLoading={this.props.isFileLoading}
|
||||
/>
|
||||
}
|
||||
{ !this.props.isViewFileState &&
|
||||
<TreeDirView
|
||||
node={this.props.changedNode}
|
||||
|
@@ -13,6 +13,7 @@ import 'seafile-ui';
|
||||
import './assets/css/fa-solid.css';
|
||||
import './assets/css/fa-regular.css';
|
||||
import './assets/css/fontawesome.css';
|
||||
import './css/layout.css';
|
||||
import './css/side-panel.css';
|
||||
import './css/wiki.css';
|
||||
import './css/toolbar.css';
|
||||
|
@@ -11,6 +11,7 @@ import 'seafile-ui';
|
||||
import './assets/css/fa-solid.css';
|
||||
import './assets/css/fa-regular.css';
|
||||
import './assets/css/fontawesome.css';
|
||||
import './css/layout.css';
|
||||
import './css/side-panel.css';
|
||||
import './css/wiki.css';
|
||||
import './css/toolbar.css';
|
||||
|
Reference in New Issue
Block a user