Add analytics for the ViewRoom action (#7666)

This commit is contained in:
Michael Telatynski 2022-02-10 14:29:55 +00:00 committed by GitHub
parent 20e9d0c159
commit 0d6ef76605
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 332 additions and 159 deletions

View file

@ -31,6 +31,7 @@ import { Action } from "./dispatcher/actions";
import { hideToast as hideUpdateToast } from "./toasts/UpdateToast"; import { hideToast as hideUpdateToast } from "./toasts/UpdateToast";
import { MatrixClientPeg } from "./MatrixClientPeg"; import { MatrixClientPeg } from "./MatrixClientPeg";
import { idbLoad, idbSave, idbDelete } from "./utils/StorageManager"; import { idbLoad, idbSave, idbDelete } from "./utils/StorageManager";
import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
export const SSO_HOMESERVER_URL_KEY = "mx_sso_hs_url"; export const SSO_HOMESERVER_URL_KEY = "mx_sso_hs_url";
export const SSO_ID_SERVER_URL_KEY = "mx_sso_is_url"; export const SSO_ID_SERVER_URL_KEY = "mx_sso_is_url";
@ -185,9 +186,10 @@ export default abstract class BasePlatform {
const notification = new window.Notification(title, notifBody); const notification = new window.Notification(title, notifBody);
notification.onclick = () => { notification.onclick = () => {
const payload: ActionPayload = { const payload: ViewRoomPayload = {
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: room.roomId, room_id: room.roomId,
_trigger: "Notification",
}; };
if (ev.getThread()) { if (ev.getThread()) {

View file

@ -56,6 +56,7 @@ import { getIncomingCallToastKey } from './toasts/IncomingCallToast';
import ToastStore from './stores/ToastStore'; import ToastStore from './stores/ToastStore';
import IncomingCallToast from "./toasts/IncomingCallToast"; import IncomingCallToast from "./toasts/IncomingCallToast";
import Resend from './Resend'; import Resend from './Resend';
import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
export const PROTOCOL_PSTN = 'm.protocol.pstn'; export const PROTOCOL_PSTN = 'm.protocol.pstn';
export const PROTOCOL_PSTN_PREFIXED = 'im.vector.protocol.pstn'; export const PROTOCOL_PSTN_PREFIXED = 'im.vector.protocol.pstn';
@ -890,9 +891,10 @@ export default class CallHandler extends EventEmitter {
call.answer(); call.answer();
this.setActiveCallRoomId(roomId); this.setActiveCallRoomId(roomId);
CountlyAnalytics.instance.trackJoinCall(roomId, call.type === CallType.Video, false); CountlyAnalytics.instance.trackJoinCall(roomId, call.type === CallType.Video, false);
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: roomId, room_id: roomId,
_trigger: "WebAcceptCall",
}); });
} }
@ -927,9 +929,10 @@ export default class CallHandler extends EventEmitter {
const roomId = await ensureDMExists(MatrixClientPeg.get(), nativeUserId); const roomId = await ensureDMExists(MatrixClientPeg.get(), nativeUserId);
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: roomId, room_id: roomId,
_trigger: "WebDialPad",
}); });
await this.placeMatrixCall(roomId, CallType.Voice, null); await this.placeMatrixCall(roomId, CallType.Voice, null);
@ -957,11 +960,12 @@ export default class CallHandler extends EventEmitter {
const dmRoomId = await ensureDMExists(MatrixClientPeg.get(), destination); const dmRoomId = await ensureDMExists(MatrixClientPeg.get(), destination);
this.placeCall(dmRoomId, call.type, call); this.placeCall(dmRoomId, call.type, call);
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: dmRoomId, room_id: dmRoomId,
should_peek: false, should_peek: false,
joining: false, joining: false,
_trigger: undefined, // other
}); });
} else { } else {
try { try {

View file

@ -262,7 +262,7 @@ interface ICreateRoomEvent extends IEvent {
}; };
} }
interface IJoinRoomEvent extends IEvent { export interface IJoinRoomEvent extends IEvent {
key: Action.JoinRoom; key: Action.JoinRoom;
dur: number; // how long it took to join (until remote echo) dur: number; // how long it took to join (until remote echo)
segmentation: { segmentation: {
@ -270,7 +270,7 @@ interface IJoinRoomEvent extends IEvent {
num_users: number; num_users: number;
is_encrypted: boolean; is_encrypted: boolean;
is_public: boolean; is_public: boolean;
type: "room_directory" | "slash_command" | "link" | "invite"; type: "room_directory" | "slash_command" | "link" | "invite" | "tombstone";
}; };
} }
/* eslint-enable camelcase */ /* eslint-enable camelcase */

View file

@ -64,6 +64,7 @@ import { TimelineRenderingType } from './contexts/RoomContext';
import RoomViewStore from "./stores/RoomViewStore"; import RoomViewStore from "./stores/RoomViewStore";
import { XOR } from "./@types/common"; import { XOR } from "./@types/common";
import { PosthogAnalytics } from "./PosthogAnalytics"; import { PosthogAnalytics } from "./PosthogAnalytics";
import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
// XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816 // XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816
interface HTMLInputEvent extends Event { interface HTMLInputEvent extends Event {
@ -344,11 +345,13 @@ export const Commands = [
logger.log( logger.log(
`/timestamp_to_event: found ${eventId} (${originServerTs}) for timestamp=${unixTimestamp}`, `/timestamp_to_event: found ${eventId} (${originServerTs}) for timestamp=${unixTimestamp}`,
); );
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
event_id: eventId, event_id: eventId,
highlighted: true, highlighted: true,
room_id: roomId, room_id: roomId,
_trigger: "SlashCommand",
_viaKeyboard: true,
}); });
})()); })());
} }
@ -608,26 +611,24 @@ export const Commands = [
roomAlias += ':' + MatrixClientPeg.get().getDomain(); roomAlias += ':' + MatrixClientPeg.get().getDomain();
} }
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_alias: roomAlias, room_alias: roomAlias,
auto_join: true, auto_join: true,
_type: "slash_command", // instrumentation _trigger: "SlashCommand",
_viaKeyboard: true,
}); });
return success(); return success();
} else if (params[0][0] === '!') { } else if (params[0][0] === '!') {
const [roomId, ...viaServers] = params; const [roomId, ...viaServers] = params;
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: roomId, room_id: roomId,
opts: {
// These are passed down to the js-sdk's /join call
viaServers: viaServers,
},
via_servers: viaServers, // for the rejoin button via_servers: viaServers, // for the rejoin button
auto_join: true, auto_join: true,
_type: "slash_command", // instrumentation _trigger: "SlashCommand",
_viaKeyboard: true,
}); });
return success(); return success();
} else if (isPermalink) { } else if (isPermalink) {
@ -649,10 +650,11 @@ export const Commands = [
const viaServers = permalinkParts.viaServers; const viaServers = permalinkParts.viaServers;
const eventId = permalinkParts.eventId; const eventId = permalinkParts.eventId;
const dispatch = { const dispatch: ViewRoomPayload = {
action: Action.ViewRoom, action: Action.ViewRoom,
auto_join: true, auto_join: true,
_type: "slash_command", // instrumentation _trigger: "SlashCommand",
_viaKeyboard: true,
}; };
if (entity[0] === '!') dispatch["room_id"] = entity; if (entity[0] === '!') dispatch["room_id"] = entity;
@ -1150,9 +1152,11 @@ export const Commands = [
const roomId = await ensureDMExists(MatrixClientPeg.get(), userId); const roomId = await ensureDMExists(MatrixClientPeg.get(), userId);
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: roomId, room_id: roomId,
_trigger: "SlashCommand",
_viaKeyboard: true,
}); });
})()); })());
}, },
@ -1172,9 +1176,11 @@ export const Commands = [
return success((async () => { return success((async () => {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
const roomId = await ensureDMExists(cli, userId); const roomId = await ensureDMExists(cli, userId);
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: roomId, room_id: roomId,
_trigger: "SlashCommand",
_viaKeyboard: true,
}); });
if (msg) { if (msg) {
cli.sendTextMessage(roomId, msg); cli.sendTextMessage(roomId, msg);

View file

@ -45,6 +45,7 @@ import { ROOM_SECURITY_TAB } from "./components/views/dialogs/RoomSettingsDialog
import AccessibleButton from './components/views/elements/AccessibleButton'; import AccessibleButton from './components/views/elements/AccessibleButton';
import RightPanelStore from './stores/right-panel/RightPanelStore'; import RightPanelStore from './stores/right-panel/RightPanelStore';
import UserIdentifierCustomisations from './customisations/UserIdentifier'; import UserIdentifierCustomisations from './customisations/UserIdentifier';
import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
export function getSenderName(event: MatrixEvent): string { export function getSenderName(event: MatrixEvent): string {
return event.sender?.name ?? event.getSender() ?? _t("Someone"); return event.sender?.name ?? event.getSender() ?? _t("Someone");
@ -522,11 +523,12 @@ function textForPowerEvent(event: MatrixEvent): () => string | null {
} }
const onPinnedOrUnpinnedMessageClick = (messageId: string, roomId: string): void => { const onPinnedOrUnpinnedMessageClick = (messageId: string, roomId: string): void => {
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
event_id: messageId, event_id: messageId,
highlighted: true, highlighted: true,
room_id: roomId, room_id: roomId,
_trigger: undefined, // room doesn't change
}); });
}; };

View file

@ -119,6 +119,7 @@ import { ActionPayload } from "../../dispatcher/payloads";
import { SummarizedNotificationState } from "../../stores/notifications/SummarizedNotificationState"; import { SummarizedNotificationState } from "../../stores/notifications/SummarizedNotificationState";
import GenericToast from '../views/toasts/GenericToast'; import GenericToast from '../views/toasts/GenericToast';
import Views from '../../Views'; import Views from '../../Views';
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
// legacy export // legacy export
export { default as Views } from "../../Views"; export { default as Views } from "../../Views";
@ -140,25 +141,6 @@ interface IScreen {
params?: QueryDict; params?: QueryDict;
} }
/* eslint-disable camelcase */
interface IRoomInfo {
room_id?: string;
room_alias?: string;
event_id?: string;
auto_join?: boolean;
highlighted?: boolean;
oob_data?: object;
via_servers?: string[];
threepid_invite?: IThreepidInvite;
justCreatedOpts?: IOpts;
// Whether or not to override default behaviour to end up at a timeline
forceTimeline?: boolean;
}
/* eslint-enable camelcase */
interface IProps { // TODO type things better interface IProps { // TODO type things better
config: { config: {
piwik: { piwik: {
@ -675,7 +657,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
// known to be in (eg. user clicks on a room in the recents panel), supply the ID // known to be in (eg. user clicks on a room in the recents panel), supply the ID
// If the user is clicking on a room in the context of the alias being presented // If the user is clicking on a room in the context of the alias being presented
// to them, supply the room alias. If both are supplied, the room ID will be ignored. // to them, supply the room alias. If both are supplied, the room ID will be ignored.
const promise = this.viewRoom(payload as any); const promise = this.viewRoom(payload as ViewRoomPayload);
if (payload.deferred_action) { if (payload.deferred_action) {
promise.then(() => { promise.then(() => {
dis.dispatch(payload.deferred_action); dis.dispatch(payload.deferred_action);
@ -894,21 +876,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
// switch view to the given room // switch view to the given room
// private async viewRoom(roomInfo: ViewRoomPayload) {
// @param {Object} roomInfo Object containing data about the room to be joined
// @param {string=} roomInfo.room_id ID of the room to join. One of room_id or room_alias must be given.
// @param {string=} roomInfo.room_alias Alias of the room to join. One of room_id or room_alias must be given.
// @param {boolean=} roomInfo.auto_join If true, automatically attempt to join the room if not already a member.
// @param {string=} roomInfo.event_id ID of the event in this room to show: this will cause a switch to the
// context of that particular event.
// @param {boolean=} roomInfo.highlighted If true, add event_id to the hash of the URL
// and alter the EventTile to appear highlighted.
// @param {Object=} roomInfo.threepid_invite Object containing data about the third party
// we received to join the room, if any.
// @param {Object=} roomInfo.oob_data Object of additional data about the room
// that has been passed out-of-band (eg.
// room name and avatar from an invite email)
private async viewRoom(roomInfo: IRoomInfo) {
this.focusComposer = true; this.focusComposer = true;
if (roomInfo.room_alias) { if (roomInfo.room_alias) {
@ -1120,9 +1088,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
const dmRooms = dmRoomMap.getDMRoomsForUserId(userId); const dmRooms = dmRoomMap.getDMRoomsForUserId(userId);
if (dmRooms.length > 0) { if (dmRooms.length > 0) {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: dmRooms[0], room_id: dmRooms[0],
_trigger: "MessageUser",
}); });
} else { } else {
dis.dispatch({ dis.dispatch({
@ -1395,9 +1364,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
} }
private viewLastRoom() { private viewLastRoom() {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: localStorage.getItem('mx_last_room_id'), room_id: localStorage.getItem('mx_last_room_id'),
_trigger: undefined, // other
}); });
} }
@ -1823,7 +1793,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
else via = params.via; else via = params.via;
} }
const payload = { const payload: ViewRoomPayload = {
action: Action.ViewRoom, action: Action.ViewRoom,
event_id: eventId, event_id: eventId,
via_servers: via, via_servers: via,
@ -1842,6 +1812,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}, },
room_alias: undefined, room_alias: undefined,
room_id: undefined, room_id: undefined,
_trigger: undefined, // unknown or external trigger
}; };
if (roomString[0] === '#') { if (roomString[0] === '#') {
payload.room_alias = roomString; payload.room_alias = roomString;

View file

@ -46,10 +46,10 @@ import BaseDialog from "../views/dialogs/BaseDialog";
import DirectorySearchBox from "../views/elements/DirectorySearchBox"; import DirectorySearchBox from "../views/elements/DirectorySearchBox";
import ScrollPanel from "./ScrollPanel"; import ScrollPanel from "./ScrollPanel";
import Spinner from "../views/elements/Spinner"; import Spinner from "../views/elements/Spinner";
import { ActionPayload } from "../../dispatcher/payloads";
import { getDisplayAliasForAliasSet } from "../../Rooms"; import { getDisplayAliasForAliasSet } from "../../Rooms";
import { Action } from "../../dispatcher/actions"; import { Action } from "../../dispatcher/actions";
import PosthogTrackers from "../../PosthogTrackers"; import PosthogTrackers from "../../PosthogTrackers";
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
const MAX_NAME_LENGTH = 80; const MAX_NAME_LENGTH = 80;
const MAX_TOPIC_LENGTH = 800; const MAX_TOPIC_LENGTH = 800;
@ -494,11 +494,11 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
private showRoom(room: IPublicRoomsChunkRoom, roomAlias?: string, autoJoin = false, shouldPeek = false) { private showRoom(room: IPublicRoomsChunkRoom, roomAlias?: string, autoJoin = false, shouldPeek = false) {
this.onFinished(); this.onFinished();
const payload: ActionPayload = { const payload: ViewRoomPayload = {
action: Action.ViewRoom, action: Action.ViewRoom,
auto_join: autoJoin, auto_join: autoJoin,
should_peek: shouldPeek, should_peek: shouldPeek,
_type: "room_directory", // instrumentation _trigger: "RoomDirectory",
}; };
if (room) { if (room) {
// Don't let the user view a room they won't be able to either // Don't let the user view a room they won't be able to either
@ -524,9 +524,6 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
if (this.state.roomServer) { if (this.state.roomServer) {
payload.via_servers = [this.state.roomServer]; payload.via_servers = [this.state.roomServer];
payload.opts = {
viaServers: [this.state.roomServer],
};
} }
} }
// It's not really possible to join Matrix rooms by ID because the HS has no way to know // It's not really possible to join Matrix rooms by ID because the HS has no way to know

View file

@ -101,6 +101,7 @@ import AppsDrawer from '../views/rooms/AppsDrawer';
import { RightPanelPhases } from '../../stores/right-panel/RightPanelStorePhases'; import { RightPanelPhases } from '../../stores/right-panel/RightPanelStorePhases';
import { ActionPayload } from "../../dispatcher/payloads"; import { ActionPayload } from "../../dispatcher/payloads";
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts"; import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
const DEBUG = false; const DEBUG = false;
let debuglog = function(msg: string) {}; let debuglog = function(msg: string) {};
@ -767,12 +768,13 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
private onUserScroll = () => { private onUserScroll = () => {
if (this.state.initialEventId && this.state.isInitialEventHighlighted) { if (this.state.initialEventId && this.state.isInitialEventHighlighted) {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: this.state.room.roomId, room_id: this.state.room.roomId,
event_id: this.state.initialEventId, event_id: this.state.initialEventId,
highlighted: false, highlighted: false,
replyingToEvent: this.state.replyToEvent, replyingToEvent: this.state.replyToEvent,
_trigger: undefined, // room doesn't change
}); });
} }
}; };
@ -871,10 +873,11 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
setImmediate(() => { setImmediate(() => {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: roomId, room_id: roomId,
deferred_action: payload, deferred_action: payload,
_trigger: "MessageSearch",
}); });
}); });
} }
@ -1171,9 +1174,10 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
if (ev.getType() === EventType.RoomCanonicalAlias) { if (ev.getType() === EventType.RoomCanonicalAlias) {
// re-view the room so MatrixChat can manage the alias in the URL properly // re-view the room so MatrixChat can manage the alias in the URL properly
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: this.state.room.roomId, room_id: this.state.room.roomId,
_trigger: undefined, // room doesn't change
}); });
return; // this event cannot affect permissions so bail return; // this event cannot affect permissions so bail
} }
@ -1643,9 +1647,10 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
// If we were viewing a highlighted event, firing view_room without // If we were viewing a highlighted event, firing view_room without
// an event will take care of both clearing the URL fragment and // an event will take care of both clearing the URL fragment and
// jumping to the bottom // jumping to the bottom
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: this.state.room.roomId, room_id: this.state.room.roomId,
_trigger: undefined, // room doesn't change
}); });
} else { } else {
// Otherwise we have to jump manually // Otherwise we have to jump manually
@ -1778,9 +1783,10 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
onHiddenHighlightsClick = () => { onHiddenHighlightsClick = () => {
const oldRoom = this.getOldRoom(); const oldRoom = this.getOldRoom();
if (!oldRoom) return; if (!oldRoom) return;
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: oldRoom.roomId, room_id: oldRoom.roomId,
_trigger: "Predecessor",
}); });
}; };

