chrome-devtools-frontend 1.0.1636056 → 1.0.1640418

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 (171) hide show
  1. package/front_end/core/common/Color.ts +0 -4
  2. package/front_end/core/host/AidaClientTypes.ts +8 -6
  3. package/front_end/core/root/Runtime.ts +2 -2
  4. package/front_end/core/sdk/DOMStorageModel.ts +1 -1
  5. package/front_end/core/sdk/SourceMap.ts +8 -3
  6. package/front_end/core/sdk/TargetManager.ts +14 -1
  7. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +147 -0
  8. package/front_end/generated/ARIAProperties.js +17 -4
  9. package/front_end/generated/InspectorBackendCommands.ts +13 -7
  10. package/front_end/generated/SupportedCSSProperties.js +1 -0
  11. package/front_end/generated/protocol-mapping.d.ts +7 -0
  12. package/front_end/generated/protocol-proxy-api.d.ts +14 -0
  13. package/front_end/generated/protocol.ts +120 -2
  14. package/front_end/global_typings/global_defs.d.ts +13 -0
  15. package/front_end/models/ai_assistance/AiAgent2.ts +116 -0
  16. package/front_end/models/ai_assistance/AiConversation.ts +22 -36
  17. package/front_end/models/ai_assistance/AiHistoryStorage.ts +0 -1
  18. package/front_end/models/ai_assistance/AiOrigins.ts +46 -0
  19. package/front_end/models/ai_assistance/AiUtils.ts +9 -0
  20. package/front_end/models/ai_assistance/README.md +16 -0
  21. package/front_end/models/ai_assistance/StorageItem.ts +30 -26
  22. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +12 -5
  23. package/front_end/models/ai_assistance/agents/AiAgent.ts +86 -32
  24. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +2 -2
  25. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +31 -10
  26. package/front_end/models/ai_assistance/agents/ConversationSummaryAgent.ts +1 -1
  27. package/front_end/models/ai_assistance/agents/FileAgent.ts +2 -2
  28. package/front_end/models/ai_assistance/agents/GreenDevAgent.ts +1 -3
  29. package/front_end/models/ai_assistance/agents/NetworkAgent.snapshot.txt +19 -0
  30. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +9 -4
  31. package/front_end/models/ai_assistance/agents/PerformanceAgent.snapshot.txt +2 -2
  32. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +41 -12
  33. package/front_end/models/ai_assistance/agents/StorageAgent.ts +442 -122
  34. package/front_end/models/ai_assistance/agents/StylingAgent.ts +2 -2
  35. package/front_end/models/ai_assistance/ai_assistance.ts +4 -2
  36. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +2 -2
  37. package/front_end/models/ai_assistance/performance/AIContext.ts +7 -8
  38. package/front_end/models/ai_assistance/skills/README.md +40 -0
  39. package/front_end/models/ai_assistance/skills/Skill.ts +13 -0
  40. package/front_end/models/ai_assistance/skills/SkillRegistry.ts +10 -0
  41. package/front_end/models/ai_assistance/skills/styling.md +6 -0
  42. package/front_end/models/bindings/CompilerScriptMapping.ts +12 -4
  43. package/front_end/models/breakpoints/BreakpointManager.ts +54 -2
  44. package/front_end/models/greendev/Prototypes.ts +0 -7
  45. package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +20 -0
  46. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +5 -0
  47. package/front_end/models/issues_manager/EmailVerificationRequestIssue.ts +293 -0
  48. package/front_end/models/issues_manager/IssuesManager.ts +5 -0
  49. package/front_end/models/issues_manager/descriptions/emailVerificationRequestDnsFetchFailed.md +1 -0
  50. package/front_end/models/issues_manager/descriptions/emailVerificationRequestDnsInvalidRecord.md +1 -0
  51. package/front_end/models/issues_manager/descriptions/emailVerificationRequestInvalidEmail.md +1 -0
  52. package/front_end/models/issues_manager/descriptions/emailVerificationRequestKeyBindingSigningFailed.md +1 -0
  53. package/front_end/models/issues_manager/descriptions/emailVerificationRequestRpOriginIsOpaque.md +1 -0
  54. package/front_end/models/issues_manager/descriptions/emailVerificationRequestTokenHttpNotFound.md +1 -0
  55. package/front_end/models/issues_manager/descriptions/emailVerificationRequestTokenInvalidContentType.md +1 -0
  56. package/front_end/models/issues_manager/descriptions/emailVerificationRequestTokenInvalidResponse.md +1 -0
  57. package/front_end/models/issues_manager/descriptions/emailVerificationRequestTokenInvalidSdJwt.md +1 -0
  58. package/front_end/models/issues_manager/descriptions/emailVerificationRequestTokenMalformedSdJwt.md +1 -0
  59. package/front_end/models/issues_manager/descriptions/emailVerificationRequestTokenNoResponse.md +1 -0
  60. package/front_end/models/issues_manager/descriptions/emailVerificationRequestUserLoggedOut.md +1 -0
  61. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownAccountsEndpointCrossOrigin.md +1 -0
  62. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownHttpNotFound.md +1 -0
  63. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownInvalidContentType.md +1 -0
  64. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownInvalidResponse.md +1 -0
  65. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownIssuanceEndpointCrossOrigin.md +1 -0
  66. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownListEmpty.md +1 -0
  67. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownMissingAccountsEndpoint.md +1 -0
  68. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownMissingIssuanceEndpoint.md +1 -0
  69. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownNoResponse.md +1 -0
  70. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownUnsupportedSigningAlgorithm.md +1 -0
  71. package/front_end/models/issues_manager/issues_manager.ts +2 -0
  72. package/front_end/models/javascript_metadata/NativeFunctions.js +1748 -1739
  73. package/front_end/models/live-metrics/web-vitals-injected/web-vitals-injected.ts +1 -1
  74. package/front_end/models/stack_trace/DetailedErrorStackParser.ts +9 -1
  75. package/front_end/models/stack_trace/StackTraceImpl.ts +29 -9
  76. package/front_end/models/stack_trace/StackTraceModel.ts +23 -11
  77. package/front_end/models/stack_trace/Trie.ts +11 -1
  78. package/front_end/models/trace/extras/TraceTree.ts +20 -1
  79. package/front_end/models/trace/insights/Common.ts +9 -0
  80. package/front_end/models/trace/lantern/core/NetworkAnalyzer.ts +21 -25
  81. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +19 -75
  82. package/front_end/panels/ai_assistance/components/AccessibilityAgentMarkdownRenderer.ts +10 -3
  83. package/front_end/panels/ai_assistance/components/ChatMessage.ts +148 -2
  84. package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +2 -3
  85. package/front_end/panels/ai_assistance/components/chatMessage.css +27 -0
  86. package/front_end/panels/application/CookieItemsView.ts +24 -0
  87. package/front_end/panels/application/DOMStorageItemsView.ts +9 -4
  88. package/front_end/panels/application/preloading/components/PreloadingString.ts +6 -0
  89. package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +4 -4
  90. package/front_end/panels/console/ConsoleViewMessage.ts +13 -102
  91. package/front_end/panels/elements/StandaloneStylesContainer.ts +10 -0
  92. package/front_end/panels/elements/StylePropertiesSection.ts +6 -2
  93. package/front_end/panels/elements/StylePropertyTreeElement.ts +30 -1
  94. package/front_end/panels/elements/StylesContainer.ts +3 -0
  95. package/front_end/panels/elements/StylesSidebarPane.ts +54 -4
  96. package/front_end/panels/elements/elements-meta.ts +14 -0
  97. package/front_end/panels/layer_viewer/layerDetailsView.css +1 -1
  98. package/front_end/panels/lighthouse/LighthouseController.ts +1 -1
  99. package/front_end/panels/lighthouse/LighthouseProtocolService.ts +4 -4
  100. package/front_end/panels/network/NetworkDataGridNode.ts +14 -0
  101. package/front_end/panels/network/NetworkLogViewColumns.ts +2 -2
  102. package/front_end/panels/network/RequestHeadersView.ts +55 -19
  103. package/front_end/panels/network/networkTimingTable.css +2 -4
  104. package/front_end/panels/recorder/components/ReplaySection.ts +28 -16
  105. package/front_end/panels/recorder/converters/LighthouseConverter.snapshot.txt +47 -0
  106. package/front_end/panels/recorder/converters/PuppeteerConverter.snapshot.txt +49 -0
  107. package/front_end/panels/recorder/converters/PuppeteerReplayConverter.snapshot.txt +33 -0
  108. package/front_end/panels/settings/SettingsScreen.ts +1 -2
  109. package/front_end/panels/sources/BreakpointsView.ts +23 -42
  110. package/front_end/panels/sources/DebuggerPlugin.ts +12 -5
  111. package/front_end/panels/sources/ScopeChainSidebarPane.ts +169 -106
  112. package/front_end/panels/timeline/components/IgnoreListSetting.ts +1 -0
  113. package/front_end/third_party/chromium/README.chromium +1 -1
  114. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +2 -2
  115. package/front_end/third_party/marked/README.chromium +3 -6
  116. package/front_end/third_party/marked/package/README.md +5 -5
  117. package/front_end/third_party/marked/package/bin/main.js +27 -22
  118. package/front_end/third_party/marked/package/bin/marked.js +2 -1
  119. package/front_end/third_party/marked/package/lib/marked.esm.d.ts +346 -256
  120. package/front_end/third_party/marked/package/lib/marked.esm.js +67 -2698
  121. package/front_end/third_party/marked/package/lib/marked.esm.js.map +7 -1
  122. package/front_end/third_party/marked/package/lib/marked.umd.js +69 -2722
  123. package/front_end/third_party/marked/package/lib/marked.umd.js.map +7 -1
  124. package/front_end/third_party/marked/package/man/marked.1 +4 -2
  125. package/front_end/third_party/marked/package/man/marked.1.md +2 -1
  126. package/front_end/third_party/marked/package/package.json +49 -57
  127. package/front_end/third_party/puppeteer-replay/README.chromium +2 -2
  128. package/front_end/third_party/puppeteer-replay/package/lib/cli.js +84 -80
  129. package/front_end/third_party/puppeteer-replay/package/lib/cli.js.map +1 -1
  130. package/front_end/third_party/puppeteer-replay/package/lib/extension-test.js +79 -83
  131. package/front_end/third_party/puppeteer-replay/package/lib/extension-test.js.map +1 -1
  132. package/front_end/third_party/puppeteer-replay/package/lib/main.d.ts +43 -171
  133. package/front_end/third_party/puppeteer-replay/package/lib/main.js +51 -206
  134. package/front_end/third_party/puppeteer-replay/package/lib/main.js.map +1 -1
  135. package/front_end/third_party/puppeteer-replay/package/package.json +37 -67
  136. package/front_end/tsconfig.json +1 -1
  137. package/front_end/ui/components/markdown_view/CodeBlock.ts +17 -6
  138. package/front_end/ui/components/markdown_view/MarkdownView.ts +39 -3
  139. package/front_end/ui/components/markdown_view/codeBlock.css +11 -0
  140. package/front_end/ui/components/markdown_view/markdownView.css +17 -0
  141. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +0 -79
  142. package/front_end/ui/legacy/components/object_ui/RemoteObjectPreviewFormatter.ts +16 -4
  143. package/front_end/ui/visual_logging/KnownContextValues.ts +4 -0
  144. package/inspector_overlay/testing/InspectorOverlayHelpers.ts +2 -0
  145. package/mcp/mcp.ts +1 -6
  146. package/package.json +14 -16
  147. package/front_end/models/ai_assistance/agents/BreakpointDebuggerAgent.ts +0 -1015
  148. package/front_end/models/ai_assistance/agents/BreakpointDebuggerAgentOverlay.ts +0 -87
  149. package/front_end/third_party/marked/package/bin/marked +0 -215
  150. package/front_end/third_party/marked/package/lib/marked.cjs +0 -2726
  151. package/front_end/third_party/marked/package/lib/marked.cjs.map +0 -1
  152. package/front_end/third_party/marked/package/lib/marked.d.cts +0 -670
  153. package/front_end/third_party/marked/package/lib/marked.js +0 -2780
  154. package/front_end/third_party/marked/package/man/marked.1.txt +0 -86
  155. package/front_end/third_party/marked/package/marked.min.js +0 -6
  156. package/front_end/third_party/marked/package/src/Lexer.js +0 -492
  157. package/front_end/third_party/marked/package/src/Parser.js +0 -286
  158. package/front_end/third_party/marked/package/src/Renderer.js +0 -166
  159. package/front_end/third_party/marked/package/src/Slugger.js +0 -49
  160. package/front_end/third_party/marked/package/src/TextRenderer.js +0 -42
  161. package/front_end/third_party/marked/package/src/Tokenizer.js +0 -755
  162. package/front_end/third_party/marked/package/src/defaults.js +0 -29
  163. package/front_end/third_party/marked/package/src/helpers.js +0 -249
  164. package/front_end/third_party/marked/package/src/marked.js +0 -350
  165. package/front_end/third_party/marked/package/src/rules.js +0 -285
  166. package/front_end/third_party/puppeteer-replay/package/lib/cjs/main.cjs +0 -2099
  167. package/front_end/third_party/puppeteer-replay/package/lib/cjs/main.cjs.map +0 -1
  168. package/front_end/third_party/puppeteer-replay/package/lib/cjs/main.d.cts +0 -686
  169. package/front_end/third_party/puppeteer-replay/package/lib/cjs/main.d.ts +0 -35
  170. package/mcp/HostBindings.ts +0 -319
  171. /package/front_end/third_party/marked/package/{LICENSE.md → LICENSE} +0 -0
@@ -14,11 +14,15 @@ import * as SDK from '../../../core/sdk/sdk.js';
14
14
  import type * as Protocol from '../../../generated/protocol.js';
15
15
  import type {
16
16
  AiWidget, BottomUpTreeAiWidget, ComputedStyleAiWidget, CoreVitalsAiWidget, DomTreeAiWidget, LighthouseReportAiWidget,
17
- PerfInsightAiWidget, PerformanceTraceAiWidget, SourceFileAiWidget, StylePropertiesAiWidget,
18
- TimelineEventSummaryAiWidget, TimelineRangeSummaryAiWidget} from '../../../models/ai_assistance/agents/AiAgent.js';
17
+ NetworkRequestGeneralHeadersAiWidget, PerfInsightAiWidget, PerformanceTraceAiWidget, SourceCodeAiWidget,
18
+ SourceFileAiWidget, SourceFilesListAiWidget, StylePropertiesAiWidget, TimelineEventSummaryAiWidget,
19
+ TimelineRangeSummaryAiWidget} from '../../../models/ai_assistance/agents/AiAgent.js';
19
20
  import * as AiAssistanceModel from '../../../models/ai_assistance/ai_assistance.js';
20
21
  import * as ComputedStyle from '../../../models/computed_style/computed_style.js';
22
+ import * as Formatter from '../../../models/formatter/formatter.js';
23
+ import * as TextUtils from '../../../models/text_utils/text_utils.js';
21
24
  import * as Trace from '../../../models/trace/trace.js';
25
+ import * as Workspace from '../../../models/workspace/workspace.js';
22
26
  import * as PanelsCommon from '../../../panels/common/common.js';
23
27
  import * as TraceBounds from '../../../services/trace_bounds/trace_bounds.js';
24
28
  import * as Marked from '../../../third_party/marked/marked.js';
@@ -32,6 +36,8 @@ import * as Lit from '../../../ui/lit/lit.js';
32
36
  import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
33
37
  import * as Elements from '../../elements/elements.js';
34
38
  import * as Lighthouse from '../../lighthouse/lighthouse.js';
39
+ import * as NetworkForward from '../../network/forward/forward.js';
40
+ import * as Network from '../../network/network.js';
35
41
  import * as TimelineComponents from '../../timeline/components/components.js';
36
42
  import type {BaseInsightComponent} from '../../timeline/components/insights/BaseInsightComponent.js';
37
43
  import * as TimelineInsights from '../../timeline/components/insights/insights.js';
@@ -384,6 +390,14 @@ const UIStringsNotTranslate = {
384
390
  * @description Title for the viewport optimization widget.
385
391
  */
386
392
  viewport: 'Viewport optimization',
393
+ /**
394
+ * @description Accessible label for the reveal button in the network request general headers widget.
395
+ */
396
+ revealNetworkRequest: 'Reveal network request',
397
+ /**
398
+ * @description Title for the network request general headers widget.
399
+ */
400
+ networkRequest: 'Network request',
387
401
  /**
388
402
  * @description Accessible label for the reveal button in the modern HTTP usage widget.
389
403
  */
@@ -400,6 +414,10 @@ const UIStringsNotTranslate = {
400
414
  * @description Title for the character set declaration widget.
401
415
  */
402
416
  characterSet: 'Character set declaration',
417
+ /**
418
+ * @description Title for the source files list widget.
419
+ */
420
+ inspectedFileNames: 'Inspected file names',
403
421
  } as const;
404
422
 
405
423
  export interface Step {
@@ -1353,6 +1371,101 @@ async function makeSourceFileWidget(widgetData: SourceFileAiWidget): Promise<Wid
1353
1371
  };
1354
1372
  }
1355
1373
 
