chrome-devtools-frontend 1.0.1604514 → 1.0.1605219

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/AUTHORS +1 -0
  2. package/front_end/Tests.js +23 -7
  3. package/front_end/core/host/AidaClient.ts +114 -63
  4. package/front_end/core/host/AidaGcaTranslation.ts +6 -0
  5. package/front_end/core/host/GcaClient.ts +112 -0
  6. package/front_end/core/host/UserMetrics.ts +0 -1
  7. package/front_end/core/host/host.ts +2 -0
  8. package/front_end/core/root/ExperimentNames.ts +0 -1
  9. package/front_end/core/root/Runtime.ts +5 -0
  10. package/front_end/core/sdk/AutofillModel.ts +3 -2
  11. package/front_end/core/sdk/CSSModel.ts +3 -4
  12. package/front_end/core/sdk/CSSProperty.ts +1 -1
  13. package/front_end/core/sdk/ConsoleModel.ts +15 -13
  14. package/front_end/core/sdk/CookieModel.ts +5 -4
  15. package/front_end/core/sdk/DOMDebuggerModel.ts +20 -14
  16. package/front_end/core/sdk/DebuggerModel.ts +21 -36
  17. package/front_end/core/sdk/EventBreakpointsModel.ts +16 -6
  18. package/front_end/core/sdk/IsolateManager.ts +12 -7
  19. package/front_end/entrypoints/main/MainImpl.ts +0 -4
  20. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +31 -17
  21. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +1 -1
  22. package/front_end/models/emulation/DeviceModeModel.ts +21 -26
  23. package/front_end/models/trace/insights/LCPDiscovery.ts +14 -6
  24. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +2 -17
  25. package/front_end/panels/ai_assistance/components/ChatMessage.ts +36 -20
  26. package/front_end/panels/ai_assistance/components/chatMessage.css +5 -1
  27. package/front_end/panels/application/ApplicationPanelSidebar.ts +6 -0
  28. package/front_end/panels/application/IndexedDBViews.ts +0 -9
  29. package/front_end/panels/application/WebMCPTreeElement.ts +35 -0
  30. package/front_end/panels/application/WebMCPView.ts +118 -0
  31. package/front_end/panels/application/application.ts +4 -0
  32. package/front_end/panels/application/webMCPView.css +65 -0
  33. package/front_end/panels/common/aiCodeCompletionSummaryToolbar.css +1 -1
  34. package/front_end/panels/console/consoleView.css +4 -0
  35. package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +23 -2
  36. package/front_end/panels/elements/StylesSidebarPane.ts +85 -20
  37. package/front_end/panels/elements/elementsPanel.css +14 -0
  38. package/front_end/panels/network/NetworkLogViewColumns.ts +3 -3
  39. package/front_end/panels/recorder/components/recordingView.css +0 -6
  40. package/front_end/panels/sensors/SensorsView.ts +28 -59
  41. package/front_end/panels/timeline/EventsTimelineTreeView.ts +2 -2
  42. package/front_end/panels/timeline/ThirdPartyTreeView.ts +35 -36
  43. package/front_end/panels/timeline/TimelineDetailsView.ts +47 -41
  44. package/front_end/panels/timeline/TimelineTreeView.ts +13 -13
  45. package/front_end/panels/timeline/components/LiveMetricsView.ts +839 -783
  46. package/front_end/panels/timeline/thirdPartyTreeView.css +2 -2
  47. package/front_end/ui/components/buttons/button.css +2 -2
  48. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +0 -11
  49. package/front_end/ui/legacy/InspectorDrawerView.ts +206 -0
  50. package/front_end/ui/legacy/InspectorView.ts +41 -91
  51. package/front_end/ui/legacy/ViewManager.ts +14 -5
  52. package/front_end/ui/legacy/inspectorDrawerTabbedPane.css +5 -0
  53. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -1
  54. package/package.json +1 -1
@@ -169,6 +169,10 @@ const HIGHLIGHTABLE_PROPERTIES = [
169
169
  {mode: 'flexibility', properties: ['flex', 'flex-basis', 'flex-grow', 'flex-shrink']},
170
170
  ];
171
171
 
172
+ const DISCLAIMER_TOOLTIP_ID = 'styles-ai-code-completion-disclaimer-tooltip';
173
+ const SPINNER_TOOLTIP_ID = 'styles-ai-code-completion-spinner-tooltip';
174
+ const CITATIONS_TOOLTIP_ID = 'styles-ai-code-completion-citations-tooltip';
175
+
172
176
  export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventTypes, typeof ElementsSidebarPane>(
173
177
  ElementsSidebarPane) implements StylesContainer {
174
178
  private matchedStyles: SDK.CSSMatchedStyles.CSSMatchedStyles|null = null;
@@ -214,6 +218,11 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
214
218
  #updateAbortController?: AbortController;
215
219
  #updateComputedStylesAbortController?: AbortController;
216
220
 
221
+ aiCodeCompletionConfig?: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig;
222
+ aiCodeCompletionProvider?: StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider;
223
+ #aiCodeCompletionSummaryToolbarContainer?: HTMLElement;
224
+ #aiCodeCompletionSummaryToolbar?: PanelsCommon.AiCodeCompletionSummaryToolbar;
225
+
217
226
  constructor(computedStyleModel: ComputedStyle.ComputedStyleModel.ComputedStyleModel) {
218
227
  super(computedStyleModel, {delegatesFocus: true});
219
228
  this.setMinimumSize(96, 26);
@@ -259,6 +268,26 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
259
268
  this.#scheduleResetUpdateIfNotEditing();
260
269
  }
261
270
  });
271
+
272
+ const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
273
+ if (AiCodeCompletion.AiCodeCompletion.AiCodeCompletion.isAiCodeCompletionStylesEnabled(devtoolsLocale.locale)) {
274
+ this.aiCodeCompletionConfig = {
275
+ completionContext: {},
276
+ generationContext: {},
277
+ onFeatureEnabled: () => {
278
+ this.#createAiCodeCompletionSummaryToolbar();
279
+ },
280
+ onFeatureDisabled: () => {
281
+ this.#cleanupAiCodeCompletion();
282
+ },
283
+ onSuggestionAccepted: this.#onAiCodeCompletionSuggestionAccepted.bind(this),
284
+ onRequestTriggered: this.#onAiCodeCompletionRequestTriggered.bind(this),
285
+ onResponseReceived: this.#onAiCodeCompletionResponseReceived.bind(this),
286
+ panel: AiCodeCompletion.AiCodeCompletion.ContextFlavor.STYLES,
287
+ };
288
+ this.aiCodeCompletionProvider =
289
+ StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider.createInstance(this.aiCodeCompletionConfig);
290
+ }
262
291
  }
263
292
 
264
293
  get webCustomData(): WebCustomData|undefined {
@@ -1528,6 +1557,45 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
1528
1557
 
1529
1558
  return button;
1530
1559
  }
1560
+
1561
+ #cleanupAiCodeCompletion(): void {
1562
+ this.#aiCodeCompletionSummaryToolbarContainer?.remove();
1563
+ this.#aiCodeCompletionSummaryToolbarContainer = undefined;
1564
+ this.#aiCodeCompletionSummaryToolbar = undefined;
1565
+ }
1566
+
1567
+ #createAiCodeCompletionSummaryToolbar(): void {
1568
+ if (this.#aiCodeCompletionSummaryToolbar) {
1569
+ return;
1570
+ }
1571
+ this.#aiCodeCompletionSummaryToolbar = new PanelsCommon.AiCodeCompletionSummaryToolbar({
1572
+ citationsTooltipId: CITATIONS_TOOLTIP_ID,
1573
+ disclaimerTooltipId: DISCLAIMER_TOOLTIP_ID,
1574
+ spinnerTooltipId: SPINNER_TOOLTIP_ID,
1575
+ panel: AiCodeCompletion.AiCodeCompletion.ContextFlavor.STYLES,
1576
+ });
1577
+ const containingPane = this.contentElement.enclosingNodeOrSelfWithClass('style-panes-wrapper') as HTMLElement;
1578
+ this.#aiCodeCompletionSummaryToolbarContainer =
1579
+ containingPane.createChild('div', 'ai-code-completion-summary-toolbar-container');
1580
+ this.#aiCodeCompletionSummaryToolbarContainer.role = 'toolbar';
1581
+ this.#aiCodeCompletionSummaryToolbar.show(this.#aiCodeCompletionSummaryToolbarContainer, undefined, true);
1582
+ }
1583
+
1584
+ #onAiCodeCompletionSuggestionAccepted(citations: Host.AidaClient.Citation[]): void {
1585
+ if (!this.#aiCodeCompletionSummaryToolbar || citations.length === 0) {
1586
+ return;
1587
+ }
1588
+ const citationsUri = citations.map(citation => citation.uri).filter((uri): uri is string => Boolean(uri));
1589
+ this.#aiCodeCompletionSummaryToolbar.updateCitations(citationsUri);
1590
+ }
1591
+
1592
+ #onAiCodeCompletionRequestTriggered(): void {
1593
+ this.#aiCodeCompletionSummaryToolbar?.setLoading(true);
1594
+ }
1595
+
1596
+ #onAiCodeCompletionResponseReceived(): void {
1597
+ this.#aiCodeCompletionSummaryToolbar?.setLoading(false);
1598
+ }
1531
1599
  }
1532
1600
 
1533
1601
  export const enum Events {
@@ -1757,8 +1825,9 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
1757
1825
  private treeElement: StylePropertyTreeElement;
1758
1826
  private isEditingName: boolean;
1759
1827
  private readonly cssVariables: string[];
1760
- aiCodeCompletionConfig?: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig;
1761
1828
  aiCodeCompletionProvider?: StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider;
1829
+ private activeAiSuggestionInfo?:
1830
+ {citations: Host.AidaClient.Citation[], rpcGlobalId?: Host.AidaClient.RpcGlobalId, sampleId?: number};
1762
1831
 
1763
1832
  #debouncedTriggerAiCodeCompletion = Common.Debouncer.debounce(() => {
1764
1833
  void this.triggerAiCodeCompletion();
@@ -1822,25 +1891,13 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
1822
1891
  }
1823
1892
  }
1824
1893
 
1825
- const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
1826
- if (AiCodeCompletion.AiCodeCompletion.AiCodeCompletion.isAiCodeCompletionStylesEnabled(devtoolsLocale.locale)) {
1827
- this.aiCodeCompletionConfig = {
1828
- completionContext: {},
1829
- generationContext: {},
1830
- onFeatureEnabled: () => {},
1831
- onFeatureDisabled: () => {},
1832
- onSuggestionAccepted: () => {},
1833
- onRequestTriggered: () => {},
1834
- onResponseReceived: () => {},
1835
- panel: AiCodeCompletion.AiCodeCompletion.ContextFlavor.STYLES,
1836
- getCompletionHint: this.getCompletionHint.bind(this),
1837
- getCurrentText: () => {
1838
- return this.text();
1839
- },
1840
- setAiAutoCompletion: this.setAiAutoCompletion.bind(this),
1841
- };
1842
- this.aiCodeCompletionProvider =
1843
- StylesAiCodeCompletionProvider.StylesAiCodeCompletionProvider.createInstance(this.aiCodeCompletionConfig);
1894
+ const stylesContainer = this.treeElement.stylesContainer();
1895
+ if (stylesContainer instanceof StylesSidebarPane) {
1896
+ this.aiCodeCompletionProvider = stylesContainer.aiCodeCompletionProvider;
1897
+ if (this.aiCodeCompletionProvider) {
1898
+ this.aiCodeCompletionProvider.getCompletionHint = this.getCompletionHint.bind(this);
1899
+ this.aiCodeCompletionProvider.setAiAutoCompletion = this.setAiAutoCompletion.bind(this);
1900
+ }
1844
1901
  }
1845
1902
  }
1846
1903
 
@@ -2192,11 +2249,13 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
2192
2249
  startTime: number,
2193
2250
  onImpression: (rpcGlobalId: Host.AidaClient.RpcGlobalId, latency: number, sampleId?: number) => void,
2194
2251
  clearCachedRequest: () => void,
2252
+ citations: Host.AidaClient.Citation[],
2195
2253
  rpcGlobalId?: Host.AidaClient.RpcGlobalId,
2196
2254
  sampleId?: number,
2197
2255
  }|null): void {
2198
2256
  if (!args) {
2199
2257
  this.treeElement.section().activeAiSuggestion = undefined;
2258
+ this.activeAiSuggestionInfo = undefined;
2200
2259
  return;
2201
2260
  }
2202
2261
 
@@ -2207,6 +2266,7 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
2207
2266
  clearCachedRequest: args.clearCachedRequest,
2208
2267
  cssProperty: this.treeElement.property,
2209
2268
  };
2269
+ this.activeAiSuggestionInfo = {citations: args.citations, rpcGlobalId: args.rpcGlobalId, sampleId: args.sampleId};
2210
2270
  const latency = performance.now() - args.startTime;
2211
2271
  if (args.rpcGlobalId) {
2212
2272
  args.onImpression(args.rpcGlobalId, latency, args.sampleId);
@@ -2305,6 +2365,11 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
2305
2365
 
2306
2366
  async commitAiSuggestion(): Promise<void> {
2307
2367
  await this.treeElement.section().commitActiveAiSuggestion();
2368
+ if (this.activeAiSuggestionInfo) {
2369
+ this.aiCodeCompletionProvider?.onSuggestionAccepted(
2370
+ this.activeAiSuggestionInfo.citations, this.activeAiSuggestionInfo.rpcGlobalId,
2371
+ this.activeAiSuggestionInfo.sampleId);
2372
+ }
2308
2373
  // Clear state and return
2309
2374
  this.setAiAutoCompletion(null);
2310
2375
  }
@@ -47,6 +47,20 @@
47
47
  border-bottom: 1px solid var(--sys-color-divider);
48
48
  }
49
49
 
50
+ .style-panes-wrapper > div:has(+ .ai-code-completion-summary-toolbar-container) {
51
+ border-bottom: 0;
52
+ }
53
+
54
+ .style-panes-wrapper .ai-code-completion-summary-toolbar-container {
55
+ container-type: inline-size;
56
+ flex-shrink: 0;
57
+ overflow: hidden;
58
+ position: fixed;
59
+ bottom: 0;
60
+ background-color: var(--sys-color-cdt-base-container);
61
+ width: 100%;
62
+ }
63
+
50
64
  #elements-content:not(.elements-wrap) > div {
51
65
  display: inline-block;
52
66
  min-width: 100%;
@@ -236,13 +236,13 @@ export class NetworkLogViewColumns {
236
236
  const title = columnConfig.title instanceof Function ? columnConfig.title() : columnConfig.title;
237
237
  return {
238
238
  id: columnConfig.id,
239
- title,
239
+ title: title as Common.UIString.LocalizedString,
240
240
  sortable: columnConfig.sortable,
241
241
  align: columnConfig.align,
242
242
  nonSelectable: columnConfig.nonSelectable,
243
243
  weight: columnConfig.weight,
244
244
  allowInSortByEvenWhenHidden: columnConfig.allowInSortByEvenWhenHidden,
245
- } as DataGrid.DataGrid.ColumnDescriptor;
245
+ };
246
246
  }
247
247
 
248
248
  wasShown(): void {
@@ -1251,7 +1251,7 @@ export interface Descriptor {
1251
1251
  hideableGroup: string|null;
1252
1252
  nonSelectable: boolean;
1253
1253
  sortable: boolean;
1254
- align?: string|null;
1254
+ align?: DataGrid.DataGrid.Align|null;
1255
1255
  isResponseHeader: boolean;
1256
1256
  isRequestHeader: boolean;
1257
1257
  sortingFunction: (arg0: NetworkNode, arg1: NetworkNode) => number | undefined;
@@ -27,7 +27,6 @@
27
27
 
28
28
  .sections {
29
29
  min-height: 0;
30
- overflow: hidden;
31
30
  background-color: var(--sys-color-cdt-base-container);
32
31
  z-index: 0;
33
32
  position: relative;
@@ -357,11 +356,6 @@
357
356
  border-bottom: 1px solid var(--sys-color-divider);
358
357
  }
359
358
 
360
- .show-code {
361
- margin-right: 14px;
362
- margin-top: 8px;
363
- }
364
-
365
359
  devtools-recorder-extension-view {
366
360
  flex: 1;
367
361
  }
@@ -333,13 +333,15 @@ export class SensorsView extends UI.Widget.VBox {
333
333
  <input
334
334
  id="latitude-input"
335
335
  type="number"
336
+ min="-90"
337
+ max="90"
336
338
  step="any"
339
+ required
337
340
  .value=${String(location.latitude)}
338
341
  name="latitude"
339
342
  title=${modifierKeyMessage}
340
343
  jslog=${VisualLogging.textField('latitude').track({change: true})}
341
344
  ${Directives.ref((el: Element | undefined) => { if (el) { this.latitudeInput = el as HTMLInputElement; } })}
342
- @input=${this.#onLocationInput.bind(this)}
343
345
  @change=${this.#onLocationChange.bind(this)}
344
346
  @keydown=${this.#onLocationKeyDown.bind(this)}
345
347
  @focus=${this.#onLocationFocus.bind(this)}
@@ -351,13 +353,15 @@ export class SensorsView extends UI.Widget.VBox {
351
353
  <input
352
354
  id="longitude-input"
353
355
  type="number"
356
+ min="-180"
357
+ max="180"
354
358
  step="any"
359
+ required
355
360
  .value=${String(location.longitude)}
356
361
  name="longitude"
357
362
  title=${modifierKeyMessage}
358
363
  jslog=${VisualLogging.textField('longitude').track({change: true})}
359
364
  ${Directives.ref((el: Element | undefined) => { if (el) { this.longitudeInput = el as HTMLInputElement; } })}
360
- @input=${this.#onLocationInput.bind(this)}
361
365
  @change=${this.#onLocationChange.bind(this)}
362
366
  @keydown=${this.#onLocationKeyDown.bind(this)}
363
367
  @focus=${this.#onLocationFocus.bind(this)}
@@ -368,11 +372,11 @@ export class SensorsView extends UI.Widget.VBox {
368
372
  <input
369
373
  id="timezone-input"
370
374
  type="text"
375
+ pattern=".*[a-zA-Z].*"
371
376
  .value=${location.timezoneId}
372
377
  name="timezone"
373
378
  jslog=${VisualLogging.textField('timezone').track({change: true})}
374
379
  ${Directives.ref((el: Element | undefined) => { if (el) { this.timezoneInput = el as HTMLInputElement; } })}
375
- @input=${this.#onLocationInput.bind(this)}
376
380
  @change=${this.#onLocationChange.bind(this)}
377
381
  @keydown=${this.#onLocationKeyDown.bind(this)}
378
382
  @focus=${this.#onLocationFocus.bind(this)}
@@ -384,11 +388,11 @@ export class SensorsView extends UI.Widget.VBox {
384
388
  <input
385
389
  id="locale-input"
386
390
  type="text"
391
+ pattern=".*[a-zA-Z]{2}.*"
387
392
  .value=${location.locale}
388
393
  name="locale"
389
394
  jslog=${VisualLogging.textField('locale').track({change: true})}
390
395
  ${Directives.ref((el: Element | undefined) => { if (el) { this.localeInput = el as HTMLInputElement; } })}
391
- @input=${this.#onLocationInput.bind(this)}
392
396
  @change=${this.#onLocationChange.bind(this)}
393
397
  @keydown=${this.#onLocationKeyDown.bind(this)}
394
398
  @focus=${this.#onLocationFocus.bind(this)}
@@ -401,12 +405,12 @@ export class SensorsView extends UI.Widget.VBox {
401
405
  <input
402
406
  id="accuracy-input"
403
407
  type="number"
408
+ min="0"
404
409
  step="any"
405
410
  .value=${String(location.accuracy || SDK.EmulationModel.Location.DEFAULT_ACCURACY)}
406
411
  name="accuracy"
407
412
  jslog=${VisualLogging.textField('accuracy').track({change: true})}
408
413
  ${Directives.ref((el: Element | undefined) => { if (el) { this.accuracyInput = el as HTMLInputElement; } })}
409
- @input=${this.#onLocationInput.bind(this)}
410
414
  @change=${this.#onLocationChange.bind(this)}
411
415
  @keydown=${this.#onLocationKeyDown.bind(this)}
412
416
  @focus=${this.#onLocationFocus.bind(this)}
@@ -448,12 +452,11 @@ export class SensorsView extends UI.Widget.VBox {
448
452
  this.#location = new SDK.EmulationModel.Location(
449
453
  coordinates.lat, coordinates.long, coordinates.timezoneId, coordinates.locale,
450
454
  coordinates.accuracy || SDK.EmulationModel.Location.DEFAULT_ACCURACY, false);
451
- this.#setInputValue(this.latitudeInput, coordinates.lat);
452
- this.#setInputValue(this.longitudeInput, coordinates.long);
453
- this.#setInputValue(this.timezoneInput, coordinates.timezoneId);
454
- this.#setInputValue(this.localeInput, coordinates.locale);
455
- this.#setInputValue(
456
- this.accuracyInput, String(coordinates.accuracy || SDK.EmulationModel.Location.DEFAULT_ACCURACY));
455
+ this.latitudeInput.value = coordinates.lat;
456
+ this.longitudeInput.value = coordinates.long;
457
+ this.timezoneInput.value = coordinates.timezoneId;
458
+ this.localeInput.value = coordinates.locale;
459
+ this.accuracyInput.value = String(coordinates.accuracy || SDK.EmulationModel.Location.DEFAULT_ACCURACY);
457
460
  }
458
461
 
459
462
  this.applyLocation();
@@ -462,17 +465,9 @@ export class SensorsView extends UI.Widget.VBox {
462
465
  }
463
466
  }
464
467
 
465
- #onLocationInput(event: Event): void {
466
- const input = event.currentTarget as HTMLInputElement;
467
- const valid = this.#validateInput(input, input.value);
468
- input.classList.toggle('error-input', !valid);
469
- }
470
-
471
468
  #onLocationChange(event: Event): void {
472
469
  const input = event.currentTarget as HTMLInputElement;
473
- const valid = this.#validateInput(input, input.value);
474
- input.classList.toggle('error-input', !valid);
475
- if (valid) {
470
+ if (input.checkValidity()) {
476
471
  this.applyLocationUserInput();
477
472
  }
478
473
  }
@@ -480,8 +475,7 @@ export class SensorsView extends UI.Widget.VBox {
480
475
  #onLocationKeyDown(event: KeyboardEvent): void {
481
476
  const input = event.currentTarget as HTMLInputElement;
482
477
  if (event.key === 'Enter') {
483
- const valid = this.#validateInput(input, input.value);
484
- if (valid) {
478
+ if (input.checkValidity()) {
485
479
  this.applyLocationUserInput();
486
480
  }
487
481
  event.preventDefault();
@@ -498,10 +492,13 @@ export class SensorsView extends UI.Widget.VBox {
498
492
  if (value === null) {
499
493
  return;
500
494
  }
501
- const stringValue = String(value);
502
- const valid = this.#validateInput(input, stringValue);
503
- if (valid) {
504
- this.#setInputValue(input, stringValue);
495
+ const prevValue = input.value;
496
+ input.value = String(value);
497
+ if (input.checkValidity()) {
498
+ this.applyLocationUserInput();
499
+ } else {
500
+ // If ArrowUp/ArrowDown adjusts the value out of bounds, we reset it.
501
+ input.value = prevValue;
505
502
  }
506
503
  event.preventDefault();
507
504
  }
@@ -511,34 +508,6 @@ export class SensorsView extends UI.Widget.VBox {
511
508
  input.select();
512
509
  }
513
510
 
514
- #validateInput(input: HTMLInputElement, value: string): boolean {
515
- if (input === this.latitudeInput) {
516
- return SDK.EmulationModel.Location.latitudeValidator(value);
517
- }
518
- if (input === this.longitudeInput) {
519
- return SDK.EmulationModel.Location.longitudeValidator(value);
520
- }
521
- if (input === this.timezoneInput) {
522
- return SDK.EmulationModel.Location.timezoneIdValidator(value);
523
- }
524
- if (input === this.localeInput) {
525
- return SDK.EmulationModel.Location.localeValidator(value);
526
- }
527
- if (input === this.accuracyInput) {
528
- return SDK.EmulationModel.Location.accuracyValidator(value).valid;
529
- }
530
- return false;
531
- }
532
-
533
- #setInputValue(input: HTMLInputElement, value: string): void {
534
- if (value === input.value) {
535
- return;
536
- }
537
- const valid = this.#validateInput(input, value);
538
- input.classList.toggle('error-input', !valid);
539
- input.value = value;
540
- }
541
-
542
511
  private applyLocationUserInput(): void {
543
512
  const location = SDK.EmulationModel.Location.parseUserInput(
544
513
  this.latitudeInput.value.trim(), this.longitudeInput.value.trim(), this.timezoneInput.value.trim(),
@@ -582,11 +551,11 @@ export class SensorsView extends UI.Widget.VBox {
582
551
  }
583
552
 
584
553
  private clearFieldsetElementInputs(): void {
585
- this.#setInputValue(this.latitudeInput, '0');
586
- this.#setInputValue(this.longitudeInput, '0');
587
- this.#setInputValue(this.timezoneInput, '');
588
- this.#setInputValue(this.localeInput, '');
589
- this.#setInputValue(this.accuracyInput, SDK.EmulationModel.Location.DEFAULT_ACCURACY.toString());
554
+ this.latitudeInput.value = '0';
555
+ this.longitudeInput.value = '0';
556
+ this.timezoneInput.value = '';
557
+ this.localeInput.value = '';
558
+ this.accuracyInput.value = SDK.EmulationModel.Location.DEFAULT_ACCURACY.toString();
590
559
  }
591
560
 
592
561
  private createDeviceOrientationSection(): void {
@@ -51,8 +51,8 @@ export class EventsTimelineTreeView extends TimelineTreeView {
51
51
  return [...super.filters(), ...this.filtersControl.filters()];
52
52
  }
53
53
 
54
- override updateContents(selection: TimelineSelection): void {
55
- super.updateContents(selection);
54
+ override set activeSelection(selection: TimelineSelection) {
55
+ super.activeSelection = selection;
56
56
  if (selectionIsEvent(selection)) {
57
57
  this.selectEvent(selection.event, true);
58
58
  }
@@ -6,7 +6,6 @@
6
6
  import * as i18n from '../../core/i18n/i18n.js';
7
7
  import * as Trace from '../../models/trace/trace.js';
8
8
  import * as DataGrid from '../../ui/legacy/components/data_grid/data_grid.js';
9
- import * as UI from '../../ui/legacy/legacy.js';
10
9
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
11
10
 
12
11
  import thirdPartyTreeViewStyles from './thirdPartyTreeView.css.js';
@@ -39,8 +38,12 @@ export class ThirdPartyTreeViewWidget extends TimelineTreeView.TimelineTreeView
39
38
  // want to do this when the user hovers.
40
39
  protected override autoSelectFirstChildOnRefresh = false;
41
40
 
42
- constructor() {
43
- super();
41
+ #onRowHovered?: (node: Trace.Extras.TraceTree.Node|null, events?: Trace.Types.Events.Event[]) => void;
42
+ #onBottomUpButtonClicked?: (node: Trace.Extras.TraceTree.Node|null) => void;
43
+ #onRowClicked?: (node: Trace.Extras.TraceTree.Node|null, events?: Trace.Types.Events.Event[]) => void;
44
+
45
+ constructor(element?: HTMLElement) {
46
+ super(element);
44
47
  this.element.setAttribute('jslog', `${VisualLogging.pane('third-party-tree').track({hover: true})}`);
45
48
  this.init();
46
49
  this.dataGrid.markColumnAsSortedBy('self', DataGrid.DataGrid.Order.Descending);
@@ -61,12 +64,14 @@ export class ThirdPartyTreeViewWidget extends TimelineTreeView.TimelineTreeView
61
64
  this.registerRequiredCSS(thirdPartyTreeViewStyles);
62
65
  }
63
66
 
64
- override setModelWithEvents(
65
- selectedEvents: Trace.Types.Events.Event[]|null, parsedTrace?: Trace.TraceModel.ParsedTrace|null,
66
- entityMappings?: Trace.EntityMapper.EntityMapper|null): void {
67
- super.setModelWithEvents(selectedEvents, parsedTrace, entityMappings);
67
+ override set model(model: {
68
+ selectedEvents: Trace.Types.Events.Event[]|null,
69
+ parsedTrace: Trace.TraceModel.ParsedTrace|null,
70
+ entityMapper: Trace.EntityMapper.EntityMapper|null,
71
+ }) {
72
+ super.model = model;
68
73
 
69
- const hasEvents = Boolean(selectedEvents && selectedEvents.length > 0);
74
+ const hasEvents = Boolean(model.selectedEvents && model.selectedEvents.length > 0);
70
75
  this.element.classList.toggle('empty-table', !hasEvents);
71
76
  }
72
77
 
@@ -252,42 +257,36 @@ export class ThirdPartyTreeViewWidget extends TimelineTreeView.TimelineTreeView
252
257
  const entity = mapper.entityForEvent(node.event);
253
258
  return Boolean(entity) && entity?.category === 'Chrome Extension';
254
259
  }
255
- }
256
-
257
- export class ThirdPartyTreeElement extends UI.Widget.WidgetElement<UI.Widget.Widget> {
258
- #treeView?: ThirdPartyTreeViewWidget;
259
-
260
- static readonly observedAttributes = ['max-rows'];
261
-
262
- set treeView(treeView: ThirdPartyTreeViewWidget) {
263
- this.#treeView = treeView;
264
- }
265
260
 
266
- constructor() {
267
- super();
268
- this.style.display = 'contents';
261
+ set maxRows(maxRows: number) {
262
+ this.element.style.setProperty('--max-rows', String(maxRows));
263
+ this.element.classList.toggle('has-max-rows', Boolean(maxRows));
269
264
  }
270
265
 
271
- attributeChangedCallback(name: string, _oldValue: string|null, newValue: string|null): void {
272
- if (name === 'max-rows' && newValue) {
273
- this.style.setProperty('--max-rows', newValue);
266
+ set onRowHovered(callback: (node: Trace.Extras.TraceTree.Node|null, events?: Trace.Types.Events.Event[]) => void) {
267
+ if (!this.#onRowHovered) {
268
+ this.addEventListener(TimelineTreeView.TimelineTreeView.Events.TREE_ROW_HOVERED, ({data}) => {
269
+ this.#onRowHovered?.(data.node, data.events);
270
+ });
274
271
  }
272
+ this.#onRowHovered = callback;
275
273
  }
276
274
 
277
- override createWidget(): UI.Widget.Widget {
278
- const containerWidget = new UI.Widget.Widget(this);
279
- containerWidget.contentElement.style.display = 'contents';
280
- if (this.#treeView) {
281
- this.#treeView.show(containerWidget.contentElement);
275
+ set onBottomUpButtonClicked(callback: (node: Trace.Extras.TraceTree.Node|null) => void) {
276
+ if (!this.#onBottomUpButtonClicked) {
277
+ this.addEventListener(TimelineTreeView.TimelineTreeView.Events.BOTTOM_UP_BUTTON_CLICKED, ({data}) => {
278
+ this.#onBottomUpButtonClicked?.(data);
279
+ });
282
280
  }
283
- return containerWidget;
281
+ this.#onBottomUpButtonClicked = callback;
284
282
  }
285
- }
286
283
 
287
- customElements.define('devtools-performance-third-party-tree-view', ThirdPartyTreeElement);
288
-
289
- declare global {
290
- interface HTMLElementTagNameMap {
291
- 'devtools-performance-third-party-tree-view': ThirdPartyTreeElement;
284
+ set onRowClicked(callback: (node: Trace.Extras.TraceTree.Node|null, events?: Trace.Types.Events.Event[]) => void) {
285
+ if (!this.#onRowClicked) {
286
+ this.addEventListener(TimelineTreeView.TimelineTreeView.Events.TREE_ROW_CLICKED, ({data}) => {
287
+ this.#onRowClicked?.(data.node, data.events);
288
+ });
289
+ }
290
+ this.#onRowClicked = callback;
292
291
  }
293
292
  }