@@ -31,20 +31,31 @@ function OperationsFilter({
31
31
onFilter,
32
32
operationStatsConnection,
33
33
selected,
34
+ clientOperationStatsConnection,
34
35
} : {
35
36
onClose ( ) : void ;
36
37
onFilter ( keys : string [ ] ) : void ;
37
38
isOpen : boolean ;
38
39
operationStatsConnection : FragmentType <
39
40
typeof OperationsFilter_OperationStatsValuesConnectionFragment
40
41
> ;
42
+ clientOperationStatsConnection ?:
43
+ | FragmentType < typeof OperationsFilter_OperationStatsValuesConnectionFragment >
44
+ | undefined ;
41
45
selected ?: string [ ] ;
42
46
} ) : ReactElement {
43
47
const operations = useFragment (
44
48
OperationsFilter_OperationStatsValuesConnectionFragment ,
45
49
operationStatsConnection ,
46
50
) ;
47
51
52
+ const clientFilteredOperations = clientOperationStatsConnection
53
+ ? useFragment (
54
+ OperationsFilter_OperationStatsValuesConnectionFragment ,
55
+ clientOperationStatsConnection ,
56
+ )
57
+ : null ;
58
+
48
59
function getOperationHashes ( ) {
49
60
const items : string [ ] = [ ] ;
50
61
for ( const { node : op } of operations . edges ) {
@@ -103,12 +114,16 @@ function OperationsFilter({
103
114
const renderRow = useCallback < ComponentType < ListChildComponentProps > > (
104
115
( { index, style } ) => {
105
116
const operation = visibleOperations [ index ] . node ;
117
+ const clientOpStats = clientFilteredOperations ?. edges . find (
118
+ e => e . node . operationHash === operation . operationHash ,
119
+ ) ?. node ;
106
120
107
121
return (
108
122
< OperationRow
109
123
style = { style }
110
124
key = { operation . id }
111
125
operationStats = { operation }
126
+ clientOperationStats = { clientFilteredOperations === null ? false : clientOpStats }
112
127
selected = { selectedItems . includes ( operation . operationHash || '' ) }
113
128
onSelect = { onSelect }
114
129
/>
@@ -157,6 +172,11 @@ function OperationsFilter({
157
172
</ Button >
158
173
</ div >
159
174
< div className = "grow pl-1" >
175
+ { clientFilteredOperations && (
176
+ < div className = "text-right text-xs text-gray-600" >
177
+ < span className = "text-gray-500" > selected</ span > / all clients
178
+ </ div >
179
+ ) }
160
180
< AutoSizer >
161
181
{ ( { height, width } ) =>
162
182
! height || ! width ? (
@@ -185,6 +205,8 @@ const OperationsFilterContainer_OperationStatsQuery = graphql(`
185
205
query OperationsFilterContainer_OperationStatsQuery(
186
206
$targetSelector: TargetSelectorInput!
187
207
$period: DateRangeInput!
208
+ $filter: OperationStatsFilterInput
209
+ $hasFilter: Boolean!
188
210
) {
189
211
target(reference: { bySelector: $targetSelector }) {
190
212
id
@@ -196,6 +218,15 @@ const OperationsFilterContainer_OperationStatsQuery = graphql(`
196
218
...OperationsFilter_OperationStatsValuesConnectionFragment
197
219
}
198
220
}
221
+ clientOperationStats: operationsStats(period: $period, filter: $filter)
222
+ @include(if: $hasFilter) {
223
+ operations {
224
+ edges {
225
+ __typename
226
+ }
227
+ ...OperationsFilter_OperationStatsValuesConnectionFragment
228
+ }
229
+ }
199
230
}
200
231
}
201
232
` ) ;
@@ -209,6 +240,7 @@ function OperationsFilterContainer({
209
240
organizationSlug,
210
241
projectSlug,
211
242
targetSlug,
243
+ clientNames,
212
244
} : {
213
245
onFilter ( keys : string [ ] ) : void ;
214
246
onClose ( ) : void ;
@@ -218,6 +250,7 @@ function OperationsFilterContainer({
218
250
organizationSlug : string ;
219
251
projectSlug : string ;
220
252
targetSlug : string ;
253
+ clientNames ?: string [ ] ;
221
254
} ) : ReactElement | null {
222
255
const [ query , refresh ] = useQuery ( {
223
256
query : OperationsFilterContainer_OperationStatsQuery ,
@@ -228,6 +261,8 @@ function OperationsFilterContainer({
228
261
targetSlug,
229
262
} ,
230
263
period,
264
+ filter : clientNames ? { clientNames } : undefined ,
265
+ hasFilter : ! ! clientNames ?. length ,
231
266
} ,
232
267
} ) ;
233
268
@@ -250,6 +285,7 @@ function OperationsFilterContainer({
250
285
return (
251
286
< OperationsFilter
252
287
operationStatsConnection = { target . operationsStats . operations }
288
+ clientOperationStatsConnection = { target . clientOperationStats ?. operations }
253
289
selected = { selected }
254
290
isOpen = { isOpen }
255
291
onClose = { onClose }
@@ -271,24 +307,47 @@ const OperationRow_OperationStatsValuesFragment = graphql(`
271
307
272
308
function OperationRow ( {
273
309
operationStats,
310
+ clientOperationStats,
274
311
selected,
275
312
onSelect,
276
313
style,
277
314
} : {
278
315
operationStats : FragmentType < typeof OperationRow_OperationStatsValuesFragment > ;
316
+ /** Stats for the operation filtered by the selected clients */
317
+ clientOperationStats ?:
318
+ | FragmentType < typeof OperationRow_OperationStatsValuesFragment >
319
+ | null
320
+ | false ;
279
321
selected : boolean ;
280
322
onSelect ( id : string , selected : boolean ) : void ;
281
323
style : any ;
282
324
} ) : ReactElement {
283
325
const operation = useFragment ( OperationRow_OperationStatsValuesFragment , operationStats ) ;
284
326
const requests = useFormattedNumber ( operation . count ) ;
327
+ const clientsOperation = clientOperationStats
328
+ ? useFragment ( OperationRow_OperationStatsValuesFragment , clientOperationStats )
329
+ : undefined ;
330
+ const hasClientOperation = clientOperationStats !== false ;
331
+ const clientsRequests = clientsOperation ? useFormattedNumber ( clientsOperation . count ) : null ;
285
332
const hash = operation . operationHash || '' ;
286
333
const change = useCallback ( ( ) => {
287
334
if ( hash ) {
288
335
onSelect ( hash , ! selected ) ;
289
336
}
290
337
} , [ onSelect , hash , selected ] ) ;
291
338
339
+ const Totals = ( ) => {
340
+ if ( hasClientOperation ) {
341
+ return (
342
+ < div className = "flex shrink-0 text-right text-gray-500" >
343
+ < span > { clientsRequests ?? 0 } </ span >
344
+ < span className = "ml-1 truncate text-gray-600" > / { requests } </ span >
345
+ </ div >
346
+ ) ;
347
+ }
348
+ return < div className = "shrink-0 text-right text-gray-600" > { requests } </ div > ;
349
+ } ;
350
+
292
351
return (
293
352
< div style = { style } className = "flex items-center gap-4 truncate" >
294
353
< Checkbox checked = { selected } onCheckedChange = { change } id = { hash } />
@@ -297,7 +356,7 @@ function OperationRow({
297
356
className = "flex w-full cursor-pointer items-center justify-between gap-4 overflow-hidden"
298
357
>
299
358
< span className = "grow overflow-hidden text-ellipsis" > { operation . name } </ span >
300
- < div className = "shrink-0 text-right text-gray-500" > { requests } </ div >
359
+ < Totals / >
301
360
</ label >
302
361
</ div >
303
362
) ;
@@ -310,13 +369,15 @@ export function OperationsFilterTrigger({
310
369
organizationSlug,
311
370
projectSlug,
312
371
targetSlug,
372
+ clientNames,
313
373
} : {
314
374
period : DateRangeInput ;
315
375
onFilter ( keys : string [ ] ) : void ;
316
376
selected ?: string [ ] ;
317
377
organizationSlug : string ;
318
378
projectSlug : string ;
319
379
targetSlug : string ;
380
+ clientNames ?: string [ ] ;
320
381
} ) : ReactElement {
321
382
const [ isOpen , toggle ] = useToggle ( ) ;
322
383
@@ -335,6 +396,7 @@ export function OperationsFilterTrigger({
335
396
period = { period }
336
397
selected = { selected }
337
398
onFilter = { onFilter }
399
+ clientNames = { clientNames }
338
400
/>
339
401
</ >
340
402
) ;
0 commit comments