chrome-devtools-frontend 1.0.1011873 → 1.0.1013237
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/codereview.settings +4 -0
- package/config/gni/devtools_grd_files.gni +3 -0
- package/front_end/core/host/UserMetrics.ts +5 -2
- package/front_end/core/i18n/locales/en-US.json +38 -2
- package/front_end/core/i18n/locales/en-XL.json +38 -2
- package/front_end/core/root/Runtime.ts +2 -0
- package/front_end/core/sdk/CSSFontFace.ts +6 -0
- package/front_end/core/sdk/CSSModel.ts +4 -0
- package/front_end/entrypoints/main/MainImpl.ts +9 -0
- package/front_end/entrypoints/wasmparser_worker/WasmParserWorker.ts +2 -14
- package/front_end/generated/InspectorBackendCommands.js +2 -0
- package/front_end/generated/protocol.ts +20 -0
- package/front_end/models/emulation/EmulatedDevices.ts +29 -2
- package/front_end/models/javascript_metadata/NativeFunctions.js +8 -17
- package/front_end/models/persistence/NetworkPersistenceManager.ts +7 -4
- package/front_end/panels/application/AppManifestView.ts +12 -1
- package/front_end/panels/application/DOMStorageItemsView.ts +5 -5
- package/front_end/panels/application/components/ProtocolHandlersView.ts +182 -0
- package/front_end/panels/application/components/components.ts +2 -0
- package/front_end/panels/application/components/protocolHandlersView.css +39 -0
- package/front_end/panels/profiler/HeapSnapshotView.ts +3 -1
- package/front_end/panels/sources/NavigatorView.ts +50 -22
- package/front_end/panels/sources/SourcesNavigator.ts +45 -1
- package/front_end/panels/sources/SourcesPanel.ts +26 -4
- package/front_end/panels/sources/navigatorTree.css +4 -0
- package/front_end/panels/sources/sourcesNavigator.css +10 -0
- package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +15 -15
- package/front_end/third_party/lighthouse/report/bundle.d.ts +23 -2
- package/front_end/third_party/lighthouse/report/bundle.js +45 -19
- package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +1 -1
- package/front_end/ui/components/linear_memory_inspector/LinearMemoryViewer.ts +16 -11
- package/front_end/ui/components/linear_memory_inspector/linearMemoryInspector.css +4 -0
- package/front_end/ui/components/panel_feedback/PreviewToggle.ts +34 -13
- package/front_end/ui/components/panel_feedback/previewToggle.css +21 -1
- package/front_end/ui/components/text_editor/config.ts +2 -2
- package/front_end/ui/legacy/ContextMenu.ts +11 -2
- package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +15 -12
- package/package.json +1 -1
- package/scripts/build/ninja/devtools_entrypoint.gni +3 -3
- package/scripts/build/ninja/wasm.gni +25 -0
- package/scripts/build/wasm-as.py +87 -0
- package/scripts/build/wasm_sourcemap.mjs +22 -0
- package/scripts/eslint_rules/lib/lit_template_result_or_nothing.js +6 -0
@@ -15,6 +15,7 @@ import * as Components from '../../ui/legacy/components/utils/utils.js';
|
|
15
15
|
import * as UI from '../../ui/legacy/legacy.js';
|
16
16
|
import type * as Protocol from '../../generated/protocol.js';
|
17
17
|
import * as IconButton from '../../ui/components/icon_button/icon_button.js';
|
18
|
+
import * as ApplicationComponents from './components/components.js';
|
18
19
|
|
19
20
|
const UIStrings = {
|
20
21
|
/**
|
@@ -44,6 +45,10 @@ const UIStrings = {
|
|
44
45
|
/**
|
45
46
|
*@description Text in App Manifest View of the Application panel
|
46
47
|
*/
|
48
|
+
protocolHandlers: 'Protocol Handlers',
|
49
|
+
/**
|
50
|
+
*@description Text in App Manifest View of the Application panel
|
51
|
+
*/
|
47
52
|
icons: 'Icons',
|
48
53
|
/**
|
49
54
|
*@description Text for the name of something
|
@@ -423,6 +428,7 @@ export class AppManifestView extends UI.Widget.VBox implements SDK.TargetManager
|
|
423
428
|
private target?: SDK.Target.Target;
|
424
429
|
private resourceTreeModel?: SDK.ResourceTreeModel.ResourceTreeModel|null;
|
425
430
|
private serviceWorkerManager?: SDK.ServiceWorkerManager.ServiceWorkerManager|null;
|
431
|
+
private protocolHandlersView: ApplicationComponents.ProtocolHandlersView.ProtocolHandlersView;
|
426
432
|
constructor() {
|
427
433
|
super(true);
|
428
434
|
|
@@ -448,8 +454,10 @@ export class AppManifestView extends UI.Widget.VBox implements SDK.TargetManager
|
|
448
454
|
this.errorsSection = this.reportView.appendSection(i18nString(UIStrings.errorsAndWarnings));
|
449
455
|
this.installabilitySection = this.reportView.appendSection(i18nString(UIStrings.installability));
|
450
456
|
this.identitySection = this.reportView.appendSection(i18nString(UIStrings.identity));
|
451
|
-
|
452
457
|
this.presentationSection = this.reportView.appendSection(i18nString(UIStrings.presentation));
|
458
|
+
const protocolHandlersSection = this.reportView.appendSection(i18nString(UIStrings.protocolHandlers));
|
459
|
+
this.protocolHandlersView = new ApplicationComponents.ProtocolHandlersView.ProtocolHandlersView();
|
460
|
+
protocolHandlersSection.contentElement.append(this.protocolHandlersView);
|
453
461
|
this.iconsSection = this.reportView.appendSection(i18nString(UIStrings.icons), 'report-section-icons');
|
454
462
|
this.shortcutSections = [];
|
455
463
|
this.screenshotsSections = [];
|
@@ -701,6 +709,9 @@ export class AppManifestView extends UI.Widget.VBox implements SDK.TargetManager
|
|
701
709
|
this.newNoteUrlField.appendChild(link);
|
702
710
|
}
|
703
711
|
|
712
|
+
const protocolHandlers = parsedManifest['protocol_handlers'] || [];
|
713
|
+
this.protocolHandlersView.data = {protocolHandlers, manifestLink: url};
|
714
|
+
|
704
715
|
const icons = parsedManifest['icons'] || [];
|
705
716
|
this.iconsSection.clearContent();
|
706
717
|
|
@@ -53,14 +53,14 @@ const UIStrings = {
|
|
53
53
|
*/
|
54
54
|
value: 'Value',
|
55
55
|
/**
|
56
|
-
*@description
|
56
|
+
*@description Name for the "DOM Storage Items" table that shows the content of the DOM Storage.
|
57
57
|
*/
|
58
58
|
domStorageItems: 'DOM Storage Items',
|
59
59
|
/**
|
60
|
-
*@description Text for announcing
|
61
|
-
|
60
|
+
*@description Text for announcing that the "DOM Storage Items" table was cleared, that is, all
|
61
|
+
* entries were deleted.
|
62
62
|
*/
|
63
|
-
domStorageItemsCleared: '
|
63
|
+
domStorageItemsCleared: 'DOM Storage Items cleared',
|
64
64
|
/**
|
65
65
|
*@description Text in DOMStorage Items View of the Application panel
|
66
66
|
*/
|
@@ -154,7 +154,7 @@ export class DOMStorageItemsView extends StorageItemsView {
|
|
154
154
|
|
155
155
|
this.dataGrid.rootNode().removeChildren();
|
156
156
|
this.dataGrid.addCreationNode(false);
|
157
|
-
UI.ARIAUtils.alert(i18nString(UIStrings.domStorageItemsCleared
|
157
|
+
UI.ARIAUtils.alert(i18nString(UIStrings.domStorageItemsCleared));
|
158
158
|
this.setCanDeleteSelected(false);
|
159
159
|
}
|
160
160
|
|
@@ -0,0 +1,182 @@
|
|
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 Host from '../../../core/host/host.js';
|
6
|
+
import * as i18n from '../../../core/i18n/i18n.js';
|
7
|
+
import * as Platform from '../../../core/platform/platform.js';
|
8
|
+
import * as Buttons from '../../../ui/components/buttons/buttons.js';
|
9
|
+
import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
|
10
|
+
import * as IconButton from '../../../ui/components/icon_button/icon_button.js';
|
11
|
+
import * as Input from '../../../ui/components/input/input.js';
|
12
|
+
// inspectorCommonStyles is imported for the chrome-select class that is used for the dropdown
|
13
|
+
// eslint-disable-next-line rulesdir/es_modules_import
|
14
|
+
import inspectorCommonStyles from '../../../ui/legacy/inspectorCommon.css.js';
|
15
|
+
import * as UI from '../../../ui/legacy/legacy.js';
|
16
|
+
import * as LitHtml from '../../../ui/lit-html/lit-html.js';
|
17
|
+
|
18
|
+
import protocolHandlersViewStyles from './protocolHandlersView.css.js';
|
19
|
+
|
20
|
+
const PROTOCOL_DOCUMENT_URL = 'https://web.dev/url-protocol-handler/';
|
21
|
+
const UIStrings = {
|
22
|
+
/**
|
23
|
+
*@description Status message for when protocol handlers are detected in the manifest
|
24
|
+
*@example {protocolhandler/manifest.json} PH1
|
25
|
+
*/
|
26
|
+
protocolDetected:
|
27
|
+
'Found valid protocol handler registration in the {PH1}. With the app installed, test the registered protocols.',
|
28
|
+
/**
|
29
|
+
*@description Status message for when protocol handlers are not detected in the manifest
|
30
|
+
*@example {protocolhandler/manifest.json} PH1
|
31
|
+
*/
|
32
|
+
protocolNotDetected:
|
33
|
+
'Define protocol handlers in the {PH1} to register your app as a handler for custom protocols when your app is installed.',
|
34
|
+
/**
|
35
|
+
*@description Text wrapping a link pointing to more information on handling protocol handlers
|
36
|
+
*@example {https://example.com/} PH1
|
37
|
+
*/
|
38
|
+
needHelpReadOur: 'Need help? Read {PH1}.',
|
39
|
+
/**
|
40
|
+
*@description Link text for more information on URL protocol handler registrations for PWAs
|
41
|
+
*/
|
42
|
+
protocolHandlerRegistrations: 'URL protocol handler registration for PWAs',
|
43
|
+
/**
|
44
|
+
*@description In text hyperlink to the PWA manifest
|
45
|
+
*/
|
46
|
+
manifest: 'manifest',
|
47
|
+
/**
|
48
|
+
*@description Text for test protocol button
|
49
|
+
*/
|
50
|
+
testProtocol: 'Test protocol',
|
51
|
+
};
|
52
|
+
|
53
|
+
const str_ = i18n.i18n.registerUIStrings('panels/application/components/ProtocolHandlersView.ts', UIStrings);
|
54
|
+
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
55
|
+
|
56
|
+
interface HTMLSelectElementEvent extends Event {
|
57
|
+
target: HTMLSelectElement;
|
58
|
+
}
|
59
|
+
|
60
|
+
interface HTMLInputElementEvent extends Event {
|
61
|
+
target: HTMLInputElement;
|
62
|
+
}
|
63
|
+
|
64
|
+
export interface ProtocolHandler {
|
65
|
+
protocol: string;
|
66
|
+
url: string;
|
67
|
+
}
|
68
|
+
|
69
|
+
export interface ProtocolHandlersData {
|
70
|
+
protocolHandlers: ProtocolHandler[];
|
71
|
+
manifestLink: Platform.DevToolsPath.UrlString;
|
72
|
+
}
|
73
|
+
|
74
|
+
export class ProtocolHandlersView extends HTMLElement {
|
75
|
+
static readonly litTagName = LitHtml.literal`devtools-protocol-handlers-view`;
|
76
|
+
readonly #shadow = this.attachShadow({mode: 'open'});
|
77
|
+
#protocolHandlers: ProtocolHandler[] = [];
|
78
|
+
#manifestLink: Platform.DevToolsPath.UrlString = Platform.DevToolsPath.EmptyUrlString;
|
79
|
+
#selectedProtocolState: string = '';
|
80
|
+
#queryInputState: string = '';
|
81
|
+
|
82
|
+
set data(data: ProtocolHandlersData) {
|
83
|
+
const isNewManifest = this.#manifestLink !== data.manifestLink;
|
84
|
+
this.#protocolHandlers = data.protocolHandlers;
|
85
|
+
this.#manifestLink = data.manifestLink;
|
86
|
+
if (isNewManifest) {
|
87
|
+
this.#update();
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
#update(): void {
|
92
|
+
this.#queryInputState = '';
|
93
|
+
this.#selectedProtocolState = this.#protocolHandlers[0]?.protocol ?? '';
|
94
|
+
this.#render();
|
95
|
+
}
|
96
|
+
|
97
|
+
#renderStatusMessage(): LitHtml.TemplateResult {
|
98
|
+
const manifestInTextLink = UI.XLink.XLink.create(this.#manifestLink, i18nString(UIStrings.manifest));
|
99
|
+
const statusString = this.#protocolHandlers.length > 0 ? UIStrings.protocolDetected : UIStrings.protocolNotDetected;
|
100
|
+
const iconData: IconButton.Icon.IconData = {
|
101
|
+
iconName: this.#protocolHandlers.length > 0 ? 'ic_checkmark_16x16' : 'ic_info_black_18dp',
|
102
|
+
color: this.#protocolHandlers.length > 0 ? 'var( --color-ic-file-image)' : 'var(--color-link)',
|
103
|
+
width: '16px',
|
104
|
+
};
|
105
|
+
return LitHtml.html`
|
106
|
+
<div class="protocol-handlers-row status">
|
107
|
+
<${IconButton.Icon.Icon.litTagName} class="inline-icon" .data=${iconData as IconButton.Icon.IconData}>
|
108
|
+
</${IconButton.Icon.Icon.litTagName}>
|
109
|
+
${i18n.i18n.getFormatLocalizedString(str_, statusString, {
|
110
|
+
PH1: manifestInTextLink,
|
111
|
+
})}
|
112
|
+
</div>
|
113
|
+
`;
|
114
|
+
}
|
115
|
+
|
116
|
+
#renderProtocolTest(): LitHtml.LitTemplate {
|
117
|
+
if (this.#protocolHandlers.length === 0) {
|
118
|
+
return LitHtml.nothing;
|
119
|
+
}
|
120
|
+
const protocolOptions = this.#protocolHandlers.filter(p => p.protocol)
|
121
|
+
.map(p => LitHtml.html`<option value=${p.protocol}>${p.protocol}://</option>`);
|
122
|
+
return LitHtml.html`
|
123
|
+
<div class="protocol-handlers-row">
|
124
|
+
<select class="chrome-select protocol-select" @change=${this.#handleProtocolSelect}>
|
125
|
+
${protocolOptions}
|
126
|
+
</select>
|
127
|
+
<input .value=${this.#queryInputState} class="devtools-text-input" type="text" @change=${
|
128
|
+
this.#handleQueryInputChange}/>
|
129
|
+
<${Buttons.Button.Button.litTagName} .variant=${Buttons.Button.Variant.PRIMARY} @click=${
|
130
|
+
this.#handleTestProtocolClick}>
|
131
|
+
${i18nString(UIStrings.testProtocol)}
|
132
|
+
</${Buttons.Button.Button.litTagName}>
|
133
|
+
</div>
|
134
|
+
`;
|
135
|
+
}
|
136
|
+
|
137
|
+
#handleProtocolSelect = (evt: HTMLSelectElementEvent): void => {
|
138
|
+
this.#selectedProtocolState = evt.target.value;
|
139
|
+
};
|
140
|
+
|
141
|
+
#handleQueryInputChange = (evt: HTMLInputElementEvent): void => {
|
142
|
+
this.#queryInputState = evt.target.value;
|
143
|
+
this.#render();
|
144
|
+
};
|
145
|
+
|
146
|
+
#handleTestProtocolClick = (): void => {
|
147
|
+
const protocolURL = `${this.#selectedProtocolState}://${this.#queryInputState}` as Platform.DevToolsPath.UrlString;
|
148
|
+
Host.InspectorFrontendHost.InspectorFrontendHostInstance.openInNewTab(protocolURL);
|
149
|
+
Host.userMetrics.actionTaken(Host.UserMetrics.Action.CaptureTestProtocolClicked);
|
150
|
+
};
|
151
|
+
|
152
|
+
connectedCallback(): void {
|
153
|
+
this.#shadow.adoptedStyleSheets = [
|
154
|
+
protocolHandlersViewStyles,
|
155
|
+
inspectorCommonStyles,
|
156
|
+
Input.textInputStyles,
|
157
|
+
];
|
158
|
+
}
|
159
|
+
|
160
|
+
#render(): void {
|
161
|
+
const protocolDocLink =
|
162
|
+
UI.XLink.XLink.create(PROTOCOL_DOCUMENT_URL, i18nString(UIStrings.protocolHandlerRegistrations));
|
163
|
+
// clang-format off
|
164
|
+
LitHtml.render(LitHtml.html`
|
165
|
+
${this.#renderStatusMessage()}
|
166
|
+
<div class="protocol-handlers-row">
|
167
|
+
${i18n.i18n.getFormatLocalizedString(str_, UIStrings.needHelpReadOur, {PH1: protocolDocLink})}
|
168
|
+
</div>
|
169
|
+
${this.#renderProtocolTest()}
|
170
|
+
`, this.#shadow, {host: this});
|
171
|
+
// clang-format on
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
ComponentHelpers.CustomElements.defineComponent('devtools-protocol-handlers-view', ProtocolHandlersView);
|
176
|
+
|
177
|
+
declare global {
|
178
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
179
|
+
interface HTMLElementTagNameMap {
|
180
|
+
'devtools-protocol-handlers-view': ProtocolHandlersView;
|
181
|
+
}
|
182
|
+
}
|
@@ -7,6 +7,7 @@ import * as EndpointsGrid from './EndpointsGrid.js';
|
|
7
7
|
import * as FrameDetailsView from './FrameDetailsView.js';
|
8
8
|
import * as InterestGroupAccessGrid from './InterestGroupAccessGrid.js';
|
9
9
|
import * as OriginTrialTreeView from './OriginTrialTreeView.js';
|
10
|
+
import * as ProtocolHandlersView from './ProtocolHandlersView.js';
|
10
11
|
import * as ReportsGrid from './ReportsGrid.js';
|
11
12
|
import * as StackTrace from './StackTrace.js';
|
12
13
|
import * as TrustTokensView from './TrustTokensView.js';
|
@@ -17,6 +18,7 @@ export {
|
|
17
18
|
FrameDetailsView,
|
18
19
|
InterestGroupAccessGrid,
|
19
20
|
OriginTrialTreeView,
|
21
|
+
ProtocolHandlersView,
|
20
22
|
ReportsGrid,
|
21
23
|
StackTrace,
|
22
24
|
TrustTokensView,
|
@@ -0,0 +1,39 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2022 The Chromium Authors. All rights reserved.
|
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
|
+
.devtools-link {
|
8
|
+
color: var(--color-link);
|
9
|
+
text-decoration: underline;
|
10
|
+
cursor: pointer;
|
11
|
+
padding: 2px 0; /* adjust focus ring size */
|
12
|
+
}
|
13
|
+
|
14
|
+
input.devtools-text-input[type="text"] {
|
15
|
+
padding: 3px 6px;
|
16
|
+
margin-left: 4px;
|
17
|
+
margin-right: 4px;
|
18
|
+
width: 250px;
|
19
|
+
height: 25px;
|
20
|
+
}
|
21
|
+
|
22
|
+
.protocol-handlers-row {
|
23
|
+
margin: 10px 0 2px 18px;
|
24
|
+
}
|
25
|
+
|
26
|
+
.inline-icon {
|
27
|
+
vertical-align: text-bottom;
|
28
|
+
}
|
29
|
+
|
30
|
+
@media (forced-colors: active) {
|
31
|
+
.devtools-link:not(.devtools-link-prevent-click) {
|
32
|
+
color: linktext;
|
33
|
+
}
|
34
|
+
|
35
|
+
.devtools-link:focus-visible {
|
36
|
+
background: Highlight;
|
37
|
+
color: HighlightText;
|
38
|
+
}
|
39
|
+
}
|
@@ -181,7 +181,9 @@ const UIStrings = {
|
|
181
181
|
heapSnapshotProfilesShowMemory:
|
182
182
|
'Heap snapshot profiles show memory distribution among your page\'s JavaScript objects and related DOM nodes.',
|
183
183
|
/**
|
184
|
-
*@description
|
184
|
+
*@description Label for a checkbox in the heap snapshot view of the profiler tool. The "heap snapshot" contains the
|
185
|
+
* current state of JavaScript memory. With this checkbox enabled, the snapshot also includes internal data that is
|
186
|
+
* specific to Chrome (hence implementation-specific).
|
185
187
|
*/
|
186
188
|
exposeInternals: 'Expose internals (includes additional implementation-specific details)',
|
187
189
|
/**
|
@@ -32,6 +32,7 @@ import * as Common from '../../core/common/common.js';
|
|
32
32
|
import * as Host from '../../core/host/host.js';
|
33
33
|
import * as i18n from '../../core/i18n/i18n.js';
|
34
34
|
import * as Platform from '../../core/platform/platform.js';
|
35
|
+
import * as Root from '../../core/root/root.js';
|
35
36
|
import * as SDK from '../../core/sdk/sdk.js';
|
36
37
|
import * as Bindings from '../../models/bindings/bindings.js';
|
37
38
|
import * as Persistence from '../../models/persistence/persistence.js';
|
@@ -64,10 +65,18 @@ const UIStrings = {
|
|
64
65
|
/**
|
65
66
|
*@description Text in Navigator View of the Sources panel
|
66
67
|
*/
|
68
|
+
authoredTooltip: 'Contains original sources',
|
69
|
+
/**
|
70
|
+
*@description Text in Navigator View of the Sources panel
|
71
|
+
*/
|
67
72
|
deployed: 'Deployed',
|
68
73
|
/**
|
69
74
|
*@description Text in Navigator View of the Sources panel
|
70
75
|
*/
|
76
|
+
deployedTooltip: 'Contains final sources the browser sees',
|
77
|
+
/**
|
78
|
+
*@description Text in Navigator View of the Sources panel
|
79
|
+
*/
|
71
80
|
areYouSureYouWantToExcludeThis: 'Are you sure you want to exclude this folder?',
|
72
81
|
/**
|
73
82
|
*@description Text in Navigator View of the Sources panel
|
@@ -162,7 +171,7 @@ export class NavigatorView extends UI.Widget.VBox implements SDK.TargetManager.O
|
|
162
171
|
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
163
172
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
164
173
|
private navigatorGroupByFolderSetting: Common.Settings.Setting<any>;
|
165
|
-
private
|
174
|
+
private navigatorGroupByAuthoredExperiment?: string;
|
166
175
|
private workspaceInternal!: Workspace.Workspace.WorkspaceImpl;
|
167
176
|
private lastSelectedUISourceCode?: Workspace.UISourceCode.UISourceCode;
|
168
177
|
private groupByFrame?: boolean;
|
@@ -173,7 +182,7 @@ export class NavigatorView extends UI.Widget.VBox implements SDK.TargetManager.O
|
|
173
182
|
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
174
183
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
175
184
|
private groupByFolder?: any;
|
176
|
-
constructor() {
|
185
|
+
constructor(enableAuthoredGrouping?: boolean) {
|
177
186
|
super(true);
|
178
187
|
|
179
188
|
this.placeholder = null;
|
@@ -198,9 +207,9 @@ export class NavigatorView extends UI.Widget.VBox implements SDK.TargetManager.O
|
|
198
207
|
|
199
208
|
this.navigatorGroupByFolderSetting = Common.Settings.Settings.instance().moduleSetting('navigatorGroupByFolder');
|
200
209
|
this.navigatorGroupByFolderSetting.addChangeListener(this.groupingChanged.bind(this));
|
201
|
-
|
202
|
-
|
203
|
-
|
210
|
+
if (enableAuthoredGrouping) {
|
211
|
+
this.navigatorGroupByAuthoredExperiment = Root.Runtime.ExperimentName.AUTHORED_DEPLOYED_GROUPING;
|
212
|
+
}
|
204
213
|
|
205
214
|
this.initGrouping();
|
206
215
|
|
@@ -686,8 +695,9 @@ export class NavigatorView extends UI.Widget.VBox implements SDK.TargetManager.O
|
|
686
695
|
NavigatorTreeNode {
|
687
696
|
if (this.groupByAuthored && isAuthored) {
|
688
697
|
if (!this.authoredNode) {
|
689
|
-
this.authoredNode =
|
690
|
-
|
698
|
+
this.authoredNode = new NavigatorGroupTreeNode(
|
699
|
+
this, null, 'group:Authored', Types.Authored, i18nString(UIStrings.authored),
|
700
|
+
i18nString(UIStrings.authoredTooltip));
|
691
701
|
this.rootNode.appendChild(this.authoredNode);
|
692
702
|
this.authoredNode.treeNode().expand();
|
693
703
|
}
|
@@ -712,8 +722,9 @@ export class NavigatorView extends UI.Widget.VBox implements SDK.TargetManager.O
|
|
712
722
|
private rootOrDeployedNode(): NavigatorTreeNode {
|
713
723
|
if (this.groupByAuthored) {
|
714
724
|
if (!this.deployedNode) {
|
715
|
-
this.deployedNode =
|
716
|
-
|
725
|
+
this.deployedNode = new NavigatorGroupTreeNode(
|
726
|
+
this, null, 'group:Deployed', Types.Deployed, i18nString(UIStrings.deployed),
|
727
|
+
i18nString(UIStrings.deployedTooltip));
|
717
728
|
this.rootNode.appendChild(this.deployedNode);
|
718
729
|
}
|
719
730
|
return this.deployedNode;
|
@@ -1007,10 +1018,17 @@ export class NavigatorView extends UI.Widget.VBox implements SDK.TargetManager.O
|
|
1007
1018
|
}
|
1008
1019
|
}
|
1009
1020
|
|
1021
|
+
/**
|
1022
|
+
* Subclasses can override to listen to grouping changes.
|
1023
|
+
*/
|
1024
|
+
onGroupingChanged(): void {
|
1025
|
+
}
|
1026
|
+
|
1010
1027
|
private groupingChanged(): void {
|
1011
1028
|
this.reset(true);
|
1012
1029
|
this.initGrouping();
|
1013
1030
|
// Reset the workspace to repopulate filesystem folders.
|
1031
|
+
this.onGroupingChanged();
|
1014
1032
|
this.resetWorkspace(Workspace.Workspace.WorkspaceImpl.instance());
|
1015
1033
|
this.workspaceInternal.uiSourceCodes().forEach(this.addUISourceCode.bind(this));
|
1016
1034
|
}
|
@@ -1019,7 +1037,11 @@ export class NavigatorView extends UI.Widget.VBox implements SDK.TargetManager.O
|
|
1019
1037
|
this.groupByFrame = true;
|
1020
1038
|
this.groupByDomain = this.navigatorGroupByFolderSetting.get();
|
1021
1039
|
this.groupByFolder = this.groupByDomain;
|
1022
|
-
|
1040
|
+
if (this.navigatorGroupByAuthoredExperiment) {
|
1041
|
+
this.groupByAuthored = Root.Runtime.experiments.isEnabled(this.navigatorGroupByAuthoredExperiment);
|
1042
|
+
} else {
|
1043
|
+
this.groupByAuthored = false;
|
1044
|
+
}
|
1023
1045
|
}
|
1024
1046
|
|
1025
1047
|
private resetForTest(): void {
|
@@ -1130,14 +1152,18 @@ export class NavigatorFolderTreeElement extends UI.TreeOutline.TreeElement {
|
|
1130
1152
|
|
1131
1153
|
setNode(node: NavigatorTreeNode): void {
|
1132
1154
|
this.node = node;
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
paths
|
1137
|
-
currentNode =
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1155
|
+
if (node.tooltip) {
|
1156
|
+
this.tooltip = node.tooltip;
|
1157
|
+
} else {
|
1158
|
+
const paths = [];
|
1159
|
+
let currentNode: NavigatorTreeNode|null = node;
|
1160
|
+
while (currentNode && !currentNode.isRoot() && currentNode.type === node.type) {
|
1161
|
+
paths.push(currentNode.title);
|
1162
|
+
currentNode = currentNode.parent;
|
1163
|
+
}
|
1164
|
+
paths.reverse();
|
1165
|
+
this.tooltip = paths.join('/');
|
1166
|
+
}
|
1141
1167
|
UI.ARIAUtils.setAccessibleName(this.listItemElement, `${this.title}, ${this.nodeType}`);
|
1142
1168
|
}
|
1143
1169
|
|
@@ -1303,12 +1329,14 @@ export class NavigatorTreeNode {
|
|
1303
1329
|
isMerged: boolean;
|
1304
1330
|
parent!: NavigatorTreeNode|null;
|
1305
1331
|
title!: string;
|
1332
|
+
tooltip?: string;
|
1306
1333
|
|
1307
|
-
constructor(navigatorView: NavigatorView, id: string, type: string) {
|
1334
|
+
constructor(navigatorView: NavigatorView, id: string, type: string, tooltip?: string) {
|
1308
1335
|
this.id = id;
|
1309
1336
|
this.navigatorView = navigatorView;
|
1310
1337
|
this.type = type;
|
1311
1338
|
this.childrenInternal = new Map();
|
1339
|
+
this.tooltip = tooltip;
|
1312
1340
|
|
1313
1341
|
this.populated = false;
|
1314
1342
|
this.isMerged = false;
|
@@ -1719,9 +1747,9 @@ export class NavigatorGroupTreeNode extends NavigatorTreeNode {
|
|
1719
1747
|
private hoverCallback?: ((arg0: boolean) => void);
|
1720
1748
|
private treeElement?: NavigatorFolderTreeElement;
|
1721
1749
|
constructor(
|
1722
|
-
navigatorView: NavigatorView, project: Workspace.Workspace.Project|null, id: string, type: string,
|
1723
|
-
|
1724
|
-
super(navigatorView, id, type);
|
1750
|
+
navigatorView: NavigatorView, project: Workspace.Workspace.Project|null, id: string, type: string, title: string,
|
1751
|
+
tooltip?: string) {
|
1752
|
+
super(navigatorView, id, type, tooltip);
|
1725
1753
|
this.project = project;
|
1726
1754
|
this.title = title;
|
1727
1755
|
this.populate();
|
@@ -32,14 +32,17 @@ import * as Common from '../../core/common/common.js';
|
|
32
32
|
import * as Host from '../../core/host/host.js';
|
33
33
|
import * as i18n from '../../core/i18n/i18n.js';
|
34
34
|
import * as Platform from '../../core/platform/platform.js';
|
35
|
+
import * as Root from '../../core/root/root.js';
|
35
36
|
import * as SDK from '../../core/sdk/sdk.js';
|
36
37
|
import * as Persistence from '../../models/persistence/persistence.js';
|
37
38
|
import * as Workspace from '../../models/workspace/workspace.js';
|
39
|
+
import * as Feedback from '../../ui/components/panel_feedback/panel_feedback.js';
|
38
40
|
import * as UI from '../../ui/legacy/legacy.js';
|
39
41
|
import * as Snippets from '../snippets/snippets.js';
|
40
42
|
|
41
43
|
import type {NavigatorUISourceCodeTreeNode} from './NavigatorView.js';
|
42
44
|
import {NavigatorView} from './NavigatorView.js';
|
45
|
+
import sourcesNavigatorStyles from './sourcesNavigator.css.js';
|
43
46
|
|
44
47
|
const UIStrings = {
|
45
48
|
/**
|
@@ -100,20 +103,61 @@ const UIStrings = {
|
|
100
103
|
*@description Text to save content as a specific file type
|
101
104
|
*/
|
102
105
|
saveAs: 'Save as...',
|
106
|
+
/**
|
107
|
+
*@description Description of the new experimental Authored/Deployed view
|
108
|
+
*/
|
109
|
+
authoredDescription: 'Group files by Authored/Deployed',
|
103
110
|
};
|
104
111
|
const str_ = i18n.i18n.registerUIStrings('panels/sources/SourcesNavigator.ts', UIStrings);
|
105
112
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
106
113
|
let networkNavigatorViewInstance: NetworkNavigatorView;
|
107
114
|
|
108
115
|
export class NetworkNavigatorView extends NavigatorView {
|
116
|
+
private previewToggle: Feedback.PreviewToggle.PreviewToggle;
|
109
117
|
private constructor() {
|
110
|
-
super();
|
118
|
+
super(true);
|
111
119
|
SDK.TargetManager.TargetManager.instance().addEventListener(
|
112
120
|
SDK.TargetManager.Events.InspectedURLChanged, this.inspectedURLChanged, this);
|
113
121
|
|
122
|
+
this.previewToggle = new Feedback.PreviewToggle.PreviewToggle();
|
123
|
+
this.onGroupingChanged();
|
124
|
+
|
125
|
+
const div = UI.Fragment.html`<div class="border-container"></div>`;
|
126
|
+
div.append(this.previewToggle);
|
127
|
+
this.contentElement.prepend(div);
|
128
|
+
|
114
129
|
// Record the sources tool load time after the file navigator has loaded.
|
115
130
|
Host.userMetrics.panelLoaded('sources', 'DevTools.Launch.Sources');
|
116
131
|
}
|
132
|
+
|
133
|
+
onGroupingChanged(): void {
|
134
|
+
// Setting the data will re-render it.
|
135
|
+
this.previewToggle.data = {
|
136
|
+
name: i18nString(UIStrings.authoredDescription),
|
137
|
+
helperText: null,
|
138
|
+
experiment: Root.Runtime.ExperimentName.AUTHORED_DEPLOYED_GROUPING,
|
139
|
+
learnMoreURL: 'https://goo.gle/authored-deployed',
|
140
|
+
feedbackURL: 'https://goo.gle/authored-deployed-feedback',
|
141
|
+
onChangeCallback: this.onAuthoredDeployedChanged,
|
142
|
+
};
|
143
|
+
}
|
144
|
+
|
145
|
+
wasShown(): void {
|
146
|
+
this.registerCSSFiles([sourcesNavigatorStyles]);
|
147
|
+
super.wasShown();
|
148
|
+
}
|
149
|
+
|
150
|
+
private onAuthoredDeployedChanged(checked: boolean): void {
|
151
|
+
Host.userMetrics.experimentChanged(Root.Runtime.ExperimentName.AUTHORED_DEPLOYED_GROUPING, checked);
|
152
|
+
// Need to signal to the NavigatorView that grouping has changed. Unfortunately,
|
153
|
+
// it can't listen to an experiment, and this class doesn't directly interact
|
154
|
+
// with it, so we will convince it a different grouping setting changed. When we switch
|
155
|
+
// from using an experiment to a setting, it will listen to that setting and we
|
156
|
+
// won't need to do this.
|
157
|
+
const groupByFolderSetting = Common.Settings.Settings.instance().moduleSetting('navigatorGroupByFolder');
|
158
|
+
groupByFolderSetting.set(groupByFolderSetting.get());
|
159
|
+
}
|
160
|
+
|
117
161
|
static instance(opts: {
|
118
162
|
forceNew: boolean|null,
|
119
163
|
} = {forceNew: null}): NetworkNavigatorView {
|
@@ -32,10 +32,12 @@ import * as Common from '../../core/common/common.js';
|
|
32
32
|
import * as Host from '../../core/host/host.js';
|
33
33
|
import * as i18n from '../../core/i18n/i18n.js';
|
34
34
|
import * as Platform from '../../core/platform/platform.js';
|
35
|
+
import * as Root from '../../core/root/root.js';
|
35
36
|
import * as SDK from '../../core/sdk/sdk.js';
|
36
37
|
import * as Bindings from '../../models/bindings/bindings.js';
|
37
38
|
import * as Extensions from '../../models/extensions/extensions.js';
|
38
39
|
import * as Workspace from '../../models/workspace/workspace.js';
|
40
|
+
import * as IconButton from '../../ui/components/icon_button/icon_button.js';
|
39
41
|
import * as ObjectUI from '../../ui/legacy/components/object_ui/object_ui.js';
|
40
42
|
import * as UI from '../../ui/legacy/legacy.js';
|
41
43
|
import * as Snippets from '../snippets/snippets.js';
|
@@ -108,7 +110,7 @@ const UIStrings = {
|
|
108
110
|
/**
|
109
111
|
*@description Text in Sources Panel of the Sources panel
|
110
112
|
*/
|
111
|
-
groupByAuthored: 'Group by Authored/Deployed
|
113
|
+
groupByAuthored: 'Group by Authored/Deployed',
|
112
114
|
/**
|
113
115
|
*@description Text for pausing the debugger on exceptions
|
114
116
|
*/
|
@@ -547,16 +549,36 @@ export class SourcesPanel extends UI.Panel.Panel implements UI.ContextMenu.Provi
|
|
547
549
|
}
|
548
550
|
}
|
549
551
|
|
552
|
+
private toggleAuthoredDeployedExperiment(): void {
|
553
|
+
const experiment = Root.Runtime.ExperimentName.AUTHORED_DEPLOYED_GROUPING;
|
554
|
+
const checked = Root.Runtime.experiments.isEnabled(experiment);
|
555
|
+
Root.Runtime.experiments.setEnabled(experiment, !checked);
|
556
|
+
Host.userMetrics.experimentChanged(experiment, checked);
|
557
|
+
// Need to signal to the NavigatorView that grouping has changed. Unfortunately,
|
558
|
+
// it can't listen to an experiment, and this class doesn't directly interact
|
559
|
+
// with it, so we will convince it a different grouping setting changed. When we switch
|
560
|
+
// from using an experiment to a setting, it will listen to that setting and we
|
561
|
+
// won't need to do this.
|
562
|
+
const groupByFolderSetting = Common.Settings.Settings.instance().moduleSetting('navigatorGroupByFolder');
|
563
|
+
groupByFolderSetting.set(groupByFolderSetting.get());
|
564
|
+
}
|
565
|
+
|
550
566
|
private populateNavigatorMenu(contextMenu: UI.ContextMenu.ContextMenu): void {
|
551
567
|
const groupByFolderSetting = Common.Settings.Settings.instance().moduleSetting('navigatorGroupByFolder');
|
552
568
|
contextMenu.appendItemsAtLocation('navigatorMenu');
|
553
569
|
contextMenu.viewSection().appendCheckboxItem(
|
554
570
|
i18nString(UIStrings.groupByFolder), () => groupByFolderSetting.set(!groupByFolderSetting.get()),
|
555
571
|
groupByFolderSetting.get());
|
556
|
-
const
|
572
|
+
const previewIcon = new IconButton.Icon.Icon();
|
573
|
+
const experiment = Root.Runtime.ExperimentName.AUTHORED_DEPLOYED_GROUPING;
|
574
|
+
previewIcon.data = {
|
575
|
+
iconName: 'ic_preview_feature',
|
576
|
+
color: 'var(--icon-color)',
|
577
|
+
width: '14px',
|
578
|
+
};
|
557
579
|
contextMenu.viewSection().appendCheckboxItem(
|
558
|
-
i18nString(UIStrings.groupByAuthored),
|
559
|
-
|
580
|
+
i18nString(UIStrings.groupByAuthored), this.toggleAuthoredDeployedExperiment,
|
581
|
+
Root.Runtime.experiments.isEnabled(experiment), false, previewIcon);
|
560
582
|
}
|
561
583
|
|
562
584
|
setIgnoreExecutionLineEvents(ignoreExecutionLineEvents: boolean): void {
|
@@ -91,6 +91,10 @@
|
|
91
91
|
background-color: var(--override-folder-tree-item-color);
|
92
92
|
}
|
93
93
|
|
94
|
+
.navigator-folder-tree-item.force-white-icons {
|
95
|
+
--icon-color: var(--override-force-white-icons-background);
|
96
|
+
}
|
97
|
+
|
94
98
|
.navigator-sm-folder-tree-item .icon,
|
95
99
|
.navigator-fs-tree-item .icon,
|
96
100
|
.navigator-fs-folder-tree-item .icon {
|
@@ -0,0 +1,10 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2022 The Chromium Authors. All rights reserved.
|
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
|
+
.border-container {
|
8
|
+
border-bottom: 1px solid var(--color-details-hairline);
|
9
|
+
flex-shrink: 0;
|
10
|
+
}
|