import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import dayjs from 'dayjs'; import classnames from 'classnames'; import { Link } from '@gatsbyjs/reach-router'; import { Utils } from '../../../utils/utils'; import { seafileAPI } from '../../../utils/seafile-api'; import { repoShareAdminAPI } from '../../../utils/repo-share-admin-api'; import { gettext, siteRoot } from '../../../utils/constants'; import Loading from '../../../components/loading'; import toaster from '../../../components/toast'; import EmptyTip from '../../../components/empty-tip'; import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog'; const itemPropTypes = { item: PropTypes.object.isRequired, deleteItem: PropTypes.func.isRequired, toggleSelectLink: PropTypes.func.isRequired }; class Item extends Component { constructor(props) { super(props); this.state = { isOperationShow: false }; } onMouseEnter = () => { this.setState({ isOperationShow: true }); }; onMouseLeave = () => { this.setState({ isOperationShow: false }); }; onDeleteLink = () => { this.props.deleteItem(this.props.item); }; cutLink = (link) => { let length = link.length; return link.slice(0, 9) + '...' + link.slice(length - 5); }; toggleSelectLink = (e) => { const { item } = this.props; this.props.toggleSelectLink(item, e.target.checked); }; render() { let item = this.props.item; let path = item.path === '/' ? '/' : item.path.slice(0, item.path.length - 1); let objUrl = `${siteRoot}library/${item.repo_id}/${encodeURIComponent(item.repo_name)}${Utils.encodePath(path)}`; return ( {item.creator_name} {item.creator_name} {item.obj_name} {this.cutLink(item.link)} {item.expire_date ? dayjs(item.expire_date).format('YYYY-MM-DD HH:mm') : '--'} {item.view_cnt} ); } } Item.propTypes = itemPropTypes; const propTypes = { repo: PropTypes.object.isRequired, }; const PER_PAGE = 25; class RepoShareAdminUploadLinks extends Component { constructor(props) { super(props); this.state = { loading: true, hasMore: false, isLoadingMore: false, page: 1, errorMsg: '', items: [], isDeleteUploadLinksDialogOpen: false }; } componentDidMount() { const { repo } = this.props; const { page } = this.state; repoShareAdminAPI.listRepoUploadLinks(repo.repo_id, page).then((res) => { this.setState({ loading: false, hasMore: res.data.length == PER_PAGE, items: res.data, }); }).catch((error) => { this.setState({ loading: false, errorMsg: Utils.getErrorMsg(error, true) // true: show login tip if 403 }); }); } deleteItem = (item) => { seafileAPI.deleteRepoUploadLink(this.props.repo.repo_id, item.token).then(() => { let items = this.state.items.filter(linkItem => { return linkItem.token !== item.token; }); this.setState({ items: items }); let message = gettext('Successfully deleted 1 item'); toaster.success(message); }).catch((error) => { let errMessage = Utils.getErrorMsg(error); toaster.danger(errMessage); }); }; toggleDeleteUploadLinksDialog = () => { this.setState({ isDeleteUploadLinksDialogOpen: !this.state.isDeleteUploadLinksDialogOpen }); }; toggleSelectAllLinks = (e) => { this._toggleSelectAllLinks(e.target.checked); }; cancelSelectAllLinks = () => { this._toggleSelectAllLinks(false); }; _toggleSelectAllLinks = (isSelected) => { const { items: links } = this.state; this.setState({ items: links.map(item => { item.isSelected = isSelected; return item; }) }); }; toggleSelectLink = (link, isSelected) => { const { items: links } = this.state; this.setState({ items: links.map(item => { if (item.token == link.token) { item.isSelected = isSelected; } return item; }) }); }; deleteUploadLinks = () => { const { items } = this.state; const tokens = items.filter(item => item.isSelected).map(link => link.token); repoShareAdminAPI.deleteUploadLinks(tokens).then(res => { const { success, failed } = res.data; if (success.length) { let newLinkList = items.filter(link => { return !success.some(deletedLink => { return deletedLink.token == link.token; }); }); this.setState({ items: newLinkList }); const length = success.length; const msg = length == 1 ? gettext('Successfully deleted 1 upload link') : gettext('Successfully deleted {number_placeholder} upload links') .replace('{number_placeholder}', length); toaster.success(msg); } failed.forEach(item => { const msg = `${item.token}: ${item.error_msg}`; toaster.danger(msg); }); }).catch((error) => { let errMessage = Utils.getErrorMsg(error); toaster.danger(errMessage); }); }; getTheadContent = (withCheckbox, isAllLinksSelected) => { return ( {withCheckbox && } {gettext('Creator')} {gettext('Name')} {gettext('Link')} {gettext('Expiration')} {gettext('Visits')} ); }; handleScroll = (event) => { if (!this.state.isLoadingMore && this.state.hasMore) { const clientHeight = event.target.clientHeight; const scrollHeight = event.target.scrollHeight; const scrollTop = event.target.scrollTop; const isBottom = (clientHeight + scrollTop + 1 >= scrollHeight); if (isBottom) { // scroll to the bottom this.setState({ isLoadingMore: true }, () => { this.getMore(); }); } } }; getMore = () => { const { page, items } = this.state; const { repo } = this.props; repoShareAdminAPI.listRepoUploadLinks(repo.repo_id, page + 1).then((res) => { this.setState({ isLoadingMore: false, hasMore: res.data.length == PER_PAGE, page: page + 1, items: items.concat(res.data) }); }).catch(error => { this.setState({ isLoadingMore: false }); let errMessage = Utils.getErrorMsg(error); toaster.danger(errMessage); }); }; render() { const { loading, isLoadingMore, errorMsg, items, isDeleteUploadLinksDialogOpen } = this.state; const selectedLinks = items.filter(item => item.isSelected); const isAllLinksSelected = items.length == selectedLinks.length; return (
{gettext('Upload Links')}
{selectedLinks.length > 0 && ( <> )}
{loading && } {!loading && errorMsg &&

{errorMsg}

} {!loading && !errorMsg && !items.length && } {!loading && !errorMsg && items.length > 0 && ( <> {this.getTheadContent(true, isAllLinksSelected)}
{this.getTheadContent(false)} {items.map((item, index) => { return ( ); })}
{isLoadingMore && }
)} {isDeleteUploadLinksDialogOpen && ( )}
); } } RepoShareAdminUploadLinks.propTypes = propTypes; export default RepoShareAdminUploadLinks;