Delete groups (legacy communities system) (#8027)

* Remove deprecated feature_communities_v2_prototypes

* Update _components

* i18n

* delint

* Cut out a bit more dead code

* Carve into legacy components

* Carve into mostly the room list code

* Carve into instances of "groupId"

* Carve out more of what comes up with "groups"

* Carve out some settings

* ignore related groups state

* Remove instances of spacesEnabled

* Fix some obvious issues

* Remove now-unused css

* Fix variable naming for legacy components

* Update i18n

* Misc cleanup from manual review

* Update snapshot for changed flag

* Appease linters

* rethemedex

* Remove now-unused AddressPickerDialog

* Make ConfirmUserActionDialog's member a required prop

* Remove useless override from RightPanelStore

* Remove extraneous CSS

* Update i18n

* Demo: "Communities are now Spaces" landing page

* Restore linkify for group IDs

* Demo: Dialog on click for communities->spaces notice

* i18n for demos

* i18n post-merge

* Update copy

* Appease the linter

* Post-merge cleanup

* Re-add spaces_learn_more_url to the new SdkConfig place

* Round 1 of post-merge fixes

* i18n

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Travis Ralston 2022-03-22 17:07:37 -06:00 committed by GitHub
parent 03c80707c9
commit fce36ec826
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
171 changed files with 317 additions and 12160 deletions

View file

@ -1,110 +0,0 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2017 New Vector Ltd
Copyright 2018 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import { _t } from '../../../languageHandler';
import HeaderButton from './HeaderButton';
import HeaderButtons, { HeaderKind } from './HeaderButtons';
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
import { Action } from "../../../dispatcher/actions";
import { ActionPayload } from "../../../dispatcher/payloads";
import { ViewUserPayload } from "../../../dispatcher/payloads/ViewUserPayload";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import RightPanelStore from '../../../stores/right-panel/RightPanelStore';
const GROUP_PHASES = [
RightPanelPhases.GroupMemberInfo,
RightPanelPhases.GroupMemberList,
];
const ROOM_PHASES = [
RightPanelPhases.GroupRoomList,
RightPanelPhases.GroupRoomInfo,
];
interface IProps {}
@replaceableComponent("views.right_panel.GroupHeaderButtons")
export default class GroupHeaderButtons extends HeaderButtons {
constructor(props: IProps) {
super(props, HeaderKind.Group);
}
protected onAction(payload: ActionPayload) {
if (payload.action === Action.ViewUser) {
if ((payload as ViewUserPayload).member) {
RightPanelStore.instance.setCards([
{ phase: RightPanelPhases.GroupRoomInfo },
{ phase: RightPanelPhases.GroupMemberList },
{ phase: RightPanelPhases.RoomMemberInfo, state: { member: payload.member } },
]);
} else {
this.setPhase(RightPanelPhases.GroupMemberList);
}
} else if (payload.action === "view_group") {
this.setPhase(RightPanelPhases.GroupMemberList);
} else if (payload.action === "view_group_room") {
this.setPhase(
RightPanelPhases.GroupRoomInfo,
{ groupRoomId: payload.groupRoomId, groupId: payload.groupId },
);
} else if (payload.action === "view_group_room_list") {
this.setPhase(RightPanelPhases.GroupRoomList);
} else if (payload.action === "view_group_member_list") {
this.setPhase(RightPanelPhases.GroupMemberList);
} else if (payload.action === "view_group_user") {
this.setPhase(RightPanelPhases.GroupMemberInfo, { member: payload.member });
}
}
private onMembersClicked = () => {
if (this.state.phase === RightPanelPhases.GroupMemberInfo) {
// send the active phase to trigger a toggle
this.setPhase(RightPanelPhases.GroupMemberInfo);
} else {
// This toggles for us, if needed
this.setPhase(RightPanelPhases.GroupMemberList);
}
};
private onRoomsClicked = () => {
// This toggles for us, if needed
this.setPhase(RightPanelPhases.GroupRoomList);
};
renderButtons() {
return <>
<HeaderButton
name="groupMembersButton"
title={_t('Members')}
isHighlighted={this.isPhase(GROUP_PHASES)}
onClick={this.onMembersClicked}
analytics={['Right Panel', 'Group Member List Button', 'click']}
/>
<HeaderButton
name="roomsButton"
title={_t('Rooms')}
isHighlighted={this.isPhase(ROOM_PHASES)}
onClick={this.onRoomsClicked}
analytics={['Right Panel', 'Group Room List Button', 'click']}
/>
</>;
}
}

View file

@ -30,7 +30,6 @@ import { NotificationColor } from '../../../stores/notifications/NotificationCol
export enum HeaderKind {
Room = "room",
Group = "group",
}
interface IState {
@ -91,9 +90,7 @@ export default abstract class HeaderButtons<P = {}> extends React.Component<IPro
private onRightPanelStoreUpdate = () => {
if (this.unmounted) return;
let phase = RightPanelStore.instance.currentCard.phase;
if (!RightPanelStore.instance.isOpenForGroup) {phase = null;}
this.setState({ phase });
this.setState({ phase: RightPanelStore.instance.currentCard.phase });
};
// XXX: Make renderButtons a prop

View file

@ -39,7 +39,6 @@ import AccessibleButton, { ButtonEvent } from '../elements/AccessibleButton';
import SdkConfig from '../../../SdkConfig';
import RoomViewStore from "../../../stores/RoomViewStore";
import MultiInviter from "../../../utils/MultiInviter";
import GroupStore from "../../../stores/GroupStore";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import E2EIcon from "../rooms/E2EIcon";
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
@ -69,7 +68,6 @@ import RoomName from "../elements/RoomName";
import { mediaFromMxc } from "../../../customisations/Media";
import UIStore from "../../../stores/UIStore";
import { ComposerInsertPayload } from "../../../dispatcher/payloads/ComposerInsertPayload";
import SpaceStore from "../../../stores/spaces/SpaceStore";
import ConfirmSpaceUserActionDialog from "../dialogs/ConfirmSpaceUserActionDialog";
import { bulkSpaceBehaviour } from "../../../utils/space";
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
@ -753,7 +751,7 @@ const MuteToggleButton: React.FC<IBaseRoomProps> = ({ member, room, powerLevels,
// if muting self, warn as it may be irreversible
if (target === cli.getUserId()) {
try {
if (!(await warnSelfDemote(SpaceStore.spacesEnabled && room?.isSpaceRoom()))) return;
if (!(await warnSelfDemote(room?.isSpaceRoom()))) return;
} catch (e) {
logger.error("Failed to warn about self demotion: ", e);
return;
@ -847,7 +845,7 @@ const RoomAdminToolsContainer: React.FC<IBaseRoomProps> = ({
stopUpdating={stopUpdating}
/>;
}
if (me.powerLevel >= redactPowerLevel && (!SpaceStore.spacesEnabled || !room.isSpaceRoom())) {
if (me.powerLevel >= redactPowerLevel && !room.isSpaceRoom()) {
redactButton = (
<RedactMessagesButton member={member} startUpdating={startUpdating} stopUpdating={stopUpdating} />
);
@ -885,99 +883,6 @@ const RoomAdminToolsContainer: React.FC<IBaseRoomProps> = ({
return <div />;
};
export interface GroupMember {
userId: string;
displayname?: string; // XXX: GroupMember objects are inconsistent :((
avatarUrl?: string;
}
const GroupAdminToolsSection: React.FC<{
groupId: string;
groupMember: GroupMember;
startUpdating(): void;
stopUpdating(): void;
}> = ({ children, groupId, groupMember, startUpdating, stopUpdating }) => {
const cli = useContext(MatrixClientContext);
const [isPrivileged, setIsPrivileged] = useState(false);
const [isInvited, setIsInvited] = useState(false);
// Listen to group store changes
useEffect(() => {
let unmounted = false;
const onGroupStoreUpdated = () => {
if (unmounted) return;
setIsPrivileged(GroupStore.isUserPrivileged(groupId));
setIsInvited(GroupStore.getGroupInvitedMembers(groupId).some(
(m) => m.userId === groupMember.userId,
));
};
GroupStore.registerListener(groupId, onGroupStoreUpdated);
onGroupStoreUpdated();
// Handle unmount
return () => {
unmounted = true;
GroupStore.unregisterListener(onGroupStoreUpdated);
};
}, [groupId, groupMember.userId]);
if (isPrivileged) {
const onKick = async () => {
const { finished } = Modal.createDialog(ConfirmUserActionDialog, {
matrixClient: cli,
groupMember,
action: isInvited ? _t('Disinvite') : _t('Remove from community'),
title: isInvited ? _t('Disinvite this user from community?')
: _t('Remove this user from community?'),
danger: true,
});
const [proceed] = await finished;
if (!proceed) return;
startUpdating();
cli.removeUserFromGroup(groupId, groupMember.userId).then(() => {
// return to the user list
dis.dispatch({
action: Action.ViewUser,
member: null,
});
}).catch((e) => {
Modal.createTrackedDialog('Failed to remove user from group', '', ErrorDialog, {
title: _t('Error'),
description: isInvited ?
_t('Failed to withdraw invitation') :
_t('Failed to remove user from community'),
});
logger.log(e);
}).finally(() => {
stopUpdating();
});
};
const kickButton = (
<AccessibleButton className="mx_UserInfo_field mx_UserInfo_destructive" onClick={onKick}>
{ isInvited ? _t('Disinvite') : _t('Remove from community') }
</AccessibleButton>
);
// No make/revoke admin API yet
/*const opLabel = this.state.isTargetMod ? _t("Revoke Moderator") : _t("Make Moderator");
giveModButton = <AccessibleButton className="mx_UserInfo_field" onClick={this.onModToggle}>
{giveOpLabel}
</AccessibleButton>;*/
return <GenericAdminToolsContainer>
{ kickButton }
{ children }
</GenericAdminToolsContainer>;
}
return <div />;
};
const useIsSynapseAdmin = (cli: MatrixClient) => {
const [isAdmin, setIsAdmin] = useState(false);
useEffect(() => {
@ -1135,7 +1040,7 @@ const PowerLevelEditor: React.FC<{
} else if (myUserId === target) {
// If we are changing our own PL it can only ever be decreasing, which we cannot reverse.
try {
if (!(await warnSelfDemote(SpaceStore.spacesEnabled && room?.isSpaceRoom()))) return;
if (!(await warnSelfDemote(room?.isSpaceRoom()))) return;
} catch (e) {
logger.error("Failed to warn about self demotion: ", e);
}
@ -1233,10 +1138,9 @@ export const useDevices = (userId: string) => {
const BasicUserInfo: React.FC<{
room: Room;
member: User | RoomMember;
groupId: string;
devices: IDevice[];
isRoomEncrypted: boolean;
}> = ({ room, member, groupId, devices, isRoomEncrypted }) => {
}> = ({ room, member, devices, isRoomEncrypted }) => {
const cli = useContext(MatrixClientContext);
const powerLevels = useRoomPowerLevels(cli, room);
@ -1338,16 +1242,6 @@ const BasicUserInfo: React.FC<{
{ synapseDeactivateButton }
</RoomAdminToolsContainer>
);
} else if (groupId) {
adminToolsContainer = (
<GroupAdminToolsSection
groupId={groupId}
groupMember={member}
startUpdating={startUpdating}
stopUpdating={stopUpdating}>
{ synapseDeactivateButton }
</GroupAdminToolsSection>
);
} else if (synapseDeactivateButton) {
adminToolsContainer = (
<GenericAdminToolsContainer>
@ -1367,10 +1261,10 @@ const BasicUserInfo: React.FC<{
if (!isRoomEncrypted) {
if (!cryptoEnabled) {
text = _t("This client does not support end-to-end encryption.");
} else if (room && (!SpaceStore.spacesEnabled || !room.isSpaceRoom())) {
} else if (room && !room.isSpaceRoom()) {
text = _t("Messages in this room are not end-to-end encrypted.");
}
} else if (!SpaceStore.spacesEnabled || !room.isSpaceRoom()) {
} else if (!room.isSpaceRoom()) {
text = _t("Messages in this room are end-to-end encrypted.");
}
@ -1452,7 +1346,7 @@ const BasicUserInfo: React.FC<{
canInvite={roomPermissions.canInvite}
isIgnored={isIgnored}
member={member as RoomMember}
isSpace={SpaceStore.spacesEnabled && room?.isSpaceRoom()}
isSpace={room?.isSpaceRoom()}
/>
{ adminToolsContainer }
@ -1461,7 +1355,7 @@ const BasicUserInfo: React.FC<{
</React.Fragment>;
};
export type Member = User | RoomMember | GroupMember;
export type Member = User | RoomMember;
const UserInfoHeader: React.FC<{
member: Member;
@ -1540,7 +1434,7 @@ const UserInfoHeader: React.FC<{
e2eIcon = <E2EIcon size={18} status={e2eStatus} isUser={true} />;
}
const displayName = (member as RoomMember).rawDisplayName || (member as GroupMember).displayname;
const displayName = (member as RoomMember).rawDisplayName;
return <React.Fragment>
{ avatarElement }
@ -1566,10 +1460,8 @@ const UserInfoHeader: React.FC<{
interface IProps {
user: Member;
groupId?: string;
room?: Room;
phase: RightPanelPhases.RoomMemberInfo
| RightPanelPhases.GroupMemberInfo
| RightPanelPhases.SpaceMemberInfo
| RightPanelPhases.EncryptionPanel;
onClose(): void;
@ -1579,7 +1471,6 @@ interface IProps {
const UserInfo: React.FC<IProps> = ({
user,
groupId,
room,
onClose,
phase = RightPanelPhases.RoomMemberInfo,
@ -1601,10 +1492,10 @@ const UserInfo: React.FC<IProps> = ({
const classes = ["mx_UserInfo"];
let cardState: IRightPanelCardState;
// We have no previousPhase for when viewing a UserInfo from a Group or without a Room at this time
// We have no previousPhase for when viewing a UserInfo without a Room at this time
if (room && phase === RightPanelPhases.EncryptionPanel) {
cardState = { member };
} else if (room?.isSpaceRoom() && SpaceStore.spacesEnabled) {
} else if (room?.isSpaceRoom()) {
cardState = { spaceId: room.roomId };
}
@ -1615,13 +1506,11 @@ const UserInfo: React.FC<IProps> = ({
let content;
switch (phase) {
case RightPanelPhases.RoomMemberInfo:
case RightPanelPhases.GroupMemberInfo:
case RightPanelPhases.SpaceMemberInfo:
content = (
<BasicUserInfo
room={room}
member={member as User}
groupId={groupId as string}
devices={devices}
isRoomEncrypted={isRoomEncrypted}
/>
@ -1649,7 +1538,7 @@ const UserInfo: React.FC<IProps> = ({
}
let scopeHeader;
if (SpaceStore.spacesEnabled && room?.isSpaceRoom()) {
if (room?.isSpaceRoom()) {
scopeHeader = <div data-test-id='space-header' className="mx_RightPanel_scopeHeader">
<RoomAvatar room={room} height={32} width={32} />
<RoomName room={room} />