1374
+ async function makeSourceCodeWidget(widgetData: SourceCodeAiWidget): Promise<WidgetMakerResponse|null> {
1375
+ const url = widgetData.data.url;
1376
+ const filename = url.split('/').pop() || url;
1377
+ const line = widgetData.data.line;
1378
+ const column = widgetData.data.column;
1379
+
1380
+ // If both line and column numbers are provided, we represent a specific function execution,
1381
+ // so the widget title is formatted as 'filename:line:column' (matching the Sources Panel style).
1382
+ // Otherwise, if line and column are not provided, we are viewing the entire file contents,
1383
+ // so the header simply displays 'filename'.
1384
+ const header = line !== undefined && column !== undefined ? `${filename}:${line}:${column}` : filename;
1385
+
1386
+ const uiSourceCode =
1387
+ Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(url as Platform.DevToolsPath.UrlString);
1388
+ const lastDotIndex = filename.lastIndexOf('.');
1389
+ const fileExtension = lastDotIndex !== -1 ? filename.substring(lastDotIndex + 1) : '';
1390
+
1391
+ let code = widgetData.data.code;
1392
+ if (TextUtils.TextUtils.isMinified(code)) {
1393
+ const canonicalMimeType = uiSourceCode?.contentType().canonicalMimeType() || 'text/javascript';
1394
+ const formatted = await Formatter.ScriptFormatter.formatScriptContent(canonicalMimeType, code, ' ');
1395
+ code = formatted.formattedContent;
1396
+ }
1397
+
1398
+ const renderedWidget = html`
1399
+ <devtools-code-block
1400
+ class="source-code-widget"
1401
+ .displayLimit=${20}
1402
+ .code=${code}
1403
+ .codeLang=${fileExtension}
1404
+ .displayToolbar=${false}
1405
+ .displayNotice=${false}
1406
+ ></devtools-code-block>
1407
+ `;
1408
+
1409
+ return {
1410
+ renderedWidget,
1411
+ title: lockedString(header),
1412
+ revealable: uiSourceCode,
1413
+ accessibleRevealLabel: i18n.i18n.lockedString(`Show ${filename} in Sources`),
1414
+ jslogContext: 'source-code-widget',
1415
+ };
1416
+ }
1417
+
1418
+ function renderFileRevealButton(
1419
+ file: Workspace.UISourceCode.UISourceCode,
1420
+ collapsed: boolean,
1421
+ ): Lit.TemplateResult {
1422
+ const onReveal = (): void => {
1423
+ void Common.Revealer.reveal(file);
1424
+ };
1425
+ const accessibleLabel = i18n.i18n.lockedString(`Show ${file.fullDisplayName()}`);
1426
+ const className = `widget-reveal-button ${collapsed ? 'collapsed-file' : 'visible-file'}`;
1427
+ return html`
1428
+ <devtools-button class=${className}
1429
+ .variant=${Buttons.Button.Variant.TEXT}
1430
+ .accessibleLabel=${accessibleLabel}
1431
+ .jslogContext=${'reveal'}
1432
+ @click=${onReveal}>
1433
+ ${file.fullDisplayName()}
1434
+ <devtools-icon name='tab-move'></devtools-icon>
1435
+ </devtools-button>
1436
+ `;
1437
+ }
1438
+
1439
+ async function makeSourceFilesListWidget(widgetData: SourceFilesListAiWidget): Promise<WidgetMakerResponse|null> {
1440
+ const files = widgetData.data.uiSourceCodes;
1441
+ if (files.length === 0) {
1442
+ return null;
1443
+ }
1444
+
1445
+ // If there are more than 10 files, only show the first 10, and hide the rest unless "Show all" is clicked.
1446
+ // clang-format off
1447
+ const renderedWidget = html`
1448
+ <div class="source-files-widget">
1449
+ ${files.slice(0, 10).map(file => renderFileRevealButton(file, /* collapsed */ false))}
1450
+ ${files.length > 10 ? html`
1451
+ <details class="source-files-details">
1452
+ <summary class="show-more-summary">${i18n.i18n.lockedString(`Show all ${files.length} files`)}</summary>
1453
+ ${files.slice(10).map(file => renderFileRevealButton(file, /* collapsed */ true))}
1454
+ </details> ` : Lit.nothing}
1455
+ </div>`;
1456
+ // clang-format on
1457
+
1458
+ const title = lockedString(UIStringsNotTranslate.inspectedFileNames);
1459
+
1460
+ return {
1461
+ renderedWidget,
1462
+ title,
1463
+ revealable: files[0],
1464
+ accessibleRevealLabel: i18n.i18n.lockedString('Reveal first file in Sources panel'),
1465
+ jslogContext: 'source-files-list-widget',
1466
+ };
1467
+ }
1468
+
1356
1469
  function renderNetworkRequestPreview(networkRequest: NonNullable<DomTreeAiWidget['data']['networkRequest']>):
1357
1470
  Lit.TemplateResult {
1358
1471
  const filename = networkRequest.url.split('/').pop() || networkRequest.url;
@@ -1460,10 +1573,16 @@ export function getWidgetSignature(widget: AiWidget): string {
1460
1573
  return `${widget.name}:${widget.data.bounds.min}-${widget.data.bounds.max}`;
1461
1574
  case 'SOURCE_FILE':
1462
1575
  return `${widget.name}:${widget.data.uiSourceCode.url()}`;
1576
+ case 'SOURCE_FILES_LIST':
1577
+ return `${widget.name}:${widget.data.uiSourceCodes.map(f => f.url()).join(',')}`;
1463
1578
  case 'LIGHTHOUSE_REPORT':
1464
1579
  return `${widget.name}:${widget.data.report.fetchTime}`;
1465
1580
  case 'TIMELINE_EVENT_SUMMARY':
1466
1581
  return `${widget.name}:${widget.data.event.ts}:${widget.data.event.name}`;
1582
+ case 'NETWORK_REQUEST_GENERAL_HEADERS':
1583
+ return `${widget.name}:${widget.data.request.requestId()}`;
1584
+ case 'SOURCE_CODE':
1585
+ return `${widget.name}:${widget.data.url}:${widget.data.line ?? ''}:${widget.data.column ?? ''}`;
1467
1586
  default:
1468
1587
  Platform.assertNever(widget, 'Unknown AiWidget name');
1469
1588
  }
@@ -1550,12 +1669,21 @@ async function renderWidgets(
1550
1669
  case 'SOURCE_FILE':
1551
1670
  response = await makeSourceFileWidget(widgetData);
1552
1671
  break;
1672
+ case 'SOURCE_FILES_LIST':
1673
+ response = await makeSourceFilesListWidget(widgetData);
1674
+ break;
1553
1675
  case 'LIGHTHOUSE_REPORT':
1554
1676
  response = await makeLighthouseReportWidget(widgetData);
1555
1677
  break;
1556
1678
  case 'TIMELINE_EVENT_SUMMARY':
1557
1679
  response = await makeTimelineEventSummaryWidget(widgetData);
1558
1680
  break;
1681
+ case 'NETWORK_REQUEST_GENERAL_HEADERS':
1682
+ response = await makeNetworkRequestGeneralHeadersWidget(widgetData);
1683
+ break;
1684
+ case 'SOURCE_CODE':
1685
+ response = await makeSourceCodeWidget(widgetData);
1686
+ break;
1559
1687
  default:
1560
1688
  Platform.assertNever(widgetData, 'Unknown AiWidget name');
1561
1689
  }
@@ -2131,3 +2259,21 @@ async function makeTimelineEventSummaryWidget(widgetData: TimelineEventSummaryAi
2131
2259
  jslogContext: 'timeline-event-summary-widget',
2132
2260
  };
2133
2261
  }