View file

@ -62,6 +62,7 @@ import { useEventEmitterState } from "../../hooks/useEventEmitter";
import { IOOBData } from "../../stores/ThreepidInviteStore"; import { IOOBData } from "../../stores/ThreepidInviteStore";
import { awaitRoomDownSync } from "../../utils/RoomUpgrade"; import { awaitRoomDownSync } from "../../utils/RoomUpgrade";
import RoomViewStore from "../../stores/RoomViewStore"; import RoomViewStore from "../../stores/RoomViewStore";
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
space: Room; space: Room;
@ -326,10 +327,9 @@ export const showRoom = (cli: MatrixClient, hierarchy: RoomHierarchy, roomId: st
} }
const roomAlias = getDisplayAliasForRoom(room) || undefined; const roomAlias = getDisplayAliasForRoom(room) || undefined;
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
should_peek: true, should_peek: true,
_type: "room_directory", // instrumentation
room_alias: roomAlias, room_alias: roomAlias,
room_id: room.room_id, room_id: room.room_id,
via_servers: Array.from(hierarchy.viaMap.get(roomId) || []), via_servers: Array.from(hierarchy.viaMap.get(roomId) || []),
@ -339,6 +339,7 @@ export const showRoom = (cli: MatrixClient, hierarchy: RoomHierarchy, roomId: st
name: room.name || roomAlias || _t("Unnamed room"), name: room.name || roomAlias || _t("Unnamed room"),
roomType, roomType,
} as IOOBData, } as IOOBData,
_trigger: "RoomDirectory",
}); });
}; };

