Skip to content

Commit 12c5665

Browse files
authored
pass selected operations filter to query for pagination; add operation counts by selected client (#7030)
1 parent 3dd4019 commit 12c5665

File tree

7 files changed

+90
-14
lines changed

7 files changed

+90
-14
lines changed

.changeset/full-moments-sleep.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'hive': minor
3+
---
4+
5+
add operation counts by selected client to insights filter

.changeset/moody-radios-switch.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'hive': patch
3+
---
4+
5+
Fix paginated operations list filtering if there are many operations by passing a list of operation
6+
IDs to filter on

packages/web/app/src/components/target/insights/Filters.tsx

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,31 @@ function OperationsFilter({
3131
onFilter,
3232
operationStatsConnection,
3333
selected,
34+
clientOperationStatsConnection,
3435
}: {
3536
onClose(): void;
3637
onFilter(keys: string[]): void;
3738
isOpen: boolean;
3839
operationStatsConnection: FragmentType<
3940
typeof OperationsFilter_OperationStatsValuesConnectionFragment
4041
>;
42+
clientOperationStatsConnection?:
43+
| FragmentType<typeof OperationsFilter_OperationStatsValuesConnectionFragment>
44+
| undefined;
4145
selected?: string[];
4246
}): ReactElement {
4347
const operations = useFragment(
4448
OperationsFilter_OperationStatsValuesConnectionFragment,
4549
operationStatsConnection,
4650
);
4751

52+
const clientFilteredOperations = clientOperationStatsConnection
53+
? useFragment(
54+
OperationsFilter_OperationStatsValuesConnectionFragment,
55+
clientOperationStatsConnection,
56+
)
57+
: null;
58+
4859
function getOperationHashes() {
4960
const items: string[] = [];
5061
for (const { node: op } of operations.edges) {
@@ -103,12 +114,16 @@ function OperationsFilter({
103114
const renderRow = useCallback<ComponentType<ListChildComponentProps>>(
104115
({ index, style }) => {
105116
const operation = visibleOperations[index].node;
117+
const clientOpStats = clientFilteredOperations?.edges.find(
118+
e => e.node.operationHash === operation.operationHash,
119+
)?.node;
106120

107121
return (
108122
<OperationRow
109123
style={style}
110124
key={operation.id}
111125
operationStats={operation}
126+
clientOperationStats={clientFilteredOperations === null ? false : clientOpStats}
112127
selected={selectedItems.includes(operation.operationHash || '')}
113128
onSelect={onSelect}
114129
/>
@@ -157,6 +172,11 @@ function OperationsFilter({
157172
</Button>
158173
</div>
159174
<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+
)}
160180
<AutoSizer>
161181
{({ height, width }) =>
162182
!height || !width ? (
@@ -185,6 +205,8 @@ const OperationsFilterContainer_OperationStatsQuery = graphql(`
185205
query OperationsFilterContainer_OperationStatsQuery(
186206
$targetSelector: TargetSelectorInput!
187207
$period: DateRangeInput!
208+
$filter: OperationStatsFilterInput
209+
$hasFilter: Boolean!
188210
) {
189211
target(reference: { bySelector: $targetSelector }) {
190212
id
@@ -196,6 +218,15 @@ const OperationsFilterContainer_OperationStatsQuery = graphql(`
196218
...OperationsFilter_OperationStatsValuesConnectionFragment
197219
}
198220
}
221+
clientOperationStats: operationsStats(period: $period, filter: $filter)
222+
@include(if: $hasFilter) {
223+
operations {
224+
edges {
225+
__typename
226+
}
227+
...OperationsFilter_OperationStatsValuesConnectionFragment
228+
}
229+
}
199230
}
200231
}
201232
`);
@@ -209,6 +240,7 @@ function OperationsFilterContainer({
209240
organizationSlug,
210241
projectSlug,
211242
targetSlug,
243+
clientNames,
212244
}: {
213245
onFilter(keys: string[]): void;
214246
onClose(): void;
@@ -218,6 +250,7 @@ function OperationsFilterContainer({
218250
organizationSlug: string;
219251
projectSlug: string;
220252
targetSlug: string;
253+
clientNames?: string[];
221254
}): ReactElement | null {
222255
const [query, refresh] = useQuery({
223256
query: OperationsFilterContainer_OperationStatsQuery,
@@ -228,6 +261,8 @@ function OperationsFilterContainer({
228261
targetSlug,
229262
},
230263
period,
264+
filter: clientNames ? { clientNames } : undefined,
265+
hasFilter: !!clientNames?.length,
231266
},
232267
});
233268

@@ -250,6 +285,7 @@ function OperationsFilterContainer({
250285
return (
251286
<OperationsFilter
252287
operationStatsConnection={target.operationsStats.operations}
288+
clientOperationStatsConnection={target.clientOperationStats?.operations}
253289
selected={selected}
254290
isOpen={isOpen}
255291
onClose={onClose}
@@ -271,24 +307,47 @@ const OperationRow_OperationStatsValuesFragment = graphql(`
271307

272308
function OperationRow({
273309
operationStats,
310+
clientOperationStats,
274311
selected,
275312
onSelect,
276313
style,
277314
}: {
278315
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;
279321
selected: boolean;
280322
onSelect(id: string, selected: boolean): void;
281323
style: any;
282324
}): ReactElement {
283325
const operation = useFragment(OperationRow_OperationStatsValuesFragment, operationStats);
284326
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;
285332
const hash = operation.operationHash || '';
286333
const change = useCallback(() => {
287334
if (hash) {
288335
onSelect(hash, !selected);
289336
}
290337
}, [onSelect, hash, selected]);
291338

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+
292351
return (
293352
<div style={style} className="flex items-center gap-4 truncate">
294353
<Checkbox checked={selected} onCheckedChange={change} id={hash} />
@@ -297,7 +356,7 @@ function OperationRow({
297356
className="flex w-full cursor-pointer items-center justify-between gap-4 overflow-hidden"
298357
>
299358
<span className="grow overflow-hidden text-ellipsis">{operation.name}</span>
300-
<div className="shrink-0 text-right text-gray-500">{requests}</div>
359+
<Totals />
301360
</label>
302361
</div>
303362
);
@@ -310,13 +369,15 @@ export function OperationsFilterTrigger({
310369
organizationSlug,
311370
projectSlug,
312371
targetSlug,
372+
clientNames,
313373
}: {
314374
period: DateRangeInput;
315375
onFilter(keys: string[]): void;
316376
selected?: string[];
317377
organizationSlug: string;
318378
projectSlug: string;
319379
targetSlug: string;
380+
clientNames?: string[];
320381
}): ReactElement {
321382
const [isOpen, toggle] = useToggle();
322383

@@ -335,6 +396,7 @@ export function OperationsFilterTrigger({
335396
period={period}
336397
selected={selected}
337398
onFilter={onFilter}
399+
clientNames={clientNames}
338400
/>
339401
</>
340402
);

packages/web/app/src/components/target/insights/List.tsx

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,9 @@ function OperationsTable({
241241
)}
242242
>
243243
<Section.Title>Operations</Section.Title>
244-
<Section.Subtitle>List of all operations with their statistics</Section.Subtitle>
244+
<Section.Subtitle>
245+
List of all operations with their statistics, filtered by selected clients.
246+
</Section.Subtitle>
245247

246248
<Table>
247249
<THead>
@@ -382,7 +384,6 @@ const OperationsTableContainer_OperationsStatsFragment = graphql(`
382384
`);
383385

384386
function OperationsTableContainer({
385-
operationsFilter,
386387
organizationSlug,
387388
projectSlug,
388389
targetSlug,
@@ -393,7 +394,6 @@ function OperationsTableContainer({
393394
...props
394395
}: {
395396
operationStats: FragmentType<typeof OperationsTableContainer_OperationsStatsFragment> | null;
396-
operationsFilter: readonly string[];
397397
organizationSlug: string;
398398
projectSlug: string;
399399
targetSlug: string;
@@ -410,13 +410,6 @@ function OperationsTableContainer({
410410
const records: Operation[] = [];
411411
if (operationStats) {
412412
for (const { node: op } of operationStats.operations.edges) {
413-
if (
414-
operationsFilter.length > 0 &&
415-
op.operationHash &&
416-
!operationsFilter.includes(op.operationHash)
417-
) {
418-
continue;
419-
}
420413
records.push({
421414
id: op.id,
422415
name: op.name,
@@ -434,7 +427,7 @@ function OperationsTableContainer({
434427
}
435428

436429
return records;
437-
}, [operationStats?.operations.edges, operationsFilter]);
430+
}, [operationStats?.operations.edges]);
438431

439432
const [pagination, setPagination] = useState<PaginationState>({ pageIndex: 0, pageSize: 20 });
440433

@@ -517,7 +510,8 @@ export function OperationsList({
517510
projectSlug: string;
518511
targetSlug: string;
519512
period: DateRangeInput;
520-
operationsFilter: readonly string[];
513+
/** Operation IDs to filter on */
514+
operationsFilter: string[];
521515
clientNamesFilter: string[];
522516
selectedPeriod: null | { to: string; from: string };
523517
}): ReactElement {
@@ -532,6 +526,7 @@ export function OperationsList({
532526
},
533527
period,
534528
filter: {
529+
operationIds: operationsFilter,
535530
clientNames: clientNamesFilter,
536531
},
537532
},
@@ -552,7 +547,6 @@ export function OperationsList({
552547
>
553548
<OperationsTableContainer
554549
operationStats={query.data?.target?.operationsStats ?? null}
555-
operationsFilter={operationsFilter}
556550
className={className}
557551
setClientFilter={setClientFilter}
558552
clientFilter={clientFilter}

packages/web/app/src/lib/urql.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export const urqlClient = createClient({
5151
ClientStats: noKey,
5252
ClientStatsValues: noKey,
5353
OperationsStats: noKey,
54+
OperationStatsValues: noKey,
5455
DurationValues: noKey,
5556
OrganizationPayload: noKey,
5657
SchemaChange: noKey,

packages/web/app/src/pages/target-insights.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ function OperationsView({
5454
period={dateRangeController.resolvedRange}
5555
selected={selectedOperations}
5656
onFilter={setSelectedOperations}
57+
clientNames={selectedClients}
5758
/>
5859
<ClientsFilterTrigger
5960
organizationSlug={organizationSlug}

scripts/seed-local-env.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const usageReportingEndpoint =
2020
: envName === 'dev'
2121
? 'https://app.dev.graphql-hive.com/usage'
2222
: 'http://localhost:4001';
23+
const target = process.env.TARGET;
2324

2425
console.log(`
2526
Environment: ${envName}
@@ -55,6 +56,7 @@ const createInstance = (
5556
: false,
5657
usage: isUsageReportingEnabled
5758
? {
59+
target: target || undefined,
5860
clientInfo: () => ({
5961
name: 'Fake Hive Client',
6062
version: '1.1.1',
@@ -348,6 +350,7 @@ async function federation() {
348350
sdl: schemaInventory,
349351
service: 'Inventory',
350352
url: 'https://inventory.localhost/graphql',
353+
target: target ? { byId: target } : null,
351354
},
352355
},
353356
}),
@@ -369,6 +372,7 @@ async function federation() {
369372
sdl: schemaPandas,
370373
service: 'Panda',
371374
url: 'https://panda.localhost/graphql',
375+
target: target ? { byId: target } : null,
372376
},
373377
},
374378
}),
@@ -391,6 +395,7 @@ async function federation() {
391395
sdl: schemaProducts,
392396
service: 'Products',
393397
url: 'https://products.localhost/graphql',
398+
target: target ? { byId: target } : null,
394399
},
395400
},
396401
}),
@@ -413,6 +418,7 @@ async function federation() {
413418
sdl: schemaReviews,
414419
service: 'Reviews',
415420
url: 'https://reviews.localhost/graphql',
421+
target: target ? { byId: target } : null,
416422
},
417423
},
418424
}),
@@ -435,6 +441,7 @@ async function federation() {
435441
sdl: schemaUsers,
436442
service: 'Users',
437443
url: 'https://users.localhost/graphql',
444+
target: target ? { byId: target } : null,
438445
},
439446
},
440447
}),

0 commit comments

Comments
 (0)