chrome-devtools-frontend 1.0.1699061 → 1.0.1700561

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 (120) hide show
  1. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +2 -2
  2. package/front_end/core/sdk/ServiceWorkerCacheModel.ts +3 -0
  3. package/front_end/core/sdk/StorageBucketsModel.ts +2 -0
  4. package/front_end/entrypoints/main/GlobalAiButton.ts +2 -6
  5. package/front_end/entrypoints/main/MainImpl.ts +8 -1
  6. package/front_end/generated/InspectorBackendCommands.ts +12 -2
  7. package/front_end/generated/SupportedCSSProperties.ts +14 -0
  8. package/front_end/generated/protocol-mapping.d.ts +48 -1
  9. package/front_end/generated/protocol-proxy-api.d.ts +37 -1
  10. package/front_end/generated/protocol.ts +131 -0
  11. package/front_end/models/bindings/NetworkProject.ts +30 -0
  12. package/front_end/models/bindings/ResourceScriptMapping.ts +62 -0
  13. package/front_end/models/change_tracker/ChangeTracker.ts +1 -1
  14. package/front_end/models/comment_manager/CD4ABridge.ts +2 -2
  15. package/front_end/models/comment_manager/CommentManager.ts +18 -0
  16. package/front_end/models/extensions/ExtensionAPI.ts +4 -2
  17. package/front_end/models/issues_manager/CookieIssue.ts +0 -2
  18. package/front_end/models/persistence/NetworkPersistenceManager.ts +29 -4
  19. package/front_end/models/source_map_scopes/NamesResolver.ts +23 -1
  20. package/front_end/models/source_map_scopes/ScopeChainModel.ts +21 -1
  21. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +5 -8
  22. package/front_end/panels/application/AppManifestView.ts +128 -134
  23. package/front_end/panels/application/CrashReportContextView.ts +5 -5
  24. package/front_end/panels/application/DeviceBoundSessionsTreeElement.ts +17 -17
  25. package/front_end/panels/application/DeviceBoundSessionsView.ts +136 -137
  26. package/front_end/panels/application/IndexedDBModel.ts +3 -0
  27. package/front_end/panels/application/OriginTrialTreeView.ts +18 -23
  28. package/front_end/panels/application/ReportingApiTreeElement.ts +3 -3
  29. package/front_end/panels/application/ReportingApiView.ts +6 -14
  30. package/front_end/panels/application/application-meta.ts +7 -7
  31. package/front_end/panels/common/CommentThreadWidget.ts +19 -6
  32. package/front_end/panels/common/CommentsOverlayWidget.ts +115 -9
  33. package/front_end/panels/common/CommentsStatusBarPill.ts +13 -1
  34. package/front_end/panels/common/ExtensionServer.ts +43 -34
  35. package/front_end/panels/common/GeminiRebrandPromoDialog.ts +1 -1
  36. package/front_end/panels/common/commentThreadWidget.css +18 -0
  37. package/front_end/panels/common/common-meta.ts +4 -1
  38. package/front_end/panels/elements/ElementsTreeElement.ts +2 -0
  39. package/front_end/panels/elements/ElementsTreeOutline.ts +11 -7
  40. package/front_end/panels/elements/elementsTreeOutline.css +4 -0
  41. package/front_end/panels/event_listeners/EventListenersView.ts +9 -4
  42. package/front_end/panels/issues/IssuesPane.ts +34 -22
  43. package/front_end/panels/network/RequestPayloadView.ts +17 -15
  44. package/front_end/panels/recorder/RecordingView.ts +32 -53
  45. package/front_end/panels/recorder/controlButton.css +6 -0
  46. package/front_end/panels/recorder/recordingView.css +11 -2
  47. package/front_end/panels/sources/DebuggerPlugin.ts +136 -55
  48. package/front_end/panels/sources/ScopeChainSidebarPane.ts +17 -15
  49. package/front_end/panels/timeline/components/IgnoreListSetting.ts +0 -2
  50. package/front_end/panels/timeline/components/LiveMetricsView.ts +59 -64
  51. package/front_end/panels/timeline/components/liveMetricsView.css +1 -0
  52. package/front_end/third_party/chromium/README.chromium +1 -1
  53. package/front_end/third_party/lighthouse/README.chromium +2 -2
  54. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1580 -1524
  55. package/front_end/third_party/lighthouse/locales/ar-XB.json +111 -72
  56. package/front_end/third_party/lighthouse/locales/ar.json +113 -74
  57. package/front_end/third_party/lighthouse/locales/bg.json +112 -73
  58. package/front_end/third_party/lighthouse/locales/ca.json +112 -73
  59. package/front_end/third_party/lighthouse/locales/cs.json +112 -73
  60. package/front_end/third_party/lighthouse/locales/da.json +112 -73
  61. package/front_end/third_party/lighthouse/locales/de.json +112 -73
  62. package/front_end/third_party/lighthouse/locales/el.json +112 -73
  63. package/front_end/third_party/lighthouse/locales/en-GB.json +111 -72
  64. package/front_end/third_party/lighthouse/locales/en-US.json +102 -66
  65. package/front_end/third_party/lighthouse/locales/en-XA.json +111 -72
  66. package/front_end/third_party/lighthouse/locales/en-XL.json +102 -66
  67. package/front_end/third_party/lighthouse/locales/es-419.json +112 -73
  68. package/front_end/third_party/lighthouse/locales/es.json +112 -73
  69. package/front_end/third_party/lighthouse/locales/fi.json +112 -73
  70. package/front_end/third_party/lighthouse/locales/fil.json +112 -73
  71. package/front_end/third_party/lighthouse/locales/fr.json +112 -73
  72. package/front_end/third_party/lighthouse/locales/he.json +112 -73
  73. package/front_end/third_party/lighthouse/locales/hi.json +112 -73
  74. package/front_end/third_party/lighthouse/locales/hr.json +112 -73
  75. package/front_end/third_party/lighthouse/locales/hu.json +112 -73
  76. package/front_end/third_party/lighthouse/locales/id.json +112 -73
  77. package/front_end/third_party/lighthouse/locales/it.json +113 -74
  78. package/front_end/third_party/lighthouse/locales/ja.json +112 -73
  79. package/front_end/third_party/lighthouse/locales/ko.json +112 -73
  80. package/front_end/third_party/lighthouse/locales/lt.json +112 -73
  81. package/front_end/third_party/lighthouse/locales/lv.json +112 -73
  82. package/front_end/third_party/lighthouse/locales/nl.json +112 -73
  83. package/front_end/third_party/lighthouse/locales/no.json +112 -73
  84. package/front_end/third_party/lighthouse/locales/pl.json +112 -73
  85. package/front_end/third_party/lighthouse/locales/pt-PT.json +112 -73
  86. package/front_end/third_party/lighthouse/locales/pt.json +112 -73
  87. package/front_end/third_party/lighthouse/locales/ro.json +112 -73
  88. package/front_end/third_party/lighthouse/locales/ru.json +112 -73
  89. package/front_end/third_party/lighthouse/locales/sk.json +112 -73
  90. package/front_end/third_party/lighthouse/locales/sl.json +112 -73
  91. package/front_end/third_party/lighthouse/locales/sr-Latn.json +112 -73
  92. package/front_end/third_party/lighthouse/locales/sr.json +112 -73
  93. package/front_end/third_party/lighthouse/locales/sv.json +124 -85
  94. package/front_end/third_party/lighthouse/locales/ta.json +112 -73
  95. package/front_end/third_party/lighthouse/locales/te.json +112 -73
  96. package/front_end/third_party/lighthouse/locales/th.json +112 -73
  97. package/front_end/third_party/lighthouse/locales/tr.json +113 -74
  98. package/front_end/third_party/lighthouse/locales/uk.json +112 -73
  99. package/front_end/third_party/lighthouse/locales/vi.json +112 -73
  100. package/front_end/third_party/lighthouse/locales/zh-HK.json +112 -73
  101. package/front_end/third_party/lighthouse/locales/zh-TW.json +113 -74
  102. package/front_end/third_party/lighthouse/locales/zh.json +113 -74
  103. package/front_end/third_party/lighthouse/report/bundle.d.ts +4 -4
  104. package/front_end/third_party/lighthouse/report/bundle.js +10 -3
  105. package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +2 -2
  106. package/front_end/third_party/lit/lit.ts +3 -0
  107. package/front_end/third_party/lit/package.json +3 -0
  108. package/front_end/third_party/lit/rebuild.sh +3 -2
  109. package/front_end/ui/comments/CommentAnchorResolver.ts +8 -2
  110. package/front_end/ui/comments/CommentOverlayManager.ts +2 -1
  111. package/front_end/ui/legacy/InspectorView.ts +4 -3
  112. package/front_end/ui/legacy/TabbedPane.ts +121 -80
  113. package/front_end/ui/legacy/Treeoutline.ts +35 -6
  114. package/front_end/ui/legacy/UIUtils.ts +7 -0
  115. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +135 -146
  116. package/front_end/ui/lit/lit.ts +1 -1
  117. package/front_end/ui/visual_logging/KnownContextValues.ts +4 -0
  118. package/inspector_overlay/highlight_anchor.ts +197 -0
  119. package/inspector_overlay/tool_highlight.ts +8 -0
  120. package/package.json +1 -1
