Merge branch 'develop' of https://github.com/matrix-org/matrix-react-sdk into t3chguy/dpsah/6785.3

 Conflicts:
	src/components/structures/RoomView.tsx
This commit is contained in:
Michael Telatynski 2020-09-09 15:16:19 +01:00
commit a1f1334250
81 changed files with 3611 additions and 805 deletions

View file

@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {CSSProperties, useRef, useState} from "react";
import React, {CSSProperties, RefObject, useRef, useState} from "react";
import ReactDOM from "react-dom";
import classNames from "classnames";
@ -416,8 +416,8 @@ export const aboveLeftOf = (elementRect: DOMRect, chevronFace = ChevronFace.None
return menuOptions;
};
export const useContextMenu = () => {
const button = useRef(null);
export const useContextMenu = (): [boolean, RefObject<HTMLElement>, () => void, () => void, (val: boolean) => void] => {
const button = useRef<HTMLElement>(null);
const [isOpen, setIsOpen] = useState(false);
const open = () => {
setIsOpen(true);

View file

@ -23,6 +23,8 @@ import * as sdk from '../../index';
import {MatrixClientPeg} from '../../MatrixClientPeg';
import EventIndexPeg from "../../indexing/EventIndexPeg";
import { _t } from '../../languageHandler';
import BaseCard from "../views/right_panel/BaseCard";
import {RightPanelPhases} from "../../stores/RightPanelStorePhases";
/*
* Component which shows the filtered file using a TimelinePanel
@ -30,6 +32,7 @@ import { _t } from '../../languageHandler';
class FilePanel extends React.Component {
static propTypes = {
roomId: PropTypes.string.isRequired,
onClose: PropTypes.func.isRequired,
};
// This is used to track if a decrypted event was a live event and should be
@ -188,18 +191,26 @@ class FilePanel extends React.Component {
render() {
if (MatrixClientPeg.get().isGuest()) {
return <div className="mx_FilePanel mx_RoomView_messageListWrapper">
return <BaseCard
className="mx_FilePanel mx_RoomView_messageListWrapper"
onClose={this.props.onClose}
previousPhase={RightPanelPhases.RoomSummary}
>
<div className="mx_RoomView_empty">
{ _t("You must <a>register</a> to use this functionality",
{},
{ 'a': (sub) => <a href="#/register" key="sub">{ sub }</a> })
}
</div>
</div>;
</BaseCard>;
} else if (this.noRoom) {
return <div className="mx_FilePanel mx_RoomView_messageListWrapper">
return <BaseCard
className="mx_FilePanel mx_RoomView_messageListWrapper"
onClose={this.props.onClose}
previousPhase={RightPanelPhases.RoomSummary}
>
<div className="mx_RoomView_empty">{ _t("You must join the room to see its files") }</div>
</div>;
</BaseCard>;
}
// wrap a TimelinePanel with the jump-to-event bits turned off.
@ -215,7 +226,12 @@ class FilePanel extends React.Component {
// console.log("rendering TimelinePanel for timelineSet " + this.state.timelineSet.room.roomId + " " +
// "(" + this.state.timelineSet._timelines.join(", ") + ")" + " with key " + this.props.roomId);
return (
<div className="mx_FilePanel" role="tabpanel">
<BaseCard
className="mx_FilePanel"
onClose={this.props.onClose}
previousPhase={RightPanelPhases.RoomSummary}
withoutScrollContainer
>
<TimelinePanel
manageReadReceipts={false}
manageReadMarkers={false}
@ -226,13 +242,17 @@ class FilePanel extends React.Component {
resizeNotifier={this.props.resizeNotifier}
empty={emptyState}
/>
</div>
</BaseCard>
);
} else {
return (
<div className="mx_FilePanel" role="tabpanel">
<BaseCard
className="mx_FilePanel"
onClose={this.props.onClose}
previousPhase={RightPanelPhases.RoomSummary}
>
<Loader />
</div>
</BaseCard>
);
}
}

View file

@ -17,14 +17,21 @@ limitations under the License.
*/
import React from 'react';
import PropTypes from "prop-types";
import { _t } from '../../languageHandler';
import {MatrixClientPeg} from "../../MatrixClientPeg";
import * as sdk from "../../index";
import BaseCard from "../views/right_panel/BaseCard";
/*
* Component which shows the global notification list using a TimelinePanel
*/
class NotificationPanel extends React.Component {
static propTypes = {
onClose: PropTypes.func.isRequired,
};
render() {
// wrap a TimelinePanel with the jump-to-event bits turned off.
const TimelinePanel = sdk.getComponent("structures.TimelinePanel");
@ -35,28 +42,27 @@ class NotificationPanel extends React.Component {
<p>{_t('You have no visible notifications in this room.')}</p>
</div>);
let content;
const timelineSet = MatrixClientPeg.get().getNotifTimelineSet();
if (timelineSet) {
return (
<div className="mx_NotificationPanel" role="tabpanel">
<TimelinePanel
manageReadReceipts={false}
manageReadMarkers={false}
timelineSet={timelineSet}
showUrlPreview={false}
tileShape="notif"
empty={emptyState}
/>
</div>
content = (
<TimelinePanel
manageReadReceipts={false}
manageReadMarkers={false}
timelineSet={timelineSet}
showUrlPreview={false}
tileShape="notif"
empty={emptyState}
/>
);
} else {
console.error("No notifTimelineSet available!");
return (
<div className="mx_NotificationPanel" role="tabpanel">
<Loader />
</div>
);
content = <Loader />;
}
return <BaseCard className="mx_NotificationPanel" onClose={this.props.onClose} withoutScrollContainer>
{ content }
</BaseCard>;
}
}

View file

@ -32,6 +32,9 @@ import {RightPanelPhases, RIGHT_PANEL_PHASES_NO_ARGS} from "../../stores/RightPa
import RightPanelStore from "../../stores/RightPanelStore";
import MatrixClientContext from "../../contexts/MatrixClientContext";
import {Action} from "../../dispatcher/actions";
import RoomSummaryCard from "../views/right_panel/RoomSummaryCard";
import WidgetCard from "../views/right_panel/WidgetCard";
import defaultDispatcher from "../../dispatcher/dispatcher";
export default class RightPanel extends React.Component {
static get propTypes() {
@ -47,10 +50,10 @@ export default class RightPanel extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
...RightPanelStore.getSharedInstance().roomPanelPhaseParams,
phase: this._getPhaseFromProps(),
isUserPrivilegedInGroup: null,
member: this._getUserForPanel(),
verificationRequest: RightPanelStore.getSharedInstance().roomPanelPhaseParams.verificationRequest,
};
this.onAction = this.onAction.bind(this);
this.onRoomStateMember = this.onRoomStateMember.bind(this);
@ -102,10 +105,6 @@ export default class RightPanel extends React.Component {
}
return RightPanelPhases.RoomMemberInfo;
} else {
if (!RIGHT_PANEL_PHASES_NO_ARGS.includes(rps.roomPanelPhase)) {
dis.dispatch({action: Action.SetRightPanelPhase, phase: RightPanelPhases.RoomMemberList});
return RightPanelPhases.RoomMemberList;
}
return rps.roomPanelPhase;
}
}
@ -186,6 +185,7 @@ export default class RightPanel extends React.Component {
event: payload.event,
verificationRequest: payload.verificationRequest,
verificationRequestPromise: payload.verificationRequestPromise,
widgetId: payload.widgetId,
});
}
}
@ -213,6 +213,14 @@ export default class RightPanel extends React.Component {
}
};
onClose = () => {
// the RightPanelStore has no way of knowing which mode room/group it is in, so we handle closing here
defaultDispatcher.dispatch({
action: Action.ToggleRightPanel,
type: this.props.groupId ? "group" : "room",
});
};
render() {
const MemberList = sdk.getComponent('rooms.MemberList');
const UserInfo = sdk.getComponent('right_panel.UserInfo');
@ -225,36 +233,42 @@ export default class RightPanel extends React.Component {
const GroupRoomInfo = sdk.getComponent('groups.GroupRoomInfo');
let panel = <div />;
const roomId = this.props.room ? this.props.room.roomId : undefined;
switch (this.state.phase) {
case RightPanelPhases.RoomMemberList:
if (this.props.room.roomId) {
panel = <MemberList roomId={this.props.room.roomId} key={this.props.room.roomId} />;
if (roomId) {
panel = <MemberList roomId={roomId} key={roomId} onClose={this.onClose} />;
}
break;
case RightPanelPhases.GroupMemberList:
if (this.props.groupId) {
panel = <GroupMemberList groupId={this.props.groupId} key={this.props.groupId} />;
}
break;
case RightPanelPhases.GroupRoomList:
panel = <GroupRoomList groupId={this.props.groupId} key={this.props.groupId} />;
break;
case RightPanelPhases.RoomMemberInfo:
case RightPanelPhases.EncryptionPanel:
panel = <UserInfo
user={this.state.member}
roomId={this.props.room.roomId}
key={this.props.room.roomId || this.state.member.userId}
room={this.props.room}
key={roomId || this.state.member.userId}
onClose={this.onCloseUserInfo}
phase={this.state.phase}
verificationRequest={this.state.verificationRequest}
verificationRequestPromise={this.state.verificationRequestPromise}
/>;
break;
case RightPanelPhases.Room3pidMemberInfo:
panel = <ThirdPartyMemberInfo event={this.state.event} key={this.props.room.roomId} />;
panel = <ThirdPartyMemberInfo event={this.state.event} key={roomId} />;
break;
case RightPanelPhases.GroupMemberInfo:
panel = <UserInfo
user={this.state.member}
@ -262,17 +276,28 @@ export default class RightPanel extends React.Component {
key={this.state.member.userId}
onClose={this.onCloseUserInfo} />;
break;
case RightPanelPhases.GroupRoomInfo:
panel = <GroupRoomInfo
groupRoomId={this.state.groupRoomId}
groupId={this.props.groupId}
key={this.state.groupRoomId} />;
break;
case RightPanelPhases.NotificationPanel:
panel = <NotificationPanel />;
panel = <NotificationPanel onClose={this.onClose} />;
break;
case RightPanelPhases.FilePanel:
panel = <FilePanel roomId={this.props.room.roomId} resizeNotifier={this.props.resizeNotifier} />;
panel = <FilePanel roomId={roomId} resizeNotifier={this.props.resizeNotifier} onClose={this.onClose} />;
break;
case RightPanelPhases.RoomSummary:
panel = <RoomSummaryCard room={this.props.room} onClose={this.onClose} />;
break;
case RightPanelPhases.Widget:
panel = <WidgetCard room={this.props.room} widgetId={this.state.widgetId} onClose={this.onClose} />;
break;
}

View file

@ -56,6 +56,7 @@ import MatrixClientContext from "../../contexts/MatrixClientContext";
import {E2EStatus, shieldStatusForRoom} from '../../utils/ShieldUtils';
import {Action} from "../../dispatcher/actions";
import {SettingLevel} from "../../settings/SettingLevel";
import {RightPanelPhases} from "../../stores/RightPanelStorePhases";
import {IMatrixClientCreds} from "../../MatrixClientPeg";
import ScrollPanel from "./ScrollPanel";
import TimelinePanel from "./TimelinePanel";
@ -1424,7 +1425,10 @@ export default class RoomView extends React.Component<IProps, IState> {
};
private onSettingsClick = () => {
dis.dispatch({ action: 'open_room_settings' });
dis.dispatch({
action: Action.SetRightPanelPhase,
phase: RightPanelPhases.RoomSummary,
});
};
private onCancelClick = () => {

View file

@ -104,8 +104,8 @@ class TimelinePanel extends React.Component {
// shape property to be passed to EventTiles
tileShape: PropTypes.string,
// placeholder text to use if the timeline is empty
empty: PropTypes.string,
// placeholder to use if the timeline is empty
empty: PropTypes.node,
// whether to show reactions for an event
showReactions: PropTypes.bool,

View file

@ -124,7 +124,11 @@ export default class LoginComponent extends React.Component {
'm.login.cas': () => this._renderSsoStep("cas"),
'm.login.sso': () => this._renderSsoStep("sso"),
};
}
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
// eslint-disable-next-line camelcase
UNSAFE_componentWillMount() {
this._initLoginLogic();
}