chrome-devtools-frontend 1.0.976703 → 1.0.978040
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/config/gni/devtools_grd_files.gni +1 -1
- package/front_end/core/host/UserMetrics.ts +23 -1
- package/front_end/core/i18n/locales/af.json +5 -5
- package/front_end/core/i18n/locales/am.json +5 -5
- package/front_end/core/i18n/locales/ar.json +5 -5
- package/front_end/core/i18n/locales/as.json +5 -5
- package/front_end/core/i18n/locales/az.json +5 -5
- package/front_end/core/i18n/locales/be.json +5 -5
- package/front_end/core/i18n/locales/bg.json +5 -5
- package/front_end/core/i18n/locales/bn.json +5 -5
- package/front_end/core/i18n/locales/bs.json +5 -5
- package/front_end/core/i18n/locales/ca.json +5 -5
- package/front_end/core/i18n/locales/cs.json +5 -5
- package/front_end/core/i18n/locales/cy.json +5 -5
- package/front_end/core/i18n/locales/da.json +5 -5
- package/front_end/core/i18n/locales/de.json +5 -5
- package/front_end/core/i18n/locales/el.json +5 -5
- package/front_end/core/i18n/locales/en-GB.json +5 -5
- package/front_end/core/i18n/locales/en-US.json +18 -15
- package/front_end/core/i18n/locales/en-XL.json +18 -15
- package/front_end/core/i18n/locales/es-419.json +5 -5
- package/front_end/core/i18n/locales/es.json +5 -5
- package/front_end/core/i18n/locales/et.json +5 -5
- package/front_end/core/i18n/locales/eu.json +5 -5
- package/front_end/core/i18n/locales/fa.json +5 -5
- package/front_end/core/i18n/locales/fi.json +5 -5
- package/front_end/core/i18n/locales/fil.json +5 -5
- package/front_end/core/i18n/locales/fr-CA.json +5 -5
- package/front_end/core/i18n/locales/fr.json +5 -5
- package/front_end/core/i18n/locales/gl.json +5 -5
- package/front_end/core/i18n/locales/gu.json +5 -5
- package/front_end/core/i18n/locales/he.json +5 -5
- package/front_end/core/i18n/locales/hi.json +5 -5
- package/front_end/core/i18n/locales/hr.json +5 -5
- package/front_end/core/i18n/locales/hu.json +5 -5
- package/front_end/core/i18n/locales/hy.json +5 -5
- package/front_end/core/i18n/locales/id.json +5 -5
- package/front_end/core/i18n/locales/is.json +5 -5
- package/front_end/core/i18n/locales/it.json +5 -5
- package/front_end/core/i18n/locales/ja.json +5 -5
- package/front_end/core/i18n/locales/ka.json +5 -5
- package/front_end/core/i18n/locales/kk.json +5 -5
- package/front_end/core/i18n/locales/km.json +5 -5
- package/front_end/core/i18n/locales/kn.json +5 -5
- package/front_end/core/i18n/locales/ko.json +5 -5
- package/front_end/core/i18n/locales/ky.json +5 -5
- package/front_end/core/i18n/locales/lo.json +5 -5
- package/front_end/core/i18n/locales/lt.json +5 -5
- package/front_end/core/i18n/locales/lv.json +5 -5
- package/front_end/core/i18n/locales/mk.json +5 -5
- package/front_end/core/i18n/locales/ml.json +5 -5
- package/front_end/core/i18n/locales/mn.json +5 -5
- package/front_end/core/i18n/locales/mr.json +5 -5
- package/front_end/core/i18n/locales/ms.json +5 -5
- package/front_end/core/i18n/locales/my.json +5 -5
- package/front_end/core/i18n/locales/ne.json +5 -5
- package/front_end/core/i18n/locales/nl.json +5 -5
- package/front_end/core/i18n/locales/no.json +5 -5
- package/front_end/core/i18n/locales/or.json +5 -5
- package/front_end/core/i18n/locales/pa.json +5 -5
- package/front_end/core/i18n/locales/pl.json +5 -5
- package/front_end/core/i18n/locales/pt-PT.json +5 -5
- package/front_end/core/i18n/locales/pt.json +5 -5
- package/front_end/core/i18n/locales/ro.json +5 -5
- package/front_end/core/i18n/locales/ru.json +5 -5
- package/front_end/core/i18n/locales/si.json +5 -5
- package/front_end/core/i18n/locales/sk.json +5 -5
- package/front_end/core/i18n/locales/sl.json +5 -5
- package/front_end/core/i18n/locales/sq.json +5 -5
- package/front_end/core/i18n/locales/sr-Latn.json +5 -5
- package/front_end/core/i18n/locales/sr.json +5 -5
- package/front_end/core/i18n/locales/sv.json +5 -5
- package/front_end/core/i18n/locales/sw.json +5 -5
- package/front_end/core/i18n/locales/ta.json +5 -5
- package/front_end/core/i18n/locales/te.json +5 -5
- package/front_end/core/i18n/locales/th.json +5 -5
- package/front_end/core/i18n/locales/tr.json +5 -5
- package/front_end/core/i18n/locales/uk.json +5 -5
- package/front_end/core/i18n/locales/ur.json +5 -5
- package/front_end/core/i18n/locales/uz.json +5 -5
- package/front_end/core/i18n/locales/vi.json +5 -5
- package/front_end/core/i18n/locales/zh-HK.json +5 -5
- package/front_end/core/i18n/locales/zh-TW.json +5 -5
- package/front_end/core/i18n/locales/zh.json +5 -5
- package/front_end/core/i18n/locales/zu.json +5 -5
- package/front_end/models/issues_manager/{SameSiteCookieIssue.ts → CookieIssue.ts} +1 -1
- package/front_end/models/issues_manager/IssuesManager.ts +1 -1
- package/front_end/models/issues_manager/NavigatorUserAgentIssue.ts +1 -1
- package/front_end/models/issues_manager/issues_manager.ts +1 -1
- package/front_end/models/persistence/NetworkPersistenceManager.ts +3 -3
- package/front_end/panels/application/ApplicationPanelCacheSection.ts +3 -0
- package/front_end/panels/application/ApplicationPanelSidebar.ts +15 -0
- package/front_end/panels/application/InterestGroupTreeElement.ts +2 -0
- package/front_end/panels/application/ReportingApiTreeElement.ts +2 -0
- package/front_end/panels/application/TrustTokensTreeElement.ts +2 -0
- package/front_end/panels/application/components/BackForwardCacheView.ts +23 -1
- package/front_end/panels/sources/components/HeadersView.css +52 -0
- package/front_end/panels/sources/components/HeadersView.ts +220 -9
- package/front_end/panels/timeline/TimelineController.ts +17 -5
- package/front_end/ui/components/expandable_list/expandableList.css +10 -0
- package/front_end/ui/components/text_editor/javascript.ts +46 -1
- package/package.json +1 -1
@@ -831,6 +831,7 @@ export class BackgroundServiceTreeElement extends ApplicationPanelTreeElement {
|
|
831
831
|
}
|
832
832
|
this.showView(this.view);
|
833
833
|
UI.Context.Context.instance().setFlavor(BackgroundServiceView, this.view);
|
834
|
+
Host.userMetrics.panelShown('background_service_' + this.serviceName);
|
834
835
|
return false;
|
835
836
|
}
|
836
837
|
}
|
@@ -854,6 +855,7 @@ export class DatabaseTreeElement extends ApplicationPanelTreeElement {
|
|
854
855
|
onselect(selectedByUser?: boolean): boolean {
|
855
856
|
super.onselect(selectedByUser);
|
856
857
|
this.sidebar.showDatabase(this.database);
|
858
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.web_sql]);
|
857
859
|
return false;
|
858
860
|
}
|
859
861
|
|
@@ -891,6 +893,7 @@ export class DatabaseTableTreeElement extends ApplicationPanelTreeElement {
|
|
891
893
|
onselect(selectedByUser?: boolean): boolean {
|
892
894
|
super.onselect(selectedByUser);
|
893
895
|
this.sidebar.showDatabase(this.database, this.tableName);
|
896
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.web_sql]);
|
894
897
|
return false;
|
895
898
|
}
|
896
899
|
}
|
@@ -914,6 +917,7 @@ export class ServiceWorkersTreeElement extends ApplicationPanelTreeElement {
|
|
914
917
|
this.view = new ServiceWorkersView();
|
915
918
|
}
|
916
919
|
this.showView(this.view);
|
920
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.service_workers]);
|
917
921
|
return false;
|
918
922
|
}
|
919
923
|
}
|
@@ -936,6 +940,7 @@ export class AppManifestTreeElement extends ApplicationPanelTreeElement {
|
|
936
940
|
this.view = new AppManifestView();
|
937
941
|
}
|
938
942
|
this.showView(this.view);
|
943
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.app_manifest]);
|
939
944
|
return false;
|
940
945
|
}
|
941
946
|
}
|
@@ -958,6 +963,7 @@ export class ClearStorageTreeElement extends ApplicationPanelTreeElement {
|
|
958
963
|
this.view = new StorageView();
|
959
964
|
}
|
960
965
|
this.showView(this.view);
|
966
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.storage]);
|
961
967
|
return false;
|
962
968
|
}
|
963
969
|
}
|
@@ -1170,6 +1176,7 @@ export class IDBDatabaseTreeElement extends ApplicationPanelTreeElement {
|
|
1170
1176
|
}
|
1171
1177
|
|
1172
1178
|
this.showView(this.view);
|
1179
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.indexed_db]);
|
1173
1180
|
return false;
|
1174
1181
|
}
|
1175
1182
|
|
@@ -1302,6 +1309,7 @@ export class IDBObjectStoreTreeElement extends ApplicationPanelTreeElement {
|
|
1302
1309
|
}
|
1303
1310
|
|
1304
1311
|
this.showView(this.view);
|
1312
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.indexed_db]);
|
1305
1313
|
return false;
|
1306
1314
|
}
|
1307
1315
|
|
@@ -1391,6 +1399,7 @@ export class IDBIndexTreeElement extends ApplicationPanelTreeElement {
|
|
1391
1399
|
}
|
1392
1400
|
|
1393
1401
|
this.showView(this.view);
|
1402
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.indexed_db]);
|
1394
1403
|
return false;
|
1395
1404
|
}
|
1396
1405
|
|
@@ -1417,6 +1426,7 @@ export class DOMStorageTreeElement extends ApplicationPanelTreeElement {
|
|
1417
1426
|
|
1418
1427
|
onselect(selectedByUser?: boolean): boolean {
|
1419
1428
|
super.onselect(selectedByUser);
|
1429
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.dom_storage]);
|
1420
1430
|
this.resourcesPanel.showDOMStorage(this.domStorage);
|
1421
1431
|
return false;
|
1422
1432
|
}
|
@@ -1469,6 +1479,7 @@ export class CookieTreeElement extends ApplicationPanelTreeElement {
|
|
1469
1479
|
onselect(selectedByUser?: boolean): boolean {
|
1470
1480
|
super.onselect(selectedByUser);
|
1471
1481
|
this.resourcesPanel.showCookies(this.target, this.cookieDomainInternal);
|
1482
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.cookies]);
|
1472
1483
|
return false;
|
1473
1484
|
}
|
1474
1485
|
}
|
@@ -1810,6 +1821,7 @@ export class FrameTreeElement extends ApplicationPanelTreeElement {
|
|
1810
1821
|
} else {
|
1811
1822
|
this.view.update();
|
1812
1823
|
}
|
1824
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.frame_details]);
|
1813
1825
|
this.showView(this.view);
|
1814
1826
|
|
1815
1827
|
this.listItemElement.classList.remove('hovered');
|
@@ -1978,6 +1990,7 @@ export class FrameResourceTreeElement extends ApplicationPanelTreeElement {
|
|
1978
1990
|
} else {
|
1979
1991
|
void this.panel.scheduleShowView(this.preparePreview());
|
1980
1992
|
}
|
1993
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.frame_resource]);
|
1981
1994
|
return false;
|
1982
1995
|
}
|
1983
1996
|
|
@@ -2065,6 +2078,7 @@ class FrameWindowTreeElement extends ApplicationPanelTreeElement {
|
|
2065
2078
|
this.view.update();
|
2066
2079
|
}
|
2067
2080
|
this.showView(this.view);
|
2081
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.frame_window]);
|
2068
2082
|
return false;
|
2069
2083
|
}
|
2070
2084
|
|
@@ -2093,6 +2107,7 @@ class WorkerTreeElement extends ApplicationPanelTreeElement {
|
|
2093
2107
|
this.view.update();
|
2094
2108
|
}
|
2095
2109
|
this.showView(this.view);
|
2110
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.frame_worker]);
|
2096
2111
|
return false;
|
2097
2112
|
}
|
2098
2113
|
|
@@ -2,6 +2,7 @@
|
|
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 Host from '../../core/host/host.js';
|
5
6
|
import * as i18n from '../../core/i18n/i18n.js';
|
6
7
|
import * as SDK from '../../core/sdk/sdk.js';
|
7
8
|
import * as UI from '../../ui/legacy/legacy.js';
|
@@ -51,6 +52,7 @@ export class InterestGroupTreeElement extends ApplicationPanelTreeElement {
|
|
51
52
|
onselect(selectedByUser?: boolean): boolean {
|
52
53
|
super.onselect(selectedByUser);
|
53
54
|
this.showView(this.view);
|
55
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.interest_groups]);
|
54
56
|
return false;
|
55
57
|
}
|
56
58
|
|
@@ -2,6 +2,7 @@
|
|
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 Host from '../../core/host/host.js';
|
5
6
|
import * as i18n from '../../core/i18n/i18n.js';
|
6
7
|
import * as UI from '../../ui/legacy/legacy.js';
|
7
8
|
|
@@ -37,6 +38,7 @@ export class ReportingApiTreeElement extends ApplicationPanelTreeElement {
|
|
37
38
|
this.view = new ReportingApiView();
|
38
39
|
}
|
39
40
|
this.showView(this.view);
|
41
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.reporting_api]);
|
40
42
|
return false;
|
41
43
|
}
|
42
44
|
}
|
@@ -9,6 +9,7 @@ import * as UI from '../../ui/legacy/legacy.js';
|
|
9
9
|
import {ApplicationPanelTreeElement} from './ApplicationPanelTreeElement.js';
|
10
10
|
import * as ApplicationComponents from './components/components.js';
|
11
11
|
import type {ResourcesPanel} from './ResourcesPanel.js';
|
12
|
+
import * as Host from '../../core/host/host.js';
|
12
13
|
|
13
14
|
const UIStrings = {
|
14
15
|
/**
|
@@ -41,6 +42,7 @@ export class TrustTokensTreeElement extends ApplicationPanelTreeElement {
|
|
41
42
|
this.view = new TrustTokensViewWidgetWrapper();
|
42
43
|
}
|
43
44
|
this.showView(this.view);
|
45
|
+
Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.trust_tokens]);
|
44
46
|
return false;
|
45
47
|
}
|
46
48
|
}
|
@@ -13,6 +13,7 @@ import * as Protocol from '../../../generated/protocol.js';
|
|
13
13
|
import * as IconButton from '../../../ui/components/icon_button/icon_button.js';
|
14
14
|
import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
|
15
15
|
import * as Coordinator from '../../../ui/components/render_coordinator/render_coordinator.js';
|
16
|
+
import * as ChromeLink from '../../../ui/components/chrome_link/chrome_link.js';
|
16
17
|
|
17
18
|
import {NotRestoredReasonDescription} from './BackForwardCacheStrings.js';
|
18
19
|
import backForwardCacheViewStyles from './backForwardCacheView.css.js';
|
@@ -97,6 +98,10 @@ const UIStrings = {
|
|
97
98
|
*/
|
98
99
|
supportPendingExplanation:
|
99
100
|
'Chrome support for these reasons is pending i.e. they will not prevent the page from being eligible for back/forward cache in a future version of Chrome.',
|
101
|
+
/**
|
102
|
+
* @description Text that precedes displaying a link to the extension which blocked the page from being eligible for back/forward cache.
|
103
|
+
*/
|
104
|
+
blockingExtensionId: 'Extension id: ',
|
100
105
|
};
|
101
106
|
const str_ = i18n.i18n.registerUIStrings('panels/application/components/BackForwardCacheView.ts', UIStrings);
|
102
107
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
@@ -370,6 +375,20 @@ export class BackForwardCacheView extends HTMLElement {
|
|
370
375
|
// clang-format on
|
371
376
|
}
|
372
377
|
|
378
|
+
#maybeRenderReasonContext(explanation: Protocol.Page.BackForwardCacheNotRestoredExplanation): LitHtml.TemplateResult|
|
379
|
+
{} {
|
380
|
+
if (explanation.reason ===
|
381
|
+
Protocol.Page.BackForwardCacheNotRestoredReason.EmbedderExtensionSentMessageToCachedFrame &&
|
382
|
+
explanation.context) {
|
383
|
+
const link = 'chrome://extensions/?id=' + explanation.context;
|
384
|
+
// clang-format off
|
385
|
+
return LitHtml.html`${i18nString(UIStrings.blockingExtensionId)}
|
386
|
+
<${ChromeLink.ChromeLink.ChromeLink.litTagName} .href=${link}>${explanation.context}</${ChromeLink.ChromeLink.ChromeLink.litTagName}>`;
|
387
|
+
// clang-format on
|
388
|
+
}
|
389
|
+
return LitHtml.nothing;
|
390
|
+
}
|
391
|
+
|
373
392
|
#renderReason(explanation: Protocol.Page.BackForwardCacheNotRestoredExplanation): LitHtml.TemplateResult {
|
374
393
|
// clang-format off
|
375
394
|
return LitHtml.html`
|
@@ -385,7 +404,10 @@ export class BackForwardCacheView extends HTMLElement {
|
|
385
404
|
} as IconButton.Icon.IconData}>
|
386
405
|
</${IconButton.Icon.Icon.litTagName}>
|
387
406
|
</div>
|
388
|
-
|
407
|
+
<div>
|
408
|
+
${NotRestoredReasonDescription[explanation.reason].name()}
|
409
|
+
${this.#maybeRenderReasonContext(explanation)}
|
410
|
+
</div>` :
|
389
411
|
LitHtml.nothing}
|
390
412
|
</${ReportView.ReportView.ReportSection.litTagName}>
|
391
413
|
<div class='gray-text'>
|
@@ -8,6 +8,58 @@
|
|
8
8
|
flex-grow: 1;
|
9
9
|
}
|
10
10
|
|
11
|
+
.row {
|
12
|
+
display: flex;
|
13
|
+
flex-direction: row;
|
14
|
+
color: var(--color-syntax-1);
|
15
|
+
font-family: var(--monospace-font-family);
|
16
|
+
font-size: var(--monospace-font-size);
|
17
|
+
align-items: center;
|
18
|
+
line-height: 18px;
|
19
|
+
margin: 2em 0 0 0.5em;
|
20
|
+
}
|
21
|
+
|
22
|
+
.row:first-child {
|
23
|
+
margin-top: 0.5em;
|
24
|
+
}
|
25
|
+
|
26
|
+
.row devtools-button {
|
27
|
+
line-height: 1;
|
28
|
+
margin-left: 0.5em;
|
29
|
+
}
|
30
|
+
|
31
|
+
.padded {
|
32
|
+
margin: 0.25em 0 0 2em;
|
33
|
+
}
|
34
|
+
|
35
|
+
.separator {
|
36
|
+
margin-right: 0.5em;
|
37
|
+
color: var(--color-text-primary);
|
38
|
+
}
|
39
|
+
|
40
|
+
.editable {
|
41
|
+
cursor: text;
|
42
|
+
color: var(--color-text-primary);
|
43
|
+
overflow-wrap: anywhere;
|
44
|
+
min-height: 18px;
|
45
|
+
line-height: 18px;
|
46
|
+
min-width: 0.5em;
|
47
|
+
background: transparent;
|
48
|
+
border: none;
|
49
|
+
outline: none;
|
50
|
+
display: inline-block;
|
51
|
+
}
|
52
|
+
|
53
|
+
.editable.red {
|
54
|
+
color: var(--color-syntax-1);
|
55
|
+
}
|
56
|
+
|
57
|
+
.editable:hover,
|
58
|
+
.editable:focus {
|
59
|
+
box-shadow: 0 0 0 1px var(--color-details-hairline);
|
60
|
+
border-radius: 2px;
|
61
|
+
}
|
62
|
+
|
11
63
|
.center-wrapper {
|
12
64
|
height: 100%;
|
13
65
|
display: flex;
|
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
import * as i18n from '../../../core/i18n/i18n.js';
|
6
6
|
import * as Persistence from '../../../models/persistence/persistence.js';
|
7
|
-
import
|
7
|
+
import * as Workspace from '../../../models/workspace/workspace.js';
|
8
8
|
import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
|
9
9
|
import * as UI from '../../../ui/legacy/legacy.js';
|
10
10
|
import * as LitHtml from '../../../ui/lit-html/lit-html.js';
|
@@ -34,9 +34,52 @@ export class HeadersView extends UI.View.SimpleView {
|
|
34
34
|
constructor(uiSourceCode: Workspace.UISourceCode.UISourceCode) {
|
35
35
|
super('HeadersView');
|
36
36
|
this.#uiSourceCode = uiSourceCode;
|
37
|
+
this.#uiSourceCode.addEventListener(
|
38
|
+
Workspace.UISourceCode.Events.WorkingCopyChanged, this.#onWorkingCopyChanged, this);
|
39
|
+
this.#uiSourceCode.addEventListener(
|
40
|
+
Workspace.UISourceCode.Events.WorkingCopyCommitted, this.#onWorkingCopyCommitted, this);
|
37
41
|
this.element.appendChild(this.#headersViewComponent);
|
42
|
+
void this.#setInitialData();
|
43
|
+
}
|
44
|
+
|
45
|
+
async #setInitialData(): Promise<void> {
|
46
|
+
const content = await this.#uiSourceCode.requestContent();
|
47
|
+
this.#setComponentData(content.content || '');
|
48
|
+
}
|
49
|
+
|
50
|
+
#setComponentData(content: string): void {
|
51
|
+
let parsingError = false;
|
52
|
+
let headerOverrides: Persistence.NetworkPersistenceManager.HeaderOverride[] = [];
|
53
|
+
content = content || '[]';
|
54
|
+
try {
|
55
|
+
headerOverrides = JSON.parse(content) as Persistence.NetworkPersistenceManager.HeaderOverride[];
|
56
|
+
if (!headerOverrides.every(Persistence.NetworkPersistenceManager.isHeaderOverride)) {
|
57
|
+
throw 'Type mismatch after parsing';
|
58
|
+
}
|
59
|
+
} catch (e) {
|
60
|
+
console.error('Failed to parse', this.#uiSourceCode.url(), 'for locally overriding headers.');
|
61
|
+
parsingError = true;
|
62
|
+
}
|
63
|
+
|
64
|
+
// Header overrides are stored as the key-value pairs of a JSON object on
|
65
|
+
// disk. For the editor we want them as an array instead, so that we can
|
66
|
+
// access/add/remove entries by their index.
|
67
|
+
const arrayOfHeaderOverrideArrays: HeaderOverride[] = headerOverrides.map(headerOverride => {
|
68
|
+
return {
|
69
|
+
applyTo: headerOverride.applyTo,
|
70
|
+
headers: Object.entries(headerOverride.headers).map(([headerName, headerValue]) => {
|
71
|
+
return {
|
72
|
+
name: headerName,
|
73
|
+
value: headerValue,
|
74
|
+
};
|
75
|
+
}),
|
76
|
+
};
|
77
|
+
});
|
78
|
+
|
38
79
|
this.#headersViewComponent.data = {
|
80
|
+
headerOverrides: arrayOfHeaderOverrideArrays,
|
39
81
|
uiSourceCode: this.#uiSourceCode,
|
82
|
+
parsingError,
|
40
83
|
};
|
41
84
|
}
|
42
85
|
|
@@ -44,39 +87,207 @@ export class HeadersView extends UI.View.SimpleView {
|
|
44
87
|
this.#uiSourceCode.commitWorkingCopy();
|
45
88
|
Persistence.NetworkPersistenceManager.NetworkPersistenceManager.instance().updateInterceptionPatterns();
|
46
89
|
}
|
90
|
+
|
91
|
+
#onWorkingCopyChanged(): void {
|
92
|
+
this.#setComponentData(this.#uiSourceCode.workingCopy());
|
93
|
+
}
|
94
|
+
|
95
|
+
#onWorkingCopyCommitted(): void {
|
96
|
+
this.#setComponentData(this.#uiSourceCode.workingCopy());
|
97
|
+
}
|
98
|
+
|
99
|
+
dispose(): void {
|
100
|
+
this.#uiSourceCode.removeEventListener(
|
101
|
+
Workspace.UISourceCode.Events.WorkingCopyChanged, this.#onWorkingCopyChanged, this);
|
102
|
+
this.#uiSourceCode.removeEventListener(
|
103
|
+
Workspace.UISourceCode.Events.WorkingCopyCommitted, this.#onWorkingCopyCommitted, this);
|
104
|
+
}
|
47
105
|
}
|
48
106
|
|
107
|
+
type Header = {
|
108
|
+
name: string,
|
109
|
+
value: string,
|
110
|
+
};
|
111
|
+
|
112
|
+
type HeaderOverride = {
|
113
|
+
applyTo: string,
|
114
|
+
headers: Header[],
|
115
|
+
};
|
116
|
+
|
49
117
|
export interface HeadersViewComponentData {
|
118
|
+
headerOverrides: HeaderOverride[];
|
50
119
|
uiSourceCode: Workspace.UISourceCode.UISourceCode;
|
120
|
+
parsingError: boolean;
|
51
121
|
}
|
52
122
|
|
53
123
|
export class HeadersViewComponent extends HTMLElement {
|
54
124
|
static readonly litTagName = LitHtml.literal`devtools-sources-headers-view`;
|
55
125
|
readonly #shadow = this.attachShadow({mode: 'open'});
|
126
|
+
readonly #boundRender = this.#render.bind(this);
|
127
|
+
#headerOverrides: HeaderOverride[] = [];
|
56
128
|
#uiSourceCode: Workspace.UISourceCode.UISourceCode|null = null;
|
129
|
+
#parsingError = false;
|
130
|
+
|
131
|
+
constructor() {
|
132
|
+
super();
|
133
|
+
this.#shadow.addEventListener('focusin', this.#onFocusIn.bind(this));
|
134
|
+
this.#shadow.addEventListener('focusout', this.#onFocusOut.bind(this));
|
135
|
+
this.#shadow.addEventListener('input', this.#onInput.bind(this));
|
136
|
+
this.#shadow.addEventListener('keydown', this.#onKeyDown.bind(this));
|
137
|
+
}
|
57
138
|
|
58
139
|
connectedCallback(): void {
|
59
140
|
this.#shadow.adoptedStyleSheets = [HeadersViewStyles];
|
60
141
|
}
|
61
142
|
|
62
143
|
set data(data: HeadersViewComponentData) {
|
144
|
+
this.#headerOverrides = data.headerOverrides;
|
63
145
|
this.#uiSourceCode = data.uiSourceCode;
|
64
|
-
this.#
|
146
|
+
this.#parsingError = data.parsingError;
|
147
|
+
void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#boundRender);
|
148
|
+
}
|
149
|
+
|
150
|
+
// 'Enter' key should not create a new line in the contenteditable. Focus
|
151
|
+
// on the next contenteditable instead.
|
152
|
+
#onKeyDown(event: Event): void {
|
153
|
+
const keyboardEvent = event as KeyboardEvent;
|
154
|
+
const target = event.target as HTMLElement;
|
155
|
+
if (target.matches('.editable') && keyboardEvent.key === 'Enter') {
|
156
|
+
event.preventDefault();
|
157
|
+
this.#focusNext(target);
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
#focusNext(target: HTMLElement): void {
|
162
|
+
const elements = Array.from(this.#shadow.querySelectorAll('.editable')) as HTMLElement[];
|
163
|
+
const idx = elements.indexOf(target);
|
164
|
+
if (idx !== -1 && idx + 1 < elements.length) {
|
165
|
+
elements[idx + 1].focus();
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
#selectAllText(target: HTMLElement): void {
|
170
|
+
const selection = window.getSelection();
|
171
|
+
const range = document.createRange();
|
172
|
+
range.selectNodeContents(target);
|
173
|
+
selection?.removeAllRanges();
|
174
|
+
selection?.addRange(range);
|
175
|
+
}
|
176
|
+
|
177
|
+
#onFocusIn(e: Event): void {
|
178
|
+
const target = e.target as HTMLElement;
|
179
|
+
if (target.matches('.editable')) {
|
180
|
+
this.#selectAllText(target);
|
181
|
+
}
|
182
|
+
}
|
183
|
+
|
184
|
+
#onFocusOut(): void {
|
185
|
+
// clear selection
|
186
|
+
const selection = window.getSelection();
|
187
|
+
selection?.removeAllRanges();
|
188
|
+
}
|
189
|
+
|
190
|
+
#onInput(e: Event): void {
|
191
|
+
const target = e.target as HTMLButtonElement;
|
192
|
+
const rowElement = target.closest('.row') as HTMLElement;
|
193
|
+
const blockIndex = Number(rowElement.dataset.blockIndex);
|
194
|
+
const headerIndex = Number(rowElement.dataset.headerIndex);
|
195
|
+
if (target.matches('.header-name')) {
|
196
|
+
this.#headerOverrides[blockIndex].headers[headerIndex].name = target.innerText;
|
197
|
+
this.#onHeadersChanged();
|
198
|
+
}
|
199
|
+
if (target.matches('.header-value')) {
|
200
|
+
this.#headerOverrides[blockIndex].headers[headerIndex].value = target.innerText;
|
201
|
+
this.#onHeadersChanged();
|
202
|
+
}
|
203
|
+
if (target.matches('.apply-to')) {
|
204
|
+
this.#headerOverrides[blockIndex].applyTo = target.innerText;
|
205
|
+
this.#onHeadersChanged();
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
#onHeadersChanged(): void {
|
210
|
+
// In the editor header overrides are represented by items in an array, so
|
211
|
+
// that we can access/add/remove entries by their index. On disk, they are
|
212
|
+
// stored as key-value pairs of a JSON object instead.
|
213
|
+
const arrayOfHeaderOverrideObjects: Persistence.NetworkPersistenceManager.HeaderOverride[] =
|
214
|
+
this.#headerOverrides.map(headerOverride => {
|
215
|
+
return {
|
216
|
+
applyTo: headerOverride.applyTo,
|
217
|
+
headers: headerOverride.headers.reduce((a, v) => ({...a, [v.name]: v.value}), {}),
|
218
|
+
};
|
219
|
+
});
|
220
|
+
this.#uiSourceCode?.setWorkingCopy(JSON.stringify(arrayOfHeaderOverrideObjects, null, 2));
|
65
221
|
}
|
66
222
|
|
67
223
|
#render(): void {
|
68
|
-
|
224
|
+
if (!ComponentHelpers.ScheduledRender.isScheduledRender(this)) {
|
225
|
+
throw new Error('HeadersView render was not scheduled');
|
226
|
+
}
|
227
|
+
|
228
|
+
if (this.#parsingError) {
|
229
|
+
const fileName = this.#uiSourceCode?.name() || '.headers';
|
230
|
+
// clang-format off
|
231
|
+
LitHtml.render(LitHtml.html`
|
232
|
+
<div class="center-wrapper">
|
233
|
+
<div class="centered">
|
234
|
+
<div class="error-header">${i18nString(UIStrings.errorWhenParsing, {PH1: fileName})}</div>
|
235
|
+
<div class="error-body">${i18nString(UIStrings.parsingErrorExplainer, {PH1: fileName})}</div>
|
236
|
+
</div>
|
237
|
+
</div>
|
238
|
+
`, this.#shadow, {host: this});
|
239
|
+
// clang-format on
|
240
|
+
return;
|
241
|
+
}
|
242
|
+
|
69
243
|
// clang-format off
|
70
244
|
LitHtml.render(LitHtml.html`
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
245
|
+
${this.#headerOverrides.map((headerOverride, blockIndex) =>
|
246
|
+
LitHtml.html`
|
247
|
+
${this.#renderApplyToRow(headerOverride.applyTo, blockIndex)}
|
248
|
+
${headerOverride.headers.map((header, headerIndex) =>
|
249
|
+
LitHtml.html`
|
250
|
+
${this.#renderHeaderRow(header, blockIndex, headerIndex)}
|
251
|
+
`,
|
252
|
+
)}
|
253
|
+
`,
|
254
|
+
)}
|
77
255
|
`, this.#shadow, {host: this});
|
78
256
|
// clang-format on
|
79
257
|
}
|
258
|
+
|
259
|
+
#renderApplyToRow(pattern: string, blockIndex: number): LitHtml.TemplateResult {
|
260
|
+
// clang-format off
|
261
|
+
return LitHtml.html`
|
262
|
+
<div class="row" data-block-index=${blockIndex}>
|
263
|
+
<div>${i18n.i18n.lockedString('Apply to')}</div>
|
264
|
+
<div class="separator">:</div>
|
265
|
+
${this.#renderEditable(pattern, 'apply-to')}
|
266
|
+
</div>
|
267
|
+
`;
|
268
|
+
// clang-format on
|
269
|
+
}
|
270
|
+
|
271
|
+
#renderHeaderRow(header: Header, blockIndex: number, headerIndex: number): LitHtml.TemplateResult {
|
272
|
+
// clang-format off
|
273
|
+
return LitHtml.html`
|
274
|
+
<div class="row padded" data-block-index=${blockIndex} data-header-index=${headerIndex}>
|
275
|
+
${this.#renderEditable(header.name, 'header-name red')}
|
276
|
+
<div class="separator">:</div>
|
277
|
+
${this.#renderEditable(header.value, 'header-value')}
|
278
|
+
`;
|
279
|
+
// clang-format on
|
280
|
+
}
|
281
|
+
|
282
|
+
#renderEditable(value: string, className?: string): LitHtml.TemplateResult {
|
283
|
+
// This uses LitHtml's `live`-directive, so that when checking whether to
|
284
|
+
// update during re-render, `value` is compared against the actual live DOM
|
285
|
+
// value of the contenteditable element and not the potentially outdated
|
286
|
+
// value from the previous render.
|
287
|
+
// clang-format off
|
288
|
+
return LitHtml.html`<span contenteditable="true" class="editable ${className}" tabindex="0" .innerText=${LitHtml.Directives.live(value)}></span>`;
|
289
|
+
// clang-format on
|
290
|
+
}
|
80
291
|
}
|
81
292
|
|
82
293
|
ComponentHelpers.CustomElements.defineComponent('devtools-sources-headers-view', HeadersViewComponent);
|
@@ -80,18 +80,31 @@ export class TimelineController implements SDK.TargetManager.SDKModelObserver<SD
|
|
80
80
|
function disabledByDefault(category: string): string {
|
81
81
|
return 'disabled-by-default-' + category;
|
82
82
|
}
|
83
|
+
|
84
|
+
// The following categories are also used in other tools, but this panel
|
85
|
+
// offers the possibility of turning them off (see below).
|
86
|
+
// 'disabled-by-default-devtools.screenshot'
|
87
|
+
// └ default: on, option: captureFilmStrip
|
88
|
+
// 'disabled-by-default-devtools.timeline.invalidationTracking'
|
89
|
+
// └ default: off, experiment: timelineInvalidationTracking
|
90
|
+
// 'disabled-by-default-v8.cpu_profiler'
|
91
|
+
// └ default: on, option: enableJSSampling
|
83
92
|
const categoriesArray = [
|
84
93
|
'-*',
|
94
|
+
TimelineModel.TimelineModel.TimelineModelImpl.Category.Console,
|
95
|
+
TimelineModel.TimelineModel.TimelineModelImpl.Category.UserTiming,
|
85
96
|
'devtools.timeline',
|
86
97
|
disabledByDefault('devtools.timeline'),
|
87
98
|
disabledByDefault('devtools.timeline.frame'),
|
88
|
-
'
|
99
|
+
disabledByDefault('devtools.timeline.stack'),
|
89
100
|
disabledByDefault('v8.compile'),
|
90
|
-
|
91
|
-
TimelineModel.TimelineModel.TimelineModelImpl.Category.
|
101
|
+
disabledByDefault('v8.cpu_profiler.hires'),
|
102
|
+
TimelineModel.TimelineModel.TimelineModelImpl.Category.LatencyInfo,
|
92
103
|
TimelineModel.TimelineModel.TimelineModelImpl.Category.Loading,
|
104
|
+
disabledByDefault('lighthouse'),
|
105
|
+
'v8.execute',
|
106
|
+
'v8',
|
93
107
|
];
|
94
|
-
categoriesArray.push(TimelineModel.TimelineModel.TimelineModelImpl.Category.LatencyInfo);
|
95
108
|
|
96
109
|
if (Root.Runtime.experiments.isEnabled('timelineV8RuntimeCallStats') && options.enableJSSampling) {
|
97
110
|
categoriesArray.push(disabledByDefault('v8.runtime_stats_sampling'));
|
@@ -99,7 +112,6 @@ export class TimelineController implements SDK.TargetManager.SDKModelObserver<SD
|
|
99
112
|
if (!Root.Runtime.Runtime.queryParam('timelineTracingJSProfileDisabled') && options.enableJSSampling) {
|
100
113
|
categoriesArray.push(disabledByDefault('v8.cpu_profiler'));
|
101
114
|
}
|
102
|
-
categoriesArray.push(disabledByDefault('devtools.timeline.stack'));
|
103
115
|
if (Root.Runtime.experiments.isEnabled('timelineInvalidationTracking')) {
|
104
116
|
categoriesArray.push(disabledByDefault('devtools.timeline.invalidationTracking'));
|
105
117
|
}
|
@@ -4,6 +4,10 @@
|
|
4
4
|
* found in the LICENSE file.
|
5
5
|
*/
|
6
6
|
|
7
|
+
:host {
|
8
|
+
overflow: hidden;
|
9
|
+
}
|
10
|
+
|
7
11
|
div {
|
8
12
|
line-height: 1.7em;
|
9
13
|
}
|
@@ -53,3 +57,9 @@ button.link {
|
|
53
57
|
font-family: inherit;
|
54
58
|
font-size: inherit;
|
55
59
|
}
|
60
|
+
|
61
|
+
.text-ellipsis {
|
62
|
+
overflow: hidden;
|
63
|
+
text-overflow: ellipsis;
|
64
|
+
white-space: nowrap;
|
65
|
+
}
|