More posthog tracking around joining rooms and room search (#7807)

This commit is contained in:
Michael Telatynski 2022-02-17 18:03:27 +00:00 committed by GitHub
parent e997676ae2
commit 658590e5bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
59 changed files with 276 additions and 116 deletions

View file

@ -91,7 +91,7 @@
"linkifyjs": "^4.0.0-beta.4",
"lodash": "^4.17.20",
"maplibre-gl": "^1.15.2",
"matrix-analytics-events": "github:matrix-org/matrix-analytics-events.git#df9c0312f51911a7364810466d041f2b79e7e080",
"matrix-analytics-events": "github:matrix-org/matrix-analytics-events.git#8e75aaf0b3e045587daeaf97a7691dbfda2f20c0",
"matrix-events-sdk": "^0.0.1-beta.6",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
"matrix-widget-api": "^0.1.0-beta.18",

View file

@ -189,7 +189,7 @@ export default abstract class BasePlatform {
const payload: ViewRoomPayload = {
action: Action.ViewRoom,
room_id: room.roomId,
_trigger: "Notification",
metricsTrigger: "Notification",
};
if (ev.getThread()) {

View file

@ -891,7 +891,7 @@ export default class CallHandler extends EventEmitter {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: roomId,
_trigger: "WebAcceptCall",
metricsTrigger: "WebAcceptCall",
});
}
@ -929,7 +929,7 @@ export default class CallHandler extends EventEmitter {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: roomId,
_trigger: "WebDialPad",
metricsTrigger: "WebDialPad",
});
await this.placeMatrixCall(roomId, CallType.Voice, null);
@ -962,7 +962,7 @@ export default class CallHandler extends EventEmitter {
room_id: dmRoomId,
should_peek: false,
joining: false,
_trigger: undefined, // other
metricsTrigger: undefined, // other
});
} else {
try {

View file

@ -350,8 +350,8 @@ export const Commands = [
event_id: eventId,
highlighted: true,
room_id: roomId,
_trigger: "SlashCommand",
_viaKeyboard: true,
metricsTrigger: "SlashCommand",
metricsViaKeyboard: true,
});
})());
}
@ -615,8 +615,8 @@ export const Commands = [
action: Action.ViewRoom,
room_alias: roomAlias,
auto_join: true,
_trigger: "SlashCommand",
_viaKeyboard: true,
metricsTrigger: "SlashCommand",
metricsViaKeyboard: true,
});
return success();
} else if (params[0][0] === '!') {
@ -627,8 +627,8 @@ export const Commands = [
room_id: roomId,
via_servers: viaServers, // for the rejoin button
auto_join: true,
_trigger: "SlashCommand",
_viaKeyboard: true,
metricsTrigger: "SlashCommand",
metricsViaKeyboard: true,
});
return success();
} else if (isPermalink) {
@ -653,8 +653,8 @@ export const Commands = [
const dispatch: ViewRoomPayload = {
action: Action.ViewRoom,
auto_join: true,
_trigger: "SlashCommand",
_viaKeyboard: true,
metricsTrigger: "SlashCommand",
metricsViaKeyboard: true,
};
if (entity[0] === '!') dispatch["room_id"] = entity;
@ -1155,8 +1155,8 @@ export const Commands = [
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: roomId,
_trigger: "SlashCommand",
_viaKeyboard: true,
metricsTrigger: "SlashCommand",
metricsViaKeyboard: true,
});
})());
},
@ -1179,8 +1179,8 @@ export const Commands = [
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: roomId,
_trigger: "SlashCommand",
_viaKeyboard: true,
metricsTrigger: "SlashCommand",
metricsViaKeyboard: true,
});
if (msg) {
cli.sendTextMessage(roomId, msg);

View file

@ -535,7 +535,7 @@ const onPinnedOrUnpinnedMessageClick = (messageId: string, roomId: string): void
event_id: messageId,
highlighted: true,
room_id: roomId,
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
};

View file

