chrome-devtools-frontend 1.0.1581449 → 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 (95) hide show
  1. package/agents/prompts/merging-devtools-module.md +144 -0
  2. package/agents/prompts/ui-widgets.md +351 -0
  3. package/agents/prompts/verification.md +2 -1
  4. package/docs/contributing/README.md +5 -6
  5. package/docs/contributing/changes.md +1 -2
  6. package/docs/styleguide/ux/README.md +1 -1
  7. package/front_end/core/sdk/OverlayModel.ts +4 -2
  8. package/front_end/core/sdk/RemoteObject.ts +7 -1
  9. package/front_end/core/sdk/StorageKeyManager.ts +6 -1
  10. package/front_end/core/sdk/Target.ts +4 -2
  11. package/front_end/entrypoint_template.html +5 -1
  12. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +31 -40
  13. package/front_end/entrypoints/greendev_floaty/floaty.css +41 -1
  14. package/front_end/entrypoints/greendev_floaty/floaty.html +8 -1
  15. package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +5 -5
  16. package/front_end/entrypoints/node_app/app/NodeMain.ts +19 -1
  17. package/front_end/entrypoints/node_app/node_app.ts +34 -0
  18. package/front_end/generated/InspectorBackendCommands.ts +1 -1
  19. package/front_end/generated/SupportedCSSProperties.js +2 -0
  20. package/front_end/generated/protocol.ts +0 -6
  21. package/front_end/models/ai_assistance/AiConversation.ts +10 -0
  22. package/front_end/models/ai_assistance/agents/AiAgent.ts +2 -0
  23. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +26 -4
  24. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +85 -7
  25. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +2 -6
  26. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +66 -2
  27. package/front_end/models/computed_style/ComputedStyleModel.ts +26 -0
  28. package/front_end/models/greendev/Prototypes.ts +1 -10
  29. package/front_end/models/issues_manager/ConnectionAllowlistIssue.ts +75 -0
  30. package/front_end/models/issues_manager/CookieIssue.ts +0 -28
  31. package/front_end/models/issues_manager/FederatedAuthRequestIssue.ts +0 -30
  32. package/front_end/models/issues_manager/IssuesManager.ts +5 -0
  33. package/front_end/models/issues_manager/descriptions/connectionAllowlistInvalidAllowlistItemType.md +12 -0
  34. package/front_end/models/issues_manager/descriptions/connectionAllowlistInvalidHeader.md +12 -0
  35. package/front_end/models/issues_manager/descriptions/connectionAllowlistInvalidUrlPattern.md +8 -0
  36. package/front_end/models/issues_manager/descriptions/connectionAllowlistItemNotInnerList.md +12 -0
  37. package/front_end/models/issues_manager/descriptions/connectionAllowlistMoreThanOneList.md +7 -0
  38. package/front_end/models/issues_manager/descriptions/connectionAllowlistReportingEndpointNotToken.md +10 -0
  39. package/front_end/models/issues_manager/issues_manager.ts +2 -0
  40. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +93 -6
  41. package/front_end/panels/ai_assistance/components/ChatInput.ts +8 -4
  42. package/front_end/panels/application/ApplicationPanelSidebar.ts +13 -11
  43. package/front_end/panels/application/DOMStorageModel.ts +1 -1
  44. package/front_end/panels/application/ResourcesPanel.ts +10 -5
  45. package/front_end/panels/application/preloading/PreloadingView.ts +8 -1
  46. package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +4 -1
  47. package/front_end/panels/application/preloading/components/PreloadingGrid.ts +2 -1
  48. package/front_end/panels/application/preloading/components/PreloadingString.ts +12 -3
  49. package/front_end/panels/application/preloading/helper/PreloadingForward.ts +14 -0
  50. package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +37 -3
  51. package/front_end/panels/changes/ChangesSidebar.ts +2 -6
  52. package/front_end/panels/common/AiCodeCompletionTeaser.ts +13 -3
  53. package/front_end/panels/common/aiCodeCompletionTeaser.css +6 -0
  54. package/front_end/panels/console/ConsoleSidebar.ts +3 -11
  55. package/front_end/panels/console_counters/WarningErrorCounter.ts +16 -10
  56. package/front_end/panels/elements/ComputedStyleWidget.ts +55 -37
  57. package/front_end/panels/elements/PlatformFontsWidget.ts +23 -10
  58. package/front_end/panels/greendev/GreenDevPanel.css +42 -1
  59. package/front_end/panels/greendev/GreenDevPanel.ts +30 -1
  60. package/front_end/panels/lighthouse/LighthouseStartView.ts +3 -5
  61. package/front_end/panels/lighthouse/lighthouseStartView.css +6 -0
  62. package/front_end/panels/network/NetworkLogView.ts +6 -6
  63. package/front_end/panels/network/RequestInitiatorView.ts +27 -19
  64. package/front_end/panels/network/RequestTimingView.ts +1 -1
  65. package/front_end/panels/settings/AISettingsTab.ts +1 -5
  66. package/front_end/panels/settings/KeybindsSettingsTab.ts +4 -3
  67. package/front_end/panels/settings/SettingsScreen.ts +0 -51
  68. package/front_end/panels/sources/OutlineQuickOpen.ts +19 -0
  69. package/front_end/panels/timeline/AnimationsTrackAppender.ts +4 -1
  70. package/front_end/panels/timeline/InteractionsTrackAppender.ts +1 -1
  71. package/front_end/panels/timeline/TimelinePanel.ts +25 -0
  72. package/front_end/panels/timeline/TimelineUIUtils.ts +13 -16
  73. package/front_end/third_party/chromium/README.chromium +1 -1
  74. package/front_end/third_party/lighthouse/README.chromium +2 -2
  75. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +145 -144
  76. package/front_end/third_party/lighthouse/report/bundle.js +12 -5
  77. package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +2 -2
  78. package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +5 -1
  79. package/front_end/ui/legacy/ListControl.ts +28 -1
  80. package/front_end/ui/legacy/Toolbar.ts +4 -4
  81. package/front_end/ui/legacy/Treeoutline.ts +5 -5
  82. package/front_end/ui/legacy/UIUtils.ts +26 -10
  83. package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +10 -13
  84. package/front_end/ui/legacy/components/utils/Linkifier.ts +4 -7
  85. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
  86. package/inspector_overlay/main.ts +18 -3
  87. package/inspector_overlay/tool_green_dev_anchors.css +54 -0
  88. package/inspector_overlay/tool_green_dev_anchors.ts +164 -0
  89. package/inspector_overlay/tool_persistent.ts +14 -0
  90. package/package.json +1 -1
  91. package/docs/contributing/design.md +0 -166
  92. package/docs/design_guidelines.md +0 -1
  93. package/front_end/models/issues_manager/descriptions/federatedAuthRequestClientMetadataHttpNotFound.md +0 -1
  94. package/front_end/models/issues_manager/descriptions/federatedAuthRequestClientMetadataInvalidResponse.md +0 -1
  95. package/front_end/models/issues_manager/descriptions/federatedAuthRequestClientMetadataNoResponse.md +0 -1
