chrome-devtools-frontend 1.0.1624409 → 1.0.1625079

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 (86) hide show
  1. package/.agents/skills/foundation-test-migration/SKILL.md +3 -3
  2. package/front_end/core/host/AidaClient.ts +6 -5
  3. package/front_end/core/host/AidaClientTypes.ts +3 -1
  4. package/front_end/core/host/DispatchHttpRequestClient.ts +6 -3
  5. package/front_end/core/platform/api/HostRuntime.ts +3 -0
  6. package/front_end/core/platform/browser/HostRuntime.ts +10 -0
  7. package/front_end/core/platform/node/HostRuntime.ts +10 -0
  8. package/front_end/core/root/Runtime.ts +6 -5
  9. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +6 -2
  10. package/front_end/models/ai_code_completion/AiCodeCompletion.ts +2 -3
  11. package/front_end/models/ai_code_generation/AiCodeGeneration.ts +2 -3
  12. package/front_end/models/javascript_metadata/NativeFunctions.js +4 -0
  13. package/front_end/models/trace/insights/DuplicatedJavaScript.ts +4 -0
  14. package/front_end/models/trace/insights/FontDisplay.ts +4 -0
  15. package/front_end/models/trace/insights/LegacyJavaScript.ts +4 -0
  16. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +8 -4
  17. package/front_end/panels/ai_assistance/components/ChatMessage.ts +7 -5
  18. package/front_end/panels/ai_assistance/components/ChatView.ts +2 -2
  19. package/front_end/panels/elements/StylePropertyTreeElement.ts +2 -2
  20. package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +6 -1
  21. package/front_end/panels/elements/StylesSidebarPane.ts +12 -1
  22. package/front_end/panels/elements/stylePropertiesTreeOutline.css +5 -1
  23. package/front_end/panels/emulation/DeviceModeToolbar.ts +144 -128
  24. package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +12 -4
  25. package/front_end/panels/timeline/components/insights/DuplicatedJavaScript.ts +4 -0
  26. package/front_end/panels/timeline/components/insights/FontDisplay.ts +4 -0
  27. package/front_end/panels/timeline/components/insights/LegacyJavaScript.ts +4 -0
  28. package/front_end/third_party/chromium/README.chromium +1 -1
  29. package/front_end/third_party/lighthouse/README.chromium +2 -2
  30. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +5176 -5104
  31. package/front_end/third_party/lighthouse/locales/ar-XB.json +72 -36
  32. package/front_end/third_party/lighthouse/locales/ar.json +72 -36
  33. package/front_end/third_party/lighthouse/locales/bg.json +72 -36
  34. package/front_end/third_party/lighthouse/locales/ca.json +72 -36
  35. package/front_end/third_party/lighthouse/locales/cs.json +72 -36
  36. package/front_end/third_party/lighthouse/locales/da.json +74 -38
  37. package/front_end/third_party/lighthouse/locales/de.json +72 -36
  38. package/front_end/third_party/lighthouse/locales/el.json +73 -37
  39. package/front_end/third_party/lighthouse/locales/en-GB.json +74 -38
  40. package/front_end/third_party/lighthouse/locales/en-US.json +245 -17
  41. package/front_end/third_party/lighthouse/locales/en-XL.json +245 -17
  42. package/front_end/third_party/lighthouse/locales/es-419.json +72 -36
  43. package/front_end/third_party/lighthouse/locales/es.json +73 -37
  44. package/front_end/third_party/lighthouse/locales/fi.json +72 -36
  45. package/front_end/third_party/lighthouse/locales/fil.json +74 -38
  46. package/front_end/third_party/lighthouse/locales/fr.json +162 -126
  47. package/front_end/third_party/lighthouse/locales/he.json +74 -38
  48. package/front_end/third_party/lighthouse/locales/hi.json +73 -37
  49. package/front_end/third_party/lighthouse/locales/hr.json +72 -36
  50. package/front_end/third_party/lighthouse/locales/hu.json +73 -37
  51. package/front_end/third_party/lighthouse/locales/id.json +74 -38
  52. package/front_end/third_party/lighthouse/locales/it.json +72 -36
  53. package/front_end/third_party/lighthouse/locales/ja.json +72 -36
  54. package/front_end/third_party/lighthouse/locales/ko.json +72 -36
  55. package/front_end/third_party/lighthouse/locales/lt.json +72 -36
  56. package/front_end/third_party/lighthouse/locales/lv.json +72 -36
  57. package/front_end/third_party/lighthouse/locales/nl.json +73 -37
  58. package/front_end/third_party/lighthouse/locales/no.json +72 -36
  59. package/front_end/third_party/lighthouse/locales/pl.json +72 -36
  60. package/front_end/third_party/lighthouse/locales/pt-PT.json +72 -36
  61. package/front_end/third_party/lighthouse/locales/pt.json +74 -38
  62. package/front_end/third_party/lighthouse/locales/ro.json +72 -36
  63. package/front_end/third_party/lighthouse/locales/ru.json +72 -36
  64. package/front_end/third_party/lighthouse/locales/sk.json +72 -36
  65. package/front_end/third_party/lighthouse/locales/sl.json +72 -36
  66. package/front_end/third_party/lighthouse/locales/sr-Latn.json +73 -37
  67. package/front_end/third_party/lighthouse/locales/sr.json +73 -37
  68. package/front_end/third_party/lighthouse/locales/sv.json +75 -39
  69. package/front_end/third_party/lighthouse/locales/ta.json +73 -37
  70. package/front_end/third_party/lighthouse/locales/te.json +72 -36
  71. package/front_end/third_party/lighthouse/locales/th.json +73 -37
  72. package/front_end/third_party/lighthouse/locales/tr.json +72 -36
  73. package/front_end/third_party/lighthouse/locales/uk.json +72 -36
  74. package/front_end/third_party/lighthouse/locales/vi.json +74 -38
  75. package/front_end/third_party/lighthouse/locales/zh-HK.json +72 -36
  76. package/front_end/third_party/lighthouse/locales/zh-TW.json +74 -38
  77. package/front_end/third_party/lighthouse/locales/zh.json +75 -39
  78. package/front_end/third_party/lighthouse/report/bundle.js +2 -1
  79. package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +1 -1
  80. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +6 -2
  81. package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +4 -1
  82. package/front_end/ui/legacy/SuggestBox.ts +1 -0
  83. package/front_end/ui/legacy/TextPrompt.ts +2 -1
  84. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +328 -47
  85. package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
  86. package/package.json +9 -8
