chrome-devtools-frontend 1.0.1698733 → 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 (164) hide show
  1. package/.agents/skills/devtools-verification/SKILL.md +19 -0
  2. package/.agents/skills/{repro-flaky-tests → fix-tests}/SKILL.md +2 -2
  3. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +2 -2
  4. package/front_end/core/sdk/DOMModel.ts +3 -5
  5. package/front_end/core/sdk/NetworkManager.ts +2 -2
  6. package/front_end/core/sdk/OverlayModel.ts +11 -12
  7. package/front_end/core/sdk/ServiceWorkerCacheModel.ts +3 -0
  8. package/front_end/core/sdk/SourceMapScopeChainEntry.ts +84 -32
  9. package/front_end/core/sdk/StorageBucketsModel.ts +2 -0
  10. package/front_end/entrypoints/main/GlobalAiButton.ts +2 -6
  11. package/front_end/entrypoints/main/MainImpl.ts +8 -1
  12. package/front_end/generated/InspectorBackendCommands.ts +12 -2
  13. package/front_end/generated/SupportedCSSProperties.ts +14 -0
  14. package/front_end/generated/protocol-mapping.d.ts +48 -1
  15. package/front_end/generated/protocol-proxy-api.d.ts +37 -1
  16. package/front_end/generated/protocol.ts +131 -0
  17. package/front_end/models/bindings/NetworkProject.ts +30 -0
  18. package/front_end/models/bindings/ResourceScriptMapping.ts +62 -0
  19. package/front_end/models/change_tracker/ChangeTracker.ts +1 -1
  20. package/front_end/models/comment_manager/CD4ABridge.ts +2 -2
  21. package/front_end/models/comment_manager/CommentManager.ts +18 -0
  22. package/front_end/models/emulation/DeviceModeModel.ts +1 -1
  23. package/front_end/models/extensions/ExtensionAPI.ts +4 -2
  24. package/front_end/models/issues_manager/CookieIssue.ts +0 -15
  25. package/front_end/models/persistence/NetworkPersistenceManager.ts +29 -4
  26. package/front_end/models/source_map_scopes/NamesResolver.ts +34 -4
  27. package/front_end/models/source_map_scopes/ScopeChainModel.ts +31 -7
  28. package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +281 -3
  29. package/front_end/panels/accessibility/accessibilityAnnouncementRecordingView.css +85 -0
  30. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +1 -2
  31. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +5 -8
  32. package/front_end/panels/animation/AnimationTimeline.ts +1 -1
  33. package/front_end/panels/application/AppManifestView.ts +128 -134
  34. package/front_end/panels/application/CrashReportContextView.ts +6 -6
  35. package/front_end/panels/application/DeviceBoundSessionsTreeElement.ts +17 -17
  36. package/front_end/panels/application/DeviceBoundSessionsView.ts +136 -137
  37. package/front_end/panels/application/IndexedDBModel.ts +3 -0
  38. package/front_end/panels/application/IndexedDBViews.ts +1 -1
  39. package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -0
  40. package/front_end/panels/application/OriginTrialTreeView.ts +18 -23
  41. package/front_end/panels/application/ReportingApiTreeElement.ts +3 -3
  42. package/front_end/panels/application/ReportingApiView.ts +6 -14
  43. package/front_end/panels/application/application-meta.ts +7 -7
  44. package/front_end/panels/application/components/AdsView.ts +63 -1
  45. package/front_end/panels/application/components/adsView.css +11 -1
  46. package/front_end/panels/common/CommentThreadWidget.ts +20 -22
  47. package/front_end/panels/common/CommentsOverlayWidget.ts +115 -9
  48. package/front_end/panels/common/CommentsStatusBarPill.ts +13 -1
  49. package/front_end/panels/common/ExtensionServer.ts +43 -34
  50. package/front_end/panels/common/GeminiRebrandPromoDialog.ts +1 -1
  51. package/front_end/panels/common/commentThreadWidget.css +6 -0
  52. package/front_end/panels/common/common-meta.ts +4 -1
  53. package/front_end/panels/elements/CSSRuleValidator.ts +1 -1
  54. package/front_end/panels/elements/ElementsPanel.ts +4 -4
  55. package/front_end/panels/elements/ElementsTreeElement.ts +9 -2
  56. package/front_end/panels/elements/ElementsTreeOutline.ts +25 -33
  57. package/front_end/panels/elements/elementsTreeOutline.css +8 -4
  58. package/front_end/panels/event_listeners/EventListenersView.ts +9 -4
  59. package/front_end/panels/issues/IssuesPane.ts +34 -22
  60. package/front_end/panels/lighthouse/LighthouseController.ts +1 -1
  61. package/front_end/panels/mobile_throttling/NetworkPanelIndicator.ts +1 -1
  62. package/front_end/panels/mobile_throttling/ThrottlingManager.ts +1 -1
  63. package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +1 -1
  64. package/front_end/panels/network/RequestPayloadView.ts +17 -15
  65. package/front_end/panels/recorder/RecordingView.ts +32 -53
  66. package/front_end/panels/recorder/StepView.ts +19 -4
  67. package/front_end/panels/recorder/TimelineSection.ts +1 -1
  68. package/front_end/panels/recorder/controlButton.css +6 -0
  69. package/front_end/panels/recorder/recordingView.css +11 -2
  70. package/front_end/panels/settings/BackendLinkingSettingsTab.ts +2 -1
  71. package/front_end/panels/settings/EditFileSystemView.ts +1 -1
  72. package/front_end/panels/sources/CallStackSidebarPane.ts +1 -1
  73. package/front_end/panels/sources/DebuggerPlugin.ts +137 -56
  74. package/front_end/panels/sources/ScopeChainSidebarPane.ts +17 -15
  75. package/front_end/panels/timeline/components/DetailsView.ts +3 -3
  76. package/front_end/panels/timeline/components/IgnoreListSetting.ts +0 -2
  77. package/front_end/panels/timeline/components/LiveMetricsView.ts +59 -64
  78. package/front_end/panels/timeline/components/OriginMap.ts +1 -1
  79. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +2 -3
  80. package/front_end/panels/timeline/components/liveMetricsView.css +1 -0
  81. package/front_end/third_party/chromium/README.chromium +1 -1
  82. package/front_end/third_party/lighthouse/README.chromium +2 -2
  83. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1580 -1524
  84. package/front_end/third_party/lighthouse/locales/ar-XB.json +111 -72
  85. package/front_end/third_party/lighthouse/locales/ar.json +113 -74
  86. package/front_end/third_party/lighthouse/locales/bg.json +112 -73
  87. package/front_end/third_party/lighthouse/locales/ca.json +112 -73
  88. package/front_end/third_party/lighthouse/locales/cs.json +112 -73
  89. package/front_end/third_party/lighthouse/locales/da.json +112 -73
  90. package/front_end/third_party/lighthouse/locales/de.json +112 -73
  91. package/front_end/third_party/lighthouse/locales/el.json +112 -73
  92. package/front_end/third_party/lighthouse/locales/en-GB.json +111 -72
  93. package/front_end/third_party/lighthouse/locales/en-US.json +102 -66
  94. package/front_end/third_party/lighthouse/locales/en-XA.json +111 -72
  95. package/front_end/third_party/lighthouse/locales/en-XL.json +102 -66
  96. package/front_end/third_party/lighthouse/locales/es-419.json +112 -73
  97. package/front_end/third_party/lighthouse/locales/es.json +112 -73
  98. package/front_end/third_party/lighthouse/locales/fi.json +112 -73
  99. package/front_end/third_party/lighthouse/locales/fil.json +112 -73
  100. package/front_end/third_party/lighthouse/locales/fr.json +112 -73
  101. package/front_end/third_party/lighthouse/locales/he.json +112 -73
  102. package/front_end/third_party/lighthouse/locales/hi.json +112 -73
  103. package/front_end/third_party/lighthouse/locales/hr.json +112 -73
  104. package/front_end/third_party/lighthouse/locales/hu.json +112 -73
  105. package/front_end/third_party/lighthouse/locales/id.json +112 -73
  106. package/front_end/third_party/lighthouse/locales/it.json +113 -74
  107. package/front_end/third_party/lighthouse/locales/ja.json +112 -73
  108. package/front_end/third_party/lighthouse/locales/ko.json +112 -73
  109. package/front_end/third_party/lighthouse/locales/lt.json +112 -73
  110. package/front_end/third_party/lighthouse/locales/lv.json +112 -73
  111. package/front_end/third_party/lighthouse/locales/nl.json +112 -73
  112. package/front_end/third_party/lighthouse/locales/no.json +112 -73
  113. package/front_end/third_party/lighthouse/locales/pl.json +112 -73
  114. package/front_end/third_party/lighthouse/locales/pt-PT.json +112 -73
  115. package/front_end/third_party/lighthouse/locales/pt.json +112 -73
  116. package/front_end/third_party/lighthouse/locales/ro.json +112 -73
  117. package/front_end/third_party/lighthouse/locales/ru.json +112 -73
  118. package/front_end/third_party/lighthouse/locales/sk.json +112 -73
  119. package/front_end/third_party/lighthouse/locales/sl.json +112 -73
  120. package/front_end/third_party/lighthouse/locales/sr-Latn.json +112 -73
  121. package/front_end/third_party/lighthouse/locales/sr.json +112 -73
  122. package/front_end/third_party/lighthouse/locales/sv.json +124 -85
  123. package/front_end/third_party/lighthouse/locales/ta.json +112 -73
  124. package/front_end/third_party/lighthouse/locales/te.json +112 -73
  125. package/front_end/third_party/lighthouse/locales/th.json +112 -73
  126. package/front_end/third_party/lighthouse/locales/tr.json +113 -74
  127. package/front_end/third_party/lighthouse/locales/uk.json +112 -73
  128. package/front_end/third_party/lighthouse/locales/vi.json +112 -73
  129. package/front_end/third_party/lighthouse/locales/zh-HK.json +112 -73
  130. package/front_end/third_party/lighthouse/locales/zh-TW.json +113 -74
  131. package/front_end/third_party/lighthouse/locales/zh.json +113 -74
  132. package/front_end/third_party/lighthouse/report/bundle.d.ts +4 -4
  133. package/front_end/third_party/lighthouse/report/bundle.js +10 -3
  134. package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +2 -2
  135. package/front_end/third_party/lit/lit.ts +3 -0
  136. package/front_end/third_party/lit/package.json +3 -0
  137. package/front_end/third_party/lit/rebuild.sh +3 -2
  138. package/front_end/ui/comments/CommentAnchorResolver.ts +8 -2
  139. package/front_end/ui/comments/CommentOverlayManager.ts +2 -1
  140. package/front_end/ui/components/buttons/Button.ts +19 -1
  141. package/front_end/ui/legacy/ContextMenu.ts +16 -1
  142. package/front_end/ui/legacy/InspectorView.ts +4 -3
  143. package/front_end/ui/legacy/PlusButton.ts +5 -6
  144. package/front_end/ui/legacy/TabbedPane.ts +121 -80
  145. package/front_end/ui/legacy/Treeoutline.ts +37 -6
  146. package/front_end/ui/legacy/UIUtils.ts +7 -0
  147. package/front_end/ui/legacy/Widget.ts +33 -0
  148. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +3 -0
  149. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +14 -4
  150. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +157 -171
  151. package/front_end/ui/lit/lit.ts +1 -1
  152. package/front_end/ui/visual_logging/KnownContextValues.ts +7 -0
  153. package/inspector_overlay/highlight_anchor.ts +197 -0
  154. package/inspector_overlay/tool_highlight.ts +8 -0
  155. package/package.json +1 -1
  156. package/.agents/skills/devtools-ci/SKILL.md +0 -65
  157. package/.agents/skills/evaluate-ai-css-completion/SKILL.md +0 -143
  158. package/.agents/skills/evaluate-ai-css-completion/scripts/evaluate.js +0 -104
  159. package/.agents/skills/fixing-skipped-tests/SKILL.md +0 -32
  160. package/.agents/skills/gerrit-cli/SKILL.md +0 -74
  161. package/.agents/skills/gerrit-cli/references/commands.md +0 -169
  162. package/.agents/skills/gerrit-cli/references/workflows.md +0 -63
  163. package/.agents/skills/gerrit-cli/scripts/import_upstream.py +0 -85
  164. package/front_end/models/issues_manager/descriptions/cookieExcludeBlockedWithinRelatedWebsiteSet.md +0 -4