@ -1084,7 +1084,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: dmRooms[0],
_trigger: "MessageUser",
metricsTrigger: "MessageUser",
});
} else {
dis.dispatch({
@ -1356,7 +1356,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: localStorage.getItem('mx_last_room_id'),
_trigger: undefined, // other
metricsTrigger: undefined, // other
});
}
@ -1797,7 +1797,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
},
room_alias: undefined,
room_id: undefined,
_trigger: undefined, // unknown or external trigger
metricsTrigger: undefined, // unknown or external trigger
};
if (roomString[0] === '#') {
payload.room_alias = roomString;

View file

@ -489,7 +489,7 @@ export default class RoomDirectory extends React.Component<IProps, IState> {
action: Action.ViewRoom,
auto_join: autoJoin,
should_peek: shouldPeek,
_trigger: "RoomDirectory",
metricsTrigger: "RoomDirectory",
};
if (room) {
// Don't let the user view a room they won't be able to either

View file

@ -102,6 +102,7 @@ import { RightPanelPhases } from '../../stores/right-panel/RightPanelStorePhases
import { ActionPayload } from "../../dispatcher/payloads";
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
import { JoinRoomPayload } from "../../dispatcher/payloads/JoinRoomPayload";
const DEBUG = false;
let debuglog = function(msg: string) {};
@ -776,7 +777,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
event_id: this.state.initialEventId,
highlighted: false,
replyingToEvent: this.state.replyToEvent,
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
}
};
@ -879,7 +880,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
action: Action.ViewRoom,
room_id: roomId,
deferred_action: payload,
_trigger: "MessageSearch",
metricsTrigger: "MessageSearch",
});
});
}
@ -1179,7 +1180,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: this.state.room.roomId,
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
return; // this event cannot affect permissions so bail
}
@ -1283,10 +1284,11 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} else {
Promise.resolve().then(() => {
const signUrl = this.props.threepidInvite?.signUrl;
dis.dispatch({
dis.dispatch<JoinRoomPayload>({
action: Action.JoinRoom,
roomId: this.getRoomId(),
opts: { inviteSignUrl: signUrl },
metricsTrigger: this.state.room?.getMyMembership() === "invite" ? "Invite" : "RoomPreview",
});
return Promise.resolve();
});
@ -1651,7 +1653,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: this.state.room.roomId,
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
} else {
// Otherwise we have to jump manually
@ -1787,7 +1789,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: oldRoom.roomId,
_trigger: "Predecessor",
metricsTrigger: "Predecessor",
});
};

View file

@ -63,6 +63,7 @@ import { IOOBData } from "../../stores/ThreepidInviteStore";
import { awaitRoomDownSync } from "../../utils/RoomUpgrade";
import RoomViewStore from "../../stores/RoomViewStore";
import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
import { JoinRoomReadyPayload } from "../../dispatcher/payloads/JoinRoomReadyPayload";
interface IProps {
space: Room;
@ -339,7 +340,7 @@ export const showRoom = (cli: MatrixClient, hierarchy: RoomHierarchy, roomId: st
name: room.name || roomAlias || _t("Unnamed room"),
roomType,
} as IOOBData,
_trigger: "RoomDirectory",
metricsTrigger: "RoomDirectory",
});
};
@ -355,7 +356,13 @@ export const joinRoom = (cli: MatrixClient, hierarchy: RoomHierarchy, roomId: st
viaServers: Array.from(hierarchy.viaMap.get(roomId) || []),
});
prom.catch(err => {
prom.then(() => {
dis.dispatch<JoinRoomReadyPayload>({
action: Action.JoinRoomReady,
roomId,
metricsTrigger: "SpaceHierarchy",
});
}, err => {
RoomViewStore.showJoinRoomError(err, roomId);
});

View file

@ -867,7 +867,7 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: this.state.firstRoomId,
_trigger: undefined, // other
metricsTrigger: undefined, // other
});
return;
}

View file

@ -202,7 +202,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
event_id: this.props.initialEvent?.getId(),
highlighted: false,
replyingToEvent: this.state.replyToEvent,
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
}
};

View file

@ -1195,7 +1195,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: this.props.timelineSet.room.roomId,
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
};
}

View file

@ -269,7 +269,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
event_id: this.props.mxEvent.getId(),
highlighted: true,
room_id: this.props.mxEvent.getRoomId(),
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
this.closeMenu();
};

View file

@ -253,8 +253,8 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: room.roomId,
_trigger: "RoomList",
_viaKeyboard: ev.type !== "click",
metricsTrigger: "RoomList",
metricsViaKeyboard: ev.type !== "click",
}, true);
};

View file

@ -120,7 +120,7 @@ const SpaceContextMenu = ({ space, hideHeader, onFinished, ...props }: IProps) =
action: Action.ViewRoom,
room_id: space.roomId,
forceTimeline: true,
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
onFinished();
};
@ -197,7 +197,7 @@ const SpaceContextMenu = ({ space, hideHeader, onFinished, ...props }: IProps) =
defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: space.roomId,
_trigger: undefined, // other
metricsTrigger: undefined, // other
});
onFinished();
};

View file

@ -81,7 +81,7 @@ const ThreadListContextMenu: React.FC<IExtendedProps> = ({
event_id: mxEvent.getId(),
highlighted: true,
room_id: mxEvent.getRoomId(),
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
closeThreadOptions();
}, [mxEvent, closeThreadOptions]);

View file