@@ -12,9 +12,11 @@ import * as IssuesManager from '../../models/issues_manager/issues_manager.js';
12
12
  import type * as IconButton from '../../ui/components/icon_button/icon_button.js';
13
13
  import * as IssueCounter from '../../ui/components/issue_counter/issue_counter.js';
14
14
  import * as UI from '../../ui/legacy/legacy.js';
15
- import {html, nothing, render} from '../../ui/lit/lit.js';
15
+ import * as Lit from '../../ui/lit/lit.js';
16
16
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
17
17
 
18
+ const {html, nothing, render} = Lit;
19
+
18
20
  const UIStrings = {
19
21
  /**
20
22
  * @description The console error count in the Warning Error Counter shown in the main toolbar (top-left in DevTools). The error count refers to the number of errors currently present in the JavaScript console.
@@ -95,21 +97,25 @@ const DEFAULT_VIEW: View = (input, _output, target) => {
95
97
 
96
98
  render(
97
99
  html`<div class="status-buttons"
98
- ><icon-button
100
+ >${
101
+ errors + warnings ? html`<icon-button
99
102
  .data=${iconData}
100
103
  title=${consoleTitle}
101
- class=${'small' + warnings || errors ? nothing as unknown as string : 'hidden'}
104
+ class=${'small'}
102
105
  jslog=${VisualLogging.counter('console').track({
103
- click: true
104
- })}
105
- ></icon-button><devtools-issue-counter
106
- class=${'main-toolbar' + (issues ? '' : ' hidden')}
106
+ click: true
107
+ })}
108
+ ></icon-button>` :
109
+ nothing}${
110
+ issues ? html`<devtools-issue-counter
111
+ class=${'main-toolbar'}
107
112
  title=${issuesTitle}
108
113
  .data=${issueCounterData}
109
114
  jslog=${VisualLogging.counter('issue').track({
110
- click: true
111
- })}
112
- ></devtools-issue-counter></div>`,
115
+ click: true
116
+ })}
117
+ ></devtools-issue-counter>` :
118
+ nothing}</div>`,
113
119
  target);
114
120
  };
115
121
 
@@ -53,7 +53,7 @@ import {categorizePropertyName, type Category, DefaultCategoryOrder} from './Pro
53
53
  import {Renderer, rendererBase, type RenderingContext, StringRenderer, URLRenderer} from './PropertyRenderer.js';
54
54
  import {StylePropertiesSection} from './StylePropertiesSection.js';
55
55
 
56
- const {html} = Lit;
56
+ const {html, render} = Lit;
57
57
 
58
58
  const UIStrings = {
59
59
  /**
@@ -197,7 +197,7 @@ const createTraceElement =
197
197
  return trace;
198
198
  };
199
199
 
200
- /** clang-format off **/
200
+ // clang-format off
201
201
  class ColorRenderer extends rendererBase(SDK.CSSPropertyParserMatchers.ColorMatch) {
202
202
  // clang-format on
203
203
  override render(match: SDK.CSSPropertyParserMatchers.ColorMatch, context: RenderingContext): Node[] {
@@ -261,21 +261,47 @@ type ComputedStyleData = {
261
261
  name: string,
262
262
  };
263
263
 
264
+ interface ComputedStyleWidgetInput {
265
+ computedStylesTree: TreeOutline.TreeOutline.TreeOutline<ComputedStyleData>;
266
+ toolbar: HTMLElement;
267
+ hasMatches: boolean;
268
+ computedStyleModel: ComputedStyleModule.ComputedStyleModel.ComputedStyleModel;
269
+ }
270
+
271
+ type View = (input: ComputedStyleWidgetInput, output: null, target: HTMLElement) => void;
272
+
273
+ export const DEFAULT_VIEW: View = (input, _output, target) => {
274
+ // clang-format off
275
+ render(html`
276
+ <div class="styles-sidebar-pane-toolbar">${input.toolbar}</div>
277
+ <div class="computed-style-tree-outline-container">
278
+ ${input.computedStylesTree}
279
+ </div>
280
+ ${!input.hasMatches ? html`<div class="gray-info-message">${i18nString(UIStrings.noMatchingProperty)}</div>` : ''}
281
+ <div class="platform-fonts-widget-container">
282
+ <devtools-widget .widgetConfig=${UI.Widget.widgetConfig(PlatformFontsWidget, { sharedModel: input.computedStyleModel})}></devtools-widget>
283
+ </div>
284
+ `, target);
285
+ // clang-format on
286
+ };
287
+
264
288
  export class ComputedStyleWidget extends UI.Widget.VBox {
265
289
  private computedStyleModel: ComputedStyleModule.ComputedStyleModel.ComputedStyleModel;
266
290
  private readonly showInheritedComputedStylePropertiesSetting: Common.Settings.Setting<boolean>;
267
291
  private readonly groupComputedStylesSetting: Common.Settings.Setting<boolean>;
268
292
  input: UI.Toolbar.ToolbarInput;
269
293
  private filterRegex: RegExp|null;
270
- private readonly noMatchesElement: HTMLElement;
271
294
  private readonly linkifier: Components.Linkifier.Linkifier;
272
295
  private readonly imagePreviewPopover: ImagePreviewPopover;
273
296
 
274
297
  #computedStylesTree = new TreeOutline.TreeOutline.TreeOutline<ComputedStyleData>();
275
298
  #treeData?: TreeOutline.TreeOutline.TreeOutlineData<ComputedStyleData>;
299
+ readonly #view: View;
300
+ private readonly toolbarElement: HTMLElement;
276
301
 
277
302
  constructor(computedStyleModel: ComputedStyleModule.ComputedStyleModel.ComputedStyleModel) {
278
303
  super({useShadowDom: true});
304
+ this.#view = DEFAULT_VIEW;
279
305
  this.registerRequiredCSS(computedStyleSidebarPaneStyles);
280
306
 
281
307
  this.contentElement.classList.add('styles-sidebar-computed-style-widget');
@@ -295,8 +321,12 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
295
321
  this.requestUpdate();
296
322
  });
297
323
 
298
- const hbox = this.contentElement.createChild('div', 'hbox styles-sidebar-pane-toolbar');
299
- const toolbar = hbox.createChild('devtools-toolbar', 'styles-pane-toolbar');
324
+ this.toolbarElement = document.createElement('div');
325
+ this.toolbarElement.classList.add('hbox', 'styles-sidebar-pane-toolbar');
326
+ const toolbar = document.createElement('devtools-toolbar');
327
+ toolbar.classList.add('styles-pane-toolbar');
328
+ this.toolbarElement.appendChild(toolbar);
329
+
300
330
  const filterInput = new UI.Toolbar.ToolbarFilter(undefined, 1, 1, undefined, undefined, false);
301
331
  filterInput.addEventListener(UI.Toolbar.ToolbarInput.Event.TEXT_CHANGED, this.onFilterChanged, this);
302
332
  toolbar.appendToolbarItem(filterInput);
@@ -308,11 +338,6 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
308
338
  toolbar.appendToolbarItem(
309
339
  new UI.Toolbar.ToolbarSettingCheckbox(this.groupComputedStylesSetting, undefined, i18nString(UIStrings.group)));
310
340
 
311
- this.noMatchesElement = this.contentElement.createChild('div', 'gray-info-message');
312
- this.noMatchesElement.textContent = i18nString(UIStrings.noMatchingProperty);
313
-
314
- this.contentElement.appendChild(this.#computedStylesTree);
315
-
316
341
  this.linkifier = new Components.Linkifier.Linkifier(maxLinkLength);
317
342
 
318
343
  this.imagePreviewPopover = new ImagePreviewPopover(this.contentElement, event => {
@@ -323,8 +348,7 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
323
348
  return null;
324
349
  }, () => this.computedStyleModel.node);
325
350
 
326
- const fontsWidget = new PlatformFontsWidget(this.computedStyleModel);
327
- fontsWidget.show(this.contentElement);
351
+ this.#updateView({hasMatches: true});
328
352
  }
329
353
 
330
354
  override onResize(): void {
@@ -342,11 +366,24 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
342
366
  UI.Context.Context.instance().setFlavor(ComputedStyleWidget, null);
343
367
  }
344
368
 
369
+ /**
370
+ * @param input.hasMatches Whether any properties matched the current filter (or if any properties exist at all).
371
+ */
372
+ #updateView({hasMatches}: {hasMatches: boolean}): void {
373
+ this.#view(
374
+ {
375
+ computedStylesTree: this.#computedStylesTree,
376
+ toolbar: this.toolbarElement,
377
+ hasMatches,
378
+ computedStyleModel: this.computedStyleModel,
379
+ },
380
+ null, this.contentElement);
381
+ }
382
+
345
383
  override async performUpdate(): Promise<void> {
346
- const [nodeStyles, matchedStyles] =
347
- await Promise.all([this.computedStyleModel.fetchComputedStyle(), this.fetchMatchedCascade()]);
384
+ const {computedStyle: nodeStyles, matchedStyles} = await this.computedStyleModel.fetchAllComputedStyleInfo();
348
385
  if (!nodeStyles || !matchedStyles) {
349
- this.noMatchesElement.classList.remove('hidden');
386
+ this.#updateView({hasMatches: false});
350
387
  return;
351
388
  }
352
389
  const shouldGroupComputedStyles = this.groupComputedStylesSetting.get();
@@ -357,25 +394,6 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
357
394
  }
358
395
  }