View file

@ -85,6 +85,7 @@ import { shouldShowComponent } from "../../customisations/helpers/UIComponents";
import { UIComponent } from "../../settings/UIFeature"; import { UIComponent } from "../../settings/UIFeature";
import { UPDATE_EVENT } from "../../stores/AsyncStore"; import { UPDATE_EVENT } from "../../stores/AsyncStore";
import PosthogTrackers from "../../PosthogTrackers"; import PosthogTrackers from "../../PosthogTrackers";
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
space: Room; space: Room;
@ -865,9 +866,10 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
private goToFirstRoom = async () => { private goToFirstRoom = async () => {
if (this.state.firstRoomId) { if (this.state.firstRoomId) {
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: this.state.firstRoomId, room_id: this.state.firstRoomId,
_trigger: undefined, // other
}); });
return; return;
} }

View file

@ -46,6 +46,7 @@ import { _t } from '../../languageHandler';
import ThreadListContextMenu from '../views/context_menus/ThreadListContextMenu'; import ThreadListContextMenu from '../views/context_menus/ThreadListContextMenu';
import RightPanelStore from '../../stores/right-panel/RightPanelStore'; import RightPanelStore from '../../stores/right-panel/RightPanelStore';
import SettingsStore from "../../settings/SettingsStore"; import SettingsStore from "../../settings/SettingsStore";
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
room: Room; room: Room;
@ -195,12 +196,13 @@ export default class ThreadView extends React.Component<IProps, IState> {
private onScroll = (): void => { private onScroll = (): void => {
if (this.props.initialEvent && this.props.isInitialEventHighlighted) { if (this.props.initialEvent && this.props.isInitialEventHighlighted) {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: this.props.room.roomId, room_id: this.props.room.roomId,
event_id: this.props.initialEvent?.getId(), event_id: this.props.initialEvent?.getId(),
highlighted: false, highlighted: false,
replyingToEvent: this.state.replyToEvent, replyingToEvent: this.state.replyToEvent,
_trigger: undefined, // room doesn't change
}); });
} }
}; };

View file

@ -52,6 +52,7 @@ import Spinner from "../views/elements/Spinner";
import EditorStateTransfer from '../../utils/EditorStateTransfer'; import EditorStateTransfer from '../../utils/EditorStateTransfer';
import ErrorDialog from '../views/dialogs/ErrorDialog'; import ErrorDialog from '../views/dialogs/ErrorDialog';
import CallEventGrouper from "./CallEventGrouper"; import CallEventGrouper from "./CallEventGrouper";
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
const PAGINATE_SIZE = 20; const PAGINATE_SIZE = 20;
const INITIAL_SIZE = 20; const INITIAL_SIZE = 20;
@ -1191,9 +1192,10 @@ class TimelinePanel extends React.Component<IProps, IState> {
if (eventId) { if (eventId) {
onFinished = () => { onFinished = () => {
// go via the dispatcher so that the URL is updated // go via the dispatcher so that the URL is updated
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: this.props.timelineSet.room.roomId, room_id: this.props.timelineSet.room.roomId,
_trigger: undefined, // room doesn't change
}); });
}; };
} }

View file

@ -47,6 +47,7 @@ import { WidgetLayoutStore } from '../../../stores/widgets/WidgetLayoutStore';
import EndPollDialog from '../dialogs/EndPollDialog'; import EndPollDialog from '../dialogs/EndPollDialog';
import { isPollEnded } from '../messages/MPollBody'; import { isPollEnded } from '../messages/MPollBody';
import { createMapSiteLink } from "../messages/MLocationBody"; import { createMapSiteLink } from "../messages/MLocationBody";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
export function canCancel(status: EventStatus): boolean { export function canCancel(status: EventStatus): boolean {
return status === EventStatus.QUEUED || status === EventStatus.NOT_SENT || status === EventStatus.ENCRYPTING; return status === EventStatus.QUEUED || status === EventStatus.NOT_SENT || status === EventStatus.ENCRYPTING;
@ -263,11 +264,12 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
} }
private viewInRoom = () => { private viewInRoom = () => {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
event_id: this.props.mxEvent.getId(), event_id: this.props.mxEvent.getId(),
highlighted: true, highlighted: true,
room_id: this.props.mxEvent.getRoomId(), room_id: this.props.mxEvent.getRoomId(),
_trigger: undefined, // room doesn't change
}); });
this.closeMenu(); this.closeMenu();
}; };

View file

@ -44,6 +44,7 @@ import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
import DMRoomMap from "../../../utils/DMRoomMap"; import DMRoomMap from "../../../utils/DMRoomMap";
import { Action } from "../../../dispatcher/actions"; import { Action } from "../../../dispatcher/actions";
import PosthogTrackers from "../../../PosthogTrackers"; import PosthogTrackers from "../../../PosthogTrackers";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
interface IProps extends IContextMenuProps { interface IProps extends IContextMenuProps {
room: Room; room: Room;
@ -198,7 +199,7 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
ensureViewingRoom(); ensureViewingRoom(ev);
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.RoomMemberList }, false); RightPanelStore.instance.pushCard({ phase: RightPanelPhases.RoomMemberList }, false);
onFinished(); onFinished();
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuPeopleItem", ev); PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuPeopleItem", ev);
@ -247,11 +248,13 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
} }
}; };
const ensureViewingRoom = () => { const ensureViewingRoom = (ev: ButtonEvent) => {
if (RoomViewStore.getRoomId() === room.roomId) return; if (RoomViewStore.getRoomId() === room.roomId) return;
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: room.roomId, room_id: room.roomId,
_trigger: "RoomList",
_viaKeyboard: ev.type !== "click",
}, true); }, true);
}; };
@ -267,7 +270,7 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
ensureViewingRoom(); ensureViewingRoom(ev);
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.FilePanel }, false); RightPanelStore.instance.pushCard({ phase: RightPanelPhases.FilePanel }, false);
onFinished(); onFinished();
}} }}
@ -280,7 +283,7 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
ensureViewingRoom(); ensureViewingRoom(ev);
RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomSummary }, false); RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomSummary }, false);
onFinished(); onFinished();
}} }}

View file

@ -39,6 +39,7 @@ import { Action } from "../../../dispatcher/actions";
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents"; import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
import { UIComponent } from "../../../settings/UIFeature"; import { UIComponent } from "../../../settings/UIFeature";
import PosthogTrackers from "../../../PosthogTrackers"; import PosthogTrackers from "../../../PosthogTrackers";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
interface IProps extends IContextMenuProps { interface IProps extends IContextMenuProps {
space: Room; space: Room;
@ -115,10 +116,11 @@ const SpaceContextMenu = ({ space, hideHeader, onFinished, ...props }: IProps) =
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: space.roomId, room_id: space.roomId,
forceTimeline: true, forceTimeline: true,
_trigger: undefined, // room doesn't change
}); });
onFinished(); onFinished();
}; };
@ -192,9 +194,10 @@ const SpaceContextMenu = ({ space, hideHeader, onFinished, ...props }: IProps) =
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: space.roomId, room_id: space.roomId,
_trigger: undefined, // other
}); });
onFinished(); onFinished();
}; };

View file

@ -28,6 +28,7 @@ import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOpti
import { WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore"; import { WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { useRovingTabIndex } from "../../../accessibility/RovingTabIndex"; import { useRovingTabIndex } from "../../../accessibility/RovingTabIndex";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
mxEvent: MatrixEvent; mxEvent: MatrixEvent;
@ -75,11 +76,12 @@ const ThreadListContextMenu: React.FC<IExtendedProps> = ({
const viewInRoom = useCallback((evt: ButtonEvent): void => { const viewInRoom = useCallback((evt: ButtonEvent): void => {
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation(); evt.stopPropagation();
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
event_id: mxEvent.getId(), event_id: mxEvent.getId(),
highlighted: true, highlighted: true,
room_id: mxEvent.getRoomId(), room_id: mxEvent.getRoomId(),
_trigger: undefined, // room doesn't change
}); });
closeThreadOptions(); closeThreadOptions();
}, [mxEvent, closeThreadOptions]); }, [mxEvent, closeThreadOptions]);

View file

@ -29,6 +29,7 @@ import { Action } from '../../../dispatcher/actions';
import { showCommunityRoomInviteDialog } from "../../../RoomInvite"; import { showCommunityRoomInviteDialog } from "../../../RoomInvite";
import GroupStore from "../../../stores/GroupStore"; import GroupStore from "../../../stores/GroupStore";
import { replaceableComponent } from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
interface IProps extends IDialogProps { interface IProps extends IDialogProps {
} }
@ -100,9 +101,10 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent<
if (result.room_id) { if (result.room_id) {
// Force the group store to update as it might have missed the general chat // Force the group store to update as it might have missed the general chat
await GroupStore.refreshGroupRooms(result.group_id); await GroupStore.refreshGroupRooms(result.group_id);
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: result.room_id, room_id: result.room_id,
_trigger: undefined, // Deprecated groups
}); });
showCommunityRoomInviteDialog(result.room_id, this.state.name); showCommunityRoomInviteDialog(result.room_id, this.state.name);
} else { } else {

View file

@ -42,6 +42,7 @@ import { UserTab } from "./UserSettingsDialog";
import TagOrderActions from "../../../actions/TagOrderActions"; import TagOrderActions from "../../../actions/TagOrderActions";
import { inviteUsersToRoom } from "../../../RoomInvite"; import { inviteUsersToRoom } from "../../../RoomInvite";
import ProgressBar from "../elements/ProgressBar"; import ProgressBar from "../elements/ProgressBar";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
matrixClient: MatrixClient; matrixClient: MatrixClient;
@ -226,9 +227,10 @@ const CreateSpaceFromCommunityDialog: React.FC<IProps> = ({ matrixClient: cli, g
onFinished(roomId); onFinished(roomId);
const onSpaceClick = () => { const onSpaceClick = () => {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: roomId, room_id: roomId,
_trigger: undefined, // other
}); });
}; };

