v2 Suggestions: add AdminAPI, rearrange sidebars, check instance feature flag

merge-requests/892/head
Alex Gleason 2021-11-26 23:36:17 -06:00
rodzic e3566db690
commit 92439137c1
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
9 zmienionych plików z 124 dodań i 19 usunięć

Wyświetl plik

@ -62,6 +62,14 @@ export const ADMIN_REMOVE_PERMISSION_GROUP_REQUEST = 'ADMIN_REMOVE_PERMISSION_GR
export const ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS = 'ADMIN_REMOVE_PERMISSION_GROUP_SUCCESS';
export const ADMIN_REMOVE_PERMISSION_GROUP_FAIL = 'ADMIN_REMOVE_PERMISSION_GROUP_FAIL';
export const ADMIN_USERS_SUGGEST_REQUEST = 'ADMIN_USERS_SUGGEST_REQUEST';
export const ADMIN_USERS_SUGGEST_SUCCESS = 'ADMIN_USERS_SUGGEST_SUCCESS';
export const ADMIN_USERS_SUGGEST_FAIL = 'ADMIN_USERS_SUGGEST_FAIL';
export const ADMIN_USERS_UNSUGGEST_REQUEST = 'ADMIN_USERS_UNSUGGEST_REQUEST';
export const ADMIN_USERS_UNSUGGEST_SUCCESS = 'ADMIN_USERS_UNSUGGEST_SUCCESS';
export const ADMIN_USERS_UNSUGGEST_FAIL = 'ADMIN_USERS_UNSUGGEST_FAIL';
const nicknamesFromIds = (getState, ids) => ids.map(id => getState().getIn(['accounts', id, 'acct']));
export function fetchConfig() {
@ -319,3 +327,31 @@ export function demoteToUser(accountId) {
]);
};
}
export function suggestUsers(accountIds) {
return (dispatch, getState) => {
const nicknames = nicknamesFromIds(getState, accountIds);
dispatch({ type: ADMIN_USERS_SUGGEST_REQUEST, accountIds });
return api(getState)
.patch('/api/pleroma/admin/users/suggest', { nicknames })
.then(({ data: { users } }) => {
dispatch({ type: ADMIN_USERS_SUGGEST_SUCCESS, users, accountIds });
}).catch(error => {
dispatch({ type: ADMIN_USERS_SUGGEST_FAIL, error, accountIds });
});
};
}
export function unsuggestUsers(accountIds) {
return (dispatch, getState) => {
const nicknames = nicknamesFromIds(getState, accountIds);
dispatch({ type: ADMIN_USERS_UNSUGGEST_REQUEST, accountIds });
return api(getState)
.patch('/api/pleroma/admin/users/unsuggest', { nicknames })
.then(({ data: { users } }) => {
dispatch({ type: ADMIN_USERS_UNSUGGEST_SUCCESS, users, accountIds });
}).catch(error => {
dispatch({ type: ADMIN_USERS_UNSUGGEST_FAIL, error, accountIds });
});
};
}

Wyświetl plik

