chrome-devtools-frontend 1.0.962581 → 1.0.964938

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 (61) hide show
  1. package/AUTHORS +1 -0
  2. package/config/gni/devtools_grd_files.gni +6 -0
  3. package/docs/resource_management.md +119 -0
  4. package/docs/workflows.md +7 -0
  5. package/front_end/core/common/ParsedURL.ts +12 -10
  6. package/front_end/core/host/UserMetrics.ts +2 -1
  7. package/front_end/core/i18n/locales/en-US.json +23 -2
  8. package/front_end/core/i18n/locales/en-XL.json +23 -2
  9. package/front_end/core/root/Runtime.ts +2 -0
  10. package/front_end/core/sdk/DOMModel.ts +2 -2
  11. package/front_end/core/sdk/DebuggerModel.ts +1 -1
  12. package/front_end/entrypoints/main/MainImpl.ts +7 -2
  13. package/front_end/generated/InspectorBackendCommands.js +8 -4
  14. package/front_end/generated/protocol-mapping.d.ts +12 -1
  15. package/front_end/generated/protocol-proxy-api.d.ts +11 -1
  16. package/front_end/generated/protocol.ts +27 -12
  17. package/front_end/models/javascript_metadata/NativeFunctions.js +7480 -4147
  18. package/front_end/models/persistence/IsolatedFileSystem.ts +3 -2
  19. package/front_end/models/persistence/PersistenceActions.ts +2 -2
  20. package/front_end/models/workspace/UISourceCode.ts +4 -5
  21. package/front_end/panels/animation/AnimationUI.ts +2 -1
  22. package/front_end/panels/application/AppManifestView.ts +7 -1
  23. package/front_end/panels/application/ApplicationPanelSidebar.ts +41 -1
  24. package/front_end/panels/application/InterestGroupStorageModel.ts +87 -0
  25. package/front_end/panels/application/InterestGroupStorageView.ts +112 -0
  26. package/front_end/panels/application/InterestGroupTreeElement.ts +61 -0
  27. package/front_end/panels/application/application.ts +4 -0
  28. package/front_end/panels/application/components/BackForwardCacheStrings.ts +1 -1
  29. package/front_end/panels/application/components/FrameDetailsView.ts +1 -0
  30. package/front_end/panels/application/components/InterestGroupAccessGrid.ts +149 -0
  31. package/front_end/panels/application/components/components.ts +2 -0
  32. package/front_end/panels/application/components/interestGroupAccessGrid.css +26 -0
  33. package/front_end/panels/application/interestGroupStorageView.css +13 -0
  34. package/front_end/panels/elements/StylePropertyTreeElement.ts +13 -0
  35. package/front_end/panels/elements/StylesSidebarPane.ts +73 -4
  36. package/front_end/panels/elements/stylesSectionTree.css +28 -0
  37. package/front_end/panels/media/PlayerListView.ts +2 -0
  38. package/front_end/panels/media/playerListView.css +3 -0
  39. package/front_end/panels/sensors/sensors-meta.ts +2 -2
  40. package/front_end/panels/sources/NavigatorView.ts +1 -1
  41. package/front_end/panels/sources/UISourceCodeFrame.ts +7 -0
  42. package/front_end/ui/components/diff_view/DiffView.ts +2 -2
  43. package/front_end/ui/components/docs/icon_button/basic.ts +1 -1
  44. package/front_end/ui/components/icon_button/IconButton.ts +1 -1
  45. package/front_end/ui/legacy/GlassPane.ts +2 -0
  46. package/front_end/ui/legacy/components/inline_editor/cssLength.css +1 -0
  47. package/front_end/ui/legacy/softDropDownButton.css +2 -0
  48. package/front_end/ui/legacy/themeColors.css +3 -1
  49. package/front_end/ui/legacy/toolbar.css +6 -0
  50. package/package.json +1 -1
  51. package/scripts/build/devtools_plugin.js +103 -0
  52. package/scripts/build/ninja/{rollup.gni → bundle.gni} +2 -2
  53. package/scripts/build/ninja/devtools_entrypoint.gni +8 -8
  54. package/scripts/build/rollup.config.js +3 -93
  55. package/scripts/devtools_paths.js +3 -2
  56. package/scripts/javascript_natives/helpers.js +211 -0
  57. package/scripts/javascript_natives/index.js +57 -194
  58. package/scripts/javascript_natives/package.json +8 -3
  59. package/scripts/javascript_natives/test.d.ts +9 -0
  60. package/scripts/javascript_natives/tests.js +195 -0
  61. package/scripts/whitespaces.txt +1 -0
