chrome-devtools-frontend 1.0.1674545 → 1.0.1675430

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 (45) hide show
  1. package/.agents/skills/devtools-ux-writing-refactor/SKILL.md +26 -9
  2. package/front_end/core/common/ParsedURL.ts +5 -1
  3. package/front_end/core/common/SettingRegistration.ts +29 -8
  4. package/front_end/core/common/Settings.ts +0 -11
  5. package/front_end/core/root/Runtime.ts +4 -0
  6. package/front_end/core/sdk/TargetManager.ts +18 -0
  7. package/front_end/entrypoints/main/MainImpl.ts +1 -0
  8. package/front_end/foundation/Universe.ts +44 -29
  9. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +15 -5
  10. package/front_end/models/emulation/DeviceModeModel.ts +60 -71
  11. package/front_end/models/emulation/EmulatedDevices.ts +18 -66
  12. package/front_end/models/persistence/AutomaticFileSystemManager.ts +2 -2
  13. package/front_end/models/persistence/IsolatedFileSystemManager.ts +20 -29
  14. package/front_end/models/workspace/FileManager.ts +13 -6
  15. package/front_end/panels/application/WebMCPView.ts +13 -5
  16. package/front_end/panels/application/components/AdsView.ts +24 -1
  17. package/front_end/panels/application/components/adsView.css +27 -21
  18. package/front_end/panels/autofill/AutofillView.ts +12 -12
  19. package/front_end/panels/autofill/autofill-meta.ts +2 -2
  20. package/front_end/panels/elements/ElementsTreeElement.ts +550 -327
  21. package/front_end/panels/elements/ElementsTreeOutline.ts +1 -1
  22. package/front_end/panels/js_timeline/js_timeline-meta.ts +8 -8
  23. package/front_end/panels/layer_viewer/LayerDetailsView.ts +30 -30
  24. package/front_end/panels/layer_viewer/LayerTreeOutline.ts +6 -6
  25. package/front_end/panels/layer_viewer/LayerViewHost.ts +1 -1
  26. package/front_end/panels/layer_viewer/Layers3DView.ts +11 -11
  27. package/front_end/panels/layer_viewer/PaintProfilerView.ts +8 -8
  28. package/front_end/panels/layer_viewer/TransformController.ts +3 -3
  29. package/front_end/panels/layer_viewer/layer_viewer-meta.ts +11 -11
  30. package/front_end/panels/mobile_throttling/ThrottlingManager.ts +1 -58
  31. package/front_end/panels/mobile_throttling/mobile_throttling.ts +0 -10
  32. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +7 -0
  33. package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +1 -2
  34. package/front_end/third_party/chromium/README.chromium +1 -1
  35. package/front_end/ui/comments/CommentAnchorResolver.ts +132 -0
  36. package/front_end/ui/comments/comments.ts +9 -0
  37. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +40 -0
  38. package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -0
  39. package/front_end/ui/settings/SettingUIRegistration.ts +4 -0
  40. package/front_end/ui/visual_logging/Debugging.ts +1 -5
  41. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  42. package/front_end/ui/visual_logging/LoggingConfig.ts +21 -0
  43. package/front_end/ui/visual_logging/visual_logging.ts +9 -0
  44. package/package.json +1 -1
  45. package/front_end/panels/mobile_throttling/MobileThrottlingSelector.ts +0 -92
@@ -124,21 +124,23 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
124
124
  #touchMobile: boolean;
125
125
  #emulationModel: SDK.EmulationModel.EmulationModel|null;
126
126
  #onModelAvailable: (() => void)|null;
127
- #outlineRect?: Rect;
128
127
  #screenOrientationLocked: boolean;
129
128
  readonly #targetManager: SDK.TargetManager.TargetManager;
130
129
  readonly #settings: Common.Settings.Settings;
131
130
  readonly #multitargetNetworkManager: SDK.NetworkManager.MultitargetNetworkManager;
131
+ readonly #fileManager: Workspace.FileManager.FileManager;
132
132
 
133
133
  constructor(
134
134
  targetManager: SDK.TargetManager.TargetManager,
135
135
  settings: Common.Settings.Settings,
136
136
  multitargetNetworkManager: SDK.NetworkManager.MultitargetNetworkManager,
137
+ fileManager: Workspace.FileManager.FileManager,
137
138
  ) {
138
139
  super();
139
140
  this.#targetManager = targetManager;
140
141
  this.#settings = settings;
141
142
  this.#multitargetNetworkManager = multitargetNetworkManager;
143
+ this.#fileManager = fileManager;
142
144
  this.#screenRect = new Rect(0, 0, 1, 1);
143
145
  this.#visiblePageRect = new Rect(0, 0, 1, 1);
144
146
  this.#availableSize = new Geometry.Size(1, 1);
@@ -207,6 +209,8 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
207
209
  Common.Settings.Settings.instance(),
208
210
  // eslint-disable-next-line @devtools/no-instance-of-migrated-singletons
209
211
  SDK.NetworkManager.MultitargetNetworkManager.instance(),
212
+ // eslint-disable-next-line @devtools/no-instance-of-migrated-singletons
213
+ Workspace.FileManager.FileManager.instance(),
210
214
  ));
