@@ -11,41 +11,60 @@ import { v4 } from "uuid";
11
11
12
12
13
13
export type Event = "invite_url_requested" | "organisation_authorised" ;
14
+ type InternalEvent = Event | "path_changed" | "dashboard_clicked" ;
15
+
16
+ export type EventProperties =
17
+ TrackOrgAuthorised
18
+ | TrackInviteUrlRequested
19
+ ;
20
+ type InternalEventProperties = (
21
+ EventProperties
22
+ | TrackDashboardClick
23
+ | TrackPathChanged
24
+ ) ;
25
+
26
+ export interface TrackOrgAuthorised {
27
+ installation_id : string ,
28
+ setup_action : string | undefined ,
29
+ }
30
+
31
+ export interface TrackInviteUrlRequested {
32
+ invite_url : string ,
33
+ }
14
34
15
- export type TrackingMsg = {
35
+ interface TrackDashboardClick {
16
36
dnt ?: boolean ,
17
37
path : string ,
18
38
button_type ?: string ,
19
39
label ?: string ,
20
- destination ?: string
40
+ destination ?: string ,
41
+ } ;
42
+
43
+ interface TrackPathChanged {
44
+ prev : string ,
45
+ path : string ,
21
46
}
22
47
23
48
//call this to track all events outside of button and anchor clicks
24
- export const trackEvent = ( event : Event , properties : any ) => {
25
- getGitpodService ( ) . server . trackEvent ( {
26
- event : event ,
27
- properties : properties
28
- } )
49
+ export const trackEvent = ( event : Event , properties : EventProperties ) => {
50
+ trackEventInternal ( event , properties ) ;
29
51
}
30
52
31
- export const getAnonymousId = ( ) : string => {
32
- let anonymousId = Cookies . get ( 'ajs_anonymous_id' ) ;
33
- if ( anonymousId ) {
34
- return anonymousId . replace ( / ^ " ( .+ (? = " $ ) ) " $ / , '$1' ) ; //strip enclosing double quotes before returning
35
- }
36
- else {
37
- anonymousId = v4 ( ) ;
38
- Cookies . set ( 'ajs_anonymous_id' , anonymousId , { domain : '.' + window . location . hostname , expires : 365 } ) ;
39
- } ;
40
- return anonymousId ;
41
- }
53
+ const trackEventInternal = ( event : InternalEvent , properties : InternalEventProperties , userKnown ?: boolean ) => {
54
+ getGitpodService ( ) . server . trackEvent ( {
55
+ //if the user is authenticated, let server determine the id. else, pass anonymousId explicitly.
56
+ anonymousId : userKnown ? undefined : getAnonymousId ( ) ,
57
+ event,
58
+ properties,
59
+ } ) ;
60
+ } ;
42
61
43
62
export const trackButtonOrAnchor = ( target : HTMLAnchorElement | HTMLButtonElement | HTMLDivElement , userKnown : boolean ) => {
44
63
//read manually passed analytics props from 'data-analytics' attribute of event target
45
- let passedProps : TrackingMsg | undefined ;
64
+ let passedProps : TrackDashboardClick | undefined ;
46
65
if ( target . dataset . analytics ) {
47
66
try {
48
- passedProps = JSON . parse ( target . dataset . analytics ) as TrackingMsg ;
67
+ passedProps = JSON . parse ( target . dataset . analytics ) as TrackDashboardClick ;
49
68
if ( passedProps . dnt ) {
50
69
return ;
51
70
}
@@ -55,10 +74,10 @@ export const trackButtonOrAnchor = (target: HTMLAnchorElement | HTMLButtonElemen
55
74
56
75
}
57
76
58
- let trackingMsg : TrackingMsg = {
77
+ let trackingMsg : TrackDashboardClick = {
59
78
path : window . location . pathname ,
60
79
label : target . textContent || undefined
61
- }
80
+ } ;
62
81
63
82
if ( target instanceof HTMLButtonElement || target instanceof HTMLDivElement ) {
64
83
//parse button data
@@ -79,60 +98,59 @@ export const trackButtonOrAnchor = (target: HTMLAnchorElement | HTMLButtonElemen
79
98
trackingMsg . destination = anchor . href ;
80
99
}
81
100
82
- const getAncestorProps = ( curr : HTMLElement | null ) : TrackingMsg | undefined => {
101
+ const getAncestorProps = ( curr : HTMLElement | null ) : TrackDashboardClick | undefined => {
83
102
if ( ! curr || curr instanceof Document ) {
84
103
return ;
85
104
}
86
- const ancestorProps : TrackingMsg | undefined = getAncestorProps ( curr . parentElement ) ;
87
- const currProps = JSON . parse ( curr . dataset . analytics || "{}" ) ;
88
- return { ...ancestorProps , ...currProps } as TrackingMsg ;
105
+ const ancestorProps : TrackDashboardClick | undefined = getAncestorProps ( curr . parentElement ) ;
106
+ const currProps = JSON . parse ( curr . dataset . analytics || "{}" ) as TrackDashboardClick ;
107
+ return { ...ancestorProps , ...currProps } ;
89
108
}
90
109
91
110
const ancestorProps = getAncestorProps ( target ) ;
92
111
93
112
//props that were passed directly to the event target take precedence over those passed to ancestor elements, which take precedence over those implicitly determined.
94
113
trackingMsg = { ...trackingMsg , ...ancestorProps , ...passedProps } ;
95
114
96
- //if the user is authenticated, let server determine the id. else, pass anonymousId explicitly.
97
- if ( userKnown ) {
98
- getGitpodService ( ) . server . trackEvent ( {
99
- event : "dashboard_clicked" ,
100
- properties : trackingMsg
101
- } ) ;
102
- } else {
103
- getGitpodService ( ) . server . trackEvent ( {
104
- anonymousId : getAnonymousId ( ) ,
105
- event : "dashboard_clicked" ,
106
- properties : trackingMsg
107
- } ) ;
108
- }
115
+ trackEventInternal ( "dashboard_clicked" , trackingMsg , userKnown ) ;
109
116
}
110
117
111
118
//call this when the path changes. Complete page call is unnecessary for SPA after initial call
112
- export const trackPathChange = ( props : { prev : string , path : string } ) => {
113
- getGitpodService ( ) . server . trackEvent ( {
114
- event : "path_changed" ,
115
- properties : props
116
- } ) ;
119
+ export const trackPathChange = ( props : TrackPathChanged ) => {
120
+ trackEventInternal ( "path_changed" , props ) ;
117
121
}
118
122
123
+
124
+ type TrackLocationProperties = {
125
+ referrer : string ,
126
+ path : string ,
127
+ host : string ,
128
+ url : string ,
129
+ } ;
130
+
119
131
export const trackLocation = async ( userKnown : boolean ) => {
120
- const props = {
132
+ const props : TrackLocationProperties = {
121
133
referrer : document . referrer ,
122
134
path : window . location . pathname ,
123
135
host : window . location . hostname ,
124
- url : window . location . href
125
- }
126
- if ( userKnown ) {
127
- //if the user is known, make server call
128
- getGitpodService ( ) . server . trackLocation ( {
129
- properties : props
130
- } ) ;
131
- } else {
132
- //make privacy preserving page call (automatically interpreted as such by server if anonymousId is passed)
133
- getGitpodService ( ) . server . trackLocation ( {
134
- anonymousId : getAnonymousId ( ) ,
135
- properties : props
136
- } ) ;
136
+ url : window . location . href ,
137
+ } ;
138
+
139
+ getGitpodService ( ) . server . trackLocation ( {
140
+ //if the user is authenticated, let server determine the id. else, pass anonymousId explicitly.
141
+ anonymousId : userKnown ? undefined : getAnonymousId ( ) ,
142
+ properties : props
143
+ } ) ;
144
+ }
145
+
146
+ const getAnonymousId = ( ) : string => {
147
+ let anonymousId = Cookies . get ( 'ajs_anonymous_id' ) ;
148
+ if ( anonymousId ) {
149
+ return anonymousId . replace ( / ^ " ( .+ (? = " $ ) ) " $ / , '$1' ) ; //strip enclosing double quotes before returning
137
150
}
151
+ else {
152
+ anonymousId = v4 ( ) ;
153
+ Cookies . set ( 'ajs_anonymous_id' , anonymousId , { domain : '.' + window . location . hostname , expires : 365 } ) ;
154
+ } ;
155
+ return anonymousId ;
138
156
}
0 commit comments