chrome-devtools-frontend 1.0.1611825 → 1.0.1613625

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 (56) hide show
  1. package/.agents/skills/verification/SKILL.md +5 -1
  2. package/front_end/Images/src/flowsheet.svg +1 -0
  3. package/front_end/core/common/Color.ts +3 -2
  4. package/front_end/core/common/MapWithDefault.ts +2 -2
  5. package/front_end/core/common/Object.ts +9 -6
  6. package/front_end/core/platform/StringUtilities.ts +5 -0
  7. package/front_end/core/sdk/NetworkManager.ts +7 -0
  8. package/front_end/generated/InspectorBackendCommands.ts +2 -2
  9. package/front_end/generated/protocol.ts +12 -2
  10. package/front_end/models/ai_assistance/agents/README.md +77 -0
  11. package/front_end/models/greendev/Prototypes.ts +7 -4
  12. package/front_end/models/har/HARFormat.ts +30 -0
  13. package/front_end/models/har/Importer.ts +12 -1
  14. package/front_end/models/har/Log.ts +28 -0
  15. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +6 -4
  16. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +62 -22
  17. package/front_end/panels/ai_assistance/PatchWidget.ts +7 -23
  18. package/front_end/panels/ai_assistance/SelectWorkspaceDialog.ts +3 -3
  19. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +7 -0
  20. package/front_end/panels/ai_assistance/ai_assistance.ts +1 -0
  21. package/front_end/panels/ai_assistance/components/ChatMessage.ts +13 -3
  22. package/front_end/panels/ai_assistance/components/ChatView.ts +4 -0
  23. package/front_end/panels/ai_assistance/components/ExportForAgentsDialog.ts +14 -7
  24. package/front_end/panels/ai_assistance/components/OptInChangeDialog.ts +179 -0
  25. package/front_end/panels/ai_assistance/components/WalkthroughView.ts +4 -3
  26. package/front_end/panels/ai_assistance/components/optInChangeDialog.css +95 -0
  27. package/front_end/panels/ai_assistance/components/walkthroughView.css +1 -1
  28. package/front_end/panels/application/CookieItemsView.ts +3 -2
  29. package/front_end/panels/changes/ChangesView.ts +0 -12
  30. package/front_end/panels/common/common.ts +0 -1
  31. package/front_end/panels/console/ConsolePrompt.ts +2 -2
  32. package/front_end/panels/elements/StylePropertyTreeElement.ts +2 -1
  33. package/front_end/panels/elements/StylesSidebarPane.ts +6 -2
  34. package/front_end/panels/elements/elements-meta.ts +14 -0
  35. package/front_end/panels/emulation/DeviceModeToolbar.ts +13 -4
  36. package/front_end/panels/network/NetworkLogView.ts +58 -28
  37. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +1 -1
  38. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +9 -17
  39. package/front_end/panels/protocol_monitor/JSONEditor.ts +30 -4
  40. package/front_end/panels/recorder/RecorderController.ts +4 -4
  41. package/front_end/panels/recorder/models/RecordingPlayer.ts +1 -1
  42. package/front_end/panels/settings/AISettingsTab.ts +53 -6
  43. package/front_end/panels/settings/SettingsScreen.ts +2 -2
  44. package/front_end/services/puppeteer/PuppeteerConnection.ts +1 -1
  45. package/front_end/third_party/chromium/README.chromium +1 -1
  46. package/front_end/ui/kit/icons/Icon.ts +1 -0
  47. package/front_end/ui/legacy/SplitWidget.ts +9 -6
  48. package/front_end/ui/legacy/TextPrompt.ts +1 -1
  49. package/front_end/ui/legacy/Treeoutline.ts +3 -2
  50. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +4 -3
  51. package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +3 -3
  52. package/front_end/ui/legacy/components/source_frame/FontView.ts +101 -88
  53. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +4 -4
  54. package/front_end/ui/visual_logging/KnownContextValues.ts +13 -0
  55. package/package.json +2 -2
  56. package/front_end/panels/common/CopyChangesToPrompt.ts +0 -233
@@ -6,13 +6,11 @@ import '../../ui/legacy/legacy.js';
6
6
 
7
7
  import * as i18n from '../../core/i18n/i18n.js';
8
8
  import type * as Platform from '../../core/platform/platform.js';
9
- import * as GreenDev from '../../models/greendev/greendev.js';
10
9
  import type * as Workspace from '../../models/workspace/workspace.js';
11
10
  import * as WorkspaceDiff from '../../models/workspace_diff/workspace_diff.js';
12
11
  import * as UI from '../../ui/legacy/legacy.js';
13
12
  import * as Lit from '../../ui/lit/lit.js';
14
13
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
15
- import * as PanelsCommon from '../common/common.js';
16
14
 
17
15
  import {ChangesSidebar, Events} from './ChangesSidebar.js';
18
16
  import changesViewStyles from './changesView.css.js';
@@ -48,8 +46,6 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
48
46
  Events.SELECTED_UI_SOURCE_CODE_CHANGED, () => input.onSelect(sidebar.selectedUISourceCode()));
49
47
  };
50
48
 
