Right panel store refactor (#7313)
Co-authored-by: J. Ryan Stinnett <jryans@gmail.com>
This commit is contained in:
parent
8e881336ab
commit
325e2ba99b
42 changed files with 765 additions and 811 deletions
|
@ -20,10 +20,8 @@ import classNames from 'classnames';
|
|||
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||
import { SetRightPanelPhasePayload } from "../../../dispatcher/payloads/SetRightPanelPhasePayload";
|
||||
import { Action } from "../../../dispatcher/actions";
|
||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
||||
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||
import RightPanelStore from '../../../stores/right-panel/RightPanelStore';
|
||||
|
||||
interface IProps {
|
||||
header?: ReactNode;
|
||||
|
@ -34,7 +32,7 @@ interface IProps {
|
|||
previousPhaseLabel?: string;
|
||||
closeLabel?: string;
|
||||
onClose?(): void;
|
||||
refireParams?;
|
||||
cardState?;
|
||||
}
|
||||
|
||||
interface IGroupProps {
|
||||
|
@ -59,16 +57,15 @@ const BaseCard: React.FC<IProps> = ({
|
|||
previousPhase,
|
||||
previousPhaseLabel,
|
||||
children,
|
||||
refireParams,
|
||||
cardState,
|
||||
}) => {
|
||||
let backButton;
|
||||
if (previousPhase) {
|
||||
const onBackClick = () => {
|
||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
||||
action: Action.SetRightPanelPhase,
|
||||
phase: previousPhase,
|
||||
refireParams: refireParams,
|
||||
});
|
||||
// TODO RightPanelStore (will be addressed in a follow up PR): this should ideally be:
|
||||
// RightPanelStore.instance.popRightPanel();
|
||||
|
||||
RightPanelStore.instance.setCard({ phase: previousPhase, state: cardState });
|
||||
};
|
||||
const label = previousPhaseLabel ?? _t("Back");
|
||||
backButton = <AccessibleButton className="mx_BaseCard_back" onClick={onBackClick} title={label} />;
|
||||
|
|
|
@ -31,9 +31,8 @@ import { useEventEmitter } from "../../../hooks/useEventEmitter";
|
|||
import Modal from "../../../Modal";
|
||||
import * as sdk from "../../../index";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import dis from "../../../dispatcher/dispatcher";
|
||||
import { Action } from "../../../dispatcher/actions";
|
||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
||||
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||
|
||||
// cancellation codes which constitute a key mismatch
|
||||
const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"];
|
||||
|
@ -117,10 +116,9 @@ const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
|
|||
setRequest(verificationRequest_);
|
||||
setPhase(verificationRequest_.phase);
|
||||
// Notify the RightPanelStore about this
|
||||
dis.dispatch({
|
||||
action: Action.SetRightPanelPhase,
|
||||
RightPanelStore.instance.setCard({
|
||||
phase: RightPanelPhases.EncryptionPanel,
|
||||
refireParams: { member, verificationRequest: verificationRequest_ },
|
||||
state: { member, verificationRequest: verificationRequest_ },
|
||||
});
|
||||
}, [member]);
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ import React from 'react';
|
|||
import { _t } from '../../../languageHandler';
|
||||
import HeaderButton from './HeaderButton';
|
||||
import HeaderButtons, { HeaderKind } from './HeaderButtons';
|
||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
||||
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||
import { Action } from "../../../dispatcher/actions";
|
||||
import { ActionPayload } from "../../../dispatcher/payloads";
|
||||
import { ViewUserPayload } from "../../../dispatcher/payloads/ViewUserPayload";
|
||||
|
|
|
@ -21,15 +21,11 @@ limitations under the License.
|
|||
import React from 'react';
|
||||
|
||||
import dis from '../../../dispatcher/dispatcher';
|
||||
import RightPanelStore from "../../../stores/RightPanelStore";
|
||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
||||
import { Action } from '../../../dispatcher/actions';
|
||||
import {
|
||||
SetRightPanelPhasePayload,
|
||||
SetRightPanelPhaseRefireParams,
|
||||
} from '../../../dispatcher/payloads/SetRightPanelPhasePayload';
|
||||
import type { EventSubscription } from "fbemitter";
|
||||
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||
import { IRightPanelCardState } from '../../../stores/right-panel/RightPanelStoreIPanelState';
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import { UPDATE_EVENT } from '../../../stores/AsyncStore';
|
||||
import { NotificationColor } from '../../../stores/notifications/NotificationColor';
|
||||
|
||||
export enum HeaderKind {
|
||||
|
@ -47,38 +43,35 @@ interface IProps {}
|
|||
|
||||
@replaceableComponent("views.right_panel.HeaderButtons")
|
||||
export default abstract class HeaderButtons<P = {}> extends React.Component<IProps & P, IState> {
|
||||
private storeToken: EventSubscription;
|
||||
private unmounted = false;
|
||||
private dispatcherRef: string;
|
||||
|
||||
constructor(props: IProps & P, kind: HeaderKind) {
|
||||
super(props);
|
||||
|
||||
const rps = RightPanelStore.getSharedInstance();
|
||||
const rps = RightPanelStore.instance;
|
||||
this.state = {
|
||||
headerKind: kind,
|
||||
phase: rps.currentCard.phase,
|
||||
threadNotificationColor: NotificationColor.None,
|
||||
phase: kind === HeaderKind.Room ? rps.visibleRoomPanelPhase : rps.visibleGroupPanelPhase,
|
||||
};
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
this.storeToken = RightPanelStore.getSharedInstance().addListener(this.onRightPanelUpdate.bind(this));
|
||||
RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||
this.dispatcherRef = dis.register(this.onAction.bind(this)); // used by subclasses
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
if (this.storeToken) this.storeToken.remove();
|
||||
this.unmounted = true;
|
||||
RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||
if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
|
||||
}
|
||||
|
||||
protected abstract onAction(payload);
|
||||
|
||||
public setPhase(phase: RightPanelPhases, extras?: Partial<SetRightPanelPhaseRefireParams>) {
|
||||
dis.dispatch<SetRightPanelPhasePayload>({
|
||||
action: Action.SetRightPanelPhase,
|
||||
phase: phase,
|
||||
refireParams: extras,
|
||||
});
|
||||
public setPhase(phase: RightPanelPhases, cardState?: Partial<IRightPanelCardState>) {
|
||||
RightPanelStore.instance.setCard({ phase, state: cardState });
|
||||
}
|
||||
|
||||
public isPhase(phases: string | string[]) {
|
||||
|
@ -89,14 +82,12 @@ export default abstract class HeaderButtons<P = {}> extends React.Component<IPro
|
|||
}
|
||||
}
|
||||
|
||||
private onRightPanelUpdate() {
|
||||
const rps = RightPanelStore.getSharedInstance();
|
||||
if (this.state.headerKind === HeaderKind.Room) {
|
||||
this.setState({ phase: rps.visibleRoomPanelPhase });
|
||||
} else if (this.state.headerKind === HeaderKind.Group) {
|
||||
this.setState({ phase: rps.visibleGroupPanelPhase });
|
||||
}
|
||||
}
|
||||
private onRightPanelStoreUpdate = () => {
|
||||
if (this.unmounted) return;
|
||||
let phase = RightPanelStore.instance.currentCard.phase;
|
||||
if (!RightPanelStore.instance.isOpenForGroup) {phase = null;}
|
||||
this.setState({ phase });
|
||||
};
|
||||
|
||||
// XXX: Make renderButtons a prop
|
||||
public abstract renderButtons(): JSX.Element;
|
||||
|
|
|
@ -25,16 +25,15 @@ import { Room } from "matrix-js-sdk/src/models/room";
|
|||
import { _t } from '../../../languageHandler';
|
||||
import HeaderButton from './HeaderButton';
|
||||
import HeaderButtons, { HeaderKind } from './HeaderButtons';
|
||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
||||
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||
import { Action } from "../../../dispatcher/actions";
|
||||
import { ActionPayload } from "../../../dispatcher/payloads";
|
||||
import RightPanelStore from "../../../stores/RightPanelStore";
|
||||
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import { useSettingValue } from "../../../hooks/useSettings";
|
||||
import { useReadPinnedEvents, usePinnedEvents } from './PinnedMessagesCard';
|
||||
import { dispatchShowThreadsPanelEvent } from "../../../dispatcher/dispatch-actions/threads";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import dis from "../../../dispatcher/dispatcher";
|
||||
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
|
||||
import { NotificationColor } from "../../../stores/notifications/NotificationColor";
|
||||
import { ThreadsRoomNotificationState } from "../../../stores/notifications/ThreadsRoomNotificationState";
|
||||
|
@ -161,7 +160,7 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
|
|||
}
|
||||
} else if (payload.action === "view_3pid_invite") {
|
||||
if (payload.event) {
|
||||
this.setPhase(RightPanelPhases.Room3pidMemberInfo, { event: payload.event });
|
||||
this.setPhase(RightPanelPhases.Room3pidMemberInfo, { memberInfoEvent: payload.event });
|
||||
} else {
|
||||
this.setPhase(RightPanelPhases.RoomMemberList);
|
||||
}
|
||||
|
@ -170,12 +169,12 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
|
|||
|
||||
private onRoomSummaryClicked = () => {
|
||||
// use roomPanelPhase rather than this.state.phase as it remembers the latest one if we close
|
||||
const lastPhase = RightPanelStore.getSharedInstance().roomPanelPhase;
|
||||
if (ROOM_INFO_PHASES.includes(lastPhase)) {
|
||||
if (this.state.phase === lastPhase) {
|
||||
this.setPhase(lastPhase);
|
||||
const currentPhase = RightPanelStore.instance.currentCard.phase;
|
||||
if (ROOM_INFO_PHASES.includes(currentPhase)) {
|
||||
if (this.state.phase === currentPhase) {
|
||||
this.setPhase(currentPhase);
|
||||
} else {
|
||||
this.setPhase(lastPhase, RightPanelStore.getSharedInstance().roomPanelPhaseParams);
|
||||
this.setPhase(currentPhase, RightPanelStore.instance.currentCard.state);
|
||||
}
|
||||
} else {
|
||||
// This toggles for us, if needed
|
||||
|
@ -198,10 +197,7 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
|
|||
|
||||
private onThreadsPanelClicked = () => {
|
||||
if (RoomHeaderButtons.THREAD_PHASES.includes(this.state.phase)) {
|
||||
dis.dispatch({
|
||||
action: Action.ToggleRightPanel,
|
||||
type: "room",
|
||||
});
|
||||
RightPanelStore.instance.togglePanel();
|
||||
} else {
|
||||
dispatchShowThreadsPanelEvent();
|
||||
}
|
||||
|
@ -227,6 +223,7 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
|
|||
rightPanelPhaseButtons.set(RightPanelPhases.ThreadPanel,
|
||||
SettingsStore.getValue("feature_thread")
|
||||
? <HeaderButton
|
||||
key={RightPanelPhases.ThreadPanel}
|
||||
name="threadsButton"
|
||||
title={_t("Threads")}
|
||||
onClick={this.onThreadsPanelClicked}
|
||||
|
|
|
@ -25,9 +25,7 @@ import { _t } from '../../../languageHandler';
|
|||
import RoomAvatar from "../avatars/RoomAvatar";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||
import { Action } from "../../../dispatcher/actions";
|
||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
||||
import { SetRightPanelPhasePayload } from "../../../dispatcher/payloads/SetRightPanelPhasePayload";
|
||||
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||
import Modal from "../../../Modal";
|
||||
import ShareDialog from '../dialogs/ShareDialog';
|
||||
import { useEventEmitter } from "../../../hooks/useEventEmitter";
|
||||
|
@ -48,6 +46,7 @@ import { Container, MAX_PINNED, WidgetLayoutStore } from "../../../stores/widget
|
|||
import RoomName from "../elements/RoomName";
|
||||
import UIStore from "../../../stores/UIStore";
|
||||
import ExportDialog from "../dialogs/ExportDialog";
|
||||
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||
|
||||
interface IProps {
|
||||
room: Room;
|
||||
|
@ -103,12 +102,10 @@ const AppRow: React.FC<IAppRowProps> = ({ app, room }) => {
|
|||
}, [room.roomId]);
|
||||
|
||||
const onOpenWidgetClick = () => {
|
||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
||||
action: Action.SetRightPanelPhase,
|
||||
// TODO RightPanelStore (will be addressed in a follow up PR): should push the widget
|
||||
RightPanelStore.instance.setCard({
|
||||
phase: RightPanelPhases.Widget,
|
||||
refireParams: {
|
||||
widgetId: app.id,
|
||||
},
|
||||
state: { widgetId: app.id },
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -237,19 +234,13 @@ const AppsSection: React.FC<IAppsSectionProps> = ({ room }) => {
|
|||
};
|
||||
|
||||
export const onRoomMembersClick = (allowClose = true) => {
|
||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
||||
action: Action.SetRightPanelPhase,
|
||||
phase: RightPanelPhases.RoomMemberList,
|
||||
allowClose,
|
||||
});
|
||||
// TODO RightPanelStore (will be addressed in a follow up PR): should push the phase
|
||||
RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomMemberList }, allowClose);
|
||||
};
|
||||
|
||||
export const onRoomFilesClick = (allowClose = true) => {
|
||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
||||
action: Action.SetRightPanelPhase,
|
||||
phase: RightPanelPhases.FilePanel,
|
||||
allowClose,
|
||||
});
|
||||
// TODO RightPanelStore (will be addressed in a follow up PR): should push the phase
|
||||
RightPanelStore.instance.setCard({ phase: RightPanelPhases.FilePanel }, allowClose);
|
||||
};
|
||||
|
||||
const onRoomSettingsClick = () => {
|
||||
|
|
|
@ -55,7 +55,7 @@ interface IState {
|
|||
editState?: EditorStateTransfer;
|
||||
replyToEvent?: MatrixEvent;
|
||||
initialEventId?: string;
|
||||
initialEventHighlighted?: boolean;
|
||||
isInitialEventHighlighted?: boolean;
|
||||
|
||||
// settings:
|
||||
showReadReceipts?: boolean;
|
||||
|
@ -103,7 +103,7 @@ export default class TimelineCard extends React.Component<IProps, IState> {
|
|||
// roomLoadError: RoomViewStore.getRoomLoadError(),
|
||||
|
||||
initialEventId: RoomViewStore.getInitialEventId(),
|
||||
initialEventHighlighted: RoomViewStore.isInitialEventHighlighted(),
|
||||
isInitialEventHighlighted: RoomViewStore.isInitialEventHighlighted(),
|
||||
replyToEvent: RoomViewStore.getQuotingEvent(),
|
||||
};
|
||||
|
||||
|
@ -127,7 +127,7 @@ export default class TimelineCard extends React.Component<IProps, IState> {
|
|||
};
|
||||
|
||||
private onScroll = (): void => {
|
||||
if (this.state.initialEventId && this.state.initialEventHighlighted) {
|
||||
if (this.state.initialEventId && this.state.isInitialEventHighlighted) {
|
||||
dis.dispatch({
|
||||
action: Action.ViewRoom,
|
||||
room_id: this.props.room.roomId,
|
||||
|
@ -145,7 +145,7 @@ export default class TimelineCard extends React.Component<IProps, IState> {
|
|||
};
|
||||
|
||||
public render(): JSX.Element {
|
||||
const highlightedEventId = this.state.initialEventHighlighted
|
||||
const highlightedEventId = this.state.isInitialEventHighlighted
|
||||
? this.state.initialEventId
|
||||
: null;
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ import E2EIcon from "../rooms/E2EIcon";
|
|||
import { useEventEmitter } from "../../../hooks/useEventEmitter";
|
||||
import { textualPowerLevel } from '../../../Roles';
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
||||
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||
import EncryptionPanel from "./EncryptionPanel";
|
||||
import { useAsyncMemo } from '../../../hooks/useAsyncMemo';
|
||||
import { legacyVerifyUser, verifyDevice, verifyUser } from '../../../verification';
|
||||
|
@ -63,7 +63,6 @@ import ErrorDialog from "../dialogs/ErrorDialog";
|
|||
import QuestionDialog from "../dialogs/QuestionDialog";
|
||||
import ConfirmUserActionDialog from "../dialogs/ConfirmUserActionDialog";
|
||||
import InfoDialog from "../dialogs/InfoDialog";
|
||||
import { SetRightPanelPhasePayload } from "../../../dispatcher/payloads/SetRightPanelPhasePayload";
|
||||
import RoomAvatar from "../avatars/RoomAvatar";
|
||||
import RoomName from "../elements/RoomName";
|
||||
import { mediaFromMxc } from "../../../customisations/Media";
|
||||
|
@ -75,6 +74,8 @@ import { bulkSpaceBehaviour } from "../../../utils/space";
|
|||
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
|
||||
import { UIComponent } from "../../../settings/UIFeature";
|
||||
import { TimelineRenderingType } from "../../../contexts/RoomContext";
|
||||
import RightPanelStore from '../../../stores/right-panel/RightPanelStore';
|
||||
import { IRightPanelCardState } from '../../../stores/right-panel/RightPanelStoreIPanelState';
|
||||
import { useUserStatusMessage } from "../../../hooks/useUserStatusMessage";
|
||||
|
||||
export interface IDevice {
|
||||
|
@ -1649,25 +1650,22 @@ const UserInfo: React.FC<IProps> = ({
|
|||
|
||||
const classes = ["mx_UserInfo"];
|
||||
|
||||
let refireParams;
|
||||
let cardState: IRightPanelCardState;
|
||||
let previousPhase: RightPanelPhases;
|
||||
// We have no previousPhase for when viewing a UserInfo from a Group or without a Room at this time
|
||||
if (room && phase === RightPanelPhases.EncryptionPanel) {
|
||||
previousPhase = RightPanelPhases.RoomMemberInfo;
|
||||
refireParams = { member };
|
||||
cardState = { member };
|
||||
} else if (room?.isSpaceRoom() && SpaceStore.spacesEnabled) {
|
||||
previousPhase = previousPhase = RightPanelPhases.SpaceMemberList;
|
||||
refireParams = { space: room };
|
||||
previousPhase = RightPanelPhases.SpaceMemberList;
|
||||
cardState = { spaceId: room.roomId };
|
||||
} else if (room) {
|
||||
previousPhase = RightPanelPhases.RoomMemberList;
|
||||
}
|
||||
|
||||
const onEncryptionPanelClose = () => {
|
||||
dis.dispatch<SetRightPanelPhasePayload>({
|
||||
action: Action.SetRightPanelPhase,
|
||||
phase: previousPhase,
|
||||
refireParams: refireParams,
|
||||
});
|
||||
// TODO RightPanelStore (will be addressed in a follow up PR): here we want to pop the panel
|
||||
RightPanelStore.instance.setCard({ phase: previousPhase, state: cardState });
|
||||
};
|
||||
|
||||
let content;
|
||||
|
@ -1723,7 +1721,7 @@ const UserInfo: React.FC<IProps> = ({
|
|||
onClose={onClose}
|
||||
closeLabel={closeLabel}
|
||||
previousPhase={previousPhase}
|
||||
refireParams={refireParams}
|
||||
cardState={cardState}
|
||||
>
|
||||
{ content }
|
||||
</BaseCard>;
|
||||
|
|
|
@ -23,14 +23,12 @@ import WidgetUtils from "../../../utils/WidgetUtils";
|
|||
import AppTile from "../elements/AppTile";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { useWidgets } from "./RoomSummaryCard";
|
||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||
import { SetRightPanelPhasePayload } from "../../../dispatcher/payloads/SetRightPanelPhasePayload";
|
||||
import { Action } from "../../../dispatcher/actions";
|
||||
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||
import { ChevronFace, ContextMenuButton, useContextMenu } from "../../structures/ContextMenu";
|
||||
import WidgetContextMenu from "../context_menus/WidgetContextMenu";
|
||||
import { Container, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore";
|
||||
import UIStore from "../../../stores/UIStore";
|
||||
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||
|
||||
interface IProps {
|
||||
room: Room;
|
||||
|
@ -50,10 +48,9 @@ const WidgetCard: React.FC<IProps> = ({ room, widgetId, onClose }) => {
|
|||
useEffect(() => {
|
||||
if (!app || isPinned) {
|
||||
// stop showing this card
|
||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
||||
action: Action.SetRightPanelPhase,
|
||||
phase: RightPanelPhases.RoomSummary,
|
||||
});
|
||||
|
||||
//TODO RightPanelStore (will be addressed in a follow up PR): here we want to just pop the widget card.
|
||||
RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomSummary });
|
||||
}
|
||||
}, [app, isPinned]);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue