chrome-devtools-frontend 1.0.1581708 → 1.0.1582745

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 (53) hide show
  1. package/front_end/core/sdk/RemoteObject.ts +7 -1
  2. package/front_end/entrypoint_template.html +5 -1
  3. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +9 -24
  4. package/front_end/entrypoints/greendev_floaty/floaty.css +1 -1
  5. package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +1 -1
  6. package/front_end/generated/InspectorBackendCommands.ts +1 -1
  7. package/front_end/generated/SupportedCSSProperties.js +2 -0
  8. package/front_end/generated/protocol.ts +0 -6
  9. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +6 -6
  10. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +17 -9
  11. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +2 -6
  12. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +66 -2
  13. package/front_end/models/greendev/Prototypes.ts +1 -10
  14. package/front_end/models/issues_manager/ConnectionAllowlistIssue.ts +75 -0
  15. package/front_end/models/issues_manager/FederatedAuthRequestIssue.ts +0 -30
  16. package/front_end/models/issues_manager/IssuesManager.ts +5 -0
  17. package/front_end/models/issues_manager/descriptions/connectionAllowlistInvalidAllowlistItemType.md +12 -0
  18. package/front_end/models/issues_manager/descriptions/connectionAllowlistInvalidHeader.md +12 -0
  19. package/front_end/models/issues_manager/descriptions/connectionAllowlistInvalidUrlPattern.md +8 -0
  20. package/front_end/models/issues_manager/descriptions/connectionAllowlistItemNotInnerList.md +12 -0
  21. package/front_end/models/issues_manager/descriptions/connectionAllowlistMoreThanOneList.md +7 -0
  22. package/front_end/models/issues_manager/descriptions/connectionAllowlistReportingEndpointNotToken.md +10 -0
  23. package/front_end/models/issues_manager/issues_manager.ts +2 -0
  24. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +7 -1
  25. package/front_end/panels/ai_assistance/components/ChatInput.ts +7 -3
  26. package/front_end/panels/application/preloading/PreloadingView.ts +8 -1
  27. package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +4 -1
  28. package/front_end/panels/application/preloading/components/PreloadingGrid.ts +2 -1
  29. package/front_end/panels/application/preloading/components/PreloadingString.ts +12 -3
  30. package/front_end/panels/application/preloading/helper/PreloadingForward.ts +14 -0
  31. package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +37 -3
  32. package/front_end/panels/changes/ChangesSidebar.ts +2 -6
  33. package/front_end/panels/console/ConsoleSidebar.ts +3 -11
  34. package/front_end/panels/lighthouse/LighthouseStartView.ts +3 -5
  35. package/front_end/panels/lighthouse/lighthouseStartView.css +6 -0
  36. package/front_end/panels/network/NetworkLogView.ts +6 -6
  37. package/front_end/panels/network/RequestInitiatorView.ts +19 -8
  38. package/front_end/panels/settings/AISettingsTab.ts +1 -5
  39. package/front_end/panels/settings/SettingsScreen.ts +0 -51
  40. package/front_end/panels/timeline/AnimationsTrackAppender.ts +4 -1
  41. package/front_end/panels/timeline/InteractionsTrackAppender.ts +1 -1
  42. package/front_end/panels/timeline/TimelineUIUtils.ts +13 -16
  43. package/front_end/third_party/chromium/README.chromium +1 -1
  44. package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +5 -1
  45. package/front_end/ui/legacy/Toolbar.ts +4 -4
  46. package/front_end/ui/legacy/Treeoutline.ts +4 -4
  47. package/front_end/ui/legacy/UIUtils.ts +9 -3
  48. package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +6 -11
  49. package/front_end/ui/legacy/components/utils/Linkifier.ts +4 -7
  50. package/package.json +1 -1
  51. package/front_end/models/issues_manager/descriptions/federatedAuthRequestClientMetadataHttpNotFound.md +0 -1
  52. package/front_end/models/issues_manager/descriptions/federatedAuthRequestClientMetadataInvalidResponse.md +0 -1
  53. package/front_end/models/issues_manager/descriptions/federatedAuthRequestClientMetadataNoResponse.md +0 -1
@@ -0,0 +1,12 @@
1
+ # An item in the `Connection-Allowlist` header is not an Inner List.
2
+
3
+ Responses' `Connection-Allowlist` header should be formatted as a [List](sfList)
4
+ containing a single [Inner List](sfInnerList) that declares the allowed set of
5
+ [URL Patterns](urlPatternSpec) for a given context.
6
+
7
+ For example, the following header allows connections to (only)
8
+ `https://example.com/`:
9
+
10
+ ```
11
+ Connection-Allowlist: ("https://example.com")
12
+ ```
@@ -0,0 +1,7 @@
1
+ # `Connection-Allowlist` has multiple items.
2
+
3
+ Responses' `Connection-Allowlist` header should be formatted as a [List](sfList)
4
+ containing a single [Inner List](sfInnerList) that declares the allowed set of
5
+ [URL Patterns](urlPatternSpec) for a given context. This response was a
6
+ [List](sfList) containing more than one item: all but the first have been
7
+ ignored.
@@ -0,0 +1,10 @@
1
+ # The `report-to` parameter in the `Connection-Allowlist` header is not a token.
2
+
3
+ If provided, the `report-to` parameter must be a [Token](sfToken)
4
+ naming a reporting endpoint.
5
+
6
+ For example:
7
+
8
+ ```
9
+ Connection-Allowlist: ("https://example.com");report-to=endpoint
10
+ ```
@@ -5,6 +5,7 @@
5
5
  import * as AttributionReportingIssue from './AttributionReportingIssue.js';