211
215
  }
212
216
 
@@ -313,8 +317,7 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
313
317
  #updateFitScale(): void {
314
318
  if (this.#type === Type.Device && this.#device && this.#mode) {
315
319
  const orientation = this.#device.orientationByName(this.#mode.orientation);
316
- this.#scaleSetting.set(
317
- this.calculateFitScale(orientation.width, orientation.height, this.currentOutline(), this.currentInsets()));
320
+ this.#scaleSetting.set(this.calculateFitScale(orientation.width, orientation.height, this.currentInsets()));
318
321
  }
319
322
  }
320
323
 
@@ -401,18 +404,6 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
401
404
  return this.#type;
402
405
  }
403
406
 
404
- screenImage(): string {
405
- return (this.#device && this.#mode) ? this.#device.modeImage(this.#mode) : '';
406
- }
407
-
408
- canShowDeviceFrame(): boolean {
409
- return Boolean(this.#device && this.#mode && this.#device.outlineImage(this.#mode));
410
- }
411
-
412
- outlineRect(): Rect|null {
413
- return this.#outlineRect || null;
414
- }
415
-
416
407
  screenRect(): Rect {
417
408
  return this.#screenRect;
418
409
  }
@@ -604,10 +595,6 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
604
595
  return Math.floor(this.#preferredSize.height / (this.#scaleSetting.get() || 1));
605
596
  }
606
597
 
607
- private currentOutline(): Insets {
608
- return new Insets(0, 0, 0, 0);
609
- }
610
-
611
598
  private currentInsets(): Insets {
612
599
  if (this.#type !== Type.Device || !this.#mode) {
613
600
  return new Insets(0, 0, 0, 0);
@@ -660,25 +647,22 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
660
647
  }
661
648
  if (this.#type === Type.Device && this.#device && this.#mode) {
662
649
  const orientation = this.#device.orientationByName(this.#mode.orientation);
663
- const outline = this.currentOutline();
664
650
  const insets = this.currentInsets();
665
- this.#fitScale = this.calculateFitScale(orientation.width, orientation.height, outline, insets);
651
+ this.#fitScale = this.calculateFitScale(orientation.width, orientation.height, insets);
666
652
  if (mobile) {
667
653
  this.#appliedUserAgentType = this.#device.touch() ? UA.MOBILE : UA.MOBILE_NO_TOUCH;
668
654
  } else {
669
655
  this.#appliedUserAgentType = this.#device.touch() ? UA.DESKTOP_TOUCH : UA.DESKTOP;
670
656
  }
671
- this.applyDeviceMetrics(
672
- new Geometry.Size(orientation.width, orientation.height), insets, outline, this.#scaleSetting.get(),
673
- this.#device.deviceScaleFactor, mobile, this.getScreenOrientationType(), resetPageScaleFactor);
657
+ this.applyDeviceMetrics(new Geometry.Size(orientation.width, orientation.height), insets,
658
+ this.#scaleSetting.get(), this.#device.deviceScaleFactor, mobile,
659
+ this.getScreenOrientationType(), resetPageScaleFactor);
674
660
  this.applyUserAgent(this.#device.userAgent, this.#device.userAgentMetadata);
675
661
  this.applyTouch(this.#device.touch(), mobile);
676
662
  } else if (this.#type === Type.None) {
677
663
  this.#fitScale = this.calculateFitScale(this.#availableSize.width, this.#availableSize.height);
678
664
  this.#appliedUserAgentType = UA.DESKTOP;
679
- this.applyDeviceMetrics(
680
- this.#availableSize, new Insets(0, 0, 0, 0), new Insets(0, 0, 0, 0), 1, 0, mobile, null,
681
- resetPageScaleFactor);
665
+ this.applyDeviceMetrics(this.#availableSize, new Insets(0, 0, 0, 0), 1, 0, mobile, null, resetPageScaleFactor);
682
666
  this.applyUserAgent('', null);
683
667
  this.applyTouch(false, false);
684
668
  } else if (this.#type === Type.Responsive) {
@@ -693,12 +677,12 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
693
677
  const defaultDeviceScaleFactor = mobile ? defaultMobileScaleFactor : 0;
694
678
  this.#fitScale = this.calculateFitScale(this.#widthSetting.get(), this.#heightSetting.get());
695
679
  this.#appliedUserAgentType = this.#uaSetting.get();
696
- this.applyDeviceMetrics(
697
- new Geometry.Size(screenWidth, screenHeight), new Insets(0, 0, 0, 0), new Insets(0, 0, 0, 0),
698
- this.#scaleSetting.get(), this.#deviceScaleFactorSetting.get() || defaultDeviceScaleFactor, mobile,
699
- screenHeight >= screenWidth ? Protocol.Emulation.ScreenOrientationType.PortraitPrimary :
700
- Protocol.Emulation.ScreenOrientationType.LandscapePrimary,
701
- resetPageScaleFactor);
680
+ this.applyDeviceMetrics(new Geometry.Size(screenWidth, screenHeight), new Insets(0, 0, 0, 0),
681
+ this.#scaleSetting.get(),
682
+ this.#deviceScaleFactorSetting.get() || defaultDeviceScaleFactor, mobile,
683
+ screenHeight >= screenWidth ? Protocol.Emulation.ScreenOrientationType.PortraitPrimary :
684
+ Protocol.Emulation.ScreenOrientationType.LandscapePrimary,
685
+ resetPageScaleFactor);
702
686
  this.applyUserAgent(
703
687
  mobile ? DeviceModeModel.defaultMobileUserAgent() : '',
704
688
  mobile ? DeviceModeModel.defaultMobileUserAgentMetadata() : null);
@@ -714,14 +698,11 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
714
698
  this.dispatchEventToListeners(Events.UPDATED);
715
699
  }
716
700
 
717
- private calculateFitScale(screenWidth: number, screenHeight: number, outline?: Insets, insets?: Insets): number {
718
- const outlineWidth = outline ? outline.left + outline.right : 0;
719
- const outlineHeight = outline ? outline.top + outline.bottom : 0;
701
+ private calculateFitScale(screenWidth: number, screenHeight: number, insets?: Insets): number {
720
702
  const insetsWidth = insets ? insets.left + insets.right : 0;
721
703
  const insetsHeight = insets ? insets.top + insets.bottom : 0;
722
- let scale = Math.min(
723
- screenWidth ? this.#preferredSize.width / (screenWidth + outlineWidth) : 1,
724
- screenHeight ? this.#preferredSize.height / (screenHeight + outlineHeight) : 1);
704
+ let scale = Math.min(screenWidth ? this.#preferredSize.width / screenWidth : 1,
705
+ screenHeight ? this.#preferredSize.height / screenHeight : 1);
725
706
  scale = Math.min(Math.floor(scale * 100), 100);
726
707
 
727
708
  let sharpScale = scale;
@@ -754,10 +735,9 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
754
735
  this.#multitargetNetworkManager.setUserAgentOverride(userAgent, userAgent ? userAgentMetadata : null);
755
736
  }
756
737
 
757
- private applyDeviceMetrics(
758
- screenSize: Geometry.Size, insets: Insets, outline: Insets, scale: number, deviceScaleFactor: number,
759
- mobile: boolean, screenOrientation: Protocol.Emulation.ScreenOrientationType|null,
760
- resetPageScaleFactor: boolean): void {
738
+ private applyDeviceMetrics(screenSize: Geometry.Size, insets: Insets, scale: number, deviceScaleFactor: number,
739
+ mobile: boolean, screenOrientation: Protocol.Emulation.ScreenOrientationType|null,
740
+ resetPageScaleFactor: boolean): void {
761
741
  screenSize.width = Math.max(1, Math.floor(screenSize.width));
762
742
  screenSize.height = Math.max(1, Math.floor(screenSize.height));
763
743
 
@@ -771,12 +751,8 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
771
751
 
772
752
  this.#appliedDeviceSize = screenSize;
773
753
  this.#appliedDeviceScaleFactor = deviceScaleFactor || window.devicePixelRatio;
774
- this.#screenRect = new Rect(
775
- Math.max(0, (this.#availableSize.width - screenSize.width * scale) / 2), outline.top * scale,
776
- screenSize.width * scale, screenSize.height * scale);
777
- this.#outlineRect = new Rect(
778
- this.#screenRect.left - outline.left * scale, 0, (outline.left + screenSize.width + outline.right) * scale,
779
- (outline.top + screenSize.height + outline.bottom) * scale);
754
+ this.#screenRect = new Rect(Math.max(0, (this.#availableSize.width - screenSize.width * scale) / 2), 0,
755
+ screenSize.width * scale, screenSize.height * scale);
780
756
  this.#visiblePageRect = new Rect(
781
757
  positionX * scale, positionY * scale,
782
758
  Math.min(pageWidth * scale, this.#availableSize.width - this.#screenRect.left - positionX * scale),
@@ -898,29 +874,21 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
898
874
  pageImage.src = 'data:image/png;base64,' + screenshot;
899
875
  pageImage.onload = async () => {
900
876
  const scale = pageImage.naturalWidth / this.screenRect().width;
901
- const outlineRectFromModel = this.outlineRect();
902
- if (!outlineRectFromModel) {
903
- throw new Error('Unable to take screenshot: no outlineRect available.');
904
- }
905
- const outlineRect = outlineRectFromModel.scale(scale);
906
877
  const screenRect = this.screenRect().scale(scale);
907
878
  const visiblePageRect = this.visiblePageRect().scale(scale);
908
- const contentLeft = screenRect.left + visiblePageRect.left - outlineRect.left;
909
- const contentTop = screenRect.top + visiblePageRect.top - outlineRect.top;
879
+ const contentLeft = visiblePageRect.left;
880
+ const contentTop = visiblePageRect.top;
910
881
 
911
- const canvas = new OffscreenCanvas(Math.floor(outlineRect.width),
882
+ const canvas = new OffscreenCanvas(Math.floor(screenRect.width),
912
883
  // Cap the height to not hit the GPU limit.
913
884
  // https://crbug.com/1260828
914
- Math.min((1 << 14), Math.floor(outlineRect.height)));
885
+ Math.min((1 << 14), Math.floor(screenRect.height)));
915
886
  const ctx = canvas.getContext('2d', {willReadFrequently: true});
916
887
  if (!ctx) {
917
888
  throw new Error('Could not get 2d context from canvas.');
918
889
  }
919
890
  ctx.imageSmoothingEnabled = false;
920
891
 
921
- if (this.screenImage()) {
922
- await this.paintImage(ctx, this.screenImage(), screenRect.relativeTo(outlineRect));
923
- }
924
892
  ctx.drawImage(pageImage, Math.floor(contentLeft), Math.floor(contentTop));
925
893
  void this.saveScreenshot(canvas);
926
894
  };
@@ -976,17 +944,41 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
976
944
 
977
945
  private async saveScreenshot(canvas: OffscreenCanvas): Promise<void> {
978
946
  const url = this.inspectedURL();
979
- let fileName = '';
947
+ let baseName = '';
980
948
  if (url) {
981
- const withoutFragment = Platform.StringUtilities.removeURLFragment(url);
982
- fileName = Platform.StringUtilities.trimURL(withoutFragment);
949
+ const parsedURL = Common.ParsedURL.ParsedURL.fromString(url);
950
+ if (parsedURL) {
951
+ const host = parsedURL.host;
952
+ const path = parsedURL.path.replace(/^\/+/, '').replace(/\/+$/, '');
953
+ baseName = host;
954
+ if (path) {
955
+ baseName += '-' + path.replaceAll('/', '-');
956
+ }
957
+ baseName = baseName.replace(/[^a-z0-9._-]/gi, '_');
958
+ }
983
959
  }
984
960
 
961
+ if (!baseName) {
962
+ baseName = 'screenshot';
963
+ }
964
+
965
+ let suffix = '';
985
966
  const device = this.device();
986
967
  if (device && this.type() === Type.Device) {
987
- fileName += `(${device.title})`;
968
+ suffix += `(${device.title})`;
969
+ }
970
+ suffix += '.png';
971
+
972
+ // The Windows save dialog / Chrome wrapper limits the suggested filename
973
+ // to 63 characters (due to a 64-byte null-terminated buffer).
974
+ // Capping the total filename length at 63 avoids truncation of the extension.
975
+ const maxBaseNameLength = Math.max(0, 63 - suffix.length);
976
+ baseName = Platform.StringUtilities.truncateToCodeUnitLength(baseName, maxBaseNameLength);
977
+
978
+ let fileName = baseName + suffix;
979
+ if (fileName.length > 63) {
980
+ fileName = Platform.StringUtilities.truncateToCodeUnitLength(fileName, 59) + '.png';
988
981
  }
989
- fileName += '.png';
990
982
  const blob = await canvas.convertToBlob({type: 'image/png'});
991
983
  const dataUrl = await new Promise<string>((resolve, reject) => {
992
984
  const reader = new FileReader();
@@ -996,11 +988,8 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
996
988
  });
997
989
  const base64 = dataUrl.slice(dataUrl.indexOf(',') + 1);
998
990
  const contentData = new TextUtils.ContentData.ContentData(base64, /* isBase64=*/ true, 'image/png');
999
- // eslint-disable-next-line @devtools/no-instance-of-migrated-singletons
1000
- await Workspace.FileManager.FileManager.instance().save(fileName as Platform.DevToolsPath.RawPathString,
1001
- contentData, /* forceSaveAs=*/ true);
1002
- // eslint-disable-next-line @devtools/no-instance-of-migrated-singletons
1003
- Workspace.FileManager.FileManager.instance().close(fileName as Platform.DevToolsPath.RawPathString);
991
+ await this.#fileManager.save(fileName as Platform.DevToolsPath.RawPathString, contentData, /* forceSaveAs=*/ true);
992
+ this.#fileManager.close(fileName as Platform.DevToolsPath.RawPathString);
1004
993
  }
1005
994
 
1006
995
  private applyTouch(touchEnabled: boolean, mobile: boolean): void {
@@ -48,12 +48,6 @@ const str_ = i18n.i18n.registerUIStrings('models/emulation/EmulatedDevices.ts',
48
48
  const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
49
49
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
50
50
 
51
- export function computeRelativeImageURL(cssURLValue: string): string {
52
- return cssURLValue.replace(/@url\(([^\)]*?)\)/g, (_match: string, url: string) => {
53
- return new URL(`../../emulated_devices/${url}`, import.meta.url).toString();
54
- });
55
- }
56
-
57
51
  export class EmulatedDevice {
58
52
  title: string;
59
53
  type: Type;
@@ -75,8 +69,8 @@ export class EmulatedDevice {
75
69
  constructor() {
76
70
  this.title = '';
77
71
  this.type = Type.Unknown;
78
- this.vertical = {width: 0, height: 0, outlineInsets: null, outlineImage: null, hinge: null};
79
- this.horizontal = {width: 0, height: 0, outlineInsets: null, outlineImage: null, hinge: null};
72
+ this.vertical = {width: 0, height: 0, hinge: null};
73
+ this.horizontal = {width: 0, height: 0, hinge: null};
80
74
  this.deviceScaleFactor = 1;
81
75
  this.capabilities = [Capability.TOUCH, Capability.MOBILE];
82
76
  this.userAgent = '';
@@ -85,8 +79,8 @@ export class EmulatedDevice {
85
79
 
86
80
  this.isDualScreen = false;
87
81
  this.isFoldableScreen = false;
88
- this.verticalSpanned = {width: 0, height: 0, outlineInsets: null, outlineImage: null, hinge: null};
89
- this.horizontalSpanned = {width: 0, height: 0, outlineInsets: null, outlineImage: null, hinge: null};
82
+ this.verticalSpanned = {width: 0, height: 0, hinge: null};
83
+ this.horizontalSpanned = {width: 0, height: 0, hinge: null};
90
84
 
91
85
  this.#show = Show.Default;
92
86
  this.#showByDefault = true;
@@ -202,15 +196,6 @@ export class EmulatedDevice {
202
196
  throw new Error('Emulated device has wrong height: ' + result.height);
203
197
  }
204
198
 
205
- const outlineInsets = parseValue(json['outline'], 'insets', 'object', null);
206
- if (outlineInsets) {
207
- result.outlineInsets = parseInsets(outlineInsets);
208
- if (result.outlineInsets.left < 0 || result.outlineInsets.top < 0) {
209
- throw new Error('Emulated device has wrong outline insets');
210
- }
211
- result.outlineImage = (parseValue(json['outline'], 'image', 'string') as string);
212
- }
213
-
214
199
  if (json['hinge']) {
215
200
  result.hinge = parseHinge(parseValue(json, 'hinge', 'object', undefined));
216
201
  }
@@ -282,9 +267,10 @@ export class EmulatedDevice {
282
267
  if (mode.insets.top < 0 || mode.insets.left < 0 || mode.insets.right < 0 || mode.insets.bottom < 0 ||
283
268
  mode.insets.top + mode.insets.bottom > orientation.height ||
284
269
  mode.insets.left + mode.insets.right > orientation.width) {
285
- throw new Error('Emulated device mode \'' + mode.title + '\'has wrong mode insets');
270
+ throw new Error(
271
+ 'Emulated device mode \'' + mode.title + '\'has wrong mode insets',
272
+ );
286
273
  }
287
- mode.image = (parseValue(modes[i], 'image', 'string', null) as string);
288
274
  const safeAreaInsets = parseValue(modes[i], 'safe-area-insets', 'object', null);
289
275
  if (safeAreaInsets) {
290
276
  mode.safeAreaInsets = parseInsets(safeAreaInsets);
@@ -419,7 +405,6 @@ export class EmulatedDevice {
419
405
  right: this.modes[i].insets.right,
420
406
  bottom: this.modes[i].insets.bottom,
421
407
  },
422
- image: this.modes[i].image || undefined,
423
408
  };
424
409
  const safeAreaInsets = this.modes[i].safeAreaInsets;
425
410
  if (safeAreaInsets) {
@@ -469,17 +454,7 @@ export class EmulatedDevice {
469
454
  const json = {} as any;
470
455
  json['width'] = orientation.width;
471
456
  json['height'] = orientation.height;
472
- if (orientation.outlineInsets) {
473
- json.outline = {
474
- insets: {
475
- left: orientation.outlineInsets.left,
476
- top: orientation.outlineInsets.top,
477
- right: orientation.outlineInsets.right,
478
- bottom: orientation.outlineInsets.bottom,
479
- },
480
- image: orientation.outlineImage,
481
- } as {image: string | null, insets: {left: number, right: number, top: number, bottom: number}};
482
- }
457
+
483
458
  if (orientation.hinge) {
484
459
  json.hinge = {
485
460
  width: orientation.hinge.width,
@@ -515,21 +490,6 @@ export class EmulatedDevice {
515
490
  return json;
516
491
  }
517
492
 
518
- modeImage(mode: Mode): string {
519
- if (!mode.image) {
520
- return '';
521
- }
522
- return computeRelativeImageURL(mode.image);
523
- }
524
-
525
- outlineImage(mode: Mode): string {
526
- const orientation = this.orientationByName(mode.orientation);
527
- if (!orientation.outlineImage) {
528
- return '';
529
- }
530
- return computeRelativeImageURL(orientation.outlineImage);
531
- }
532
-
533
493
  orientationByName(name: string): Orientation {
534
494
  switch (name) {
535
495
  case VerticalSpanned:
@@ -688,8 +648,16 @@ export class EmulatedDevicesList extends Common.ObjectWrapper.ObjectWrapper<Even
688
648
  if (device) {
689
649
  result.add(device);
690
650
  if (!device.modes.length) {
691
- device.modes.push({title: '', orientation: Horizontal, insets: new Insets(0, 0, 0, 0), image: null});
692
- device.modes.push({title: '', orientation: Vertical, insets: new Insets(0, 0, 0, 0), image: null});
651
+ device.modes.push({
652
+ title: '',
653
+ orientation: Horizontal,
654
+ insets: new Insets(0, 0, 0, 0),
655
+ });
656
+ device.modes.push({
657
+ title: '',
658
+ orientation: Vertical,
659
+ insets: new Insets(0, 0, 0, 0),
660
+ });
693
661
  }
694
662
  } else {
695
663
  success = false;
@@ -769,7 +737,6 @@ export interface Mode {
769
737
  title: string;
770
738
  orientation: string;
771
739
  insets: Insets;
772
- image: string|null;
773
740
  safeAreaInsets?: Insets;
774
741
  cutout?: Cutout;
775
742
  }
@@ -791,14 +758,11 @@ export type Cutout = BaseCutout&({shape: CutoutShape.RECTANGLE}|{shape: CutoutSh
791
758
  export interface Orientation {
792
759
  width: number;
793
760
  height: number;
794
- outlineInsets: Insets|null;
795
- outlineImage: string|null;
796
761
  hinge: SDK.OverlayModel.Hinge|null;
797
762
  }
798
763
  export interface JSONMode {
799
764
  title: string;
800
765
  orientation: string;
801
- image?: string;
802
766
  insets: {
803
767
  left: number,
804
768
  right: number,
@@ -2136,10 +2100,6 @@ const emulatedDevices = [
2136
2100
  'title': 'Nest Hub Max',
2137
2101
  'screen': {
2138
2102
  'horizontal': {
2139
- 'outline': {
2140
- 'image': '@url(optimized/google-nest-hub-max-horizontal.avif)',
2141
- 'insets': {'left': 92, 'top': 96, 'right': 91, 'bottom': 248},
2142
- },
2143
2103
  'width': 1280,
2144
2104
  'height': 800,
2145
2105
  },
@@ -2249,19 +2209,11 @@ const emulatedDevices = [
2249
2209
  'title': 'Moto G4',
2250
2210
  'screen': {
2251
2211
  'horizontal': {
2252
- 'outline': {
2253
- 'image': '@url(optimized/MotoG4-landscape.avif)',
2254
- 'insets': {'left': 91, 'top': 30, 'right': 74, 'bottom': 30},
2255
- },
2256
2212
  'width': 640,
2257
2213
  'height': 360,
2258
2214
  },
2259
2215
  'device-pixel-ratio': 3,
2260
2216
  'vertical': {
2261
- 'outline': {
2262
- 'image': '@url(optimized/MotoG4-portrait.avif)',
2263
- 'insets': {'left': 30, 'top': 91, 'right': 30, 'bottom': 74},
2264
- },
2265
2217
  'width': 360,
2266
2218
  'height': 640,
2267
2219
  },
@@ -113,12 +113,12 @@ export class AutomaticFileSystemManager extends Common.ObjectWrapper.ObjectWrapp
113
113
  */
114
114
  static removeInstance(): void {
115
115
  if (Root.DevToolsContext.globalInstance().has(AutomaticFileSystemManager)) {
116
- Root.DevToolsContext.globalInstance().get(AutomaticFileSystemManager).#dispose();
116
+ Root.DevToolsContext.globalInstance().get(AutomaticFileSystemManager).dispose();
117
117
  Root.DevToolsContext.globalInstance().delete(AutomaticFileSystemManager);
118
118
  }
119
119
  }
120
120
 
121
- #dispose(): void {
121
+ dispose(): void {
122
122
  this.#inspectorFrontendHost.events.removeEventListener(
123
123
  Host.InspectorFrontendHostAPI.Events.FileSystemRemoved, this.#fileSystemRemoved, this);
124
124
  this.#projectSettingsModel.removeEventListener(
@@ -35,6 +35,7 @@ export class IsolatedFileSystemManager extends Common.ObjectWrapper.ObjectWrappe
35
35
  private readonly fileSystemsLoadedPromise: Promise<IsolatedFileSystem[]>;
36
36
  readonly #settings: Common.Settings.Settings;
37
37
  readonly #console: Common.Console.Console;
38
+ readonly #eventDescriptors: Common.EventTarget.EventDescriptor[];
38
39
  constructor(settings: Common.Settings.Settings, console: Common.Console.Console) {
39
40
  super();
40
41
  this.#settings = settings;
@@ -44,20 +45,22 @@ export class IsolatedFileSystemManager extends Common.ObjectWrapper.ObjectWrappe
44
45
  this.callbacks = new Map();
45
46
  this.progresses = new Map();
46
47
 
47
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
48
- Host.InspectorFrontendHostAPI.Events.FileSystemRemoved, this.onFileSystemRemoved, this);
49
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
50
- Host.InspectorFrontendHostAPI.Events.FileSystemAdded, this.onFileSystemAdded, this);
51
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
52
- Host.InspectorFrontendHostAPI.Events.FileSystemFilesChangedAddedRemoved, this.onFileSystemFilesChanged, this);
53
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
54
- Host.InspectorFrontendHostAPI.Events.IndexingTotalWorkCalculated, this.onIndexingTotalWorkCalculated, this);
55
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
56
- Host.InspectorFrontendHostAPI.Events.IndexingWorked, this.onIndexingWorked, this);
57
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
58
- Host.InspectorFrontendHostAPI.Events.IndexingDone, this.onIndexingDone, this);
59
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
60
- Host.InspectorFrontendHostAPI.Events.SearchCompleted, this.onSearchCompleted, this);
48
+ this.#eventDescriptors = [
49
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
50
+ Host.InspectorFrontendHostAPI.Events.FileSystemRemoved, this.onFileSystemRemoved, this),
51
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
52
+ Host.InspectorFrontendHostAPI.Events.FileSystemAdded, this.onFileSystemAdded, this),
53
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
54
+ Host.InspectorFrontendHostAPI.Events.FileSystemFilesChangedAddedRemoved, this.onFileSystemFilesChanged, this),
55
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
56
+ Host.InspectorFrontendHostAPI.Events.IndexingTotalWorkCalculated, this.onIndexingTotalWorkCalculated, this),
57
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
58
+ Host.InspectorFrontendHostAPI.Events.IndexingWorked, this.onIndexingWorked, this),
59
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
60
+ Host.InspectorFrontendHostAPI.Events.IndexingDone, this.onIndexingDone, this),
61
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
62
+ Host.InspectorFrontendHostAPI.Events.SearchCompleted, this.onSearchCompleted, this),
63
+ ];
61
64
 
62
65
  // Initialize exclude pattern settings
63
66
  const defaultCommonExcludedFolders = [
@@ -101,20 +104,7 @@ export class IsolatedFileSystemManager extends Common.ObjectWrapper.ObjectWrappe
101
104
 
102
105
  // TODO(crbug.com/542394587): Should be `Symbol.dispsoe`
103
106
  dispose(): void {
104
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.removeEventListener(
105
- Host.InspectorFrontendHostAPI.Events.FileSystemRemoved, this.onFileSystemRemoved, this);
106
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.removeEventListener(
107
- Host.InspectorFrontendHostAPI.Events.FileSystemAdded, this.onFileSystemAdded, this);
108
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.removeEventListener(
109
- Host.InspectorFrontendHostAPI.Events.FileSystemFilesChangedAddedRemoved, this.onFileSystemFilesChanged, this);
110
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.removeEventListener(
111
- Host.InspectorFrontendHostAPI.Events.IndexingTotalWorkCalculated, this.onIndexingTotalWorkCalculated, this);
112
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.removeEventListener(
113
- Host.InspectorFrontendHostAPI.Events.IndexingWorked, this.onIndexingWorked, this);
114
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.removeEventListener(
115
- Host.InspectorFrontendHostAPI.Events.IndexingDone, this.onIndexingDone, this);
116
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.removeEventListener(
117
- Host.InspectorFrontendHostAPI.Events.SearchCompleted, this.onSearchCompleted, this);
107
+ Common.EventTarget.removeEventListeners(this.#eventDescriptors);
118
108
  }
119
109
 
120
110
  static instance(opts: {
@@ -141,8 +131,9 @@ export class IsolatedFileSystemManager extends Common.ObjectWrapper.ObjectWrappe
141
131
 
142
132
  private requestFileSystems(): Promise<IsolatedFileSystem[]> {
143
133
  const {resolve, promise} = Promise.withResolvers<IsolatedFileSystem[]>();
144
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
134
+ const descriptor = Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
145
135
  Host.InspectorFrontendHostAPI.Events.FileSystemsLoaded, onFileSystemsLoaded, this);
136
+ this.#eventDescriptors.push(descriptor);
146
137
  Host.InspectorFrontendHost.InspectorFrontendHostInstance.requestFileSystems();
147
138
  return promise;
148
139
 
@@ -15,14 +15,21 @@ export interface SaveCallbackParam {
15
15
  export class FileManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
16
16
  readonly #saveCallbacks = new Map<
17
17
  Platform.DevToolsPath.RawPathString|Platform.DevToolsPath.UrlString, (arg0: SaveCallbackParam|null) => void>();
18
+ readonly #eventDescriptors: Common.EventTarget.EventDescriptor[];
18
19
  constructor() {
19
20
  super();
20
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
21
- Host.InspectorFrontendHostAPI.Events.SavedURL, this.savedURL, this);
22
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
23
- Host.InspectorFrontendHostAPI.Events.CanceledSaveURL, this.#canceledSavedURL, this);
24
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
25
- Host.InspectorFrontendHostAPI.Events.AppendedToURL, this.appendedToURL, this);
21
+ this.#eventDescriptors = [
22
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
23
+ Host.InspectorFrontendHostAPI.Events.SavedURL, this.savedURL, this),
24
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
25
+ Host.InspectorFrontendHostAPI.Events.CanceledSaveURL, this.#canceledSavedURL, this),
26
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(
27
+ Host.InspectorFrontendHostAPI.Events.AppendedToURL, this.appendedToURL, this),
28
+ ];
29
+ }
30
+
31
+ dispose(): void {
32
+ Common.EventTarget.removeEventListeners(this.#eventDescriptors);
26
33
  }
27
34
 
28
35
  static instance(opts: {forceNew: boolean|null} = {forceNew: null}): FileManager {
@@ -198,6 +198,14 @@ const UIStrings = {
198
198
  * @description Label for a list of tool flags or attributes
199
199
  */
200
200
  flags: 'Flags',
201
+ /**
202
+ * @description Text for the label of the tool description
203
+ */
204
+ description: 'Description',
205
+ /**
206
+ * @description Text for the label of the tool origin
207
+ */
208
+ origin: 'Origin',
201
209
  } as const;
202
210
  const str_ = i18n.i18n.registerUIStrings('panels/application/WebMCPView.ts', UIStrings);
203
211
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -714,7 +722,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
714
722
  } as ProtocolMonitor.JSONEditor.Command,
715
723
  });
716
724
  }
717
- }}>Run tool</devtools-button>
725
+ }}>${i18nString(UIStrings.runTool)}</devtools-button>
718
726
  ` : nothing}
719
727
  </div>
720
728
  </devtools-split-view>
@@ -1124,9 +1132,9 @@ const TOOL_DETAILS_VIEW = (input: ToolDetailsViewInput, output: undefined, targe
1124
1132
  render(html`
1125
1133
  <style>${webMCPViewStyles}</style>
1126
1134
  <div class="tool-details-grid">
1127
- <div class="label">Name</div>
1135
+ <div class="label">${i18nString(UIStrings.name)}</div>
1128
1136
  <div class="value source-code">${tool.name}</div>
1129
- <div class="label">Description</div>
1137
+ <div class="label">${i18nString(UIStrings.description)}</div>
1130
1138
  <div class="value">${tool.description}</div>
1131
1139
  ${flags.length > 0 ? html`
1132
1140
  <div class="label">${i18nString(UIStrings.flags)}</div>
@@ -1137,7 +1145,7 @@ const TOOL_DETAILS_VIEW = (input: ToolDetailsViewInput, output: undefined, targe
1137
1145
  <div class="value">${Components.Linkifier.Linkifier.linkifyRevealable(tool.frame, tool.frame.displayName())}</div>
1138
1146
  ` : nothing}
1139
1147
  ${origin instanceof SDK.DOMModel.DOMNode ? html`
1140
- <div class="label">Origin</div>
1148
+ <div class="label">${i18nString(UIStrings.origin)}</div>
1141
1149
  <div class="value tool-origin-container">
1142
1150
  <span
1143
1151
  class="node-text-container source-code tool-origin-node"
@@ -1161,7 +1169,7 @@ const TOOL_DETAILS_VIEW = (input: ToolDetailsViewInput, output: undefined, targe
1161
1169
  @click=${() => input.revealNode(origin)}
1162
1170
  ></devtools-button>
1163
1171
  </div>` : origin ? html`
1164
- <div class="label">Origin</div>
1172
+ <div class="label">${i18nString(UIStrings.origin)}</div>
1165
1173
  <div class="value stack-trace">
1166
1174
  ${widget(Components.JSPresentationUtils.StackTracePreviewContent,
1167
1175
  {stackTrace: origin, options: { expandable: true}})}