@@ -21,12 +21,14 @@ import './networkTab.css';
21
21
import { NetworkResourceDetails } from './networkResourceDetails' ;
22
22
import { bytesToString , msToString } from '@web/uiUtils' ;
23
23
import { PlaceholderPanel } from './placeholderPanel' ;
24
- import type { MultiTraceModel } from './modelUtil' ;
24
+ import { context , type MultiTraceModel } from './modelUtil' ;
25
25
import { GridView , type RenderedGridCell } from '@web/components/gridView' ;
26
26
import { SplitView } from '@web/components/splitView' ;
27
+ import type { ContextEntry } from '../entries' ;
27
28
28
29
type NetworkTabModel = {
29
30
resources : Entry [ ] ,
31
+ contextIdMap : ContextIdMap ,
30
32
} ;
31
33
32
34
type RenderedEntry = {
@@ -39,6 +41,7 @@ type RenderedEntry = {
39
41
start : number ,
40
42
route : string ,
41
43
resource : Entry ,
44
+ contextId : string ,
42
45
} ;
43
46
type ColumnName = keyof RenderedEntry ;
44
47
type Sorting = { by : ColumnName , negate : boolean } ;
@@ -54,7 +57,8 @@ export function useNetworkTabModel(model: MultiTraceModel | undefined, selectedT
54
57
} ) ;
55
58
return filtered ;
56
59
} , [ model , selectedTime ] ) ;
57
- return { resources } ;
60
+ const contextIdMap = React . useMemo ( ( ) => new ContextIdMap ( model ) , [ model ] ) ;
61
+ return { resources, contextIdMap } ;
58
62
}
59
63
60
64
export const NetworkTab : React . FunctionComponent < {
@@ -66,11 +70,11 @@ export const NetworkTab: React.FunctionComponent<{
66
70
const [ selectedEntry , setSelectedEntry ] = React . useState < RenderedEntry | undefined > ( undefined ) ;
67
71
68
72
const { renderedEntries } = React . useMemo ( ( ) => {
69
- const renderedEntries = networkModel . resources . map ( entry => renderEntry ( entry , boundaries ) ) ;
73
+ const renderedEntries = networkModel . resources . map ( entry => renderEntry ( entry , boundaries , networkModel . contextIdMap ) ) ;
70
74
if ( sorting )
71
75
sort ( renderedEntries , sorting ) ;
72
76
return { renderedEntries } ;
73
- } , [ networkModel . resources , sorting , boundaries ] ) ;
77
+ } , [ networkModel . resources , networkModel . contextIdMap , sorting , boundaries ] ) ;
74
78
75
79
if ( ! networkModel . resources . length )
76
80
return < PlaceholderPanel text = 'No network calls' /> ;
@@ -81,7 +85,7 @@ export const NetworkTab: React.FunctionComponent<{
81
85
selectedItem = { selectedEntry }
82
86
onSelected = { item => setSelectedEntry ( item ) }
83
87
onHighlighted = { item => onEntryHovered ( item ?. resource ) }
84
- columns = { selectedEntry ? [ 'name' ] : [ 'name' , 'method' , 'status' , 'contentType' , 'duration' , 'size' , 'start' , 'route' ] }
88
+ columns = { visibleColumns ( ! ! selectedEntry , renderedEntries ) }
85
89
columnTitle = { columnTitle }
86
90
columnWidth = { columnWidth }
87
91
isError = { item => item . status . code >= 400 }
@@ -100,6 +104,8 @@ export const NetworkTab: React.FunctionComponent<{
100
104
} ;
101
105
102
106
const columnTitle = ( column : ColumnName ) => {
107
+ if ( column === 'contextId' )
108
+ return 'Source' ;
103
109
if ( column === 'name' )
104
110
return 'Name' ;
105
111
if ( column === 'method' )
@@ -128,10 +134,28 @@ const columnWidth = (column: ColumnName) => {
128
134
return 60 ;
129
135
if ( column === 'contentType' )
130
136
return 200 ;
137
+ if ( column === 'contextId' )
138
+ return 60 ;
131
139
return 100 ;
132
140
} ;
133
141
142
+ function visibleColumns ( entrySelected : boolean , renderedEntries : RenderedEntry [ ] ) : ( keyof RenderedEntry ) [ ] {
143
+ if ( entrySelected )
144
+ return [ 'name' ] ;
145
+ const columns : ( keyof RenderedEntry ) [ ] = [ ] ;
146
+ if ( hasMultipleContexts ( renderedEntries ) )
147
+ columns . push ( 'contextId' ) ;
148
+ columns . push ( 'name' , 'method' , 'status' , 'contentType' , 'duration' , 'size' , 'start' , 'route' ) ;
149
+ return columns ;
150
+ }
151
+
134
152
const renderCell = ( entry : RenderedEntry , column : ColumnName ) : RenderedGridCell => {
153
+ if ( column === 'contextId' ) {
154
+ return {
155
+ body : entry . contextId ,
156
+ title : entry . name . url ,
157
+ } ;
158
+ }
135
159
if ( column === 'name' ) {
136
160
return {
137
161
body : entry . name . name ,
@@ -159,7 +183,57 @@ const renderCell = (entry: RenderedEntry, column: ColumnName): RenderedGridCell
159
183
return { body : '' } ;
160
184
} ;
161
185
162
- const renderEntry = ( resource : Entry , boundaries : Boundaries ) : RenderedEntry => {
186
+ class ContextIdMap {
187
+ private _pagerefToShortId = new Map < string , string > ( ) ;
188
+ private _contextToId = new Map < ContextEntry , string > ( ) ;
189
+ private _lastPageId = 0 ;
190
+ private _lastApiRequestContextId = 0 ;
191
+
192
+ constructor ( model : MultiTraceModel | undefined ) { }
193
+
194
+ contextId ( resource : Entry ) : string {
195
+ if ( resource . pageref )
196
+ return this . _pageId ( resource . pageref ) ;
197
+ else if ( resource . _apiRequest )
198
+ return this . _apiRequestContextId ( resource ) ;
199
+ return '' ;
200
+ }
201
+
202
+ private _pageId ( pageref : string ) : string {
203
+ let shortId = this . _pagerefToShortId . get ( pageref ) ;
204
+ if ( ! shortId ) {
205
+ ++ this . _lastPageId ;
206
+ shortId = 'page#' + this . _lastPageId ;
207
+ this . _pagerefToShortId . set ( pageref , shortId ) ;
208
+ }
209
+ return shortId ;
210
+ }
211
+
212
+ private _apiRequestContextId ( resource : Entry ) : string {
213
+ const contextEntry = context ( resource ) ;
214
+ if ( ! contextEntry )
215
+ return '' ;
216
+ let contextId = this . _contextToId . get ( contextEntry ) ;
217
+ if ( ! contextId ) {
218
+ ++ this . _lastApiRequestContextId ;
219
+ contextId = 'api#' + this . _lastApiRequestContextId ;
220
+ this . _contextToId . set ( contextEntry , contextId ) ;
221
+ }
222
+ return contextId ;
223
+ }
224
+ }
225
+
226
+ function hasMultipleContexts ( renderedEntries : RenderedEntry [ ] ) : boolean {
227
+ const contextIds = new Set < string > ( ) ;
228
+ for ( const entry of renderedEntries ) {
229
+ contextIds . add ( entry . contextId ) ;
230
+ if ( contextIds . size > 1 )
231
+ return true ;
232
+ }
233
+ return false ;
234
+ }
235
+
236
+ const renderEntry = ( resource : Entry , boundaries : Boundaries , contextIdGenerator : ContextIdMap ) : RenderedEntry => {
163
237
const routeStatus = formatRouteStatus ( resource ) ;
164
238
let resourceName : string ;
165
239
try {
@@ -184,7 +258,8 @@ const renderEntry = (resource: Entry, boundaries: Boundaries): RenderedEntry =>
184
258
size : resource . response . _transferSize ! > 0 ? resource . response . _transferSize ! : resource . response . bodySize ,
185
259
start : resource . _monotonicTime ! - boundaries . minimum ,
186
260
route : routeStatus ,
187
- resource
261
+ resource,
262
+ contextId : contextIdGenerator . contextId ( resource ) ,
188
263
} ;
189
264
} ;
190
265
@@ -249,4 +324,7 @@ function comparator(sortBy: ColumnName) {
249
324
return a . route . localeCompare ( b . route ) ;
250
325
} ;
251
326
}
327
+
328
+ if ( sortBy === 'contextId' )
329
+ return ( a : RenderedEntry , b : RenderedEntry ) => a . contextId . localeCompare ( b . contextId ) ;
252
330
}
0 commit comments