2262
+
2263
+ async function makeNetworkRequestGeneralHeadersWidget(widgetData: NetworkRequestGeneralHeadersAiWidget):
2264
+ Promise<WidgetMakerResponse|null> {
2265
+ const renderedWidget = html`<devtools-widget class="network-request-general-headers-widget" ${widget(() => {
2266
+ return Network.RequestHeadersView.RequestHeadersView.createGeneralHeadersView(widgetData.data.request);
2267
+ })}></devtools-widget>`;
2268
+
2269
+ return {
2270
+ renderedWidget,
2271
+ revealable: NetworkForward.UIRequestLocation.UIRequestLocation.tab(
2272
+ widgetData.data.request,
2273
+ NetworkForward.UIRequestLocation.UIRequestTabs.HEADERS_COMPONENT,
2274
+ ),
2275
+ accessibleRevealLabel: lockedString(UIStringsNotTranslate.revealNetworkRequest),
2276
+ title: lockedString(UIStringsNotTranslate.networkRequest),
2277
+ jslogContext: 'network-request-general-headers-widget',
2278
+ };
2279
+ }
@@ -17,8 +17,7 @@ const {until} = Lit.Directives;
17
17
 
18
18
  export class PerformanceAgentMarkdownRenderer extends MarkdownRendererWithCodeBlock {
19
19
  constructor(
20
- private mainFrameId = '',
21
- private lookupEvent: (key: Trace.Types.File.SerializableKey) => Trace.Types.Events.Event | null = () => null) {
20
+ private mainFrameId = '', private lookupEvent: (key: string) => Trace.Types.Events.Event | null = () => null) {
22
21
  super();
23
22
  }
24
23
 
@@ -31,7 +30,7 @@ export class PerformanceAgentMarkdownRenderer extends MarkdownRendererWithCodeBl
31
30
  until(this.#linkifyNode(nodeId, token.text).then(node => node || token.text), token.text)}</span>`;
32
31
  }
33
32
 
34
- const event = this.lookupEvent(token.href.slice(1) as Trace.Types.File.SerializableKey);
33
+ const event = this.lookupEvent(token.href.slice(1));
35
34
  if (!event) {
36
35
  return html`${token.text}`;
37
36
  }
@@ -281,6 +281,10 @@
281
281
  gap: var(--sys-size-2);
282
282
  }
283
283
 
284
+ .show-all-container {
285
+ padding-bottom: 0;
286
+ }
287
+
284
288
  .js-code-output {
285
289
  devtools-code-block {
286
290
  --code-block-max-code-height: 50px;
@@ -597,4 +601,27 @@
597
601
  }
598
602
  }
599
603
  }
604
+
605
+
606
+ .source-files-details {
607
+ display: contents;
608
+
609
+ summary {
610
+ list-style: none;
611
+ cursor: pointer;
612
+ padding: 4px 12px;
613
+ border: 1px solid var(--sys-color-neutral-outline);
614
+ border-radius: var(--sys-shape-corner-small);
615
+ color: var(--sys-color-primary);
616
+ width: fit-content;
617
+
618
+ &:hover {
619
+ background-color: var(--sys-color-state-hover-on-subtle);
620
+ }
621
+ }
622
+
623
+ &[open] summary {
624
+ display: none;
625
+ }
626
+ }
600
627
  }
@@ -34,6 +34,7 @@
34
34
  import * as Common from '../../core/common/common.js';
35
35
  import * as i18n from '../../core/i18n/i18n.js';
36
36
  import * as SDK from '../../core/sdk/sdk.js';
37
+ import * as AiAssistanceModel from '../../models/ai_assistance/ai_assistance.js';
37
38
  import * as Geometry from '../../models/geometry/geometry.js';
38
39
  import * as IssuesManager from '../../models/issues_manager/issues_manager.js';
39
40
  import * as CookieTable from '../../ui/legacy/components/cookie_table/cookie_table.js';
@@ -260,6 +261,7 @@ export class CookieItemsView extends UI.Widget.VBox {
260
261
  this.cookieDomain = domain;
261
262
  this.refreshItems();
262
263
  this.model.addEventListener(SDK.CookieModel.Events.COOKIE_LIST_UPDATED, this.onCookieListUpdate, this);
264
+ this.updateAiAssistanceContext(null);
263
265
  }
264
266
 
