Skip to content

Commit

Permalink
['share dialog' - 'Share Link', 'Share Admin' - 'Links'] share links:…
Browse files Browse the repository at this point in the history
… get limited links per request, scroll down to get more (#5840)
  • Loading branch information
llj authored Dec 20, 2023
1 parent 5356238 commit bd05e05
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 14 deletions.
49 changes: 45 additions & 4 deletions frontend/src/components/share-link-panel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const propTypes = {
itemType: PropTypes.string
};

const PER_PAGE = 25;

class ShareLinkPanel extends React.Component {

constructor(props) {
Expand All @@ -28,6 +30,9 @@ class ShareLinkPanel extends React.Component {

this.state = {
isLoading: true,
hasMore: false,
isLoadingMore: false,
page: 1,
mode: 'listLinks',
sharedLinkInfo: null,
shareLinks: [],
Expand All @@ -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 => {
Expand Down Expand Up @@ -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':
Expand Down Expand Up @@ -242,6 +281,8 @@ class ShareLinkPanel extends React.Component {
toggleSelectLink={this.toggleSelectLink}
deleteShareLinks={this.deleteShareLinks}
deleteLink={this.deleteLink}
handleScroll={this.handleScroll}
isLoadingMore={isLoadingMore}
/>
);
}
Expand Down
10 changes: 7 additions & 3 deletions frontend/src/components/share-link-panel/link-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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>
Expand All @@ -114,6 +117,7 @@ class LinkList extends React.Component {
})}
</tbody>
</table>
{isLoadingMore && <Loading />}
</div>
</div>
)}
Expand Down
4 changes: 0 additions & 4 deletions frontend/src/pages/markdown-editor/editor-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
54 changes: 51 additions & 3 deletions frontend/src/pages/share-admin/share-links.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}
}
}
Expand Down Expand Up @@ -360,13 +366,18 @@ const propTypes = {
onSearchedClick: PropTypes.func.isRequired
};

const PER_PAGE = 25;

class ShareAdminShareLinks extends Component {

constructor(props) {
super(props);
this.state = {
isCleanInvalidShareLinksDialogOpen: false,
loading: true,
hasMore: false,
isLoadingMore: false,
page: 1,
errorMsg: '',
items: [],
sortBy: 'name', // 'name' or 'time'
Expand Down Expand Up @@ -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) => {
Expand All @@ -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 => {
Expand Down Expand Up @@ -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}
Expand Down

0 comments on commit bd05e05

Please sign in to comment.