View file

@ -46,6 +46,8 @@ import BaseAvatar from "../avatars/BaseAvatar";
import SpaceStore from "../../../stores/spaces/SpaceStore"; import SpaceStore from "../../../stores/spaces/SpaceStore";
import { roomContextDetailsText } from "../../../Rooms"; import { roomContextDetailsText } from "../../../Rooms";
import { Action } from "../../../dispatcher/actions"; import { Action } from "../../../dispatcher/actions";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { ButtonEvent } from "../elements/AccessibleButton";
const AVATAR_SIZE = 30; const AVATAR_SIZE = 30;
@ -75,10 +77,12 @@ enum SendState {
const Entry: React.FC<IEntryProps> = ({ room, event, matrixClient: cli, onFinished }) => { const Entry: React.FC<IEntryProps> = ({ room, event, matrixClient: cli, onFinished }) => {
const [sendState, setSendState] = useState<SendState>(SendState.CanSend); const [sendState, setSendState] = useState<SendState>(SendState.CanSend);
const jumpToRoom = () => { const jumpToRoom = (ev: ButtonEvent) => {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: room.roomId, room_id: room.roomId,
_trigger: "WebForwardShortcut",
_viaKeyboard: ev.type !== "click",
}); });
onFinished(true); onFinished(true);
}; };

View file

@ -71,6 +71,7 @@ import CallHandler from "../../../CallHandler";
import UserIdentifierCustomisations from '../../../customisations/UserIdentifier'; import UserIdentifierCustomisations from '../../../customisations/UserIdentifier';
import CopyableText from "../elements/CopyableText"; import CopyableText from "../elements/CopyableText";
import { ScreenName } from '../../../PosthogTrackers'; import { ScreenName } from '../../../PosthogTrackers';
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
// we have a number of types defined from the Matrix spec which can't reasonably be altered here. // we have a number of types defined from the Matrix spec which can't reasonably be altered here.
/* eslint-disable camelcase */ /* eslint-disable camelcase */
@ -679,11 +680,12 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
existingRoom = DMRoomMap.shared().getDMRoomForIdentifiers(targetIds); existingRoom = DMRoomMap.shared().getDMRoomForIdentifiers(targetIds);
} }
if (existingRoom) { if (existingRoom) {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: existingRoom.roomId, room_id: existingRoom.roomId,
should_peek: false, should_peek: false,
joining: false, joining: false,
_trigger: "MessageUser",
}); });
this.props.onFinished(true); this.props.onFinished(true);
return; return;

View file

@ -68,6 +68,7 @@ import { BetaPill } from "../beta/BetaCard";
import { UserTab } from "./UserSettingsDialog"; import { UserTab } from "./UserSettingsDialog";
import BetaFeedbackDialog from "./BetaFeedbackDialog"; import BetaFeedbackDialog from "./BetaFeedbackDialog";
import SdkConfig from "../../../SdkConfig"; import SdkConfig from "../../../SdkConfig";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
const MAX_RECENT_SEARCHES = 10; const MAX_RECENT_SEARCHES = 10;
const SECTION_LIMIT = 50; // only show 50 results per section for performance reasons const SECTION_LIMIT = 50; // only show 50 results per section for performance reasons
@ -214,7 +215,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
}); });
}; };
const viewRoom = (roomId: string, persist = false) => { const viewRoom = (roomId: string, persist = false, viaKeyboard = false) => {
if (persist) { if (persist) {
const recents = new Set(SettingsStore.getValue("SpotlightSearch.recentSearches", null).reverse()); const recents = new Set(SettingsStore.getValue("SpotlightSearch.recentSearches", null).reverse());
// remove & add the room to put it at the end // remove & add the room to put it at the end
@ -229,9 +230,11 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
); );
} }
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: roomId, room_id: roomId,
_trigger: "WebUnifiedSearch",
_viaKeyboard: viaKeyboard,
}); });
onFinished(); onFinished();
}; };
@ -249,8 +252,8 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
<Option <Option
id={`mx_SpotlightDialog_button_result_${room.roomId}`} id={`mx_SpotlightDialog_button_result_${room.roomId}`}
key={room.roomId} key={room.roomId}
onClick={() => { onClick={(ev) => {
viewRoom(room.roomId, true); viewRoom(room.roomId, true, ev.type !== "click");
}} }}
> >
<DecoratedRoomAvatar room={room} avatarSize={20} tooltipProps={{ tabIndex: -1 }} /> <DecoratedRoomAvatar room={room} avatarSize={20} tooltipProps={{ tabIndex: -1 }} />
@ -300,8 +303,8 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
<Option <Option
id={`mx_SpotlightDialog_button_result_${room.room_id}`} id={`mx_SpotlightDialog_button_result_${room.room_id}`}
key={room.room_id} key={room.room_id}
onClick={() => { onClick={(ev) => {
viewRoom(room.room_id, true); viewRoom(room.room_id, true, ev.type !== "click");
}} }}
> >
<BaseAvatar <BaseAvatar
@ -389,8 +392,8 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
<Option <Option
id={`mx_SpotlightDialog_button_recentSearch_${room.roomId}`} id={`mx_SpotlightDialog_button_recentSearch_${room.roomId}`}
key={room.roomId} key={room.roomId}
onClick={() => { onClick={(ev) => {
viewRoom(room.roomId, true); viewRoom(room.roomId, true, ev.type !== "click");
}} }}
> >
<DecoratedRoomAvatar room={room} avatarSize={20} tooltipProps={{ tabIndex: -1 }} /> <DecoratedRoomAvatar room={room} avatarSize={20} tooltipProps={{ tabIndex: -1 }} />
@ -417,8 +420,8 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
id={`mx_SpotlightDialog_button_recentlyViewed_${room.roomId}`} id={`mx_SpotlightDialog_button_recentlyViewed_${room.roomId}`}
title={room.name} title={room.name}
key={room.roomId} key={room.roomId}
onClick={() => { onClick={(ev) => {
viewRoom(room.roomId); viewRoom(room.roomId, false, ev.type !== "click");
}} }}
> >
<DecoratedRoomAvatar room={room} avatarSize={32} tooltipProps={{ tabIndex: -1 }} /> <DecoratedRoomAvatar room={room} avatarSize={32} tooltipProps={{ tabIndex: -1 }} />

View file

@ -37,6 +37,7 @@ import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
import { normalizeWheelEvent } from "../../../utils/Mouse"; import { normalizeWheelEvent } from "../../../utils/Mouse";
import { IDialogProps } from '../dialogs/IDialogProps'; import { IDialogProps } from '../dialogs/IDialogProps';
import UIStore from '../../../stores/UIStore'; import UIStore from '../../../stores/UIStore';
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
// Max scale to keep gaps around the image // Max scale to keep gaps around the image
const MAX_SCALE = 0.95; const MAX_SCALE = 0.95;
@ -333,11 +334,12 @@ export default class ImageView extends React.Component<IProps, IState> {
// This allows the permalink to be opened in a new tab/window or copied as // This allows the permalink to be opened in a new tab/window or copied as
// matrix.to, but also for it to enable routing within Element when clicked. // matrix.to, but also for it to enable routing within Element when clicked.
ev.preventDefault(); ev.preventDefault();
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
event_id: this.props.mxEvent.getId(), event_id: this.props.mxEvent.getId(),
highlighted: true, highlighted: true,
room_id: this.props.mxEvent.getRoomId(), room_id: this.props.mxEvent.getRoomId(),
_trigger: undefined, // room doesn't change
}); });
this.props.onFinished(); this.props.onFinished();
}; };

View file

@ -36,6 +36,7 @@ import IconizedContextMenu, {
IconizedContextMenuOptionList, IconizedContextMenuOptionList,
} from "../context_menus/IconizedContextMenu"; } from "../context_menus/IconizedContextMenu";
import JumpToDatePicker from './JumpToDatePicker'; import JumpToDatePicker from './JumpToDatePicker';
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
function getDaysArray(): string[] { function getDaysArray(): string[] {
return [ return [
@ -141,11 +142,12 @@ export default class DateSeparator extends React.Component<IProps, IState> {
`found ${eventId} (${originServerTs}) for timestamp=${unixTimestamp} (looking forward)`, `found ${eventId} (${originServerTs}) for timestamp=${unixTimestamp} (looking forward)`,
); );
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
event_id: eventId, event_id: eventId,
highlighted: true, highlighted: true,
room_id: roomId, room_id: roomId,
_trigger: undefined, // room doesn't change
}); });
} catch (e) { } catch (e) {
const code = e.errcode || e.statusCode; const code = e.errcode || e.statusCode;

View file

@ -25,6 +25,7 @@ import { _t } from '../../../languageHandler';
import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { MatrixClientPeg } from '../../../MatrixClientPeg';
import EventTileBubble from "./EventTileBubble"; import EventTileBubble from "./EventTileBubble";
import { replaceableComponent } from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
/* the MatrixEvent to show */ /* the MatrixEvent to show */
@ -39,11 +40,13 @@ export default class RoomCreate extends React.Component<IProps> {
const predecessor = this.props.mxEvent.getContent()['predecessor']; const predecessor = this.props.mxEvent.getContent()['predecessor'];
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
event_id: predecessor['event_id'], event_id: predecessor['event_id'],
highlighted: true, highlighted: true,
room_id: predecessor['room_id'], room_id: predecessor['room_id'],
_trigger: "Predecessor",
_viaKeyboard: e.type !== "click",
}); });
}; };

View file

