chrome-devtools-frontend 1.0.1642246 → 1.0.1642899

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 (59) hide show
  1. package/SECURITY.md +1 -0
  2. package/front_end/core/host/UserMetrics.ts +2 -1
  3. package/front_end/core/sdk/CSSMatchedStyles.ts +55 -26
  4. package/front_end/core/sdk/CSSRule.ts +1 -0
  5. package/front_end/core/sdk/DebuggerModel.ts +5 -0
  6. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +4 -3
  7. package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +4 -3
  8. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +11 -0
  9. package/front_end/models/ai_assistance/AiAgent2.ts +80 -16
  10. package/front_end/models/ai_assistance/AiConversation.ts +3 -2
  11. package/front_end/models/ai_assistance/README.md +8 -0
  12. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +50 -39
  13. package/front_end/models/ai_assistance/agents/AiAgent.ts +17 -6
  14. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +2 -2
  15. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +195 -147
  16. package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +1 -26
  17. package/front_end/models/ai_assistance/agents/StylingAgent.ts +24 -309
  18. package/front_end/models/ai_assistance/ai_assistance.ts +8 -0
  19. package/front_end/models/ai_assistance/contexts/DOMNodeContext.snapshot.txt +51 -0
  20. package/front_end/models/ai_assistance/contexts/DOMNodeContext.ts +200 -0
  21. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +13 -12
  22. package/front_end/models/ai_assistance/skills/styling.md +36 -2
  23. package/front_end/models/ai_assistance/tools/GetStyles.ts +137 -0
  24. package/front_end/models/ai_assistance/tools/Tool.ts +55 -0
  25. package/front_end/models/ai_assistance/tools/ToolRegistry.ts +34 -0
  26. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +4 -0
  27. package/front_end/models/javascript_metadata/NativeFunctions.js +16 -0
  28. package/front_end/models/lighthouse/LighthouseReporterTypes.ts +5 -0
  29. package/front_end/models/live-metrics/LiveMetrics.ts +24 -13
  30. package/front_end/models/stack_trace/DetailedErrorStackParser.ts +2 -2
  31. package/front_end/models/stack_trace/StackTrace.ts +4 -1
  32. package/front_end/models/stack_trace/StackTraceImpl.ts +9 -2
  33. package/front_end/models/stack_trace/StackTraceModel.ts +17 -4
  34. package/front_end/models/stack_trace/Trie.ts +1 -1
  35. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +19 -15
  36. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +16 -0
  37. package/front_end/panels/ai_assistance/components/ChatInput.ts +2 -2
  38. package/front_end/panels/application/DOMStorageItemsView.ts +4 -0
  39. package/front_end/panels/application/KeyValueStorageItemsView.ts +39 -7
  40. package/front_end/panels/common/ExtensionServer.ts +26 -15
  41. package/front_end/panels/console/SymbolizedErrorWidget.ts +96 -2
  42. package/front_end/panels/console/symbolizedErrorWidget.css +48 -0
  43. package/front_end/panels/elements/StandaloneStylesContainer.ts +1 -1
  44. package/front_end/panels/elements/StylePropertiesSection.ts +8 -0
  45. package/front_end/panels/elements/StylePropertyHighlighter.ts +4 -2
  46. package/front_end/panels/elements/StylePropertyTreeElement.ts +6 -5
  47. package/front_end/panels/elements/StylesContainer.ts +1 -1
  48. package/front_end/panels/elements/StylesSidebarPane.ts +4 -4
  49. package/front_end/panels/layer_viewer/PaintProfilerView.ts +106 -132
  50. package/front_end/panels/lighthouse/LighthousePanel.ts +4 -3
  51. package/front_end/panels/network/NetworkLogView.ts +3 -0
  52. package/front_end/panels/network/networkLogView.css +0 -15
  53. package/front_end/third_party/chromium/README.chromium +1 -1
  54. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +36 -3
  55. package/front_end/ui/legacy/components/data_grid/dataGridAiButton.css +20 -0
  56. package/front_end/ui/legacy/components/utils/Linkifier.ts +19 -4
  57. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  58. package/front_end/ui/visual_logging/LoggingDriver.ts +13 -0
  59. package/package.json +1 -1