@ -104,7 +104,7 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent<
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: result.room_id,
_trigger: undefined, // Deprecated groups
metricsTrigger: undefined, // Deprecated groups
});
showCommunityRoomInviteDialog(result.room_id, this.state.name);
} else {

View file

@ -230,7 +230,7 @@ const CreateSpaceFromCommunityDialog: React.FC<IProps> = ({ matrixClient: cli, g
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: roomId,
_trigger: undefined, // other
metricsTrigger: undefined, // other
});
};

View file

@ -81,8 +81,8 @@ const Entry: React.FC<IEntryProps> = ({ room, event, matrixClient: cli, onFinish
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: room.roomId,
_trigger: "WebForwardShortcut",
_viaKeyboard: ev.type !== "click",
metricsTrigger: "WebForwardShortcut",
metricsViaKeyboard: ev.type !== "click",
});
onFinished(true);
};

View file

@ -682,7 +682,7 @@ export default class InviteDialog extends React.PureComponent<IInviteDialogProps
room_id: existingRoom.roomId,
should_peek: false,
joining: false,
_trigger: "MessageUser",
metricsTrigger: "MessageUser",
});
this.props.onFinished(true);
return;

View file

@ -94,6 +94,7 @@ export default class RoomSettingsDialog extends React.Component<IProps, IState>
_td("General"),
"mx_RoomSettingsDialog_settingsIcon",
<GeneralRoomSettingsTab roomId={this.props.roomId} />,
"RoomSettingsGeneral",
));
tabs.push(new Tab(
ROOM_SECURITY_TAB,
@ -103,18 +104,21 @@ export default class RoomSettingsDialog extends React.Component<IProps, IState>
roomId={this.props.roomId}
closeSettingsFn={() => this.props.onFinished(true)}
/>,
"RoomSettingsSecurityPrivacy",
));
tabs.push(new Tab(
ROOM_ROLES_TAB,
_td("Roles & Permissions"),
"mx_RoomSettingsDialog_rolesIcon",
<RolesRoomSettingsTab roomId={this.props.roomId} />,
"RoomSettingsRolesPermissions",
));
tabs.push(new Tab(
ROOM_NOTIFICATIONS_TAB,
_td("Notifications"),
"mx_RoomSettingsDialog_notificationsIcon",
<NotificationSettingsTab roomId={this.props.roomId} closeSettingsFn={() => this.props.onFinished(true)} />,
"RoomSettingsNotifications",
));
if (SettingsStore.getValue("feature_bridge_state")) {
@ -123,6 +127,7 @@ export default class RoomSettingsDialog extends React.Component<IProps, IState>
_td("Bridges"),
"mx_RoomSettingsDialog_bridgesIcon",
<BridgeSettingsTab roomId={this.props.roomId} />,
"RoomSettingsBridges",
));
}
@ -135,6 +140,7 @@ export default class RoomSettingsDialog extends React.Component<IProps, IState>
roomId={this.props.roomId}
closeSettingsFn={() => this.props.onFinished(true)}
/>,
"RoomSettingsAdvanced",
));
}

View file

@ -30,6 +30,7 @@ import { normalize } from "matrix-js-sdk/src/utils";
import { IHierarchyRoom } from "matrix-js-sdk/src/@types/spaces";
import { RoomHierarchy } from "matrix-js-sdk/src/room-hierarchy";
import { RoomType } from "matrix-js-sdk/src/@types/event";
import { WebSearch as WebSearchEvent } from "matrix-analytics-events/types/typescript/WebSearch";
import { IDialogProps } from "./IDialogProps";
import { _t } from "../../../languageHandler";
@ -72,6 +73,7 @@ import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { getMetaSpaceName } from "../../../stores/spaces";
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
import { PosthogAnalytics } from "../../../PosthogAnalytics";
import { getCachedRoomIDForAlias } from "../../../RoomAliasCache";
const MAX_RECENT_SEARCHES = 10;
@ -205,6 +207,26 @@ type Result = IRoomResult | IResult;
const isRoomResult = (result: any): result is IRoomResult => !!result?.room;
export const useWebSearchMetrics = (numResults: number, queryLength: number, viaSpotlight: boolean): void => {
useEffect(() => {
if (!queryLength) return;
// send metrics after a 1s debounce
const timeoutId = setTimeout(() => {
PosthogAnalytics.instance.trackEvent<WebSearchEvent>({
eventName: "WebSearch",
viaSpotlight,
numResults,
queryLength,
});
}, 1000);
return () => {
clearTimeout(timeoutId);
};
}, [numResults, queryLength, viaSpotlight]);
};
const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) => {
const cli = MatrixClientPeg.get();
const rovingContext = useContext(RovingTabIndexContext);
@ -270,6 +292,9 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
return results;
}, [possibleResults, trimmedQuery]);
const numResults = trimmedQuery ? people.length + rooms.length + spaces.length : 0;
useWebSearchMetrics(numResults, query.length, true);
const activeSpace = SpaceStore.instance.activeSpaceRoom;
const [spaceResults, spaceResultsLoading] = useSpaceResults(activeSpace, query);
@ -310,8 +335,8 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: roomId,
_trigger: "WebUnifiedSearch",
_viaKeyboard: viaKeyboard,
metricsTrigger: "WebUnifiedSearch",
metricsViaKeyboard: viaKeyboard,
});
onFinished();
};
@ -429,8 +454,8 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
action: Action.ViewRoom,
room_alias: trimmedQuery,
auto_join: true,
_trigger: "WebUnifiedSearch",
_viaKeyboard: ev.type !== "click",
metricsTrigger: "WebUnifiedSearch",
metricsViaKeyboard: ev.type !== "click",
});
onFinished();
}}
@ -670,6 +695,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", onFinished }) =>
onFinished={onFinished}
hasCancel={false}
onKeyDown={onDialogKeyDown}
screenName="UnifiedSearch"
>
<div className="mx_SpotlightDialog_searchBox mx_textinput">
<input

