chrome-devtools-frontend 1.0.1608868 → 1.0.1611099

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 (59) hide show
  1. package/eslint.config.mjs +3 -1
  2. package/front_end/core/host/AidaGcaTranslation.ts +13 -0
  3. package/front_end/core/sdk/PreloadingModel.ts +1 -1
  4. package/front_end/entrypoints/heap_snapshot_worker/AllocationProfile.ts +1 -1
  5. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +1 -11
  6. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotWorkerDispatcher.ts +1 -1
  7. package/front_end/generated/InspectorBackendCommands.ts +1 -2
  8. package/front_end/generated/SupportedCSSProperties.js +23 -4
  9. package/front_end/generated/protocol-mapping.d.ts +0 -9
  10. package/front_end/generated/protocol-proxy-api.d.ts +0 -7
  11. package/front_end/generated/protocol.ts +0 -20
  12. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +12 -3
  13. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +5 -4
  14. package/front_end/models/ai_assistance/agents/ConversationSummaryAgent.ts +24 -1
  15. package/front_end/models/ai_assistance/agents/PerformanceAgent.snapshot.txt +2 -2
  16. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +41 -22
  17. package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +2 -2
  18. package/front_end/models/ai_assistance/agents/StylingAgent.ts +5 -3
  19. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +10 -5
  20. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +69 -69
  21. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +1 -1
  22. package/front_end/models/javascript_metadata/NativeFunctions.js +8 -12
  23. package/front_end/models/live-metrics/LiveMetrics.ts +43 -41
  24. package/front_end/models/trace/EntityMapper.ts +12 -0
  25. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +7 -9
  26. package/front_end/panels/ai_assistance/components/ChatMessage.ts +66 -34
  27. package/front_end/panels/ai_assistance/components/ExportForAgentsDialog.ts +1 -1
  28. package/front_end/panels/ai_assistance/components/WalkthroughView.ts +1 -0
  29. package/front_end/panels/ai_assistance/components/chatMessage.css +15 -0
  30. package/front_end/panels/ai_assistance/components/walkthroughView.css +5 -4
  31. package/front_end/panels/application/ApplicationPanelSidebar.ts +8 -0
  32. package/front_end/panels/application/IndexedDBViews.ts +1 -1
  33. package/front_end/panels/application/ResourcesPanel.ts +8 -0
  34. package/front_end/panels/application/ServiceWorkerCacheViews.ts +1 -1
  35. package/front_end/panels/application/application-meta.ts +11 -0
  36. package/front_end/panels/application/application.ts +1 -0
  37. package/front_end/panels/application/components/StorageMetadataView.ts +31 -7
  38. package/front_end/panels/application/components/backForwardCacheView.css +4 -0
  39. package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +29 -0
  40. package/front_end/panels/elements/ElementsTreeElement.ts +4 -0
  41. package/front_end/panels/lighthouse/LighthousePanel.ts +3 -1
  42. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +1 -1
  43. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +1 -1
  44. package/front_end/panels/profiler/HeapSnapshotView.ts +1 -1
  45. package/front_end/panels/timeline/TimelinePanel.ts +2 -6
  46. package/front_end/panels/timeline/utils/Helpers.ts +1 -1
  47. package/front_end/third_party/chromium/README.chromium +1 -1
  48. package/front_end/ui/legacy/InspectorDrawerView.ts +188 -15
  49. package/front_end/ui/legacy/InspectorView.ts +162 -11
  50. package/front_end/ui/legacy/TabbedPane.ts +2 -2
  51. package/front_end/ui/legacy/inspectorDrawerTabbedPane.css +54 -0
  52. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
  53. package/front_end/ui/visual_logging/LoggingDriver.ts +3 -3
  54. package/mcp/mcp.ts +2 -1
  55. package/package.json +4 -5
  56. /package/front_end/models/{heap_snapshot_model → heap_snapshot}/ChildrenProvider.ts +0 -0
  57. /package/front_end/models/{heap_snapshot_model → heap_snapshot}/HeapSnapshotModel.ts +0 -0
  58. /package/front_end/models/{heap_snapshot_model → heap_snapshot}/HeapSnapshotProxy.ts +0 -0
  59. /package/front_end/models/{heap_snapshot_model/heap_snapshot_model.ts → heap_snapshot/heap_snapshot.ts} +0 -0
@@ -2179,7 +2179,7 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
2179
2179
  PerfUI.LineLevelProfile.Performance.instance().initialize(cpuProfiles, primaryPageTarget);
2180
2180
 
2181
2181
  // Initialize EntityMapper
2182
- this.#entityMapper = new Trace.EntityMapper.EntityMapper(parsedTrace);
2182
+ this.#entityMapper = Trace.EntityMapper.EntityMapper.getOrCreate(parsedTrace);
2183
2183
 
2184
2184
  // Set up SourceMapsResolver to ensure we resolve any function names in
2185
2185
  // profile calls.
@@ -2189,9 +2189,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
2189
2189
  SourceMapsResolver.SourceMappingsUpdated.eventName, this.#onSourceMapsNodeNamesResolvedBound);
2190
2190
  void this.#sourceMapsResolver.install();
2191
2191
 