51
- const hasCopyToPrompt = GreenDev.Prototypes.instance().isEnabled('copyToGemini');
52
-
53
49
  render(
54
50
  // clang-format off
55
51
  html`
@@ -70,14 +66,6 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
70
66
  workspaceDiff: input.workspaceDiff
71
67
  })}
72
68
  </div>
73
- ${hasCopyToPrompt ? html`
74
- <devtools-widget class="copy-to-prompt"
75
- ${widget(PanelsCommon.CopyChangesToPrompt, {
76
- workspaceDiff: input.workspaceDiff,
77
- patchAgentCSSChange: null,
78
- })}
79
- ></devtools-widget>
80
- ` : Lit.nothing}
81
69
  </div>
82
70
  <devtools-widget slot="sidebar" ${widget(ChangesSidebar, {workspaceDiff: input.workspaceDiff})}
83
71
  ${UI.Widget.widgetRef(ChangesSidebar, onSidebar)}>
@@ -111,4 +111,3 @@ export * as PersistenceUtils from './PersistenceUtils.js';
111
111
  export * as DOMLinkifier from './DOMLinkifier.js';
112
112
  export * as ThrottlingUtils from './ThrottlingUtils.js';
113
113
  export * as ExtensionIframe from './ExtensionView.js';
114
- export {CopyChangesToPrompt} from './CopyChangesToPrompt.js';
@@ -29,11 +29,11 @@ const UIStrings = {
29
29
  */
30
30
  consolePrompt: 'Console prompt',
31
31
  /**
32
- * @description Warning shown to users when pasting text into the DevTools console.
32
+ * @description Warning shown to users when pasting text into the DevTools console. IMPORTANT: keep double quotes around PH1 and do not use single quotes.
33
33
  * @example {allow pasting} PH1
34
34
  */
35
35
  selfXssWarning:
36
- 'Warning: Don’t paste code into the DevTools Console that you don’t understand or haven’t reviewed yourself. This could allow attackers to steal your identity or take control of your computer. Please type {PH1} below and press Enter to allow pasting.',
36
+ 'Warning: Don’t paste code into the DevTools Console that you don’t understand or haven’t reviewed yourself. This could allow attackers to steal your identity or take control of your computer. Please type {PH1} below and press Enter to allow pasting.',
37
37
  /**
38
38
  * @description Text a user needs to type in order to confirm that they are aware of the danger of pasting code into the DevTools console.
39
39
  */
@@ -2782,7 +2782,8 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
2782
2782
  existingElement?.remove();
2783
2783
  }
2784
2784
 
2785
- if (!this.overriddenByAnimation() || UI.ViewManager.ViewManager.instance().isViewVisible('animations')) {
2785
+ if (!this.overriddenByAnimation() || UI.ViewManager.ViewManager.instance().isViewVisible('animations') ||
2786
+ !Common.Settings.Settings.instance().moduleSetting('css-animations-only-when-animations-tab-open').get()) {
2786
2787
  return;
2787
2788
  }
2788
2789
 
@@ -1096,10 +1096,12 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
1096
1096
  // the matched styles we reenable the button.
1097
1097
  LayersWidget.ButtonProvider.instance().item().setVisible(false);
1098
1098
  const animationsPanelVisible = UI.ViewManager.ViewManager.instance().isViewVisible('animations');
1099
+ const cssAnimationsOnlyWhenAnimationsTabOpen =
1100
+ Common.Settings.Settings.instance().moduleSetting('css-animations-only-when-animations-tab-open').get();
1099
1101
  for (const style of matchedStyles.nodeStyles()) {
1100
1102
  const isTransitionOrAnimationStyle = style.type === SDK.CSSStyleDeclaration.Type.Transition ||
1101
1103
  style.type === SDK.CSSStyleDeclaration.Type.Animation;
1102
- if (isTransitionOrAnimationStyle && !animationsPanelVisible) {
1104
+ if (isTransitionOrAnimationStyle && cssAnimationsOnlyWhenAnimationsTabOpen && !animationsPanelVisible) {
1103
1105
  continue;
1104
1106
  }
1105
1107
 
@@ -2288,7 +2290,7 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
2288
2290
  do {
2289
2291
  if (cursor.name === ':') {
2290
2292
  name = suggestionText.slice(node.from, cursor.from);
2291
- value = suggestionText.slice(cursor.to + 1, node.to);
2293
+ value = suggestionText.slice(cursor.to, node.to);
2292
2294
  }
2293
2295
  } while (cursor.nextSibling());
2294
2296
  }
@@ -2348,6 +2350,8 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
2348
2350
  }
2349
2351
 
2350
2352
  if (suggestionForCurrentPrompt !== textAfterAccept) {
2353
+ // Explicitly set the query range as it is cleared during `acceptAutoComplete`
2354
+ this.queryRange = new TextUtils.TextRange.TextRange(0, 0, 0, textAfterAccept.length);
2351
2355
  // Re-apply the ghost text for the remainder
2352
2356
  this.applySuggestion({text: suggestionForCurrentPrompt}, true);
2353
2357
  }
@@ -163,6 +163,10 @@ const UIStrings = {
163
163
  * @description Command for toggling the eye dropper when the color picker is open
164
164
  */
165
165
  toggleEyeDropper: 'Toggle eye dropper',
166
+ /**
167
+ * @description Title of a setting under the Elements category.
168
+ */
169
+ cssAnimationsOnlyWhenAnimationsTabOpen: 'Show animation styles only when the Animations tab is open',
166
170
  } as const;
167
171
  const str_ = i18n.i18n.registerUIStrings('panels/elements/elements-meta.ts', UIStrings);
168
172
  const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
@@ -569,6 +573,16 @@ Common.Settings.registerSettingExtension({
569
573
  defaultValue: true,
570
574
  });
571
575
 
576
+ Common.Settings.registerSettingExtension({
577
+ category: Common.Settings.SettingCategory.ELEMENTS,
578
+ storageType: Common.Settings.SettingStorageType.SYNCED,
579
+ order: 6,
580
+ title: i18nLazyString(UIStrings.cssAnimationsOnlyWhenAnimationsTabOpen),
581
+ settingName: 'css-animations-only-when-animations-tab-open',
582
+ settingType: Common.Settings.SettingType.BOOLEAN,
583
+ defaultValue: true,
584
+ });
585
+
572
586
  Common.Settings.registerSettingExtension({
573
587
  settingName: 'show-event-listeners-for-ancestors',
574
588
  settingType: Common.Settings.SettingType.BOOLEAN,
@@ -217,6 +217,7 @@ export class DeviceModeToolbar {
217
217
  private widthInput: EmulationComponents.DeviceSizeInputElement.SizeInputElement;
218
218
  private heightInput: EmulationComponents.DeviceSizeInputElement.SizeInputElement;
219
219
  private deviceScaleItem!: UI.Toolbar.ToolbarComboBox;
220
+ private deviceScaleItems: UI.Toolbar.ToolbarItem[] = [];
220
221
  private deviceSelectItem!: UI.Toolbar.ToolbarComboBox;
221
222
  private scaleItem!: UI.Toolbar.ToolbarComboBox;
222
223
  private uaItem!: UI.Toolbar.ToolbarComboBox;
@@ -341,10 +342,14 @@ export class DeviceModeToolbar {
341
342
  this.deviceScaleItem = new UI.Toolbar.ToolbarComboBox(
342
343
  this.onDeviceScaleChange.bind(this), i18nString(UIStrings.devicePixelRatio), 'dark-text', 'device-pixel-ratio');
343
344
  this.deviceScaleItem.turnShrinkable();
344
- this.deviceScaleItem.setVisible(this.showDeviceScaleFactorSetting.get());
345
345
  const deviceScaleSpan = uiI18n.getFormatLocalizedString(str_, UIStrings.dpr, {PH1: this.deviceScaleItem.element});
346
- mainToolbar.append(...deviceScaleSpan.childNodes);
347
- mainToolbar.appendToolbarItem(this.deviceScaleItem);
346
+ for (const node of Array.from(deviceScaleSpan.childNodes)) {
347
+ const item = node === this.deviceScaleItem.element ? this.deviceScaleItem :
348
+ new UI.Toolbar.ToolbarText(node.textContent || '');
349
+ item.setVisible(this.showDeviceScaleFactorSetting.get());
350
+ this.deviceScaleItems.push(item);
351
+ mainToolbar.appendToolbarItem(item);
352
+ }
348
353
  mainToolbar.appendToolbarItem(new UI.Toolbar.ToolbarItem(this.createEmptyToolbarElement()));
349
354
  this.uaItem = new UI.Toolbar.ToolbarComboBox(
350
355
  this.onUAChange.bind(this), i18nString(UIStrings.deviceType), 'dark-text', 'device-type');
@@ -758,7 +763,11 @@ export class DeviceModeToolbar {
758
763
 
759
764
  private updateDeviceScaleFactorVisibility(): void {
760
765
  if (this.deviceScaleItem) {
761
- this.deviceScaleItem.setVisible(this.showDeviceScaleFactorSetting.get());
766
+ const visible = this.showDeviceScaleFactorSetting.get();
767
+ this.deviceScaleItem.setVisible(visible);
768
+ for (const item of this.deviceScaleItems) {
769
+ item.setVisible(visible);
770
+ }
762
771
  }
763
772
  }
764
773
 
@@ -1880,10 +1880,30 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
1880
1880
  const throttlingMenu =
1881
1881
  contextMenu.debugSection().appendSubMenuItem(i18nString(UIStrings.throttleRequests), /* disabled=*/ true);
1882
1882
 
1883
- const urlWithoutScheme = request.parsedURL.urlWithoutScheme();
1884
- const urlPattern = urlWithoutScheme &&
1883
+ const parsed = request.parsedURL;
1884
+ let urlPatternString = '';
1885
+ if (parsed.isValid) {
1886
+ // We cannot escape parsed.urlWithoutScheme() directly. If we escaped the first '?'
1887
+ // URLPattern would treat the entire string as the pathname and fail to match the query string.
1888
+ // Thus, we must escape the components individually and reconstruct the pattern string.
1889
+ urlPatternString = '*://' + Platform.StringUtilities.escapeForURLPattern(parsed.host);
1890
+ if (parsed.port) {
1891
+ urlPatternString += ':' + Platform.StringUtilities.escapeForURLPattern(parsed.port);
1892
+ }
1893
+ urlPatternString += Platform.StringUtilities.escapeForURLPattern(parsed.path);
1894
+ if (parsed.queryParams) {
1895
+ urlPatternString += '?' + Platform.StringUtilities.escapeForURLPattern(parsed.queryParams);
1896
+ }
1897
+ if (parsed.fragment) {
1898
+ urlPatternString += '#' + Platform.StringUtilities.escapeForURLPattern(parsed.fragment);
1899
+ }
1900
+ } else if (parsed.urlWithoutScheme()) {
1901
+ urlPatternString = '*://' + Platform.StringUtilities.escapeForURLPattern(parsed.urlWithoutScheme());
1902
+ }
1903
+
1904
+ const urlPattern = urlPatternString &&
1885
1905
  SDK.NetworkManager.RequestURLPattern.create(
1886
- `*://${urlWithoutScheme}` as SDK.NetworkManager.URLPatternConstructorString);
1906
+ urlPatternString as SDK.NetworkManager.URLPatternConstructorString);
1887
1907
  if (urlPattern) {
1888
1908
  throttlingMenu.setEnabled(true);
1889
1909
  blockingMenu.setEnabled(true);
@@ -1906,30 +1926,39 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
1906
1926
  {jslogContext: 'throttle-request-url'});