@ -41,6 +41,7 @@ import ContentMessages from '../../../ContentMessages';
import UploadBar from '../../structures/UploadBar'; import UploadBar from '../../structures/UploadBar';
import SettingsStore from '../../../settings/SettingsStore'; import SettingsStore from '../../../settings/SettingsStore';
import JumpToBottomButton from '../rooms/JumpToBottomButton'; import JumpToBottomButton from '../rooms/JumpToBottomButton';
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
room: Room; room: Room;
@ -144,12 +145,13 @@ export default class TimelineCard extends React.Component<IProps, IState> {
private onUserScroll = (): void => { private onUserScroll = (): void => {
if (this.state.initialEventId && this.state.isInitialEventHighlighted) { if (this.state.initialEventId && this.state.isInitialEventHighlighted) {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: this.props.room.roomId, room_id: this.props.room.roomId,
event_id: this.state.initialEventId, event_id: this.state.initialEventId,
highlighted: false, highlighted: false,
replyingToEvent: this.state.replyToEvent, replyingToEvent: this.state.replyToEvent,
_trigger: undefined, // room doesn't change
}); });
} }
}; };

View file

@ -79,6 +79,7 @@ import { IRightPanelCardState } from '../../../stores/right-panel/RightPanelStor
import { useUserStatusMessage } from "../../../hooks/useUserStatusMessage"; import { useUserStatusMessage } from "../../../hooks/useUserStatusMessage";
import UserIdentifierCustomisations from '../../../customisations/UserIdentifier'; import UserIdentifierCustomisations from '../../../customisations/UserIdentifier';
import PosthogTrackers from "../../../PosthogTrackers"; import PosthogTrackers from "../../../PosthogTrackers";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
export interface IDevice { export interface IDevice {
deviceId: string; deviceId: string;
@ -123,13 +124,15 @@ export const getE2EStatus = (cli: MatrixClient, userId: string, devices: IDevice
return anyDeviceUnverified ? E2EStatus.Warning : E2EStatus.Verified; return anyDeviceUnverified ? E2EStatus.Warning : E2EStatus.Verified;
}; };
async function openDMForUser(matrixClient: MatrixClient, userId: string): Promise<void> { async function openDMForUser(matrixClient: MatrixClient, userId: string, viaKeyboard = false): Promise<void> {
const lastActiveRoom = findDMForUser(matrixClient, userId); const lastActiveRoom = findDMForUser(matrixClient, userId);
if (lastActiveRoom) { if (lastActiveRoom) {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: lastActiveRoom.roomId, room_id: lastActiveRoom.roomId,
_trigger: "MessageUser",
_viaKeyboard: viaKeyboard,
}); });
return; return;
} }
@ -327,10 +330,10 @@ const MessageButton = ({ userId }: { userId: string }) => {
return ( return (
<AccessibleButton <AccessibleButton
onClick={async () => { onClick={async (ev) => {
if (busy) return; if (busy) return;
setBusy(true); setBusy(true);
await openDMForUser(cli, userId); await openDMForUser(cli, userId, ev.type !== "click");
setBusy(false); setBusy(false);
}} }}
className="mx_UserInfo_field" className="mx_UserInfo_field"
@ -389,11 +392,12 @@ const UserOptionsSection: React.FC<{
if (member.roomId && !isSpace) { if (member.roomId && !isSpace) {
const onReadReceiptButton = function() { const onReadReceiptButton = function() {
const room = cli.getRoom(member.roomId); const room = cli.getRoom(member.roomId);
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
highlighted: true, highlighted: true,
event_id: room.getEventReadUpTo(member.userId), event_id: room.getEventReadUpTo(member.userId),
room_id: member.roomId, room_id: member.roomId,
_trigger: undefined, // room doesn't change
}); });
}; };

View file

@ -77,6 +77,7 @@ import { CardContext } from '../right_panel/BaseCard';
import { copyPlaintext } from '../../../utils/strings'; import { copyPlaintext } from '../../../utils/strings';
import { DecryptionFailureTracker } from '../../../DecryptionFailureTracker'; import { DecryptionFailureTracker } from '../../../DecryptionFailureTracker';
import RedactedBody from '../messages/RedactedBody'; import RedactedBody from '../messages/RedactedBody';
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
const eventTileTypes = { const eventTileTypes = {
[EventType.RoomMessage]: 'messages.MessageEvent', [EventType.RoomMessage]: 'messages.MessageEvent',
@ -714,11 +715,12 @@ export default class EventTile extends React.Component<IProps, IState> {
private viewInRoom = (evt: ButtonEvent): void => { private viewInRoom = (evt: ButtonEvent): void => {
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation(); evt.stopPropagation();
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
event_id: this.props.mxEvent.getId(), event_id: this.props.mxEvent.getId(),
highlighted: true, highlighted: true,
room_id: this.props.mxEvent.getRoomId(), room_id: this.props.mxEvent.getRoomId(),
_trigger: undefined, // room doesn't change
}); });
}; };
@ -1016,11 +1018,12 @@ export default class EventTile extends React.Component<IProps, IState> {
// This allows the permalink to be opened in a new tab/window or copied as // This allows the permalink to be opened in a new tab/window or copied as
// matrix.to, but also for it to enable routing within Element when clicked. // matrix.to, but also for it to enable routing within Element when clicked.
e.preventDefault(); e.preventDefault();
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
event_id: this.props.mxEvent.getId(), event_id: this.props.mxEvent.getId(),
highlighted: true, highlighted: true,
room_id: this.props.mxEvent.getRoomId(), room_id: this.props.mxEvent.getRoomId(),
_trigger: this.props.timelineRenderingType === TimelineRenderingType.Search ? "MessageSearch" : undefined,
}); });
}; };

View file

@ -23,6 +23,7 @@ import {
} from "../../../accessibility/RovingTabIndex"; } from "../../../accessibility/RovingTabIndex";
import NotificationBadge from "./NotificationBadge"; import NotificationBadge from "./NotificationBadge";
import { NotificationState } from "../../../stores/notifications/NotificationState"; import { NotificationState } from "../../../stores/notifications/NotificationState";
import { ButtonEvent } from "../elements/AccessibleButton";
interface IProps { interface IProps {
isMinimized: boolean; isMinimized: boolean;
@ -30,7 +31,7 @@ interface IProps {
displayName: string; displayName: string;
avatar: React.ReactElement; avatar: React.ReactElement;
notificationState?: NotificationState; notificationState?: NotificationState;
onClick: () => void; onClick: (ev: ButtonEvent) => void;
} }
interface IState { interface IState {

View file

@ -49,6 +49,7 @@ import RoomContext from '../../../contexts/RoomContext';
import { SettingUpdatedPayload } from "../../../dispatcher/payloads/SettingUpdatedPayload"; import { SettingUpdatedPayload } from "../../../dispatcher/payloads/SettingUpdatedPayload";
import MessageComposerButtons from './MessageComposerButtons'; import MessageComposerButtons from './MessageComposerButtons';
import { ButtonEvent } from '../elements/AccessibleButton'; import { ButtonEvent } from '../elements/AccessibleButton';
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
let instanceCount = 0; let instanceCount = 0;
const NARROW_MODE_BREAKPOINT = 500; const NARROW_MODE_BREAKPOINT = 500;
@ -227,21 +228,17 @@ export default class MessageComposer extends React.Component<IProps, IState> {
} }
const viaServers = [this.state.tombstone.getSender().split(':').slice(1).join(':')]; const viaServers = [this.state.tombstone.getSender().split(':').slice(1).join(':')];
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
highlighted: true, highlighted: true,
event_id: createEventId, event_id: createEventId,
room_id: replacementRoomId, room_id: replacementRoomId,
auto_join: true, auto_join: true,
_type: "tombstone", // instrumentation
// Try to join via the server that sent the event. This converts @something:example.org // Try to join via the server that sent the event. This converts @something:example.org
// into a server domain by splitting on colons and ignoring the first entry ("@something"). // into a server domain by splitting on colons and ignoring the first entry ("@something").
via_servers: viaServers, via_servers: viaServers,
opts: { _trigger: "Tombstone",
// These are passed down to the js-sdk's /join call _viaKeyboard: ev.type !== "click",
viaServers: viaServers,
},
}); });
}; };

View file

@ -31,6 +31,7 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { getUserNameColorClass } from "../../../utils/FormattingUtils"; import { getUserNameColorClass } from "../../../utils/FormattingUtils";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { TileShape } from "./EventTile"; import { TileShape } from "./EventTile";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
room: Room; room: Room;
@ -45,11 +46,12 @@ export default class PinnedEventTile extends React.Component<IProps> {
public static contextType = MatrixClientContext; public static contextType = MatrixClientContext;
private onTileClicked = () => { private onTileClicked = () => {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
event_id: this.props.event.getId(), event_id: this.props.event.getId(),
highlighted: true, highlighted: true,
room_id: this.props.event.getRoomId(), room_id: this.props.event.getRoomId(),
_trigger: undefined, // room doesn't change
}); });
}; };

View file

@ -26,6 +26,7 @@ import InteractiveTooltip, { Direction } from "../elements/InteractiveTooltip";
import { roomContextDetailsText } from "../../../Rooms"; import { roomContextDetailsText } from "../../../Rooms";
import { Action } from "../../../dispatcher/actions"; import { Action } from "../../../dispatcher/actions";
import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar"; import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
const RecentlyViewedButton = () => { const RecentlyViewedButton = () => {
const tooltipRef = useRef<InteractiveTooltip>(); const tooltipRef = useRef<InteractiveTooltip>();
@ -39,10 +40,12 @@ const RecentlyViewedButton = () => {
return <MenuItem return <MenuItem
key={crumb.roomId} key={crumb.roomId}
onClick={() => { onClick={(ev) => {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: crumb.roomId, room_id: crumb.roomId,
_trigger: "WebVerticalBreadcrumbs",
_viaKeyboard: ev.type !== "click",
}); });
tooltipRef.current?.hideTooltip(); tooltipRef.current?.hideTooltip();
}} }}

View file