2192
- // Initialize EntityMapper
2193
- this.#entityMapper = new Trace.EntityMapper.EntityMapper(parsedTrace);
2194
-
2195
2192
  this.statusDialog?.updateProgressBar(i18nString(UIStrings.processed), 80);
2196
2193
  this.updateMiniMap();
2197
2194
  this.statusDialog?.updateProgressBar(i18nString(UIStrings.processed), 90);
@@ -3060,7 +3057,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
3060
3057
 
3061
3058
  return trace;
3062
3059
  }
3063
-
3064
3060
  }
3065
3061
 
3066
3062
  export const enum State {
@@ -3143,7 +3139,7 @@ export class BottomUpProfileRevealer implements Common.Revealer.Revealer<Utils.H
3143
3139
  TraceBounds.TraceBounds.BoundsManager.instance().setTimelineVisibleWindow(
3144
3140
  revealable.bounds, {ignoreMiniMapBounds: true, shouldAnimate: true});
3145
3141
  panel.select(null);
3146
- panel.getFlameChart().selectDetailsViewTab(Tab.BottomUp, null);
3142
+ panel.getFlameChart().selectDetailsViewTab(Tab.BottomUp, revealable.node ?? null);
3147
3143
  }
3148
3144
  }
3149
3145
 
@@ -138,6 +138,6 @@ export class RevealableTimeRange {
138
138
  }
139
139
 
