Basic threads analytics into Posthog MVP (#7871)
This commit is contained in:
parent
182aedc3d4
commit
75e41b4c1c
10 changed files with 51 additions and 18 deletions
|
@ -91,7 +91,7 @@
|
||||||
"linkifyjs": "^4.0.0-beta.4",
|
"linkifyjs": "^4.0.0-beta.4",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"maplibre-gl": "^1.15.2",
|
"maplibre-gl": "^1.15.2",
|
||||||
"matrix-analytics-events": "github:matrix-org/matrix-analytics-events.git#8e75aaf0b3e045587daeaf97a7691dbfda2f20c0",
|
"matrix-analytics-events": "github:matrix-org/matrix-analytics-events.git#daad3faed54f0b1f1e026a7498b4653e4d01cd90",
|
||||||
"matrix-events-sdk": "^0.0.1-beta.7",
|
"matrix-events-sdk": "^0.0.1-beta.7",
|
||||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
|
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
|
||||||
"matrix-widget-api": "^0.1.0-beta.18",
|
"matrix-widget-api": "^0.1.0-beta.18",
|
||||||
|
|
|
@ -152,13 +152,13 @@ export class PosthogAnalytics {
|
||||||
// we persist the last `$screen_name` and send it for all events until it is replaced
|
// we persist the last `$screen_name` and send it for all events until it is replaced
|
||||||
private lastScreen: ScreenName = "Loading";
|
private lastScreen: ScreenName = "Loading";
|
||||||
|
|
||||||
private sanitizeProperties = (properties: posthog.Properties): posthog.Properties => {
|
private sanitizeProperties = (properties: posthog.Properties, eventName: string): posthog.Properties => {
|
||||||
// Callback from posthog to sanitize properties before sending them to the server.
|
// Callback from posthog to sanitize properties before sending them to the server.
|
||||||
//
|
//
|
||||||
// Here we sanitize posthog's built in properties which leak PII e.g. url reporting.
|
// Here we sanitize posthog's built in properties which leak PII e.g. url reporting.
|
||||||
// See utils.js _.info.properties in posthog-js.
|
// See utils.js _.info.properties in posthog-js.
|
||||||
|
|
||||||
if (properties["eventName"] === "$pageview") {
|
if (eventName === "$pageview") {
|
||||||
this.lastScreen = properties["$current_url"];
|
this.lastScreen = properties["$current_url"];
|
||||||
}
|
}
|
||||||
// We inject a screen identifier in $current_url as per https://posthog.com/tutorials/spa
|
// We inject a screen identifier in $current_url as per https://posthog.com/tutorials/spa
|
||||||
|
|
|
@ -38,6 +38,8 @@ import TimelinePanel from './TimelinePanel';
|
||||||
import { Layout } from '../../settings/enums/Layout';
|
import { Layout } from '../../settings/enums/Layout';
|
||||||
import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks';
|
import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks';
|
||||||
import Measured from '../views/elements/Measured';
|
import Measured from '../views/elements/Measured';
|
||||||
|
import PosthogTrackers from "../../PosthogTrackers";
|
||||||
|
import { ButtonEvent } from "../views/elements/AccessibleButton";
|
||||||
|
|
||||||
export async function getThreadTimelineSet(
|
export async function getThreadTimelineSet(
|
||||||
client: MatrixClient,
|
client: MatrixClient,
|
||||||
|
@ -178,7 +180,15 @@ export const ThreadPanelHeader = ({ filterOption, setFilterOption, empty }: {
|
||||||
return <div className="mx_ThreadPanel__header">
|
return <div className="mx_ThreadPanel__header">
|
||||||
<span>{ _t("Threads") }</span>
|
<span>{ _t("Threads") }</span>
|
||||||
{ !empty && <>
|
{ !empty && <>
|
||||||
<ContextMenuButton className="mx_ThreadPanel_dropdown" inputRef={button} isExpanded={menuDisplayed} onClick={() => menuDisplayed ? closeMenu() : openMenu()}>
|
<ContextMenuButton
|
||||||
|
className="mx_ThreadPanel_dropdown"
|
||||||
|
inputRef={button}
|
||||||
|
isExpanded={menuDisplayed}
|
||||||
|
onClick={(ev: ButtonEvent) => {
|
||||||
|
openMenu();
|
||||||
|
PosthogTrackers.trackInteraction("WebRightPanelThreadPanelFilterDropdown", ev);
|
||||||
|
}}
|
||||||
|
>
|
||||||
{ `${_t('Show:')} ${value.label}` }
|
{ `${_t('Show:')} ${value.label}` }
|
||||||
</ContextMenuButton>
|
</ContextMenuButton>
|
||||||
{ contextMenu }
|
{ contextMenu }
|
||||||
|
|
|
@ -50,6 +50,8 @@ import FileDropTarget from "./FileDropTarget";
|
||||||
import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
||||||
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
|
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
|
||||||
import Measured from '../views/elements/Measured';
|
import Measured from '../views/elements/Measured';
|
||||||
|
import PosthogTrackers from "../../PosthogTrackers";
|
||||||
|
import { ButtonEvent } from "../views/elements/AccessibleButton";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
room: Room;
|
room: Room;
|
||||||
|
@ -321,6 +323,9 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
||||||
header={this.renderThreadViewHeader()}
|
header={this.renderThreadViewHeader()}
|
||||||
ref={this.card}
|
ref={this.card}
|
||||||
onKeyDown={this.onKeyDown}
|
onKeyDown={this.onKeyDown}
|
||||||
|
onBack={(ev: ButtonEvent) => {
|
||||||
|
PosthogTrackers.trackInteraction("WebThreadViewBackButton", ev);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Measured
|
<Measured
|
||||||
sensor={this.card.current}
|
sensor={this.card.current}
|
||||||
|
|
|
@ -24,12 +24,13 @@ import classNames from 'classnames';
|
||||||
import Analytics from '../../../Analytics';
|
import Analytics from '../../../Analytics';
|
||||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import { ButtonEvent } from "../elements/AccessibleButton";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
// Whether this button is highlighted
|
// Whether this button is highlighted
|
||||||
isHighlighted: boolean;
|
isHighlighted: boolean;
|
||||||
// click handler
|
// click handler
|
||||||
onClick: () => void;
|
onClick: (ev: ButtonEvent) => void;
|
||||||
// The parameters to track the click event
|
// The parameters to track the click event
|
||||||
analytics: Parameters<typeof Analytics.trackEvent>;
|
analytics: Parameters<typeof Analytics.trackEvent>;
|
||||||
|
|
||||||
|
@ -42,9 +43,9 @@ interface IProps {
|
||||||
// TODO: replace this, the composer buttons and the right panel buttons with a unified representation
|
// TODO: replace this, the composer buttons and the right panel buttons with a unified representation
|
||||||
@replaceableComponent("views.right_panel.HeaderButton")
|
@replaceableComponent("views.right_panel.HeaderButton")
|
||||||
export default class HeaderButton extends React.Component<IProps> {
|
export default class HeaderButton extends React.Component<IProps> {
|
||||||
private onClick = () => {
|
private onClick = (ev: ButtonEvent) => {
|
||||||
Analytics.trackEvent(...this.props.analytics);
|
Analytics.trackEvent(...this.props.analytics);
|
||||||
this.props.onClick();
|
this.props.onClick(ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
|
|
@ -38,6 +38,8 @@ import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNo
|
||||||
import { NotificationColor } from "../../../stores/notifications/NotificationColor";
|
import { NotificationColor } from "../../../stores/notifications/NotificationColor";
|
||||||
import { ThreadsRoomNotificationState } from "../../../stores/notifications/ThreadsRoomNotificationState";
|
import { ThreadsRoomNotificationState } from "../../../stores/notifications/ThreadsRoomNotificationState";
|
||||||
import { NotificationStateEvents } from "../../../stores/notifications/NotificationState";
|
import { NotificationStateEvents } from "../../../stores/notifications/NotificationState";
|
||||||
|
import PosthogTrackers from "../../../PosthogTrackers";
|
||||||
|
import { ButtonEvent } from "../elements/AccessibleButton";
|
||||||
|
|
||||||
const ROOM_INFO_PHASES = [
|
const ROOM_INFO_PHASES = [
|
||||||
RightPanelPhases.RoomSummary,
|
RightPanelPhases.RoomSummary,
|
||||||
|
@ -207,11 +209,12 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
|
||||||
this.setPhase(RightPanelPhases.Timeline);
|
this.setPhase(RightPanelPhases.Timeline);
|
||||||
};
|
};
|
||||||
|
|
||||||
private onThreadsPanelClicked = () => {
|
private onThreadsPanelClicked = (ev: ButtonEvent) => {
|
||||||
if (RoomHeaderButtons.THREAD_PHASES.includes(this.state.phase)) {
|
if (RoomHeaderButtons.THREAD_PHASES.includes(this.state.phase)) {
|
||||||
RightPanelStore.instance.togglePanel();
|
RightPanelStore.instance.togglePanel();
|
||||||
} else {
|
} else {
|
||||||
showThreadPanel();
|
showThreadPanel();
|
||||||
|
PosthogTrackers.trackInteraction("WebRoomHeaderButtonsThreadsButton", ev);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ 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, MouseEvent } from 'react';
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { EventType, MsgType, RelationType } from "matrix-js-sdk/src/@types/event";
|
import { EventType, MsgType, RelationType } from "matrix-js-sdk/src/@types/event";
|
||||||
import { EventStatus, MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/models/event";
|
import { EventStatus, MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/models/event";
|
||||||
|
@ -81,6 +81,7 @@ import { DecryptionFailureTracker } from '../../../DecryptionFailureTracker';
|
||||||
import RedactedBody from '../messages/RedactedBody';
|
import RedactedBody from '../messages/RedactedBody';
|
||||||
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
|
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
|
||||||
import { shouldDisplayReply } from '../../../utils/Reply';
|
import { shouldDisplayReply } from '../../../utils/Reply';
|
||||||
|
import PosthogTrackers from "../../../PosthogTrackers";
|
||||||
|
|
||||||
export type GetRelationsForEvent = (eventId: string, relationType: string, eventType: string) => Relations;
|
export type GetRelationsForEvent = (eventId: string, relationType: string, eventType: string) => Relations;
|
||||||
|
|
||||||
|
@ -684,17 +685,19 @@ export default class EventTile extends React.Component<IProps, IState> {
|
||||||
return (
|
return (
|
||||||
<CardContext.Consumer>
|
<CardContext.Consumer>
|
||||||
{ context =>
|
{ context =>
|
||||||
<div
|
<AccessibleButton
|
||||||
className="mx_ThreadInfo"
|
className="mx_ThreadInfo"
|
||||||
onClick={() => {
|
onClick={(ev: ButtonEvent) => {
|
||||||
showThread({ rootEvent: this.props.mxEvent, push: context.isCard });
|
showThread({ rootEvent: this.props.mxEvent, push: context.isCard });
|
||||||
|
PosthogTrackers.trackInteraction("WebRoomTimelineThreadSummaryButton", ev);
|
||||||
}}
|
}}
|
||||||
|
aria-label={_t("Open thread")}
|
||||||
>
|
>
|
||||||
<span className="mx_ThreadInfo_threads-amount">
|
<span className="mx_ThreadInfo_threads-amount">
|
||||||
{ count }
|
{ count }
|
||||||
</span>
|
</span>
|
||||||
{ this.renderThreadLastMessagePreview() }
|
{ this.renderThreadLastMessagePreview() }
|
||||||
</div>
|
</AccessibleButton>
|
||||||
}
|
}
|
||||||
</CardContext.Consumer>
|
</CardContext.Consumer>
|
||||||
);
|
);
|
||||||
|
@ -1507,7 +1510,12 @@ export default class EventTile extends React.Component<IProps, IState> {
|
||||||
"data-notification": this.state.threadNotification,
|
"data-notification": this.state.threadNotification,
|
||||||
"onMouseEnter": () => this.setState({ hover: true }),
|
"onMouseEnter": () => this.setState({ hover: true }),
|
||||||
"onMouseLeave": () => this.setState({ hover: false }),
|
"onMouseLeave": () => this.setState({ hover: false }),
|
||||||
"onClick": () => showThread({ rootEvent: this.props.mxEvent, push: true }),
|
"onClick": (ev: MouseEvent) => {
|
||||||
|
showThread({ rootEvent: this.props.mxEvent, push: true });
|
||||||
|
const target = ev.currentTarget as HTMLElement;
|
||||||
|
const index = Array.from(target.parentElement.children).indexOf(target);
|
||||||
|
PosthogTrackers.trackInteraction("WebThreadsPanelThreadItem", ev, index);
|
||||||
|
},
|
||||||
}, <>
|
}, <>
|
||||||
{ sender }
|
{ sender }
|
||||||
{ avatar }
|
{ avatar }
|
||||||
|
|
|
@ -345,12 +345,17 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PosthogAnalytics.instance.trackEvent<ComposerEvent>({
|
const posthogEvent: ComposerEvent = {
|
||||||
eventName: "Composer",
|
eventName: "Composer",
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
inThread: this.props.relation?.rel_type === RelationType.Thread,
|
|
||||||
isReply: !!this.props.replyToEvent,
|
isReply: !!this.props.replyToEvent,
|
||||||
});
|
inThread: this.props.relation?.rel_type === RelationType.Thread,
|
||||||
|
};
|
||||||
|
if (posthogEvent.inThread) {
|
||||||
|
const threadRoot = this.props.room.findEventById(this.props.relation.event_id);
|
||||||
|
posthogEvent.startsThread = threadRoot?.getThread()?.events.length === 1;
|
||||||
|
}
|
||||||
|
PosthogAnalytics.instance.trackEvent<ComposerEvent>(posthogEvent);
|
||||||
|
|
||||||
// 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')) {
|
||||||
|
|
|
@ -1659,6 +1659,7 @@
|
||||||
"From a thread": "From a thread",
|
"From a thread": "From a thread",
|
||||||
"%(count)s reply|other": "%(count)s replies",
|
"%(count)s reply|other": "%(count)s replies",
|
||||||
"%(count)s reply|one": "%(count)s reply",
|
"%(count)s reply|one": "%(count)s reply",
|
||||||
|
"Open thread": "Open thread",
|
||||||
"This event could not be displayed": "This event could not be displayed",
|
"This event could not be displayed": "This event could not be displayed",
|
||||||
"Your key share request has been sent - please check your other sessions for key share requests.": "Your key share request has been sent - please check your other sessions for key share requests.",
|
"Your key share request has been sent - please check your other sessions for key share requests.": "Your key share request has been sent - please check your other sessions for key share requests.",
|
||||||
"Key share requests are sent to your other sessions automatically. If you rejected or dismissed the key share request on your other sessions, click here to request the keys for this session again.": "Key share requests are sent to your other sessions automatically. If you rejected or dismissed the key share request on your other sessions, click here to request the keys for this session again.",
|
"Key share requests are sent to your other sessions automatically. If you rejected or dismissed the key share request on your other sessions, click here to request the keys for this session again.": "Key share requests are sent to your other sessions automatically. If you rejected or dismissed the key share request on your other sessions, click here to request the keys for this session again.",
|
||||||
|
|
|
@ -6261,9 +6261,9 @@ mathml-tag-names@^2.1.3:
|
||||||
resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3"
|
resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3"
|
||||||
integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==
|
integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==
|
||||||
|
|
||||||
"matrix-analytics-events@github:matrix-org/matrix-analytics-events.git#8e75aaf0b3e045587daeaf97a7691dbfda2f20c0":
|
"matrix-analytics-events@github:matrix-org/matrix-analytics-events.git#daad3faed54f0b1f1e026a7498b4653e4d01cd90":
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://codeload.github.com/matrix-org/matrix-analytics-events/tar.gz/8e75aaf0b3e045587daeaf97a7691dbfda2f20c0"
|
resolved "https://codeload.github.com/matrix-org/matrix-analytics-events/tar.gz/daad3faed54f0b1f1e026a7498b4653e4d01cd90"
|
||||||
|
|
||||||
matrix-events-sdk@^0.0.1-beta.6:
|
matrix-events-sdk@^0.0.1-beta.6:
|
||||||
version "0.0.1-beta.6"
|
version "0.0.1-beta.6"
|
||||||
|
|
Loading…
Reference in a new issue