@ -68,6 +68,8 @@ const messages = defineMessages({
demoteToUser: { id: 'admin.users.actions.demote_to_user', defaultMessage: 'Demote @{name} to a regular user' },
subscribe: { id: 'account.subscribe', defaultMessage: 'Subscribe to notifications from @{name}' },
unsubscribe: { id: 'account.unsubscribe', defaultMessage: 'Unsubscribe to notifications from @{name}' },
suggestUser: { id: 'admin.users.actions.suggest_user', defaultMessage: 'Suggest @{name}' },
unsuggestUser: { id: 'admin.users.actions.unsuggest_user', defaultMessage: 'Unsuggest @{name}' },
});
const mapStateToProps = state => {
@ -405,6 +407,20 @@ class Header extends ImmutablePureComponent {
});
}
if (account.getIn(['pleroma', 'is_suggested'])) {
menu.push({
text: intl.formatMessage(messages.unsuggestUser, { name: account.get('username') }),
action: this.props.onUnsuggestUser,
icon: require('@tabler/icons/icons/user-x.svg'),
});
} else {
menu.push({
text: intl.formatMessage(messages.suggestUser, { name: account.get('username') }),
action: this.props.onSuggestUser,
icon: require('@tabler/icons/icons/user-check.svg'),
});
}
if (account.get('id') !== me) {
menu.push({
text: intl.formatMessage(messages.deactivateUser, { name: account.get('username') }),

Wyświetl plik

@ -117,6 +117,14 @@ export default class Header extends ImmutablePureComponent {
this.props.onDemoteToUser(this.props.account);
}
handleSuggestUser = () => {
this.props.onSuggestUser(this.props.account);
}
handleUnsuggestUser = () => {
this.props.onUnsuggestUser(this.props.account);
}
render() {
const { account, identity_proofs } = this.props;
const moved = (account) ? account.get('moved') : false;
@ -148,6 +156,8 @@ export default class Header extends ImmutablePureComponent {
onPromoteToAdmin={this.handlePromoteToAdmin}
onPromoteToModerator={this.handlePromoteToModerator}
onDemoteToUser={this.handleDemoteToUser}
onSuggestUser={this.handleSuggestUser}
onUnsuggestUser={this.handleUnsuggestUser}
username={this.props.username}
/>
</div>

Wyświetl plik

@ -32,6 +32,8 @@ import {
promoteToAdmin,
promoteToModerator,
demoteToUser,
suggestUsers,
unsuggestUsers,
} from 'soapbox/actions/admin';
import { isAdmin } from 'soapbox/utils/accounts';
import snackbar from 'soapbox/actions/snackbar';
@ -47,7 +49,8 @@ const messages = defineMessages({
promotedToModerator: { id: 'admin.users.actions.promote_to_moderator_message', defaultMessage: '@{acct} was promoted to a moderator' },
demotedToModerator: { id: 'admin.users.actions.demote_to_moderator_message', defaultMessage: '@{acct} was demoted to a moderator' },
demotedToUser: { id: 'admin.users.actions.demote_to_user_message', defaultMessage: '@{acct} was demoted to a regular user' },
userSuggested: { id: 'admin.users.user_suggested_message', defaultMessage: '@{acct} was suggested' },
userUnsuggested: { id: 'admin.users.user_unsuggested_message', defaultMessage: '@{acct} was unsuggested' },
});
const makeMapStateToProps = () => {
@ -213,6 +216,22 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
.then(() => dispatch(snackbar.success(message)))
.catch(() => {});
},
onSuggestUser(account) {
const message = intl.formatMessage(messages.userSuggested, { acct: account.get('acct') });
dispatch(suggestUsers([account.get('id')]))
.then(() => dispatch(snackbar.success(message)))
.catch(() => {});
},
onUnsuggestUser(account) {
const message = intl.formatMessage(messages.userUnsuggested, { acct: account.get('acct') });
dispatch(unsuggestUsers([account.get('id')]))
.then(() => dispatch(snackbar.success(message)))
.catch(() => {});
},
});
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Header));

Wyświetl plik

@ -62,6 +62,9 @@ class DefaultPage extends ImmutablePureComponent {
{Component => <Component key='sign-up-panel' />}
</BundleContainer>
)}
<BundleContainer fetchComponent={PromoPanel}>
{Component => <Component key='promo-panel' />}
</BundleContainer>
{showTrendsPanel && (
<BundleContainer fetchComponent={TrendsPanel}>
{Component => <Component limit={3} key='trends-panel' />}
@ -72,9 +75,6 @@ class DefaultPage extends ImmutablePureComponent {
{Component => <Component limit={5} key='wtf-panel' />}
</BundleContainer>
)}
<BundleContainer fetchComponent={PromoPanel}>
{Component => <Component key='promo-panel' />}
</BundleContainer>
<LinkFooter key='link-footer' />
</Sticky>
</div>

Wyświetl plik

@ -96,16 +96,6 @@ class HomePage extends ImmutablePureComponent {
{Component => <Component key='sign-up-panel' />}
</BundleContainer>
)}
{showTrendsPanel && (
<BundleContainer fetchComponent={TrendsPanel}>
{Component => <Component limit={3} key='trends-panel' />}
</BundleContainer>
)}
{showWhoToFollowPanel && (
<BundleContainer fetchComponent={WhoToFollowPanel}>
{Component => <Component limit={5} key='wtf-panel' />}
</BundleContainer>
)}
<BundleContainer fetchComponent={PromoPanel}>
{Component => <Component key='promo-panel' />}
</BundleContainer>
@ -119,6 +109,16 @@ class HomePage extends ImmutablePureComponent {
{Component => <Component limit={cryptoLimit} key='crypto-panel' />}
</BundleContainer>
)}
{showTrendsPanel && (
<BundleContainer fetchComponent={TrendsPanel}>
{Component => <Component limit={3} key='trends-panel' />}
</BundleContainer>
)}
{showWhoToFollowPanel && (
<BundleContainer fetchComponent={WhoToFollowPanel}>
{Component => <Component limit={5} key='wtf-panel' />}
</BundleContainer>
)}
<LinkFooter key='link-footer' />
</Sticky>
</div>

