Skip to content

Commit 1b09512

Browse files
Adriana IxbaDevtools-frontend LUCI CQ
authored andcommitted
[RPP] Create 3p checkbox behind an experiment
https://screencast.googleplex.com/cast/NTIzMzM4NzExMDQwMDAwMHxlYTY5OWI3Zi01NQ Bug:383568427 Change-Id: Ieef63de82f9a77e2e2c3cdfee8c2a790fbfa8962 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6087616 Reviewed-by: Adam Raine <[email protected]> Commit-Queue: Adriana Ixba <[email protected]>
1 parent 435b93d commit 1b09512

File tree

10 files changed

+151
-8
lines changed

10 files changed

+151
-8
lines changed

front_end/core/host/UserMetrics.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -942,8 +942,9 @@ export enum KeyboardShortcutAction {
942942
'elements.refresh-event-listeners' = 115,
943943
'coverage.clear' = 116,
944944
'coverage.export' = 117,
945+
'timeline.dim-third-parties' = 118,
945946
/* eslint-enable @typescript-eslint/naming-convention */
946-
MAX_VALUE = 118,
947+
MAX_VALUE = 119,
947948
}
948949

949950
export const enum IssueOpener {
@@ -994,10 +995,11 @@ export enum DevtoolsExperiments {
994995
'timeline-dim-unrelated-events' = 103,
995996
'timeline-alternative-navigation' = 104,
996997
'timeline-ignore-list' = 105,
998+
'timeline-third-party-dependencies' = 106,
997999
/* eslint-enable @typescript-eslint/naming-convention */
9981000

9991001
// Increment this when new experiments are added.
1000-
MAX_VALUE = 106,
1002+
MAX_VALUE = 107,
10011003
}
10021004

10031005
export const enum CSSPropertyDocumentation {

front_end/core/root/Runtime.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ export const enum ExperimentName {
301301
TIMELINE_DIM_UNRELATED_EVENTS = 'timeline-dim-unrelated-events',
302302
TIMELINE_ALTERNATIVE_NAVIGATION = 'timeline-alternative-navigation',
303303
TIMELINE_IGNORE_LIST = 'timeline-ignore-list',
304+
TIMELINE_THIRD_PARTY_DEPENDENCIES = 'timeline-third-party-dependencies',
304305
// when adding to this enum, you'll need to also add to REGISTERED_EXPERIMENTS in EnvironmentHelpers.ts
305306
}
306307

front_end/entrypoints/main/MainImpl.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,11 @@ export class MainImpl {
408408
'Performance panel: enable an ignore list setting dialog',
409409
);
410410

411+
Root.Runtime.experiments.register(
412+
Root.Runtime.ExperimentName.TIMELINE_THIRD_PARTY_DEPENDENCIES,
413+
'Performance panel: enable third party depenedency features',
414+
);
415+
411416
Root.Runtime.experiments.enableExperimentsByDefault([
412417
'css-type-component-length-deprecate',
413418
Root.Runtime.ExperimentName.AUTOFILL_VIEW,

front_end/panels/timeline/TimelineFlameChartView.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,13 @@ export class TimelineFlameChartView extends
389389
return this.element;
390390
}
391391

392+
dimEvents(events: Trace.Types.Events.Event[]): void {
393+
const relatedMainIndices = events.map(event => this.mainDataProvider.indexForEvent(event) ?? -1);
394+
const relatedNetworkIndices = events.map(event => this.networkDataProvider.indexForEvent(event) ?? -1);
395+
this.mainFlameChart.enableDimming(relatedMainIndices, false /** shouldAddOutlines */);
396+
this.networkFlameChart.enableDimming(relatedNetworkIndices, false /** shouldAddOutlines */);
397+
}
398+
392399
#dimInsightRelatedEvents(relatedEvents: Trace.Types.Events.Event[]): void {
393400
// Dim all events except those related to the active insight.
394401
const relatedMainIndices = relatedEvents.map(event => this.mainDataProvider.indexForEvent(event) ?? -1);
@@ -435,8 +442,13 @@ export class TimelineFlameChartView extends
435442

436443
relevantEvents.push(...provider.search(bounds).map(r => r.index));
437444
}
438-
this.mainFlameChart.enableDimming(relatedMainIndices);
439-
this.networkFlameChart.enableDimming(relatedNetworkIndices);
445+
this.mainFlameChart.enableDimmingForUnrelatedEntries(relatedMainIndices);
446+
this.networkFlameChart.enableDimmingForUnrelatedEntries(relatedNetworkIndices);
447+
}
448+
449+
disableAllDimming(): void {
450+
this.mainFlameChart.disableDimming();
451+
this.networkFlameChart.disableDimming();
440452
}
441453

442454
#sortMarkersForPreferredVisualOrder(markers: Trace.Types.Events.Event[]): void {

front_end/panels/timeline/TimelinePanel.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,10 @@ const UIStrings = {
329329
* @description Description of the Timeline right/left panning action that appears in the Performance panel shortcuts dialog.
330330
*/
331331
timelinePanLeftRight: 'Timeline right/left',
332+
/**
333+
* @description Title for the Dim 3rd Parties checkbox.
334+
*/
335+
dimThirdParties: 'Dim 3rd Parties',
332336
};
333337
const str_ = i18n.i18n.registerUIStrings('panels/timeline/TimelinePanel.ts', UIStrings);
334338
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -374,6 +378,7 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
374378
private readonly timelinePane: UI.Widget.VBox;
375379
readonly #minimapComponent = new TimelineMiniMap();
376380
#viewMode: ViewMode = {mode: 'LANDING_PAGE'};
381+
readonly #dimThirdPartiesSetting: Common.Settings.Setting<boolean>|null = null;
377382

378383
/**
379384
* We get given any filters for a new trace when it is recorded/imported.
@@ -424,6 +429,7 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
424429

425430
#traceEngineModel: Trace.TraceModel.Model;
426431
#sourceMapsResolver: Utils.SourceMapsResolver.SourceMapsResolver|null = null;
432+
#entityMapper: Utils.EntityMapper.EntityMapper|null = null;
427433
#onSourceMapsNodeNamesResolvedBound = this.#onSourceMapsNodeNamesResolved.bind(this);
428434
readonly #onChartPlayableStateChangeBound: (event: Common.EventTarget.EventTargetEvent<boolean>) => void;
429435
#sidebarToggleButton = this.#splitWidget.createShowHideSidebarButton(
@@ -533,6 +539,13 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
533539
this.showMemorySetting.setTitle(i18nString(UIStrings.memory));
534540
this.showMemorySetting.addChangeListener(this.onMemoryModeChanged, this);
535541

542+
if (Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.TIMELINE_THIRD_PARTY_DEPENDENCIES)) {
543+
this.#dimThirdPartiesSetting =
544+
Common.Settings.Settings.instance().createSetting('timeline-dim-third-parties', false);
545+
this.#dimThirdPartiesSetting.setTitle(i18nString(UIStrings.dimThirdParties));
546+
this.#dimThirdPartiesSetting.addChangeListener(this.onDimThirdPartiesChanged, this);
547+
}
548+
536549
this.#thirdPartyTracksSetting = TimelinePanel.extensionDataVisibilitySetting();
537550
this.#thirdPartyTracksSetting.addChangeListener(this.#extensionDataVisibilityChanged, this);
538551
this.#thirdPartyTracksSetting.setTitle(i18nString(UIStrings.showCustomtracks));
@@ -879,6 +892,7 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
879892
this.#setModelForActiveTrace();
880893
this.#removeStatusPane();
881894
this.#showSidebarIfRequired();
895+
this.#dimThirdPartiesIfRequired(newMode.traceIndex);
882896
return;
883897
}
884898

@@ -1106,6 +1120,13 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
11061120
this.panelToolbar.appendToolbarItem(new UI.Toolbar.ToolbarItem(showIgnoreListSetting));
11071121
}
11081122

1123+
if (Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.TIMELINE_THIRD_PARTY_DEPENDENCIES) &&
1124+
this.#dimThirdPartiesSetting) {
1125+
const dimThirdPartiesCheckbox =
1126+
this.createSettingCheckbox(this.#dimThirdPartiesSetting, i18nString(UIStrings.dimThirdParties));
1127+
this.panelToolbar.appendToolbarItem(dimThirdPartiesCheckbox);
1128+
}
1129+
11091130
// Isolate selector
11101131
if (isNode) {
11111132
const isolateSelector = new IsolateSelector();
@@ -1491,6 +1512,13 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
14911512
this.select(null);
14921513
}
14931514

1515+
private onDimThirdPartiesChanged(): void {
1516+
if (this.#viewMode.mode !== 'VIEWING_TRACE') {
1517+
return;
1518+
}
1519+
this.#dimThirdPartiesIfRequired(this.#viewMode.traceIndex);
1520+
}
1521+
14941522
#extensionDataVisibilityChanged(): void {
14951523
this.flameChart.extensionDataVisibilityChanged();
14961524
}
@@ -2002,6 +2030,9 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
20022030
Utils.SourceMapsResolver.SourceMappingsUpdated.eventName, this.#onSourceMapsNodeNamesResolvedBound);
20032031
void this.#sourceMapsResolver.install();
20042032

2033+
// Initialize EntityMapper
2034+
this.#entityMapper = new Utils.EntityMapper.EntityMapper(parsedTrace);
2035+
20052036
this.statusPane?.updateProgressBar(i18nString(UIStrings.processed), 80);
20062037
this.updateMiniMap();
20072038
this.statusPane?.updateProgressBar(i18nString(UIStrings.processed), 90);
@@ -2085,6 +2116,20 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
20852116
this.#restoreSidebarVisibilityOnTraceLoad = false;
20862117
}
20872118

2119+
#dimThirdPartiesIfRequired(traceIndex: number): void {
2120+
const parsedTrace = this.#traceEngineModel.parsedTrace(traceIndex);
2121+
if (!parsedTrace) {
2122+
return;
2123+
}
2124+
const thirdPartyEvents = this.#entityMapper?.thirdPartyEvents() ?? [];
2125+
if (this.#dimThirdPartiesSetting?.get() && thirdPartyEvents.length) {
2126+
this.flameChart.dimEvents(thirdPartyEvents);
2127+
} else {
2128+
// Ensure dimming stores are cleared, and there is no dimming.
2129+
this.flameChart.disableAllDimming();
2130+
}
2131+
}
2132+
20882133
// Build a map mapping annotated entries to the colours that are used to display them in the FlameChart.
20892134
// We need this map to display the entries in the sidebar with the same colours.
20902135
private buildColorsAnnotationsMap(annotations: Trace.Types.File.Annotation[]): Map<Trace.Types.Events.Event, string> {

front_end/panels/timeline/utils/EntityMapper.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,34 @@ describeWithEnvironment('EntityMapper', function() {
9191
});
9292
});
9393
});
94+
describe('first party', () => {
95+
it('correctly captures the first party entity', async function() {
96+
const {parsedTrace: localhostTrace} = await TraceLoader.traceEngine(this, 'load-simple.json.gz');
97+
let mapper = new Utils.EntityMapper.EntityMapper(localhostTrace);
98+
let got = mapper.firstPartyEntity();
99+
assert.deepEqual(got?.name, 'localhost');
100+
101+
const {parsedTrace: paulTrace} = await TraceLoader.traceEngine(this, 'lantern/paul/trace.json.gz');
102+
mapper = new Utils.EntityMapper.EntityMapper(paulTrace);
103+
got = mapper.firstPartyEntity();
104+
assert.deepEqual(got?.name, 'paulirish.com');
105+
106+
const {parsedTrace: webDevTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz');
107+
mapper = new Utils.EntityMapper.EntityMapper(webDevTrace);
108+
got = mapper.firstPartyEntity();
109+
assert.deepEqual(got?.name, 'web.dev');
110+
});
111+
it('correctly captures 3p events', async function() {
112+
const {parsedTrace: paulTrace} = await TraceLoader.traceEngine(this, 'lantern/paul/trace.json.gz');
113+
const mapper = new Utils.EntityMapper.EntityMapper(paulTrace);
114+
const got = mapper.firstPartyEntity();
115+
assert.exists(got);
116+
assert.deepEqual(got.name, 'paulirish.com');
117+
const firstPartyEvents = mapper.eventsForEntity(got);
118+
const gotThirdPartyEvents = mapper.thirdPartyEvents();
119+
gotThirdPartyEvents.forEach(e => {
120+
assert.isTrue(!firstPartyEvents.includes(e));
121+
});
122+
});
123+
});
94124
});

front_end/panels/timeline/utils/EntityMapper.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,19 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import type * as Trace from '../../../models/trace/trace.js';
5+
import * as Trace from '../../../models/trace/trace.js';
66

77
export class EntityMapper {
88
#parsedTrace: Trace.Handlers.Types.ParsedTrace;
99
#entityMappings: Trace.Handlers.Helpers.EntityMappings;
10+
#firstPartyEntity: Trace.Handlers.Helpers.Entity|null;
11+
#thirdPartyEvents: Trace.Types.Events.Event[] = [];
1012

1113
constructor(parsedTrace: Trace.Handlers.Types.ParsedTrace) {
1214
this.#parsedTrace = parsedTrace;
1315
this.#entityMappings = this.#initializeEntityMappings(this.#parsedTrace);
16+
this.#firstPartyEntity = this.#findFirstPartyEntity();
17+
this.#thirdPartyEvents = this.#getThirdPartyEvents();
1418
}
1519

1620
/**
@@ -40,6 +44,21 @@ export class EntityMapper {
4044
};
4145
}
4246

47+
#findFirstPartyEntity(): Trace.Handlers.Helpers.Entity|null {
48+
// As a starting point, we consider the first navigation as the 1P.
49+
const nav = Array.from(this.#parsedTrace.Meta.navigationsByNavigationId.values()).sort((a, b) => a.ts - b.ts)[0];
50+
const firstPartyUrl = nav?.args.data?.documentLoaderURL ?? this.#parsedTrace.Meta.mainFrameURL;
51+
return Trace.Handlers.Helpers.getEntityForUrl(firstPartyUrl, this.#entityMappings.createdEntityCache) ?? null;
52+
}
53+
54+
#getThirdPartyEvents(): Trace.Types.Events.Event[] {
55+
const entries = Array.from(this.#entityMappings.eventsByEntity.entries());
56+
const thirdPartyEvents = entries.flatMap(([entity, requests]) => {
57+
return entity.name !== this.#firstPartyEntity?.name ? requests : [];
58+
});
59+
return thirdPartyEvents;
60+
}
61+
4362
#mergeEventsByEntities(
4463
a: Map<Trace.Handlers.Helpers.Entity, Trace.Types.Events.Event[]>,
4564
b: Map<Trace.Handlers.Helpers.Entity, Trace.Types.Events.Event[]>):
@@ -70,6 +89,14 @@ export class EntityMapper {
7089
return this.#entityMappings.eventsByEntity.get(entity) ?? [];
7190
}
7291

92+
firstPartyEntity(): Trace.Handlers.Helpers.Entity|null {
93+
return this.#firstPartyEntity;
94+
}
95+
96+
thirdPartyEvents(): Trace.Types.Events.Event[] {
97+
return this.#thirdPartyEvents;
98+
}
99+
73100
mappings(): Trace.Handlers.Helpers.EntityMappings {
74101
return this.#entityMappings;
75102
}

front_end/testing/EnvironmentHelpers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ const REGISTERED_EXPERIMENTS = [
132132
Root.Runtime.ExperimentName.TIMELINE_DIM_UNRELATED_EVENTS,
133133
Root.Runtime.ExperimentName.TIMELINE_ALTERNATIVE_NAVIGATION,
134134
Root.Runtime.ExperimentName.TIMELINE_IGNORE_LIST,
135+
Root.Runtime.ExperimentName.TIMELINE_THIRD_PARTY_DEPENDENCIES,
135136
];
136137

137138
export async function initializeGlobalVars({reset = true} = {}) {

front_end/ui/legacy/components/perf_ui/FlameChart.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ export class FlameChart extends Common.ObjectWrapper.eventMixin<EventTypes, type
313313
private forceDecorationCache?: boolean[]|null;
314314
private entryColorsCache?: string[]|null;
315315
private entryIndicesToNotDim?: number[]|null;
316+
private entryIndicesToDim?: number[]|null;
316317
private colorDimmingCache = new Map<string, string>();
317318
private totalTime?: number;
318319
private lastPopoverState: PopoverState;
@@ -332,6 +333,8 @@ export class FlameChart extends Common.ObjectWrapper.eventMixin<EventTypes, type
332333

333334
#indexToDrawOverride = new Map<number, DrawOverride>();
334335

336+
#shouldAddOutlines: boolean = true;
337+
335338
constructor(
336339
dataProvider: FlameChartDataProvider, flameChartDelegate: FlameChartDelegate,
337340
optionalConfig: OptionalFlameChartConfig = {}) {
@@ -496,7 +499,12 @@ export class FlameChart extends Common.ObjectWrapper.eventMixin<EventTypes, type
496499

497500
#shouldDimEvent(entryIndex: number): boolean {
498501
// If a search is active, that enables a mode where we dim all events that do not match the search results.
499-
// Otherwise the events to not dim are defined by the last call to `enableDimming`.
502+
if (this.entryIndicesToDim && !this.#searchResultEntries) {
503+
return this.entryIndicesToDim.includes(entryIndex);
504+
}
505+
506+
// Otherwise the events to not dim are defined by the last call to `enableDimmingForUnrelatedEntries` or
507+
// `enableDimming`.
500508
const entriesToNotDim = this.#searchResultEntries ?? this.entryIndicesToNotDim;
501509
if (!entriesToNotDim) {
502510
return false;
@@ -505,13 +513,22 @@ export class FlameChart extends Common.ObjectWrapper.eventMixin<EventTypes, type
505513
return !entriesToNotDim.includes(entryIndex);
506514
}
507515

508-
enableDimming(entryIndicesToNotDim: number[]): void {
516+
enableDimming(entryIndices: number[], shouldAddOutlines: boolean): void {
517+
this.entryIndicesToDim = entryIndices;
518+
this.#shouldAddOutlines = shouldAddOutlines;
519+
this.entryIndicesToNotDim = [];
520+
this.draw();
521+
}
522+
523+
enableDimmingForUnrelatedEntries(entryIndicesToNotDim: number[]): void {
509524
this.entryIndicesToNotDim = entryIndicesToNotDim;
525+
this.entryIndicesToDim = [];
510526
this.draw();
511527
}
512528

513529
disableDimming(): void {
514530
this.entryIndicesToNotDim = null;
531+
this.entryIndicesToDim = null;
515532
this.draw();
516533
}
517534

@@ -2265,7 +2282,7 @@ export class FlameChart extends Common.ObjectWrapper.eventMixin<EventTypes, type
22652282
this.#drawEventRect(context, timelineData, entryIndex);
22662283
}
22672284

2268-
if (!shouldDim) {
2285+
if (!shouldDim && this.#shouldAddOutlines) {
22692286
// In some scenarios we want to draw outlines around events for added visual contrast.
22702287
// But we only do this if the events are not being dimmed.
22712288
this.#maybeAddOutlines(context, color);
@@ -3326,6 +3343,7 @@ export class FlameChart extends Common.ObjectWrapper.eventMixin<EventTypes, type
33263343
this.forceDecorationCache = null;
33273344
this.entryColorsCache = null;
33283345
this.entryIndicesToNotDim = null;
3346+
this.entryIndicesToDim = null;
33293347
this.colorDimmingCache.clear();
33303348
this.rawTimelineDataLength = 0;
33313349
this.#groupTreeRoot = null;
@@ -3937,6 +3955,7 @@ export class FlameChart extends Common.ObjectWrapper.eventMixin<EventTypes, type
39373955
this.rawTimelineDataLength = 0;
39383956
this.#groupTreeRoot = null;
39393957
this.entryIndicesToNotDim = null;
3958+
this.entryIndicesToDim = null;
39403959
this.colorDimmingCache.clear();
39413960
this.highlightedMarkerIndex = -1;
39423961
this.highlightedEntryIndex = -1;

front_end/ui/visual_logging/KnownContextValues.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3391,6 +3391,7 @@ export const knownContextValues = new Set([
33913391
'timeline-counters-graph-js-heap-size-used',
33923392
'timeline-counters-graph-nodes',
33933393
'timeline-debug-mode',
3394+
'timeline-dim-third-parties',
33943395
'timeline-dim-unrelated-events',
33953396
'timeline-disable-js-sampling',
33963397
'timeline-enhanced-traces',

0 commit comments

Comments
 (0)