265
267
  override performUpdate(): void {
@@ -302,6 +304,7 @@ export class CookieItemsView extends UI.Widget.VBox {
302
304
  override wasShown(): void {
303
305
  super.wasShown();
304
306
  this.refreshItems();
307
+ this.updateAiAssistanceContext(this.selectedCookie);
305
308
  }
306
309
 
307
310
  private showPreview(cookie: SDK.Cookie.Cookie|null): void {
@@ -310,6 +313,27 @@ export class CookieItemsView extends UI.Widget.VBox {
310
313
  }
311
314
  this.selectedCookie = cookie;
312
315
  this.requestUpdate();
316
+ this.updateAiAssistanceContext(cookie);
317
+ }
318
+
319
+ private updateAiAssistanceContext(cookie: SDK.Cookie.Cookie|null): void {
320
+ if (!cookie || cookie.httpOnly()) {
321
+ UI.Context.Context.instance().setFlavor(AiAssistanceModel.StorageItem.StorageItem, null);
322
+ return;
323
+ }
324
+
325
+ const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
326
+ const mainPageOrigin =
327
+ target?.inspectedURL() ? Common.ParsedURL.ParsedURL.extractOrigin(target.inspectedURL()) : '';
328
+
329
+ if (!mainPageOrigin) {
330
+ // If we don't have a primary target origin, we shouldn't allow the AI assistance context to be attached.
331
+ UI.Context.Context.instance().setFlavor(AiAssistanceModel.StorageItem.StorageItem, null);
332
+ return;
333
+ }
334
+
335
+ const storageItem = new AiAssistanceModel.StorageItem.CookieItem(mainPageOrigin, this.cookieDomain, cookie.name());
336
+ UI.Context.Context.instance().setFlavor(AiAssistanceModel.StorageItem.StorageItem, storageItem);
313
337
  }
314
338
 
315
339
  private handleCookieSelected(selectedCookie: SDK.Cookie.Cookie|null): void {
@@ -190,13 +190,18 @@ export class DOMStorageItemsView extends KeyValueStorageItemsView {
190
190
  const origin = parsedKey.origin;
191
191
  const storageType = this.domStorage.isLocalStorage ? 'localStorage' : 'sessionStorage';
192
192
 
193
- if (!item) {
194
- const storageItem = new AiAssistanceModel.StorageItem.StorageItem({origin, storageKey});
195
- UI.Context.Context.instance().setFlavor(AiAssistanceModel.StorageItem.StorageItem, storageItem);
193
+ const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
194
+ const mainPageOrigin =
195
+ target?.inspectedURL() ? Common.ParsedURL.ParsedURL.extractOrigin(target.inspectedURL()) : '';
196
+
197
+ if (!mainPageOrigin) {
198
+ // If we don't have a primary target origin, we shouldn't allow the AI assistance context to be attached.
199
+ UI.Context.Context.instance().setFlavor(AiAssistanceModel.StorageItem.StorageItem, null);
196
200
  return;
197
201
  }
198
202
 
199
- const storageItem = new AiAssistanceModel.StorageItem.StorageItem({origin, storageKey, storageType, key: item.key});
203
+ const storageItem = new AiAssistanceModel.StorageItem.DOMStorageItem(
204
+ mainPageOrigin, origin, storageKey, storageType, item ? item.key : undefined);
200
205
  UI.Context.Context.instance().setFlavor(AiAssistanceModel.StorageItem.StorageItem, storageItem);
201
206
  }
202
207
 
@@ -454,6 +454,8 @@ export const PrefetchReasonDescription: Record<string, {name: () => Platform.UIS
454
454
  PrefetchNotEligibleRedirectFromServiceWorker: {name: () => i18n.i18n.lockedString('Unknown')},
455
455
  PrefetchNotEligibleRedirectToServiceWorker: {name: () => i18n.i18n.lockedString('Unknown')},
456
456
  PrefetchEvictedAfterBrowsingDataRemoved: {name: i18nLazyString(UIStrings.PrefetchEvictedAfterBrowsingDataRemoved)},
457
+ PrefetchNotEligibleBlockedByConnectionAllowlist: {name: () => i18n.i18n.lockedString('Unknown')},
458
+ PrefetchCancelledOnUserNavigation: {name: () => i18n.i18n.lockedString('Unknown')},
457
459
  };
458
460
 
459
461
  /** Decoding PrefetchFinalStatus prefetchAttempt to failure description. **/
@@ -540,6 +542,10 @@ export function prefetchFailureReason(
540
542
  return PrefetchReasonDescription['PrefetchNotEligibleRedirectToServiceWorker'].name();
541
543
  case Protocol.Preload.PrefetchStatus.PrefetchEvictedAfterBrowsingDataRemoved:
542
544
  return PrefetchReasonDescription['PrefetchEvictedAfterBrowsingDataRemoved'].name();
545
+ case Protocol.Preload.PrefetchStatus.PrefetchNotEligibleBlockedByConnectionAllowlist:
546
+ return PrefetchReasonDescription['PrefetchNotEligibleBlockedByConnectionAllowlist'].name();
547
+ case Protocol.Preload.PrefetchStatus.PrefetchCancelledOnUserNavigation:
548
+ return PrefetchReasonDescription['PrefetchCancelledOnUserNavigation'].name();
543
549
  default:
544
550
  // Note that we use switch and exhaustiveness check to prevent to
545
551
  // forget updating these strings, but allow to handle unknown
@@ -475,14 +475,14 @@ export class UsedPreloadingView extends UI.Widget.VBox {
475
475
  if (prerenderLike?.status === SDK.PreloadingModel.PreloadingStatus.FAILURE &&
476
476
  prefetch?.status === SDK.PreloadingModel.PreloadingStatus.SUCCESS) {
477
477
  kind = UsedKind.DOWNGRADED_PRERENDER_TO_PREFETCH_AND_USED;
478
- } else if (prefetch?.status === SDK.PreloadingModel.PreloadingStatus.SUCCESS) {
479
- kind = UsedKind.PREFETCH_USED;
480
478
  } else if (prerenderLike?.status === SDK.PreloadingModel.PreloadingStatus.SUCCESS) {
481
479
  kind = UsedKind.PRERENDER_USED;
482
- } else if (prefetch?.status === SDK.PreloadingModel.PreloadingStatus.FAILURE) {
483
- kind = UsedKind.PREFETCH_FAILED;
480
+ } else if (prefetch?.status === SDK.PreloadingModel.PreloadingStatus.SUCCESS) {
481
+ kind = UsedKind.PREFETCH_USED;
484
482
  } else if (prerenderLike?.status === SDK.PreloadingModel.PreloadingStatus.FAILURE) {
485
483
  kind = UsedKind.PRERENDER_FAILED;
484
+ } else if (prefetch?.status === SDK.PreloadingModel.PreloadingStatus.FAILURE) {
485
+ kind = UsedKind.PREFETCH_FAILED;
486
486
  } else {
487
487
  kind = UsedKind.NO_PRELOADS;
488
488
  }
@@ -43,8 +43,6 @@ import * as SDK from '../../core/sdk/sdk.js';
43
43
  import * as Protocol from '../../generated/protocol.js';
44
44
  import * as AiAssistanceModel from '../../models/ai_assistance/ai_assistance.js';
45
45
  import * as Bindings from '../../models/bindings/bindings.js';
46
- import * as Breakpoints from '../../models/breakpoints/breakpoints.js';
47
- import * as Greendev from '../../models/greendev/greendev.js';
48
46
  import type * as IssuesManager from '../../models/issues_manager/issues_manager.js';
49
47
  import * as Logs from '../../models/logs/logs.js';
50
48
  import * as StackTrace from '../../models/stack_trace/stack_trace.js';
@@ -63,7 +61,6 @@ import * as Components from '../../ui/legacy/components/utils/utils.js';
63
61
  import * as UI from '../../ui/legacy/legacy.js';
64
62
  import {type LitTemplate, nothing, render} from '../../ui/lit/lit.js';
65
63
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
66
- import * as AiAssistancePanel from '../ai_assistance/ai_assistance.js';
67
64
 
68
65
  import {format, updateStyle} from './ConsoleFormat.js';
69
66
  import {ConsoleInsightTeaser} from './ConsoleInsightTeaser.js';
@@ -515,16 +512,17 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
515
512
  }
516
513
  } else {
517
514
  const messageText = this.message.messageText;
518
- const fragment = this.linkifyWithCustomLinkifier(messageText, (text, url, lineNumber, columnNumber) => {
519
- const linkElement = url === request.url() ?
520
- Components.Linkifier.Linkifier.linkifyRevealable(
521
- (request), url, request.url(), undefined, undefined, 'network-request') :
522
- Components.Linkifier.Linkifier.linkifyURL(
523
- url, ({text, lineNumber, columnNumber} as Components.Linkifier.LinkifyURLOptions));
524
- linkElement.tabIndex = -1;
525
- this.selectableChildren.push({element: linkElement, forceSelect: () => linkElement.focus()});
526
- return linkElement;
527
- });
515
+ const fragment =
516
+ ConsoleViewMessage.linkifyWithCustomLinkifier(messageText, (text, url, lineNumber, columnNumber) => {
517
+ const linkElement = url === request.url() ?
518
+ Components.Linkifier.Linkifier.linkifyRevealable(
519
+ (request), url, request.url(), undefined, undefined, 'network-request') :
520
+ Components.Linkifier.Linkifier.linkifyURL(
521
+ url, ({text, lineNumber, columnNumber} as Components.Linkifier.LinkifyURLOptions));
522
+ linkElement.tabIndex = -1;
523
+ this.selectableChildren.push({element: linkElement, forceSelect: () => linkElement.focus()});
524
+ return linkElement;
525
+ });
528
526
  appendOrShow(messageElement, fragment);
529
527
  }
530
528
  return messageElement;
@@ -1508,11 +1506,6 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
1508
1506
  this.consoleRowWrapper.append(this.#createHoverButton());
1509
1507
  }
1510
1508
 
1511
- const breakpointAgentEnabled = Greendev.Prototypes.instance().isEnabled('breakpointDebuggerAgent');
1512
- if (breakpointAgentEnabled && this.message.level === Protocol.Log.LogEntryLevel.Error) {
1513
- this.consoleRowWrapper.append(this.#createBreakpointButton());
1514
- }
1515
-
1516
1509
  if (this.repeatCountInternal > 1) {
1517
1510
  this.showRepeatCountElement();
1518
1511
  }
@@ -1606,88 +1599,6 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
1606
1599
  return button;
1607
1600
  }
1608
1601
 
1609
- #createBreakpointButton(): HTMLButtonElement {
1610
- const button = document.createElement('button');
1611
-
1612
- const icon = new Icon();
1613
- icon.name = 'bug';
1614
- icon.style.color = 'var(--devtools-icon-color)';
1615
- icon.classList.add('medium');
1616
- button.append(icon);
1617
-
1618
- const label = document.createElement('div');
1619
- label.classList.add('button-label');
1620
- const text = document.createElement('div');
1621
- // We use a data attribute and a CSS pseudo-element for the button label
1622
- // to prevent the text from being picked up by the console's custom
1623
- // copy-to-clipboard traversal, which only collects actual text nodes.
1624
- text.setAttribute('data-text', 'Debug with breakpoint AI');
1625
- label.append(text);
1626
- button.append(label);
1627
- button.classList.add('hover-button');
1628
- // Offset the button to the left of the existing one (24px width + 6px right + gap)
1629
- if (this.shouldShowInsights()) {
1630
- button.style.right = '36px';
1631
- }
1632
- button.ariaLabel = 'Debug with breakpoint AI';
1633
- button.tabIndex = 0;
1634
-
1635
- button.onclick = async (event: Event) => {
1636
- event.stopPropagation();
1637
- const runtimeModel = this.message.runtimeModel();
1638
- if (!runtimeModel) {
1639
- return;
1640
- }
1641
- const debuggerModel = runtimeModel.debuggerModel();
1642
- const debuggerWorkspaceBinding = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance();
1643
- let uiLocation: Workspace.UISourceCode.UILocation|null = null;
1644
-
1645
- // 1. Try stack trace latest called line
1646
- if (this.message.stackTrace?.callFrames.length) {
1647
- const callFrame = this.message.stackTrace.callFrames[0];
1648
- if (callFrame.scriptId) {
1649
- const script = debuggerModel.scriptForId(callFrame.scriptId);
1650
- if (script) {
1651
- const rawLocation = new SDK.DebuggerModel.Location(
1652
- debuggerModel, callFrame.scriptId, callFrame.lineNumber, callFrame.columnNumber);
1653
- uiLocation = await debuggerWorkspaceBinding.rawLocationToUILocation(rawLocation);
1654
- }
1655
- }
1656
- }
1657
-
1658
- // 2. Try scriptId on message
1659
- if (!uiLocation && this.message.scriptId) {
1660
- const script = debuggerModel.scriptForId(this.message.scriptId);
1661
- if (script) {
1662
- const rawLocation = new SDK.DebuggerModel.Location(
1663
- debuggerModel, this.message.scriptId, this.message.line, this.message.column);
1664
- uiLocation = await debuggerWorkspaceBinding.rawLocationToUILocation(rawLocation);
1665
- }
1666
- }
1667
-
1668
- // 3. Try URL
1669
- if (!uiLocation && this.message.url) {
1670
- const uiSourceCode = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(this.message.url);
1671
- if (uiSourceCode) {
1672
- uiLocation = uiSourceCode.uiLocation(this.message.line, this.message.column);
1673
- }
1674
- }
1675
-
1676
- if (uiLocation) {
1677
- await Common.Revealer.reveal(uiLocation);
1678
- const breakpointManager = Breakpoints.BreakpointManager.BreakpointManager.instance();
1679
- await breakpointManager.setBreakpoint(
1680
- uiLocation.uiSourceCode, uiLocation.lineNumber, uiLocation.columnNumber,
1681
- Breakpoints.BreakpointManager.EMPTY_BREAKPOINT_CONDITION, /* enabled */ true,
1682
- /* isLogpoint */ false, Breakpoints.BreakpointManager.BreakpointOrigin.OTHER);
1683
- const aiPanel = await AiAssistancePanel.AiAssistancePanel.instance();
1684
- void aiPanel.handleBreakpointConversation(uiLocation, this.text);
1685
- }
1686
- };
1687
-
1688
- return button;
1689
- }
1690
-
1691
1602
  private shouldRenderAsWarning(): boolean {
1692
1603
  return (this.message.level === Protocol.Log.LogEntryLevel.Verbose ||
1693
1604
  this.message.level === Protocol.Log.LogEntryLevel.Info) &&
@@ -2029,7 +1940,7 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
2029
1940
  return formattedResult;
2030
1941
  }
2031
1942
 
2032
- private linkifyWithCustomLinkifier(
1943
+ static linkifyWithCustomLinkifier(
2033
1944
  string: string,
2034
1945
  linkifier: (arg0: string, arg1: Platform.DevToolsPath.UrlString, arg2?: number, arg3?: number) => Node):
2035
1946
  DocumentFragment|UI.Widget.Widget {
@@ -2077,7 +1988,7 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
2077
1988
  }
2078
1989
 
2079
1990
  private linkifyStringAsFragment(string: string): DocumentFragment|UI.Widget.Widget {
2080
- return this.linkifyWithCustomLinkifier(string, (text, url, lineNumber, columnNumber) => {
1991
+ return ConsoleViewMessage.linkifyWithCustomLinkifier(string, (text, url, lineNumber, columnNumber) => {
2081
1992
  const options = {text, lineNumber, columnNumber};
2082
1993
  const linkElement =
2083
1994
  Components.Linkifier.Linkifier.linkifyURL(url, (options as Components.Linkifier.LinkifyURLOptions));
@@ -327,4 +327,14 @@ export class StandaloneStylesContainer extends Common.ObjectWrapper.eventMixin<E
327
327
  removeStyleUpdateListener(listener: () => void): void {
328
328
  this.removeEventListener(Events.STYLES_UPDATE_COMPLETED, listener);
329
329
  }
330
+
331
+ trackForLazyRendering(_element: Element, _callback: () => void): void {
332
+ }
333
+
334
+ shouldRenderLazily(): boolean {
335
+ return false;
336
+ }
337
+
338
+ untrackForLazyRendering(_element: Element): void {
339
+ }
330
340
  }
@@ -343,7 +343,7 @@ export class StylePropertiesSection {
343
343
  this.#isCollapsed = false;
344
344
  this.markSelectorMatches();
345
345
  this.onpopulate();
346
- this.#updateCollapsedState();
346
+ this.updateCollapsedState();
347
347
  }
348
348
 
349
349
  setComputedStyles(computedStyles: Map<string, string>|null): void {
@@ -1317,6 +1317,10 @@ export class StylePropertiesSection {
1317
1317
  * since the user intentionally toggled them off and they should remain visible.
1318
1318
  */
1319
1319
  #shouldCollapse(): boolean {
1320
+ if (!Common.Settings.Settings.instance().moduleSetting('collapse-non-contributing-css-rules').get()) {
1321
+ return false;
1322
+ }
1323
+
1320
1324
  const style = this.styleInternal;
1321
1325
  const properties = style.leadingProperties();
1322
1326
 
@@ -1343,7 +1347,7 @@ export class StylePropertiesSection {
1343
1347
  return allOverloaded;
1344
1348
  }
1345
1349
 
1346
- #updateCollapsedState(): void {
1350
+ updateCollapsedState(): void {
1347
1351
  const shouldCollapse = this.#shouldCollapse();
1348
1352
  // Mark as collapsible so the toggle icon is always shown for
1349
1353
  // sections that can be collapsed, even after manual expansion.
@@ -2063,6 +2063,8 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
2063
2063
  #gridNames: Set<string>|undefined = undefined;
2064
2064
  #tooltipKeyCounts = new Map<string, number>();
2065
2065
 
2066
+ #lazyRender?: boolean;
2067
+
2066
2068
  constructor(
2067
2069
  {stylesContainer, section, matchedStyles, property, isShorthand, inherited, overloaded, newProperty}:
2068
2070
  StylePropertyTreeElementParams,
@@ -2080,6 +2082,7 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
2080
2082
  this.#parentSection = section;
2081
2083
  this.isShorthand = isShorthand;
2082
2084
  this.newProperty = newProperty;
2085
+ this.#lazyRender = stylesContainer.shouldRenderLazily();
2083
2086
  if (this.newProperty) {
2084
2087
  this.listItemElement.textContent = '';
2085
2088
  }
@@ -2088,6 +2091,8 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
2088
2091
  }
2089
2092
 
2090
2093
  override onunbind(): void {
2094
+ this.#stylesContainer.untrackForLazyRendering(this.listItemElement);
2095
+ this.#lazyRender = false;
2091
2096
  this.property.removeEventListener(SDK.CSSProperty.Events.LOCAL_VALUE_UPDATED, this.updateTitle, this);
2092
2097
  super.onunbind();
2093
2098
  }
@@ -2371,7 +2376,31 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
2371
2376
  }
2372
2377
 
2373
2378
  override onattach(): void {
2374
- this.updateTitle();
2379
+ if (this.#lazyRender) {
2380
+ this.nameElement = Renderer.renderNameElement(this.name);
2381
+ this.valueElement = Renderer.renderValueElement(this.property, null, []).valueElement;
2382
+
2383
+ // Add a placeholder to maintain alignment with eager rendering.
2384
+ if (this.parent?.root || !this.property.parsedOk) {
2385
+ const placeholder = document.createElement('span');
2386
+ placeholder.classList.add('enabled-button');
2387
+ this.listItemElement.appendChild(placeholder);
2388
+ }
2389
+
2390
+ this.listItemElement.classList.toggle('inactive', !this.property.activeInStyle());
2391
+ this.listItemElement.appendChild(this.nameElement);
2392
+ const lineBreakValue = this.valueElement.firstElementChild?.tagName === 'BR';
2393
+ this.listItemElement.createChild('span', 'styles-name-value-separator').textContent = lineBreakValue ? ':' : ': ';
2394
+ this.listItemElement.appendChild(this.valueElement);
2395
+ this.listItemElement.createChild('span', 'styles-semicolon').textContent = ';';
2396
+
2397
+ this.#stylesContainer.trackForLazyRendering(this.listItemElement, () => {
2398
+ this.#lazyRender = false;
2399
+ this.updateTitle();
2400
+ });
2401
+ } else {
2402
+ this.updateTitle();
2403
+ }
2375
2404
 
2376
2405
  this.listItemElement.addEventListener('mousedown', event => {
2377
2406
  if (event.button === 0) {
@@ -57,4 +57,7 @@ export interface StylesContainer {
57
57
  setActiveProperty(treeElement: StylePropertyTreeElement|null): void;
58
58
  addStyleUpdateListener(listener: () => void): void;
59
59
  removeStyleUpdateListener(listener: () => void): void;
60
+ trackForLazyRendering(element: Element, callback: () => void): void;
61
+ untrackForLazyRendering(element: Element): void;
62
+ shouldRenderLazily(): boolean;
60
63
  }