chrome-devtools-frontend 1.0.1555174 → 1.0.1555430
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/protocol_client/InspectorBackend.ts +1 -1
- package/front_end/core/root/Runtime.ts +0 -4
- package/front_end/core/sdk/DOMModel.ts +101 -7
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +1 -1
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +1 -1
- package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +1 -1
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +1 -1
- package/front_end/{ui/components → models}/annotations/AnnotationRepository.ts +3 -3
- package/front_end/models/annotations/README.md +7 -0
- package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +8 -0
- package/front_end/models/stack_trace/StackTrace.ts +13 -2
- package/front_end/models/stack_trace/StackTraceImpl.ts +81 -6
- package/front_end/models/stack_trace/StackTraceModel.ts +35 -3
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +45 -4
- package/front_end/panels/ai_assistance/components/ArtifactsViewer.ts +57 -0
- package/front_end/panels/ai_assistance/components/ChatView.ts +1 -0
- package/front_end/panels/ai_assistance/components/artifactsViewer.css +10 -0
- package/front_end/panels/application/preloading/PreloadingView.ts +12 -6
- package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +230 -237
- package/front_end/panels/application/preloading/components/PreloadingGrid.ts +96 -79
- package/front_end/panels/application/preloading/components/preloadingGrid.css +26 -29
- package/front_end/panels/application/preloading/preloadingView.css +6 -0
- package/front_end/panels/common/Annotation.ts +1 -1
- package/front_end/panels/common/AnnotationManager.ts +1 -1
- package/front_end/panels/common/ExtensionView.ts +1 -0
- package/front_end/panels/console/ConsoleContextSelector.ts +74 -9
- package/front_end/panels/console/consoleContextSelector.css +31 -29
- package/front_end/panels/coverage/coverageListView.css +59 -57
- package/front_end/panels/elements/ElementsPanel.ts +1 -1
- package/front_end/panels/elements/ElementsTreeElement.ts +39 -1
- package/front_end/panels/elements/ElementsTreeOutline.ts +23 -21
- package/front_end/panels/elements/TopLayerContainer.ts +26 -91
- package/front_end/panels/explain/components/ConsoleInsight.ts +3 -3
- package/front_end/panels/network/NetworkItemView.ts +1 -1
- package/front_end/panels/network/NetworkLogView.ts +1 -1
- package/front_end/panels/network/NetworkPanel.ts +1 -1
- package/front_end/panels/recorder/RecorderController.ts +0 -1
- package/front_end/panels/security/SecurityPanelSidebar.ts +5 -0
- package/front_end/panels/timeline/TimelineUIUtils.ts +5 -8
- package/front_end/panels/timeline/components/TimelineSummary.ts +75 -54
- package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +16 -25
- package/front_end/panels/timeline/components/insights/Cache.ts +12 -8
- package/front_end/panels/timeline/components/insights/DOMSize.ts +25 -21
- package/front_end/panels/timeline/components/insights/DuplicatedJavaScript.ts +7 -7
- package/front_end/panels/timeline/components/insights/FontDisplay.ts +7 -5
- package/front_end/panels/timeline/components/insights/ForcedReflow.ts +11 -9
- package/front_end/panels/timeline/components/insights/INPBreakdown.ts +7 -6
- package/front_end/panels/timeline/components/insights/ImageDelivery.ts +7 -5
- package/front_end/panels/timeline/components/insights/InsightRenderer.ts +20 -18
- package/front_end/panels/timeline/components/insights/LCPBreakdown.ts +12 -12
- package/front_end/panels/timeline/components/insights/LegacyJavaScript.ts +7 -7
- package/front_end/panels/timeline/components/insights/ModernHTTP.ts +7 -5
- package/front_end/panels/timeline/components/insights/NetworkDependencyTree.ts +15 -13
- package/front_end/panels/timeline/components/insights/RenderBlocking.ts +2 -2
- package/front_end/panels/timeline/components/insights/SlowCSSSelector.ts +15 -14
- package/front_end/panels/timeline/components/insights/Table.ts +152 -130
- package/front_end/panels/timeline/components/insights/ThirdParties.ts +11 -9
- package/front_end/panels/timeline/components/timelineSummary.css +58 -57
- package/front_end/panels/timeline/thirdPartyTreeView.css +109 -0
- package/front_end/panels/timeline/timelineDetailsView.css +2 -4
- package/front_end/panels/timeline/timelinePanel.css +0 -110
- package/front_end/ui/legacy/TabbedPane.ts +1 -1
- package/front_end/ui/legacy/ViewManager.ts +2 -32
- package/package.json +1 -1
- /package/front_end/{ui/components → models}/annotations/AnnotationType.ts +0 -0
- /package/front_end/{ui/components → models}/annotations/annotations.ts +0 -0
|
@@ -6,15 +6,17 @@ import './Table.js';
|
|
|
6
6
|
|
|
7
7
|
import type {ModernHTTPInsightModel} from '../../../../models/trace/insights/ModernHTTP.js';
|
|
8
8
|
import * as Trace from '../../../../models/trace/trace.js';
|
|
9
|
+
import * as UI from '../../../../ui/legacy/legacy.js';
|
|
9
10
|
import * as Lit from '../../../../ui/lit/lit.js';
|
|
10
11
|
|
|
11
12
|
import {BaseInsightComponent} from './BaseInsightComponent.js';
|
|
12
13
|
import {eventRef} from './EventRef.js';
|
|
13
|
-
import {createLimitedRows, renderOthersLabel,
|
|
14
|
+
import {createLimitedRows, renderOthersLabel, Table, type TableDataRow} from './Table.js';
|
|
14
15
|
|
|
15
16
|
const {UIStrings, i18nString, createOverlayForRequest} = Trace.Insights.Models.ModernHTTP;
|
|
16
17
|
|
|
17
18
|
const {html} = Lit;
|
|
19
|
+
const {widgetConfig} = UI.Widget;
|
|
18
20
|
|
|
19
21
|
export class ModernHTTP extends BaseInsightComponent<ModernHTTPInsightModel> {
|
|
20
22
|
override internalName = 'modern-http';
|
|
@@ -56,13 +58,13 @@ export class ModernHTTP extends BaseInsightComponent<ModernHTTPInsightModel> {
|
|
|
56
58
|
// clang-format off
|
|
57
59
|
return html`
|
|
58
60
|
<div class="insight-section">
|
|
59
|
-
<devtools-
|
|
60
|
-
|
|
61
|
+
<devtools-widget .widgetConfig=${widgetConfig(Table, {
|
|
62
|
+
data: {
|
|
61
63
|
insight: this,
|
|
62
64
|
headers: [i18nString(UIStrings.request), i18nString(UIStrings.protocol)],
|
|
63
65
|
rows,
|
|
64
|
-
}
|
|
65
|
-
</devtools-
|
|
66
|
+
}})}>
|
|
67
|
+
</devtools-widget>
|
|
66
68
|
</div>`;
|
|
67
69
|
// clang-format on
|
|
68
70
|
}
|
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
CriticalRequestNode, NetworkDependencyTreeInsightModel} from
|
|
11
11
|
'../../../../models/trace/insights/NetworkDependencyTree.js';
|
|
12
12
|
import * as Trace from '../../../../models/trace/trace.js';
|
|
13
|
+
import * as UI from '../../../../ui/legacy/legacy.js';
|
|
13
14
|
import * as Lit from '../../../../ui/lit/lit.js';
|
|
14
15
|
|
|
15
16
|
import {BaseInsightComponent} from './BaseInsightComponent.js';
|
|
@@ -17,11 +18,12 @@ import {eventRef} from './EventRef.js';
|
|
|
17
18
|
import {md} from './Helpers.js';
|
|
18
19
|
import networkDependencyTreeInsightStyles from './networkDependencyTreeInsight.css.js';
|
|
19
20
|
import {nodeLink} from './NodeLink.js';
|
|
20
|
-
import {renderOthersLabel,
|
|
21
|
+
import {renderOthersLabel, Table, type TableDataRow} from './Table.js';
|
|
21
22
|
|
|
22
23
|
const {UIStrings, i18nString} = Trace.Insights.Models.NetworkDependencyTree;
|
|
23
24
|
|
|
24
25
|
const {html} = Lit;
|
|
26
|
+
const {widgetConfig} = UI.Widget;
|
|
25
27
|
|
|
26
28
|
export const MAX_CHAINS_TO_SHOW = 5;
|
|
27
29
|
|
|
@@ -115,13 +117,13 @@ export class NetworkDependencyTree extends BaseInsightComponent<NetworkDependenc
|
|
|
115
117
|
|
|
116
118
|
// clang-format off
|
|
117
119
|
return html`
|
|
118
|
-
<devtools-
|
|
119
|
-
|
|
120
|
+
<devtools-widget .widgetConfig=${widgetConfig(Table, {
|
|
121
|
+
data: {
|
|
120
122
|
insight: this,
|
|
121
123
|
headers: [i18nString(UIStrings.columnRequest), i18nString(UIStrings.columnTime)],
|
|
122
124
|
rows,
|
|
123
|
-
}
|
|
124
|
-
</devtools-
|
|
125
|
+
}})}>
|
|
126
|
+
</devtools-widget>
|
|
125
127
|
`;
|
|
126
128
|
// clang-format on
|
|
127
129
|
}
|
|
@@ -240,13 +242,13 @@ export class NetworkDependencyTree extends BaseInsightComponent<NetworkDependenc
|
|
|
240
242
|
<div class="insight-section">
|
|
241
243
|
${preconnectOriginsTableTitle}
|
|
242
244
|
${this.#renderTooManyPreconnectsWarning()}
|
|
243
|
-
<devtools-
|
|
244
|
-
|
|
245
|
+
<devtools-widget .widgetConfig=${widgetConfig(Table, {
|
|
246
|
+
data: {
|
|
245
247
|
insight: this,
|
|
246
248
|
headers: [i18nString(UIStrings.columnOrigin), i18nString(UIStrings.columnSource)],
|
|
247
249
|
rows,
|
|
248
|
-
}
|
|
249
|
-
</devtools-
|
|
250
|
+
}})}>
|
|
251
|
+
</devtools-widget>
|
|
250
252
|
</div>
|
|
251
253
|
`;
|
|
252
254
|
// clang-format on
|
|
@@ -283,13 +285,13 @@ export class NetworkDependencyTree extends BaseInsightComponent<NetworkDependenc
|
|
|
283
285
|
return html`
|
|
284
286
|
<div class="insight-section">
|
|
285
287
|
${estSavingTableTitle}
|
|
286
|
-
<devtools-
|
|
287
|
-
|
|
288
|
+
<devtools-widget .widgetConfig=${widgetConfig(Table, {
|
|
289
|
+
data: {
|
|
288
290
|
insight: this,
|
|
289
291
|
headers: [i18nString(UIStrings.columnOrigin), i18nString(UIStrings.columnWastedMs)],
|
|
290
292
|
rows,
|
|
291
|
-
}
|
|
292
|
-
</devtools-
|
|
293
|
+
}})}>
|
|
294
|
+
</devtools-widget>
|
|
293
295
|
</div>
|
|
294
296
|
`;
|
|
295
297
|
// clang-format on
|
|
@@ -58,13 +58,13 @@ export class RenderBlocking extends BaseInsightComponent<RenderBlockingInsightMo
|
|
|
58
58
|
// clang-format off
|
|
59
59
|
return html`
|
|
60
60
|
<div class="insight-section">
|
|
61
|
-
<devtools-
|
|
61
|
+
<devtools-widget
|
|
62
62
|
.data=${{
|
|
63
63
|
insight: this,
|
|
64
64
|
headers: [i18nString(UIStrings.renderBlockingRequest), i18nString(UIStrings.duration)],
|
|
65
65
|
rows,
|
|
66
66
|
}}>
|
|
67
|
-
</devtools-
|
|
67
|
+
</devtools-widget>
|
|
68
68
|
</div>
|
|
69
69
|
`;
|
|
70
70
|
// clang-format on
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
-
import './Table.js';
|
|
6
5
|
import '../../../../ui/components/linkifier/linkifier.js';
|
|
7
6
|
|
|
8
7
|
import * as i18n from '../../../../core/i18n/i18n.js';
|
|
@@ -12,14 +11,16 @@ import type * as Protocol from '../../../../generated/protocol.js';
|
|
|
12
11
|
import type {SlowCSSSelectorInsightModel} from '../../../../models/trace/insights/SlowCSSSelector.js';
|
|
13
12
|
import * as Trace from '../../../../models/trace/trace.js';
|
|
14
13
|
import type * as Linkifier from '../../../../ui/components/linkifier/linkifier.js';
|
|
14
|
+
import * as UI from '../../../../ui/legacy/legacy.js';
|
|
15
15
|
import * as Lit from '../../../../ui/lit/lit.js';
|
|
16
16
|
|
|
17
17
|
import {BaseInsightComponent} from './BaseInsightComponent.js';
|
|
18
|
-
import
|
|
18
|
+
import {Table} from './Table.js';
|
|
19
19
|
|
|
20
20
|
const {UIStrings, i18nString} = Trace.Insights.Models.SlowCSSSelector;
|
|
21
21
|
|
|
22
22
|
const {html} = Lit;
|
|
23
|
+
const {widgetConfig} = UI.Widget;
|
|
23
24
|
|
|
24
25
|
export class SlowCSSSelector extends BaseInsightComponent<SlowCSSSelectorInsightModel> {
|
|
25
26
|
override internalName = 'slow-css-selector';
|
|
@@ -106,8 +107,8 @@ export class SlowCSSSelector extends BaseInsightComponent<SlowCSSSelectorInsight
|
|
|
106
107
|
// clang-format off
|
|
107
108
|
const sections = [html`
|
|
108
109
|
<div class="insight-section">
|
|
109
|
-
<devtools-
|
|
110
|
-
|
|
110
|
+
<devtools-widget .widgetConfig=${widgetConfig(Table, {
|
|
111
|
+
data: {
|
|
111
112
|
insight: this,
|
|
112
113
|
headers: [i18nString(UIStrings.total), ''],
|
|
113
114
|
rows: [
|
|
@@ -115,8 +116,8 @@ export class SlowCSSSelector extends BaseInsightComponent<SlowCSSSelectorInsight
|
|
|
115
116
|
{values: [i18nString(UIStrings.matchCount), this.model.totalMatchCount]},
|
|
116
117
|
{values: [i18nString(UIStrings.elapsed), i18n.TimeUtilities.millisToString(this.model.totalElapsedMs)]},
|
|
117
118
|
],
|
|
118
|
-
}
|
|
119
|
-
</devtools-
|
|
119
|
+
}})}>
|
|
120
|
+
</devtools-widget>
|
|
120
121
|
</div>
|
|
121
122
|
`];
|
|
122
123
|
// clang-format on
|
|
@@ -126,14 +127,14 @@ export class SlowCSSSelector extends BaseInsightComponent<SlowCSSSelectorInsight
|
|
|
126
127
|
// clang-format off
|
|
127
128
|
sections.push(html`
|
|
128
129
|
<div class="insight-section">
|
|
129
|
-
<devtools-
|
|
130
|
-
|
|
130
|
+
<devtools-widget .widgetConfig=${widgetConfig(Table, {
|
|
131
|
+
data: {
|
|
131
132
|
insight: this,
|
|
132
133
|
headers: [`${i18nString(UIStrings.topSelectorElapsedTime)}: ${time(Trace.Types.Timing.Micro(selector['elapsed (us)']))}`],
|
|
133
134
|
rows: [{
|
|
134
135
|
values: [html`${selector.selector} ${Lit.Directives.until(this.getSelectorLinks(cssModel, selector))}`]}]
|
|
135
|
-
}}
|
|
136
|
-
</devtools-
|
|
136
|
+
}})}>
|
|
137
|
+
</devtools-widget>
|
|
137
138
|
</div>
|
|
138
139
|
`);
|
|
139
140
|
// clang-format on
|
|
@@ -144,15 +145,15 @@ export class SlowCSSSelector extends BaseInsightComponent<SlowCSSSelectorInsight
|
|
|
144
145
|
// clang-format off
|
|
145
146
|
sections.push(html`
|
|
146
147
|
<div class="insight-section">
|
|
147
|
-
<devtools-
|
|
148
|
-
|
|
148
|
+
<devtools-widget .widgetConfig=${widgetConfig(Table, {
|
|
149
|
+
data: {
|
|
149
150
|
insight: this,
|
|
150
151
|
headers: [`${i18nString(UIStrings.topSelectorMatchAttempt)}: ${selector['match_attempts']}`],
|
|
151
152
|
rows: [{
|
|
152
153
|
values: [html`${selector.selector} ${Lit.Directives.until(this.getSelectorLinks(cssModel, selector))}` as unknown as string],
|
|
153
154
|
}]
|
|
154
|
-
}}
|
|
155
|
-
</devtools-
|
|
155
|
+
}})}>
|
|
156
|
+
</devtools-widget>
|
|
156
157
|
</div>
|
|
157
158
|
`);
|
|
158
159
|
// clang-format on
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
// Copyright 2024 The Chromium Authors
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
|
-
/* eslint-disable @devtools/no-lit-render-outside-of-view */
|
|
5
4
|
|
|
6
5
|
import * as i18n from '../../../../core/i18n/i18n.js';
|
|
7
6
|
import type * as Trace from '../../../../models/trace/trace.js';
|
|
8
|
-
import * as
|
|
7
|
+
import * as UI from '../../../../ui/legacy/legacy.js';
|
|
9
8
|
import * as Lit from '../../../../ui/lit/lit.js';
|
|
10
9
|
|
|
11
10
|
import type * as BaseInsightComponent from './BaseInsightComponent.js';
|
|
@@ -48,7 +47,7 @@ export interface TableState {
|
|
|
48
47
|
selectionIsSticky: boolean;
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
interface TableData {
|
|
52
51
|
insight: BaseInsightComponent;
|
|
53
52
|
headers: string[];
|
|
54
53
|
rows: TableDataRow[];
|
|
@@ -60,6 +59,11 @@ export interface TableDataRow {
|
|
|
60
59
|
subRows?: TableDataRow[];
|
|
61
60
|
}
|
|
62
61
|
|
|
62
|
+
interface FlattenedTableDataRow {
|
|
63
|
+
row: TableDataRow;
|
|
64
|
+
depth: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
63
67
|
export function renderOthersLabel(numOthers: number): string {
|
|
64
68
|
return i18nString(UIStrings.others, {PH1: numOthers});
|
|
65
69
|
}
|
|
@@ -94,113 +98,195 @@ export function createLimitedRows<T>(arr: T[], aggregator: RowLimitAggregator<T>
|
|
|
94
98
|
return items;
|
|
95
99
|
}
|
|
96
100
|
|
|
97
|
-
|
|
98
|
-
|
|
101
|
+
interface ViewInput {
|
|
102
|
+
interactive: boolean;
|
|
103
|
+
headers: string[];
|
|
104
|
+
flattenedRows: FlattenedTableDataRow[];
|
|
105
|
+
|
|
106
|
+
onHoverRow: (row: TableDataRow, rowEl: HTMLElement) => void;
|
|
107
|
+
onClickRow: (row: TableDataRow, rowEl: HTMLElement) => void;
|
|
108
|
+
onMouseLeave: () => void;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
type View = (input: ViewInput, output: undefined, target: HTMLElement) => void;
|
|
112
|
+
|
|
113
|
+
export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
114
|
+
const {
|
|
115
|
+
interactive,
|
|
116
|
+
headers,
|
|
117
|
+
flattenedRows,
|
|
118
|
+
onHoverRow,
|
|
119
|
+
onClickRow,
|
|
120
|
+
onMouseLeave,
|
|
121
|
+
} = input;
|
|
122
|
+
|
|
123
|
+
const numColumns = headers.length;
|
|
124
|
+
|
|
125
|
+
function renderRow({row, depth}: FlattenedTableDataRow): Lit.TemplateResult {
|
|
126
|
+
const thStyles = Lit.Directives.styleMap({
|
|
127
|
+
paddingLeft: `calc(${depth} * var(--sys-size-5))`,
|
|
128
|
+
backgroundImage: `repeating-linear-gradient(
|
|
129
|
+
to right,
|
|
130
|
+
var(--sys-color-tonal-outline) 0 var(--sys-size-1),
|
|
131
|
+
transparent var(--sys-size-1) var(--sys-size-5)
|
|
132
|
+
)`,
|
|
133
|
+
backgroundPosition: '0 0',
|
|
134
|
+
backgroundRepeat: 'no-repeat',
|
|
135
|
+
backgroundSize: `calc(${depth} * var(--sys-size-5))`,
|
|
136
|
+
});
|
|
137
|
+
const trStyles = Lit.Directives.styleMap({
|
|
138
|
+
color: depth ? 'var(--sys-color-on-surface-subtle)' : '',
|
|
139
|
+
});
|
|
140
|
+
const columnEls = row.values.map(
|
|
141
|
+
(value, i) => i === 0 ? html`<th
|
|
142
|
+
scope="row"
|
|
143
|
+
colspan=${i === row.values.length - 1 ? numColumns - i : 1}
|
|
144
|
+
style=${thStyles}>${value}
|
|
145
|
+
</th>` :
|
|
146
|
+
html`<td>${value}</td>`);
|
|
147
|
+
return html`<tr style=${trStyles}>${columnEls}</tr>`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const findRowAndEl = (el: HTMLElement): {row: TableDataRow, rowEl: HTMLElement} => {
|
|
151
|
+
const rowEl = el.closest('tr') as HTMLTableRowElement;
|
|
152
|
+
const row = flattenedRows[rowEl.sectionRowIndex].row;
|
|
153
|
+
return {row, rowEl};
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// clang-format off
|
|
157
|
+
Lit.render(html`
|
|
158
|
+
<style>${tableStyles}</style>
|
|
159
|
+
<table
|
|
160
|
+
class=${Lit.Directives.classMap({
|
|
161
|
+
interactive,
|
|
162
|
+
})}
|
|
163
|
+
@mouseleave=${interactive ? onMouseLeave : null}>
|
|
164
|
+
<thead>
|
|
165
|
+
<tr>
|
|
166
|
+
${headers.map(h => html`<th scope="col">${h}</th>`)}
|
|
167
|
+
</tr>
|
|
168
|
+
</thead>
|
|
169
|
+
<tbody
|
|
170
|
+
@mouseover=${interactive ? (e: Event) => {
|
|
171
|
+
const {row, rowEl} = findRowAndEl(e.target as HTMLElement);
|
|
172
|
+
onHoverRow(row, rowEl);
|
|
173
|
+
} : null}
|
|
174
|
+
@click=${interactive ? (e: Event) => {
|
|
175
|
+
const {row, rowEl} = findRowAndEl(e.target as HTMLElement);
|
|
176
|
+
onClickRow(row, rowEl);
|
|
177
|
+
} : null}
|
|
178
|
+
>${flattenedRows.map(renderRow)}</tbody>
|
|
179
|
+
</table>`,
|
|
180
|
+
target);
|
|
181
|
+
// clang-format on
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
export class Table extends UI.Widget.Widget {
|
|
185
|
+
#view: View;
|
|
99
186
|
#insight?: BaseInsightComponent;
|
|
100
187
|
#state?: TableState;
|
|
101
188
|
#headers?: string[];
|
|
102
189
|
/** The rows as given as by the user, which may include recursive rows via subRows. */
|
|
103
190
|
#rows?: TableDataRow[];
|
|
104
191
|
/** All rows/subRows, in the order that they appear visually. This is the result of traversing `#rows` and any subRows found. */
|
|
105
|
-
#flattenedRows?:
|
|
192
|
+
#flattenedRows?: FlattenedTableDataRow[];
|
|
106
193
|
#rowToParentRow = new Map<TableDataRow, TableDataRow>();
|
|
107
194
|
#interactive = false;
|
|
108
|
-
#
|
|
195
|
+
#currentHoverRow: TableDataRow|null = null;
|
|
196
|
+
|
|
197
|
+
constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
|
|
198
|
+
super(element, {useShadowDom: true});
|
|
199
|
+
this.#view = view;
|
|
200
|
+
}
|
|
109
201
|
|
|
110
202
|
set data(data: TableData) {
|
|
111
203
|
this.#insight = data.insight;
|
|
112
204
|
this.#state = data.insight.sharedTableState;
|
|
113
205
|
this.#headers = data.headers;
|
|
114
206
|
this.#rows = data.rows;
|
|
207
|
+
this.#flattenedRows = this.#createFlattenedRows();
|
|
115
208
|
// If this table isn't interactive, don't attach mouse listeners or use CSS :hover.
|
|
116
209
|
this.#interactive = this.#rows.some(row => row.overlays || row.subRows?.length);
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
connectedCallback(): void {
|
|
121
|
-
void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#render);
|
|
210
|
+
this.requestUpdate();
|
|
122
211
|
}
|
|
123
212
|
|
|
124
|
-
#
|
|
125
|
-
if (!this.#
|
|
126
|
-
return;
|
|
213
|
+
#createFlattenedRows(): FlattenedTableDataRow[] {
|
|
214
|
+
if (!this.#rows) {
|
|
215
|
+
return [];
|
|
127
216
|
}
|
|
128
217
|
|
|
129
|
-
|
|
130
|
-
|
|
218
|
+
const rowToParentRow = this.#rowToParentRow;
|
|
219
|
+
rowToParentRow.clear();
|
|
220
|
+
|
|
221
|
+
const flattenedRows: FlattenedTableDataRow[] = [];
|
|
222
|
+
function traverse(parent: TableDataRow|null, row: TableDataRow, depth = 0): void {
|
|
223
|
+
if (parent) {
|
|
224
|
+
rowToParentRow.set(row, parent);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
flattenedRows.push({depth, row});
|
|
228
|
+
|
|
229
|
+
for (const subRow of row.subRows ?? []) {
|
|
230
|
+
traverse(row, subRow, depth + 1);
|
|
231
|
+
}
|
|
131
232
|
}
|
|
132
233
|
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
return;
|
|
234
|
+
for (const row of this.#rows) {
|
|
235
|
+
traverse(null, row);
|
|
136
236
|
}
|
|
137
237
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
238
|
+
return flattenedRows;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
#onHoverRow(row: TableDataRow, rowEl: HTMLElement): void {
|
|
242
|
+
if (row === this.#currentHoverRow) {
|
|
141
243
|
return;
|
|
142
244
|
}
|
|
143
245
|
|
|
144
|
-
for (const el of
|
|
246
|
+
for (const el of this.element.querySelectorAll('.hover')) {
|
|
145
247
|
el.classList.remove('hover');
|
|
146
248
|
}
|
|
147
249
|
|
|
148
250
|
// Add 'hover' class to all parent rows.
|
|
149
|
-
let
|
|
150
|
-
while (
|
|
151
|
-
const index = this.#flattenedRows.indexOf(row);
|
|
152
|
-
const rowEl = rowEls[index];
|
|
251
|
+
let curRow: TableDataRow|undefined = this.#rowToParentRow.get(row);
|
|
252
|
+
while (curRow) {
|
|
153
253
|
rowEl.classList.add('hover');
|
|
154
|
-
|
|
254
|
+
curRow = this.#rowToParentRow.get(row);
|
|
155
255
|
}
|
|
156
256
|
|
|
157
|
-
this.#
|
|
257
|
+
this.#currentHoverRow = row;
|
|
158
258
|
// Temporarily selects the row, but only if there is not already a sticky selection.
|
|
159
|
-
this.#onSelectedRowChanged(
|
|
259
|
+
this.#onSelectedRowChanged(row, rowEl, {isHover: true});
|
|
160
260
|
}
|
|
161
261
|
|
|
162
|
-
#onClickRow(
|
|
163
|
-
if (!(e.target instanceof HTMLElement)) {
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const rowEl = e.target.closest('tr');
|
|
168
|
-
if (!rowEl?.parentElement) {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const index = [...rowEl.parentElement.children].indexOf(rowEl);
|
|
173
|
-
if (index === -1) {
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
|
|
262
|
+
#onClickRow(row: TableDataRow, rowEl: HTMLElement): void {
|
|
177
263
|
// If the desired overlays consist of just a single ENTRY_OUTLINE, then
|
|
178
264
|
// it is more intuitive to just select the target event.
|
|
179
|
-
const overlays =
|
|
265
|
+
const overlays = row.overlays;
|
|
180
266
|
if (overlays?.length === 1 && overlays[0].type === 'ENTRY_OUTLINE') {
|
|
181
|
-
this.dispatchEvent(new EventReferenceClick(overlays[0].entry));
|
|
267
|
+
this.element.dispatchEvent(new EventReferenceClick(overlays[0].entry));
|
|
182
268
|
return;
|
|
183
269
|
}
|
|
184
270
|
|
|
185
271
|
// Select the row and make it sticky.
|
|
186
|
-
this.#onSelectedRowChanged(
|
|
272
|
+
this.#onSelectedRowChanged(row, rowEl, {sticky: true});
|
|
187
273
|
}
|
|
188
274
|
|
|
189
275
|
#onMouseLeave(): void {
|
|
190
|
-
for (const el of this.shadowRoot?.querySelectorAll('.hover') ?? []) {
|
|
276
|
+
for (const el of this.element.shadowRoot?.querySelectorAll('.hover') ?? []) {
|
|
191
277
|
el.classList.remove('hover');
|
|
192
278
|
}
|
|
193
279
|
|
|
194
|
-
this.#
|
|
280
|
+
this.#currentHoverRow = null;
|
|
195
281
|
// Unselect the row, unless it's sticky.
|
|
196
282
|
this.#onSelectedRowChanged(null, null);
|
|
197
283
|
}
|
|
198
284
|
|
|
199
|
-
#onSelectedRowChanged(
|
|
285
|
+
#onSelectedRowChanged(row: TableDataRow|null, rowEl: HTMLElement|null, opts: {
|
|
200
286
|
sticky?: boolean,
|
|
201
287
|
isHover?: boolean,
|
|
202
288
|
} = {}): void {
|
|
203
|
-
if (!this.#
|
|
289
|
+
if (!this.#state || !this.#insight) {
|
|
204
290
|
return;
|
|
205
291
|
}
|
|
206
292
|
|
|
@@ -214,8 +300,8 @@ export class Table extends HTMLElement {
|
|
|
214
300
|
opts.sticky = false;
|
|
215
301
|
}
|
|
216
302
|
|
|
217
|
-
if (rowEl &&
|
|
218
|
-
const overlays =
|
|
303
|
+
if (rowEl && row) {
|
|
304
|
+
const overlays = row.overlays;
|
|
219
305
|
if (overlays) {
|
|
220
306
|
this.#insight.toggleTemporaryOverlays(overlays, {updateTraceWindow: !opts.isHover});
|
|
221
307
|
}
|
|
@@ -229,83 +315,19 @@ export class Table extends HTMLElement {
|
|
|
229
315
|
this.#state.selectionIsSticky = opts.sticky ?? false;
|
|
230
316
|
}
|
|
231
317
|
|
|
232
|
-
|
|
233
|
-
if (!this.#headers || !this.#
|
|
318
|
+
override performUpdate(): void {
|
|
319
|
+
if (!this.#headers || !this.#flattenedRows) {
|
|
234
320
|
return;
|
|
235
321
|
}
|
|
236
322
|
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
const thStyles = Lit.Directives.styleMap({
|
|
249
|
-
paddingLeft: `calc(${depth} * var(--sys-size-5))`,
|
|
250
|
-
backgroundImage: `repeating-linear-gradient(
|
|
251
|
-
to right,
|
|
252
|
-
var(--sys-color-tonal-outline) 0 var(--sys-size-1),
|
|
253
|
-
transparent var(--sys-size-1) var(--sys-size-5)
|
|
254
|
-
)`,
|
|
255
|
-
backgroundPosition: '0 0',
|
|
256
|
-
backgroundRepeat: 'no-repeat',
|
|
257
|
-
backgroundSize: `calc(${depth} * var(--sys-size-5))`,
|
|
258
|
-
});
|
|
259
|
-
const trStyles = Lit.Directives.styleMap({
|
|
260
|
-
color: depth ? 'var(--sys-color-on-surface-subtle)' : '',
|
|
261
|
-
});
|
|
262
|
-
const columnEls = row.values.map(
|
|
263
|
-
(value, i) => i === 0 ? html`<th
|
|
264
|
-
scope="row"
|
|
265
|
-
colspan=${i === row.values.length - 1 ? numColumns - i : 1}
|
|
266
|
-
style=${thStyles}>${value}
|
|
267
|
-
</th>` :
|
|
268
|
-
html`<td>${value}</td>`);
|
|
269
|
-
rowEls.push(html`<tr style=${trStyles}>${columnEls}</tr>`);
|
|
270
|
-
|
|
271
|
-
flattenedRows.push(row);
|
|
272
|
-
|
|
273
|
-
for (const subRow of row.subRows ?? []) {
|
|
274
|
-
traverse(row, subRow, depth + 1);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
for (const row of this.#rows) {
|
|
279
|
-
traverse(null, row);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
this.#flattenedRows = flattenedRows;
|
|
283
|
-
|
|
284
|
-
Lit.render(
|
|
285
|
-
html`<style>${tableStyles}</style>
|
|
286
|
-
<table
|
|
287
|
-
class=${Lit.Directives.classMap({
|
|
288
|
-
interactive: this.#interactive,
|
|
289
|
-
})}
|
|
290
|
-
@mouseleave=${this.#interactive ? this.#onMouseLeave : null}>
|
|
291
|
-
<thead>
|
|
292
|
-
<tr>
|
|
293
|
-
${this.#headers.map(h => html`<th scope="col">${h}</th>`)}
|
|
294
|
-
</tr>
|
|
295
|
-
</thead>
|
|
296
|
-
<tbody
|
|
297
|
-
@mouseover=${this.#interactive ? this.#onHoverRow : null}
|
|
298
|
-
@click=${this.#interactive ? this.#onClickRow : null}
|
|
299
|
-
>${rowEls}</tbody>
|
|
300
|
-
</table>`,
|
|
301
|
-
this.#shadow, {host: this});
|
|
323
|
+
const input: ViewInput = {
|
|
324
|
+
interactive: this.#interactive,
|
|
325
|
+
headers: this.#headers,
|
|
326
|
+
flattenedRows: this.#flattenedRows,
|
|
327
|
+
onHoverRow: this.#onHoverRow.bind(this),
|
|
328
|
+
onClickRow: this.#onClickRow.bind(this),
|
|
329
|
+
onMouseLeave: this.#onMouseLeave.bind(this),
|
|
330
|
+
};
|
|
331
|
+
this.#view(input, undefined, this.contentElement);
|
|
302
332
|
}
|
|
303
333
|
}
|
|
304
|
-
|
|
305
|
-
declare global {
|
|
306
|
-
interface HTMLElementTagNameMap {
|
|
307
|
-
'devtools-performance-table': Table;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
customElements.define('devtools-performance-table', Table);
|
|
@@ -5,14 +5,16 @@
|
|
|
5
5
|
import * as i18n from '../../../../core/i18n/i18n.js';
|
|
6
6
|
import type {ThirdPartiesInsightModel} from '../../../../models/trace/insights/ThirdParties.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
|
-
import {createLimitedRows, renderOthersLabel, type RowLimitAggregator} from './Table.js';
|
|
12
|
+
import {createLimitedRows, renderOthersLabel, type RowLimitAggregator, Table} from './Table.js';
|
|
12
13
|
|
|
13
14
|
const {UIStrings, i18nString, createOverlaysForSummary} = Trace.Insights.Models.ThirdParties;
|
|
14
15
|
|
|
15
16
|
const {html} = Lit;
|
|
17
|
+
const {widgetConfig} = UI.Widget;
|
|
16
18
|
|
|
17
19
|
const MAX_TO_SHOW = 5;
|
|
18
20
|
|
|
@@ -77,13 +79,13 @@ export class ThirdParties extends BaseInsightComponent<ThirdPartiesInsightModel>
|
|
|
77
79
|
// clang-format off
|
|
78
80
|
sections.push(html`
|
|
79
81
|
<div class="insight-section">
|
|
80
|
-
<devtools-
|
|
81
|
-
|
|
82
|
+
<devtools-widget .widgetConfig=${widgetConfig(Table, {
|
|
83
|
+
data: {
|
|
82
84
|
insight: this,
|
|
83
85
|
headers: [i18nString(UIStrings.columnThirdParty), i18nString(UIStrings.columnTransferSize)],
|
|
84
86
|
rows,
|
|
85
|
-
}}>
|
|
86
|
-
</devtools-
|
|
87
|
+
}})}>
|
|
88
|
+
</devtools-widget>
|
|
87
89
|
</div>
|
|
88
90
|
`);
|
|
89
91
|
// clang-format on
|
|
@@ -94,13 +96,13 @@ export class ThirdParties extends BaseInsightComponent<ThirdPartiesInsightModel>
|
|
|
94
96
|
// clang-format off
|
|
95
97
|
sections.push(html`
|
|
96
98
|
<div class="insight-section">
|
|
97
|
-
<devtools-
|
|
98
|
-
|
|
99
|
+
<devtools-widget .widgetConfig=${widgetConfig(Table, {
|
|
100
|
+
data: {
|
|
99
101
|
insight: this,
|
|
100
102
|
headers: [i18nString(UIStrings.columnThirdParty), i18nString(UIStrings.columnMainThreadTime)],
|
|
101
103
|
rows,
|
|
102
|
-
}}>
|
|
103
|
-
</devtools-
|
|
104
|
+
}})}>
|
|
105
|
+
</devtools-widget>
|
|
104
106
|
</div>
|
|
105
107
|
`);
|
|
106
108
|
// clang-format on
|