chrome-devtools-frontend 1.0.1576287 → 1.0.1576915

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 (50) hide show
  1. package/front_end/core/sdk/DebuggerModel.ts +14 -4
  2. package/front_end/generated/SupportedCSSProperties.js +37 -0
  3. package/front_end/models/bindings/DebuggerLanguagePlugins.ts +37 -38
  4. package/front_end/models/javascript_metadata/NativeFunctions.js +8 -0
  5. package/front_end/models/stack_trace/StackTrace.ts +19 -18
  6. package/front_end/panels/accessibility/AXBreadcrumbsPane.ts +5 -3
  7. package/front_end/panels/ai_assistance/components/ChatMessage.ts +5 -1
  8. package/front_end/panels/animation/AnimationGroupPreviewUI.ts +1 -1
  9. package/front_end/panels/application/ServiceWorkerUpdateCycleView.ts +1 -0
  10. package/front_end/panels/application/components/BackForwardCacheView.ts +4 -2
  11. package/front_end/panels/autofill/AutofillView.ts +1 -1
  12. package/front_end/panels/browser_debugger/XHRBreakpointsSidebarPane.ts +1 -0
  13. package/front_end/panels/console/ConsoleViewMessage.ts +1 -0
  14. package/front_end/panels/elements/ElementsTreeElement.ts +1 -0
  15. package/front_end/panels/elements/LayoutPane.ts +8 -7
  16. package/front_end/panels/elements/components/ElementsBreadcrumbs.ts +1 -1
  17. package/front_end/panels/elements/components/StylePropertyEditor.ts +2 -1
  18. package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +1 -1
  19. package/front_end/panels/linear_memory_inspector/components/LinearMemoryValueInterpreter.ts +1 -1
  20. package/front_end/panels/linear_memory_inspector/components/ValueInterpreterDisplay.ts +1 -1
  21. package/front_end/panels/media/PlayerListView.ts +1 -1
  22. package/front_end/panels/network/NetworkLogViewColumns.ts +2 -1
  23. package/front_end/panels/network/RequestPayloadView.ts +42 -91
  24. package/front_end/panels/network/ShowMoreDetailsWidget.ts +96 -0
  25. package/front_end/panels/network/components/RequestHeaderSection.ts +1 -1
  26. package/front_end/panels/network/network.ts +2 -0
  27. package/front_end/panels/protocol_monitor/JSONEditor.ts +1 -1
  28. package/front_end/panels/recorder/components/RecordingListView.ts +1 -1
  29. package/front_end/panels/recorder/components/StepEditor.ts +3 -3
  30. package/front_end/panels/settings/KeybindsSettingsTab.ts +2 -1
  31. package/front_end/panels/sources/CallStackSidebarPane.ts +58 -11
  32. package/front_end/panels/sources/DebuggerPlugin.ts +19 -22
  33. package/front_end/panels/sources/SourcesPanel.ts +6 -24
  34. package/front_end/panels/sources/components/HeadersView.ts +2 -2
  35. package/front_end/panels/timeline/components/BreadcrumbsUI.ts +1 -1
  36. package/front_end/panels/timeline/components/SidebarAnnotationsTab.ts +1 -1
  37. package/front_end/third_party/chromium/README.chromium +1 -1
  38. package/front_end/ui/components/report_view/ReportView.ts +2 -2
  39. package/front_end/ui/components/report_view/report.css +1 -0
  40. package/front_end/ui/components/suggestion_input/SuggestionInput.ts +7 -12
  41. package/front_end/ui/components/tree_outline/TreeOutline.ts +1 -1
  42. package/front_end/ui/legacy/ContextMenu.ts +12 -7
  43. package/front_end/ui/legacy/ListControl.ts +2 -1
  44. package/front_end/ui/legacy/ListWidget.ts +1 -1
  45. package/front_end/ui/legacy/SoftContextMenu.ts +2 -1
  46. package/front_end/ui/legacy/Treeoutline.ts +1 -0
  47. package/front_end/ui/legacy/components/data_grid/DataGrid.ts +4 -2
  48. package/front_end/ui/legacy/components/quick_open/FilteredListWidget.ts +1 -1
  49. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  50. package/package.json +1 -1
@@ -49,8 +49,10 @@ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
49
49
 
50
50
  import requestPayloadTreeStyles from './requestPayloadTree.css.js';
51
51
  import requestPayloadViewStyles from './requestPayloadView.css.js';
52
+ import {ShowMoreDetailsWidget} from './ShowMoreDetailsWidget.js';
52
53
 
53
54
  const {classMap} = Directives;
