Move Promote/Demote admin into entity store
This commit is contained in:
parent
bc457b61d1
commit
89bdc9b4a1
9 changed files with 143 additions and 53 deletions
|
@ -28,6 +28,10 @@ interface EntityActionEndpoints {
|
||||||
delete?: string
|
delete?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface EntityCallbacks<TEntity extends Entity = Entity> {
|
||||||
|
onSuccess?(entity: TEntity): void
|
||||||
|
}
|
||||||
|
|
||||||
function useEntityActions<TEntity extends Entity = Entity, P = any>(
|
function useEntityActions<TEntity extends Entity = Entity, P = any>(
|
||||||
path: EntityPath,
|
path: EntityPath,
|
||||||
endpoints: EntityActionEndpoints,
|
endpoints: EntityActionEndpoints,
|
||||||
|
@ -38,7 +42,7 @@ function useEntityActions<TEntity extends Entity = Entity, P = any>(
|
||||||
const getState = useGetState();
|
const getState = useGetState();
|
||||||
const [entityType, listKey] = path;
|
const [entityType, listKey] = path;
|
||||||
|
|
||||||
function createEntity(params: P): Promise<CreateEntityResult<TEntity>> {
|
function createEntity(params: P, callbacks: EntityCallbacks = {}): Promise<CreateEntityResult<TEntity>> {
|
||||||
if (!endpoints.post) return Promise.reject(endpoints);
|
if (!endpoints.post) return Promise.reject(endpoints);
|
||||||
|
|
||||||
return api.post(endpoints.post, params).then((response) => {
|
return api.post(endpoints.post, params).then((response) => {
|
||||||
|
@ -48,6 +52,10 @@ function useEntityActions<TEntity extends Entity = Entity, P = any>(
|
||||||
// TODO: optimistic updating
|
// TODO: optimistic updating
|
||||||
dispatch(importEntities([entity], entityType, listKey));
|
dispatch(importEntities([entity], entityType, listKey));
|
||||||
|
|
||||||
|
if (callbacks.onSuccess) {
|
||||||
|
callbacks.onSuccess(entity);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
response,
|
response,
|
||||||
entity,
|
entity,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import clsx from 'clsx';
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { defineMessages, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { groupDemoteAccount, groupKick, groupPromoteAccount } from 'soapbox/actions/groups';
|
import { groupKick } from 'soapbox/actions/groups';
|
||||||
import { openModal } from 'soapbox/actions/modals';
|
import { openModal } from 'soapbox/actions/modals';
|
||||||
import Account from 'soapbox/components/account';
|
import Account from 'soapbox/components/account';
|
||||||
import DropdownMenu from 'soapbox/components/dropdown-menu/dropdown-menu';
|
import DropdownMenu from 'soapbox/components/dropdown-menu/dropdown-menu';
|
||||||
|
@ -10,8 +10,8 @@ import { HStack } from 'soapbox/components/ui';
|
||||||
import { deleteEntities } from 'soapbox/entity-store/actions';
|
import { deleteEntities } from 'soapbox/entity-store/actions';
|
||||||
import { Entities } from 'soapbox/entity-store/entities';
|
import { Entities } from 'soapbox/entity-store/entities';
|
||||||
import { useAccount, useAppDispatch, useFeatures } from 'soapbox/hooks';
|
import { useAccount, useAppDispatch, useFeatures } from 'soapbox/hooks';
|
||||||
import { useBlockGroupMember } from 'soapbox/hooks/api/groups/useBlockGroupMember';
|
import { useBlockGroupMember, useDemoteGroupMember, usePromoteGroupMember } from 'soapbox/hooks/api';
|
||||||
import { BaseGroupRoles, useGroupRoles } from 'soapbox/hooks/useGroupRoles';
|
import { BaseGroupRoles, TruthSocialGroupRoles, useGroupRoles } from 'soapbox/hooks/useGroupRoles';
|
||||||
import toast from 'soapbox/toast';
|
import toast from 'soapbox/toast';
|
||||||
|
|
||||||
import type { Menu as IMenu } from 'soapbox/components/dropdown-menu';
|
import type { Menu as IMenu } from 'soapbox/components/dropdown-menu';
|
||||||
|
@ -24,17 +24,17 @@ const messages = defineMessages({
|
||||||
blocked: { id: 'group.group_mod_block.success', defaultMessage: 'You have successfully blocked @{name} from the group' },
|
blocked: { id: 'group.group_mod_block.success', defaultMessage: 'You have successfully blocked @{name} from the group' },
|
||||||
demotedToUser: { id: 'group.group_mod_demote.success', defaultMessage: 'Demoted @{name} to group user' },
|
demotedToUser: { id: 'group.group_mod_demote.success', defaultMessage: 'Demoted @{name} to group user' },
|
||||||
groupModBlock: { id: 'group.group_mod_block', defaultMessage: 'Ban from group' },
|
groupModBlock: { id: 'group.group_mod_block', defaultMessage: 'Ban from group' },
|
||||||
groupModDemote: { id: 'group.group_mod_demote', defaultMessage: 'Demote @{name}' },
|
groupModDemote: { id: 'group.group_mod_demote', defaultMessage: 'Remove {role} role' },
|
||||||
groupModKick: { id: 'group.group_mod_kick', defaultMessage: 'Kick @{name} from group' },
|
groupModKick: { id: 'group.group_mod_kick', defaultMessage: 'Kick @{name} from group' },
|
||||||
groupModPromoteAdmin: { id: 'group.group_mod_promote_admin', defaultMessage: 'Promote @{name} to group administrator' },
|
groupModPromoteAdmin: { id: 'group.group_mod_promote_admin', defaultMessage: 'Promote @{name} to group administrator' },
|
||||||
groupModPromoteMod: { id: 'group.group_mod_promote_mod', defaultMessage: 'Promote @{name} to group moderator' },
|
groupModPromoteMod: { id: 'group.group_mod_promote_mod', defaultMessage: 'Assign {role} role' },
|
||||||
kickConfirm: { id: 'confirmations.kick_from_group.confirm', defaultMessage: 'Kick' },
|
kickConfirm: { id: 'confirmations.kick_from_group.confirm', defaultMessage: 'Kick' },
|
||||||
kickFromGroupMessage: { id: 'confirmations.kick_from_group.message', defaultMessage: 'Are you sure you want to kick @{name} from this group?' },
|
kickFromGroupMessage: { id: 'confirmations.kick_from_group.message', defaultMessage: 'Are you sure you want to kick @{name} from this group?' },
|
||||||
kicked: { id: 'group.group_mod_kick.success', defaultMessage: 'Kicked @{name} from group' },
|
kicked: { id: 'group.group_mod_kick.success', defaultMessage: 'Kicked @{name} from group' },
|
||||||
promoteConfirm: { id: 'confirmations.promote_in_group.confirm', defaultMessage: 'Promote' },
|
promoteConfirm: { id: 'confirmations.promote_in_group.confirm', defaultMessage: 'Promote' },
|
||||||
promoteConfirmMessage: { id: 'confirmations.promote_in_group.message', defaultMessage: 'Are you sure you want to promote @{name}? You will not be able to demote them.' },
|
promoteConfirmMessage: { id: 'confirmations.promote_in_group.message', defaultMessage: 'Are you sure you want to promote @{name}? You will not be able to demote them.' },
|
||||||
promotedToAdmin: { id: 'group.group_mod_promote_admin.success', defaultMessage: 'Promoted @{name} to group administrator' },
|
promotedToAdmin: { id: 'group.group_mod_promote_admin.success', defaultMessage: 'Promoted @{name} to group administrator' },
|
||||||
promotedToMod: { id: 'group.group_mod_promote_mod.success', defaultMessage: 'Promoted @{name} to group moderator' },
|
promotedToMod: { id: 'group.group_mod_promote_mod.success', defaultMessage: 'You have successfully promoted @{name} to group {role}.' },
|
||||||
});
|
});
|
||||||
|
|
||||||
interface IGroupMemberListItem {
|
interface IGroupMemberListItem {
|
||||||
|
@ -49,8 +49,10 @@ const GroupMemberListItem = (props: IGroupMemberListItem) => {
|
||||||
const features = useFeatures();
|
const features = useFeatures();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const { normalizeRole } = useGroupRoles();
|
const { roles, isAdminRole, normalizeRole } = useGroupRoles();
|
||||||
const blockGroupMember = useBlockGroupMember(group, member);
|
const blockGroupMember = useBlockGroupMember(group, member);
|
||||||
|
const promoteGroupMember = usePromoteGroupMember(group, member);
|
||||||
|
const demoteGroupMember = useDemoteGroupMember(group, member);
|
||||||
|
|
||||||
const account = useAccount(member.account.id) as AccountEntity;
|
const account = useAccount(member.account.id) as AccountEntity;
|
||||||
|
|
||||||
|
@ -78,39 +80,59 @@ const GroupMemberListItem = (props: IGroupMemberListItem) => {
|
||||||
heading: intl.formatMessage(messages.blockFromGroupHeading),
|
heading: intl.formatMessage(messages.blockFromGroupHeading),
|
||||||
message: intl.formatMessage(messages.blockFromGroupMessage, { name: account.username }),
|
message: intl.formatMessage(messages.blockFromGroupMessage, { name: account.username }),
|
||||||
confirm: intl.formatMessage(messages.blockConfirm),
|
confirm: intl.formatMessage(messages.blockConfirm),
|
||||||
onConfirm: () => blockGroupMember({ account_ids: [member.account.id] }).then(() => {
|
onConfirm: () => {
|
||||||
dispatch(deleteEntities([member.id], Entities.GROUP_MEMBERSHIPS));
|
blockGroupMember({ account_ids: [member.account.id] }, {
|
||||||
toast.success(intl.formatMessage(messages.blocked, { name: account.acct }));
|
onSuccess() {
|
||||||
}),
|
dispatch(deleteEntities([member.id], Entities.GROUP_MEMBERSHIPS));
|
||||||
|
toast.success(intl.formatMessage(messages.blocked, { name: account.acct }));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPromote = (role: 'admin' | 'moderator', warning?: boolean) => {
|
const onPromote = (role: TruthSocialGroupRoles | BaseGroupRoles, warning?: boolean) => {
|
||||||
if (warning) {
|
if (warning) {
|
||||||
return dispatch(openModal('CONFIRM', {
|
return dispatch(openModal('CONFIRM', {
|
||||||
message: intl.formatMessage(messages.promoteConfirmMessage, { name: account.username }),
|
message: intl.formatMessage(messages.promoteConfirmMessage, { name: account.username }),
|
||||||
confirm: intl.formatMessage(messages.promoteConfirm),
|
confirm: intl.formatMessage(messages.promoteConfirm),
|
||||||
onConfirm: () => dispatch(groupPromoteAccount(group.id, account.id, role)).then(() =>
|
onConfirm: () => {
|
||||||
toast.success(intl.formatMessage(role === 'admin' ? messages.promotedToAdmin : messages.promotedToMod, { name: account.acct })),
|
promoteGroupMember({ role: role, account_ids: [account.id] }, {
|
||||||
),
|
onSuccess() {
|
||||||
|
toast.success(
|
||||||
|
intl.formatMessage(
|
||||||
|
isAdminRole(role) ? messages.promotedToAdmin : messages.promotedToMod, { name: account.acct, role },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
return dispatch(groupPromoteAccount(group.id, account.id, role)).then(() =>
|
promoteGroupMember({ role: role, account_ids: [account.id] }, {
|
||||||
toast.success(intl.formatMessage(role === 'admin' ? messages.promotedToAdmin : messages.promotedToMod, { name: account.acct })),
|
onSuccess() {
|
||||||
);
|
toast.success(
|
||||||
|
intl.formatMessage(
|
||||||
|
isAdminRole(role) ? messages.promotedToAdmin : messages.promotedToMod, { name: account.acct, role },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePromoteToGroupAdmin = () => onPromote('admin', true);
|
const handlePromoteToGroupAdmin = () => onPromote(roles.admin, true);
|
||||||
|
|
||||||
const handlePromoteToGroupMod = () => {
|
const handleAssignModerator = () => {
|
||||||
onPromote('moderator', group.relationship!.role === 'moderator');
|
onPromote(roles.moderator, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDemote = () => {
|
const handleDemote = () => {
|
||||||
dispatch(groupDemoteAccount(group.id, account.id, 'user')).then(() =>
|
demoteGroupMember({ role: roles.user, account_ids: [account.id] }, {
|
||||||
toast.success(intl.formatMessage(messages.demotedToUser, { name: account.acct })),
|
onSuccess() {
|
||||||
).catch(() => {});
|
toast.success(intl.formatMessage(messages.demotedToUser, { name: account.acct }));
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const menu: IMenu = useMemo(() => {
|
const menu: IMenu = useMemo(() => {
|
||||||
|
@ -120,6 +142,31 @@ const GroupMemberListItem = (props: IGroupMemberListItem) => {
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isCurrentUserAdmin && !isMemberAdmin && account.acct === account.username) {
|
||||||
|
if (isMemberModerator) {
|
||||||
|
if (features.groupsPromoteToAdmin) {
|
||||||
|
items.push({
|
||||||
|
text: intl.formatMessage(messages.groupModPromoteAdmin, { name: account.username }),
|
||||||
|
icon: require('@tabler/icons/arrow-up-circle.svg'),
|
||||||
|
action: handlePromoteToGroupAdmin,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
text: intl.formatMessage(messages.groupModDemote, { role: roles.moderator, name: account.username }),
|
||||||
|
icon: require('@tabler/icons/briefcase.svg'),
|
||||||
|
action: handleDemote,
|
||||||
|
destructive: true,
|
||||||
|
});
|
||||||
|
} else if (isMemberUser) {
|
||||||
|
items.push({
|
||||||
|
text: intl.formatMessage(messages.groupModPromoteMod, { role: roles.moderator }),
|
||||||
|
icon: require('@tabler/icons/briefcase.svg'),
|
||||||
|
action: handleAssignModerator,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(isCurrentUserAdmin || isCurrentUserModerator) &&
|
(isCurrentUserAdmin || isCurrentUserModerator) &&
|
||||||
(isMemberModerator || isMemberUser) &&
|
(isMemberModerator || isMemberUser) &&
|
||||||
|
@ -141,29 +188,6 @@ const GroupMemberListItem = (props: IGroupMemberListItem) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCurrentUserAdmin && !isMemberAdmin && account.acct === account.username) {
|
|
||||||
items.push(null);
|
|
||||||
|
|
||||||
if (isMemberModerator) {
|
|
||||||
items.push({
|
|
||||||
text: intl.formatMessage(messages.groupModPromoteAdmin, { name: account.username }),
|
|
||||||
icon: require('@tabler/icons/arrow-up-circle.svg'),
|
|
||||||
action: handlePromoteToGroupAdmin,
|
|
||||||
});
|
|
||||||
items.push({
|
|
||||||
text: intl.formatMessage(messages.groupModDemote, { name: account.username }),
|
|
||||||
icon: require('@tabler/icons/arrow-down-circle.svg'),
|
|
||||||
action: handleDemote,
|
|
||||||
});
|
|
||||||
} else if (isMemberUser) {
|
|
||||||
items.push({
|
|
||||||
text: intl.formatMessage(messages.groupModPromoteMod, { name: account.username }),
|
|
||||||
icon: require('@tabler/icons/arrow-up-circle.svg'),
|
|
||||||
action: handlePromoteToGroupMod,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}, [group, account]);
|
}, [group, account]);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { useEntityActions } from 'soapbox/entity-store/hooks';
|
||||||
import type { Group, GroupMember } from 'soapbox/schemas';
|
import type { Group, GroupMember } from 'soapbox/schemas';
|
||||||
|
|
||||||
function useBlockGroupMember(group: Group, groupMember: GroupMember) {
|
function useBlockGroupMember(group: Group, groupMember: GroupMember) {
|
||||||
const { createEntity } = useEntityActions(
|
const { createEntity } = useEntityActions<GroupMember>(
|
||||||
[Entities.GROUP_MEMBERSHIPS, groupMember.id],
|
[Entities.GROUP_MEMBERSHIPS, groupMember.id],
|
||||||
{ post: `/api/v1/groups/${group.id}/blocks` },
|
{ post: `/api/v1/groups/${group.id}/blocks` },
|
||||||
);
|
);
|
||||||
|
|
19
app/soapbox/hooks/api/groups/useDemoteGroupMember.ts
Normal file
19
app/soapbox/hooks/api/groups/useDemoteGroupMember.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import { Entities } from 'soapbox/entity-store/entities';
|
||||||
|
import { useEntityActions } from 'soapbox/entity-store/hooks';
|
||||||
|
import { groupMemberSchema } from 'soapbox/schemas';
|
||||||
|
|
||||||
|
import type { Group, GroupMember } from 'soapbox/schemas';
|
||||||
|
|
||||||
|
function useDemoteGroupMember(group: Group, groupMember: GroupMember) {
|
||||||
|
const { createEntity } = useEntityActions<GroupMember>(
|
||||||
|
[Entities.GROUP_MEMBERSHIPS, groupMember.id],
|
||||||
|
{ post: `/api/v1/groups/${group.id}/demote` },
|
||||||
|
{ schema: z.array(groupMemberSchema).transform((arr) => arr[0]) },
|
||||||
|
);
|
||||||
|
|
||||||
|
return createEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { useDemoteGroupMember };
|
19
app/soapbox/hooks/api/groups/usePromoteGroupMember.ts
Normal file
19
app/soapbox/hooks/api/groups/usePromoteGroupMember.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import { Entities } from 'soapbox/entity-store/entities';
|
||||||
|
import { useEntityActions } from 'soapbox/entity-store/hooks';
|
||||||
|
import { groupMemberSchema } from 'soapbox/schemas';
|
||||||
|
|
||||||
|
import type { Group, GroupMember } from 'soapbox/schemas';
|
||||||
|
|
||||||
|
function usePromoteGroupMember(group: Group, groupMember: GroupMember) {
|
||||||
|
const { createEntity } = useEntityActions<GroupMember>(
|
||||||
|
[Entities.GROUP_MEMBERSHIPS, groupMember.id],
|
||||||
|
{ post: `/api/v1/groups/${group.id}/promote` },
|
||||||
|
{ schema: z.array(groupMemberSchema).transform((arr) => arr[0]) },
|
||||||
|
);
|
||||||
|
|
||||||
|
return createEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { usePromoteGroupMember };
|
6
app/soapbox/hooks/api/index.ts
Normal file
6
app/soapbox/hooks/api/index.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
/**
|
||||||
|
* Groups
|
||||||
|
*/
|
||||||
|
export { useBlockGroupMember } from './groups/useBlockGroupMember';
|
||||||
|
export { useDemoteGroupMember } from './groups/useDemoteGroupMember';
|
||||||
|
export { usePromoteGroupMember } from './groups/usePromoteGroupMember';
|
|
@ -30,6 +30,14 @@ const useGroupRoles = () => {
|
||||||
const isTruthSocial = version.software === TRUTHSOCIAL;
|
const isTruthSocial = version.software === TRUTHSOCIAL;
|
||||||
const selectedRoles = isTruthSocial ? TruthSocialGroupRoles : BaseGroupRoles;
|
const selectedRoles = isTruthSocial ? TruthSocialGroupRoles : BaseGroupRoles;
|
||||||
|
|
||||||
|
const isAdminRole = (role: TruthSocialGroupRoles | BaseGroupRoles) => {
|
||||||
|
if (isTruthSocial) {
|
||||||
|
return role === TruthSocialGroupRoles.ADMIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return role === BaseGroupRoles.ADMIN;
|
||||||
|
};
|
||||||
|
|
||||||
const normalizeRole = (role: TruthSocialGroupRoles) => {
|
const normalizeRole = (role: TruthSocialGroupRoles) => {
|
||||||
if (isTruthSocial) {
|
if (isTruthSocial) {
|
||||||
return roleMap[role];
|
return roleMap[role];
|
||||||
|
@ -39,6 +47,7 @@ const useGroupRoles = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
isAdminRole,
|
||||||
normalizeRole,
|
normalizeRole,
|
||||||
roles: {
|
roles: {
|
||||||
admin: selectedRoles.ADMIN,
|
admin: selectedRoles.ADMIN,
|
||||||
|
|
|
@ -772,14 +772,14 @@
|
||||||
"group.group_mod_authorize.success": "Accepted @{name} to group",
|
"group.group_mod_authorize.success": "Accepted @{name} to group",
|
||||||
"group.group_mod_block": "Ban from group",
|
"group.group_mod_block": "Ban from group",
|
||||||
"group.group_mod_block.success": "You have successfully blocked @{name} from the group",
|
"group.group_mod_block.success": "You have successfully blocked @{name} from the group",
|
||||||
"group.group_mod_demote": "Demote @{name}",
|
"group.group_mod_demote": "Remove {role} role",
|
||||||
"group.group_mod_demote.success": "Demoted @{name} to group user",
|
"group.group_mod_demote.success": "Demoted @{name} to group user",
|
||||||
"group.group_mod_kick": "Kick @{name} from group",
|
"group.group_mod_kick": "Kick @{name} from group",
|
||||||
"group.group_mod_kick.success": "Kicked @{name} from group",
|
"group.group_mod_kick.success": "Kicked @{name} from group",
|
||||||
"group.group_mod_promote_admin": "Promote @{name} to group administrator",
|
"group.group_mod_promote_admin": "Promote @{name} to group administrator",
|
||||||
"group.group_mod_promote_admin.success": "Promoted @{name} to group administrator",
|
"group.group_mod_promote_admin.success": "Promoted @{name} to group administrator",
|
||||||
"group.group_mod_promote_mod": "Promote @{name} to group moderator",
|
"group.group_mod_promote_mod": "Assign {role} role",
|
||||||
"group.group_mod_promote_mod.success": "Promoted @{name} to group moderator",
|
"group.group_mod_promote_mod.success": "You have successfully promoted @{name} to group {role}.",
|
||||||
"group.group_mod_reject": "Reject",
|
"group.group_mod_reject": "Reject",
|
||||||
"group.group_mod_reject.success": "Rejected @{name} from group",
|
"group.group_mod_reject.success": "Rejected @{name} from group",
|
||||||
"group.group_mod_unblock": "Unblock",
|
"group.group_mod_unblock": "Unblock",
|
||||||
|
|
|
@ -528,9 +528,14 @@ const getInstanceFeatures = (instance: Instance) => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can query pending Group requests.
|
* Can query pending Group requests.
|
||||||
*/
|
*/
|
||||||
groupsPending: v.software === TRUTHSOCIAL,
|
groupsPending: v.software === TRUTHSOCIAL,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can promote members to Admins.
|
||||||
|
*/
|
||||||
|
groupsPromoteToAdmin: v.software !== TRUTHSOCIAL,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can hide follows/followers lists and counts.
|
* Can hide follows/followers lists and counts.
|
||||||
* @see PATCH /api/v1/accounts/update_credentials
|
* @see PATCH /api/v1/accounts/update_credentials
|
||||||
|
|
Loading…
Reference in a new issue