Wyświetl plik

@ -63,6 +63,9 @@ class StatusPage extends ImmutablePureComponent {
{Component => <Component key='sign-up-panel' />}
</BundleContainer>
)}
<BundleContainer fetchComponent={PromoPanel}>
{Component => <Component key='promo-panel' />}
</BundleContainer>
{showTrendsPanel && (
<BundleContainer fetchComponent={TrendsPanel}>
{Component => <Component limit={3} key='trends-panel' />}
@ -73,9 +76,6 @@ class StatusPage extends ImmutablePureComponent {
{Component => <Component limit={5} key='wtf-panel' />}
</BundleContainer>
)}
<BundleContainer fetchComponent={PromoPanel}>
{Component => <Component key='promo-panel' />}
</BundleContainer>
<LinkFooter key='link-footer' />
</Sticky>
</div>

Wyświetl plik

@ -30,6 +30,10 @@ import {
ADMIN_USERS_DELETE_FAIL,
ADMIN_USERS_DEACTIVATE_REQUEST,
ADMIN_USERS_DEACTIVATE_FAIL,
ADMIN_USERS_SUGGEST_REQUEST,
ADMIN_USERS_SUGGEST_FAIL,
ADMIN_USERS_UNSUGGEST_REQUEST,
ADMIN_USERS_UNSUGGEST_FAIL,
} from 'soapbox/actions/admin';
const initialState = ImmutableMap();
@ -185,6 +189,14 @@ const importAdminUsers = (state, adminUsers) => {
});
};
const setSuggested = (state, accountIds, isSuggested) => {
return state.withMutations(state => {
accountIds.forEach(id => {
state.setIn([id, 'pleroma', 'is_suggested'], isSuggested);
});
});
};
export default function accounts(state = initialState, action) {
switch(action.type) {
case ACCOUNT_IMPORT:
@ -224,6 +236,12 @@ export default function accounts(state = initialState, action) {
return setActive(state, action.accountIds, true);
case ADMIN_USERS_FETCH_SUCCESS:
return importAdminUsers(state, action.users);
case ADMIN_USERS_SUGGEST_REQUEST:
case ADMIN_USERS_UNSUGGEST_FAIL:
return setSuggested(state, action.accountIds, true);
case ADMIN_USERS_UNSUGGEST_REQUEST:
case ADMIN_USERS_SUGGEST_FAIL:
return setSuggested(state, action.accountIds, false);
default:
return state;
}

Wyświetl plik

@ -24,8 +24,14 @@ export const getFeatures = createSelector([
v.software === MASTODON && gte(v.compatVersion, '2.1.0'),
v.software === PLEROMA && gte(v.version, '0.9.9'),
]),
suggestions: v.software === MASTODON && gte(v.compatVersion, '2.4.3'),
suggestionsV2: v.software === MASTODON && gte(v.compatVersion, '3.4.0'),
suggestions: any([
v.software === MASTODON && gte(v.compatVersion, '2.4.3'),
features.includes('v2_suggestions'),
]),
suggestionsV2: any([
v.software === MASTODON && gte(v.compatVersion, '3.4.0'),
features.includes('v2_suggestions'),
]),
trends: v.software === MASTODON && gte(v.compatVersion, '3.0.0'),
mediaV2: any([
v.software === MASTODON && gte(v.compatVersion, '3.1.3'),