1907
1927
  }
1908
1928
 
1909
- const domain = request.parsedURL.domain();
1910
- const domainPattern = domain &&
1911
- SDK.NetworkManager.RequestURLPattern.create(
1912
- `*://${domain}` as SDK.NetworkManager.URLPatternConstructorString);
1913
- if (domainPattern) {
1914
- throttlingMenu.setEnabled(true);
1915
- blockingMenu.setEnabled(true);
1916
- const existingConditions = manager.requestConditions.findCondition(domainPattern.constructorString);
1917
- const isBlocking = existingConditions?.conditions === SDK.NetworkManager.BlockingConditions;
1918
- const isThrottling = existingConditions &&
1919
- existingConditions.conditions !== SDK.NetworkManager.BlockingConditions &&
1920
- existingConditions.conditions !== SDK.NetworkManager.NoThrottlingConditions;
1921
- const croppedURL = Platform.StringUtilities.trimMiddle(domainPattern.constructorString, maxBlockedURLLength);
1922
- blockingMenu.debugSection().appendItem(
1923
- isBlocking ? i18nString(UIStrings.unblockS, {PH1: croppedURL}) : i18nString(UIStrings.blockRequestDomain),
1924
- () => isBlocking ? removeRequestCondition(domainPattern) :
1925
- addRequestCondition(domainPattern, SDK.NetworkManager.BlockingConditions),
1926
- {jslogContext: 'block-request-domain'});
1927
- throttlingMenu.debugSection().appendItem(
1928
- isThrottling ? i18nString(UIStrings.unthrottleS, {PH1: croppedURL}) :
1929
- i18nString(UIStrings.throttleRequestDomain),
1930
- () => isThrottling ? removeRequestCondition(domainPattern) :
1931
- addRequestCondition(domainPattern, SDK.NetworkManager.Slow3GConditions),
1932
- {jslogContext: 'throttle-request-domain'});
1929
+ let domainPatternString = '';
1930
+ if (parsed.isValid) {
1931
+ domainPatternString = '*://' + Platform.StringUtilities.escapeForURLPattern(parsed.host);
1932
+ if (parsed.port) {
1933
+ domainPatternString += ':' + Platform.StringUtilities.escapeForURLPattern(parsed.port);
1934
+ }
1935
+ } else if (parsed.domain()) {
1936
+ domainPatternString = '*://' + Platform.StringUtilities.escapeForURLPattern(parsed.domain());
1937
+ }
1938
+
1939
+ const domainPattern = domainPatternString &&
1940
+ SDK.NetworkManager.RequestURLPattern.create(
1941
+ domainPatternString as SDK.NetworkManager.URLPatternConstructorString);
1942
+ if (domainPattern) {
1943
+ throttlingMenu.setEnabled(true);
1944
+ blockingMenu.setEnabled(true);
1945
+ const existingConditions = manager.requestConditions.findCondition(domainPattern.constructorString);
1946
+ const isBlocking = existingConditions?.conditions === SDK.NetworkManager.BlockingConditions;
1947
+ const isThrottling = existingConditions &&
1948
+ existingConditions.conditions !== SDK.NetworkManager.BlockingConditions &&
1949
+ existingConditions.conditions !== SDK.NetworkManager.NoThrottlingConditions;
1950
+ const croppedURL = Platform.StringUtilities.trimMiddle(domainPattern.constructorString, maxBlockedURLLength);
1951
+ blockingMenu.debugSection().appendItem(
1952
+ isBlocking ? i18nString(UIStrings.unblockS, {PH1: croppedURL}) : i18nString(UIStrings.blockRequestDomain),
1953
+ () => isBlocking ? removeRequestCondition(domainPattern) :
1954
+ addRequestCondition(domainPattern, SDK.NetworkManager.BlockingConditions),
1955
+ {jslogContext: 'block-request-domain'});
1956
+ throttlingMenu.debugSection().appendItem(
1957
+ isThrottling ? i18nString(UIStrings.unthrottleS, {PH1: croppedURL}) :
1958
+ i18nString(UIStrings.throttleRequestDomain),
1959
+ () => isThrottling ? removeRequestCondition(domainPattern) :
1960
+ addRequestCondition(domainPattern, SDK.NetworkManager.Slow3GConditions),
1961
+ {jslogContext: 'throttle-request-domain'});
1933
1962
  }
1934
1963
 
1935
1964
  if (SDK.NetworkManager.NetworkManager.canReplayRequest(request)) {
@@ -1944,7 +1973,8 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
1944
1973
  const requests = Logs.NetworkLog.NetworkLog.instance().requests().filter(request => this.applyFilter(request));
1945
1974
  return requests.filter(NetworkLogView.getHTTPRequestsFilter).filter(request => {
1946
1975
  return request.finished ||
1947
- (request.resourceType() === Common.ResourceType.resourceTypes.WebSocket && request.responseReceivedTime);
1976
+ (request.resourceType() === Common.ResourceType.resourceTypes.WebSocket && request.responseReceivedTime) ||
1977
+ Boolean(request.eventSourceMessages()?.length);
1948
1978
  });
1949
1979
  }
1950
1980
 
@@ -300,7 +300,7 @@ export class HeapSnapshotSortableDataGrid extends Common.ObjectWrapper
300
300
  let field1 = nodeA[sortFields.fieldName1];
301
301
  // @ts-expect-error
302
302
  let field2 = nodeB[sortFields.fieldName1];
303
- let result: number|(0 | 1 | -1) = field1 < field2 ? -1 : (field1 > field2 ? 1 : 0);
303
+ let result: number = field1 < field2 ? -1 : (field1 > field2 ? 1 : 0);
304
304
  if (!sortFields.ascending1) {
305
305
  result = -result;
306
306
  }
@@ -136,31 +136,23 @@ export class HeapSnapshotGridNode extends
136
136
  Common.ObjectWrapper.eventMixin<HeapSnapshotGridNode.EventTypes, typeof HeapSnapshotGridNodeBase>(
137
137
  HeapSnapshotGridNodeBase) {
138
138
  dataGridInternal: HeapSnapshotSortableDataGrid;
139
- instanceCount: number;
140
- readonly savedChildren: Map<number, HeapSnapshotGridNode>;
139
+ instanceCount = 0;
140
+ readonly savedChildren = new Map<number, HeapSnapshotGridNode>();
141
+ /**
142
+ * List of position ranges for all visible nodes: [startPos1, endPos1),...,[startPosN, endPosN)
143
+ * Position is an item position in the provider.
144
+ */
141
145
  retrievedChildrenRanges: Array<{
142
146
  from: number,
143
147
  to: number,
144
- }>;
145
- providerObject: HeapSnapshotModel.ChildrenProvider.ChildrenProvider|null;
146
- reachableFromWindow: boolean;
148
+ }> = [];
149
+ providerObject: HeapSnapshotModel.ChildrenProvider.ChildrenProvider|null = null;
150
+ reachableFromWindow = false;
147
151
  populated?: boolean;
148
152
 
149
153
  constructor(tree: HeapSnapshotSortableDataGrid, hasChildren: boolean) {
150
154
  super(null, hasChildren);
151
155
  this.dataGridInternal = tree;
152
- this.instanceCount = 0;
153
-
154
- this.savedChildren = new Map();
155
-
156
- /**
157
- * List of position ranges for all visible nodes: [startPos1, endPos1),...,[startPosN, endPosN)
158
- * Position is an item position in the provider.
159
- */
160
- this.retrievedChildrenRanges = [];
161
-
162
- this.providerObject = null;
163
- this.reachableFromWindow = false;
164
156
  }
165
157
 
166
158
  get name(): string|undefined {
@@ -64,6 +64,7 @@ export const enum ParameterType {
64
64
  BOOLEAN = 'boolean',
65
65
  ARRAY = 'array',
66
66
  OBJECT = 'object',
67
+ UNKNOWN = 'unknown',
67
68
  }
68
69
 
69
70
  interface BaseParameter {
@@ -100,7 +101,13 @@ interface ObjectParameter extends BaseParameter {
100
101
  value?: Parameter[];
101
102
  }
102
103
 
103
- export type Parameter = ArrayParameter|NumberParameter|StringParameter|BooleanParameter|ObjectParameter;
104
+ interface UnknownParameter extends BaseParameter {
105
+ type: ParameterType.UNKNOWN;
106
+ value?: string;
107
+ }
108
+
109
+ export type Parameter =
110
+ ArrayParameter|NumberParameter|StringParameter|BooleanParameter|ObjectParameter|UnknownParameter;
104
111
 
105
112
  export interface Command {
106
113
  command: string;
@@ -128,6 +135,8 @@ interface ViewInput {
128
135
  onParameterKeydown: (event: KeyboardEvent) => void;
129
136
  onParameterKeyBlur: (event: Event) => void;
130
137
  onParameterValueBlur: (event: Event) => void;
138
+ displayTargetSelector?: boolean;
139
+ displayCommandInput?: boolean;
131
140
  }
132
141
 
133
142
  export type View = (input: ViewInput, output: object, target: HTMLElement) => void;
@@ -149,6 +158,7 @@ const defaultValueByType = new Map<string, string|number|boolean>([
149
158
  ['string', ''],
150
159
  ['number', 0],
151
160
  ['boolean', false],
161
+ ['unknown', ''],
152
162
  ]);
153
163
 
154
164
  const DUMMY_DATA = 'dummy';
@@ -176,6 +186,8 @@ export class JSONEditor extends Common.ObjectWrapper.eventMixin<EventTypes, type
176
186
  #targetId?: string;
177
187
  #hintPopoverHelper?: UI.PopoverHelper.PopoverHelper;
178
188
  #view: View;
189
+ displayTargetSelector = true;
190
+ displayCommandInput = true;
179
191
 
180
192
  constructor(element: HTMLElement, view = DEFAULT_VIEW) {
181
193
  super(element, {useShadowDom: true});
@@ -240,6 +252,10 @@ export class JSONEditor extends Common.ObjectWrapper.eventMixin<EventTypes, type
240
252
  }
241
253
  }
242
254
 
255
+ set commandToDisplay(command: string) {
256
+ this.displayCommand(command, {});
257
+ }
258
+
243
259
  get targetId(): string|undefined {
244
260
  return this.#targetId;
245
261
  }
@@ -312,6 +328,13 @@ export class JSONEditor extends Common.ObjectWrapper.eventMixin<EventTypes, type
312
328
  }
313
329
  return nestedArrayParameters.length === 0 ? [] : nestedArrayParameters;
314
330
  }
331
+ case ParameterType.UNKNOWN: {
332
+ try {
333
+ return JSON.parse(parameter.value as string);
334
+ } catch {
335
+ return parameter.value;
336
+ }
337
+ }
315
338
  default: {
316
339
  return parameter.value;
317
340
  }
@@ -387,7 +410,7 @@ export class JSONEditor extends Common.ObjectWrapper.eventMixin<EventTypes, type
387
410
  typeRef: schema?.typeRef,
388
411
  value,
389
412
  description,
390
- } as Parameter;
413
+ } as unknown as Parameter;
391
414
  }
