From 91ccbe43955ba86bfe87970e96beb433fc64f74b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 9 Feb 2022 09:21:56 +0000 Subject: [PATCH] Add way to track posthog user properties and send numSpaces (#7716) --- package.json | 2 +- src/PosthogAnalytics.ts | 41 ++++++++++++++++++++---- src/actions/MatrixActionCreators.ts | 2 -- src/components/structures/MatrixChat.tsx | 7 ---- src/components/structures/RoomView.tsx | 4 +-- src/stores/LifecycleStore.ts | 2 +- src/stores/spaces/SpaceStore.ts | 3 ++ yarn.lock | 4 +-- 8 files changed, 43 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 4f0631a17e..a5e536e0bb 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,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#dfa6feaa12bcfc8e99b05a148e12fff7f9d62f08", + "matrix-analytics-events": "github:matrix-org/matrix-analytics-events.git#53844e3f6f9fefa88384a996b2bf5e60bb301b94", "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", diff --git a/src/PosthogAnalytics.ts b/src/PosthogAnalytics.ts index 6243a17b55..dec956d3ad 100644 --- a/src/PosthogAnalytics.ts +++ b/src/PosthogAnalytics.ts @@ -17,6 +17,7 @@ limitations under the License. import posthog, { PostHog } from 'posthog-js'; import { MatrixClient } from "matrix-js-sdk/src/client"; import { logger } from "matrix-js-sdk/src/logger"; +import { UserProperties } from "matrix-analytics-events/types/typescript/UserProperties"; import PlatformPeg from './PlatformPeg'; import SdkConfig from './SdkConfig'; @@ -42,6 +43,10 @@ import SettingsStore from "./settings/SettingsStore"; interface IEvent { // The event name that will be used by PostHog. Event names should use camelCase. eventName: string; + + // do not allow these to be sent manually, we enqueue them all for caching purposes + "$set"?: void; + "$set_once"?: void; } export enum Anonymity { @@ -109,6 +114,8 @@ export class PosthogAnalytics { private static _instance = null; private platformSuperProperties = {}; private static ANALYTICS_EVENT_TYPE = "im.vector.analytics"; + private propertiesForNextEvent: Partial> = {}; + private userPropertyCache: UserProperties = {}; public static get instance(): PosthogAnalytics { if (!this._instance) { @@ -198,7 +205,11 @@ export class PosthogAnalytics { } const { origin, hash, pathname } = window.location; properties['$redacted_current_url'] = getRedactedCurrentLocation(origin, hash, pathname); - this.posthog.capture(eventName, properties); + this.posthog.capture(eventName, { + ...this.propertiesForNextEvent, + ...properties, + }); + this.propertiesForNextEvent = {}; } public isEnabled(): boolean { @@ -260,13 +271,29 @@ export class PosthogAnalytics { this.setAnonymity(Anonymity.Disabled); } - public trackEvent( - event: E, - ): void { + public trackEvent({ eventName, ...properties }: E): void { if (this.anonymity == Anonymity.Disabled || this.anonymity == Anonymity.Anonymous) return; - const eventWithoutName = { ...event }; - delete eventWithoutName.eventName; - this.capture(event.eventName, eventWithoutName); + this.capture(eventName, properties); + } + + public setProperty(key: K, value: UserProperties[K]): void { + if (this.userPropertyCache[key] === value) return; // nothing to do + this.userPropertyCache[key] = value; + + if (!this.propertiesForNextEvent["$set"]) { + this.propertiesForNextEvent["$set"] = {}; + } + this.propertiesForNextEvent["$set"][key] = value; + } + + public setPropertyOnce(key: K, value: UserProperties[K]): void { + if (this.userPropertyCache[key]) return; // nothing to do + this.userPropertyCache[key] = value; + + if (!this.propertiesForNextEvent["$set_once"]) { + this.propertiesForNextEvent["$set_once"] = {}; + } + this.propertiesForNextEvent["$set_once"][key] = value; } public async updatePlatformSuperProperties(): Promise { diff --git a/src/actions/MatrixActionCreators.ts b/src/actions/MatrixActionCreators.ts index 72834782d6..c17ae3b596 100644 --- a/src/actions/MatrixActionCreators.ts +++ b/src/actions/MatrixActionCreators.ts @@ -22,8 +22,6 @@ import { IRoomTimelineData } from "matrix-js-sdk/src/models/event-timeline-set"; import dis from "../dispatcher/dispatcher"; import { ActionPayload } from "../dispatcher/payloads"; -// TODO: migrate from sync_state to MatrixActions.sync so that more js-sdk events -// become dispatches in the same place. /** * Create a MatrixActions.sync action that represents a MatrixClient `sync` event, * each parameter mapping to a key-value in the action. diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index df087e0415..58d5094f7c 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -1523,13 +1523,6 @@ export default class MatrixChat extends React.PureComponent { }); cli.on('sync', (state: SyncState, prevState?: SyncState, data?: ISyncStateData) => { - // LifecycleStore and others cannot directly subscribe to matrix client for - // events because flux only allows store state changes during flux dispatches. - // So dispatch directly from here. Ideally we'd use a SyncStateStore that - // would do this dispatch and expose the sync state itself (by listening to - // its own dispatch). - dis.dispatch({ action: 'sync_state', prevState, state }); - if (state === SyncState.Error || state === SyncState.Reconnecting) { if (data.error instanceof InvalidStoreError) { Lifecycle.handleInvalidStoreError(data.error); diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index d7eb1b3d3a..3f7fb31a22 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -879,10 +879,10 @@ export class RoomView extends React.Component { }); } break; - case 'sync_state': + case 'MatrixActions.sync': if (!this.state.matrixClientIsReady) { this.setState({ - matrixClientIsReady: this.context && this.context.isInitialSyncComplete(), + matrixClientIsReady: this.context?.isInitialSyncComplete(), }, () => { // send another "initial" RVS update to trigger peeking if needed this.onRoomViewStoreUpdate(true); diff --git a/src/stores/LifecycleStore.ts b/src/stores/LifecycleStore.ts index 97d3734a52..51203b3582 100644 --- a/src/stores/LifecycleStore.ts +++ b/src/stores/LifecycleStore.ts @@ -56,7 +56,7 @@ class LifecycleStore extends Store { deferredAction: null, }); break; - case 'sync_state': { + case 'MatrixActions.sync': { if (payload.state !== 'PREPARED') { break; } diff --git a/src/stores/spaces/SpaceStore.ts b/src/stores/spaces/SpaceStore.ts index 35961b104b..127fd75f15 100644 --- a/src/stores/spaces/SpaceStore.ts +++ b/src/stores/spaces/SpaceStore.ts @@ -53,6 +53,7 @@ import { } from "."; import { getCachedRoomIDForAlias } from "../../RoomAliasCache"; import { EffectiveMembership, getEffectiveMembership } from "../../utils/membership"; +import { PosthogAnalytics } from "../../PosthogAnalytics"; interface IState {} @@ -490,6 +491,8 @@ export class SpaceStoreClass extends AsyncStoreWithClient { this.parentMap.getOrCreate(child.roomId, new Set()).add(space.roomId); }); }); + + PosthogAnalytics.instance.setProperty("numSpaces", joinedSpaces.length); }; private rebuildHomeSpace = () => { diff --git a/yarn.lock b/yarn.lock index 1277942779..f35f4458a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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#dfa6feaa12bcfc8e99b05a148e12fff7f9d62f08": +"matrix-analytics-events@github:matrix-org/matrix-analytics-events.git#53844e3f6f9fefa88384a996b2bf5e60bb301b94": version "0.0.1" - resolved "https://codeload.github.com/matrix-org/matrix-analytics-events/tar.gz/dfa6feaa12bcfc8e99b05a148e12fff7f9d62f08" + resolved "https://codeload.github.com/matrix-org/matrix-analytics-events/tar.gz/53844e3f6f9fefa88384a996b2bf5e60bb301b94" matrix-events-sdk@^0.0.1-beta.6: version "0.0.1-beta.6"