140
140
  export class RevealableBottomUpProfile {
141
- constructor(public bounds: Trace.Types.Timing.TraceWindowMicro) {
141
+ constructor(public bounds: Trace.Types.Timing.TraceWindowMicro, public node?: Trace.Extras.TraceTree.Node) {
142
142
  }
143
143
  }
@@ -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: f6aa8926592f9b5bd54bf4b6430d3abb4bc480f6
4
+ Revision: 295046833fe5ffe7765e09abf4e9c15980d09e76
5
5
  Update Mechanism: Manual (https://crbug.com/428069060)
6
6
  License: BSD-3-Clause
7
7
  License File: LICENSE
@@ -2,7 +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
 
5
- import type * as Common from '../../core/common/common.js';
5
+ import * as Common from '../../core/common/common.js';
6
6
  import * as i18n from '../../core/i18n/i18n.js';
7
7
  import * as VisualLogging from '../visual_logging/visual_logging.js';
8
8
 
@@ -14,11 +14,29 @@ import {ToolbarButton, type ToolbarMenuButton} from './Toolbar.js';
14
14
  import type {TabbedViewLocation} from './View.js';
15
15
  import {ViewManager} from './ViewManager.js';
16
16
 
17
+ const VERTICAL_MINIMIZED_DRAWER_SIZE = 27;
18
+
17
19
  class DrawerTabbedPane extends TabbedPane {
18
20
  constructor() {
19
21
  super();
20
22
  this.registerRequiredCSS(drawerTabbedPaneStyles);
21
23
  }
24
+
25
+ setVerticalMinimized(isMinimized: boolean): void {
26
+ this.element.classList.toggle('drawer-minimized-vertical', isMinimized);
27
+ this.contentElement.classList.toggle('collapsed-vertical-drawer-container', isMinimized);
28
+ this.tabbedPaneContentElement().classList.toggle('hide-element', isMinimized);
29
+ this.headerElement().classList.toggle('collapsed-vertical-drawer-header', isMinimized);
30
+ this.headerContentsElement.classList.toggle('hide-element', isMinimized);
31
+ this.leftToolbar().classList.toggle('hide-element', isMinimized);
32
+ this.rightToolbar().classList.toggle('collapsed-vertical-drawer-right-toolbar', isMinimized);
33
+ this.rightToolbar().classList.toggle('collapsed-vertical-drawer-toolbar-content', isMinimized);
34
+ }
35
+
36
+ restoreAfterVerticalMinimized(): void {
37
+ this.clearMeasuredWidths();
38
+ this.headerResized();
39
+ }
22
40
  }
23
41
 
24
42
  const UIStrings = {
@@ -26,6 +44,14 @@ const UIStrings = {
26
44
  * @description Title of more tabs button in the drawer view.
27
45
  */
28
46
  moreTools: 'More Tools',
47
+ /**
48
+ * @description Text that appears when hover over the minimize button on the drawer view.
49
+ */
50
+ minimizeDrawer: 'Minimize drawer',
51
+ /**
52
+ * @description Text that appears when hover over the expand button on the drawer view.
53
+ */
54
+ expandDrawer: 'Expand drawer',
29
55
  /**
30
56
  * @description Text that appears when hover over the close button on the drawer view.
31
57
  */
@@ -44,9 +70,13 @@ interface InspectorDrawerViewOptions {
44
70
  revealDrawer: () => void;
45
71
  isVisible: () => boolean;
46
72
  drawerLabel: string;
73
+ onToggleMinimized: () => void;
47
74
  onHide: () => void;
48
75
  onToggleOrientation: () => void;
76
+ onExpandFromMinimized: () => void;
77
+ onMinimizeFromTabInteraction: () => void;
49
78
  onTabSelected: (tabId: string) => void;
79
+ isConsoleOpenInMainAndDrawer: (tabId: string) => boolean;
50
80
  tabDelegate: TabbedPaneTabDelegate;
51
81
  enableOrientationToggle: boolean;
52
82
  isVertical: boolean;
@@ -59,10 +89,17 @@ interface InspectorDrawerViewOptions {
59
89
  setInspectorMinimumSize: (width: number, height: number) => void;
60
90
  }
61
91
 
92
+ interface InspectorDrawerPresentation {
93
+ isVertical: boolean;
94
+ isMinimized: boolean;
95
+ verticalExpandedMinimumWidth: number;
96
+ }
97
+
62
98
  export class InspectorDrawerView {
63
99
  readonly tabbedLocation: TabbedViewLocation;
64
100
  readonly tabbedPane: DrawerTabbedPane;
65
101
  readonly #splitWidget: SplitWidget;
102
+ readonly #drawerMinimizedSetting: Common.Settings.Setting<boolean>;
66
103
  readonly #verticalExpandedMinimumWidth: number;
67
104
  readonly #minimumSizes: {
68
105
  inspectorWidthWhenVertical: number,
@@ -70,17 +107,28 @@ export class InspectorDrawerView {
70
107
  inspectorHeight: number,
71
108
  };
72
109
  readonly #setInspectorMinimumSize: (width: number, height: number) => void;
110
+ #drawerSizeBeforeMinimize = 0;
111
+ #wasVerticalAndMinimized = false;
73
112
  readonly #toggleOrientationButton: ToolbarButton;
113
+ readonly #minimizeExpandButton: ToolbarButton;
74
114
  readonly #closeDrawerButton: ToolbarButton;
75
115
  readonly #moreTabsButton: ToolbarMenuButton|null;
116
+ readonly #onExpandFromMinimized: () => void;
117
+ readonly #onMinimizeFromTabInteraction: () => void;
76
118
  readonly #onTabSelected: (tabId: string) => void;
119
+ readonly #isConsoleOpenInMainAndDrawer: (tabId: string) => boolean;
77
120
 
78
121
  constructor(options: InspectorDrawerViewOptions) {
79
122
  this.#splitWidget = options.splitWidget;
80
123
  this.#verticalExpandedMinimumWidth = options.verticalExpandedMinimumWidth;
81
124
  this.#minimumSizes = options.minimumSizes;
82
125
  this.#setInspectorMinimumSize = options.setInspectorMinimumSize;
126
+ this.#onExpandFromMinimized = options.onExpandFromMinimized;
127
+ this.#onMinimizeFromTabInteraction = options.onMinimizeFromTabInteraction;
83
128
  this.#onTabSelected = options.onTabSelected;
129
+ this.#isConsoleOpenInMainAndDrawer = options.isConsoleOpenInMainAndDrawer;
130
+ this.#drawerMinimizedSetting =
131
+ Common.Settings.Settings.instance().createLocalSetting('inspector.drawer-minimized', false);
84
132
  this.tabbedLocation = ViewManager.instance().createTabbedLocation(
85
133
  options.revealDrawer, 'drawer-view', true, true, undefined, options.isVisible, () => new DrawerTabbedPane());
86
134
  this.#moreTabsButton = this.tabbedLocation.enableMoreTabsButton();
@@ -89,8 +137,15 @@ export class InspectorDrawerView {
89
137
  this.tabbedPane.element.classList.add('drawer-tabbed-pane');
90
138
  this.tabbedPane.element.setAttribute('jslog', `${VisualLogging.drawer()}`);
91
139
 
140
+ this.#minimizeExpandButton = new ToolbarButton(
141
+ i18nString(UIStrings.minimizeDrawer), options.isVertical ? 'right-panel-close' : 'bottom-panel-close');
142
+ this.#minimizeExpandButton.element.setAttribute(
143
+ 'jslog', `${VisualLogging.toggle('minimize-drawer').track({click: true})}`);
144
+ this.#minimizeExpandButton.addEventListener(ToolbarButton.Events.CLICK, options.onToggleMinimized);
145
+
92
146
  this.#closeDrawerButton = new ToolbarButton(i18nString(UIStrings.closeDrawer), 'cross');
93
- this.#closeDrawerButton.element.setAttribute('jslog', `${VisualLogging.close().track({click: true})}`);
147
+ this.#closeDrawerButton.element.setAttribute(
148
+ 'jslog', `${VisualLogging.close('close-drawer').track({click: true})}`);
94
149
  this.#closeDrawerButton.addEventListener(ToolbarButton.Events.CLICK, options.onHide);
95
150
 
96
151
  this.#toggleOrientationButton = new ToolbarButton(
@@ -102,7 +157,9 @@ export class InspectorDrawerView {
102
157
  if (options.enableOrientationToggle) {
103
158
  this.tabbedPane.rightToolbar().appendToolbarItem(this.#toggleOrientationButton);
104
159
  }
160
+ this.tabbedPane.rightToolbar().appendToolbarItem(this.#minimizeExpandButton);
105
161
  this.tabbedPane.rightToolbar().appendToolbarItem(this.#closeDrawerButton);
162
+ this.tabbedPane.addEventListener(TabbedPaneEvents.TabInvoked, this.#drawerTabInvoked, this);
106
163
  this.tabbedPane.addEventListener(TabbedPaneEvents.TabSelected, this.#drawerTabSelected, this);
107
164
  this.tabbedPane.setTabDelegate(options.tabDelegate);
108
165
  const selectedDrawerTab = this.tabbedPane.selectedTabId;
@@ -120,7 +177,17 @@ export class InspectorDrawerView {
120
177
  drag: true,
121
178
  keydown: 'ArrowUp|ArrowLeft|ArrowDown|ArrowRight|Enter|Space',
122
179
  })}`);
123
- this.#updatePresentation();
180
+ this.#updatePresentation(false);
181
+ }
182
+
183
+ restoreMinimizedStateFromSettings(): void {
184
+ if (!this.#drawerMinimizedSetting.get()) {
185
+ return;
186
+ }
187
+
188
+ // The drawer starts hidden; show it first, then minimize.
189
+ this.#splitWidget.showBoth();
190
+ this.setMinimized(true);
124
191
  }
125
192
 
126
193
  setVertical(shouldBeVertical: boolean): void {
@@ -129,12 +196,14 @@ export class InspectorDrawerView {
129
196
  }
130
197
 
131
198
  const previousShowMode = this.#splitWidget.showMode();
199
+ const wasDrawerMinimized = this.isMinimized();
200
+
132
201
  this.#splitWidget.setVertical(shouldBeVertical);
133
- this.#updatePresentation();
134
- this.applyState(previousShowMode);
202
+ this.#updatePresentation(wasDrawerMinimized);
203
+ this.applyState(previousShowMode, wasDrawerMinimized);
135
204
  }
136
205
 
137
- applyState(showMode: ShowMode): void {
206
+ applyState(showMode: ShowMode, minimized: boolean): void {
138
207
  if (this.#splitWidget.showMode() !== showMode) {
139
208
  switch (showMode) {
140
209
  case ShowMode.BOTH:
@@ -148,22 +217,63 @@ export class InspectorDrawerView {
148
217
  break;
149
218
  }
150
219
  }
151
- this.#updatePresentation();
220
+
221
+ const shouldBeMinimized = showMode === ShowMode.BOTH && minimized;
222
+ if (showMode === ShowMode.BOTH) {
223
+ this.setMinimized(shouldBeMinimized);
224
+ return;
225
+ }
226
+
227
+ this.#splitWidget.setSidebarMinimized(false);
228
+ this.#splitWidget.setResizable(false);
229
+ this.#updatePresentation(false);
230
+ this.#drawerMinimizedSetting.set(false);
152
231
  }
153
232
 
154
233
  show(hasTargetDrawer: boolean): void {
234
+ const wasDrawerVisible = this.isVisibleForEvents();
155
235
  this.tabbedPane.setAutoSelectFirstItemOnShow(!hasTargetDrawer);
156
236
  this.#splitWidget.showBoth();
237
+ this.#dispatchPaneVisibilityChangedIfNeeded(wasDrawerVisible);
157
238
  }
158
239
 
159
240
  hide(): void {
160
- this.#splitWidget.hideSidebar(true);
241
+ const wasDrawerVisible = this.isVisibleForEvents();
242
+ const wasMinimized = this.isMinimized();
243
+ this.#splitWidget.hideSidebar(!wasMinimized);
244
+ if (wasMinimized) {
245
+ this.#updatePresentation(false);
246
+ this.#splitWidget.setSidebarMinimized(false);
247
+ this.#splitWidget.setResizable(true);
248
+ }
249
+ this.#drawerMinimizedSetting.set(false);
250
+ this.#dispatchPaneVisibilityChangedIfNeeded(wasDrawerVisible);
251
+ }
252
+
253
+ setMinimized(minimized: boolean): void {
254
+ const wasDrawerVisible = this.isVisibleForEvents();
255
+ if (minimized && !this.isMinimized()) {
256
+ this.#drawerSizeBeforeMinimize = this.#splitWidget.sidebarSize();
257
+ }
258
+
259
+ this.#updatePresentation(minimized);
260
+ this.#splitWidget.setSidebarMinimized(minimized);
261
+ this.#dispatchPaneVisibilityChangedIfNeeded(wasDrawerVisible);
262
+ this.#splitWidget.setResizable(!minimized);
263
+ this.#drawerMinimizedSetting.set(minimized);
264
+ if (!minimized && this.#drawerSizeBeforeMinimize > 0) {
265
+ this.#splitWidget.setSidebarSize(this.#drawerSizeBeforeMinimize);
266
+ }
161
267
  }
162
268
 
163
269
  drawerVisible(): boolean {
164
270
  return this.tabbedPane.isShowing();
165
271
  }
166
272
 
273
+ isVisibleForEvents(): boolean {
274
+ return this.#splitWidget.sidebarIsShowing() && !this.isMinimized();
275
+ }
276
+
167
277
  drawerSize(): number {
168
278
  return this.#splitWidget.sidebarSize();
169
279
  }
@@ -176,31 +286,94 @@ export class InspectorDrawerView {
176
286
  return this.#splitWidget.totalSize();
177
287
  }
178
288
 
289
+ isMinimized(): boolean {
290
+ return this.#splitWidget.isSidebarMinimized();
291
+ }
292
+
179
293
  isVertical(): boolean {
180
294
  return this.#splitWidget.isVertical();
181
295
  }
182
296
 
183
- updatePresentation(isVertical: boolean): void {
297
+ updatePresentation({isVertical, isMinimized, verticalExpandedMinimumWidth}: InspectorDrawerPresentation): void {
184
298
  this.#toggleOrientationButton.setGlyph(isVertical ? 'dock-bottom' : 'dock-right');
299
+ this.#updateMinimizeExpandButton(isVertical, isMinimized);
185
300
 
186
- if (isVertical) {
187
- this.tabbedPane.setMinimumSize(this.#verticalExpandedMinimumWidth, 27);
301
+ const isVerticalAndMinimized = isVertical && isMinimized;
302
+ if (isVerticalAndMinimized) {
303
+ this.tabbedPane.setMinimumSize(VERTICAL_MINIMIZED_DRAWER_SIZE, VERTICAL_MINIMIZED_DRAWER_SIZE);
304
+ } else if (isVertical) {
305
+ this.tabbedPane.setMinimumSize(verticalExpandedMinimumWidth, VERTICAL_MINIMIZED_DRAWER_SIZE);
188
306
  } else {
189
- this.tabbedPane.setMinimumSize(0, 27);
307
+ this.tabbedPane.setMinimumSize(0, VERTICAL_MINIMIZED_DRAWER_SIZE);
308
+ }
309
+
310
+ this.tabbedPane.setVerticalMinimized(isVerticalAndMinimized);
311
+
312
+ if (this.#moreTabsButton) {
313
+ this.#moreTabsButton.setVisible(!isVerticalAndMinimized);
190
314
  }
315
+
316
+ if (!isVerticalAndMinimized && this.#wasVerticalAndMinimized) {
317
+ this.tabbedPane.restoreAfterVerticalMinimized();
318
+ }
319
+ this.#wasVerticalAndMinimized = isVerticalAndMinimized;
320
+ }
321
+
322
+ #updateMinimizeExpandButton(isVertical: boolean, isMinimized: boolean): void {
323
+ if (isMinimized) {
324
+ this.#minimizeExpandButton.setGlyph(isVertical ? 'right-panel-open' : 'bottom-panel-open');
325
+ this.#minimizeExpandButton.setTitle(i18nString(UIStrings.expandDrawer));
326
+ return;
327
+ }
328
+
329
+ this.#minimizeExpandButton.setGlyph(isVertical ? 'right-panel-close' : 'bottom-panel-close');
330
+ this.#minimizeExpandButton.setTitle(i18nString(UIStrings.minimizeDrawer));
191
331
  }
192
332
 
193
- #updatePresentation(): void {
333
+ #updatePresentation(minimized: boolean): void {
194
334
  const drawerIsVertical = this.#splitWidget.isVertical();
195
335
  this.#setInspectorMinimumSize(
196
336
  drawerIsVertical ? this.#minimumSizes.inspectorWidthWhenVertical :
197
337
  this.#minimumSizes.inspectorWidthWhenHorizontal,
198
338
  this.#minimumSizes.inspectorHeight);
199
- this.updatePresentation(drawerIsVertical);
339
+ this.updatePresentation({
340
+ isVertical: drawerIsVertical,
341
+ isMinimized: minimized,
342
+ verticalExpandedMinimumWidth: this.#verticalExpandedMinimumWidth,
343
+ });
344
+ }
345
+
346
+ #dispatchPaneVisibilityChangedIfNeeded(wasDrawerVisible: boolean): void {
347
+ const isDrawerVisible = this.isVisibleForEvents();
348
+ if (wasDrawerVisible === isDrawerVisible) {
349
+ return;
350
+ }
351
+ this.tabbedPane.dispatchEventToListeners(TabbedPaneEvents.PaneVisibilityChanged, {isVisible: isDrawerVisible});
200
352
  }
201
353
 
202
354
  #drawerTabSelected(event: Common.EventTarget.EventTargetEvent<EventData>): void {
203
- const {tabId} = event.data;
355
+ const {tabId, prevTabId, isUserGesture} = event.data;
204
356
  this.#onTabSelected(tabId);
357
+
358
+ if (this.#isConsoleOpenInMainAndDrawer(tabId)) {
359
+ return;
360
+ }
361
+
362
+ if (isUserGesture && prevTabId && prevTabId !== tabId && this.isMinimized()) {
363
+ this.#onExpandFromMinimized();
364
+ }
365
+ }
366
+
367
+ #drawerTabInvoked(event: Common.EventTarget.EventTargetEvent<EventData>): void {
368
+ const {tabId, isUserGesture} = event.data;
369
+ if (isUserGesture && this.#isConsoleOpenInMainAndDrawer(tabId)) {
370
+ if (!this.isMinimized()) {
371
+ this.#onMinimizeFromTabInteraction();
372
+ }
373
+ return;
374
+ }
375
+ if (isUserGesture && this.isMinimized()) {
376
+ this.#onExpandFromMinimized();
377
+ }
205
378
  }
206
379
  }
@@ -24,7 +24,7 @@ import {Infobar, Type as InfobarType} from './Infobar.js';
24
24
  import {InspectorDrawerView} from './InspectorDrawerView.js';
25
25
  import {KeyboardShortcut} from './KeyboardShortcut.js';
26
26
  import type {Panel} from './Panel.js';
27
- import {SplitWidget} from './SplitWidget.js';
27
+ import {type ShowMode, SplitWidget} from './SplitWidget.js';
28
28
  import {type EventData, Events as TabbedPaneEvents, type TabbedPane, type TabbedPaneTabDelegate} from './TabbedPane.js';
29
29
  import {Tooltip} from './Tooltip.js';
30
30
  import type {TabbedViewLocation, View, ViewLocation, ViewLocationResolver} from './View.js';
@@ -32,6 +32,14 @@ import {ViewManager} from './ViewManager.js';
32
32
  import {VBox, type Widget, WidgetFocusRestorer} from './Widget.js';
33
33
 
34
34
  const UIStrings = {
35
+ /**
36
+ * @description The aria label for the drawer minimized.
37
+ */
38
+ drawerMinimized: 'Drawer minimized',
39
+ /**
40
+ * @description The aria label for the drawer expanded.
41
+ */
42
+ drawerExpanded: 'Drawer expanded',
35
43
  /**
36
44
  * @description The ARIA label for the main tab bar that contains the DevTools panels
37
45
  */
@@ -111,10 +119,10 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
111
119
  let inspectorViewInstance: InspectorView|null = null;
112
120
 
113
121
  const MIN_MAIN_PANEL_WIDTH = 240;
114
- const MIN_VERTICAL_DRAWER_WIDTH = 200;
122
+ const MIN_VERTICAL_DRAWER_WIDTH = 280;
115
123
  // Inspector need to have space for both main panel and the drawer + some slack for borders
116
124
  const MIN_INSPECTOR_WIDTH_HORIZONTAL_DRAWER = 250;
117
- const MIN_INSPECTOR_WIDTH_VERTICAL_DRAWER = 450;
125
+ const MIN_INSPECTOR_WIDTH_VERTICAL_DRAWER = 530;
118
126
  const MIN_INSPECTOR_HEIGHT = 72;
119
127
 
120
128
  export enum DrawerOrientation {
@@ -135,6 +143,12 @@ export interface DrawerOrientationByDockMode {
135
143
  [DockMode.UNDOCKED]: DrawerOrientation;
136
144
  }
137
145
 
146
+ interface ScrollState {
147
+ element: HTMLElement;
148
+ scrollTop: number;
149
+ scrollLeft: number;
150
+ }
151
+
138
152
  export class InspectorView extends VBox implements ViewLocationResolver {
139
153
  private readonly drawerOrientationByDockSetting: Common.Settings.Setting<DrawerOrientationByDockMode>;
140
154
  private readonly drawerSplitWidget: SplitWidget;
@@ -148,12 +162,15 @@ export class InspectorView extends VBox implements ViewLocationResolver {
148
162
  private readonly keyDownBound: (event: KeyboardEvent) => void;
149
163
  private currentPanelLocked?: boolean;
150
164
  private focusRestorer?: WidgetFocusRestorer|null;
165
+ #mainPanelAtDrawerFocus: string|null = null;
151
166
  private ownerSplitWidget?: SplitWidget;
152
167
  private reloadRequiredInfobar?: Infobar;
153
168
  #chromeRestartRequiredInfobar?: Infobar;
154
169
  #debuggedTabReloadRequiredInfobar?: Infobar;
155
170
  #selectOverrideFolderInfobar?: Infobar;
156
171
  #resizeObserver: ResizeObserver;
172
+ #drawerShowModeBeforeDockSideChange: ShowMode|null = null;
173
+ #drawerMinimizedBeforeDockSideChange: boolean|null = null;
157
174
 
158
175
  constructor() {
159
176
  super();
@@ -183,11 +200,15 @@ export class InspectorView extends VBox implements ViewLocationResolver {
183
200
  focus: false,
184
201
  hasTargetDrawer: true,
185
202
  }),
186
- isVisible: () => this.drawerSplitWidget.sidebarIsShowing(),
203
+ isVisible: () => this.drawerSplitWidget.sidebarIsShowing() && !this.drawerSplitWidget.isSidebarMinimized(),
187
204
  drawerLabel: i18nString(UIStrings.drawer),
205
+ onToggleMinimized: this.toggleDrawerMinimized.bind(this),
188
206
  onHide: this.closeDrawer.bind(this),
189
207
  onToggleOrientation: this.toggleDrawerOrientation.bind(this),
208
+ onExpandFromMinimized: this.#expandDrawerFromInteraction.bind(this),
209
+ onMinimizeFromTabInteraction: this.minimizeDrawer.bind(this),
190
210
  onTabSelected: this.tabSelected.bind(this),
211
+ isConsoleOpenInMainAndDrawer: tabId => tabId === 'console-view' && this.tabbedPane.selectedTabId === 'console',
191
212
  tabDelegate: this.tabDelegate,
192
213
  enableOrientationToggle: Boolean(Root.Runtime.hostConfig.devToolsFlexibleLayout?.verticalDrawerEnabled),
193
214
  isVertical,
@@ -258,8 +279,14 @@ export class InspectorView extends VBox implements ViewLocationResolver {
258
279
  this.attachInfobar(infobar);
259
280
  }
260
281
  this.#resizeObserver = new ResizeObserver(this.#observedResize.bind(this));
282
+ DockController.instance().addEventListener(
283
+ DockControllerEvents.BEFORE_DOCK_SIDE_CHANGED, this.#rememberDrawerStateBeforeDockSideChange, this);
261
284
  DockController.instance().addEventListener(
262
285
  DockControllerEvents.DOCK_SIDE_CHANGED, this.#applyDrawerOrientationForDockSide, this);
286
+ DockController.instance().addEventListener(
287
+ DockControllerEvents.AFTER_DOCK_SIDE_CHANGED, this.#restoreDrawerStateAfterDockSideChange, this);
288
+
289
+ this.#drawerView.restoreMinimizedStateFromSettings();
263
290
  }
264
291
 
265
292
  static instance(opts: {
@@ -328,6 +355,10 @@ export class InspectorView extends VBox implements ViewLocationResolver {
328
355
  this.#drawerView.setVertical(shouldBeVertical);
329
356
  }
330
357
 
358
+ #applyDrawerState(showMode: ShowMode, minimized: boolean): void {
359
+ this.#drawerView.applyState(showMode, minimized);
360
+ }
361
+
331
362
  #observedResize(): void {
332
363
  const rect = this.element.getBoundingClientRect();
333
364
  this.element.style.setProperty('--devtools-window-left', `${rect.left}px`);
@@ -350,8 +381,24 @@ export class InspectorView extends VBox implements ViewLocationResolver {
350
381
  super.willHide();
351
382
  this.#resizeObserver.unobserve(this.element);
352
383
  this.element.ownerDocument.removeEventListener('keydown', this.keyDownBound, false);
353
- DockController.instance().removeEventListener(
354
- DockControllerEvents.DOCK_SIDE_CHANGED, this.#applyDrawerOrientationForDockSide, this);
384
+ }
385
+
386
+ #rememberDrawerStateBeforeDockSideChange(): void {
387
+ this.#drawerShowModeBeforeDockSideChange = this.drawerSplitWidget.showMode();
388
+ this.#drawerMinimizedBeforeDockSideChange = this.isDrawerMinimized();
389
+ }
390
+
391
+ #restoreDrawerStateAfterDockSideChange(): void {
392
+ const showMode = this.#drawerShowModeBeforeDockSideChange;
393
+ const minimized = this.#drawerMinimizedBeforeDockSideChange;
394
+ this.#drawerShowModeBeforeDockSideChange = null;
395
+ this.#drawerMinimizedBeforeDockSideChange = null;
396
+
397
+ if (showMode === null || minimized === null) {
398
+ return;
399
+ }
400
+
401
+ this.#applyDrawerState(showMode, minimized);
355
402
  }
356
403
 
357
404
  resolveLocation(locationName: string): ViewLocation|null {
@@ -435,14 +482,26 @@ export class InspectorView extends VBox implements ViewLocationResolver {
435
482
  }
436
483
 
437
484
  showDrawer({focus, hasTargetDrawer}: {focus: boolean, hasTargetDrawer: boolean}): void {
438
- if (this.#drawerView.drawerVisible()) {
485
+ // Both checks are needed: during an animated hide, drawerVisible()
486
+ // (tabbedPane.isShowing()) remains true until the animation completes and
487
+ // the widget is detached, but sidebarIsShowing() turns false synchronously.
488
+ if (this.#drawerView.drawerVisible() && this.drawerSplitWidget.sidebarIsShowing()) {
489
+ // Only expand a minimized drawer when the user explicitly requested
490
+ // focus (e.g. keyboard shortcut or direct action). Programmatic calls
491
+ // (like tab switches) should not auto-expand.
492
+ if (focus && this.isDrawerMinimized()) {
493
+ this.setDrawerMinimized(false);
494
+ ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.drawerExpanded));
495
+ }
439
496
  return;
440
497
  }
441
498
  this.#drawerView.show(hasTargetDrawer);
442
499
  if (focus) {
443
500
  this.focusRestorer = new WidgetFocusRestorer(this.drawerTabbedPane);
501
+ this.#mainPanelAtDrawerFocus = this.tabbedPane.selectedTabId;
444
502
  } else {
445
503
  this.focusRestorer = null;
504
+ this.#mainPanelAtDrawerFocus = null;
446
505
  }
447
506
  this.#applyDrawerOrientationForDockSide();
448
507
  ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.drawerShown));
@@ -452,15 +511,29 @@ export class InspectorView extends VBox implements ViewLocationResolver {
452
511
  return this.#drawerView.drawerVisible();
453
512
  }
454
513
 
514
+ minimizeDrawer(): void {
515
+ if (!this.#drawerView.drawerVisible()) {
516
+ return;
517
+ }
518
+ this.focusRestorer = null;
519
+ this.#mainPanelAtDrawerFocus = null;
520
+ this.setDrawerMinimized(true);
521
+ ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.drawerMinimized));
522
+ }
523
+
455
524
  closeDrawer(): void {
456
525
  if (!this.#drawerView.drawerVisible()) {
457
526
  return;
458
527
  }
459
- if (this.focusRestorer) {
528
+ // Preserve main panel scroll positions across the drawer layout change.
529
+ const scrollState = this.#captureMainPanelScrollState();
530
+ if (this.focusRestorer && this.#mainPanelAtDrawerFocus === this.tabbedPane.selectedTabId) {
460
531
  this.focusRestorer.restore();
461
532
  }
462
533
  this.focusRestorer = null;
534
+ this.#mainPanelAtDrawerFocus = null;
463
535
  this.#drawerView.hide();
536
+ this.#restoreMainPanelScrollState(scrollState);
464
537
  ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.drawerHidden));
465
538
  }
466
539
 
@@ -494,8 +567,62 @@ export class InspectorView extends VBox implements ViewLocationResolver {
494
567
  }
495
568
 
496
569
  setDrawerMinimized(minimized: boolean): void {
497
- this.drawerSplitWidget.setSidebarMinimized(minimized);
498
- this.drawerSplitWidget.setResizable(!minimized);
570
+ // Preserve main panel scroll positions across the drawer layout change.
571
+ const scrollState = this.#captureMainPanelScrollState();
572
+ this.#drawerView.setMinimized(minimized);
573
+ this.#restoreMainPanelScrollState(scrollState);
574
+ }
575
+
576
+ // Showing, hiding, or minimizing the drawer causes SplitWidget to
577
+ // manipulate CSS classes and remove inline layout properties, triggering a
578
+ // flexbox reflow that resets scroll positions in the main panel. We capture
579
+ // them before the operation and restore them afterwards to preserve the
580
+ // user's scroll position.
581
+ #captureMainPanelScrollState(): ScrollState[] {
582
+ const selectedTabId = this.tabbedPane.selectedTabId;
583
+ if (!selectedTabId) {
584
+ return [];
585
+ }
586
+
587
+ let panel: Widget|null = null;
588
+ try {
589
+ panel = ViewManager.instance().materializedWidget(selectedTabId);
590
+ } catch {
591
+ return [];
592
+ }
593
+
594
+ if (!panel) {
595
+ return [];
596
+ }
597
+
598
+ const rootElement = panel.element as HTMLElement;
599
+ const scrollableElements: HTMLElement[] = [
600
+ rootElement,
601
+ ...rootElement.querySelectorAll<HTMLElement>('*'),
602
+ ];
603
+
604
+ return scrollableElements.filter(element => element.scrollTop !== 0 || element.scrollLeft !== 0)
605
+ .map(element => ({
606
+ element,
607
+ scrollTop: element.scrollTop,
608
+ scrollLeft: element.scrollLeft,
609
+ }));
610
+ }
611
+
612
+ #restoreMainPanelScrollState(scrollState: ScrollState[]): void {
613
+ if (!scrollState.length) {
614
+ return;
615
+ }
616
+
617
+ this.element.window().requestAnimationFrame(() => {
618
+ for (const {element, scrollTop, scrollLeft} of scrollState) {
619
+ if (!element.isConnected) {
620
+ continue;
621
+ }
622
+ element.scrollTop = scrollTop;
623
+ element.scrollLeft = scrollLeft;
624
+ }
625
+ });
499
626
  }
500
627
 
501
628
  drawerSize(): number {
@@ -511,13 +638,37 @@ export class InspectorView extends VBox implements ViewLocationResolver {
511
638
  }
512
639
 
513
640
  isDrawerMinimized(): boolean {
514
- return this.drawerSplitWidget.isSidebarMinimized();
641
+ return this.#drawerView.isMinimized();
642
+ }
643
+
644
+ toggleDrawerMinimized(): void {
645
+ if (!this.#drawerView.drawerVisible()) {
646
+ // If the drawer is not visible at all, show and expand it.
647
+ this.showDrawer({focus: true, hasTargetDrawer: false});
648
+ return;
649
+ }
650
+ const minimized = this.isDrawerMinimized();
651
+ if (minimized && this.drawerTabbedPane.selectedTabId === 'console-view' &&
652
+ this.tabbedPane.selectedTabId === 'console') {
653
+ return;
654
+ }
655
+ this.setDrawerMinimized(!minimized);
656
+ if (!minimized) {
657
+ ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.drawerMinimized));
658
+ } else {
659
+ ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.drawerExpanded));
660
+ }
515
661
  }
516
662
 
517
663
  isDrawerOrientationVertical(): boolean {
518
664
  return this.#drawerView.isVertical();
519
665
  }
520
666
 
667
+ #expandDrawerFromInteraction(): void {
668
+ this.setDrawerMinimized(false);
669
+ ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.drawerExpanded));
670
+ }
671
+
521
672
  private keyDown(event: KeyboardEvent): void {
522
673
  if (!KeyboardShortcut.eventHasCtrlEquivalentKey(event) || event.altKey || event.shiftKey) {
523
674
  return;