@@ -2,6 +2,7 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
  /* eslint-disable @devtools/no-imperative-dom-api */
5
+ /* eslint-disable @devtools/no-lit-render-outside-of-view */
5
6
 
6
7
  import '../../ui/legacy/legacy.js';
7
8
 
@@ -11,8 +12,8 @@ import * as i18n from '../../core/i18n/i18n.js';
11
12
  import * as Platform from '../../core/platform/platform.js';
12
13
  import * as EmulationModel from '../../models/emulation/emulation.js';
13
14
  import * as Buttons from '../../ui/components/buttons/buttons.js';
14
- import * as uiI18n from '../../ui/i18n/i18n.js';
15
15
  import * as UI from '../../ui/legacy/legacy.js';
16
+ import {Directives, html, i18nTemplate, type LitTemplate, render} from '../../ui/lit/lit.js';
16
17
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
17
18
  import * as MobileThrottling from '../mobile_throttling/mobile_throttling.js';
18
19
 
@@ -187,6 +188,9 @@ const UIStrings = {
187
188
  } as const;
188
189
  const str_ = i18n.i18n.registerUIStrings('panels/emulation/DeviceModeToolbar.ts', UIStrings);
189
190
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
191
+ const {ref, classMap} = Directives;
192
+ const {widget} = UI.Widget;
193
+ const {bindToSetting} = UI.UIUtils;
190
194
 