6
6
  import * as CheckFormsIssuesTrigger from './CheckFormsIssuesTrigger.js';
7
7
  import * as ClientHintIssue from './ClientHintIssue.js';
8
+ import * as ConnectionAllowlistIssue from './ConnectionAllowlistIssue.js';
8
9
  import * as ContentSecurityPolicyIssue from './ContentSecurityPolicyIssue.js';
9
10
  import * as ContrastCheckTrigger from './ContrastCheckTrigger.js';
10
11
  import * as CookieDeprecationMetadataIssue from './CookieDeprecationMetadataIssue.js';
@@ -39,6 +40,7 @@ export {
39
40
  AttributionReportingIssue,
40
41
  CheckFormsIssuesTrigger,
41
42
  ClientHintIssue,
43
+ ConnectionAllowlistIssue,
42
44
  ContentSecurityPolicyIssue,
43
45
  ContrastCheckTrigger,
44
46
  CookieDeprecationMetadataIssue,
@@ -1417,7 +1417,13 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1417
1417
  });
1418
1418
 
1419
1419
  void this.#toggleSearchElementAction.execute();
1420
- return await result;
1420
+ try {
1421
+ return await result;
1422
+ } finally {
1423
+ if (this.#toggleSearchElementAction.toggled()) {
1424
+ void this.#toggleSearchElementAction.execute();
1425
+ }
1426
+ }
1421
1427
  }
1422
1428
 
1423
1429
  async #startConversation(
@@ -42,7 +42,11 @@ const UIStrings = {
42
42
  /**
43
43
  * @description Label added to the button that remove the currently selected context in AI Assistance panel.
44
44
  */
45
- removeContext: 'Remove selected context',
45
+ removeContext: 'Remove from context',
46
+ /**
47
+ * @description Label added to the button that add selected context from the current panel in AI Assistance panel.
48
+ */
49
+ addContext: 'Add selected item as context',
46
50
  } as const;
47
51
 
48
52
  /*
@@ -387,8 +391,8 @@ export const
387
391
  :
388
392
  input.onContextAdd ? html`
389
393
  <devtools-button
390
- title=${i18nString(UIStrings.removeContext)}
391
- aria-label=${i18nString(UIStrings.removeContext)}
394
+ title=${i18nString(UIStrings.addContext)}
395
+ aria-label=${i18nString(UIStrings.addContext)}
392
396
  class="add-context"
393
397
  .iconName=${'plus'}
394
398
  .size=${Buttons.Button.Size.SMALL}
@@ -22,7 +22,7 @@ import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
22
22
 
23
23
  import * as PreloadingComponents from './components/components.js';
24
24
  import {ruleSetTagOrLocationShort} from './components/PreloadingString.js';
25
- import type * as PreloadingHelper from './helper/helper.js';
25
+ import * as PreloadingHelper from './helper/helper.js';
26
26
  import preloadingViewStyles from './preloadingView.css.js';
27
27
  import preloadingViewDropDownStyles from './preloadingViewDropDown.css.js';
28
28
 
@@ -501,10 +501,17 @@ export class PreloadingAttemptView extends UI.Widget.VBox {
501
501
  const ruleSet = this.model.getRuleSetById(id);
502
502
  return ruleSet === null ? [] : [ruleSet];
503
503
  });
504
+
505
+ // Lookup status code for prefetch attempts
506
+ const statusCode = attempt.action === Protocol.Preload.SpeculationAction.Prefetch ?
507
+ PreloadingHelper.PreloadingForward.prefetchStatusCode(attempt.requestId) :
508
+ undefined;
509
+
504
510
  return {
505
511
  id,
506
512
  pipeline,
507
513
  ruleSets,
514
+ statusCode,
508
515
  };
509
516
  });
510
517
  this.preloadingGrid.rows = rows;
@@ -349,7 +349,10 @@ export class PreloadingDetailsReportView extends LegacyWrapper.LegacyWrapper.Wra
349
349
  return Lit.nothing;
350
350
  }
351
351
 
352
- const failureDescription = prefetchFailureReason(attempt);
352
+ // Lookup status code for Non2XX failures
353
+ const statusCode = PreloadingHelper.PreloadingForward.prefetchStatusCode(attempt.requestId);
354
+
355
+ const failureDescription = prefetchFailureReason(attempt, statusCode);
353
356
  if (failureDescription === null) {
354
357
  return Lit.nothing;
355
358
  }
@@ -51,6 +51,7 @@ export interface PreloadingGridRow {
51
51
  id: string;
52
52
  pipeline: SDK.PreloadingModel.PreloadPipeline;
53
53
  ruleSets: Protocol.Preload.RuleSet[];
54
+ statusCode?: number;
54
55
  }
55
56
 
56
57
  export interface ViewInput {
@@ -107,7 +108,7 @@ export const PRELOADING_GRID_DEFAULT_VIEW: View = (input, _output, target): void
107
108
  'vertical-align': 'sub',
108
109
  })}
109
110
  ></devtools-icon>` : ''}
110
- ${hasWarning ? i18nString(UIStrings.prefetchFallbackReady) : composedStatus(attempt)}
111
+ ${hasWarning ? i18nString(UIStrings.prefetchFallbackReady) : composedStatus(attempt, row.statusCode)}
111
112
  </div>
112
113
  </td>
113
114
  </tr>`;
@@ -31,6 +31,11 @@ const UIStrings = {
31
31
  * @description Description text for Prefetch status PrefetchFailedNon2XX.
32
32
  */
