chrome-devtools-frontend 1.0.1543472 → 1.0.1544076

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 (109) hide show
  1. package/AUTHORS +1 -0
  2. package/front_end/core/host/AidaClient.ts +10 -7
  3. package/front_end/core/host/DispatchHttpRequestClient.ts +18 -3
  4. package/front_end/core/root/Runtime.ts +8 -7
  5. package/front_end/core/sdk/CPUThrottlingManager.ts +0 -4
  6. package/front_end/core/sdk/CSSMatchedStyles.ts +7 -9
  7. package/front_end/core/sdk/CSSModel.ts +1 -1
  8. package/front_end/core/sdk/CSSRule.ts +18 -6
  9. package/front_end/core/sdk/ChildTargetManager.ts +2 -2
  10. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotLoader.ts +2 -0
  11. package/front_end/entrypoints/main/MainImpl.ts +0 -16
  12. package/front_end/foundation/Universe.ts +12 -1
  13. package/front_end/models/ai_assistance/agents/AiAgent.ts +10 -8
  14. package/front_end/models/ai_assistance/agents/PatchAgent.ts +7 -1
  15. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +0 -5
  16. package/front_end/models/ai_assistance/agents/StylingAgent.ts +4 -8
  17. package/front_end/models/ai_code_completion/AiCodeCompletion.ts +1 -1
  18. package/front_end/models/ai_code_generation/AiCodeGeneration.ts +5 -3
  19. package/front_end/models/bindings/CSSWorkspaceBinding.ts +8 -7
  20. package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +9 -8
  21. package/front_end/models/bindings/ResourceMapping.ts +57 -15
  22. package/front_end/models/live-metrics/LiveMetrics.ts +12 -20
  23. package/front_end/panels/accessibility/AccessibilityNodeView.ts +6 -2
  24. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +1 -1
  25. package/front_end/panels/ai_assistance/components/ChatView.ts +2 -4
  26. package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +2 -1
  27. package/front_end/panels/animation/AnimationTimeline.ts +6 -6
  28. package/front_end/panels/application/components/ReportsGrid.ts +7 -2
  29. package/front_end/panels/application/components/SharedStorageAccessGrid.ts +5 -3
  30. package/front_end/panels/application/components/TrustTokensView.ts +7 -1
  31. package/front_end/panels/application/preloading/PreloadingView.ts +10 -4
  32. package/front_end/panels/application/preloading/components/PreloadingDisabledInfobar.ts +7 -11
  33. package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +15 -3
  34. package/front_end/panels/browser_debugger/DOMBreakpointsSidebarPane.ts +12 -13
  35. package/front_end/panels/{elements → common}/DOMLinkifier.ts +6 -6
  36. package/front_end/panels/common/common.ts +1 -0
  37. package/front_end/panels/console/ConsoleViewMessage.ts +4 -4
  38. package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +2 -1
  39. package/front_end/panels/elements/ElementsTreeElement.ts +3 -1
  40. package/front_end/panels/elements/StylePropertiesSection.ts +52 -15
  41. package/front_end/panels/elements/StylePropertyTreeElement.ts +8 -3
  42. package/front_end/panels/elements/StylesSidebarPane.ts +24 -14
  43. package/front_end/panels/elements/elements-meta.ts +11 -2
  44. package/front_end/panels/elements/elements.ts +0 -3
  45. package/front_end/panels/explain/components/ConsoleInsight.ts +31 -20
  46. package/front_end/panels/issues/AffectedResourcesView.ts +2 -1
  47. package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +2 -1
  48. package/front_end/panels/network/NetworkLogView.ts +1 -1
  49. package/front_end/panels/recorder/RecorderController.ts +7 -1
  50. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +42 -294
  51. package/front_end/panels/sources/DebuggerPausedMessage.ts +3 -3
  52. package/front_end/panels/sources/SourcesPanel.ts +5 -1
  53. package/front_end/panels/timeline/TimelineUIUtils.ts +3 -2
  54. package/front_end/panels/timeline/components/LiveMetricsView.ts +7 -4
  55. package/front_end/panels/timeline/components/insights/NodeLink.ts +3 -2
  56. package/front_end/third_party/puppeteer/README.chromium +2 -2
  57. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/HTTPRequest.d.ts +1 -0
  58. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/HTTPRequest.d.ts.map +1 -1
  59. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/HTTPRequest.js +4 -1
  60. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/HTTPRequest.js.map +1 -1
  61. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkEventManager.d.ts +1 -0
  62. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkEventManager.d.ts.map +1 -1
  63. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkEventManager.js +8 -0
  64. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkEventManager.js.map +1 -1
  65. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
  66. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.js +22 -0
  67. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.js.map +1 -1
  68. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  69. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
  70. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
  71. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
  72. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  73. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  74. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  75. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +34 -6
  76. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/HTTPRequest.d.ts +1 -0
  77. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/HTTPRequest.d.ts.map +1 -1
  78. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/HTTPRequest.js +4 -1
  79. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/HTTPRequest.js.map +1 -1
  80. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkEventManager.d.ts +1 -0
  81. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkEventManager.d.ts.map +1 -1
  82. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkEventManager.js +8 -0
  83. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkEventManager.js.map +1 -1
  84. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
  85. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.js +22 -0
  86. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.js.map +1 -1
  87. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
  88. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
  89. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
  90. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  91. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  92. package/front_end/third_party/puppeteer/package/package.json +2 -2
  93. package/front_end/third_party/puppeteer/package/src/cdp/HTTPRequest.ts +5 -1
  94. package/front_end/third_party/puppeteer/package/src/cdp/NetworkEventManager.ts +16 -1
  95. package/front_end/third_party/puppeteer/package/src/cdp/NetworkManager.ts +28 -0
  96. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  97. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  98. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +8 -5
  99. package/front_end/ui/i18n/i18n.ts +16 -0
  100. package/front_end/ui/legacy/UIUtils.ts +1 -1
  101. package/front_end/ui/legacy/Widget.ts +56 -25
  102. package/front_end/ui/legacy/XLink.ts +0 -2
  103. package/front_end/ui/legacy/components/object_ui/ObjectPopoverHelper.ts +3 -1
  104. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +155 -198
  105. package/front_end/ui/legacy/inspectorCommon.css +0 -4
  106. package/mcp/mcp.ts +1 -0
  107. package/package.json +1 -1
  108. package/front_end/ui/components/expandable_list/ExpandableList.docs.ts +0 -30
  109. /package/front_end/panels/{elements → common}/domLinkifier.css +0 -0
