Wire up bunch of interaction events into Posthog (#7707)
parent
5620b83d34
commit
999e1b7421
|
@ -14,8 +14,9 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { PureComponent } from "react";
|
import { PureComponent, SyntheticEvent } from "react";
|
||||||
import { Screen as ScreenEvent } from "matrix-analytics-events/types/typescript/Screen";
|
import { Screen as ScreenEvent } from "matrix-analytics-events/types/typescript/Screen";
|
||||||
|
import { Interaction as InteractionEvent } from "matrix-analytics-events/types/typescript/Interaction";
|
||||||
|
|
||||||
import PageType from "./PageTypes";
|
import PageType from "./PageTypes";
|
||||||
import Views from "./Views";
|
import Views from "./Views";
|
||||||
|
@ -88,6 +89,21 @@ export default class PosthogTrackers {
|
||||||
this.override = null;
|
this.override = null;
|
||||||
this.trackPage();
|
this.trackPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static trackInteraction(name: InteractionEvent["name"], ev?: SyntheticEvent): void {
|
||||||
|
let interactionType: InteractionEvent["interactionType"];
|
||||||
|
if (ev?.type === "click") {
|
||||||
|
interactionType = "Pointer";
|
||||||
|
} else if (ev?.type.startsWith("key")) {
|
||||||
|
interactionType = "Keyboard";
|
||||||
|
}
|
||||||
|
|
||||||
|
PosthogAnalytics.instance.trackEvent<InteractionEvent>({
|
||||||
|
eventName: "Interaction",
|
||||||
|
interactionType,
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PosthogScreenTracker extends PureComponent<{ screenName: ScreenName }> {
|
export class PosthogScreenTracker extends PureComponent<{ screenName: ScreenName }> {
|
||||||
|
|
|
@ -25,6 +25,7 @@ import * as ContentHelpers from 'matrix-js-sdk/src/content-helpers';
|
||||||
import { parseFragment as parseHtml, Element as ChildElement } from "parse5";
|
import { parseFragment as parseHtml, Element as ChildElement } from "parse5";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { IContent } from 'matrix-js-sdk/src/models/event';
|
import { IContent } from 'matrix-js-sdk/src/models/event';
|
||||||
|
import { SlashCommand as SlashCommandEvent } from "matrix-analytics-events/types/typescript/SlashCommand";
|
||||||
|
|
||||||
import { MatrixClientPeg } from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import dis from './dispatcher/dispatcher';
|
import dis from './dispatcher/dispatcher';
|
||||||
|
@ -62,6 +63,7 @@ import { shouldShowComponent } from "./customisations/helpers/UIComponents";
|
||||||
import { TimelineRenderingType } from './contexts/RoomContext';
|
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";
|
||||||
|
|
||||||
// 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 {
|
||||||
|
@ -105,6 +107,7 @@ interface ICommandOpts {
|
||||||
aliases?: string[];
|
aliases?: string[];
|
||||||
args?: string;
|
args?: string;
|
||||||
description: string;
|
description: string;
|
||||||
|
analyticsName?: SlashCommandEvent["command"];
|
||||||
runFn?: RunFn;
|
runFn?: RunFn;
|
||||||
category: string;
|
category: string;
|
||||||
hideCompletionAfterSpace?: boolean;
|
hideCompletionAfterSpace?: boolean;
|
||||||
|
@ -121,6 +124,7 @@ export class Command {
|
||||||
public readonly category: string;
|
public readonly category: string;
|
||||||
public readonly hideCompletionAfterSpace: boolean;
|
public readonly hideCompletionAfterSpace: boolean;
|
||||||
public readonly renderingTypes?: TimelineRenderingType[];
|
public readonly renderingTypes?: TimelineRenderingType[];
|
||||||
|
public readonly analyticsName?: SlashCommandEvent["command"];
|
||||||
private readonly _isEnabled?: () => boolean;
|
private readonly _isEnabled?: () => boolean;
|
||||||
|
|
||||||
constructor(opts: ICommandOpts) {
|
constructor(opts: ICommandOpts) {
|
||||||
|
@ -133,6 +137,7 @@ export class Command {
|
||||||
this.hideCompletionAfterSpace = opts.hideCompletionAfterSpace || false;
|
this.hideCompletionAfterSpace = opts.hideCompletionAfterSpace || false;
|
||||||
this._isEnabled = opts.isEnabled;
|
this._isEnabled = opts.isEnabled;
|
||||||
this.renderingTypes = opts.renderingTypes;
|
this.renderingTypes = opts.renderingTypes;
|
||||||
|
this.analyticsName = opts.analyticsName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCommand() {
|
public getCommand() {
|
||||||
|
@ -167,6 +172,13 @@ export class Command {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.analyticsName) {
|
||||||
|
PosthogAnalytics.instance.trackEvent<SlashCommandEvent>({
|
||||||
|
eventName: "SlashCommand",
|
||||||
|
command: this.analyticsName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return this.runFn.bind(this)(roomId, args);
|
return this.runFn.bind(this)(roomId, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,6 +500,7 @@ export const Commands = [
|
||||||
command: 'invite',
|
command: 'invite',
|
||||||
args: '<user-id> [<reason>]',
|
args: '<user-id> [<reason>]',
|
||||||
description: _td('Invites user with given id to current room'),
|
description: _td('Invites user with given id to current room'),
|
||||||
|
analyticsName: "invite",
|
||||||
isEnabled: () => shouldShowComponent(UIComponent.InviteUsers),
|
isEnabled: () => shouldShowComponent(UIComponent.InviteUsers),
|
||||||
runFn: function(roomId, args) {
|
runFn: function(roomId, args) {
|
||||||
if (args) {
|
if (args) {
|
||||||
|
@ -674,6 +687,7 @@ export const Commands = [
|
||||||
command: 'part',
|
command: 'part',
|
||||||
args: '[<room-address>]',
|
args: '[<room-address>]',
|
||||||
description: _td('Leave room'),
|
description: _td('Leave room'),
|
||||||
|
analyticsName: "part",
|
||||||
runFn: function(roomId, args) {
|
runFn: function(roomId, args) {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,6 @@ import { EchoChamber } from "../../../stores/local-echo/EchoChamber";
|
||||||
import { RoomNotifState } from "../../../RoomNotifs";
|
import { RoomNotifState } from "../../../RoomNotifs";
|
||||||
import Modal from "../../../Modal";
|
import Modal from "../../../Modal";
|
||||||
import ExportDialog from "../dialogs/ExportDialog";
|
import ExportDialog from "../dialogs/ExportDialog";
|
||||||
import { onRoomFilesClick, onRoomMembersClick } from "../right_panel/RoomSummaryCard";
|
|
||||||
import RoomViewStore from "../../../stores/RoomViewStore";
|
import RoomViewStore from "../../../stores/RoomViewStore";
|
||||||
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import { ROOM_NOTIFICATIONS_TAB } from "../dialogs/RoomSettingsDialog";
|
import { ROOM_NOTIFICATIONS_TAB } from "../dialogs/RoomSettingsDialog";
|
||||||
|
@ -44,6 +43,7 @@ import { useEventEmitterState } from "../../../hooks/useEventEmitter";
|
||||||
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
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";
|
||||||
|
|
||||||
interface IProps extends IContextMenuProps {
|
interface IProps extends IContextMenuProps {
|
||||||
room: Room;
|
room: Room;
|
||||||
|
@ -86,6 +86,8 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
|
||||||
room_id: room.roomId,
|
room_id: room.roomId,
|
||||||
});
|
});
|
||||||
onFinished();
|
onFinished();
|
||||||
|
|
||||||
|
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuLeaveItem", ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
leaveOption = <IconizedContextMenuOption
|
leaveOption = <IconizedContextMenuOption
|
||||||
|
@ -109,6 +111,8 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
|
||||||
roomId: room.roomId,
|
roomId: room.roomId,
|
||||||
});
|
});
|
||||||
onFinished();
|
onFinished();
|
||||||
|
|
||||||
|
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuInviteItem", ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
inviteOption = <IconizedContextMenuOption
|
inviteOption = <IconizedContextMenuOption
|
||||||
|
@ -124,7 +128,10 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
|
||||||
if (room.getMyMembership() === "join") {
|
if (room.getMyMembership() === "join") {
|
||||||
const isFavorite = roomTags.includes(DefaultTagID.Favourite);
|
const isFavorite = roomTags.includes(DefaultTagID.Favourite);
|
||||||
favouriteOption = <IconizedContextMenuCheckbox
|
favouriteOption = <IconizedContextMenuCheckbox
|
||||||
onClick={(e) => onTagRoom(e, DefaultTagID.Favourite)}
|
onClick={(e) => {
|
||||||
|
onTagRoom(e, DefaultTagID.Favourite);
|
||||||
|
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuFavouriteToggle", e);
|
||||||
|
}}
|
||||||
active={isFavorite}
|
active={isFavorite}
|
||||||
label={isFavorite ? _t("Favourited") : _t("Favourite")}
|
label={isFavorite ? _t("Favourited") : _t("Favourite")}
|
||||||
iconClassName="mx_RoomTile_iconStar"
|
iconClassName="mx_RoomTile_iconStar"
|
||||||
|
@ -171,6 +178,8 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
|
||||||
initial_tab_id: ROOM_NOTIFICATIONS_TAB,
|
initial_tab_id: ROOM_NOTIFICATIONS_TAB,
|
||||||
});
|
});
|
||||||
onFinished();
|
onFinished();
|
||||||
|
|
||||||
|
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuNotificationsItem", ev);
|
||||||
}}
|
}}
|
||||||
label={_t("Notifications")}
|
label={_t("Notifications")}
|
||||||
iconClassName={iconClassName}
|
iconClassName={iconClassName}
|
||||||
|
@ -190,8 +199,9 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
ensureViewingRoom();
|
ensureViewingRoom();
|
||||||
onRoomMembersClick(false);
|
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.RoomMemberList }, false);
|
||||||
onFinished();
|
onFinished();
|
||||||
|
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuPeopleItem", ev);
|
||||||
}}
|
}}
|
||||||
label={_t("People")}
|
label={_t("People")}
|
||||||
iconClassName="mx_RoomTile_iconPeople"
|
iconClassName="mx_RoomTile_iconPeople"
|
||||||
|
@ -258,7 +268,7 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
ensureViewingRoom();
|
ensureViewingRoom();
|
||||||
onRoomFilesClick(false);
|
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.FilePanel }, false);
|
||||||
onFinished();
|
onFinished();
|
||||||
}}
|
}}
|
||||||
label={_t("Files")}
|
label={_t("Files")}
|
||||||
|
@ -291,6 +301,7 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
|
||||||
room_id: room.roomId,
|
room_id: room.roomId,
|
||||||
});
|
});
|
||||||
onFinished();
|
onFinished();
|
||||||
|
PosthogTrackers.trackInteraction("WebRoomHeaderContextMenuSettingsItem", ev);
|
||||||
}}
|
}}
|
||||||
label={_t("Settings")}
|
label={_t("Settings")}
|
||||||
iconClassName="mx_RoomTile_iconSettings"
|
iconClassName="mx_RoomTile_iconSettings"
|
||||||
|
|
|
@ -19,7 +19,7 @@ import classNames from 'classnames';
|
||||||
|
|
||||||
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
|
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
|
||||||
import RightPanelStore from '../../../stores/right-panel/RightPanelStore';
|
import RightPanelStore from '../../../stores/right-panel/RightPanelStore';
|
||||||
import { backLabelForPhase } from '../../../stores/right-panel/RightPanelStorePhases';
|
import { backLabelForPhase } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
|
|
||||||
|
@ -30,8 +30,9 @@ interface IProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
withoutScrollContainer?: boolean;
|
withoutScrollContainer?: boolean;
|
||||||
closeLabel?: string;
|
closeLabel?: string;
|
||||||
onClose?(): void;
|
onClose?(ev: ButtonEvent): void;
|
||||||
cardState?;
|
onBack?(ev: ButtonEvent): void;
|
||||||
|
cardState?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IGroupProps {
|
interface IGroupProps {
|
||||||
|
@ -49,6 +50,7 @@ export const Group: React.FC<IGroupProps> = ({ className, title, children }) =>
|
||||||
const BaseCard: React.FC<IProps> = ({
|
const BaseCard: React.FC<IProps> = ({
|
||||||
closeLabel,
|
closeLabel,
|
||||||
onClose,
|
onClose,
|
||||||
|
onBack,
|
||||||
className,
|
className,
|
||||||
header,
|
header,
|
||||||
footer,
|
footer,
|
||||||
|
@ -59,7 +61,8 @@ const BaseCard: React.FC<IProps> = ({
|
||||||
const cardHistory = RightPanelStore.instance.roomPhaseHistory;
|
const cardHistory = RightPanelStore.instance.roomPhaseHistory;
|
||||||
if (cardHistory.length > 1) {
|
if (cardHistory.length > 1) {
|
||||||
const prevCard = cardHistory[cardHistory.length - 2];
|
const prevCard = cardHistory[cardHistory.length - 2];
|
||||||
const onBackClick = () => {
|
const onBackClick = (ev: ButtonEvent) => {
|
||||||
|
onBack?.(ev);
|
||||||
RightPanelStore.instance.popCard();
|
RightPanelStore.instance.popCard();
|
||||||
};
|
};
|
||||||
const label = backLabelForPhase(prevCard.phase) ?? _t("Back");
|
const label = backLabelForPhase(prevCard.phase) ?? _t("Back");
|
||||||
|
|
|
@ -23,7 +23,7 @@ import { useIsEncrypted } from '../../../hooks/useIsEncrypted';
|
||||||
import BaseCard, { Group } from "./BaseCard";
|
import BaseCard, { Group } from "./BaseCard";
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import RoomAvatar from "../avatars/RoomAvatar";
|
import RoomAvatar from "../avatars/RoomAvatar";
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
|
||||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||||
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import Modal from "../../../Modal";
|
import Modal from "../../../Modal";
|
||||||
|
@ -47,6 +47,7 @@ import RoomName from "../elements/RoomName";
|
||||||
import UIStore from "../../../stores/UIStore";
|
import UIStore from "../../../stores/UIStore";
|
||||||
import ExportDialog from "../dialogs/ExportDialog";
|
import ExportDialog from "../dialogs/ExportDialog";
|
||||||
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||||
|
import PosthogTrackers from "../../../PosthogTrackers";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
room: Room;
|
room: Room;
|
||||||
|
@ -59,7 +60,7 @@ interface IAppsSectionProps {
|
||||||
|
|
||||||
interface IButtonProps {
|
interface IButtonProps {
|
||||||
className: string;
|
className: string;
|
||||||
onClick(): void;
|
onClick(ev: ButtonEvent): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Button: React.FC<IButtonProps> = ({ children, className, onClick }) => {
|
const Button: React.FC<IButtonProps> = ({ children, className, onClick }) => {
|
||||||
|
@ -229,16 +230,18 @@ const AppsSection: React.FC<IAppsSectionProps> = ({ room }) => {
|
||||||
</Group>;
|
</Group>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const onRoomMembersClick = (allowClose = true) => {
|
const onRoomMembersClick = (ev: ButtonEvent) => {
|
||||||
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.RoomMemberList }, allowClose);
|
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.RoomMemberList }, true);
|
||||||
|
PosthogTrackers.trackInteraction("WebRightPanelRoomInfoPeopleButton", ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const onRoomFilesClick = (allowClose = true) => {
|
const onRoomFilesClick = () => {
|
||||||
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.FilePanel }, allowClose);
|
RightPanelStore.instance.pushCard({ phase: RightPanelPhases.FilePanel }, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onRoomSettingsClick = () => {
|
const onRoomSettingsClick = (ev: ButtonEvent) => {
|
||||||
defaultDispatcher.dispatch({ action: "open_room_settings" });
|
defaultDispatcher.dispatch({ action: "open_room_settings" });
|
||||||
|
PosthogTrackers.trackInteraction("WebRightPanelRoomInfoSettingsButton", ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
const RoomSummaryCard: React.FC<IProps> = ({ room, onClose }) => {
|
const RoomSummaryCard: React.FC<IProps> = ({ room, onClose }) => {
|
||||||
|
|
|
@ -34,7 +34,7 @@ import Modal from '../../../Modal';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import createRoom, { findDMForUser, privateShouldBeEncrypted } from '../../../createRoom';
|
import createRoom, { findDMForUser, privateShouldBeEncrypted } from '../../../createRoom';
|
||||||
import DMRoomMap from '../../../utils/DMRoomMap';
|
import DMRoomMap from '../../../utils/DMRoomMap';
|
||||||
import AccessibleButton from '../elements/AccessibleButton';
|
import AccessibleButton, { ButtonEvent } from '../elements/AccessibleButton';
|
||||||
import SdkConfig from '../../../SdkConfig';
|
import SdkConfig from '../../../SdkConfig';
|
||||||
import RoomViewStore from "../../../stores/RoomViewStore";
|
import RoomViewStore from "../../../stores/RoomViewStore";
|
||||||
import MultiInviter from "../../../utils/MultiInviter";
|
import MultiInviter from "../../../utils/MultiInviter";
|
||||||
|
@ -78,6 +78,7 @@ import RightPanelStore from '../../../stores/right-panel/RightPanelStore';
|
||||||
import { IRightPanelCardState } from '../../../stores/right-panel/RightPanelStoreIPanelState';
|
import { IRightPanelCardState } from '../../../stores/right-panel/RightPanelStoreIPanelState';
|
||||||
import { useUserStatusMessage } from "../../../hooks/useUserStatusMessage";
|
import { useUserStatusMessage } from "../../../hooks/useUserStatusMessage";
|
||||||
import UserIdentifierCustomisations from '../../../customisations/UserIdentifier';
|
import UserIdentifierCustomisations from '../../../customisations/UserIdentifier';
|
||||||
|
import PosthogTrackers from "../../../PosthogTrackers";
|
||||||
|
|
||||||
export interface IDevice {
|
export interface IDevice {
|
||||||
deviceId: string;
|
deviceId: string;
|
||||||
|
@ -422,7 +423,7 @@ const UserOptionsSection: React.FC<{
|
||||||
|
|
||||||
if (canInvite && (member?.membership ?? 'leave') === 'leave' && shouldShowComponent(UIComponent.InviteUsers)) {
|
if (canInvite && (member?.membership ?? 'leave') === 'leave' && shouldShowComponent(UIComponent.InviteUsers)) {
|
||||||
const roomId = member && member.roomId ? member.roomId : RoomViewStore.getRoomId();
|
const roomId = member && member.roomId ? member.roomId : RoomViewStore.getRoomId();
|
||||||
const onInviteUserButton = async () => {
|
const onInviteUserButton = async (ev: ButtonEvent) => {
|
||||||
try {
|
try {
|
||||||
// We use a MultiInviter to re-use the invite logic, even though
|
// We use a MultiInviter to re-use the invite logic, even though
|
||||||
// we're only inviting one user.
|
// we're only inviting one user.
|
||||||
|
@ -438,6 +439,8 @@ const UserOptionsSection: React.FC<{
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PosthogTrackers.trackInteraction("WebRightPanelRoomUserInfoInviteButton", ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
inviteUserButton = (
|
inviteUserButton = (
|
||||||
|
@ -1719,6 +1722,11 @@ const UserInfo: React.FC<IProps> = ({
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
closeLabel={closeLabel}
|
closeLabel={closeLabel}
|
||||||
cardState={cardState}
|
cardState={cardState}
|
||||||
|
onBack={(ev: ButtonEvent) => {
|
||||||
|
if (RightPanelStore.instance.previousCard.phase === RightPanelPhases.RoomMemberList) {
|
||||||
|
PosthogTrackers.trackInteraction("WebRightPanelRoomUserInfoBackButton", ev);
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{ content }
|
{ content }
|
||||||
</BaseCard>;
|
</BaseCard>;
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { EventStatus, IContent, MatrixEvent } from 'matrix-js-sdk/src/models/eve
|
||||||
import { MsgType } from 'matrix-js-sdk/src/@types/event';
|
import { MsgType } from 'matrix-js-sdk/src/@types/event';
|
||||||
import { Room } from 'matrix-js-sdk/src/models/room';
|
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
import { Composer as ComposerEvent } from "matrix-analytics-events/types/typescript/Composer";
|
||||||
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import dis from '../../../dispatcher/dispatcher';
|
import dis from '../../../dispatcher/dispatcher';
|
||||||
|
@ -46,6 +47,7 @@ import RoomContext from '../../../contexts/RoomContext';
|
||||||
import { ComposerType } from "../../../dispatcher/payloads/ComposerInsertPayload";
|
import { ComposerType } from "../../../dispatcher/payloads/ComposerInsertPayload";
|
||||||
import { getSlashCommand, isSlashCommand, runSlashCommand, shouldSendAnyway } from "../../../editor/commands";
|
import { getSlashCommand, isSlashCommand, runSlashCommand, shouldSendAnyway } from "../../../editor/commands";
|
||||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||||
|
import { PosthogAnalytics } from "../../../PosthogAnalytics";
|
||||||
|
|
||||||
function getHtmlReplyFallback(mxEvent: MatrixEvent): string {
|
function getHtmlReplyFallback(mxEvent: MatrixEvent): string {
|
||||||
const html = mxEvent.getContent().formatted_body;
|
const html = mxEvent.getContent().formatted_body;
|
||||||
|
@ -295,9 +297,17 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
||||||
private sendEdit = async (): Promise<void> => {
|
private sendEdit = async (): Promise<void> => {
|
||||||
if (this.state.saveDisabled) return;
|
if (this.state.saveDisabled) return;
|
||||||
|
|
||||||
const startTime = CountlyAnalytics.getTimestamp();
|
|
||||||
const editedEvent = this.props.editState.getEvent();
|
const editedEvent = this.props.editState.getEvent();
|
||||||
|
|
||||||
|
PosthogAnalytics.instance.trackEvent<ComposerEvent>({
|
||||||
|
eventName: "Composer",
|
||||||
|
isEditing: true,
|
||||||
|
inThread: !!editedEvent?.getThread(),
|
||||||
|
isReply: !!editedEvent.replyEventId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const startTime = CountlyAnalytics.getTimestamp();
|
||||||
|
|
||||||
// Replace emoticon at the end of the message
|
// Replace emoticon at the end of the message
|
||||||
if (SettingsStore.getValue('MessageComposerInput.autoReplaceEmoji')) {
|
if (SettingsStore.getValue('MessageComposerInput.autoReplaceEmoji')) {
|
||||||
const caret = this.editorRef.current?.getCaret();
|
const caret = this.editorRef.current?.getCaret();
|
||||||
|
@ -323,7 +333,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
||||||
if (!containsEmote(this.model) && isSlashCommand(this.model)) {
|
if (!containsEmote(this.model) && isSlashCommand(this.model)) {
|
||||||
const [cmd, args, commandText] = getSlashCommand(this.model);
|
const [cmd, args, commandText] = getSlashCommand(this.model);
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
const threadId = this.props.editState?.getEvent()?.getThread()?.id || null;
|
const threadId = editedEvent?.getThread()?.id || null;
|
||||||
if (cmd.category === CommandCategories.messages) {
|
if (cmd.category === CommandCategories.messages) {
|
||||||
editContent["m.new_content"] = await runSlashCommand(cmd, args, roomId, threadId);
|
editContent["m.new_content"] = await runSlashCommand(cmd, args, roomId, threadId);
|
||||||
if (!editContent["m.new_content"]) {
|
if (!editContent["m.new_content"]) {
|
||||||
|
|
|
@ -40,13 +40,14 @@ import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import TruncatedList from '../elements/TruncatedList';
|
import TruncatedList from '../elements/TruncatedList';
|
||||||
import Spinner from "../elements/Spinner";
|
import Spinner from "../elements/Spinner";
|
||||||
import SearchBox from "../../structures/SearchBox";
|
import SearchBox from "../../structures/SearchBox";
|
||||||
import AccessibleButton from '../elements/AccessibleButton';
|
import AccessibleButton, { ButtonEvent } from '../elements/AccessibleButton';
|
||||||
import EntityTile from "./EntityTile";
|
import EntityTile from "./EntityTile";
|
||||||
import MemberTile from "./MemberTile";
|
import MemberTile from "./MemberTile";
|
||||||
import BaseAvatar from '../avatars/BaseAvatar';
|
import BaseAvatar from '../avatars/BaseAvatar';
|
||||||
import SpaceStore from "../../../stores/spaces/SpaceStore";
|
import SpaceStore from "../../../stores/spaces/SpaceStore";
|
||||||
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";
|
||||||
|
|
||||||
const INITIAL_LOAD_NUM_MEMBERS = 30;
|
const INITIAL_LOAD_NUM_MEMBERS = 30;
|
||||||
const INITIAL_LOAD_NUM_INVITED = 5;
|
const INITIAL_LOAD_NUM_INVITED = 5;
|
||||||
|
@ -595,7 +596,9 @@ export default class MemberList extends React.Component<IProps, IState> {
|
||||||
</BaseCard>;
|
</BaseCard>;
|
||||||
}
|
}
|
||||||
|
|
||||||
onInviteButtonClick = (): void => {
|
private onInviteButtonClick = (ev: ButtonEvent): void => {
|
||||||
|
PosthogTrackers.trackInteraction("WebRightPanelMemberListInviteButton", ev);
|
||||||
|
|
||||||
if (MatrixClientPeg.get().isGuest()) {
|
if (MatrixClientPeg.get().isGuest()) {
|
||||||
dis.dispatch({ action: 'require_registration' });
|
dis.dispatch({ action: 'require_registration' });
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -13,6 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { createRef } from 'react';
|
import React, { createRef } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { MatrixEvent, IEventRelation } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent, IEventRelation } from "matrix-js-sdk/src/models/event";
|
||||||
|
@ -47,12 +48,13 @@ import UIStore, { UI_EVENTS } from '../../../stores/UIStore';
|
||||||
import RoomContext from '../../../contexts/RoomContext';
|
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';
|
||||||
|
|
||||||
let instanceCount = 0;
|
let instanceCount = 0;
|
||||||
const NARROW_MODE_BREAKPOINT = 500;
|
const NARROW_MODE_BREAKPOINT = 500;
|
||||||
|
|
||||||
interface ISendButtonProps {
|
interface ISendButtonProps {
|
||||||
onClick: () => void;
|
onClick: (ev: ButtonEvent) => void;
|
||||||
title?: string; // defaults to something generic
|
title?: string; // defaults to something generic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ import IconizedContextMenu, {
|
||||||
} from "../context_menus/IconizedContextMenu";
|
} from "../context_menus/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";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
room: Room;
|
room: Room;
|
||||||
|
@ -255,6 +256,8 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
const target = ev.target as HTMLButtonElement;
|
const target = ev.target as HTMLButtonElement;
|
||||||
this.setState({ notificationsMenuPosition: target.getBoundingClientRect() });
|
this.setState({ notificationsMenuPosition: target.getBoundingClientRect() });
|
||||||
|
|
||||||
|
PosthogTrackers.trackInteraction("WebRoomListRoomTileNotificationsMenu", ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
private onCloseNotificationsMenu = () => {
|
private onCloseNotificationsMenu = () => {
|
||||||
|
@ -322,6 +325,8 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
|
||||||
room_id: this.props.room.roomId,
|
room_id: this.props.room.roomId,
|
||||||
});
|
});
|
||||||
this.setState({ generalMenuPosition: null }); // hide the menu
|
this.setState({ generalMenuPosition: null }); // hide the menu
|
||||||
|
|
||||||
|
PosthogTrackers.trackInteraction("WebRoomListRoomTileContextMenuLeaveItem", ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
private onForgetRoomClick = (ev: ButtonEvent) => {
|
private onForgetRoomClick = (ev: ButtonEvent) => {
|
||||||
|
@ -344,6 +349,8 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
|
||||||
room_id: this.props.room.roomId,
|
room_id: this.props.room.roomId,
|
||||||
});
|
});
|
||||||
this.setState({ generalMenuPosition: null }); // hide the menu
|
this.setState({ generalMenuPosition: null }); // hide the menu
|
||||||
|
|
||||||
|
PosthogTrackers.trackInteraction("WebRoomListRoomTileContextMenuSettingsItem", ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
private onCopyRoomClick = (ev: ButtonEvent) => {
|
private onCopyRoomClick = (ev: ButtonEvent) => {
|
||||||
|
@ -366,6 +373,8 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
|
||||||
roomId: this.props.room.roomId,
|
roomId: this.props.room.roomId,
|
||||||
});
|
});
|
||||||
this.setState({ generalMenuPosition: null }); // hide the menu
|
this.setState({ generalMenuPosition: null }); // hide the menu
|
||||||
|
|
||||||
|
PosthogTrackers.trackInteraction("WebRoomListRoomTileContextMenuInviteItem", ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
private async saveNotifState(ev: ButtonEvent, newState: RoomNotifState) {
|
private async saveNotifState(ev: ButtonEvent, newState: RoomNotifState) {
|
||||||
|
@ -500,7 +509,10 @@ export default class RoomTile extends React.PureComponent<IProps, IState> {
|
||||||
>
|
>
|
||||||
<IconizedContextMenuOptionList>
|
<IconizedContextMenuOptionList>
|
||||||
<IconizedContextMenuCheckbox
|
<IconizedContextMenuCheckbox
|
||||||
onClick={(e) => this.onTagRoom(e, DefaultTagID.Favourite)}
|
onClick={(e) => {
|
||||||
|
this.onTagRoom(e, DefaultTagID.Favourite);
|
||||||
|
PosthogTrackers.trackInteraction("WebRoomListRoomTileContextMenuFavouriteToggle", e);
|
||||||
|
}}
|
||||||
active={isFavorite}
|
active={isFavorite}
|
||||||
label={favouriteLabel}
|
label={favouriteLabel}
|
||||||
iconClassName="mx_RoomTile_iconStar"
|
iconClassName="mx_RoomTile_iconStar"
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { DebouncedFunc, throttle } from 'lodash';
|
||||||
import { EventType, RelationType } from "matrix-js-sdk/src/@types/event";
|
import { EventType, RelationType } from "matrix-js-sdk/src/@types/event";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { Room } from 'matrix-js-sdk/src/models/room';
|
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||||
|
import { Composer as ComposerEvent } from "matrix-analytics-events/types/typescript/Composer";
|
||||||
|
|
||||||
import dis from '../../../dispatcher/dispatcher';
|
import dis from '../../../dispatcher/dispatcher';
|
||||||
import EditorModel from '../../../editor/model';
|
import EditorModel from '../../../editor/model';
|
||||||
|
@ -57,6 +58,7 @@ import DocumentPosition from "../../../editor/position";
|
||||||
import { ComposerType } from "../../../dispatcher/payloads/ComposerInsertPayload";
|
import { ComposerType } from "../../../dispatcher/payloads/ComposerInsertPayload";
|
||||||
import { getSlashCommand, isSlashCommand, runSlashCommand, shouldSendAnyway } from "../../../editor/commands";
|
import { getSlashCommand, isSlashCommand, runSlashCommand, shouldSendAnyway } from "../../../editor/commands";
|
||||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||||
|
import { PosthogAnalytics } from "../../../PosthogAnalytics";
|
||||||
|
|
||||||
interface IAddReplyOpts {
|
interface IAddReplyOpts {
|
||||||
permalinkCreator?: RoomPermalinkCreator;
|
permalinkCreator?: RoomPermalinkCreator;
|
||||||
|
@ -344,6 +346,13 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PosthogAnalytics.instance.trackEvent<ComposerEvent>({
|
||||||
|
eventName: "Composer",
|
||||||
|
isEditing: false,
|
||||||
|
inThread: this.props.relation?.rel_type === RelationType.Thread,
|
||||||
|
isReply: !!this.props.replyToEvent,
|
||||||
|
});
|
||||||
|
|
||||||
// Replace emoticon at the end of the message
|
// Replace emoticon at the end of the message
|
||||||
if (SettingsStore.getValue('MessageComposerInput.autoReplaceEmoji')) {
|
if (SettingsStore.getValue('MessageComposerInput.autoReplaceEmoji')) {
|
||||||
const indexOfLastPart = model.parts.length - 1;
|
const indexOfLastPart = model.parts.length - 1;
|
||||||
|
|
|
@ -18,7 +18,7 @@ import React, { ContextType } from 'react';
|
||||||
|
|
||||||
import { _t } from "../../../../../languageHandler";
|
import { _t } from "../../../../../languageHandler";
|
||||||
import RoomProfileSettings from "../../../room_settings/RoomProfileSettings";
|
import RoomProfileSettings from "../../../room_settings/RoomProfileSettings";
|
||||||
import AccessibleButton from "../../../elements/AccessibleButton";
|
import AccessibleButton, { ButtonEvent } from "../../../elements/AccessibleButton";
|
||||||
import dis from "../../../../../dispatcher/dispatcher";
|
import dis from "../../../../../dispatcher/dispatcher";
|
||||||
import MatrixClientContext from "../../../../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../../../../contexts/MatrixClientContext";
|
||||||
import SettingsStore from "../../../../../settings/SettingsStore";
|
import SettingsStore from "../../../../../settings/SettingsStore";
|
||||||
|
@ -27,6 +27,7 @@ import { replaceableComponent } from "../../../../../utils/replaceableComponent"
|
||||||
import UrlPreviewSettings from "../../../room_settings/UrlPreviewSettings";
|
import UrlPreviewSettings from "../../../room_settings/UrlPreviewSettings";
|
||||||
import RelatedGroupSettings from "../../../room_settings/RelatedGroupSettings";
|
import RelatedGroupSettings from "../../../room_settings/RelatedGroupSettings";
|
||||||
import AliasSettings from "../../../room_settings/AliasSettings";
|
import AliasSettings from "../../../room_settings/AliasSettings";
|
||||||
|
import PosthogTrackers from "../../../../../PosthogTrackers";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
roomId: string;
|
roomId: string;
|
||||||
|
@ -49,11 +50,13 @@ export default class GeneralRoomSettingsTab extends React.Component<IProps, ISta
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private onLeaveClick = (): void => {
|
private onLeaveClick = (ev: ButtonEvent): void => {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'leave_room',
|
action: 'leave_room',
|
||||||
room_id: this.props.roomId,
|
room_id: this.props.roomId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
PosthogTrackers.trackInteraction("WebRoomSettingsLeaveButton", ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
|
|
Loading…
Reference in New Issue