chrome-devtools-frontend 1.0.1558690 → 1.0.1561080
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/Images/src/container.svg +4 -0
- package/front_end/core/common/Gzip.ts +15 -0
- package/front_end/core/host/InspectorFrontendHostStub.ts +0 -3
- package/front_end/core/platform/ArrayUtilities.ts +13 -0
- package/front_end/core/root/Runtime.ts +0 -5
- package/front_end/core/sdk/CSSMetadata.ts +6 -6
- package/front_end/core/sdk/CSSModel.ts +2 -2
- package/front_end/core/sdk/DOMModel.ts +15 -3
- package/front_end/core/sdk/NetworkManager.ts +4 -0
- package/front_end/core/sdk/NetworkRequest.ts +9 -0
- package/front_end/core/sdk/OverlayModel.ts +20 -9
- package/front_end/entrypoints/main/MainImpl.ts +2 -1
- package/front_end/generated/InspectorBackendCommands.ts +6 -3
- package/front_end/generated/SupportedCSSProperties.js +64 -32
- package/front_end/generated/protocol-mapping.d.ts +16 -0
- package/front_end/generated/protocol-proxy-api.d.ts +12 -0
- package/front_end/generated/protocol.ts +38 -1
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +1 -1
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +11 -7
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +23 -22
- package/front_end/models/badges/UserBadges.ts +48 -16
- package/front_end/models/greendev/Prototypes.ts +6 -1
- package/front_end/models/trace/LanternComputationData.ts +4 -3
- package/front_end/models/trace/Processor.ts +6 -5
- package/front_end/models/trace/Styles.ts +10 -1
- package/front_end/models/trace/extras/TraceTree.ts +1 -1
- package/front_end/models/trace/handlers/LargestImagePaintHandler.ts +2 -2
- package/front_end/models/trace/handlers/MetaHandler.ts +14 -0
- package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +59 -34
- package/front_end/models/trace/helpers/Timing.ts +8 -1
- package/front_end/models/trace/insights/Common.ts +1 -1
- package/front_end/models/trace/insights/LCPBreakdown.ts +4 -4
- package/front_end/models/trace/insights/LCPDiscovery.ts +3 -3
- package/front_end/models/trace/insights/RenderBlocking.ts +1 -1
- package/front_end/models/trace/insights/types.ts +1 -1
- package/front_end/models/trace/types/TraceEvents.ts +62 -10
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +11 -142
- package/front_end/panels/ai_assistance/PatchWidget.ts +90 -72
- package/front_end/panels/ai_assistance/ai_assistance.ts +1 -0
- package/front_end/panels/ai_assistance/components/ChatInput.ts +701 -0
- package/front_end/panels/ai_assistance/components/ChatView.ts +71 -1268
- package/front_end/panels/ai_assistance/components/UserActionRow.ts +514 -31
- package/front_end/panels/ai_assistance/components/chatInput.css +387 -0
- package/front_end/panels/ai_assistance/components/chatView.css +38 -599
- package/front_end/panels/ai_assistance/components/userActionRow.css +230 -0
- package/front_end/panels/autofill/AutofillView.ts +2 -2
- package/front_end/panels/changes/ChangesView.ts +15 -1
- package/front_end/panels/changes/changesView.css +6 -0
- package/front_end/panels/common/AiCodeGenerationTeaser.ts +48 -12
- package/front_end/panels/common/BadgeNotification.ts +44 -58
- package/front_end/panels/common/CopyChangesToPrompt.ts +233 -0
- package/front_end/panels/common/aiCodeGenerationTeaser.css +14 -0
- package/front_end/panels/common/common.ts +2 -1
- package/front_end/panels/console/consoleView.css +1 -1
- package/front_end/panels/elements/CSSRuleValidator.ts +38 -0
- package/front_end/panels/elements/ElementsTreeElement.ts +222 -377
- package/front_end/panels/elements/ElementsTreeOutline.ts +0 -23
- package/front_end/panels/elements/ShortcutTreeElement.ts +57 -50
- package/front_end/panels/elements/StylePropertiesSection.ts +1 -3
- package/front_end/panels/elements/StylesSidebarPane.ts +15 -4
- package/front_end/panels/elements/components/AdornerManager.ts +5 -149
- package/front_end/panels/issues/HiddenIssuesRow.ts +1 -2
- package/front_end/panels/issues/IssueKindView.ts +2 -4
- package/front_end/panels/issues/IssueView.ts +2 -4
- package/front_end/panels/network/NetworkDataGridNode.ts +65 -1
- package/front_end/panels/network/NetworkLogView.ts +2 -4
- package/front_end/panels/network/NetworkLogViewColumns.ts +9 -0
- package/front_end/panels/screencast/ScreencastApp.ts +1 -0
- package/front_end/panels/settings/SettingsScreen.ts +3 -2
- package/front_end/panels/timeline/CompatibilityTracksAppender.ts +14 -1
- package/front_end/panels/timeline/StatusDialog.ts +4 -3
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +1 -4
- package/front_end/panels/timeline/TimelineController.ts +185 -3
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +52 -25
- package/front_end/panels/timeline/TimelineFlameChartNetworkDataProvider.ts +3 -16
- package/front_end/panels/timeline/TimelineFlameChartView.ts +65 -21
- package/front_end/panels/timeline/TimelinePanel.ts +86 -126
- package/front_end/panels/timeline/TimelineTreeView.ts +1 -0
- package/front_end/panels/timeline/TimelineUIUtils.ts +28 -2
- package/front_end/panels/timeline/TimingsTrackAppender.ts +3 -1
- package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +1 -1
- package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +2 -2
- package/front_end/panels/timeline/components/insights/RenderBlocking.ts +6 -4
- package/front_end/panels/timeline/components/insights/Table.ts +3 -3
- package/front_end/panels/timeline/overlays/OverlaysImpl.ts +4 -0
- package/front_end/panels/timeline/timelinePanel.css +8 -1
- package/front_end/panels/timeline/utils/EntryNodes.ts +2 -1
- package/front_end/panels/whats_new/ReleaseNoteText.ts +15 -9
- package/front_end/panels/whats_new/resources/WNDT.md +6 -6
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/codemirror.next/rebuild.sh +1 -1
- package/front_end/third_party/lit/rebuild.sh +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts +2 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.js +9 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.d.ts +3 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.js +9 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPResponse.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.d.ts +3 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.js +10 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Request.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js +8 -4
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/injected.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +10 -1
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +13 -7
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts +2 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.js +9 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.d.ts +3 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.js +9 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPResponse.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.d.ts +3 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.js +10 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/Request.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js +8 -4
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/injected.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/types.d.ts +10 -1
- package/front_end/third_party/puppeteer/package/package.json +3 -3
- package/front_end/third_party/puppeteer/package/src/api/Page.ts +2 -3
- package/front_end/third_party/puppeteer/package/src/bidi/HTTPRequest.ts +13 -0
- package/front_end/third_party/puppeteer/package/src/bidi/HTTPResponse.ts +10 -0
- package/front_end/third_party/puppeteer/package/src/bidi/core/Request.ts +15 -0
- package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +9 -4
- package/front_end/third_party/puppeteer/package/src/generated/injected.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/ui/components/adorners/Adorner.ts +8 -68
- package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +70 -28
- package/front_end/ui/legacy/SearchableView.ts +11 -5
- package/front_end/ui/legacy/SplitWidget.ts +1 -1
- package/front_end/ui/legacy/TabbedPane.ts +1 -1
- package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +43 -9
- package/front_end/ui/visual_logging/KnownContextValues.ts +16 -0
- package/package.json +2 -1
|
@@ -229,9 +229,17 @@ const UIStrings = {
|
|
|
229
229
|
*/
|
|
230
230
|
processingTrace: 'Processing trace…',
|
|
231
231
|
/**
|
|
232
|
-
* @description Text in Timeline Panel of the Performance panel
|
|
232
|
+
* @description Text in Timeline Panel of the Performance panel. Shown to the user after they request to download the trace.
|
|
233
|
+
*/
|
|
234
|
+
preparingTraceForDownload: 'Preparing…',
|
|
235
|
+
/**
|
|
236
|
+
* @description Text in Timeline Panel of the Performance panel. Shown to the user after they request to download the trace.
|
|
233
237
|
*/
|
|
234
|
-
|
|
238
|
+
compressingTraceForDownload: 'Compressing…',
|
|
239
|
+
/**
|
|
240
|
+
* @description Text in Timeline Panel of the Performance panel. Shown to the user after they request to download the trace.
|
|
241
|
+
*/
|
|
242
|
+
encodingTraceForDownload: 'Encoding…',
|
|
235
243
|
/**
|
|
236
244
|
* @description Tooltip description for a checkbox that toggles the visibility of data added by extensions of this panel (Performance).
|
|
237
245
|
*/
|
|
@@ -333,7 +341,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
333
341
|
private readonly recordingOptionUIControls: UI.Toolbar.ToolbarItem[];
|
|
334
342
|
private state: State;
|
|
335
343
|
private recordingPageReload: boolean;
|
|
336
|
-
private readonly millisecondsToRecordAfterLoadEvent: number;
|
|
337
344
|
private readonly toggleRecordAction: UI.ActionRegistration.Action;
|
|
338
345
|
private readonly recordReloadAction: UI.ActionRegistration.Action;
|
|
339
346
|
readonly #historyManager: TimelineHistoryManager;
|
|
@@ -447,12 +454,9 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
447
454
|
">💫</div>`;
|
|
448
455
|
const adorner = new Adorners.Adorner.Adorner();
|
|
449
456
|
adorner.classList.add('fix-perf-icon');
|
|
450
|
-
adorner.
|
|
451
|
-
|
|
452
|
-
content: adornerContent,
|
|
453
|
-
};
|
|
457
|
+
adorner.name = i18nString(UIStrings.fixMe);
|
|
458
|
+
adorner.append(adornerContent);
|
|
454
459
|
this.#traceEngineModel = traceModel || this.#instantiateNewModel();
|
|
455
|
-
this.#listenForProcessingProgress();
|
|
456
460
|
|
|
457
461
|
this.element.addEventListener('contextmenu', this.contextMenu.bind(this), false);
|
|
458
462
|
this.dropTarget = new UI.DropTarget.DropTarget(
|
|
@@ -462,7 +466,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
462
466
|
this.recordingOptionUIControls = [];
|
|
463
467
|
this.state = State.IDLE;
|
|
464
468
|
this.recordingPageReload = false;
|
|
465
|
-
this.millisecondsToRecordAfterLoadEvent = 5000;
|
|
466
469
|
this.toggleRecordAction = UI.ActionRegistry.ActionRegistry.instance().getAction('timeline.toggle-recording');
|
|
467
470
|
this.recordReloadAction = UI.ActionRegistry.ActionRegistry.instance().getAction('timeline.record-reload');
|
|
468
471
|
|
|
@@ -527,9 +530,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
527
530
|
|
|
528
531
|
this.createFileSelector();
|
|
529
532
|
|
|
530
|
-
SDK.TargetManager.TargetManager.instance().addModelListener(
|
|
531
|
-
SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.Load, this.loadEventFired, this);
|
|
532
|
-
|
|
533
533
|
this.flameChart = new TimelineFlameChartView(this);
|
|
534
534
|
this.element.addEventListener(
|
|
535
535
|
'toggle-popover', event => this.flameChart.togglePopover((event as CustomEvent).detail));
|
|
@@ -675,7 +675,7 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
675
675
|
#setActiveInsight(insight: TimelineComponents.Sidebar.ActiveInsight|null, opts: {
|
|
676
676
|
highlightInsight: boolean,
|
|
677
677
|
} = {highlightInsight: false}): void {
|
|
678
|
-
if (insight) {
|
|
678
|
+
if (insight && this.#splitWidget.showMode() !== UI.SplitWidget.ShowMode.BOTH) {
|
|
679
679
|
this.#splitWidget.showBoth();
|
|
680
680
|
}
|
|
681
681
|
this.#sideBar.setActiveInsight(insight, {highlight: opts.highlightInsight});
|
|
@@ -732,7 +732,25 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
732
732
|
config.includeRuntimeCallStats = Root.Runtime.experiments.isEnabled('timeline-v8-runtime-call-stats');
|
|
733
733
|
config.debugMode = Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.TIMELINE_DEBUG_MODE);
|
|
734
734
|
|
|
735
|
-
|
|
735
|
+
const traceEngineModel = Trace.TraceModel.Model.createWithAllHandlers(config);
|
|
736
|
+
|
|
737
|
+
traceEngineModel.addEventListener(Trace.TraceModel.ModelUpdateEvent.eventName, e => {
|
|
738
|
+
const updateEvent = e as Trace.TraceModel.ModelUpdateEvent;
|
|
739
|
+
const str = i18nString(UIStrings.processed);
|
|
740
|
+
|
|
741
|
+
// Trace Engine will report progress from [0...1] but we still have more work to do. So, scale them down a bit.
|
|
742
|
+
const traceParseMaxProgress = 0.7;
|
|
743
|
+
|
|
744
|
+
if (updateEvent.data.type === Trace.TraceModel.ModelUpdateType.COMPLETE) {
|
|
745
|
+
this.statusDialog?.updateProgressBar(str, 100 * traceParseMaxProgress);
|
|
746
|
+
} else if (updateEvent.data.type === Trace.TraceModel.ModelUpdateType.PROGRESS_UPDATE) {
|
|
747
|
+
const data = updateEvent.data.data;
|
|
748
|
+
this.statusDialog?.updateProgressBar(str, data.percent * 100 * traceParseMaxProgress);
|
|
749
|
+
}
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
this.#traceEngineModel = traceEngineModel;
|
|
753
|
+
return this.#traceEngineModel;
|
|
736
754
|
}
|
|
737
755
|
|
|
738
756
|
static extensionDataVisibilitySetting(): Common.Settings.Setting<boolean> {
|
|
@@ -1455,6 +1473,9 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
1455
1473
|
}
|
|
1456
1474
|
|
|
1457
1475
|
this.#showExportTraceErrorDialog(error);
|
|
1476
|
+
} finally {
|
|
1477
|
+
this.statusDialog?.remove();
|
|
1478
|
+
this.statusDialog = null;
|
|
1458
1479
|
}
|
|
1459
1480
|
}
|
|
1460
1481
|
|
|
@@ -1464,6 +1485,24 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
1464
1485
|
addModifications: boolean,
|
|
1465
1486
|
shouldCompress: boolean,
|
|
1466
1487
|
}): Promise<void> {
|
|
1488
|
+
this.statusDialog = new StatusDialog(
|
|
1489
|
+
{
|
|
1490
|
+
hideStopButton: true,
|
|
1491
|
+
showProgress: true,
|
|
1492
|
+
},
|
|
1493
|
+
async () => {
|
|
1494
|
+
this.statusDialog?.remove();
|
|
1495
|
+
this.statusDialog = null;
|
|
1496
|
+
});
|
|
1497
|
+
this.statusDialog.showPane(this.statusPaneContainer, 'tinted');
|
|
1498
|
+
this.statusDialog.updateStatus(i18nString(UIStrings.preparingTraceForDownload));
|
|
1499
|
+
this.statusDialog.updateProgressBar(i18nString(UIStrings.preparingTraceForDownload), 0);
|
|
1500
|
+
this.statusDialog.requestUpdate();
|
|
1501
|
+
await this.statusDialog.updateComplete;
|
|
1502
|
+
// Not sure why the above isn't sufficient.
|
|
1503
|
+
await new Promise(resolve => requestAnimationFrame(resolve));
|
|
1504
|
+
await new Promise(resolve => requestAnimationFrame(resolve));
|
|
1505
|
+
|
|
1467
1506
|
// Base the filename on the trace's time of recording
|
|
1468
1507
|
const isoDate =
|
|
1469
1508
|
Platform.DateUtilities.toISO8601Compact(metadata.startTime ? new Date(metadata.startTime) : new Date());
|
|
@@ -1499,8 +1538,16 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
1499
1538
|
let blob = new Blob(blobParts, {type: 'application/json'});
|
|
1500
1539
|
|
|
1501
1540
|
if (config.shouldCompress) {
|
|
1541
|
+
this.statusDialog.updateStatus(i18nString(UIStrings.compressingTraceForDownload));
|
|
1542
|
+
this.statusDialog.updateProgressBar(i18nString(UIStrings.compressingTraceForDownload), 0);
|
|
1543
|
+
|
|
1502
1544
|
fileName = `${fileName}.gz` as Platform.DevToolsPath.RawPathString;
|
|
1503
|
-
const
|
|
1545
|
+
const inputSize = blob.size;
|
|
1546
|
+
const monitoredStream = Common.Gzip.createMonitoredStream(blob.stream(), bytesRead => {
|
|
1547
|
+
this.statusDialog?.updateProgressBar(
|
|
1548
|
+
i18nString(UIStrings.compressingTraceForDownload), bytesRead / inputSize * 100);
|
|
1549
|
+
});
|
|
1550
|
+
const gzStream = Common.Gzip.compressStream(monitoredStream);
|
|
1504
1551
|
blob = await new Response(gzStream, {
|
|
1505
1552
|
headers: {'Content-Type': 'application/gzip'},
|
|
1506
1553
|
}).blob();
|
|
@@ -1515,9 +1562,12 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
1515
1562
|
try {
|
|
1516
1563
|
// The maximum string length in v8 is `2 ** 29 - 23`, aka 538 MB.
|
|
1517
1564
|
// If the gzipped&base64-encoded trace is larger than that, this'll throw a RangeError.
|
|
1565
|
+
this.statusDialog.updateStatus(i18nString(UIStrings.encodingTraceForDownload));
|
|
1566
|
+
this.statusDialog.updateProgressBar(i18nString(UIStrings.encodingTraceForDownload), 100);
|
|
1518
1567
|
bytesAsB64 = await Common.Base64.encode(blob);
|
|
1519
1568
|
} catch {
|
|
1520
1569
|
}
|
|
1570
|
+
|
|
1521
1571
|
if (bytesAsB64?.length) {
|
|
1522
1572
|
const contentData = new TextUtils.ContentData.ContentData(bytesAsB64, /* isBase64=*/ true, blob.type);
|
|
1523
1573
|
await Workspace.FileManager.FileManager.instance().save(fileName, contentData, /* forceSaveAs=*/ true);
|
|
@@ -1531,6 +1581,9 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
1531
1581
|
a.click();
|
|
1532
1582
|
URL.revokeObjectURL(url);
|
|
1533
1583
|
}
|
|
1584
|
+
|
|
1585
|
+
this.statusDialog.remove();
|
|
1586
|
+
this.statusDialog = null;
|
|
1534
1587
|
}
|
|
1535
1588
|
|
|
1536
1589
|
async handleSaveToFileAction(): Promise<void> {
|
|
@@ -1794,41 +1847,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
1794
1847
|
return navigationEntry.url as Platform.DevToolsPath.UrlString;
|
|
1795
1848
|
}
|
|
1796
1849
|
|
|
1797
|
-
async #navigateToAboutBlank(): Promise<void> {
|
|
1798
|
-
const aboutBlankNavigationComplete = new Promise<void>(async (resolve, reject) => {
|
|
1799
|
-
if (!this.controller) {
|
|
1800
|
-
reject('Could not find TimelineController');
|
|
1801
|
-
return;
|
|
1802
|
-
}
|
|
1803
|
-
const target = this.controller.primaryPageTarget;
|
|
1804
|
-
const resourceModel = target.model(SDK.ResourceTreeModel.ResourceTreeModel);
|
|
1805
|
-
if (!resourceModel) {
|
|
1806
|
-
reject('Could not load resourceModel');
|
|
1807
|
-
return;
|
|
1808
|
-
}
|
|
1809
|
-
|
|
1810
|
-
/**
|
|
1811
|
-
* To clear out the page and any state from prior test runs, we
|
|
1812
|
-
* navigate to about:blank before initiating the trace recording.
|
|
1813
|
-
* Once we have navigated to about:blank, we start recording and
|
|
1814
|
-
* then navigate to the original page URL, to ensure we profile the
|
|
1815
|
-
* page load.
|
|
1816
|
-
**/
|
|
1817
|
-
function waitForAboutBlank(event: Common.EventTarget.EventTargetEvent<SDK.ResourceTreeModel.ResourceTreeFrame>):
|
|
1818
|
-
void {
|
|
1819
|
-
if (event.data.url === 'about:blank') {
|
|
1820
|
-
resolve();
|
|
1821
|
-
} else {
|
|
1822
|
-
reject(`Unexpected navigation to ${event.data.url}`);
|
|
1823
|
-
}
|
|
1824
|
-
resourceModel?.removeEventListener(SDK.ResourceTreeModel.Events.FrameNavigated, waitForAboutBlank);
|
|
1825
|
-
}
|
|
1826
|
-
resourceModel.addEventListener(SDK.ResourceTreeModel.Events.FrameNavigated, waitForAboutBlank);
|
|
1827
|
-
await resourceModel.navigate('about:blank' as Platform.DevToolsPath.UrlString);
|
|
1828
|
-
});
|
|
1829
|
-
await aboutBlankNavigationComplete;
|
|
1830
|
-
}
|
|
1831
|
-
|
|
1832
1850
|
async #startCPUProfilingRecording(): Promise<void> {
|
|
1833
1851
|
try {
|
|
1834
1852
|
this.cpuProfiler = UI.Context.Context.instance().flavor(SDK.CPUProfilerModel.CPUProfilerModel);
|
|
@@ -1889,30 +1907,18 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
1889
1907
|
}
|
|
1890
1908
|
|
|
1891
1909
|
const urlToTrace = await this.#evaluateInspectedURL();
|
|
1892
|
-
|
|
1893
|
-
//
|
|
1894
|
-
|
|
1895
|
-
// timeline will show data & screenshots from a previous page load that
|
|
1896
|
-
// was not relevant.
|
|
1897
|
-
if (this.recordingPageReload) {
|
|
1898
|
-
await this.#navigateToAboutBlank();
|
|
1899
|
-
}
|
|
1900
|
-
const recordingOptions = {
|
|
1910
|
+
|
|
1911
|
+
// Order is important here: we tell the controller to start recording, which enables tracing.
|
|
1912
|
+
await this.controller.startRecording({
|
|
1901
1913
|
enableJSSampling: !this.disableCaptureJSProfileSetting.get(),
|
|
1902
1914
|
capturePictures: this.captureLayersAndPicturesSetting.get(),
|
|
1903
1915
|
captureFilmStrip: this.showScreenshotsSetting.get(),
|
|
1904
1916
|
captureSelectorStats: this.captureSelectorStatsSetting.get(),
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
if (response.getError()) {
|
|
1909
|
-
throw new Error(response.getError());
|
|
1910
|
-
}
|
|
1917
|
+
navigateToUrl: this.recordingPageReload ? urlToTrace : undefined,
|
|
1918
|
+
});
|
|
1919
|
+
|
|
1911
1920
|
// Once we get here, we know tracing is active.
|
|
1912
|
-
|
|
1913
|
-
// If the user has just hit "record", we don't do any navigating.
|
|
1914
|
-
const recordingConfig = this.recordingPageReload ? {navigateToUrl: urlToTrace} : undefined;
|
|
1915
|
-
this.recordingStarted(recordingConfig);
|
|
1921
|
+
this.recordingStarted();
|
|
1916
1922
|
} catch (e) {
|
|
1917
1923
|
await this.recordingFailed(e.message);
|
|
1918
1924
|
}
|
|
@@ -1965,7 +1971,7 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
1965
1971
|
{
|
|
1966
1972
|
description: error,
|
|
1967
1973
|
buttonText: i18nString(UIStrings.close),
|
|
1968
|
-
hideStopButton:
|
|
1974
|
+
hideStopButton: false,
|
|
1969
1975
|
showProgress: undefined,
|
|
1970
1976
|
showTimer: undefined,
|
|
1971
1977
|
},
|
|
@@ -2055,7 +2061,7 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
2055
2061
|
|
|
2056
2062
|
private onClearButton(): void {
|
|
2057
2063
|
this.#historyManager.clear();
|
|
2058
|
-
this.#
|
|
2064
|
+
this.#instantiateNewModel();
|
|
2059
2065
|
ModificationsManager.reset();
|
|
2060
2066
|
this.#uninstallSourceMapsResolver();
|
|
2061
2067
|
this.flameChart.getMainDataProvider().reset();
|
|
@@ -2364,28 +2370,11 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
2364
2370
|
return ThemeSupport.ThemeSupport.instance().getComputedValue('--app-color-system');
|
|
2365
2371
|
}
|
|
2366
2372
|
|
|
2367
|
-
private recordingStarted(
|
|
2368
|
-
if (config && this.recordingPageReload && this.controller) {
|
|
2369
|
-
// If the user hit "Reload & record", by this point we have:
|
|
2370
|
-
// 1. Navigated to about:blank
|
|
2371
|
-
// 2. Initiated tracing.
|
|
2372
|
-
// We therefore now should navigate back to the original URL that the user wants to profile.
|
|
2373
|
-
const resourceModel = this.controller?.primaryPageTarget.model(SDK.ResourceTreeModel.ResourceTreeModel);
|
|
2374
|
-
if (!resourceModel) {
|
|
2375
|
-
void this.recordingFailed('Could not navigate to original URL');
|
|
2376
|
-
return;
|
|
2377
|
-
}
|
|
2378
|
-
// We don't need to await this because we are purposefully showing UI
|
|
2379
|
-
// progress as the page loads & tracing is underway.
|
|
2380
|
-
void resourceModel.navigate(config.navigateToUrl);
|
|
2381
|
-
}
|
|
2382
|
-
|
|
2373
|
+
private recordingStarted(): void {
|
|
2383
2374
|
this.#changeView({mode: 'STATUS_PANE_OVERLAY'});
|
|
2384
2375
|
this.setState(State.RECORDING);
|
|
2385
|
-
this.showRecordingStarted();
|
|
2386
2376
|
if (this.statusDialog) {
|
|
2387
2377
|
this.statusDialog.enableAndFocusButton();
|
|
2388
|
-
this.statusDialog.updateStatus(i18nString(UIStrings.tracing));
|
|
2389
2378
|
this.statusDialog.updateProgressBar(i18nString(UIStrings.bufferUsage), 0);
|
|
2390
2379
|
this.statusDialog.startTimer();
|
|
2391
2380
|
}
|
|
@@ -2397,6 +2386,12 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
2397
2386
|
}
|
|
2398
2387
|
}
|
|
2399
2388
|
|
|
2389
|
+
recordingStatus(status: string): void {
|
|
2390
|
+
if (this.statusDialog) {
|
|
2391
|
+
this.statusDialog.updateStatus(status);
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
|
|
2400
2395
|
/**
|
|
2401
2396
|
* Hide the sidebar, but persist the user's state, because when they import a
|
|
2402
2397
|
* trace we want to revert the sidebar back to what it was.
|
|
@@ -2467,23 +2462,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
2467
2462
|
this.statusDialog?.updateStatus(i18nString(UIStrings.processingTrace));
|
|
2468
2463
|
}
|
|
2469
2464
|
|
|
2470
|
-
#listenForProcessingProgress(): void {
|
|
2471
|
-
this.#traceEngineModel.addEventListener(Trace.TraceModel.ModelUpdateEvent.eventName, e => {
|
|
2472
|
-
const updateEvent = e as Trace.TraceModel.ModelUpdateEvent;
|
|
2473
|
-
const str = i18nString(UIStrings.processed);
|
|
2474
|
-
|
|
2475
|
-
// Trace Engine will report progress from [0...1] but we still have more work to do. So, scale them down a bit.
|
|
2476
|
-
const traceParseMaxProgress = 0.7;
|
|
2477
|
-
|
|
2478
|
-
if (updateEvent.data.type === Trace.TraceModel.ModelUpdateType.COMPLETE) {
|
|
2479
|
-
this.statusDialog?.updateProgressBar(str, 100 * traceParseMaxProgress);
|
|
2480
|
-
} else if (updateEvent.data.type === Trace.TraceModel.ModelUpdateType.PROGRESS_UPDATE) {
|
|
2481
|
-
const data = updateEvent.data.data;
|
|
2482
|
-
this.statusDialog?.updateProgressBar(str, data.percent * 100 * traceParseMaxProgress);
|
|
2483
|
-
}
|
|
2484
|
-
});
|
|
2485
|
-
}
|
|
2486
|
-
|
|
2487
2465
|
#onSourceMapsNodeNamesResolved(): void {
|
|
2488
2466
|
// Source maps can change the way calls hierarchies should look in
|
|
2489
2467
|
// the flame chart (f.e. if some calls are ignore listed after
|
|
@@ -2855,7 +2833,7 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
2855
2833
|
},
|
|
2856
2834
|
() => this.stopRecording());
|
|
2857
2835
|
this.statusDialog.showPane(this.statusPaneContainer);
|
|
2858
|
-
this.statusDialog.updateStatus(i18nString(UIStrings.
|
|
2836
|
+
this.statusDialog.updateStatus(i18nString(UIStrings.tracing));
|
|
2859
2837
|
this.statusDialog.updateProgressBar(i18nString(UIStrings.bufferUsage), 0);
|
|
2860
2838
|
}
|
|
2861
2839
|
|
|
@@ -2865,24 +2843,6 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
2865
2843
|
}
|
|
2866
2844
|
}
|
|
2867
2845
|
|
|
2868
|
-
private async loadEventFired(
|
|
2869
|
-
event: Common.EventTarget
|
|
2870
|
-
.EventTargetEvent<{resourceTreeModel: SDK.ResourceTreeModel.ResourceTreeModel, loadTime: number}>):
|
|
2871
|
-
Promise<void> {
|
|
2872
|
-
if (this.state !== State.RECORDING || !this.recordingPageReload ||
|
|
2873
|
-
this.controller?.primaryPageTarget !== event.data.resourceTreeModel.target()) {
|
|
2874
|
-
return;
|
|
2875
|
-
}
|
|
2876
|
-
const controller = this.controller;
|
|
2877
|
-
await new Promise(r => window.setTimeout(r, this.millisecondsToRecordAfterLoadEvent));
|
|
2878
|
-
|
|
2879
|
-
// Check if we're still in the same recording session.
|
|
2880
|
-
if (controller !== this.controller || this.state !== State.RECORDING) {
|
|
2881
|
-
return;
|
|
2882
|
-
}
|
|
2883
|
-
void this.stopRecording();
|
|
2884
|
-
}
|
|
2885
|
-
|
|
2886
2846
|
private frameForSelection(selection: TimelineSelection): Trace.Types.Events.LegacyTimelineFrame|null {
|
|
2887
2847
|
if (this.#viewMode.mode !== 'VIEWING_TRACE') {
|
|
2888
2848
|
return null;
|
|
@@ -3061,7 +3021,7 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
|
3061
3021
|
* 3. Flash the Insight with the highlight colour we use in other panels.
|
|
3062
3022
|
*/
|
|
3063
3023
|
revealInsight(insightModel: Trace.Insights.Types.InsightModel): void {
|
|
3064
|
-
const insightSetKey = insightModel.navigationId ?? Trace.Types.Events.NO_NAVIGATION;
|
|
3024
|
+
const insightSetKey = insightModel.navigation?.args.data?.navigationId ?? Trace.Types.Events.NO_NAVIGATION;
|
|
3065
3025
|
this.#setActiveInsight({model: insightModel, insightSetKey}, {highlightInsight: true});
|
|
3066
3026
|
}
|
|
3067
3027
|
|
|
@@ -171,6 +171,7 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
|
171
171
|
export class TimelineTreeView extends
|
|
172
172
|
Common.ObjectWrapper.eventMixin<TimelineTreeView.EventTypes, typeof UI.Widget.VBox>(UI.Widget.VBox)
|
|
173
173
|
implements UI.SearchableView.Searchable {
|
|
174
|
+
/** This is sorted by ts. */
|
|
174
175
|
#selectedEvents: Trace.Types.Events.Event[]|null;
|
|
175
176
|
private searchResults: Trace.Extras.TraceTree.Node[];
|
|
176
177
|
linkifier!: Components.Linkifier.Linkifier;
|
|
@@ -824,6 +824,10 @@ export class TimelineUIUtils {
|
|
|
824
824
|
link = 'https://web.dev/lcp/';
|
|
825
825
|
name = 'largest contentful paint';
|
|
826
826
|
break;
|
|
827
|
+
case Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION:
|
|
828
|
+
link = 'https://developer.chrome.com/docs/web-platform/soft-navigations-experiment';
|
|
829
|
+
name = 'largest contentful paint (soft navigation)';
|
|
830
|
+
break;
|
|
827
831
|
case Trace.Types.Events.Name.MARK_FCP:
|
|
828
832
|
link = 'https://web.dev/first-contentful-paint/';
|
|
829
833
|
name = 'first contentful paint';
|
|
@@ -1001,6 +1005,20 @@ export class TimelineUIUtils {
|
|
|
1001
1005
|
return contentHelper.fragment;
|
|
1002
1006
|
}
|
|
1003
1007
|
|
|
1008
|
+
if (Trace.Types.Events.isNavigationStart(event)) {
|
|
1009
|
+
url = (event.args.data?.documentLoaderURL ?? event.args.data?.url) as Platform.DevToolsPath.UrlString;
|
|
1010
|
+
if (url) {
|
|
1011
|
+
contentHelper.appendElementRow(i18nString(UIStrings.url), LegacyComponents.Linkifier.Linkifier.linkifyURL(url));
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
if (Trace.Types.Events.isSoftNavigationStart(event)) {
|
|
1016
|
+
url = event.args.context.URL as Platform.DevToolsPath.UrlString;
|
|
1017
|
+
if (url) {
|
|
1018
|
+
contentHelper.appendElementRow(i18nString(UIStrings.url), LegacyComponents.Linkifier.Linkifier.linkifyURL(url));
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1004
1022
|
if (Trace.Types.Events.isV8Compile(event)) {
|
|
1005
1023
|
url = event.args.data?.url as Platform.DevToolsPath.UrlString;
|
|
1006
1024
|
if (url) {
|
|
@@ -1428,6 +1446,7 @@ export class TimelineUIUtils {
|
|
|
1428
1446
|
break;
|
|
1429
1447
|
}
|
|
1430
1448
|
|
|
1449
|
+
case Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION:
|
|
1431
1450
|
// @ts-expect-error Fall-through intended.
|
|
1432
1451
|
case Trace.Types.Events.Name.MARK_LCP_CANDIDATE: {
|
|
1433
1452
|
contentHelper.appendTextRow(i18nString(UIStrings.type), String(unsafeEventData['type']));
|
|
@@ -2244,6 +2263,10 @@ export class TimelineUIUtils {
|
|
|
2244
2263
|
color = 'var(--color-text-primary)';
|
|
2245
2264
|
tall = true;
|
|
2246
2265
|
break;
|
|
2266
|
+
case Trace.Types.Events.Name.SOFT_NAVIGATION_START:
|
|
2267
|
+
color = 'var(--sys-color-blue)';
|
|
2268
|
+
tall = true;
|
|
2269
|
+
break;
|
|
2247
2270
|
case Trace.Types.Events.Name.FRAME_STARTED_LOADING:
|
|
2248
2271
|
color = 'green';
|
|
2249
2272
|
tall = true;
|
|
@@ -2264,6 +2287,7 @@ export class TimelineUIUtils {
|
|
|
2264
2287
|
color = 'var(--sys-color-green-bright)';
|
|
2265
2288
|
tall = true;
|
|
2266
2289
|
break;
|
|
2290
|
+
case Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION:
|
|
2267
2291
|
case Trace.Types.Events.Name.MARK_LCP_CANDIDATE:
|
|
2268
2292
|
color = 'var(--sys-color-green)';
|
|
2269
2293
|
tall = true;
|
|
@@ -2509,6 +2533,7 @@ export function timeStampForEventAdjustedForClosestNavigationIfPossible(
|
|
|
2509
2533
|
event,
|
|
2510
2534
|
parsedTrace.data.Meta.traceBounds,
|
|
2511
2535
|
parsedTrace.data.Meta.navigationsByNavigationId,
|
|
2536
|
+
parsedTrace.data.Meta.softNavigationsById,
|
|
2512
2537
|
parsedTrace.data.Meta.navigationsByFrameId,
|
|
2513
2538
|
);
|
|
2514
2539
|
return Trace.Helpers.Timing.microToMilli(time);
|
|
@@ -2523,7 +2548,8 @@ export function timeStampForEventAdjustedForClosestNavigationIfPossible(
|
|
|
2523
2548
|
export function isMarkerEvent(parsedTrace: Trace.TraceModel.ParsedTrace, event: Trace.Types.Events.Event): boolean {
|
|
2524
2549
|
const {Name} = Trace.Types.Events;
|
|
2525
2550
|
|
|
2526
|
-
if (event.name === Name.TIME_STAMP || event.name === Name.NAVIGATION_START
|
|
2551
|
+
if (event.name === Name.TIME_STAMP || event.name === Name.NAVIGATION_START ||
|
|
2552
|
+
event.name === Name.SOFT_NAVIGATION_START) {
|
|
2527
2553
|
return true;
|
|
2528
2554
|
}
|
|
2529
2555
|
|
|
@@ -2532,7 +2558,7 @@ export function isMarkerEvent(parsedTrace: Trace.TraceModel.ParsedTrace, event:
|
|
|
2532
2558
|
}
|
|
2533
2559
|
|
|
2534
2560
|
if (Trace.Types.Events.isMarkDOMContent(event) || Trace.Types.Events.isMarkLoad(event) ||
|
|
2535
|
-
Trace.Types.Events.
|
|
2561
|
+
Trace.Types.Events.isAnyLargestContentfulPaintCandidate(event)) {
|
|
2536
2562
|
// isOutermostMainFrame was added in 2022, so we fallback to isMainFrame
|
|
2537
2563
|
// for older traces.
|
|
2538
2564
|
if (!event.args.data) {
|
|
@@ -42,6 +42,7 @@ export const SORT_ORDER_PAGE_LOAD_MARKERS: Readonly<Record<string, number>> = {
|
|
|
42
42
|
[Trace.Types.Events.Name.MARK_FIRST_PAINT]: 2,
|
|
43
43
|
[Trace.Types.Events.Name.MARK_DOM_CONTENT]: 3,
|
|
44
44
|
[Trace.Types.Events.Name.MARK_LCP_CANDIDATE]: 4,
|
|
45
|
+
[Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION]: 5,
|
|
45
46
|
};
|
|
46
47
|
|
|
47
48
|
export class TimingsTrackAppender implements TrackAppender {
|
|
@@ -182,7 +183,7 @@ export class TimingsTrackAppender implements TrackAppender {
|
|
|
182
183
|
color = '#1A6937';
|
|
183
184
|
title = Trace.Handlers.ModelHandlers.PageLoadMetrics.MetricName.FCP;
|
|
184
185
|
}
|
|
185
|
-
if (Trace.Types.Events.
|
|
186
|
+
if (Trace.Types.Events.isAnyLargestContentfulPaintCandidate(markerEvent)) {
|
|
186
187
|
color = '#1A3422';
|
|
187
188
|
title = Trace.Handlers.ModelHandlers.PageLoadMetrics.MetricName.LCP;
|
|
188
189
|
}
|
|
@@ -282,6 +283,7 @@ export class TimingsTrackAppender implements TrackAppender {
|
|
|
282
283
|
event,
|
|
283
284
|
this.#parsedTrace.data.Meta.traceBounds,
|
|
284
285
|
this.#parsedTrace.data.Meta.navigationsByNavigationId,
|
|
286
|
+
this.#parsedTrace.data.Meta.softNavigationsById,
|
|
285
287
|
this.#parsedTrace.data.Meta.navigationsByFrameId,
|
|
286
288
|
);
|
|
287
289
|
info.formattedTime = getDurationString(timeOfEvent);
|
|
@@ -84,7 +84,7 @@ interface InsightData {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
interface LocalMetrics {
|
|
87
|
-
lcp: {value: Trace.Types.Timing.Micro, event: Trace.Types.Events.
|
|
87
|
+
lcp: {value: Trace.Types.Timing.Micro, event: Trace.Types.Events.AnyLargestContentfulPaintCandidate}|null;
|
|
88
88
|
cls: {value: number, worstClusterEvent: Trace.Types.Events.Event|null};
|
|
89
89
|
inp: {value: Trace.Types.Timing.Micro, event: Trace.Types.Events.SyntheticInteractionPair}|null;
|
|
90
90
|
}
|
|
@@ -75,7 +75,7 @@ interface ViewInput {
|
|
|
75
75
|
estimatedSavingsAriaLabel: string|null;
|
|
76
76
|
renderContent: () => Lit.LitTemplate;
|
|
77
77
|
dispatchInsightToggle: () => void;
|
|
78
|
-
onHeaderKeyDown: () => void;
|
|
78
|
+
onHeaderKeyDown: (event: KeyboardEvent) => void;
|
|
79
79
|
onAskAIButtonClick: () => void;
|
|
80
80
|
}
|
|
81
81
|
|
|
@@ -412,7 +412,7 @@ export abstract class BaseInsightComponent<T extends InsightModel> extends UI.Wi
|
|
|
412
412
|
showAskAI: this.#canShowAskAI(),
|
|
413
413
|
dispatchInsightToggle: () => this.#dispatchInsightToggle(),
|
|
414
414
|
renderContent: () => this.renderContent(),
|
|
415
|
-
onHeaderKeyDown:
|
|
415
|
+
onHeaderKeyDown: this.#onHeaderKeyDown.bind(this),
|
|
416
416
|
onAskAIButtonClick: () => this.#onAskAIButtonClick(),
|
|
417
417
|
};
|
|
418
418
|
this.#view(input, undefined, this.contentElement);
|
|
@@ -5,15 +5,17 @@
|
|
|
5
5
|
import * as i18n from '../../../../core/i18n/i18n.js';
|
|
6
6
|
import type {RenderBlockingInsightModel} from '../../../../models/trace/insights/RenderBlocking.js';
|
|
7
7
|
import * as Trace from '../../../../models/trace/trace.js';
|
|
8
|
+
import * as UI from '../../../../ui/legacy/legacy.js';
|
|
8
9
|
import * as Lit from '../../../../ui/lit/lit.js';
|
|
9
10
|
|
|
10
11
|
import {BaseInsightComponent} from './BaseInsightComponent.js';
|
|
11
12
|
import {eventRef} from './EventRef.js';
|
|
12
|
-
import {createLimitedRows, renderOthersLabel, type TableDataRow} from './Table.js';
|
|
13
|
+
import {createLimitedRows, renderOthersLabel, Table, type TableDataRow} from './Table.js';
|
|
13
14
|
|
|
14
15
|
const {UIStrings, i18nString, createOverlayForRequest} = Trace.Insights.Models.RenderBlocking;
|
|
15
16
|
|
|
16
17
|
const {html} = Lit;
|
|
18
|
+
const {widgetConfig} = UI.Widget;
|
|
17
19
|
|
|
18
20
|
export class RenderBlocking extends BaseInsightComponent<RenderBlockingInsightModel> {
|
|
19
21
|
override internalName = 'render-blocking-requests';
|
|
@@ -58,12 +60,12 @@ export class RenderBlocking extends BaseInsightComponent<RenderBlockingInsightMo
|
|
|
58
60
|
// clang-format off
|
|
59
61
|
return html`
|
|
60
62
|
<div class="insight-section">
|
|
61
|
-
<devtools-widget
|
|
62
|
-
|
|
63
|
+
<devtools-widget .widgetConfig=${widgetConfig(Table, {
|
|
64
|
+
data: {
|
|
63
65
|
insight: this,
|
|
64
66
|
headers: [i18nString(UIStrings.renderBlockingRequest), i18nString(UIStrings.duration)],
|
|
65
67
|
rows,
|
|
66
|
-
}}>
|
|
68
|
+
}})}>
|
|
67
69
|
</devtools-widget>
|
|
68
70
|
</div>
|
|
69
71
|
`;
|
|
@@ -239,11 +239,11 @@ export class Table extends UI.Widget.Widget {
|
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
#onHoverRow(row: TableDataRow, rowEl: HTMLElement): void {
|
|
242
|
-
if (row === this.#currentHoverRow) {
|
|
242
|
+
if (row === this.#currentHoverRow || !this.element.shadowRoot) {
|
|
243
243
|
return;
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
-
for (const el of this.element.querySelectorAll('.hover')) {
|
|
246
|
+
for (const el of this.element.shadowRoot.querySelectorAll('.hover')) {
|
|
247
247
|
el.classList.remove('hover');
|
|
248
248
|
}
|
|
249
249
|
|
|
@@ -251,7 +251,7 @@ export class Table extends UI.Widget.Widget {
|
|
|
251
251
|
let curRow: TableDataRow|undefined = this.#rowToParentRow.get(row);
|
|
252
252
|
while (curRow) {
|
|
253
253
|
rowEl.classList.add('hover');
|
|
254
|
-
curRow = this.#rowToParentRow.get(
|
|
254
|
+
curRow = this.#rowToParentRow.get(curRow);
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
this.#currentHoverRow = row;
|
|
@@ -1616,6 +1616,10 @@ export class Overlays extends EventTarget {
|
|
|
1616
1616
|
#mouseMoveOverlay(
|
|
1617
1617
|
e: MouseEvent, event: Trace.Types.Events.PageLoadEvent, name: string, overlay: Trace.Types.Overlays.TimingsMarker,
|
|
1618
1618
|
markers: HTMLElement, marker: HTMLElement): void {
|
|
1619
|
+
if (Trace.Types.Events.isSoftNavigationStart(event)) {
|
|
1620
|
+
name = 'Soft Nav';
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1619
1623
|
const fieldResult = overlay.entryToFieldResult.get(event);
|
|
1620
1624
|
const popoverElement = this.#createOverlayPopover(overlay.adjustedTimestamp, name, fieldResult);
|
|
1621
1625
|
this.#lastMouseOffsetX = e.offsetX + (markers.offsetLeft || 0) + (marker.offsetLeft || 0);
|
|
@@ -90,11 +90,18 @@
|
|
|
90
90
|
pointer-events: none;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
.timeline.panel .status-pane-container.
|
|
93
|
+
.timeline.panel .status-pane-container.opaque {
|
|
94
94
|
background-color: var(--sys-color-cdt-base-container);
|
|
95
95
|
pointer-events: auto;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
.timeline.panel .status-pane-container.tinted {
|
|
99
|
+
/* stylelint-disable-next-line plugin/use_theme_colors */
|
|
100
|
+
background-color: #0005;
|
|
101
|
+
background-blend-mode: multiply;
|
|
102
|
+
pointer-events: auto;
|
|
103
|
+
}
|
|
104
|
+
|
|
98
105
|
.timeline-landing-page.legacy > div > p {
|
|
99
106
|
flex: none;
|
|
100
107
|
white-space: pre-line;
|
|
@@ -29,7 +29,8 @@ export function nodeIdsForEvent(
|
|
|
29
29
|
} else if (Trace.Types.Events.isSyntheticLayoutShift(event) && event.args.data?.impacted_nodes) {
|
|
30
30
|
event.args.data.impacted_nodes.forEach(node => foundIds.add(node.node_id));
|
|
31
31
|
} else if (
|
|
32
|
-
Trace.Types.Events.
|
|
32
|
+
Trace.Types.Events.isAnyLargestContentfulPaintCandidate(event) &&
|
|
33
|
+
typeof event.args.data?.nodeId !== 'undefined') {
|
|
33
34
|
foundIds.add(event.args.data.nodeId);
|
|
34
35
|
} else if (Trace.Types.Events.isPaint(event) && typeof event.args.data.nodeId !== 'undefined') {
|
|
35
36
|
foundIds.add(event.args.data.nodeId);
|
|
@@ -40,22 +40,28 @@ export function getReleaseNote(): ReleaseNote {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
let releaseNote: ReleaseNote = {
|
|
43
|
-
version:
|
|
44
|
-
header: 'What\'s new in DevTools
|
|
43
|
+
version: 144,
|
|
44
|
+
header: 'What\'s new in DevTools 144',
|
|
45
45
|
markdownLinks: [
|
|
46
|
+
{
|
|
47
|
+
key: 'request-conditions',
|
|
48
|
+
link: 'https://developer.chrome.com/blog/new-in-devtools-144/#request-conditions',
|
|
49
|
+
},
|
|
46
50
|
{
|
|
47
51
|
key: 'mcp-server',
|
|
48
|
-
link: 'https://developer.chrome.com/blog/new-in-devtools-
|
|
52
|
+
link: 'https://developer.chrome.com/blog/new-in-devtools-144/#mcp-server',
|
|
49
53
|
},
|
|
50
54
|
{
|
|
51
|
-
key: '
|
|
52
|
-
link: 'https://developer.chrome.com/blog/new-in-devtools-
|
|
55
|
+
key: 'adopted-stylesheets',
|
|
56
|
+
link: 'https://developer.chrome.com/blog/new-in-devtools-144/#adopted-stylesheets',
|
|
53
57
|
},
|
|
58
|
+
],
|
|
59
|
+
videoLinks: [
|
|
54
60
|
{
|
|
55
|
-
|
|
56
|
-
link: 'https://developer.chrome.com/blog/new-in-devtools-
|
|
61
|
+
description: 'See past highlights from Chrome 144',
|
|
62
|
+
link: 'https://developer.chrome.com/blog/new-in-devtools-144' as Platform.DevToolsPath.UrlString,
|
|
63
|
+
type: VideoType.WHATS_NEW,
|
|
57
64
|
},
|
|
58
65
|
],
|
|
59
|
-
|
|
60
|
-
link: 'https://developer.chrome.com/blog/new-in-devtools-143/',
|
|
66
|
+
link: 'https://developer.chrome.com/blog/new-in-devtools-144/',
|
|
61
67
|
};
|