@ -32,6 +32,7 @@ import { replaceableComponent } from '../../../utils/replaceableComponent';
import { getEventDisplayInfo, isVoiceMessage } from '../../../utils/EventUtils'; import { getEventDisplayInfo, isVoiceMessage } from '../../../utils/EventUtils';
import MFileBody from "../messages/MFileBody"; import MFileBody from "../messages/MFileBody";
import MVoiceMessageBody from "../messages/MVoiceMessageBody"; import MVoiceMessageBody from "../messages/MVoiceMessageBody";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
mxEvent: MatrixEvent; mxEvent: MatrixEvent;
@ -94,11 +95,12 @@ export default class ReplyTile extends React.PureComponent<IProps> {
if (this.props.toggleExpandedQuote && e.shiftKey) { if (this.props.toggleExpandedQuote && e.shiftKey) {
this.props.toggleExpandedQuote(); this.props.toggleExpandedQuote();
} else { } else {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
event_id: this.props.mxEvent.getId(), event_id: this.props.mxEvent.getId(),
highlighted: true, highlighted: true,
room_id: this.props.mxEvent.getRoomId(), room_id: this.props.mxEvent.getRoomId(),
_trigger: undefined, // room doesn't change
}); });
} }
} }

View file

@ -29,6 +29,8 @@ import Toolbar from "../../../accessibility/Toolbar";
import { replaceableComponent } from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
import { Action } from "../../../dispatcher/actions"; import { Action } from "../../../dispatcher/actions";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { ButtonEvent } from "../elements/AccessibleButton";
interface IProps { interface IProps {
} }
@ -44,7 +46,7 @@ interface IState {
skipFirst: boolean; skipFirst: boolean;
} }
const RoomBreadcrumbTile = ({ room, onClick }: { room: Room, onClick: () => void }) => { const RoomBreadcrumbTile = ({ room, onClick }: { room: Room, onClick: (ev: ButtonEvent) => void }) => {
const [onFocus, isActive, ref] = useRovingTabIndex(); const [onFocus, isActive, ref] = useRovingTabIndex();
return ( return (
@ -103,18 +105,24 @@ export default class RoomBreadcrumbs extends React.PureComponent<IProps, IState>
setTimeout(() => this.setState({ doAnimation: true, skipFirst: false }), 0); setTimeout(() => this.setState({ doAnimation: true, skipFirst: false }), 0);
}; };
private viewRoom = (room: Room, index: number) => { private viewRoom = (room: Room, index: number, viaKeyboard = false) => {
Analytics.trackEvent("Breadcrumbs", "click_node", String(index)); Analytics.trackEvent("Breadcrumbs", "click_node", String(index));
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: room.roomId, room_id: room.roomId,
_trigger: "WebHorizontalBreadcrumbs",
_viaKeyboard: viaKeyboard,
}); });
}; };
public render(): React.ReactElement { public render(): React.ReactElement {
const tiles = BreadcrumbsStore.instance.rooms.map((r, i) => { const tiles = BreadcrumbsStore.instance.rooms.map((r, i) => (
return <RoomBreadcrumbTile key={r.roomId} room={r} onClick={() => this.viewRoom(r, i)} />; <RoomBreadcrumbTile
}); key={r.roomId}
room={r}
onClick={(ev: ButtonEvent) => this.viewRoom(r, i, ev.type !== "click")}
/>
));
if (tiles.length > 0) { if (tiles.length > 0) {
// NOTE: The CSSTransition timeout MUST match the timeout in our CSS! // NOTE: The CSSTransition timeout MUST match the timeout in our CSS!

View file

@ -23,6 +23,7 @@ import { Action } from '../../../dispatcher/actions';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import { replaceableComponent } from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
import RoomDetailRow from "./RoomDetailRow"; import RoomDetailRow from "./RoomDetailRow";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
rooms?: Room[]; rooms?: Room[];
@ -39,10 +40,11 @@ export default class RoomDetailList extends React.Component<IProps> {
} }
private onDetailsClick = (ev: React.MouseEvent, room: Room): void => { private onDetailsClick = (ev: React.MouseEvent, room: Room): void => {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: room.roomId, room_id: room.roomId,
room_alias: room.getCanonicalAlias() || (room.getAltAliases() || [])[0], room_alias: room.getCanonicalAlias() || (room.getAltAliases() || [])[0],
_trigger: undefined, // Deprecated groups
}); });
}; };

View file

@ -65,6 +65,7 @@ import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../str
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import PosthogTrackers from "../../../PosthogTrackers"; import PosthogTrackers from "../../../PosthogTrackers";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
onKeyDown: (ev: React.KeyboardEvent, state: IRovingTabIndexState) => void; onKeyDown: (ev: React.KeyboardEvent, state: IRovingTabIndexState) => void;
@ -217,9 +218,10 @@ const UntaggedAuxButton = ({ tabIndex }: IAuxButtonProps) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
closeMenu(); closeMenu();
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: activeSpace.roomId, room_id: activeSpace.roomId,
_trigger: undefined, // other
}); });
}} }}
/> />
@ -417,10 +419,12 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
const currentRoomId = RoomViewStore.getRoomId(); const currentRoomId = RoomViewStore.getRoomId();
const room = this.getRoomDelta(currentRoomId, viewRoomDeltaPayload.delta, viewRoomDeltaPayload.unread); const room = this.getRoomDelta(currentRoomId, viewRoomDeltaPayload.delta, viewRoomDeltaPayload.unread);
if (room) { if (room) {
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: room.roomId, room_id: room.roomId,
show_room_tile: true, // to make sure the room gets scrolled into view show_room_tile: true, // to make sure the room gets scrolled into view
_trigger: "WebKeyboardShortcut",
_viaKeyboard: true,
}); });
} }
} else if (payload.action === Action.PstnSupportUpdated) { } else if (payload.action === Action.PstnSupportUpdated) {
@ -501,9 +505,10 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
private onExplore = () => { private onExplore = () => {
if (!isMetaSpace(this.props.activeSpace)) { if (!isMetaSpace(this.props.activeSpace)) {
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: this.props.activeSpace, room_id: this.props.activeSpace,
_trigger: undefined, // other
}); });
} else { } else {
const initialText = RoomListStore.instance.getFirstNameFilterCondition()?.search; const initialText = RoomListStore.instance.getFirstNameFilterCondition()?.search;
@ -525,16 +530,18 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
resizeMethod="crop" resizeMethod="crop"
/> />
); );
const viewRoom = () => { const viewRoom = (ev) => {
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_alias: room.canonical_alias || room.aliases?.[0], room_alias: room.canonical_alias || room.aliases?.[0],
room_id: room.room_id, room_id: room.room_id,
via_servers: room.viaServers, via_servers: room.viaServers,
oobData: { oob_data: {
avatarUrl: room.avatar_url, avatarUrl: room.avatar_url,
name, name,
}, },
_trigger: "RoomList",
_viaKeyboard: ev.type !== "click",
}); });
}; };
return ( return (

View file

@ -60,6 +60,7 @@ import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
import TooltipTarget from "../elements/TooltipTarget"; import TooltipTarget from "../elements/TooltipTarget";
import { BetaPill } from "../beta/BetaCard"; import { BetaPill } from "../beta/BetaCard";
import PosthogTrackers from "../../../PosthogTrackers"; import PosthogTrackers from "../../../PosthogTrackers";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
const contextMenuBelow = (elementRect: DOMRect) => { const contextMenuBelow = (elementRect: DOMRect) => {
// align the context menu's icons with the icon which opened the context menu // align the context menu's icons with the icon which opened the context menu
@ -104,9 +105,10 @@ const PrototypeCommunityContextMenu = (props: ComponentProps<typeof SpaceContext
// anyways. // anyways.
const chat = CommunityPrototypeStore.instance.getSelectedCommunityGeneralChat(); const chat = CommunityPrototypeStore.instance.getSelectedCommunityGeneralChat();
if (chat) { if (chat) {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: chat.roomId, room_id: chat.roomId,
_trigger: undefined, // Deprecated groups
}, true); }, true);
RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomMemberList }, undefined, chat.roomId); RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomMemberList }, undefined, chat.roomId);
} else { } else {
@ -274,9 +276,10 @@ const RoomListHeader = ({ spacePanelDisabled, onVisibilityChange }: IProps) => {
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: activeSpace.roomId, room_id: activeSpace.roomId,
_trigger: undefined, // other
}); });
closePlusMenu(); closePlusMenu();
}} }}

View file

@ -57,6 +57,7 @@ import { ListNotificationState } from "../../../stores/notifications/ListNotific
import { getKeyBindingsManager } from "../../../KeyBindingsManager"; import { getKeyBindingsManager } from "../../../KeyBindingsManager";
import { replaceableComponent } from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
const SHOW_N_BUTTON_HEIGHT = 28; // As defined by CSS const SHOW_N_BUTTON_HEIGHT = 28; // As defined by CSS
const RESIZE_HANDLE_HEIGHT = 4; // As defined by CSS const RESIZE_HANDLE_HEIGHT = 4; // As defined by CSS
@ -428,10 +429,12 @@ export default class RoomSublist extends React.Component<IProps, IState> {
} }
if (room) { if (room) {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: room.roomId, room_id: room.roomId,
show_room_tile: true, // to make sure the room gets scrolled into view show_room_tile: true, // to make sure the room gets scrolled into view
_trigger: "WebRoomListNotificationBadge",
_viaKeyboard: ev.type !== "click",
}); });
} }
}; };

View file

@ -53,6 +53,7 @@ import IconizedContextMenu, {
import { CommunityPrototypeStore, IRoomProfile } from "../../../stores/CommunityPrototypeStore"; import { CommunityPrototypeStore, IRoomProfile } from "../../../stores/CommunityPrototypeStore";
import { replaceableComponent } from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
import PosthogTrackers from "../../../PosthogTrackers"; import PosthogTrackers from "../../../PosthogTrackers";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
room: Room; room: Room;
@ -239,11 +240,13 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
private onTileClick = (ev: React.KeyboardEvent) => { private onTileClick = (ev: React.KeyboardEvent) => {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
show_room_tile: true, // make sure the room is visible in the list show_room_tile: true, // make sure the room is visible in the list
room_id: this.props.room.roomId, room_id: this.props.room.roomId,
clear_search: (ev && (ev.key === Key.ENTER || ev.key === Key.SPACE)), clear_search: (ev && (ev.key === Key.ENTER || ev.key === Key.SPACE)),
_trigger: "RoomList",
_viaKeyboard: ev.type !== "click",
}); });
}; };

View file