View file

@ -199,7 +199,11 @@ export default class UserSettingsDialog extends React.Component<IProps, IState>
title={_t("Settings")}
>
<div className='mx_SettingsDialog_content'>
<TabbedView tabs={this.getTabs()} initialTabId={this.props.initialTabId} />
<TabbedView
tabs={this.getTabs()}
initialTabId={this.props.initialTabId}
screenName="UserSettings"
/>
</div>
</BaseDialog>
);

View file

@ -339,7 +339,7 @@ export default class ImageView extends React.Component<IProps, IState> {
event_id: this.props.mxEvent.getId(),
highlighted: true,
room_id: this.props.mxEvent.getRoomId(),
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
this.props.onFinished();
};

View file

@ -147,7 +147,7 @@ export default class DateSeparator extends React.Component<IProps, IState> {
event_id: eventId,
highlighted: true,
room_id: roomId,
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
} catch (e) {
const code = e.errcode || e.statusCode;

View file

@ -45,8 +45,8 @@ export default class RoomCreate extends React.Component<IProps> {
event_id: predecessor['event_id'],
highlighted: true,
room_id: predecessor['room_id'],
_trigger: "Predecessor",
_viaKeyboard: e.type !== "click",
metricsTrigger: "Predecessor",
metricsViaKeyboard: e.type !== "click",
});
};

View file

@ -151,7 +151,7 @@ export default class TimelineCard extends React.Component<IProps, IState> {
event_id: this.state.initialEventId,
highlighted: false,
replyingToEvent: this.state.replyToEvent,
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
}
};

View file

@ -131,8 +131,8 @@ async function openDMForUser(matrixClient: MatrixClient, userId: string, viaKeyb
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: lastActiveRoom.roomId,
_trigger: "MessageUser",
_viaKeyboard: viaKeyboard,
metricsTrigger: "MessageUser",
metricsViaKeyboard: viaKeyboard,
});
return;
}
@ -397,7 +397,7 @@ const UserOptionsSection: React.FC<{
highlighted: true,
event_id: room.getEventReadUpTo(member.userId),
room_id: member.roomId,
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
};

View file

@ -720,7 +720,7 @@ export default class EventTile extends React.Component<IProps, IState> {
event_id: this.props.mxEvent.getId(),
highlighted: true,
room_id: this.props.mxEvent.getRoomId(),
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
};
@ -1023,7 +1023,9 @@ export default class EventTile extends React.Component<IProps, IState> {
event_id: this.props.mxEvent.getId(),
highlighted: true,
room_id: this.props.mxEvent.getRoomId(),
_trigger: this.props.timelineRenderingType === TimelineRenderingType.Search ? "MessageSearch" : undefined,
metricsTrigger: this.props.timelineRenderingType === TimelineRenderingType.Search
? "MessageSearch"
: undefined,
});
};

View file

@ -237,8 +237,8 @@ export default class MessageComposer extends React.Component<IProps, IState> {
// 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").
via_servers: viaServers,
_trigger: "Tombstone",
_viaKeyboard: ev.type !== "click",
metricsTrigger: "Tombstone",
metricsViaKeyboard: ev.type !== "click",
});
};

View file

@ -51,7 +51,7 @@ export default class PinnedEventTile extends React.Component<IProps> {
event_id: this.props.event.getId(),
highlighted: true,
room_id: this.props.event.getRoomId(),
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
};

View file

@ -44,8 +44,8 @@ const RecentlyViewedButton = () => {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: crumb.roomId,
_trigger: "WebVerticalBreadcrumbs",
_viaKeyboard: ev.type !== "click",
metricsTrigger: "WebVerticalBreadcrumbs",
metricsViaKeyboard: ev.type !== "click",
});
tooltipRef.current?.hideTooltip();
}}

