chrome-devtools-frontend 1.0.1672557 → 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 (177) 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 +30 -34
  4. package/front_end/core/common/Settings.ts +4 -64
  5. package/front_end/core/host/UserMetrics.ts +127 -117
  6. package/front_end/core/protocol_client/PuppeteerDevToolsConnection.ts +42 -9
  7. package/front_end/core/root/Runtime.ts +14 -0
  8. package/front_end/core/sdk/NetworkManager.ts +0 -35
  9. package/front_end/core/sdk/SourceMap.ts +1 -19
  10. package/front_end/core/sdk/SourceMapManager.ts +75 -48
  11. package/front_end/core/sdk/SourceMapScopesInfo.ts +0 -62
  12. package/front_end/core/sdk/TargetManager.ts +18 -0
  13. package/front_end/devtools_compatibility.js +1 -1
  14. package/front_end/entrypoints/main/MainImpl.ts +1 -0
  15. package/front_end/foundation/Universe.ts +44 -29
  16. package/front_end/generated/InspectorBackendCommands.ts +4 -3
  17. package/front_end/generated/SupportedCSSProperties.ts +16 -1
  18. package/front_end/generated/protocol-mapping.d.ts +8 -0
  19. package/front_end/generated/protocol-proxy-api.d.ts +6 -0
  20. package/front_end/generated/protocol.ts +16 -2
  21. package/front_end/models/ai_assistance/AiSetting.ts +66 -3
  22. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +15 -5
  23. package/front_end/models/bindings/CompilerScriptMapping.ts +1 -1
  24. package/front_end/models/emulation/DeviceModeModel.ts +82 -102
  25. package/front_end/models/emulation/EmulatedDevices.ts +18 -66
  26. package/front_end/models/javascript_metadata/NativeFunctions.js +4 -4
  27. package/front_end/models/persistence/AutomaticFileSystemManager.ts +2 -2
  28. package/front_end/models/persistence/IsolatedFileSystemManager.ts +20 -29
  29. package/front_end/models/trace/ModelImpl.ts +5 -0
  30. package/front_end/models/trace/Processor.ts +5 -0
  31. package/front_end/models/trace/handlers/LayoutShiftsHandler.ts +7 -1
  32. package/front_end/models/trace/handlers/MetaHandler.ts +8 -4
  33. package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +11 -0
  34. package/front_end/models/workspace/FileManager.ts +13 -6
  35. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +11 -10
  36. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +3 -45
  37. package/front_end/panels/application/BackgroundServiceView.ts +42 -40
  38. package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -0
  39. package/front_end/panels/application/WebMCPView.ts +13 -5
  40. package/front_end/panels/application/components/AdsView.ts +24 -1
  41. package/front_end/panels/application/components/adsView.css +27 -21
  42. package/front_end/panels/autofill/AutofillView.ts +12 -12
  43. package/front_end/panels/autofill/autofill-meta.ts +2 -2
  44. package/front_end/panels/common/ExtensionServer.ts +7 -1
  45. package/front_end/panels/common/common.ts +0 -1
  46. package/front_end/panels/console/ConsoleInsightTeaser.ts +7 -6
  47. package/front_end/panels/console/ConsoleViewMessage.ts +1 -1
  48. package/front_end/panels/elements/ClassesPaneWidget.ts +2 -2
  49. package/front_end/panels/elements/ElementsTreeElement.ts +602 -327
  50. package/front_end/panels/elements/ElementsTreeOutline.ts +1 -1
  51. package/front_end/panels/elements/StylesSidebarPane.ts +1 -1
  52. package/front_end/panels/elements/components/AdornerManager.ts +1 -0
  53. package/front_end/panels/emulation/AdvancedApp.ts +3 -3
  54. package/front_end/panels/emulation/DeviceModeToolbar.ts +2 -11
  55. package/front_end/panels/emulation/DeviceModeView.ts +234 -75
  56. package/front_end/panels/emulation/InspectedPagePlaceholder.ts +1 -1
  57. package/front_end/panels/emulation/deviceModeView.css +4 -21
  58. package/front_end/panels/emulation/emulation-meta.ts +4 -30
  59. package/front_end/panels/emulation/emulation.ts +0 -3
  60. package/front_end/panels/explain/components/ConsoleInsight.ts +11 -7
  61. package/front_end/panels/js_timeline/js_timeline-meta.ts +8 -8
  62. package/front_end/panels/layer_viewer/LayerDetailsView.ts +30 -30
  63. package/front_end/panels/layer_viewer/LayerTreeOutline.ts +6 -6
  64. package/front_end/panels/layer_viewer/LayerViewHost.ts +1 -1
  65. package/front_end/panels/layer_viewer/Layers3DView.ts +11 -11
  66. package/front_end/panels/layer_viewer/PaintProfilerView.ts +8 -8
  67. package/front_end/panels/layer_viewer/TransformController.ts +3 -3
  68. package/front_end/panels/layer_viewer/layer_viewer-meta.ts +11 -11
  69. package/front_end/panels/layers/LayersPanel.ts +2 -2
  70. package/front_end/panels/layers/layers-meta.ts +2 -2
  71. package/front_end/panels/lighthouse/LighthouseController.ts +3 -7
  72. package/front_end/panels/mobile_throttling/CPUThrottlingSelector.ts +313 -0
  73. package/front_end/panels/mobile_throttling/NetworkPanelIndicator.ts +0 -10
  74. package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +21 -10
  75. package/front_end/panels/mobile_throttling/ThrottlingManager.ts +1 -58
  76. package/front_end/panels/mobile_throttling/mobile_throttling.ts +2 -9
  77. package/front_end/panels/network/NetworkConfigView.ts +1 -71
  78. package/front_end/panels/network/networkConfigView.css +1 -2
  79. package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +3 -3
  80. package/front_end/panels/profiler/HeapDetachedElementsView.ts +5 -5
  81. package/front_end/panels/profiler/HeapProfileView.ts +32 -32
  82. package/front_end/panels/profiler/HeapProfilerPanel.ts +2 -2
  83. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +33 -37
  84. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +26 -27
  85. package/front_end/panels/profiler/HeapSnapshotView.ts +48 -48
  86. package/front_end/panels/profiler/IsolateSelector.ts +10 -10
  87. package/front_end/panels/profiler/ModuleUIStrings.ts +25 -25
  88. package/front_end/panels/profiler/ProfileLauncherView.ts +6 -6
  89. package/front_end/panels/profiler/ProfilesPanel.ts +6 -6
  90. package/front_end/panels/profiler/WritableProfileHeader.ts +6 -6
  91. package/front_end/panels/profiler/profiler-meta.ts +7 -7
  92. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +7 -0
  93. package/front_end/panels/recorder/RecorderPanel.ts +1 -1
  94. package/front_end/panels/settings/AISettingsTab.ts +27 -23
  95. package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +1 -2
  96. package/front_end/panels/timeline/TimelineFlameChartNetworkDataProvider.ts +12 -17
  97. package/front_end/panels/timeline/TimelinePanel.ts +20 -35
  98. package/front_end/panels/timeline/components/LiveMetricsView.ts +27 -6
  99. package/front_end/panels/timeline/components/NetworkTrackWidget.ts +1 -1
  100. package/front_end/panels/timeline/components/components.ts +0 -4
  101. package/front_end/panels/timeline/components/liveMetricsView.css +7 -0
  102. package/front_end/third_party/chromium/README.chromium +1 -1
  103. package/front_end/third_party/source-map-scopes-codec/package/CONTRIBUTING.md +0 -0
  104. package/front_end/third_party/source-map-scopes-codec/package/LICENSE +0 -0
  105. package/front_end/third_party/source-map-scopes-codec/package/README.md +0 -0
  106. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts +0 -0
  107. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts.map +1 -1
  108. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts +0 -0
  109. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts.map +0 -0
  110. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts +0 -0
  111. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts.map +0 -0
  112. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts +0 -0
  113. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts.map +0 -0
  114. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts +0 -0
  115. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts.map +0 -0
  116. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts +0 -0
  117. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts.map +0 -0
  118. package/front_end/third_party/source-map-scopes-codec/package/deno.json +1 -1
  119. package/front_end/third_party/source-map-scopes-codec/package/package.json +1 -1
  120. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js +2 -0
  121. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js.map +1 -1
  122. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.ts +2 -0
  123. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js +0 -0
  124. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js.map +0 -0
  125. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.ts +0 -0
  126. package/front_end/third_party/source-map-scopes-codec/package/src/codec.js +0 -0
  127. package/front_end/third_party/source-map-scopes-codec/package/src/codec.js.map +0 -0
  128. package/front_end/third_party/source-map-scopes-codec/package/src/codec.ts +0 -0
  129. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +0 -0
  130. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js.map +0 -0
  131. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.ts +0 -0
  132. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js +0 -0
  133. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js.map +0 -0
  134. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.ts +0 -0
  135. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +0 -0
  136. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js.map +0 -0
  137. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.ts +0 -0
  138. package/front_end/third_party/source-map-scopes-codec/package/src/mod.js +0 -0
  139. package/front_end/third_party/source-map-scopes-codec/package/src/mod.js.map +0 -0
  140. package/front_end/third_party/source-map-scopes-codec/package/src/mod.ts +0 -0
  141. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js +0 -0
  142. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js.map +0 -0
  143. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.ts +0 -0
  144. package/front_end/third_party/source-map-scopes-codec/package/src/util.js +0 -0
  145. package/front_end/third_party/source-map-scopes-codec/package/src/util.js.map +0 -0
  146. package/front_end/third_party/source-map-scopes-codec/package/src/util.ts +0 -0
  147. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js +0 -0
  148. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js.map +0 -0
  149. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.ts +0 -0
  150. package/front_end/ui/comments/CommentAnchorResolver.ts +132 -0
  151. package/front_end/ui/comments/comments.ts +9 -0
  152. package/front_end/ui/components/dialogs/ShortcutDialog.ts +2 -0
  153. package/front_end/ui/components/settings/SettingCheckbox.ts +4 -12
  154. package/front_end/ui/components/settings/settingCheckbox.css +0 -7
  155. package/front_end/ui/legacy/Treeoutline.ts +14 -14
  156. package/front_end/ui/legacy/UIUtils.ts +2 -47
  157. package/front_end/ui/legacy/Widget.ts +10 -2
  158. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +40 -0
  159. package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +1 -1
  160. package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -0
  161. package/front_end/ui/lit/Directives.ts +80 -0
  162. package/front_end/ui/lit/lit.ts +1 -0
  163. package/front_end/ui/lit/render.ts +8 -0
  164. package/front_end/ui/settings/SettingUIRegistration.ts +4 -0
  165. package/front_end/ui/visual_logging/Debugging.ts +1 -5
  166. package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
  167. package/front_end/ui/visual_logging/LoggingConfig.ts +21 -0
  168. package/front_end/ui/visual_logging/visual_logging.ts +9 -0
  169. package/mcp/mcp.ts +1 -0
  170. package/package.json +1 -1
  171. package/front_end/panels/common/ThrottlingUtils.ts +0 -51
  172. package/front_end/panels/emulation/DeviceModeWrapper.ts +0 -248
  173. package/front_end/panels/mobile_throttling/MobileThrottlingSelector.ts +0 -92
  174. package/front_end/panels/timeline/components/CPUThrottlingSelector.ts +0 -235
  175. package/front_end/panels/timeline/components/NetworkThrottlingSelector.ts +0 -245
  176. package/front_end/panels/timeline/components/cpuThrottlingSelector.css +0 -30
  177. package/front_end/panels/timeline/components/networkThrottlingSelector.css +0 -24
