chrome-devtools-frontend 1.0.1602348 → 1.0.1603822
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/.agents/skills/version-control/SKILL.md +17 -2
- package/AUTHORS +1 -0
- package/front_end/core/common/Settings.ts +1 -871
- package/front_end/core/common/VersionController.ts +880 -0
- package/front_end/core/common/common.ts +2 -0
- package/front_end/core/platform/HostRuntime.ts +9 -3
- package/front_end/core/protocol_client/InspectorBackend.ts +8 -0
- package/front_end/core/root/Runtime.ts +5 -0
- package/front_end/core/sdk/OverlayModel.ts +13 -13
- package/front_end/core/sdk/OverlayPersistentHighlighter.ts +13 -10
- package/front_end/core/sdk/RuntimeModel.ts +5 -5
- package/front_end/core/sdk/ServiceWorkerManager.ts +4 -2
- package/front_end/core/sdk/Target.ts +5 -0
- package/front_end/core/sdk/TargetManager.ts +5 -0
- package/front_end/core/sdk/WebMCPModel.ts +104 -0
- package/front_end/core/sdk/sdk.ts +2 -0
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +13 -19
- package/front_end/generated/InspectorBackendCommands.ts +3 -0
- package/front_end/generated/protocol-mapping.d.ts +8 -0
- package/front_end/generated/protocol-proxy-api.d.ts +10 -0
- package/front_end/generated/protocol.ts +57 -0
- package/front_end/models/ai_assistance/AiConversation.ts +3 -3
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +50 -0
- package/front_end/models/ai_assistance/agents/AiAgent.ts +14 -1
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +19 -4
- package/front_end/models/ai_assistance/agents/NetworkAgent.ts +7 -1
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +30 -7
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +0 -23
- package/front_end/models/ai_assistance/data_formatters/LighthouseFormatter.snapshot.txt +60 -9
- package/front_end/models/ai_assistance/data_formatters/LighthouseFormatter.ts +71 -15
- package/front_end/models/heap_snapshot_model/HeapSnapshotModel.ts +7 -7
- package/front_end/models/javascript_metadata/NativeFunctions.js +6 -2
- package/front_end/models/lighthouse/LighthouseReporterTypes.ts +10 -8
- package/front_end/models/lighthouse/RunTypes.ts +3 -1
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +13 -5
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +143 -18
- package/front_end/panels/ai_assistance/components/WalkthroughView.ts +30 -10
- package/front_end/panels/ai_assistance/components/chatMessage.css +58 -3
- package/front_end/panels/ai_assistance/components/walkthroughView.css +35 -5
- package/front_end/panels/application/AppManifestView.ts +2 -2
- package/front_end/panels/application/BackgroundServiceView.ts +9 -9
- package/front_end/panels/application/FrameDetailsView.ts +4 -13
- package/front_end/panels/application/IndexedDBViews.ts +1 -1
- package/front_end/panels/application/ServiceWorkerCacheViews.ts +3 -3
- package/front_end/panels/application/components/PermissionsPolicySection.ts +1 -1
- package/front_end/panels/application/components/permissionsPolicySection.css +54 -52
- package/front_end/panels/application/frameDetailsReportView.css +13 -1
- package/front_end/panels/common/ThrottlingUtils.ts +46 -0
- package/front_end/panels/common/common.ts +1 -0
- package/front_end/panels/elements/CSSValueTraceView.ts +9 -1
- package/front_end/panels/elements/ComputedStyleWidget.ts +11 -1
- package/front_end/panels/elements/PropertiesWidget.ts +14 -13
- package/front_end/panels/elements/PropertyRenderer.ts +10 -9
- package/front_end/panels/elements/StandaloneStylesContainer.ts +15 -5
- package/front_end/panels/elements/StylePropertiesSection.ts +0 -49
- package/front_end/panels/elements/StylePropertyTreeElement.ts +20 -0
- package/front_end/panels/elements/StylesContainer.ts +0 -1
- package/front_end/panels/elements/StylesSidebarPane.ts +65 -31
- package/front_end/panels/elements/stylePropertiesTreeOutline.css +5 -0
- package/front_end/panels/issues/AffectedSelectivePermissionsInterventionView.ts +2 -2
- package/front_end/panels/lighthouse/LighthouseController.ts +4 -1
- package/front_end/panels/media/EventDisplayTable.ts +3 -2
- package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +14 -0
- package/front_end/panels/network/EventSourceMessagesView.ts +2 -2
- package/front_end/panels/network/ResourceChunkView.ts +1 -1
- package/front_end/panels/profiler/HeapDetachedElementsView.ts +9 -4
- package/front_end/panels/profiler/HeapProfileView.ts +8 -4
- package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +40 -33
- package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +1 -1
- package/front_end/panels/profiler/HeapSnapshotProxy.ts +1 -1
- package/front_end/panels/profiler/HeapSnapshotView.ts +12 -18
- package/front_end/panels/profiler/LiveHeapProfileView.ts +3 -4
- package/front_end/panels/profiler/ProfileHeader.ts +5 -11
- package/front_end/panels/profiler/ProfileView.ts +1 -10
- package/front_end/panels/sensors/SensorsView.ts +24 -43
- package/front_end/panels/settings/keybindsSettingsTab.css +25 -31
- package/front_end/panels/timeline/EventsTimelineTreeView.ts +2 -2
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +8 -0
- package/front_end/panels/timeline/TimelinePanel.ts +14 -2
- package/front_end/panels/timeline/TimelineTreeView.ts +19 -17
- package/front_end/panels/timeline/components/FieldSettingsDialog.ts +5 -9
- package/front_end/panels/timeline/components/LiveMetricsView.ts +1 -2
- package/front_end/panels/timeline/components/OriginMap.ts +176 -159
- package/front_end/panels/timeline/components/originMap.css +4 -51
- package/front_end/panels/timeline/components/timelineRangeSummaryView.css +3 -1
- package/front_end/panels/timeline/thirdPartyTreeView.css +6 -0
- package/front_end/panels/timeline/timeline-meta.ts +11 -0
- package/front_end/panels/timeline/utils/Helpers.ts +5 -25
- package/front_end/panels/webauthn/WebauthnPane.ts +52 -0
- package/front_end/third_party/acorn/README.chromium +1 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/{list → lists}/List.ts +1 -1
- package/front_end/ui/components/{list → lists}/list.css +0 -1
- package/front_end/ui/legacy/Treeoutline.ts +7 -3
- package/front_end/ui/legacy/UIUtils.ts +13 -11
- package/front_end/ui/legacy/Widget.ts +5 -0
- package/front_end/ui/legacy/components/data_grid/DataGrid.ts +1 -1
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +3 -3
- package/front_end/ui/legacy/components/data_grid/SortableDataGrid.ts +2 -2
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +39 -23
- package/front_end/ui/legacy/components/perf_ui/GCActionDelegate.ts +20 -4
- package/front_end/ui/legacy/treeoutline.css +4 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
- package/package.json +1 -1
- /package/front_end/ui/components/{list → lists}/lists.ts +0 -0
|
@@ -82,10 +82,17 @@ export interface ReportJSON {
|
|
|
82
82
|
export type DetailsJSON =
|
|
83
83
|
|TableDetailsJSON|OpportunityDetailsJSON|FilmstripDetailsJSON|ScreenshotDetailsJSON|DebugDataDetailsJSON;
|
|
84
84
|
|
|
85
|
+
export interface SubItemsJSON {
|
|
86
|
+
type: 'subitems';
|
|
87
|
+
items: Array<Record<string, TableItemValue>>;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export type TableItem = Record<string, TableItemValue|SubItemsJSON|undefined>;
|
|
91
|
+
|
|
85
92
|
export interface TableDetailsJSON {
|
|
86
93
|
type: 'table';
|
|
87
94
|
headings: TableHeadingJSON[];
|
|
88
|
-
items:
|
|
95
|
+
items: TableItem[];
|
|
89
96
|
summary?: OpportunitySummary;
|
|
90
97
|
}
|
|
91
98
|
|
|
@@ -96,7 +103,7 @@ export interface TableHeadingJSON {
|
|
|
96
103
|
itemType?: string;
|
|
97
104
|
subItemsHeading?: {
|
|
98
105
|
key: string,
|
|
99
|
-
valueType
|
|
106
|
+
valueType?: string,
|
|
100
107
|
};
|
|
101
108
|
}
|
|
102
109
|
|
|
@@ -109,12 +116,7 @@ export type TableItemValue =|string|number|NodeDetailsJSON|SourceLocationDetails
|
|
|
109
116
|
export interface OpportunityDetailsJSON {
|
|
110
117
|
type: 'opportunity';
|
|
111
118
|
headings: TableHeadingJSON[];
|
|
112
|
-
items:
|
|
113
|
-
url: string,
|
|
114
|
-
wastedBytes?: number,
|
|
115
|
-
wastedMs?: number,
|
|
116
|
-
totalBytes?: number, [key: string]: unknown,
|
|
117
|
-
}>;
|
|
119
|
+
items: TableItem[];
|
|
118
120
|
overallSavingsMs: number;
|
|
119
121
|
overallSavingsBytes?: number;
|
|
120
122
|
}
|
|
@@ -6,6 +6,7 @@ import type * as Host from '../../core/host/host.js';
|
|
|
6
6
|
import type * as Platform from '../../core/platform/platform.js';
|
|
7
7
|
|
|
8
8
|
export type CategoryId = 'performance'|'accessibility'|'best-practices'|'seo';
|
|
9
|
+
export type RunMode = 'navigation'|'timespan'|'snapshot';
|
|
9
10
|
|
|
10
11
|
export interface Preset {
|
|
11
12
|
setting: Common.Settings.Setting<boolean>;
|
|
@@ -33,10 +34,11 @@ export interface Flags {
|
|
|
33
34
|
disableStorageReset?: boolean;
|
|
34
35
|
throttlingMethod?: string;
|
|
35
36
|
formFactor?: string|boolean;
|
|
36
|
-
mode?:
|
|
37
|
+
mode?: RunMode;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
export interface RunOverrides {
|
|
40
41
|
categoryIds?: CategoryId[];
|
|
42
|
+
mode?: RunMode;
|
|
41
43
|
isAIControlled?: boolean;
|
|
42
44
|
}
|
|
@@ -821,7 +821,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
821
821
|
return;
|
|
822
822
|
}
|
|
823
823
|
// If the UI changed, we reset the visibility of the AI Walkthrough.
|
|
824
|
-
this.#
|
|
824
|
+
this.#resetWalkthrough();
|
|
825
825
|
this.#walkthrough.isInlined = isNarrow;
|
|
826
826
|
this.requestUpdate();
|
|
827
827
|
}
|
|
@@ -888,8 +888,12 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
888
888
|
return await TimelinePanel.TimelinePanel.TimelinePanel.executeRecordAndReload();
|
|
889
889
|
}
|
|
890
890
|
|
|
891
|
-
async #handleLighthouseRun(
|
|
892
|
-
|
|
891
|
+
async #handleLighthouseRun(overrides?: LHModel.RunTypes.RunOverrides):
|
|
892
|
+
Promise<LHModel.ReporterTypes.ReportJSON|null> {
|
|
893
|
+
return await LighthousePanel.LighthousePanel.LighthousePanel.executeLighthouseRecording({
|
|
894
|
+
isAIControlled: true,
|
|
895
|
+
...overrides,
|
|
896
|
+
});
|
|
893
897
|
}
|
|
894
898
|
|
|
895
899
|
#getDefaultConversationType(): AiAssistanceModel.AiHistoryStorage.ConversationType|undefined {
|
|
@@ -988,6 +992,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
988
992
|
performanceRecordAndReload: this.#handlePerformanceRecordAndReload.bind(this),
|
|
989
993
|
onInspectElement: this.#handleInspectElement.bind(this),
|
|
990
994
|
networkTimeCalculator: NetworkPanel.NetworkPanel.NetworkPanel.instance().networkLogView.timeCalculator(),
|
|
995
|
+
lighthouseRecording: this.#handleLighthouseRun.bind(this),
|
|
991
996
|
});
|
|
992
997
|
}
|
|
993
998
|
}
|
|
@@ -1026,6 +1031,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1026
1031
|
performanceRecordAndReload: this.#handlePerformanceRecordAndReload.bind(this),
|
|
1027
1032
|
onInspectElement: this.#handleInspectElement.bind(this),
|
|
1028
1033
|
networkTimeCalculator: NetworkPanel.NetworkPanel.NetworkPanel.instance().networkLogView.timeCalculator(),
|
|
1034
|
+
lighthouseRecording: this.#handleLighthouseRun.bind(this),
|
|
1029
1035
|
});
|
|
1030
1036
|
this.#updateConversationState(conversation);
|
|
1031
1037
|
this.#conversation?.setContext(context);
|
|
@@ -1501,6 +1507,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1501
1507
|
performanceRecordAndReload: this.#handlePerformanceRecordAndReload.bind(this),
|
|
1502
1508
|
onInspectElement: this.#handleInspectElement.bind(this),
|
|
1503
1509
|
networkTimeCalculator: NetworkPanel.NetworkPanel.NetworkPanel.instance().networkLogView.timeCalculator(),
|
|
1510
|
+
lighthouseRecording: this.#handleLighthouseRun.bind(this),
|
|
1504
1511
|
});
|
|
1505
1512
|
}
|
|
1506
1513
|
this.#updateConversationState(conversation);
|
|
@@ -1556,7 +1563,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1556
1563
|
this.#updateConversationState();
|
|
1557
1564
|
}
|
|
1558
1565
|
|
|
1559
|
-
#
|
|
1566
|
+
#resetWalkthrough(): void {
|
|
1560
1567
|
this.#walkthrough.isExpanded = false;
|
|
1561
1568
|
this.#walkthrough.activeMessage = null;
|
|
1562
1569
|
}
|
|
@@ -1567,7 +1574,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1567
1574
|
}
|
|
1568
1575
|
|
|
1569
1576
|
// Ensure we clear the walkthrough so it doesn't hold onto a chat that is about to be deleted.
|
|
1570
|
-
this.#
|
|
1577
|
+
this.#resetWalkthrough();
|
|
1571
1578
|
|
|
1572
1579
|
void AiAssistanceModel.AiHistoryStorage.AiHistoryStorage.instance().deleteHistoryEntry(this.#conversation.id);
|
|
1573
1580
|
this.#updateConversationState();
|
|
@@ -1592,6 +1599,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
|
|
|
1592
1599
|
|
|
1593
1600
|
#handleNewChatRequest(): void {
|
|
1594
1601
|
this.#updateConversationState();
|
|
1602
|
+
this.#resetWalkthrough();
|
|
1595
1603
|
UI.ARIAUtils.LiveAnnouncer.alert(i18nString(UIStrings.newChatCreated));
|
|
1596
1604
|
|
|
1597
1605
|
if (Annotations.AnnotationRepository.annotationsEnabled()) {
|
|
@@ -14,9 +14,11 @@ import * as SDK from '../../../core/sdk/sdk.js';
|
|
|
14
14
|
import type * as Protocol from '../../../generated/protocol.js';
|
|
15
15
|
import type {
|
|
16
16
|
AiWidget, ComputedStyleAiWidget, CoreVitalsAiWidget, DomTreeAiWidget, LcpBreakdownAiWidget, PerformanceTraceAiWidget,
|
|
17
|
-
StylePropertiesAiWidget} from '../../../models/ai_assistance/agents/AiAgent.js';
|
|
17
|
+
StylePropertiesAiWidget, TimelineRangeSummaryAiWidget} from '../../../models/ai_assistance/agents/AiAgent.js';
|
|
18
18
|
import * as AiAssistanceModel from '../../../models/ai_assistance/ai_assistance.js';
|
|
19
19
|
import * as ComputedStyle from '../../../models/computed_style/computed_style.js';
|
|
20
|
+
import * as Trace from '../../../models/trace/trace.js';
|
|
21
|
+
import * as PanelsCommon from '../../../panels/common/common.js';
|
|
20
22
|
import * as Marked from '../../../third_party/marked/marked.js';
|
|
21
23
|
import * as Buttons from '../../../ui/components/buttons/buttons.js';
|
|
22
24
|
import * as Input from '../../../ui/components/input/input.js';
|
|
@@ -47,7 +49,10 @@ const SCROLL_ROUNDING_OFFSET = 1;
|
|
|
47
49
|
* Strings that don't need to be translated at this time.
|
|
48
50
|
*/
|
|
49
51
|
const UIStringsNotTranslate = {
|
|
50
|
-
|
|
52
|
+
/**
|
|
53
|
+
* @description Text used in the button to close an open walkthrough
|
|
54
|
+
*/
|
|
55
|
+
closeAgentWalkthrough: 'Close agent walkthrough',
|
|
51
56
|
/**
|
|
52
57
|
* @description The title of the button that allows submitting positive
|
|
53
58
|
* feedback about the response for AI assistance.
|
|
@@ -181,7 +186,23 @@ const UIStringsNotTranslate = {
|
|
|
181
186
|
/**
|
|
182
187
|
* @description Title used for revealing the performance trace.
|
|
183
188
|
*/
|
|
184
|
-
revealTrace: 'Reveal trace'
|
|
189
|
+
revealTrace: 'Reveal trace',
|
|
190
|
+
/**
|
|
191
|
+
* @description Title for the core web vitals widget.
|
|
192
|
+
*/
|
|
193
|
+
coreVitals: 'Core Web Vitals',
|
|
194
|
+
/**
|
|
195
|
+
* @description Title for the LCP breakdown widget.
|
|
196
|
+
*/
|
|
197
|
+
lcpBreakdown: 'LCP breakdown',
|
|
198
|
+
/**
|
|
199
|
+
* @description Title for the LCP element widget.
|
|
200
|
+
*/
|
|
201
|
+
lcpElement: 'LCP element',
|
|
202
|
+
/**
|
|
203
|
+
* @description Title for the performance summary widget.
|
|
204
|
+
*/
|
|
205
|
+
performanceSummary: 'Performance summary'
|
|
185
206
|
} as const;
|
|
186
207
|
|
|
187
208
|
export interface Step {
|
|
@@ -495,18 +516,25 @@ function renderWalkthroughSidebarButton(
|
|
|
495
516
|
}
|
|
496
517
|
|
|
497
518
|
const hasOneStepWithWidget = steps.some(step => step.widgets?.length);
|
|
498
|
-
const
|
|
519
|
+
const isOpen = input.message === input.walkthrough.activeMessage;
|
|
520
|
+
|
|
521
|
+
const title = isOpen ? lockedString(UIStringsNotTranslate.closeAgentWalkthrough) : walkthroughTitle({
|
|
499
522
|
isLoading: input.isLoading,
|
|
500
523
|
hasWidgets: hasOneStepWithWidget,
|
|
501
524
|
lastStep,
|
|
502
525
|
});
|
|
503
526
|
|
|
527
|
+
// The button should be tonal when there are widgets, but we only
|
|
528
|
+
// want to change it visually at the end once everything has stopped
|
|
529
|
+
// loading.
|
|
530
|
+
const variant = hasOneStepWithWidget && !input.isLoading ? Buttons.Button.Variant.TONAL : Buttons.Button.Variant.TEXT;
|
|
531
|
+
|
|
504
532
|
// clang-format off
|
|
505
533
|
return html`
|
|
506
534
|
<div class="walkthrough-toggle-container">
|
|
507
535
|
${input.isLoading ? html`<devtools-spinner></devtools-spinner>` : Lit.nothing}
|
|
508
536
|
<devtools-button
|
|
509
|
-
.variant=${
|
|
537
|
+
.variant=${variant}
|
|
510
538
|
.size=${Buttons.Button.Size.SMALL}
|
|
511
539
|
.title=${lastStep.isLoading ? titleForStep(lastStep) : lockedString(UIStringsNotTranslate.showThinking)}
|
|
512
540
|
.jslogContext=${walkthrough.isExpanded ? 'ai-hide-walkthrough-sidebar' : 'ai-show-walkthrough-sidebar'}
|
|
@@ -521,7 +549,9 @@ function renderWalkthroughSidebarButton(
|
|
|
521
549
|
walkthrough.onOpen(message as ModelChatMessage);
|
|
522
550
|
}
|
|
523
551
|
}}
|
|
524
|
-
|
|
552
|
+
>
|
|
553
|
+
${title}<devtools-icon class="chevron" .name=${'chevron-right'}></devtools-icon>
|
|
554
|
+
</devtools-button>
|
|
525
555
|
</div>
|
|
526
556
|
`;
|
|
527
557
|
// clang-format on
|
|
@@ -656,6 +686,8 @@ interface WidgetMakerResponse {
|
|
|
656
686
|
renderedWidget: Lit.LitTemplate|null;
|
|
657
687
|
revealable: unknown;
|
|
658
688
|
customRevealTitle?: Platform.UIString.LocalizedString;
|
|
689
|
+
// Can be null if the widget is only used to add the Reveal CTA.
|
|
690
|
+
title: Lit.LitTemplate|Platform.UIString.LocalizedString|null;
|
|
659
691
|
}
|
|
660
692
|
|
|
661
693
|
const nodeCache = new Map<Protocol.DOM.BackendNodeId, SDK.DOMModel.DOMNode>();
|
|
@@ -694,11 +726,20 @@ async function makeComputedStyleWidget(widgetData: ComputedStyleAiWidget): Promi
|
|
|
694
726
|
// This disables showing the nested traces and detailed information in the widget.
|
|
695
727
|
propertyTraces: null,
|
|
696
728
|
allowUserControl: false,
|
|
697
|
-
filterText: new RegExp(widgetData.data.properties.join('|'), 'i')
|
|
729
|
+
filterText: new RegExp(widgetData.data.properties.join('|'), 'i'),
|
|
730
|
+
enableNarrowViewResizing: false,
|
|
698
731
|
})}></devtools-widget>`;
|
|
699
732
|
// clang-format on
|
|
700
733
|
|
|
701
|
-
return {
|
|
734
|
+
return {
|
|
735
|
+
renderedWidget,
|
|
736
|
+
revealable: new Elements.ElementsPanel.NodeComputedStyles(domNodeForId),
|
|
737
|
+
title: html`<devtools-widget
|
|
738
|
+
${widget(PanelsCommon.DOMLinkifier.DOMNodeLink, {
|
|
739
|
+
node: domNodeForId,
|
|
740
|
+
})}
|
|
741
|
+
></devtools-widget>`,
|
|
742
|
+
};
|
|
702
743
|
}
|
|
703
744
|
|
|
704
745
|
async function makeCoreVitalsWidget(widgetData: CoreVitalsAiWidget): Promise<WidgetMakerResponse|null> {
|
|
@@ -708,7 +749,11 @@ async function makeCoreVitalsWidget(widgetData: CoreVitalsAiWidget): Promise<Wid
|
|
|
708
749
|
</devtools-widget>`;
|
|
709
750
|
// clang-format on
|
|
710
751
|
|
|
711
|
-
return {
|
|
752
|
+
return {
|
|
753
|
+
renderedWidget,
|
|
754
|
+
revealable: new TimelineUtils.Helpers.RevealableCoreVitals(widgetData.data.insightSetKey),
|
|
755
|
+
title: lockedString(UIStringsNotTranslate.coreVitals),
|
|
756
|
+
};
|
|
712
757
|
}
|
|
713
758
|
|
|
714
759
|
async function makeStylePropertiesWidget(widgetData: StylePropertiesAiWidget): Promise<WidgetMakerResponse|null> {
|
|
@@ -727,7 +772,15 @@ async function makeStylePropertiesWidget(widgetData: StylePropertiesAiWidget): P
|
|
|
727
772
|
</devtools-widget>`;
|
|
728
773
|
// clang-format on
|
|
729
774
|
|
|
730
|
-
return {
|
|
775
|
+
return {
|
|
776
|
+
renderedWidget,
|
|
777
|
+
revealable: domNodeForId,
|
|
778
|
+
title: html`<devtools-widget
|
|
779
|
+
${widget(PanelsCommon.DOMLinkifier.DOMNodeLink, {
|
|
780
|
+
node: domNodeForId,
|
|
781
|
+
})}
|
|
782
|
+
></devtools-widget>`,
|
|
783
|
+
};
|
|
731
784
|
}
|
|
732
785
|
|
|
733
786
|
async function makeLcpBreakdownWidget(widgetData: LcpBreakdownAiWidget): Promise<WidgetMakerResponse|null> {
|
|
@@ -745,7 +798,11 @@ async function makeLcpBreakdownWidget(widgetData: LcpBreakdownAiWidget): Promise
|
|
|
745
798
|
})}></devtools-widget>`;
|
|
746
799
|
// clang-format on
|
|
747
800
|
|
|
748
|
-
return {
|
|
801
|
+
return {
|
|
802
|
+
renderedWidget,
|
|
803
|
+
revealable: new TimelineUtils.Helpers.RevealableInsight(insight),
|
|
804
|
+
title: lockedString(UIStringsNotTranslate.lcpBreakdown),
|
|
805
|
+
};
|
|
749
806
|
}
|
|
750
807
|
|
|
751
808
|
function renderWidgetResponse(response: WidgetMakerResponse|null): Lit.LitTemplate {
|
|
@@ -764,21 +821,38 @@ function renderWidgetResponse(response: WidgetMakerResponse|null): Lit.LitTempla
|
|
|
764
821
|
'widget-and-revealer-container': true,
|
|
765
822
|
'revealer-only': response.renderedWidget === null,
|
|
766
823
|
});
|
|
824
|
+
|
|
825
|
+
const revealButton = html`
|
|
826
|
+
<devtools-button class="widget-reveal-button"
|
|
827
|
+
.variant=${Buttons.Button.Variant.TEXT}
|
|
828
|
+
@click=${onReveal}
|
|
829
|
+
>
|
|
830
|
+
${response.customRevealTitle ?? lockedString(UIStringsNotTranslate.reveal)}
|
|
831
|
+
<devtools-icon name='tab-move'></devtools-icon>
|
|
832
|
+
</devtools-button>
|
|
833
|
+
`;
|
|
834
|
+
|
|
767
835
|
// clang-format off
|
|
768
836
|
return html`
|
|
769
837
|
<div class=${classes}>
|
|
838
|
+
${response.title ? html`
|
|
839
|
+
<div class="widget-header">
|
|
840
|
+
<div class="widget-name">${response.title}</div>
|
|
841
|
+
<div class="widget-reveal-container">
|
|
842
|
+
${revealButton}
|
|
843
|
+
</div>
|
|
844
|
+
</div>
|
|
845
|
+
` : Lit.nothing}
|
|
770
846
|
${response.renderedWidget ? html`
|
|
771
847
|
<div class="widget-content-container">
|
|
772
848
|
${response.renderedWidget}
|
|
773
849
|
</div>` : Lit.nothing
|
|
774
850
|
}
|
|
775
|
-
|
|
776
|
-
<
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
>${response.customRevealTitle ?? lockedString(UIStringsNotTranslate.reveal)}</devtools-button>
|
|
781
|
-
</div>
|
|
851
|
+
${!response.title ? html`
|
|
852
|
+
<div class="widget-reveal-container">
|
|
853
|
+
${revealButton}
|
|
854
|
+
</div>
|
|
855
|
+
` : Lit.nothing}
|
|
782
856
|
</div>
|
|
783
857
|
`;
|
|
784
858
|
// clang-format on
|
|
@@ -787,6 +861,7 @@ function renderWidgetResponse(response: WidgetMakerResponse|null): Lit.LitTempla
|
|
|
787
861
|
async function makePerformanceTraceWidget(widgetData: PerformanceTraceAiWidget): Promise<WidgetMakerResponse|null> {
|
|
788
862
|
return {
|
|
789
863
|
renderedWidget: null,
|
|
864
|
+
title: null,
|
|
790
865
|
revealable: new Timeline.TimelinePanel.ParsedTraceRevealable(widgetData.data.parsedTrace),
|
|
791
866
|
customRevealTitle: lockedString(UIStringsNotTranslate.revealTrace),
|
|
792
867
|
};
|
|
@@ -846,6 +921,7 @@ async function makeDomTreeWidget(widgetData: DomTreeAiWidget): Promise<WidgetMak
|
|
|
846
921
|
return {
|
|
847
922
|
renderedWidget,
|
|
848
923
|
revealable: new SDK.DOMModel.DeferredDOMNode(root.domModel().target(), root.backendNodeId()),
|
|
924
|
+
title: lockedString(UIStringsNotTranslate.lcpElement),
|
|
849
925
|
};
|
|
850
926
|
}
|
|
851
927
|
|
|
@@ -892,6 +968,9 @@ async function renderWidgets(
|
|
|
892
968
|
case 'LCP_BREAKDOWN':
|
|
893
969
|
response = await makeLcpBreakdownWidget(widgetData);
|
|
894
970
|
break;
|
|
971
|
+
case 'TIMELINE_RANGE_SUMMARY':
|
|
972
|
+
response = await makeTimelineRangeSummaryWidget(widgetData);
|
|
973
|
+
break;
|
|
895
974
|
default:
|
|
896
975
|
Platform.assertNever(widgetData, 'Unknown AiWidget name');
|
|
897
976
|
}
|
|
@@ -1318,3 +1397,49 @@ export class ChatMessage extends UI.Widget.Widget {
|
|
|
1318
1397
|
void this.performUpdate();
|
|
1319
1398
|
}
|
|
1320
1399
|
}
|
|
1400
|
+
|
|
1401
|
+
async function makeTimelineRangeSummaryWidget(widgetData: TimelineRangeSummaryAiWidget):
|
|
1402
|
+
Promise<WidgetMakerResponse|null> {
|
|
1403
|
+
const {bounds, parsedTrace, track} = widgetData.data;
|
|
1404
|
+
let events: readonly Trace.Types.Events.Event[] = [];
|
|
1405
|
+
if (track === 'main') {
|
|
1406
|
+
const flameChartView = Timeline.TimelinePanel.TimelinePanel.instance().getFlameChart();
|
|
1407
|
+
const mainDataProvider = flameChartView.getMainDataProvider();
|
|
1408
|
+
const mainTrack =
|
|
1409
|
+
mainDataProvider.timelineData().groups.find((group: {name: string}) => group.name.startsWith('Main \u2014 '));
|
|
1410
|
+
if (mainTrack) {
|
|
1411
|
+
events = mainDataProvider.groupTreeEvents(mainTrack) ?? [];
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
const eventsArray = Array.from(events);
|
|
1415
|
+
eventsArray.sort((a, b) => a.ts - b.ts);
|
|
1416
|
+
|
|
1417
|
+
const thirdPartyTree = new Timeline.ThirdPartyTreeView.ThirdPartyTreeViewWidget();
|
|
1418
|
+
const mapper = new Trace.EntityMapper.EntityMapper(parsedTrace);
|
|
1419
|
+
thirdPartyTree.setModelWithEvents(eventsArray, parsedTrace, mapper);
|
|
1420
|
+
thirdPartyTree.updateContents(Timeline.TimelineSelection.selectionFromRangeMicroSeconds(bounds.min, bounds.max));
|
|
1421
|
+
thirdPartyTree.refreshTree(true);
|
|
1422
|
+
|
|
1423
|
+
// clang-format off
|
|
1424
|
+
const template = html`
|
|
1425
|
+
<devtools-widget
|
|
1426
|
+
${widget(TimelineComponents.TimelineRangeSummaryView.TimelineRangeSummaryView, {
|
|
1427
|
+
data: {
|
|
1428
|
+
parsedTrace,
|
|
1429
|
+
events,
|
|
1430
|
+
startTime: Trace.Helpers.Timing.microToMilli(bounds.min),
|
|
1431
|
+
endTime: Trace.Helpers.Timing.microToMilli(bounds.max),
|
|
1432
|
+
thirdPartyTreeTemplate: html`<devtools-performance-third-party-tree-view
|
|
1433
|
+
max-rows="10"
|
|
1434
|
+
.treeView=${thirdPartyTree}></devtools-performance-third-party-tree-view>`,
|
|
1435
|
+
} as TimelineComponents.TimelineRangeSummaryView.TimelineRangeSummaryViewData,
|
|
1436
|
+
})}
|
|
1437
|
+
></devtools-widget>`;
|
|
1438
|
+
// clang-format on
|
|
1439
|
+
|
|
1440
|
+
return {
|
|
1441
|
+
renderedWidget: template,
|
|
1442
|
+
revealable: new TimelineUtils.Helpers.RevealableTimeRange(bounds),
|
|
1443
|
+
title: lockedString(UIStringsNotTranslate.performanceSummary),
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
@@ -90,10 +90,10 @@ function renderInlineWalkthrough(input: ViewInput, stepsOutput: Lit.LitTemplate,
|
|
|
90
90
|
// clang-format off
|
|
91
91
|
return html`
|
|
92
92
|
<details class="walkthrough-inline" ?open=${input.isExpanded} @toggle=${onToggle}>
|
|
93
|
-
<summary>
|
|
93
|
+
<summary ?data-has-widgets=${!input.isLoading && hasWidgets}>
|
|
94
94
|
${input.isLoading ? html`<devtools-spinner></devtools-spinner>` : Lit.nothing}
|
|
95
95
|
${walkthroughTitle({isLoading: input.isLoading, lastStep, hasWidgets})}
|
|
96
|
-
<devtools-icon name="chevron-
|
|
96
|
+
<devtools-icon name="chevron-right"></devtools-icon>
|
|
97
97
|
</summary>
|
|
98
98
|
${stepsOutput}
|
|
99
99
|
</details>
|
|
@@ -182,8 +182,6 @@ export class WalkthroughView extends UI.Widget.Widget {
|
|
|
182
182
|
#view: View;
|
|
183
183
|
|
|
184
184
|
#message: ModelChatMessage|null = null;
|
|
185
|
-
// TODO(b/487921187): fix loading state - also unsure if we need this vs
|
|
186
|
-
// looking at the loading state in the message's steps.
|
|
187
185
|
#isLoading = false;
|
|
188
186
|
#markdownRenderer: MarkdownLitRenderer|null = null;
|
|
189
187
|
#onToggle: (isOpen: boolean) => void = () => {};
|
|
@@ -196,6 +194,7 @@ export class WalkthroughView extends UI.Widget.Widget {
|
|
|
196
194
|
|
|
197
195
|
#output: ViewOutput = {};
|
|
198
196
|
#stepsContainerResizeObserver = new ResizeObserver(() => this.#handleStepsContainerResize());
|
|
197
|
+
#lastStepsContainerWidth = 0;
|
|
199
198
|
|
|
200
199
|
constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
|
|
201
200
|
super(element);
|
|
@@ -218,12 +217,27 @@ export class WalkthroughView extends UI.Widget.Widget {
|
|
|
218
217
|
}
|
|
219
218
|
}
|
|
220
219
|
|
|
221
|
-
override onResize(): void {
|
|
222
|
-
this.#handleStepsContainerResize();
|
|
223
|
-
}
|
|
224
|
-
|
|
225
220
|
#handleStepsContainerResize(): void {
|
|
226
|
-
|
|
221
|
+
const width = this.#output.stepsContainer?.offsetWidth ?? 0;
|
|
222
|
+
/**
|
|
223
|
+
* If the width has changed, it's likely due to a manual resize (e.g., the
|
|
224
|
+
* user dragging the sidebar). In these cases, we want to avoid jumping the
|
|
225
|
+
* scroll position to the bottom, as it can be jarring for the user. We
|
|
226
|
+
* only auto-scroll if the width remains the same, meaning only the height
|
|
227
|
+
* has changed (likely due to new content being added).
|
|
228
|
+
*/
|
|
229
|
+
if (width !== this.#lastStepsContainerWidth) {
|
|
230
|
+
this.#lastStepsContainerWidth = width;
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* We only want to auto-scroll if the walkthrough is "live", which means it's
|
|
236
|
+
* currently loading. If it's not loading, it's a walkthrough for a previous
|
|
237
|
+
* message, and we don't want to jump the user to the bottom if they've
|
|
238
|
+
* scrolled away.
|
|
239
|
+
*/
|
|
240
|
+
if (!this.#pinScrollToBottom || !this.#isLoading) {
|
|
227
241
|
return;
|
|
228
242
|
}
|
|
229
243
|
|
|
@@ -338,7 +352,13 @@ export class WalkthroughView extends UI.Widget.Widget {
|
|
|
338
352
|
|
|
339
353
|
this.#registerResizeObservers();
|
|
340
354
|
|
|
341
|
-
|
|
355
|
+
/**
|
|
356
|
+
* We only want to auto-scroll if the walkthrough is "live", which means it's
|
|
357
|
+
* currently loading. If it's not loading, it's a walkthrough for a previous
|
|
358
|
+
* message, and we don't want to jump the user to the bottom if they've
|
|
359
|
+
* scrolled away.
|
|
360
|
+
*/
|
|
361
|
+
if (this.#pinScrollToBottom && this.#isLoading) {
|
|
342
362
|
this.scrollToBottom();
|
|
343
363
|
}
|
|
344
364
|
}
|
|
@@ -346,6 +346,13 @@
|
|
|
346
346
|
display: flex;
|
|
347
347
|
gap: var(--sys-size-4);
|
|
348
348
|
align-items: center;
|
|
349
|
+
|
|
350
|
+
.chevron {
|
|
351
|
+
color: var(--sys-color-primary);
|
|
352
|
+
width: var(--sys-size-8);
|
|
353
|
+
height: var(--sys-size-8);
|
|
354
|
+
margin-left: var(--sys-size-2);
|
|
355
|
+
}
|
|
349
356
|
}
|
|
350
357
|
|
|
351
358
|
|
|
@@ -372,14 +379,50 @@
|
|
|
372
379
|
gap: var(--sys-size-5);
|
|
373
380
|
}
|
|
374
381
|
|
|
382
|
+
.widget-header {
|
|
383
|
+
display: flex;
|
|
384
|
+
justify-content: space-between;
|
|
385
|
+
height: var(--sys-size-11);
|
|
386
|
+
align-items: center;
|
|
387
|
+
background: var(--sys-color-surface5);
|
|
388
|
+
padding: var(--sys-size-2) var(--sys-size-4);
|
|
389
|
+
border-top-left-radius: var(--sys-shape-corner-small);
|
|
390
|
+
border-top-right-radius: var(--sys-shape-corner-small);
|
|
391
|
+
|
|
392
|
+
.widget-name {
|
|
393
|
+
font: var(--sys-typescale-body4-regular);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.widget-reveal-container {
|
|
397
|
+
padding: 0;
|
|
398
|
+
background: none;
|
|
399
|
+
border-radius: 0;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.widget-reveal-button {
|
|
404
|
+
display: flex;
|
|
405
|
+
align-items: center;
|
|
406
|
+
|
|
407
|
+
devtools-icon {
|
|
408
|
+
margin-left: var(--sys-size-3);
|
|
409
|
+
color: var(--sys-color-primary);
|
|
410
|
+
width: var(--sys-size-8);
|
|
411
|
+
height: var(--sys-size-8);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
}
|
|
415
|
+
|
|
375
416
|
.widget-and-revealer-container {
|
|
376
417
|
width: 100%;
|
|
418
|
+
min-width: var(--sys-size-30);
|
|
419
|
+
max-width: var(--sys-size-33);
|
|
377
420
|
}
|
|
378
421
|
|
|
379
422
|
.widget-reveal-container {
|
|
380
423
|
background: var(--sys-color-surface5);
|
|
381
|
-
border-bottom-right-radius: var(--sys-shape-corner-
|
|
382
|
-
border-bottom-left-radius: var(--sys-shape-corner-
|
|
424
|
+
border-bottom-right-radius: var(--sys-shape-corner-small);
|
|
425
|
+
border-bottom-left-radius: var(--sys-shape-corner-small);
|
|
383
426
|
padding: 0 var(--sys-size-4) var(--sys-size-4) 0;
|
|
384
427
|
}
|
|
385
428
|
|
|
@@ -389,13 +432,25 @@
|
|
|
389
432
|
}
|
|
390
433
|
|
|
391
434
|
.widget-content-container {
|
|
392
|
-
padding: var(--sys-size-4);
|
|
435
|
+
padding: var(--sys-size-4) var(--sys-size-5);
|
|
393
436
|
border-top-left-radius: var(--sys-shape-corner-medium);
|
|
394
437
|
border-top-right-radius: var(--sys-shape-corner-medium);
|
|
395
438
|
overflow-x: auto;
|
|
396
439
|
background-color: var(--sys-color-surface3);
|
|
397
440
|
|
|
398
441
|
--override-computed-style-property-white-space: normal;
|
|
442
|
+
|
|
443
|
+
/* When header is present, content follows it and shouldn't have top radii */
|
|
444
|
+
.widget-header+& {
|
|
445
|
+
border-top-left-radius: 0;
|
|
446
|
+
border-top-right-radius: 0;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/* When header is present, content is the last child and needs bottom radii */
|
|
450
|
+
.widget-header+&:last-child {
|
|
451
|
+
border-bottom-left-radius: var(--sys-shape-corner-medium);
|
|
452
|
+
border-bottom-right-radius: var(--sys-shape-corner-medium);
|
|
453
|
+
}
|
|
399
454
|
}
|
|
400
455
|
|
|
401
456
|
.network-request-preview {
|
|
@@ -100,25 +100,45 @@
|
|
|
100
100
|
.walkthrough-inline {
|
|
101
101
|
border-radius: var(--sys-size-5);
|
|
102
102
|
overflow: hidden;
|
|
103
|
-
background-color: var(--sys-color-
|
|
103
|
+
background-color: var(--sys-color-surface2);
|
|
104
104
|
width: fit-content;
|
|
105
105
|
|
|
106
106
|
&[open] {
|
|
107
107
|
width: auto;
|
|
108
|
+
background-color: var(--sys-color-surface1);
|
|
108
109
|
}
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
.walkthrough-inline > summary {
|
|
112
113
|
display: flex;
|
|
113
114
|
align-items: center;
|
|
114
|
-
padding:
|
|
115
|
+
padding: 0 var(--sys-size-6);
|
|
115
116
|
cursor: pointer;
|
|
116
117
|
background-color: transparent;
|
|
118
|
+
/* The same height as a DevTools Button */
|
|
119
|
+
height: var(--sys-size-11);
|
|
117
120
|
font: var(--sys-typescale-body4-regular);
|
|
121
|
+
font-weight:var(--ref-typeface-weight-medium);
|
|
118
122
|
user-select: none;
|
|
119
123
|
list-style: none; /* Hide default triangle */
|
|
120
124
|
justify-content: flex-start;
|
|
121
125
|
gap: var(--sys-size-4);
|
|
126
|
+
color: var(--sys-color-primary);
|
|
127
|
+
|
|
128
|
+
devtools-icon {
|
|
129
|
+
color: var(--sys-color-primary);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* Align the summary to look like the tonal button */
|
|
133
|
+
&[data-has-widgets] {
|
|
134
|
+
background: var(--sys-color-tonal-container);
|
|
135
|
+
color: var(--sys-color-on-tonal-container);
|
|
136
|
+
border-radius: var(--sys-shape-corner-full);
|
|
137
|
+
|
|
138
|
+
devtools-icon {
|
|
139
|
+
color: var(--sys-color-on-tonal-container);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
122
142
|
}
|
|
123
143
|
|
|
124
144
|
.walkthrough-inline > summary::-webkit-details-marker {
|
|
@@ -131,8 +151,6 @@
|
|
|
131
151
|
|
|
132
152
|
.walkthrough-inline .steps-container {
|
|
133
153
|
padding: var(--sys-size-6);
|
|
134
|
-
max-height: 300px; /* Limit height for inline view */
|
|
135
|
-
overflow-y: auto;
|
|
136
154
|
border-top: 1px solid var(--sys-color-divider);
|
|
137
155
|
background-color: transparent;
|
|
138
156
|
}
|
|
@@ -141,9 +159,21 @@
|
|
|
141
159
|
width: var(--sys-size-8);
|
|
142
160
|
height: var(--sys-size-8);
|
|
143
161
|
transition: transform 0.2s;
|
|
162
|
+
margin-left: auto;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.walkthrough-inline[open] > summary {
|
|
166
|
+
border-radius: var(--sys-shape-corner-medium-small);
|
|
167
|
+
border-bottom-right-radius: 0;
|
|
168
|
+
border-bottom-left-radius: 0;
|
|
169
|
+
background: var(--sys-color-surface5);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.walkthrough-inline .step {
|
|
173
|
+
background-color: var(--sys-color-surface5);
|
|
144
174
|
}
|
|
145
175
|
|
|
146
176
|
.walkthrough-inline[open] > summary > devtools-icon {
|
|
147
|
-
transform: rotate(
|
|
177
|
+
transform: rotate(270deg);
|
|
148
178
|
}
|
|
149
179
|
}
|
|
@@ -1106,8 +1106,8 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
1106
1106
|
${identityData && onCopyId ? renderIdentity(identityData, onCopyId, output) : nothing}
|
|
1107
1107
|
${presentationData ? renderPresentation(presentationData, output) : nothing}
|
|
1108
1108
|
${protocolHandlersData ? renderProtocolHandlers(protocolHandlersData, output) : nothing}
|
|
1109
|
-
${iconsData && onToggleIconMasked
|
|
1110
|
-
renderIcons(iconsData, maskedIcons, onToggleIconMasked, output) : nothing}
|
|
1109
|
+
${iconsData && onToggleIconMasked ?
|
|
1110
|
+
renderIcons(iconsData, Boolean(maskedIcons), onToggleIconMasked, output) : nothing}
|
|
1111
1111
|
${windowControlsData && output ? renderWindowControlsSection(
|
|
1112
1112
|
windowControlsData, selectedPlatform, onSelectOs, onToggleWcoToolbar, output) : nothing}
|
|
1113
1113
|
${shortcutsData ? renderShortcuts(shortcutsData) : nothing}
|