@@ -9,8 +9,8 @@ import * as TextUtils from '../text_utils/text_utils.js';
9
9
  import * as Workspace from '../workspace/workspace.js';
10
10
 
11
11
  import {ContentProviderBasedProject} from './ContentProviderBasedProject.js';
12
- import {CSSWorkspaceBinding} from './CSSWorkspaceBinding.js';
13
- import {DebuggerWorkspaceBinding} from './DebuggerWorkspaceBinding.js';
12
+ import type {CSSWorkspaceBinding} from './CSSWorkspaceBinding.js';
13
+ import type {DebuggerWorkspaceBinding} from './DebuggerWorkspaceBinding.js';
14
14
  import {NetworkProject} from './NetworkProject.js';
15
15
  import {resourceMetadata} from './ResourceUtils.js';
16
16
 
@@ -30,13 +30,46 @@ export class ResourceMapping implements SDK.TargetManager.SDKModelObserver<SDK.R
30
30
  readonly workspace: Workspace.Workspace.WorkspaceImpl;
31
31
  readonly #modelToInfo = new Map<SDK.ResourceTreeModel.ResourceTreeModel, ModelInfo>();
32
32
 
33
+ #debuggerWorkspaceBinding: DebuggerWorkspaceBinding|null = null;
34
+ #cssWorkspaceBinding: CSSWorkspaceBinding|null = null;
35
+
33
36
  constructor(targetManager: SDK.TargetManager.TargetManager, workspace: Workspace.Workspace.WorkspaceImpl) {
34
37
  this.workspace = workspace;
35
38
  targetManager.observeModels(SDK.ResourceTreeModel.ResourceTreeModel, this);
36
39
  }
37
40
 
41
+ get debuggerWorkspaceBinding(): DebuggerWorkspaceBinding|null {
42
+ // TODO(crbug.com/458180550): Throw when this.#debuggerWorkspaceBinding is null and never return null.
43
+ // The only reason we don't throw and return an instance unconditionally
44
+ // is that unit tests often don't set-up both the *WorkspaceBindings.
45
+ return this.#debuggerWorkspaceBinding;
46
+ }
47
+
48
+ /* {@link DebuggerWorkspaceBinding} and ResourceMapping form a cycle so we can't wire it up at ctor time. */
49
+ set debuggerWorkspaceBinding(debuggerWorkspaceBinding: DebuggerWorkspaceBinding) {
50
+ if (this.#debuggerWorkspaceBinding) {
51
+ throw new Error('DebuggerWorkspaceBinding already set');
52
+ }
53
+ this.#debuggerWorkspaceBinding = debuggerWorkspaceBinding;
54
+ }
55
+
56
+ get cssWorkspaceBinding(): CSSWorkspaceBinding|null {
57
+ // TODO(crbug.com/458180550): Throw when this.#cssWorkspaceBinding is null and never return null.
58
+ // The only reason we don't throw and return an instance unconditionally
59
+ // is that unit tests often don't set-up both the *WorkspaceBindings.
60
+ return this.#cssWorkspaceBinding;
61
+ }
62
+
63
+ /* {@link CSSWorkspaceBinding} and ResourceMapping form a cycle so we can't wire it up at ctor time. */
64
+ set cssWorkspaceBinding(cssWorkspaceBinding: CSSWorkspaceBinding) {
65
+ if (this.#cssWorkspaceBinding) {
66
+ throw new Error('CSSWorkspaceBinding already set');
67
+ }
68
+ this.#cssWorkspaceBinding = cssWorkspaceBinding;
69
+ }
70
+
38
71
  modelAdded(resourceTreeModel: SDK.ResourceTreeModel.ResourceTreeModel): void {
39
- const info = new ModelInfo(this.workspace, resourceTreeModel);
72
+ const info = new ModelInfo(this, resourceTreeModel);
40
73
  this.#modelToInfo.set(resourceTreeModel, info);
41
74
  }
42
75
 