@@ -27,6 +27,7 @@
27
27
  width: 100%;
28
28
  justify-content: space-between;
29
29
  align-items: center;
30
+ gap: var(--sys-size-4);
30
31
  }
31
32
 
32
33
  .sent-status {
@@ -35,6 +36,7 @@
35
36
  gap: var(--sys-size-2);
36
37
  font-size: var(--sys-typescale-body5-size);
37
38
  color: var(--sys-color-on-surface-subtle);
39
+ flex-shrink: 0;
38
40
  }
39
41
 
40
42
  .check-icon {
@@ -153,7 +155,23 @@
153
155
  padding: var(--sys-size-4) var(--sys-size-5);
154
156
  }
155
157
 
158
+ .tooltip-link {
159
+ display: block;
160
+ margin-top: var(--sys-size-4);
161
+ color: var(--sys-color-primary);
162
+ padding-left: 0;
163
+ background: none;
164
+ border: none;
165
+ font: inherit;
166
+ text-decoration: underline;
167
+ cursor: pointer;
168
+ }
169
+
170
+ .selected-item devtools-widget,
156
171
  .selected-item-text {
172
+ display: block;
173
+ flex: 0 1 auto;
174
+ min-width: 0;
157
175
  overflow: hidden;
158
176
  white-space: nowrap;
159
177
  text-overflow: ellipsis;
@@ -65,7 +65,10 @@ UI.ActionRegistration.registerActionExtension({
65
65
  });
66
66
 
67
67
  UI.Toolbar.registerToolbarItem({
68
- actionId: 'comments.toggle-comment-mode',
68
+ async loadItem() {
69
+ const Common = await loadCommonModule();
70
+ return new Common.CommentsOverlayWidget.ButtonProvider();
71
+ },
69
72
  location: UI.Toolbar.ToolbarItemLocation.MAIN_TOOLBAR_LEFT,
70
73
  order: 1,
71
74
  condition: isCommentsEnabled,
@@ -3178,6 +3178,8 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
3178
3178
  drag: true,
3179
3179
  click: true,
3180
3180
  })}`);
3181
+ this.listItemElement.setAttribute('data-backend-node-id', String(node.backendNodeId()));
3182
+ this.listItemElement.setAttribute('data-target-id', node.domModel().target().id());
3181
3183
 
3182
3184
  this.widgetWrapper = document.createElement('div');
3183
3185
  this.widgetWrapper.style.display = 'contents';
@@ -977,7 +977,7 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
977
977
  },
978
978
  updateRecord: input.updateRecordForNode?.(node) ?? null,
979
979
  })}${hasChildren ? html`<ul role="group">
