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,107 +0,0 @@
/*
Copyright 2019 New Vector Ltd.
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 classNames from 'classnames';
import CustomRoomTagStore from '../../stores/CustomRoomTagStore';
import AutoHideScrollbar from './AutoHideScrollbar';
import * as sdk from '../../index';
import dis from '../../dispatcher/dispatcher';
import * as FormattingUtils from '../../utils/FormattingUtils';
import { replaceableComponent } from "../../utils/replaceableComponent";
@replaceableComponent("structures.CustomRoomTagPanel")
class CustomRoomTagPanel extends React.Component {
constructor(props) {
super(props);
this.state = {
tags: CustomRoomTagStore.getSortedTags(),
};
}
componentDidMount() {
this._tagStoreToken = CustomRoomTagStore.addListener(() => {
this.setState({ tags: CustomRoomTagStore.getSortedTags() });
});
}
componentWillUnmount() {
if (this._tagStoreToken) {
this._tagStoreToken.remove();
}
}
render() {
const tags = this.state.tags.map((tag) => {
return (<CustomRoomTagTile tag={tag} key={tag.name} />);
});
const classes = classNames('mx_CustomRoomTagPanel', {
mx_CustomRoomTagPanel_empty: this.state.tags.length === 0,
});
return (<div className={classes}>
<div className="mx_CustomRoomTagPanel_divider" />
<AutoHideScrollbar className="mx_CustomRoomTagPanel_scroller">
{ tags }
</AutoHideScrollbar>
</div>);
}
}
class CustomRoomTagTile extends React.Component {
onClick = () => {
dis.dispatch({ action: 'select_custom_room_tag', tag: this.props.tag.name });
};
render() {
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
const AccessibleTooltipButton = sdk.getComponent('elements.AccessibleTooltipButton');
const tag = this.props.tag;
const avatarHeight = 40;
const className = classNames({
"CustomRoomTagPanel_tileSelected": tag.selected,
});
const name = tag.name;
const badgeNotifState = tag.badgeNotifState;
let badgeElement;
if (badgeNotifState) {
const badgeClasses = classNames({
"mx_TagTile_badge": true,
"mx_TagTile_badgeHighlight": badgeNotifState.hasMentions,
});
badgeElement = (<div className={badgeClasses}>{ FormattingUtils.formatCount(badgeNotifState.count) }</div>);
}
return (
<AccessibleTooltipButton className={className} onClick={this.onClick} title={name}>
<div className="mx_TagTile_avatar">
<BaseAvatar
name={tag.avatarLetter}
idName={name}
width={avatarHeight}
height={avatarHeight}
/>
{ badgeElement }
</div>
</AccessibleTooltipButton>
);
}
}
export default CustomRoomTagPanel;

View file

@ -1,182 +0,0 @@
/*
Copyright 2017, 2018 New Vector Ltd.
Copyright 2020 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 classNames from 'classnames';
import { ClientEvent } from "matrix-js-sdk/src/client";
import type { EventSubscription } from "fbemitter";
import GroupFilterOrderStore from '../../stores/GroupFilterOrderStore';
import GroupActions from '../../actions/GroupActions';
import dis from '../../dispatcher/dispatcher';
import { _t } from '../../languageHandler';
import MatrixClientContext from "../../contexts/MatrixClientContext";
import AutoHideScrollbar from "./AutoHideScrollbar";
import SettingsStore from "../../settings/SettingsStore";
import UserTagTile from "../views/elements/UserTagTile";
import { replaceableComponent } from "../../utils/replaceableComponent";
import UIStore from "../../stores/UIStore";
import DNDTagTile from "../views/elements/DNDTagTile";
import ActionButton from "../views/elements/ActionButton";
interface IGroupFilterPanelProps {
}
// FIXME: Properly type this after migrating GroupFilterOrderStore.js to Typescript
type OrderedTagsTemporaryType = Array<{}>;
// FIXME: Properly type this after migrating GroupFilterOrderStore.js to Typescript
type SelectedTagsTemporaryType = Array<{}>;
interface IGroupFilterPanelState {
// FIXME: Properly type this after migrating GroupFilterOrderStore.js to Typescript
orderedTags: OrderedTagsTemporaryType;
// FIXME: Properly type this after migrating GroupFilterOrderStore.js to Typescript
selectedTags: SelectedTagsTemporaryType;
}
@replaceableComponent("structures.GroupFilterPanel")
class GroupFilterPanel extends React.Component<IGroupFilterPanelProps, IGroupFilterPanelState> {
public static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
public state = {
orderedTags: [],
selectedTags: [],
};
private ref = React.createRef<HTMLDivElement>();
private unmounted = false;
private groupFilterOrderStoreToken?: EventSubscription;
public componentDidMount() {
this.unmounted = false;
this.context.on(ClientEvent.GroupMyMembership, this.onGroupMyMembership);
this.context.on(ClientEvent.Sync, this.onClientSync);
this.groupFilterOrderStoreToken = GroupFilterOrderStore.addListener(() => {
if (this.unmounted) {
return;
}
this.setState({
orderedTags: GroupFilterOrderStore.getOrderedTags() || [],
selectedTags: GroupFilterOrderStore.getSelectedTags(),
});
});
// This could be done by anything with a matrix client
dis.dispatch(GroupActions.fetchJoinedGroups(this.context));
UIStore.instance.trackElementDimensions("GroupPanel", this.ref.current);
}
public componentWillUnmount() {
this.unmounted = true;
this.context.removeListener(ClientEvent.GroupMyMembership, this.onGroupMyMembership);
this.context.removeListener(ClientEvent.Sync, this.onClientSync);
if (this.groupFilterOrderStoreToken) {
this.groupFilterOrderStoreToken.remove();
}
UIStore.instance.stopTrackingElementDimensions("GroupPanel");
}
private onGroupMyMembership = () => {
if (this.unmounted) return;
dis.dispatch(GroupActions.fetchJoinedGroups(this.context));
};
private onClientSync = (syncState, prevState) => {
// Consider the client reconnected if there is no error with syncing.
// This means the state could be RECONNECTING, SYNCING, PREPARED or CATCHUP.
const reconnected = syncState !== "ERROR" && prevState !== syncState;
if (reconnected) {
// Load joined groups
dis.dispatch(GroupActions.fetchJoinedGroups(this.context));
}
};
private onClick = e => {
// only dispatch if its not a no-op
if (this.state.selectedTags.length > 0) {
dis.dispatch({ action: 'deselect_tags' });
}
};
private onClearFilterClick = ev => {
dis.dispatch({ action: 'deselect_tags' });
};
private renderGlobalIcon() {
if (!SettingsStore.getValue("feature_communities_v2_prototypes")) return null;
return (
<div>
<UserTagTile />
<hr className="mx_GroupFilterPanel_divider" />
</div>
);
}
public render() {
const tags = this.state.orderedTags.map((tag, index) => {
return <DNDTagTile
key={tag}
tag={tag}
index={index}
selected={this.state.selectedTags.includes(tag)}
/>;
});
const itemsSelected = this.state.selectedTags.length > 0;
const classes = classNames('mx_GroupFilterPanel', {
mx_GroupFilterPanel_items_selected: itemsSelected,
});
let createButton = (
<ActionButton
tooltip
label={_t("Communities")}
action="toggle_my_groups"
className="mx_TagTile mx_TagTile_plus"
/>
);
if (SettingsStore.getValue("feature_communities_v2_prototypes")) {
createButton = (
<ActionButton
tooltip
label={_t("Create community")}
action="view_create_group"
className="mx_TagTile mx_TagTile_plus" />
);
}
return <div className={classes} onClick={this.onClearFilterClick} ref={this.ref}>
<AutoHideScrollbar
className="mx_GroupFilterPanel_scroller"
onClick={this.onClick}
>
<div className="mx_GroupFilterPanel_tagTileContainer">
{ this.renderGlobalIcon() }
{ tags }
<div>
{ createButton }
</div>
</div>
</AutoHideScrollbar>
</div>;
}
}
export default GroupFilterPanel;

File diff suppressed because it is too large Load diff

View file

@ -42,7 +42,6 @@ import IndicatorScrollbar from "./IndicatorScrollbar";
import RoomBreadcrumbs from "../views/rooms/RoomBreadcrumbs";
import SettingsStore from "../../settings/SettingsStore";
import VoiceChannelRadio from "../views/voip/VoiceChannelRadio";
import UserMenu from "./UserMenu";
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
import { shouldShowComponent } from "../../customisations/helpers/UIComponents";
import { UIComponent } from "../../settings/UIFeature";
@ -385,7 +384,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
onBlur={this.onBlur}
onKeyDown={this.onKeyDown}
>
{ !SpaceStore.spacesEnabled && <UserMenu isPanelCollapsed={true} /> }
<RoomSearch
isMinimized={this.props.isMinimized}
ref={this.roomSearchRef}
@ -429,7 +427,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
{ !this.props.isMinimized && (
<RoomListHeader
onVisibilityChange={this.refreshStickyHeaders}
spacePanelDisabled={!SpaceStore.spacesEnabled}
/>
) }
<div className="mx_LeftPanel_roomListWrapper">

View file

@ -1,115 +0,0 @@
/*
Copyright 2021 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, { useContext } from "react";
import MatrixClientContext from "../../contexts/MatrixClientContext";
import { _t } from "../../languageHandler";
import AccessibleButton from "../views/elements/AccessibleButton";
import ErrorBoundary from "../views/elements/ErrorBoundary";
import { useAsyncMemo } from "../../hooks/useAsyncMemo";
import Spinner from "../views/elements/Spinner";
import GroupAvatar from "../views/avatars/GroupAvatar";
import { linkifyElement } from "../../HtmlUtils";
import defaultDispatcher from "../../dispatcher/dispatcher";
import { Action } from "../../dispatcher/actions";
import { UserTab } from "../views/dialogs/UserSettingsDialog";
import { IGroupSummary } from "../../@types/groups";
interface IProps {
groupId: string;
}
const onSwapClick = () => {
defaultDispatcher.dispatch({
action: Action.ViewUserSettings,
initialTabId: UserTab.Preferences,
});
};
// XXX: temporary community migration component, reuses SpaceRoomView & SpacePreview classes for simplicity
const LegacyCommunityPreview = ({ groupId }: IProps) => {
const cli = useContext(MatrixClientContext);
const groupSummary = useAsyncMemo<IGroupSummary>(() => cli.getGroupSummary(groupId), [cli, groupId]);
if (!groupSummary) {
return <main className="mx_SpaceRoomView">
<div className="mx_MainSplit">
<div className="mx_SpaceRoomView_preview">
<Spinner />
</div>
</div>
</main>;
}
let visibilitySection: JSX.Element;
if (groupSummary.profile.is_public) {
visibilitySection = <span className="mx_SpaceRoomView_info_public">
{ _t("Public community") }
</span>;
} else {
visibilitySection = <span className="mx_SpaceRoomView_info_private">
{ _t("Private community") }
</span>;
}
return <main className="mx_SpaceRoomView">
<ErrorBoundary>
<div className="mx_MainSplit">
<div className="mx_SpaceRoomView_preview">
<GroupAvatar
groupId={groupId}
groupName={groupSummary.profile.name}
groupAvatarUrl={groupSummary.profile.avatar_url}
height={80}
width={80}
resizeMethod='crop'
/>
<h1 className="mx_SpaceRoomView_preview_name">
{ groupSummary.profile.name }
</h1>
<div className="mx_SpaceRoomView_info">
{ visibilitySection }
</div>
<div className="mx_SpaceRoomView_preview_topic" ref={e => e && linkifyElement(e)}>
{ groupSummary.profile.short_description }
</div>
<div className="mx_SpaceRoomView_preview_spaceBetaPrompt">
{ groupSummary.user?.membership === "join"
? _t("To view %(communityName)s, swap to communities in your <a>preferences</a>", {
communityName: groupSummary.profile.name,
}, {
a: sub => (
<AccessibleButton onClick={onSwapClick} kind="link">{ sub }</AccessibleButton>
),
})
: _t("To join %(communityName)s, swap to communities in your <a>preferences</a>", {
communityName: groupSummary.profile.name,
}, {
a: sub => (
<AccessibleButton onClick={onSwapClick} kind="link">{ sub }</AccessibleButton>
),
})
}
</div>
</div>
</div>
</ErrorBoundary>
</main>;
};
export default LegacyCommunityPreview;

View file

@ -0,0 +1,51 @@
/*
Copyright 2020 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 * as React from "react";
import AutoHideScrollbar from './AutoHideScrollbar';
import { _t } from "../../languageHandler";
import SdkConfig, { DEFAULTS } from "../../SdkConfig";
interface IProps {
groupId: string;
}
const LegacyGroupView: React.FC<IProps> = ({ groupId }) => {
// XXX: Stealing classes from the HomePage component for CSS simplicity.
// XXX: Inline CSS because this is all temporary
const learnMoreUrl = SdkConfig.get().spaces_learn_more_url ?? DEFAULTS.spaces_learn_more_url;
return <AutoHideScrollbar className="mx_HomePage mx_HomePage_default">
<div className="mx_HomePage_default_wrapper">
<h1 style={{ fontSize: '24px' }}>{ _t("That link is no longer supported") }</h1>
<p>
{ _t(
"You're trying to access a community link (%(groupId)s).<br/>" +
"Communities are no longer supported and have been replaced by spaces.<br2/>" +
"<a>Learn more about spaces here.</a>",
{ groupId },
{
br: () => <br />,
br2: () => <br />,
a: (sub) => <a href={learnMoreUrl} rel="noreferrer noopener" target="_blank">{ sub }</a>,
},
) }
</p>
</div>
</AutoHideScrollbar>;
};
export default LegacyGroupView;

View file

@ -60,21 +60,16 @@ import { UPDATE_EVENT } from "../../stores/AsyncStore";
import RoomView from './RoomView';
import type { RoomView as RoomViewType } from './RoomView';
import ToastContainer from './ToastContainer';
import MyGroups from "./MyGroups";
import UserView from "./UserView";
import GroupView from "./GroupView";
import BackdropPanel from "./BackdropPanel";
import SpaceStore from "../../stores/spaces/SpaceStore";
import GroupFilterPanel from './GroupFilterPanel';
import CustomRoomTagPanel from './CustomRoomTagPanel';
import { mediaFromMxc } from "../../customisations/Media";
import LegacyCommunityPreview from "./LegacyCommunityPreview";
import { UserTab } from "../views/dialogs/UserSettingsDialog";
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
import RightPanelStore from '../../stores/right-panel/RightPanelStore';
import { TimelineRenderingType } from "../../contexts/RoomContext";
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
import { SwitchSpacePayload } from "../../dispatcher/payloads/SwitchSpacePayload";
import LegacyGroupView from "./LegacyGroupView";
import { IConfigOptions } from "../../IConfigOptions";
import LeftPanelLiveShareWarning from '../views/beacon/LeftPanelLiveShareWarning';
@ -106,11 +101,11 @@ interface IProps {
collapseLhs: boolean;
config: IConfigOptions;
currentUserId?: string;
currentGroupId?: string;
currentGroupIsNew?: boolean;
justRegistered?: boolean;
roomJustCreatedOpts?: IOpts;
forceTimeline?: boolean; // see props on MatrixChat
currentGroupId?: string;
}
interface IState {
@ -499,7 +494,7 @@ class LoggedInView extends React.Component<IProps, IState> {
handled = true;
break;
case KeyBindingAction.ToggleRoomSidePanel:
if (this.props.page_type === "room_view" || this.props.page_type === "group_view") {
if (this.props.page_type === "room_view") {
RightPanelStore.instance.togglePanel();
handled = true;
}
@ -570,7 +565,6 @@ class LoggedInView extends React.Component<IProps, IState> {
if (
!handled &&
PlatformPeg.get().overrideBrowserShortcuts() &&
SpaceStore.spacesEnabled &&
ev.code.startsWith("Digit") &&
ev.code !== "Digit0" && // this is the shortcut for reset zoom, don't override it
isOnlyCtrlOrCmdKeyEvent(ev)
@ -642,10 +636,6 @@ class LoggedInView extends React.Component<IProps, IState> {
/>;
break;
case PageTypes.MyGroups:
pageElement = <MyGroups />;
break;
case PageTypes.HomePage:
pageElement = <HomePage justRegistered={this.props.justRegistered} />;
break;
@ -653,16 +643,9 @@ class LoggedInView extends React.Component<IProps, IState> {
case PageTypes.UserView:
pageElement = <UserView userId={this.props.currentUserId} resizeNotifier={this.props.resizeNotifier} />;
break;
case PageTypes.GroupView:
if (SpaceStore.spacesEnabled) {
pageElement = <LegacyCommunityPreview groupId={this.props.currentGroupId} />;
} else {
pageElement = <GroupView
groupId={this.props.currentGroupId}
isNew={this.props.currentGroupIsNew}
resizeNotifier={this.props.resizeNotifier}
/>;
}
case PageTypes.LegacyGroupView:
pageElement = <LegacyGroupView groupId={this.props.currentGroupId} />;
break;
}
@ -694,23 +677,11 @@ class LoggedInView extends React.Component<IProps, IState> {
<div className='mx_LeftPanel_outerWrapper'>
<LeftPanelLiveShareWarning isMinimized={this.props.collapseLhs || false} />
<div className='mx_LeftPanel_wrapper'>
{ SettingsStore.getValue('TagPanel.enableTagPanel') &&
(<div className="mx_GroupFilterPanelContainer">
<BackdropPanel
blurMultiplier={0.5}
backgroundImage={this.state.backgroundImage}
/>
<GroupFilterPanel />
{ SettingsStore.getValue("feature_custom_tags") ? <CustomRoomTagPanel /> : null }
</div>)
}
{ SpaceStore.spacesEnabled ? <>
<BackdropPanel
blurMultiplier={0.5}
backgroundImage={this.state.backgroundImage}
/>
<SpacePanel />
</> : null }
<BackdropPanel
blurMultiplier={0.5}
backgroundImage={this.state.backgroundImage}
/>
<SpacePanel />
<BackdropPanel
backgroundImage={this.state.backgroundImage}
/>

View file

@ -84,14 +84,11 @@ import {
} from "../../stores/notifications/RoomNotificationStateStore";
import { SettingLevel } from "../../settings/SettingLevel";
import { leaveRoomBehaviour } from "../../utils/membership";
import CreateCommunityPrototypeDialog from "../views/dialogs/CreateCommunityPrototypeDialog";
import ThreepidInviteStore, { IThreepidInvite, IThreepidInviteWireFormat } from "../../stores/ThreepidInviteStore";
import { UIFeature } from "../../settings/UIFeature";
import { CommunityPrototypeStore } from "../../stores/CommunityPrototypeStore";
import DialPadModal from "../views/voip/DialPadModal";
import { showToast as showMobileGuideToast } from '../../toasts/MobileGuideToast';
import { shouldUseLoginForWelcome } from "../../utils/pages";
import SpaceStore from "../../stores/spaces/SpaceStore";
import { replaceableComponent } from "../../utils/replaceableComponent";
import RoomListStore from "../../stores/room-list/RoomListStore";
import { RoomUpdateCause } from "../../stores/room-list/models";
@ -99,7 +96,6 @@ import SecurityCustomisations from "../../customisations/Security";
import Spinner from "../views/elements/Spinner";
import QuestionDialog from "../views/dialogs/QuestionDialog";
import UserSettingsDialog, { UserTab } from '../views/dialogs/UserSettingsDialog';
import CreateGroupDialog from '../views/dialogs/CreateGroupDialog';
import CreateRoomDialog from '../views/dialogs/CreateRoomDialog';
import RoomDirectory from './RoomDirectory';
import KeySignatureUploadFailedDialog from "../views/dialogs/KeySignatureUploadFailedDialog";
@ -147,7 +143,6 @@ const ONBOARDING_FLOW_STARTERS = [
Action.ViewUserSettings,
'view_create_chat',
'view_create_room',
'view_create_group',
];
interface IScreen {
@ -184,10 +179,10 @@ interface IState {
// in the case where we view a room by ID or by RoomView when it resolves
// what ID an alias points at.
currentRoomId?: string;
currentGroupId?: string;
currentGroupIsNew?: boolean;
// If we're trying to just view a user ID (i.e. /user URL), this is it
currentUserId?: string;
// Group ID for legacy "communities don't exist" page
currentGroupId?: string;
// this is persisted as mx_lhs_size, loaded in LoggedInView
collapseLhs: boolean;
// Parameters used in the registration dance with the IS
@ -668,6 +663,9 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}
break;
}
case 'view_legacy_group':
this.viewLegacyGroup(payload.groupId);
break;
case Action.ViewUserSettings: {
const tabPayload = payload as OpenToTabPayload;
Modal.createTrackedDialog('User settings', '', UserSettingsDialog,
@ -684,15 +682,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
// View the welcome or home page if we need something to look at
this.viewSomethingBehindModal();
break;
case 'view_create_group': {
const prototype = SettingsStore.getValue("feature_communities_v2_prototypes");
Modal.createTrackedDialog(
'Create Community',
'',
prototype ? CreateCommunityPrototypeDialog : CreateGroupDialog,
);
break;
}
case Action.ViewRoomDirectory: {
Modal.createTrackedDialog('Room directory', '', RoomDirectory, {
initialText: payload.initialText,
@ -702,13 +691,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
this.viewSomethingBehindModal();
break;
}
case 'view_my_groups':
this.setPage(PageType.MyGroups);
this.notifyNewScreen('groups');
break;
case 'view_group':
this.viewGroup(payload);
break;
case 'view_welcome_page':
this.viewWelcome();
break;
@ -740,17 +722,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
// function will have cleared that state and not execute that path.
this.showScreenAfterLogin();
break;
case 'toggle_my_groups':
// persist that the user has interacted with this, use it to dismiss the beta dot
localStorage.setItem("mx_seenSpacesBeta", "1");
// We just dispatch the page change rather than have to worry about
// what the logic is for each of these branches.
if (this.state.page_type === PageType.MyGroups) {
dis.dispatch({ action: 'view_last_screen' });
} else {
dis.dispatch({ action: 'view_my_groups' });
}
break;
case 'hide_left_panel':
this.setState({
collapseLhs: true,
@ -952,33 +923,12 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
});
}
private async viewGroup(payload) {
const groupId = payload.group_id;
// Wait for the first sync to complete
if (!this.firstSyncComplete) {
if (!this.firstSyncPromise) {
logger.warn('Cannot view a group before first sync. group_id:', groupId);
return;
}
await this.firstSyncPromise.promise;
}
this.setState({
view: Views.LOGGED_IN,
currentGroupId: groupId,
currentGroupIsNew: payload.group_is_new,
});
this.setPage(PageType.GroupView);
this.notifyNewScreen('group/' + groupId);
}
private viewSomethingBehindModal() {
if (this.state.view !== Views.LOGGED_IN) {
this.viewWelcome();
return;
}
if (!this.state.currentGroupId && !this.state.currentRoomId && !this.state.currentUserId) {
if (!this.state.currentRoomId && !this.state.currentUserId) {
this.viewHome();
}
}
@ -1034,19 +984,17 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
});
}
private async createRoom(defaultPublic = false, defaultName?: string) {
const communityId = CommunityPrototypeStore.instance.getSelectedCommunityId();
if (communityId) {
// double check the user will have permission to associate this room with the community
if (!CommunityPrototypeStore.instance.isAdminOf(communityId)) {
Modal.createTrackedDialog('Pre-failure to create room', '', ErrorDialog, {
title: _t("Cannot create rooms in this community"),
description: _t("You do not have permission to create rooms in this community."),
});
return;
}
}
private viewLegacyGroup(groupId: string) {
this.setStateForNewView({
view: Views.LOGGED_IN,
currentRoomId: null,
currentGroupId: groupId,
});
this.notifyNewScreen('group/' + groupId);
this.setPage(PageType.LegacyGroupView);
}
private async createRoom(defaultPublic = false, defaultName?: string) {
const modal = Modal.createTrackedDialog('Create Room', '', CreateRoomDialog, {
defaultPublic,
defaultName,
@ -1110,7 +1058,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
private leaveRoomWarnings(roomId: string) {
const roomToLeave = MatrixClientPeg.get().getRoom(roomId);
const isSpace = SpaceStore.spacesEnabled && roomToLeave?.isSpaceRoom();
const isSpace = roomToLeave?.isSpaceRoom();
// Show a warning if there are additional complications.
const warnings = [];
@ -1148,7 +1096,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
const roomToLeave = MatrixClientPeg.get().getRoom(roomId);
const warnings = this.leaveRoomWarnings(roomId);
const isSpace = SpaceStore.spacesEnabled && roomToLeave?.isSpaceRoom();
const isSpace = roomToLeave?.isSpaceRoom();
Modal.createTrackedDialog(isSpace ? "Leave space" : "Leave room", '', QuestionDialog, {
title: isSpace ? _t("Leave space") : _t("Leave room"),
description: (
@ -1775,14 +1723,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
const type = screen === "start_sso" ? "sso" : "cas";
PlatformPeg.get().startSingleSignOn(cli, type, this.getFragmentAfterLogin());
} else if (screen === 'groups') {
if (SpaceStore.spacesEnabled) {
dis.dispatch({ action: Action.ViewHomePage });
return;
}
dis.dispatch({
action: 'view_my_groups',
});
} else if (screen.indexOf('room/') === 0) {
// Rooms can have the following formats:
// #room_alias:domain or !opaque_id:domain
@ -1865,12 +1805,9 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
});
} else if (screen.indexOf('group/') === 0) {
const groupId = screen.substring(6);
// TODO: Check valid group ID
dis.dispatch({
action: 'view_group',
group_id: groupId,
action: 'view_legacy_group',
groupId: groupId,
});
} else {
logger.info("Ignoring showScreen for '%s'", screen);

View file

@ -157,9 +157,6 @@ interface IProps {
// which layout to use
layout?: Layout;
// whether or not to show flair at all
enableFlair?: boolean;
resizeNotifier: ResizeNotifier;
permalinkCreator?: RoomPermalinkCreator;
editState?: EditorStateTransfer;
@ -811,7 +808,6 @@ export default class MessagePanel extends React.Component<IProps, IState> {
getRelationsForEvent={this.props.getRelationsForEvent}
showReactions={this.props.showReactions}
layout={this.props.layout}
enableFlair={this.props.enableFlair}
showReadReceipts={this.props.showReadReceipts}
callEventGrouper={callEventGrouper}
hideSender={this.state.hideSender}

View file

@ -1,147 +0,0 @@
/*
Copyright 2017 Vector Creations Ltd
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2020 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 * as sdk from '../../index';
import { _t } from '../../languageHandler';
import SdkConfig from '../../SdkConfig';
import dis from '../../dispatcher/dispatcher';
import AccessibleButton from '../views/elements/AccessibleButton';
import MatrixClientContext from "../../contexts/MatrixClientContext";
import AutoHideScrollbar from "./AutoHideScrollbar";
import { replaceableComponent } from "../../utils/replaceableComponent";
@replaceableComponent("structures.MyGroups")
export default class MyGroups extends React.Component {
static contextType = MatrixClientContext;
state = {
groups: null,
error: null,
};
componentDidMount() {
this._fetch();
}
_onCreateGroupClick = () => {
dis.dispatch({ action: 'view_create_group' });
};
_fetch() {
this.context.getJoinedGroups().then((result) => {
this.setState({ groups: result.groups, error: null });
}, (err) => {
if (err.errcode === 'M_GUEST_ACCESS_FORBIDDEN') {
// Indicate that the guest isn't in any groups (which should be true)
this.setState({ groups: [], error: null });
return;
}
this.setState({ groups: null, error: err });
});
}
render() {
const brand = SdkConfig.get().brand;
const Loader = sdk.getComponent("elements.Spinner");
const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader');
const GroupTile = sdk.getComponent("groups.GroupTile");
let content;
let contentHeader;
if (this.state.groups) {
const groupNodes = [];
this.state.groups.forEach((g) => {
groupNodes.push(<GroupTile key={g} groupId={g} />);
});
contentHeader = groupNodes.length > 0 ? <h3>{ _t('Your Communities') }</h3> : <div />;
content = groupNodes.length > 0 ?
<AutoHideScrollbar className="mx_MyGroups_scrollable">
<div className="mx_MyGroups_microcopy">
<p>
{ _t(
"Did you know: you can use communities to filter your %(brand)s experience!",
{ brand },
) }
</p>
<p>
{ _t(
"You can click on an avatar in the " +
"filter panel at any time to see only the rooms and people associated " +
"with that community.",
) }
</p>
</div>
<div className="mx_MyGroups_joinedGroups">
{ groupNodes }
</div>
</AutoHideScrollbar> :
<div className="mx_MyGroups_placeholder">
{ _t(
"You're not currently a member of any communities.",
) }
</div>;
} else if (this.state.error) {
content = <div className="mx_MyGroups_error">
{ _t('Error whilst fetching joined communities') }
</div>;
} else {
content = <Loader />;
}
return <div className="mx_MyGroups">
<SimpleRoomHeader title={_t("Communities")} icon={require("../../../res/img/icons-groups.svg").default} />
<div className='mx_MyGroups_header'>
<div className="mx_MyGroups_headerCard">
<AccessibleButton className='mx_MyGroups_headerCard_button' onClick={this._onCreateGroupClick} />
<div className="mx_MyGroups_headerCard_content">
<div className="mx_MyGroups_headerCard_header">
{ _t('Create a new community') }
</div>
{ _t(
'Create a community to group together users and rooms! ' +
'Build a custom homepage to mark out your space in the Matrix universe.',
) }
</div>
</div>
{ /*<div className="mx_MyGroups_joinBox mx_MyGroups_headerCard">
<AccessibleButton className='mx_MyGroups_headerCard_button' onClick={this._onJoinGroupClick}>
<img src={require("../../../res/img/icons-create-room.svg").default} width="50" height="50" />
</AccessibleButton>
<div className="mx_MyGroups_headerCard_content">
<div className="mx_MyGroups_headerCard_header">
{ _t('Join an existing community') }
</div>
{ _t(
'To join an existing community you\'ll have to '+
'know its community identifier; this will look '+
'something like <i>+example:matrix.org</i>.',
{},
{ 'i': (sub) => <i>{ sub }</i> })
}
</div>
</div>*/ }
</div>
<div className="mx_MyGroups_content">
{ contentHeader }
{ content }
</div>
</div>;
}
}