View file

@ -100,7 +100,7 @@ export default class ReplyTile extends React.PureComponent<IProps> {
event_id: this.props.mxEvent.getId(),
highlighted: true,
room_id: this.props.mxEvent.getRoomId(),
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
}
}

View file

@ -110,8 +110,8 @@ export default class RoomBreadcrumbs extends React.PureComponent<IProps, IState>
defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: room.roomId,
_trigger: "WebHorizontalBreadcrumbs",
_viaKeyboard: viaKeyboard,
metricsTrigger: "WebHorizontalBreadcrumbs",
metricsViaKeyboard: viaKeyboard,
});
};

View file

@ -44,7 +44,7 @@ export default class RoomDetailList extends React.Component<IProps> {
action: Action.ViewRoom,
room_id: room.roomId,
room_alias: room.getCanonicalAlias() || (room.getAltAliases() || [])[0],
_trigger: undefined, // Deprecated groups
metricsTrigger: undefined, // Deprecated groups
});
};

View file

@ -221,7 +221,7 @@ const UntaggedAuxButton = ({ tabIndex }: IAuxButtonProps) => {
defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: activeSpace.roomId,
_trigger: undefined, // other
metricsTrigger: undefined, // other
});
PosthogTrackers.trackInteraction("WebRoomListRoomsSublistPlusMenuExploreRoomsItem", e);
}}
@ -424,8 +424,8 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
action: Action.ViewRoom,
room_id: room.roomId,
show_room_tile: true, // to make sure the room gets scrolled into view
_trigger: "WebKeyboardShortcut",
_viaKeyboard: true,
metricsTrigger: "WebKeyboardShortcut",
metricsViaKeyboard: true,
});
}
} else if (payload.action === Action.PstnSupportUpdated) {
@ -509,7 +509,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: this.props.activeSpace,
_trigger: undefined, // other
metricsTrigger: undefined, // other
});
PosthogTrackers.trackInteraction("WebRoomListRoomsSublistPlusMenuExploreRoomsItem", ev);
} else {
@ -542,8 +542,8 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
avatarUrl: room.avatar_url,
name,
},
_trigger: "RoomList",
_viaKeyboard: ev.type !== "click",
metricsTrigger: "RoomList",
metricsViaKeyboard: ev.type !== "click",
});
};
return (

View file

@ -61,6 +61,7 @@ import TooltipTarget from "../elements/TooltipTarget";
import { BetaPill } from "../beta/BetaCard";
import PosthogTrackers from "../../../PosthogTrackers";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { useWebSearchMetrics } from "../dialogs/SpotlightDialog";
const contextMenuBelow = (elementRect: DOMRect) => {
// align the context menu's icons with the icon which opened the context menu
@ -108,7 +109,7 @@ const PrototypeCommunityContextMenu = (props: ComponentProps<typeof SpaceContext
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: chat.roomId,
_trigger: undefined, // Deprecated groups
metricsTrigger: undefined, // Deprecated groups
}, true);
RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomMemberList }, undefined, chat.roomId);
} else {
@ -177,14 +178,18 @@ const RoomListHeader = ({ spacePanelDisabled, onVisibilityChange }: IProps) => {
});
const joiningRooms = useJoiningRooms();
const filterCondition = RoomListStore.instance.getFirstNameFilterCondition();
const count = useEventEmitterState(RoomListStore.instance, LISTS_UPDATE_EVENT, () => {
if (RoomListStore.instance.getFirstNameFilterCondition()) {
if (filterCondition) {
return Object.values(RoomListStore.instance.orderedLists).flat(1).length;
} else {
return null;
}
});
// we pass null for the queryLength to inhibit the metrics hook for when there is no filterCondition
useWebSearchMetrics(count, filterCondition ? filterCondition.search.length : null, false);
const spaceName = useEventEmitterState(activeSpace, "Room.name", () => activeSpace?.name);
useEffect(() => {
@ -279,7 +284,7 @@ const RoomListHeader = ({ spacePanelDisabled, onVisibilityChange }: IProps) => {
defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: activeSpace.roomId,
_trigger: undefined, // other
metricsTrigger: undefined, // other
});
closePlusMenu();
PosthogTrackers.trackInteraction("WebRoomListHeaderPlusMenuExploreRoomsItem", e);

View file

@ -433,8 +433,8 @@ export default class RoomSublist extends React.Component<IProps, IState> {
action: Action.ViewRoom,
room_id: room.roomId,
show_room_tile: true, // to make sure the room gets scrolled into view
_trigger: "WebRoomListNotificationBadge",
_viaKeyboard: ev.type !== "click",
metricsTrigger: "WebRoomListNotificationBadge",
metricsViaKeyboard: ev.type !== "click",
});
}
};

