github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/web/src/analytics.ts (about) 1 import { Action, Location } from "history" 2 import { 3 FilterLevel, 4 filterSetFromLocation, 5 FilterSource, 6 isRegexp, 7 TermState, 8 } from "./logfilters" 9 10 export const emptyTags = Object.freeze({}) 11 12 export type Tags = { 13 [key: string]: string | undefined 14 action?: AnalyticsAction | Action 15 type?: AnalyticsType 16 } 17 18 // The `type` tag describes what section of the UI 19 // that the analytics event takes place in 20 export enum AnalyticsType { 21 Account = "account", 22 Cluster = "cluster", 23 Detail = "resource-detail", 24 Grid = "grid", // aka Table View 25 Shortcut = "shortcuts", 26 Unknown = "unknown", 27 Update = "update", 28 } 29 30 // The `action` tag describes the type of UI interaction 31 export enum AnalyticsAction { 32 Click = "click", 33 Close = "close", 34 Collapse = "collapse", 35 Edit = "edit", 36 Expand = "expand", 37 Load = "load", 38 Shortcut = "shortcut", 39 Star = "star", 40 Unstar = "unstar", 41 SidebarToggle = "sidebarToggle", 42 } 43 44 // Fire and forget all analytics events 45 export const incr = (name: string, tags: Tags = {}): void => { 46 let url = `//${window.location.host}/api/analytics` 47 48 // Uncomment to debug analytics events 49 // console.log("analytics event: \nname:", name, "\npayload:", tags) 50 51 fetch(url, { 52 method: "post", 53 body: JSON.stringify([{ verb: "incr", name: name, tags: tags }]), 54 }) 55 } 56 57 export const pathToTag = (path: string): AnalyticsType => { 58 if (path.indexOf("/") === 0) { 59 path = path.substring(1) // chop off the leading / 60 } 61 let parts = path.split("/") 62 if (parts[0] === "") { 63 return AnalyticsType.Grid 64 } 65 if (parts[0] === "overview") { 66 return AnalyticsType.Grid 67 } 68 69 if (parts[0] === "r") { 70 if (parts[2] === "overview") { 71 return AnalyticsType.Detail 72 } 73 } 74 75 return AnalyticsType.Unknown 76 } 77 78 export let navigationToTags = ( 79 location: Location, 80 action: AnalyticsAction | Action 81 ): Tags => { 82 let tags: Tags = { type: pathToTag(location.pathname) } 83 84 // If the location has a `state`, use the `action` property for the analytics event 85 const locationAction: Action | undefined = location.state 86 ? (location as Location<{ action?: Action }>).state?.action 87 : undefined 88 if (action === "PUSH" && locationAction) { 89 tags.action = locationAction 90 } 91 92 let filterSet = filterSetFromLocation(location) 93 if (filterSet.level != FilterLevel.all) { 94 tags.level = filterSet.level 95 } 96 if (filterSet.source != FilterSource.all) { 97 tags.source = filterSet.source 98 } 99 if (filterSet.term.state !== TermState.Empty) { 100 const termType = isRegexp(filterSet.term.input) ? "regexp" : "text" 101 tags.term = termType 102 } 103 return tags 104 }