chrome-devtools-frontend 1.0.1643855 → 1.0.1645245
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/front_end/core/host/UserMetrics.ts +3 -2
- package/front_end/core/sdk/CSSPropertyParserMatchers.ts +2 -3
- package/front_end/core/sdk/NetworkRequest.ts +0 -1
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +37 -0
- package/front_end/generated/SupportedCSSProperties.js +4 -2
- package/front_end/models/ai_assistance/AiAgent2.ts +23 -13
- package/front_end/models/ai_assistance/README.md +5 -4
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +15 -0
- package/front_end/models/ai_assistance/agents/README.md +57 -0
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +26 -3
- package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +9 -12
- package/front_end/models/ai_assistance/tools/GetStyles.ts +19 -12
- package/front_end/models/ai_assistance/tools/README.md +45 -0
- package/front_end/models/ai_assistance/tools/Tool.ts +74 -11
- package/front_end/models/ai_assistance/tools/ToolRegistry.ts +21 -5
- package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +18 -2
- package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +4 -0
- package/front_end/models/stack_trace/DetailedErrorStackParser.ts +17 -4
- package/front_end/models/stack_trace/StackTraceModel.ts +34 -1
- package/front_end/models/trace/Styles.ts +29 -7
- package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +33 -4
- package/front_end/models/trace/helpers/Timing.ts +10 -0
- package/front_end/models/trace/types/TraceEvents.ts +22 -2
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +8 -2
- package/front_end/panels/ai_assistance/ai_assistance-meta.ts +16 -0
- package/front_end/panels/application/ApplicationPanelSidebar.ts +44 -0
- package/front_end/panels/application/ServiceWorkersView.ts +2 -2
- package/front_end/panels/application/WebMCPView.ts +0 -1
- package/front_end/panels/application/components/BackForwardCacheView.ts +1 -2
- package/front_end/panels/console/ConsoleView.ts +6 -1
- package/front_end/panels/console/ConsoleViewMessage.ts +46 -213
- package/front_end/panels/console/SymbolizedErrorWidget.ts +4 -1
- package/front_end/panels/elements/AdoptedStyleSheetTreeElement.ts +0 -1
- package/front_end/panels/elements/ElementsTreeElement.ts +0 -2
- package/front_end/panels/elements/PropertyRenderer.ts +0 -1
- package/front_end/panels/elements/StylesSidebarPane.ts +9 -2
- package/front_end/panels/issues/AffectedResourcesView.ts +1 -1
- package/front_end/panels/issues/AffectedSourcesView.ts +1 -1
- package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +0 -1
- package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +10 -0
- package/front_end/panels/network/NetworkDataGridNode.ts +1 -2
- package/front_end/panels/network/NetworkLogView.ts +34 -7
- package/front_end/panels/profiler/HeapProfileView.ts +0 -1
- package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +0 -1
- package/front_end/panels/profiler/HeapSnapshotView.ts +1 -1
- package/front_end/panels/settings/components/SyncSection.ts +1 -1
- package/front_end/panels/timeline/TimelineFlameChartView.ts +5 -4
- package/front_end/panels/timeline/TimelinePanel.ts +7 -0
- package/front_end/panels/timeline/TimelineUIUtils.ts +13 -14
- package/front_end/panels/timeline/TimingsTrackAppender.ts +7 -5
- package/front_end/panels/timeline/components/LayoutShiftDetails.ts +0 -1
- package/front_end/panels/timeline/components/NetworkRequestDetails.ts +0 -2
- package/front_end/panels/timeline/components/insights/ForcedReflow.ts +0 -1
- package/front_end/panels/timeline/components/insights/NodeLink.ts +0 -1
- package/front_end/panels/timeline/overlays/OverlaysImpl.ts +2 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/helpers/OpenInNewTab.ts +3 -3
- package/front_end/ui/kit/link/Link.ts +16 -2
- package/front_end/ui/legacy/InspectorDrawerView.ts +14 -5
- package/front_end/ui/legacy/InspectorView.ts +4 -1
- package/front_end/ui/legacy/PlusButton.ts +6 -1
- package/front_end/ui/legacy/Widget.ts +19 -1
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +95 -31
- package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +0 -1
- package/front_end/ui/legacy/components/utils/Linkifier.ts +2 -16
- package/front_end/ui/visual_logging/KnownContextValues.ts +5 -0
- package/package.json +1 -1
|
@@ -505,6 +505,11 @@ const UIStrings = {
|
|
|
505
505
|
* @description Context menu item in Network panel to assess security headers of a request via AI.
|
|
506
506
|
*/
|
|
507
507
|
assessSecurityHeaders: 'Assess security headers',
|
|
508
|
+
/**
|
|
509
|
+
* @description A comment in a generated command indicating that the URL scheme is unsupported. The placeholder is the comment prefix (e.g. '//' or '#').
|
|
510
|
+
* @example {//} PH1
|
|
511
|
+
*/
|
|
512
|
+
unsupportedUrlScheme: '{PH1} Unsupported URL scheme',
|
|
508
513
|
} as const;
|
|
509
514
|
const str_ = i18n.i18n.registerUIStrings('panels/network/NetworkLogView.ts', UIStrings);
|
|
510
515
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
@@ -557,6 +562,8 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
|
|
|
557
562
|
private readonly textFilterSetting: Common.Settings.Setting<string>;
|
|
558
563
|
private networkRequestToNode: WeakMap<SDK.NetworkRequest.NetworkRequest, NetworkRequestNode>;
|
|
559
564
|
|
|
565
|
+
static #allowedSchemes = new Set(['http:', 'https:', 'ws:', 'wss:', 'data:']);
|
|
566
|
+
|
|
560
567
|
constructor(
|
|
561
568
|
filterBar: UI.FilterBar.FilterBar, progressBarContainer: Element,
|
|
562
569
|
networkLogLargeRowsSetting: Common.Settings.Setting<boolean>) {
|
|
@@ -2319,6 +2326,18 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
|
|
|
2319
2326
|
return requests.filter(request => !request.isBlobRequest());
|
|
2320
2327
|
}
|
|
2321
2328
|
|
|
2329
|
+
static #getValidClipboardUrl(url: string): Platform.DevToolsPath.UrlString|null {
|
|
2330
|
+
try {
|
|
2331
|
+
const parsedUrl = new URL(url);
|
|
2332
|
+
if (!NetworkLogView.#allowedSchemes.has(parsedUrl.protocol)) {
|
|
2333
|
+
return null;
|
|
2334
|
+
}
|
|
2335
|
+
return url as Platform.DevToolsPath.UrlString;
|
|
2336
|
+
} catch {
|
|
2337
|
+
return null;
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2322
2341
|
private async generateFetchCall(request: SDK.NetworkRequest.NetworkRequest, style: FetchStyle): Promise<string> {
|
|
2323
2342
|
const ignoredHeaders = new Set<string>([
|
|
2324
2343
|
// Internal headers
|
|
@@ -2355,7 +2374,11 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
|
|
|
2355
2374
|
|
|
2356
2375
|
const credentialHeaders = new Set<string>(['cookie', 'authorization']);
|
|
2357
2376
|
|
|
2358
|
-
const
|
|
2377
|
+
const validUrl = NetworkLogView.#getValidClipboardUrl(request.url());
|
|
2378
|
+
if (!validUrl) {
|
|
2379
|
+
return i18nString(UIStrings.unsupportedUrlScheme, {PH1: '//'});
|
|
2380
|
+
}
|
|
2381
|
+
const url = JSON.stringify(validUrl);
|
|
2359
2382
|
|
|
2360
2383
|
const requestHeaders = request.requestHeaders();
|
|
2361
2384
|
const headerData: Headers = requestHeaders.reduce((result, header) => {
|
|
@@ -2507,11 +2530,11 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
|
|
|
2507
2530
|
// (it may be different from the inspected page platform).
|
|
2508
2531
|
const escapeString = platform === 'win' ? escapeStringWin : escapeStringPosix;
|
|
2509
2532
|
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
command.push('--url ' + escapeString(
|
|
2533
|
+
const validUrl = NetworkLogView.#getValidClipboardUrl(request.url());
|
|
2534
|
+
if (!validUrl) {
|
|
2535
|
+
return i18nString(UIStrings.unsupportedUrlScheme, {PH1: '#'});
|
|
2536
|
+
}
|
|
2537
|
+
command.push('--url ' + escapeString(validUrl).replace(/[[{}\]]/g, '\\$&'));
|
|
2515
2538
|
|
|
2516
2539
|
let inferredMethod = 'GET';
|
|
2517
2540
|
const data = [];
|
|
@@ -2617,7 +2640,11 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
|
|
|
2617
2640
|
return null;
|
|
2618
2641
|
}
|
|
2619
2642
|
|
|
2620
|
-
|
|
2643
|
+
const validUrl = NetworkLogView.#getValidClipboardUrl(request.url());
|
|
2644
|
+
if (!validUrl) {
|
|
2645
|
+
return i18nString(UIStrings.unsupportedUrlScheme, {PH1: '#'});
|
|
2646
|
+
}
|
|
2647
|
+
command.push('-Uri ' + escapeString(validUrl));
|
|
2621
2648
|
|
|
2622
2649
|
if (request.requestMethod !== 'GET') {
|
|
2623
2650
|
command.push('-Method ' + escapeString(request.requestMethod));
|
|
@@ -628,7 +628,6 @@ export class NodeFormatter implements Formatter {
|
|
|
628
628
|
const target = heapProfilerModel ? heapProfilerModel.target() : null;
|
|
629
629
|
const options = {
|
|
630
630
|
className: 'profile-node-file',
|
|
631
|
-
inlineFrameIndex: 0,
|
|
632
631
|
};
|
|
633
632
|
return this.profileView.linkifier().maybeLinkifyConsoleCallFrame(target, node.profileNode.callFrame, options);
|
|
634
633
|
}
|
|
@@ -1467,7 +1467,6 @@ export class AllocationGridNode extends HeapSnapshotGridNode {
|
|
|
1467
1467
|
String(allocationNode.scriptId) as Protocol.Runtime.ScriptId,
|
|
1468
1468
|
allocationNode.scriptName as Platform.DevToolsPath.UrlString, allocationNode.line - 1, {
|
|
1469
1469
|
columnNumber: allocationNode.column - 1,
|
|
1470
|
-
inlineFrameIndex: 0,
|
|
1471
1470
|
className: 'profile-node-file',
|
|
1472
1471
|
});
|
|
1473
1472
|
urlElement.style.maxWidth = '75%';
|
|
@@ -1949,7 +1949,7 @@ export class HeapAllocationStackView extends UI.Widget.Widget {
|
|
|
1949
1949
|
continue;
|
|
1950
1950
|
}
|
|
1951
1951
|
const target = this.heapProfilerModel ? this.heapProfilerModel.target() : null;
|
|
1952
|
-
const options = {columnNumber: frame.column - 1
|
|
1952
|
+
const options = {columnNumber: frame.column - 1};
|
|
1953
1953
|
const urlElement = this.linkifier.linkifyScriptLocation(
|
|
1954
1954
|
target, String(frame.scriptId) as Protocol.Runtime.ScriptId,
|
|
1955
1955
|
frame.scriptName as Platform.DevToolsPath.UrlString, frame.line - 1, options);
|
|
@@ -346,7 +346,7 @@ export class SyncSection extends UI.Widget.Widget {
|
|
|
346
346
|
// TODO: investigate if /advance link is alive
|
|
347
347
|
const warningLink =
|
|
348
348
|
this.#syncInfo.isSyncActive ? 'chrome://settings/syncSetup/advanced' : 'chrome://settings/syncSetup';
|
|
349
|
-
UIHelpers.openInNewTab(warningLink);
|
|
349
|
+
UIHelpers.openInNewTab(warningLink, /* allowPrivileged=*/ true);
|
|
350
350
|
event.consume();
|
|
351
351
|
}
|
|
352
352
|
|
|
@@ -69,9 +69,10 @@ export const SORT_ORDER_PAGE_LOAD_MARKERS: Readonly<Record<string, number>> = {
|
|
|
69
69
|
[Trace.Types.Events.Name.SOFT_NAVIGATION_START]: 1,
|
|
70
70
|
[Trace.Types.Events.Name.MARK_LOAD]: 2,
|
|
71
71
|
[Trace.Types.Events.Name.MARK_FCP]: 3,
|
|
72
|
-
[Trace.Types.Events.Name.
|
|
73
|
-
[Trace.Types.Events.Name.
|
|
74
|
-
[Trace.Types.Events.Name.
|
|
72
|
+
[Trace.Types.Events.Name.MARK_SOFT_FCP]: 4,
|
|
73
|
+
[Trace.Types.Events.Name.MARK_DOM_CONTENT]: 5,
|
|
74
|
+
[Trace.Types.Events.Name.MARK_LCP_CANDIDATE]: 6,
|
|
75
|
+
[Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION]: 7,
|
|
75
76
|
};
|
|
76
77
|
|
|
77
78
|
// Threshold to match up overlay markers that are off by a tiny amount so they aren't rendered
|
|
@@ -676,7 +677,7 @@ export class TimelineFlameChartView extends Common.ObjectWrapper.eventMixin<Even
|
|
|
676
677
|
event.name === Trace.Types.Events.Name.SOFT_NAVIGATION_START ||
|
|
677
678
|
event.name === Trace.Types.Events.Name.MARK_LCP_CANDIDATE ||
|
|
678
679
|
event.name === Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION ||
|
|
679
|
-
event.name === Trace.Types.Events.Name.MARK_FCP ||
|
|
680
|
+
event.name === Trace.Types.Events.Name.MARK_FCP || event.name === Trace.Types.Events.Name.MARK_SOFT_FCP ||
|
|
680
681
|
event.name === Trace.Types.Events.Name.MARK_DOM_CONTENT ||
|
|
681
682
|
event.name === Trace.Types.Events.Name.MARK_LOAD);
|
|
682
683
|
|
|
@@ -2435,6 +2435,13 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
2435
2435
|
async loadingStarted(): Promise<void> {
|
|
2436
2436
|
this.#changeView({mode: 'STATUS_PANE_OVERLAY'});
|
|
2437
2437
|
|
|
2438
|
+
// If recording was stopped automatically (e.g. page reload or AI-triggered trace),
|
|
2439
|
+
// we must transition to STOP_PENDING so that loadingComplete() knows the resulting
|
|
2440
|
+
// trace is a fresh recording.
|
|
2441
|
+
if (this.state === State.RECORDING) {
|
|
2442
|
+
this.setState(State.STOP_PENDING);
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2438
2445
|
if (this.statusDialog) {
|
|
2439
2446
|
this.statusDialog.remove();
|
|
2440
2447
|
}
|
|
@@ -668,7 +668,6 @@ export class TimelineUIUtils {
|
|
|
668
668
|
const options = {
|
|
669
669
|
tabStop: true,
|
|
670
670
|
showColumnNumber: false,
|
|
671
|
-
inlineFrameIndex: 0,
|
|
672
671
|
};
|
|
673
672
|
details = LegacyComponents.Linkifier.Linkifier.linkifyURL(url, options);
|
|
674
673
|
}
|
|
@@ -763,7 +762,6 @@ export class TimelineUIUtils {
|
|
|
763
762
|
lineNumber,
|
|
764
763
|
columnNumber,
|
|
765
764
|
showColumnNumber: true,
|
|
766
|
-
inlineFrameIndex: 0,
|
|
767
765
|
className: 'timeline-details',
|
|
768
766
|
tabStop: true,
|
|
769
767
|
omitOrigin,
|
|
@@ -788,14 +786,13 @@ export class TimelineUIUtils {
|
|
|
788
786
|
const options = {
|
|
789
787
|
className: 'timeline-details',
|
|
790
788
|
tabStop: true,
|
|
791
|
-
inlineFrameIndex: 0,
|
|
792
789
|
showColumnNumber: true,
|
|
793
790
|
columnNumber: frame.columnNumber,
|
|
794
791
|
lineNumber: frame.lineNumber,
|
|
795
792
|
maxLength,
|
|
796
793
|
};
|
|
797
794
|
if (isFreshOrEnhanced) {
|
|
798
|
-
return linkifier.maybeLinkifyConsoleCallFrame(target, frame, {showColumnNumber: true
|
|
795
|
+
return linkifier.maybeLinkifyConsoleCallFrame(target, frame, {showColumnNumber: true});
|
|
799
796
|
}
|
|
800
797
|
return LegacyComponents.Linkifier.Linkifier.linkifyURL(frame.url as Platform.DevToolsPath.UrlString, options);
|
|
801
798
|
}
|
|
@@ -809,17 +806,21 @@ export class TimelineUIUtils {
|
|
|
809
806
|
name = 'Largest Contentful Paint';
|
|
810
807
|
break;
|
|
811
808
|
case Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION:
|
|
812
|
-
link = 'https://developer.chrome.com/docs/web-platform/soft-navigations
|
|
809
|
+
link = 'https://developer.chrome.com/docs/web-platform/soft-navigations';
|
|
813
810
|
name = 'Soft Largest Contentful Paint';
|
|
814
811
|
break;
|
|
815
812
|
case Trace.Types.Events.Name.SOFT_NAVIGATION_START:
|
|
816
|
-
link = 'https://developer.chrome.com/docs/web-platform/soft-navigations
|
|
813
|
+
link = 'https://developer.chrome.com/docs/web-platform/soft-navigations';
|
|
817
814
|
name = 'Soft Navigations';
|
|
818
815
|
break;
|
|
819
816
|
case Trace.Types.Events.Name.MARK_FCP:
|
|
820
817
|
link = 'https://web.dev/first-contentful-paint/';
|
|
821
818
|
name = 'First Contentful Paint';
|
|
822
819
|
break;
|
|
820
|
+
case Trace.Types.Events.Name.MARK_SOFT_FCP:
|
|
821
|
+
link = 'https://developer.chrome.com/docs/web-platform/soft-navigations';
|
|
822
|
+
name = 'Soft First Contentful Paint';
|
|
823
|
+
break;
|
|
823
824
|
default:
|
|
824
825
|
break;
|
|
825
826
|
}
|
|
@@ -963,7 +964,7 @@ export class TimelineUIUtils {
|
|
|
963
964
|
|
|
964
965
|
// Add timestamp to user timings, including custom extensibility markers
|
|
965
966
|
if (Trace.Helpers.Trace.eventHasCategory(event, Trace.Types.Events.Categories.UserTiming) ||
|
|
966
|
-
Trace.Types.Extensions.isSyntheticExtensionEntry(event)) {
|
|
967
|
+
Trace.Types.Extensions.isSyntheticExtensionEntry(event) || Trace.Types.Events.isSoftNavigationStart(event)) {
|
|
967
968
|
const adjustedEventTimeStamp = timeStampForEventAdjustedForClosestNavigationIfPossible(
|
|
968
969
|
event,
|
|
969
970
|
parsedTrace,
|
|
@@ -1228,7 +1229,6 @@ export class TimelineUIUtils {
|
|
|
1228
1229
|
const options = {
|
|
1229
1230
|
tabStop: true,
|
|
1230
1231
|
showColumnNumber: false,
|
|
1231
|
-
inlineFrameIndex: 0,
|
|
1232
1232
|
};
|
|
1233
1233
|
contentHelper.appendElementRow(
|
|
1234
1234
|
i18nString(UIStrings.imageUrl), LegacyComponents.Linkifier.Linkifier.linkifyURL(url, options));
|
|
@@ -1242,7 +1242,6 @@ export class TimelineUIUtils {
|
|
|
1242
1242
|
const options = {
|
|
1243
1243
|
tabStop: true,
|
|
1244
1244
|
showColumnNumber: false,
|
|
1245
|
-
inlineFrameIndex: 0,
|
|
1246
1245
|
};
|
|
1247
1246
|
contentHelper.appendElementRow(
|
|
1248
1247
|
i18nString(UIStrings.stylesheetUrl), LegacyComponents.Linkifier.Linkifier.linkifyURL(url, options));
|
|
@@ -1444,6 +1443,7 @@ export class TimelineUIUtils {
|
|
|
1444
1443
|
|
|
1445
1444
|
case Trace.Types.Events.Name.MARK_FIRST_PAINT:
|
|
1446
1445
|
case Trace.Types.Events.Name.MARK_FCP:
|
|
1446
|
+
case Trace.Types.Events.Name.MARK_SOFT_FCP:
|
|
1447
1447
|
case Trace.Types.Events.Name.MARK_LOAD:
|
|
1448
1448
|
case Trace.Types.Events.Name.MARK_DOM_CONTENT: {
|
|
1449
1449
|
const adjustedEventTimeStamp = timeStampForEventAdjustedForClosestNavigationIfPossible(
|
|
@@ -2074,7 +2074,7 @@ export class TimelineUIUtils {
|
|
|
2074
2074
|
tall = true;
|
|
2075
2075
|
break;
|
|
2076
2076
|
case Trace.Types.Events.Name.SOFT_NAVIGATION_START:
|
|
2077
|
-
color = 'var(--
|
|
2077
|
+
color = 'var(--color-text-primary)';
|
|
2078
2078
|
tall = true;
|
|
2079
2079
|
break;
|
|
2080
2080
|
case Trace.Types.Events.Name.FRAME_STARTED_LOADING:
|
|
@@ -2094,6 +2094,7 @@ export class TimelineUIUtils {
|
|
|
2094
2094
|
tall = true;
|
|
2095
2095
|
break;
|
|
2096
2096
|
case Trace.Types.Events.Name.MARK_FCP:
|
|
2097
|
+
case Trace.Types.Events.Name.MARK_SOFT_FCP:
|
|
2097
2098
|
color = 'var(--sys-color-green-bright)';
|
|
2098
2099
|
tall = true;
|
|
2099
2100
|
break;
|
|
@@ -2299,7 +2300,6 @@ export class TimelineDetailsContentHelper {
|
|
|
2299
2300
|
tabStop: true,
|
|
2300
2301
|
columnNumber: startColumn,
|
|
2301
2302
|
showColumnNumber: true,
|
|
2302
|
-
inlineFrameIndex: 0,
|
|
2303
2303
|
text,
|
|
2304
2304
|
omitOrigin,
|
|
2305
2305
|
};
|
|
@@ -2316,8 +2316,7 @@ export class TimelineDetailsContentHelper {
|
|
|
2316
2316
|
return;
|
|
2317
2317
|
}
|
|
2318
2318
|
const locationContent = document.createElement('span');
|
|
2319
|
-
const link = this.#linkifier.maybeLinkifyScriptLocation(
|
|
2320
|
-
this.target, null, url, startLine, {tabStop: true, inlineFrameIndex: 0});
|
|
2319
|
+
const link = this.#linkifier.maybeLinkifyScriptLocation(this.target, null, url, startLine, {tabStop: true});
|
|
2321
2320
|
if (!link) {
|
|
2322
2321
|
return;
|
|
2323
2322
|
}
|
|
@@ -2407,7 +2406,7 @@ export function isMarkerEvent(parsedTrace: Trace.TraceModel.ParsedTrace, event:
|
|
|
2407
2406
|
return true;
|
|
2408
2407
|
}
|
|
2409
2408
|
|
|
2410
|
-
if (Trace.Types.Events.
|
|
2409
|
+
if (Trace.Types.Events.isAnyFirstContentfulPaint(event) || Trace.Types.Events.isFirstPaint(event)) {
|
|
2411
2410
|
return event.args.frame === parsedTrace.data.Meta.mainFrameId;
|
|
2412
2411
|
}
|
|
2413
2412
|
|
|
@@ -37,12 +37,14 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
|
37
37
|
*/
|
|
38
38
|
export const SORT_ORDER_PAGE_LOAD_MARKERS: Readonly<Record<string, number>> = {
|
|
39
39
|
[Trace.Types.Events.Name.NAVIGATION_START]: 0,
|
|
40
|
-
[Trace.Types.Events.Name.
|
|
41
|
-
[Trace.Types.Events.Name.MARK_FCP]: 2,
|
|
40
|
+
[Trace.Types.Events.Name.SOFT_NAVIGATION_START]: 1,
|
|
42
41
|
[Trace.Types.Events.Name.MARK_FIRST_PAINT]: 2,
|
|
43
|
-
[Trace.Types.Events.Name.
|
|
44
|
-
[Trace.Types.Events.Name.
|
|
45
|
-
[Trace.Types.Events.Name.
|
|
42
|
+
[Trace.Types.Events.Name.MARK_FCP]: 3,
|
|
43
|
+
[Trace.Types.Events.Name.MARK_SOFT_FCP]: 4,
|
|
44
|
+
[Trace.Types.Events.Name.MARK_DOM_CONTENT]: 5,
|
|
45
|
+
[Trace.Types.Events.Name.MARK_LOAD]: 6,
|
|
46
|
+
[Trace.Types.Events.Name.MARK_LCP_CANDIDATE]: 7,
|
|
47
|
+
[Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION]: 8,
|
|
46
48
|
};
|
|
47
49
|
|
|
48
50
|
export class TimingsTrackAppender implements TrackAppender {
|
|
@@ -436,7 +436,6 @@ function linkifyURL(url: Platform.DevToolsPath.UrlString): HTMLElement {
|
|
|
436
436
|
return LegacyComponents.Linkifier.Linkifier.linkifyURL(url, {
|
|
437
437
|
tabStop: true,
|
|
438
438
|
showColumnNumber: false,
|
|
439
|
-
inlineFrameIndex: 0,
|
|
440
439
|
maxLength: MAX_URL_LENGTH,
|
|
441
440
|
});
|
|
442
441
|
}
|
|
@@ -267,7 +267,6 @@ function renderURL(request: Trace.Types.Events.SyntheticNetworkRequest): Lit.Tem
|
|
|
267
267
|
const options: LegacyComponents.Linkifier.LinkifyURLOptions = {
|
|
268
268
|
tabStop: true,
|
|
269
269
|
showColumnNumber: false,
|
|
270
|
-
inlineFrameIndex: 0,
|
|
271
270
|
maxLength: MAX_URL_LENGTH,
|
|
272
271
|
};
|
|
273
272
|
const linkifiedURL = LegacyComponents.Linkifier.Linkifier.linkifyURL(
|
|
@@ -439,7 +438,6 @@ function renderInitiatedBy(
|
|
|
439
438
|
const options: LegacyComponents.Linkifier.LinkifyOptions = {
|
|
440
439
|
tabStop: true,
|
|
441
440
|
showColumnNumber: true,
|
|
442
|
-
inlineFrameIndex: 0,
|
|
443
441
|
};
|
|
444
442
|
// If we have a stack trace, that is the most reliable way to get the initiator data and display a link to the source.
|
|
445
443
|
if (hasStackTrace) {
|
|
@@ -39,7 +39,6 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
39
39
|
const options = {
|
|
40
40
|
tabStop: true,
|
|
41
41
|
showColumnNumber: false,
|
|
42
|
-
inlineFrameIndex: 0,
|
|
43
42
|
maxLength: MAX_URL_LENGTH,
|
|
44
43
|
};
|
|
45
44
|
const linkEl = LegacyComponents.Linkifier.Linkifier.linkifyURL(fallbackUrl, options);
|
|
@@ -1627,6 +1627,8 @@ export class Overlays extends EventTarget {
|
|
|
1627
1627
|
markers: HTMLElement, marker: HTMLElement): void {
|
|
1628
1628
|
if (Trace.Types.Events.isSoftNavigationStart(event)) {
|
|
1629
1629
|
name = 'Soft Nav';
|
|
1630
|
+
} else if (Trace.Types.Events.isSoftFirstContentfulPaint(event)) {
|
|
1631
|
+
name = 'Soft FCP';
|
|
1630
1632
|
} else if (Trace.Types.Events.isSoftLargestContentfulPaintCandidate(event)) {
|
|
1631
1633
|
name = 'Soft LCP';
|
|
1632
1634
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Name: Dependencies sourced from the upstream `chromium` repository
|
|
2
2
|
URL: Internal
|
|
3
3
|
Version: N/A
|
|
4
|
-
Revision:
|
|
4
|
+
Revision: db882e11eb73564831cdf0a63b661a81332df665
|
|
5
5
|
Update Mechanism: Manual (https://crbug.com/428069060)
|
|
6
6
|
License: BSD-3-Clause
|
|
7
7
|
License File: LICENSE
|
|
@@ -57,15 +57,15 @@ import * as SDK from '../../core/sdk/sdk.js';
|
|
|
57
57
|
* @throws TypeError if `url` is not a valid URL.
|
|
58
58
|
* @see https://en.wikipedia.org/wiki/UTM_parameters
|
|
59
59
|
*/
|
|
60
|
-
export function openInNewTab(url: URL|string): void {
|
|
60
|
+
export function openInNewTab(url: URL|string, allowPrivileged?: boolean): void {
|
|
61
61
|
url = new URL(url);
|
|
62
62
|
if (Common.ParsedURL.schemeIs(url, 'javascript:')) {
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
// Navigating to a chrome:// link via a normal anchor doesn't work, so we "navigate"
|
|
67
|
-
// there using CDP.
|
|
68
|
-
if (Common.ParsedURL.schemeIs(url, 'chrome:')) {
|
|
67
|
+
// there using CDP if explicitly requested.
|
|
68
|
+
if (allowPrivileged && Common.ParsedURL.schemeIs(url, 'chrome:')) {
|
|
69
69
|
const rootTarget = SDK.TargetManager.TargetManager.instance().rootTarget();
|
|
70
70
|
if (rootTarget === null) {
|
|
71
71
|
return;
|
|
@@ -60,7 +60,7 @@ export class Link extends HTMLElement {
|
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
UIHelpers.openInNewTab(href);
|
|
63
|
+
UIHelpers.openInNewTab(href, this.allowPrivileged);
|
|
64
64
|
|
|
65
65
|
event.consume();
|
|
66
66
|
}
|
|
@@ -73,6 +73,18 @@ export class Link extends HTMLElement {
|
|
|
73
73
|
this.setAttribute('href', href);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
get allowPrivileged(): boolean {
|
|
77
|
+
return this.hasAttribute('allow-privileged');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
set allowPrivileged(allowPrivileged: boolean) {
|
|
81
|
+
if (allowPrivileged) {
|
|
82
|
+
this.setAttribute('allow-privileged', '');
|
|
83
|
+
} else {
|
|
84
|
+
this.removeAttribute('allow-privileged');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
76
88
|
get jslogContext(): string|null {
|
|
77
89
|
return this.getAttribute('jslogcontext');
|
|
78
90
|
}
|
|
@@ -98,7 +110,7 @@ export class Link extends HTMLElement {
|
|
|
98
110
|
oldValue: string|null,
|
|
99
111
|
newValue: string|null,
|
|
100
112
|
): void {
|
|
101
|
-
if (oldValue
|
|
113
|
+
if (oldValue === newValue) {
|
|
102
114
|
return;
|
|
103
115
|
}
|
|
104
116
|
if (name === 'jslogcontext') {
|
|
@@ -145,9 +157,11 @@ export class Link extends HTMLElement {
|
|
|
145
157
|
className?: string,
|
|
146
158
|
jsLogContext?: string,
|
|
147
159
|
tabindex = 0,
|
|
160
|
+
allowPrivileged = false,
|
|
148
161
|
): Link {
|
|
149
162
|
const link = new Link();
|
|
150
163
|
link.href = url as Platform.DevToolsPath.UrlString;
|
|
164
|
+
link.allowPrivileged = allowPrivileged;
|
|
151
165
|
linkText = linkText ?? url;
|
|
152
166
|
link.textContent = Platform.StringUtilities.trimMiddle(linkText, 150);
|
|
153
167
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import * as Common from '../../core/common/common.js';
|
|
6
6
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
7
|
+
import * as Root from '../../core/root/root.js';
|
|
7
8
|
import * as VisualLogging from '../visual_logging/visual_logging.js';
|
|
8
9
|
|
|
9
10
|
import * as ARIAUtils from './ARIAUtils.js';
|
|
@@ -129,11 +130,19 @@ export class InspectorDrawerView {
|
|
|
129
130
|
this.#isConsoleOpenInMainAndDrawer = options.isConsoleOpenInMainAndDrawer;
|
|
130
131
|
this.#drawerMinimizedSetting =
|
|
131
132
|
Common.Settings.Settings.instance().createLocalSetting('inspector.drawer-minimized', false);
|
|
132
|
-
this.tabbedLocation = ViewManager.instance().createTabbedLocation(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
this.tabbedLocation = ViewManager.instance().createTabbedLocation(options.revealDrawer, 'drawer-view', true, true, {
|
|
134
|
+
isLocationVisible: options.isVisible,
|
|
135
|
+
tabbedPaneFactory: () => new DrawerTabbedPane(),
|
|
136
|
+
plusButton: {title: i18nString(UIStrings.moreTools), jslogContext: 'plus-button-drawer'},
|
|
137
|
+
});
|
|
138
|
+
// When the plus button is disabled we keep the legacy left-toolbar
|
|
139
|
+
// three-dot menu so users can still reach hidden / addable tools.
|
|
140
|
+
if (Root.Runtime.hostConfig.devToolsPlusButton?.enabled) {
|
|
141
|
+
this.#moreTabsButton = null;
|
|
142
|
+
} else {
|
|
143
|
+
this.#moreTabsButton = this.tabbedLocation.enableMoreTabsButton();
|
|
144
|
+
this.#moreTabsButton.setTitle(i18nString(UIStrings.moreTools));
|
|
145
|
+
}
|
|
137
146
|
this.tabbedPane = this.tabbedLocation.tabbedPane() as DrawerTabbedPane;
|
|
138
147
|
this.tabbedPane.element.classList.add('drawer-tabbed-pane');
|
|
139
148
|
this.tabbedPane.element.setAttribute('jslog', `${VisualLogging.drawer()}`);
|
|
@@ -228,7 +228,10 @@ export class InspectorView extends VBox implements ViewLocationResolver {
|
|
|
228
228
|
this.tabbedLocation = ViewManager.instance().createTabbedLocation(
|
|
229
229
|
Host.InspectorFrontendHost.InspectorFrontendHostInstance.bringToFront.bind(
|
|
230
230
|
Host.InspectorFrontendHost.InspectorFrontendHostInstance),
|
|
231
|
-
'panel', true, true, {
|
|
231
|
+
'panel', true, true, {
|
|
232
|
+
defaultTab: Root.Runtime.Runtime.queryParam('panel'),
|
|
233
|
+
plusButton: {jslogContext: 'plus-button-panel'},
|
|
234
|
+
});
|
|
232
235
|
|
|
233
236
|
this.tabbedPane = this.tabbedLocation.tabbedPane();
|
|
234
237
|
this.tabbedPane.setMinimumSize(MIN_MAIN_PANEL_WIDTH, 0);
|
|
@@ -108,8 +108,13 @@ export class PlusButtonPresenter {
|
|
|
108
108
|
for (const view of views()) {
|
|
109
109
|
// Skip views that already have a tab. Hidden tabs are already listed
|
|
110
110
|
// in the overflow section above, and visible tabs are accessible
|
|
111
|
-
// directly in the tab strip.
|
|
111
|
+
// directly in the tab strip. Track their id and title so the
|
|
112
|
+
// cross-location loop below cannot offer a same-titled duplicate
|
|
113
|
+
// (e.g. drawer "Console" while the panel "Console" is already
|
|
114
|
+
// visible — they have different view ids).
|
|
112
115
|
if (tabbedPane.hasTab(view.viewId())) {
|
|
116
|
+
seenIds.add(view.viewId());
|
|
117
|
+
seenTitles.add(view.title());
|
|
113
118
|
continue;
|
|
114
119
|
}
|
|
115
120
|
// Transient views are not user-addable.
|
|
@@ -483,6 +483,12 @@ export type WidgetOptions<ContentTypeT extends HTMLElement|DocumentFragment = HT
|
|
|
483
483
|
classes?: never,
|
|
484
484
|
});
|
|
485
485
|
|
|
486
|
+
const enum UpdateState {
|
|
487
|
+
NORMAL = 'NORMAL', // Standard state: update can be aborted for efficiency.
|
|
488
|
+
INTERRUPTED = 'INTERRUPTED', // An update was physically running and got aborted; replacement must be shielded.
|
|
489
|
+
SHIELDED = 'SHIELDED', // Current update is a replacement for an interrupted one and cannot be aborted.
|
|
490
|
+
}
|
|
491
|
+
|
|
486
492
|
export class Widget<ContentTypeT extends HTMLElement|DocumentFragment = HTMLElement> {
|
|
487
493
|
readonly element: HTMLElement;
|
|
488
494
|
#contentElement: ContentTypeT;
|
|
@@ -501,6 +507,7 @@ export class Widget<ContentTypeT extends HTMLElement|DocumentFragment = HTMLElem
|
|
|
501
507
|
#externallyManaged?: boolean;
|
|
502
508
|
#updateComplete = UPDATE_COMPLETE;
|
|
503
509
|
#updateController?: AbortController;
|
|
510
|
+
#updateState = UpdateState.NORMAL;
|
|
504
511
|
|
|
505
512
|
/**
|
|
506
513
|
* Constructs a new `Widget` with the given `options`.
|
|
@@ -1165,12 +1172,17 @@ export class Widget<ContentTypeT extends HTMLElement|DocumentFragment = HTMLElem
|
|
|
1165
1172
|
}
|
|
1166
1173
|
|
|
1167
1174
|
addUpdateController(controller: AbortController): void {
|
|
1175
|
+
const wasInterrupted = this.#updateState === UpdateState.INTERRUPTED;
|
|
1168
1176
|
this.#updateController?.abort();
|
|
1169
1177
|
this.#updateController = controller;
|
|
1178
|
+
// Transition to SHIELDED if we are replacing a starved update, otherwise reset to NORMAL.
|
|
1179
|
+
this.#updateState = wasInterrupted ? UpdateState.SHIELDED : UpdateState.NORMAL;
|
|
1170
1180
|
}
|
|
1171
1181
|
|
|
1172
1182
|
cancelUpdateController(): void {
|
|
1173
1183
|
this.#updateController?.abort();
|
|
1184
|
+
this.#updateController = undefined;
|
|
1185
|
+
this.#updateState = UpdateState.NORMAL;
|
|
1174
1186
|
}
|
|
1175
1187
|
|
|
1176
1188
|
/**
|
|
@@ -1180,7 +1192,13 @@ export class Widget<ContentTypeT extends HTMLElement|DocumentFragment = HTMLElem
|
|
|
1180
1192
|
* frame.
|
|
1181
1193
|
*/
|
|
1182
1194
|
requestUpdate(): void {
|
|
1183
|
-
|
|
1195
|
+
// If the state is SHIELDED, we skip the abort call entirely to break the starvation loop.
|
|
1196
|
+
if (this.#updateState !== UpdateState.SHIELDED) {
|
|
1197
|
+
if (currentlyProcessed.has(this)) {
|
|
1198
|
+
this.#updateState = UpdateState.INTERRUPTED;
|
|
1199
|
+
}
|
|
1200
|
+
this.#updateController?.abort();
|
|
1201
|
+
}
|
|
1184
1202
|
this.#updateComplete = enqueueWidgetUpdate(this);
|
|
1185
1203
|
}
|
|
1186
1204
|
|