@@ -11,9 +11,13 @@ import type * as SDK from '../../core/sdk/sdk.js';
11
11
  import type * as Protocol from '../../generated/protocol.js';
12
12
  import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
13
13
  import * as UI from '../../ui/legacy/legacy.js';
14
+ import * as Lit from '../../ui/lit/lit.js';
14
15
 
15
16
  import paintProfilerStyles from './paintProfiler.css.js';
16
17
 
18
+ const {html, render, nothing} = Lit;
19
+ const {repeat} = Lit.Directives;
20
+
17
21
  const UIStrings = {
18
22
  /**
19
23
  * @description Text to indicate the progress of a profile
@@ -397,161 +401,131 @@ export interface EventTypes {
397
401
  [Events.WINDOW_CHANGED]: void;
398
402
  }
399
403
 
400
- export class PaintProfilerCommandLogView extends UI.Widget.VBox {
401
- private readonly treeOutline: UI.TreeOutline.TreeOutlineInShadow;
402
- private log: SDK.PaintProfiler.PaintProfilerLogItem[];
403
- private readonly treeItemCache: Map<SDK.PaintProfiler.PaintProfilerLogItem, LogTreeElement>;
404
- private selectionWindow?: {left: number, right: number}|null;
405
- constructor() {
406
- super();
407
- this.setMinimumSize(100, 25);
408
- this.element.classList.add('overflow-auto');
409
-
410
- this.treeOutline = new UI.TreeOutline.TreeOutlineInShadow();
411
- UI.ARIAUtils.setLabel(this.treeOutline.contentElement, i18nString(UIStrings.commandLog));
412
- this.element.appendChild(this.treeOutline.element);
413
- this.setDefaultFocusedElement(this.treeOutline.contentElement);
414
-
415
- this.log = [];
416
- this.treeItemCache = new Map();
417
- }
418
-
419
- setCommandLog(log: SDK.PaintProfiler.PaintProfilerLogItem[]): void {
420
- this.log = log;
404
+ export interface CommandLogViewInput {
405
+ visibleLogItems: SDK.PaintProfiler.PaintProfilerLogItem[];
406
+ }
421
407
 
422
- this.updateWindow({left: 0, right: this.log.length});
408
+ function paramToString(param: SDK.PaintProfiler.RawPaintProfilerLogItemParamValue, name: string): string {
409
+ if (typeof param !== 'object') {
410
+ return typeof param === 'string' && param.length > 100 ? name : JSON.stringify(param);
423
411
  }
424
-
425
- private appendLogItem(logItem: SDK.PaintProfiler.PaintProfilerLogItem): void {
426
- let treeElement = this.treeItemCache.get(logItem);
427
- if (!treeElement) {
428
- treeElement = new LogTreeElement(logItem);
429
- this.treeItemCache.set(logItem, treeElement);
430
- } else if (treeElement.parent) {
431
- return;
412
+ let str = '';
413
+ let keyCount = 0;
414
+ for (const key in param) {
415
+ const paramKey = param[key];
416
+ if (++keyCount > 4 || typeof paramKey === 'object' || (typeof paramKey === 'string' && paramKey.length > 100)) {
417
+ return name;
418
+ }
419
+ if (str) {
420
+ str += ', ';
432
421
  }
433
- this.treeOutline.appendChild(treeElement);
422
+ str += paramKey;
434
423
  }
424
+ return str;
425
+ }
435
426
 
436
- updateWindow(selectionWindow: {left: number, right: number}|null): void {
437
- this.selectionWindow = selectionWindow;
438
- this.requestUpdate();
427
+ function paramsToString(params: SDK.PaintProfiler.RawPaintProfilerLogItemParams|null): string {
428
+ let str = '';
429
+ for (const key in params) {
430
+ if (str) {
431
+ str += ', ';
432
+ }
433
+ str += paramToString(params[key], key);
439
434
  }
435
+ return str;
436
+ }
440
437
 
441
- override performUpdate(): Promise<void> {
442
- if (!this.selectionWindow || !this.log.length) {
443
- this.treeOutline.removeChildren();
444
- return Promise.resolve();
445
- }
446
- const root = this.treeOutline.rootElement();
447
- for (;;) {
448
- const child = root.firstChild() as LogTreeElement;
449
- if (!child || child.logItem.commandIndex >= this.selectionWindow.left) {
450
- break;
438
+ function renderProperty(name: string, value: SDK.PaintProfiler.RawPaintProfilerLogItemParamValue): Lit.LitTemplate {
439
+ const isObject = value !== null && typeof value === 'object';
440
+
441
+ // clang-format off
442
+ return html`
443
+ <li role="treeitem">
444
+ <span>${name}: </span>${
445
+ isObject ? html`
446
+ <ul role="group">
447
+ ${Object.entries(value).map(([key, val]) => renderProperty(key, val))}
448
+ </ul>` : html`
449
+ <span>${JSON.stringify(value)}</span>`
451
450
  }
452
- root.removeChildAtIndex(0);
453
- }
454
- for (;;) {
455
- const child = root.lastChild() as LogTreeElement;
456
- if (!child || child.logItem.commandIndex < this.selectionWindow.right) {
457
- break;
458
- }
459
- root.removeChildAtIndex(root.children().length - 1);
460
- }
461
- for (let i = this.selectionWindow.left, right = this.selectionWindow.right; i < right; ++i) {
462
- this.appendLogItem(this.log[i]);
463
- }
464
- return Promise.resolve();
465
- }
451
+ </li>
452
+ `;
453
+ // clang-format on
466
454
  }
467
455
 
468
- export class LogTreeElement extends UI.TreeOutline.TreeElement {
469
- readonly logItem: SDK.PaintProfiler.PaintProfilerLogItem;
456
+ function renderLogItem(logItem: SDK.PaintProfiler.PaintProfilerLogItem): Lit.LitTemplate {
457
+ const hasParams = Boolean(logItem.params && Object.keys(logItem.params).length > 0);
458
+ const titleText = logItem.method + '(' + paramsToString(logItem.params) + ')';
459
+
460
+ // clang-format off
461
+ return html`
462
+ <li role="treeitem">
463
+ ${titleText}
464
+ ${hasParams ? html`
465
+ <ul role="group">
466
+ ${Object.entries(logItem.params || {}).map(([key, val]) => renderProperty(key, val))}
467
+ </ul>` : nothing}
468
+ </li>
469
+ `;
470
+ // clang-format on
471
+ }
470
472
 
471
- constructor(logItem: SDK.PaintProfiler.PaintProfilerLogItem) {
472
- super('', Boolean(logItem.params));
473
- this.logItem = logItem;
474
- }
473
+ // clang-format off
474
+ export const COMMAND_LOG_DEFAULT_VIEW = (input: CommandLogViewInput, _output: undefined, target: HTMLElement): void => {
475
+ render(html`
476
+ <div class="overflow-auto flex-auto vbox">
477
+ <devtools-tree
478
+ autofocus
479
+ aria-label=${i18nString(UIStrings.commandLog)}
480
+ .template=${html`
481
+ <ul role="tree">
482
+ ${repeat(input.visibleLogItems,
483
+ item => item.commandIndex,
484
+ item => renderLogItem(item))}
485
+ </ul>`}>
486
+ </devtools-tree>
487
+ </div>`,
488
+ target);
489
+ };
490
+ // clang-format on
491
+
492
+ type CommandLogView = typeof COMMAND_LOG_DEFAULT_VIEW;
475
493
 
476
- override onattach(): void {
477
- this.update();
478
- }
494
+ export class PaintProfilerCommandLogView extends UI.Widget.VBox {
495
+ private log: SDK.PaintProfiler.PaintProfilerLogItem[];
496
+ private selectionWindow?: {left: number, right: number}|null;
497
+ readonly #view: CommandLogView;
479
498
 
480
- override async onpopulate(): Promise<void> {
481
- for (const param in this.logItem.params) {
482
- LogPropertyTreeElement.appendLogPropertyItem(this, param, this.logItem.params[param]);
483
- }
484
- }
499
+ constructor(element?: HTMLElement, view: CommandLogView = COMMAND_LOG_DEFAULT_VIEW) {
500
+ super(element);
501
+ this.#view = view;
502
+ this.setMinimumSize(100, 25);
485
503
 
486
- private paramToString(param: SDK.PaintProfiler.RawPaintProfilerLogItemParamValue, name: string): string {
487
- if (typeof param !== 'object') {
488
- return typeof param === 'string' && param.length > 100 ? name : JSON.stringify(param);
489
- }
490
- let str = '';
491
- let keyCount = 0;
492
- for (const key in param) {
493
- const paramKey = param[key];
494
- if (++keyCount > 4 || paramKey === 'object' || (paramKey === 'string' && paramKey.length > 100)) {
495
- return name;
496
- }
497
- if (str) {
498
- str += ', ';
499
- }
500
- str += paramKey;
501
- }
502
- return str;
504
+ this.log = [];
503
505
  }
504
506
 
505
- private paramsToString(params: SDK.PaintProfiler.RawPaintProfilerLogItemParams|null): string {
506
- let str = '';
507
- for (const key in params) {
508
- if (str) {
509
- str += ', ';
510
- }
511
- str += this.paramToString(params[key], key);
512
- }
513
- return str;
507
+ override wasShown(): void {
508
+ super.wasShown();
509
+ this.requestUpdate();
514
510
  }
515
511
 
516
- private update(): void {
517
- const title = document.createDocumentFragment();
518
- UI.UIUtils.createTextChild(title, this.logItem.method + '(' + this.paramsToString(this.logItem.params) + ')');
519
- this.title = title;
512
+ setCommandLog(log: SDK.PaintProfiler.PaintProfilerLogItem[]): void {
513
+ this.log = log;
514
+ this.updateWindow({left: 0, right: this.log.length});
520
515
  }
521
- }
522
-
523
- export class LogPropertyTreeElement extends UI.TreeOutline.TreeElement {
524
- private property: {name: string, value: SDK.PaintProfiler.RawPaintProfilerLogItemParamValue};
525
516
 
526
- constructor(property: {name: string, value: SDK.PaintProfiler.RawPaintProfilerLogItemParamValue}) {
527
- super();
528
- this.property = property;
517
+ updateWindow(selectionWindow: {left: number, right: number}|null): void {
518
+ this.selectionWindow = selectionWindow;
519
+ this.requestUpdate();
529
520
  }
530
521
 
531
- static appendLogPropertyItem(
532
- element: UI.TreeOutline.TreeElement, name: string,
533
- value: SDK.PaintProfiler.RawPaintProfilerLogItemParamValue): void {
534
- const treeElement = new LogPropertyTreeElement({name, value});
535
- element.appendChild(treeElement);
536
- if (value && typeof value === 'object') {
537
- for (const property in value) {
538
- LogPropertyTreeElement.appendLogPropertyItem(treeElement, property, value[property]);
539
- }
540
- }
541
- }
522
+ override performUpdate(): Promise<void> {
523
+ const visibleLogItems = this.selectionWindow && this.log.length ?
524
+ this.log.slice(this.selectionWindow.left, this.selectionWindow.right) :
525
+ [];
542
526
 
543
- override onattach(): void {
544
- const title = document.createDocumentFragment();
545
- const nameElement = title.createChild('span', 'name');
546
- nameElement.textContent = this.property.name;
547
- const separatorElement = title.createChild('span', 'separator');
548
- separatorElement.textContent = ': ';
549
- if (this.property.value === null || typeof this.property.value !== 'object') {
550
- const valueElement = title.createChild('span', 'value');
551
- valueElement.textContent = JSON.stringify(this.property.value);
552
- valueElement.classList.add('cm-js-' + (this.property.value === null ? 'null' : typeof this.property.value));
553
- }
554
- this.title = title;
527
+ this.#view({visibleLogItems}, undefined, this.contentElement);
528
+ return Promise.resolve();
555
529
  }
556
530
  }
557
531
 
@@ -374,11 +374,12 @@ export class LighthousePanel extends UI.Panel.Panel {
374
374
  }
375
375
 
376
376
  private loadedFromFile(report: string): void {
377
- const data = JSON.parse(report);
378
- if (!data['lighthouseVersion']) {
377
+ const data = JSON.parse(report) as LighthouseModel.ReporterTypes.ReportJSON;
378
+ if (!data.lighthouseVersion) {
379
379
  return;
380
380
  }
381
- this.buildReportUI(data as LighthouseModel.ReporterTypes.ReportJSON);
381
+ data.isImported = true;
382
+ this.buildReportUI(data);
382
383
  }
383
384
 
384
385
  override elementsToRestoreScrollPositionsFor(): Element[] {
@@ -54,6 +54,8 @@ import * as Adorners from '../../ui/components/adorners/adorners.js';
54
54
  import * as Buttons from '../../ui/components/buttons/buttons.js';
55
55
  import * as RenderCoordinator from '../../ui/components/render_coordinator/render_coordinator.js';
56
56
  import * as DataGrid from '../../ui/legacy/components/data_grid/data_grid.js';
57
+ // eslint-disable-next-line @devtools/es-modules-import
58
+ import dataGridAiButtonStyles from '../../ui/legacy/components/data_grid/dataGridAiButton.css.js';
57
59
  import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
58
60
  import * as Components from '../../ui/legacy/components/utils/utils.js';
59
61
  import * as UI from '../../ui/legacy/legacy.js';
@@ -560,6 +562,7 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
560
562
  networkLogLargeRowsSetting: Common.Settings.Setting<boolean>) {
561
563
  super();
562
564
  this.registerRequiredCSS(networkLogViewStyles);
565
+ this.registerRequiredCSS(dataGridAiButtonStyles);
563
566
  this.setMinimumSize(50, 64);
564
567
 
565
568
  this.element.id = 'network-container';
@@ -268,21 +268,6 @@ td.time-column {
268
268
  vertical-align: sub;
269
269
  }
270
270
 
271
- .data-grid-data-grid-node .ai-button-container {
272
- display: none;
273
- float: right;
274
-
275
- devtools-floating-button {
276
- position: absolute;
277
- z-index: 999;
278
- margin-left: -17px;
279
- }
280
- }
281
-
282
- .data-grid-data-grid-node:hover .ai-button-container {
283
- display: inline-flex;
284
- }
285
-
286
271
  .image-network-icon-preview {
287
272
  inset: 0;
288
273
  margin: auto;
@@ -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: 3b896e6bd479ace00cb8f591bd5b8905a94459a1
4
+ Revision: 2d046db188ecad76b2859f8baeb9685cb8fe9c08
5
5
  Update Mechanism: Manual (https://crbug.com/428069060)
6
6
  License: BSD-3-Clause
7
7
  License File: LICENSE
@@ -34,6 +34,7 @@
34
34
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
35
  */
36
36
  import '../data_grid/data_grid.js';
37
+ import '../../../components/buttons/buttons.js';
37
38
 
38
39
  import * as Common from '../../../../core/common/common.js';
39
40
  import * as i18n from '../../../../core/i18n/i18n.js';
@@ -43,12 +44,15 @@ import type * as Protocol from '../../../../generated/protocol.js';
43
44
  import * as IssuesManager from '../../../../models/issues_manager/issues_manager.js';
44
45
  import * as NetworkForward from '../../../../panels/network/forward/forward.js';
45
46
  import {Icon} from '../../../kit/kit.js';
46
- import {Directives, html, render} from '../../../lit/lit.js';
47
+ import {Directives, html, nothing, render} from '../../../lit/lit.js';
47
48
  import * as UI from '../../legacy.js';
49
+ import dataGridAiButtonStyles from '../data_grid/dataGridAiButton.css.js';
48
50
 
49
51
  import cookiesTableStyles from './cookiesTable.css.js';
50
52
 
51
- interface ViewInput {
53
+ const STORAGE_FLOATING_BUTTON_ACTION_ID = 'ai-assistance.storage-floating-button';
54
+
55
+ export interface ViewInput {
52
56
  data: CookieData[];
53
57
  selectedKey?: string;
54
58
  editable?: boolean;
@@ -61,6 +65,9 @@ interface ViewInput {
61
65
  onDelete: (data: CookieData) => void;
62
66
  onContextMenu: (data: CookieData, menu: UI.ContextMenu.ContextMenu) => void;
63
67
  onSelect: (key: string|undefined) => void;
68
+ showAiButton?: boolean;
69
+ aiButtonTitle?: string;
70
+ onAiButtonClick?: (cookie: CookieData, event: Event) => void;
64
71
  }
65
72
  type ViewFunction = (input: ViewInput, output: object, target: HTMLElement) => void;
66
73
  type AttributeWithIcon = SDK.Cookie.Attribute.NAME|SDK.Cookie.Attribute.VALUE|SDK.Cookie.Attribute.DOMAIN|
@@ -219,6 +226,7 @@ export class CookiesTable extends UI.Widget.VBox {
219
226
  @deselect=${() => input.onSelect(undefined)}
220
227
  >
221
228
  <table>
229
+ ${input.showAiButton ? html`<style>${dataGridAiButtonStyles}</style>` : nothing}
222
230
  <tr>
223
231
  <th id=${SDK.Cookie.Attribute.NAME} sortable ?disclosure=${input.editable} ?editable=${input.editable} long weight="24">
224
232
  ${i18nString(UIStrings.name)}
@@ -275,7 +283,15 @@ export class CookiesTable extends UI.Widget.VBox {
275
283
  @delete=${()=> input.onDelete(cookie)}
276
284
  @contextmenu=${(e: CustomEvent<UI.ContextMenu.ContextMenu>) => input.onContextMenu(cookie, e.detail)}
277
285
  @select=${() => input.onSelect(cookie.key)}>
278
- <td>${cookie.icons?.name}${cookie.name}</td>
286
+ <td>${input.showAiButton && !Boolean(cookie['http-only']) ? html`
287
+ <span class="ai-button-container">
288
+ <devtools-floating-button
289
+ icon-name=${Root.Runtime.hostConfig.devToolsGeminiRebranding?.enabled ? 'spark' : 'smart-assistant'}
290
+ title=${ifDefined(input.aiButtonTitle)}
291
+ @click=${(e: Event) => input.onAiButtonClick?.(cookie, e)}
292
+ ></devtools-floating-button>
293
+ </span>
294
+ ` : nothing}${cookie.icons?.name}${cookie.name}</td>
279
295
  <td>${cookie.value}</td>
280
296
  <td>${cookie.icons?.domain}${cookie.domain}</td>
281
297
  <td>${cookie.icons?.path}${cookie.path}</td>
@@ -404,6 +420,19 @@ export class CookiesTable extends UI.Widget.VBox {
404
420
  onDelete: this.onDeleteCookie.bind(this),
405
421
  onSelect: this.onSelect.bind(this),
406
422
  onContextMenu: this.populateContextMenu.bind(this),
423
+ showAiButton: this.isAiButtonEnabled(),
424
+ aiButtonTitle: this.isAiButtonEnabled() &&
425
+ UI.ActionRegistry.ActionRegistry.instance().hasAction(STORAGE_FLOATING_BUTTON_ACTION_ID) ?
426
+ UI.ActionRegistry.ActionRegistry.instance().getAction(STORAGE_FLOATING_BUTTON_ACTION_ID).title() :
427
+ undefined,
428
+ onAiButtonClick: (cookie: CookieData, event: Event) => {
429
+ event.stopPropagation();
430
+ this.onSelect(cookie.key);
431
+ const actionRegistry = UI.ActionRegistry.ActionRegistry.instance();
432
+ if (actionRegistry.hasAction(STORAGE_FLOATING_BUTTON_ACTION_ID)) {
433
+ void actionRegistry.getAction(STORAGE_FLOATING_BUTTON_ACTION_ID).execute();
434
+ }
435
+ },
407
436
  };
408
437
  const output = {};
409
438
  this.view(input, output, this.element);
@@ -414,6 +443,10 @@ export class CookiesTable extends UI.Widget.VBox {
414
443
  this.#selectedCallback?.(this.selectedCookie());
415
444
  }
416
445
 
446
+ private isAiButtonEnabled(): boolean {
447
+ return UI.ActionRegistry.ActionRegistry.instance().hasAction(STORAGE_FLOATING_BUTTON_ACTION_ID);
448
+ }
449
+
417
450
  private onDeleteCookie(data: CookieData): void {
418
451
  const cookie = this.cookies.find(cookie => cookie.key() === data.key);
419
452
  if (cookie && this.#deleteCallback) {
@@ -0,0 +1,20 @@
1
+ /*
2
+ * Copyright 2026 The Chromium Authors
3
+ * Use of this source code is governed by a BSD-style license that can be
4
+ * found in the LICENSE file.
5
+ */
6
+
7
+ .data-grid-data-grid-node .ai-button-container {
8
+ display: none;
9
+ float: right;
10
+
11
+ devtools-floating-button {
12
+ position: absolute;
13
+ z-index: 999;
14
+ margin-left: -17px;
15
+ }
16
+ }
17
+
18
+ .data-grid-data-grid-node:hover .ai-button-container {
19
+ display: inline-flex;
20
+ }
@@ -399,7 +399,12 @@ export class Linkifier extends Common.ObjectWrapper.ObjectWrapper<EventTypes> im
399
399
  jslogContext: options?.jslogContext || 'script-location',
400
400
  omitOrigin: options?.omitOrigin,
401
401
  } satisfies LinkifyURLOptions;
402
- const fallbackAnchor = Linkifier.linkifyURL(frame.url as Platform.DevToolsPath.UrlString, linkifyURLOptions);
402
+ const fallbackOptions = {
403
+ ...linkifyURLOptions,
404
+ showColumnNumber: frame.isWasm || Boolean(options?.showColumnNumber),
405
+ omitLineAndRenderColumnAsHex: frame.isWasm,
406
+ };
407
+ const fallbackAnchor = Linkifier.linkifyURL(frame.url as Platform.DevToolsPath.UrlString, fallbackOptions);
403
408
  if (!frame.uiSourceCode) {
404
409
  const isIgnoreListed = (options?.ignoreListManager ?? Workspace.IgnoreListManager.IgnoreListManager.instance())
405
410
  .isUserIgnoreListedURL(frame.url as Platform.DevToolsPath.UrlString);
@@ -602,6 +607,11 @@ export class Linkifier extends Common.ObjectWrapper.ObjectWrapper<EventTypes> im
602
607
  const maxLength = options.maxLength || UI.UIUtils.MaxLengthForDisplayedURLs;
603
608
  const bypassURLTrimming = options.bypassURLTrimming;
604
609
  const omitOrigin = options.omitOrigin;
610
+ const omitLineAndRenderColumnAsHex = options.omitLineAndRenderColumnAsHex;
611
+
612
+ if (omitLineAndRenderColumnAsHex && showColumnNumber === false) {
613
+ throw new Error('omitLineAndRenderColumnAsHex requires showColumnNumber to not be explicitly false');
614
+ }
605
615
 
606
616
  if (!url || Common.ParsedURL.schemeIs(url, 'javascript:')) {
607
617
  // clang-format off
@@ -619,7 +629,11 @@ export class Linkifier extends Common.ObjectWrapper.ObjectWrapper<EventTypes> im
619
629
  }
620
630
  }
621
631
 
622
- if (typeof lineNumber === 'number' && !text) {
632
+ if (omitLineAndRenderColumnAsHex && !text) {
633
+ if (typeof columnNumber === 'number') {
634
+ linkText += ':0x' + columnNumber.toString(16);
635
+ }
636
+ } else if (typeof lineNumber === 'number' && !text) {
623
637
  linkText += ':' + (lineNumber + 1);
624
638
  if (showColumnNumber && typeof columnNumber === 'number') {
625
639
  linkText += ':' + (columnNumber + 1);
@@ -947,7 +961,7 @@ export class Linkifier extends Common.ObjectWrapper.ObjectWrapper<EventTypes> im
947
961
  }
948
962
 
949
963
  for (const registration of linkHandlers.values().filter(r => r.handler)) {
950
- const {title, handler, shouldHandleOpenResource} = registration;
964
+ const {title, origin, handler, shouldHandleOpenResource} = registration;
951
965
  if (url && !shouldHandleOpenResource(url, specificSchemeHandlers)) {
952
966
  continue;
953
967
  }
@@ -957,7 +971,7 @@ export class Linkifier extends Common.ObjectWrapper.ObjectWrapper<EventTypes> im
957
971
  jslogContext: 'open-using',
958
972
  handler: handler.bind(null, contentProviderOrUrl, lineNumber, columnNumber),
959
973
  };
960
- if (title === Linkifier.linkHandlerSetting().get()) {
974
+ if (origin === Linkifier.linkHandlerSetting().get()) {
961
975
  result.unshift(action);
962
976
  } else {
963
977
  result.push(action);
@@ -1182,6 +1196,7 @@ export interface LinkifyURLOptions {
1182
1196
  jslogContext?: string;
1183
1197
  omitOrigin?: boolean;
1184
1198
  onRef?: (el: HTMLElement) => void;
1199
+ omitLineAndRenderColumnAsHex?: boolean;
1185
1200
  }
1186
1201
 
1187
1202
  export interface LinkifyOptions {
@@ -362,6 +362,7 @@ export const knownContextValues = new Set([
362
362
  'ai-assistance-v2-opt-in-change-dialog-seen',
363
363
  'ai-assistance-v2-opt-in.got-it',
364
364
  'ai-assistance-v2-opt-in.manage-settings',
365
+ 'ai-assistance.storage-floating-button',
365
366
  'ai-code-completion-citations',
366
367
  'ai-code-completion-citations.citation-link',
367
368
  'ai-code-completion-disclaimer',
@@ -80,6 +80,12 @@ export async function addDocument(document: Document): Promise<void> {
80
80
  }
81
81
  document.addEventListener('visibilitychange', scheduleProcessing);
82
82
  document.addEventListener('scroll', scheduleProcessing);
83
+ const resizeListener = (): void => {
84
+ viewportRects.delete(document);
85
+ scheduleProcessing();
86
+ };
87
+ document.defaultView?.addEventListener('resize', resizeListener);
88
+ resizeListeners.set(document, resizeListener);
83
89
  observeMutations([document.body]);
84
90
  }
85
91
 
@@ -90,12 +96,18 @@ export async function stopLogging(): Promise<void> {
90
96
  for (const document of documents) {
91
97
  document.removeEventListener('visibilitychange', scheduleProcessing);
92
98
  document.removeEventListener('scroll', scheduleProcessing);
99
+ const resizeListener = resizeListeners.get(document);
100
+ if (resizeListener) {
101
+ document.defaultView?.removeEventListener('resize', resizeListener);
102
+ resizeListeners.delete(document);
103
+ }
93
104
  }
94
105
  mutationObserver.disconnect();
95
106
  resizeObserver.disconnect();
96
107
  intersectionObserver.disconnect();
97
108
  documents.length = 0;
98
109
  viewportRects.clear();
110
+ resizeListeners.clear();
99
111
  processingThrottler = noOpThrottler;
100
112
  pendingResize.clear();
101
113
  pendingChange.clear();
@@ -130,6 +142,7 @@ export function scheduleProcessing(): void {
130
142
  }
131
143
 
132
144
  const viewportRects = new Map<Document, DOMRect>();
145
+ const resizeListeners = new Map<Document, () => void>();
133
146
  const viewportRectFor = (element: Element): DOMRect => {
134
147
  const ownerDocument = element.ownerDocument;
135
148
  const viewportRect = viewportRects.get(ownerDocument) ||
package/package.json CHANGED
@@ -92,5 +92,5 @@
92
92
  "webidl2": "24.5.0",
93
93
  "yargs": "17.7.2"
94
94
  },
95
- "version": "1.0.1642246"
95
+ "version": "1.0.1642899"
96
96
  }