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:
parent
03c80707c9
commit
fce36ec826
171 changed files with 317 additions and 12160 deletions
|
@ -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;
|
|
@ -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
|
@ -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">
|
||||
|
|
|
@ -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;
|
51
src/components/structures/LegacyGroupView.tsx
Normal file
51
src/components/structures/LegacyGroupView.tsx
Normal 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;
|
|
@ -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}
|
||||
/>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue