chrome-devtools-frontend 1.0.1539972 → 1.0.1541552

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 (106) hide show
  1. package/eslint.config.mjs +167 -151
  2. package/front_end/Tests.js +5 -1
  3. package/front_end/core/common/Revealer.ts +5 -0
  4. package/front_end/core/common/Settings.ts +106 -95
  5. package/front_end/core/host/InspectorFrontendHost.ts +10 -10
  6. package/front_end/core/sdk/NetworkManager.ts +16 -11
  7. package/front_end/core/sdk/sdk-meta.ts +0 -35
  8. package/front_end/entrypoints/main/MainImpl.ts +15 -7
  9. package/front_end/entrypoints/shell/shell.ts +1 -0
  10. package/front_end/entrypoints/trace_app/trace_app.ts +1 -0
  11. package/front_end/foundation/README.md +10 -0
  12. package/front_end/foundation/Universe.ts +29 -0
  13. package/front_end/foundation/foundation.ts +7 -0
  14. package/front_end/generated/InspectorBackendCommands.ts +6 -3
  15. package/front_end/generated/SupportedCSSProperties.js +13 -0
  16. package/front_end/generated/protocol.ts +58 -2
  17. package/front_end/models/ai_assistance/BuiltInAi.ts +2 -1
  18. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +44 -34
  19. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +121 -56
  20. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +104 -62
  21. package/front_end/models/ai_assistance/performance/AIQueries.ts +56 -2
  22. package/front_end/{panels/issues → models/issues_manager}/IssueAggregator.ts +83 -65
  23. package/front_end/models/issues_manager/issues_manager.ts +2 -0
  24. package/front_end/models/trace/Processor.ts +5 -4
  25. package/front_end/models/trace/insights/types.ts +1 -1
  26. package/front_end/models/trace/types/TraceEvents.ts +1 -1
  27. package/front_end/models/workspace/IgnoreListManager.ts +41 -47
  28. package/front_end/models/workspace/workspace-meta.ts +40 -0
  29. package/front_end/panels/ai_assistance/components/MarkdownRendererWithCodeBlock.ts +1 -1
  30. package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +1 -1
  31. package/front_end/panels/animation/AnimationTimeline.ts +4 -4
  32. package/front_end/panels/animation/AnimationUI.ts +28 -34
  33. package/front_end/panels/elements/ElementsTreeElement.ts +37 -9
  34. package/front_end/panels/elements/LayoutPane.ts +2 -2
  35. package/front_end/panels/elements/components/AdornerManager.ts +9 -9
  36. package/front_end/panels/elements/layoutPane.css +5 -9
  37. package/front_end/panels/event_listeners/EventListenersView.ts +1 -1
  38. package/front_end/panels/explain/components/ConsoleInsight.ts +498 -449
  39. package/front_end/panels/issues/AffectedResourcesView.ts +3 -4
  40. package/front_end/panels/issues/CorsIssueDetailsView.ts +1 -2
  41. package/front_end/panels/issues/IssueView.ts +1 -1
  42. package/front_end/panels/issues/IssuesPane.ts +12 -15
  43. package/front_end/panels/issues/issues.ts +0 -2
  44. package/front_end/panels/network/NetworkDataGridNode.ts +2 -1
  45. package/front_end/panels/network/RequestConditionsDrawer.ts +149 -46
  46. package/front_end/panels/network/RequestTimingView.ts +13 -8
  47. package/front_end/panels/network/network-meta.ts +11 -0
  48. package/front_end/panels/settings/emulation/components/userAgentClientHintsForm.css +1 -1
  49. package/front_end/panels/sources/DebuggerPlugin.ts +1 -1
  50. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +1 -1
  51. package/front_end/panels/sources/breakpointsView.css +1 -1
  52. package/front_end/panels/sources/sourcesPanel.css +2 -2
  53. package/front_end/panels/timeline/TimelineFlameChartView.ts +3 -3
  54. package/front_end/panels/timeline/TimelinePanel.ts +3 -3
  55. package/front_end/panels/timeline/components/LayoutShiftDetails.ts +16 -10
  56. package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +2 -0
  57. package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +4 -1
  58. package/front_end/third_party/chromium/README.chromium +1 -1
  59. package/front_end/third_party/puppeteer/README.chromium +2 -2
  60. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
  61. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.js +3 -1
  62. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.js.map +1 -1
  63. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +2 -2
  64. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +2 -2
  65. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  66. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  67. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +4 -4
  68. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
  69. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.js +3 -1
  70. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.js.map +1 -1
  71. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +2 -2
  72. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +2 -2
  73. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  74. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  75. package/front_end/third_party/puppeteer/package/package.json +1 -1
  76. package/front_end/third_party/puppeteer/package/src/cdp/NetworkManager.ts +3 -1
  77. package/front_end/third_party/puppeteer/package/src/revisions.ts +2 -2
  78. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  79. package/front_end/ui/components/markdown_view/MarkdownView.ts +6 -6
  80. package/front_end/ui/components/snackbars/Snackbars.docs.ts +46 -0
  81. package/front_end/ui/{components/docs/context_menu/basic.ts → legacy/ContextMenu.docs.ts} +58 -25
  82. package/front_end/ui/legacy/UIUtils.ts +2 -1
  83. package/front_end/ui/legacy/components/inline_editor/BezierEditor.ts +1 -1
  84. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +148 -125
  85. package/front_end/ui/legacy/components/perf_ui/TimelineOverviewPane.ts +3 -3
  86. package/front_end/ui/legacy/components/perf_ui/pieChart.css +1 -1
  87. package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -1
  88. package/front_end/ui/legacy/inspectorCommon.css +3 -2
  89. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  90. package/mcp/mcp.ts +16 -0
  91. package/package.json +2 -1
  92. package/front_end/ui/components/docs/context_menu/basic.html +0 -45
  93. package/front_end/ui/components/docs/linkifier/simple-url.html +0 -25
  94. package/front_end/ui/components/docs/linkifier/simple-url.ts +0 -25
  95. package/front_end/ui/components/docs/panel_feedback/basic.html +0 -25
  96. package/front_end/ui/components/docs/panel_feedback/basic.ts +0 -21
  97. package/front_end/ui/components/docs/panel_feedback/button.html +0 -25
  98. package/front_end/ui/components/docs/panel_feedback/button.ts +0 -19
  99. package/front_end/ui/components/docs/panel_introduction_steps/basic.html +0 -25
  100. package/front_end/ui/components/docs/panel_introduction_steps/basic.ts +0 -28
  101. package/front_end/ui/components/docs/perf_piechart/basic-with-legend.html +0 -20
  102. package/front_end/ui/components/docs/perf_piechart/basic-with-legend.ts +0 -20
  103. package/front_end/ui/components/docs/perf_piechart/basic-without-legend.html +0 -20
  104. package/front_end/ui/components/docs/perf_piechart/basic-without-legend.ts +0 -18
  105. package/front_end/ui/components/docs/snackbars/basic.html +0 -17
  106. package/front_end/ui/components/docs/snackbars/basic.ts +0 -50
@@ -18,7 +18,6 @@ import * as Components from '../../ui/legacy/components/utils/utils.js';
18
18
  import * as UI from '../../ui/legacy/legacy.js';
19
19
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
20
20
 
21
- import type {AggregatedIssue} from './IssueAggregator.js';
22
21
  import type {IssueView} from './IssueView.js';
23
22
 
24
23
  const UIStrings = {
@@ -65,7 +64,7 @@ export interface CreateRequestCellOptions {
65
64
  */
66
65
  export abstract class AffectedResourcesView extends UI.TreeOutline.TreeElement {
67
66
  readonly #parentView: IssueView;
68
- protected issue: AggregatedIssue;
67
+ protected issue: IssuesManager.IssueAggregator.AggregatedIssue;
69
68
  protected affectedResourcesCountElement: HTMLElement;
70
69
  protected affectedResources: HTMLElement;
71
70
  #affectedResourcesCount: number;
@@ -73,7 +72,7 @@ export abstract class AffectedResourcesView extends UI.TreeOutline.TreeElement {
73
72
  #unresolvedFrameIds: Set<string>;
74
73
  protected requestResolver: Logs.RequestResolver.RequestResolver;
75
74
 
76
- constructor(parent: IssueView, issue: AggregatedIssue, jslogContext: string) {
75
+ constructor(parent: IssueView, issue: IssuesManager.IssueAggregator.AggregatedIssue, jslogContext: string) {
77
76
  super(/* title */ undefined, /* expandable */ undefined, jslogContext);
78
77
  this.#parentView = parent;
79
78
  this.issue = issue;
@@ -91,7 +90,7 @@ export abstract class AffectedResourcesView extends UI.TreeOutline.TreeElement {
91
90
  * Sets the issue to take the resources from. Does not
92
91
  * trigger an update, the caller needs to do that explicitly.
93
92
  */
94
- setIssue(issue: AggregatedIssue): void {
93
+ setIssue(issue: IssuesManager.IssueAggregator.AggregatedIssue): void {
95
94
  this.issue = issue;
96
95
  }
97
96
 
@@ -11,7 +11,6 @@ import * as IssuesManager from '../../models/issues_manager/issues_manager.js';
11
11
  import * as NetworkForward from '../../panels/network/forward/forward.js';
12
12
 
13
13
  import {AffectedItem, AffectedResourcesView} from './AffectedResourcesView.js';
14
- import type {AggregatedIssue} from './IssueAggregator.js';
15
14
  import type {IssueView} from './IssueView.js';
16
15
 
17
16
  const UIStrings = {
@@ -128,7 +127,7 @@ const str_ = i18n.i18n.registerUIStrings('panels/issues/CorsIssueDetailsView.ts'
128
127
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
129
128
 
130
129
  export class CorsIssueDetailsView extends AffectedResourcesView {
131
- constructor(parent: IssueView, issue: AggregatedIssue, jslogContext: string) {
130
+ constructor(parent: IssueView, issue: IssuesManager.IssueAggregator.AggregatedIssue, jslogContext: string) {
132
131
  super(parent, issue, jslogContext);
133
132
  this.affectedResourcesCountElement.classList.add('cors-issue-affected-resource-label');
134
133
  }
@@ -8,6 +8,7 @@ import * as Host from '../../core/host/host.js';
8
8
  import * as i18n from '../../core/i18n/i18n.js';
9
9
  import type * as Platform from '../../core/platform/platform.js';
10
10
  import * as Protocol from '../../generated/protocol.js';
11
+ import type {AggregatedIssue} from '../../models/issues_manager/IssueAggregator.js';
11
12
  import * as IssuesManager from '../../models/issues_manager/issues_manager.js';
12
13
  import * as NetworkForward from '../../panels/network/forward/forward.js';
13
14
  import * as Adorners from '../../ui/components/adorners/adorners.js';
@@ -36,7 +37,6 @@ import * as Components from './components/components.js';
36
37
  import type {HiddenIssuesMenuData} from './components/HideIssuesMenu.js';
37
38
  import {CorsIssueDetailsView} from './CorsIssueDetailsView.js';
38
39
  import {GenericIssueDetailsView} from './GenericIssueDetailsView.js';
39
- import type {AggregatedIssue} from './IssueAggregator.js';
40
40
 
41
41
  const UIStrings = {
42
42
  /**
@@ -14,12 +14,6 @@ import * as UI from '../../ui/legacy/legacy.js';
14
14
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
15
15
 
16
16
  import {HiddenIssuesRow} from './HiddenIssuesRow.js';
17
- import {
18
- type AggregatedIssue,
19
- type AggregationKey,
20
- Events as IssueAggregatorEvents,
21
- IssueAggregator,
22
- } from './IssueAggregator.js';
23
17
  import {getGroupIssuesByKindSetting, IssueKindView, issueKindViewSortPriority} from './IssueKindView.js';
24
18
  import issuesPaneStyles from './issuesPane.css.js';
25
19
  import issuesTreeStyles from './issuesTree.css.js';
@@ -181,14 +175,14 @@ export function getGroupIssuesByCategorySetting(): Common.Settings.Setting<boole
181
175
 
182
176
  export class IssuesPane extends UI.Widget.VBox {
183
177
  #categoryViews: Map<IssuesManager.Issue.IssueCategory, IssueCategoryView>;
184
- #issueViews: Map<AggregationKey, IssueView>;
178
+ #issueViews: Map<IssuesManager.IssueAggregator.AggregationKey, IssueView>;
185
179
  #kindViews: Map<IssuesManager.Issue.IssueKind, IssueKindView>;
186
180
  #showThirdPartyCheckbox: UI.Toolbar.ToolbarSettingCheckbox|null;
187
181
  #issuesTree: UI.TreeOutline.TreeOutlineInShadow;
188
182
  #hiddenIssuesRow: HiddenIssuesRow;
189
183
  #noIssuesMessageDiv: UI.EmptyWidget.EmptyWidget;
190
184
  #issuesManager: IssuesManager.IssuesManager.IssuesManager;
191
- #aggregator: IssueAggregator;
185
+ #aggregator: IssuesManager.IssueAggregator.IssueAggregator;
192
186
  #issueViewUpdatePromise: Promise<void> = Promise.resolve();
193
187
 
194
188
  constructor() {
@@ -222,9 +216,11 @@ export class IssuesPane extends UI.Widget.VBox {
222
216
  this.#noIssuesMessageDiv.show(this.contentElement);
223
217
 
224
218
  this.#issuesManager = IssuesManager.IssuesManager.IssuesManager.instance();
225
- this.#aggregator = new IssueAggregator(this.#issuesManager);
226
- this.#aggregator.addEventListener(IssueAggregatorEvents.AGGREGATED_ISSUE_UPDATED, this.#issueUpdated, this);
227
- this.#aggregator.addEventListener(IssueAggregatorEvents.FULL_UPDATE_REQUIRED, this.#onFullUpdate, this);
219
+ this.#aggregator = new IssuesManager.IssueAggregator.IssueAggregator(this.#issuesManager);
220
+ this.#aggregator.addEventListener(
221
+ IssuesManager.IssueAggregator.Events.AGGREGATED_ISSUE_UPDATED, this.#issueUpdated, this);
222
+ this.#aggregator.addEventListener(
223
+ IssuesManager.IssueAggregator.Events.FULL_UPDATE_REQUIRED, this.#onFullUpdate, this);
228
224
  this.#hiddenIssuesRow.hidden = this.#issuesManager.numberOfHiddenIssues() === 0;
229
225
  this.#onFullUpdate();
230
226
  this.#issuesManager.addEventListener(
@@ -292,16 +288,16 @@ export class IssuesPane extends UI.Widget.VBox {
292
288
  return {toolbarContainer};
293
289
  }
294
290
 
295
- #issueUpdated(event: Common.EventTarget.EventTargetEvent<AggregatedIssue>): void {
291
+ #issueUpdated(event: Common.EventTarget.EventTargetEvent<IssuesManager.IssueAggregator.AggregatedIssue>): void {
296
292
  this.#scheduleIssueViewUpdate(event.data);
297
293
  }
298
294
 
299
- #scheduleIssueViewUpdate(issue: AggregatedIssue): void {
295
+ #scheduleIssueViewUpdate(issue: IssuesManager.IssueAggregator.AggregatedIssue): void {
300
296
  this.#issueViewUpdatePromise = this.#issueViewUpdatePromise.then(() => this.#updateIssueView(issue));
301
297
  }
302
298
 
303
299
  /** Don't call directly. Use `scheduleIssueViewUpdate` instead. */
304
- async #updateIssueView(issue: AggregatedIssue): Promise<void> {
300
+ async #updateIssueView(issue: IssuesManager.IssueAggregator.AggregatedIssue): Promise<void> {
305
301
  let issueView = this.#issueViews.get(issue.aggregationKey());
306
302
  if (!issueView) {
307
303
  const description = issue.getDescription();
@@ -361,7 +357,8 @@ export class IssuesPane extends UI.Widget.VBox {
361
357
  }
362
358
  }
363
359
 
364
- #getIssueViewParent(issue: AggregatedIssue): UI.TreeOutline.TreeOutline|UI.TreeOutline.TreeElement {
360
+ #getIssueViewParent(issue: IssuesManager.IssueAggregator.AggregatedIssue): UI.TreeOutline.TreeOutline
361
+ |UI.TreeOutline.TreeElement {
365
362
  if (issue.isHidden()) {
366
363
  return this.#hiddenIssuesRow;
367
364
  }
@@ -2,13 +2,11 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
- import * as IssueAggregator from './IssueAggregator.js';
6
5
  import * as IssueRevealer from './IssueRevealer.js';
7
6
  import * as IssuesPane from './IssuesPane.js';
8
7
  import * as IssueView from './IssueView.js';
9
8
 
10
9
  export {
11
- IssueAggregator,
12
10
  IssueRevealer,
13
11
  IssuesPane,
14
12
  IssueView,
@@ -958,7 +958,7 @@ export class NetworkRequestNode extends NetworkNode {
958
958
  return this.requestInternal.resourceType() === Common.ResourceType.resourceTypes.Prefetch;
959
959
  }
960
960
 
961
- throttlingConditions(): {conditions: SDK.NetworkManager.Conditions, urlPattern?: string}|undefined {
961
+ throttlingConditions(): SDK.NetworkManager.AppliedNetworkConditions|undefined {
962
962
  return SDK.NetworkManager.MultitargetNetworkManager.instance().appliedRequestConditions(this.requestInternal);
963
963
  }
964
964
 
@@ -1522,6 +1522,7 @@ export class NetworkRequestNode extends NetworkNode {
1522
1522
  throttlingConditions.conditions.title();
1523
1523
  const icon = IconButton.Icon.create('watch');
1524
1524
  icon.title = i18nString(UIStrings.wasThrottled, {PH1: throttlingConditionsTitle});
1525
+ icon.addEventListener('click', () => void Common.Revealer.reveal(throttlingConditions));
1525
1526
  cell.append(icon);
1526
1527
  }
1527
1528
  if (this.requestInternal.duration > 0) {
@@ -18,10 +18,12 @@ import * as UI from '../../ui/legacy/legacy.js';
18
18
  import {Directives, html, type LitTemplate, nothing, render} from '../../ui/lit/lit.js';
19
19
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
20
20
  import * as MobileThrottling from '../mobile_throttling/mobile_throttling.js';
21
+ import * as PanelUtils from '../utils/utils.js';
21
22
 
22
23
  import requestConditionsDrawerStyles from './requestConditionsDrawer.css.js';
23
24
 
24
25
  const {ref} = Directives;
26
+ const {widgetConfig} = UI.Widget;
25
27
 
26
28
  const UIStrings = {
27
29
  /**
@@ -107,11 +109,11 @@ const UIStrings = {
107
109
  /**
108
110
  * @description Aria label on a button moving an entry up
109
111
  */
110
- increasePriority: 'Increase priority',
112
+ increasePriority: 'Move up (higher patterns are checked first)',
111
113
  /**
112
114
  * @description Aria label on a button moving an entry down
113
115
  */
114
- decreasePriority: 'Decrease priority',
116
+ decreasePriority: 'Move down (higher patterns are checked first)',
115
117
  } as const;
116
118
  const str_ = i18n.i18n.registerUIStrings('panels/network/RequestConditionsDrawer.ts', UIStrings);
117
119
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -178,6 +180,109 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
178
180
  target);
179
181
  };
180
182
 
183
+ interface AffectedCountViewInput {
184
+ count: number;
185
+ }
186
+ type AffectedCountView = (input: AffectedCountViewInput, output: object, target: HTMLElement) => void;
187
+ export const AFFECTED_COUNT_DEFAULT_VIEW: AffectedCountView = (input, output, target) => {
188
+ if (Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled) {
189
+ render(html`${i18nString(UIStrings.dAffected, {PH1: input.count})}`, target);
190
+ } else {
191
+ render(html`${i18nString(UIStrings.dBlocked, {PH1: input.count})}`, target);
192
+ }
193
+ };
194
+
195
+ function matchesUrl(conditions: SDK.NetworkManager.RequestCondition, url: string): boolean {
196
+ function matchesPattern(pattern: string, url: string): boolean {
197
+ let pos = 0;
198
+ const parts = pattern.split('*');
199
+ for (let index = 0; index < parts.length; index++) {
200
+ const part = parts[index];
201
+ if (!part.length) {
202
+ continue;
203
+ }
204
+ pos = url.indexOf(part, pos);
205
+ if (pos === -1) {
206
+ return false;
207
+ }
208
+ pos += part.length;
209
+ }
210
+ return true;
211
+ }
212
+
213
+ return Boolean(
214
+ Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled ?
215
+ conditions.originalOrUpgradedURLPattern?.test(url) :
216
+ (conditions.wildcardURL && matchesPattern(conditions.wildcardURL, url)));
217
+ }
218
+
219
+ export class AffectedCountWidget extends UI.Widget.Widget {
220
+ readonly #view: AffectedCountView;
221
+ #condition?: SDK.NetworkManager.RequestCondition;
222
+ #drawer?: RequestConditionsDrawer;
223
+ constructor(target?: HTMLElement, view = AFFECTED_COUNT_DEFAULT_VIEW) {
224
+ super(target, {classes: ['blocked-url-count']});
225
+ this.#view = view;
226
+ }
227
+
228
+ get condition(): SDK.NetworkManager.RequestCondition|undefined {
229
+ return this.#condition;
230
+ }
231
+
232
+ set condition(conditions: SDK.NetworkManager.RequestCondition) {
233
+ this.#condition = conditions;
234
+ this.requestUpdate();
235
+ }
236
+
237
+ get drawer(): RequestConditionsDrawer|undefined {
238
+ return this.#drawer;
239
+ }
240
+
241
+ set drawer(drawer: RequestConditionsDrawer) {
242
+ this.#drawer = drawer;
243
+ this.requestUpdate();
244
+ }
245
+
246
+ override performUpdate(): void {
247
+ if (!this.#condition || !this.#drawer) {
248
+ return;
249
+ }
250
+
251
+ const count = !Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled || this.#condition.isBlocking ?
252
+ this.#drawer.blockedRequestsCount(this.#condition) :
253
+ this.#drawer.throttledRequestsCount(this.#condition);
254
+
255
+ this.#view({count}, {}, this.element);
256
+ }
257
+
258
+ override wasShown(): void {
259
+ SDK.TargetManager.TargetManager.instance().addModelListener(
260
+ SDK.NetworkManager.NetworkManager, SDK.NetworkManager.Events.RequestFinished, this.#onRequestFinished, this,
261
+ {scoped: true});
262
+ Logs.NetworkLog.NetworkLog.instance().addEventListener(Logs.NetworkLog.Events.Reset, this.requestUpdate, this);
263
+ super.wasShown();
264
+ }
265
+
266
+ override willHide(): void {
267
+ super.willHide();
268
+ SDK.TargetManager.TargetManager.instance().removeModelListener(
269
+ SDK.NetworkManager.NetworkManager, SDK.NetworkManager.Events.RequestFinished, this.#onRequestFinished, this);
270
+ Logs.NetworkLog.NetworkLog.instance().removeEventListener(Logs.NetworkLog.Events.Reset, this.requestUpdate, this);
271
+ }
272
+
273
+ #onRequestFinished(event: Common.EventTarget.EventTargetEvent<SDK.NetworkRequest.NetworkRequest>): void {
274
+ if (!this.#condition) {
275
+ return;
276
+ }
277
+
278
+ const request = event.data;
279
+ if ((request.appliedNetworkConditionsId && this.#condition.ruleIds.has(request.appliedNetworkConditionsId)) ||
280
+ (request.wasBlocked() && matchesUrl(this.#condition, request.url()))) {
281
+ this.requestUpdate();
282
+ }
283
+ }
284
+ }
285
+
181
286
  function learnMore(): LitTemplate {
182
287
  return html`<x-link
183
288
  href=${NETWORK_REQUEST_BLOCKING_EXPLANATION_URL}
@@ -196,6 +301,7 @@ export class RequestConditionsDrawer extends UI.Widget.VBox implements
196
301
  private blockedCountForUrl: Map<Platform.DevToolsPath.UrlString, number>;
197
302
  #throttledCount = new Map<string, number>();
198
303
  #view: View;
304
+ #listElements = new WeakMap<SDK.NetworkManager.RequestCondition, HTMLElement>();
199
305
 
200
306
  constructor(target?: HTMLElement, view = DEFAULT_VIEW) {
201
307
  super(target, {
@@ -249,9 +355,8 @@ export class RequestConditionsDrawer extends UI.Widget.VBox implements
249
355
  }
250
356
 
251
357
  renderItem(condition: SDK.NetworkManager.RequestCondition, editable: boolean, index: number): Element {
252
- const blockedCount = this.blockedRequestsCount(condition);
253
- const throttledCount = this.#throttledRequestsCount(condition);
254
358
  const element = document.createElement('div');
359
+ this.#listElements.set(condition, element);
255
360
  element.classList.add('blocked-url');
256
361
  const toggle = (e: Event): void => {
257
362
  if (editable) {
@@ -338,20 +443,18 @@ export class RequestConditionsDrawer extends UI.Widget.VBox implements
338
443
  aria-details=url-pattern-${index}>
339
444
  ${constructorStringOrWildcardURL}
340
445
  </div>
341
- <devtools-widget
342
- class=conditions-selector
343
- ?disabled=${!editable}
344
- .widgetConfig=${UI.Widget.widgetConfig(
345
- MobileThrottling.NetworkThrottlingSelector.NetworkThrottlingSelectorWidget, {
346
- variant:
347
- MobileThrottling.NetworkThrottlingSelector.NetworkThrottlingSelect.Variant.INDIVIDUAL_REQUEST_CONDITIONS,
348
- jslogContext: 'request-conditions',
349
- onConditionsChanged,
350
- currentConditions: condition.conditions,
351
- })}></devtools-widget>
352
- <div class=blocked-url-count>${i18nString(UIStrings.dAffected, {PH1: condition.isBlocking
353
- ? blockedCount
354
- : throttledCount})}</div>`,
446
+ <devtools-widget
447
+ class=conditions-selector
448
+ ?disabled=${!editable}
449
+ .widgetConfig=${UI.Widget.widgetConfig(
450
+ MobileThrottling.NetworkThrottlingSelector.NetworkThrottlingSelectorWidget, {
451
+ variant:
452
+ MobileThrottling.NetworkThrottlingSelector.NetworkThrottlingSelect.Variant.INDIVIDUAL_REQUEST_CONDITIONS,
453
+ jslogContext: 'request-conditions',
454
+ onConditionsChanged,
455
+ currentConditions: condition.conditions,
456
+ })}></devtools-widget>
457
+ <devtools-widget .widgetConfig=${widgetConfig(AffectedCountWidget, {condition, drawer: this})}></devtools-widget>`,
355
458
  // clang-format on
356
459
  element);
357
460
  } else {
@@ -365,7 +468,7 @@ export class RequestConditionsDrawer extends UI.Widget.VBox implements
365
468
  ?disabled=${!editable}
366
469
  .jslog=${VisualLogging.toggle().track({ change: true })}>
367
470
  <div @click=${toggle} class=blocked-url-label>${wildcardURL}</div>
368
- <div class=blocked-url-count>${i18nString(UIStrings.dBlocked, {PH1: blockedCount})}</div>`,
471
+ <devtools-widget .widgetConfig=${widgetConfig(AffectedCountWidget, {condition, drawer: this})}></devtools-widget>`,
369
472
  // clang-format on
370
473
  element);
371
474
  }
@@ -461,20 +564,17 @@ export class RequestConditionsDrawer extends UI.Widget.VBox implements
461
564
  this.requestUpdate();
462
565
  }
463
566
 
464
- private blockedRequestsCount(condition: SDK.NetworkManager.RequestCondition): number {
567
+ blockedRequestsCount(condition: SDK.NetworkManager.RequestCondition): number {
465
568
  let result = 0;
466
569
  for (const blockedUrl of this.blockedCountForUrl.keys()) {
467
- const match = Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled ?
468
- condition.originalOrUpgradedURLPattern?.test(blockedUrl) :
469
- (condition.wildcardURL && this.matches(condition.wildcardURL, blockedUrl));
470
- if (match) {
570
+ if (matchesUrl(condition, blockedUrl)) {
471
571
  result += (this.blockedCountForUrl.get(blockedUrl) as number);
472
572
  }
473
573
  }
474
574
  return result;
475
575
  }
476
576
 
477
- #throttledRequestsCount(condition: SDK.NetworkManager.RequestCondition): number {
577
+ throttledRequestsCount(condition: SDK.NetworkManager.RequestCondition): number {
478
578
  let result = 0;
479
579
  for (const ruleId of condition.ruleIds) {
480
580
  result += this.#throttledCount.get(ruleId) ?? 0;
@@ -482,27 +582,9 @@ export class RequestConditionsDrawer extends UI.Widget.VBox implements
482
582
  return result;
483
583
  }
484
584
 
485
- private matches(pattern: string, url: string): boolean {
486
- let pos = 0;
487
- const parts = pattern.split('*');
488
- for (let index = 0; index < parts.length; index++) {
489
- const part = parts[index];
490
- if (!part.length) {
491
- continue;
492
- }
493
- pos = url.indexOf(part, pos);
494
- if (pos === -1) {
495
- return false;
496
- }
497
- pos += part.length;
498
- }
499
- return true;
500
- }
501
-
502
585
  private onNetworkLogReset(_event: Common.EventTarget.EventTargetEvent<Logs.NetworkLog.ResetEvent>): void {
503
586
  this.blockedCountForUrl.clear();
504
587
  this.#throttledCount.clear();
505
- this.update();
506
588
  }
507
589
 
508
590
  private onRequestFinished(event: Common.EventTarget.EventTargetEvent<SDK.NetworkRequest.NetworkRequest>): void {
@@ -515,10 +597,8 @@ export class RequestConditionsDrawer extends UI.Widget.VBox implements
515
597
  const count = this.blockedCountForUrl.get(request.url()) || 0;
516
598
  this.blockedCountForUrl.set(request.url(), count + 1);
517
599
  }
518
- if (request.appliedNetworkConditionsId || request.wasBlocked()) {
519
- this.update();
520
- }
521
600
  }
601
+
522
602
  override wasShown(): void {
523
603
  UI.Context.Context.instance().setFlavor(RequestConditionsDrawer, this);
524
604
  super.wasShown();
@@ -528,6 +608,20 @@ export class RequestConditionsDrawer extends UI.Widget.VBox implements
528
608
  super.willHide();
529
609
  UI.Context.Context.instance().setFlavor(RequestConditionsDrawer, null);
530
610
  }
611
+
612
+ static async reveal(appliedConditions: SDK.NetworkManager.AppliedNetworkConditions): Promise<void> {
613
+ await UI.ViewManager.ViewManager.instance().showView('network.blocked-urls');
614
+ const drawer = UI.Context.Context.instance().flavor(RequestConditionsDrawer);
615
+ if (!drawer) {
616
+ console.assert(!!drawer, 'Drawer not initialized');
617
+ return;
618
+ }
619
+ const conditions = drawer.manager.requestConditions.conditions.find(
620
+ condition => condition.ruleIds.has(appliedConditions.appliedNetworkConditionsId) &&
621
+ condition.constructorString && condition.constructorString === appliedConditions.urlPattern);
622
+ const element = (conditions && drawer.#listElements.get(conditions));
623
+ element && PanelUtils.PanelUtils.highlightElement(element);
624
+ }
531
625
  }
532
626
 
533
627
  export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
@@ -550,3 +644,12 @@ export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
550
644
  return false;
551
645
  }
552
646
  }
647
+
648
+ export class AppliedConditionsRevealer implements
649
+ Common.Revealer.Revealer<SDK.NetworkManager.AppliedNetworkConditions> {
650
+ async reveal(request: SDK.NetworkManager.AppliedNetworkConditions): Promise<void> {
651
+ if (request.urlPattern) {
652
+ await RequestConditionsDrawer.reveal(request);
653
+ }
654
+ }
655
+ }
@@ -307,11 +307,16 @@ interface ViewInput {
307
307
  serverTimings: SDK.ServerTiming.ServerTiming[];
308
308
  fetchDetails?: UI.TreeOutline.TreeOutlineInShadow;
309
309
  routerDetails?: UI.TreeOutline.TreeOutlineInShadow;
310
- wasThrottled?: SDK.NetworkManager.Conditions;
310
+ wasThrottled?: SDK.NetworkManager.AppliedNetworkConditions;
311
311
  }
312
312
 
313
313
  type View = (input: ViewInput, output: object, target: HTMLElement) => void;
314
314
  export const DEFAULT_VIEW: View = (input, output, target) => {
315
+ const revealThrottled = (): void => {
316
+ if (input.wasThrottled) {
317
+ void Common.Revealer.reveal(input.wasThrottled);
318
+ }
319
+ };
315
320
  const scale = 100 / (input.endTime - input.startTime);
316
321
  const isClickable = (range: NetworkTimeCalculator.RequestTimeRange): boolean =>
317
322
  range.name === 'serviceworker-respondwith' || range.name === 'serviceworker-routerevaluation';
@@ -376,11 +381,11 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
376
381
  }
377
382
  };
378
383
 
379
- const throttledRequestTitle = input.wasThrottled ?
380
- i18nString(
381
- UIStrings.wasThrottled,
382
- {PH1: typeof input.wasThrottled.title === 'string' ? input.wasThrottled.title : input.wasThrottled.title()}) :
383
- undefined;
384
+ const throttledRequestTitle = input.wasThrottled ? i18nString(UIStrings.wasThrottled, {
385
+ PH1: typeof input.wasThrottled.conditions.title === 'string' ? input.wasThrottled.conditions.title :
386
+ input.wasThrottled.conditions.title()
387
+ }) :
388
+ undefined;
384
389
 
385
390
  const classes = classMap({
386
391
  ['network-timing-table']: true,
@@ -503,7 +508,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
503
508
  </x-link>
504
509
  <td></td>
505
510
  <td class=${input.wasThrottled ? 'throttled' : ''} title=${ifDefined(throttledRequestTitle)}>
506
- ${input.wasThrottled ? html` <devtools-icon name=watch ></devtools-icon>` : nothing}
511
+ ${input.wasThrottled ? html` <devtools-icon name=watch @click=${revealThrottled}></devtools-icon>` : nothing}
507
512
  ${i18n.TimeUtilities.secondsToString(input.totalDuration, true)}
508
513
  </td>
509
514
  </tr>
@@ -578,7 +583,7 @@ export class RequestTimingView extends UI.Widget.VBox {
578
583
  requestUnfinished: false,
579
584
  fetchDetails: this.#fetchDetailsTree(),
580
585
  routerDetails: this.#routerDetailsTree(),
581
- wasThrottled: conditions?.urlPattern ? conditions.conditions : undefined,
586
+ wasThrottled: conditions?.urlPattern ? conditions : undefined,
582
587
  timeRanges,
583
588
  };
584
589
  this.#view(input, {}, this.contentElement);
@@ -521,3 +521,14 @@ Common.Revealer.registerRevealer({
521
521
  return new Network.NetworkPanel.NetworkLogWithFilterRevealer();
522
522
  },
523
523
  });
524
+
525
+ Common.Revealer.registerRevealer({
526
+ contextTypes() {
527
+ return [SDK.NetworkManager.AppliedNetworkConditions];
528
+ },
529
+ destination: Common.Revealer.RevealerDestination.NETWORK_PANEL,
530
+ async loadRevealer() {
531
+ const Network = await loadNetworkModule();
532
+ return new Network.RequestConditionsDrawer.AppliedConditionsRevealer();
533
+ },
534
+ });
@@ -92,7 +92,7 @@ hr.section-separator {
92
92
 
93
93
  .input-field:focus {
94
94
  border: 1px solid var(--sys-color-state-focus-ring);
95
- outline-width: 0;
95
+ outline-style: none;
96
96
  }
97
97
 
98
98
  .add-container {
@@ -2008,7 +2008,7 @@ class ValueDecoration extends CodeMirror.WidgetType {
2008
2008
  } else {
2009
2009
  const propertyValue = ObjectUI.ObjectPropertiesSection.ObjectPropertiesSection.createPropertyValue(
2010
2010
  value, /* wasThrown */ false, /* showPreview */ false);
2011
- nameValuePair.appendChild(propertyValue.element);
2011
+ nameValuePair.appendChild(propertyValue);
2012
2012
  }
2013
2013
  }
2014
2014
  return widget;
@@ -498,7 +498,7 @@ export class WatchExpression extends Common.ObjectWrapper.ObjectWrapper<EventTyp
498
498
  const propertyValue =
499
499
  ObjectUI.ObjectPropertiesSection.ObjectPropertiesSection.createPropertyValueWithCustomSupport(
500
500
  expressionValue, Boolean(exceptionDetails), false /* showPreview */, this.linkifier);
501
- this.valueElement = propertyValue.element;
501
+ this.valueElement = propertyValue;
502
502
  }
503
503
  const separatorElement = document.createElement('span');
504
504
  separatorElement.classList.add('watch-expressions-separator');
@@ -271,6 +271,6 @@
271
271
  .pause-on-uncaught-exceptions:focus,
272
272
  .pause-on-caught-exceptions:focus {
273
273
  background-color: var(--sys-color-tonal-container);
274
- outline-width: 0;
274
+ outline-style: none;
275
275
  }
276
276
  }
@@ -28,8 +28,8 @@
28
28
  */
29
29
 
30
30
  .paused-message {
31
- align-self: center;
32
- width: fit-content;
31
+ display: flex;
32
+ justify-content: center;
33
33
  }
34
34
 
35
35
  .scripts-debug-toolbar {
@@ -622,10 +622,10 @@ export class TimelineFlameChartView extends Common.ObjectWrapper.eventMixin<Even
622
622
  }
623
623
 
624
624
  const fieldMetricResultsByNavigationId = new Map<string, Trace.Insights.Common.CrUXFieldMetricResults|null>();
625
- for (const [key, insightSet] of insights) {
626
- if (insightSet.navigation) {
625
+ for (const insightSet of insights.values()) {
626
+ if (insightSet.navigation?.args.data?.navigationId) {
627
627
  fieldMetricResultsByNavigationId.set(
628
- key,
628
+ insightSet.navigation.args.data.navigationId,
629
629
  Trace.Insights.Common.getFieldMetricsForInsightSet(
630
630
  insightSet, metadata, CrUXManager.CrUXManager.instance().getSelectedScope()));
631
631
  }
@@ -3094,15 +3094,15 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
3094
3094
  };
3095
3095
  }
3096
3096
 
3097
- const navigationId = Array.from(parsedTrace.insights.keys()).find(k => k !== 'NO_NAVIGATION');
3098
- if (!navigationId) {
3097
+ const insightSetId = Array.from(parsedTrace.insights.keys()).find(k => k !== 'NO_NAVIGATION');
3098
+ if (!insightSetId) {
3099
3099
  return {
3100
3100
  type: AiAssistanceModel.AiAgent.ExternalRequestResponseType.ERROR,
3101
3101
  message: 'The trace was loaded successfully but no navigation was detected.',
3102
3102
  };
3103
3103
  }
3104
3104
 
3105
- const insightsForNav = parsedTrace.insights.get(navigationId);
3105
+ const insightsForNav = parsedTrace.insights.get(insightSetId);
3106
3106
  if (!insightsForNav) {
3107
3107
  return {
3108
3108
  type: AiAssistanceModel.AiAgent.ExternalRequestResponseType.ERROR,