Svelte: Add basic telemetry to svelte implementation (#62190)

* Move telemetry service to the shared package

* Migrate web to the shared based telemetry

* Add svelte telemetry events

* Run svelte format

* Format:changed

* Format:changed and fix custom log view event handler

* Rebased onto main
This commit is contained in:
Vova Kulikov 2024-04-26 12:56:33 +02:00 committed by GitHub
parent 645358f125
commit c2afde8b43
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
157 changed files with 917 additions and 630 deletions

View File

@ -297,8 +297,16 @@ ts_project(
"src/symbols/SymbolKind.tsx",
"src/symbols/SymbolTag.tsx",
"src/symbols/symbolIcons.ts",
"src/telemetry/event-names.ts",
"src/telemetry/index.ts",
"src/telemetry/telemetryService.ts",
"src/telemetry/web/backend.ts",
"src/telemetry/web/cookies.ts",
"src/telemetry/web/dom.ts",
"src/telemetry/web/eventLogger.ts",
"src/telemetry/web/sessionTracker.ts",
"src/telemetry/web/userTracker.ts",
"src/telemetry/web/util.ts",
"src/theme.ts",
"src/theme-types.ts",
"src/tracking/event-log-creators.ts",
@ -332,18 +340,22 @@ ts_project(
"//:node_modules/@sourcegraph/extension-api-classes",
"//:node_modules/@types/classnames",
"//:node_modules/@types/history",
"//:node_modules/@types/js-cookie",
"//:node_modules/@types/lodash",
"//:node_modules/@types/lru-cache",
"//:node_modules/@types/minimatch",
"//:node_modules/@types/node",
"//:node_modules/@types/react",
"//:node_modules/@types/uuid",
"//:node_modules/@types/whatwg-url",
"//:node_modules/classnames",
"//:node_modules/comlink",
"//:node_modules/core-js",
"//:node_modules/date-fns",
"//:node_modules/fast-json-stable-stringify",
"//:node_modules/history",
"//:node_modules/js-base64",
"//:node_modules/js-cookie",
"//:node_modules/lodash",
"//:node_modules/lru-cache",
"//:node_modules/mdi-react",
@ -357,6 +369,7 @@ ts_project(
"//:node_modules/use-deep-compare-effect",
"//:node_modules/util",
"//:node_modules/utility-types",
"//:node_modules/uuid",
"//:node_modules/whatwg-url",
"//:node_modules/zustand",
"//schema:settings", #keep
@ -438,6 +451,8 @@ ts_project(
"src/search/query/validate.test.ts",
"src/settings/settings.test.ts",
"src/settings/temporary/useTemporarySetting.test.tsx",
"src/telemetry/web/userTracker.test.ts",
"src/telemetry/web/util.test.ts",
"src/testSetup.test.ts",
"src/tracking/utm.test.ts",
"src/util/dom.test.ts",

View File

@ -8,6 +8,7 @@
"lint:js": "eslint --cache '**/*.[jt]s?(x)'",
"lint:css": "stylelint 'src/**/*.scss' --quiet",
"test": "vitest",
"build-ts": "tsc --build tsconfig.json --emitDeclarationOnly",
"generate": "concurrently -r npm:generate:*",
"generate:graphql-operations": "ts-node -T dev/generateGraphQlOperations.ts",
"generate:schema": "ts-node -T dev/generateSchema.ts json-schema-draft-07 settings site batch_spec opencodegraph",
@ -29,4 +30,4 @@
"@sourcegraph/wildcard": "workspace:*"
},
"sideEffects": true
}
}

View File

@ -0,0 +1,58 @@
// NOTE(naman): Remember to add events to allow list: https://sourcegraph.com/docs/dev/background-information/data-usage-pipeline#allow-list
export const enum EventName {
CODY_CHAT_PAGE_VIEWED = 'web:codyChat:pageViewed',
CODY_CHAT_SUBMIT = 'web:codyChat:submit',
CODY_CHAT_EDIT = 'web:codyChat:edit',
CODY_CHAT_INITIALIZED = 'web:codyChat:initialized',
CODY_CHAT_EDITOR_WIDGET_VIEWED = 'web:codyChat:editorWidgetViewed',
CODY_CHAT_HISTORY_CLEARED = 'web:codyChat:historyCleared',
CODY_CHAT_HISTORY_ITEM_DELETED = 'web:codyChat:historyItemDeleted',
CODY_CHAT_SCOPE_REPO_ADDED = 'web:codyChat:scopeRepoAdded',
CODY_CHAT_SCOPE_REPO_REMOVED = 'web:codyChat:scopeRepoRemoved',
CODY_CHAT_SCOPE_RESET = 'web:codyChat:scopeReset',
CODY_CHAT_SCOPE_INFERRED_REPO_ENABLED = 'web:codyChat:inferredRepoEnabled',
CODY_CHAT_SCOPE_INFERRED_REPO_DISABLED = 'web:codyChat:inferredRepoDisabled',
CODY_CHAT_SCOPE_INFERRED_FILE_ENABLED = 'web:codyChat:inferredFileEnabled',
CODY_CHAT_SCOPE_INFERRED_FILE_DISABLED = 'web:codyChat:inferredFileDisabled',
VIEW_GET_CODY = 'GetCody',
CODY_EDITOR_WIDGET_VIEWED = 'web:codyEditorWidget:viewed',
CODY_SIDEBAR_CHAT_OPENED = 'web:codySidebar:chatOpened',
CODY_SIGNUP_CTA_CLICK = 'CodySignUpCTAClick',
CODY_CHAT_DOWNLOAD_VSCODE = 'web:codyChat:downloadVSCodeCTA',
CODY_CHAT_GET_EDITOR_EXTENSION = 'web:codyChat:getEditorExtensionCTA',
CODY_CHAT_TRY_ON_PUBLIC_CODE = 'web:codyChat:tryOnPublicCodeCTA',
CODY_CTA = 'ClickedOnCodyCTA',
VIEW_EDITOR_EXTENSIONS = 'CodyClickViewEditorExtensions',
TRY_CODY_VSCODE = 'VSCodeInstall',
TRY_CODY_MARKETPLACE = 'VSCodeMarketplace',
TRY_CODY_WEB = 'TryCodyWeb',
TRY_CODY_WEB_ONBOARDING_DISPLAYED = 'TryCodyWebOnboardingDisplayed',
TRY_CODY_SIGNUP_INITIATED = 'CodySignUpInitiated',
SPEAK_TO_AN_ENGINEER_CTA = 'SpeakToACodyEngineerCTA',
AUTH_INITIATED = 'AuthInitiated',
SIGNUP_COMPLETED = 'web:auth:signUpCompleted',
SINGIN_COMPLETED = 'web:auth:signInCompleted',
JOIN_IDE_WAITLIST = 'JoinIDEWaitlist',
DOWNLOAD_IDE = 'DownloadIDE',
DOWNLOAD_APP = 'DownloadApp',
CODY_EDITOR_SETUP_VIEWED = 'CodyEditorSetUpViewed',
CODY_EDITOR_SETUP_OPEN_MARKETPLACE = 'CodyEditorSetUpOpenMarketplace',
CODY_EDITOR_FEATURES_VIEWED = 'CodyEditorFeaturesViewed',
CODY_MANAGEMENT_PAGE_VIEWED = 'CodyManageViewed',
CODY_SUBSCRIPTION_PAGE_VIEWED = 'CodyPlanSelectionViewed',
CODY_SUBSCRIPTION_PLAN_CLICKED = 'CodyPlanSelectionClicked',
CODY_SUBSCRIPTION_PLAN_CONFIRMED = 'CodyPlanSelectionConfirmed',
CODY_SUBSCRIPTION_ADD_CREDIT_CARD_CLICKED = 'CodyAddCreditCard',
CODY_MANAGE_SUBSCRIPTION_CLICKED = 'CodyManageSubscriptionClicked',
CODY_ONBOARDING_WELCOME_VIEWED = 'CodyWelcomeViewed',
CODY_ONBOARDING_PURPOSE_VIEWED = 'CodyUseCaseViewed',
CODY_ONBOARDING_PURPOSE_SELECTED = 'CodyUseCaseSelected',
CODY_ONBOARDING_CHOOSE_EDITOR_VIEWED = 'CodyEditorViewed',
CODY_ONBOARDING_CHOOSE_EDITOR_SKIPPED = 'CodyEditorSkipped',
CODY_ONBOARDING_CHOOSE_EDITOR_SELECTED = 'CodyEditorSelected',
CODY_HANDRAISER_TEST_ENROLLMENT = 'HubspotFormFromWorkPersonalToHandRaiserTestEnrollment',
}

View File

@ -0,0 +1,85 @@
import { EMPTY, type Observable, Subject, lastValueFrom } from 'rxjs'
import { bufferTime, catchError, concatMap } from 'rxjs/operators'
import { gql, dataOrThrowErrors, requestGraphQLCommon, type GraphQLResult } from '@sourcegraph/http-client'
import type { LogEventsResult, LogEventsVariables, Event } from '../../graphql-operations'
const getHeaders = (): { [header: string]: string } => {
const headers: { [header: string]: string } = {
...window.context?.xhrHeaders,
Accept: 'application/json',
'Content-Type': 'application/json',
}
const parameters = new URLSearchParams(location.search)
const trace = parameters.get('trace')
if (trace) {
headers['X-Sourcegraph-Should-Trace'] = trace
}
// Get values from URL and local overrides
const feat = parameters.getAll('feat')
if (feat.length) {
headers['X-Sourcegraph-Override-Feature'] = feat.join(',')
}
return headers
}
const requestGraphQL = <TResult, TVariables = object>(
request: string,
variables?: TVariables
): Observable<GraphQLResult<TResult>> =>
requestGraphQLCommon({
request,
variables,
headers: getHeaders(),
})
// Log events in batches.
const BATCHED_EVENTS = new Subject<Event>()
export const logEventsMutation = gql`
mutation LogEvents($events: [Event!]) {
logEvents(events: $events) {
alwaysNil
}
}
`
function sendEvents(events: Event[]): Promise<void> {
return lastValueFrom(
requestGraphQL<LogEventsResult, LogEventsVariables>(logEventsMutation, {
events,
})
)
.then(dataOrThrowErrors)
.then(() => {})
}
BATCHED_EVENTS.pipe(
bufferTime(1000),
concatMap(events => {
if (events.length > 0) {
return sendEvents(events)
}
return EMPTY
}),
// TODO: log errors to Sentry
catchError(() => [])
)
// eslint-disable-next-line rxjs/no-ignored-subscription
.subscribe()
/**
* Log a raw user action (used to allow site admins on a Sourcegraph instance
* to see a count of unique users on a daily, weekly, and monthly basis).
*
* When invoked on a non-Sourcegraph.com instance, this data is stored in the
* instance's database, and not sent to Sourcegraph.com.
*
* @deprecated Use a TelemetryRecorder or TelemetryRecorderProvider from
* src/telemetry instead.
*/
export function logEvent(event: Event): void {
BATCHED_EVENTS.next(event)
}

View File

@ -32,6 +32,8 @@ export const userCookieSettings: CookieAttributes = {
sameSite: 'Lax',
// Specify the Domain attribute to ensure subdomains (sourcegraph.com) can receive this cookie.
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#define_where_cookies_are_sent
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
domain: location.hostname,
}
@ -46,5 +48,7 @@ export const deviceSessionCookieSettings: CookieAttributes = {
sameSite: 'Lax',
// Specify the Domain attribute to ensure subdomains (sourcegraph.com) can receive this cookie.
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#define_where_cookies_are_sent
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
domain: location.hostname,
}

View File

@ -0,0 +1,51 @@
import { Observable } from 'rxjs'
export interface ObserveQuerySelectorInit {
/**
* Any valid HTML/CSS selector
*/
selector: string
/**
* Timeout in milliseconds
*/
timeout: number
/**
* Target element to observe for changes.
* Default is document
*/
target?: HTMLElement
}
class ElementNotFoundError extends Error {
public readonly name = 'ElementNotFoundError'
constructor({ selector, timeout: timeoutMs }: ObserveQuerySelectorInit) {
super(`Could not find element with selector ${selector} within ${timeoutMs}ms.`)
}
}
/**
* Returns an observable that emits when an element that matches `selector` is found.
* Errors out if the selector doesn't yield an element by `timeoutMs`
*/
export const observeQuerySelector = ({ selector, timeout, target }: ObserveQuerySelectorInit): Observable<Element> =>
new Observable(function subscribe(observer) {
const targetElement = target ?? document
const intervalId = setInterval(() => {
const element = targetElement.querySelector(selector)
if (element) {
observer.next(element)
observer.complete()
}
}, Math.min(100, timeout))
const timeoutId = setTimeout(() => {
clearInterval(intervalId)
// If the element still hasn't appeared, call error handler.
observer.error(ElementNotFoundError)
}, timeout)
return function unsubscribe() {
clearTimeout(timeoutId)
clearInterval(intervalId)
}
})

View File

@ -3,15 +3,15 @@ import { catchError, map, share, take } from 'rxjs/operators'
import * as uuid from 'uuid'
import { isErrorLike, isFirefox, logger } from '@sourcegraph/common'
import type { SharedEventLogger } from '@sourcegraph/shared/src/api/sharedEventLogger'
import { EventClient } from '@sourcegraph/shared/src/graphql-operations'
import type { TelemetryService } from '@sourcegraph/shared/src/telemetry/telemetryService'
import type { UTMMarker } from '@sourcegraph/shared/src/tracking/utm'
import { EventName } from '../util/constants'
import { observeQuerySelector } from '../util/dom'
import type { SharedEventLogger } from '../../api/sharedEventLogger'
import { type Event, EventClient, EventSource } from '../../graphql-operations'
import type { UTMMarker } from '../../tracking/utm'
import { EventName } from '../event-names'
import type { TelemetryService } from '../telemetryService'
import { serverAdmin } from './services/serverAdminWrapper'
import { logEvent } from './backend'
import { observeQuerySelector } from './dom'
import { sessionTracker } from './sessionTracker'
import { userTracker } from './userTracker'
import { stripURLParameters } from './util'
@ -100,13 +100,13 @@ export class EventLogger implements TelemetryService, SharedEventLogger {
}
private logViewEventInternal(eventName: string, eventProperties?: any, logAsActiveUser = true): void {
const props = pageViewQueryParameters(window.location.href)
serverAdmin.trackPageView(eventName, logAsActiveUser, eventProperties)
const props = pageViewQueryParameters(location.href)
logEvent(this.createEvent(eventName, logAsActiveUser, eventProperties))
this.logToConsole(eventName, props)
// Use flag to ensure URL query params are only stripped once
if (!this.hasStrippedQueryParameters) {
handleQueryEvents(window.location.href)
handleQueryEvents(location.href)
this.hasStrippedQueryParameters = true
}
}
@ -175,13 +175,13 @@ export class EventLogger implements TelemetryService, SharedEventLogger {
// Use flag to ensure URL query params are only stripped once
if (!this.hasStrippedQueryParameters) {
handleQueryEvents(window.location.href)
handleQueryEvents(location.href)
this.hasStrippedQueryParameters = true
}
}
public logInternal(eventLabel: string, eventProperties?: any, publicArgument?: any): void {
serverAdmin.trackAction(eventLabel, eventProperties, publicArgument)
logEvent(this.createEvent(eventLabel, eventProperties, publicArgument))
this.logToConsole(eventLabel, eventProperties, publicArgument)
}
@ -227,13 +227,38 @@ export class EventLogger implements TelemetryService, SharedEventLogger {
this.listeners.add(callback)
return () => this.listeners.delete(callback)
}
private createEvent(event: string, eventProperties?: unknown, publicArgument?: unknown): Event {
return {
event,
userCookieID: EVENT_LOGGER.user.anonymousUserID,
cohortID: EVENT_LOGGER.user.cohortID || null,
firstSourceURL: EVENT_LOGGER.session.getFirstSourceURL(),
lastSourceURL: EVENT_LOGGER.session.getLastSourceURL(),
referrer: EVENT_LOGGER.session.getReferrer(),
originalReferrer: EVENT_LOGGER.session.getOriginalReferrer(),
sessionReferrer: EVENT_LOGGER.session.getSessionReferrer(),
sessionFirstURL: EVENT_LOGGER.session.getSessionFirstURL(),
deviceSessionID: EVENT_LOGGER.user.deviceSessionID,
url: location.href,
source: EventSource.WEB,
argument: eventProperties ? JSON.stringify(eventProperties) : null,
publicArgument: publicArgument ? JSON.stringify(publicArgument) : null,
deviceID: EVENT_LOGGER.user.deviceID,
eventID: EVENT_LOGGER.getEventID(),
insertID: EVENT_LOGGER.getInsertID(),
client: EVENT_LOGGER.getClient(),
connectedSiteID: window.context?.siteID,
hashedLicenseKey: window.context?.hashedLicenseKey,
}
}
}
/**
* @deprecated Use a TelemetryRecorder or TelemetryRecorderProvider from
* src/telemetry instead.
*/
export const eventLogger = new EventLogger()
export const EVENT_LOGGER = new EventLogger()
export function debugEventLoggingEnabled(): boolean {
return !!localStorage && localStorage.getItem('eventLogDebug') === 'true'
@ -254,12 +279,12 @@ function handleQueryEvents(url: string): void {
const parsedUrl = new URL(url)
if (parsedUrl.searchParams.has('signup')) {
const args = { serviceType: parsedUrl.searchParams.get('signup') || '' }
eventLogger.logInternal(EventName.SIGNUP_COMPLETED, args, args)
EVENT_LOGGER.logInternal(EventName.SIGNUP_COMPLETED, args, args)
}
if (parsedUrl.searchParams.has('signin')) {
const args = { serviceType: parsedUrl.searchParams.get('signin') || '' }
eventLogger.logInternal(EventName.SINGIN_COMPLETED, args, args)
EVENT_LOGGER.logInternal(EventName.SINGIN_COMPLETED, args, args)
}
stripURLParameters(url, ['utm_campaign', 'utm_source', 'utm_medium', 'signup', 'signin'])
@ -284,13 +309,13 @@ function pageViewQueryParameters(url: string): UTMMarker {
}
if (utmSource === 'saved-search-email') {
eventLogger.log('SavedSearchEmailClicked')
EVENT_LOGGER.log('SavedSearchEmailClicked')
} else if (utmSource === 'saved-search-slack') {
eventLogger.log('SavedSearchSlackClicked')
EVENT_LOGGER.log('SavedSearchSlackClicked')
} else if (utmSource === 'code-monitoring-email') {
eventLogger.log('CodeMonitorEmailLinkClicked')
EVENT_LOGGER.log('CodeMonitorEmailLinkClicked')
} else if (utmSource === 'hubspot' && utmCampaign?.match(/^cloud-onboarding-email(.*)$/)) {
eventLogger.log('UTMCampaignLinkClicked', utmProps, utmProps)
EVENT_LOGGER.log('UTMCampaignLinkClicked', utmProps, utmProps)
} else if (
[
'safari-extension',
@ -301,9 +326,9 @@ function pageViewQueryParameters(url: string): UTMMarker {
'gitlab-integration',
].includes(utmSource ?? '')
) {
eventLogger.log('UTMCodeHostIntegration', utmProps, utmProps)
EVENT_LOGGER.log('UTMCodeHostIntegration', utmProps, utmProps)
} else if (utmMedium === 'VSCODE' && utmCampaign === 'vsce-sign-up') {
eventLogger.log('VSCODESignUpLinkClicked', utmProps, utmProps)
EVENT_LOGGER.log('VSCODESignUpLinkClicked', utmProps, utmProps)
}
return utmProps

View File

@ -14,7 +14,7 @@ export class SessionTracker {
* Session tracking is only done in Sourcegraph.com, where cookie values are set in Google Tag Manager
* to ensure consistency across all public Sourcegraph-managed properties (e.g. marketing sites, blog, etc.)
*/
private isSourcegraphDotComMode = window.context?.sourcegraphDotComMode || false
private isSourcegraphDotComMode = window.context?.sourcegraphDotComMode
private originalReferrer: string
private sessionReferrer: string

View File

@ -0,0 +1,29 @@
import { describe, expect, it } from 'vitest'
import { getPreviousMonday } from './util'
describe(`${getPreviousMonday.name}()`, () => {
it('gets the current day if it is a Monday', () => {
const date = new Date(2021, 5, 14) // June 14, 2021 is a Monday
const monday = getPreviousMonday(date)
expect(monday).toBe('2021-06-14')
})
it('gets the previous Monday if it is not a Monday', () => {
const date = new Date(2021, 5, 13) // June 13, 2021 is a Sunday
const monday = getPreviousMonday(date)
expect(monday).toBe('2021-06-07')
})
it('gets the previous Monday if it is in a different month', () => {
const date = new Date(2021, 5, 3) // June 3, 2021 is a Thursday
const monday = getPreviousMonday(date)
expect(monday).toBe('2021-05-31')
})
it('gets the previous Monday if it is in a different year', () => {
const date = new Date(2021, 0, 2) // Jan 2, 2021 is a Saturday
const monday = getPreviousMonday(date)
expect(monday).toBe('2020-12-28')
})
})

View File

@ -0,0 +1,29 @@
import { formatISO, startOfWeek } from 'date-fns'
export const DOTCOM_URL = new URL('https://sourcegraph.com')
/**
* Strip provided URL parameters and update window history
*/
export function stripURLParameters(url: string, parametersToRemove: string[] = []): void {
const parsedUrl = new URL(url)
const existingParameters = parametersToRemove.filter(key => parsedUrl.searchParams.has(key))
// Update history state only if we have parameters to remove in the url.
if (existingParameters.length !== 0) {
for (const key of existingParameters) {
parsedUrl.searchParams.delete(key)
}
window.history.replaceState(window.history.state, window.document.title, parsedUrl.href)
}
}
/**
* Returns the Monday at or before the supplied date, in YYYY-MM-DD format.
* This is used to generate cohort IDs for users who
* started using the site on the same week.
*/
export function getPreviousMonday(date: Date): string {
return formatISO(startOfWeek(date, { weekStartsOn: 1 }), { representation: 'date' })
}

View File

@ -1,5 +1,5 @@
<script lang="ts" context="module">
import { faker } from '@faker-js/faker';
import { faker } from '@faker-js/faker'
import { Story } from '@storybook/addon-svelte-csf'
import CodeExcerpt from './CodeExcerpt.svelte'
@ -19,7 +19,12 @@ const obj = {
<script lang="ts">
faker.seed(16)
const plaintextLines = code.trim().split('\n')
const highlightedHTMLRows = plaintextLines.map((line, index) => `<tr><td class="line" data-line="${index + 1}" /><td class="code"><span style="color: ${faker.color.rgb()}">${line}</span></td></tr>`)
const highlightedHTMLRows = plaintextLines.map(
(line, index) =>
`<tr><td class="line" data-line="${
index + 1
}" /><td class="code"><span style="color: ${faker.color.rgb()}">${line}</span></td></tr>`
)
</script>
<Story name="Default">
@ -35,17 +40,17 @@ const obj = {
<h3>Hidden line numbers</h3>
<div class="wrapper">
<CodeExcerpt startLine={1} {plaintextLines} hideLineNumbers/>
<CodeExcerpt startLine={1} {plaintextLines} hideLineNumbers />
</div>
<h3>Collapsed whitespace</h3>
<div class="wrapper">
<CodeExcerpt startLine={1} {plaintextLines} collapseWhitespace/>
<CodeExcerpt startLine={1} {plaintextLines} collapseWhitespace />
</div>
<h3>With highlighted code</h3>
<div class="wrapper">
<CodeExcerpt startLine={1} {plaintextLines} {highlightedHTMLRows}/>
<CodeExcerpt startLine={1} {plaintextLines} {highlightedHTMLRows} />
</div>
</Story>

View File

@ -153,6 +153,7 @@
export let selectedLines: LineOrPositionOrRange | null = null
export let codeIntelAPI: CodeIntelAPI | null
export let staticHighlightRanges: Range[] = []
export let onCopy: () => void = () => {}
/**
* The initial scroll position when the editor is first mounted.
* Changing the value afterwards has no effect.
@ -326,7 +327,7 @@
</script>
{#if browser}
<div bind:this={container} class="root test-editor" data-editor="codemirror6" />
<div bind:this={container} class="root test-editor" data-editor="codemirror6" on:copy={onCopy} />
{:else}
<div class="root">
<pre>{blobInfo.content}</pre>

View File

@ -1,22 +1,18 @@
// We want to limit the number of imported modules as much as possible
/* eslint-disable no-restricted-imports */
import { onMount } from 'svelte'
// Dev build breaks if this import is moved to `$lib/web` ¯\_(ツ)_/¯
import type { EventLogger } from '@sourcegraph/web/src/tracking/eventLogger'
import { PUBLIC_ENABLE_EVENT_LOGGER } from '$env/static/public'
/**
* Can only be called during component initialization. It logs a view event when
* the component is mounted (and event logging is enabled).
*/
export function logViewEvent(...args: Parameters<EventLogger['logViewEvent']>): void {
export function logViewEvent(eventName: string, eventProperties?: any, publicArgument?: any): void {
if (PUBLIC_ENABLE_EVENT_LOGGER) {
onMount(() => {
// TODO: Implement event logging
console.log('logViewEvent', args)
console.log('logViewEvent', eventName, eventProperties, publicArgument)
})
}
}

View File

@ -12,6 +12,7 @@
export let title: string
export let filterPlaceholder: string = ''
export let showAll: boolean = false
export let onFilterSelect: (kind: SectionItem['kind']) => void = () => {}
let filterText = ''
$: processedFilterText = filterText.trim().toLowerCase()
@ -37,6 +38,7 @@
<a
href={updateFilterInURL($page.url, item, item.selected).toString()}
class:selected={item.selected}
on:click={() => onFilterSelect(item.kind)}
>
<span class="label">
<slot name="label" label={item.label} value={item.value}>

View File

@ -37,6 +37,7 @@
import LanguageIcon from '$lib/LanguageIcon.svelte'
import CodeHostIcon from '$lib/search/CodeHostIcon.svelte'
import SymbolKind from '$lib/search/SymbolKind.svelte'
import { SVELTE_LOGGER, SVELTE_TELEMETRY_EVENTS } from '$lib/telemetry'
import { displayRepoName, scanSearchQuery, type Filter } from '$lib/shared'
import Tooltip from '$lib/Tooltip.svelte'
import Button from '$lib/wildcard/Button.svelte'
@ -75,11 +76,17 @@
$: resetModifier = inferOperatingSystem(navigator.userAgent) === 'MacOS' ? '⌥' : 'Alt'
$: resetURL = resetFilters($page.url).toString()
$: enableReset = selectedFilters.length > 0
function handleResetKeydown(event: KeyboardEvent) {
if (enableReset && event.altKey && event.key === 'Backspace') {
goto(resetURL)
}
}
function handleFilterSelect(kind: SectionItem['kind']): void {
SVELTE_LOGGER.log(SVELTE_TELEMETRY_EVENTS.SelectSearchFilter, { kind }, { kind })
}
onMount(() => {
window.addEventListener('keydown', handleResetKeydown)
return () => window.removeEventListener('keydown', handleResetKeydown)
@ -98,7 +105,7 @@
</div>
{#if !queryHasTypeFilter(searchQuery)}
<Section items={typeFilters} title="By type" showAll>
<Section items={typeFilters} title="By type" showAll onFilterSelect={handleFilterSelect}>
<svelte:fragment slot="label" let:label>
<Icon svgPath={typeFilterIcons[label]} inline aria-hidden="true" />&nbsp;
{label}
@ -106,7 +113,12 @@
</Section>
{/if}
<Section items={groupedFilters.repo} title="By repository" filterPlaceholder="Filter repositories">
<Section
items={groupedFilters.repo}
title="By repository"
filterPlaceholder="Filter repositories"
onFilterSelect={handleFilterSelect}
>
<svelte:fragment slot="label" let:label>
<Tooltip tooltip={label} placement="right">
<span>
@ -116,27 +128,42 @@
</Tooltip>
</svelte:fragment>
</Section>
<Section items={groupedFilters.lang} title="By language" filterPlaceholder="Filter languages">
<Section
items={groupedFilters.lang}
title="By language"
filterPlaceholder="Filter languages"
onFilterSelect={handleFilterSelect}
>
<svelte:fragment slot="label" let:label>
<LanguageIcon class="icon" language={label} inline />&nbsp;
{label}
</svelte:fragment>
</Section>
<Section items={groupedFilters['symbol type']} title="By symbol type" filterPlaceholder="Filter symbol types">
<Section
items={groupedFilters['symbol type']}
title="By symbol type"
filterPlaceholder="Filter symbol types"
onFilterSelect={handleFilterSelect}
>
<svelte:fragment slot="label" let:label>
<SymbolKind symbolKind={label.toUpperCase()} />
{label}
</svelte:fragment>
</Section>
<Section items={groupedFilters.author} title="By author" filterPlaceholder="Filter authors" />
<Section items={groupedFilters['commit date']} title="By commit date">
<Section
items={groupedFilters.author}
title="By author"
filterPlaceholder="Filter authors"
onFilterSelect={handleFilterSelect}
/>
<Section items={groupedFilters['commit date']} title="By commit date" onFilterSelect={handleFilterSelect}>
<span class="commit-date-label" slot="label" let:label let:value>
{label}
<small><pre>{value}</pre></small>
</span>
</Section>
<Section items={groupedFilters.file} title="By file" showAll />
<Section items={groupedFilters.utility} title="Utility" showAll />
<Section items={groupedFilters.file} title="By file" showAll onFilterSelect={handleFilterSelect} />
<Section items={groupedFilters.utility} title="Utility" showAll onFilterSelect={handleFilterSelect} />
{#if state === 'loading'}
<LoadingSkeleton />

View File

@ -117,6 +117,7 @@
export let autoFocus = false
export let size: 'normal' | 'compat' = 'normal'
export let queryState: QueryStateStore
export let onSubmit: (state: QueryState) => void = () => {}
export function focus() {
input?.focus()
@ -191,6 +192,7 @@
event.preventDefault()
if (!mode) {
// Only submit query if you are not in history mode
onSubmit($queryState)
void submitQuery($queryState)
}
}

View File

@ -0,0 +1,43 @@
import { EventLogger } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
class SvelteTelemetry extends EventLogger {
public override logViewEvent(event: string): void {
super.logViewEvent(event, { isSveltePrototype: true })
}
public override log(eventName: string, eventProperties?: any, publicArgument?: any): void {
super.log(
eventName,
{ ...eventProperties, isSveltePrototype: true },
{ ...publicArgument, isSveltePrototype: true }
)
}
}
export const SVELTE_LOGGER = new SvelteTelemetry()
// These events are minimal set of telemetry events that we
// use in react version, note that names should be identical
// with event names that we use in react
export enum SVELTE_TELEMETRY_EVENTS {
// Note that prefix 'View' will be added by EventLogger
ViewHomePage = 'Home',
ViewSearchResultsPage = 'SearchResults',
ViewRepositoryPage = 'Repository',
ViewBlobPage = 'Blob',
SearchSubmit = 'SearchSubmitted',
SearchResultClick = 'SearchResultClicked',
ShowHistoryPanel = 'ShowHistoryPanel',
HideHistoryPanel = 'HideHistoryPanel',
CodeCopied = 'CodeCopied',
GoToCodeHost = 'GoToCodeHostClicked',
GitBlameEnabled = 'GitBlameEnabled',
SelectSearchFilter = 'SearchFiltersSelectFilter',
}
export const codeCopiedEvent = (page: string): [string, { page: string }, { page: string }] => [
SVELTE_TELEMETRY_EVENTS.CodeCopied,
{ page },
{ page },
]

View File

@ -1,3 +1,21 @@
<script context="module" lang="ts">
import { SVELTE_LOGGER, SVELTE_TELEMETRY_EVENTS } from '$lib/telemetry'
// Not ideal solution, [TODO] Improve Tabs component API in order
// to expose more info about nature of switch tab / close tab actions
function trackHistoryPanelTabAction(selectedTab: number | null, nextSelectedTab: number | null) {
if (nextSelectedTab === 0) {
SVELTE_LOGGER.log(SVELTE_TELEMETRY_EVENTS.ShowHistoryPanel)
return
}
if (nextSelectedTab === null && selectedTab == 0) {
SVELTE_LOGGER.log(SVELTE_TELEMETRY_EVENTS.HideHistoryPanel)
return
}
}
</script>
<script lang="ts">
import { tick } from 'svelte'
@ -51,6 +69,8 @@
}
async function selectTab(event: { detail: number | null }) {
trackHistoryPanelTabAction(selectedTab, event.detail)
if (event.detail === null) {
const url = new URL($page.url)
url.searchParams.delete('rev')

View File

@ -1,9 +1,12 @@
<script lang="ts">
// @sg RepoRoot
import Readme from '$lib/repo/Readme.svelte'
import SidebarToggleButton from '$lib/repo/SidebarToggleButton.svelte'
import { onMount } from 'svelte'
import { sidebarOpen } from '$lib/repo/stores'
import { createPromiseStore } from '$lib/utils'
import { SVELTE_LOGGER, SVELTE_TELEMETRY_EVENTS } from '$lib/telemetry'
import Readme from '$lib/repo/Readme.svelte'
import SidebarToggleButton from '$lib/repo/SidebarToggleButton.svelte'
import type { PageData } from './$types'
import type { RepoPage_Readme } from './page.gql'
@ -12,6 +15,10 @@
const readme = createPromiseStore<RepoPage_Readme | null>()
$: readme.set(data.readme)
onMount(() => {
SVELTE_LOGGER.logViewEvent(SVELTE_TELEMETRY_EVENTS.ViewRepositoryPage)
})
</script>
<h3 class="header">

View File

@ -1,6 +1,7 @@
<svelte:options immutable />
<script lang="ts">
import { onMount } from 'svelte'
import { mdiFileEyeOutline, mdiMapSearch, mdiWrap, mdiWrapDisabled } from '@mdi/js'
import { capitalize } from 'lodash'
import { from } from 'rxjs'
@ -8,6 +9,7 @@
import { afterNavigate, goto, preloadData } from '$app/navigation'
import { page } from '$app/stores'
import { SVELTE_LOGGER, SVELTE_TELEMETRY_EVENTS, codeCopiedEvent } from '$lib/telemetry'
import type { ScrollSnapshot } from '$lib/codemirror/utils'
import CodeMirrorBlob from '$lib/CodeMirrorBlob.svelte'
import { isErrorLike, SourcegraphURL, type LineOrPositionOrRange, pluralize } from '$lib/common'
@ -88,6 +90,10 @@
},
})
onMount(() => {
SVELTE_LOGGER.logViewEvent(SVELTE_TELEMETRY_EVENTS.ViewBlobPage)
})
afterNavigate(event => {
// Only restore scroll position when the user used the browser history to navigate back
// and forth. When the user reloads the page, in which case SvelteKit will also call
@ -98,6 +104,19 @@
}
})
function handleCopy(): void {
SVELTE_LOGGER.log(...codeCopiedEvent('blob-view'))
}
function onViewModeChange(event: CustomEvent<ViewMode>): void {
// TODO: track other blob mode
if (event.detail === ViewMode.Blame) {
SVELTE_LOGGER.log(SVELTE_TELEMETRY_EVENTS.GitBlameEnabled)
}
goto(viewModeURL(event.detail), { replaceState: true, keepFocus: true })
}
function viewModeURL(viewMode: ViewMode) {
switch (viewMode) {
case ViewMode.Code: {
@ -176,7 +195,7 @@
? [ViewMode.Default, ViewMode.Code, ViewMode.Blame]
: [ViewMode.Default, ViewMode.Blame]}
on:preload={event => preloadData(viewModeURL(event.detail))}
on:change={event => goto(viewModeURL(event.detail), { replaceState: true, keepFocus: true })}
on:change={onViewModeChange}
>
<svelte:fragment slot="label" let:value>
{value === ViewMode.Default ? (isFormatted ? 'Formatted' : 'Code') : capitalize(value)}
@ -241,6 +260,7 @@
)
}}
{codeIntelAPI}
onCopy={handleCopy}
/>
{/key}
{:else if fileLoadingError}

View File

@ -1,15 +1,20 @@
<script lang="ts">
import { SVELTE_LOGGER, SVELTE_TELEMETRY_EVENTS } from '$lib/telemetry'
import Tooltip from '$lib/Tooltip.svelte'
import { getHumanNameForCodeHost } from '$lib/repo/shared/codehost'
import CodeHostIcon from '$lib/search/CodeHostIcon.svelte'
import type { OpenInCodeHostAction } from './OpenInCodeHostAction.gql'
export let data: OpenInCodeHostAction
function handleOpenCodeHostClick(): void {
SVELTE_LOGGER.log(SVELTE_TELEMETRY_EVENTS.GoToCodeHost)
}
</script>
{#each data.externalURLs as { url, serviceKind } (url)}
<Tooltip tooltip="Open in code host">
<a href={url} target="_blank" rel="noopener noreferrer">
<a href={url} target="_blank" rel="noopener noreferrer" on:click={handleOpenCodeHostClick}>
{#if serviceKind}
<CodeHostIcon repository={serviceKind} disableTooltip />
<span data-action-label>

View File

@ -63,7 +63,7 @@
<li
class="location"
class:selected
on:click={() => selectedLocation = selected ? null : location}
on:click={() => (selectedLocation = selected ? null : location)}
>
<span class="code-file">
<span class="code">

View File

@ -25,25 +25,39 @@
export let location: ReferencePanelCodeExcerpt_Location
$: plaintextLines = location.range ? getLines(location.resource).slice(location.range.start.line, location.range.end.line + 1) : []
$: matches = location.range ? [{
startLine: location.range.start.line,
endLine: location.range.end.line,
startCharacter: location.range.start.character,
endCharacter: location.range.end.character,
}] : []
$: plaintextLines = location.range
? getLines(location.resource).slice(location.range.start.line, location.range.end.line + 1)
: []
$: matches = location.range
? [
{
startLine: location.range.start.line,
endLine: location.range.end.line,
startCharacter: location.range.start.character,
endCharacter: location.range.end.character,
},
]
: []
let visible = false
// We rely on fetchFileRangeMatches to cache the result for us so that repeated
// calls will not result in repeated network requests.
$: highlightedHTMLRows = visible && location.range ? derived(toReadable(fetchFileRangeMatches({
result: {
repository: location.resource.repository.name,
commit: location.resource.commit.oid,
path: location.resource.path,
},
ranges: [{ startLine: location.range.start.line, endLine: location.range.end.line +1 }],
})), result => result.value?.[0] || []) : readable([])
$: highlightedHTMLRows =
visible && location.range
? derived(
toReadable(
fetchFileRangeMatches({
result: {
repository: location.resource.repository.name,
commit: location.resource.commit.oid,
path: location.resource.path,
},
ranges: [{ startLine: location.range.start.line, endLine: location.range.end.line + 1 }],
})
),
result => result.value?.[0] || []
)
: readable([])
</script>
{#if location.range && plaintextLines.length > 0}

View File

@ -1,12 +1,14 @@
<script lang="ts">
import { tick } from 'svelte'
import { mdiMagnify } from '@mdi/js'
import { createDialog } from '@melt-ui/svelte'
import Icon from '$lib/Icon.svelte'
import SearchInput from '$lib/search/input/SearchInput.svelte'
import { queryStateStore } from '$lib/search/state'
import { QueryState, queryStateStore } from '$lib/search/state'
import { settings } from '$lib/stores'
import { mdiMagnify } from '@mdi/js'
import { tick } from 'svelte'
import { repositoryInsertText } from '$lib/shared'
import { SVELTE_LOGGER, SVELTE_TELEMETRY_EVENTS } from '$lib/telemetry'
export let repoName: string
@ -18,6 +20,14 @@
let searchInput: SearchInput | undefined
let queryState = queryStateStore({ query: `repo:${repositoryInsertText({ repository: repoName })} ` }, $settings)
function handleSearchSubmit(state: QueryState): void {
SVELTE_LOGGER.log(
SVELTE_TELEMETRY_EVENTS.SearchSubmit,
{ source: 'repo', query: state.query },
{ source: 'repo', patternType: state.patternType }
)
}
$: if ($open) {
// @melt-ui automatically focuses the search input but that positions the cursor at the
// start of the input. We can move the cursor to the end by calling focus(), but we need
@ -30,7 +40,7 @@
<div class="wrapper">
<div {...$overlay} use:overlay class="overlay" />
<div {...$content} use:content>
<SearchInput bind:this={searchInput} {queryState} />
<SearchInput bind:this={searchInput} {queryState} onSubmit={handleSearchSubmit} />
</div>
</div>
{:else}

View File

@ -1,9 +1,10 @@
<script lang="ts">
import { setContext } from 'svelte'
import { setContext, onMount } from 'svelte'
import { SVELTE_LOGGER, SVELTE_TELEMETRY_EVENTS } from '$lib/telemetry'
import { logoLight, logoDark } from '$lib/images'
import SearchInput from '$lib/search/input/SearchInput.svelte'
import type { QueryStateStore } from '$lib/search/state'
import type { QueryStateStore, QueryState } from '$lib/search/state'
import type { SearchPageContext } from '$lib/search/utils'
import { isLightTheme } from '$lib/stores'
@ -16,13 +17,25 @@
queryState.setQuery(newQuery)
},
})
onMount(() => {
SVELTE_LOGGER.logViewEvent(SVELTE_TELEMETRY_EVENTS.ViewHomePage)
})
function handleSubmit(state: QueryState) {
SVELTE_LOGGER.log(
SVELTE_TELEMETRY_EVENTS.SearchSubmit,
{ source: 'home', query: state.query },
{ source: 'home', patternType: state.patternType }
)
}
</script>
<section>
<div class="content">
<img class="logo" src={$isLightTheme ? logoLight : logoDark} alt="Sourcegraph Logo" />
<div class="search">
<SearchInput {queryState} autoFocus />
<SearchInput {queryState} autoFocus onSubmit={handleSubmit} />
<SearchHomeNotifications />
</div>
</div>

View File

@ -16,19 +16,16 @@
<script lang="ts">
import { mdiCloseOctagonOutline } from '@mdi/js'
import type { Observable } from 'rxjs'
import { tick } from 'svelte'
import { onMount, tick } from 'svelte'
import { writable } from 'svelte/store'
import { beforeNavigate, goto } from '$app/navigation'
import { limitHit } from '$lib/branded'
import Icon from '$lib/Icon.svelte'
import { observeIntersection } from '$lib/intersection-observer'
import GlobalHeaderPortal from '$lib/navigation/GlobalHeaderPortal.svelte'
import type { URLQueryFilter } from '$lib/search/dynamicFilters'
import DynamicFiltersSidebar from '$lib/search/dynamicFilters/Sidebar.svelte'
import { createRecentSearchesStore } from '$lib/search/input/recentSearches'
import SearchInput from '$lib/search/input/SearchInput.svelte'
import { getQueryURL, type QueryStateStore } from '$lib/search/state'
import { SVELTE_LOGGER, SVELTE_TELEMETRY_EVENTS, codeCopiedEvent } from '$lib/telemetry'
import {
type AggregateStreamingSearchResults,
type PathMatch,
@ -36,9 +33,14 @@
type SymbolMatch,
type ContentMatch,
} from '$lib/shared'
import type { QueryState } from '$lib/search/state'
import Icon from '$lib/Icon.svelte'
import Panel from '$lib/wildcard/resizable-panel/Panel.svelte'
import PanelGroup from '$lib/wildcard/resizable-panel/PanelGroup.svelte'
import PanelResizeHandle from '$lib/wildcard/resizable-panel/PanelResizeHandle.svelte'
import SearchInput from '$lib/search/input/SearchInput.svelte'
import DynamicFiltersSidebar from '$lib/search/dynamicFilters/Sidebar.svelte'
import GlobalHeaderPortal from '$lib/navigation/GlobalHeaderPortal.svelte'
import PreviewPanel from './PreviewPanel.svelte'
import SearchAlert from './SearchAlert.svelte'
@ -99,10 +101,15 @@
},
queryState,
})
beforeNavigate(() => {
cache.set(queryFromURL, { count, expanded: expandedSet, preview: $previewResult })
})
onMount(() => {
SVELTE_LOGGER.logViewEvent(SVELTE_TELEMETRY_EVENTS.ViewSearchResultsPage)
})
function loadMore(event: { detail: boolean }) {
if (event.detail) {
count += INCREMENTAL_ITEMS_TO_SHOW
@ -121,6 +128,22 @@
await tick()
void goto(getQueryURL($queryState))
}
function handleResultCopy(): void {
SVELTE_LOGGER.log(...codeCopiedEvent('search-result'))
}
function handleSearchResultClick(): void {
SVELTE_LOGGER.log(SVELTE_TELEMETRY_EVENTS.SearchResultClick)
}
function handleSubmit(state: QueryState) {
SVELTE_LOGGER.log(
SVELTE_TELEMETRY_EVENTS.SearchSubmit,
{ source: 'nav', query: state.query },
{ source: 'nav', patternType: state.patternType }
)
}
</script>
<svelte:head>
@ -129,7 +152,7 @@
<GlobalHeaderPortal>
<div class="search-header">
<SearchInput {queryState} size="compat" />
<SearchInput {queryState} size="compat" onSubmit={handleSubmit} />
</div>
</GlobalHeaderPortal>
@ -155,7 +178,7 @@
<SearchAlert alert={$stream.alert} />
</div>
{/if}
<ol>
<ol on:click={handleSearchResultClick} on:copy={handleResultCopy}>
{#each resultsToShow as result, i}
{@const component = getSearchResultComponent(result)}
{#if i === resultsToShow.length - 1}

View File

@ -1674,12 +1674,6 @@ ts_project(
"src/tour/components/withErrorBoundary.tsx",
"src/tour/data/index.tsx",
"src/tour/hooks.ts",
"src/tracking/TelemetricLink.tsx",
"src/tracking/cookies.ts",
"src/tracking/eventLogger.ts",
"src/tracking/services/serverAdminWrapper.tsx",
"src/tracking/sessionTracker.ts",
"src/tracking/userTracker.ts",
"src/tracking/util.ts",
"src/types/fzy.js/index.d.ts",
"src/user/area/UserArea.tsx",
@ -1790,7 +1784,6 @@ ts_project(
"//:node_modules/@types/d3-scale-chromatic",
"//:node_modules/@types/d3-time-format",
"//:node_modules/@types/history",
"//:node_modules/@types/js-cookie",
"//:node_modules/@types/js-yaml",
"//:node_modules/@types/lodash",
"//:node_modules/@types/lru-cache",
@ -1825,7 +1818,6 @@ ts_project(
"//:node_modules/http-status-codes",
"//:node_modules/ignore",
"//:node_modules/is-absolute-url",
"//:node_modules/js-cookie",
"//:node_modules/js-yaml",
"//:node_modules/jsonc-parser",
"//:node_modules/linguist-languages",
@ -1997,7 +1989,6 @@ ts_project(
"src/testSetup.test.ts",
"src/tour/components/Tour/Tour.test.tsx",
"src/tour/components/Tour/useTour.test.tsx",
"src/tracking/userTracker.test.ts",
"src/tracking/util.test.ts",
"src/user/index.test.ts",
"src/user/settings/auth/ExternalAccount.test.tsx",

View File

@ -19,6 +19,7 @@ import {
import { aggregateStreamingSearch } from '@sourcegraph/shared/src/search/stream'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { isBatchChangesExecutionEnabled } from './batches'
import { useBreadcrumbs, type BreadcrumbSetters, type BreadcrumbsProps } from './components/Breadcrumbs'
@ -26,7 +27,6 @@ import { NotFoundPage } from './components/HeroPage'
import type { SearchStreamingProps } from './search'
import type { StaticSourcegraphWebAppContext, DynamicSourcegraphWebAppContext } from './SourcegraphWebApp'
import type { StaticAppConfig } from './staticAppConfig'
import { eventLogger } from './tracking/eventLogger'
import { getLicenseFeatures } from './util/license'
export interface StaticLegacyRouteContext extends LegacyRouteComputedContext, LegacyRouteStaticInjections {}
@ -151,7 +151,7 @@ export const LegacyRouteContextProvider: FC<PropsWithChildren<LegacyRouteContext
*/
streamSearch: aggregateStreamingSearch,
fetchHighlightedFileLineRanges: _fetchHighlightedFileLineRanges,
telemetryService: eventLogger,
telemetryService: EVENT_LOGGER,
telemetryRecorder: platformContext.telemetryRecorder,
/**
* Breadcrumb props

View File

@ -35,6 +35,7 @@ import {
import { TemporarySettingsProvider } from '@sourcegraph/shared/src/settings/temporary/TemporarySettingsProvider'
import { TemporarySettingsStorage } from '@sourcegraph/shared/src/settings/temporary/TemporarySettingsStorage'
import { NoOpTelemetryRecorderProvider } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { WildcardThemeContext, type WildcardTheme } from '@sourcegraph/wildcard'
import { authenticatedUser as authenticatedUserSubject, type AuthenticatedUser, authenticatedUserValue } from './auth'
@ -53,7 +54,6 @@ import { GLOBAL_SEARCH_CONTEXT_SPEC } from './SearchQueryStateObserver'
import type { StaticAppConfig } from './staticAppConfig'
import { setQueryStateFromSettings, useDeveloperSettings, useNavbarQueryState } from './stores'
import { TelemetryRecorderProvider } from './telemetry'
import { eventLogger } from './tracking/eventLogger'
import { UserSessionStores } from './UserSessionStores'
import { getLicenseFeatures } from './util/license'
import { siteSubjectNoAdmin, viewerSubjectFromSettings } from './util/settings'
@ -224,7 +224,7 @@ export class LegacySourcegraphWebApp extends React.Component<StaticAppConfig, Le
batchChangesExecutionEnabled={isBatchChangesExecutionEnabled(this.state.settingsCascade)}
batchChangesWebhookLogsEnabled={window.context.batchChangesWebhookLogsEnabled}
fetchHighlightedFileLineRanges={this.fetchHighlightedFileLineRanges}
telemetryService={eventLogger}
telemetryService={EVENT_LOGGER}
telemetryRecorder={window.context.telemetryRecorder}
isSourcegraphDotCom={window.context.sourcegraphDotComMode}
isSearchContextSpecAvailable={isSearchContextSpecAvailable}

View File

@ -9,10 +9,10 @@ import { catchError, debounceTime } from 'rxjs/operators'
import { asError, type ErrorLike, isErrorLike, logger } from '@sourcegraph/common'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { LoadingSpinner, ErrorAlert } from '@sourcegraph/wildcard'
import { PageTitle } from '../components/PageTitle'
import { eventLogger } from '../tracking/eventLogger'
import { ApiConsoleToolbar } from './ApiConsoleToolbar'
@ -104,7 +104,7 @@ class ApiConsoleInner extends React.PureComponent<InnerProps, State> {
}
public componentDidMount(): void {
eventLogger.logViewEvent('ApiConsole')
EVENT_LOGGER.logViewEvent('ApiConsole')
this.props.telemetryRecorder.recordEvent('api-console', 'view')
// Update the browser URL bar when query/variables/operation name are

View File

@ -3,13 +3,13 @@ import React, { useEffect, useState } from 'react'
import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Text, Link, ErrorAlert, Form, Input, TextArea, Container, Alert } from '@sourcegraph/wildcard'
import { LoaderButton } from '../components/LoaderButton'
import { PageTitle } from '../components/PageTitle'
import type { SourcegraphContext } from '../jscontext'
import { PageRoutes } from '../routes.constants'
import { eventLogger } from '../tracking/eventLogger'
import { checkRequestAccessAllowed } from '../util/checkRequestAccessAllowed'
import { AuthPageWrapper } from './AuthPageWrapper'
@ -124,7 +124,7 @@ export interface RequestAccessPageProps extends TelemetryV2Props {}
*/
export const RequestAccessPage: React.FunctionComponent<RequestAccessPageProps> = ({ telemetryRecorder }) => {
useEffect(() => {
eventLogger.logPageView('RequestAccessPage')
EVENT_LOGGER.logPageView('RequestAccessPage')
telemetryRecorder.recordEvent('auth.requestAccess', 'view')
}, [telemetryRecorder])
const location = useLocation()

View File

@ -4,13 +4,13 @@ import { useLocation } from 'react-router-dom'
import { asError, type ErrorLike, isErrorLike, logger } from '@sourcegraph/common'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Button, Link, LoadingSpinner, Alert, Text, Input, ErrorAlert, Form, Container } from '@sourcegraph/wildcard'
import type { AuthenticatedUser } from '../auth'
import { LoaderButton } from '../components/LoaderButton'
import { PageTitle } from '../components/PageTitle'
import type { SourcegraphContext } from '../jscontext'
import { eventLogger } from '../tracking/eventLogger'
import { AuthPageWrapper } from './AuthPageWrapper'
import { PasswordInput } from './SignInSignUpCommon'
@ -239,7 +239,7 @@ export const ResetPasswordPage: React.FunctionComponent<ResetPasswordPageProps>
const location = useLocation()
React.useEffect(() => {
eventLogger.logViewEvent('ResetPassword', false)
EVENT_LOGGER.logViewEvent('ResetPassword', false)
props.telemetryRecorder.recordEvent('auth.resetPassword', 'view')
}, [props.telemetryRecorder])

View File

@ -6,12 +6,12 @@ import { partition } from 'lodash'
import { Navigate, useLocation, useSearchParams } from 'react-router-dom'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Alert, Icon, Text, Link, Button, ErrorAlert, AnchorLink, Container } from '@sourcegraph/wildcard'
import type { AuthenticatedUser } from '../auth'
import { PageTitle } from '../components/PageTitle'
import type { AuthProvider, SourcegraphContext } from '../jscontext'
import { eventLogger } from '../tracking/eventLogger'
import { checkRequestAccessAllowed } from '../util/checkRequestAccessAllowed'
import { AuthPageWrapper } from './AuthPageWrapper'
@ -40,7 +40,7 @@ export interface SignInPageProps extends TelemetryV2Props {
export const SignInPage: React.FunctionComponent<React.PropsWithChildren<SignInPageProps>> = props => {
const { context, authenticatedUser } = props
useEffect(() => {
eventLogger.logViewEvent('SignIn', null, false)
EVENT_LOGGER.logViewEvent('SignIn', null, false)
props.telemetryRecorder.recordEvent('auth.signIn', 'view')
}, [props.telemetryRecorder])
@ -246,7 +246,7 @@ const SignUpNotice: React.FunctionComponent<SignUpNoticeProps> = ({
<Link
to="https://sourcegraph.com/get-started?t=enterprise"
onClick={() => {
eventLogger.log('ClickedOnEnterpriseCTA', { location: 'SignInPage' })
EVENT_LOGGER.log('ClickedOnEnterpriseCTA', { location: 'SignInPage' })
telemetryRecorder.recordEvent('auth.enterpriseCTA', 'click')
}}
>

View File

@ -8,6 +8,7 @@ import { catchError, switchMap } from 'rxjs/operators'
import { asError } from '@sourcegraph/common'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import {
useInputValidation,
type ValidationOptions,
@ -17,7 +18,6 @@ import { Link, Icon, Label, Text, Button, AnchorLink, LoaderInput, ErrorAlert }
import { LoaderButton } from '../components/LoaderButton'
import type { AuthProvider, SourcegraphContext } from '../jscontext'
import { eventLogger } from '../tracking/eventLogger'
import { EventName, V2AuthProviderTypes } from '../util/constants'
import { validatePassword, getPasswordRequirements } from '../util/security'
@ -110,14 +110,14 @@ export const SignUpForm: React.FunctionComponent<React.PropsWithChildren<SignUpF
email: emailState.value,
username: usernameState.value,
password: passwordState.value,
anonymousUserId: eventLogger.user.anonymousUserID,
firstSourceUrl: eventLogger.session.getFirstSourceURL(),
lastSourceUrl: eventLogger.session.getLastSourceURL(),
anonymousUserId: EVENT_LOGGER.user.anonymousUserID,
firstSourceUrl: EVENT_LOGGER.session.getFirstSourceURL(),
lastSourceUrl: EVENT_LOGGER.session.getLastSourceURL(),
}).catch(error => {
setError(asError(error))
setLoading(false)
})
eventLogger.log('InitiateSignUp')
EVENT_LOGGER.log('InitiateSignUp')
telemetryRecorder.recordEvent('auth', 'initiate', { metadata: { type: V2AuthProviderTypes.builtin } })
},
[onSignUp, disabled, emailState, usernameState, passwordState, telemetryRecorder]
@ -129,7 +129,7 @@ export const SignUpForm: React.FunctionComponent<React.PropsWithChildren<SignUpF
(type: AuthProvider['serviceType']) => () => {
// TODO: Log events with keepalive=true to ensure they always outlive the webpage
// https://github.com/sourcegraph/sourcegraph/issues/19174
eventLogger.log(EventName.AUTH_INITIATED, { type }, { type })
EVENT_LOGGER.log(EventName.AUTH_INITIATED, { type }, { type })
telemetryRecorder.recordEvent('auth', 'initiate', { metadata: { type: V2AuthProviderTypes[type] } })
},
[telemetryRecorder]

View File

@ -4,6 +4,7 @@ import { Navigate, useLocation } from 'react-router-dom'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { useIsLightTheme } from '@sourcegraph/shared/src/theme'
import { Container, Link, Text } from '@sourcegraph/wildcard'
@ -11,7 +12,6 @@ import type { AuthenticatedUser } from '../auth'
import { PageTitle } from '../components/PageTitle'
import type { SourcegraphContext } from '../jscontext'
import { PageRoutes } from '../routes.constants'
import { eventLogger } from '../tracking/eventLogger'
import { EventName } from '../util/constants'
import { AuthPageWrapper } from './AuthPageWrapper'
@ -50,7 +50,7 @@ export const SignUpPage: React.FunctionComponent<React.PropsWithChildren<SignUpP
const isLightTheme = useIsLightTheme()
useEffect(() => {
eventLogger.logViewEvent('SignUp', null, false)
EVENT_LOGGER.logViewEvent('SignUp', null, false)
telemetryRecorder.recordEvent('auth.signUp', 'view', {
metadata: { 'invited-by-user': invitedBy !== null ? 1 : 0 },
})
@ -60,7 +60,7 @@ export const SignUpPage: React.FunctionComponent<React.PropsWithChildren<SignUpP
isAuthenticated: !!authenticatedUser,
allowSignup: context.allowSignup,
}
eventLogger.log('SignUpInvitedByUser', parameters, parameters)
EVENT_LOGGER.log('SignUpInvitedByUser', parameters, parameters)
}
}, [invitedBy, authenticatedUser, context.allowSignup, telemetryRecorder])

View File

@ -3,12 +3,12 @@ import React, { useEffect, useState } from 'react'
import { Navigate, useLocation, useParams } from 'react-router-dom'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Alert, Link, LoadingSpinner, ErrorAlert, Container } from '@sourcegraph/wildcard'
import type { AuthenticatedUser } from '../auth'
import { PageTitle } from '../components/PageTitle'
import type { SourcegraphContext } from '../jscontext'
import { eventLogger } from '../tracking/eventLogger'
import { AuthPageWrapper } from './AuthPageWrapper'
import { getReturnTo } from './SignInSignUpCommon'
@ -52,11 +52,11 @@ export const UnlockAccountPage: React.FunctionComponent<React.PropsWithChildren<
throw new Error('The url you provided is either expired or invalid.')
}
eventLogger.log('OkUnlockAccount')
EVENT_LOGGER.log('OkUnlockAccount')
props.telemetryRecorder.recordEvent('auth.unlockAccount', 'success')
} catch (error) {
setError(error)
eventLogger.log('KoUnlockAccount')
EVENT_LOGGER.log('KoUnlockAccount')
props.telemetryRecorder.recordEvent('auth.unlockAccount', 'fail')
} finally {
setLoading(false)
@ -67,7 +67,7 @@ export const UnlockAccountPage: React.FunctionComponent<React.PropsWithChildren<
if (props.authenticatedUser) {
return
}
eventLogger.logPageView('UnlockUserAccountRequest', null, false)
EVENT_LOGGER.logPageView('UnlockUserAccountRequest', null, false)
props.telemetryRecorder.recordEvent('auth.unlockAccount', 'view')
unlockAccount().catch(error => {

View File

@ -5,10 +5,10 @@ import { useLocation } from 'react-router-dom'
import { asError, logger } from '@sourcegraph/common'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Label, Button, LoadingSpinner, Link, Text, Input, Form } from '@sourcegraph/wildcard'
import type { SourcegraphContext } from '../jscontext'
import { eventLogger } from '../tracking/eventLogger'
import { V2AuthProviderTypes } from '../util/constants'
import { getReturnTo, PasswordInput } from './SignInSignUpCommon'
@ -52,7 +52,7 @@ export const UsernamePasswordSignInForm: React.FunctionComponent<React.PropsWith
}
setLoading(true)
eventLogger.log('InitiateSignIn')
EVENT_LOGGER.log('InitiateSignIn')
telemetryRecorder.recordEvent('auth', 'initiate', { metadata: { type: V2AuthProviderTypes.builtin } })
try {
const response = await fetch('/-/sign-in', {

View File

@ -24,9 +24,9 @@ import {
} from '@sourcegraph/cody-ui'
import type { AuthenticatedUser } from '@sourcegraph/shared/src/auth'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Button, Icon, TextArea, Link, Tooltip, Alert, Text, H2 } from '@sourcegraph/wildcard'
import { eventLogger } from '../../../tracking/eventLogger'
import { CodyPageIcon } from '../../chat/CodyPageIcon'
import { isCodyEnabled, isEmailVerificationNeededForCody, isSignInRequiredForCody } from '../../isCodyEnabled'
import { useCodySidebar } from '../../sidebar/Provider'
@ -54,7 +54,7 @@ export const ChatUI: React.FC<IChatUIProps> = ({
telemetryRecorder,
}): JSX.Element => {
const onFeedbackSubmit = (feedback: string): void => {
eventLogger.log(`web:cody:feedbackSubmit:${feedback}`)
EVENT_LOGGER.log(`web:cody:feedbackSubmit:${feedback}`)
// TODO (dadlerj): update @sourcegraph/cody-ui/dist/Chat package to enforce a limited set of feedback strings.
// Until then, this is a hack to avoid arbitrary event features.
if (feedback === 'positive' || feedback === 'negative') {

View File

@ -4,6 +4,7 @@ import { mdiChevronRight, mdiCodeBracesBox, mdiGit } from '@mdi/js'
import classNames from 'classnames'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Theme, useTheme } from '@sourcegraph/shared/src/theme'
import { Badge, H1, H2, H3, H4, Icon, Link, PageHeader, Text } from '@sourcegraph/wildcard'
@ -14,7 +15,6 @@ import { Page } from '../../../components/Page'
import { PageTitle } from '../../../components/PageTitle'
import type { SourcegraphContext } from '../../../jscontext'
import { MeetCodySVG } from '../../../repo/components/TryCodyWidget/WidgetIcons'
import { eventLogger } from '../../../tracking/eventLogger'
import { EventName } from '../../../util/constants'
import { CodyColorIcon, CodyHelpIcon, CodyWorkIcon } from '../../chat/CodyPageIcon'
@ -29,7 +29,7 @@ interface CodyPlatformCardProps {
/* eslint-disable @sourcegraph/sourcegraph/check-help-links */
const onSpeakToAnEngineer = (): void => eventLogger.log(EventName.SPEAK_TO_AN_ENGINEER_CTA)
const onSpeakToAnEngineer = (): void => EVENT_LOGGER.log(EventName.SPEAK_TO_AN_ENGINEER_CTA)
const IDEIcon: React.FunctionComponent<{}> = () => (
<svg viewBox="-4 -4 31 31" fill="none" xmlns="http://www.w3.org/2000/svg" className={styles.codyPlatformCardIcon}>
@ -182,7 +182,7 @@ export const CodyMarketingPage: React.FunctionComponent<CodyMarketingPageProps>
ctaClassName={styles.authButton}
iconClassName={styles.buttonIcon}
telemetryRecorder={telemetryRecorder}
telemetryService={eventLogger}
telemetryService={EVENT_LOGGER}
/>
</div>
<Text className="mt-3 mb-0">

View File

@ -3,10 +3,10 @@ import { useState, useEffect } from 'react'
import classNames from 'classnames'
import type { TelemetryRecorder } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { useIsLightTheme } from '@sourcegraph/shared/src/theme'
import { Text, Button } from '@sourcegraph/wildcard'
import { eventLogger } from '../../tracking/eventLogger'
import { EventName } from '../../util/constants'
import styles from './CodyOnboarding.module.scss'
@ -23,7 +23,7 @@ export function WelcomeStep({
const [show, setShow] = useState(false)
const isLightTheme = useIsLightTheme()
useEffect(() => {
eventLogger.log(
EVENT_LOGGER.log(
EventName.CODY_ONBOARDING_WELCOME_VIEWED,
{ tier: pro ? 'pro' : 'free' },
{ tier: pro ? 'pro' : 'free' }

View File

@ -3,9 +3,9 @@ import { useState, useEffect } from 'react'
import classNames from 'classnames'
import type { TelemetryRecorder } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Button, H2, Link, Text } from '@sourcegraph/wildcard'
import { eventLogger } from '../../../tracking/eventLogger'
import { EventName } from '../../../util/constants'
import { EditorStep } from '../../management/CodyManagementPage'
@ -29,10 +29,10 @@ export function JetBrainsInstructions({
useEffect(() => {
if (step === EditorStep.SetupInstructions) {
eventLogger.log(EventName.CODY_EDITOR_SETUP_VIEWED, { editor: 'JetBrains' })
EVENT_LOGGER.log(EventName.CODY_EDITOR_SETUP_VIEWED, { editor: 'JetBrains' })
telemetryRecorder.recordEvent('cody.editorSetupPage', 'view', { metadata: { jetBrains: 1 } })
} else if (step === EditorStep.CodyFeatures) {
eventLogger.log(EventName.CODY_EDITOR_FEATURES_VIEWED, { editor: 'JetBrains' })
EVENT_LOGGER.log(EventName.CODY_EDITOR_FEATURES_VIEWED, { editor: 'JetBrains' })
telemetryRecorder.recordEvent('cody.editorFeaturesPage', 'view', { metadata: { jetBrains: 1 } })
}
}, [step, telemetryRecorder])
@ -60,7 +60,7 @@ export function JetBrainsInstructions({
rel="noopener"
onClick={event => {
event.preventDefault()
eventLogger.log(EventName.CODY_EDITOR_SETUP_OPEN_MARKETPLACE, {
EVENT_LOGGER.log(EventName.CODY_EDITOR_SETUP_OPEN_MARKETPLACE, {
editor: 'JetBrains',
})
telemetryRecorder.recordEvent(

View File

@ -3,9 +3,9 @@ import { useState, useEffect } from 'react'
import classNames from 'classnames'
import type { TelemetryRecorder } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Button, ButtonLink, H2, Text } from '@sourcegraph/wildcard'
import { eventLogger } from '../../../tracking/eventLogger'
import { EventName } from '../../../util/constants'
import { EditorStep } from '../../management/CodyManagementPage'
@ -29,10 +29,10 @@ export function NeoVimInstructions({
useEffect(() => {
if (step === EditorStep.SetupInstructions) {
eventLogger.log(EventName.CODY_EDITOR_SETUP_VIEWED, { editor: 'NeoVim' })
EVENT_LOGGER.log(EventName.CODY_EDITOR_SETUP_VIEWED, { editor: 'NeoVim' })
telemetryRecorder.recordEvent('cody.editorSetupPage', 'view', { metadata: { neoVim: 1 } })
} else if (step === EditorStep.CodyFeatures) {
eventLogger.log(EventName.CODY_EDITOR_FEATURES_VIEWED, { editor: 'NeoVim' })
EVENT_LOGGER.log(EventName.CODY_EDITOR_FEATURES_VIEWED, { editor: 'NeoVim' })
telemetryRecorder.recordEvent('cody.editorFeaturesPage', 'view', { metadata: { neoVim: 1 } })
}
}, [step, telemetryRecorder])
@ -68,7 +68,7 @@ export function NeoVimInstructions({
target="_blank"
onClick={event => {
event.preventDefault()
eventLogger.log(EventName.CODY_EDITOR_SETUP_OPEN_MARKETPLACE, {
EVENT_LOGGER.log(EventName.CODY_EDITOR_SETUP_OPEN_MARKETPLACE, {
editor: 'NeoVim',
})
telemetryRecorder.recordEvent('cody.onboarding.openMarketplace', 'click', {

View File

@ -3,9 +3,9 @@ import { useState, useEffect } from 'react'
import classNames from 'classnames'
import type { TelemetryRecorder } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Button, ButtonLink, H2, Text } from '@sourcegraph/wildcard'
import { eventLogger } from '../../../tracking/eventLogger'
import { EventName } from '../../../util/constants'
import { EditorStep } from '../../management/CodyManagementPage'
@ -29,10 +29,10 @@ export function VSCodeInstructions({
useEffect(() => {
if (step === EditorStep.SetupInstructions) {
eventLogger.log(EventName.CODY_EDITOR_SETUP_VIEWED, { editor: 'VS Code' })
EVENT_LOGGER.log(EventName.CODY_EDITOR_SETUP_VIEWED, { editor: 'VS Code' })
telemetryRecorder.recordEvent('cody.editorSetupPage', 'view', { metadata: { vsCode: 1 } })
} else if (step === EditorStep.CodyFeatures) {
eventLogger.log(EventName.CODY_EDITOR_FEATURES_VIEWED, { editor: 'VS Code' })
EVENT_LOGGER.log(EventName.CODY_EDITOR_FEATURES_VIEWED, { editor: 'VS Code' })
telemetryRecorder.recordEvent('cody.editorFeaturesPage', 'view', { metadata: { vsCode: 1 } })
}
}, [step, telemetryRecorder])
@ -69,7 +69,7 @@ export function VSCodeInstructions({
target="_blank"
onClick={event => {
event.preventDefault()
eventLogger.log(EventName.CODY_EDITOR_SETUP_OPEN_MARKETPLACE, {
EVENT_LOGGER.log(EventName.CODY_EDITOR_SETUP_OPEN_MARKETPLACE, {
editor: 'VS Code',
})
telemetryRecorder.recordEvent('cody.onboarding.openMarketplace', 'click', {

View File

@ -7,6 +7,7 @@ import type { AuthenticatedUser } from '@sourcegraph/shared/src/auth'
import { SearchPatternType } from '@sourcegraph/shared/src/graphql-operations'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import type { TelemetryService } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { useIsLightTheme } from '@sourcegraph/shared/src/theme'
import { buildSearchURLQuery } from '@sourcegraph/shared/src/util/url'
import { Alert, Form, Input, LoadingSpinner, Text, Badge, Link, useSessionStorage } from '@sourcegraph/wildcard'
@ -14,7 +15,6 @@ import { Alert, Form, Input, LoadingSpinner, Text, Badge, Link, useSessionStorag
import { BrandLogo } from '../../components/branding/BrandLogo'
import { useFeatureFlag } from '../../featureFlags/useFeatureFlag'
import { useURLSyncedString } from '../../hooks/useUrlSyncedString'
import { eventLogger } from '../../tracking/eventLogger'
import { DOTCOM_URL } from '../../tracking/util'
import { CodyIcon } from '../components/CodyIcon'
import { isEmailVerificationNeededForCody } from '../isCodyEnabled'
@ -40,7 +40,7 @@ export const CodySearchPage: React.FunctionComponent<CodeSearchPageProps> = ({
telemetryRecorder,
}) => {
useEffect(() => {
eventLogger.logPageView('CodySearch')
EVENT_LOGGER.logPageView('CodySearch')
telemetryRecorder.recordEvent('cody.search', 'view')
}, [telemetryRecorder])
@ -70,7 +70,7 @@ export const CodySearchPage: React.FunctionComponent<CodeSearchPageProps> = ({
return
}
eventLogger.log(
EVENT_LOGGER.log(
'web:codySearch:submit',
!isPrivateInstance ? { input: sanitizedInput } : null,
!isPrivateInstance ? { input: sanitizedInput } : null
@ -82,7 +82,7 @@ export const CodySearchPage: React.FunctionComponent<CodeSearchPageProps> = ({
setLoading(false)
if (query) {
eventLogger.log(
EVENT_LOGGER.log(
'web:codySearch:submitSucceeded',
!isPrivateInstance ? { input: sanitizedInput, translatedQuery: query } : null,
!isPrivateInstance ? { input: sanitizedInput, translatedQuery: query } : null
@ -94,7 +94,7 @@ export const CodySearchPage: React.FunctionComponent<CodeSearchPageProps> = ({
search: buildSearchURLQuery(query, SearchPatternType.regexp, false) + '&ref=cody-search',
})
} else {
eventLogger.log(
EVENT_LOGGER.log(
'web:codySearch:submitFailed',
!isPrivateInstance ? { input: sanitizedInput, reason: 'untranslatable' } : null,
!isPrivateInstance ? { input: sanitizedInput, reason: 'untranslatable' } : null
@ -107,7 +107,7 @@ export const CodySearchPage: React.FunctionComponent<CodeSearchPageProps> = ({
},
error => {
telemetryRecorder.recordEvent('cody.search', 'fail')
eventLogger.log(
EVENT_LOGGER.log(
'web:codySearch:submitFailed',
!isPrivateInstance
? {

View File

@ -6,6 +6,7 @@ import { useNavigate } from 'react-router-dom'
import { useQuery } from '@sourcegraph/http-client'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import {
Badge,
Button,
@ -25,7 +26,6 @@ import { Page } from '../../components/Page'
import { PageTitle } from '../../components/PageTitle'
import { CodySubscriptionPlan } from '../../graphql-operations'
import type { UserCodyPlanResult, UserCodyPlanVariables } from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'
import { EventName } from '../../util/constants'
import { CodyColorIcon } from '../chat/CodyPageIcon'
import { useIsCodyPaymentsTestingMode } from '../featureFlags'
@ -63,7 +63,7 @@ export const CodySubscriptionPage: React.FunctionComponent<CodySubscriptionPageP
const manageSubscriptionRedirectURL = `${codyPaymentsUrl}/cody/subscription`
useEffect(() => {
eventLogger.log(EventName.CODY_SUBSCRIPTION_PAGE_VIEWED, { utm_source }, { utm_source })
EVENT_LOGGER.log(EventName.CODY_SUBSCRIPTION_PAGE_VIEWED, { utm_source }, { utm_source })
telemetryRecorder.recordEvent('cody.planSelection', 'view')
}, [utm_source, telemetryRecorder])
@ -98,7 +98,7 @@ export const CodySubscriptionPage: React.FunctionComponent<CodySubscriptionPageP
<Button
variant="primary"
onClick={() => {
eventLogger.log(EventName.CODY_MANAGE_SUBSCRIPTION_CLICKED)
EVENT_LOGGER.log(EventName.CODY_MANAGE_SUBSCRIPTION_CLICKED)
window.location.href = manageSubscriptionRedirectURL
}}
>
@ -222,7 +222,7 @@ export const CodySubscriptionPage: React.FunctionComponent<CodySubscriptionPageP
className="mb-0 text-muted d-inline cursor-pointer"
size="small"
onClick={() => {
eventLogger.log(EventName.CODY_MANAGE_SUBSCRIPTION_CLICKED)
EVENT_LOGGER.log(EventName.CODY_MANAGE_SUBSCRIPTION_CLICKED)
telemetryRecorder.recordEvent('cody.planSelection', 'click', {
metadata: { tier: 0 },
})
@ -236,7 +236,7 @@ export const CodySubscriptionPage: React.FunctionComponent<CodySubscriptionPageP
className="flex-1"
variant="primary"
onClick={() => {
eventLogger.log(
EVENT_LOGGER.log(
EventName.CODY_SUBSCRIPTION_PLAN_CLICKED,
{ tier: 'pro' },
{ tier: 'pro' }
@ -352,7 +352,7 @@ export const CodySubscriptionPage: React.FunctionComponent<CodySubscriptionPageP
to="https://sourcegraph.com/contact/request-info?utm_source=cody_subscription_page"
target="_blank"
onClick={() => {
eventLogger.log(
EVENT_LOGGER.log(
EventName.CODY_SUBSCRIPTION_PLAN_CLICKED,
{ tier: 'enterprise' },
{ tier: 'enterprise' }

View File

@ -13,9 +13,9 @@ import type {
import { Transcript, useClient, NoopEditor } from '@sourcegraph/cody-shared'
import type { Scalars } from '@sourcegraph/shared/src/graphql-operations'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { useLocalStorage } from '@sourcegraph/wildcard'
import { eventLogger } from '../tracking/eventLogger'
import { EventName } from '../util/constants'
import { isEmailVerificationNeededForCody } from './isCodyEnabled'
@ -196,7 +196,7 @@ export const useCodyChat = ({
if (!transcript) {
return
}
eventLogger.log(v1EventLabel, { transcriptId: transcript.id, ...eventProperties })
EVENT_LOGGER.log(v1EventLabel, { transcriptId: transcript.id, ...eventProperties })
let numericID = new Date(transcript.id).getTime()
if (isNaN(numericID)) {
@ -257,7 +257,7 @@ export const useCodyChat = ({
return
}
eventLogger.log(EventName.CODY_CHAT_HISTORY_CLEARED)
EVENT_LOGGER.log(EventName.CODY_CHAT_HISTORY_CLEARED)
const newTranscript = initializeNewChatInternal()
if (newTranscript) {
@ -360,7 +360,7 @@ export const useCodyChat = ({
const executeRecipe = useCallback<typeof executeRecipeInternal>(
async (recipeId, options): Promise<Transcript | null> => {
eventLogger.log(`web:codyChat:recipe:${recipeId}:executed`, { recipeId })
EVENT_LOGGER.log(`web:codyChat:recipe:${recipeId}:executed`, { recipeId })
const transcript = await executeRecipeInternal(recipeId, options)

View File

@ -4,8 +4,8 @@ import { mdiCardBulletedOutline, mdiDotsVertical, mdiProgressPencil, mdiShuffleV
import { TranslateToLanguage } from '@sourcegraph/cody-shared'
import type { TelemetryRecorder } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { eventLogger } from '../../tracking/eventLogger'
import { EventName } from '../../util/constants'
import type { CodeMirrorEditor } from '../components/CodeMirrorEditor'
import type { useCodySidebar } from '../sidebar/Provider'
@ -19,7 +19,7 @@ export const CodyRecipesWidget: React.FC<{ editor?: CodeMirrorEditor; telemetryR
telemetryRecorder,
}) => {
useEffect(() => {
eventLogger.log(EventName.CODY_CHAT_EDITOR_WIDGET_VIEWED)
EVENT_LOGGER.log(EventName.CODY_CHAT_EDITOR_WIDGET_VIEWED)
telemetryRecorder.recordEvent('cody.chat.editor-widget', 'view')
}, [telemetryRecorder])

View File

@ -3,6 +3,7 @@ import React, { type FC, useState, useCallback, useRef, useEffect } from 'react'
import { noop } from 'lodash'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import {
Alert,
Container,
@ -17,7 +18,6 @@ import {
} from '@sourcegraph/wildcard'
import { GitHubAppDomain } from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'
import { PageTitle } from '../PageTitle'
interface StateResponse {
@ -91,7 +91,7 @@ export const CreateGitHubAppPage: FC<CreateGitHubAppPageProps> = ({
const [error, setError] = useState<string>()
useEffect(() => {
eventLogger.logPageView('SiteAdminCreateGiHubApp')
EVENT_LOGGER.logPageView('SiteAdminCreateGiHubApp')
telemetryRecorder.recordEvent('admin.GitHubApp.create', 'view')
}, [telemetryRecorder])

View File

@ -6,10 +6,10 @@ import { useLocation } from 'react-router-dom'
import { useQuery } from '@sourcegraph/http-client'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { ButtonLink, Container, ErrorAlert, Icon, Link, LoadingSpinner, PageHeader } from '@sourcegraph/wildcard'
import { type GitHubAppsResult, type GitHubAppsVariables, GitHubAppDomain } from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'
import {
ConnectionContainer,
ConnectionLoading,
@ -38,7 +38,7 @@ export const GitHubAppsPage: React.FC<Props> = ({ batchChangesEnabled, telemetry
const gitHubApps = useMemo(() => data?.gitHubApps?.nodes ?? [], [data])
useEffect(() => {
eventLogger.logPageView('SiteAdminGitHubApps')
EVENT_LOGGER.logPageView('SiteAdminGitHubApps')
telemetryRecorder.recordEvent('admin.GitHubApps', 'view')
}, [telemetryRecorder])

View File

@ -1,9 +1,11 @@
import { type FC, useState } from 'react'
import {
debugEventLoggingEnabled,
setDebugEventLoggingEnabled,
} from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Checkbox } from '@sourcegraph/wildcard'
import { debugEventLoggingEnabled, setDebugEventLoggingEnabled } from '../../tracking/eventLogger'
export const EventLoggingDebugToggle: FC<{}> = () => {
const [enabled, setEnabled] = useState(debugEventLoggingEnabled())
return (

View File

@ -5,11 +5,11 @@ import { kebabCase } from 'lodash'
import { Timestamp } from '@sourcegraph/branded/src/components/Timestamp'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { useIsLightTheme } from '@sourcegraph/shared/src/theme'
import { Link, Icon, Text, Tooltip, Button, AnchorLink } from '@sourcegraph/wildcard'
import type { BatchChangeFields } from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'
import { MonacoBatchSpecEditor } from './batch-spec/edit/editor/MonacoBatchSpecEditor'
@ -68,7 +68,7 @@ export const BatchSpecDownloadLink: React.FunctionComponent<React.PropsWithChild
telemetryRecorder,
}) {
const onClick: () => void = () => {
eventLogger.log('batch_change_editor:download_for_src_cli:clicked')
EVENT_LOGGER.log('batch_change_editor:download_for_src_cli:clicked')
telemetryRecorder.recordEvent('batchChange.editor.downloadForCLI', 'click')
}
const component = asButton ? (

View File

@ -5,6 +5,7 @@ import { VisuallyHidden } from '@reach/visually-hidden'
import { animated } from 'react-spring'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import {
Button,
Checkbox,
@ -20,7 +21,6 @@ import {
Tooltip,
} from '@sourcegraph/wildcard'
import { eventLogger } from '../../../../tracking/eventLogger'
import type { ExecutionOptions } from '../BatchSpecContext'
import styles from './RunBatchSpecButton.module.scss'
@ -56,7 +56,7 @@ export const RunBatchSpecButton: React.FunctionComponent<React.PropsWithChildren
variant="primary"
onClick={() => {
execute()
eventLogger.log('batch_change_editor:run_batch_spec:clicked')
EVENT_LOGGER.log('batch_change_editor:run_batch_spec:clicked')
telemetryRecorder.recordEvent('batchChange.editor.runSpec', 'click')
}}
aria-label={typeof isExecutionDisabled === 'string' ? isExecutionDisabled : undefined}

View File

@ -5,10 +5,10 @@ import { useLocation } from 'react-router-dom'
import { animated, useSpring } from 'react-spring'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Button, useLocalStorage, H3, H4, Icon, Link, Text, VIEWPORT_XL } from '@sourcegraph/wildcard'
import type { Scalars } from '../../../../../graphql-operations'
import { eventLogger } from '../../../../../tracking/eventLogger'
import { createRenderTemplate } from '../../../create/useSearchTemplate'
import { insertNameIntoLibraryItem } from '../../yaml-util'
@ -134,7 +134,7 @@ export const LibraryPane: React.FunctionComponent<React.PropsWithChildren<Librar
if (selectedItem && !('isReadOnly' in props && props.isReadOnly)) {
const codeWithName = updateTemplateWithQueryAndName(selectedItem.code)
const templateName = selectedItem.name
eventLogger.log('batch_change_editor:template:loaded', { template: templateName })
EVENT_LOGGER.log('batch_change_editor:template:loaded', { template: templateName })
props.telemetryRecorder.recordEvent('batchChange.editor.template', 'load')
props.onReplaceItem(codeWithName)
setSelectedItem(undefined)
@ -191,7 +191,7 @@ export const LibraryPane: React.FunctionComponent<React.PropsWithChildren<Librar
rel="noopener noreferrer"
to="https://github.com/sourcegraph/batch-change-examples"
onClick={() => {
eventLogger.log('batch_change_editor:view_more_examples:clicked')
EVENT_LOGGER.log('batch_change_editor:view_more_examples:clicked')
props.telemetryRecorder.recordEvent('batchChange.editor.viewMoreExamples', 'click')
}}
>

View File

@ -7,6 +7,7 @@ import { animated, useSpring } from 'react-spring'
import { CodeSnippet } from '@sourcegraph/branded/src/components/CodeSnippet'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Alert, Button, H4, Icon, Tooltip, useAccordion, useStopwatch, ErrorAlert } from '@sourcegraph/wildcard'
import type { Connection } from '../../../../../components/FilteredConnection'
@ -15,7 +16,6 @@ import {
type PreviewHiddenBatchSpecWorkspaceFields,
type PreviewVisibleBatchSpecWorkspaceFields,
} from '../../../../../graphql-operations'
import { eventLogger } from '../../../../../tracking/eventLogger'
import { useBatchChangesLicense } from '../../../useBatchChangesLicense'
import { Header as WorkspacesListHeader } from '../../../workspaces-list'
import { type BatchSpecContextState, useBatchSpecContext } from '../../BatchSpecContext'
@ -166,7 +166,7 @@ const MemoizedWorkspacesPreview: React.FunctionComponent<React.PropsWithChildren
isWorkspacesPreviewInProgress
? cancel
: () => {
eventLogger.log('batch_change_editor:preview_workspaces:clicked')
EVENT_LOGGER.log('batch_change_editor:preview_workspaces:clicked')
telemetryRecorder.recordEvent('batchChange.editor.previewWorkspaces', 'click')
return preview(debouncedCode)
}

View File

@ -6,6 +6,7 @@ import { useNavigate, useLocation } from 'react-router-dom'
import { useMutation } from '@sourcegraph/http-client'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import {
Button,
Icon,
@ -28,7 +29,6 @@ import {
type RetryBatchSpecExecutionResult,
type RetryBatchSpecExecutionVariables,
} from '../../../../graphql-operations'
import { eventLogger } from '../../../../tracking/eventLogger'
import { type BatchSpecContextState, useBatchSpecContext } from '../BatchSpecContext'
import { CANCEL_BATCH_SPEC_EXECUTION, RETRY_BATCH_SPEC_EXECUTION } from './backend'
@ -172,7 +172,7 @@ const MemoizedActionsMenu: React.FunctionComponent<
className={styles.previewButton}
style={{ width: menuWidth }}
onClick={() => {
eventLogger.log('batch_change_execution:preview:clicked')
EVENT_LOGGER.log('batch_change_execution:preview:clicked')
telemetryRecorder.recordEvent('batchChange.execution', 'preview')
}}
>
@ -232,12 +232,12 @@ const MemoizedActionsMenu: React.FunctionComponent<
onConfirm={
cancelModalType === 'cancel'
? () => {
eventLogger.log('batch_change_execution:actions_execution_cancel:clicked')
EVENT_LOGGER.log('batch_change_execution:actions_execution_cancel:clicked')
telemetryRecorder.recordEvent('batchChange.execution', 'cancel')
return cancelBatchSpecExecution()
}
: () => {
eventLogger.log('batch_change_execution:actions_execution_cancel_and_edit:clicked')
EVENT_LOGGER.log('batch_change_execution:actions_execution_cancel_and_edit:clicked')
telemetryRecorder.recordEvent('batchChange.execution', 'edit')
return cancelAndEdit()
}

View File

@ -19,6 +19,7 @@ import indicator from 'ordinal/indicator'
import { dataOrThrowErrors } from '@sourcegraph/http-client'
import type { Maybe } from '@sourcegraph/shared/src/graphql-operations'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import {
Badge,
LoadingSpinner,
@ -64,7 +65,6 @@ import {
type BatchSpecWorkspaceStepResult,
type BatchSpecWorkspaceStepVariables,
} from '../../../../../graphql-operations'
import { eventLogger } from '../../../../../tracking/eventLogger'
import { queryChangesetSpecFileDiffs as _queryChangesetSpecFileDiffs } from '../../../preview/list/backend'
import { ChangesetSpecFileDiffConnection } from '../../../preview/list/ChangesetSpecFileDiffConnection'
import {
@ -197,7 +197,7 @@ const WorkspaceHeader: React.FunctionComponent<React.PropsWithChildren<Workspace
className={styles.workspaceDetail}
onClick={() => {
toggleShowDiagnostics()
eventLogger.log('batch_change_execution:workspace_timeline:clicked')
EVENT_LOGGER.log('batch_change_execution:workspace_timeline:clicked')
telemetryRecorder.recordEvent('batchChange.execution.workspaceTimeline', 'click')
}}
variant="link"
@ -640,7 +640,7 @@ const WorkspaceStep: React.FunctionComponent<React.PropsWithChildren<WorkspaceSt
size="medium"
behavior="forceRender"
onChange={index => {
eventLogger.log(`batch_change_execution:workspace_tab_${tabsNames[index]}:clicked`)
EVENT_LOGGER.log(`batch_change_execution:workspace_tab_${tabsNames[index]}:clicked`)
telemetryRecorder.recordEvent('batchChange.execution.tab', 'click', {
metadata: { tab: index },
})

View File

@ -7,11 +7,11 @@ import { isErrorLike, asError } from '@sourcegraph/common'
import type { Settings } from '@sourcegraph/shared/src/schema/settings.schema'
import type { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Button, Link, Icon, Tooltip } from '@sourcegraph/wildcard'
import { isBatchChangesExecutionEnabled } from '../../../batches'
import type { Scalars } from '../../../graphql-operations'
import { eventLogger } from '../../../tracking/eventLogger'
import { deleteBatchChange as _deleteBatchChange } from './backend'
@ -81,7 +81,7 @@ export const BatchChangeDetailsActionSection: React.FunctionComponent<
variant="secondary"
as={Link}
onClick={() => {
eventLogger.log('batch_change_details:edit:clicked')
EVENT_LOGGER.log('batch_change_details:edit:clicked')
telemetryRecorder.recordEvent('batchChange.details', 'edit')
}}
>
@ -96,7 +96,7 @@ export const BatchChangeDetailsActionSection: React.FunctionComponent<
outline={true}
as={Link}
onClick={() => {
eventLogger.log('batch_change_details:close:clicked')
EVENT_LOGGER.log('batch_change_details:close:clicked')
telemetryRecorder.recordEvent('batchChange.details', 'close')
}}
>

View File

@ -5,10 +5,10 @@ import { of } from 'rxjs'
import { pluralize } from '@sourcegraph/common'
import type { TelemetryRecorder, TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Button, useObservable, Icon } from '@sourcegraph/wildcard'
import { type AllChangesetIDsVariables, type Scalars, BulkOperationType } from '../../../../graphql-operations'
import { eventLogger } from '../../../../tracking/eventLogger'
import { type Action, DropdownButton } from '../../DropdownButton'
import { MultiSelectContext } from '../../MultiSelectContext'
import {
@ -53,7 +53,7 @@ const AVAILABLE_ACTIONS: Record<BulkOperationType, ChangesetListAction> = {
dropdownDescription:
'Attempt to close all selected changesets on the code hosts. The changesets will remain part of the batch change.',
onTrigger: (batchChangeID, changesetIDs, onDone, onCancel, telemetryRecorder) => {
eventLogger.log('batch_change_details:bulk_action_close:clicked')
EVENT_LOGGER.log('batch_change_details:bulk_action_close:clicked')
telemetryRecorder.recordEvent('batchChange.details.bulkAction', 'close')
return (
<CloseChangesetsModal
@ -72,7 +72,7 @@ const AVAILABLE_ACTIONS: Record<BulkOperationType, ChangesetListAction> = {
dropdownDescription:
'Create a comment on all selected changesets. For example, you could ask people for reviews, give an update, or post a cat GIF.',
onTrigger: (batchChangeID, changesetIDs, onDone, onCancel, telemetryRecorder) => {
eventLogger.log('batch_change_details:bulk_action_comment:clicked')
EVENT_LOGGER.log('batch_change_details:bulk_action_comment:clicked')
telemetryRecorder.recordEvent('batchChange.details.bulkAction', 'comment')
return (
<CreateCommentModal
@ -97,7 +97,7 @@ const AVAILABLE_ACTIONS: Record<BulkOperationType, ChangesetListAction> = {
changesetIDs={changesetIDs}
afterCreate={onDone}
onCancel={onCancel}
telemetryService={eventLogger}
telemetryService={EVENT_LOGGER}
telemetryRecorder={telemetryRecorder}
/>
),
@ -108,7 +108,7 @@ const AVAILABLE_ACTIONS: Record<BulkOperationType, ChangesetListAction> = {
dropdownTitle: 'Export Changeset(s)',
dropdownDescription: 'Export selected changesets',
onTrigger: (batchChangeID, changesetIDs, onDone, onCancel, telemetryRecorder) => {
eventLogger.log('batch_change_details:bulk_action_export:clicked')
EVENT_LOGGER.log('batch_change_details:bulk_action_export:clicked')
telemetryRecorder.recordEvent('batchChange.details.bulkAction', 'export')
return (
<ExportChangesetsModal
@ -128,7 +128,7 @@ const AVAILABLE_ACTIONS: Record<BulkOperationType, ChangesetListAction> = {
dropdownDescription:
'Attempt to merge all selected changesets. Some changesets may be unmergeable if there are rules preventing merge, such as CI requirements.',
onTrigger: (batchChangeID, changesetIDs, onDone, onCancel, telemetryRecorder) => {
eventLogger.log('batch_change_details:bulk_action_merge:clicked')
EVENT_LOGGER.log('batch_change_details:bulk_action_merge:clicked')
telemetryRecorder.recordEvent('batchChange.details.bulkAction', 'merge')
return (
<MergeChangesetsModal
@ -146,7 +146,7 @@ const AVAILABLE_ACTIONS: Record<BulkOperationType, ChangesetListAction> = {
dropdownTitle: 'Publish changesets',
dropdownDescription: 'Attempt to publish all selected changesets to the code hosts.',
onTrigger: (batchChangeID, changesetIDs, onDone, onCancel, telemetryRecorder) => {
eventLogger.log('batch_change_details:bulk_action_published:clicked')
EVENT_LOGGER.log('batch_change_details:bulk_action_published:clicked')
telemetryRecorder.recordEvent('batchChange.details.bulkAction', 'publish')
return (
<PublishChangesetsModal
@ -164,7 +164,7 @@ const AVAILABLE_ACTIONS: Record<BulkOperationType, ChangesetListAction> = {
dropdownTitle: 'Retry changesets',
dropdownDescription: 'Re-enqueues the selected changesets for processing, if they failed.',
onTrigger: (batchChangeID, changesetIDs, onDone, onCancel, telemetryRecorder) => {
eventLogger.log('batch_change_details:bulk_action_retry:clicked')
EVENT_LOGGER.log('batch_change_details:bulk_action_retry:clicked')
telemetryRecorder.recordEvent('batchChange.details.bulkAction', 'retry')
return (
<ReenqueueChangesetsModal

View File

@ -9,6 +9,7 @@ import type { Settings } from '@sourcegraph/shared/src/schema/settings.schema'
import type { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Button, PageHeader, Link, Container, H3, Text, screenReaderAnnounce } from '@sourcegraph/wildcard'
import type { AuthenticatedUser } from '../../../auth'
@ -36,7 +37,6 @@ import type {
GetLicenseAndUsageInfoResult,
GetLicenseAndUsageInfoVariables,
} from '../../../graphql-operations'
import { eventLogger } from '../../../tracking/eventLogger'
import { BATCH_CHANGES, BATCH_CHANGES_BY_NAMESPACE, GET_LICENSE_AND_USAGE_INFO } from './backend'
import { BatchChangeListFilters } from './BatchChangeListFilters'
@ -168,7 +168,7 @@ export const BatchChangeListPage: React.FunctionComponent<React.PropsWithChildre
to="https://sourcegraph.com"
variant="primary"
onClick={() => {
eventLogger.log('ClickedOnEnterpriseCTA', { location: 'TryBatchChanges' })
EVENT_LOGGER.log('ClickedOnEnterpriseCTA', { location: 'TryBatchChanges' })
telemetryRecorder.recordEvent('batchChanges.enterpriseCTA', 'click', {
metadata: { location: 0 },
})
@ -375,7 +375,7 @@ const BatchChangeListTabHeader: React.FunctionComponent<
to=""
onClick={event => {
onSelectGettingStarted(event)
eventLogger.log('batch_change_homepage:getting_started:clicked')
EVENT_LOGGER.log('batch_change_homepage:getting_started:clicked')
telemetryRecorder.recordEvent('batchChanges.gettingStarted', 'click')
}}
className={classNames('nav-link', selectedTab === 'gettingStarted' && 'active')}

View File

@ -3,12 +3,12 @@ import React from 'react'
import { mdiOpenInNew } from '@mdi/js'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Alert, Container, H2, H3, Link, Text, Icon, useReducedMotion } from '@sourcegraph/wildcard'
import { BatchChangesIcon } from '../../../batches/icons'
import { CallToActionBanner } from '../../../components/CallToActionBanner'
import { CtaBanner } from '../../../components/CtaBanner'
import { eventLogger } from '../../../tracking/eventLogger'
export interface GettingStartedProps extends TelemetryV2Props {
isSourcegraphDotCom: boolean
@ -99,7 +99,7 @@ export const GettingStarted: React.FunctionComponent<React.PropsWithChildren<Get
<Link
to="https://sourcegraph.com"
onClick={() => {
eventLogger.log('ClickedOnEnterpriseCTA', { location: 'BatchChangesGettingStarted' })
EVENT_LOGGER.log('ClickedOnEnterpriseCTA', { location: 'BatchChangesGettingStarted' })
telemetryRecorder.recordEvent('batchChanges.enterpriseCTA', 'click', {
metadata: { location: 1 },
})

View File

@ -3,10 +3,9 @@ import React from 'react'
import { mdiPlus } from '@mdi/js'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Link, type LinkProps, Button, Icon, Tooltip } from '@sourcegraph/wildcard'
import { eventLogger } from '../../../tracking/eventLogger'
interface NewBatchChangeButtonProps extends Pick<LinkProps, 'to'>, TelemetryV2Props {
// canCreate indicates whether or not the currently-authenticated user has sufficient
// permissions to create a batch change in whatever context this button is being
@ -27,7 +26,7 @@ export const NewBatchChangeButton: React.FunctionComponent<React.PropsWithChildr
variant="primary"
as={Link}
onClick={() => {
eventLogger.log('batch_change_list_page:create_batch_change_details:clicked')
EVENT_LOGGER.log('batch_change_list_page:create_batch_change_details:clicked')
telemetryRecorder.recordEvent('batchChanges', 'create')
}}
>

View File

@ -6,10 +6,10 @@ import { useNavigate } from 'react-router-dom'
import { isErrorLike } from '@sourcegraph/common'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Alert, Button, Code, Link, Tooltip, ErrorAlert } from '@sourcegraph/wildcard'
import type { BatchSpecFields } from '../../../graphql-operations'
import { eventLogger } from '../../../tracking/eventLogger'
import { MultiSelectContext } from '../MultiSelectContext'
import { applyBatchChange, createBatchChange } from './backend'
@ -121,10 +121,10 @@ export const CreateUpdateBatchChangeAlert: React.FunctionComponent<
)}
onClick={() => {
if (batchChange) {
eventLogger.log('batch_change_execution_preview:apply_update:clicked')
EVENT_LOGGER.log('batch_change_execution_preview:apply_update:clicked')
telemetryRecorder.recordEvent('batchChange.execution.updateAndApply', 'click')
} else {
eventLogger.log('batch_change_execution_preview:apply:clicked')
EVENT_LOGGER.log('batch_change_execution_preview:apply:clicked')
telemetryRecorder.recordEvent('batchChange.execution.createAndApply', 'click')
}
return onApply()

View File

@ -4,6 +4,7 @@ import { useLocation } from 'react-router-dom'
import { of } from 'rxjs'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Container, Link, H2, H3 } from '@sourcegraph/wildcard'
import type { AuthenticatedUser } from '../../auth'
@ -16,7 +17,6 @@ import type {
ListUserCodeMonitorsResult,
ListUserCodeMonitorsVariables,
} from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'
import { CodeMonitorNode, type CodeMonitorNodeProps } from './CodeMonitoringNode'
import type { CodeMonitoringPageProps } from './CodeMonitoringPage'
@ -85,7 +85,7 @@ export const CodeMonitorList: React.FunctionComponent<React.PropsWithChildren<Co
<Link
to="https://sourcegraph.com"
onClick={() => {
eventLogger.log('ClickedOnEnterpriseCTA', { location: 'Monitoring' })
EVENT_LOGGER.log('ClickedOnEnterpriseCTA', { location: 'Monitoring' })
telemetryRecorder.recordEvent('codeMonitor.enterpriseCTA', 'click', {
metadata: { location: 1 },
})

View File

@ -5,11 +5,11 @@ import classNames from 'classnames'
import type { AuthenticatedUser } from '@sourcegraph/shared/src/auth'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { useIsLightTheme } from '@sourcegraph/shared/src/theme'
import { Link, Button, CardBody, Card, Icon, H2, H3, H4, Text } from '@sourcegraph/wildcard'
import { CallToActionBanner } from '../../components/CallToActionBanner'
import { eventLogger } from '../../tracking/eventLogger'
import styles from './CodeMonitoringGettingStarted.module.scss'
@ -72,7 +72,7 @@ export const CodeMonitoringGettingStarted: React.FunctionComponent<
const assetsRoot = window.context?.assetsRoot || ''
const logExampleMonitorClicked = useCallback(() => {
eventLogger.log('CodeMonitoringExampleMonitorClicked')
EVENT_LOGGER.log('CodeMonitoringExampleMonitorClicked')
telemetryRecorder.recordEvent('codeMonitor.example', 'click')
}, [telemetryRecorder])
@ -113,7 +113,7 @@ export const CodeMonitoringGettingStarted: React.FunctionComponent<
<Link
to={ctaBannerUrl}
onClick={() => {
eventLogger.log('ClickedOnEnterpriseCTA', { location: 'MonitoringGettingStarted' })
EVENT_LOGGER.log('ClickedOnEnterpriseCTA', { location: 'MonitoringGettingStarted' })
telemetryRecorder.recordEvent('codeMonitor.enterpriseCTA', 'click', {
metadata: { location: 0 },
})

View File

@ -10,6 +10,7 @@ import { asError, isErrorLike } from '@sourcegraph/common'
import type { Settings } from '@sourcegraph/shared/src/schema/settings.schema'
import type { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import {
PageHeader,
LoadingSpinner,
@ -24,7 +25,6 @@ import {
import type { AuthenticatedUser } from '../../auth'
import { CodeMonitoringLogo } from '../../code-monitoring/CodeMonitoringLogo'
import { PageTitle } from '../../components/PageTitle'
import { eventLogger } from '../../tracking/eventLogger'
import {
fetchUserCodeMonitors as _fetchUserCodeMonitors,
@ -127,17 +127,17 @@ export const CodeMonitoringPage: React.FunctionComponent<React.PropsWithChildren
if (userHasCodeMonitors !== undefined) {
switch (currentTab) {
case 'getting-started': {
eventLogger.logPageView('CodeMonitoringGettingStartedPage')
EVENT_LOGGER.logPageView('CodeMonitoringGettingStartedPage')
telemetryRecorder.recordEvent('codeMonitor.gettingStarted', 'view')
break
}
case 'logs': {
eventLogger.logPageView('CodeMonitoringLogsPage')
EVENT_LOGGER.logPageView('CodeMonitoringLogsPage')
telemetryRecorder.recordEvent('codeMonitor.logs', 'view')
break
}
case 'list': {
eventLogger.logPageView('CodeMonitoringPage')
EVENT_LOGGER.logPageView('CodeMonitoringPage')
telemetryRecorder.recordEvent('codeMonitor.list', 'view')
}
}

View File

@ -5,6 +5,7 @@ import { useLocation } from 'react-router-dom'
import type { Observable } from 'rxjs'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { PageHeader, Link } from '@sourcegraph/wildcard'
import type { AuthenticatedUser } from '../../auth'
@ -12,7 +13,6 @@ import { withAuthenticatedUser } from '../../auth/withAuthenticatedUser'
import { CodeMonitoringLogo } from '../../code-monitoring/CodeMonitoringLogo'
import { PageTitle } from '../../components/PageTitle'
import type { CodeMonitorFields } from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'
import { convertActionsForCreate } from './action-converters'
import { createCodeMonitor as _createCodeMonitor } from './backend'
@ -42,7 +42,7 @@ const AuthenticatedCreateCodeMonitorPage: React.FunctionComponent<
)
useEffect(() => {
eventLogger.logPageView('CreateCodeMonitorPage', {
EVENT_LOGGER.logPageView('CreateCodeMonitorPage', {
hasTriggerQuery: !!triggerQuery,
hasDescription: !!description,
})
@ -53,7 +53,7 @@ const AuthenticatedCreateCodeMonitorPage: React.FunctionComponent<
const createMonitorRequest = useCallback(
(codeMonitor: CodeMonitorFields): Observable<Partial<CodeMonitorFields>> => {
eventLogger.log('CreateCodeMonitorFormSubmitted')
EVENT_LOGGER.log('CreateCodeMonitorFormSubmitted')
telemetryRecorder.recordEvent('codeMonitor.create', 'submit')
return createCodeMonitor({
monitor: {

View File

@ -7,6 +7,7 @@ import { startWith, catchError, tap } from 'rxjs/operators'
import { asError, isErrorLike } from '@sourcegraph/common'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { PageHeader, Link, LoadingSpinner, useObservable } from '@sourcegraph/wildcard'
import type { AuthenticatedUser } from '../../auth'
@ -14,7 +15,6 @@ import { withAuthenticatedUser } from '../../auth/withAuthenticatedUser'
import { CodeMonitoringLogo } from '../../code-monitoring/CodeMonitoringLogo'
import { PageTitle } from '../../components/PageTitle'
import type { CodeMonitorFields } from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'
import { convertActionsForUpdate } from './action-converters'
import {
@ -47,7 +47,7 @@ const AuthenticatedManageCodeMonitorPage: React.FunctionComponent<
const LOADING = 'loading' as const
useEffect(() => {
eventLogger.logPageView('ManageCodeMonitorPage')
EVENT_LOGGER.logPageView('ManageCodeMonitorPage')
telemetryRecorder.recordEvent('codeMonitor.manage', 'view')
}, [telemetryRecorder])
@ -84,7 +84,7 @@ const AuthenticatedManageCodeMonitorPage: React.FunctionComponent<
const updateMonitorRequest = React.useCallback(
(codeMonitor: CodeMonitorFields): Observable<Partial<CodeMonitorFields>> => {
eventLogger.log('ManageCodeMonitorFormSubmitted')
EVENT_LOGGER.log('ManageCodeMonitorFormSubmitted')
telemetryRecorder.recordEvent('codeMonitor.manage.update', 'submit')
return updateCodeMonitor(
{
@ -104,7 +104,7 @@ const AuthenticatedManageCodeMonitorPage: React.FunctionComponent<
const deleteMonitorRequest = React.useCallback(
(id: string): Observable<void> => {
eventLogger.log('ManageCodeMonitorDeleteSubmitted')
EVENT_LOGGER.log('ManageCodeMonitorDeleteSubmitted')
telemetryRecorder.recordEvent('codeMonitor.manage.delete', 'submit')
return deleteCodeMonitor(id)
},

View File

@ -4,6 +4,7 @@ import { useApolloClient } from '@apollo/client'
import { mdiMapSearch } from '@mdi/js'
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Container, Link, PageHeader, Icon, H3, Text } from '@sourcegraph/wildcard'
import {
@ -13,7 +14,6 @@ import {
} from '../../../components/FilteredConnection'
import { PageTitle } from '../../../components/PageTitle'
import type { ExecutorFields } from '../../../graphql-operations'
import { eventLogger } from '../../../tracking/eventLogger'
import { ExecutorNode } from './ExecutorNode'
import { queryExecutors as defaultQueryExecutors } from './useExecutors'
@ -49,7 +49,7 @@ export const ExecutorsListPage: React.FC<ExecutorsListPageProps> = ({
telemetryRecorder,
}) => {
useEffect(() => {
eventLogger.logViewEvent('ExecutorsList')
EVENT_LOGGER.logViewEvent('ExecutorsList')
telemetryRecorder.recordEvent('executors.list', 'view')
}, [telemetryRecorder])

View File

@ -4,9 +4,9 @@ import { lastValueFrom } from 'rxjs'
import { type ErrorLike, logger } from '@sourcegraph/common'
import { BillingCategory, BillingProduct } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { TelemetryRecorder } from '@sourcegraph/telemetry'
import { eventLogger } from '../../../tracking/eventLogger'
import { CodeInsightsBackendContext, type Insight } from '../core'
import { getTrackingTypeByInsightType } from '../pings'
import { V2InsightType } from '../pings/types'
@ -45,7 +45,7 @@ export function useDeleteInsight(
await lastValueFrom(deleteInsight(insight.id), { defaultValue: undefined })
const insightType = getTrackingTypeByInsightType(insight.type)
eventLogger.log('InsightRemoval', { insightType }, { insightType })
EVENT_LOGGER.log('InsightRemoval', { insightType }, { insightType })
telemetryRecorder.recordEvent('insight', 'delete', {
metadata: { insightType: V2InsightType[insightType] },
})

View File

@ -4,9 +4,9 @@ import { lastValueFrom } from 'rxjs'
import { type ErrorLike, logger } from '@sourcegraph/common'
import { BillingCategory, BillingProduct } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { TelemetryRecorder } from '@sourcegraph/telemetry'
import { eventLogger } from '../../../tracking/eventLogger'
import { CodeInsightsBackendContext, type Insight, type InsightDashboard } from '../core'
import { getTrackingTypeByInsightType } from '../pings'
import { V2InsightType } from '../pings/types'
@ -53,7 +53,7 @@ export function useRemoveInsightFromDashboard(
const insightType = getTrackingTypeByInsightType(insight.type)
eventLogger.log('InsightRemovalFromDashboard', { insightType }, { insightType })
EVENT_LOGGER.log('InsightRemovalFromDashboard', { insightType }, { insightType })
telemetryRecorder.recordEvent('insight', 'removeFromDashboard', {
metadata: { insightType: V2InsightType[insightType] },
})

View File

@ -4,9 +4,9 @@ import { useNavigate } from 'react-router-dom'
import { lastValueFrom } from 'rxjs'
import { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import type { SubmissionErrors } from '@sourcegraph/wildcard'
import { eventLogger } from '../../../../../../tracking/eventLogger'
import { CodeInsightsBackendContext, type CreationInsightInput } from '../../../../core'
import { useQueryParameters } from '../../../../hooks'
import { getTrackingTypeByInsightType } from '../../../../pings'
@ -46,7 +46,7 @@ export function useEditPageHandlers(props: Props): useHandleSubmitOutput {
)
const insightType = getTrackingTypeByInsightType(newInsight.type)
eventLogger.log('InsightEdit', { insightType }, { insightType })
EVENT_LOGGER.log('InsightEdit', { insightType }, { insightType })
telemetryRecorder.recordEvent('insight', 'edit', { metadata: { type: V2InsightType[insightType] } })
navigate(redirectUrl)
}

View File

@ -5,13 +5,13 @@ import classNames from 'classnames'
import type { AuthenticatedUser } from '@sourcegraph/shared/src/auth'
import { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Button, Card, CardBody, Link, PageHeader } from '@sourcegraph/wildcard'
import { CallToActionBanner } from '../../../../../components/CallToActionBanner'
import { Page } from '../../../../../components/Page'
import { PageTitle } from '../../../../../components/PageTitle'
import { CodeInsightsIcon } from '../../../../../insights/Icons'
import { eventLogger } from '../../../../../tracking/eventLogger'
import { CodeInsightsLandingPageContext, CodeInsightsLandingPageType } from '../CodeInsightsLandingPageContext'
import { CodeInsightsDescription } from '../getting-started/components/code-insights-description/CodeInsightsDescription'
@ -49,7 +49,7 @@ export const CodeInsightsDotComGetStarted: React.FunctionComponent<
to="https://sourcegraph.com"
variant="primary"
onClick={() => {
eventLogger.log('ClickedOnEnterpriseCTA', { location: 'TryInsights' })
EVENT_LOGGER.log('ClickedOnEnterpriseCTA', { location: 'TryInsights' })
telemetryRecorder.recordEvent('insights.enterpriseCTA', 'click', {
metadata: { location: 0 },
})
@ -93,7 +93,7 @@ export const CodeInsightsDotComGetStarted: React.FunctionComponent<
<Link
to="https://sourcegraph.com"
onClick={() => {
eventLogger.log('ClickedOnEnterpriseCTA', { location: 'Insights' })
EVENT_LOGGER.log('ClickedOnEnterpriseCTA', { location: 'Insights' })
telemetryRecorder.recordEvent('insights.enterpriseCTA', 'click', {
metadata: { location: 0 },
})

View File

@ -4,12 +4,12 @@ import { mdiMagnify, mdiPlus } from '@mdi/js'
import type { PlatformContextProps } from '@sourcegraph/shared/src/platform/context'
import type { SearchContextProps } from '@sourcegraph/shared/src/search'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { PageHeader, Link, Button, Icon, Alert } from '@sourcegraph/wildcard'
import type { AuthenticatedUser } from '../../auth'
import { CallToActionBanner } from '../../components/CallToActionBanner'
import { Page } from '../../components/Page'
import { eventLogger } from '../../tracking/eventLogger'
import { SearchContextsList } from './SearchContextsList'
@ -65,7 +65,7 @@ export const SearchContextsListPage: React.FunctionComponent<SearchContextsListP
<Link
to="https://sourcegraph.com"
onClick={() => {
eventLogger.log('ClickedOnEnterpriseCTA', { location: 'ContextsSettings' })
EVENT_LOGGER.log('ClickedOnEnterpriseCTA', { location: 'ContextsSettings' })
platformContext.telemetryRecorder.recordEvent(
'searchContexts.enterpriseCTA',
'click'

View File

@ -5,13 +5,13 @@ import { map } from 'rxjs/operators'
import { createAggregateError } from '@sourcegraph/common'
import { gql } from '@sourcegraph/http-client'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Badge, Link, H2, Text } from '@sourcegraph/wildcard'
import { queryGraphQL } from '../../backend/graphql'
import { FilteredConnection } from '../../components/FilteredConnection'
import { PageTitle } from '../../components/PageTitle'
import type { AuthProviderFields, AuthProvidersResult } from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'
interface AuthProviderNodeProps {
/** The auth provider to display in this item. */
@ -58,7 +58,7 @@ interface Props {}
*/
export class SiteAdminAuthenticationProvidersPage extends React.Component<Props> {
public componentDidMount(): void {
eventLogger.logViewEvent('SiteAdminAuthentication')
EVENT_LOGGER.logViewEvent('SiteAdminAuthentication')
}
public render(): JSX.Element | null {

View File

@ -6,6 +6,7 @@ import { map } from 'rxjs/operators'
import { createAggregateError } from '@sourcegraph/common'
import { gql } from '@sourcegraph/http-client'
import type { Scalars } from '@sourcegraph/shared/src/graphql-operations'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Button, Link, H2, Text } from '@sourcegraph/wildcard'
import { requestGraphQL } from '../../backend/graphql'
@ -17,7 +18,6 @@ import type {
ExternalAccountsResult,
ExternalAccountsVariables,
} from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'
import {
ExternalAccountNode,
type ExternalAccountNodeProps,
@ -41,7 +41,7 @@ export class SiteAdminExternalAccountsPage extends React.Component<Props> {
private externalAccountUpdates = new Subject<void>()
public componentDidMount(): void {
eventLogger.logViewEvent('SiteAdminExternalAccounts')
EVENT_LOGGER.logViewEvent('SiteAdminExternalAccounts')
}
public componentWillUnmount(): void {

View File

@ -4,10 +4,10 @@ import { Navigate, useParams } from 'react-router-dom'
import { catchError } from 'rxjs/operators'
import { asError, type ErrorLike, isErrorLike } from '@sourcegraph/common'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { LoadingSpinner, useObservable, ErrorAlert } from '@sourcegraph/wildcard'
import { PageTitle } from '../../components/PageTitle'
import { eventLogger } from '../../tracking/eventLogger'
import { fetchPreciseIndex } from './backend'
@ -16,7 +16,7 @@ import { fetchPreciseIndex } from './backend'
*/
export const SiteAdminPreciseIndexPage: React.FC<{}> = () => {
const { id = '' } = useParams<{ id: string }>()
useEffect(() => eventLogger.logViewEvent('SiteAdminPreciseIndex'))
useEffect(() => EVENT_LOGGER.logViewEvent('SiteAdminPreciseIndex'))
const indexOrError = useObservable(
useMemo(() => fetchPreciseIndex({ id }).pipe(catchError((error): [ErrorLike] => [asError(error)])), [id])

View File

@ -6,6 +6,7 @@ import { map } from 'rxjs/operators'
import { createAggregateError } from '@sourcegraph/common'
import { gql } from '@sourcegraph/http-client'
import { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Container, Link, PageHeader, Text } from '@sourcegraph/wildcard'
import { queryGraphQL } from '../../../backend/graphql'
@ -17,7 +18,6 @@ import type {
ProductSubscriptionsVariables,
UserAreaUserFields,
} from '../../../graphql-operations'
import { eventLogger } from '../../../tracking/eventLogger'
import {
ProductSubscriptionNode,
ProductSubscriptionNodeHeader,
@ -89,7 +89,7 @@ export const UserSubscriptionsProductSubscriptionsPage: React.FunctionComponent<
<Link
to="https://sourcegraph.com"
onClick={() => {
eventLogger.log('ClickedOnEnterpriseCTA', { location: 'Subscriptions' })
EVENT_LOGGER.log('ClickedOnEnterpriseCTA', { location: 'Subscriptions' })
props.telemetryRecorder.recordEvent('settings.userSubscriptions.enterpriseCTA', 'click')
}}
>

View File

@ -1,9 +1,8 @@
import classNames from 'classnames'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Badge, Icon, Link } from '@sourcegraph/wildcard'
import { eventLogger } from '../tracking/eventLogger'
import styles from './DownloadAppButton.module.scss'
interface DownloadAppButtonProps {
@ -24,7 +23,7 @@ export const DownloadAppButton: React.FunctionComponent<DownloadAppButtonProps>
eventType,
}) => {
const handleOnClick = (): void => {
eventLogger.log(eventName, { type: eventType })
EVENT_LOGGER.log(eventName, { type: eventType })
}
return (

View File

@ -6,6 +6,7 @@ import { useNavigate, useLocation } from 'react-router-dom'
import type { AuthenticatedUser } from '@sourcegraph/shared/src/auth'
import { noOpTelemetryRecorder } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Badge, H2, Icon, Link, PageHeader, Text } from '@sourcegraph/wildcard'
import { ExternalsAuth } from '../auth/components/ExternalsAuth'
@ -13,7 +14,6 @@ import { CodyLetsWorkIcon } from '../cody/chat/CodyPageIcon'
import { Page } from '../components/Page'
import { PageTitle } from '../components/PageTitle'
import type { SourcegraphContext } from '../jscontext'
import { eventLogger } from '../tracking/eventLogger'
import { EventName } from '../util/constants'
import { DownloadAppButton } from './DownloadAppButton'
@ -39,9 +39,9 @@ const SOURCEGRAPH_MAC_INTEL = 'https://sourcegraph.com/.api/app/latest?arch=x86_
const SOURCEGRAPH_LINUX = 'https://sourcegraph.com/.api/app/latest?arch=x86_64&target=linux'
const logEvent = (eventName: string, type?: string, source?: string): void =>
eventLogger.log(eventName, { type, source })
EVENT_LOGGER.log(eventName, { type, source })
const logPageView = (pageTitle: string): void => eventLogger.logPageView(pageTitle)
const logPageView = (pageTitle: string): void => EVENT_LOGGER.logPageView(pageTitle)
/* eslint-disable @sourcegraph/sourcegraph/check-help-links */
@ -112,7 +112,7 @@ export const GetCodyPage: React.FunctionComponent<GetCodyPageProps> = ({ authent
onClick={() => {}}
ctaClassName={styles.authButton}
telemetryRecorder={noOpTelemetryRecorder}
telemetryService={eventLogger}
telemetryService={EVENT_LOGGER}
/>
</div>
</div>

View File

@ -4,10 +4,9 @@ import classNames from 'classnames'
import { range } from 'lodash'
import { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Button } from '@sourcegraph/wildcard'
import { eventLogger } from '../../tracking/eventLogger'
import radioStyles from './SurveyRatingRadio.module.scss'
interface SurveyRatingRadio extends TelemetryV2Props {
@ -29,7 +28,7 @@ export const SurveyRatingRadio: React.FunctionComponent<React.PropsWithChildren<
}
const handleChange = (score: number): void => {
eventLogger.log('SurveyButtonClicked', { score }, { score })
EVENT_LOGGER.log('SurveyButtonClicked', { score }, { score })
props.telemetryRecorder.recordEvent('surveyNPS.button', 'click', { metadata: { score } })
if (props.onChange) {

View File

@ -4,11 +4,11 @@ import { useNavigate } from 'react-router-dom'
import { useMutation, gql } from '@sourcegraph/http-client'
import { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Button, LoadingSpinner, Label, Text, Form } from '@sourcegraph/wildcard'
import type { AuthenticatedUser } from '../../auth'
import type { SubmitSurveyResult, SubmitSurveyVariables } from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'
import { SurveyRatingRadio } from '../components/SurveyRatingRadio'
import { SurveyUseCaseForm } from '../components/SurveyUseCaseForm'
@ -79,7 +79,7 @@ export const SurveyForm: React.FunctionComponent<React.PropsWithChildren<SurveyF
return
}
eventLogger.log('SurveySubmitted')
EVENT_LOGGER.log('SurveySubmitted')
telemetryRecorder.recordEvent('surveyNPS', 'submit')
await submitSurvey({

View File

@ -3,12 +3,12 @@ import React, { useEffect } from 'react'
import { useParams, useLocation } from 'react-router-dom'
import { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { FeedbackText } from '@sourcegraph/wildcard'
import type { AuthenticatedUser } from '../../auth'
import { HeroPage } from '../../components/HeroPage'
import { PageTitle } from '../../components/PageTitle'
import { eventLogger } from '../../tracking/eventLogger'
import { TweetFeedback } from '../components/TweetFeedback'
import { SurveyForm } from './SurveyForm'
@ -32,7 +32,7 @@ export const SurveyPage: React.FunctionComponent<React.PropsWithChildren<SurveyP
const score = props.forceScore || matchParameters.score
useEffect(() => {
eventLogger.logViewEvent('Survey')
EVENT_LOGGER.logViewEvent('Survey')
props.telemetryRecorder.recordEvent('surveyNPS.page', 'view')
}, [props.telemetryRecorder])

View File

@ -3,10 +3,10 @@ import React, { useEffect, useState } from 'react'
import { gql, useMutation } from '@apollo/client'
import { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import type { AuthenticatedUser } from '../../auth'
import type { SubmitSurveyResult, SubmitSurveyVariables } from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'
import { SurveySuccessToast } from './SurveySuccessToast'
import { SurveyUseCaseToast } from './SurveyUseCaseToast'
@ -58,7 +58,7 @@ export const SurveyToastContent: React.FunctionComponent<React.PropsWithChildren
})
useEffect(() => {
eventLogger.log('SurveyReminderViewed')
EVENT_LOGGER.log('SurveyReminderViewed')
telemetryRecorder.recordEvent('surveyNPS.toast', 'view')
}, [telemetryRecorder])

View File

@ -6,12 +6,12 @@ import classNames from 'classnames'
import type { AuthenticatedUser } from '@sourcegraph/shared/src/auth'
import { useTemporarySetting } from '@sourcegraph/shared/src/settings/temporary/useTemporarySetting'
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { useIsLightTheme } from '@sourcegraph/shared/src/theme'
import { Container, Icon, Link, H2, H3, Text, useReducedMotion } from '@sourcegraph/wildcard'
import { CallToActionBanner } from '../../components/CallToActionBanner'
import { PageRoutes } from '../../routes.constants'
import { eventLogger } from '../../tracking/eventLogger'
import styles from './NotebooksGettingStartedTab.module.scss'
@ -131,7 +131,7 @@ export const NotebooksGettingStartedTab: React.FunctionComponent<
<Link
to="https://sourcegraph.com"
onClick={() =>
eventLogger.log('ClickedOnEnterpriseCTA', { location: 'NotebooksGettingStarted' })
EVENT_LOGGER.log('ClickedOnEnterpriseCTA', { location: 'NotebooksGettingStarted' })
}
>
get Sourcegraph Enterprise

View File

@ -12,9 +12,9 @@ import {
} from '@sourcegraph/shared/src/backend/file'
import type { PlatformContextProps } from '@sourcegraph/shared/src/platform/context'
import { aggregateStreamingSearch } from '@sourcegraph/shared/src/search/stream'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Alert, LoadingSpinner, useObservable } from '@sourcegraph/wildcard'
import { eventLogger } from '../../tracking/eventLogger'
import { fetchNotebook } from '../backend'
import { convertNotebookTitleToFileName } from '../serialize'
@ -32,7 +32,7 @@ const LOADING = 'loading' as const
export const EmbeddedNotebookPage: FC<EmbeddedNotebookPageProps> = ({ platformContext, ...props }) => {
const { notebookId } = useParams()
useEffect(() => eventLogger.logPageView('EmbeddedNotebookPage'), [])
useEffect(() => EVENT_LOGGER.logPageView('EmbeddedNotebookPage'), [])
platformContext.telemetryRecorder.recordEvent('embeddedNotebook', 'view')
const notebookOrError = useObservable(
@ -78,7 +78,7 @@ export const EmbeddedNotebookPage: FC<EmbeddedNotebookPageProps> = ({ platformCo
viewerCanManage={false}
fetchHighlightedFileLineRanges={fetchHighlightedFileLineRanges}
streamSearch={aggregateStreamingSearch}
telemetryService={eventLogger}
telemetryService={EVENT_LOGGER}
telemetryRecorder={platformContext.telemetryRecorder}
platformContext={platformContext}
exportedFileName={convertNotebookTitleToFileName(notebookOrError.title)}

View File

@ -9,6 +9,7 @@ import { SimpleActionItem } from '@sourcegraph/shared/src/actions/SimpleActionIt
import type { PlatformContext } from '@sourcegraph/shared/src/platform/context'
import { isSettingsValid, type Settings } from '@sourcegraph/shared/src/settings/settings'
import { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import {
Button,
Icon,
@ -22,7 +23,6 @@ import {
import { RepoHeaderActionAnchor, RepoHeaderActionMenuLink } from '../repo/components/RepoHeaderActions'
import { RepoActionInfo } from '../repo/RepoActionInfo'
import { eventLogger } from '../tracking/eventLogger'
import { getEditorSettingsErrorMessage } from './build-url'
import type { EditorSettings } from './editor-settings'
@ -110,7 +110,7 @@ export const OpenInEditorActionItem: React.FunctionComponent<OpenInEditorActionI
/>
}
onClick={() => {
eventLogger.log('OpenInEditorClicked', { editor: editor.id }, { editor: editor.id })
EVENT_LOGGER.log('OpenInEditorClicked', { editor: editor.id }, { editor: editor.id })
props.telemetryRecorder.recordEvent('blob.openInEditor', 'click', {
metadata: { editor: editor.telemetryID },
})

View File

@ -7,6 +7,7 @@ import { catchError, concatMap, distinctUntilKeyChanged, map, tap, withLatestFro
import { asError, type ErrorLike, isErrorLike, logger } from '@sourcegraph/common'
import { dataOrThrowErrors, gql } from '@sourcegraph/http-client'
import { OrganizationInvitationResponseType } from '@sourcegraph/shared/src/graphql-operations'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { LoadingSpinner, Button, Link, Alert, H3, Text, ErrorAlert, Form } from '@sourcegraph/wildcard'
import { orgURL } from '..'
@ -19,7 +20,6 @@ import type {
RespondToOrganizationInvitationResult,
RespondToOrganizationInvitationVariables,
} from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'
import { userURL } from '../../user'
import { OrgAvatar } from '../OrgAvatar'
@ -51,7 +51,7 @@ export const OrgInvitationPageLegacy = withAuthenticatedUser(
private subscriptions = new Subscription()
public componentDidMount(): void {
eventLogger.logViewEvent('OrgInvitation')
EVENT_LOGGER.logViewEvent('OrgInvitation')
const orgChanges = this.componentUpdates.pipe(
distinctUntilKeyChanged('org'),
@ -74,7 +74,7 @@ export const OrgInvitationPageLegacy = withAuthenticatedUser(
organizationInvitation: org.viewerPendingInvitation!.id,
responseType,
}).pipe(
tap(() => eventLogger.log('OrgInvitationRespondedTo')),
tap(() => EVENT_LOGGER.log('OrgInvitationRespondedTo')),
tap(() =>
this.props.onDidRespondToInvitation(
responseType === OrganizationInvitationResponseType.ACCEPT

View File

@ -3,6 +3,7 @@ import { map, mergeMap } from 'rxjs/operators'
import { createAggregateError } from '@sourcegraph/common'
import { gql } from '@sourcegraph/http-client'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { refreshAuthenticatedUser } from '../auth'
import { requestGraphQL } from '../backend/graphql'
@ -15,7 +16,6 @@ import type {
UpdateOrganizationResult,
UpdateOrganizationVariables,
} from '../graphql-operations'
import { eventLogger } from '../tracking/eventLogger'
export const ORGANIZATION_MEMBERS_QUERY = gql`
query OrganizationSettingsMembers(
@ -80,10 +80,10 @@ export function createOrganization(args: {
).pipe(
mergeMap(({ data, errors }) => {
if (!data?.createOrganization) {
eventLogger.log('NewOrgFailed')
EVENT_LOGGER.log('NewOrgFailed')
throw createAggregateError(errors)
}
eventLogger.log('NewOrgCreated')
EVENT_LOGGER.log('NewOrgCreated')
return concat(refreshAuthenticatedUser(), [data.createOrganization])
})
)
@ -115,10 +115,10 @@ export function removeUserFromOrganization(args: {
).pipe(
mergeMap(({ errors }) => {
if (errors && errors.length > 0) {
eventLogger.log('RemoveOrgMemberFailed')
EVENT_LOGGER.log('RemoveOrgMemberFailed')
throw createAggregateError(errors)
}
eventLogger.log('OrgMemberRemoved')
EVENT_LOGGER.log('OrgMemberRemoved')
// Reload user data
return concat(refreshAuthenticatedUser(), [undefined])
})
@ -149,10 +149,10 @@ export function updateOrganization(id: Scalars['ID'], displayName: string): Prom
).pipe(
map(({ data, errors }) => {
if (!data || (errors && errors.length > 0)) {
eventLogger.log('UpdateOrgSettingsFailed')
EVENT_LOGGER.log('UpdateOrgSettingsFailed')
throw createAggregateError(errors)
}
eventLogger.log('OrgSettingsUpdated')
EVENT_LOGGER.log('OrgSettingsUpdated')
return
})
)

View File

@ -7,6 +7,7 @@ import { logger } from '@sourcegraph/common'
import { gql, useMutation, useQuery } from '@sourcegraph/http-client'
import { UserAvatar } from '@sourcegraph/shared/src/components/UserAvatar'
import { OrganizationInvitationResponseType } from '@sourcegraph/shared/src/graphql-operations'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Alert, AnchorLink, Button, LoadingSpinner, Link, H2, H3, Form } from '@sourcegraph/wildcard'
import { orgURL } from '..'
@ -19,7 +20,6 @@ import type {
RespondToOrgInvitationResult,
RespondToOrgInvitationVariables,
} from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'
import { userURL } from '../../user'
import { OrgAvatar } from '../OrgAvatar'
@ -92,7 +92,7 @@ export const OrgInvitationPage: React.FunctionComponent<React.PropsWithChildren<
const willVerifyEmail = data?.recipientEmail && !data?.isVerifiedEmail
useEffect(() => {
eventLogger.logPageView('OrganizationInvitation', { organizationId: orgId, invitationId: data?.id })
EVENT_LOGGER.logPageView('OrganizationInvitation', { organizationId: orgId, invitationId: data?.id })
}, [orgId, data?.id])
const [respondToInvitation, { loading: respondLoading, error: respondError }] = useMutation<
@ -105,7 +105,7 @@ export const OrgInvitationPage: React.FunctionComponent<React.PropsWithChildren<
})
const acceptInvitation = useCallback(async () => {
eventLogger.log(
EVENT_LOGGER.log(
'OrganizationInvitationAcceptClicked',
{
organizationId: orgId,
@ -125,13 +125,13 @@ export const OrgInvitationPage: React.FunctionComponent<React.PropsWithChildren<
response: OrganizationInvitationResponseType.ACCEPT,
},
})
eventLogger.log(
EVENT_LOGGER.log(
'OrganizationInvitationAcceptSucceeded',
{ organizationId: orgId, invitationId: data?.id },
{ organizationId: orgId, invitationId: data?.id }
)
} catch {
eventLogger.log(
EVENT_LOGGER.log(
'OrganizationInvitationAcceptFailed',
{ organizationId: orgId, invitationId: data?.id },
{ organizationId: orgId, invitationId: data?.id }
@ -145,7 +145,7 @@ export const OrgInvitationPage: React.FunctionComponent<React.PropsWithChildren<
}, [data?.id, navigate, orgId, orgName, respondToInvitation, willVerifyEmail])
const declineInvitation = useCallback(async () => {
eventLogger.log(
EVENT_LOGGER.log(
'OrganizationInvitationDeclineClicked',
{
organizationId: orgId,
@ -165,13 +165,13 @@ export const OrgInvitationPage: React.FunctionComponent<React.PropsWithChildren<
response: OrganizationInvitationResponseType.REJECT,
},
})
eventLogger.log(
EVENT_LOGGER.log(
'OrganizationInvitationDeclineSucceeded',
{ organizationId: orgId, invitationId: data?.id },
{ organizationId: orgId, invitationId: data?.id }
)
} catch {
eventLogger.log(
EVENT_LOGGER.log(
'OrganizationInvitationDeclineFailed',
{ organizationId: orgId, invitationId: data?.id },
{ organizationId: orgId, invitationId: data?.id }

View File

@ -3,12 +3,12 @@ import React, { useCallback, useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { asError, isErrorLike } from '@sourcegraph/common'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Button, Container, PageHeader, LoadingSpinner, Link, Input, ErrorAlert, Form } from '@sourcegraph/wildcard'
import { ORG_NAME_MAX_LENGTH, VALID_ORG_NAME_REGEXP } from '..'
import { Page } from '../../components/Page'
import { PageTitle } from '../../components/PageTitle'
import { eventLogger } from '../../tracking/eventLogger'
import { createOrganization } from '../backend'
import styles from './NewOrganizationPage.module.scss'
@ -18,7 +18,7 @@ interface Props {}
export const NewOrganizationPage: React.FunctionComponent<React.PropsWithChildren<Props>> = () => {
const navigate = useNavigate()
useEffect(() => {
eventLogger.logViewEvent('NewOrg')
EVENT_LOGGER.logViewEvent('NewOrg')
}, [])
const [loading, setLoading] = useState<boolean | Error>(false)
const [name, setName] = useState<string>('')
@ -36,7 +36,7 @@ export const NewOrganizationPage: React.FunctionComponent<React.PropsWithChildre
const onSubmit = useCallback<React.FormEventHandler<HTMLFormElement>>(
async event => {
event.preventDefault()
eventLogger.log('CreateNewOrgClicked')
EVENT_LOGGER.log('CreateNewOrgClicked')
if (!event.currentTarget.checkValidity()) {
return
}

View File

@ -4,9 +4,9 @@ import { gql, useMutation } from '@apollo/client'
import { mdiClose } from '@mdi/js'
import { useNavigate } from 'react-router-dom'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Button, Input, LoadingSpinner, Modal, Icon, H3, Text } from '@sourcegraph/wildcard'
import { eventLogger } from '../../tracking/eventLogger'
import type { OrgAreaRouteContext } from '../area/OrgArea'
interface DeleteOrgModalProps extends OrgAreaRouteContext {
@ -52,7 +52,7 @@ export const DeleteOrgModal: React.FunctionComponent<React.PropsWithChildren<Del
pathname: '/settings',
})
} catch {
eventLogger.log('OrgDeletionFailed')
EVENT_LOGGER.log('OrgDeletionFailed')
}
}, [org, deleteOrganization, navigate])

View File

@ -8,6 +8,7 @@ import { map } from 'rxjs/operators'
import { asError, createAggregateError, isErrorLike } from '@sourcegraph/common'
import { gql } from '@sourcegraph/http-client'
import type { Scalars } from '@sourcegraph/shared/src/graphql-operations'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import {
LoadingSpinner,
Button,
@ -33,7 +34,6 @@ import type {
AddUserToOrganizationVariables,
InviteUserToOrganizationFields,
} from '../../../graphql-operations'
import { eventLogger } from '../../../tracking/eventLogger'
import styles from './InviteForm.module.scss'
@ -68,7 +68,7 @@ export const InviteForm: React.FunctionComponent<React.PropsWithChildren<Props>>
const [isInviteShown, setShowInvitation] = useState<boolean>(false)
const inviteUser = useCallback(() => {
eventLogger.log('InviteOrgMemberClicked')
EVENT_LOGGER.log('InviteOrgMemberClicked')
;(async () => {
setLoading('inviteUserToOrganization')
const { invitationURL, sentInvitationEmail } = await inviteUserToOrganization(username, orgID)
@ -226,10 +226,10 @@ function inviteUserToOrganization(
).pipe(
map(({ data, errors }) => {
if (!data?.inviteUserToOrganization || (errors && errors.length > 0)) {
eventLogger.log('InviteOrgMemberFailed')
EVENT_LOGGER.log('InviteOrgMemberFailed')
throw createAggregateError(errors)
}
eventLogger.log('OrgMemberInvited')
EVENT_LOGGER.log('OrgMemberInvited')
return data.inviteUserToOrganization
})
)
@ -253,10 +253,10 @@ function addUserToOrganization(username: string, organization: Scalars['ID']): P
).pipe(
map(({ data, errors }) => {
if (!data?.addUserToOrganization || (errors && errors.length > 0)) {
eventLogger.log('AddOrgMemberFailed')
EVENT_LOGGER.log('AddOrgMemberFailed')
throw createAggregateError(errors)
}
eventLogger.log('OrgMemberAdded')
EVENT_LOGGER.log('OrgMemberAdded')
})
)
)

View File

@ -6,6 +6,7 @@ import { useNavigate } from 'react-router-dom'
import { pluralize } from '@sourcegraph/common'
import { useMutation } from '@sourcegraph/http-client'
import { UserAvatar } from '@sourcegraph/shared/src/components/UserAvatar'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import {
Container,
PageHeader,
@ -31,7 +32,6 @@ import type {
RemoveUserFromOrganizationResult,
RemoveUserFromOrganizationVariables,
} from '../../../graphql-operations'
import { eventLogger } from '../../../tracking/eventLogger'
import { userURL } from '../../../user'
import type { OrgAreaRouteContext } from '../../area/OrgArea'
import { ORGANIZATION_MEMBERS_QUERY, REMOVE_USER_FROM_ORGANIZATION_QUERY } from '../../backend'
@ -136,7 +136,7 @@ export const OrgSettingsMembersPage: React.FunctionComponent<Props> = ({
onOrganizationUpdate,
}) => {
React.useEffect(() => {
eventLogger.logViewEvent('OrgMembers')
EVENT_LOGGER.logViewEvent('OrgMembers')
}, [])
const navigate = useNavigate()

View File

@ -2,11 +2,11 @@ import React, { useCallback, useEffect, useState } from 'react'
import { Timestamp } from '@sourcegraph/branded/src/components/Timestamp'
import { asError, isErrorLike } from '@sourcegraph/common'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Container, PageHeader, Button, LoadingSpinner, Input, Text, ErrorAlert, Form } from '@sourcegraph/wildcard'
import { ORG_DISPLAY_NAME_MAX_LENGTH } from '../..'
import { PageTitle } from '../../../components/PageTitle'
import { eventLogger } from '../../../tracking/eventLogger'
import type { OrgAreaRouteContext } from '../../area/OrgArea'
import { updateOrganization } from '../../backend'
@ -20,7 +20,7 @@ export const OrgSettingsProfilePage: React.FunctionComponent<React.PropsWithChil
onOrganizationUpdate,
}) => {
useEffect(() => {
eventLogger.logViewEvent('OrgSettingsProfile')
EVENT_LOGGER.logViewEvent('OrgSettingsProfile')
}, [org.id])
const [displayName, setDisplayName] = useState<string>(org.displayName ?? '')

View File

@ -9,6 +9,7 @@ import type { ViewerSettingsResult, ViewerSettingsVariables } from '@sourcegraph
import type { PlatformContext } from '@sourcegraph/shared/src/platform/context'
import { mutateSettings, updateSettings } from '@sourcegraph/shared/src/settings/edit'
import { gqlToCascade, type SettingsSubject } from '@sourcegraph/shared/src/settings/settings'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import {
toPrettyBlobURL,
type RepoFile,
@ -21,7 +22,6 @@ import { CallbackTelemetryProcessor } from '@sourcegraph/telemetry'
import { getWebGraphQLClient, requestGraphQL } from '../backend/graphql'
import type { TelemetryRecorderProvider } from '../telemetry'
import { eventLogger } from '../tracking/eventLogger'
/**
* Creates the {@link PlatformContext} for the web app.
@ -91,7 +91,7 @@ export function createPlatformContext(props: {
urlToFile: toPrettyWebBlobURL,
sourcegraphURL: window.context.externalURL,
clientApplication: 'sourcegraph',
telemetryService: eventLogger,
telemetryService: EVENT_LOGGER,
telemetryRecorder: props.telemetryRecorderProvider.getRecorder(
window.context.debug
? [

View File

@ -20,6 +20,7 @@ import {
import { viewerSettingsQuery } from '@sourcegraph/shared/src/backend/settings'
import type { ViewerSettingsResult, ViewerSettingsVariables } from '@sourcegraph/shared/src/graphql-operations'
import type { PlatformContext } from '@sourcegraph/shared/src/platform/context'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import type { Config } from '@sourcegraph/shared/src/testing/config'
import type {
@ -594,10 +595,10 @@ export function createOrganization(
}).pipe(
mergeMap(({ data, errors }) => {
if (!data?.createOrganization) {
eventLogger.log('NewOrgFailed')
EVENT_LOGGER.log('NewOrgFailed')
throw createAggregateError(errors)
}
eventLogger.log('NewOrgCreated')
EVENT_LOGGER.log('NewOrgCreated')
return concat([data.createOrganization])
})
)
@ -711,10 +712,10 @@ export function addExternalService(
}).pipe(
map(({ data, errors }) => {
if (!data?.addExternalService || (errors && errors.length > 0)) {
eventLogger.log('AddExternalServiceFailed')
EVENT_LOGGER.log('AddExternalServiceFailed')
throw createAggregateError(errors)
}
eventLogger.log('AddExternalServiceSucceeded')
EVENT_LOGGER.log('AddExternalServiceSucceeded')
return data.addExternalService
})
)

View File

@ -4,6 +4,7 @@ import { createAggregateError } from '@sourcegraph/common'
import { gql } from '@sourcegraph/http-client'
import type { Scalars } from '@sourcegraph/shared/src/graphql-operations'
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { useDebounce } from '@sourcegraph/wildcard'
import { useShowMorePagination } from '../../components/FilteredConnection/hooks/useShowMorePagination'
@ -19,7 +20,6 @@ import type {
RepositoriesForPopoverVariables,
RepositoryPopoverFields,
} from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'
import {
ConnectionPopover,
ConnectionPopoverContainer,
@ -69,7 +69,7 @@ export const RepositoriesPopover: React.FunctionComponent<React.PropsWithChildre
const query = useDebounce(searchValue, 200)
useEffect(() => {
eventLogger.logViewEvent('RepositoriesPopover')
EVENT_LOGGER.logViewEvent('RepositoriesPopover')
telemetryService.log('RepositoriesPopover')
}, [telemetryService])

View File

@ -2,10 +2,10 @@ import * as React from 'react'
import MapSearchIcon from 'mdi-react/MapSearchIcon'
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
import { Code, Link, Text } from '@sourcegraph/wildcard'
import { HeroPage } from '../components/HeroPage'
import { eventLogger } from '../tracking/eventLogger'
import styles from './RepositoryNotFoundPage.module.scss'
@ -22,7 +22,7 @@ interface Props {
* attempts to present the user with actions to solve the problem.
*/
export const RepositoryNotFoundPage: React.FunctionComponent<Props> = ({ repo, viewerCanAdminister }) => {
React.useEffect(() => eventLogger.logViewEvent('RepositoryError'), [])
React.useEffect(() => EVENT_LOGGER.logViewEvent('RepositoryError'), [])
return (
<HeroPage

Some files were not shown because too many files have changed in this diff Show More