2019-07-02 03:06:39 +00:00
import React , { Component , Fragment } from 'react' ;
2018-11-19 03:53:44 +00:00
import { Link } from '@reach/router' ;
2019-07-02 03:06:39 +00:00
import moment from 'moment' ;
2019-08-21 08:36:55 +00:00
import { Dropdown , DropdownToggle , DropdownItem } from 'reactstrap' ;
2019-12-05 07:45:16 +00:00
import { gettext , siteRoot , canGenerateShareLink } from '../../utils/constants' ;
2018-11-19 03:53:44 +00:00
import { seafileAPI } from '../../utils/seafile-api' ;
import { Utils } from '../../utils/utils' ;
2019-07-16 02:01:09 +00:00
import toaster from '../../components/toast' ;
2019-08-21 08:36:55 +00:00
import Loading from '../../components/loading' ;
2019-06-10 09:30:10 +00:00
import EmptyTip from '../../components/empty-tip' ;
2019-08-21 08:36:55 +00:00
import UploadLink from '../../models/upload-link' ;
import ShareAdminLink from '../../components/dialog/share-admin-link' ;
2018-11-19 03:53:44 +00:00
class Content extends Component {
2018-12-26 08:07:22 +00:00
2018-11-19 03:53:44 +00:00
render ( ) {
2018-12-27 02:24:34 +00:00
const { loading , errorMsg , items } = this . props ;
2018-11-19 03:53:44 +00:00
if ( loading ) {
2019-08-21 08:36:55 +00:00
return < Loading / > ;
}
if ( errorMsg ) {
2018-11-19 03:53:44 +00:00
return < p className = "error text-center" > { errorMsg } < / p > ;
2020-11-02 05:56:35 +00:00
}
2018-11-19 03:53:44 +00:00
2019-08-21 08:36:55 +00:00
const emptyTip = (
< EmptyTip >
2020-01-03 08:50:17 +00:00
< h2 > { gettext ( 'No upload links' ) } < / h 2 >
< p > { gettext ( 'You have not created any upload links yet. An upload link allows anyone to upload files to a folder or library. You can create an upload link for a folder or library by clicking the share icon to the right of its name.' ) } < / p >
2019-08-21 08:36:55 +00:00
< / E m p t y T i p >
) ;
2018-11-19 03:53:44 +00:00
2019-08-21 08:36:55 +00:00
const isDesktop = Utils . isDesktop ( ) ;
const table = (
< table className = { ` table-hover ${ isDesktop ? '' : 'table-thead-hidden' } ` } >
< thead >
{ isDesktop ? (
< tr >
< th width = "4%" > { /*icon*/ } < / t h >
< th width = "30%" > { gettext ( 'Name' ) } < / t h >
< th width = "24%" > { gettext ( 'Library' ) } < / t h >
< th width = "16%" > { gettext ( 'Visits' ) } < / t h >
< th width = "16%" > { gettext ( 'Expiration' ) } < / t h >
< th width = "10%" > { /*Operations*/ } < / t h >
< / t r >
2020-11-02 05:56:35 +00:00
) : (
2019-08-21 08:36:55 +00:00
< tr >
< th width = "12%" > < / t h >
< th width = "80%" > < / t h >
< th width = "8%" > < / t h >
2020-11-02 05:56:35 +00:00
< / t r >
) }
2019-08-21 08:36:55 +00:00
< / t h e a d >
< tbody >
{ items . map ( ( item , index ) => {
return ( < Item key = { index } isDesktop = { isDesktop } item = { item } onRemoveLink = { this . props . onRemoveLink } / > ) ;
} ) }
< / t b o d y >
< / t a b l e >
) ;
2020-11-02 05:56:35 +00:00
return items . length ? table : emptyTip ;
2018-11-19 03:53:44 +00:00
}
}
class Item extends Component {
constructor ( props ) {
super ( props ) ;
this . state = {
2019-08-21 08:36:55 +00:00
isOpIconShown : false ,
isOpMenuOpen : false , // for mobile
isLinkDialogOpen : false
2018-11-19 03:53:44 +00:00
} ;
}
2019-08-21 08:36:55 +00:00
toggleOpMenu = ( ) => {
this . setState ( {
isOpMenuOpen : ! this . state . isOpMenuOpen
} ) ;
}
toggleLinkDialog = ( ) => {
this . setState ( {
isLinkDialogOpen : ! this . state . isLinkDialogOpen
2020-11-02 05:56:35 +00:00
} ) ;
2019-08-21 08:36:55 +00:00
}
2018-12-26 08:07:22 +00:00
handleMouseOver = ( ) => {
2019-08-21 08:36:55 +00:00
this . setState ( { isOpIconShown : true } ) ;
2018-11-19 03:53:44 +00:00
}
2018-12-26 08:07:22 +00:00
handleMouseOut = ( ) => {
2019-08-21 08:36:55 +00:00
this . setState ( { isOpIconShown : false } ) ;
2018-11-19 03:53:44 +00:00
}
2018-12-26 08:07:22 +00:00
viewLink = ( e ) => {
2018-11-19 03:53:44 +00:00
e . preventDefault ( ) ;
2019-08-21 08:36:55 +00:00
this . toggleLinkDialog ( ) ;
2018-11-19 03:53:44 +00:00
}
2020-11-02 05:56:35 +00:00
2018-12-26 08:07:22 +00:00
removeLink = ( e ) => {
2018-11-19 03:53:44 +00:00
e . preventDefault ( ) ;
2018-12-27 02:24:34 +00:00
this . props . onRemoveLink ( this . props . item ) ;
2018-11-19 03:53:44 +00:00
}
2019-08-21 08:36:55 +00:00
renderExpiration = ( ) => {
2020-05-25 09:29:16 +00:00
const item = this . props . item ;
2019-07-02 03:06:39 +00:00
if ( ! item . expire _date ) {
2020-05-25 09:29:16 +00:00
return '--' ;
2020-11-02 05:56:35 +00:00
}
2020-05-25 09:29:16 +00:00
const expire _date = moment ( item . expire _date ) . format ( 'YYYY-MM-DD' ) ;
const expire _time = moment ( item . expire _date ) . format ( 'YYYY-MM-DD HH:mm:ss' ) ;
return ( < span className = { item . is _expired ? 'error' : '' } title = { expire _time } > { expire _date } < / s p a n > ) ;
2019-07-02 03:06:39 +00:00
}
2018-12-27 02:24:34 +00:00
render ( ) {
let item = this . props . item ;
2019-08-21 08:36:55 +00:00
const { isOpIconShown , isLinkDialogOpen } = this . state ;
2018-11-19 03:53:44 +00:00
2019-08-21 08:36:55 +00:00
const iconUrl = Utils . getFolderIconUrl ( false ) ;
const repoUrl = ` ${ siteRoot } library/ ${ item . repo _id } / ${ encodeURIComponent ( item . repo _name ) } ` ;
const objUrl = ` ${ repoUrl } ${ Utils . encodePath ( item . path ) } ` ;
2018-11-19 03:53:44 +00:00
2019-08-21 08:36:55 +00:00
const desktopItem = (
2021-09-24 09:11:14 +00:00
< tr onMouseOver = { this . handleMouseOver } onMouseOut = { this . handleMouseOut } onFocus = { this . handleMouseOver } >
2019-08-21 08:36:55 +00:00
< td > < img src = { iconUrl } alt = "" width = "24" / > < / t d >
< td > < Link to = { objUrl } > { item . obj _name } < / L i n k > < / t d >
< td > < Link to = { repoUrl } > { item . repo _name } < / L i n k > < / t d >
2018-12-27 02:24:34 +00:00
< td > { item . view _cnt } < / t d >
2019-08-21 08:36:55 +00:00
< td > { this . renderExpiration ( ) } < / t d >
2018-11-19 03:53:44 +00:00
< td >
2021-09-24 09:11:14 +00:00
{ ! item . is _expired && < a href = "#" className = { ` sf2-icon-link action-icon ${ isOpIconShown ? '' : 'invisible' } ` } title = { gettext ( 'View' ) } aria - label = { gettext ( 'View' ) } role = "button" onClick = { this . viewLink } > < / a > }
< a href = "#" className = { ` sf2-icon-delete action-icon ${ isOpIconShown ? '' : 'invisible' } ` } title = { gettext ( 'Remove' ) } aria - label = { gettext ( 'Remove' ) } role = "button" onClick = { this . removeLink } > < / a >
2018-11-19 03:53:44 +00:00
< / t d >
< / t r >
) ;
2019-08-21 08:36:55 +00:00
const mobileItem = (
< tr >
< td > < img src = { iconUrl } alt = "" width = "24" / > < / t d >
< td >
2020-11-02 05:56:35 +00:00
< Link to = { objUrl } > { item . obj _name } < / L i n k >
2019-08-21 08:36:55 +00:00
< br / >
< span > { item . repo _name } < /span><br / >
< span className = "item-meta-info" > { item . view _cnt } < span className = "small text-secondary" > ( { gettext ( 'Visits' ) } ) < / s p a n > < / s p a n >
< span className = "item-meta-info" > { this . renderExpiration ( ) } < span className = "small text-secondary" > ( { gettext ( 'Expiration' ) } ) < / s p a n > < / s p a n >
< / t d >
< td >
< Dropdown isOpen = { this . state . isOpMenuOpen } toggle = { this . toggleOpMenu } >
< DropdownToggle
tag = "i"
className = "sf-dropdown-toggle fa fa-ellipsis-v ml-0"
title = { gettext ( 'More Operations' ) }
data - toggle = "dropdown"
aria - expanded = { this . state . isOpMenuOpen }
/ >
< div className = { this . state . isOpMenuOpen ? '' : 'd-none' } onClick = { this . toggleOpMenu } >
< div className = "mobile-operation-menu-bg-layer" > < / d i v >
< div className = "mobile-operation-menu" >
{ ! item . is _expired && < DropdownItem className = "mobile-menu-item" onClick = { this . viewLink } > { gettext ( 'View' ) } < / D r o p d o w n I t e m > }
< DropdownItem className = "mobile-menu-item" onClick = { this . removeLink } > { gettext ( 'Remove' ) } < / D r o p d o w n I t e m >
< / d i v >
< / d i v >
< / D r o p d o w n >
< / t d >
< / t r >
) ;
return (
< Fragment >
{ this . props . isDesktop ? desktopItem : mobileItem }
{ isLinkDialogOpen &&
< ShareAdminLink
link = { item . link }
toggleDialog = { this . toggleLinkDialog }
/ >
}
< / F r a g m e n t >
) ;
2018-11-19 03:53:44 +00:00
}
}
class ShareAdminUploadLinks extends Component {
2018-12-26 08:07:22 +00:00
2018-11-19 03:53:44 +00:00
constructor ( props ) {
super ( props ) ;
this . state = {
loading : true ,
errorMsg : '' ,
items : [ ]
} ;
}
componentDidMount ( ) {
2020-01-11 05:29:04 +00:00
seafileAPI . listUserUploadLinks ( ) . then ( ( res ) => {
2018-12-27 02:24:34 +00:00
let items = res . data . map ( item => {
2019-08-21 08:36:55 +00:00
return new UploadLink ( item ) ;
2018-12-27 02:24:34 +00:00
} ) ;
2018-11-19 03:53:44 +00:00
this . setState ( {
loading : false ,
2018-12-27 02:24:34 +00:00
items : items
2018-11-19 03:53:44 +00:00
} ) ;
} ) . catch ( ( error ) => {
2019-12-05 07:45:16 +00:00
this . setState ( {
loading : false ,
errorMsg : Utils . getErrorMsg ( error , true ) // true: show login tip if 403
} ) ;
2018-11-19 03:53:44 +00:00
} ) ;
}
2018-12-27 02:24:34 +00:00
onRemoveLink = ( item ) => {
seafileAPI . deleteUploadLink ( item . token ) . then ( ( ) => {
let items = this . state . items . filter ( uploadItem => {
return uploadItem . token !== item . token ;
} ) ;
this . setState ( { items : items } ) ;
2019-08-21 08:36:55 +00:00
const message = gettext ( 'Successfully deleted 1 item.' ) ;
2019-07-16 02:01:09 +00:00
toaster . success ( message ) ;
2018-12-27 02:24:34 +00:00
} ) . catch ( ( error ) => {
2019-08-21 08:36:55 +00:00
const errMessage = Utils . getErrorMsg ( error ) ;
2019-07-16 02:01:09 +00:00
toaster . danger ( errMessage ) ;
2018-12-27 02:24:34 +00:00
} ) ;
}
2018-11-19 03:53:44 +00:00
render ( ) {
return (
2018-11-26 09:53:18 +00:00
< div className = "main-panel-center" >
< div className = "cur-view-container" >
2019-02-20 05:11:13 +00:00
< div className = "cur-view-path share-upload-nav" >
2018-11-26 09:53:18 +00:00
< ul className = "nav" >
2019-08-21 08:36:55 +00:00
{ canGenerateShareLink && (
2018-12-27 02:24:34 +00:00
< li className = "nav-item" > < Link to = { ` ${ siteRoot } share-admin-share-links/ ` } className = "nav-link" > { gettext ( 'Share Links' ) } < / L i n k > < / l i >
) }
2018-11-26 09:53:18 +00:00
< li className = "nav-item" > < Link to = { ` ${ siteRoot } share-admin-upload-links/ ` } className = "nav-link active" > { gettext ( 'Upload Links' ) } < / L i n k > < / l i >
< / u l >
< / d i v >
< div className = "cur-view-content" >
2018-12-27 02:24:34 +00:00
< Content
2019-08-21 08:36:55 +00:00
loading = { this . state . loading }
2018-12-27 02:24:34 +00:00
errorMsg = { this . state . errorMsg }
items = { this . state . items }
onRemoveLink = { this . onRemoveLink }
/ >
2018-11-26 06:00:32 +00:00
< / d i v >
2018-11-19 03:53:44 +00:00
< / d i v >
2018-11-26 09:53:18 +00:00
< / d i v >
2018-11-19 03:53:44 +00:00
) ;
}
}
export default ShareAdminUploadLinks ;