392
415
 
393
416
  #convertPrimitiveParameter(key: string, value: unknown, schema?: Parameter): Parameter {
@@ -967,6 +990,8 @@ export class JSONEditor extends Common.ObjectWrapper.eventMixin<EventTypes, type
967
990
  computeDropdownValues: (parameter: Parameter) => {
968
991
  return this.#computeDropdownValues(parameter);
969
992
  },
993
+ displayTargetSelector: this.displayTargetSelector,
994
+ displayCommandInput: this.displayCommandInput,
970
995
  };
971
996
  const viewOutput = {};
972
997
  this.#view(viewInput, viewOutput, this.contentElement);
@@ -1229,7 +1254,8 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
1229
1254
  render(html`
1230
1255
  <div class="wrapper" @keydown=${input.onKeydown} jslog=${VisualLogging.pane('command-editor').track({resize: true})}>
1231
1256
  <div class="editor-wrapper">
1232
- ${renderTargetSelectorRow(input)}
1257
+ ${input.displayTargetSelector !== false ? renderTargetSelectorRow(input) : nothing}
1258
+ ${input.displayCommandInput !== false ? html`
1233
1259
  <div class="row attribute padded">
1234
1260
  <div class="command">command<span class="separator">:</span></div>
1235
1261
  <devtools-suggestion-input
@@ -1241,7 +1267,7 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
1241
1267
  @blur=${input.onCommandInputBlur}
1242
1268
  class=${classMap({'json-input': true})}
1243
1269
  ></devtools-suggestion-input>
1244
- </div>
1270
+ </div>` : nothing}
1245
1271
  ${input.parameters.length ? html`
1246
1272
  <div class="row attribute padded">
1247
1273
  <div>parameters<span class="separator">:</span></div>
@@ -133,21 +133,21 @@ const UIStrings = {
133
133
  */
134
134
  doYouTrustThisCode: 'Do you trust this recording?',
135
135
  /**
136
- * @description Warning shown to users when imports code into DevTools Recorder.
136
+ * @description Warning shown to users when imports code into DevTools Recorder. IMPORTANT: keep double quotes around PH1 and do not use single quotes.
137
137
  * @example {allow importing} PH1
138
138
  */
139
139
  doNotImport:
140
- 'Don\'t import recordings you do not understand or have not reviewed yourself into DevTools. This could allow attackers to steal your identity or take control of your computer. Please type \'\'{PH1}\'\' below to allow importing.',
140
+ 'Don\'t import recordings you do not understand or have not reviewed yourself into DevTools. This could allow attackers to steal your identity or take control of your computer. Please type {PH1} below to allow importing.',
141
141
  /**
142
142
  * @description Text a user needs to type in order to confirm that they
143
143
  *are aware of the danger of import code into the DevTools Recorder.
144
144
  */
145
145
  allowImporting: 'allow importing',
146
146
  /**
147
- * @description Input box placeholder which instructs the user to type 'allow importing' into the input box.
147
+ * @description Input box placeholder which instructs the user to type 'allow importing' into the input box. IMPORTANT: keep double quotes around PH1 and do not use single quotes.
148
148
  * @example {allow importing} PH1
149
149
  */
150
- typeAllowImporting: 'Type \'\'{PH1}\'\'',
150
+ typeAllowImporting: 'Type {PH1}',
151
151
  } as const;
152
152
  const str_ = i18n.i18n.registerUIStrings('panels/recorder/RecorderController.ts', UIStrings);
153
153
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -133,7 +133,7 @@ export class RecordingPlayer extends Common.ObjectWrapper.ObjectWrapper<EventTyp
133
133
  throw new Error('could not find main page!');
134
134
  }