@@ -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
 
@@ -51,6 +51,11 @@ export class Model extends EventTarget {
51
51
  this.#processor = new TraceProcessor(handlers, this.#config);
52
52
  }
53
53
 
54
+ updateConfiguration(config: Types.Configuration.Configuration): void {
55
+ this.#config = config;
56
+ this.#processor.updateConfiguration(config);
57
+ }
58
+
54
59
  /**
55
60
  * Parses an array of trace events into a structured object containing all the
56
61
  * information parsed by the trace handlers.
@@ -94,6 +94,11 @@ export class TraceProcessor extends EventTarget {
94
94
  }
95
95
  }
96
96
 
97
+ updateConfiguration(config: Types.Configuration.Configuration): void {
98
+ this.#modelConfiguration = config;
99
+ this.#passConfigToHandlers();
100
+ }
101
+
97
102
  /**
98
103
  * When the user passes in a set of handlers, we want to ensure that we have all
99
104
  * the required handlers. Handlers can depend on other handlers, so if the user
@@ -141,6 +141,11 @@ export function reset(): void {
141
141
  clsWindowID = -1;
142
142
  }
143
143
 
144
+ let enableSoftNavigation = true;
145
+ export function handleUserConfig(userConfig: Types.Configuration.Configuration): void {
146
+ enableSoftNavigation = userConfig.enableSoftNavigation;
147
+ }
148
+
144
149
  export function handleEvent(event: Types.Events.Event): void {
145
150
  if (Types.Events.isLayoutShift(event) && !event.args.data?.had_recent_input) {
146
151
  layoutShiftEvents.push(event);
@@ -290,8 +295,9 @@ export async function finalize(): Promise<void> {
290
295
 
291
296
  async function buildLayoutShiftsClusters(): Promise<void> {
292
297
  const {navigationsByFrameId, mainFrameId, traceBounds, softNavigationsById} = metaHandlerData();
298
+ const softNavigations = enableSoftNavigation ? Array.from(softNavigationsById.values()) : [];
293
299
  const navigations: Types.Events.Event[] =
294
- [...(navigationsByFrameId.get(mainFrameId) || []), ...softNavigationsById.values()].sort((a, b) => a.ts - b.ts);
300
+ [...(navigationsByFrameId.get(mainFrameId) || []), ...softNavigations].sort((a, b) => a.ts - b.ts);
295
301
  if (layoutShiftEvents.length === 0) {
296
302
  return;
297
303
  }
@@ -8,7 +8,11 @@ import * as Types from '../types/types.js';
8
8
 
9
9
  import type {FinalizeOptions} from './types.js';
10
10
 
11
- let config: {showAllEvents: boolean};
11
+ let config: Types.Configuration.Configuration = Types.Configuration.defaults();
12
+
13
+ export function handleUserConfig(userConfig: Types.Configuration.Configuration): void {
14
+ config = userConfig;
15
+ }
12
16
 
13
17
  // We track the renderer processes we see in each frame on the way through the trace.
14
18
  let rendererProcessesByFrameId: FrameProcessData = new Map();
@@ -328,7 +332,7 @@ export function handleEvent(event: Types.Events.Event): void {
328
332
  return;
329
333
  }
330
334
 
331
- if (Types.Events.isSoftNavigationStart(event)) {
335
+ if (config.enableSoftNavigation && Types.Events.isSoftNavigationStart(event)) {
332
336
  softNavigationsById.set(event.args.context.performanceTimelineNavigationId, event);
333
337
  }
334
338
 
@@ -359,7 +363,7 @@ export function handleEvent(event: Types.Events.Event): void {
359
363
  }
360
364
 
361
365
  export async function finalize(options?: FinalizeOptions): Promise<void> {
362
- config = {showAllEvents: Boolean(options?.showAllEvents)};
366
+ config.showAllEvents = Boolean(options?.showAllEvents);
363
367
 
364
368
  // We try to set the minimum time by finding the event with the smallest
365
369
  // timestamp. However, if we also got a timestamp from the
@@ -476,7 +480,7 @@ export async function finalize(options?: FinalizeOptions): Promise<void> {
476
480
  }
477
481
 
478
482
  export interface MetaHandlerData {
479
- config: {showAllEvents: boolean};
483
+ config: Types.Configuration.Configuration;
480
484
  traceIsGeneric: boolean;
481
485
  traceBounds: Types.Timing.TraceWindowMicro;
482
486
  browserProcessId: Types.Events.ProcessID;
@@ -53,6 +53,11 @@ export function reset(): void {
53
53
  metaCharsetCheckEventsArray = [];
54
54
  }
55
55
 
56
+ let enableSoftNavigation = true;
57
+ export function handleUserConfig(userConfig: Types.Configuration.Configuration): void {
58
+ enableSoftNavigation = userConfig.enableSoftNavigation;
59
+ }
60
+
56
61
  let pageLoadEventsArray: Types.Events.PageLoadEvent[] = [];
57
62
 
58
63
  // Once we've found the LCP events in the trace we want to fetch their DOM Node
@@ -74,6 +79,12 @@ export function handleEvent(event: Types.Events.Event): void {
74
79
  if (!Types.Events.eventIsPageLoadEvent(event)) {
75
80
  return;
76
81
  }
82
+ if (!enableSoftNavigation &&
83
+ (Types.Events.isSoftNavigationStart(event) ||
84
+ event.name === Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION ||
85
+ Types.Events.isSoftFirstContentfulPaint(event))) {
86
+ return;
87
+ }
77
88
  pageLoadEventsArray.push(event);
78
89
 
79
90
  // A soft nav entry includes the Soft FCP details but we want to process both
@@ -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 {
@@ -594,7 +594,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
594
594
  #conversationSummary?: AiAssistanceModel.ConversationSummary.ConversationSummary;
595
595
  #viewOutput: PanelViewOutput = {};
596
596
  #serverSideLoggingEnabled = isAiAssistanceServerSideLoggingEnabled();
597
- #aiAssistanceEnabledSetting: Common.Settings.Setting<boolean>|undefined;
597
+ #aiAssistanceEnabledSetting: AiAssistanceModel.AiSetting.AiSetting<boolean>;
598
598
  #changeManager = new AiAssistanceModel.ChangeManager.ChangeManager();
599
599
  #mutex = new Common.Mutex.Mutex();
600
600
 
@@ -860,13 +860,12 @@ export class AiAssistancePanel extends UI.Panel.Panel {
860
860
  this.requestUpdate();
861
861
  }
862
862
 
863
- #getAiAssistanceEnabledSetting(): Common.Settings.Setting<boolean>|undefined {
864
- try {
865
- return Common.Settings.Settings.instance().moduleSetting('ai-assistance-enabled') as
866
- Common.Settings.Setting<boolean>;
867
- } catch {
868
- return;
869
- }
863
+ #getAiAssistanceEnabledSetting(): AiAssistanceModel.AiSetting.AiSetting<boolean> {
864
+ return new AiAssistanceModel.AiSetting.AiSetting(
865
+ AiAssistanceModel.AiUtils.aiAssistanceEnabledSettingDescriptor,
866
+ Host.AidaClient.HostConfigTracker.instance(),
867
+ Common.Settings.Settings.instance(),
868
+ );
870
869
  }
871
870
 
872
871
  static async instance(opts: {
@@ -1061,7 +1060,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1061
1060
 
1062
1061
  AiAssistanceModel.AiHistoryStorage.AiHistoryStorage.instance().addEventListener(
1063
1062
  AiAssistanceModel.AiHistoryStorage.Events.HISTORY_DELETED, this.#onHistoryDeleted, this);
1064
- this.#aiAssistanceEnabledSetting?.addChangeListener(this.requestUpdate, this);
1063
+ this.#aiAssistanceEnabledSetting.addEventListener(AiAssistanceModel.AiSetting.Events.CHANGED, this.requestUpdate,
1064
+ this);
1065
1065
  Host.AidaClient.HostConfigTracker.instance().addEventListener(
1066
1066
  Host.AidaClient.Events.AIDA_AVAILABILITY_CHANGED, this.#handleAidaAvailabilityChange);
1067
1067
  const initialAvailability = Host.AidaClient.HostConfigTracker.instance().aidaAvailability;
@@ -1107,7 +1107,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1107
1107
  super.willHide();
1108
1108
  AiAssistanceModel.AiHistoryStorage.AiHistoryStorage.instance().removeEventListener(
1109
1109
  AiAssistanceModel.AiHistoryStorage.Events.HISTORY_DELETED, this.#onHistoryDeleted, this);
1110
- this.#aiAssistanceEnabledSetting?.removeChangeListener(this.requestUpdate, this);
1110
+ this.#aiAssistanceEnabledSetting.removeEventListener(AiAssistanceModel.AiSetting.Events.CHANGED, this.requestUpdate,
1111
+ this);
1111
1112
  Host.AidaClient.HostConfigTracker.instance().removeEventListener(
1112
1113
  Host.AidaClient.Events.AIDA_AVAILABILITY_CHANGED, this.#handleAidaAvailabilityChange);
1113
1114
  this.#toggleSearchElementAction?.removeEventListener(
@@ -4,9 +4,10 @@
4
4
 
5
5
  import * as Common from '../../core/common/common.js';
6
6
  import * as i18n from '../../core/i18n/i18n.js';
7
- import type * as Platform from '../../core/platform/platform.js';
8
7
  import * as Root from '../../core/root/root.js';
8
+ import * as AiAssistanceModel from '../../models/ai_assistance/ai_assistance.js';
9
9
  import * as UI from '../../ui/legacy/legacy.js';
10
+ import * as SettingUIRegistration from '../../ui/settings/settings.js';
10
11
 
11
12
  import type * as AiAssistance from './ai_assistance.js';
12
13
 
@@ -50,21 +51,6 @@ const UIStrings = {
50
51
  * @description Text of a context menu item to redirect to the Gemini panel with the current context.
51
52
  */