@@ -176,7 +176,7 @@ export class IsolatedFileSystem extends PlatformFileSystem {
176
176
  this.initialGitFoldersInternal.add(parentFolder);
177
177
  }
178
178
  if (this.isFileExcluded(entry.fullPath + '/')) {
179
- this.excludedEmbedderFolders.push(Common.ParsedURL.ParsedURL.capFilePrefix(
179
+ this.excludedEmbedderFolders.push(Common.ParsedURL.ParsedURL.urlToRawPathString(
180
180
  this.path() + entry.fullPath as Platform.DevToolsPath.UrlString, Host.Platform.isWin()));
181
181
  continue;
182
182
  }
@@ -555,7 +555,8 @@ export class IsolatedFileSystem extends PlatformFileSystem {
555
555
 
556
556
  tooltipForURL(url: string): string {
557
557
  const path = Platform.StringUtilities.trimMiddle(
558
- Common.ParsedURL.ParsedURL.capFilePrefix(url as Platform.DevToolsPath.UrlString, Host.Platform.isWin()), 150);
558
+ Common.ParsedURL.ParsedURL.urlToRawPathString(url as Platform.DevToolsPath.UrlString, Host.Platform.isWin()),
559
+ 150);
559
560
  return i18nString(UIStrings.linkedToS, {PH1: path});
560
561
  }
561
562
 
@@ -94,8 +94,8 @@ export class ContextMenuProvider implements UI.ContextMenu.Provider {
94
94
  const fileURL = binding ? binding.fileSystem.contentURL() : contentProvider.contentURL();
95
95
  if (fileURL.startsWith('file://')) {
96
96
  // TODO(crbug.com/1253323): Cast to UrlString will be removed when migration to branded types is complete.
97
- const path =
98
- Common.ParsedURL.ParsedURL.capFilePrefix(fileURL as Platform.DevToolsPath.UrlString, Host.Platform.isWin());
97
+ const path = Common.ParsedURL.ParsedURL.urlToRawPathString(
98
+ fileURL as Platform.DevToolsPath.UrlString, Host.Platform.isWin());
99
99
  contextMenu.revealSection().appendItem(
100
100
  i18nString(UIStrings.openInContainingFolder),
101
101
  () => Host.InspectorFrontendHost.InspectorFrontendHostInstance.showItemInFolder(path));
@@ -263,8 +263,7 @@ export class UISourceCode extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
263
263
  return;
264
264
  }
265
265
 
266
- if (this.contentInternal && 'content' in this.contentInternal &&
267
- this.contentInternal.content === updatedContent.content) {
266
+ if (this.contentInternal?.content === updatedContent.content) {
268
267
  this.lastAcceptedContent = null;
269
268
  return;
270
269
  }
@@ -331,7 +330,7 @@ export class UISourceCode extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
331
330
  if (this.isDirty()) {
332
331
  return this.workingCopyInternal as string;
333
332
  }
334
- return (this.contentInternal && 'content' in this.contentInternal && this.contentInternal.content) || '';
333
+ return this.contentInternal?.content || '';
335
334
  }
336
335
 
337
336
  resetWorkingCopy(): void {
@@ -393,7 +392,7 @@ export class UISourceCode extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
393
392
  }
394
393
 
395
394
  content(): string {
396
- return (this.contentInternal && 'content' in this.contentInternal && this.contentInternal.content) || '';
395
+ return this.contentInternal?.content || '';
397
396
  }
398
397
 
399
398
  loadError(): string|null {
@@ -439,7 +438,7 @@ export class UISourceCode extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
439
438
  }
440
439
 
441
440
  removeMessage(message: Message): void {
442
- if (this.messagesInternal && this.messagesInternal.delete(message)) {
441
+ if (this.messagesInternal?.delete(message)) {
443
442
  this.dispatchEventToListeners(Events.MessageRemoved, message);
444
443
  }
445
444
  }
@@ -279,7 +279,8 @@ export class AnimationUI {
279
279
  const iterationWidth = this.duration() * this.#timeline.pixelMsRatio();
280
280
  let iteration;
281
281
  for (iteration = 1; iteration < this.#animationInternal.source().iterations() &&
282
- iterationWidth * (iteration - 1) < this.#timeline.width();
282
+ iterationWidth * (iteration - 1) < this.#timeline.width() &&
283
+ (iterationWidth > 0 || this.#animationInternal.source().iterations() !== Infinity);
283
284
  iteration++) {
284
285
  this.renderIteration(this.#tailGroup, iteration);
285
286
  }
@@ -617,7 +617,13 @@ export class AppManifestView extends UI.Widget.VBox implements SDK.TargetManager
617
617
  const copyButton = new IconButton.IconButton.IconButton();
618
618
  copyButton.title = i18nString(UIStrings.copyToClipboard);
619
619
  copyButton.data = {
620
- groups: [{iconName: 'copy_icon', iconHeight: '12px', iconWidth: '12px', text: ''}],
620
+ groups: [{
621
+ iconName: 'copy_icon',
622
+ iconHeight: '12px',
623
+ iconWidth: '12px',
624
+ text: '',
625
+ iconColor: 'var(--color-text-primary)',
626
+ }],
621
627
  clickHandler: (): void => {
622
628
  Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(recommendedId);
623
629
  },
@@ -59,6 +59,8 @@ import {DOMStorageModel, Events as DOMStorageModelEvents} from './DOMStorageMode
59
59
  import type {Database as IndexedDBModelDatabase, DatabaseId, Index, ObjectStore} from './IndexedDBModel.js';
60
60
  import {Events as IndexedDBModelEvents, IndexedDBModel} from './IndexedDBModel.js';
61
61
  import {IDBDatabaseView, IDBDataView} from './IndexedDBViews.js';
62
+ import {InterestGroupStorageModel, Events as InterestGroupModelEvents} from './InterestGroupStorageModel.js';
63
+ import {InterestGroupTreeElement} from './InterestGroupTreeElement.js';
62
64
  import {OpenedWindowDetailsView, WorkerDetailsView} from './OpenedWindowDetailsView.js';
63
65
  import type {ResourcesPanel} from './ResourcesPanel.js';
64
66
  import {ServiceWorkersView} from './ServiceWorkersView.js';
@@ -186,6 +188,7 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
186
188
  localStorageListTreeElement: ExpandableApplicationPanelTreeElement;
187
189
  sessionStorageListTreeElement: ExpandableApplicationPanelTreeElement;
188
190
  indexedDBListTreeElement: IndexedDBTreeElement;
191
+ interestGroupTreeElement: InterestGroupTreeElement;
189
192
  databasesListTreeElement: ExpandableApplicationPanelTreeElement;
190
193
  cookieListTreeElement: ExpandableApplicationPanelTreeElement;
191
194
  trustTokensTreeElement: TrustTokensTreeElement;
@@ -276,6 +279,9 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
276
279
  this.trustTokensTreeElement = new TrustTokensTreeElement(panel);
277
280
  storageTreeElement.appendChild(this.trustTokensTreeElement);
278
281
 
282
+ this.interestGroupTreeElement = new InterestGroupTreeElement(panel);
283
+ storageTreeElement.appendChild(this.interestGroupTreeElement);
284
+
279
285
  const cacheSectionTitle = i18nString(UIStrings.cache);
280
286
  const cacheTreeElement = this.addSidebarSection(cacheSectionTitle);
281
287
  this.cacheStorageListTreeElement = new ServiceWorkerCacheTreeElement(panel);
@@ -349,7 +355,10 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
349
355
  modelAdded: (model: IndexedDBModel): void => model.enable(),
350
356
  modelRemoved: (model: IndexedDBModel): void => this.indexedDBListTreeElement.removeIndexedDBForModel(model),
351
357
  });
352
-
358
+ SDK.TargetManager.TargetManager.instance().observeModels(InterestGroupStorageModel, {
359
+ modelAdded: (model: InterestGroupStorageModel): void => this.interestGroupModelAdded(model),
360
+ modelRemoved: (model: InterestGroupStorageModel): void => this.interestGroupModelRemoved(model),
361
+ });
353
362
  // Work-around for crbug.com/1152713: Something is wrong with custom scrollbars and size containment.
354
363
  // @ts-ignore
355
364
  this.contentElement.style.contain = 'layout style';
@@ -376,6 +385,11 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
376
385
  this.databaseModel.addEventListener(DatabaseModelEvents.DatabasesRemoved, this.resetWebSQL, this);
377
386
  }
378
387
 
388
+ const interestGroupModel = target.model(InterestGroupStorageModel);
389
+ if (interestGroupModel) {
390
+ interestGroupModel.addEventListener(InterestGroupModelEvents.InterestGroupAccess, this.interestGroupAccess, this);
391
+ }
392
+
379
393
  const resourceTreeModel = target.model(SDK.ResourceTreeModel.ResourceTreeModel);
380
394
  if (!resourceTreeModel) {
381
395
  return;
@@ -408,6 +422,12 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
408
422
  this.databaseModel = null;
409
423
  }
410
424
 
425
+ const interestGroupModel = target.model(InterestGroupStorageModel);
426
+ if (interestGroupModel) {
427
+ interestGroupModel.removeEventListener(
428
+ InterestGroupModelEvents.InterestGroupAccess, this.interestGroupAccess, this);
429
+ }
430
+
411
431
  this.resetWithFrames();
412
432
  }
413
433
 
@@ -422,6 +442,10 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
422
442
  if (this.databaseModel) {
423
443
  this.databaseModel.enable();
424
444
  }
445
+ const interestGroupModel = this.target && this.target.model(InterestGroupStorageModel);
446
+ if (interestGroupModel) {
447
+ interestGroupModel.enable();
448
+ }
425
449
 
426
450
  const cacheStorageModel = this.target && this.target.model(SDK.ServiceWorkerCacheModel.ServiceWorkerCacheModel);
427
451
  if (cacheStorageModel) {
@@ -461,6 +485,16 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
461
485
  model.removeEventListener(DOMStorageModelEvents.DOMStorageRemoved, this.domStorageRemoved, this);
462
486
  }
463
487
 
488
+ private interestGroupModelAdded(model: InterestGroupStorageModel): void {
489
+ model.enable();
490
+ model.addEventListener(InterestGroupModelEvents.InterestGroupAccess, this.interestGroupAccess, this);
491
+ }
492
+
493
+ private interestGroupModelRemoved(model: InterestGroupStorageModel): void {
494
+ model.disable();
495
+ model.removeEventListener(InterestGroupModelEvents.InterestGroupAccess, this.interestGroupAccess, this);
496
+ }
497
+
464
498
  private resetWithFrames(): void {
465
499
  this.resourcesSection.reset();
466
500
  this.reset();
@@ -516,6 +550,7 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
516
550
  this.domains = {};
517
551
  this.resetWebSQL();
518
552
  this.cookieListTreeElement.removeChildren();
553
+ this.interestGroupTreeElement.clearEvents();
519
554
  }
520
555
 
521
556
  private frameNavigated(event: Common.EventTarget.EventTargetEvent<SDK.ResourceTreeModel.ResourceTreeFrame>): void {
@@ -533,6 +568,11 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
533
568
  this.databasesListTreeElement.appendChild(databaseTreeElement);
534
569
  }
535
570
 
571
+ private interestGroupAccess(event: Common.EventTarget.EventTargetEvent<Protocol.Storage.InterestGroupAccessedEvent>):
572
+ void {
573
+ this.interestGroupTreeElement.addEvent(event.data);
574
+ }
575
+
536
576
  private addCookieDocument(frame: SDK.ResourceTreeModel.ResourceTreeFrame): void {
537
577
  // In case the current frame was unreachable, show it's cookies
538
578
  // instead of the error interstitials because they might help to
@@ -0,0 +1,87 @@
1
+ /*
2
+ * Copyright (C) 2021 Google Inc. All rights reserved.
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without
5
+ * modification, are permitted provided that the following conditions are
6
+ * met:
7
+ *
8
+ * * Redistributions of source code must retain the above copyright
9
+ * notice, this list of conditions and the following disclaimer.
10
+ * * Redistributions in binary form must reproduce the above
11
+ * copyright notice, this list of conditions and the following disclaimer
12
+ * in the documentation and/or other materials provided with the
13
+ * distribution.
14
+ * * Neither the name of Google Inc. nor the names of its
15
+ * contributors may be used to endorse or promote products derived from
16
+ * this software without specific prior written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
31
+ import * as SDK from '../../core/sdk/sdk.js';
32
+ import type * as Protocol from '../../generated/protocol.js';
33
+ import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
34
+
35
+ export class InterestGroupStorageModel extends SDK.SDKModel.SDKModel<EventTypes> implements
36
+ ProtocolProxyApi.StorageDispatcher {
37
+ private readonly storageAgent: ProtocolProxyApi.StorageApi;
38
+ private enabled?: boolean;
39
+
40
+ constructor(target: SDK.Target.Target) {
41
+ super(target);
42
+ target.registerStorageDispatcher(this);
43
+ this.storageAgent = target.storageAgent();
44
+ this.enabled = false;
45
+ }
46
+
47
+ enable(): void {
48
+ if (this.enabled) {
49
+ return;
50
+ }
51
+ void this.storageAgent.invoke_setInterestGroupTracking({enable: true});
52
+ }
53
+
54
+ disable(): void {
55
+ if (!this.enabled) {
56
+ return;
57
+ }
58
+ void this.storageAgent.invoke_setInterestGroupTracking({enable: false});
59
+ }
60
+
61
+ interestGroupAccessed(event: Protocol.Storage.InterestGroupAccessedEvent): void {
62
+ this.dispatchEventToListeners(Events.InterestGroupAccess, event);
63
+ }
64
+
65
+ indexedDBListUpdated(_event: Protocol.Storage.IndexedDBListUpdatedEvent): void {
66
+ }
67
+
68
+ indexedDBContentUpdated(_event: Protocol.Storage.IndexedDBContentUpdatedEvent): void {
69
+ }
70
+
71
+ cacheStorageListUpdated(_event: Protocol.Storage.CacheStorageListUpdatedEvent): void {
72
+ }
73
+
74
+ cacheStorageContentUpdated(_event: Protocol.Storage.CacheStorageContentUpdatedEvent): void {
75
+ }
76
+ }
77
+
78
+ SDK.SDKModel.SDKModel.register(
79
+ InterestGroupStorageModel, {capabilities: SDK.Target.Capability.Storage, autostart: false});
80
+
81
+ export const enum Events {
82
+ InterestGroupAccess = 'InterestGroupAccess',
83
+ }
84
+
85
+ export type EventTypes = {
86
+ [Events.InterestGroupAccess]: Protocol.Storage.InterestGroupAccessedEvent,
87
+ };
@@ -0,0 +1,112 @@
1
+ // Copyright 2021 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import * as i18n from '../../core/i18n/i18n.js';
6
+ import * as UI from '../../ui/legacy/legacy.js';
7
+ import type * as DataGrid from '../../ui/components/data_grid/data_grid.js';
8
+ import type * as Protocol from '../../generated/protocol.js';
9
+ import * as SourceFrame from '../../ui/legacy/components/source_frame/source_frame.js';
10
+ import * as ApplicationComponents from './components/components.js';
11
+
12
+ import interestGroupStorageViewStyles from './interestGroupStorageView.css.js';
13
+
14
+ const UIStrings = {
15
+ /**
16
+ *@description Placeholder text instructing the user how to display interest group
17
+ *details.
18
+ */
19
+ clickToDisplayBody: 'Click on any interest group event to display the group\'s current state',
20
+ /**
21
+ interestGroupStorageItems: 'InterestGroup Storage Items',
22
+ */
23
+ };
24
+ const str_ = i18n.i18n.registerUIStrings('panels/application/InterestGroupStorageView.ts', UIStrings);
25
+ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
26
+
27
+ interface InterestGroupDetailsGetter {
28
+ getInterestGroupDetails: (owner: string, name: string) => Promise<Protocol.Storage.InterestGroupDetails|null>;
29
+ }
30
+
31
+ function eventEquals(
32
+ a: Protocol.Storage.InterestGroupAccessedEvent, b: Protocol.Storage.InterestGroupAccessedEvent): boolean {
33
+ return (a.accessTime === b.accessTime && a.type === b.type && a.ownerOrigin === b.ownerOrigin && a.name === b.name);
34
+ }
35
+
36
+ export class InterestGroupStorageView extends UI.SplitWidget.SplitWidget {
37
+ private readonly interestGroupGrid = new ApplicationComponents.InterestGroupAccessGrid.InterestGroupAccessGrid();
38
+ private events: Protocol.Storage.InterestGroupAccessedEvent[] = [];
39
+ private detailsGetter: InterestGroupDetailsGetter;
40
+
41
+ constructor(detailsGetter: InterestGroupDetailsGetter) {
42
+ super(/* isVertical */ false, /* secondIsSidebar: */ true);
43
+ this.detailsGetter = detailsGetter;
44
+
45
+ const topPanel = new UI.Widget.VBox();
46
+ const bottomPanel = new UI.Widget.VBox();
47
+ topPanel.setMinimumSize(0, 80);
48
+ this.setMainWidget(topPanel);
49
+ bottomPanel.setMinimumSize(0, 40);
50
+ this.setSidebarWidget(bottomPanel);
51
+
52
+ topPanel.contentElement.appendChild(this.interestGroupGrid);
53
+ this.interestGroupGrid.addEventListener('cellfocused', this.onFocus.bind(this));
54
+
55
+ bottomPanel.contentElement.classList.add('placeholder');
56
+ const centered = bottomPanel.contentElement.createChild('div');
57
+ centered.textContent = i18nString(UIStrings.clickToDisplayBody);
58
+ }
59
+
60
+ wasShown(): void {
61
+ super.wasShown();
62
+ const sbw = this.sidebarWidget();
63
+ if (sbw) {
64
+ sbw.registerCSSFiles([interestGroupStorageViewStyles]);
65
+ }
66
+ }
67
+
68
+ addEvent(event: Protocol.Storage.InterestGroupAccessedEvent): void {
69
+ // Only add if not already present.
70
+ const foundEvent = this.events.find(t => eventEquals(t, event));
71
+ if (!foundEvent) {
72
+ this.events.push(event);
73
+ this.interestGroupGrid.data = this.events;
74
+ }
75
+ }
76
+
77
+ clearEvents(): void {
78
+ this.events = [];
79
+ this.interestGroupGrid.data = this.events;
80
+ }
81
+
82
+ private async onFocus(event: Event): Promise<void> {
83
+ const focusedEvent = event as DataGrid.DataGridEvents.BodyCellFocusedEvent;
84
+ const row = focusedEvent.data.row;
85
+ if (!row) {
86
+ return;
87
+ }
88
+
89
+ const ownerOrigin = row.cells.find(cell => cell.columnId === 'event-group-owner')?.value as string;
90
+ const name = row.cells.find(cell => cell.columnId === 'event-group-name')?.value as string;
91
+ if (!ownerOrigin || !name) {
92
+ return;
93
+ }
94
+
95
+ const details = await this.detailsGetter.getInterestGroupDetails(ownerOrigin, name);
96
+ if (details) {
97
+ const jsonView = await SourceFrame.JSONView.JSONView.createView(JSON.stringify(details));
98
+ jsonView?.setMinimumSize(0, 40);
99
+ if (jsonView) {
100
+ this.setSidebarWidget(jsonView);
101
+ }
102
+ }
103
+ }
104
+
105
+ getEventsForTesting(): Array<Protocol.Storage.InterestGroupAccessedEvent> {
106
+ return this.events;
107
+ }
108
+
109
+ getInterestGroupGridForTesting(): ApplicationComponents.InterestGroupAccessGrid.InterestGroupAccessGrid {
110
+ return this.interestGroupGrid;
111
+ }
112
+ }
@@ -0,0 +1,61 @@
1
+ // Copyright 2022 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import * as i18n from '../../core/i18n/i18n.js';
6
+ import * as SDK from '../../core/sdk/sdk.js';
7
+ import * as UI from '../../ui/legacy/legacy.js';
8
+
9
+ import type * as Protocol from '../../generated/protocol.js';
10
+
11
+ import {ApplicationPanelTreeElement} from './ApplicationPanelTreeElement.js';
12
+ import type {ResourcesPanel} from './ResourcesPanel.js';
13
+ import {InterestGroupStorageView} from './InterestGroupStorageView.js';
14
+
15
+ const UIStrings = {
16
+ /**
17
+ *@description Label for an item in the Application Panel Sidebar of the Application panel
18
+ */
19
+ interestGroups: 'Interest Groups',
20
+ };
21
+ const str_ = i18n.i18n.registerUIStrings('panels/application/InterestGroupTreeElement.ts', UIStrings);
22
+ export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
23
+
24
+ export class InterestGroupTreeElement extends ApplicationPanelTreeElement {
25
+ private view: InterestGroupStorageView;
26
+
27
+ constructor(storagePanel: ResourcesPanel) {
28
+ super(storagePanel, i18nString(UIStrings.interestGroups), false);
29
+ const interestGroupIcon = UI.Icon.Icon.create('mediumicon-database', 'resource-tree-item');
30
+ this.setLeadingIcons([interestGroupIcon]);
31
+ this.view = new InterestGroupStorageView(this);
32
+ }
33
+
34
+ get itemURL(): string {
35
+ return 'interest-groups://';
36
+ }
37
+
38
+ async getInterestGroupDetails(owner: string, name: string): Promise<Protocol.Storage.InterestGroupDetails|null> {
39
+ const mainTarget = SDK.TargetManager.TargetManager.instance().mainTarget();
40
+ if (!mainTarget) {
41
+ return null;
42
+ }
43
+ const response =
44
+ await mainTarget.storageAgent().invoke_getInterestGroupDetails({'ownerOrigin': owner, 'name': name});
45
+ return response.details;
46
+ }
47
+
48
+ onselect(selectedByUser?: boolean): boolean {
49
+ super.onselect(selectedByUser);
50
+ this.showView(this.view);
51
+ return false;
52
+ }
53
+
54
+ addEvent(event: Protocol.Storage.InterestGroupAccessedEvent): void {
55
+ this.view.addEvent(event);
56
+ }
57
+
58
+ clearEvents(): void {
59
+ this.view.clearEvents();
60
+ }
61
+ }
@@ -14,6 +14,8 @@ import * as DOMStorageItemsView from './DOMStorageItemsView.js';
14
14
  import * as DOMStorageModel from './DOMStorageModel.js';
15
15
  import * as IndexedDBModel from './IndexedDBModel.js';
16
16
  import * as IndexedDBViews from './IndexedDBViews.js';
17
+ import * as InterestGroupStorageModel from './InterestGroupStorageModel.js';
18
+ import * as InterestGroupStorageView from './InterestGroupStorageView.js';
17
19
  import * as OpenedWindowDetailsView from './OpenedWindowDetailsView.js';
18
20
  import * as ReportingApiReportsView from './ReportingApiReportsView.js';
19
21
  import * as ResourcesPanel from './ResourcesPanel.js';
@@ -36,6 +38,8 @@ export {
36
38
  DOMStorageModel,
37
39
  IndexedDBModel,
38
40
  IndexedDBViews,
41
+ InterestGroupStorageModel,
42
+ InterestGroupStorageView,
39
43
  OpenedWindowDetailsView,
40
44
  ReportingApiReportsView,
41
45
  ResourcesPanel,
@@ -508,7 +508,7 @@ const str_ = i18n.i18n.registerUIStrings('panels/application/components/BackForw
508
508
  const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
509
509
 
510
510
  export const NotRestoredReasonDescription = {
511
- 'NotMainFrame': {name: i18nLazyString(UIStrings.notMainFrame)},
511
+ 'NotPrimaryMainFrame': {name: i18nLazyString(UIStrings.notMainFrame)},
512
512
  'BackForwardCacheDisabled': {name: i18nLazyString(UIStrings.backForwardCacheDisabled)},
513
513
  'RelatedActiveContentsExist': {name: i18nLazyString(UIStrings.relatedActiveContentsExist)},
514
514
  'HTTPStatusNotOK': {name: i18nLazyString(UIStrings.HTTPStatusNotOK)},
@@ -342,6 +342,7 @@ export class FrameDetailsReportView extends HTMLElement {
342
342
  {
343
343
  iconName: 'refresh_12x12_icon',
344
344
  text: i18nString(UIStrings.refresh),
345
+ iconColor: 'var(--color-text-primary)',
345
346
  } as IconButton.IconButton.IconWithTextData,
346
347
  ],
347
348
  } as IconButton.IconButton.IconButtonData}>
@@ -0,0 +1,149 @@
1
+ // Copyright 2022 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import * as i18n from '../../../core/i18n/i18n.js';
6
+ import * as DataGrid from '../../../ui/components/data_grid/data_grid.js';
7
+ import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
8
+ import * as IconButton from '../../../ui/components/icon_button/icon_button.js';
9
+ import * as LitHtml from '../../../ui/lit-html/lit-html.js';
10
+ import type * as Protocol from '../../../generated/protocol.js';
11
+
12
+ import interestGroupAccessGridStyles from './interestGroupAccessGrid.css.js';
13
+
14
+ const UIStrings = {
15
+ /**
16
+ *@description Hover text for an info icon in the Interest Group Event panel
17
+ */
18
+ allInterestGroupStorageEvents: 'All interest group storage events.',
19
+ /**
20
+ *@description Text in InterestGroupStorage Items View of the Application panel
21
+ */
22
+ eventTime: 'Event Time',
23
+ /**
24
+ *@description Text in InterestGroupStorage Items View of the Application panel
25
+ */
26
+ eventType: 'Access Type',
27
+ /**
28
+ *@description Text in InterestGroupStorage Items View of the Application panel
29
+ */
30
+ groupOwner: 'Owner',
31
+ /**
32
+ *@description Text in InterestGroupStorage Items View of the Application panel
33
+ */
34
+ groupName: 'Name',
35
+ };
36
+ const str_ = i18n.i18n.registerUIStrings('panels/application/components/InterestGroupAccessGrid.ts', UIStrings);
37
+ export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
38
+
39
+ export class InterestGroupAccessGrid extends HTMLElement {
40
+ static readonly litTagName = LitHtml.literal`devtools-interest-group-access-grid`;
41
+ readonly #shadow = this.attachShadow({mode: 'open'});
42
+ #datastores: Array<Protocol.Storage.InterestGroupAccessedEvent> = [];
43
+
44
+ connectedCallback(): void {
45
+ this.#shadow.adoptedStyleSheets = [interestGroupAccessGridStyles];
46
+ this.#render();
47
+ }
48
+
49
+ set data(data: Array<Protocol.Storage.InterestGroupAccessedEvent>) {
50
+ this.#datastores = data;
51
+ this.#render();
52
+ }
53
+
54
+ #render(): void {
55
+ // clang-format off
56
+ LitHtml.render(LitHtml.html`
57
+ <div>
58
+ <span class="heading">Interest Groups</span>
59
+ <${IconButton.Icon.Icon.litTagName} class="info-icon" title=${
60
+ i18nString(UIStrings.allInterestGroupStorageEvents)}
61
+ .data=${
62
+ {iconName: 'ic_info_black_18dp', color: 'var(--color-link)', width: '14px'} as
63
+ IconButton.Icon.IconWithName}>
64
+ </${IconButton.Icon.Icon.litTagName}>
65
+ ${this.#renderGrid()}
66
+ </div>
67
+ `, this.#shadow, {host: this});
68
+ // clang-format on
69
+ }
70
+
71
+ #renderGrid(): LitHtml.TemplateResult {
72
+ const gridData: DataGrid.DataGridController.DataGridControllerData = {
73
+ columns: [
74
+ {
75
+ id: 'event-time',
76
+ title: i18nString(UIStrings.eventTime),
77
+ widthWeighting: 10,
78
+ hideable: false,
79
+ visible: true,
80
+ sortable: true,
81
+ },
82
+ {
83
+ id: 'event-type',
84
+ title: i18nString(UIStrings.eventType),
85
+ widthWeighting: 5,
86
+ hideable: false,
87
+ visible: true,
88
+ sortable: true,
89
+ },
90
+ {
91
+ id: 'event-group-owner',
92
+ title: i18nString(UIStrings.groupOwner),
93
+ widthWeighting: 10,
94
+ hideable: false,
95
+ visible: true,
96
+ sortable: true,
97
+ },
98
+ {
99
+ id: 'event-group-name',
100
+ title: i18nString(UIStrings.groupName),
101
+ widthWeighting: 10,
102
+ hideable: false,
103
+ visible: true,
104
+ sortable: true,
105
+ },
106
+ ],
107
+ rows: this.#buildRows(),
108
+ initialSort: {
109
+ columnId: 'event-time',
110
+ direction: DataGrid.DataGridUtils.SortDirection.ASC,
111
+ },
112
+ };
113
+
114
+ return LitHtml.html`
115
+ <${DataGrid.DataGridController.DataGridController.litTagName} .data=${
116
+ gridData as DataGrid.DataGridController.DataGridControllerData}></${
117
+ DataGrid.DataGridController.DataGridController.litTagName}>
118
+ `;
119
+ }
120
+
121
+ #buildRows(): DataGrid.DataGridUtils.Row[] {
122
+ return this.#datastores.map(event => ({
123
+ cells: [
124
+ {
125
+ columnId: 'event-time',
126
+ value: event.accessTime,
127
+ renderer: this.#renderDateForDataGridCell.bind(this),
128
+ },
129
+ {columnId: 'event-type', value: event.type},
130
+ {columnId: 'event-group-owner', value: event.ownerOrigin},
131
+ {columnId: 'event-group-name', value: event.name},
132
+ ],
133
+ }));
134
+ }
135
+
136
+ #renderDateForDataGridCell(value: DataGrid.DataGridUtils.CellValue): LitHtml.TemplateResult {
137
+ const date = new Date(1e3 * (value as number));
138
+ return LitHtml.html`${date.toLocaleString()}`;
139
+ }
140
+ }
141
+
142
+ ComponentHelpers.CustomElements.defineComponent('devtools-interest-group-access-grid', InterestGroupAccessGrid);
143
+
144
+ declare global {
145
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
146
+ interface HTMLElementTagNameMap {
147
+ 'devtools-interest-group-access-grid': InterestGroupAccessGrid;
148
+ }
149
+ }
@@ -5,6 +5,7 @@
5
5
  import * as BackForwardCacheView from './BackForwardCacheView.js';
6
6
  import * as EndpointsGrid from './EndpointsGrid.js';
7
7
  import * as FrameDetailsView from './FrameDetailsView.js';
8
+ import * as InterestGroupAccessGrid from './InterestGroupAccessGrid.js';
8
9
  import * as OriginTrialTreeView from './OriginTrialTreeView.js';
9
10
  import * as ReportsGrid from './ReportsGrid.js';
10
11
  import * as StackTrace from './StackTrace.js';
@@ -14,6 +15,7 @@ export {
14
15
  BackForwardCacheView,
15
16
  EndpointsGrid,
16
17
  FrameDetailsView,
18
+ InterestGroupAccessGrid,
17
19
  OriginTrialTreeView,
18
20
  ReportsGrid,
19
21
  StackTrace,