View file

@ -31,9 +31,6 @@ import WidgetCard from "../views/right_panel/WidgetCard";
import { replaceableComponent } from "../../utils/replaceableComponent";
import SettingsStore from "../../settings/SettingsStore";
import MemberList from "../views/rooms/MemberList";
import GroupMemberList from "../views/groups/GroupMemberList";
import GroupRoomList from "../views/groups/GroupRoomList";
import GroupRoomInfo from "../views/groups/GroupRoomInfo";
import UserInfo from "../views/right_panel/UserInfo";
import ThirdPartyMemberInfo from "../views/rooms/ThirdPartyMemberInfo";
import FilePanel from "./FilePanel";
@ -51,7 +48,6 @@ import { Action } from '../../dispatcher/actions';
interface IProps {
room?: Room; // if showing panels for a given room, this is set
groupId?: string; // if showing panels for a given group, this is set
overwriteCard?: IRightPanelCard; // used to display a custom card and ignoring the RightPanelStore (used for UserView)
resizeNotifier: ResizeNotifier;
permalinkCreator?: RoomPermalinkCreator;
@ -96,9 +92,6 @@ export default class RightPanel extends React.Component<IProps, IState> {
if (props.room) {
currentCard = RightPanelStore.instance.currentCardForRoom(props.room.roomId);
}
if (props.groupId) {
currentCard = RightPanelStore.instance.currentGroup;
}
if (currentCard?.phase && !RightPanelStore.instance.isPhaseValid(currentCard.phase, !!props.room)) {
// XXX: We can probably get rid of this workaround once GroupView is dead, it's unmounting happens weirdly
@ -186,16 +179,6 @@ export default class RightPanel extends React.Component<IProps, IState> {
/>;
break;
case RightPanelPhases.GroupMemberList:
if (this.props.groupId) {
card = <GroupMemberList groupId={this.props.groupId} key={this.props.groupId} />;
}
break;
case RightPanelPhases.GroupRoomList:
card = <GroupRoomList groupId={this.props.groupId} key={this.props.groupId} />;
break;
case RightPanelPhases.RoomMemberInfo:
case RightPanelPhases.SpaceMemberInfo:
case RightPanelPhases.EncryptionPanel: {
@ -218,24 +201,6 @@ export default class RightPanel extends React.Component<IProps, IState> {
card = <ThirdPartyMemberInfo event={cardState.memberInfoEvent} key={roomId} />;
break;
case RightPanelPhases.GroupMemberInfo:
card = <UserInfo
user={cardState.member}
groupId={this.props.groupId}
key={cardState.member.userId}
phase={phase}
onClose={this.onClose}
/>;
break;
case RightPanelPhases.GroupRoomInfo:
card = <GroupRoomInfo
groupRoomId={cardState.groupRoomId}
groupId={this.props.groupId}
key={cardState.groupRoomId}
/>;
break;
case RightPanelPhases.NotificationPanel:
card = <NotificationPanel onClose={this.onClose} />;
break;

View file

@ -31,9 +31,6 @@ import { instanceForInstanceId, protocolNameForInstanceId } from '../../utils/Di
import Analytics from '../../Analytics';
import NetworkDropdown, { ALL_ROOMS, Protocols } from "../views/directory/NetworkDropdown";
import SettingsStore from "../../settings/SettingsStore";
import GroupFilterOrderStore from "../../stores/GroupFilterOrderStore";
import GroupStore from "../../stores/GroupStore";
import FlairStore from "../../stores/FlairStore";
import { replaceableComponent } from "../../utils/replaceableComponent";
import { mediaFromMxc } from "../../customisations/Media";
import { IDialogProps } from "../views/dialogs/IDialogProps";
@ -72,8 +69,6 @@ interface IState {
instanceId: string;
roomServer: string;
filterString: string;
selectedCommunityId?: string;
communityName?: string;
}
@replaceableComponent("structures.RoomDirectory")
@ -86,15 +81,11 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
constructor(props) {
super(props);
const selectedCommunityId = SettingsStore.getValue("feature_communities_v2_prototypes")
? GroupFilterOrderStore.getSelectedTags()[0]
: null;
let protocolsLoading = true;
if (!MatrixClientPeg.get()) {
// We may not have a client yet when invoked from welcome page
protocolsLoading = false;
} else if (!selectedCommunityId) {
} else {
MatrixClientPeg.get().getThirdpartyProtocols().then((response) => {
this.protocols = response;
const myHomeserver = MatrixClientPeg.getHomeserverName();
@ -147,14 +138,6 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
),
});
});
} else {
// We don't use the protocols in the communities v2 prototype experience
protocolsLoading = false;
// Grab the profile info async
FlairStore.getGroupProfileCached(MatrixClientPeg.get(), this.state.selectedCommunityId).then(profile => {
this.setState({ communityName: profile.name });
});
}
this.state = {
@ -164,8 +147,6 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
instanceId: localStorage.getItem(LAST_INSTANCE_KEY),
roomServer: localStorage.getItem(LAST_SERVER_KEY),
filterString: this.props.initialText || "",
selectedCommunityId,
communityName: null,
protocolsLoading,
};
}
@ -182,33 +163,6 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
}
private refreshRoomList = () => {
if (this.state.selectedCommunityId) {
this.setState({
publicRooms: GroupStore.getGroupRooms(this.state.selectedCommunityId).map(r => {
return {
// Translate all the group properties to the directory format
room_id: r.roomId,
name: r.name,
topic: r.topic,
canonical_alias: r.canonicalAlias,
num_joined_members: r.numJoinedMembers,
avatarUrl: r.avatarUrl,
world_readable: r.worldReadable,
guest_can_join: r.guestsCanJoin,
};
}).filter(r => {
const filterString = this.state.filterString;
if (filterString) {
const containedIn = (s: string) => (s || "").toLowerCase().includes(filterString.toLowerCase());
return containedIn(r.name) || containedIn(r.topic) || containedIn(r.canonical_alias);
}
return true;
}),
loading: false,
});
return;
}
this.nextBatch = null;
this.setState({
publicRooms: [],
@ -218,7 +172,6 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
};
private getMoreRooms(): Promise<boolean> {
if (this.state.selectedCommunityId) return Promise.resolve(false); // no more rooms
if (!MatrixClientPeg.get()) return Promise.resolve(false);
this.setState({
@ -342,7 +295,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
private onRoomClicked = (room: IPublicRoomsChunkRoom, ev: React.MouseEvent) => {
// If room was shift-clicked, remove it from the room directory
if (ev.shiftKey && !this.state.selectedCommunityId) {
if (ev.shiftKey) {
ev.preventDefault();
this.removeFromDirectory(room);
}
@ -755,18 +708,6 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
}
}
let dropdown = (
<NetworkDropdown
protocols={this.protocols}
onOptionChange={this.onOptionChange}
selectedServerName={this.state.roomServer}
selectedInstanceId={this.state.instanceId}
/>
);
if (this.state.selectedCommunityId) {
dropdown = null;
}
listHeader = <div className="mx_RoomDirectory_listheader">
<DirectorySearchBox
className="mx_RoomDirectory_searchbox"
@ -777,7 +718,12 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
showJoinButton={showJoinButton}
initialText={this.props.initialText}
/>
{ dropdown }
<NetworkDropdown
protocols={this.protocols}
onOptionChange={this.onOptionChange}
selectedServerName={this.state.roomServer}
selectedInstanceId={this.state.instanceId}
/>
</div>;
}
const explanation =
@ -789,10 +735,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
) },
);
const title = this.state.selectedCommunityId
? _t("Explore rooms in %(communityName)s", {
communityName: this.state.communityName || this.state.selectedCommunityId,
}) : _t("Explore rooms");
const title = _t("Explore rooms");
return (
<BaseDialog
className="mx_RoomDirectory_dialog"

View file

@ -96,7 +96,6 @@ import RoomStatusBar from "./RoomStatusBar";
import MessageComposer from '../views/rooms/MessageComposer';
import JumpToBottomButton from "../views/rooms/JumpToBottomButton";
import TopUnreadMessagesBar from "../views/rooms/TopUnreadMessagesBar";
import SpaceStore from "../../stores/spaces/SpaceStore";
import { showThread } from '../../dispatcher/dispatch-actions/threads';
import { fetchInitialEvent } from "../../utils/EventUtils";
import { ComposerInsertPayload, ComposerType } from "../../dispatcher/payloads/ComposerInsertPayload";
@ -1254,7 +1253,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
};
private onInviteButtonClick = () => {
// call AddressPickerDialog
// open the room inviter
dis.dispatch({
action: 'view_invite',
roomId: this.state.room.roomId,
@ -1807,7 +1806,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
const myMembership = this.state.room.getMyMembership();
// SpaceRoomView handles invites itself
if (myMembership === "invite" && (!SpaceStore.spacesEnabled || !this.state.room.isSpaceRoom())) {
if (myMembership === "invite" && !this.state.room.isSpaceRoom()) {
if (this.state.joining || this.state.rejecting) {
return (
<ErrorBoundary>
@ -1938,7 +1937,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
room={this.state.room}
/>
);
if (!this.state.canPeek && (!SpaceStore.spacesEnabled || !this.state.room?.isSpaceRoom())) {
if (!this.state.canPeek && !this.state.room?.isSpaceRoom()) {
return (
<div className="mx_RoomView">
{ previewBar }

View file

@ -57,7 +57,6 @@ import {
} from "../../utils/space";
import SpaceHierarchy, { showRoom } from "./SpaceHierarchy";
import MemberAvatar from "../views/avatars/MemberAvatar";
import SpaceStore from "../../stores/spaces/SpaceStore";
import { RoomFacePile } from "../views/elements/FacePile";
import {
AddExistingToSpace,
@ -71,12 +70,9 @@ import IconizedContextMenu, {
} from "../views/context_menus/IconizedContextMenu";
import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
import { BetaPill } from "../views/beta/BetaCard";
import { UserTab } from "../views/dialogs/UserSettingsDialog";
import { EffectiveMembership, getEffectiveMembership } from "../../utils/membership";
import { SpaceFeedbackPrompt } from "../views/spaces/SpaceCreateMenu";
import { useAsyncMemo } from "../../hooks/useAsyncMemo";
import Spinner from "../views/elements/Spinner";
import GroupAvatar from "../views/avatars/GroupAvatar";
import { useDispatcher } from "../../hooks/useDispatcher";
import { useRoomState } from "../../hooks/useRoomState";
import { shouldShowComponent } from "../../customisations/helpers/UIComponents";
@ -84,7 +80,6 @@ import { UIComponent } from "../../settings/UIFeature";
import { UPDATE_EVENT } from "../../stores/AsyncStore";
import PosthogTrackers from "../../PosthogTrackers";
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
import { CreateEventField, IGroupSummary } from "../../@types/groups";
interface IProps {
space: Room;
@ -179,33 +174,6 @@ const SpaceInfo = ({ space }: { space: Room }) => {
</div>;
};
const onPreferencesClick = () => {
defaultDispatcher.dispatch({
action: Action.ViewUserSettings,
initialTabId: UserTab.Preferences,
});
};
// XXX: temporary community migration component
const GroupTile = ({ groupId }: { groupId: string }) => {
const cli = useContext(MatrixClientContext);
const groupSummary = useAsyncMemo<IGroupSummary>(() => cli.getGroupSummary(groupId), [cli, groupId]);
if (!groupSummary) return <Spinner />;
return <>
<GroupAvatar
groupId={groupId}
groupName={groupSummary.profile.name}
groupAvatarUrl={groupSummary.profile.avatar_url}
width={16}
height={16}
resizeMethod='crop'
/>
{ groupSummary.profile.name }
</>;
};
interface ISpacePreviewProps {
space: Room;
onJoinButtonClicked(): void;
@ -223,8 +191,6 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }: ISp
const [busy, setBusy] = useState(false);
const spacesEnabled = SpaceStore.spacesEnabled;
const joinRule = useRoomState(space, state => state.getJoinRule());
const cannotJoin = getEffectiveMembership(myMembership) === EffectiveMembership.Leave
&& joinRule !== JoinRule.Public;
@ -282,7 +248,6 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }: ISp
setBusy(true);
onJoinButtonClicked();
}}
disabled={!spacesEnabled}
>
{ _t("Accept") }
</AccessibleButton>
@ -298,7 +263,7 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }: ISp
setBusy(true);
}
}}
disabled={!spacesEnabled || cannotJoin}
disabled={cannotJoin}
>
{ _t("Join") }
</AccessibleButton>
@ -310,18 +275,7 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }: ISp
}
let footer;
if (!spacesEnabled) {
footer = <div className="mx_SpaceRoomView_preview_spaceBetaPrompt">
{ myMembership === "join"
? _t("To view this Space, hide communities in your <a>preferences</a>", {}, {
a: sub => <AccessibleButton onClick={onPreferencesClick} kind="link">{ sub }</AccessibleButton>,
})
: _t("To join this Space, hide communities in your <a>preferences</a>", {}, {
a: sub => <AccessibleButton onClick={onPreferencesClick} kind="link">{ sub }</AccessibleButton>,
})
}
</div>;
} else if (cannotJoin) {
if (cannotJoin) {
footer = <div className="mx_SpaceRoomView_preview_spaceBetaPrompt">
{ _t("To view %(spaceName)s, you need an invite", {
spaceName: space.name,
@ -329,18 +283,7 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }: ISp
</div>;
}
let migratedCommunitySection: JSX.Element;
const createContent = space.currentState.getStateEvents(EventType.RoomCreate, "")?.getContent();
if (createContent[CreateEventField]) {
migratedCommunitySection = <div className="mx_SpaceRoomView_preview_migratedCommunity">
{ _t("Created from <Community />", {}, {
Community: () => <GroupTile groupId={createContent[CreateEventField]} />,
}) }
</div>;
}
return <div className="mx_SpaceRoomView_preview">
{ migratedCommunitySection }
{ inviterSection }
<RoomAvatar room={space} height={80} width={80} viewAvatarOnClick={true} />
<h1 className="mx_SpaceRoomView_preview_name">
@ -884,7 +827,7 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
private renderBody() {
switch (this.state.phase) {
case Phase.Landing:
if (this.state.myMembership === "join" && SpaceStore.spacesEnabled) {
if (this.state.myMembership === "join") {
return <SpaceLanding space={this.props.space} />;
} else {
return <SpacePreview

View file

@ -41,7 +41,6 @@ import { Action } from '../../dispatcher/actions';
import Timer from '../../utils/Timer';
import shouldHideEvent from '../../shouldHideEvent';
import { haveTileForEvent } from "../views/rooms/EventTile";
import { UIFeature } from "../../settings/UIFeature";
import { replaceableComponent } from "../../utils/replaceableComponent";
import { arrayFastClone } from "../../utils/arrays";
import MessagePanel from "./MessagePanel";
@ -1648,7 +1647,6 @@ class TimelinePanel extends React.Component<IProps, IState> {
editState={this.props.editState}
showReactions={this.props.showReactions}
layout={this.props.layout}
enableFlair={SettingsStore.getValue(UIFeature.Flair)}
hideThreadedMessages={this.props.hideThreadedMessages}
disableGrouping={this.props.disableGrouping}
callEventGroupers={this.callEventGroupers}

View file

@ -16,7 +16,6 @@ limitations under the License.
import React, { createRef, useContext, useRef, useState } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import * as fbEmitter from "fbemitter";
import classNames from "classnames";
import { MatrixClientPeg } from "../../MatrixClientPeg";
@ -50,7 +49,6 @@ import IconizedContextMenu, {
IconizedContextMenuOption,
IconizedContextMenuOptionList,
} from "../views/context_menus/IconizedContextMenu";
import GroupFilterOrderStore from "../../stores/GroupFilterOrderStore";
import { UIFeature } from "../../settings/UIFeature";
import HostSignupAction from "./HostSignupAction";
import SpaceStore from "../../stores/spaces/SpaceStore";
@ -151,7 +149,6 @@ export default class UserMenu extends React.Component<IProps, IState> {
private themeWatcherRef: string;
private readonly dndWatcherRef: string;
private buttonRef: React.RefObject<HTMLButtonElement> = createRef();
private tagStoreRef: fbEmitter.EventSubscription;
constructor(props: IProps) {
super(props);
@ -165,9 +162,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
};
OwnProfileStore.instance.on(UPDATE_EVENT, this.onProfileUpdate);
if (SpaceStore.spacesEnabled) {
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdate);
}
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdate);
SettingsStore.monitorSetting("feature_dnd", null);
SettingsStore.monitorSetting("doNotDisturb", null);
@ -184,7 +179,6 @@ export default class UserMenu extends React.Component<IProps, IState> {
public componentDidMount() {
this.dispatcherRef = defaultDispatcher.register(this.onAction);
this.themeWatcherRef = SettingsStore.watchSetting("theme", null, this.onThemeChanged);
this.tagStoreRef = GroupFilterOrderStore.addListener(this.onTagStoreUpdate);
}
public componentWillUnmount() {
@ -192,16 +186,9 @@ export default class UserMenu extends React.Component<IProps, IState> {
if (this.dndWatcherRef) SettingsStore.unwatchSetting(this.dndWatcherRef);
if (this.dispatcherRef) defaultDispatcher.unregister(this.dispatcherRef);
OwnProfileStore.instance.off(UPDATE_EVENT, this.onProfileUpdate);
this.tagStoreRef.remove();
if (SpaceStore.spacesEnabled) {
SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdate);
}
SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdate);
}
private onTagStoreUpdate = () => {
this.forceUpdate(); // we don't have anything useful in state to update
};
private isUserOnDarkTheme(): boolean {
if (SettingsStore.getValue("use_system_theme")) {
return window.matchMedia("(prefers-color-scheme: dark)").matches;