33
33
  PrefetchFailedNon2XX: 'The prefetch failed because of a non-2xx HTTP response status code.',
34
+ /**
35
+ * @description Description text for Prefetch status PrefetchFailedNon2XX when the HTTP status code is known.
36
+ * @example {404} PH1
37
+ */
38
+ PrefetchFailedNon2XXWithStatusCode: 'The prefetch failed because of a non-2xx HTTP response status code ({PH1}).',
34
39
  /**
35
40
  * @description Description text for Prefetch status PrefetchIneligibleRetryAfter.
36
41
  */
@@ -446,7 +451,8 @@ export const PrefetchReasonDescription: Record<string, {name: () => Platform.UIS
446
451
  };
447
452
 
448
453
  /** Decoding PrefetchFinalStatus prefetchAttempt to failure description. **/
449
- export function prefetchFailureReason({prefetchStatus}: SDK.PreloadingModel.PrefetchAttempt): string|null {
454
+ export function prefetchFailureReason(
455
+ {prefetchStatus}: SDK.PreloadingModel.PrefetchAttempt, statusCode?: number): string|null {
450
456
  // If you face an error on rolling CDP changes, see
451
457
  // https://docs.google.com/document/d/1PnrfowsZMt62PX1EvvTp2Nqs3ji1zrklrAEe1JYbkTk
452
458
  switch (prefetchStatus) {
@@ -478,6 +484,9 @@ export function prefetchFailureReason({prefetchStatus}: SDK.PreloadingModel.Pref
478
484
  case Protocol.Preload.PrefetchStatus.PrefetchFailedNetError:
479
485
  return PrefetchReasonDescription['PrefetchFailedNetError'].name();
480
486
  case Protocol.Preload.PrefetchStatus.PrefetchFailedNon2XX:
487
+ if (statusCode !== undefined) {
488
+ return i18nString(UIStrings.PrefetchFailedNon2XXWithStatusCode, {PH1: String(statusCode)});
489
+ }
481
490
  return PrefetchReasonDescription['PrefetchFailedNon2XX'].name();
482
491
  case Protocol.Preload.PrefetchStatus.PrefetchIneligibleRetryAfter:
483
492
  return PrefetchReasonDescription['PrefetchIneligibleRetryAfter'].name();
@@ -795,7 +804,7 @@ export function status(status: SDK.PreloadingModel.PreloadingStatus): string {
795
804
  }
796
805
  }
797
806
 
798
- export function composedStatus(attempt: SDK.PreloadingModel.PreloadingAttempt): string {
807
+ export function composedStatus(attempt: SDK.PreloadingModel.PreloadingAttempt, statusCode?: number): string {
799
808
  const short = status(attempt.status);
800
809
 
801
810
  if (attempt.status !== SDK.PreloadingModel.PreloadingStatus.FAILURE) {
@@ -804,7 +813,7 @@ export function composedStatus(attempt: SDK.PreloadingModel.PreloadingAttempt):
804
813
 
805
814
  switch (attempt.action) {
806
815
  case Protocol.Preload.SpeculationAction.Prefetch: {
807
- const detail = prefetchFailureReason(attempt) ?? i18n.i18n.lockedString('Internal error');
816
+ const detail = prefetchFailureReason(attempt, statusCode) ?? i18n.i18n.lockedString('Internal error');
808
817
  return short + ' - ' + detail;
809
818
  }
810
819
  case Protocol.Preload.SpeculationAction.Prerender:
@@ -3,6 +3,7 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import type * as Protocol from '../../../../generated/protocol.js';
6
+ import * as Logs from '../../../../models/logs/logs.js';
6
7
 
7
8
  export class RuleSetView {
8
9
  readonly ruleSetId: Protocol.Preload.RuleSetId|null;
@@ -19,3 +20,16 @@ export class AttemptViewWithFilter {
19
20
  this.ruleSetId = ruleSetId;
20
21
  }
21
22
  }
23
+
24
+ /**
25
+ * Retrieves the HTTP status code for a prefetch attempt by looking up its
26
+ * network request in the network log.
27
+ */
28
+ export function prefetchStatusCode(requestId: Protocol.Network.RequestId): number|undefined {
29
+ const networkLog = Logs.NetworkLog.NetworkLog.instance();
30
+ const requests = networkLog.requestsForId(requestId);
31
+ if (requests.length > 0) {
32
+ return requests[requests.length - 1].statusCode;
33
+ }
34
+ return undefined;
35
+ }
@@ -134,6 +134,9 @@ interface ViewOutput {
134
134
  interface ViewInput {
135
135
  onFilterChanged: (filterText: string|null) => void;
136
136
  onBreakpointChange: (breakpoint: SDK.CategorizedBreakpoint.CategorizedBreakpoint, enabled: boolean) => void;
137
+ onItemSelected: (item: SDK.CategorizedBreakpoint.Category|SDK.CategorizedBreakpoint.CategorizedBreakpoint|
138
+ null) => void;
139
+ onSpaceKeyDown: () => void;
137
140
 
138
141
  filterText: string|null;
139
142
  userExpandedCategories: Set<SDK.CategorizedBreakpoint.Category>;
@@ -200,6 +203,13 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
200
203
  }
201
204
  };
202
205
 
206
+ const onKeyDown = (e: KeyboardEvent): void => {
207
+ if (e.key === ' ') {
208
+ input.onSpaceKeyDown();
209
+ e.preventDefault();
210
+ }
211
+ };
212
+
203
213
  render(
204
214
  // clang-format off
205
215
  html`
@@ -210,10 +220,11 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
210
220
  style="flex: 1;"
211
221
  ></devtools-toolbar-input>
212
222
  </devtools-toolbar>
213
- <devtools-tree autofocus .template=${html`
223
+ <devtools-tree autofocus @keydown=${onKeyDown} .template=${html`
214
224
  <ul role="tree">
215
225
  ${filteredCategories.map(([category, breakpoints]) => html`
216
- <li @expand=${(e: UI.TreeOutline.TreeViewElement.ExpandEvent) => onExpand(category, e)}
226
+ <li @select=${() => input.onItemSelected(category)}
227
+ @expand=${(e: UI.TreeOutline.TreeViewElement.ExpandEvent) => onExpand(category, e)}
217
228
  role="treeitem"
218
229
  jslog-context=${category}
219
230
  aria-checked=${breakpoints.some(breakpoint => breakpoint.enabled())
@@ -233,7 +244,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
233
244
  role="group"
234
245
  ?hidden=${!shouldExpandCategory(breakpoints) && !input.userExpandedCategories.has(category)}>
235
246
  ${breakpoints.map(breakpoint => html`
236
- <li
247
+ <li @select=${() => input.onItemSelected(breakpoint)}
237
248
  role="treeitem"
238
249
  aria-checked=${breakpoint.enabled()}
239
250
  jslog-context=${Platform.StringUtilities.toKebabCase(breakpoint.name)}>
@@ -265,6 +276,7 @@ export abstract class CategorizedBreakpointsSidebarPane extends UI.Widget.VBox {
265
276
  #filterText: string|null = null;
266
277
  #view: View;
267
278
  #userExpandedCategories = new Set<SDK.CategorizedBreakpoint.Category>();
279
+ #selectedItem: SDK.CategorizedBreakpoint.Category|SDK.CategorizedBreakpoint.CategorizedBreakpoint|null = null;
268
280
  constructor(
269
281
  breakpoints: SDK.CategorizedBreakpoint.CategorizedBreakpoint[], jslog: string, viewId: string,
270
282
  view = DEFAULT_VIEW) {
@@ -321,6 +333,26 @@ export abstract class CategorizedBreakpointsSidebarPane extends UI.Widget.VBox {
321
333
  this.requestUpdate();
322
334
  }
323
335
 
336
+ #onItemSelected(item: SDK.CategorizedBreakpoint.Category|SDK.CategorizedBreakpoint.CategorizedBreakpoint|null): void {
337
+ this.#selectedItem = item;
338
+ }
339
+
340
+ #onSpaceKeyDown(): void {
341
+ const selected = this.#selectedItem;
342
+ if (!selected) {
343
+ return;
344
+ }
345
+ if (selected instanceof SDK.CategorizedBreakpoint.CategorizedBreakpoint) {
346
+ this.onBreakpointChanged(selected, !selected.enabled());
347
+ } else {
348
+ const breakpoints = this.categories.get(selected);
349
+ if (breakpoints) {
350
+ const newEnabled = breakpoints.some(bp => !bp.enabled());
351
+ breakpoints.forEach(bp => this.onBreakpointChanged(bp, newEnabled));
352
+ }
353
+ }
354
+ }
355
+
324
356
  protected onBreakpointChanged(breakpoint: SDK.CategorizedBreakpoint.CategorizedBreakpoint, enabled: boolean): void {
325
357
  breakpoint.setEnabled(enabled);
326
358
  this.requestUpdate();
@@ -331,6 +363,8 @@ export abstract class CategorizedBreakpointsSidebarPane extends UI.Widget.VBox {
331
363
  filterText: this.#filterText,
332
364
  onFilterChanged: this.#onFilterChanged.bind(this),
333
365
  onBreakpointChange: this.onBreakpointChanged.bind(this),
366
+ onItemSelected: this.#onItemSelected.bind(this),
367
+ onSpaceKeyDown: this.#onSpaceKeyDown.bind(this),
334
368
  sortedCategoryNames: this.#sortedCategories,
335
369
  categories: this.categories,
336
370
  highlightedItem: this.#highlightedItem,
@@ -24,7 +24,7 @@ const UIStrings = {
24
24
  } as const;
25
25
  const str_ = i18n.i18n.registerUIStrings('panels/changes/ChangesSidebar.ts', UIStrings);
26
26
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
27
- const {render, html, Directives: {ref}} = Lit;
27
+ const {render, html} = Lit;
28
28
  interface ViewInput {
29
29
  selectedSourceCode: Workspace.UISourceCode.UISourceCode|null;
30
30
  onSelect: (uiSourceCode: Workspace.UISourceCode.UISourceCode|null) => void;
@@ -38,20 +38,16 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
38
38
  uiSourceCode.url();
39
39
  const icon = (uiSourceCode: Workspace.UISourceCode.UISourceCode): string =>
40
40
  Snippets.ScriptSnippetFileSystem.isSnippetsUISourceCode(uiSourceCode) ? 'snippet' : 'document';
41
- const configElements = new WeakMap<HTMLLIElement, Workspace.UISourceCode.UISourceCode>();
42
- const onSelect = (e: UI.TreeOutline.TreeViewElement.SelectEvent): void =>
43
- input.onSelect(configElements.get(e.detail) ?? null);
44
41
  render(
45
42
  // clang-format off
46
43
  html`<devtools-tree
47
- @selected=${onSelect}
48
44
  navigation-variant
49
45
  hide-overflow .template=${html`
50
46
  <ul role="tree">
51
47
  ${input.sourceCodes.values().map(uiSourceCode => html`
52
48
  <li
53
49
  role="treeitem"
54
- ${ref(e => e instanceof HTMLLIElement && configElements.set(e, uiSourceCode))}
50
+ @select=${() => input.onSelect(uiSourceCode)}
55
51
  ?selected=${uiSourceCode === input.selectedSourceCode}>
56
52
  <style>${changesSidebarStyles}</style>
57
53
  <div class=${'navigator-' + uiSourceCode.contentType().name() + '-tree-item'}>
@@ -50,7 +50,7 @@ const UIStrings = {
50
50
  } as const;
51
51
  const str_ = i18n.i18n.registerUIStrings('panels/console/ConsoleSidebar.ts', UIStrings);
52
52
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
53
- const {render, html, nothing, Directives} = Lit;
53
+ const {render, html, nothing} = Lit;
54
54
 
55
55
  export const enum GroupName {
56
56
  CONSOLE_API = 'user message',
@@ -78,18 +78,10 @@ interface ViewInput {
78
78
 
79
79
  export type View = (input: ViewInput, output: object, target: HTMLElement) => void;
80
80
  export const DEFAULT_VIEW: View = (input, output, target) => {
81
- const nodeFilterMap = new WeakMap<Element, ConsoleFilter>();
82
- const onSelectionChanged = (event: UI.TreeOutline.TreeViewElement.SelectEvent): void => {
83
- const filter = nodeFilterMap.get(event.detail);
84
- if (filter) {
85
- input.onSelectionChanged(filter);
86
- }
87
- };
88
81
  render(
89
82
  html`<devtools-tree
90
83
  navigation-variant
91
84
  hide-overflow
92
- @select=${onSelectionChanged}
93
85
  .template=${
94
86
  html`
95
87
  <ul role="tree">
@@ -98,7 +90,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
98
90
  group => html`
99
91
  <li
100
92
  role="treeitem"
101
- ${Directives.ref(element => element && nodeFilterMap.set(element, group.filter))}
93
+ @select=${() => input.onSelectionChanged(group.filter)}
102
94
  ?selected=${group.filter === input.selectedFilter}>
103
95
  <style>${consoleSidebarStyles}</style>
104
96
  <devtools-icon name=${GROUP_ICONS[group.name].icon}></devtools-icon>
@@ -112,7 +104,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
112
104
  <ul role="group" hidden>
113
105
  ${group.urlGroups.values().map(urlGroup => html`
114
106
  <li
115
- ${Directives.ref(element => element && nodeFilterMap.set(element, urlGroup.filter))}
107
+ @select=${() => input.onSelectionChanged(urlGroup.filter)}
116
108
  role="treeitem"
117
109
  ?selected=${urlGroup.filter === input.selectedFilter}
118
110
  title=${urlGroup.url ?? ''}>
@@ -166,8 +166,6 @@ export class StartView extends UI.Widget.Widget {
166
166
  checkbox.setIndeterminate(true);
167
167
  }
168
168
  }
169
- UI.ARIAUtils.markAsGroup(categoryFormElements);
170
- UI.ARIAUtils.setLabel(categoryFormElements, i18nString(UIStrings.categories));
171
169
  }
172
170
 
173
171
  private render(): void {
@@ -194,10 +192,10 @@ export class StartView extends UI.Widget.Widget {
194
192
  <div class="lighthouse-form-elements" $="device-type-form-elements"></div>
195
193
  </div>
196
194
  <div class="lighthouse-form-categories">
197
- <div class="lighthouse-form-section">
198
- <div class="lighthouse-form-section-label">${i18nString(UIStrings.categories)}</div>
195
+ <fieldset class="lighthouse-form-section lighthouse-form-categories-fieldset">
196
+ <legend class="lighthouse-form-section-label">${i18nString(UIStrings.categories)}</legend>
199
197
  <div class="lighthouse-form-elements" $="categories-form-elements"></div>
200
- </div>
198
+ </fieldset>
201
199
  </div>
202
200
  </div>
203
201
  <div $="warning-text" class="lighthouse-warning-text hidden"></div>
@@ -52,6 +52,12 @@
52
52
  flex: 1 1;
53
53
  }
54
54
 
55
+ .lighthouse-form-categories-fieldset {
56
+ border: none;
57
+ margin: 0;
58
+ padding: 8px;
59
+ }
60
+
55
61
  .lighthouse-form-section-label {
56
62
  margin: 7px 0;
57
63
  font-weight: 500;
@@ -1933,14 +1933,14 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
1933
1933
  const isThrottling = existingConditions &&
1934
1934
  existingConditions.conditions !== SDK.NetworkManager.BlockingConditions &&
1935
1935
  existingConditions.conditions !== SDK.NetworkManager.NoThrottlingConditions;
1936
+ const croppedURL = Platform.StringUtilities.trimMiddle(urlPattern.constructorString, maxBlockedURLLength);
1936
1937
  blockingMenu.debugSection().appendItem(
1937
- isBlocking ? i18nString(UIStrings.unblockS, {PH1: urlPattern.constructorString}) :
1938
- i18nString(UIStrings.blockRequestUrl),
1938
+ isBlocking ? i18nString(UIStrings.unblockS, {PH1: croppedURL}) : i18nString(UIStrings.blockRequestUrl),
1939
1939
  () => isBlocking ? removeRequestCondition(urlPattern) :
1940
1940
  addRequestCondition(urlPattern, SDK.NetworkManager.BlockingConditions),
1941
1941
  {jslogContext: 'block-request-url'});
1942
1942
  throttlingMenu.debugSection().appendItem(
1943
- isThrottling ? i18nString(UIStrings.unthrottleS, {PH1: urlPattern.constructorString}) :
1943
+ isThrottling ? i18nString(UIStrings.unthrottleS, {PH1: croppedURL}) :
1944
1944
  i18nString(UIStrings.throttleRequestUrl),
1945
1945
  () => isThrottling ? removeRequestCondition(urlPattern) :
1946
1946
  addRequestCondition(urlPattern, SDK.NetworkManager.Slow3GConditions),
@@ -1959,14 +1959,14 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
1959
1959
  const isThrottling = existingConditions &&
1960
1960
  existingConditions.conditions !== SDK.NetworkManager.BlockingConditions &&
1961
1961
  existingConditions.conditions !== SDK.NetworkManager.NoThrottlingConditions;
1962
+ const croppedURL = Platform.StringUtilities.trimMiddle(domainPattern.constructorString, maxBlockedURLLength);
1962
1963
  blockingMenu.debugSection().appendItem(
1963
- isBlocking ? i18nString(UIStrings.unblockS, {PH1: domainPattern.constructorString}) :
1964
- i18nString(UIStrings.blockRequestDomain),
1964
+ isBlocking ? i18nString(UIStrings.unblockS, {PH1: croppedURL}) : i18nString(UIStrings.blockRequestDomain),
1965
1965
  () => isBlocking ? removeRequestCondition(domainPattern) :
1966
1966
  addRequestCondition(domainPattern, SDK.NetworkManager.BlockingConditions),
1967
1967
  {jslogContext: 'block-request-domain'});
1968
1968
  throttlingMenu.debugSection().appendItem(
1969
- isThrottling ? i18nString(UIStrings.unthrottleS, {PH1: domainPattern.constructorString}) :
1969
+ isThrottling ? i18nString(UIStrings.unthrottleS, {PH1: croppedURL}) :
1970
1970
  i18nString(UIStrings.throttleRequestDomain),
1971
1971
  () => isThrottling ? removeRequestCondition(domainPattern) :
1972
1972
  addRequestCondition(domainPattern, SDK.NetworkManager.Slow3GConditions),
@@ -37,7 +37,7 @@ const str_ = i18n.i18n.registerUIStrings('panels/network/RequestInitiatorView.ts
37
37
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
38
38
  export interface ViewInput {
39
39
  initiatorGraph: Logs.NetworkLog.InitiatorGraph;
40
- hasStackTrace: boolean;
40
+ stackTrace: StackTrace.StackTrace.StackTrace|null;
41
41
  request: SDK.NetworkRequest.NetworkRequest;
42
42
  linkifier: Components.Linkifier.Linkifier;
43
43
  target?: SDK.Target.Target;
@@ -45,7 +45,7 @@ export interface ViewInput {
45
45
 
46
46
  export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLElement): void => {
47
47
  const hasInitiatorData =
48
- input.initiatorGraph.initiators.size > 1 || input.initiatorGraph.initiated.size > 1 || input.hasStackTrace;
48
+ input.initiatorGraph.initiators.size > 1 || input.initiatorGraph.initiated.size > 1 || input.stackTrace;
49
49
 
50
50
  if (!hasInitiatorData) {
51
51
  render(
@@ -59,6 +59,9 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLE
59
59
  }
60
60
 
61
61
  const renderStackTraceSection = (): Lit.TemplateResult => {
62
+ if (!input.stackTrace) {
63
+ return html`${nothing}`;
64
+ }
62
65
  return html`
63
66
  <li role="treeitem" class="request-initiator-view-section-title" aria-expanded="true">
64
67
  ${i18nString(UIStrings.requestCallStack)}
@@ -67,7 +70,8 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLE
67
70
  <devtools-widget .widgetConfig=${widgetConfig(Components.JSPresentationUtils.StackTracePreviewContent, {
68
71
  target: input.target,
69
72
  linkifier: input.linkifier,
70
- options: {runtimeStackTrace: input.request.initiator()?.stack, tabStops: true}
73
+ options: {tabStops: true},
74
+ stackTrace: input.stackTrace,
71
75
  })}></devtools-widget>
72
76
  </li>
73
77
  </ul>
@@ -146,7 +150,7 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLE
146
150
  ${requestInitiatorViewTreeStyles}
147
151
  </style>
148
152
  <ul role="tree">
149
- ${input.hasStackTrace ? renderStackTraceSection() : Lit.nothing}
153
+ ${renderStackTraceSection()}
150
154
  ${
151
155
  (input.initiatorGraph.initiators.size > 1 || input.initiatorGraph.initiated.size > 1) ?
152
156
  renderInitiatorChain(input.initiatorGraph) :
@@ -198,15 +202,22 @@ export class RequestInitiatorView extends UI.Widget.VBox {
198
202
  return {preview, stackTrace};
199
203
  }
200
204
 
201
- override performUpdate(): void {
205
+ override async performUpdate(): Promise<void> {
202
206
  const initiatorGraph = Logs.NetworkLog.NetworkLog.instance().initiatorGraphForRequest(this.request);
203
- const hasStackTrace = !!this.request.initiator()?.stack;
207
+ const targetManager = SDK.TargetManager.TargetManager.instance();
204
208
  const networkManager = SDK.NetworkManager.NetworkManager.forRequest(this.request);
205
- const target = networkManager ? networkManager.target() : undefined;
209
+ const target = networkManager?.target() ?? targetManager.primaryPageTarget() ?? targetManager.rootTarget();
210
+
211
+ const rawStack = this.request.initiator()?.stack;
212
+ let stackTrace: StackTrace.StackTrace.StackTrace|null = null;
213
+ if (rawStack && target) {
214
+ stackTrace = await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance()
215
+ .createStackTraceFromProtocolRuntime(rawStack, target);
216
+ }
206
217
 
207
218
  const viewInput: ViewInput = {
208
219
  initiatorGraph,
209
- hasStackTrace,
220
+ stackTrace,
210
221
  request: this.request,
211
222
  linkifier: this.linkifier,
212
223
  target: target || undefined,
@@ -10,7 +10,6 @@ import * as i18n from '../../core/i18n/i18n.js';
10
10
  import type * as Platform from '../../core/platform/platform.js';
11
11
  import * as Root from '../../core/root/root.js';
12
12
  import * as AiAssistanceModel from '../../models/ai_assistance/ai_assistance.js';
13
- import * as AiCodeGeneration from '../../models/ai_code_generation/ai_code_generation.js';
14
13
  import * as Buttons from '../../ui/components/buttons/buttons.js';
15
14
  import * as Input from '../../ui/components/input/input.js';
16
15
  import * as Switch from '../../ui/components/switch/switch.js';
@@ -537,10 +536,7 @@ export class AISettingsTab extends UI.Widget.VBox {
537
536
  }
538
537
 
539
538
  if (this.#aiCodeCompletionSetting) {
540
- const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
541
- const isAiCodeGenerationEnabled =
542
- AiCodeGeneration.AiCodeGeneration.AiCodeGeneration.isAiCodeGenerationEnabled(devtoolsLocale.locale);
543
- const settingItems = isAiCodeGenerationEnabled ?
539
+ const settingItems = Root.Runtime.hostConfig.devToolsAiCodeGeneration?.enabled ?
544
540
  [
545
541
  {iconName: 'code', text: i18nString(UIStrings.asYouTypeRelevantDataIsBeingSentToGoogle)}, {
546
542
  iconName: 'text-analysis',
@@ -631,16 +631,6 @@ const GREENDEV_VIEW: View = (input, _output, target) => {
631
631
  ${renderPrototypeCheckboxes(input.settings, ['aiAnnotations', 'inDevToolsFloaty', 'copyToGemini'])}
632
632
  </div>
633
633
  </devtools-card>
634
-
635
- <devtools-card .heading=${'GreenDev widgets'}>
636
- <div class="experiments-warning-subsection">
637
- <devtools-icon .name=${'warning'}></devtools-icon>
638
- <span>${i18nString(UIStrings.greenDevUnstable)}</span>
639
- </div>
640
- <div class="settings-experiments-block greendev-widgets">
641
- ${renderWidgetOptions(input.settings)}
642
- </div>
643
- </devtools-card>
644
634
  </div>
645
635
  `, target);
646
636
  // clang-format on
@@ -649,50 +639,9 @@ const GREENDEV_VIEW: View = (input, _output, target) => {
649
639
  const GREENDEV_PROTOTYPE_NAMES: Record<keyof GreenDev.GreenDevSettings, string> = {
650
640
  inDevToolsFloaty: 'In DevTools context picker',
651
641
  aiAnnotations: 'AI auto-annotations',
652
- inlineWidgets: 'Inline widgets in AI Assistance',
653
- artifactViewer: 'Widgets in the Artifact viewer',
654
642
  copyToGemini: 'Copy changes to AI Prompt'
655
643
  };
656
644
 
657
- function renderWidgetOptions(settings: GreenDev.GreenDevSettings): TemplateResult {
658
- function onChange(nowActiveRadio: 'inlineWidgets'|'artifactViewer'|'none') {
659
- return () => {
660
- switch (nowActiveRadio) {
661
- case 'inlineWidgets': {
662
- settings.artifactViewer.set(false);
663
- settings.inlineWidgets.set(true);
664
- break;
665
- }
666
- case 'artifactViewer': {
667
- settings.artifactViewer.set(true);
668
- settings.inlineWidgets.set(false);
669
- break;
670
- }
671
- case 'none': {
672
- settings.artifactViewer.set(false);
673
- settings.inlineWidgets.set(false);
674
- }
675
- }
676
-
677
- UI.InspectorView.InspectorView.instance().displayReloadRequiredWarning(
678
- i18nString(UIStrings.settingsChangedReloadDevTools));
679
- };
680
- }
681
- // clang-format off
682
- return html`
683
- <p class="settings-experiment">
684
- <label><input type="radio" name="widgets-choice" @change=${onChange('inlineWidgets')}>${GREENDEV_PROTOTYPE_NAMES['inlineWidgets']}</label>
685
- </p>
686
- <p class="settings-experiment">
687
- <label><input type="radio" name="widgets-choice" @change=${onChange('artifactViewer')}>${GREENDEV_PROTOTYPE_NAMES['artifactViewer']}</label>
688
- </p>
689
- <p class="settings-experiment">
690
- <label><input type="radio" name="widgets-choice" @change=${onChange('none')}>None</label>
691
- </p>
692
- `;
693
- // clang-format on
694
- }
695
-
696
645
  function renderPrototypeCheckboxes(
697
646
  settings: GreenDev.GreenDevSettings,
698
647
  keys: Array<keyof GreenDev.GreenDevSettings>,
@@ -48,7 +48,10 @@ export class AnimationsTrackAppender implements TrackAppender {
48
48
  }
49
49
 
50
50
  #appendTrackHeaderAtLevel(currentLevel: number, expanded?: boolean): void {
51
- const style = buildGroupStyle({useFirstLineForOverview: false});
51
+ const style = buildGroupStyle({
52
+ useFirstLineForOverview: false,
53
+ collapsible: PerfUI.FlameChart.GroupCollapsibleState.IF_MULTI_ROW,
54
+ });
52
55
  const group = buildTrackHeader(
53
56
  VisualLoggingTrackName.ANIMATIONS, currentLevel, i18nString(UIStrings.animations), style,
54
57
  /* selectable= */ true, expanded);
@@ -71,7 +71,7 @@ export class InteractionsTrackAppender implements TrackAppender {
71
71
  #appendTrackHeaderAtLevel(currentLevel: number, expanded?: boolean): void {
72
72
  const trackIsCollapsible = this.#parsedTrace.data.UserInteractions.interactionEvents.length > 0;
73
73
  const style = buildGroupStyle({
74
- collapsible: trackIsCollapsible ? PerfUI.FlameChart.GroupCollapsibleState.ALWAYS :
74
+ collapsible: trackIsCollapsible ? PerfUI.FlameChart.GroupCollapsibleState.IF_MULTI_ROW :
75
75
  PerfUI.FlameChart.GroupCollapsibleState.NEVER,
76
76
  useDecoratorsForOverview: true,
77
77
  });