55
+ const {widgetConfig} = UI.Widget;
54
56
  const UIStrings = {
55
57
  /**
56
58
  * @description A context menu item Payload View of the Network panel to copy a parsed value.
@@ -77,10 +79,6 @@ const UIStrings = {
77
79
  * @description Text in Request Payload View of the Network panel
78
80
  */
79
81
  formData: 'Form Data',
80
- /**
81
- * @description Text to show more content
82
- */
83
- showMore: 'Show more',
84
82
  /**
85
83
  * @description Text for toggling the view of payload data (e.g. query string parameters) from source to parsed in the payload tab
86
84
  */
@@ -134,7 +132,7 @@ export class RequestPayloadView extends UI.Widget.VBox {
134
132
 
135
133
  this.queryStringCategory = new Category(root, 'query-string');
136
134
  this.formDataCategory = new Category(root, 'form-data');
137
- this.requestPayloadCategory = new Category(root, 'request-payload', i18nString(UIStrings.requestPayload));
135
+ this.requestPayloadCategory = new Category(root, 'request-payload');
138
136
  }
139
137
 
140
138
  override wasShown(): void {
@@ -200,45 +198,16 @@ export class RequestPayloadView extends UI.Widget.VBox {
200
198
  }
201
199
  }
202
200
 
203
- private populateTreeElementWithSourceText(treeElement: UI.TreeOutline.TreeElement, sourceText: string|null): void {
204
- const MAX_LENGTH = 3000;
205
- const text = (sourceText || '').trim();
206
- const trim = text.length > MAX_LENGTH;
207
-
208
- const sourceTextElement = document.createElement('span');
209
- sourceTextElement.classList.add('payload-value');
210
- sourceTextElement.classList.add('source-code');
211
- sourceTextElement.textContent = trim ? text.substr(0, MAX_LENGTH) : text;
212
-
213
- const sourceTreeElement = new UI.TreeOutline.TreeElement(sourceTextElement);
201
+ private populateTreeElementWithSourceText(treeElement: UI.TreeOutline.TreeElement, text: string): void {
202
+ const sourceTreeElement = new UI.TreeOutline.TreeElement();
214
203
 
215
204
  treeElement.removeChildren();
216
205
  treeElement.appendChild(sourceTreeElement);
217
206
  this.addEntryContextMenuHandler(sourceTreeElement, i18nString(UIStrings.copyPayload), 'copy-payload', () => text);
218
- if (!trim) {
219
- return;
220
- }
221
-
222
- const showMoreButton = new Buttons.Button.Button();
223
- showMoreButton.data = {variant: Buttons.Button.Variant.OUTLINED, jslogContext: 'show-more'};
224
- showMoreButton.innerText = i18nString(UIStrings.showMore);
225
- showMoreButton.classList.add('request-payload-show-more-button');
226
-
227
- function showMore(): void {
228
- showMoreButton.remove();
229
- sourceTextElement.textContent = text;
230
- sourceTreeElement.listItemElement.removeEventListener('contextmenu', onContextMenuShowMore);
231
- }
232
- showMoreButton.addEventListener('click', showMore);
233
-
234
- function onContextMenuShowMore(event: Event): void {
235
- const contextMenu = new UI.ContextMenu.ContextMenu(event);
236
- const section = contextMenu.newSection();
237
- section.appendItem(i18nString(UIStrings.showMore), showMore, {jslogContext: 'show-more'});
238
- void contextMenu.show();
239
- }
240
- sourceTreeElement.listItemElement.addEventListener('contextmenu', onContextMenuShowMore);
241
- sourceTextElement.appendChild(showMoreButton);
207
+ render(
208
+ html`<devtools-widget class='payload-value source-code'
209
+ .widgetConfig=${widgetConfig(ShowMoreDetailsWidget, {text})}></devtools-widget>`,
210
+ sourceTreeElement.listItemElement);
242
211
  }
243
212
 
244
213
  private refreshParams(
@@ -306,7 +275,7 @@ export class RequestPayloadView extends UI.Widget.VBox {
306
275
 
307
276
  paramsTreeElement.removeChildren();
308
277
  if (shouldViewSource) {
309
- this.populateTreeElementWithSourceText(paramsTreeElement, sourceText);
278
+ this.populateTreeElementWithSourceText(paramsTreeElement, (sourceText ?? '').trim());
310
279
  paramsTreeElement.listItemElement.addEventListener('contextmenu', viewParsedContextMenu);
311
280
  } else {
312
281
  this.populateTreeElementWithParsedParameters(paramsTreeElement, params);
@@ -363,25 +332,6 @@ export class RequestPayloadView extends UI.Widget.VBox {
363
332
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
364
333
  private refreshRequestJSONPayload(parsedObject: any, sourceText: string): void {
365
334
  const rootListItem = this.requestPayloadCategory;
366
- rootListItem.removeChildren();
367
-
368
- const rootListItemElement = rootListItem.listItemElement;
369
- rootListItemElement.removeChildren();
370
- rootListItemElement.createChild('div', 'selection fill');
371
- UI.UIUtils.createTextChild(rootListItemElement, this.requestPayloadCategory.title.toString());
372
-
373
- if (viewSourceForItems.has(rootListItem)) {
374
- this.appendJSONPayloadSource(rootListItem, parsedObject, sourceText);
375
- } else {
376
- this.appendJSONPayloadParsed(rootListItem, parsedObject, sourceText);
377
- }
378
- }
379
-
380
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
381
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
382
- private appendJSONPayloadSource(rootListItem: Category, parsedObject: any, sourceText: string): void {
383
- const rootListItemElement = rootListItem.listItemElement;
384
- this.populateTreeElementWithSourceText(rootListItem, sourceText);
385
335
 
386
336
  const viewParsed = function(this: RequestPayloadView, event: Event): void {
387
337
  rootListItemElement.removeEventListener('contextmenu', viewParsedContextMenu);
@@ -390,9 +340,6 @@ export class RequestPayloadView extends UI.Widget.VBox {
390
340
  event.consume();
391
341
  };
392
342
 
393
- const viewParsedButton = this.createViewSourceToggle(/* viewSource */ true, viewParsed.bind(this));
394
- rootListItemElement.appendChild(viewParsedButton);
395
-
396
343
  const viewParsedContextMenu = (event: Event): void => {
397
344
  if (!rootListItem.expanded) {
398
345
  return;
@@ -403,27 +350,6 @@ export class RequestPayloadView extends UI.Widget.VBox {
403
350
  void contextMenu.show();
404
351
  };
405
352
 
406
- rootListItemElement.addEventListener('contextmenu', viewParsedContextMenu);
407
- }
408
-
409
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
410
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
411
- private appendJSONPayloadParsed(rootListItem: Category, parsedObject: any, sourceText: string): void {
412
- const object = (SDK.RemoteObject.RemoteObject.fromLocalObject(parsedObject) as SDK.RemoteObject.LocalJSONObject);
413
- const section =
414
- new ObjectUI.ObjectPropertiesSection.RootElement(new ObjectUI.ObjectPropertiesSection.ObjectTree(object));
415
- section.title = (object.description);
416
- section.expand();
417
- // `editable` is not a valid property for `ObjectUI.ObjectPropertiesSection.RootElement`. Only for
418
- // `ObjectUI.ObjectPropertiesSection.ObjectPropertiesSection`. We do not know if this assignment is
419
- // safe to delete.
420
- // @ts-expect-error
421
- section.editable = false;
422
- rootListItem.childrenListElement.classList.add('source-code', 'object-properties-section');
423
-
424
- rootListItem.appendChild(section);
425
- const rootListItemElement = rootListItem.listItemElement;
426
-
427
353
  const viewSource = function(this: RequestPayloadView, event: Event): void {
428
354
  rootListItemElement.removeEventListener('contextmenu', viewSourceContextMenu);
429
355
 
@@ -442,16 +368,41 @@ export class RequestPayloadView extends UI.Widget.VBox {
442
368
  void contextMenu.show();
443
369
  };
444
370
 
445
- const viewSourceButton = this.createViewSourceToggle(/* viewSource */ false, viewSource.bind(this));
446
- rootListItemElement.appendChild(viewSourceButton);
371
+ const showSource = viewSourceForItems.has(rootListItem);
372
+ const rootListItemElement = rootListItem.listItemElement;
373
+ render(
374
+ html`<div class="selection fill"></div>${i18nString(UIStrings.requestPayload)}${
375
+ this.createViewSourceToggle(showSource, showSource ? viewParsed.bind(this) : viewSource.bind(this))}`,
376
+ rootListItemElement);
377
+
378
+ rootListItem.removeChildren();
379
+ if (showSource) {
380
+ this.populateTreeElementWithSourceText(rootListItem, sourceText);
381
+ rootListItemElement.addEventListener('contextmenu', viewParsedContextMenu);
382
+ } else {
383
+ rootListItem.childrenListElement.classList.add('source-code', 'object-properties-section');
384
+ this.populateTreeElementWithObject(rootListItem, parsedObject);
385
+ rootListItemElement.addEventListener('contextmenu', viewSourceContextMenu);
386
+ }
387
+ }
447
388
 
448
- rootListItemElement.addEventListener('contextmenu', viewSourceContextMenu);
389
+ private populateTreeElementWithObject(rootListItem: Category, parsedObject: object): void {
390
+ const object = new SDK.RemoteObject.LocalJSONObject(parsedObject);
391
+ const section =
392
+ new ObjectUI.ObjectPropertiesSection.RootElement(new ObjectUI.ObjectPropertiesSection.ObjectTree(object));
393
+ section.title = (object.description);
394
+ section.expand();
395
+ rootListItem.appendChild(section);
449
396
  }
450
397
 
451
- private createViewSourceToggle(viewSource: boolean, handler: (arg0: Event) => void): Element {
452
- const viewSourceToggleTitle = viewSource ? i18nString(UIStrings.viewParsed) : i18nString(UIStrings.viewSource);
453
- return UI.UIUtils.createTextButton(
454
- viewSourceToggleTitle, handler, {jslogContext: 'source-parse', className: 'payload-toggle'});
398
+ private createViewSourceToggle(viewSource: boolean, handler: (arg0: Event) => void): LitTemplate {
399
+ return html`<devtools-button
400
+ class=payload-toggle
401
+ jslogi=${VisualLogging.action().track({click: true}).context('source-parse')}
402
+ .variant=${Buttons.Button.Variant.OUTLINED}
403
+ @click=${handler}>
404
+ ${viewSource ? i18nString(UIStrings.viewParsed) : i18nString(UIStrings.viewSource)}
405
+ </devtools-button>`;
455
406
  }
456
407
 
457
408
  private toggleURLDecoding(event: Event): void {
@@ -0,0 +1,96 @@
1
+ // Copyright 2026 The Chromium Authors
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import * as i18n from '../../core/i18n/i18n.js';
6
+ import * as Buttons from '../../ui/components/buttons/buttons.js';
7
+ import * as UI from '../../ui/legacy/legacy.js';
8
+ import * as Lit from '../../ui/lit/lit.js';
9
+ const UIStrings = {
10
+ /**
11
+ * @description Text to show more content
12
+ */
13
+ showMore: 'Show more',
14
+ } as const;
15
+ const str_ = i18n.i18n.registerUIStrings('panels/network/ShowMoreDetailsWidget.ts', UIStrings);
16
+ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
17
+
18
+ const {render, html} = Lit;
19
+ interface ViewInput {
20
+ text: string;
21
+ showMore: boolean;
22
+ onToggle: () => void;
23
+ copy: CopyMenuItem|null;
24
+ }
25
+ type View = (input: ViewInput, output: object, target: HTMLElement) => void;
26
+ const MAX_LENGTH = 3000;
27
+
28
+ export const DEFAULT_VIEW: View = (input, output, target) => {
29
+ const onContextMenuShowMore = (event: Event): void => {
30
+ const contextMenu = new UI.ContextMenu.ContextMenu(event);
31
+ if (input.copy) {
32
+ contextMenu.clipboardSection().appendItem(input.copy.menuItem, input.copy.handler);
33
+ }
34
+ if (!input.showMore) {
35
+ contextMenu.newSection().appendItem(i18nString(UIStrings.showMore), input.onToggle, {jslogContext: 'show-more'});
36
+ }
37
+ void contextMenu.show();
38
+ };
39
+
40
+ render(html`<span
41
+ @contextmenu=${onContextMenuShowMore}
42
+ >${input.showMore ? input.text : input.text.substr(0, MAX_LENGTH)}</span>
43
+ ${
44
+ !input.showMore && input.text.length > MAX_LENGTH ? html`<devtools-button
45
+ .variant=${Buttons.Button.Variant.OUTLINED}
46
+ .jslogContext=${'show-more'}
47
+ @click=${input.onToggle}>
48
+ ${i18nString(UIStrings.showMore)}
49
+ </devtools-button>` :
50
+ Lit.nothing}`,
51
+ target);
52
+ };
53
+
54
+ interface CopyMenuItem {
55
+ menuItem: UI.ContextMenu.Item;
56
+ handler: () => void;
57
+ }
58
+
59
+ export class ShowMoreDetailsWidget extends UI.Widget.Widget {
60
+ readonly #view: View;
61
+ #text = '';
62
+ #showMore = false;
63
+ #copy: CopyMenuItem|null = null;
64
+ constructor(target?: HTMLElement, view = DEFAULT_VIEW) {
65
+ super(target);
66
+ this.#view = view;
67
+ }
68
+
69
+ get text(): string {
70
+ return this.#text;
71
+ }
72
+
73
+ set text(text: string) {
74
+ this.#text = text;
75
+ this.requestUpdate();
76
+ }
77
+
78
+ set copy(copy: CopyMenuItem) {
79
+ this.#copy = copy;
80
+ this.requestUpdate();
81
+ }
82
+
83
+ override performUpdate(): void {
84
+ this.#view(
85
+ {
86
+ copy: this.#copy,
87
+ text: this.#text,
88
+ showMore: this.#showMore,
89
+ onToggle: () => {
90
+ this.#showMore = true;
91
+ this.requestUpdate();
92
+ },
93
+ },
94
+ {}, this.contentElement);
95
+ }
96
+ }
@@ -59,7 +59,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
59
59
  ${headers.map(header => html`
60
60
  <devtools-header-section-row
61
61
  .data=${{ header }}
62
- jslog=${VisualLogging.item('request-header')}
62
+ jslog=${VisualLogging.item('request-header').track({resize: true})}
63
63
  ></devtools-header-section-row>
64
64
  `)}
65
65
  `, target);
@@ -52,6 +52,7 @@ import * as RequestResponseView from './RequestResponseView.js';
52
52
  import * as RequestTimingView from './RequestTimingView.js';
53
53
  import * as ResourceDirectSocketChunkView from './ResourceDirectSocketChunkView.js';
54
54
  import * as ResourceWebSocketFrameView from './ResourceWebSocketFrameView.js';
55
+ import * as ShowMoreDetailsWidget from './ShowMoreDetailsWidget.js';
55
56
  import * as SignedExchangeInfoView from './SignedExchangeInfoView.js';
56
57
 
57
58
  export {
@@ -79,5 +80,6 @@ export {
79
80
  RequestTimingView,
80
81
  ResourceDirectSocketChunkView,
81
82
  ResourceWebSocketFrameView,
83
+ ShowMoreDetailsWidget,
82
84
  SignedExchangeInfoView,
83
85
  };
@@ -990,7 +990,7 @@ function renderTargetSelectorRow(input: ViewInput): Lit.TemplateResult|undefined
990
990
  jslog=${VisualLogging.dropDown('target-selector').track({change: true})}
991
991
  @change=${input.onTargetSelected}>
992
992
  ${input.targets.map(target => html`
993
- <option jslog=${VisualLogging.item('target').track({click: true})}
993
+ <option jslog=${VisualLogging.item('target').track({click: true, resize: true})}
994
994
  value=${target.id()} ?selected=${target.id() === input.targetId}>
995
995
  ${target.name()} (${target.inspectedURL()})
996
996
  </option>`)}
@@ -140,7 +140,7 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
140
140
  @keydown=${(event: Event) => onKeyDown(recording.storageName, event)}
141
141
  @click=${(event: Event) => onOpenClick(recording.storageName, event)}
142
142
  jslog=${VisualLogging.item()
143
- .track({ click: true })
143
+ .track({ click: true, resize: true })
144
144
  .context('recording')}>
145
145
  <div class="icon">
146
146
  <devtools-icon name="flow">
@@ -646,7 +646,7 @@ export class StepEditor extends LitElement {
646
646
  #renderTypeRow(editable: boolean): Lit.TemplateResult {
647
647
  this.#renderedAttributes.add('type');
648
648
  // clang-format off
649
- return html`<div class="row attribute" data-attribute="type" jslog=${VisualLogging.treeItem('type')}>
649
+ return html`<div class="row attribute" data-attribute="type" jslog=${VisualLogging.treeItem('type').track({resize: true})}>
650
650
  <div id="type">type<span class="separator">:</span></div>
651
651
  <devtools-suggestion-input
652
652
  aria-labelledby="type"
@@ -667,7 +667,7 @@ export class StepEditor extends LitElement {
667
667
  return;
668
668
  }
669
669
  // clang-format off
670
- return html`<div class="row attribute" data-attribute=${attribute} jslog=${VisualLogging.treeItem(Platform.StringUtilities.toKebabCase(attribute))}>
670
+ return html`<div class="row attribute" data-attribute=${attribute} jslog=${VisualLogging.treeItem(Platform.StringUtilities.toKebabCase(attribute)).track({resize: true})}>
671
671
  <div id=${attribute}>${attribute}<span class="separator">:</span></div>
672
672
  <devtools-suggestion-input
673
673
  .disabled=${this.disabled}
@@ -706,7 +706,7 @@ export class StepEditor extends LitElement {
706
706
  }
707
707
  // clang-format off
708
708
  return html`
709
- <div class="attribute" data-attribute="frame" jslog=${VisualLogging.treeItem('frame')}>
709
+ <div class="attribute" data-attribute="frame" jslog=${VisualLogging.treeItem('frame').track({resize: true})}>
710
710
  <div class="row">
711
711
  <div id="frame">frame<span class="separator">:</span></div>
712
712
  ${this.#renderDeleteButton('frame')}
@@ -344,7 +344,8 @@ export class ShortcutListItem {
344
344
  this.settingsTab = settingsTab;
345
345
  this.item = item;
346
346
  this.element = document.createElement('div');
347
- this.element.setAttribute('jslog', `${VisualLogging.item().context(item.id()).track({keydown: 'Escape'})}`);
347
+ this.element.setAttribute(
348
+ 'jslog', `${VisualLogging.item().context(item.id()).track({keydown: 'Escape', resize: true})}`);
348
349
  this.editedShortcuts = new Map();
349
350
  this.shortcutInputs = new Map();
350
351
  this.shortcuts = UI.ShortcutRegistry.ShortcutRegistry.instance().shortcutsForAction(item.id());
@@ -88,6 +88,16 @@ const UIStrings = {
88
88
  * The user opens this context menu by selecting a specific call frame in the call stack sidebar pane.
89
89
  */
90
90
  restartFrame: 'Restart frame',
91
+ /**
92
+ * @description Error message that is displayed in UI debugging information cannot be found for a call frame
93
+ * @example {main} PH1
94
+ */
95
+ failedToLoadDebugSymbolsForFunction: 'No debug information for function "{PH1}"',
96
+ /**
97
+ * @description Error message that is displayed in UI when a file needed for debugging information for a call frame is missing
98
+ * @example {mainp.debug.wasm.dwp} PH1
99
+ */
100
+ debugSymbolsIncomplete: 'The debug information for function {PH1} is incomplete',
91
101
  } as const;
92
102
  const str_ = i18n.i18n.registerUIStrings('panels/sources/CallStackSidebarPane.ts', UIStrings);
93
103
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -253,10 +263,11 @@ export class CallStackSidebarPane extends UI.View.SimpleView implements UI.Conte
253
263
  const itemPromises = [];
254
264
  const uniqueWarnings = new Set<string>();
255
265
  for (const frame of details.callFrames) {
256
- const itemPromise = Item.createForDebuggerCallFrame(frame, this.locationPool, this.refreshItem.bind(this));
266
+ const itemPromise =
267
+ Item.createForDebuggerCallFrame(frame, this.locationPool, this.refreshItem.bind(this), this.list);
257
268
  itemPromises.push(itemPromise);
258
269
  if (frame.missingDebugInfoDetails) {
259
- uniqueWarnings.add(frame.missingDebugInfoDetails.details);
270
+ uniqueWarnings.add(convertMissingDebugInfo(frame.missingDebugInfoDetails, frame.functionName).details);
260
271
  }
261
272
  }
262
273
  const items = await Promise.all(itemPromises);
@@ -272,7 +283,8 @@ export class CallStackSidebarPane extends UI.View.SimpleView implements UI.Conte
272
283
  asyncStackTrace = stackTrace;
273
284
  const title = UI.UIUtils.asyncStackTraceLabel(asyncStackTrace.description, previousStackTrace);
274
285
  items.push(...await Item.createItemsForAsyncStack(
275
- title, details.debuggerModel, asyncStackTrace.callFrames, this.locationPool, this.refreshItem.bind(this)));
286
+ title, details.debuggerModel, asyncStackTrace.callFrames, this.locationPool, this.refreshItem.bind(this),
287
+ this.list));
276
288
  previousStackTrace = asyncStackTrace.callFrames;
277
289
 
278
290
  if (--maxAsyncStackChainDepth <= 0) {
@@ -367,9 +379,10 @@ export class CallStackSidebarPane extends UI.View.SimpleView implements UI.Conte
367
379
  const icon = new Icon();
368
380
  icon.name = 'warning-filled';
369
381
  icon.classList.add('call-frame-warning-icon', 'small');
370
- const messages = callframe.missingDebugInfoDetails.resources.map(
382
+ const {resources, details} = convertMissingDebugInfo(callframe.missingDebugInfoDetails, callframe.functionName);
383
+ const messages = resources.map(
371
384
  r => i18nString(UIStrings.debugFileNotFound, {PH1: Common.ParsedURL.ParsedURL.extractName(r.resourceUrl)}));
372
- UI.Tooltip.Tooltip.install(icon, [callframe.missingDebugInfoDetails.details, ...messages].join('\n'));
385
+ UI.Tooltip.Tooltip.install(icon, [details, ...messages].join('\n'));
373
386
  element.appendChild(icon);
374
387
  }
375
388
  return element;
@@ -541,12 +554,13 @@ export class Item {
541
554
  updateDelegate: (arg0: Item) => void;
542
555
  /** Only set for synchronous frames */
543
556
  readonly frame?: SDK.DebuggerModel.CallFrame;
557
+ readonly list: UI.ListControl.ListControl<Item>;
544
558
 
545
559
  static async createForDebuggerCallFrame(
546
560
  frame: SDK.DebuggerModel.CallFrame, locationPool: Bindings.LiveLocation.LiveLocationPool,
547
- updateDelegate: (arg0: Item) => void): Promise<Item> {
561
+ updateDelegate: (arg0: Item) => void, list: UI.ListControl.ListControl<Item>): Promise<Item> {
548
562
  const name = frame.functionName;
549
- const item = new Item(UI.UIUtils.beautifyFunctionName(name), updateDelegate, frame);
563
+ const item = new Item(UI.UIUtils.beautifyFunctionName(name), updateDelegate, frame, list);
550
564
  await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().createCallFrameLiveLocation(
551
565
  frame.location(), item.update.bind(item), locationPool);
552
566
  void SourceMapScopes.NamesResolver.resolveDebuggerFrameFunctionName(frame).then(functionName => {
@@ -563,16 +577,17 @@ export class Item {
563
577
 
564
578
  static async createItemsForAsyncStack(
565
579
  title: string, debuggerModel: SDK.DebuggerModel.DebuggerModel, frames: Protocol.Runtime.CallFrame[],
566
- locationPool: Bindings.LiveLocation.LiveLocationPool, updateDelegate: (arg0: Item) => void): Promise<Item[]> {
580
+ locationPool: Bindings.LiveLocation.LiveLocationPool, updateDelegate: (arg0: Item) => void,
581
+ list: UI.ListControl.ListControl<Item>): Promise<Item[]> {
567
582
  const headerItemToItemsSet = new WeakMap<Item, Set<Item>>();
568
- const asyncHeaderItem = new Item(title, updateDelegate);
583
+ const asyncHeaderItem = new Item(title, updateDelegate, undefined, list);
569
584
  headerItemToItemsSet.set(asyncHeaderItem, new Set());
570
585
  asyncHeaderItem.isAsyncHeader = true;
571
586
 
572
587
  const asyncFrameItems = [];
573
588
  const liveLocationPromises = [];
574
589
  for (const frame of frames) {
575
- const item = new Item(UI.UIUtils.beautifyFunctionName(frame.functionName), update);
590
+ const item = new Item(UI.UIUtils.beautifyFunctionName(frame.functionName), update, undefined, list);
576
591
  const rawLocation =
577
592
  debuggerModel.createRawLocationByScriptId(frame.scriptId, frame.lineNumber, frame.columnNumber);
578
593
  liveLocationPromises.push(
@@ -613,7 +628,9 @@ export class Item {
613
628
  }
614
629
  }
615
630
 
616
- constructor(title: string, updateDelegate: (arg0: Item) => void, frame?: SDK.DebuggerModel.CallFrame) {
631
+ constructor(
632
+ title: string, updateDelegate: (arg0: Item) => void, frame: SDK.DebuggerModel.CallFrame|undefined,
633
+ list: UI.ListControl.ListControl<Item>) {
617
634
  this.isIgnoreListed = false;
618
635
  this.title = title;
619
636
  this.linkText = '';
@@ -621,6 +638,7 @@ export class Item {
621
638
  this.isAsyncHeader = false;
622
639
  this.updateDelegate = updateDelegate;
623
640
  this.frame = frame;
641
+ this.list = list;
624
642
  }
625
643
 
626
644
  private async update(liveLocation: Bindings.LiveLocation.LiveLocation): Promise<void> {
@@ -628,6 +646,35 @@ export class Item {
628
646
  this.isIgnoreListed = Boolean(uiLocation?.isIgnoreListed());
629
647
  this.linkText = uiLocation ? uiLocation.linkText() : '';
630
648
  this.uiLocation = uiLocation;
649
+
650
+ if (this.frame && uiLocation && this === this.list.selectedItem()) {
651
+ UI.Context.Context.instance().setFlavor(
652
+ StackTrace.StackTrace.DebuggableFrameFlavor,
653
+ StackTrace.StackTrace.DebuggableFrameFlavor.for({
654
+ uiSourceCode: uiLocation.uiSourceCode,
655
+ line: uiLocation.lineNumber,
656
+ column: uiLocation.columnNumber ?? -1,
657
+ sdkFrame: this.frame,
658
+ }));
659
+ }
660
+
631
661
  this.updateDelegate(this);
632
662
  }
633
663
  }
664
+
665
+ export function convertMissingDebugInfo(
666
+ missingDebugInfo: SDK.DebuggerModel.MissingDebugInfo, functionName: string|undefined):
667
+ {details: Platform.UIString.LocalizedString, resources: SDK.DebuggerModel.MissingDebugFiles[]} {
668
+ switch (missingDebugInfo.type) {
669
+ case SDK.DebuggerModel.MissingDebugInfoType.PARTIAL_INFO:
670
+ return {
671
+ details: i18nString(UIStrings.debugSymbolsIncomplete, {PH1: functionName ?? ''}),
672
+ resources: missingDebugInfo.missingDebugFiles
673
+ };
674
+ case SDK.DebuggerModel.MissingDebugInfoType.NO_INFO:
675
+ return {
676
+ details: i18nString(UIStrings.failedToLoadDebugSymbolsForFunction, {PH1: functionName ?? ''}),
677
+ resources: []
678
+ };
679
+ }
680
+ }
@@ -31,6 +31,7 @@ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
31
31
  import {AddDebugInfoURLDialog} from './AddSourceMapURLDialog.js';
32
32
  import {BreakpointEditDialog} from './BreakpointEditDialog.js';
33
33
  import {BreakpointsSidebarController} from './BreakpointsView.js';
34
+ import {convertMissingDebugInfo} from './CallStackSidebarPane.js';
34
35
  import {Plugin} from './Plugin.js';
35
36
  import {SourcesPanel} from './SourcesPanel.js';
36
37
 
@@ -201,7 +202,6 @@ export class DebuggerPlugin extends Plugin {
201
202
  // truth for re-creating the breakpoints.
202
203
  private breakpoints: BreakpointDescription[] = [];
203
204
  private continueToLocations: Array<{from: number, to: number, async: boolean, click: () => void}>|null = null;
204
- private readonly liveLocationPool: Bindings.LiveLocation.LiveLocationPool;
205
205
  // When the editor content is changed by the user, this becomes
206
206
  // true. When the plugin is muted, breakpoints show up as disabled
207
207
  // and can't be manipulated. It is cleared again when the content is
@@ -252,7 +252,6 @@ export class DebuggerPlugin extends Plugin {
252
252
 
253
253
  UI.Context.Context.instance().addFlavorChangeListener(
254
254
  StackTrace.StackTrace.DebuggableFrameFlavor, this.callFrameChanged, this);
255
- this.liveLocationPool = new Bindings.LiveLocation.LiveLocationPool();
256
255
 
257
256
  this.updateScriptFiles();
258
257
 
@@ -1441,7 +1440,9 @@ export class DebuggerPlugin extends Plugin {
1441
1440
  });
1442
1441
  }
1443
1442
 
1444
- private updateMissingDebugInfoInfobar(warning: SDK.DebuggerModel.MissingDebugInfoDetails|null): void {
1443
+ private updateMissingDebugInfoInfobar(
1444
+ warning: {resources: SDK.DebuggerModel.MissingDebugFiles[], details: Platform.UIString.LocalizedString}|
1445
+ null): void {
1445
1446
  if (this.missingDebugInfoBar) {
1446
1447
  return;
1447
1448
  }
@@ -1655,25 +1656,22 @@ export class DebuggerPlugin extends Plugin {
1655
1656
  }
1656
1657
 
1657
1658
  private async callFrameChanged(): Promise<void> {
1658
- this.liveLocationPool.disposeAll();
1659
- const debuggableFrame = UI.Context.Context.instance().flavor(StackTrace.StackTrace.DebuggableFrameFlavor);
1660
- if (!debuggableFrame) {
1661
- this.setExecutionLocation(null);
1659
+ const frameFlavor = UI.Context.Context.instance().flavor(StackTrace.StackTrace.DebuggableFrameFlavor);
1660
+ if (frameFlavor?.frame.uiSourceCode?.canonicalScriptId() === this.uiSourceCode.canonicalScriptId()) {
1661
+ const uiLocation = new Workspace.UISourceCode.UILocation(
1662
+ frameFlavor.frame.uiSourceCode, frameFlavor.frame.line, frameFlavor.frame.column);
1663
+ this.setExecutionLocation(uiLocation);
1664
+ if (frameFlavor.sdkFrame.missingDebugInfoDetails) {
1665
+ this.updateMissingDebugInfoInfobar(
1666
+ convertMissingDebugInfo(frameFlavor.sdkFrame.missingDebugInfoDetails, frameFlavor.sdkFrame.functionName));
1667
+ } else {
1668
+ this.updateMissingDebugInfoInfobar(null);
1669
+ }
1670
+ // We are paused and the user is specifically looking at this UISourceCode either because
1671
+ // this file is on top of stack, or the user explicitly selected a stack frame for this UISourceCode.
1672
+ this.#recordSourcesPanelDebuggedMetrics();
1662
1673
  } else {
1663
- const callFrame = debuggableFrame.sdkFrame;
1664
- await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().createCallFrameLiveLocation(
1665
- callFrame.location(), async (liveLocation: Bindings.LiveLocation.LiveLocation) => {
1666
- const uiLocation = await liveLocation.uiLocation();
1667
- if (uiLocation && uiLocation.uiSourceCode.canonicalScriptId() === this.uiSourceCode.canonicalScriptId()) {
1668
- this.setExecutionLocation(uiLocation);
1669
- this.updateMissingDebugInfoInfobar(callFrame.missingDebugInfoDetails);
1670
- // We are paused and the user is specifically looking at this UISourceCode either because
1671
- // this file is on top of stack, or the user explicitly selected a stack frame for this UISourceCode.
1672
- this.#recordSourcesPanelDebuggedMetrics();
1673
- } else {
1674
- this.setExecutionLocation(null);
1675
- }
1676
- }, this.liveLocationPool);
1674
+ this.setExecutionLocation(null);
1677
1675
  }
1678
1676
  }
1679
1677
 
@@ -1744,7 +1742,6 @@ export class DebuggerPlugin extends Plugin {
1744
1742
  this.editor = undefined;
1745
1743
 
1746
1744
  UI.Context.Context.instance().removeFlavorChangeListener(SDK.DebuggerModel.CallFrame, this.callFrameChanged, this);
1747
- this.liveLocationPool.disposeAll();
1748
1745
  }
1749
1746
 
1750
1747
  /**