Fix right panel data flow (#7811)

This commit is contained in:
J. Ryan Stinnett 2022-02-16 11:19:28 +00:00 committed by GitHub
parent 78524bddce
commit 0dc1355441
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 254 additions and 74 deletions

View file

@ -330,8 +330,8 @@ class MatrixClientPegClass implements IMatrixClientPeg {
}
}
if (!window.mxMatrixClientPeg) {
window.mxMatrixClientPeg = new MatrixClientPegClass();
}
export const MatrixClientPeg: IMatrixClientPeg = new MatrixClientPegClass();
export const MatrixClientPeg = window.mxMatrixClientPeg;
if (!window.mxMatrixClientPeg) {
window.mxMatrixClientPeg = MatrixClientPeg;
}

View file

@ -1,6 +1,6 @@
/*
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2015 - 2021 The Matrix.org Foundation C.I.C.
Copyright 2015 - 2022 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.
@ -23,7 +23,6 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { throttle } from 'lodash';
import dis from '../../dispatcher/dispatcher';
import GroupStore from '../../stores/GroupStore';
import { RightPanelPhases } from '../../stores/right-panel/RightPanelStorePhases';
import RightPanelStore from "../../stores/right-panel/RightPanelStore";
import MatrixClientContext from "../../contexts/MatrixClientContext";
@ -59,8 +58,7 @@ interface IProps {
}
interface IState {
phase: RightPanelPhases;
isUserPrivilegedInGroup?: boolean;
phase?: RightPanelPhases;
searchQuery: string;
cardState?: IRightPanelCardState;
}
@ -73,9 +71,6 @@ export default class RightPanel extends React.Component<IProps, IState> {
super(props, context);
this.state = {
cardState: RightPanelStore.instance.currentCard?.state,
phase: RightPanelStore.instance.currentCard?.phase,
isUserPrivilegedInGroup: null,
searchQuery: "",
};
}
@ -88,7 +83,6 @@ export default class RightPanel extends React.Component<IProps, IState> {
const cli = this.context;
cli.on("RoomState.members", this.onRoomStateMember);
RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
this.initGroupStore(this.props.groupId);
}
public componentWillUnmount(): void {
@ -96,32 +90,16 @@ export default class RightPanel extends React.Component<IProps, IState> {
this.context.removeListener("RoomState.members", this.onRoomStateMember);
}
RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
this.unregisterGroupStore();
}
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
public UNSAFE_componentWillReceiveProps(newProps: IProps): void { // eslint-disable-line
if (newProps.groupId !== this.props.groupId) {
this.unregisterGroupStore();
this.initGroupStore(newProps.groupId);
}
public static getDerivedStateFromProps(props: IProps): Partial<IState> {
const currentCard = RightPanelStore.instance.currentCardForRoom(props.room.roomId);
return {
cardState: currentCard.state,
phase: currentCard.phase,
};
}
private initGroupStore(groupId: string) {
if (!groupId) return;
GroupStore.registerListener(groupId, this.onGroupStoreUpdated);
}
private unregisterGroupStore() {
GroupStore.unregisterListener(this.onGroupStoreUpdated);
}
private onGroupStoreUpdated = () => {
this.setState({
isUserPrivilegedInGroup: GroupStore.isUserPrivileged(this.props.groupId),
});
};
private onRoomStateMember = (ev: MatrixEvent, state: RoomState, member: RoomMember) => {
if (!this.props.room || member.roomId !== this.props.room.roomId) {
return;
@ -139,10 +117,10 @@ export default class RightPanel extends React.Component<IProps, IState> {
};
private onRightPanelStoreUpdate = () => {
const currentPanel = RightPanelStore.instance.currentCard;
const currentCard = RightPanelStore.instance.currentCardForRoom(this.props.room.roomId);
this.setState({
cardState: currentPanel.state,
phase: currentPanel.phase,
cardState: currentCard.state,
phase: currentCard.phase,
});
};

View file

@ -248,7 +248,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
canPeek: false,
showApps: false,
isPeeking: false,
showRightPanel: RightPanelStore.instance.isOpenForRoom,
showRightPanel: false,
joining: false,
atEndOfLiveTimeline: true,
atEndOfLiveTimelineInit: false,
@ -342,7 +342,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
// Show chat in right panel when a widget is maximised
RightPanelStore.instance.setCard({ phase: RightPanelPhases.Timeline });
} else if (
RightPanelStore.instance.isOpenForRoom &&
RightPanelStore.instance.isOpen &&
RightPanelStore.instance.roomPhaseHistory.some(card => (card.phase === RightPanelPhases.Timeline))
) {
// hide chat in right panel when the widget is minimized
@ -411,6 +411,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
showDisplaynameChanges: SettingsStore.getValue("showDisplaynameChanges", roomId),
wasContextSwitch: RoomViewStore.getWasContextSwitch(),
initialEventId: null, // default to clearing this, will get set later in the method if needed
showRightPanel: RightPanelStore.instance.isOpenForRoom(roomId),
};
const initialEventId = RoomViewStore.getInitialEventId();
@ -782,7 +783,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
private onRightPanelStoreUpdate = () => {
this.setState({
showRightPanel: RightPanelStore.instance.isOpenForRoom,
showRightPanel: RightPanelStore.instance.isOpenForRoom(this.state.roomId),
});
};

View file

@ -809,7 +809,7 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
this.state = {
phase,
showRightPanel: RightPanelStore.instance.isOpenForRoom,
showRightPanel: RightPanelStore.instance.isOpenForRoom(this.props.space.roomId),
myMembership: this.props.space.getMyMembership(),
};
@ -832,7 +832,7 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
private onRightPanelStoreUpdate = () => {
this.setState({
showRightPanel: RightPanelStore.instance.isOpenForRoom,
showRightPanel: RightPanelStore.instance.isOpenForRoom(this.props.space.roomId),
});
};

View file

@ -123,7 +123,7 @@ const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
state: { member, verificationRequest: verificationRequest_ },
});
}
if (!RightPanelStore.instance.isOpenForRoom) RightPanelStore.instance.togglePanel();
if (!RightPanelStore.instance.isOpen) RightPanelStore.instance.togglePanel();
}, [member]);
const requested =

View file

@ -72,16 +72,16 @@ export default abstract class HeaderButtons<P = {}> extends React.Component<IPro
public setPhase(phase: RightPanelPhases, cardState?: Partial<IRightPanelCardState>) {
const rps = RightPanelStore.instance;
if (rps.currentCard.phase == phase && !cardState && rps.isOpenForRoom) {
if (rps.currentCard.phase == phase && !cardState && rps.isOpen) {
rps.togglePanel();
} else {
RightPanelStore.instance.setCard({ phase, state: cardState });
if (!rps.isOpenForRoom) rps.togglePanel();
if (!rps.isOpen) rps.togglePanel();
}
}
public isPhase(phases: string | string[]): boolean {
if (!RightPanelStore.instance.isOpenForRoom) return false;
if (!RightPanelStore.instance.isOpen) return false;
if (Array.isArray(phases)) {
return phases.includes(this.state.phase);
} else {

View file

@ -40,19 +40,19 @@ const WidgetCard: React.FC<IProps> = ({ room, widgetId, onClose }) => {
const apps = useWidgets(room);
const app = apps.find(a => a.id === widgetId);
const isPinned = app && WidgetLayoutStore.instance.isInContainer(room, app, Container.Top);
const isRight = app && WidgetLayoutStore.instance.isInContainer(room, app, Container.Right);
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu();
useEffect(() => {
if (!app || isPinned) {
if (!app || !isRight) {
// stop showing this card
RightPanelStore.instance.popCard();
}
}, [app, isPinned]);
}, [app, isRight]);
// Don't render anything as we are about to transition
if (!app || isPinned) return null;
if (!app || !isRight) return null;
let contextMenu;
if (menuDisplayed) {

View file

@ -1,5 +1,5 @@
/*
* Copyright 2021 The Matrix.org Foundation C.I.C.
* Copyright 2021 - 2022 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.
@ -15,6 +15,7 @@
*/
import { MatrixClient } from "matrix-js-sdk/src/client";
import { SyncState } from "matrix-js-sdk/src/sync";
import { Dispatcher } from "flux";
import { EventEmitter } from "events";
@ -65,7 +66,7 @@ export abstract class ReadyWatchingStore extends EventEmitter implements IDestro
// Everything after this is unnecessary (we only need to know once we have a client)
// and we intentionally don't set the client before this point to avoid stores
// updating for every event emitted during the cached sync.
if (!(payload.prevState === 'PREPARED' && payload.state !== 'PREPARED')) {
if (!(payload.prevState === SyncState.Prepared && payload.state !== SyncState.Prepared)) {
return;
}

View file

@ -1,5 +1,5 @@
/*
Copyright 2019-2021 The Matrix.org Foundation C.I.C.
Copyright 2019-2022 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.
@ -90,14 +90,30 @@ export default class RightPanelStore extends ReadyWatchingStore {
}
// Getters
public get isOpenForRoom(): boolean {
/**
* If you are calling this from a component that already knows about a
* specific room from props / state, then it's best to prefer
* `isOpenForRoom` below to ensure all your data is for a single room
* during room changes.
*/
public get isOpen(): boolean {
return this.byRoom[this.viewedRoomId]?.isOpen ?? false;
}
public isOpenForRoom(roomId: string): boolean {
return this.byRoom[roomId]?.isOpen ?? false;
}
public get roomPhaseHistory(): Array<IRightPanelCard> {
return this.byRoom[this.viewedRoomId]?.history ?? [];
}
/**
* If you are calling this from a component that already knows about a
* specific room from props / state, then it's best to prefer
* `currentCardForRoom` below to ensure all your data is for a single room
* during room changes.
*/
public get currentCard(): IRightPanelCard {
const hist = this.roomPhaseHistory;
if (hist.length >= 1) {
@ -111,7 +127,7 @@ export default class RightPanelStore extends ReadyWatchingStore {
if (hist.length > 0) {
return hist[hist.length - 1];
}
return this.currentCard ?? { state: {}, phase: null };
return { state: {}, phase: null };
}
public get previousCard(): IRightPanelCard {
@ -123,7 +139,7 @@ export default class RightPanelStore extends ReadyWatchingStore {
}
// The Group associated getters are just for backwards compatibility. Can be removed when deprecating groups.
public get isOpenForGroup(): boolean { return this.isOpenForRoom; }
public get isOpenForGroup(): boolean { return this.isOpen; }
public get groupPhaseHistory(): Array<IRightPanelCard> { return this.roomPhaseHistory; }
public get currentGroup(): IRightPanelCard { return this.currentCard; }
public get previousGroup(): IRightPanelCard { return this.previousCard; }
@ -216,13 +232,13 @@ export default class RightPanelStore extends ReadyWatchingStore {
}
public show() {
if (!this.isOpenForRoom) {
if (!this.isOpen) {
this.togglePanel();
}
}
public hide() {
if (this.isOpenForRoom) {
if (this.isOpen) {
this.togglePanel();
}
}
@ -235,8 +251,8 @@ export default class RightPanelStore extends ReadyWatchingStore {
this.byRoom[this.viewedRoomId] = this.byRoom[this.viewedRoomId] ??
convertToStatePanel(SettingsStore.getValue("RightPanel.phases", this.viewedRoomId), room);
} else {
console.warn("Could not restore the right panel after load because there was no associated room object." +
"The right panel can only be restored for rooms and spaces but not for groups");
console.warn("Could not restore the right panel after load because there was no associated room object. " +
"The right panel can only be restored for rooms and spaces but not for groups.");
}
}