52
53
  debugWithGemini: 'Debug with Gemini',
53
- /**
54
- * @description Message shown to the user if the DevTools locale is not
55
- * supported.
56
- */
57
- wrongLocale: 'To use this feature, set your language preference to English in DevTools settings.',
58
- /**
59
- * @description Message shown to the user if the user's region is not
60
- * supported.
61
- */
62
- geoRestricted: 'This feature is unavailable in your region.',
63
- /**
64
- * @description Message shown to the user if the enterprise policy does
65
- * not allow this feature.
66
- */
67
- policyRestricted: 'This setting is managed by your administrator.',
68
54
  } as const;
69
55
 
70
56
  const str_ = i18n.i18n.registerUIStrings('panels/ai_assistance/ai_assistance-meta.ts', UIStrings);
@@ -76,13 +62,6 @@ function i18nAiBrandedString(gemini: string, assistance: string) {
76
62
  return () => Root.Runtime.hostConfig.devToolsGeminiRebranding?.enabled ? i18nString(gemini) : i18nString(assistance);
77
63
  }
78
64
 
79
- const setting = 'ai-assistance-enabled';
80
-
81
- function isLocaleRestricted(): boolean {
82
- const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
83
- return !devtoolsLocale.locale.startsWith('en-');
84
- }
85
-
86
65
  function isGeoRestricted(config?: Root.Runtime.HostConfig): boolean {
87
66
  return config?.aidaAvailability?.blockedByGeo === true;
88
67
  }