135
135
 
136
- browser.on('targetdiscovered', (targetInfo: Protocol.Target.TargetInfo) => {
136
+ browser.on('targetdiscovered', (targetInfo: ReturnType<puppeteer.Target['_getTargetInfo']>) => {
137
137
  // Pop-ups opened by the main target won't be auto-attached. Therefore,
138
138
  // we need to create a session for them explicitly. We user openedId
139
139
  // and type to classify a target as requiring a session.
@@ -120,6 +120,29 @@ const UIStrings = {
120
120
  */
121
121
  helpUnderstandStylingNetworkPerformanceAndFile:
122
122
  'Get help with understanding CSS styles, network requests, performance, and files',
123
+ /**
124
+ * @description Text describing the 'AI assistance' feature when V2 is enabled
125
+ */
126
+ aiAssistanceDescriptionV2: 'Get context-aware help on the inspected page',
127
+ /**
128
+ * @description First item in the description of the AI assistance feature when V2 is enabled
129
+ */
130
+ aiAssistanceWhenOnItem1V2:
131
+ 'Debug styling, network, performance, source code, accessibility and storage issues with DevTools AI assistance',
132
+ /**
133
+ * @description Second item in the description of the AI assistance feature when V2 is enabled
134
+ */
135
+ aiAssistanceWhenOnItem2V2: 'Follow the agent\'s reasoning step-by-step and quickly jump to the relevant source data',
136
+ /**
137
+ * @description Explainer for which data is being sent by the AI assistance feature when V2 is enabled
138
+ */
139
+ aiAssistanceThingsToConsiderV2:
140
+ 'To generate explanations, chat messages, data accessible for this site via DevTools panels and Web APIs, and items you select such as network requests, files, and performance traces 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.',
141
+ /**
142
+ * @description Explainer for which data is being sent by the AI assistance feature when V2 is enabled and logging is disabled
143
+ */
144
+ aiAssistanceThingsToConsiderNoLoggingV2:
145
+ 'To generate explanations, chat messages, data accessible for this site via DevTools panels and Web APIs, and items you select such as network requests, files, and performance traces are sent to Google. The content you submit and that is generated by this feature will not be used to improve Google’s AI models. This is an experimental AI feature and won’t always get it right.',
123
146
  /**
124
147
  * @description Text describing the 'Code suggestions' feature
125
148
  */
@@ -480,6 +503,7 @@ export class AISettingsTab extends UI.Widget.VBox {
480
503
  }
481
504
 
482
505
  if (this.#aiAssistanceSetting) {
506
+ const isV2 = Root.Runtime.hostConfig.devToolsAiAssistanceV2?.enabled;
483
507
  const aiAssistanceData: AiSettingParams = {
484
508
  settingName: i18n.i18n.lockedString(
485
509
  AiAssistanceModel.AiUtils.isGeminiBranding() ? 'Gemini in Chrome DevTools' : 'AI assistance'),
@@ -488,12 +512,18 @@ export class AISettingsTab extends UI.Widget.VBox {
488
512
  enableSettingText: i18nString(UIStrings.enableAiAssistance),
489
513
  settingItems: [
490
514
  {iconName: 'info', text: this.#getAiAssistanceSettingInfo()},
491
- {iconName: 'pen-spark', text: i18nString(UIStrings.receiveStylingSuggestions)}
515
+ {
516
+ iconName: 'pen-spark',
517
+ text: isV2 ? i18nString(UIStrings.aiAssistanceWhenOnItem2V2) :
518
+ i18nString(UIStrings.receiveStylingSuggestions),
519
+ },
492
520
  ],
493
521
  toConsiderSettingItems: [{
494
522
  iconName: 'google',
495
- text: noLogging ? i18nString(UIStrings.freestylerSendsDataNoLogging) :
496
- i18nString(UIStrings.freestylerSendsData)
523
+ text: isV2 ? (noLogging ? i18nString(UIStrings.aiAssistanceThingsToConsiderNoLoggingV2) :
524
+ i18nString(UIStrings.aiAssistanceThingsToConsiderV2)) :
525
+ (noLogging ? i18nString(UIStrings.freestylerSendsDataNoLogging) :
526
+ i18nString(UIStrings.freestylerSendsData)),
497
527
  }],
498
528
  learnMoreLink: {
499
529
  url: 'https://developer.chrome.com/docs/devtools/ai-assistance',
@@ -581,6 +611,9 @@ export class AISettingsTab extends UI.Widget.VBox {
581
611
 
582
612
  #getAiAssistanceSettingDescription(): Platform.UIString.LocalizedString {
583
613
  const {hostConfig} = Root.Runtime;
614
+ if (hostConfig.devToolsAiAssistanceV2?.enabled) {
615
+ return i18nString(UIStrings.aiAssistanceDescriptionV2);
616
+ }
584
617
  if (hostConfig.devToolsAiAssistancePerformanceAgent?.enabled) {
585
618
  return i18nString(UIStrings.helpUnderstandStylingNetworkPerformanceAndFile);
586
619
  }
@@ -595,6 +628,9 @@ export class AISettingsTab extends UI.Widget.VBox {
595
628
 
596
629
  #getAiAssistanceSettingInfo(): Platform.UIString.LocalizedString {
597
630
  const {hostConfig} = Root.Runtime;
631
+ if (hostConfig.devToolsAiAssistanceV2?.enabled) {
632
+ return i18nString(UIStrings.aiAssistanceWhenOnItem1V2);
633
+ }
598
634
  if (hostConfig.devToolsAiAssistancePerformanceAgent?.enabled) {
599
635
  return i18nString(UIStrings.explainStylingNetworkPerformanceAndFile);
600
636
  }
@@ -648,9 +684,20 @@ export class AISettingsTab extends UI.Widget.VBox {
648
684
  .createSetting('console-insights-skip-reminder', true, Common.Settings.SettingStorageType.SESSION)
649
685
  .set(true);
650
686
  }
651
- } else if (setting.name === 'ai-assistance-enabled' && !setting.get()) {
652
- // If the "AI Assistance" is toggled off, we remove all the history entries related to the feature.
653
- void AiAssistanceModel.AiHistoryStorage.AiHistoryStorage.instance().deleteAll();
687
+ } else if (setting.name === 'ai-assistance-enabled') {
688
+ if (!setting.get()) {
689
+ // If the "AI Assistance" is toggled off, we remove all the history entries related to the feature.
690
+ void AiAssistanceModel.AiHistoryStorage.AiHistoryStorage.instance().deleteAll();
691
+ }
692
+
693
+ if (Root.Runtime.hostConfig.devToolsAiAssistanceV2?.enabled && setting.get()) {
694
+ // If the user turns on ai-assistance whilst on the V2 experiment, they
695
+ // do not need to see the opt-in change management dialog. This dialog
696
+ // exists to inform users who opted-in to "V1" that in "V2" there are
697
+ // some data access changes. But if a user opts-in when on "V2", they
698
+ // do not need to see that dialog.
699
+ Common.Settings.Settings.instance().moduleSetting('ai-assistance-v2-opt-in-change-dialog-seen').set(true);
700
+ }
654
701
  }
655
702
  this.requestUpdate();
656
703
  }
@@ -636,7 +636,7 @@ const GREENDEV_VIEW: View = (input, _output, target) => {
636
636
  <span>${i18nString(UIStrings.greenDevUnstable)}</span>
637
637
  </div>
638
638
  <div class="settings-experiments-block">
639
- ${renderPrototypeCheckboxes(input.settings, ['aiAnnotations', 'copyToGemini', 'breakpointDebuggerAgent', 'emulationCapabilities'])}
639
+ ${renderPrototypeCheckboxes(input.settings, ['aiAnnotations', 'beyondStyling', 'breakpointDebuggerAgent', 'emulationCapabilities'])}
640
640
  </div>
641
641
  </devtools-card>
642
642
  </div>
@@ -646,7 +646,7 @@ const GREENDEV_VIEW: View = (input, _output, target) => {
646
646
 
647
647
  const GREENDEV_PROTOTYPE_NAMES: Record<keyof GreenDev.GreenDevSettings, string> = {
648
648
  aiAnnotations: 'AI auto-annotations',
649
- copyToGemini: 'Copy changes to AI Prompt',
649
+ beyondStyling: 'Beyond Styling',
650
650
  breakpointDebuggerAgent: 'Breakpoint Debugger Agent',
651
651
  emulationCapabilities: 'Emulation Capabilities',
652
652
  };
@@ -91,7 +91,7 @@ export class PuppeteerConnectionHelper {
91
91
  undefined /* process */,
92
92
  undefined /* closeCallback */,
93
93
  undefined /* targetFilterCallback */,
94
- target => isPageTargetCallback((target as puppeteer.Target)._getTargetInfo()),
94
+ target => isPageTargetCallback((target as puppeteer.Target)._getTargetInfo() as Protocol.Target.TargetInfo),
95
95
  false /* waitForInitiallyDiscoveredTargets */,
96
96
  );
97
97
 
@@ -1,7 +1,7 @@
1
1
  Name: Dependencies sourced from the upstream `chromium` repository
2
2
  URL: Internal
3
3
  Version: N/A
4
- Revision: ba9b7fcecd6da792b29305cac5a406adc76fc1e5
4
+ Revision: a287ca9049cc3727d680078c1d9275b32f721c2d
5
5
  Update Mechanism: Manual (https://crbug.com/428069060)
6
6
  License: BSD-3-Clause
7
7
  License File: LICENSE
@@ -3,6 +3,7 @@
3
3
  // found in the LICENSE file.
4
4
  /* eslint-disable @devtools/no-imperative-dom-api */
5
5
 
6
+ // @ts-expect-error tsc 6 can't find type declarations for this file.
6
7
  import '../../../Images/Images.js';
7
8
 
8
9
  import iconStyles from './icon.css.js';