View file

@ -245,8 +245,8 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
show_room_tile: true, // make sure the room is visible in the list
room_id: this.props.room.roomId,
clear_search: (ev && (ev.key === Key.ENTER || ev.key === Key.SPACE)),
_trigger: "RoomList",
_viaKeyboard: ev.type !== "click",
metricsTrigger: "RoomList",
metricsViaKeyboard: ev.type !== "click",
});
};

View file

@ -271,7 +271,7 @@ const JoinRuleSettings = ({ room, promptUpgrade, aliasWarning, onError, beforeCh
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: roomId,
_trigger: undefined, // other
metricsTrigger: undefined, // other
});
// open new settings on this tab

View file

@ -95,8 +95,8 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
action: Action.ViewRoom,
room_id: this.state.oldRoomId,
event_id: this.state.oldEventId,
_trigger: "WebPredecessorSettings",
_viaKeyboard: e.type !== "click",
metricsTrigger: "WebPredecessorSettings",
metricsViaKeyboard: e.type !== "click",
});
this.props.closeSettingsFn();
};

View file

@ -117,7 +117,7 @@ const CommunityMigrator = ({ onFinished }) => {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: community.spaceId,
_trigger: undefined, // other
metricsTrigger: undefined, // other
});
onFinished();
} else {

View file

@ -115,7 +115,7 @@ export default class VerificationRequestToast extends React.PureComponent<IProps
action: Action.ViewRoom,
room_id: request.channel.roomId,
should_peek: false,
_trigger: "VerificationRequest",
metricsTrigger: "VerificationRequest",
});
const member = cli.getUser(request.otherUserId);
RightPanelStore.instance.setCards(

View file

@ -41,7 +41,7 @@ const onExpandClick = (roomId: string) => {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: roomId,
_trigger: "WebFloatingCallWindow",
metricsTrigger: "WebFloatingCallWindow",
});
};

View file

@ -218,7 +218,7 @@ export default class PipView extends React.Component<IProps, IState> {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: callRoomId ?? widgetRoomId,
_trigger: "WebFloatingCallWindow",
metricsTrigger: "WebFloatingCallWindow",
});
}
};

View file

@ -264,7 +264,7 @@ export default async function createRoom(opts: IOpts): Promise<string | null> {
// stream, if it hasn't already.
joining: true,
justCreatedOpts: opts,
_trigger: "Created",
metricsTrigger: "Created",
});
}
return roomId;

View file

@ -153,12 +153,12 @@ export enum Action {
UploadCanceled = "upload_canceled",
/**
* Fired when requesting to join a room
* Fired when requesting to join a room. Should be used with JoinRoomPayload.
*/
JoinRoom = "join_room",
/**
* Fired when successfully joining a room
* Fired when successfully joining a room. Should be used with a JoinRoomReadyPayload.
*/
JoinRoomReady = "join_room_ready",
@ -168,7 +168,7 @@ export enum Action {
JoinRoomError = "join_room_error",
/**
* Inserts content into the active composer. Should be used with ComposerInsertPayload
* Inserts content into the active composer. Should be used with ComposerInsertPayload.
*/
ComposerInsert = "composer_insert",

View file

@ -0,0 +1,33 @@
/*
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 { JoinedRoom as JoinedRoomEvent } from "matrix-analytics-events/types/typescript/JoinedRoom";
import { IJoinRoomOpts } from "matrix-js-sdk/src/@types/requests";
import { ActionPayload } from "../payloads";
import { Action } from "../actions";
/* eslint-disable camelcase */
export interface JoinRoomPayload extends Pick<ActionPayload, "action"> {
action: Action.JoinRoom;
roomId: string;
opts?: IJoinRoomOpts;
// additional parameters for the purpose of metrics & instrumentation
metricsTrigger: JoinedRoomEvent["trigger"];
}
/* eslint-enable camelcase */

View file

@ -0,0 +1,30 @@
/*
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 { JoinedRoom as JoinedRoomEvent } from "matrix-analytics-events/types/typescript/JoinedRoom";
import { ActionPayload } from "../payloads";
import { Action } from "../actions";
/* eslint-disable camelcase */
export interface JoinRoomReadyPayload extends Pick<ActionPayload, "action"> {
action: Action.JoinRoomReady;
roomId: string;
// additional parameters for the purpose of metrics & instrumentation
metricsTrigger: JoinedRoomEvent["trigger"];
}
/* eslint-enable camelcase */

View file

@ -48,7 +48,7 @@ export interface ViewRoomPayload extends Pick<ActionPayload, "action"> {
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"];
metricsTrigger: ViewRoomEvent["trigger"];
metricsViaKeyboard?: ViewRoomEvent["viaKeyboard"];
}
/* eslint-enable camelcase */

View file

@ -120,8 +120,8 @@ function onAliasClick(event: MouseEvent, roomAlias: string) {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_alias: roomAlias,
_trigger: "Timeline",
_viaKeyboard: false,
metricsTrigger: "Timeline",
metricsViaKeyboard: false,
});
}