980
- ${UI.TreeOutline.ifExpanded(html`
980
+ ${isExpanded && !isEditingAsHTML ? html`
981
981
  ${node.adoptedStyleSheetsForNode.length > 0 ? renderAdoptedStyleSheets(node, depth + 1) : nothing}
982
982
  ${repeat(children, child => child.id, child => renderNode(child, depth + 1))}
983
983
  ${remainingChildrenCount > 0 ? html`
@@ -1034,7 +1034,7 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
1034
1034
  updateRecord: input.updateRecordForNode?.(node) ?? null,
1035
1035
  })}</li>
1036
1036
  ` : nothing}
1037
- `)}
1037
+ ` : nothing}
1038
1038
  </ul>` : nothing}</li>
1039
1039
  `;
1040
1040
  // clang-format on
@@ -1062,7 +1062,7 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
1062
1062
  <style>${CodeHighlighter.codeHighlighterStyles}</style>
1063
1063
  <div class=${disclosureClasses} style=${disclosureStyles}>
1064
1064
  <devtools-tree
1065
- class="elements-tree-outline source-code ${input.wrap ? '' : 'elements-tree-nowrap'} ${input.hideGutter ? 'elements-hide-gutter' : ''} ${isSingleNode ? 'single-node' : ''}"
1065
+ class="elements-tree-outline ${input.wrap ? '' : 'elements-tree-nowrap'} ${input.hideGutter ? 'elements-hide-gutter' : ''} ${isSingleNode ? 'single-node' : ''}"
1066
1066
  disclosure-class="elements-disclosure ${isSingleNode ? 'single-node' : ''} ${input.maxRowsShown ? 'elements-tree-truncated' : ''}"
1067
1067
  jslog=${VisualLogging.tree('elements')}
1068
1068
  ?show-selection-on-keyboard-focus=${input.showSelectionOnKeyboardFocus}
@@ -1464,7 +1464,6 @@ export class DOMTreeWidget extends UI.Widget.Widget {
1464
1464
  if (domModel.existingDocument()) {
1465
1465
  this.rootDOMNode = domModel.existingDocument();
1466
1466
  }
1467
- this.onDocumentUpdated(domModel);
1468
1467
  }
1469
1468
 
1470
1469
  #updateModifiedNodesTimeout?: number;
@@ -1518,12 +1517,12 @@ export class DOMTreeWidget extends UI.Widget.Widget {
1518
1517
  event: Common.EventTarget.EventTargetEvent<{node: SDK.DOMModel.DOMNode, parent: SDK.DOMModel.DOMNode}>): void {
1519
1518
  const {node, parent} = event.data;
1520
1519
  this.resetClipboardIfNeeded(node);
1521
- if (this.#selectedDOMNode && (this.#selectedDOMNode === node || node.isAncestor(this.#selectedDOMNode))) {
1522
- this.selectDOMNode(this.#findNextNodeOnRemoval(node, parent), true);
1523
- }
1524
1520
  if (parent) {
1525
1521
  this.#addUpdateRecord(parent).nodeRemoved(node);
1526
1522
  }
1523
+ if (this.#selectedDOMNode && (this.#selectedDOMNode === node || node.isAncestor(this.#selectedDOMNode))) {
1524
+ this.selectDOMNode(this.#findNextNodeOnRemoval(node, parent), true);
1525
+ }
1527
1526
  this.#updateModifiedNodesSoon();
1528
1527
  }
1529
1528
 
@@ -1671,6 +1670,11 @@ export class DOMTreeWidget extends UI.Widget.Widget {
1671
1670
  }
1672
1671
  this.#selectedAdoptedStyleSheet = null;
1673
1672
  if (this.#view === DECLARATIVE_VIEW) {
1673
+ if (node?.nodeType() === Node.TEXT_NODE && node.parentNode &&
1674
+ (!nodeHasVisibleChildren(node.parentNode, this.rootDOMNode, this.maxTreeDepth, this.omitRootDOMNode) ||
1675
+ !getVisibleChildren(node.parentNode, this.#showComments).includes(node))) {
1676
+ node = node.parentNode;
1677
+ }
1674
1678
  const isSameNode = this.#selectedDOMNode === node && this.#selectedClosingTag === Boolean(isClosingTag);
1675
1679
  this.#selectedDOMNode = node;
1676
1680
  this.#selectedClosingTag = Boolean(isClosingTag);
@@ -486,6 +486,10 @@ li.hovered:not(.always-parent) + ol.children:not(.shadow-root) {
486
486
  margin-left: -12px;
487
487
  }
488
488
 
489
+ .tree-outline-disclosure > ol > li.parent:only-of-type:not(.expanded) {
490
+ margin-top: 2px;
491
+ }
492
+
489
493
  .tree-outline-disclosure li.parent:not(.always-parent)::before {
490
494
  box-sizing: border-box;
491
495
  user-select: none;
@@ -236,12 +236,16 @@ export class EventListenersView extends UI.Widget.VBox {
236
236
  }
237
237
 
238
238
  override async performUpdate(): Promise<void> {
239
- if (!this.#listeners && this.#objects) {
240
- this.#listeners =
241
- await EventListenersView.#loadListeners(this.#objects.filter((o): o is NonNullable<typeof o> => !!o));
239
+ let listeners = this.#listeners;
240
+ if (!listeners && this.#objects) {
241
+ const objects = this.#objects;
242
+ listeners = await EventListenersView.#loadListeners(objects.filter((o): o is NonNullable<typeof o> => !!o));
243
+ if (this.#objects === objects) {
244
+ this.#listeners = listeners;
245
+ }
242
246
  }
243
247
  const input: ViewInput = {
244
- listeners: this.#listeners ?? new Map(),
248
+ listeners: listeners ?? new Map(),
245
249
  filter: this.#filter,
246
250
  togglePassiveListener: (listener: SDK.DOMDebuggerModel.EventListener) => {
247
251
  void listener.togglePassive().then(() => {
@@ -276,6 +280,7 @@ export class EventListenersView extends UI.Widget.VBox {
276
280
  },
277
281
  linkifier: this.#linkifier,
278
282
  };
283
+ this.#linkifier.reset();
279
284
  this.#view(input, {}, this.contentElement);
280
285
  this.eventListenersArrivedForTest();
281
286
  }
@@ -183,7 +183,7 @@ export class IssuesPane extends UI.Widget.VBox {
183
183
  #noIssuesMessageDiv: UI.EmptyWidget.EmptyWidget;
184
184
  #issuesManager: IssuesManager.IssuesManager.IssuesManager;
185
185
  #aggregator: IssuesManager.IssueAggregator.IssueAggregator;
186
- #issueViewUpdatePromise: Promise<void> = Promise.resolve();
186
+ #dirtyIssues = new Set<IssuesManager.IssueAggregator.AggregatedIssue>();
187
187
 
188
188
  constructor() {
189
189
  super({
@@ -217,14 +217,16 @@ export class IssuesPane extends UI.Widget.VBox {
217
217
 
218
218
  this.#issuesManager = IssuesManager.IssuesManager.IssuesManager.instance();
219
219
  this.#aggregator = new IssuesManager.IssueAggregator.IssueAggregator(this.#issuesManager);
220
- this.#aggregator.addEventListener(
221
- IssuesManager.IssueAggregator.Events.AGGREGATED_ISSUE_UPDATED, this.#issueUpdated, this);
220
+ this.#aggregator.addEventListener(IssuesManager.IssueAggregator.Events.AGGREGATED_ISSUE_UPDATED, event => {
221
+ this.#dirtyIssues.add(event.data);
222
+ this.requestUpdate();
223
+ });
222
224
  this.#aggregator.addEventListener(
223
225
  IssuesManager.IssueAggregator.Events.FULL_UPDATE_REQUIRED, this.#onFullUpdate, this);
224
226
  this.#hiddenIssuesRow.hidden = this.#issuesManager.numberOfHiddenIssues() === 0;
225
227
  this.#onFullUpdate();
226
- this.#issuesManager.addEventListener(
227
- IssuesManager.IssuesManager.Events.ISSUES_COUNT_UPDATED, this.#updateCounts, this);
228
+ this.#issuesManager.addEventListener(IssuesManager.IssuesManager.Events.ISSUES_COUNT_UPDATED, this.requestUpdate,
229
+ this);
228
230
  }
229
231
 
230
232
  override elementsToRestoreScrollPositionsFor(): Element[] {
@@ -289,15 +291,15 @@ export class IssuesPane extends UI.Widget.VBox {
289
291
  return {toolbarContainer};
290
292
  }
291
293
 
292
- #issueUpdated(event: Common.EventTarget.EventTargetEvent<IssuesManager.IssueAggregator.AggregatedIssue>): void {
293
- this.#scheduleIssueViewUpdate(event.data);
294
- }
295
-
296
- #scheduleIssueViewUpdate(issue: IssuesManager.IssueAggregator.AggregatedIssue): void {
297
- this.#issueViewUpdatePromise = this.#issueViewUpdatePromise.then(() => this.#updateIssueView(issue));
294
+ override async performUpdate(): Promise<void> {
295
+ // Snapshot and clear so new arrivals during `await` schedule a fresh update
296
+ const issuesToUpdate = [...this.#dirtyIssues];
297
+ this.#dirtyIssues.clear();
298
+ await Promise.allSettled(issuesToUpdate.map(issue => this.#updateIssueView(issue)));
299
+ this.#updateCounts();
298
300
  }
299
301
 
300
- /** Don't call directly. Use `scheduleIssueViewUpdate` instead. */
302
+ /** Don't call directly. Use `requestUpdate` instead. */
301
303
  async #updateIssueView(issue: IssuesManager.IssueAggregator.AggregatedIssue): Promise<void> {
302
304
  let issueView = this.#issueViews.get(issue.aggregationKey());
303
305
  if (!issueView) {
@@ -306,12 +308,22 @@ export class IssuesPane extends UI.Widget.VBox {
306
308
  console.warn('Could not find description for issue code:', issue.code());
307
309
  return;
308
310
  }
309
- const markdownDescription =
310
- await IssuesManager.MarkdownIssueDescription.createIssueDescriptionFromMarkdown(description);
311
- issueView = new IssueView(issue, markdownDescription);
312
- this.#issueViews.set(issue.aggregationKey(), issueView);
313
- const parent = this.#getIssueViewParent(issue);
314
- this.appendIssueViewToParent(issueView, parent);
311
+ try {
312
+ const markdownDescription =
313
+ await IssuesManager.MarkdownIssueDescription.createIssueDescriptionFromMarkdown(description);
314
+ issueView = new IssueView(issue, markdownDescription);
315
+ const parent = this.#getIssueViewParent(issue);
316
+ // `appendIssueViewToParent` attaches `issueView` to the tree and synchronously invokes
317
+ // `IssueView.onattach()`, which renders `MarkdownView` tokens and can throw if an unsupported
318
+ // token or missing link key is encountered. Since `TreeElement.insertChild()` attaches the
319
+ // child before calling `onattach()`, we must detach `issueView` if `onattach()` fails.
320
+ this.appendIssueViewToParent(issueView, parent);
321
+ this.#issueViews.set(issue.aggregationKey(), issueView);
322
+ } catch (err) {
323
+ console.error(err);
324
+ issueView?.parent?.removeChild(issueView);
325
+ return;
326
+ }
315
327
  } else {
316
328
  issueView.setIssue(issue);
317
329
  const newParent = this.#getIssueViewParent(issue);
@@ -322,7 +334,6 @@ export class IssuesPane extends UI.Widget.VBox {
322
334
  }
323
335
  }
324
336
  issueView.update();
325
- this.#updateCounts();
326
337
  }
327
338
 
328
339
  appendIssueViewToParent(issueView: IssueView, parent: UI.TreeOutline.TreeOutline|UI.TreeOutline.TreeElement): void {
@@ -415,15 +426,16 @@ export class IssuesPane extends UI.Widget.VBox {
415
426
  }
416
427
 
417
428
  #fullUpdate(force: boolean): void {
429
+ this.#dirtyIssues.clear();
418
430
  this.#clearViews(this.#categoryViews, force ? undefined : this.#aggregator.aggregatedIssueCategories());
419
431
  this.#clearViews(this.#kindViews, force ? undefined : this.#aggregator.aggregatedIssueKinds());
420
432
  this.#clearViews(this.#issueViews, force ? undefined : this.#aggregator.aggregatedIssueCodes());
421
433
  if (this.#aggregator) {
422
434
  for (const issue of this.#aggregator.aggregatedIssues()) {
423
- this.#scheduleIssueViewUpdate(issue);
435
+ this.#dirtyIssues.add(issue);
424
436
  }
425
437
  }
426
- this.#updateCounts();
438
+ this.requestUpdate();
427
439
  }
428
440
 
429
441
  #updateIssueKindViewsCount(): void {
@@ -465,7 +477,7 @@ export class IssuesPane extends UI.Widget.VBox {
465
477
  }
466
478
 
467
479
  async reveal(issue: IssuesManager.Issue.Issue): Promise<void> {
468
- await this.#issueViewUpdatePromise;
480
+ await this.updateComplete;
469
481
  const key = this.#aggregator.keyForIssue(issue);
470
482
  const issueView = this.#issueViews.get(key);
471
483
  if (issueView) {
@@ -471,21 +471,23 @@ export class RequestPayloadView extends UI.Widget.VBox {
471
471
  ObjectUI.ObjectPropertiesSection.populateObjectTreeContextMenu(
472
472
  contextMenu,
473
473
  objectTree,
474
- async () => {
475
- await objectTree.expandRecursively(ObjectUI.ObjectPropertiesSection.EXPANDABLE_MAX_DEPTH);
476
- this.requestUpdate();
477
- },
478
- () => {
479
- objectTree.collapseRecursively();
480
- this.requestUpdate();
481
- },
482
- () => {
483
- objectTree.sortPropertiesAlphabetically = !objectTree.sortPropertiesAlphabetically;
484
- this.requestUpdate();
485
- },
486
- () => {
487
- objectTree.includeNullOrUndefinedValues = !objectTree.includeNullOrUndefinedValues;
488
- this.requestUpdate();
474
+ {
475
+ expandRecursively: async () => {
476
+ await objectTree.expandRecursively(ObjectUI.ObjectPropertiesSection.EXPANDABLE_MAX_DEPTH);
477
+ this.requestUpdate();
478
+ },
479
+ collapseChildren: () => {
480
+ objectTree.collapseRecursively();
481
+ this.requestUpdate();
482
+ },
483
+ sortPropertiesAlphabetically: () => {
484
+ objectTree.sortPropertiesAlphabetically = !objectTree.sortPropertiesAlphabetically;
485
+ this.requestUpdate();
486
+ },
487
+ onShowAllToggled: () => {
488
+ objectTree.includeNullOrUndefinedValues = !objectTree.includeNullOrUndefinedValues;
489
+ this.requestUpdate();
490
+ },
489
491
  },
490
492
  );
491
493
  },
@@ -13,9 +13,7 @@ import * as CodeMirror from '../../third_party/codemirror.next/codemirror.next.j
13
13
  import type * as PuppeteerReplay from '../../third_party/puppeteer-replay/puppeteer-replay.js';
14
14
  import * as Buttons from '../../ui/components/buttons/buttons.js';
15
15
  import * as CodeHighlighter from '../../ui/components/code_highlighter/code_highlighter.js';
16
- import * as Dialogs from '../../ui/components/dialogs/dialogs.js';
17
16
  import * as Input from '../../ui/components/input/input.js';
18
- import type * as Menus from '../../ui/components/menus/menus.js';
19
17
  import * as TextEditor from '../../ui/components/text_editor/text_editor.js';
20
18
  import * as UI from '../../ui/legacy/legacy.js';
21
19
  import * as Lit from '../../ui/lit/lit.js';
@@ -148,6 +146,10 @@ const UIStrings = {
148
146
  * @description The announcement when the code sidebar is closed.
149
147
  */
150
148
  codeSidebarClosed: 'Code sidebar closed',
149
+ /**
150
+ * @description Label for the select that changes the code format in the Recorder panel.
151
+ */
152
+ codeFormat: 'Code format',
151
153
  } as const;
152
154
  const str_ = i18n.i18n.registerUIStrings(
153
155
  'panels/recorder/RecordingView.ts',
@@ -182,7 +184,6 @@ const networkConditionPresets = [
182
184
  function renderSettings({
183
185
  settings,
184
186
  replaySettingsExpanded,
185
- onSelectMenuLabelClick,
186
187
  onNetworkConditionsChange,
187
188
  onTimeoutInput,
188
189
  isRecording,
@@ -277,7 +278,7 @@ function renderSettings({
277
278
  }
278
279
 
279
280
  replaySettingsFragments.push(html`<div class="editable-setting">
280
- <label class="wrapping-label" @click=${onSelectMenuLabelClick}>
281
+ <label class="wrapping-label">
281
282
  ${i18nString(UIStrings.network)}
282
283
  <select
283
284
  title=${menuButtonTitle}
@@ -380,7 +381,7 @@ function renderTimelineArea(input: ViewInput, output: ViewOutput): Lit.LitTempla
380
381
  // clang-format on
381
382
  }
382
383
  // clang-format off
383
- /* eslint-disable @devtools/no-deprecated-component-usages */
384
+
384
385
  return html`
385
386
  <devtools-split-view
386
387
  direction="auto"
@@ -394,35 +395,33 @@ function renderTimelineArea(input: ViewInput, output: ViewOutput): Lit.LitTempla
394
395
  <div slot="sidebar" jslog=${VisualLogging.pane('source-code').track({resize: true})}>
395
396
  ${input.showCodeView ? html`
396
397
  <div class="section-toolbar" jslog=${VisualLogging.toolbar()}>
397
- <devtools-select-menu
398
- @selectmenuselected=${input.onCodeFormatChange}
399
- .showDivider=${true}
400
- .showArrow=${true}
401
- .sideButton=${false}
402
- .showSelectedItem=${true}
403
- .position=${Dialogs.Dialog.DialogVerticalPosition.BOTTOM}
404
- .buttonTitle=${input.converterName || ''}
405
- .jslogContext=${'code-format'}
406
- >
398
+ <label class="code-format-label">
399
+ ${i18nString(UIStrings.codeFormat)}
400
+ <select
401
+ @change=${(event: Event) => {
402
+ if (event.target instanceof HTMLSelectElement) {
403
+ input.onCodeFormatChange(event.target.value);
404
+ }
405
+ }}
406
+ jslog=${VisualLogging.dropDown('code-format').track({change: true})}>
407
407
  ${input.builtInConverters.map(converter => {
408
- return html`<devtools-menu-item
409
- .value=${converter.getId()}
410
- .selected=${input.converterId === converter.getId()}
411
- jslog=${VisualLogging.action().track({click: true}).context(`converter-${Platform.StringUtilities.toKebabCase(converter.getId())}`)}
412
- >
408
+ return html`<option
409
+ value=${converter.getId()}
410
+ ?selected=${input.converterId === converter.getId()}
411
+ jslog=${VisualLogging.item(`converter-${Platform.StringUtilities.toKebabCase(converter.getId())}`)}>
413
412
  ${converter.getFormatName()}
414
- </devtools-menu-item>`;
413
+ </option>`;
415
414
  })}
416
415
  ${input.extensionConverters.map(converter => {
417
- return html`<devtools-menu-item
418
- .value=${converter.getId()}
419
- .selected=${input.converterId === converter.getId()}
420
- jslog=${VisualLogging.action().track({click: true}).context('converter-extension')}
421
- >
416
+ return html`<option
417
+ value=${converter.getId()}
418
+ ?selected=${input.converterId === converter.getId()}
419
+ jslog=${VisualLogging.item('converter-extension')}>
422
420
  ${converter.getFormatName()}
423
- </devtools-menu-item>`;
421
+ </option>`;
424
422
  })}
425
- </devtools-select-menu>
423
+ </select>
424
+ </label>
426
425
  <devtools-button
427
426
  title=${Models.Tooltip.getTooltipForActions(
428
427
  i18nString(UIStrings.hideCode),
@@ -444,7 +443,7 @@ function renderTimelineArea(input: ViewInput, output: ViewOutput): Lit.LitTempla
444
443
  </div>
445
444
  </devtools-split-view>
446
445
  `;
447
- /* eslint-enable @devtools/no-deprecated-component-usages */
446
+
448
447
  // clang-format on
449
448
  }
450
449
 
@@ -735,7 +734,6 @@ interface ViewInput {
735
734
  breakpointIndexes: Set<number>;
736
735
  builtInConverters: readonly Converters.Converter.Converter[];
737
736
  converterId: string;
738
- converterName: string|null;
739
737
  currentError: Error|null;
740
738
  currentStep: Models.Schema.Step|null;
741
739
  editorState: CodeMirror.EditorState|null;
@@ -766,14 +764,11 @@ interface ViewInput {
766
764
  speed: Models.RecordingPlayer.PlayRecordingSpeed,
767
765
  extension?: Extensions.ExtensionManager.Extension,
768
766
  ) => void;
769
- onCodeFormatChange: (
770
- event: Menus.SelectMenu.SelectMenuItemSelectedEvent,
771
- ) => void;
767
+ onCodeFormatChange: (codeFormat: string) => void;
772
768
  onCopyStep: (step: Models.Schema.Step) => void;
773
769
  onEditTitleButtonClick: (event: Event) => void;
774
770
  onNetworkConditionsChange: (event: Event) => void;
775
771
  onReplaySettingsKeydown: (event: Event) => void;
776
- onSelectMenuLabelClick: (event: Event) => void;
777
772
  onStepClick: (step: Models.Schema.Step|Models.Section.Section) => void;
778
773
  onStepHover: (step: Models.Schema.Step|Models.Section.Section) => void;
779
774
  onTimeoutInput: (event: Event) => void;
@@ -932,19 +927,11 @@ export class RecordingView extends UI.Widget.Widget {
932
927
  }
933
928
 
934
929
  override performUpdate(): void {
935
- const converter =
936
- [
937
- ...(this.builtInConverters || []),
938
- ...(this.extensionConverters || []),
939
- ].find(converter => converter.getId() === this.#converterId) ??
940
- this.builtInConverters[0];
941
-
942
930
  this.#view(
943
931
  {
944
932
  breakpointIndexes: this.breakpointIndexes,
945
933
  builtInConverters: this.builtInConverters,
946
934
  converterId: this.#converterId,
947
- converterName: converter?.getFormatName(),
948
935
  currentError: this.currentError ?? null,
949
936
  currentStep: this.currentStep ?? null,
950
937
  editorState: this.#editorState ?? null,
@@ -998,7 +985,6 @@ export class RecordingView extends UI.Widget.Widget {
998
985
  onEditTitleButtonClick: this.#onEditTitleButtonClick.bind(this),
999
986
  onNetworkConditionsChange: this.#onNetworkConditionsChange.bind(this),
1000
987
  onReplaySettingsKeydown: this.#onReplaySettingsKeydown.bind(this),
1001
- onSelectMenuLabelClick: this.#onSelectMenuLabelClick.bind(this),
1002
988
  onStepClick: this.#onStepClick.bind(this),
1003
989
  onStepHover: this.#onStepHover.bind(this),
1004
990
  onTimeoutInput: this.#onTimeoutInput.bind(this),
@@ -1175,13 +1161,6 @@ export class RecordingView extends UI.Widget.Widget {
1175
1161
  input.focus();
1176
1162
  };
1177
1163
 
1178
- #onSelectMenuLabelClick = (event: Event): void => {
1179
- const target = event.target as HTMLElement;
1180
- if (target.matches('.wrapping-label')) {
1181
- target.querySelector('devtools-select-menu')?.click();
1182
- }
1183
- };
1184
-
1185
1164
  async #copyCurrentSelection(step?: Models.Schema.Step|null): Promise<void> {
1186
1165
  let converter =
1187
1166
  [
@@ -1294,10 +1273,10 @@ export class RecordingView extends UI.Widget.Widget {
1294
1273
  this.#viewOutput.highlightLinesInEditor?.(line, length, scroll);
1295
1274
  };
1296
1275
 
1297
- #onCodeFormatChange = (event: Menus.SelectMenu.SelectMenuItemSelectedEvent): void => {
1298
- this.#converterId = event.itemValue as string;
1276
+ #onCodeFormatChange = (codeFormat: string): void => {
1277
+ this.#converterId = codeFormat;
1299
1278
  if (this.recorderSettings) {
1300
- this.recorderSettings.preferredCopyFormat = event.itemValue as string;
1279
+ this.recorderSettings.preferredCopyFormat = codeFormat;
1301
1280
  }
1302
1281
 
1303
1282
  void this.#convertToCode();
@@ -14,11 +14,17 @@
14
14
  .control {
15
15
  background: none;
16
16
  border: none;
17
+ border-radius: var(--sys-shape-corner-small);
17
18
  display: flex;
18
19
  flex-direction: column;
19
20
  align-items: center;
20
21
  }
21
22
 
23
+ .control:focus-visible {
24
+ outline: var(--sys-size-2) solid var(--sys-color-state-focus-ring);
25
+ outline-offset: var(--sys-size-2);
26
+ }
27
+
22
28
  .control[disabled] {
23
29
  filter: grayscale(100%);
24
30
  cursor: auto;
@@ -326,9 +326,18 @@
326
326
  gap: 3px;
327
327
  }
328
328
 
329
- .section-toolbar > devtools-select-menu {
329
+ .code-format-label {
330
+ display: flex;
331
+ align-items: center;
332
+ flex: 1;
333
+ gap: var(--sys-size-3);
334
+ min-width: 0;
335
+ white-space: nowrap;
336
+ }
337
+
338
+ .code-format-label > select {
330
339
  height: var(--sys-size-11);
331
- min-width: 50px;
340
+ min-width: 0;
332
341
  }
333
342
 
334
343
  .sections .section-toolbar {