chrome-devtools-frontend 1.0.1613625 → 1.0.1615539

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 (64) hide show
  1. package/AUTHORS +1 -0
  2. package/docs/contributing/infrastructure.md +0 -1
  3. package/front_end/core/common/VersionController.ts +17 -1
  4. package/front_end/core/host/UserMetrics.ts +0 -1
  5. package/front_end/core/root/ExperimentNames.ts +0 -1
  6. package/front_end/core/sdk/OverlayModel.ts +2 -4
  7. package/front_end/core/sdk/sdk-meta.ts +13 -0
  8. package/front_end/entrypoints/device_mode_emulation_frame/device_mode_emulation_frame.ts +4 -0
  9. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +0 -1
  10. package/front_end/entrypoints/greendev_floaty/floaty.css +3 -0
  11. package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +0 -1
  12. package/front_end/entrypoints/main/MainImpl.ts +0 -6
  13. package/front_end/entrypoints/shell/shell.ts +4 -0
  14. package/front_end/entrypoints/trace_app/trace_app.ts +4 -0
  15. package/front_end/generated/InspectorBackendCommands.ts +6 -4
  16. package/front_end/generated/protocol-mapping.d.ts +14 -0
  17. package/front_end/generated/protocol-proxy-api.d.ts +10 -0
  18. package/front_end/generated/protocol.ts +33 -3
  19. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +10 -2
  20. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +23 -7
  21. package/front_end/models/ai_assistance/agents/PerformanceAgent.snapshot.txt +4 -1
  22. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +200 -46
  23. package/front_end/models/issues_manager/IssuesManager.ts +4 -0
  24. package/front_end/models/javascript_metadata/NativeFunctions.js +673 -639
  25. package/front_end/models/stack_trace/DetailedErrorStackParser.ts +161 -0
  26. package/front_end/models/stack_trace/StackTrace.ts +18 -0
  27. package/front_end/models/stack_trace/StackTraceImpl.ts +96 -4
  28. package/front_end/models/stack_trace/StackTraceModel.ts +39 -0
  29. package/front_end/models/stack_trace/Trie.ts +21 -0
  30. package/front_end/models/stack_trace/stack_trace_impl.ts +2 -0
  31. package/front_end/panels/ai_assistance/components/AccessibilityAgentMarkdownRenderer.ts +55 -14
  32. package/front_end/panels/ai_assistance/components/ChatView.ts +4 -3
  33. package/front_end/panels/ai_assistance/components/ExportForAgentsDialog.ts +4 -1
  34. package/front_end/panels/ai_assistance/components/optInChangeDialog.css +1 -2
  35. package/front_end/panels/application/WebMCPView.ts +270 -18
  36. package/front_end/panels/application/components/ProtocolHandlersView.ts +2 -2
  37. package/front_end/panels/application/webMCPView.css +4 -1
  38. package/front_end/panels/common/AiCodeCompletionDisclaimer.ts +7 -0
  39. package/front_end/panels/console/ConsoleContextSelector.ts +1 -1
  40. package/front_end/panels/console/ConsoleViewMessage.ts +8 -2
  41. package/front_end/panels/console/consoleView.css +4 -0
  42. package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +2 -3
  43. package/front_end/panels/css_overview/CSSOverviewModel.ts +1 -2
  44. package/front_end/panels/network/RequestConditionsDrawer.ts +4 -2
  45. package/front_end/panels/network/RequestPayloadView.ts +8 -3
  46. package/front_end/panels/network/RequestTimingView.ts +6 -7
  47. package/front_end/panels/performance_monitor/PerformanceMonitor.ts +7 -5
  48. package/front_end/third_party/chromium/README.chromium +1 -1
  49. package/front_end/third_party/codemirror/codemirror-tsconfig.json +4 -4
  50. package/front_end/third_party/lighthouse/lighthouse-tsconfig.json +1 -1
  51. package/front_end/tsconfig.json +2 -1
  52. package/front_end/ui/legacy/EmptyWidget.ts +2 -2
  53. package/front_end/ui/legacy/components/color_picker/ContrastDetails.ts +1 -2
  54. package/front_end/ui/legacy/components/color_picker/ContrastOverlay.ts +4 -5
  55. package/front_end/ui/legacy/components/source_frame/XMLView.ts +12 -7
  56. package/front_end/ui/lit/lit.ts +4 -1
  57. package/front_end/ui/lit/render.ts +81 -0
  58. package/front_end/ui/visual_logging/KnownContextValues.ts +3 -1
  59. package/package.json +1 -1
  60. /package/front_end/third_party/codemirror/package/addon/runmode/{runmode-standalone.mjs.d.ts → runmode-standalone.d.mts} +0 -0
  61. /package/front_end/third_party/codemirror/package/mode/css/{css.mjs.d.ts → css.d.mts} +0 -0
  62. /package/front_end/third_party/codemirror/package/mode/javascript/{javascript.mjs.d.ts → javascript.d.mts} +0 -0
  63. /package/front_end/third_party/codemirror/package/mode/xml/{xml.mjs.d.ts → xml.d.mts} +0 -0
  64. /package/front_end/third_party/lighthouse/report-assets/{report-generator.mjs.d.ts → report-generator.d.mts} +0 -0
@@ -8,7 +8,10 @@ import '../../ui/components/node_text/node_text.js';
8
8
  import '../../ui/legacy/components/data_grid/data_grid.js';
9
9
  import '../../ui/legacy/legacy.js';
10
10
 
11
+ import type {JSONSchema7, JSONSchema7Definition} from 'json-schema';
12
+
11
13
  import * as Common from '../../core/common/common.js';
14
+ import * as Host from '../../core/host/host.js';
12
15
  import * as i18n from '../../core/i18n/i18n.js';
13
16
  import * as Platform from '../../core/platform/platform.js';
14
17
  import * as SDK from '../../core/sdk/sdk.js';
@@ -30,6 +33,7 @@ import {
30
33
  type TemplateResult,
31
34
  } from '../../ui/lit/lit.js';
32
35
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
36
+ import * as ProtocolMonitor from '../protocol_monitor/protocol_monitor.js';
33
37
 
34
38
  import webMCPViewStyles from './webMCPView.css.js';
35
39
 
@@ -130,7 +134,7 @@ const UIStrings = {
130
134
  /**
131
135
  * @description Text for the status of a tool call that succeeded
132
136
  */
133
- success: 'Success',
137
+ completed: 'Completed',
134
138
  /**
135
139
  * @description Text for the status of a tool call that has failed
136
140
  */
@@ -155,6 +159,14 @@ const UIStrings = {
155
159
  * @example {1} PH1
156
160
  */
157
161
  inProgressCount: '{PH1} In Progress',
162
+ /**
163
+ * @description Context menu action to copy the name of a tool
164
+ */
165
+ copyName: 'Copy name',
166
+ /**
167
+ * @description Context menu action to copy the description of a tool
168
+ */
169
+ copyDescription: 'Copy description',
158
170
  } as const;
159
171
  const str_ = i18n.i18n.registerUIStrings('panels/application/WebMCPView.ts', UIStrings);
160
172
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -167,7 +179,7 @@ export interface FilterState {
167
179
  declarative?: boolean,
168
180
  };
169
181
  statusTypes?: {
170
- success?: boolean,
182
+ completed?: boolean,
171
183
  error?: boolean,
172
184
  pending?: boolean,
173
185
  };
@@ -202,8 +214,8 @@ export function filterToolCalls(
202
214
  const statusTypes = filterState.statusTypes;
203
215
  if (statusTypes) {
204
216
  filtered = filtered.filter(call => {
205
- const {success, error, pending} = statusTypes;
206
- if (success && call.result?.status === Protocol.WebMCP.InvocationStatus.Success) {
217
+ const {completed, error, pending} = statusTypes;
218
+ if (completed && call.result?.status === Protocol.WebMCP.InvocationStatus.Completed) {
207
219
  return true;
208
220
  }
209
221
  if (error && call.result?.status === Protocol.WebMCP.InvocationStatus.Error) {
@@ -243,33 +255,33 @@ export function filterToolCalls(
243
255
  }
244
256
  export type View = (input: ViewInput, output: object, target: HTMLElement) => void;
245
257
  function calculateToolStats(calls: WebMCP.WebMCPModel.Call[]):
246
- {total: number, success: number, failed: number, canceled: number, inProgress: number} {
247
- let total = 0, success = 0, failed = 0, canceled = 0, inProgress = 0;
258
+ {total: number, completed: number, failed: number, canceled: number, inProgress: number} {
259
+ let total = 0, completed = 0, failed = 0, canceled = 0, inProgress = 0;
248
260
  for (const call of calls) {
249
261
  total++;
250
262
  if (call.result?.status === Protocol.WebMCP.InvocationStatus.Error) {
251
263
  failed++;
252
264
  } else if (call.result?.status === Protocol.WebMCP.InvocationStatus.Canceled) {
253
265
  canceled++;
254
- } else if (call.result?.status === Protocol.WebMCP.InvocationStatus.Success) {
255
- success++;
266
+ } else if (call.result?.status === Protocol.WebMCP.InvocationStatus.Completed) {
267
+ completed++;
256
268
  } else if (call.result === undefined) {
257
269
  inProgress++;
258
270
  }
259
271
  }
260
- return {total, success, failed, canceled, inProgress};
272
+ return {total, completed, failed, canceled, inProgress};
261
273
  }
262
274
 
263
275
  function getIconGroupsFromStats(toolStats: ReturnType<typeof calculateToolStats>):
264
276
  IconButton.IconButton.IconWithTextData[] {
265
277
  const groups = [];
266
- if (toolStats.success > 0) {
278
+ if (toolStats.completed > 0) {
267
279
  groups.push({
268
280
  iconName: 'check-circle',
269
281
  iconColor: 'var(--sys-color-green)',
270
282
  iconWidth: '16px',
271
283
  iconHeight: '16px',
272
- text: String(toolStats.success),
284
+ text: String(toolStats.completed),
273
285
  });
274
286
  }
275
287
  if (toolStats.failed > 0) {
@@ -341,12 +353,22 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
341
353
  return i18nString(UIStrings.error);
342
354
  case Protocol.WebMCP.InvocationStatus.Canceled:
343
355
  return i18nString(UIStrings.canceled);
344
- case Protocol.WebMCP.InvocationStatus.Success:
345
- return i18nString(UIStrings.success);
356
+ case Protocol.WebMCP.InvocationStatus.Completed:
357
+ return i18nString(UIStrings.completed);
346
358
  default:
347
359
  return i18nString(UIStrings.inProgress);
348
360
  }
349
361
  };
362
+ const onToolContextMenu = (event: Event, tool: WebMCP.WebMCPModel.Tool): void => {
363
+ const contextMenu = new UI.ContextMenu.ContextMenu(event);
364
+ contextMenu.defaultSection().appendItem(i18nString(UIStrings.copyName), () => {
365
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(tool.name);
366
+ }, {jslogContext: 'webmcp.copy-tool-name'});
367
+ contextMenu.defaultSection().appendItem(i18nString(UIStrings.copyDescription), () => {
368
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(tool.description);
369
+ }, {jslogContext: 'webmcp.copy-tool-description'});
370
+ void contextMenu.show();
371
+ };
350
372
  // clang-format off
351
373
  render(html`
352
374
  <style>${webMCPViewStyles}</style>
@@ -488,7 +510,8 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
488
510
  const groups = getIconGroupsFromStats(toolStats);
489
511
  return html`
490
512
  <div class=${Directives.classMap({'tool-item': true, selected: tool === input.selectedTool})}
491
- @click=${() => input.onToolSelect(tool)}>
513
+ @click=${() => input.onToolSelect(tool)}
514
+ @contextmenu=${(e: Event) => onToolContextMenu(e, tool)}>
492
515
  <div class="tool-name-container">
493
516
  <div class="tool-name source-code">${tool.name}</div>
494
517
  ${groups.length > 0 ? html`<icon-button .data=${
@@ -600,19 +623,19 @@ export class WebMCPView extends UI.Widget.VBox {
600
623
  }
601
624
 
602
625
  #showStatusTypesContextMenu(contextMenu: UI.ContextMenu.ContextMenu): void {
603
- const toggle = (key: 'success'|'error'|'pending'): void => {
626
+ const toggle = (key: 'completed'|'error'|'pending'): void => {
604
627
  const current = this.#filterState.statusTypes ?? {};
605
628
  const next = {...current, [key]: !current[key]};
606
629
  let statusTypesToPass: FilterState['statusTypes'] = next;
607
- if (!next.success && !next.error && !next.pending) {
630
+ if (!next.completed && !next.error && !next.pending) {
608
631
  statusTypesToPass = undefined;
609
632
  }
610
633
  this.#handleFilterChange({...this.#filterState, statusTypes: statusTypesToPass});
611
634
  };
612
635
 
613
636
  contextMenu.defaultSection().appendCheckboxItem(
614
- i18nString(UIStrings.success), () => toggle('success'),
615
- {checked: this.#filterState.statusTypes?.['success'] ?? false, jslogContext: 'webmcp.success'});
637
+ i18nString(UIStrings.completed), () => toggle('completed'),
638
+ {checked: this.#filterState.statusTypes?.['completed'] ?? false, jslogContext: 'webmcp.completed'});
616
639
  contextMenu.defaultSection().appendCheckboxItem(
617
640
  i18nString(UIStrings.error), () => toggle('error'),
618
641
  {checked: this.#filterState.statusTypes?.['error'] ?? false, jslogContext: 'webmcp.error'});
@@ -990,3 +1013,232 @@ export class ToolDetailsWidget extends UI.Widget.Widget {
990
1013
  this.requestUpdate();
991
1014
  }
992
1015
  }
1016
+
1017
+ export interface ParsedToolSchema {
1018
+ parameters: ProtocolMonitor.JSONEditor.Parameter[];
1019
+ typesByName: Map<string, ProtocolMonitor.JSONEditor.Parameter[]>;
1020
+ enumsByName: Map<string, Record<string, string>>;
1021
+ }
1022
+
1023
+ const parsedSchemaCache = new WeakMap<object, ParsedToolSchema>();
1024
+
1025
+ export function parseToolSchema(schema: JSONSchema7): ParsedToolSchema {
1026
+ if (typeof schema === 'object' && schema !== null) {
1027
+ const cached = parsedSchemaCache.get(schema);
1028
+ if (cached) {
1029
+ return cached;
1030
+ }
1031
+ }
1032
+
1033
+ const typesByName = new Map<string, ProtocolMonitor.JSONEditor.Parameter[]>();
1034
+ const enumsByName = new Map<string, Record<string, string>>();
1035
+ const simpleTypesByName = new Map<string, ProtocolMonitor.JSONEditor.ParameterType>();
1036
+ let typeCount = 0;
1037
+
1038
+ function createEnumRecord(values: unknown[]): Record<string, string> {
1039
+ const enumRecord: Record<string, string> = {};
1040
+ for (const val of values) {
1041
+ enumRecord[String(val)] = String(val);
1042
+ }
1043
+ return enumRecord;
1044
+ }
1045
+
1046
+ function preScanDefinition(name: string, def: JSONSchema7Definition): void {
1047
+ if (typeof def === 'boolean') {
1048
+ return;
1049
+ }
1050
+ if (def.type === 'string' && def.enum) {
1051
+ enumsByName.set(name, createEnumRecord(def.enum));
1052
+ } else if (def.type && typeof def.type === 'string' && def.type !== 'object' && def.type !== 'array') {
1053
+ let paramType = ProtocolMonitor.JSONEditor.ParameterType.STRING;
1054
+ switch (def.type) {
1055
+ case 'number':
1056
+ case 'integer':
1057
+ paramType = ProtocolMonitor.JSONEditor.ParameterType.NUMBER;
1058
+ break;
1059
+ case 'boolean':
1060
+ paramType = ProtocolMonitor.JSONEditor.ParameterType.BOOLEAN;
1061
+ break;
1062
+ }
1063
+ simpleTypesByName.set(name, paramType);
1064
+ }
1065
+ }
1066
+
1067
+ function parseDefinition(name: string, def: JSONSchema7Definition): void {
1068
+ if (typeof def === 'boolean') {
1069
+ return;
1070
+ }
1071
+ if (def.type === 'object' && def.properties) {
1072
+ const nestedParams: ProtocolMonitor.JSONEditor.Parameter[] = [];
1073
+ for (const [key, value] of Object.entries(def.properties)) {
1074
+ const isOpt = !(def.required || []).includes(key);
1075
+ nestedParams.push(parseProperty(key, value, isOpt));
1076
+ }
1077
+ typesByName.set(name, nestedParams);
1078
+ }
1079
+ }
1080
+
1081
+ // First pass: populate enums and simple types
1082
+ if (schema.definitions) {
1083
+ for (const [name, def] of Object.entries(schema.definitions)) {
1084
+ preScanDefinition(name, def);
1085
+ }
1086
+ }
1087
+ if (schema.$defs) {
1088
+ for (const [name, def] of Object.entries(schema.$defs)) {
1089
+ preScanDefinition(name, def);
1090
+ }
1091
+ }
1092
+
1093
+ // Second pass: parse objects
1094
+ if (schema.definitions) {
1095
+ for (const [name, def] of Object.entries(schema.definitions)) {
1096
+ parseDefinition(name, def);
1097
+ }
1098
+ }
1099
+ if (schema.$defs) {
1100
+ for (const [name, def] of Object.entries(schema.$defs)) {
1101
+ parseDefinition(name, def);
1102
+ }
1103
+ }
1104
+
1105
+ function parseProperty(
1106
+ name: string, propDef: JSONSchema7Definition, optional: boolean): ProtocolMonitor.JSONEditor.Parameter {
1107
+ if (typeof propDef === 'boolean') {
1108
+ return {
1109
+ name,
1110
+ optional,
1111
+ description: '',
1112
+ type: ProtocolMonitor.JSONEditor.ParameterType.STRING,
1113
+ isCorrectType: true,
1114
+ };
1115
+ }
1116
+ const prop = propDef;
1117
+ if (prop.$ref) {
1118
+ const typeRef = prop.$ref.split('/').pop() || '';
1119
+ let paramType = ProtocolMonitor.JSONEditor.ParameterType.OBJECT;
1120
+ if (enumsByName.has(typeRef)) {
1121
+ paramType = ProtocolMonitor.JSONEditor.ParameterType.STRING;
1122
+ } else {
1123
+ const simpleType = simpleTypesByName.get(typeRef);
1124
+ if (simpleType !== undefined) {
1125
+ paramType = simpleType;
1126
+ }
1127
+ }
1128
+ return {
1129
+ name,
1130
+ optional,
1131
+ description: prop.description || '',
1132
+ type: paramType,
1133
+ typeRef,
1134
+ isCorrectType: true,
1135
+ };
1136
+ }
1137
+
1138
+ const typeStr = Array.isArray(prop.type) ? prop.type[0] : prop.type;
1139
+ let type: string|undefined = typeStr === 'integer' ? 'number' : typeStr;
1140
+ if (!typeStr) {
1141
+ if (prop.properties) {
1142
+ type = 'object';
1143
+ } else if (prop.items) {
1144
+ type = 'array';
1145
+ } else {
1146
+ type = 'unknown';
1147
+ }
1148
+ }
1149
+ const description = prop.description || '';
1150
+
1151
+ let paramType = ProtocolMonitor.JSONEditor.ParameterType.UNKNOWN;
1152
+ switch (type) {
1153
+ case 'string':
1154
+ paramType = ProtocolMonitor.JSONEditor.ParameterType.STRING;
1155
+ break;
1156
+ case 'number':
1157
+ paramType = ProtocolMonitor.JSONEditor.ParameterType.NUMBER;
1158
+ break;
1159
+ case 'boolean':
1160
+ paramType = ProtocolMonitor.JSONEditor.ParameterType.BOOLEAN;
1161
+ break;
1162
+ case 'object':
1163
+ paramType = ProtocolMonitor.JSONEditor.ParameterType.OBJECT;
1164
+ break;
1165
+ case 'array':
1166
+ paramType = ProtocolMonitor.JSONEditor.ParameterType.ARRAY;
1167
+ break;
1168
+ }
1169
+
1170
+ const base: ProtocolMonitor.JSONEditor.Parameter = {
1171
+ name,
1172
+ optional,
1173
+ description,
1174
+ type: paramType,
1175
+ isCorrectType: true,
1176
+ };
1177
+
1178
+ if (type === 'object') {
1179
+ if (prop.properties) {
1180
+ const typeRef = `Object_${++typeCount}`;
1181
+ const nestedParams: ProtocolMonitor.JSONEditor.Parameter[] = [];
1182
+ for (const [key, value] of Object.entries(prop.properties)) {
1183
+ const isOpt = !(prop.required || []).includes(key);
1184
+ nestedParams.push(parseProperty(key, value, isOpt));
1185
+ }
1186
+ typesByName.set(typeRef, nestedParams);
1187
+ base.typeRef = typeRef;
1188
+ } else {
1189
+ base.isKeyEditable = true;
1190
+ }
1191
+ } else if (type === 'array') {
1192
+ const items =
1193
+ prop.items && !Array.isArray(prop.items) && typeof prop.items !== 'boolean' ? prop.items : undefined;
1194
+ if (items) {
1195
+ const itemTypeStr = Array.isArray(items.type) ? items.type[0] : items.type;
1196
+ if (items.$ref) {
1197
+ base.typeRef = items.$ref.split('/').pop() || '';
1198
+ } else if (itemTypeStr === 'object' && items.properties) {
1199
+ const typeRef = `Object_${++typeCount}`;
1200
+ const nestedParams: ProtocolMonitor.JSONEditor.Parameter[] = [];
1201
+ for (const [key, value] of Object.entries(items.properties)) {
1202
+ const isOpt = !(items.required || []).includes(key);
1203
+ nestedParams.push(parseProperty(key, value, isOpt));
1204
+ }
1205
+ typesByName.set(typeRef, nestedParams);
1206
+ base.typeRef = typeRef;
1207
+ } else if (itemTypeStr) {
1208
+ const itemType = itemTypeStr === 'integer' ? 'number' : itemTypeStr;
1209
+ if (itemType === 'string' && items.enum) {
1210
+ const typeRef = `Enum_${++typeCount}`;
1211
+ enumsByName.set(typeRef, createEnumRecord(items.enum));
1212
+ base.typeRef = typeRef;
1213
+ } else {
1214
+ base.typeRef = itemType as string;
1215
+ }
1216
+ } else {
1217
+ base.typeRef = 'string';
1218
+ }
1219
+ } else {
1220
+ base.typeRef = 'string';
1221
+ }
1222
+ } else if (type === 'string' && prop.enum) {
1223
+ const typeRef = `Enum_${++typeCount}`;
1224
+ enumsByName.set(typeRef, createEnumRecord(prop.enum));
1225
+ base.typeRef = typeRef;
1226
+ }
1227
+
1228
+ return base;
1229
+ }
1230
+
1231
+ const parameters: ProtocolMonitor.JSONEditor.Parameter[] = [];
1232
+ if ((schema.type === 'object' || !schema.type) && schema.properties) {
1233
+ for (const [key, value] of Object.entries(schema.properties)) {
1234
+ const isOpt = !(schema.required || []).includes(key);
1235
+ parameters.push(parseProperty(key, value, isOpt));
1236
+ }
1237
+ }
1238
+
1239
+ const result = {parameters, typesByName, enumsByName};
1240
+ if (typeof schema === 'object' && schema !== null) {
1241
+ parsedSchemaCache.set(schema, result);
1242
+ }
1243
+ return result;
1244
+ }
@@ -150,7 +150,7 @@ const DEFAULT_VIEW: View = (input, _output, target) => {
150
150
  </div>
151
151
  ${renderProtocolTest(input.protocolHandler, input.queryInputState, input.protocolSelectHandler,
152
152
  input.queryInputChangeHandler, input.testProtocolClickHandler)}
153
- `, target);
153
+ `, target, {container: {classes: ['vbox']}});
154
154
  // clang-format on
155
155
  };
156
156
 
@@ -172,7 +172,7 @@ export class ProtocolHandlersView extends UI.Widget.Widget {
172
172
  #view: View;
173
173
 
174
174
  constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
175
- super(element, {useShadowDom: false, classes: ['vbox']});
175
+ super(element, {useShadowDom: false});
176
176
  this.#view = view;
177
177
  }
178
178
 
@@ -77,7 +77,7 @@
77
77
  height: 100%;
78
78
  display: flex;
79
79
  flex-direction: column;
80
- overflow: auto;
80
+ overflow: hidden;
81
81
  }
82
82
 
83
83
  .tool-details-grid {
@@ -86,6 +86,7 @@
86
86
  gap: 0 var(--sys-size-16);
87
87
  padding: calc(0.5*var(--sys-size-6)) var(--sys-size-8);
88
88
  align-items: flex-start;
89
+ overflow-y: auto;
89
90
 
90
91
  .label {
91
92
  color: var(--sys-color-on-surface-subtle);
@@ -94,6 +95,8 @@
94
95
  }
95
96
 
96
97
  .value {
98
+ user-select: text;
99
+
97
100
  &.source-code {
98
101
  color: var(--sys-color-token-attribute);
99
102
  }
@@ -166,8 +166,15 @@ export const DEFAULT_SUMMARY_TOOLBAR_VIEW: View =
166
166
  role="link"
167
167
  jslog=${VisualLogging.link('open-ai-settings').track({
168
168
  click: true,
169
+ keydown: 'Enter',
169
170
  })}
170
171
  @click=${input.onManageInSettingsTooltipClick}
172
+ @keydown=${(e: KeyboardEvent) => {
173
+ if (e.key === 'Enter') {
174
+ e.consume(true);
175
+ input.onManageInSettingsTooltipClick();
176
+ }
177
+ }}
171
178
  >${lockedString(UIStringsNotTranslate.manageInSettings)}</span></div></devtools-tooltip>
172
179
  </div>
173
180
  `, target);
@@ -303,7 +303,7 @@ interface ViewInput {
303
303
  type View = (input: ViewInput, output: undefined, target: HTMLElement) => void;
304
304
 
305
305
  const DEFAULT_VIEW: View = (input, _output, target): void => {
306
- if (!input.title || !input.subtitle) {
306
+ if (!input.title) {
307
307
  render(nothing, target);
308
308
  return;
309
309
  }
@@ -1592,7 +1592,10 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
1592
1592
  const label = document.createElement('div');
1593
1593
  label.classList.add('button-label');
1594
1594
  const text = document.createElement('div');
1595
- text.innerText = this.getExplainLabel();
1595
+ // We use a data attribute and a CSS pseudo-element for the button label
1596
+ // to prevent the text from being picked up by the console's custom
1597
+ // copy-to-clipboard traversal, which only collects actual text nodes.
1598
+ text.setAttribute('data-text', this.getExplainLabel());
1596
1599
  label.append(text);
1597
1600
  button.append(label);
1598
1601
  button.classList.add('hover-button');
@@ -1615,7 +1618,10 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
1615
1618
  const label = document.createElement('div');
1616
1619
  label.classList.add('button-label');
1617
1620
  const text = document.createElement('div');
1618
- text.innerText = 'Debug with breakpoint AI';
1621
+ // We use a data attribute and a CSS pseudo-element for the button label
1622
+ // to prevent the text from being picked up by the console's custom
1623
+ // copy-to-clipboard traversal, which only collects actual text nodes.
1624
+ text.setAttribute('data-text', 'Debug with breakpoint AI');
1619
1625
  label.append(text);
1620
1626
  button.append(label);
1621
1627
  button.classList.add('hover-button');
@@ -615,6 +615,10 @@
615
615
  & div {
616
616
  display: inline-block;
617
617
  vertical-align: -1px;
618
+
619
+ &::after {
620
+ content: attr(data-text);
621
+ }
618
622
  }
619
623
  }
620
624
 
@@ -8,7 +8,6 @@ import '../../ui/kit/kit.js';
8
8
  import * as Common from '../../core/common/common.js';
9
9
  import * as i18n from '../../core/i18n/i18n.js';
10
10
  import * as Platform from '../../core/platform/platform.js';
11
- import * as Root from '../../core/root/root.js';
12
11
  import * as SDK from '../../core/sdk/sdk.js';
13
12
  import type * as Protocol from '../../generated/protocol.js';
14
13
  import * as Geometry from '../../models/geometry/geometry.js';
@@ -483,7 +482,7 @@ function renderContrastIssue(key: string, issues: ContrastIssue[]): TemplateResu
483
482
  const color = (minContrastIssue.textColor.asString(Common.Color.Format.HEXA));
484
483
  const backgroundColor = (minContrastIssue.backgroundColor.asString(Common.Color.Format.HEXA));
485
484
 
486
- const showAPCA = Root.Runtime.experiments.isEnabled(Root.ExperimentNames.ExperimentName.APCA);
485
+ const showAPCA = Common.Settings.Settings.instance().moduleSetting('apca').get();
487
486
 
488
487
  const title = i18nString(UIStrings.textColorSOverSBackgroundResults, {
489
488
  PH1: color,
@@ -1041,7 +1040,7 @@ function renderContrastRatio(data: PopulateNodesEventNodeTypes): TemplateResult
1041
1040
  if (!('contrastRatio' in data)) {
1042
1041
  throw new Error('Contrast ratio entry is missing a contrast ratio.');
1043
1042
  }
1044
- const showAPCA = Root.Runtime.experiments.isEnabled(Root.ExperimentNames.ExperimentName.APCA);
1043
+ const showAPCA = Common.Settings.Settings.instance().moduleSetting('apca').get();
1045
1044
  const contrastRatio = Platform.NumberUtilities.floor(data.contrastRatio, 2);
1046
1045
  const contrastRatioString = showAPCA ? contrastRatio + '%' : contrastRatio;
1047
1046
  const border = getBorderString(data.backgroundColor);
@@ -3,7 +3,6 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import * as Common from '../../core/common/common.js';
6
- import * as Root from '../../core/root/root.js';
7
6
  import * as SDK from '../../core/sdk/sdk.js';
8
7
  import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
9
8
  import type * as Protocol from '../../generated/protocol.js';
@@ -267,7 +266,7 @@ export class CSSOverviewModel extends SDK.SDKModel.SDKModel<void> {
267
266
  const formattedTextColor = formatColor(blendedTextColor);
268
267
  const formattedBackgroundColor = formatColor(blendedBackgroundColor.asLegacyColor());
269
268
  const key = `${formattedTextColor}_${formattedBackgroundColor}`;
270
- if (Root.Runtime.experiments.isEnabled(Root.ExperimentNames.ExperimentName.APCA)) {
269
+ if (Common.Settings.Settings.instance().moduleSetting('apca').get()) {
271
270
  const contrastRatio = contrastInfo.contrastRatioAPCA();
272
271
  const threshold = contrastInfo.contrastRatioAPCAThreshold();
273
272
  const passes = contrastRatio && threshold ? Math.abs(contrastRatio) >= threshold : false;
@@ -291,7 +291,9 @@ interface AffectedCountViewInput {
291
291
  }
292
292
  type AffectedCountView = (input: AffectedCountViewInput, output: object, target: HTMLElement) => void;
293
293
  export const AFFECTED_COUNT_DEFAULT_VIEW: AffectedCountView = (input, output, target) => {
294
- render(html`${i18nString(UIStrings.dAffected, {PH1: input.count})}`, target);
294
+ render(
295
+ html`${i18nString(UIStrings.dAffected, {PH1: input.count})}`, target,
296
+ {container: {classes: ['blocked-url-count']}});
295
297
  };
296
298
 
297
299
  function matchesUrl(conditions: SDK.NetworkManager.RequestCondition, url: string): boolean {
@@ -304,7 +306,7 @@ export class AffectedCountWidget extends UI.Widget.Widget {
304
306
  #lookUpRequestCount?: (condition: SDK.NetworkManager.RequestCondition) => number;
305
307
 
306
308
  constructor(target?: HTMLElement, view = AFFECTED_COUNT_DEFAULT_VIEW) {
307
- super(target, {classes: ['blocked-url-count']});
309
+ super(target);
308
310
  this.#view = view;
309
311
  }
310
312
 
@@ -289,8 +289,13 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
289
289
  </ul>
290
290
  </li>
291
291
  </ul>
292
- `}></devtools-tree>
293
- `, target);
292
+ `}></devtools-tree>`, target, {
293
+ container: {
294
+ classes: ['request-payload-view'],
295
+ attributes: {
296
+ jslog: `${VisualLogging.pane('payload').track({resize: true})}`,
297
+ },
298
+ }});
294
299
  // clang-format on
295
300
  };
296
301
 
@@ -305,7 +310,7 @@ export class RequestPayloadView extends UI.Widget.VBox {
305
310
  #viewQueryParamSource = false;
306
311
 
307
312
  constructor(target?: HTMLElement, view = DEFAULT_VIEW) {
308
- super({jslog: `${VisualLogging.pane('payload').track({resize: true})}`, classes: ['request-payload-view']});
313
+ super();
309
314
  this.#view = view;
310
315
  }
311
316
 
@@ -407,9 +407,9 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
407
407
  }
408
408
  }
409
409
 
410
- render(
411
- // clang-format off
412
- html`<style>${networkingTimingTableStyles}</style>
410
+ // clang-format off
411
+ render(html`
412
+ <style>${networkingTimingTableStyles}</style>
413
413
  <table
414
414
  class=${classes}
415
415
  jslog=${VisualLogging.pane('timing').track({
@@ -532,9 +532,8 @@ ${uiI18n.getFormatLocalizedStringTemplate(str_, UIStrings.duringDevelopmentYouCa
532
532
  html`<devtools-link href="https://web.dev/custom-metrics/#server-timing-api" .jslogContext=${'server-timing-api'}>${i18nString(UIStrings.theServerTimingApi)}</devtools-link>`})}
533
533
  </td>
534
534
  </tr>` : nothing}
535
- </table>`,
536
- // clang-format on
537
- target);
535
+ </table>`, target, {container: {classes: ['resource-timing-view']}});
536
+ // clang-format on
538
537
  };
539
538
 
540
539
  export class RequestTimingView extends UI.Widget.VBox {
@@ -543,7 +542,7 @@ export class RequestTimingView extends UI.Widget.VBox {
543
542
  #lastMinimumBoundary = -1;
544
543
  readonly #view: View;
545
544
  constructor(target?: HTMLElement, view = DEFAULT_VIEW) {
546
- super(target, {classes: ['resource-timing-view']});
545
+ super(target);
547
546
  this.#view = view;
548
547
  }
549
548
 
@@ -626,8 +626,9 @@ interface ControlPaneInput {
626
626
  type ControlPaneView = (input: ControlPaneInput, output: object, target: HTMLElement) => void;
627
627
 
628
628
  const CONTROL_PANE_DEFAULT_VIEW: ControlPaneView = (input, _output, target) => {
629
- render(
630
- input.chartsInfo.map(chartInfo => {
629
+ // clang-format off
630
+ render(html`
631
+ ${input.chartsInfo.map(chartInfo => {
631
632
  const chartName = chartInfo.metrics[0].name;
632
633
  const active = input.enabledCharts.has(chartName);
633
634
  const value = input.metricValues.get(chartName) || 0;
@@ -637,8 +638,9 @@ const CONTROL_PANE_DEFAULT_VIEW: ControlPaneView = (input, _output, target) => {
637
638
  value,
638
639
  (e: Event) => input.onCheckboxChange(chartName, e),
639
640
  );
640
- }),
641
- target);
641
+ })}
642
+ `, target, {container: {classes: ['perfmon-control-pane']}});
643
+ // clang-format on
642
644
  };
643
645
 
644
646
  export class ControlPane extends UI.Widget.VBox {
@@ -651,7 +653,7 @@ export class ControlPane extends UI.Widget.VBox {
651
653
  readonly #view: ControlPaneView;
652
654
 
653
655
  constructor(element: HTMLElement, view = CONTROL_PANE_DEFAULT_VIEW) {
654
- super(element, {useShadowDom: false, classes: ['perfmon-control-pane']});
656
+ super(element, {useShadowDom: false});
655
657
  this.#view = view;
656
658
 
657
659
  this.#enabledChartsSetting = Common.Settings.Settings.instance().createSetting(
@@ -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: a287ca9049cc3727d680078c1d9275b32f721c2d
4
+ Revision: 7e9e4ee5d284534f90cf424bf02eb9d65ed151ec
5
5
  Update Mechanism: Manual (https://crbug.com/428069060)
6
6
  License: BSD-3-Clause
7
7
  License File: LICENSE