359
396
 
360
- private async fetchMatchedCascade(): Promise<SDK.CSSMatchedStyles.CSSMatchedStyles|null> {
361
- const node = this.computedStyleModel.node;
362
- if (!node || !this.computedStyleModel.cssModel()) {
363
- return null;
364
- }
365
-
366
- const cssModel = this.computedStyleModel.cssModel();
367
- if (!cssModel) {
368
- return null;
369
- }
370
-
371
- return await cssModel.cachedMatchedCascadeForNode(node).then(validateStyles.bind(this));
372
-
373
- function validateStyles(this: ComputedStyleWidget, matchedStyles: SDK.CSSMatchedStyles.CSSMatchedStyles|null):
374
- SDK.CSSMatchedStyles.CSSMatchedStyles|null {
375
- return matchedStyles && matchedStyles.node() === this.computedStyleModel.node ? matchedStyles : null;
376
- }
377
- }
378
-
379
397
  private async rebuildAlphabeticalList(
380
398
  nodeStyle: ComputedStyleModule.ComputedStyleModel.ComputedStyle,
381
399
  matchedStyles: SDK.CSSMatchedStyles.CSSMatchedStyles): Promise<void> {
@@ -426,7 +444,7 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
426
444
  this.linkifier.reset();
427
445
  const cssModel = this.computedStyleModel.cssModel();
428
446
  if (!nodeStyle || !matchedStyles || !cssModel) {
429
- this.noMatchesElement.classList.remove('hidden');
447
+ this.#updateView({hasMatches: false});
430
448
  return;
431
449
  }
432
450
 
@@ -648,7 +666,7 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
648
666
  defaultRenderer: this.#treeData.defaultRenderer,
649
667
  compact: this.#treeData.compact,
650
668
  };
