1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-10 11:21:29 +00:00
Files
seahub/frontend/src/pages/wikis/wikis.js

436 lines
11 KiB
JavaScript
Raw Normal View History

2018-12-10 13:33:32 +08:00
import React, { Component, Fragment } from 'react';
2018-12-08 00:01:23 +08:00
import PropTypes from 'prop-types';
import { seafileAPI } from '../../utils/seafile-api';
import { gettext, siteRoot, loginUrl } from '../../utils/constants';
import moment from 'moment';
import { Button } from 'reactstrap';
import Toast from '../../components/toast';
import MenuControl from '../../components/menu-control';
import WikiAdd from './wiki-add';
import WikiMenu from './wiki-menu';
import WikiRename from './wiki-rename';
2018-12-10 13:33:32 +08:00
import NewWikiDialog from '../../components/dialog/new-wiki-dialog';
import WikiDeleteDialog from '../../components/dialog/wiki-delete-dialog';
import WikiSelectDialog from '../../components/dialog/wiki-select-dialog';
import ModalPortal from '../../components/modal-portal';
2018-12-08 00:01:23 +08:00
const itempropTypes = {
wiki: PropTypes.object.isRequired,
2018-12-08 11:40:28 +08:00
renameWiki: PropTypes.func.isRequired,
2018-12-08 00:01:23 +08:00
deleteWiki: PropTypes.func.isRequired,
};
class Item extends Component {
constructor(props) {
super(props);
this.state = {
isShowWikiMenu: false,
2018-12-10 13:33:32 +08:00
position: {top:'', left: ''},
2018-12-08 00:01:23 +08:00
isItemFreezed: false,
isShowDeleteDialog: false,
isShowMenuControl: false,
isRenameing: false,
highlight: '',
};
}
componentDidMount() {
document.addEventListener('click', this.onHideWikiMenu);
}
componentWillUnmount() {
document.removeEventListener('click', this.onHideWikiMenu);
}
onMenuToggle = (e) => {
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
if (this.state.isShowWikiMenu) {
this.onHideWikiMenu();
} else {
this.onShowWikiMenu(e);
}
}
onShowWikiMenu = (e) => {
let left = e.clientX - 8*16;
let top = e.clientY + 12;
let position = {top: top, left: left};
this.setState({
isShowWikiMenu: true,
2018-12-10 13:33:32 +08:00
position: position,
2018-12-08 00:01:23 +08:00
isItemFreezed: true,
});
}
onHideWikiMenu = () => {
this.setState({
isShowWikiMenu: false,
isItemFreezed: false,
});
}
onMouseEnter = () => {
if (!this.state.isItemFreezed) {
this.setState({
isShowMenuControl: true,
highlight: 'tr-highlight',
});
}
}
onMouseLeave = () => {
if (!this.state.isItemFreezed) {
this.setState({
isShowMenuControl: false,
highlight: '',
});
}
}
onRenameToggle = () => {
this.setState({
isShowWikiMenu: false,
isItemFreezed: true,
isRenameing: true,
});
}
onRenameConfirm = (newName) => {
2018-12-08 11:40:28 +08:00
let wiki = this.props.wiki;
2018-12-08 00:01:23 +08:00
if (newName === wiki.name) {
this.onRenameCancel();
return false;
}
if (!newName) {
let errMessage = 'Name is required.';
Toast.error(gettext(errMessage));
return false;
}
if (newName.indexOf('/') > -1) {
let errMessage = 'Name should not include ' + '\'/\'' + '.';
Toast.error(gettext(errMessage));
return false;
}
this.renameWiki(newName);
this.onRenameCancel();
}
onRenameCancel = () => {
this.setState({
isRenameing: false,
isItemFreezed: false,
});
}
onDeleteToggle = () => {
this.setState({
isShowDeleteDialog: !this.state.isShowDeleteDialog,
});
}
renameWiki = (newName) => {
2018-12-08 11:40:28 +08:00
let wiki = this.props.wiki;
this.props.renameWiki(wiki, newName);
2018-12-08 00:01:23 +08:00
}
deleteWiki = () => {
let wiki = this.props.wiki;
this.props.deleteWiki(wiki);
this.setState({
isShowDeleteDialog: !this.state.isShowDeleteDialog,
});
}
render() {
2018-12-08 11:40:28 +08:00
let wiki = this.props.wiki;
2018-12-08 00:01:23 +08:00
let userProfileURL = `${siteRoot}profile/${encodeURIComponent(wiki.owner)}/`;
return (
2018-12-10 13:33:32 +08:00
<Fragment>
<tr className={this.state.highlight} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
<td>
{this.state.isRenameing ?
<WikiRename wiki={wiki} onRenameConfirm={this.onRenameConfirm} onRenameCancel={this.onRenameCancel}/> :
<a href={wiki.link}>{gettext(wiki.name)}</a>
}
</td>
<td><a href={userProfileURL} target='_blank'>{gettext(wiki.owner_nickname)}</a></td>
<td>{moment(wiki.updated_at).fromNow()}</td>
<td className="menu-toggle" onClick={this.onMenuToggle}>
<MenuControl
isShow={this.state.isShowMenuControl}
onClick={this.onMenuToggle}
2018-12-08 00:01:23 +08:00
/>
2018-12-10 13:33:32 +08:00
{this.state.isShowWikiMenu &&
<WikiMenu
position={this.state.position}
onRenameToggle={this.onRenameToggle}
onDeleteToggle={this.onDeleteToggle}
/>
}
</td>
</tr>
{this.state.isShowDeleteDialog &&
<ModalPortal>
<WikiDeleteDialog
2018-12-08 00:01:23 +08:00
toggleCancel={this.onDeleteToggle}
handleSubmit={this.deleteWiki}
/>
2018-12-10 13:33:32 +08:00
</ModalPortal>
}
</Fragment>
2018-12-08 00:01:23 +08:00
);
}
}
Item.propTypes = itempropTypes;
const contentpropTypes = {
data: PropTypes.object.isRequired,
2018-12-08 11:40:28 +08:00
renameWiki: PropTypes.func.isRequired,
2018-12-08 00:01:23 +08:00
deleteWiki: PropTypes.func.isRequired,
};
class WikisContent extends Component {
render() {
let {loading, errorMsg, wikis} = this.props.data;
if (loading) {
return <span className="loading-icon loading-tip"></span>;
} else if (errorMsg) {
return <p className="error text-center">{errorMsg}</p>;
} else {
return (
<table>
<thead>
<tr>
<th width="50%">{gettext('Name')}</th>
<th width="20%">{gettext('Owner')}</th>
<th width="20%">{gettext('Last Update')}</th>
<th width="10%">{/* operation */}</th>
</tr>
</thead>
<tbody>
{wikis.map((wiki, index) => {
2018-12-08 11:40:28 +08:00
return(
<Item key={index} wiki={wiki}
renameWiki={this.props.renameWiki}
deleteWiki={this.props.deleteWiki}
/>);
2018-12-08 00:01:23 +08:00
})}
</tbody>
</table>
);
}
}
}
WikisContent.propTypes = contentpropTypes;
class Wikis extends Component {
constructor(props) {
super(props);
this.state = {
loading: true,
errorMsg: '',
wikis: [],
isShowWikiAdd: false,
2018-12-10 13:33:32 +08:00
position: {top:'', left: ''},
2018-12-08 00:01:23 +08:00
isShowSelectDialog: false,
isShowCreateDialog: false,
};
}
componentDidMount() {
document.addEventListener('click', this.onHideWikiAdd);
this.getWikis();
}
componentWillUnmount() {
document.removeEventListener('click', this.onHideWikiAdd);
}
getWikis = () => {
seafileAPI.listWikis().then(res => {
this.setState({
loading: false,
wikis: res.data.data,
});
}).catch((error) => {
if (error.response) {
if (error.response.status == 403) {
this.setState({
loading: false,
errorMsg: gettext('Permission denied')
});
location.href = `${loginUrl}?next=${encodeURIComponent(location.href)}`;
} else {
this.setState({
loading: false,
errorMsg: gettext('Error')
});
}
} else {
this.setState({
loading: false,
errorMsg: gettext('Please check the network.')
});
}
});
}
onAddMenuToggle = (e) => {
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
if (this.state.isShowWikiAdd) {
this.onHideWikiAdd();
} else {
this.onShowWikiAdd(e);
}
}
onShowWikiAdd = (e) => {
let left = e.clientX - 10*20;
let top = e.clientY + 12;
let position = {top: top, left: left};
this.setState({
isShowWikiAdd: true,
2018-12-10 13:33:32 +08:00
position: position,
2018-12-08 00:01:23 +08:00
});
}
onHideWikiAdd = () => {
this.setState({
isShowWikiAdd: false,
});
}
onSelectToggle = () => {
this.setState({
isShowSelectDialog: !this.state.isShowSelectDialog,
});
}
onCreateToggle = () => {
this.setState({
isShowCreateDialog: !this.state.isShowCreateDialog,
});
}
addWiki = (isExist, name, repoID) => {
seafileAPI.addWiki(isExist, name, repoID).then((res) => {
this.state.wikis.push(res.data);
this.setState({
wikis: this.state.wikis
});
}).catch((error) => {
if(error.response) {
let errorMsg = error.response.data.error_msg;
Toast.error(errorMsg);
}
});
}
2018-12-08 11:40:28 +08:00
renameWiki = (wiki, newName) => {
seafileAPI.renameWiki(wiki.slug, newName).then((res) => {
let wikis = this.state.wikis.map((item) => {
if (item.name === wiki.name) {
item = res.data;
}
return item;
});
this.setState({
wikis: wikis
});
}).catch((error) => {
if(error.response) {
let errorMsg = error.response.data.error_msg;
Toast.error(errorMsg);
}
});
}
2018-12-08 00:01:23 +08:00
deleteWiki = (wiki) => {
seafileAPI.deleteWiki(wiki.slug).then(() => {
this.setState({
wikis: this.state.wikis.filter(item => {
return item.name !== wiki.name
})
});
}).catch((error) => {
if(error.response) {
let errorMsg = error.response.data.error_msg;
Toast.error(errorMsg);
}
});
}
render() {
return (
2018-12-10 13:33:32 +08:00
<Fragment>
<div className="main-panel-center">
<div className="cur-view-container" id="wikis">
<div className="cur-view-path">
<h3 className="sf-heading">{gettext('Wikis')}</h3>
<div style={{float:'right'}}>
<Button className="fa fa-plus-square" onClick={this.onAddMenuToggle}>
{gettext('Add Wiki')}
</Button>
2018-12-08 00:01:23 +08:00
</div>
2018-12-10 13:33:32 +08:00
{this.state.isShowWikiAdd &&
<WikiAdd
isShowWikiAdd={this.state.isShowWikiAdd}
position={this.state.position}
onSelectToggle={this.onSelectToggle}
onCreateToggle={this.onCreateToggle}
/>
}
</div>
<div className="cur-view-content">
{(this.state.loading || this.state.wikis.length !== 0) &&
<WikisContent
data={this.state}
renameWiki={this.renameWiki}
deleteWiki={this.deleteWiki}
/>
}
{(!this.state.loading && this.state.wikis.length === 0) &&
<div className="message empty-tip">
<h2>{gettext('You do not have any Wiki.')}</h2>
<p>{gettext('Seafile Wiki enables you to organize your knowledge in a simple way. The contents of wiki is stored in a normal library with pre-defined file/folder structure. This enables you to edit your wiki in your desktop and then sync back to the server.')}</p>
</div>
}
</div>
2018-12-08 00:01:23 +08:00
</div>
</div>
2018-12-10 13:33:32 +08:00
{this.state.isShowCreateDialog &&
<ModalPortal>
<NewWikiDialog
toggleCancel={this.onCreateToggle}
addWiki={this.addWiki}
/>
</ModalPortal>
}
{this.state.isShowSelectDialog &&
<ModalPortal>
<WikiSelectDialog
toggleCancel={this.onSelectToggle}
addWiki={this.addWiki}
/>
</ModalPortal>
}
</Fragment>
2018-12-08 00:01:23 +08:00
);
}
}
export default Wikis;