@ -34,6 +34,7 @@ import { useLocalEcho } from "../../../hooks/useLocalEcho";
import dis from "../../../dispatcher/dispatcher"; import dis from "../../../dispatcher/dispatcher";
import { ROOM_SECURITY_TAB } from "../dialogs/RoomSettingsDialog"; import { ROOM_SECURITY_TAB } from "../dialogs/RoomSettingsDialog";
import { Action } from "../../../dispatcher/actions"; import { Action } from "../../../dispatcher/actions";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
room: Room; room: Room;
@ -267,9 +268,10 @@ const JoinRuleSettings = ({ room, promptUpgrade, aliasWarning, onError, beforeCh
closeSettingsFn(); closeSettingsFn();
// switch to the new room in the background // switch to the new room in the background
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: roomId, room_id: roomId,
_trigger: undefined, // other
}); });
// open new settings on this tab // open new settings on this tab

View file

@ -27,6 +27,7 @@ import dis from "../../../../../dispatcher/dispatcher";
import { Action } from '../../../../../dispatcher/actions'; import { Action } from '../../../../../dispatcher/actions';
import { replaceableComponent } from "../../../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../../../utils/replaceableComponent";
import CopyableText from "../../../elements/CopyableText"; import CopyableText from "../../../elements/CopyableText";
import { ViewRoomPayload } from "../../../../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
roomId: string; roomId: string;
@ -90,10 +91,12 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: this.state.oldRoomId, room_id: this.state.oldRoomId,
event_id: this.state.oldEventId, event_id: this.state.oldEventId,
_trigger: "WebPredecessorSettings",
_viaKeyboard: e.type !== "click",
}); });
this.props.closeSettingsFn(); this.props.closeSettingsFn();
}; };

View file

@ -38,6 +38,7 @@ import Spinner from "../../../elements/Spinner";
import { UserTab } from "../../../dialogs/UserSettingsDialog"; import { UserTab } from "../../../dialogs/UserSettingsDialog";
import { OpenToTabPayload } from "../../../../../dispatcher/payloads/OpenToTabPayload"; import { OpenToTabPayload } from "../../../../../dispatcher/payloads/OpenToTabPayload";
import { Action } from "../../../../../dispatcher/actions"; import { Action } from "../../../../../dispatcher/actions";
import { ViewRoomPayload } from "../../../../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
closeSettingsFn(success: boolean): void; closeSettingsFn(success: boolean): void;
@ -113,9 +114,10 @@ const CommunityMigrator = ({ onFinished }) => {
kind="primary_outline" kind="primary_outline"
onClick={() => { onClick={() => {
if (community.spaceId) { if (community.spaceId) {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: community.spaceId, room_id: community.spaceId,
_trigger: undefined, // other
}); });
onFinished(); onFinished();
} else { } else {

View file

@ -31,6 +31,7 @@ import { Action } from "../../../dispatcher/actions";
import { replaceableComponent } from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
import VerificationRequestDialog from "../dialogs/VerificationRequestDialog"; import VerificationRequestDialog from "../dialogs/VerificationRequestDialog";
import RightPanelStore from "../../../stores/right-panel/RightPanelStore"; import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
interface IProps { interface IProps {
toastKey: string; toastKey: string;
@ -110,10 +111,11 @@ export default class VerificationRequestToast extends React.PureComponent<IProps
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
try { try {
if (request.channel.roomId) { if (request.channel.roomId) {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: request.channel.roomId, room_id: request.channel.roomId,
should_peek: false, should_peek: false,
_trigger: "VerificationRequest",
}); });
const member = cli.getUser(request.otherUserId); const member = cli.getUser(request.otherUserId);
RightPanelStore.instance.setCards( RightPanelStore.instance.setCards(

View file

@ -22,6 +22,7 @@ import RoomAvatar from '../../avatars/RoomAvatar';
import dis from '../../../../dispatcher/dispatcher'; import dis from '../../../../dispatcher/dispatcher';
import { Action } from '../../../../dispatcher/actions'; import { Action } from '../../../../dispatcher/actions';
import AccessibleTooltipButton from '../../elements/AccessibleTooltipButton'; import AccessibleTooltipButton from '../../elements/AccessibleTooltipButton';
import { ViewRoomPayload } from "../../../../dispatcher/payloads/ViewRoomPayload";
interface CallViewHeaderProps { interface CallViewHeaderProps {
pipMode: boolean; pipMode: boolean;
@ -37,9 +38,10 @@ const onFullscreenClick = () => {
}; };
const onExpandClick = (roomId: string) => { const onExpandClick = (roomId: string) => {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: roomId, room_id: roomId,
_trigger: "WebFloatingCallWindow",
}); });
}; };

View file

@ -36,6 +36,7 @@ import ActiveWidgetStore, { ActiveWidgetStoreEvent } from '../../../stores/Activ
import { UPDATE_EVENT } from '../../../stores/AsyncStore'; import { UPDATE_EVENT } from '../../../stores/AsyncStore';
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases'; import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
import RightPanelStore from '../../../stores/right-panel/RightPanelStore'; import RightPanelStore from '../../../stores/right-panel/RightPanelStore';
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
const SHOW_CALL_IN_STATES = [ const SHOW_CALL_IN_STATES = [
CallState.Connected, CallState.Connected,
@ -227,9 +228,10 @@ export default class PipView extends React.Component<IProps, IState> {
const callRoomId = this.state.primaryCall?.roomId; const callRoomId = this.state.primaryCall?.roomId;
const widgetRoomId = ActiveWidgetStore.instance.getRoomId(this.state.persistentWidgetId); const widgetRoomId = ActiveWidgetStore.instance.getRoomId(this.state.persistentWidgetId);
if (!!(callRoomId ?? widgetRoomId)) { if (!!(callRoomId ?? widgetRoomId)) {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: callRoomId ?? widgetRoomId, room_id: callRoomId ?? widgetRoomId,
_trigger: "WebFloatingCallWindow",
}); });
} }
}; };

View file

@ -46,6 +46,7 @@ import { makeSpaceParentEvent } from "./utils/space";
import { Action } from "./dispatcher/actions"; import { Action } from "./dispatcher/actions";
import ErrorDialog from "./components/views/dialogs/ErrorDialog"; import ErrorDialog from "./components/views/dialogs/ErrorDialog";
import Spinner from "./components/views/elements/Spinner"; import Spinner from "./components/views/elements/Spinner";
import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
// we define a number of interfaces which take their names from the js-sdk // we define a number of interfaces which take their names from the js-sdk
/* eslint-disable camelcase */ /* eslint-disable camelcase */
@ -257,7 +258,7 @@ export default async function createRoom(opts: IOpts): Promise<string | null> {
// state over multiple syncs so we can't atomically know when we have the // state over multiple syncs so we can't atomically know when we have the
// entire thing. // entire thing.
if (opts.andView) { if (opts.andView) {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: roomId, room_id: roomId,
should_peek: false, should_peek: false,
@ -266,6 +267,7 @@ export default async function createRoom(opts: IOpts): Promise<string | null> {
// stream, if it hasn't already. // stream, if it hasn't already.
joining: true, joining: true,
justCreatedOpts: opts, justCreatedOpts: opts,
_trigger: "Created",
}); });
} }
CountlyAnalytics.instance.trackRoomCreate(startTime, roomId); CountlyAnalytics.instance.trackRoomCreate(startTime, roomId);

View file

@ -93,7 +93,7 @@ export enum Action {
UpdateSystemFont = "update_system_font", UpdateSystemFont = "update_system_font",
/** /**
* Changes room based on payload parameters. * Changes room based on payload parameters. Should be used with JoinRoomPayload.
*/ */
ViewRoom = "view_room", ViewRoom = "view_room",

View file

@ -0,0 +1,54 @@
/*
Copyright 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.
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 { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { ViewRoom as ViewRoomEvent } from "matrix-analytics-events/types/typescript/ViewRoom";
import { ActionPayload } from "../payloads";
import { Action } from "../actions";
import { IOOBData, IThreepidInvite } from "../../stores/ThreepidInviteStore";
import { IOpts } from "../../createRoom";
/* eslint-disable camelcase */
export interface ViewRoomPayload extends Pick<ActionPayload, "action"> {
action: Action.ViewRoom;
// either of room_id or room_alias must be specified
room_id?: string;
room_alias?: string;
event_id?: string; // the event to ensure is in view if any
highlighted?: boolean; // whether to highlight `event_id`
should_peek?: boolean; // whether we should peek the room if we are not yet joined
joining?: boolean; // whether we have already sent a join request for this room
via_servers?: string[]; // the list of servers to join via if no room_alias is provided
context_switch?: boolean; // whether this view room was a consequence of switching spaces
replyingToEvent?: MatrixEvent; // the event we are replying to in this room if any
auto_join?: boolean; // whether to automatically join the room if we are not already
threepid_invite?: IThreepidInvite; // details about any 3pid invite we have to this room
justCreatedOpts?: IOpts; // if this is a newly created room then this is a reference to the creation opts
oob_data?: IOOBData; // any out-of-band data about this room can be used to render some room details without peeking
forceTimeline?: boolean; // Whether to override default behaviour to end up at a timeline
show_room_tile?: boolean; // Whether to ensure that the room tile is visible in the room list
clear_search?: boolean; // Whether to clear the room list search
deferred_action?: ActionPayload; // Action to fire after MatrixChat handles this ViewRoom action
// additional parameters for the purpose of metrics & instrumentation
_trigger: ViewRoomEvent["trigger"];
_viaKeyboard?: ViewRoomEvent["viaKeyboard"];
}
/* eslint-enable camelcase */

View file

@ -30,6 +30,7 @@ import {
import dis from './dispatcher/dispatcher'; import dis from './dispatcher/dispatcher';
import { Action } from './dispatcher/actions'; import { Action } from './dispatcher/actions';
import { ViewUserPayload } from './dispatcher/payloads/ViewUserPayload'; import { ViewUserPayload } from './dispatcher/payloads/ViewUserPayload';
import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
export enum Type { export enum Type {
URL = "url", URL = "url",
@ -116,9 +117,11 @@ function onUserClick(event: MouseEvent, userId: string) {
function onAliasClick(event: MouseEvent, roomAlias: string) { function onAliasClick(event: MouseEvent, roomAlias: string) {
event.preventDefault(); event.preventDefault();
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_alias: roomAlias, room_alias: roomAlias,
_trigger: "Timeline",
_viaKeyboard: false,
}); });
} }

View file

@ -31,6 +31,7 @@ import FlairStore from "./FlairStore";
import GroupFilterOrderStore from "./GroupFilterOrderStore"; import GroupFilterOrderStore from "./GroupFilterOrderStore";
import GroupStore from "./GroupStore"; import GroupStore from "./GroupStore";
import dis from "../dispatcher/dispatcher"; import dis from "../dispatcher/dispatcher";
import { ViewRoomPayload } from "../dispatcher/payloads/ViewRoomPayload";
interface IState { interface IState {
// nothing of value - we use account data // nothing of value - we use account data
@ -150,9 +151,10 @@ export class CommunityPrototypeStore extends AsyncStoreWithClient<IState> {
// Automatically select the general chat when switching communities // Automatically select the general chat when switching communities
const chat = this.getGeneralChat(payload.tag); const chat = this.getGeneralChat(payload.tag);
if (chat) { if (chat) {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: chat.roomId, room_id: chat.roomId,
_trigger: undefined, // Deprecated groups
}); });
} }
} }