651
- this.noMatchesElement.classList.toggle('hidden', Boolean(tree.length));
669
+ this.#updateView({hasMatches: Boolean(tree.length)});
652
670
  }
653
671
 
654
672
  private async filterGroupLists(): Promise<void> {
@@ -675,7 +693,7 @@ export class ComputedStyleWidget extends UI.Widget.VBox {
675
693
  compact: this.#treeData.compact,
676
694
  };
677
695
  await this.#computedStylesTree.expandRecursively(0);
678
- this.noMatchesElement.classList.toggle('hidden', Boolean(tree.length));
696
+ this.#updateView({hasMatches: Boolean(tree.length)});
679
697
  }
680
698
  }
681
699
 
@@ -78,24 +78,37 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
78
78
  };
79
79
 
80
80
  export class PlatformFontsWidget extends UI.Widget.VBox {
81
- private readonly sharedModel: ComputedStyle.ComputedStyleModel.ComputedStyleModel;
82
81
  readonly #view: View;
82
+ #sharedModel: ComputedStyle.ComputedStyleModel.ComputedStyleModel|null = null;
83
83
 
84
- constructor(sharedModel: ComputedStyle.ComputedStyleModel.ComputedStyleModel, view: View = DEFAULT_VIEW) {
85
- super({useShadowDom: true});
84
+ constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
85
+ super(element, {useShadowDom: true});
86
86
  this.#view = view;
87
87
  this.registerRequiredCSS(platformFontsWidgetStyles);
88
+ }
89
+
90
+ get sharedModel(): ComputedStyle.ComputedStyleModel.ComputedStyleModel|null {
91
+ return this.#sharedModel;
92
+ }
93
+
94
+ set sharedModel(model: ComputedStyle.ComputedStyleModel.ComputedStyleModel) {
95
+ if (model !== this.sharedModel) {
96
+ this.sharedModel?.removeEventListener(
97
+ ComputedStyle.ComputedStyleModel.Events.CSS_MODEL_CHANGED, this.requestUpdate, this);
98
+ this.sharedModel?.removeEventListener(
99
+ ComputedStyle.ComputedStyleModel.Events.COMPUTED_STYLE_CHANGED, this.requestUpdate, this);
100
+
101
+ model.addEventListener(ComputedStyle.ComputedStyleModel.Events.CSS_MODEL_CHANGED, this.requestUpdate, this);
102
+ model.addEventListener(ComputedStyle.ComputedStyleModel.Events.COMPUTED_STYLE_CHANGED, this.requestUpdate, this);
103
+ }
88
104
 
89
- this.sharedModel = sharedModel;
90
- this.sharedModel.addEventListener(
91
- ComputedStyle.ComputedStyleModel.Events.CSS_MODEL_CHANGED, this.requestUpdate, this);
92
- this.sharedModel.addEventListener(
93
- ComputedStyle.ComputedStyleModel.Events.COMPUTED_STYLE_CHANGED, this.requestUpdate, this);
105
+ this.#sharedModel = model;
106
+ void this.requestUpdate();
94
107
  }
95
108
 
96
109
  override async performUpdate(): Promise<void> {
97
- const cssModel = this.sharedModel.cssModel();
98
- const node = this.sharedModel.node;
110
+ const cssModel = this.#sharedModel?.cssModel();
111
+ const node = this.#sharedModel?.node;
99
112
  if (!node || !cssModel) {
100
113
  this.#view({platformFonts: null}, {}, this.contentElement);
101
114
  return;
@@ -234,8 +234,49 @@
234
234
  }
235
235
 
236
236
  .green-dev-floaty-disclaimer {
237
- font-size: 14px;
237
+ font-size: 15px;
238
238
  color: #666;
239
239
  text-align: center;
240
240
  margin-top: 8px;
241
+ position: relative; /* For tooltip positioning */
242
+ }
243
+
244
+ .disclaimer-link {
245
+ color: #666; /* Match text color */
246
+ text-decoration: underline;
247
+ cursor: pointer;
248
+ }
249
+
250
+ .disclaimer-tooltip {
251
+ display: none;
252
+ position: absolute;
253
+ bottom: 100%; /* Position above */
254
+ left: 50%;
255
+ transform: translateX(-50%);
256
+ width: 300px;
257
+ padding: 12px;
258
+ background-color: #fff;
259
+ border: 1px solid #ccc;
260
+ border-radius: 8px;
261
+ box-shadow: 0 2px 10px rgb(0 0 0 / 20%);
262
+ z-index: 1000;
263
+ text-align: left;
264
+ font-size: 16px;
265
+ line-height: 1.4;
266
+ color: #333;
267
+ white-space: normal; /* Ensure text wraps */
268
+ }
269
+
270
+ .disclaimer-link:hover + .disclaimer-tooltip,
271
+ .disclaimer-tooltip:hover {
272
+ display: block;
273
+ }
274
+
275
+ .learn-more-link {
276
+ color: #0b57d0;
277
+ text-decoration: none;
278
+ }
279
+
280
+ .learn-more-link:hover {
281
+ text-decoration: underline;
241
282
  }
@@ -4,6 +4,8 @@
4
4
  /* eslint-disable @devtools/no-imperative-dom-api */
5
5
 
6
6
  import type * as Common from '../../core/common/common.js';
7
+ import * as Host from '../../core/host/host.js';
8
+ import type * as Platform from '../../core/platform/platform.js';
7
9
  import * as SDK from '../../core/sdk/sdk.js';
8
10
  import type * as Protocol from '../../generated/protocol.js';
9
11
  import * as UI from '../../ui/legacy/legacy.js';
@@ -186,7 +188,34 @@ export class GreenDevPanel extends UI.Panel.Panel {
186
188
 
187
189
  const disclaimer = document.createElement('div');
188
190
  disclaimer.className = 'green-dev-floaty-disclaimer';
189
- disclaimer.textContent = 'Relevant data is sent to Google';
191
+
192
+ const link = document.createElement('span');
193
+ link.className = 'disclaimer-link';
194
+ link.textContent = 'Relevant data';
195
+ disclaimer.appendChild(link);
196
+
197
+ disclaimer.appendChild(document.createTextNode(' is sent to Google'));
198
+
199
+ const tooltip = document.createElement('div');
200
+ tooltip.className = 'disclaimer-tooltip';
201
+
202
+ tooltip.appendChild(document.createTextNode(
203
+ 'Chat messages and any data the inspected page can access via Web APIs are sent to Google and may be seen by human reviewers to improve this feature. This is an experimental AI feature and won\'t always get it right.'));
204
+ tooltip.appendChild(document.createElement('br'));
205
+ tooltip.appendChild(document.createElement('br'));
206
+
207
+ const learnMore = document.createElement('a');
208
+ const href = 'https://developer.chrome.com/docs/devtools/ai-assistance' as Platform.DevToolsPath.UrlString;
209
+ learnMore.href = href;
210
+ learnMore.className = 'learn-more-link';
211
+ learnMore.textContent = 'Learn about AI in DevTools';
212
+ learnMore.addEventListener('click', event => {
213
+ event.preventDefault();
214
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.openInNewTab(href);
215
+ });
216
+ tooltip.appendChild(learnMore);
217
+
218
+ disclaimer.appendChild(tooltip);
190
219
  blueCard.appendChild(disclaimer);
191
220
 
192
221
  content.appendChild(blueCard);
@@ -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) :
@@ -184,32 +188,36 @@ export class RequestInitiatorView extends UI.Widget.VBox {
184
188
  if (!initiator?.stack) {
185
189
  return null;
186
190
  }
191
+ const targetManager = SDK.TargetManager.TargetManager.instance();
187
192
  const networkManager = SDK.NetworkManager.NetworkManager.forRequest(request);
188
- const target = networkManager ? networkManager.target() : undefined;
193
+ const target = networkManager?.target() ?? targetManager.primaryPageTarget() ?? targetManager.rootTarget();
194
+ let stackTrace: StackTrace.StackTrace.StackTrace|null = null;
195
+ const preview = new Components.JSPresentationUtils.StackTracePreviewContent(
196
+ undefined, target ?? undefined, linkifier, {tabStops: focusableLink});
189
197
  if (target) {
190
- const stackTrace = await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance()
191
- .createStackTraceFromProtocolRuntime(initiator.stack, target);
192
- const preview = new Components.JSPresentationUtils.StackTracePreviewContent(
193
- undefined, target, linkifier, {tabStops: focusableLink});
198
+ stackTrace = await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance()
199
+ .createStackTraceFromProtocolRuntime(initiator.stack, target);
194
200
  preview.stackTrace = stackTrace;
195
- return {preview, stackTrace};
196
201
  }
197
- return {
198
- preview: new Components.JSPresentationUtils.StackTracePreviewContent(
199
- undefined, target, linkifier, {runtimeStackTrace: initiator.stack, tabStops: focusableLink}),
200
- stackTrace: null
201
- };
202
+ return {preview, stackTrace};
202
203
  }
203
204
 
204
- override performUpdate(): void {
205
+ override async performUpdate(): Promise<void> {
205
206
  const initiatorGraph = Logs.NetworkLog.NetworkLog.instance().initiatorGraphForRequest(this.request);
206
- const hasStackTrace = !!this.request.initiator()?.stack;
207
+ const targetManager = SDK.TargetManager.TargetManager.instance();
207
208
  const networkManager = SDK.NetworkManager.NetworkManager.forRequest(this.request);
208
- 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
+ }
209
217
 
210
218
  const viewInput: ViewInput = {
211
219
  initiatorGraph,
212
- hasStackTrace,
220
+ stackTrace,
213
221
  request: this.request,
214
222
  linkifier: this.linkifier,
215
223
  target: target || undefined,
@@ -576,7 +576,7 @@ export class RequestTimingView extends UI.Widget.VBox {
576
576
  calculator: this.#calculator,
577
577
  requestStartTime: this.#request.startTime,
578
578
  requestIssueTime: this.#request.issueTime(),
579
- requestUnfinished: false,
579
+ requestUnfinished: !this.#request.finished,
580
580
  fetchDetails: this.#fetchDetailsTree(),
581
581
  routerDetails: this.#routerDetailsTree(),
582
582
  wasThrottled: conditions?.urlPattern ? conditions : 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',
@@ -222,8 +222,9 @@ export class KeybindsSettingsTab extends UI.Widget.VBox implements UI.ListContro
222
222
  return 0;
223
223
  }
224
224
 
225
- isItemSelectable(_item: KeybindsItem): boolean {
226
- return true;
225
+ isItemSelectable(item: KeybindsItem): boolean {
226
+ // Category headers (UI.ActionRegistration.ActionCategory) should not be selectable
227
+ return item instanceof UI.ActionRegistration.Action;
227
228
  }
228
229
 
229
230
  selectedItemChanged(
@@ -314,7 +315,7 @@ export class KeybindsSettingsTab extends UI.Widget.VBox implements UI.ListContro
314
315
  }
315
316
  this.list.refreshAllItems();
316
317
  if (!this.list.selectedItem()) {
317
- this.list.selectItem(this.items.at(0));
318
+ this.list.selectFirstItem();
318
319
  }
319
320
  }
320
321