View file

@ -154,7 +154,7 @@ export class CommunityPrototypeStore extends AsyncStoreWithClient<IState> {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: chat.roomId,
_trigger: undefined, // Deprecated groups
metricsTrigger: undefined, // Deprecated groups
});
}
}

View file

@ -21,7 +21,9 @@ import { Store } from 'flux/utils';
import { MatrixError } from "matrix-js-sdk/src/http-api";
import { logger } from "matrix-js-sdk/src/logger";
import { ViewRoom as ViewRoomEvent } from "matrix-analytics-events/types/typescript/ViewRoom";
import { JoinedRoom as JoinedRoomEvent } from "matrix-analytics-events/types/typescript/JoinedRoom";
import { JoinRule } from "matrix-js-sdk/src/@types/partials";
import { Room } from "matrix-js-sdk/src/models/room";
import dis from '../dispatcher/dispatcher';
import { MatrixClientPeg } from '../MatrixClientPeg';
@ -38,6 +40,8 @@ import { ViewRoomPayload } from "../dispatcher/payloads/ViewRoomPayload";
import DMRoomMap from "../utils/DMRoomMap";
import SpaceStore from "./spaces/SpaceStore";
import { isMetaSpace, MetaSpace } from "./spaces";
import { JoinRoomPayload } from "../dispatcher/payloads/JoinRoomPayload";
import { JoinRoomReadyPayload } from "../dispatcher/payloads/JoinRoomReadyPayload";
const NUM_JOIN_RETRY = 5;
@ -149,11 +153,42 @@ class RoomViewStore extends Store<ActionPayload> {
case Action.JoinRoomError:
this.joinRoomError(payload);
break;
case Action.JoinRoomReady:
case Action.JoinRoomReady: {
if (this.state.roomId === payload.roomId) {
this.setState({ shouldPeek: false });
}
const cli = MatrixClientPeg.get();
const updateMetrics = () => {
const room = cli.getRoom(payload.roomId);
const numMembers = room.getJoinedMemberCount();
const roomSize = numMembers > 1000 ? "MoreThanAThousand"
: numMembers > 100 ? "OneHundredAndOneToAThousand"
: numMembers > 10 ? "ElevenToOneHundred"
: numMembers > 2 ? "ThreeToTen"
: numMembers > 1 ? "Two"
: "One";
PosthogAnalytics.instance.trackEvent<JoinedRoomEvent>({
eventName: "JoinedRoom",
trigger: payload.metricsTrigger,
roomSize,
isDM: !!DMRoomMap.shared().getUserIdForRoomId(room.roomId),
isSpace: room.isSpaceRoom(),
});
cli.off("Room", updateMetrics);
};
if (cli.getRoom(payload.roomId)) {
updateMetrics();
} else {
cli.on("Room", updateMetrics);
}
break;
}
case 'on_client_not_viable':
case 'on_logged_out':
this.reset();
@ -168,7 +203,7 @@ class RoomViewStore extends Store<ActionPayload> {
action: Action.ViewRoom,
room_id: payload.event.getRoomId(),
replyingToEvent: payload.event,
_trigger: undefined, // room doesn't change
metricsTrigger: undefined, // room doesn't change
});
} else {
this.setState({
@ -191,7 +226,7 @@ class RoomViewStore extends Store<ActionPayload> {
private async viewRoom(payload: ViewRoomPayload): Promise<void> {
if (payload.room_id) {
if (payload._trigger !== null && payload.room_id !== this.state.roomId) {
if (payload.metricsTrigger !== null && payload.room_id !== this.state.roomId) {
let activeSpace: ViewRoomEvent["activeSpace"];
if (SpaceStore.instance.activeSpace === MetaSpace.Home) {
activeSpace = "Home";
@ -205,8 +240,8 @@ class RoomViewStore extends Store<ActionPayload> {
PosthogAnalytics.instance.trackEvent<ViewRoomEvent>({
eventName: "ViewRoom",
trigger: payload._trigger,
viaKeyboard: payload._viaKeyboard,
trigger: payload.metricsTrigger,
viaKeyboard: payload.metricsViaKeyboard,
isDM: !!DMRoomMap.shared().getUserIdForRoomId(payload.room_id),
isSpace: MatrixClientPeg.get().getRoom(payload.room_id)?.isSpaceRoom(),
activeSpace,
@ -240,10 +275,11 @@ class RoomViewStore extends Store<ActionPayload> {
this.setState(newState);
if (payload.auto_join) {
dis.dispatch({
dis.dispatch<JoinRoomPayload>({
...payload,
action: Action.JoinRoom,
roomId: payload.room_id,
metricsTrigger: payload.metricsTrigger as JoinRoomPayload["metricsTrigger"],
});
}
} else if (payload.room_alias) {
@ -297,7 +333,7 @@ class RoomViewStore extends Store<ActionPayload> {
});
}
private async joinRoom(payload: ActionPayload) {
private async joinRoom(payload: JoinRoomPayload) {
this.setState({
joining: true,
});
@ -308,9 +344,9 @@ class RoomViewStore extends Store<ActionPayload> {
const address = roomAlias || roomId;
const viaServers = this.state.viaServers || [];
try {
await retry<any, MatrixError>(() => cli.joinRoom(address, {
await retry<Room, MatrixError>(() => cli.joinRoom(address, {
viaServers,
...payload.opts,
...(payload.opts || {}),
}), NUM_JOIN_RETRY, (err) => {
// if we received a Gateway timeout then retry
return err.httpStatus === 504;
@ -319,9 +355,10 @@ class RoomViewStore extends Store<ActionPayload> {
// 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
// room.
dis.dispatch({
dis.dispatch<JoinRoomReadyPayload>({
action: Action.JoinRoomReady,
roomId,
metricsTrigger: payload.metricsTrigger,
});
} catch (err) {
dis.dispatch({

View file

@ -161,7 +161,8 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: roomId,
_trigger: "WebSpacePanelNotificationBadge",
context_switch: true,
metricsTrigger: "WebSpacePanelNotificationBadge",
});
} else {
const lists = RoomListStore.instance.unfilteredLists;
@ -178,7 +179,8 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: unreadRoom.roomId,
_trigger: "WebSpacePanelNotificationBadge",
context_switch: true,
metricsTrigger: "WebSpacePanelNotificationBadge",
});
break;
}
@ -227,14 +229,14 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
action: Action.ViewRoom,
room_id: roomId,
context_switch: true,
_trigger: "WebSpaceContextSwitch",
metricsTrigger: "WebSpaceContextSwitch",
});
} else if (cliSpace) {
defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: space,
context_switch: true,
_trigger: "WebSpaceContextSwitch",
metricsTrigger: "WebSpaceContextSwitch",
});
} else {
defaultDispatcher.dispatch({

View file

@ -296,7 +296,7 @@ export class StopGapWidget extends EventEmitter {
defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: targetRoomId,
_trigger: "Widget",
metricsTrigger: "Widget",
});
// acknowledge so the widget doesn't freak out

View file

@ -191,7 +191,7 @@ export async function leaveRoomBehaviour(roomId: string, retry = true, spinner =
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: SpaceStore.instance.activeSpace,
_trigger: undefined, // other
metricsTrigger: undefined, // other
});
} else {
dis.dispatch({ action: 'view_home_page' });

View file

@ -28,7 +28,11 @@ export async function timeout<T, Y>(promise: Promise<T>, timeoutValue: Y, ms: nu
}
// Helper method to retry a Promise a given number of times or until a predicate fails
export async function retry<T, E extends Error>(fn: () => Promise<T>, num: number, predicate?: (e: E) => boolean) {
export async function retry<T, E extends Error>(
fn: () => Promise<T>,
num: number,
predicate?: (e: E) => boolean,
): Promise<T> {
let lastErr: E;
for (let i = 0; i < num; i++) {
try {

View file

@ -38,6 +38,8 @@ describe('RoomViewStore', function() {
beforeEach(function() {
testUtils.stubClient();
peg.get().credentials = { userId: "@test:example.com" };
peg.get().on = jest.fn();
peg.get().off = jest.fn();
// Reset the state of the store
RoomViewStore.reset();

View file

@ -6249,9 +6249,9 @@ mathml-tag-names@^2.1.3:
resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3"
integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==
"matrix-analytics-events@github:matrix-org/matrix-analytics-events.git#df9c0312f51911a7364810466d041f2b79e7e080":
"matrix-analytics-events@github:matrix-org/matrix-analytics-events.git#8e75aaf0b3e045587daeaf97a7691dbfda2f20c0":
version "0.0.1"
resolved "https://codeload.github.com/matrix-org/matrix-analytics-events/tar.gz/df9c0312f51911a7364810466d041f2b79e7e080"
resolved "https://codeload.github.com/matrix-org/matrix-analytics-events/tar.gz/8e75aaf0b3e045587daeaf97a7691dbfda2f20c0"
matrix-events-sdk@^0.0.1-beta.6:
version "0.0.1-beta.6"