Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/core/src/domain/telemetry/telemetryEvent.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,11 @@ export type TelemetryConfigurationEvent = CommonTelemetryProperties & {
*/
beta_encode_cookie_options?: boolean
[k: string]: unknown

/**
* Whether the allowed HTML attributes list is used
*/
use_allowed_html_attributes?: boolean
}
[k: string]: unknown
}
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/tools/experimentalFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export enum ExperimentalFeature {
USE_CHANGE_RECORDS = 'use_change_records',
SOURCE_CODE_CONTEXT = 'source_code_context',
LCP_SUBPARTS = 'lcp_subparts',
COMPOSED_PATH_SELECTOR = 'composed_path_selector',
}

const enabledExperimentalFeatures: Set<ExperimentalFeature> = new Set()
Expand Down
19 changes: 19 additions & 0 deletions packages/rum-core/src/domain/action/trackClickActions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ describe('trackClickActions', () => {
selector: '#button',
width: 100,
height: 100,
composed_path_selector: undefined,
},
position: { x: 50, y: 50 },
events: [domEvent],
Expand Down Expand Up @@ -698,6 +699,24 @@ describe('trackClickActions', () => {
expect(events[0].target?.selector).not.toContain(SHADOW_DOM_MARKER)
})
})

describe('when composed path selector is enabled', () => {
it('should return a composed_path_selector', () => {
addExperimentalFeatures([ExperimentalFeature.COMPOSED_PATH_SELECTOR])
startClickActionsTracking()
emulateClick({
target: button,
activity: {},
eventProperty: {
composed: true,
composedPath: () => [button, document.body, document],
},
})

clock.tick(EXPIRE_DELAY)
expect(events[0].target?.composed_path_selector).toBeDefined()
})
})
})

describe('finalizeClicks', () => {
Expand Down
22 changes: 21 additions & 1 deletion packages/rum-core/src/domain/action/trackClickActions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import type { Duration, ClocksState, TimeStamp } from '@datadog/browser-core'
import { timeStampNow, Observable, timeStampToClocks, relativeToClocks, generateUUID } from '@datadog/browser-core'
import {
timeStampNow,
Observable,
timeStampToClocks,
relativeToClocks,
generateUUID,
isExperimentalFeatureEnabled,
ExperimentalFeature,
} from '@datadog/browser-core'
import { isNodeShadowHost } from '../../browser/htmlDomUtils'
import type { FrustrationType } from '../../rawRumEvent.types'
import { ActionType } from '../../rawRumEvent.types'
Expand All @@ -13,6 +21,7 @@ import type { RumConfiguration } from '../configuration'
import type { RumMutationRecord } from '../../browser/domMutationObservable'
import { startEventTracker } from '../eventTracker'
import type { StoppedEvent, DiscardedEvent, EventTracker } from '../eventTracker'
import { getComposedPathSelector } from '../getComposedPathSelector'
import type { ClickChain } from './clickChain'
import { createClickChain } from './clickChain'
import { getActionNameFromElement } from './getActionNameFromElement'
Expand All @@ -36,6 +45,7 @@ export interface ClickAction {
nameSource: ActionNameSource
target?: {
selector: string | undefined
composed_path_selector?: string
width: number
height: number
}
Expand Down Expand Up @@ -236,6 +246,15 @@ function computeClickActionBase(
const rect = target.getBoundingClientRect()
const selector = getSelectorFromElement(target, configuration.actionNameAttribute)

const composedPathSelector =
isExperimentalFeatureEnabled(ExperimentalFeature.COMPOSED_PATH_SELECTOR) && typeof event.composedPath === 'function'
? getComposedPathSelector(
event.composedPath(),
configuration.actionNameAttribute,
configuration.allowedHtmlAttributes || []
)
: undefined

if (selector) {
updateInteractionSelector(event.timeStamp, selector)
}
Expand All @@ -248,6 +267,7 @@ function computeClickActionBase(
width: Math.round(rect.width),
height: Math.round(rect.height),
selector,
composed_path_selector: composedPathSelector ?? undefined,
},
position: {
// Use clientX and Y because for SVG element offsetX and Y are relatives to the <svg> element
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,7 @@ describe('serializeRumConfiguration', () => {
profilingSampleRate: 42,
propagateTraceBaggage: true,
betaTrackActionsInShadowDom: true,
allowedHtmlAttributes: ['data-testid'],
}

type MapRumInitConfigurationKey<Key extends string> = Key extends keyof InitConfiguration
Expand All @@ -641,6 +642,7 @@ describe('serializeRumConfiguration', () => {
| 'excludedActivityUrls'
| 'remoteConfigurationProxy'
| 'allowedGraphQlUrls'
| 'allowedHtmlAttributes'
? `use_${CamelToSnakeCase<Key>}`
: Key extends 'trackLongTasks'
? 'track_long_task' // We forgot the s, keeping this for backward compatibility
Expand Down Expand Up @@ -687,6 +689,7 @@ describe('serializeRumConfiguration', () => {
remote_configuration_id: '123',
use_remote_configuration_proxy: true,
profiling_sample_rate: 42,
use_allowed_html_attributes: true,
})
})
})
14 changes: 14 additions & 0 deletions packages/rum-core/src/domain/configuration/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,15 @@ export interface RumInitConfiguration extends InitConfiguration {
* @category Data Collection
*/
allowedGraphQlUrls?: Array<MatchOption | GraphQlUrlOption> | undefined

/**
* A list of HTML attributes allowed to be used in the action selector collection.
* Matches attributes against the event target and its ancestors.
* If not provided, the SDK will use a default list of HTML attributes.
*
* @category Data Collection
*/
allowedHtmlAttributes?: MatchOption[] | undefined
}

export type HybridInitConfiguration = Omit<RumInitConfiguration, 'applicationId' | 'clientToken'>
Expand Down Expand Up @@ -321,6 +330,7 @@ export interface RumConfiguration extends Configuration {
profilingSampleRate: number
propagateTraceBaggage: boolean
allowedGraphQlUrls: GraphQlUrlOption[]
allowedHtmlAttributes?: MatchOption[]
}

export function validateAndBuildRumConfiguration(
Expand Down Expand Up @@ -400,6 +410,9 @@ export function validateAndBuildRumConfiguration(
profilingSampleRate: initConfiguration.profilingSampleRate ?? 0,
propagateTraceBaggage: !!initConfiguration.propagateTraceBaggage,
allowedGraphQlUrls,
allowedHtmlAttributes: Array.isArray(initConfiguration.allowedHtmlAttributes)
? initConfiguration.allowedHtmlAttributes.filter(isMatchOption)
: [],
...baseConfiguration,
}
}
Expand Down Expand Up @@ -548,6 +561,7 @@ export function serializeRumConfiguration(configuration: RumInitConfiguration) {
remote_configuration_id: configuration.remoteConfigurationId,
profiling_sample_rate: configuration.profilingSampleRate,
use_remote_configuration_proxy: !!configuration.remoteConfigurationProxy,
use_allowed_html_attributes: isNonEmptyArray(configuration.allowedHtmlAttributes),
...baseSerializedConfiguration,
} satisfies RawTelemetryConfiguration
}
Loading
Loading