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 >
}
< / t d >
< td > < a href = { userProfileURL } target = '_blank' > { gettext ( wiki . owner _nickname ) } < / a > < / t d >
< td > { moment ( wiki . updated _at ) . fromNow ( ) } < / t d >
< 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 }
/ >
}
< / t d >
< / t r >
{ 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
< / M o d a l P o r t a l >
}
< / F r a g m e n t >
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" > < / s p a n > ;
} else if ( errorMsg ) {
return < p className = "error text-center" > { errorMsg } < / p > ;
} else {
return (
< table >
< thead >
< tr >
< th width = "50%" > { gettext ( 'Name' ) } < / t h >
< th width = "20%" > { gettext ( 'Owner' ) } < / t h >
< th width = "20%" > { gettext ( 'Last Update' ) } < / t h >
< th width = "10%" > { /* operation */ } < / t h >
< / t r >
< / t h e a d >
< 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
} ) }
< / t b o d y >
< / t a b l e >
) ;
}
}
}
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' ) } < / h 3 >
< div style = { { float : 'right' } } >
< Button className = "fa fa-plus-square" onClick = { this . onAddMenuToggle } >
{ gettext ( 'Add Wiki' ) }
< / B u t t o n >
2018-12-08 00:01:23 +08:00
< / d i v >
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 }
/ >
}
< / d i v >
< 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.' ) } < / h 2 >
< 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 >
< / d i v >
}
< / d i v >
2018-12-08 00:01:23 +08:00
< / d i v >
< / d i v >
2018-12-10 13:33:32 +08:00
{ this . state . isShowCreateDialog &&
< ModalPortal >
< NewWikiDialog
toggleCancel = { this . onCreateToggle }
addWiki = { this . addWiki }
/ >
< / M o d a l P o r t a l >
}
{ this . state . isShowSelectDialog &&
< ModalPortal >
< WikiSelectDialog
toggleCancel = { this . onSelectToggle }
addWiki = { this . addWiki }
/ >
< / M o d a l P o r t a l >
}
< / F r a g m e n t >
2018-12-08 00:01:23 +08:00
) ;
}
}
export default Wikis ;