191
195
  /**
192
196
  * Even though the emulation panel uses all UI elements, the tooltips are not supported.
@@ -218,8 +222,8 @@ export class DeviceModeToolbar {
218
222
  private spanButton!: Buttons.Button.Button;
219
223
  private postureItem!: HTMLSelectElement;
220
224
  private modeButton!: Buttons.Button.Button;
221
- private widthInput: HTMLInputElement;
222
- private heightInput: HTMLInputElement;
225
+ private widthInput!: HTMLInputElement;
226
+ private heightInput!: HTMLInputElement;
223
227
  private deviceScaleItem!: HTMLSelectElement;
224
228
  private deviceScaleItems: HTMLElement[] = [];
225
229
  private deviceSelectItem!: HTMLSelectElement;
@@ -255,9 +259,6 @@ export class DeviceModeToolbar {
255
259
 
256
260
  this.lastMode = new Map();
257
261
 
258
- this.widthInput = this.createSizeInput(i18nString(UIStrings.width), 'width');
259
- this.heightInput = this.createSizeInput(i18nString(UIStrings.heightLeaveEmptyForFull), 'height');
260
-
261
262
  this.#element = document.createElement('div');
262
263
  this.#element.classList.add('device-mode-toolbar');
263
264
  this.#element.setAttribute('jslog', `${VisualLogging.toolbar('device-mode').track({resize: true})}`);
@@ -304,16 +305,22 @@ export class DeviceModeToolbar {
304
305
  return element;
305
306
  }
306
307
 
307
- private createSizeInput(title: string, jslogContext: string): HTMLInputElement {
308
- const input = document.createElement('input');
309
- input.type = 'number';
310
- input.max = String(EmulationModel.DeviceModeModel.MaxDeviceSize);
311
- input.min = String(EmulationModel.DeviceModeModel.MinDeviceSize);
312
- input.title = title;
313
- input.classList.add('device-mode-size-input');
314
- input.setAttribute('jslog', `${VisualLogging.textField().track({change: true}).context(jslogContext)}`);
315
-
316
- input.addEventListener('keydown', (event: Event) => {
308
+ private createSizeInput(
309
+ title: string, jslogContext: string, value: string|undefined, disabled: boolean|undefined,
310
+ refCallback: (el: Element|undefined) => void, onChange: () => void): LitTemplate {
311
+ return html`
312
+ <input type="number"
313
+ max=${EmulationModel.DeviceModeModel.MaxDeviceSize}
314
+ min=${EmulationModel.DeviceModeModel.MinDeviceSize}
315
+ title=${title}
316
+ class="device-mode-size-input"
317
+ .disabled=${disabled ?? false}
318
+ jslog=${VisualLogging.textField().track({change: true}).context(jslogContext)}
319
+ .value=${value ?? ''}
320
+ @change=${onChange}
321
+ ${ref(refCallback)}
322
+ @keydown=${(event: Event): void => {
323
+ const input = event.target as HTMLInputElement;
317
324
  let modifiedValue = UI.UIUtils.modifiedFloatNumber(Number(input.value), event);
318
325
  if (modifiedValue === null) {
319
326
  return;
@@ -324,125 +331,134 @@ export class DeviceModeToolbar {
324
331
  event.preventDefault();
325
332
  input.value = String(modifiedValue);
326
333
  input.dispatchEvent(new Event('change'));
327
- });
328
- return input;
334
+ }}>`;
329
335
  }
330
336
 
331
337
  private createMainToolbar(): UI.Toolbar.Toolbar {
332
338
  const mainToolbar = this.#element.createChild('devtools-toolbar', 'main-toolbar');
333
-
334
- mainToolbar.append(this.createEmptyToolbarElement());
335
- this.deviceSelectItem = document.createElement('select');
336
- this.deviceSelectItem.classList.add('dark-text', 'toolbar-has-dropdown-shrinkable');
337
- this.deviceSelectItem.title = i18nString(UIStrings.deviceType);
338
- UI.ARIAUtils.setLabel(this.deviceSelectItem, i18nString(UIStrings.deviceType));
339
- this.deviceSelectItem.addEventListener('change', this.onDeviceChange.bind(this));
340
- this.deviceSelectItem.setAttribute('jslog', `${VisualLogging.dropDown().track({change: true}).context('device')}`);
341
- const dimensionsSpan = uiI18n.getFormatLocalizedString(str_, UIStrings.dimensions, {PH1: this.deviceSelectItem});
342
- mainToolbar.append(...dimensionsSpan.childNodes);
343
- mainToolbar.append(this.deviceSelectItem);
344
-
345
- this.widthInput.addEventListener('change', () => {
346
- const width = Number(this.widthInput.value);
347
- if (this.autoAdjustScaleSetting.get()) {
348
- this.model.setWidthAndScaleToFit(width);
349
- } else {
350
- this.model.setWidth(width);
351
- }
352
- });
353
- this.heightInput.addEventListener('change', () => {
354
- const height = Number(this.heightInput.value);
355
- if (this.autoAdjustScaleSetting.get()) {
356
- this.model.setHeightAndScaleToFit(height);
357
- } else {
358
- this.model.setHeight(height);
359
- }
360
- });
361
- mainToolbar.append(this.widthInput);
362
- this.xItem = document.createElement('div');
363
- this.xItem.classList.add('device-mode-x');
364
- this.xItem.textContent = '×';
365
- mainToolbar.append(this.xItem);
366
- mainToolbar.append(this.heightInput);
367
-
368
- mainToolbar.append(this.createEmptyToolbarElement());
369
- this.scaleItem = document.createElement('select');
370
- this.scaleItem.classList.add('dark-text', 'toolbar-has-dropdown-shrinkable');
371
- this.scaleItem.title = i18nString(UIStrings.zoom);
372
- UI.ARIAUtils.setLabel(this.scaleItem, i18nString(UIStrings.zoom));
373
- this.scaleItem.addEventListener('change', this.onScaleChange.bind(this));
374
- this.scaleItem.setAttribute('jslog', `${VisualLogging.dropDown().track({change: true}).context('scale')}`);
375
- mainToolbar.append(this.scaleItem);
376
-
377
- const autoAdjustScaleButton = new UI.Toolbar.ToolbarSettingToggle(
378
- this.autoAdjustScaleSetting, 'center-focus-weak', i18nString(UIStrings.autoadjustZoom));
379
- mainToolbar.appendToolbarItem(autoAdjustScaleButton);
380
-
381
- mainToolbar.append(this.createEmptyToolbarElement());
382
-
383
- this.deviceScaleItem = document.createElement('select');
384
- this.deviceScaleItem.classList.add('dark-text', 'toolbar-has-dropdown-shrinkable');
385
- this.deviceScaleItem.title = i18nString(UIStrings.devicePixelRatio);
386
- UI.ARIAUtils.setLabel(this.deviceScaleItem, i18nString(UIStrings.devicePixelRatio));
387
- this.deviceScaleItem.addEventListener('change', this.onDeviceScaleChange.bind(this));
388
- this.deviceScaleItem.setAttribute(
389
- 'jslog', `${VisualLogging.dropDown().track({change: true}).context('device-pixel-ratio')}`);
390
- const deviceScaleSpan = uiI18n.getFormatLocalizedString(str_, UIStrings.dpr, {PH1: this.deviceScaleItem});
339
+ // clang-format off
340
+ render(html`
341
+ <div class="device-mode-empty-toolbar-element"></div>
342
+ ${i18nTemplate(str_, UIStrings.dimensions, {PH1: html`
343
+ <select class="dark-text toolbar-has-dropdown-shrinkable"
344
+ title=${i18nString(UIStrings.deviceType)}
345
+ aria-label=${i18nString(UIStrings.deviceType)}
346
+ @change=${this.onDeviceChange.bind(this)}
347
+ jslog=${VisualLogging.dropDown().track({change: true}).context('device')}
348
+ ${ref(el => { this.deviceSelectItem = el as HTMLSelectElement; })}>
349
+ </select>`})}
350
+
351
+ ${this.createSizeInput(
352
+ i18nString(UIStrings.width), 'width', this.widthInput?.value, this.widthInput?.disabled,
353
+ el => { this.widthInput = el as HTMLInputElement; },
354
+ () => {
355
+ const width = Number(this.widthInput.value);
356
+ if (this.autoAdjustScaleSetting.get()) {
357
+ this.model.setWidthAndScaleToFit(width);
358
+ } else {
359
+ this.model.setWidth(width);
360
+ }
361
+ })}
362
+
363
+ <div class="device-mode-x" ${ref(el => { this.xItem = el as HTMLElement; })}>×</div>
364
+ ${this.createSizeInput(
365
+ i18nString(UIStrings.heightLeaveEmptyForFull), 'height', this.heightInput?.value, this.heightInput?.disabled,
366
+ el => { this.heightInput = el as HTMLInputElement; },
367
+ () => {
368
+ const height = Number(this.heightInput.value);
369
+ if (this.autoAdjustScaleSetting.get()) {
370
+ this.model.setHeightAndScaleToFit(height);
371
+ } else {
372
+ this.model.setHeight(height);
373
+ }
374
+ })}
375
+
376
+ <div class="device-mode-empty-toolbar-element"></div>
377
+ <select class="dark-text toolbar-has-dropdown-shrinkable"
378
+ title=${i18nString(UIStrings.zoom)}
379
+ aria-label=${i18nString(UIStrings.zoom)}
380
+ @change=${this.onScaleChange.bind(this)}
381
+ jslog=${VisualLogging.dropDown().track({change: true}).context('scale')}
382
+ ${ref((el: Element|undefined) => { this.scaleItem = el as HTMLSelectElement; })}>
383
+ </select>
384
+
385
+ <devtools-button .data=${{variant: Buttons.Button.Variant.TOOLBAR, iconName: 'center-focus-weak',
386
+ toggledIconName: 'center-focus-weak', toggleType: Buttons.Button.ToggleType.PRIMARY} as Buttons.Button.ButtonData}
387
+ class="toolbar-button" title=${i18nString(UIStrings.autoadjustZoom)}
388
+ ${bindToSetting(this.autoAdjustScaleSetting)}>
389
+ </devtools-button>
390
+
391
+ <div class="device-mode-empty-toolbar-element"></div>
392
+
393
+ <span>
394
+ ${i18nTemplate(str_, UIStrings.dpr, {
395
+ PH1: html`
396
+ <select class="dark-text toolbar-has-dropdown-shrinkable"
397
+ title=${i18nString(UIStrings.devicePixelRatio)}
398
+ aria-label=${i18nString(UIStrings.devicePixelRatio)}
399
+ @change=${this.onDeviceScaleChange.bind(this)}
400
+ jslog=${VisualLogging.dropDown().track({change: true}).context('device-pixel-ratio')}
401
+ ${ref(el => { this.deviceScaleItem = el as HTMLSelectElement; })}>
402
+ </select>`
403
+ })}
404
+ </span>
405
+
406
+ <div class="device-mode-empty-toolbar-element"></div>
407
+ <select class="dark-text toolbar-has-dropdown-shrinkable
408
+ ${classMap({hidden: !this.showUserAgentTypeSetting.get()})}"
409
+ title=${i18nString(UIStrings.deviceType)}
410
+ aria-label=${i18nString(UIStrings.deviceType)}
411
+ @change=${this.onUAChange.bind(this)}
412
+ jslog=${VisualLogging.dropDown().track({change: true}).context('device-type')}
413
+ ${ref(el => { this.uaItem = el as HTMLSelectElement; })}>
414
+ </select>
415
+ <select class="dark-text" ${widget(MobileThrottling.NetworkThrottlingSelector.NetworkThrottlingSelect, {
416
+ title: i18nString(UIStrings.throttling),
417
+ bindToGlobalConditions: true,
418
+ })}></select>
419
+ <select class="dark-text toolbar-has-dropdown-shrinkable" ${widget(
420
+ MobileThrottling.ThrottlingManager.SaveDataOverrideSelect)}></select>
421
+
422
+ <div class="device-mode-empty-toolbar-element"></div>
423
+ <devtools-button class="toolbar-button"
424
+ .data=${{variant: Buttons.Button.Variant.ICON, iconName: 'screen-rotation'} as Buttons.Button.ButtonData}
425
+ jslog=${VisualLogging.action('screen-rotation').track({click: true})}
426
+ @click=${this.modeMenuClicked.bind(this)}
427
+ ${ref(el => { this.modeButton = el as Buttons.Button.Button; })}>
428
+ </devtools-button>
429
+
430
+ <!-- Show dual screen toolbar -->
431
+ <devtools-button class="toolbar-button"
432
+ .data=${{variant: Buttons.Button.Variant.ICON, iconName: 'device-fold'} as Buttons.Button.ButtonData}
433
+ jslog=${VisualLogging.action('device-fold').track({click: true})}
434
+ @click=${this.spanClicked.bind(this)}
435
+ ${ref(el => { this.spanButton = el as Buttons.Button.Button; })}>
436
+ </devtools-button>
437
+
438
+ <!-- Show posture toolbar menu for foldable devices. -->
439
+ <div class="device-mode-empty-toolbar-element"></div>
440
+ <select class="dark-text toolbar-has-dropdown-shrinkable"
441
+ title=${i18nString(UIStrings.devicePosture)}
442
+ aria-label=${i18nString(UIStrings.devicePosture)}
443
+ @change=${this.onPostureChange.bind(this)}
444
+ jslog=${VisualLogging.dropDown().track({change: true}).context('device-posture')}
445
+ ${ref(el => { this.postureItem = el as HTMLSelectElement; })}>
446
+ </select>`,
447
+ mainToolbar);
448
+ // clang-format on
449
+ const deviceScaleSpan = this.deviceScaleItem.parentElement as HTMLElement;
391
450
  for (const node of Array.from(deviceScaleSpan.childNodes)) {
392
- if (node === this.deviceScaleItem) {
393
- this.deviceScaleItem.classList.toggle('hidden', !this.showDeviceScaleFactorSetting.get());
394
- this.deviceScaleItems.push(this.deviceScaleItem);
395
- mainToolbar.append(this.deviceScaleItem);
396
- } else {
397
- const item = new UI.Toolbar.ToolbarText(node.textContent || '');
398
- item.setVisible(this.showDeviceScaleFactorSetting.get());
399
- this.deviceScaleItems.push(item.element);
400
- mainToolbar.appendToolbarItem(item);
451
+ if (node instanceof HTMLElement) {
452
+ this.deviceScaleItems.push(node);
453
+ } else if (node instanceof Text) {
454
+ const span = document.createElement('span');
455
+ span.classList.add('toolbar-text');
456
+ span.appendChild(node);
457
+ this.deviceScaleItems.push(span);
401
458
  }
402
459
  }
403
- mainToolbar.append(this.createEmptyToolbarElement());
404
- this.uaItem = document.createElement('select');
405
- this.uaItem.classList.add('dark-text', 'toolbar-has-dropdown-shrinkable');
406
- this.uaItem.title = i18nString(UIStrings.deviceType);
407
- UI.ARIAUtils.setLabel(this.uaItem, i18nString(UIStrings.deviceType));
408
- this.uaItem.addEventListener('change', this.onUAChange.bind(this));
409
- this.uaItem.setAttribute('jslog', `${VisualLogging.dropDown().track({change: true}).context('device-type')}`);
410
- this.uaItem.classList.toggle('hidden', !this.showUserAgentTypeSetting.get());
411
- mainToolbar.append(this.uaItem);
412
-
413
- MobileThrottling.NetworkThrottlingSelector.NetworkThrottlingSelect.createForGlobalConditions(
414
- mainToolbar, i18nString(UIStrings.throttling));
415
- const saveDataItem = MobileThrottling.ThrottlingManager.throttlingManager().createSaveDataOverrideSelector();
416
- saveDataItem.classList.add('dark-text', 'toolbar-has-dropdown-shrinkable');
417
- mainToolbar.append(saveDataItem);
418
-
419
- mainToolbar.append(this.createEmptyToolbarElement());
420
- this.modeButton = new Buttons.Button.Button();
421
- this.modeButton.classList.add('toolbar-button');
422
- this.modeButton.data = {variant: Buttons.Button.Variant.ICON, iconName: 'screen-rotation'};
423
- this.modeButton.setAttribute('jslog', `${VisualLogging.action('screen-rotation').track({click: true})}`);
424
- this.modeButton.addEventListener('click', this.modeMenuClicked.bind(this));
425
- mainToolbar.append(this.modeButton);
426
-
427
- // Show dual screen toolbar.
428
- this.spanButton = new Buttons.Button.Button();
429
- this.spanButton.classList.add('toolbar-button');
430
- this.spanButton.data = {variant: Buttons.Button.Variant.ICON, iconName: 'device-fold'};
431
- this.spanButton.setAttribute('jslog', `${VisualLogging.action('device-fold').track({click: true})}`);
432
- this.spanButton.addEventListener('click', this.spanClicked.bind(this));
433
- mainToolbar.append(this.spanButton);
434
-
435
- // Show posture toolbar menu for foldable devices.
436
- mainToolbar.append(this.createEmptyToolbarElement());
437
- this.postureItem = document.createElement('select');
438
- this.postureItem.classList.add('dark-text', 'toolbar-has-dropdown-shrinkable');
439
- this.postureItem.title = i18nString(UIStrings.devicePosture);
440
- UI.ARIAUtils.setLabel(this.postureItem, i18nString(UIStrings.devicePosture));
441
- this.postureItem.addEventListener('change', this.onPostureChange.bind(this));
442
- this.postureItem.setAttribute(
443
- 'jslog', `${VisualLogging.dropDown().track({change: true}).context('device-posture')}`);
444
- mainToolbar.append(this.postureItem);
445
-
460
+ deviceScaleSpan.replaceWith(...this.deviceScaleItems);
461
+ this.updateDeviceScaleFactorVisibility();
446
462
  return mainToolbar;
447
463
  }
448
464
 
@@ -206,7 +206,6 @@ export class SidebarSingleInsightSet extends UI.Widget.Widget {
206
206
  const activeInsight = this.#data.activeInsight;
207
207
  const agentFocus = AIAssistance.AIContext.AgentFocus.fromInsight(this.#data.parsedTrace, model);
208
208
  const isActiveInsight = activeInsight?.model === model;
209
-
210
209
  const componentClass = INSIGHT_NAME_TO_COMPONENT[insightName as keyof typeof INSIGHT_NAME_TO_COMPONENT];
211
210
  const widgetConfig = {
212
211
  selected: isActiveInsight,
@@ -222,10 +221,19 @@ export class SidebarSingleInsightSet extends UI.Widget.Widget {
222
221
  fieldMetrics,
223
222
  };
224
223
 
224
+ const items = [{componentClass, widgetConfig}];
225
+
225
226
  // clang-format off
226
- return html`<devtools-widget class="insight-component-widget" ?highlight-insight=${isActiveInsight && this.#isActiveInsightHighlighted}
227
- ${widget(componentClass, widgetConfig)}
228
- ></devtools-widget>`;
227
+ // We use `repeat` to force the widget to be recreated if the model
228
+ // changes (e.g. on new trace import). If Lit tries to reuse DOM
229
+ // across different traces, where the ordering of the sidebar
230
+ // insights changes, this causes errors.
231
+ const output = Lit.Directives.repeat(items, data => data.widgetConfig.model, data => {
232
+ return html`<devtools-widget class="insight-component-widget" ?highlight-insight=${isActiveInsight && this.#isActiveInsightHighlighted}
233
+ ${widget(data.componentClass, data.widgetConfig)}
234
+ ></devtools-widget>`;
235
+ });
236
+ return html`${output}`;
229
237
  // clang-format on
230
238
  }
231
239
 
@@ -58,6 +58,10 @@ export class DuplicatedJavaScript extends BaseInsightComponent<DuplicatedJavaScr
58
58
  return Lit.nothing;
59
59
  }
60
60
 
61
+ if (this.model.duplicationGroupedByNodeModules.size === 0) {
62
+ return html`<div class="insight-section">${i18nString(UIStrings.noDuplicatedJavaScript)}</div>`;
63
+ }
64
+
61
65
  const rows: TableDataRow[] =
62
66
  [...this.model.duplicationGroupedByNodeModules.entries()].slice(0, 10).map(([source, data]) => {
63
67
  const scriptToOverlay = new Map();
@@ -73,6 +73,10 @@ export class FontDisplay extends BaseInsightComponent<FontDisplayInsightModel> {
73
73
  return Lit.nothing;
74
74
  }
75
75
 
76
+ if (this.model.fonts.length === 0) {
77
+ return html`<div class="insight-section">${i18nString(UIStrings.noFonts)}</div>`;
78
+ }
79
+
76
80
  const rows = createLimitedRows(this.model.fonts, this);
77
81
 
78
82
  // clang-format off
@@ -58,6 +58,10 @@ export class LegacyJavaScript extends BaseInsightComponent<LegacyJavaScriptInsig
58
58
  return Lit.nothing;
59
59
  }
60
60
 
61
+ if (this.model.legacyJavaScriptResults.size === 0) {
62
+ return html`<div class="insight-section">${i18nString(UIStrings.noLegacyJavaScript)}</div>`;
63
+ }
64
+
61
65
  const rows: TableDataRow[] =
62
66
  [...this.model.legacyJavaScriptResults.entries()].slice(0, 10).map(([script, result]) => {
63
67
  const overlays: Trace.Types.Overlays.Overlay[] = [];
@@ -1,7 +1,7 @@
1
1
  Name: Dependencies sourced from the upstream `chromium` repository
2
2
  URL: Internal
3
3
  Version: N/A
4
- Revision: e388465394450fcfccc5529cf634c8561999f3b8
4
+ Revision: 9f3e9aaccba63bd2ec30334e45e0bfd07ebcc8f1
5
5
  Update Mechanism: Manual (https://crbug.com/428069060)
6
6
  License: BSD-3-Clause
7
7
  License File: LICENSE
@@ -1,7 +1,7 @@
1
1
  Name: Lighthouse
2
2
  Short Name: lighthouse
3
- Version: 13.1.0
4
- Revision: 0248afea9c9443c9fddd73e705256e38e8c6e042
3
+ Version: 13.2.0
4
+ Revision: a160d341f363acf2d99314214a6e0de7d0fead1f
5
5
  Update Mechanism: Manual
6
6
  URL: https://github.com/GoogleChrome/lighthouse
7
7
  License: Apache-2.0