@@ -250,11 +283,13 @@ class ModelInfo {
250
283
  readonly #bindings = new Map<string, Binding>();
251
284
  readonly #cssModel: SDK.CSSModel.CSSModel;
252
285
  readonly #eventListeners: Common.EventTarget.EventDescriptor[];
253
- constructor(
254
- workspace: Workspace.Workspace.WorkspaceImpl, resourceTreeModel: SDK.ResourceTreeModel.ResourceTreeModel) {
286
+ readonly resourceMapping: ResourceMapping;
287
+
288
+ constructor(resourceMapping: ResourceMapping, resourceTreeModel: SDK.ResourceTreeModel.ResourceTreeModel) {
255
289
  const target = resourceTreeModel.target();
290
+ this.resourceMapping = resourceMapping;
256
291
  this.project = new ContentProviderBasedProject(
257
- workspace, 'resources:' + target.id(), Workspace.Workspace.projectTypes.Network, '',
292
+ resourceMapping.workspace, 'resources:' + target.id(), Workspace.Workspace.projectTypes.Network, '',
258
293
  false /* isServiceProject */);
259
294
  NetworkProject.setTargetForProject(this.project, target);
260
295
 
@@ -332,7 +367,7 @@ class ModelInfo {
332
367
 
333
368
  let binding = this.#bindings.get(resource.url);
334
369
  if (!binding) {
335
- binding = new Binding(this.project, resource);
370
+ binding = new Binding(this, resource);
336
371
  this.#bindings.set(resource.url, binding);
337
372
  } else {
338
373
  binding.addResource(resource);
@@ -396,9 +431,16 @@ class Binding implements TextUtils.ContentProvider.ContentProvider {
396
431
  stylesheet: SDK.CSSStyleSheetHeader.CSSStyleSheetHeader,
397
432
  edit: SDK.CSSModel.Edit|null,
398
433
  }> = [];
399
- constructor(project: ContentProviderBasedProject, resource: SDK.Resource.Resource) {
434
+
435
+ readonly #debuggerWorkspaceBinding: DebuggerWorkspaceBinding|null;
436
+ readonly #cssWorkspaceBinding: CSSWorkspaceBinding|null;
437
+
438
+ constructor(modelInfo: ModelInfo, resource: SDK.Resource.Resource) {
400
439
  this.resources = new Set([resource]);
401
- this.#project = project;
440
+ this.#project = modelInfo.project;
441
+ this.#debuggerWorkspaceBinding = modelInfo.resourceMapping.debuggerWorkspaceBinding;
442
+ this.#cssWorkspaceBinding = modelInfo.resourceMapping.cssWorkspaceBinding;
443
+
402
444
  this.#uiSourceCode = this.#project.createUISourceCode(resource.url, resource.contentType());
403
445
  boundUISourceCodes.add(this.#uiSourceCode);
404
446
  if (resource.frameId) {
@@ -407,8 +449,8 @@ class Binding implements TextUtils.ContentProvider.ContentProvider {
407
449
  this.#project.addUISourceCodeWithProvider(this.#uiSourceCode, this, resourceMetadata(resource), resource.mimeType);
408
450
 
409
451
  void Promise.all([
410
- ...this.inlineScripts().map(script => DebuggerWorkspaceBinding.instance().updateLocations(script)),
411
- ...this.inlineStyles().map(style => CSSWorkspaceBinding.instance().updateLocations(style)),
452
+ ...this.inlineScripts().map(script => this.#debuggerWorkspaceBinding?.updateLocations(script)),
453
+ ...this.inlineStyles().map(style => this.#cssWorkspaceBinding?.updateLocations(style)),
412
454
  ]);
413
455
  }
414
456
 
@@ -478,7 +520,7 @@ class Binding implements TextUtils.ContentProvider.ContentProvider {
478
520
  continue;
479
521
  }
480
522
  scriptRangeMap.set(script, range.rebaseAfterTextEdit(oldRange, newRange));
481
- updatePromises.push(DebuggerWorkspaceBinding.instance().updateLocations(script));
523
+ updatePromises.push(this.#debuggerWorkspaceBinding?.updateLocations(script));
482
524
  }
483
525
  for (const style of styles) {
484
526
  const range = styleSheetRangeMap.get(style) ?? computeStyleSheetRange(style);
@@ -486,7 +528,7 @@ class Binding implements TextUtils.ContentProvider.ContentProvider {
486
528
  continue;
487
529
  }
488
530
  styleSheetRangeMap.set(style, range.rebaseAfterTextEdit(oldRange, newRange));
489
- updatePromises.push(CSSWorkspaceBinding.instance().updateLocations(style));
531
+ updatePromises.push(this.#cssWorkspaceBinding?.updateLocations(style));
490
532
  }
491
533
  await Promise.all(updatePromises);
492
534
  }
@@ -510,8 +552,8 @@ class Binding implements TextUtils.ContentProvider.ContentProvider {
510
552
  dispose(): void {
511
553
  this.#project.removeUISourceCode(this.#uiSourceCode.url());
512
554
  void Promise.all([
513
- ...this.inlineScripts().map(script => DebuggerWorkspaceBinding.instance().updateLocations(script)),
514
- ...this.inlineStyles().map(style => CSSWorkspaceBinding.instance().updateLocations(style)),
555
+ ...this.inlineScripts().map(script => this.#debuggerWorkspaceBinding?.updateLocations(script)),
556
+ ...this.inlineStyles().map(style => this.#cssWorkspaceBinding?.updateLocations(style)),
515
557
  ]);
516
558
  }
517
559
 
@@ -163,7 +163,8 @@ export class LiveMetrics extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
163
163
  * DOM nodes can't be sent over a runtime binding, so we have to retrieve
164
164
  * them separately.
165
165
  */
166
- async #resolveNodeRef(index: number, executionContextId: Protocol.Runtime.ExecutionContextId): Promise<NodeRef|null> {
166
+ async #resolveNodeRef(index: number, executionContextId: Protocol.Runtime.ExecutionContextId):
167
+ Promise<SDK.DOMModel.DOMNode|null> {
167
168
  if (!this.#target) {
168
169
  return null;
169
170
  }
@@ -195,8 +196,7 @@ export class LiveMetrics extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
195
196
  return null;
196
197
  }
197
198
 
198
- const link = await Common.Linkifier.Linkifier.linkify(node);
199
- return {node, link};
199
+ return node;
200
200
  } catch {
201
201
  return null;
202
202
  } finally {
@@ -236,26 +236,23 @@ export class LiveMetrics extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
236
236
  ...this.#layoutShifts.flatMap(shift => shift.affectedNodeRefs),
237
237
  ].filter(nodeRef => !!nodeRef);
238
238
 
239
- const idsToRefresh = new Set(toRefresh.map(nodeRef => nodeRef.node.backendNodeId()));
239
+ const idsToRefresh = new Set(toRefresh.map(nodeRef => nodeRef.backendNodeId()));
240
240
  const nodes = await domModel.pushNodesByBackendIdsToFrontend(idsToRefresh);
241
241
  if (!nodes) {
242
242
  return;
243
243
  }
244
244
 
245
- const allPromises = toRefresh.map(async nodeRef => {
246
- const refreshedNode = nodes.get(nodeRef.node.backendNodeId());
245
+ for (let i = 0; i < toRefresh.length; i++) {
246
+ const refreshedNode = nodes.get(toRefresh[i].backendNodeId());
247
247
 
248
248
  // It is possible for the refreshed node to be undefined even though it was defined previously.
249
249
  // We should keep the affected nodes consistent from the user perspective, so we will just keep the stale node instead of removing it.
250
250
  if (!refreshedNode) {
251
- return;
251
+ continue;
252
252
  }
253
253
 
254
- nodeRef.node = refreshedNode;
255
- nodeRef.link = await Common.Linkifier.Linkifier.linkify(refreshedNode);
256
- });
257
-
258
- await Promise.all(allPromises);
254
+ toRefresh[i] = refreshedNode;
255
+ }
259
256
 
260
257
  this.#sendStatusUpdate();
261
258
  }
@@ -599,14 +596,9 @@ export interface MetricValue {
599
596
  warnings?: string[];
600
597
  }
601
598
 
602
- export interface NodeRef {
603
- node: SDK.DOMModel.DOMNode;
604
- link: Node;
605
- }
606
-
607
599
  export interface LcpValue extends MetricValue {
608
600
  phases: Spec.LcpPhases;
609
- nodeRef?: NodeRef;
601
+ nodeRef?: SDK.DOMModel.DOMNode;
610
602
  }
611
603
 
612
604
  export interface InpValue extends MetricValue {
@@ -621,7 +613,7 @@ export interface ClsValue extends MetricValue {
621
613
  export interface LayoutShift {
622
614
  score: number;
623
615
  uniqueLayoutShiftId: Spec.UniqueLayoutShiftId;
624
- affectedNodeRefs: NodeRef[];
616
+ affectedNodeRefs: SDK.DOMModel.DOMNode[];
625
617
  }
626
618
 
627
619
  export interface Interaction {
@@ -633,7 +625,7 @@ export interface Interaction {
633
625
  nextPaintTime: number;
634
626
  phases: Spec.InpPhases;
635
627
  longAnimationFrameTimings: Spec.PerformanceLongAnimationFrameTimingJSON[];
636
- nodeRef?: NodeRef;
628
+ nodeRef?: SDK.DOMModel.DOMNode;
637
629
  }
638
630
 
639
631
  export interface StatusEvent {
@@ -10,6 +10,7 @@ import * as Protocol from '../../generated/protocol.js';
10
10
  import * as uiI18n from '../../ui/i18n/i18n.js';
11
11
  import * as UI from '../../ui/legacy/legacy.js';
12
12
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
13
+ import * as PanelsCommon from '../common/common.js';
13
14
 
14
15
  import accessibilityNodeStyles from './accessibilityNode.css.js';
15
16
  import {AXAttributes, AXNativeSourceTypes, AXSourceTypes} from './AccessibilityStrings.js';
@@ -587,8 +588,11 @@ export class AXRelatedNodeElement {
587
588
  const valueElement = document.createElement('span');
588
589
  element.appendChild(valueElement);
589
590
  void this.deferredNode.resolvePromise().then(node => {
590
- void Common.Linkifier.Linkifier.linkify(node, {tooltip: undefined, preventKeyboardFocus: true})
591
- .then(linkfied => valueElement.appendChild(linkfied));
591
+ if (!node) {
592
+ return;
593
+ }
594
+ valueElement.appendChild(PanelsCommon.DOMLinkifier.Linkifier.instance().linkify(
595
+ node, {tooltip: undefined, preventKeyboardFocus: true}));
592
596
  });
593
597
  } else if (this.idref) {
594
598
  element.classList.add('invalid');
@@ -474,7 +474,7 @@ function agentToConversationType(agent: AiAssistanceModel.AiAgent.AiAgent<unknow
474
474
  }
475
475
 
476
476
  if (agent instanceof AiAssistanceModel.PerformanceAgent.PerformanceAgent) {
477
- return agent.getConversationType();
477
+ return AiAssistanceModel.AiHistoryStorage.ConversationType.PERFORMANCE;
478
478
  }
479
479
 
480
480
  throw new Error('Provided agent does not have a corresponding conversation type');
@@ -12,7 +12,7 @@ import type * as Platform from '../../../core/platform/platform.js';
12
12
  import * as SDK from '../../../core/sdk/sdk.js';
13
13
  import * as AiAssistanceModel from '../../../models/ai_assistance/ai_assistance.js';
14
14
  import * as Workspace from '../../../models/workspace/workspace.js';
15
- import * as ElementsPanel from '../../../panels/elements/elements.js';
15
+ import * as PanelsCommon from '../../../panels/common/common.js';
16
16
  import * as PanelUtils from '../../../panels/utils/utils.js';
17
17
  import * as Marked from '../../../third_party/marked/marked.js';
18
18
  import * as Buttons from '../../../ui/components/buttons/buttons.js';
@@ -532,7 +532,6 @@ export class ChatView extends HTMLElement {
532
532
  suggestions: this.#props.emptyStateSuggestions,
533
533
  userInfo: this.#props.userInfo,
534
534
  markdownRenderer: this.#props.markdownRenderer,
535
- conversationType: this.#props.conversationType,
536
535
  changeSummary: this.#props.changeSummary,
537
536
  changeManager: this.#props.changeManager,
538
537
  onSuggestionClick: this.#handleSuggestionClick,
@@ -932,7 +931,7 @@ function renderContextTitle(
932
931
  // FIXME: move this to the model code.
933
932
  const hiddenClassList = item.classNames().filter(
934
933
  className => className.startsWith(AiAssistanceModel.Injected.AI_ASSISTANCE_CSS_CLASS_NAME));
935
- return html`<devtools-widget .widgetConfig=${UI.Widget.widgetConfig(ElementsPanel.DOMLinkifier.DOMNodeLink, {
934
+ return html`<devtools-widget .widgetConfig=${UI.Widget.widgetConfig(PanelsCommon.DOMLinkifier.DOMNodeLink, {
936
935
  node: item,
937
936
  options: {hiddenClassList, disabled}
938
937
  })}></devtools-widget>`;
@@ -1458,7 +1457,6 @@ function renderMainContents({
1458
1457
  onFeedbackSubmit: (rpcId: Host.AidaClient.RpcGlobalId, rate: Host.AidaClient.Rating, feedback?: string) => void,
1459
1458
  onCopyResponseClick: (message: ModelChatMessage) => void,
1460
1459
  onMessageContainerRef: (el: Element|undefined) => void,
1461
- conversationType: AiAssistanceModel.AiHistoryStorage.ConversationType,
1462
1460
  changeSummary?: string,
1463
1461
  }): Lit.LitTemplate {
1464
1462
  if (messages.length > 0) {
@@ -8,6 +8,7 @@ import type * as Protocol from '../../../generated/protocol.js';
8
8
  import * as Trace from '../../../models/trace/trace.js';
9
9
  import type * as Marked from '../../../third_party/marked/marked.js';
10
10
  import * as Lit from '../../../ui/lit/lit.js';
11
+ import * as PanelsCommon from '../../common/common.js';
11
12
 
12
13
  import {MarkdownRendererWithCodeBlock} from './MarkdownRendererWithCodeBlock.js';
13
14
 
@@ -84,7 +85,7 @@ export class PerformanceAgentMarkdownRenderer extends MarkdownRendererWithCodeBl
84
85
  return;
85
86
  }
86
87
 
87
- const linkedNode = await Common.Linkifier.Linkifier.linkify(node, {textContent: label});
88
+ const linkedNode = PanelsCommon.DOMLinkifier.Linkifier.instance().linkify(node, {textContent: label});
88
89
  return linkedNode;
89
90
  }
90
91
  }
@@ -18,6 +18,7 @@ import * as Buttons from '../../ui/components/buttons/buttons.js';
18
18
  import * as UI from '../../ui/legacy/legacy.js';
19
19
  import * as Lit from '../../ui/lit/lit.js';
20
20
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
21
+ import * as PanelsCommon from '../common/common.js';
21
22
 
22
23
  import {AnimationGroupPreviewUI} from './AnimationGroupPreviewUI.js';
23
24
  import animationTimelineStyles from './animationTimeline.css.js';
@@ -1222,13 +1223,12 @@ export class NodeUI {
1222
1223
  }
1223
1224
  this.#node = node;
1224
1225
  this.nodeChanged();
1225
- void Common.Linkifier.Linkifier.linkify(node).then(link => {
1226
- link.addEventListener('click', () => {
1227
- Host.userMetrics.actionTaken(Host.UserMetrics.Action.AnimatedNodeDescriptionClicked);
1228
- });
1229
-
1230
- this.#description.appendChild(link);
1226
+ const link = PanelsCommon.DOMLinkifier.Linkifier.instance().linkify(node);
1227
+ link.addEventListener('click', () => {
1228
+ Host.userMetrics.actionTaken(Host.UserMetrics.Action.AnimatedNodeDescriptionClicked);
1231
1229
  });
1230
+
1231
+ this.#description.appendChild(link);
1232
1232
  if (!node.ownerDocument) {
1233
1233
  this.nodeRemoved();
1234
1234
  }
@@ -108,8 +108,13 @@ export const DEFAULT_VIEW = (input: ViewInput, output: undefined, target: HTMLEl
108
108
  <span class="empty-state-header">${i18nString(UIStrings.noReportsToDisplay)}</span>
109
109
  <div class="empty-state-description">
110
110
  <span>${i18nString(UIStrings.reportingApiDescription)}</span>
111
- ${UI.XLink.XLink.create(REPORTING_API_EXPLANATION_URL, i18nString(UIStrings.learnMore), undefined,
112
- undefined, 'learn-more')}
111
+ <x-link
112
+ class="devtools-link"
113
+ href=${REPORTING_API_EXPLANATION_URL}
114
+ jslog=${VisualLogging.link()
115
+ .track({ click: true, keydown: 'Enter|Space' })
116
+ .context('learn-more')}
117
+ >${i18nString(UIStrings.learnMore)}</x-link>
113
118
  </div>
114
119
  </div>
115
120
  `}
@@ -97,9 +97,11 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
97
97
  <div class="empty-state-header">${i18nString(UIStrings.noEvents)}</div>
98
98
  <div class="empty-state-description">
99
99
  <span>${i18nString(UIStrings.sharedStorageDescription)}</span>
100
- ${
101
- UI.XLink.XLink.create(
102
- SHARED_STORAGE_EXPLANATION_URL, i18nString(UIStrings.learnMore), 'x-link', undefined, 'learn-more')}
100
+ <x-link
101
+ class="x-link devtools-link"
102
+ href=${SHARED_STORAGE_EXPLANATION_URL}
103
+ jslog=${VisualLogging.link().track({click: true, keydown: 'Enter|Space'}).context('learn-more')}
104
+ >${i18nString(UIStrings.learnMore)}</x-link>
103
105
  </div>
104
106
  </div>`
105
107
  : html`
@@ -115,7 +115,13 @@ export class TrustTokensView extends LegacyWrapper.LegacyWrapper.WrappableCompon
115
115
  <div class="empty-state-header">${i18nString(UIStrings.noTrustTokens)}</div>
116
116
  <div class="empty-state-description">
117
117
  <span>${i18nString(UIStrings.trustTokensDescription)}</span>
118
- ${UI.XLink.XLink.create(PRIVATE_STATE_TOKENS_EXPLANATION_URL, i18nString(UIStrings.learnMore), 'x-link', undefined, 'learn-more')}
118
+ <x-link
119
+ class="x-link devtools-link"
120
+ href=${PRIVATE_STATE_TOKENS_EXPLANATION_URL}
121
+ jslog=${VisualLogging.link()
122
+ .track({ click: true, keydown: 'Enter|Space' })
123
+ .context('learn-more')}
124
+ >${i18nString(UIStrings.learnMore)}</x-link>
119
125
  </div>
120
126
  </div>
121
127
  `;
@@ -245,7 +245,11 @@ export class PreloadingRuleSetView extends UI.Widget.VBox {
245
245
  <span class="empty-state-header">${i18nString(UIStrings.noRulesDetected)}</span>
246
246
  <div class="empty-state-description">
247
247
  <span>${i18nString(UIStrings.rulesDescription)}</span>
248
- ${UI.XLink.XLink.create(SPECULATION_EXPLANATION_URL, i18nString(UIStrings.learnMore), 'x-link', undefined, 'learn-more')}
248
+ <x-link
249
+ class="x-link devtools-link"
250
+ href=${SPECULATION_EXPLANATION_URL}
251
+ jslog=${VisualLogging.link().track({click: true, keydown:'Enter|Space'}).context('learn-more')}
252
+ >${i18nString(UIStrings.learnMore)}</x-link>
249
253
  </div>
250
254
  </div>
251
255
  <devtools-split-view sidebar-position="second">
@@ -402,9 +406,11 @@ export class PreloadingAttemptView extends UI.Widget.VBox {
402
406
  <span class="empty-state-header">${i18nString(UIStrings.noPrefetchAttempts)}</span>
403
407
  <div class="empty-state-description">
404
408
  <span>${i18nString(UIStrings.prefetchDescription)}</span>
405
- ${
406
- UI.XLink.XLink.create(
407
- SPECULATION_EXPLANATION_URL, i18nString(UIStrings.learnMore), 'x-link', undefined, 'learn-more')}
409
+ <x-link
410
+ class="x-link devtools-link"
411
+ href=${SPECULATION_EXPLANATION_URL}
412
+ jslog=${VisualLogging.link().track({click: true, keydown: 'Enter|Space'}).context('learn-more')}
413
+ >${i18nString(UIStrings.learnMore)}</x-link>
408
414
  </div>
409
415
  </div>
410
416
  <devtools-split-view sidebar-position="second">
@@ -14,7 +14,7 @@ import * as Dialogs from '../../../../ui/components/dialogs/dialogs.js';
14
14
  import * as LegacyWrapper from '../../../../ui/components/legacy_wrapper/legacy_wrapper.js';
15
15
  import * as RenderCoordinator from '../../../../ui/components/render_coordinator/render_coordinator.js';
16
16
  import * as uiI18n from '../../../../ui/i18n/i18n.js';
17
- import * as UI from '../../../../ui/legacy/legacy.js';
17
+ import type * as UI from '../../../../ui/legacy/legacy.js';
18
18
  import * as Lit from '../../../../ui/lit/lit.js';
19
19
  import * as VisualLogging from '../../../../ui/visual_logging/visual_logging.js';
20
20
 
@@ -98,6 +98,8 @@ const str_ =
98
98
  i18n.i18n.registerUIStrings('panels/application/preloading/components/PreloadingDisabledInfobar.ts', UIStrings);
99
99
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
100
100
 
101
+ const LINK = 'https://developer.chrome.com/blog/prerender-pages/';
102
+
101
103
  export class PreloadingDisabledInfobar extends LegacyWrapper.LegacyWrapper.WrappableComponent<UI.Widget.VBox> {
102
104
  readonly #shadow = this.attachShadow({mode: 'open'});
103
105
  #data: Protocol.Preload.PreloadEnabledStateUpdatedEvent = {
@@ -168,14 +170,6 @@ export class PreloadingDisabledInfobar extends LegacyWrapper.LegacyWrapper.Wrapp
168
170
  }
169
171
 
170
172
  #dialogContents(): Lit.LitTemplate {
171
- const LINK = 'https://developer.chrome.com/blog/prerender-pages/';
172
-
173
- const learnMoreLink =
174
- UI.XLink.XLink.create(LINK, i18nString(UIStrings.footerLearnMore), undefined, undefined, 'learn-more');
175
- const iconLink = UI.Fragment.html`
176
- <x-link class="icon-link devtools-link" tabindex="0" href="${LINK}"></x-link>
177
- ` as UI.XLink.XLink;
178
-
179
173
  return html`
180
174
  <div id='contents'>
181
175
  <devtools-report>
@@ -186,8 +180,10 @@ export class PreloadingDisabledInfobar extends LegacyWrapper.LegacyWrapper.Wrapp
186
180
  ${this.#maybeDisableByHoldbackPrerenderSpeculationRules()}
187
181
  </devtools-report>
188
182
  <div id='footer'>
189
- ${learnMoreLink}
190
- ${iconLink}
183
+ <x-link class="devtools-link" tabindex="0" href=${LINK}
184
+ jslog=${VisualLogging.link().track({click: true, keydown: 'Enter|Space'}).context('learn-more')}
185
+ >${i18nString(UIStrings.footerLearnMore)}</x-link>
186
+ <x-link class="icon-link devtools-link" tabindex="0" href=${LINK}></x-link>
191
187
  </div>
192
188
  </div>
193
189
  `;
@@ -16,7 +16,7 @@ import * as SDK from '../../../../core/sdk/sdk.js';
16
16
  import * as Protocol from '../../../../generated/protocol.js';
17
17
  import * as LegacyWrapper from '../../../../ui/components/legacy_wrapper/legacy_wrapper.js';
18
18
  import * as RenderCoordinator from '../../../../ui/components/render_coordinator/render_coordinator.js';
19
- import * as UI from '../../../../ui/legacy/legacy.js';
19
+ import type * as UI from '../../../../ui/legacy/legacy.js';
20
20
  import * as Lit from '../../../../ui/lit/lit.js';
21
21
  import * as VisualLogging from '../../../../ui/visual_logging/visual_logging.js';
22
22
  import * as PreloadingHelper from '../helper/helper.js';
@@ -176,7 +176,13 @@ export class UsedPreloadingView extends LegacyWrapper.LegacyWrapper.WrappableCom
176
176
  <devtools-report-divider></devtools-report-divider>
177
177
 
178
178
  <devtools-report-section>
179
- ${UI.XLink.XLink.create('https://developer.chrome.com/blog/prerender-pages/', i18nString(UIStrings.learnMore), 'link', undefined, 'learn-more')}
179
+ <x-link
180
+ class="link devtools-link"
181
+ href=${'https://developer.chrome.com/blog/prerender-pages/'}
182
+ jslog=${VisualLogging.link()
183
+ .track({ click: true, keydown: 'Enter|Space' })
184
+ .context('learn-more')}
185
+ >${i18nString(UIStrings.learnMore)}</x-link>
180
186
  </devtools-report-section>
181
187
  </devtools-report>
182
188
  `;
@@ -319,7 +325,13 @@ export class UsedPreloadingView extends LegacyWrapper.LegacyWrapper.WrappableCom
319
325
  return html`
320
326
  <devtools-report-section-header>${i18nString(UIStrings.currentURL)}</devtools-report-section-header>
321
327
  <devtools-report-section>
322
- ${UI.XLink.XLink.create(this.#data.pageURL, undefined, 'link', undefined, 'current-url')}
328
+ <x-link
329
+ class="link devtools-link"
330
+ href=${this.#data.pageURL}
331
+ jslog=${VisualLogging.link()
332
+ .track({ click: true, keydown: 'Enter|Space' })
333
+ .context('current-url')}
334
+ >${this.#data.pageURL}</x-link>
323
335
  </devtools-report-section>
324
336
 
325
337
  <devtools-report-section-header>${i18nString(UIStrings.preloadedURLs)}</devtools-report-section-header>
@@ -11,6 +11,7 @@ import * as SDK from '../../core/sdk/sdk.js';
11
11
  import * as Protocol from '../../generated/protocol.js';
12
12
  import * as UI from '../../ui/legacy/legacy.js';
13
13
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
14
+ import * as PanelsCommon from '../common/common.js';
14
15
  import * as Sources from '../sources/sources.js';
15
16
 
16
17
  import domBreakpointsSidebarPaneStyles from './domBreakpointsSidebarPane.css.js';
@@ -203,19 +204,17 @@ export class DOMBreakpointsSidebarPane extends UI.Widget.VBox implements
203
204
  const linkifiedNode = document.createElement('monospace');
204
205
  linkifiedNode.style.display = 'block';
205
206
  labelElement.appendChild(linkifiedNode);
206
- void Common.Linkifier.Linkifier.linkify(item.node, {preventKeyboardFocus: true, tooltip: undefined})
207
- .then(linkified => {
208
- linkifiedNode.appendChild(linkified);
209
- // Give the checkbox an aria-label as it is required for all form element
210
- UI.ARIAUtils.setLabel(
211
- checkbox, i18nString(UIStrings.sS, {PH1: breakpointTypeText, PH2: linkified.deepTextContent()}));
212
- // The parent list element is the one that actually gets focused.
213
- // Assign it an aria-label with complete information for the screen reader to read out properly
214
- UI.ARIAUtils.setLabel(
215
- element,
216
- i18nString(
217
- UIStrings.sSS, {PH1: breakpointTypeText, PH2: linkified.deepTextContent(), PH3: checkedStateText}));
218
- });
207
+ const linkified = PanelsCommon.DOMLinkifier.Linkifier.instance().linkify(
208
+ item.node, {preventKeyboardFocus: true, tooltip: undefined});
209
+ linkifiedNode.appendChild(linkified);
210
+ // Give the checkbox an aria-label as it is required for all form element
211
+ UI.ARIAUtils.setLabel(
212
+ checkbox, i18nString(UIStrings.sS, {PH1: breakpointTypeText, PH2: linkified.deepTextContent()}));
213
+ // The parent list element is the one that actually gets focused.
214
+ // Assign it an aria-label with complete information for the screen reader to read out properly
215
+ UI.ARIAUtils.setLabel(
216
+ element,
217
+ i18nString(UIStrings.sSS, {PH1: breakpointTypeText, PH2: linkified.deepTextContent(), PH3: checkedStateText}));
219
218
 
220
219
  labelElement.appendChild(description);
221
220
 
@@ -21,7 +21,7 @@ const UIStrings = {
21
21
  */
22
22
  node: '<node>',
23
23
  } as const;
24
- const str_ = i18n.i18n.registerUIStrings('panels/elements/DOMLinkifier.ts', UIStrings);
24
+ const str_ = i18n.i18n.registerUIStrings('panels/common/DOMLinkifier.ts', UIStrings);
25
25
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
26
26
 
27
27
  export interface Options extends Common.Linkifier.Options {
@@ -247,15 +247,15 @@ export class Linkifier implements Common.Linkifier.Linkifier {
247
247
 
248
248
  return linkifierInstance;
249
249
  }
250
- linkify(object: Object, options?: Options): Node {
251
- if (object instanceof SDK.DOMModel.DOMNode) {
250
+ linkify(node: SDK.DOMModel.DOMNode|SDK.DOMModel.DeferredDOMNode, options?: Options): HTMLElement {
251
+ if (node instanceof SDK.DOMModel.DOMNode) {
252
252
  const link = document.createElement('devtools-widget') as UI.Widget.WidgetElement<DOMNodeLink>;
253
- link.widgetConfig = UI.Widget.widgetConfig(e => new DOMNodeLink(e, object, options));
253
+ link.widgetConfig = UI.Widget.widgetConfig(e => new DOMNodeLink(e, node, options));
254
254
  return link;
255
255
  }
256
- if (object instanceof SDK.DOMModel.DeferredDOMNode) {
256
+ if (node instanceof SDK.DOMModel.DeferredDOMNode) {
257
257
  const link = document.createElement('devtools-widget') as UI.Widget.WidgetElement<DeferredDOMNodeLink>;
258
- link.widgetConfig = UI.Widget.widgetConfig(e => new DeferredDOMNodeLink(e, object, options));
258
+ link.widgetConfig = UI.Widget.widgetConfig(e => new DeferredDOMNodeLink(e, node, options));
259
259
  return link;
260
260
  }
261
261
  throw new Error('Can\'t linkify non-node');
@@ -104,3 +104,4 @@ export * as ExtensionPanel from './ExtensionPanel.js';
104
104
  export * as ExtensionServer from './ExtensionServer.js';
105
105
  export * as ExtensionView from './ExtensionView.js';
106
106
  export * as PersistenceUtils from './PersistenceUtils.js';
107
+ export * as DOMLinkifier from './DOMLinkifier.js';
@@ -843,8 +843,8 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
843
843
  const result = document.createElement('span');
844
844
  const description = obj.description || '';
845
845
  if (description.length > getMaxTokenizableStringLength()) {
846
- const propertyValue = new ObjectUI.ObjectPropertiesSection.ExpandableTextPropertyValue(
847
- document.createElement('span'), description, getLongStringVisibleLength());
846
+ const propertyValue =
847
+ new ObjectUI.ObjectPropertiesSection.ExpandableTextPropertyValue(description, getLongStringVisibleLength());
848
848
  result.appendChild(propertyValue.element);
849
849
  } else {
850
850
  UI.UIUtils.createTextChild(result, description);
@@ -1889,8 +1889,8 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
1889
1889
  linkifier: (arg0: string, arg1: Platform.DevToolsPath.UrlString, arg2?: number, arg3?: number) => Node):
1890
1890
  DocumentFragment {
1891
1891
  if (string.length > getMaxTokenizableStringLength()) {
1892
- const propertyValue = new ObjectUI.ObjectPropertiesSection.ExpandableTextPropertyValue(
1893
- document.createElement('span'), string, getLongStringVisibleLength());
1892
+ const propertyValue =
1893
+ new ObjectUI.ObjectPropertiesSection.ExpandableTextPropertyValue(string, getLongStringVisibleLength());
1894
1894
  const fragment = document.createDocumentFragment();
1895
1895
  fragment.appendChild(propertyValue.element);
1896
1896
  return fragment;
@@ -17,6 +17,7 @@ import * as Components from '../../ui/legacy/components/utils/utils.js';
17
17
  import * as UI from '../../ui/legacy/legacy.js';
18
18
  import {Directives, html, type LitTemplate, nothing, render, type TemplateResult} from '../../ui/lit/lit.js';
19
19
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
20
+ import * as PanelsCommon from '../common/common.js';
20
21
 
21
22
  import cssOverviewCompletedViewStyles from './cssOverviewCompletedView.css.js';
22
23
  import type {GlobalStyleStats} from './CSSOverviewModel.js';
@@ -984,7 +985,7 @@ export class ElementDetailsView extends UI.Widget.Widget {
984
985
  if ('nodeId' in item && visibility.has('node-id')) {
985
986
  const frontendNode = relatedNodesMap?.get(item.nodeId) ?? null;
986
987
  if (frontendNode) {
987
- link = await Common.Linkifier.Linkifier.linkify(frontendNode) as HTMLElement;
988
+ link = PanelsCommon.DOMLinkifier.Linkifier.instance().linkify(frontendNode);
988
989
  showNode = () => frontendNode.scrollIntoView();
989
990
  }
990
991
  }