mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-17 15:53:28 +00:00
['share dialog' - 'Share Link', 'Share Admin' - 'Links'] share links: get limited links per request, scroll down to get more (#5840)
This commit is contained in:
@@ -18,6 +18,8 @@ const propTypes = {
|
||||
itemType: PropTypes.string
|
||||
};
|
||||
|
||||
const PER_PAGE = 25;
|
||||
|
||||
class ShareLinkPanel extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
@@ -28,6 +30,9 @@ class ShareLinkPanel extends React.Component {
|
||||
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
hasMore: false,
|
||||
isLoadingMore: false,
|
||||
page: 1,
|
||||
mode: 'listLinks',
|
||||
sharedLinkInfo: null,
|
||||
shareLinks: [],
|
||||
@@ -37,11 +42,12 @@ class ShareLinkPanel extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let path = this.props.itemPath;
|
||||
let repoID = this.props.repoID;
|
||||
seafileAPI.getShareLink(repoID, path).then((res) => {
|
||||
const { page } = this.state;
|
||||
const { repoID, itemPath: path } = this.props;
|
||||
seafileAPI.listShareLinks({repoID, path, page}).then((res) => {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
hasMore: res.data.length == PER_PAGE,
|
||||
shareLinks: res.data.map(item => new ShareLink(item))
|
||||
});
|
||||
}).catch(error => {
|
||||
@@ -184,13 +190,46 @@ class ShareLinkPanel extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
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, shareLinks } = this.state;
|
||||
const { repoID, itemPath: path } = this.props;
|
||||
seafileAPI.listShareLinks({repoID, path, page: page + 1}).then((res) => {
|
||||
this.setState({
|
||||
isLoadingMore: false,
|
||||
hasMore: res.data.length == PER_PAGE,
|
||||
page: page + 1,
|
||||
shareLinks: shareLinks.concat(res.data.map(item => new ShareLink(item)))
|
||||
});
|
||||
}).catch(error => {
|
||||
this.setState({
|
||||
isLoadingMore: false
|
||||
});
|
||||
let errMessage = Utils.getErrorMsg(error);
|
||||
toaster.danger(errMessage);
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
if (this.state.isLoading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
const { repoID, itemPath, userPerm } = this.props;
|
||||
const { mode, shareLinks, sharedLinkInfo, permissionOptions, currentPermission } = this.state;
|
||||
const { mode, shareLinks, sharedLinkInfo, permissionOptions, currentPermission, isLoadingMore } = this.state;
|
||||
|
||||
switch (mode) {
|
||||
case 'displayLinkDetails':
|
||||
@@ -242,6 +281,8 @@ class ShareLinkPanel extends React.Component {
|
||||
toggleSelectLink={this.toggleSelectLink}
|
||||
deleteShareLinks={this.deleteShareLinks}
|
||||
deleteLink={this.deleteLink}
|
||||
handleScroll={this.handleScroll}
|
||||
isLoadingMore={isLoadingMore}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import { gettext, siteRoot } from '../../utils/constants';
|
||||
import EmptyTip from '../empty-tip';
|
||||
import LinkItem from './link-item';
|
||||
import CommonOperationConfirmationDialog from '../../components/dialog/common-operation-confirmation-dialog';
|
||||
import Loading from '../../components/loading';
|
||||
|
||||
const propTypes = {
|
||||
shareLinks: PropTypes.array.isRequired,
|
||||
@@ -13,7 +14,9 @@ const propTypes = {
|
||||
toggleSelectAllLinks: PropTypes.func.isRequired,
|
||||
toggleSelectLink: PropTypes.func.isRequired,
|
||||
deleteLink: PropTypes.func.isRequired,
|
||||
deleteShareLinks: PropTypes.func.isRequired
|
||||
deleteShareLinks: PropTypes.func.isRequired,
|
||||
isLoadingMore: PropTypes.bool.isRequired,
|
||||
handleScroll: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
class LinkList extends React.Component {
|
||||
@@ -46,7 +49,7 @@ class LinkList extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { shareLinks, permissionOptions } = this.props;
|
||||
const { shareLinks, permissionOptions, isLoadingMore, handleScroll } = this.props;
|
||||
const selectedLinks = shareLinks.filter(item => item.isSelected);
|
||||
const isAllLinksSelected = shareLinks.length == selectedLinks.length;
|
||||
|
||||
@@ -88,7 +91,7 @@ class LinkList extends React.Component {
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<div className='table-real-container'>
|
||||
<div className='table-real-container' onScroll={handleScroll}>
|
||||
<table className="table-real-content table-thead-hidden">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -114,6 +117,7 @@ class LinkList extends React.Component {
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
{isLoadingMore && <Loading />}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
@@ -129,10 +129,6 @@ class EditorApi {
|
||||
return seafileAPI.getInternalLink(repoID, filePath);
|
||||
}
|
||||
|
||||
getShareLink() {
|
||||
return seafileAPI.getShareLink(repoID, filePath);
|
||||
}
|
||||
|
||||
createShareLink (repoID, filePath, userPassword, userValidDays, permissions) {
|
||||
return seafileAPI.createShareLink(repoID, filePath, userPassword, userValidDays, permissions);
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ import Selector from '../../components/single-selector';
|
||||
|
||||
const contentPropTypes = {
|
||||
loading: PropTypes.bool.isRequired,
|
||||
isLoadingMore: PropTypes.bool.isRequired,
|
||||
errorMsg: PropTypes.string.isRequired,
|
||||
items: PropTypes.array.isRequired,
|
||||
sortBy: PropTypes.string.isRequired,
|
||||
@@ -114,7 +115,12 @@ class Content extends Component {
|
||||
</table>
|
||||
);
|
||||
|
||||
return items.length ? table : emptyTip;
|
||||
return items.length ? (
|
||||
<>
|
||||
{table}
|
||||
{this.props.isLoadingMore && <div className="flex-shrink-0"><Loading /></div>}
|
||||
</>
|
||||
) : emptyTip;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,6 +366,8 @@ const propTypes = {
|
||||
onSearchedClick: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
const PER_PAGE = 25;
|
||||
|
||||
class ShareAdminShareLinks extends Component {
|
||||
|
||||
constructor(props) {
|
||||
@@ -367,6 +375,9 @@ class ShareAdminShareLinks extends Component {
|
||||
this.state = {
|
||||
isCleanInvalidShareLinksDialogOpen: false,
|
||||
loading: true,
|
||||
hasMore: false,
|
||||
isLoadingMore: false,
|
||||
page: 1,
|
||||
errorMsg: '',
|
||||
items: [],
|
||||
sortBy: 'name', // 'name' or 'time'
|
||||
@@ -437,12 +448,14 @@ class ShareAdminShareLinks extends Component {
|
||||
}
|
||||
|
||||
listUserShareLinks() {
|
||||
seafileAPI.listUserShareLinks().then((res) => {
|
||||
const { page } = this.state;
|
||||
seafileAPI.listShareLinks({ page }).then((res) => {
|
||||
let items = res.data.map(item => {
|
||||
return new ShareLink(item);
|
||||
});
|
||||
this.setState({
|
||||
loading: false,
|
||||
hasMore: res.data.length == PER_PAGE,
|
||||
items: this._sortItems(items, this.state.sortBy, this.state.sortOrder)
|
||||
});
|
||||
}).catch((error) => {
|
||||
@@ -453,6 +466,40 @@ class ShareAdminShareLinks extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
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 } = this.state;
|
||||
seafileAPI.listShareLinks({ page: page + 1 }).then((res) => {
|
||||
let moreItems = res.data.map(item => {
|
||||
return new ShareLink(item);
|
||||
});
|
||||
this.setState({
|
||||
isLoadingMore: false,
|
||||
hasMore: res.data.length == PER_PAGE,
|
||||
page: page + 1,
|
||||
items: this._sortItems(this.state.items.concat(moreItems), this.state.sortBy, this.state.sortOrder)
|
||||
});
|
||||
}).catch((error) => {
|
||||
this.setState({
|
||||
isLoadingMore: false,
|
||||
errorMsg: Utils.getErrorMsg(error, true) // true: show login tip if 403
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
onRemoveLink = (item) => {
|
||||
seafileAPI.deleteShareLink(item.token).then(() => {
|
||||
let items = this.state.items.filter(uploadItem => {
|
||||
@@ -511,9 +558,10 @@ class ShareAdminShareLinks extends Component {
|
||||
</ul>
|
||||
{(!Utils.isDesktop() && this.state.items.length > 0) && <span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>}
|
||||
</div>
|
||||
<div className="cur-view-content">
|
||||
<div className="cur-view-content" onScroll={this.handleScroll}>
|
||||
<Content
|
||||
loading={this.state.loading}
|
||||
isLoadingMore={this.state.isLoadingMore}
|
||||
errorMsg={this.state.errorMsg}
|
||||
items={this.state.items}
|
||||
sortBy={this.state.sortBy}
|
||||
|
Reference in New Issue
Block a user