@@ -88,6 +88,10 @@
88
88
  display: flex;
89
89
  }
90
90
 
91
+ .elements-disclosure li .tree-element-title {
92
+ display: contents;
93
+ }
94
+
91
95
  .elements-disclosure li.parent:not(.always-parent) {
92
96
  /** Keep it in sync with ElementsTreeElements.updateDecorations **/
93
97
  margin-left: calc(-1 * var(--sys-size-6));
@@ -482,6 +486,10 @@ li.hovered:not(.always-parent) + ol.children:not(.shadow-root) {
482
486
  margin-left: -12px;
483
487
  }
484
488
 
489
+ .tree-outline-disclosure > ol > li.parent:only-of-type:not(.expanded) {
490
+ margin-top: 2px;
491
+ }
492
+
485
493
  .tree-outline-disclosure li.parent:not(.always-parent)::before {
486
494
  box-sizing: border-box;
487
495
  user-select: none;
@@ -629,7 +637,3 @@ li.hovered:not(.always-parent) + ol.children:not(.shadow-root) {
629
637
  .tree-outline-disclosure li.in-clipboard .highlight {
630
638
  outline: 1px dotted var(--sys-color-divider);
631
639
  }
632
-
633
- .tree-outline-disclosure li.elements-tree-expand-all {
634
- margin: var(--sys-size-2) 0;
635
- }
@@ -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) {
@@ -40,7 +40,7 @@ const UIStrings = {
40
40
  /**
41
41
  * @description Help text in the Lighthouse panel.
42
42
  */
43
- atLeastOneCategoryMustBeSelected: 'At least one category must be selected.',
43
+ atLeastOneCategoryMustBeSelected: 'At least one category must be selected',
44
44
  /**
45
45
  * @description Text in sidebar of the Application panel.
46
46
  */
@@ -15,7 +15,7 @@ const UIStrings = {
15
15
  /**
16
16
  * @description Icon title for warning indicator in the Network panel title.
17
17
  */
18
- requestsMayBeOverridden: 'Requests may be overridden locally. See the Sources panel',
18
+ requestsMayBeOverridden: 'Requests may be overridden locally. See the Sources panel.',
19
19
  /**
20
20
  * @description Icon title for warning indicator in the Network panel title.
21
21
  */
@@ -42,7 +42,7 @@ const UIStrings = {
42
42
  /**
43
43
  * @description Tooltip text in throttling manager of the Performance panel.
44
44
  */
45
- excessConcurrency: 'Exceeding the default value may degrade system performance.',
45
+ excessConcurrency: 'Exceeding the default value may degrade system performance',
46
46
  /**
47
47
  * @description Tooltip text in throttling manager of the Performance panel.
48
48
  */
@@ -159,7 +159,7 @@ const UIStrings = {
159
159
  * @description Text to explain why the user should run the CPU calibration process.
160
160
  */
161
161
  calibrationCTA:
162
- 'To use the CPU throttling presets, run the calibration process to determine the ideal throttling rate for your device.',
162
+ 'To use the CPU throttling presets, run the calibration process to determine the ideal throttling rate for your device',
163
163
  /**
164
164
  * @description Text to explain what CPU throttling presets are.
165
165
  */
@@ -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();
@@ -18,6 +18,7 @@ import stepViewStyles from './stepView.css.js';
18
18
  import {TimelineSection} from './TimelineSection.js';
19
19
 
20
20
  const {html} = Lit;
21
+ const {ifDefined} = Lit.Directives;
21
22
  const {widget} = UI.Widget;
22
23
 
23
24
  const UIStrings = {
@@ -276,8 +277,7 @@ function renderStepActions(input: ViewInput): Lit.TemplateResult|null {
276
277
  return html`
277
278
  <devtools-menu-button
278
279
  class="step-actions"
279
- title=${i18nString(UIStrings.openStepActions)}
280
- aria-label=${i18nString(UIStrings.openStepActions)}
280
+ .accessibleLabel=${i18nString(UIStrings.openStepActions)}
281
281
  .populateMenuCall=${input.populateStepContextMenu}
282
282
  @keydown=${(event: Event) => {
283
283
  event.stopPropagation();
@@ -312,6 +312,8 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
312
312
  section: input.section,
313
313
  });
314
314
  const subtitle = input.step ? getSelectorPreview(input.step) : getSectionPreview(input.section);
315
+ const breakpointTitle =
316
+ input.hasBreakpoint ? i18nString(UIStrings.removeBreakpoint) : i18nString(UIStrings.addBreakpoint);
315
317
 
316
318
  // clang-format off
317
319
  Lit.render(
@@ -347,13 +349,26 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
347
349
  }
348
350
  }}
349
351
  class=${Lit.Directives.classMap(stepClasses)}>
350
- <svg slot="icon" width="24" height="24" class="icon">
352
+ <svg slot="icon" width="24" height="24" class="icon"
353
+ role=${input.step ? 'button' : 'presentation'}
354
+ aria-label=${ifDefined(input.step ? breakpointTitle : undefined)}
355
+ aria-hidden=${ifDefined(input.step ? undefined : 'true')}
356
+ tabindex=${ifDefined(input.step ? 0 : undefined)}
357
+ @click=${input.step ? input.onBreakpointClick : undefined}
358
+ @keydown=${input.step ? (event: KeyboardEvent) => {
359
+ if (event.key === 'Enter' || event.key === ' ') {
360
+ input.onBreakpointClick();
361
+ event.preventDefault();
362
+ event.stopPropagation();
363
+ }
364
+ } : undefined}
365
+ jslog=${ifDefined(input.step ? VisualLogging.action('breakpoint').track({click: true}) : undefined)}>
351
366
  <circle class="circle-icon"/>
352
367
  <g class="error-icon">
353
368
  <path d="M1.5 1.5L6.5 6.5" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
354
369
  <path d="M1.5 6.5L6.5 1.5" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
355
370
  </g>
356
- <path @click=${input.onBreakpointClick} jslog=${VisualLogging.action('breakpoint').track({click: true})} class="breakpoint-icon" d="M2.5 5.5H17.7098L21.4241 12L17.7098 18.5H2.5V5.5Z"/>
371
+ <path class="breakpoint-icon" d="M2.5 5.5H17.7098L21.4241 12L17.7098 18.5H2.5V5.5Z"/>
357
372
  </svg>
358
373
  <div class="summary">
359
374
  <div class="title-container ${isExpandable ? 'action' : ''}"
@@ -37,7 +37,7 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
37
37
  <div class=${Lit.Directives.classMap(classes)}>
38
38
  <div class="overlay"></div>
39
39
  <div class="icon"><slot name="icon"></slot></div>
40
- <svg width="24" height="100%" class="bar">
40
+ <svg width="24" height="100%" class="bar" aria-hidden="true">
41
41
  <rect class="line" x="7" y="0" width="2" height="100%" />
42
42
  </svg>
43
43
  <slot></slot>
@@ -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 {
@@ -93,7 +93,7 @@ const UIStrings = {
93
93
  /**
94
94
  * @description Warning message displayed below the backend linking rules table when one or more rules are invalid.
95
95
  */
96
- invalidRulesWarning: 'Invalid rules will not be applied or saved.',
96
+ invalidRulesWarning: 'Invalid rules will not be applied or saved',
97
97
  } as const;
98
98
 
99
99
  const str_ = i18n.i18n.registerUIStrings('panels/settings/BackendLinkingSettingsTab.ts', UIStrings);
@@ -168,6 +168,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
168
168
  name=${i18nString(UIStrings.rulesSectionHeading)}
169
169
  striped
170
170
  inline
171
+ deletable
171
172
  @delete=${() => {}}
172
173
  @create=${onCreate}>
173
174
  <table>
@@ -78,7 +78,7 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
78
78
  @create=${input.onCreate}
79
79
  class="exclude-subfolders-table"
80
80
  parts="excluded-folder-row-with-error"
81
- inline striped>
81
+ inline striped deletable>
82
82
  <table>
83
83
  <thead>
84
84
  <tr>
@@ -79,7 +79,7 @@ const UIStrings = {
79
79
  * @description Error message that is displayed in UI when a file needed for debugging information for a call frame is missing
80
80
  * @example {src/myapp.debug.wasm.dwp} PH1
81
81
  */
82
- debugFileNotFound: 'Failed to load debug file "{PH1}".',
82
+ debugFileNotFound: 'Failed to load debug file "{PH1}"',
83
83
  /**
84
84
  * @description A context menu item in the call stack sidebar pane. "Restart" is a verb and
85
85
  * "frame" is a noun. "Frame" refers to an individual item in the call stack, i.e. a call frame.