mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-07 01:41:39 +00:00
sysadmin reconstruct links page (#4153)
* sysadmin reconstruct links page * optimize code * optimize code
This commit is contained in:
@@ -1,8 +1,6 @@
|
|||||||
import React, { Component, Fragment } from 'react';
|
import React, { Component, Fragment } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { gettext } from '../utils/constants';
|
import { gettext } from '../utils/constants';
|
||||||
import { Label } from 'reactstrap';
|
|
||||||
|
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
gotoPreviousPage: PropTypes.func.isRequired,
|
gotoPreviousPage: PropTypes.func.isRequired,
|
||||||
@@ -10,7 +8,8 @@ const propTypes = {
|
|||||||
currentPage: PropTypes.number.isRequired,
|
currentPage: PropTypes.number.isRequired,
|
||||||
hasNextPage: PropTypes.bool.isRequired,
|
hasNextPage: PropTypes.bool.isRequired,
|
||||||
canResetPerPage: PropTypes.bool.isRequired,
|
canResetPerPage: PropTypes.bool.isRequired,
|
||||||
resetPerPage: PropTypes.func
|
resetPerPage: PropTypes.func,
|
||||||
|
curPerPage: PropTypes.number,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Paginator extends Component {
|
class Paginator extends Component {
|
||||||
@@ -30,6 +29,7 @@ class Paginator extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
let { curPerPage } = this.props;
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="my-6 text-center">
|
<div className="my-6 text-center">
|
||||||
@@ -41,11 +41,11 @@ class Paginator extends Component {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
{this.props.canResetPerPage &&
|
{this.props.canResetPerPage &&
|
||||||
<div>
|
<div className="text-center">
|
||||||
{gettext('Per page:')}{' '}
|
{gettext('Per page:')}{' '}
|
||||||
<Label onClick={() => {return this.resetPerPage(25);}}>25</Label>
|
<span className={`${curPerPage === 25 ? '' : 'a-simulate '} mr-1`} onClick={() => {return this.resetPerPage(25);}}>25</span>
|
||||||
<Label onClick={() => {return this.resetPerPage(50);}}>50</Label>
|
<span className={`${curPerPage === 50 ? '' : 'a-simulate '} mr-1`} onClick={() => {return this.resetPerPage(50);}}>50</span>
|
||||||
<Label onClick={() => {return this.resetPerPage(100);}}>100</Label>
|
<span className={`${curPerPage === 100 ? '' : 'a-simulate '} mr-1`} onClick={() => {return this.resetPerPage(100);}}>100</span>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
@@ -20,6 +20,9 @@ import Groups from './groups/groups';
|
|||||||
import GroupRepos from './groups/group-repos';
|
import GroupRepos from './groups/group-repos';
|
||||||
import GroupMembers from './groups/group-members';
|
import GroupMembers from './groups/group-members';
|
||||||
|
|
||||||
|
import ShareLinks from './links/share-links';
|
||||||
|
import UploadLinks from './links/upload-links';
|
||||||
|
|
||||||
import WebSettings from './web-settings/web-settings';
|
import WebSettings from './web-settings/web-settings';
|
||||||
import Notifications from './notifications/notifications';
|
import Notifications from './notifications/notifications';
|
||||||
import FileScanRecords from './file-scan-records';
|
import FileScanRecords from './file-scan-records';
|
||||||
@@ -112,6 +115,8 @@ class SysAdmin extends React.Component {
|
|||||||
<Groups path={siteRoot + 'sys/groups'} />
|
<Groups path={siteRoot + 'sys/groups'} />
|
||||||
<GroupRepos path={siteRoot + 'sys/groups/:groupID/libraries'} />
|
<GroupRepos path={siteRoot + 'sys/groups/:groupID/libraries'} />
|
||||||
<GroupMembers path={siteRoot + 'sys/groups/:groupID/members'} />
|
<GroupMembers path={siteRoot + 'sys/groups/:groupID/members'} />
|
||||||
|
<ShareLinks path={siteRoot + 'sys/share-links'} />
|
||||||
|
<UploadLinks path={siteRoot + 'sys/upload-links'} />
|
||||||
<FileScanRecords
|
<FileScanRecords
|
||||||
path={siteRoot + 'sys/file-scan-records'}
|
path={siteRoot + 'sys/file-scan-records'}
|
||||||
currentTab={currentTab}
|
currentTab={currentTab}
|
||||||
|
40
frontend/src/pages/sys-admin/links/links-nav.js
Normal file
40
frontend/src/pages/sys-admin/links/links-nav.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Link } from '@reach/router';
|
||||||
|
import { siteRoot, gettext } from '../../../utils/constants';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
currentItem: PropTypes.string.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
class Nav extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.navItems = [
|
||||||
|
{name: 'shareLinks', urlPart:'share-links', text: gettext('Share Links')},
|
||||||
|
{name: 'uploadLinks', urlPart:'upload-links', text: gettext('Upload Links')},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { currentItem } = this.props;
|
||||||
|
return (
|
||||||
|
<div className="cur-view-path tab-nav-container">
|
||||||
|
<ul className="nav">
|
||||||
|
{this.navItems.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<li className="nav-item" key={index}>
|
||||||
|
<Link to={`${siteRoot}sys/${item.urlPart}/`} className={`nav-link${currentItem == item.name ? ' active' : ''}`}>{item.text}</Link>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Nav.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default Nav;
|
222
frontend/src/pages/sys-admin/links/share-links.js
Normal file
222
frontend/src/pages/sys-admin/links/share-links.js
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
import React, { Component, Fragment } from 'react';
|
||||||
|
import { seafileAPI } from '../../../utils/seafile-api';
|
||||||
|
import { gettext, loginUrl, siteRoot } from '../../../utils/constants';
|
||||||
|
import toaster from '../../../components/toast';
|
||||||
|
import { Utils } from '../../../utils/utils';
|
||||||
|
import EmptyTip from '../../../components/empty-tip';
|
||||||
|
import moment from 'moment';
|
||||||
|
import Loading from '../../../components/loading';
|
||||||
|
import Paginator from '../../../components/paginator';
|
||||||
|
import LinksNav from './links-nav';
|
||||||
|
import MainPanelTopbar from '../main-panel-topbar';
|
||||||
|
|
||||||
|
|
||||||
|
class Content extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
getPreviousPage = () => {
|
||||||
|
this.props.getShareLinksByPage(this.props.currentPage - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
getNextPage = () => {
|
||||||
|
this.props.getShareLinksByPage(this.props.currentPage + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { loading, errorMsg, items, perPage, currentPage , hasNextPage }= this.props;
|
||||||
|
if (loading) {
|
||||||
|
return <Loading />;
|
||||||
|
} else if (errorMsg) {
|
||||||
|
return <p className="error text-center">{errorMsg}</p>;
|
||||||
|
} else {
|
||||||
|
const emptyTip = (
|
||||||
|
<EmptyTip>
|
||||||
|
<h2>{gettext('No Share Links.')}</h2>
|
||||||
|
</EmptyTip>
|
||||||
|
);
|
||||||
|
const table = (
|
||||||
|
<Fragment>
|
||||||
|
<table className="table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="18%">{gettext('Name')}</th>
|
||||||
|
<th width="18%">{gettext('Token')}</th>
|
||||||
|
<th width="18%">{gettext('Owner')}</th>
|
||||||
|
<th width="18%">{gettext('Created At')}</th>
|
||||||
|
<th width="18%">{gettext('Count')}</th>
|
||||||
|
<th width="10%">{/*Operations*/}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
{items &&
|
||||||
|
<tbody>
|
||||||
|
{items.map((item, index) => {
|
||||||
|
return (<Item
|
||||||
|
key={index}
|
||||||
|
item={item}
|
||||||
|
deleteShareLink={this.props.deleteShareLink}
|
||||||
|
/>);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
<Paginator
|
||||||
|
gotoPreviousPage={this.getPreviousPage}
|
||||||
|
gotoNextPage={this.getNextPage}
|
||||||
|
currentPage={currentPage}
|
||||||
|
hasNextPage={hasNextPage}
|
||||||
|
canResetPerPage={true}
|
||||||
|
curPerPage={perPage}
|
||||||
|
resetPerPage={this.props.resetPerPage}
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
return items.length ? table : emptyTip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Item extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isOpIconShown: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMouseOver = () => {
|
||||||
|
this.setState({
|
||||||
|
isOpIconShown: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMouseOut = () => {
|
||||||
|
this.setState({
|
||||||
|
isOpIconShown: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteShareLink = () => {
|
||||||
|
this.props.deleteShareLink(this.props.item.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { isOpIconShown } = this.state;
|
||||||
|
let { item } = this.props;
|
||||||
|
let deleteIcon = `op-icon sf2-icon-delete ${isOpIconShown ? '' : 'invisible'}`;
|
||||||
|
return (
|
||||||
|
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut}>
|
||||||
|
<td>{item.obj_name}</td>
|
||||||
|
<td>{item.token}</td>
|
||||||
|
<td><a href={siteRoot + 'useradmin/info/' + item.creator_email + '/'}>{item.creator_name}</a></td>
|
||||||
|
<td>{moment(item.ctime).fromNow()}</td>
|
||||||
|
<td>{item.view_cnt}</td>
|
||||||
|
<td>
|
||||||
|
<a href="#" className={deleteIcon} title={gettext('delete')} onClick={this.deleteShareLink}></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShareLinks extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
loading: true,
|
||||||
|
errorMsg: '',
|
||||||
|
shareLinkList: [],
|
||||||
|
perPage: 100,
|
||||||
|
currentPage: 1,
|
||||||
|
hasNextPage: false,
|
||||||
|
};
|
||||||
|
this.initPage = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
this.getShareLinksByPage(this.initPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
getShareLinksByPage = (page) => {
|
||||||
|
let { perPage } = this.state;
|
||||||
|
seafileAPI.sysAdminListAllShareLinks(page, perPage).then((res) => {
|
||||||
|
this.setState({
|
||||||
|
shareLinkList: res.data.share_link_list,
|
||||||
|
loading: false,
|
||||||
|
currentPage: page,
|
||||||
|
hasNextPage: Utils.hasNextPage(page, perPage, res.data.count),
|
||||||
|
});
|
||||||
|
}).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.')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteShareLink = (linkToken) => {
|
||||||
|
seafileAPI.sysAdminDeleteShareLink(linkToken).then(res => {
|
||||||
|
let newShareLinkList = this.state.shareLinkList.filter(item =>
|
||||||
|
item.token != linkToken
|
||||||
|
);
|
||||||
|
this.setState({shareLinkList: newShareLinkList});
|
||||||
|
}).catch(error => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
resetPerPage = (newPerPage) => {
|
||||||
|
this.setState({
|
||||||
|
perPage: newPerPage,
|
||||||
|
}, () => this.getShareLinksByPage(this.initPage));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { shareLinkList, currentPage, perPage, hasNextPage } = this.state;
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<MainPanelTopbar />
|
||||||
|
<div className="main-panel-center flex-row">
|
||||||
|
<div className="cur-view-container">
|
||||||
|
<LinksNav currentItem="shareLinks" />
|
||||||
|
<div className="cur-view-content">
|
||||||
|
<Content
|
||||||
|
loading={this.state.loading}
|
||||||
|
errorMsg={this.state.errorMsg}
|
||||||
|
items={shareLinkList}
|
||||||
|
currentPage={currentPage}
|
||||||
|
perPage={perPage}
|
||||||
|
hasNextPage={hasNextPage}
|
||||||
|
getShareLinksByPage={this.getShareLinksByPage}
|
||||||
|
resetPerPage={this.resetPerPage}
|
||||||
|
deleteShareLink={this.deleteShareLink}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ShareLinks;
|
224
frontend/src/pages/sys-admin/links/upload-links.js
Normal file
224
frontend/src/pages/sys-admin/links/upload-links.js
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
import React, { Component, Fragment } from 'react';
|
||||||
|
import { seafileAPI } from '../../../utils/seafile-api';
|
||||||
|
import { gettext, loginUrl, siteRoot } from '../../../utils/constants';
|
||||||
|
import toaster from '../../../components/toast';
|
||||||
|
import { Utils } from '../../../utils/utils';
|
||||||
|
import EmptyTip from '../../../components/empty-tip';
|
||||||
|
import moment from 'moment';
|
||||||
|
import Loading from '../../../components/loading';
|
||||||
|
import Paginator from '../../../components/paginator';
|
||||||
|
import LinksNav from './links-nav';
|
||||||
|
import MainPanelTopbar from '../main-panel-topbar';
|
||||||
|
|
||||||
|
|
||||||
|
class Content extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
getPreviousPage = () => {
|
||||||
|
this.props.getUploadLinksByPage(this.props.currentPage - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
getNextPage = () => {
|
||||||
|
this.props.getUploadLinksByPage(this.props.currentPage + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { loading, errorMsg, items, perPage, currentPage, hasNextPage } = this.props;
|
||||||
|
if (loading) {
|
||||||
|
return <Loading />;
|
||||||
|
} else if (errorMsg) {
|
||||||
|
return <p className="error text-center">{errorMsg}</p>;
|
||||||
|
} else {
|
||||||
|
const emptyTip = (
|
||||||
|
<EmptyTip>
|
||||||
|
<h2>{gettext('No Upload Links.')}</h2>
|
||||||
|
</EmptyTip>
|
||||||
|
);
|
||||||
|
const table = (
|
||||||
|
<Fragment>
|
||||||
|
<table className="table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="18%">{gettext('Name')}</th>
|
||||||
|
<th width="18%">{gettext('Token')}</th>
|
||||||
|
<th width="18%">{gettext('Owner')}</th>
|
||||||
|
<th width="18%">{gettext('Created At')}</th>
|
||||||
|
<th width="18%">{gettext('Count')}</th>
|
||||||
|
<th width="10%">{/*Operations*/}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
{items &&
|
||||||
|
<tbody>
|
||||||
|
{items.map((item, index) => {
|
||||||
|
return (<Item
|
||||||
|
key={index}
|
||||||
|
item={item}
|
||||||
|
deleteUploadLink={this.props.deleteUploadLink}
|
||||||
|
/>);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
<Paginator
|
||||||
|
gotoPreviousPage={this.getPreviousPage}
|
||||||
|
gotoNextPage={this.getNextPage}
|
||||||
|
currentPage={currentPage}
|
||||||
|
hasNextPage={hasNextPage}
|
||||||
|
canResetPerPage={true}
|
||||||
|
curPerPage={perPage}
|
||||||
|
resetPerPage={this.props.resetPerPage}
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
return items.length ? table : emptyTip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Item extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isOpIconShown: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMouseOver = () => {
|
||||||
|
this.setState({
|
||||||
|
isOpIconShown: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMouseOut = () => {
|
||||||
|
this.setState({
|
||||||
|
isOpIconShown: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteUploadLink = () => {
|
||||||
|
this.props.deleteUploadLink(this.props.item.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { isOpIconShown } = this.state;
|
||||||
|
let { item } = this.props;
|
||||||
|
let deleteIcon = `op-icon sf2-icon-delete ${isOpIconShown ? '' : 'invisible'}`;
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<tr onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut}>
|
||||||
|
<td>{item.path}</td>
|
||||||
|
<td>{item.token}</td>
|
||||||
|
<td><a href={siteRoot + 'useradmin/info/' + item.creator_email + '/'}>{item.creator_name}</a></td>
|
||||||
|
<td>{moment(item.ctime).fromNow()}</td>
|
||||||
|
<td>{item.view_cnt}</td>
|
||||||
|
<td>
|
||||||
|
<a href="#" className={deleteIcon} title={gettext('delete')} onClick={this.deleteUploadLink}></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UploadLinks extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
loading: true,
|
||||||
|
errorMsg: '',
|
||||||
|
uploadLinkList: [],
|
||||||
|
perPage: 100,
|
||||||
|
currentPage: 1,
|
||||||
|
hasNextPage: false,
|
||||||
|
};
|
||||||
|
this.initPage = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
this.getUploadLinksByPage(this.initPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUploadLinksByPage = (page) => {
|
||||||
|
let { perPage } = this.state;
|
||||||
|
seafileAPI.sysAdminListAllUploadLinks(page, perPage).then((res) => {
|
||||||
|
this.setState({
|
||||||
|
uploadLinkList: res.data.upload_link_list,
|
||||||
|
loading: false,
|
||||||
|
currentPage: page,
|
||||||
|
hasNextPage: Utils.hasNextPage(page, perPage, res.data.count),
|
||||||
|
});
|
||||||
|
}).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.')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteUploadLink = (linkToken) => {
|
||||||
|
seafileAPI.sysAdminDeleteUploadLink(linkToken).then(res => {
|
||||||
|
let newUploadLinkList = this.state.uploadLinkList.filter(item =>
|
||||||
|
item.token != linkToken
|
||||||
|
);
|
||||||
|
this.setState({uploadLinkList: newUploadLinkList});
|
||||||
|
}).catch(error => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
resetPerPage = (newPerPage) => {
|
||||||
|
this.setState({
|
||||||
|
perPage: newPerPage,
|
||||||
|
}, () => this.getShareLinksByPage(this.initPage));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { uploadLinkList, currentPage, perPage, hasNextPage } = this.state;
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<MainPanelTopbar />
|
||||||
|
<div className="main-panel-center flex-row">
|
||||||
|
<div className="cur-view-container">
|
||||||
|
<LinksNav currentItem="uploadLinks" />
|
||||||
|
<div className="cur-view-content">
|
||||||
|
<Content
|
||||||
|
loading={this.state.loading}
|
||||||
|
errorMsg={this.state.errorMsg}
|
||||||
|
items={uploadLinkList}
|
||||||
|
currentPage={currentPage}
|
||||||
|
perPage={perPage}
|
||||||
|
hasNextPage={hasNextPage}
|
||||||
|
getUploadLinksByPage={this.getUploadLinksByPage}
|
||||||
|
resetPerPage={this.resetPerPage}
|
||||||
|
deleteUploadLink={this.deleteUploadLink}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UploadLinks;
|
@@ -145,10 +145,14 @@ class SidePanel extends React.Component {
|
|||||||
}
|
}
|
||||||
{isDefaultAdmin &&
|
{isDefaultAdmin &&
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<a className='nav-link ellipsis' href={siteRoot + 'sys/publinkadmin/'}>
|
<Link
|
||||||
<span className="sf2-icon-link" aria-hidden="true"></span>
|
className={`nav-link ellipsis ${this.getActiveClass('links')}`}
|
||||||
|
to={siteRoot + 'sys/share-links/'}
|
||||||
|
onClick={() => this.props.tabItemClick('links')}
|
||||||
|
>
|
||||||
|
<span className="sf2-icon-msgs" aria-hidden="true"></span>
|
||||||
<span className="nav-text">{gettext('Links')}</span>
|
<span className="nav-text">{gettext('Links')}</span>
|
||||||
</a>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
{sysadminExtraEnabled && canViewUserLog &&
|
{sysadminExtraEnabled && canViewUserLog &&
|
||||||
|
@@ -1192,6 +1192,12 @@ export const Utils = {
|
|||||||
result = '00:' + result;
|
result = '00:' + result;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
hasNextPage(curPage, perPage, totalCount) {
|
||||||
|
// when curPage * perPage >= totalCount, do not have next page.
|
||||||
|
// so hasNextPage = true, when curPage * perPage < totalCount
|
||||||
|
return curPage * perPage < totalCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@@ -675,7 +675,8 @@ urlpatterns = [
|
|||||||
url(r'^sys/organizations/(?P<org_id>\d+)/groups/$', sysadmin_org_react_fake_view, name="sys_organization_groups"),
|
url(r'^sys/organizations/(?P<org_id>\d+)/groups/$', sysadmin_org_react_fake_view, name="sys_organization_groups"),
|
||||||
url(r'^sys/organizations/(?P<org_id>\d+)/libraries/$', sysadmin_org_react_fake_view, name="sys_organization_repos"),
|
url(r'^sys/organizations/(?P<org_id>\d+)/libraries/$', sysadmin_org_react_fake_view, name="sys_organization_repos"),
|
||||||
url(r'^sys/organizations/(?P<org_id>\d+)/settings/$', sysadmin_org_react_fake_view, name="sys_organization_settings"),
|
url(r'^sys/organizations/(?P<org_id>\d+)/settings/$', sysadmin_org_react_fake_view, name="sys_organization_settings"),
|
||||||
|
url(r'^sys/share-links/$', sysadmin_react_fake_view, name="sys_share_links"),
|
||||||
|
url(r'^sys/upload-links/$', sysadmin_react_fake_view, name="sys_upload_links"),
|
||||||
url(r'^sys/work-weixin/$', sysadmin_react_fake_view, name="sys_work_weixin"),
|
url(r'^sys/work-weixin/$', sysadmin_react_fake_view, name="sys_work_weixin"),
|
||||||
url(r'^sys/work-weixin/departments/$', sysadmin_react_fake_view, name="sys_work_weixin_departments"),
|
url(r'^sys/work-weixin/departments/$', sysadmin_react_fake_view, name="sys_work_weixin_departments"),
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user