chrome-devtools-frontend 1.0.1593959 → 1.0.1595925
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.
- package/docs/contributing/settings-experiments-features.md +25 -5
- package/front_end/core/common/README.md +126 -0
- package/front_end/core/sdk/CSSModel.ts +22 -0
- package/front_end/core/sdk/CSSNavigation.ts +33 -0
- package/front_end/core/sdk/CSSRule.ts +12 -2
- package/front_end/core/sdk/sdk-meta.ts +22 -18
- package/front_end/core/sdk/sdk.ts +2 -0
- package/front_end/design_system_tokens.css +538 -259
- package/front_end/entrypoints/main/main-meta.ts +2 -2
- package/front_end/generated/InspectorBackendCommands.ts +3 -5
- package/front_end/generated/SupportedCSSProperties.js +12 -0
- package/front_end/generated/protocol-mapping.d.ts +0 -8
- package/front_end/generated/protocol-proxy-api.d.ts +0 -6
- package/front_end/generated/protocol.ts +1 -19
- package/front_end/models/issues_manager/Issue.ts +1 -0
- package/front_end/models/issues_manager/IssueAggregator.ts +9 -0
- package/front_end/models/issues_manager/IssuesManager.ts +5 -0
- package/front_end/models/issues_manager/SelectivePermissionsInterventionIssue.ts +65 -0
- package/front_end/models/issues_manager/descriptions/selectivePermissionsIntervention.md +7 -0
- package/front_end/models/issues_manager/issues_manager.ts +2 -0
- package/front_end/models/javascript_metadata/NativeFunctions.js +49 -10
- package/front_end/models/persistence/persistence-meta.ts +4 -4
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +12 -1
- package/front_end/panels/ai_assistance/components/ChatInput.ts +37 -30
- package/front_end/panels/ai_assistance/components/ChatView.ts +4 -2
- package/front_end/panels/ai_assistance/components/WalkthroughView.ts +10 -7
- package/front_end/panels/ai_assistance/components/chatInput.css +26 -1
- package/front_end/panels/ai_assistance/components/walkthroughView.css +15 -0
- package/front_end/panels/application/StorageView.ts +8 -2
- package/front_end/panels/application/preloading/PreloadingView.ts +105 -7
- package/front_end/panels/application/preloading/preloadingView.css +4 -0
- package/front_end/panels/console/ConsoleView.ts +2 -2
- package/front_end/panels/console/console-meta.ts +18 -14
- package/front_end/panels/elements/ComputedStyleWidget.ts +12 -7
- package/front_end/panels/elements/ElementsPanel.ts +1 -1
- package/front_end/panels/elements/ElementsTreeOutline.ts +4 -6
- package/front_end/panels/elements/ImagePreviewPopover.ts +6 -9
- package/front_end/panels/elements/StylePropertiesSection.ts +30 -0
- package/front_end/panels/elements/StylesSidebarPane.ts +13 -7
- package/front_end/panels/elements/elements-meta.ts +12 -8
- package/front_end/panels/issues/AffectedSelectivePermissionsInterventionView.ts +120 -0
- package/front_end/panels/issues/IssueView.ts +2 -0
- package/front_end/panels/issues/IssuesPane.ts +6 -0
- package/front_end/panels/issues/issues.ts +2 -0
- package/front_end/panels/lighthouse/LighthouseStartView.ts +99 -38
- package/front_end/panels/lighthouse/LighthouseTimespanView.ts +53 -14
- package/front_end/panels/lighthouse/RadioSetting.ts +33 -19
- package/front_end/panels/lighthouse/lighthouse.ts +2 -0
- package/front_end/panels/media/PlayerMessagesView.ts +62 -49
- package/front_end/panels/media/media.ts +2 -0
- package/front_end/panels/media/playerMessagesView.css +1 -1
- package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +49 -24
- package/front_end/panels/settings/FrameworkIgnoreListSettingsTab.ts +2 -2
- package/front_end/panels/sources/sources-meta.ts +8 -4
- package/front_end/panels/utils/utils.ts +11 -5
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/lit/lib/async-directive.d.ts +465 -0
- package/front_end/third_party/lit/lib/async-directive.js +23 -0
- package/front_end/third_party/lit/lib/async-directive.js.map +1 -0
- package/front_end/third_party/lit/lib/decorators.d.ts +7 -1
- package/front_end/third_party/lit/lib/decorators.js +2 -2
- package/front_end/third_party/lit/lib/decorators.js.map +1 -1
- package/front_end/third_party/lit/lib/directive.js.map +1 -1
- package/front_end/third_party/lit/lib/directives.d.ts +27 -8
- package/front_end/third_party/lit/lib/directives.js +8 -8
- package/front_end/third_party/lit/lib/directives.js.map +1 -1
- package/front_end/third_party/lit/lib/lit.d.ts +15 -5
- package/front_end/third_party/lit/lib/lit.js +4 -4
- package/front_end/third_party/lit/lib/lit.js.map +1 -1
- package/front_end/third_party/lit/lib/static-html.js +2 -2
- package/front_end/third_party/lit/lib/static-html.js.map +1 -1
- package/front_end/third_party/lit/lit.ts +2 -1
- package/front_end/third_party/lit/rollup.config.mjs +1 -1
- package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +5 -0
- package/front_end/ui/legacy/components/utils/ImagePreview.ts +27 -23
- package/front_end/ui/lit/lit.ts +1 -0
- package/front_end/ui/visual_logging/Debugging.ts +1 -1
- package/front_end/ui/visual_logging/KnownContextValues.ts +4 -0
- package/package.json +1 -1
|
@@ -43,6 +43,7 @@ import * as IssuesManager from '../../models/issues_manager/issues_manager.js';
|
|
|
43
43
|
import * as CodeHighlighter from '../../ui/components/code_highlighter/code_highlighter.js';
|
|
44
44
|
import * as Highlighting from '../../ui/components/highlighting/highlighting.js';
|
|
45
45
|
import * as IssueCounter from '../../ui/components/issue_counter/issue_counter.js';
|
|
46
|
+
import * as UIComponentUtils from '../../ui/legacy/components/utils/utils.js';
|
|
46
47
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
47
48
|
import {html, nothing, render} from '../../ui/lit/lit.js';
|
|
48
49
|
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
|
@@ -555,18 +556,15 @@ export class ElementsTreeOutline extends
|
|
|
555
556
|
}
|
|
556
557
|
return link;
|
|
557
558
|
},
|
|
558
|
-
link => {
|
|
559
|
+
async link => {
|
|
559
560
|
const listItem = UI.UIUtils.enclosingNodeOrSelfWithNodeName(link, 'li');
|
|
560
561
|
if (!listItem) {
|
|
561
|
-
return
|
|
562
|
+
return undefined;
|
|
562
563
|
}
|
|
563
564
|
|
|
564
565
|
const treeElement =
|
|
565
566
|
(UI.TreeOutline.TreeElement.getTreeElementBylistItemNode(listItem) as ElementsTreeElement | undefined);
|
|
566
|
-
|
|
567
|
-
return null;
|
|
568
|
-
}
|
|
569
|
-
return treeElement.node();
|
|
567
|
+
return await UIComponentUtils.ImagePreview.loadPrecomputedFeatures(treeElement?.node());
|
|
570
568
|
});
|
|
571
569
|
|
|
572
570
|
this.updateRecords = new Map();
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import type * as Platform from '../../core/platform/platform.js';
|
|
6
|
-
import type * as SDK from '../../core/sdk/sdk.js';
|
|
7
6
|
import * as Components from '../../ui/legacy/components/utils/utils.js';
|
|
8
7
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
9
8
|
|
|
@@ -15,13 +14,15 @@ import * as UI from '../../ui/legacy/legacy.js';
|
|
|
15
14
|
*/
|
|
16
15
|
export class ImagePreviewPopover {
|
|
17
16
|
private readonly getLinkElement: (arg0: Event) => Element | null;
|
|
18
|
-
private readonly getDOMNode: (arg0: Element) => SDK.DOMModel.DOMNode | null;
|
|
19
17
|
private readonly popover: UI.PopoverHelper.PopoverHelper;
|
|
18
|
+
|
|
19
|
+
#getNodeFeatures: (link: Element) => Promise<Components.ImagePreview.PrecomputedFeatures|undefined>;
|
|
20
|
+
|
|
20
21
|
constructor(
|
|
21
22
|
container: HTMLElement, getLinkElement: (arg0: Event) => Element | null,
|
|
22
|
-
|
|
23
|
+
getNodeFeatures: (arg0: Element) => Promise<Components.ImagePreview.PrecomputedFeatures|undefined>) {
|
|
23
24
|
this.getLinkElement = getLinkElement;
|
|
24
|
-
this
|
|
25
|
+
this.#getNodeFeatures = getNodeFeatures;
|
|
25
26
|
this.popover =
|
|
26
27
|
new UI.PopoverHelper.PopoverHelper(container, this.handleRequest.bind(this), 'elements.image-preview');
|
|
27
28
|
this.popover.setTimeout(0, 100);
|
|
@@ -39,11 +40,7 @@ export class ImagePreviewPopover {
|
|
|
39
40
|
return {
|
|
40
41
|
box: link.boxInWindow(),
|
|
41
42
|
show: async (popover: UI.GlassPane.GlassPane) => {
|
|
42
|
-
const
|
|
43
|
-
if (!node) {
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
const precomputedFeatures = await Components.ImagePreview.ImagePreview.loadDimensionsForNode(node);
|
|
43
|
+
const precomputedFeatures = await this.#getNodeFeatures(link);
|
|
47
44
|
const preview = await Components.ImagePreview.ImagePreview.build(href, true, {
|
|
48
45
|
precomputedFeatures,
|
|
49
46
|
align: Components.ImagePreview.Align.CENTER,
|
|
@@ -807,6 +807,7 @@ export class StylePropertiesSection {
|
|
|
807
807
|
let scopeIndex = 0;
|
|
808
808
|
let supportsIndex = 0;
|
|
809
809
|
let nestingIndex = 0;
|
|
810
|
+
let navigationsIndex = 0;
|
|
810
811
|
this.nestingLevel = 0;
|
|
811
812
|
for (const ruleType of rule.ruleTypes) {
|
|
812
813
|
let ancestorRuleElement;
|
|
@@ -829,6 +830,9 @@ export class StylePropertiesSection {
|
|
|
829
830
|
case Protocol.CSS.CSSRuleType.StartingStyleRule:
|
|
830
831
|
ancestorRuleElement = this.createStartingStyleElement();
|
|
831
832
|
break;
|
|
833
|
+
case Protocol.CSS.CSSRuleType.NavigationRule:
|
|
834
|
+
ancestorRuleElement = this.createNavigationElement(rule.navigations[navigationsIndex++]);
|
|
835
|
+
break;
|
|
832
836
|
}
|
|
833
837
|
if (ancestorRuleElement) {
|
|
834
838
|
this.#ancestorRuleListElement.prepend(ancestorRuleElement);
|
|
@@ -1007,6 +1011,27 @@ export class StylePropertiesSection {
|
|
|
1007
1011
|
return supportsElement;
|
|
1008
1012
|
}
|
|
1009
1013
|
|
|
1014
|
+
protected createNavigationElement(navigation: SDK.CSSNavigation.CSSNavigation): ElementsComponents.CSSQuery.CSSQuery
|
|
1015
|
+
|undefined {
|
|
1016
|
+
if (!navigation.text) {
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
let onQueryTextClick;
|
|
1021
|
+
if (navigation.styleSheetId) {
|
|
1022
|
+
onQueryTextClick = this.handleQueryRuleClick.bind(this, navigation);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
const navigationElement = new ElementsComponents.CSSQuery.CSSQuery();
|
|
1026
|
+
navigationElement.data = {
|
|
1027
|
+
queryPrefix: '@navigation',
|
|
1028
|
+
queryText: navigation.text,
|
|
1029
|
+
onQueryTextClick,
|
|
1030
|
+
jslogContext: 'navigation',
|
|
1031
|
+
};
|
|
1032
|
+
return navigationElement;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1010
1035
|
protected createNestingElement(nestingSelector?: string): HTMLElement|undefined {
|
|
1011
1036
|
if (!nestingSelector) {
|
|
1012
1037
|
return;
|
|
@@ -1419,6 +1444,8 @@ export class StylePropertiesSection {
|
|
|
1419
1444
|
success = await cssModel.setSupportsText(query.styleSheetId, range, newContent);
|
|
1420
1445
|
} else if (query instanceof SDK.CSSScope.CSSScope) {
|
|
1421
1446
|
success = await cssModel.setScopeText(query.styleSheetId, range, newContent);
|
|
1447
|
+
} else if (query instanceof SDK.CSSNavigation.CSSNavigation) {
|
|
1448
|
+
success = await cssModel.setNavigationText(query.styleSheetId, range, newContent);
|
|
1422
1449
|
} else {
|
|
1423
1450
|
success = await cssModel.setMediaText(query.styleSheetId, range, newContent);
|
|
1424
1451
|
}
|
|
@@ -1871,6 +1898,9 @@ export class FunctionRuleSection extends StylePropertiesSection {
|
|
|
1871
1898
|
if ('supports' in condition) {
|
|
1872
1899
|
return this.createSupportsElement(condition.supports);
|
|
1873
1900
|
}
|
|
1901
|
+
if ('navigation' in condition) {
|
|
1902
|
+
return this.createNavigationElement(condition.navigation);
|
|
1903
|
+
}
|
|
1874
1904
|
return;
|
|
1875
1905
|
}
|
|
1876
1906
|
|
|
@@ -236,13 +236,19 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
236
236
|
this.contentElement.addEventListener('copy', this.clipboardCopy.bind(this));
|
|
237
237
|
|
|
238
238
|
this.boundOnScroll = this.onScroll.bind(this);
|
|
239
|
-
this.imagePreviewPopover = new ImagePreviewPopover(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
239
|
+
this.imagePreviewPopover = new ImagePreviewPopover(
|
|
240
|
+
this.contentElement,
|
|
241
|
+
event => {
|
|
242
|
+
const link = event.composedPath()[0];
|
|
243
|
+
if (link instanceof Element) {
|
|
244
|
+
return link;
|
|
245
|
+
}
|
|
246
|
+
return null;
|
|
247
|
+
},
|
|
248
|
+
async () => {
|
|
249
|
+
const features = await Components.ImagePreview.loadPrecomputedFeatures(this.node());
|
|
250
|
+
return features;
|
|
251
|
+
});
|
|
246
252
|
|
|
247
253
|
UI.ViewManager.ViewManager.instance().addEventListener(UI.ViewManager.Events.VIEW_VISIBILITY_CHANGED, event => {
|
|
248
254
|
if (event.data.revealedViewId === 'animations' || event.data.hiddenViewId === 'animations') {
|
|
@@ -110,9 +110,13 @@ const UIStrings = {
|
|
|
110
110
|
/**
|
|
111
111
|
* @description Title of a setting under the Elements category. Whether to show/hide code comments in HTML.
|
|
112
112
|
*/
|
|
113
|
+
htmlComments: 'HTML comments',
|
|
114
|
+
/**
|
|
115
|
+
* @description Title of an option under the Elements category that can be invoked through the Command Menu
|
|
116
|
+
*/
|
|
113
117
|
showHtmlComments: 'Show `HTML` comments',
|
|
114
118
|
/**
|
|
115
|
-
* @description Title of
|
|
119
|
+
* @description Title of an option under the Elements category that can be invoked through the Command Menu
|
|
116
120
|
*/
|
|
117
121
|
hideHtmlComments: 'Hide `HTML` comments',
|
|
118
122
|
/**
|
|
@@ -126,12 +130,12 @@ const UIStrings = {
|
|
|
126
130
|
* the inspect tooltip (an information pane that hovers next to selected DOM elements) has extra
|
|
127
131
|
* detail.
|
|
128
132
|
*/
|
|
129
|
-
|
|
133
|
+
detailedInspectTooltip: 'Detailed inspect tooltip',
|
|
130
134
|
/**
|
|
131
135
|
* @description Title of a setting under the Elements category in Settings. Turns on a mode where
|
|
132
136
|
* hovering over CSS properties in the Styles pane will display a popover with documentation.
|
|
133
137
|
*/
|
|
134
|
-
|
|
138
|
+
CSSDocumentationTooltip: 'CSS documentation tooltip',
|
|
135
139
|
/**
|
|
136
140
|
* @description A context menu item (command) in the Elements panel that copy the styles of
|
|
137
141
|
* the HTML element.
|
|
@@ -146,7 +150,7 @@ const UIStrings = {
|
|
|
146
150
|
* @description Title of a setting under the Elements category. Whether to show/hide hide
|
|
147
151
|
* the shadow DOM nodes of HTML elements that are built into the browser (e.g. the <input> element).
|
|
148
152
|
*/
|
|
149
|
-
|
|
153
|
+
userAgentShadowDOM: 'User agent shadow `DOM`',
|
|
150
154
|
/**
|
|
151
155
|
* @description Command for showing the 'Computed' tool. Displays computed CSS styles in Elements sidebar.
|
|
152
156
|
*/
|
|
@@ -489,7 +493,7 @@ Common.Settings.registerSettingExtension({
|
|
|
489
493
|
category: Common.Settings.SettingCategory.ELEMENTS,
|
|
490
494
|
storageType: Common.Settings.SettingStorageType.SYNCED,
|
|
491
495
|
order: 1,
|
|
492
|
-
title: i18nLazyString(UIStrings.
|
|
496
|
+
title: i18nLazyString(UIStrings.userAgentShadowDOM),
|
|
493
497
|
settingName: 'show-ua-shadow-dom',
|
|
494
498
|
settingType: Common.Settings.SettingType.BOOLEAN,
|
|
495
499
|
defaultValue: false,
|
|
@@ -528,7 +532,7 @@ Common.Settings.registerSettingExtension({
|
|
|
528
532
|
category: Common.Settings.SettingCategory.ELEMENTS,
|
|
529
533
|
storageType: Common.Settings.SettingStorageType.SYNCED,
|
|
530
534
|
order: 3,
|
|
531
|
-
title: i18nLazyString(UIStrings.
|
|
535
|
+
title: i18nLazyString(UIStrings.htmlComments),
|
|
532
536
|
settingName: 'show-html-comments',
|
|
533
537
|
settingType: Common.Settings.SettingType.BOOLEAN,
|
|
534
538
|
defaultValue: true,
|
|
@@ -558,7 +562,7 @@ Common.Settings.registerSettingExtension({
|
|
|
558
562
|
category: Common.Settings.SettingCategory.ELEMENTS,
|
|
559
563
|
storageType: Common.Settings.SettingStorageType.SYNCED,
|
|
560
564
|
order: 5,
|
|
561
|
-
title: i18nLazyString(UIStrings.
|
|
565
|
+
title: i18nLazyString(UIStrings.detailedInspectTooltip),
|
|
562
566
|
settingName: 'show-detailed-inspect-tooltip',
|
|
563
567
|
settingType: Common.Settings.SettingType.BOOLEAN,
|
|
564
568
|
defaultValue: true,
|
|
@@ -581,7 +585,7 @@ Common.Settings.registerSettingExtension({
|
|
|
581
585
|
Common.Settings.registerSettingExtension({
|
|
582
586
|
category: Common.Settings.SettingCategory.ELEMENTS,
|
|
583
587
|
storageType: Common.Settings.SettingStorageType.SYNCED,
|
|
584
|
-
title: i18nLazyString(UIStrings.
|
|
588
|
+
title: i18nLazyString(UIStrings.CSSDocumentationTooltip),
|
|
585
589
|
settingName: 'show-css-property-documentation-on-hover',
|
|
586
590
|
settingType: Common.Settings.SettingType.BOOLEAN,
|
|
587
591
|
defaultValue: true,
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// Copyright 2026 The Chromium Authors
|
|
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 type * as Platform from '../../core/platform/platform.js';
|
|
7
|
+
import type * as SDK from '../../core/sdk/sdk.js';
|
|
8
|
+
import type * as Protocol from '../../generated/protocol.js';
|
|
9
|
+
import * as Bindings from '../../models/bindings/bindings.js';
|
|
10
|
+
import type * as IssuesManager from '../../models/issues_manager/issues_manager.js';
|
|
11
|
+
import * as Components from '../../ui/legacy/components/utils/utils.js';
|
|
12
|
+
import * as UI from '../../ui/legacy/legacy.js';
|
|
13
|
+
import {Directives, html, type LitTemplate, nothing, render} from '../../ui/lit/lit.js';
|
|
14
|
+
|
|
15
|
+
import {AffectedResourcesView} from './AffectedResourcesView.js';
|
|
16
|
+
|
|
17
|
+
const UIStrings = {
|
|
18
|
+
/**
|
|
19
|
+
* @description Label for number of affected resources indication in issue view
|
|
20
|
+
*/
|
|
21
|
+
nViolations: '{n, plural, =1 {# violation} other {# violations}}',
|
|
22
|
+
/**
|
|
23
|
+
* @description Title for the API column in the Selective Permissions Intervention affected resources list
|
|
24
|
+
*/
|
|
25
|
+
api: 'API',
|
|
26
|
+
/**
|
|
27
|
+
* @description Title for the Script column in the Selective Permissions Intervention affected resources list
|
|
28
|
+
*/
|
|
29
|
+
script: 'Script',
|
|
30
|
+
/**
|
|
31
|
+
* @description Title for the Ad Ancestry column in the Selective Permissions Intervention affected resources list
|
|
32
|
+
*/
|
|
33
|
+
adAncestry: 'Ad Ancestry',
|
|
34
|
+
/**
|
|
35
|
+
* @description Text for unknown value
|
|
36
|
+
*/
|
|
37
|
+
unknown: 'unknown',
|
|
38
|
+
/**
|
|
39
|
+
* @description Text for loading state
|
|
40
|
+
*/
|
|
41
|
+
loading: 'loading…',
|
|
42
|
+
} as const;
|
|
43
|
+
const str_ = i18n.i18n.registerUIStrings('panels/issues/AffectedSelectivePermissionsInterventionView.ts', UIStrings);
|
|
44
|
+
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
45
|
+
|
|
46
|
+
export class AffectedSelectivePermissionsInterventionView extends AffectedResourcesView {
|
|
47
|
+
readonly #linkifier = new Components.Linkifier.Linkifier();
|
|
48
|
+
|
|
49
|
+
protected getResourceNameWithCount(count: number): string {
|
|
50
|
+
return i18nString(UIStrings.nViolations, {n: count});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
#render(): void {
|
|
54
|
+
const issues = Array.from(this.issue.getSelectivePermissionsInterventionIssues());
|
|
55
|
+
// eslint-disable-next-line @devtools/no-lit-render-outside-of-view
|
|
56
|
+
render(
|
|
57
|
+
html`
|
|
58
|
+
<tr>
|
|
59
|
+
<td class="affected-resource-header">${i18nString(UIStrings.api)}</td>
|
|
60
|
+
<td class="affected-resource-header">${i18nString(UIStrings.script)}</td>
|
|
61
|
+
<td class="affected-resource-header">${i18nString(UIStrings.adAncestry)}</td>
|
|
62
|
+
</tr>
|
|
63
|
+
${issues.map(issue => this.#renderDetail(issue))}
|
|
64
|
+
`,
|
|
65
|
+
this.affectedResources, {host: this});
|
|
66
|
+
this.updateAffectedResourceCount(issues.length);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#renderDetail(issue: IssuesManager.SelectivePermissionsInterventionIssue.SelectivePermissionsInterventionIssue):
|
|
70
|
+
LitTemplate {
|
|
71
|
+
const details = issue.details();
|
|
72
|
+
const issuesModel = issue.model();
|
|
73
|
+
|
|
74
|
+
const stackTracePromise = (details.stackTrace && issuesModel) ?
|
|
75
|
+
this.#resolveStackTrace(details.stackTrace, issuesModel) :
|
|
76
|
+
Promise.resolve(html`<span>${i18nString(UIStrings.unknown)}</span>`);
|
|
77
|
+
|
|
78
|
+
const target = issuesModel ? issuesModel.target() : null;
|
|
79
|
+
|
|
80
|
+
return html`
|
|
81
|
+
<tr class="affected-resource-directive">
|
|
82
|
+
<td>${details.apiName}</td>
|
|
83
|
+
<td>${Directives.until(stackTracePromise, html`<span>${i18nString(UIStrings.loading)}</span>`)}</td>
|
|
84
|
+
<td class="affected-resource-cell">
|
|
85
|
+
<div class="ad-ancestry-list">
|
|
86
|
+
${(details.adAncestry?.adAncestryChain || []).map(script => {
|
|
87
|
+
const link = this.#linkifier.linkifyScriptLocation(
|
|
88
|
+
target, script.scriptId, script.name as Platform.DevToolsPath.UrlString, 0);
|
|
89
|
+
return html`<div>${link}</div>`;
|
|
90
|
+
})}
|
|
91
|
+
${
|
|
92
|
+
details.adAncestry?.rootScriptFilterlistRule ?
|
|
93
|
+
html`<div>Rule: ${details.adAncestry.rootScriptFilterlistRule}</div>` :
|
|
94
|
+
nothing}
|
|
95
|
+
</div>
|
|
96
|
+
</td>
|
|
97
|
+
</tr>
|
|
98
|
+
`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async #resolveStackTrace(stackTrace: Protocol.Runtime.StackTrace, issuesModel: SDK.IssuesModel.IssuesModel):
|
|
102
|
+
Promise<LitTemplate> {
|
|
103
|
+
const debuggerWorkspaceBinding = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance();
|
|
104
|
+
const stackTraceTranslated =
|
|
105
|
+
await debuggerWorkspaceBinding.createStackTraceFromProtocolRuntime(stackTrace, issuesModel.target());
|
|
106
|
+
return html`
|
|
107
|
+
<devtools-widget .widgetConfig=${UI.Widget.widgetConfig(Components.JSPresentationUtils.StackTracePreviewContent, {
|
|
108
|
+
stackTrace: stackTraceTranslated,
|
|
109
|
+
options: {expandable: true},
|
|
110
|
+
})}>
|
|
111
|
+
</devtools-widget>
|
|
112
|
+
`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
update(): void {
|
|
116
|
+
this.requestResolver.clear();
|
|
117
|
+
this.#linkifier.reset();
|
|
118
|
+
this.#render();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -29,6 +29,7 @@ import {AffectedMetadataAllowedSitesView} from './AffectedMetadataAllowedSitesVi
|
|
|
29
29
|
import {AffectedPartitioningBlobURLView} from './AffectedPartitioningBlobURLView.js';
|
|
30
30
|
import {AffectedPermissionElementsView} from './AffectedPermissionElementsView.js';
|
|
31
31
|
import {AffectedItem, AffectedResourcesView, extractShortPath} from './AffectedResourcesView.js';
|
|
32
|
+
import {AffectedSelectivePermissionsInterventionView} from './AffectedSelectivePermissionsInterventionView.js';
|
|
32
33
|
import {AffectedSharedArrayBufferIssueDetailsView} from './AffectedSharedArrayBufferIssueDetailsView.js';
|
|
33
34
|
import {AffectedSourcesView} from './AffectedSourcesView.js';
|
|
34
35
|
import {AffectedTrackingSitesView} from './AffectedTrackingSitesView.js';
|
|
@@ -260,6 +261,7 @@ export class IssueView extends UI.TreeOutline.TreeElement {
|
|
|
260
261
|
new AffectedDescendantsWithinSelectElementView(this, this.#issue, 'disallowed-select-descendants-details'),
|
|
261
262
|
new AffectedPartitioningBlobURLView(this, this.#issue, 'partitioning-blob-url-details'),
|
|
262
263
|
new AffectedPermissionElementsView(this, this.#issue, 'permission-element-elements'),
|
|
264
|
+
new AffectedSelectivePermissionsInterventionView(this, this.#issue, 'selective-permissions-intervention-details'),
|
|
263
265
|
];
|
|
264
266
|
this.#hiddenIssuesMenu = new Components.HideIssuesMenu.HideIssuesMenu();
|
|
265
267
|
this.#aggregatedIssuesCount = null;
|
|
@@ -110,6 +110,10 @@ const UIStrings = {
|
|
|
110
110
|
* @description Category title for a group of permission element issues
|
|
111
111
|
*/
|
|
112
112
|
permissionElement: 'PEPC Element',
|
|
113
|
+
/**
|
|
114
|
+
* @description Category title for the different 'Selective Permissions Intervention' issues.
|
|
115
|
+
*/
|
|
116
|
+
selectivePermissionsIntervention: 'Selective Permissions Intervention',
|
|
113
117
|
} as const;
|
|
114
118
|
const str_ = i18n.i18n.registerUIStrings('panels/issues/IssuesPane.ts', UIStrings);
|
|
115
119
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
@@ -153,6 +157,8 @@ class IssueCategoryView extends UI.TreeOutline.TreeElement {
|
|
|
153
157
|
return i18nString(UIStrings.generic);
|
|
154
158
|
case IssuesManager.Issue.IssueCategory.PERMISSION_ELEMENT:
|
|
155
159
|
return i18nString(UIStrings.permissionElement);
|
|
160
|
+
case IssuesManager.Issue.IssueCategory.SELECTIVE_PERMISSIONS_INTERVENTION:
|
|
161
|
+
return i18nString(UIStrings.selectivePermissionsIntervention);
|
|
156
162
|
case IssuesManager.Issue.IssueCategory.OTHER:
|
|
157
163
|
return i18nString(UIStrings.other);
|
|
158
164
|
}
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
+
import * as AffectedSelectivePermissionsInterventionView from './AffectedSelectivePermissionsInterventionView.js';
|
|
5
6
|
import * as IssueRevealer from './IssueRevealer.js';
|
|
6
7
|
import * as IssuesPane from './IssuesPane.js';
|
|
7
8
|
import * as IssueView from './IssueView.js';
|
|
8
9
|
|
|
9
10
|
export {
|
|
11
|
+
AffectedSelectivePermissionsInterventionView,
|
|
10
12
|
IssueRevealer,
|
|
11
13
|
IssuesPane,
|
|
12
14
|
IssueView,
|
|
@@ -11,6 +11,7 @@ import type * as Platform from '../../core/platform/platform.js';
|
|
|
11
11
|
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
12
12
|
import {Link} from '../../ui/kit/kit.js';
|
|
13
13
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
14
|
+
import {Directives, html, render} from '../../ui/lit/lit.js';
|
|
14
15
|
|
|
15
16
|
import {type LighthouseController, type Preset, Presets, RuntimeSettings} from './LighthouseController.js';
|
|
16
17
|
import type {LighthousePanel} from './LighthousePanel.js';
|
|
@@ -55,6 +56,78 @@ const UIStrings = {
|
|
|
55
56
|
const str_ = i18n.i18n.registerUIStrings('panels/lighthouse/LighthouseStartView.ts', UIStrings);
|
|
56
57
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
57
58
|
|
|
59
|
+
const renderStartView = (
|
|
60
|
+
_input: Record<string, never>,
|
|
61
|
+
output: {
|
|
62
|
+
helpText?: HTMLElement,
|
|
63
|
+
warningText?: HTMLElement,
|
|
64
|
+
modeFormElements?: HTMLElement,
|
|
65
|
+
deviceTypeFormElements?: HTMLElement,
|
|
66
|
+
categoriesFormElements?: HTMLElement,
|
|
67
|
+
},
|
|
68
|
+
target: HTMLElement,
|
|
69
|
+
): void => {
|
|
70
|
+
// clang-format off
|
|
71
|
+
render(
|
|
72
|
+
html`
|
|
73
|
+
<form class="lighthouse-start-view">
|
|
74
|
+
<header class="hbox">
|
|
75
|
+
<div class="lighthouse-logo"></div>
|
|
76
|
+
<div class="lighthouse-title">
|
|
77
|
+
${i18nString(UIStrings.generateLighthouseReport)}
|
|
78
|
+
</div>
|
|
79
|
+
<div class="lighthouse-start-button-container"></div>
|
|
80
|
+
</header>
|
|
81
|
+
<div
|
|
82
|
+
${Directives.ref(e => {
|
|
83
|
+
output.helpText = e as HTMLElement;
|
|
84
|
+
})}
|
|
85
|
+
class="lighthouse-help-text hidden"
|
|
86
|
+
></div>
|
|
87
|
+
<div class="lighthouse-options hbox">
|
|
88
|
+
<div class="lighthouse-form-section">
|
|
89
|
+
<div
|
|
90
|
+
class="lighthouse-form-elements"
|
|
91
|
+
${Directives.ref(e => {
|
|
92
|
+
output.modeFormElements = e as HTMLElement;
|
|
93
|
+
})}
|
|
94
|
+
></div>
|
|
95
|
+
</div>
|
|
96
|
+
<div class="lighthouse-form-section">
|
|
97
|
+
<div
|
|
98
|
+
class="lighthouse-form-elements"
|
|
99
|
+
${Directives.ref(e => {
|
|
100
|
+
output.deviceTypeFormElements = e as HTMLElement;
|
|
101
|
+
})}
|
|
102
|
+
></div>
|
|
103
|
+
</div>
|
|
104
|
+
<div class="lighthouse-form-categories">
|
|
105
|
+
<fieldset class="lighthouse-form-section lighthouse-form-categories-fieldset">
|
|
106
|
+
<legend class="lighthouse-form-section-label">
|
|
107
|
+
${i18nString(UIStrings.categories)}
|
|
108
|
+
</legend>
|
|
109
|
+
<div
|
|
110
|
+
class="lighthouse-form-elements"
|
|
111
|
+
${Directives.ref(e => {
|
|
112
|
+
output.categoriesFormElements = e as HTMLElement;
|
|
113
|
+
})}
|
|
114
|
+
></div>
|
|
115
|
+
</fieldset>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
<div
|
|
119
|
+
${Directives.ref(e => {
|
|
120
|
+
output.warningText = e as HTMLElement;
|
|
121
|
+
})}
|
|
122
|
+
class="lighthouse-warning-text hidden"
|
|
123
|
+
></div>
|
|
124
|
+
</form>
|
|
125
|
+
`,
|
|
126
|
+
target,
|
|
127
|
+
);
|
|
128
|
+
// clang-format on
|
|
129
|
+
};
|
|
130
|
+
|
|
58
131
|
export class StartView extends UI.Widget.Widget {
|
|
59
132
|
private controller: LighthouseController;
|
|
60
133
|
private panel: LighthousePanel;
|
|
@@ -145,13 +218,11 @@ export class StartView extends UI.Widget.Widget {
|
|
|
145
218
|
}
|
|
146
219
|
}
|
|
147
220
|
|
|
148
|
-
private populateFormControls(
|
|
221
|
+
private populateFormControls(deviceTypeFormElements: Element, categoryFormElements: Element, mode?: string): void {
|
|
149
222
|
// Populate the device type
|
|
150
|
-
const deviceTypeFormElements = fragment.$('device-type-form-elements');
|
|
151
223
|
this.populateRuntimeSettingAsRadio('lighthouse.device-type', i18nString(UIStrings.device), deviceTypeFormElements);
|
|
152
224
|
|
|
153
225
|
// Populate the categories
|
|
154
|
-
const categoryFormElements = fragment.$('categories-form-elements') as HTMLElement;
|
|
155
226
|
|
|
156
227
|
this.checkboxes = [];
|
|
157
228
|
for (const preset of Presets) {
|
|
@@ -174,44 +245,34 @@ export class StartView extends UI.Widget.Widget {
|
|
|
174
245
|
this.populateRuntimeSettingAsToolbarDropdown('lighthouse.throttling', this.#settingsToolbar);
|
|
175
246
|
|
|
176
247
|
const {mode} = this.controller.getFlags();
|
|
177
|
-
this.populateStartButton(mode);
|
|
178
248
|
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
<div class="lighthouse-form-elements" $="device-type-form-elements"></div>
|
|
193
|
-
</div>
|
|
194
|
-
<div class="lighthouse-form-categories">
|
|
195
|
-
<fieldset class="lighthouse-form-section lighthouse-form-categories-fieldset">
|
|
196
|
-
<legend class="lighthouse-form-section-label">${i18nString(UIStrings.categories)}</legend>
|
|
197
|
-
<div class="lighthouse-form-elements" $="categories-form-elements"></div>
|
|
198
|
-
</fieldset>
|
|
199
|
-
</div>
|
|
200
|
-
</div>
|
|
201
|
-
<div $="warning-text" class="lighthouse-warning-text hidden"></div>
|
|
202
|
-
</form>
|
|
203
|
-
`;
|
|
204
|
-
|
|
205
|
-
this.helpText = fragment.$('help-text');
|
|
206
|
-
this.warningText = fragment.$('warning-text');
|
|
207
|
-
|
|
208
|
-
const modeFormElements = fragment.$('mode-form-elements');
|
|
209
|
-
this.populateRuntimeSettingAsRadio('lighthouse.mode', i18nString(UIStrings.mode), modeFormElements);
|
|
249
|
+
const output = {
|
|
250
|
+
helpText: undefined as HTMLElement | undefined,
|
|
251
|
+
warningText: undefined as HTMLElement | undefined,
|
|
252
|
+
modeFormElements: undefined as HTMLElement | undefined,
|
|
253
|
+
deviceTypeFormElements: undefined as HTMLElement | undefined,
|
|
254
|
+
categoriesFormElements: undefined as HTMLElement | undefined,
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
renderStartView(
|
|
258
|
+
{},
|
|
259
|
+
output,
|
|
260
|
+
this.contentElement,
|
|
261
|
+
);
|
|
210
262
|
|
|
211
|
-
this.
|
|
263
|
+
this.helpText = output.helpText;
|
|
264
|
+
this.warningText = output.warningText;
|
|
212
265
|
|
|
213
|
-
|
|
214
|
-
|
|
266
|
+
const modeFormElements = output.modeFormElements;
|
|
267
|
+
const deviceTypeFormElements = output.deviceTypeFormElements;
|
|
268
|
+
const categoriesFormElements = output.categoriesFormElements;
|
|
269
|
+
|
|
270
|
+
if (!modeFormElements || !deviceTypeFormElements || !categoriesFormElements) {
|
|
271
|
+
throw new Error('Required elements not found in template');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
this.populateRuntimeSettingAsRadio('lighthouse.mode', i18nString(UIStrings.mode), modeFormElements);
|
|
275
|
+
this.populateFormControls(deviceTypeFormElements, categoriesFormElements, mode);
|
|
215
276
|
|
|
216
277
|
this.refresh();
|
|
217
278
|
}
|
|
@@ -7,6 +7,7 @@ import * as i18n from '../../core/i18n/i18n.js';
|
|
|
7
7
|
import * as Geometry from '../../models/geometry/geometry.js';
|
|
8
8
|
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
9
9
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
10
|
+
import {Directives, html, render} from '../../ui/lit/lit.js';
|
|
10
11
|
|
|
11
12
|
import lighthouseDialogStyles from './lighthouseDialog.css.js';
|
|
12
13
|
import type {LighthousePanel} from './LighthousePanel.js';
|
|
@@ -37,6 +38,43 @@ const UIStrings = {
|
|
|
37
38
|
const str_ = i18n.i18n.registerUIStrings('panels/lighthouse/LighthouseTimespanView.ts', UIStrings);
|
|
38
39
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
39
40
|
|
|
41
|
+
const renderTimespanView = (
|
|
42
|
+
input: {
|
|
43
|
+
cancelButton: Element,
|
|
44
|
+
endButton: Element,
|
|
45
|
+
},
|
|
46
|
+
output: {
|
|
47
|
+
statusHeader?: HTMLElement,
|
|
48
|
+
contentContainer?: HTMLElement,
|
|
49
|
+
},
|
|
50
|
+
target: ShadowRoot,
|
|
51
|
+
): void => {
|
|
52
|
+
// clang-format off
|
|
53
|
+
render(
|
|
54
|
+
html`
|
|
55
|
+
<div class="lighthouse-view vbox">
|
|
56
|
+
<span
|
|
57
|
+
${Directives.ref(e => {
|
|
58
|
+
output.statusHeader = e as HTMLElement;
|
|
59
|
+
})}
|
|
60
|
+
class="header"
|
|
61
|
+
></span>
|
|
62
|
+
<span
|
|
63
|
+
${Directives.ref(e => {
|
|
64
|
+
output.contentContainer = e as HTMLElement;
|
|
65
|
+
})}
|
|
66
|
+
class="lighthouse-dialog-text"
|
|
67
|
+
></span>
|
|
68
|
+
<div class="lighthouse-action-buttons hbox">
|
|
69
|
+
${input.cancelButton} ${input.endButton}
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
`,
|
|
73
|
+
target,
|
|
74
|
+
);
|
|
75
|
+
// clang-format on
|
|
76
|
+
};
|
|
77
|
+
|
|
40
78
|
export class TimespanView extends UI.Dialog.Dialog {
|
|
41
79
|
private panel: LighthousePanel;
|
|
42
80
|
private statusHeader: Element|null;
|
|
@@ -90,20 +128,21 @@ export class TimespanView extends UI.Dialog.Dialog {
|
|
|
90
128
|
className: 'cancel',
|
|
91
129
|
jslogContext: 'lighthouse.cancel',
|
|
92
130
|
});
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
131
|
+
|
|
132
|
+
const output = {
|
|
133
|
+
statusHeader: undefined as HTMLElement | undefined,
|
|
134
|
+
contentContainer: undefined as HTMLElement | undefined,
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
renderTimespanView(
|
|
138
|
+
{
|
|
139
|
+
cancelButton,
|
|
140
|
+
endButton: this.endButton,
|
|
141
|
+
},
|
|
142
|
+
output, dialogRoot);
|
|
143
|
+
|
|
144
|
+
this.statusHeader = output.statusHeader ?? null;
|
|
145
|
+
this.contentContainer = output.contentContainer ?? null;
|
|
107
146
|
|
|
108
147
|
this.setSizeBehavior(UI.GlassPane.SizeBehavior.SET_EXACT_WIDTH_MAX_HEIGHT);
|
|
109
148
|
this.setMaxContentSize(new Geometry.Size(500, 400));
|