@@ -140,30 +119,9 @@ UI.ViewManager.registerViewExtension({
140
119
  },
141
120
  });
142
121
 
143
- Common.Settings.registerSettingExtension({
122
+ SettingUIRegistration.SettingUIRegistration.register(AiAssistanceModel.AiUtils.aiAssistanceEnabledSettingDescriptor, {
144
123
  category: Common.Settings.SettingCategory.AI,
145
- settingName: setting,
146
- settingType: Common.Settings.SettingType.BOOLEAN,
147
124
  title: i18nAiBrandedString(UIStrings.enableGemini, UIStrings.enableAiAssistance),
148
- defaultValue: false,
149
- reloadRequired: false,
150
- condition: isAnyFeatureAvailable,
151
- disabledCondition: config => {
152
- const reasons: Platform.UIString.LocalizedString[] = [];
153
- if (isGeoRestricted(config)) {
154
- reasons.push(i18nString(UIStrings.geoRestricted));
155
- }
156
- if (isPolicyRestricted(config)) {
157
- reasons.push(i18nString(UIStrings.policyRestricted));
158
- }
159
- if (isLocaleRestricted()) {
160
- reasons.push(i18nString(UIStrings.wrongLocale));
161
- }
162
- if (reasons.length > 0) {
163
- return {disabled: true, reasons};
164
- }
165
- return {disabled: false};
166
- },
167
125
  });
168
126
 
169
127
  UI.ActionRegistration.registerActionExtension({
@@ -156,7 +156,8 @@ export class BackgroundServiceView extends UI.Widget.VBox {
156
156
  private readonly splitWidget: UI.SplitWidget.SplitWidget;
157
157
  private readonly dataGrid: DataGrid.DataGrid.DataGridImpl<EventData>;
158
158
  private readonly previewPanel: UI.Widget.VBox;
159
- private selectedEventNode: EventDataNode|null;
159
+ #isRecording = false;
160
+ #selectedEventNode: EventDataNode|null = null;
160
161
  private preview: UI.Widget.Widget|null;
161
162
 
162
163
  static getUIString(serviceName: string): string {
@@ -214,7 +215,7 @@ export class BackgroundServiceView extends UI.Widget.VBox {
214
215
 
215
216
  this.toolbar = this.contentElement.createChild('devtools-toolbar', 'background-service-toolbar');
216
217
  this.toolbar.setAttribute('jslog', `${VisualLogging.toolbar()}`);
217
- void this.setupToolbar();
218
+ this.setupToolbar();
218
219
 
219
220
  /**
220
221
  * This will contain the DataGrid for displaying events, and a panel at the bottom for showing
@@ -228,15 +229,13 @@ export class BackgroundServiceView extends UI.Widget.VBox {
228
229
  this.previewPanel = new UI.Widget.VBox();
229
230
  this.previewPanel.element.setAttribute('jslog', `${VisualLogging.pane('preview').track({resize: true})}`);
230
231
 
231
- this.selectedEventNode = null;
232
-
233
232
  this.preview = null;
234
233
 
235
234
  this.splitWidget.setMainWidget(this.dataGrid.asWidget());
236
235
  this.splitWidget.setSidebarWidget(this.previewPanel);
237
236
  this.splitWidget.hideMain();
238
237
 
239
- this.showPreview(null);
238
+ this.performUpdate();
240
239
  }
241
240
 
242
241
  getDataGrid(): DataGrid.DataGrid.DataGridImpl<EventData> {
@@ -246,7 +245,7 @@ export class BackgroundServiceView extends UI.Widget.VBox {
246
245
  /**
247
246
  * Creates the toolbar UI element.
248
247
  */
249
- private async setupToolbar(): Promise<void> {
248
+ private setupToolbar(): void {
250
249
  this.toolbar.wrappable = true;
251
250
  this.recordButton = (UI.Toolbar.Toolbar.createActionButton(this.recordAction) as UI.Toolbar.ToolbarToggle);
252
251
  this.recordButton.toggleOnClick(false);
@@ -264,7 +263,6 @@ export class BackgroundServiceView extends UI.Widget.VBox {
264
263
  this.saveButton.addEventListener(UI.Toolbar.ToolbarButton.Events.CLICK, _event => {
265
264
  void this.saveToFile();
266
265
  });
267
- this.saveButton.setEnabled(false);
268
266
  this.toolbar.appendToolbarItem(this.saveButton);
269
267
 
270
268
  this.toolbar.appendSeparator();
@@ -295,18 +293,17 @@ export class BackgroundServiceView extends UI.Widget.VBox {
295
293
  * Clears the grid and panel.
296
294
  */
297
295
  private clearView(): void {
298
- this.selectedEventNode = null;
296
+ this.#selectedEventNode = null;
299
297
  this.dataGrid.rootNode().removeChildren();
300
298
  this.splitWidget.hideMain();
301
- this.saveButton.setEnabled(false);
302
- this.showPreview(null);
299
+ this.performUpdate();
303
300
  }
304
301
 
305
302
  /**
306
303
  * Called when the `Toggle Record` button is clicked.
307
304
  */
308
305
  toggleRecording(): void {
309
- const isRecording = !this.recordButton.isToggled();
306
+ const isRecording = !this.#isRecording;
310
307
  this.model.setRecording(isRecording, this.serviceName);
311
308
  const featureName = BackgroundServiceView.getUIString(this.serviceName).toLowerCase();
312
309
 
@@ -331,19 +328,12 @@ export class BackgroundServiceView extends UI.Widget.VBox {
331
328
  return;
332
329
  }
333
330
 
334
- if (state.isRecording === this.recordButton.isToggled()) {
331
+ if (state.isRecording === this.#isRecording) {
335
332
  return;
336
333
  }
337
334
 
338
- this.recordButton.setToggled(state.isRecording);
339
- this.updateRecordButtonTooltip();
340
- this.showPreview(this.selectedEventNode);
341
- }
342
-
343
- private updateRecordButtonTooltip(): void {
344
- const buttonTooltip = this.recordButton.isToggled() ? i18nString(UIStrings.stopRecordingEvents) :
345
- i18nString(UIStrings.startRecordingEvents);
346
- this.recordButton.setTitle(buttonTooltip, 'background-service.toggle-recording');
335
+ this.#isRecording = state.isRecording;
336
+ this.performUpdate();
347
337
  }
348
338
 
349
339
  private onEventReceived({
@@ -380,8 +370,7 @@ export class BackgroundServiceView extends UI.Widget.VBox {
380
370
  }
381
371
 
382
372
  if (this.dataGrid.rootNode().children.length === 1) {
383
- this.saveButton.setEnabled(true);
384
- this.showPreview(this.selectedEventNode);
373
+ this.performUpdate();
385
374
  }
386
375
  }
387
376
 
@@ -401,12 +390,31 @@ export class BackgroundServiceView extends UI.Widget.VBox {
401
390
  });
402
391
  dataGrid.setStriped(true);
403
392
 
404
- dataGrid.addEventListener(
405
- DataGrid.DataGrid.Events.SELECTED_NODE, event => this.showPreview((event.data as EventDataNode)));
393
+ dataGrid.addEventListener(DataGrid.DataGrid.Events.SELECTED_NODE, event => {
394
+ this.#selectedEventNode = event.data as EventDataNode;
395
+ this.performUpdate();
396
+ });
406
397
 
407
398
  return dataGrid;
408
399
  }
409
400
 
401
+ override performUpdate(): void {
402
+ this.#updateToolbar();
403
+ this.#updatePreview();
404
+ }
405
+
406
+ #updateToolbar(): void {
407
+ if (this.recordButton) {
408
+ this.recordButton.setToggled(this.#isRecording);
409
+ const buttonTooltip =
410
+ this.#isRecording ? i18nString(UIStrings.stopRecordingEvents) : i18nString(UIStrings.startRecordingEvents);
411
+ this.recordButton.setTitle(buttonTooltip, 'background-service.toggle-recording');
412
+ }
413
+ if (this.saveButton) {
414
+ this.saveButton.setEnabled(this.dataGrid.rootNode().children.length > 0);
415
+ }
416
+ }
417
+
410
418
  /**
411
419
  * Creates the data object to pass to the DataGrid Node.
412
420
  */
@@ -475,19 +483,13 @@ export class BackgroundServiceView extends UI.Widget.VBox {
475
483
  return url as Platform.DevToolsPath.UrlString;
476
484
  }
477
485
 
478
- private showPreview(dataNode: EventDataNode|null): void {
479
- if (this.selectedEventNode && this.selectedEventNode === dataNode) {
480
- return;
481
- }
482
-
483
- this.selectedEventNode = dataNode;
484
-
486
+ #updatePreview(): void {
485
487
  if (this.preview) {
486
488
  this.preview.detach();
487
489
  }
488
490
 
489
- if (this.selectedEventNode) {
490
- this.preview = this.selectedEventNode.createPreview();
491
+ if (this.#selectedEventNode) {
492
+ this.preview = this.#selectedEventNode.createPreview();
491
493
  this.preview.show(this.previewPanel.contentElement);
492
494
  return;
493
495
  }
@@ -496,7 +498,7 @@ export class BackgroundServiceView extends UI.Widget.VBox {
496
498
  if (this.dataGrid.rootNode().children.length) {
497
499
  emptyWidget = new UI.EmptyWidget.EmptyWidget(
498
500
  i18nString(UIStrings.noEventSelected), i18nString(UIStrings.selectAnEventToViewMetadata));
499
- } else if (this.recordButton.isToggled()) {
501
+ } else if (this.#isRecording) {
500
502
  // Inform users that we are recording/waiting for events.
501
503
  const featureName = BackgroundServiceView.getUIString(this.serviceName).toLowerCase();
502
504
  emptyWidget = new UI.EmptyWidget.EmptyWidget(
@@ -505,11 +507,11 @@ export class BackgroundServiceView extends UI.Widget.VBox {
505
507
  } else {
506
508
  const recordShortcuts =
507
509
  UI.ShortcutRegistry.ShortcutRegistry.instance().shortcutsForAction('background-service.toggle-recording')[0];
508
- emptyWidget = new UI.EmptyWidget.EmptyWidget(
509
- i18nString(UIStrings.noRecording), i18nString(UIStrings.startRecordingToDebug, {
510
- PH1: i18nString(UIStrings.startRecordingEvents),
511
- PH2: recordShortcuts.title(),
512
- }));
510
+ emptyWidget = new UI.EmptyWidget.EmptyWidget(i18nString(UIStrings.noRecording),
511
+ i18nString(UIStrings.startRecordingToDebug, {
512
+ PH1: i18nString(UIStrings.startRecordingEvents),
513
+ PH2: recordShortcuts ? recordShortcuts.title() : '',
514
+ }));
513
515
  emptyWidget.link = this.createLearnMoreLink();
514
516
 
515
517
  const button = UI.UIUtils.createTextButton(
@@ -280,6 +280,7 @@ export abstract class KeyValueStorageItemsView extends UI.Widget.VBox {
280
280
  },
281
281
  };
282
282
  this.#view(viewInput, viewOutput, this.contentElement);
283
+ this.doResize();
283
284
  }
284
285
 
285
286
  protected isAiButtonEnabled(): boolean {
@@ -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}})}