1
0
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:
llj
2023-12-20 12:01:18 +08:00
committed by GitHub
parent 53562381a8
commit bd05e05a1a
4 changed files with 103 additions and 14 deletions

View File

@@ -18,6 +18,8 @@ const propTypes = {
itemType: PropTypes.string itemType: PropTypes.string
}; };
const PER_PAGE = 25;
class ShareLinkPanel extends React.Component { class ShareLinkPanel extends React.Component {
constructor(props) { constructor(props) {
@@ -28,6 +30,9 @@ class ShareLinkPanel extends React.Component {
this.state = { this.state = {
isLoading: true, isLoading: true,
hasMore: false,
isLoadingMore: false,
page: 1,
mode: 'listLinks', mode: 'listLinks',
sharedLinkInfo: null, sharedLinkInfo: null,
shareLinks: [], shareLinks: [],
@@ -37,11 +42,12 @@ class ShareLinkPanel extends React.Component {
} }
componentDidMount() { componentDidMount() {
let path = this.props.itemPath; const { page } = this.state;
let repoID = this.props.repoID; const { repoID, itemPath: path } = this.props;
seafileAPI.getShareLink(repoID, path).then((res) => { seafileAPI.listShareLinks({repoID, path, page}).then((res) => {
this.setState({ this.setState({
isLoading: false, isLoading: false,
hasMore: res.data.length == PER_PAGE,
shareLinks: res.data.map(item => new ShareLink(item)) shareLinks: res.data.map(item => new ShareLink(item))
}); });
}).catch(error => { }).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() { render() {
if (this.state.isLoading) { if (this.state.isLoading) {
return <Loading />; return <Loading />;
} }
const { repoID, itemPath, userPerm } = this.props; 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) { switch (mode) {
case 'displayLinkDetails': case 'displayLinkDetails':
@@ -242,6 +281,8 @@ class ShareLinkPanel extends React.Component {
toggleSelectLink={this.toggleSelectLink} toggleSelectLink={this.toggleSelectLink}
deleteShareLinks={this.deleteShareLinks} deleteShareLinks={this.deleteShareLinks}
deleteLink={this.deleteLink} deleteLink={this.deleteLink}
handleScroll={this.handleScroll}
isLoadingMore={isLoadingMore}
/> />
); );
} }

View File

@@ -4,6 +4,7 @@ import { gettext, siteRoot } from '../../utils/constants';
import EmptyTip from '../empty-tip'; import EmptyTip from '../empty-tip';
import LinkItem from './link-item'; import LinkItem from './link-item';
import CommonOperationConfirmationDialog from '../../components/dialog/common-operation-confirmation-dialog'; import CommonOperationConfirmationDialog from '../../components/dialog/common-operation-confirmation-dialog';
import Loading from '../../components/loading';
const propTypes = { const propTypes = {
shareLinks: PropTypes.array.isRequired, shareLinks: PropTypes.array.isRequired,
@@ -13,7 +14,9 @@ const propTypes = {
toggleSelectAllLinks: PropTypes.func.isRequired, toggleSelectAllLinks: PropTypes.func.isRequired,
toggleSelectLink: PropTypes.func.isRequired, toggleSelectLink: PropTypes.func.isRequired,
deleteLink: 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 { class LinkList extends React.Component {
@@ -46,7 +49,7 @@ class LinkList extends React.Component {
}; };
render() { render() {
const { shareLinks, permissionOptions } = this.props; const { shareLinks, permissionOptions, isLoadingMore, handleScroll } = this.props;
const selectedLinks = shareLinks.filter(item => item.isSelected); const selectedLinks = shareLinks.filter(item => item.isSelected);
const isAllLinksSelected = shareLinks.length == selectedLinks.length; const isAllLinksSelected = shareLinks.length == selectedLinks.length;
@@ -88,7 +91,7 @@ class LinkList extends React.Component {
</tr> </tr>
</thead> </thead>
</table> </table>
<div className='table-real-container'> <div className='table-real-container' onScroll={handleScroll}>
<table className="table-real-content table-thead-hidden"> <table className="table-real-content table-thead-hidden">
<thead> <thead>
<tr> <tr>
@@ -114,6 +117,7 @@ class LinkList extends React.Component {
})} })}
</tbody> </tbody>
</table> </table>
{isLoadingMore && <Loading />}
</div> </div>
</div> </div>
)} )}

View File

@@ -129,10 +129,6 @@ class EditorApi {
return seafileAPI.getInternalLink(repoID, filePath); return seafileAPI.getInternalLink(repoID, filePath);
} }
getShareLink() {
return seafileAPI.getShareLink(repoID, filePath);
}
createShareLink (repoID, filePath, userPassword, userValidDays, permissions) { createShareLink (repoID, filePath, userPassword, userValidDays, permissions) {
return seafileAPI.createShareLink(repoID, filePath, userPassword, userValidDays, permissions); return seafileAPI.createShareLink(repoID, filePath, userPassword, userValidDays, permissions);
} }

View File

@@ -19,6 +19,7 @@ import Selector from '../../components/single-selector';
const contentPropTypes = { const contentPropTypes = {
loading: PropTypes.bool.isRequired, loading: PropTypes.bool.isRequired,
isLoadingMore: PropTypes.bool.isRequired,
errorMsg: PropTypes.string.isRequired, errorMsg: PropTypes.string.isRequired,
items: PropTypes.array.isRequired, items: PropTypes.array.isRequired,
sortBy: PropTypes.string.isRequired, sortBy: PropTypes.string.isRequired,
@@ -114,7 +115,12 @@ class Content extends Component {
</table> </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 onSearchedClick: PropTypes.func.isRequired
}; };
const PER_PAGE = 25;
class ShareAdminShareLinks extends Component { class ShareAdminShareLinks extends Component {
constructor(props) { constructor(props) {
@@ -367,6 +375,9 @@ class ShareAdminShareLinks extends Component {
this.state = { this.state = {
isCleanInvalidShareLinksDialogOpen: false, isCleanInvalidShareLinksDialogOpen: false,
loading: true, loading: true,
hasMore: false,
isLoadingMore: false,
page: 1,
errorMsg: '', errorMsg: '',
items: [], items: [],
sortBy: 'name', // 'name' or 'time' sortBy: 'name', // 'name' or 'time'
@@ -437,12 +448,14 @@ class ShareAdminShareLinks extends Component {
} }
listUserShareLinks() { listUserShareLinks() {
seafileAPI.listUserShareLinks().then((res) => { const { page } = this.state;
seafileAPI.listShareLinks({ page }).then((res) => {
let items = res.data.map(item => { let items = res.data.map(item => {
return new ShareLink(item); return new ShareLink(item);
}); });
this.setState({ this.setState({
loading: false, loading: false,
hasMore: res.data.length == PER_PAGE,
items: this._sortItems(items, this.state.sortBy, this.state.sortOrder) items: this._sortItems(items, this.state.sortBy, this.state.sortOrder)
}); });
}).catch((error) => { }).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) => { onRemoveLink = (item) => {
seafileAPI.deleteShareLink(item.token).then(() => { seafileAPI.deleteShareLink(item.token).then(() => {
let items = this.state.items.filter(uploadItem => { let items = this.state.items.filter(uploadItem => {
@@ -511,9 +558,10 @@ class ShareAdminShareLinks extends Component {
</ul> </ul>
{(!Utils.isDesktop() && this.state.items.length > 0) && <span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>} {(!Utils.isDesktop() && this.state.items.length > 0) && <span className="sf3-font sf3-font-sort action-icon" onClick={this.toggleSortOptionsDialog}></span>}
</div> </div>
<div className="cur-view-content"> <div className="cur-view-content" onScroll={this.handleScroll}>
<Content <Content
loading={this.state.loading} loading={this.state.loading}
isLoadingMore={this.state.isLoadingMore}
errorMsg={this.state.errorMsg} errorMsg={this.state.errorMsg}
items={this.state.items} items={this.state.items}
sortBy={this.state.sortBy} sortBy={this.state.sortBy}