View file

@ -20,6 +20,7 @@ import React, { ReactNode } from "react";
import { Store } from 'flux/utils'; import { Store } from 'flux/utils';
import { MatrixError } from "matrix-js-sdk/src/http-api"; import { MatrixError } from "matrix-js-sdk/src/http-api";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { ViewRoom as ViewRoomEvent } from "matrix-analytics-events/types/typescript/ViewRoom";
import dis from '../dispatcher/dispatcher'; import dis from '../dispatcher/dispatcher';
import { MatrixClientPeg } from '../MatrixClientPeg'; import { MatrixClientPeg } from '../MatrixClientPeg';
@ -30,8 +31,10 @@ import { getCachedRoomIDForAlias, storeRoomAliasInCache } from '../RoomAliasCach
import { ActionPayload } from "../dispatcher/payloads"; import { ActionPayload } from "../dispatcher/payloads";
import { Action } from "../dispatcher/actions"; import { Action } from "../dispatcher/actions";
import { retry } from "../utils/promise"; import { retry } from "../utils/promise";
import CountlyAnalytics from "../CountlyAnalytics"; import CountlyAnalytics, { IJoinRoomEvent } from "../CountlyAnalytics";
import { TimelineRenderingType } from "../contexts/RoomContext"; import { TimelineRenderingType } from "../contexts/RoomContext";
import { PosthogAnalytics } from "../PosthogAnalytics";
import { ViewRoomPayload } from "../dispatcher/payloads/ViewRoomPayload";
const NUM_JOIN_RETRY = 5; const NUM_JOIN_RETRY = 5;
@ -158,10 +161,11 @@ class RoomViewStore extends Store<ActionPayload> {
if (payload.context === TimelineRenderingType.Room) { if (payload.context === TimelineRenderingType.Room) {
if (payload.event if (payload.event
&& payload.event.getRoomId() !== this.state.roomId) { && payload.event.getRoomId() !== this.state.roomId) {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: payload.event.getRoomId(), room_id: payload.event.getRoomId(),
replyingToEvent: payload.event, replyingToEvent: payload.event,
_trigger: undefined, // room doesn't change
}); });
} else { } else {
this.setState({ this.setState({
@ -182,8 +186,16 @@ class RoomViewStore extends Store<ActionPayload> {
} }
} }
private async viewRoom(payload: ActionPayload) { private async viewRoom(payload: ViewRoomPayload): Promise<void> {
if (payload.room_id) { if (payload.room_id) {
if (payload._trigger !== null && payload.room_id !== this.state.roomId) {
PosthogAnalytics.instance.trackEvent<ViewRoomEvent>({
eventName: "ViewRoom",
trigger: payload._trigger,
viaKeyboard: payload._viaKeyboard,
});
}
const newState = { const newState = {
roomId: payload.room_id, roomId: payload.room_id,
roomAlias: payload.room_alias, roomAlias: payload.room_alias,
@ -204,7 +216,7 @@ class RoomViewStore extends Store<ActionPayload> {
}; };
// Allow being given an event to be replied to when switching rooms but sanity check its for this room // Allow being given an event to be replied to when switching rooms but sanity check its for this room
if (payload.replyingToEvent && payload.replyingToEvent.getRoomId() === payload.room_id) { if (payload.replyingToEvent?.getRoomId() === payload.room_id) {
newState.replyingToEvent = payload.replyingToEvent; newState.replyingToEvent = payload.replyingToEvent;
} }
@ -287,7 +299,20 @@ class RoomViewStore extends Store<ActionPayload> {
// if we received a Gateway timeout then retry // if we received a Gateway timeout then retry
return err.httpStatus === 504; return err.httpStatus === 504;
}); });
CountlyAnalytics.instance.trackRoomJoin(startTime, roomId, payload._type);
let type: IJoinRoomEvent["segmentation"]["type"] = undefined;
switch ((payload as ViewRoomPayload)._trigger) {
case "SlashCommand":
type = "slash_command";
break;
case "Tombstone":
type = "tombstone";
break;
case "RoomDirectory":
type = "room_directory";
break;
}
CountlyAnalytics.instance.trackRoomJoin(startTime, roomId, type);
// We do *not* clear the 'joining' flag because the Room object and/or our 'joined' member event may not // We do *not* clear the 'joining' flag because the Room object and/or our 'joined' member event may not
// have come down the sync stream yet, and that's the point at which we'd consider the user joined to the // have come down the sync stream yet, and that's the point at which we'd consider the user joined to the

View file

@ -54,6 +54,7 @@ import {
import { getCachedRoomIDForAlias } from "../../RoomAliasCache"; import { getCachedRoomIDForAlias } from "../../RoomAliasCache";
import { EffectiveMembership, getEffectiveMembership } from "../../utils/membership"; import { EffectiveMembership, getEffectiveMembership } from "../../utils/membership";
import { PosthogAnalytics } from "../../PosthogAnalytics"; import { PosthogAnalytics } from "../../PosthogAnalytics";
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
interface IState {} interface IState {}
@ -157,10 +158,11 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
if (space) { if (space) {
const roomId = this.getNotificationState(space).getFirstRoomWithNotifications(); const roomId = this.getNotificationState(space).getFirstRoomWithNotifications();
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: roomId, room_id: roomId,
context_switch: true, context_switch: true,
_trigger: "WebSpaceContextSwitch",
}); });
} else { } else {
const lists = RoomListStore.instance.unfilteredLists; const lists = RoomListStore.instance.unfilteredLists;
@ -174,10 +176,11 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
} }
}); });
if (unreadRoom) { if (unreadRoom) {
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: unreadRoom.roomId, room_id: unreadRoom.roomId,
context_switch: true, context_switch: true,
_trigger: "WebSpaceContextSwitch",
}); });
break; break;
} }
@ -222,16 +225,18 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
this.matrixClient.getRoom(roomId)?.getMyMembership() === "join" && this.matrixClient.getRoom(roomId)?.getMyMembership() === "join" &&
this.isRoomInSpace(space, roomId) this.isRoomInSpace(space, roomId)
) { ) {
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: roomId, room_id: roomId,
context_switch: true, context_switch: true,
_trigger: "WebSpaceContextSwitch",
}); });
} else if (cliSpace) { } else if (cliSpace) {
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: space, room_id: space,
context_switch: true, context_switch: true,
_trigger: "WebSpaceContextSwitch",
}); });
} else { } else {
defaultDispatcher.dispatch({ defaultDispatcher.dispatch({

View file

@ -59,6 +59,7 @@ import { ELEMENT_CLIENT_ID } from "../../identifiers";
import { getUserLanguage } from "../../languageHandler"; import { getUserLanguage } from "../../languageHandler";
import { WidgetVariableCustomisations } from "../../customisations/WidgetVariables"; import { WidgetVariableCustomisations } from "../../customisations/WidgetVariables";
import { arrayFastClone } from "../../utils/arrays"; import { arrayFastClone } from "../../utils/arrays";
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
// TODO: Destroy all of this code // TODO: Destroy all of this code
@ -293,9 +294,10 @@ export class StopGapWidget extends EventEmitter {
} }
// at this point we can change rooms, so do that // at this point we can change rooms, so do that
defaultDispatcher.dispatch({ defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: targetRoomId, room_id: targetRoomId,
_trigger: "Widget",
}); });
// acknowledge so the widget doesn't freak out // acknowledge so the widget doesn't freak out

View file

@ -29,6 +29,7 @@ import Spinner from "../components/views/elements/Spinner";
import { isMetaSpace } from "../stores/spaces"; import { isMetaSpace } from "../stores/spaces";
import SpaceStore from "../stores/spaces/SpaceStore"; import SpaceStore from "../stores/spaces/SpaceStore";
import { Action } from "../dispatcher/actions"; import { Action } from "../dispatcher/actions";
import { ViewRoomPayload } from "../dispatcher/payloads/ViewRoomPayload";
/** /**
* Approximation of a membership status for a given room. * Approximation of a membership status for a given room.
@ -187,9 +188,10 @@ export async function leaveRoomBehaviour(roomId: string, retry = true, spinner =
SpaceStore.instance.activeSpace !== roomId && SpaceStore.instance.activeSpace !== roomId &&
RoomViewStore.getRoomId() === roomId RoomViewStore.getRoomId() === roomId
) { ) {
dis.dispatch({ dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom, action: Action.ViewRoom,
room_id: SpaceStore.instance.activeSpace, room_id: SpaceStore.instance.activeSpace,
_trigger: undefined, // other
}); });
} else { } else {
dis.dispatch({ action: 'view_home_page' }); dis.dispatch({ action: 'view_home_page' });