1
0
mirror of https://github.com/mastodon/mastodon synced 2024-11-27 22:38:27 +09:00

Fix WebUI pagination of following, followers, follow requests, blocks and mutes lists (#13445)

* Fix following, followers and follow requests pagination

* Fix pagination of blocks and mutes
This commit is contained in:
ThibG 2020-04-12 13:38:00 +02:00 committed by GitHub
parent e51cbbbf5b
commit ec31b1b752
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 8 deletions

View File

@ -19,6 +19,7 @@ const messages = defineMessages({
const mapStateToProps = state => ({ const mapStateToProps = state => ({
accountIds: state.getIn(['user_lists', 'blocks', 'items']), accountIds: state.getIn(['user_lists', 'blocks', 'items']),
hasMore: !!state.getIn(['user_lists', 'blocks', 'next']), hasMore: !!state.getIn(['user_lists', 'blocks', 'next']),
isLoading: state.getIn(['user_lists', 'blocks', 'isLoading'], true),
}); });
export default @connect(mapStateToProps) export default @connect(mapStateToProps)
@ -31,6 +32,7 @@ class Blocks extends ImmutablePureComponent {
shouldUpdateScroll: PropTypes.func, shouldUpdateScroll: PropTypes.func,
accountIds: ImmutablePropTypes.list, accountIds: ImmutablePropTypes.list,
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
isLoading: PropTypes.bool,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
multiColumn: PropTypes.bool, multiColumn: PropTypes.bool,
}; };
@ -44,7 +46,7 @@ class Blocks extends ImmutablePureComponent {
}, 300, { leading: true }); }, 300, { leading: true });
render () { render () {
const { intl, accountIds, shouldUpdateScroll, hasMore, multiColumn } = this.props; const { intl, accountIds, shouldUpdateScroll, hasMore, multiColumn, isLoading } = this.props;
if (!accountIds) { if (!accountIds) {
return ( return (
@ -63,6 +65,7 @@ class Blocks extends ImmutablePureComponent {
scrollKey='blocks' scrollKey='blocks'
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
hasMore={hasMore} hasMore={hasMore}
isLoading={isLoading}
shouldUpdateScroll={shouldUpdateScroll} shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}

View File

@ -19,6 +19,7 @@ const messages = defineMessages({
const mapStateToProps = state => ({ const mapStateToProps = state => ({
accountIds: state.getIn(['user_lists', 'follow_requests', 'items']), accountIds: state.getIn(['user_lists', 'follow_requests', 'items']),
isLoading: state.getIn(['user_lists', 'follow_requests', 'isLoading'], true),
hasMore: !!state.getIn(['user_lists', 'follow_requests', 'next']), hasMore: !!state.getIn(['user_lists', 'follow_requests', 'next']),
locked: !!state.getIn(['accounts', me, 'locked']), locked: !!state.getIn(['accounts', me, 'locked']),
domain: state.getIn(['meta', 'domain']), domain: state.getIn(['meta', 'domain']),
@ -33,6 +34,7 @@ class FollowRequests extends ImmutablePureComponent {
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func, shouldUpdateScroll: PropTypes.func,
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
isLoading: PropTypes.bool,
accountIds: ImmutablePropTypes.list, accountIds: ImmutablePropTypes.list,
locked: PropTypes.bool, locked: PropTypes.bool,
domain: PropTypes.string, domain: PropTypes.string,
@ -49,7 +51,7 @@ class FollowRequests extends ImmutablePureComponent {
}, 300, { leading: true }); }, 300, { leading: true });
render () { render () {
const { intl, shouldUpdateScroll, accountIds, hasMore, multiColumn, locked, domain } = this.props; const { intl, shouldUpdateScroll, accountIds, hasMore, multiColumn, locked, domain, isLoading } = this.props;
if (!accountIds) { if (!accountIds) {
return ( return (
@ -77,6 +79,7 @@ class FollowRequests extends ImmutablePureComponent {
scrollKey='follow_requests' scrollKey='follow_requests'
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
hasMore={hasMore} hasMore={hasMore}
isLoading={isLoading}
shouldUpdateScroll={shouldUpdateScroll} shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}

View File

@ -22,6 +22,7 @@ const mapStateToProps = (state, props) => ({
isAccount: !!state.getIn(['accounts', props.params.accountId]), isAccount: !!state.getIn(['accounts', props.params.accountId]),
accountIds: state.getIn(['user_lists', 'followers', props.params.accountId, 'items']), accountIds: state.getIn(['user_lists', 'followers', props.params.accountId, 'items']),
hasMore: !!state.getIn(['user_lists', 'followers', props.params.accountId, 'next']), hasMore: !!state.getIn(['user_lists', 'followers', props.params.accountId, 'next']),
isLoading: state.getIn(['user_lists', 'followers', props.params.accountId, 'isLoading'], true),
blockedBy: state.getIn(['relationships', props.params.accountId, 'blocked_by'], false), blockedBy: state.getIn(['relationships', props.params.accountId, 'blocked_by'], false),
}); });
@ -34,6 +35,7 @@ class Followers extends ImmutablePureComponent {
shouldUpdateScroll: PropTypes.func, shouldUpdateScroll: PropTypes.func,
accountIds: ImmutablePropTypes.list, accountIds: ImmutablePropTypes.list,
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
isLoading: PropTypes.bool,
blockedBy: PropTypes.bool, blockedBy: PropTypes.bool,
isAccount: PropTypes.bool, isAccount: PropTypes.bool,
multiColumn: PropTypes.bool, multiColumn: PropTypes.bool,
@ -58,7 +60,7 @@ class Followers extends ImmutablePureComponent {
}, 300, { leading: true }); }, 300, { leading: true });
render () { render () {
const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount, multiColumn } = this.props; const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount, multiColumn, isLoading } = this.props;
if (!isAccount) { if (!isAccount) {
return ( return (
@ -85,6 +87,7 @@ class Followers extends ImmutablePureComponent {
<ScrollableList <ScrollableList
scrollKey='followers' scrollKey='followers'
hasMore={hasMore} hasMore={hasMore}
isLoading={isLoading}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
shouldUpdateScroll={shouldUpdateScroll} shouldUpdateScroll={shouldUpdateScroll}
prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />} prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />}

View File

@ -22,6 +22,7 @@ const mapStateToProps = (state, props) => ({
isAccount: !!state.getIn(['accounts', props.params.accountId]), isAccount: !!state.getIn(['accounts', props.params.accountId]),
accountIds: state.getIn(['user_lists', 'following', props.params.accountId, 'items']), accountIds: state.getIn(['user_lists', 'following', props.params.accountId, 'items']),
hasMore: !!state.getIn(['user_lists', 'following', props.params.accountId, 'next']), hasMore: !!state.getIn(['user_lists', 'following', props.params.accountId, 'next']),
isLoading: state.getIn(['user_lists', 'following', props.params.accountId, 'isLoading'], true),
blockedBy: state.getIn(['relationships', props.params.accountId, 'blocked_by'], false), blockedBy: state.getIn(['relationships', props.params.accountId, 'blocked_by'], false),
}); });
@ -34,6 +35,7 @@ class Following extends ImmutablePureComponent {
shouldUpdateScroll: PropTypes.func, shouldUpdateScroll: PropTypes.func,
accountIds: ImmutablePropTypes.list, accountIds: ImmutablePropTypes.list,
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
isLoading: PropTypes.bool,
blockedBy: PropTypes.bool, blockedBy: PropTypes.bool,
isAccount: PropTypes.bool, isAccount: PropTypes.bool,
multiColumn: PropTypes.bool, multiColumn: PropTypes.bool,
@ -58,7 +60,7 @@ class Following extends ImmutablePureComponent {
}, 300, { leading: true }); }, 300, { leading: true });
render () { render () {
const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount, multiColumn } = this.props; const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount, multiColumn, isLoading } = this.props;
if (!isAccount) { if (!isAccount) {
return ( return (
@ -85,6 +87,7 @@ class Following extends ImmutablePureComponent {
<ScrollableList <ScrollableList
scrollKey='following' scrollKey='following'
hasMore={hasMore} hasMore={hasMore}
isLoading={isLoading}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
shouldUpdateScroll={shouldUpdateScroll} shouldUpdateScroll={shouldUpdateScroll}
prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />} prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />}

View File

@ -19,6 +19,7 @@ const messages = defineMessages({
const mapStateToProps = state => ({ const mapStateToProps = state => ({
accountIds: state.getIn(['user_lists', 'mutes', 'items']), accountIds: state.getIn(['user_lists', 'mutes', 'items']),
hasMore: !!state.getIn(['user_lists', 'mutes', 'next']), hasMore: !!state.getIn(['user_lists', 'mutes', 'next']),
isLoading: state.getIn(['user_lists', 'mutes', 'isLoading'], true),
}); });
export default @connect(mapStateToProps) export default @connect(mapStateToProps)
@ -30,6 +31,7 @@ class Mutes extends ImmutablePureComponent {
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func, shouldUpdateScroll: PropTypes.func,
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
isLoading: PropTypes.bool,
accountIds: ImmutablePropTypes.list, accountIds: ImmutablePropTypes.list,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
multiColumn: PropTypes.bool, multiColumn: PropTypes.bool,
@ -44,7 +46,7 @@ class Mutes extends ImmutablePureComponent {
}, 300, { leading: true }); }, 300, { leading: true });
render () { render () {
const { intl, shouldUpdateScroll, hasMore, accountIds, multiColumn } = this.props; const { intl, shouldUpdateScroll, hasMore, accountIds, multiColumn, isLoading } = this.props;
if (!accountIds) { if (!accountIds) {
return ( return (
@ -63,6 +65,7 @@ class Mutes extends ImmutablePureComponent {
scrollKey='mutes' scrollKey='mutes'
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
hasMore={hasMore} hasMore={hasMore}
isLoading={isLoading}
shouldUpdateScroll={shouldUpdateScroll} shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}

View File

@ -2,12 +2,24 @@ import {
NOTIFICATIONS_UPDATE, NOTIFICATIONS_UPDATE,
} from '../actions/notifications'; } from '../actions/notifications';
import { import {
FOLLOWERS_FETCH_REQUEST,
FOLLOWERS_FETCH_SUCCESS, FOLLOWERS_FETCH_SUCCESS,
FOLLOWERS_FETCH_FAIL,
FOLLOWERS_EXPAND_REQUEST,
FOLLOWERS_EXPAND_SUCCESS, FOLLOWERS_EXPAND_SUCCESS,
FOLLOWERS_EXPAND_FAIL,
FOLLOWING_FETCH_REQUEST,
FOLLOWING_FETCH_SUCCESS, FOLLOWING_FETCH_SUCCESS,
FOLLOWING_FETCH_FAIL,
FOLLOWING_EXPAND_REQUEST,
FOLLOWING_EXPAND_SUCCESS, FOLLOWING_EXPAND_SUCCESS,
FOLLOWING_EXPAND_FAIL,
FOLLOW_REQUESTS_FETCH_REQUEST,
FOLLOW_REQUESTS_FETCH_SUCCESS, FOLLOW_REQUESTS_FETCH_SUCCESS,
FOLLOW_REQUESTS_FETCH_FAIL,
FOLLOW_REQUESTS_EXPAND_REQUEST,
FOLLOW_REQUESTS_EXPAND_SUCCESS, FOLLOW_REQUESTS_EXPAND_SUCCESS,
FOLLOW_REQUESTS_EXPAND_FAIL,
FOLLOW_REQUEST_AUTHORIZE_SUCCESS, FOLLOW_REQUEST_AUTHORIZE_SUCCESS,
FOLLOW_REQUEST_REJECT_SUCCESS, FOLLOW_REQUEST_REJECT_SUCCESS,
} from '../actions/accounts'; } from '../actions/accounts';
@ -16,12 +28,20 @@ import {
FAVOURITES_FETCH_SUCCESS, FAVOURITES_FETCH_SUCCESS,
} from '../actions/interactions'; } from '../actions/interactions';
import { import {
BLOCKS_FETCH_REQUEST,
BLOCKS_FETCH_SUCCESS, BLOCKS_FETCH_SUCCESS,
BLOCKS_FETCH_FAIL,
BLOCKS_EXPAND_REQUEST,
BLOCKS_EXPAND_SUCCESS, BLOCKS_EXPAND_SUCCESS,
BLOCKS_EXPAND_FAIL,
} from '../actions/blocks'; } from '../actions/blocks';
import { import {
MUTES_FETCH_REQUEST,
MUTES_FETCH_SUCCESS, MUTES_FETCH_SUCCESS,
MUTES_FETCH_FAIL,
MUTES_EXPAND_REQUEST,
MUTES_EXPAND_SUCCESS, MUTES_EXPAND_SUCCESS,
MUTES_EXPAND_FAIL,
} from '../actions/mutes'; } from '../actions/mutes';
import { import {
DIRECTORY_FETCH_REQUEST, DIRECTORY_FETCH_REQUEST,
@ -47,12 +67,13 @@ const normalizeList = (state, type, id, accounts, next) => {
return state.setIn([type, id], ImmutableMap({ return state.setIn([type, id], ImmutableMap({
next, next,
items: ImmutableList(accounts.map(item => item.id)), items: ImmutableList(accounts.map(item => item.id)),
isLoading: false,
})); }));
}; };
const appendToList = (state, type, id, accounts, next) => { const appendToList = (state, type, id, accounts, next) => {
return state.updateIn([type, id], map => { return state.updateIn([type, id], map => {
return map.set('next', next).update('items', list => list.concat(accounts.map(item => item.id))); return map.set('next', next).set('isLoading', false).update('items', list => list.concat(accounts.map(item => item.id)));
}); });
}; };
@ -68,10 +89,22 @@ export default function userLists(state = initialState, action) {
return normalizeList(state, 'followers', action.id, action.accounts, action.next); return normalizeList(state, 'followers', action.id, action.accounts, action.next);
case FOLLOWERS_EXPAND_SUCCESS: case FOLLOWERS_EXPAND_SUCCESS:
return appendToList(state, 'followers', action.id, action.accounts, action.next); return appendToList(state, 'followers', action.id, action.accounts, action.next);
case FOLLOWERS_FETCH_REQUEST:
case FOLLOWERS_EXPAND_REQUEST:
return state.setIn(['followers', action.id, 'isLoading'], true);
case FOLLOWERS_FETCH_FAIL:
case FOLLOWERS_EXPAND_FAIL:
return state.setIn(['followers', action.id, 'isLoading'], false);
case FOLLOWING_FETCH_SUCCESS: case FOLLOWING_FETCH_SUCCESS:
return normalizeList(state, 'following', action.id, action.accounts, action.next); return normalizeList(state, 'following', action.id, action.accounts, action.next);
case FOLLOWING_EXPAND_SUCCESS: case FOLLOWING_EXPAND_SUCCESS:
return appendToList(state, 'following', action.id, action.accounts, action.next); return appendToList(state, 'following', action.id, action.accounts, action.next);
case FOLLOWING_FETCH_REQUEST:
case FOLLOWING_EXPAND_REQUEST:
return state.setIn(['following', action.id, 'isLoading'], true);
case FOLLOWING_FETCH_FAIL:
case FOLLOWING_EXPAND_FAIL:
return state.setIn(['following', action.id, 'isLoading'], false);
case REBLOGS_FETCH_SUCCESS: case REBLOGS_FETCH_SUCCESS:
return state.setIn(['reblogged_by', action.id], ImmutableList(action.accounts.map(item => item.id))); return state.setIn(['reblogged_by', action.id], ImmutableList(action.accounts.map(item => item.id)));
case FAVOURITES_FETCH_SUCCESS: case FAVOURITES_FETCH_SUCCESS:
@ -79,9 +112,15 @@ export default function userLists(state = initialState, action) {
case NOTIFICATIONS_UPDATE: case NOTIFICATIONS_UPDATE:
return action.notification.type === 'follow_request' ? normalizeFollowRequest(state, action.notification) : state; return action.notification.type === 'follow_request' ? normalizeFollowRequest(state, action.notification) : state;
case FOLLOW_REQUESTS_FETCH_SUCCESS: case FOLLOW_REQUESTS_FETCH_SUCCESS:
return state.setIn(['follow_requests', 'items'], ImmutableList(action.accounts.map(item => item.id))).setIn(['follow_requests', 'next'], action.next); return state.setIn(['follow_requests', 'items'], ImmutableList(action.accounts.map(item => item.id))).setIn(['follow_requests', 'next'], action.next).setIn(['follow_requests', 'isLoading'], false);
case FOLLOW_REQUESTS_EXPAND_SUCCESS: case FOLLOW_REQUESTS_EXPAND_SUCCESS:
return state.updateIn(['follow_requests', 'items'], list => list.concat(action.accounts.map(item => item.id))).setIn(['follow_requests', 'next'], action.next); return state.updateIn(['follow_requests', 'items'], list => list.concat(action.accounts.map(item => item.id))).setIn(['follow_requests', 'next'], action.next).setIn(['follow_requests', 'isLoading'], false);
case FOLLOW_REQUESTS_FETCH_REQUEST:
case FOLLOW_REQUESTS_EXPAND_REQUEST:
return state.setIn(['follow_requests', 'isLoading'], true);
case FOLLOW_REQUESTS_FETCH_FAIL:
case FOLLOW_REQUESTS_EXPAND_FAIL:
return state.setIn(['follow_requests', 'isLoading'], false);
case FOLLOW_REQUEST_AUTHORIZE_SUCCESS: case FOLLOW_REQUEST_AUTHORIZE_SUCCESS:
case FOLLOW_REQUEST_REJECT_SUCCESS: case FOLLOW_REQUEST_REJECT_SUCCESS:
return state.updateIn(['follow_requests', 'items'], list => list.filterNot(item => item === action.id)); return state.updateIn(['follow_requests', 'items'], list => list.filterNot(item => item === action.id));
@ -89,10 +128,22 @@ export default function userLists(state = initialState, action) {
return state.setIn(['blocks', 'items'], ImmutableList(action.accounts.map(item => item.id))).setIn(['blocks', 'next'], action.next); return state.setIn(['blocks', 'items'], ImmutableList(action.accounts.map(item => item.id))).setIn(['blocks', 'next'], action.next);
case BLOCKS_EXPAND_SUCCESS: case BLOCKS_EXPAND_SUCCESS:
return state.updateIn(['blocks', 'items'], list => list.concat(action.accounts.map(item => item.id))).setIn(['blocks', 'next'], action.next); return state.updateIn(['blocks', 'items'], list => list.concat(action.accounts.map(item => item.id))).setIn(['blocks', 'next'], action.next);
case BLOCKS_FETCH_REQUEST:
case BLOCKS_EXPAND_REQUEST:
return state.setIn(['blocks', 'isLoading'], true);
case BLOCKS_FETCH_FAIL:
case BLOCKS_EXPAND_FAIL:
return state.setIn(['blocks', 'isLoading'], false);
case MUTES_FETCH_SUCCESS: case MUTES_FETCH_SUCCESS:
return state.setIn(['mutes', 'items'], ImmutableList(action.accounts.map(item => item.id))).setIn(['mutes', 'next'], action.next); return state.setIn(['mutes', 'items'], ImmutableList(action.accounts.map(item => item.id))).setIn(['mutes', 'next'], action.next);
case MUTES_EXPAND_SUCCESS: case MUTES_EXPAND_SUCCESS:
return state.updateIn(['mutes', 'items'], list => list.concat(action.accounts.map(item => item.id))).setIn(['mutes', 'next'], action.next); return state.updateIn(['mutes', 'items'], list => list.concat(action.accounts.map(item => item.id))).setIn(['mutes', 'next'], action.next);
case MUTES_FETCH_REQUEST:
case MUTES_EXPAND_REQUEST:
return state.setIn(['mutes', 'isLoading'], true);
case MUTES_FETCH_FAIL:
case MUTES_EXPAND_FAIL:
return state.setIn(['mutes', 'isLoading'], false);
case DIRECTORY_FETCH_SUCCESS: case DIRECTORY_FETCH_SUCCESS:
return state.setIn(['directory', 'items'], ImmutableList(action.accounts.map(item => item.id))).setIn(['directory', 'isLoading'], false); return state.setIn(['directory', 'items'], ImmutableList(action.accounts.map(item => item.id))).setIn(['directory', 'isLoading'], false);
case DIRECTORY_EXPAND_SUCCESS: case DIRECTORY_EXPAND_SUCCESS: