Skip to content

Commit 5fec03c

Browse files
Console 1493 schema explorer displaying argument descriptions (#7282)
1 parent 714906f commit 5fec03c

File tree

18 files changed

+470
-474
lines changed

18 files changed

+470
-474
lines changed

packages/web/app/src/components/target/explorer/common.tsx

Lines changed: 31 additions & 394 deletions
Large diffs are not rendered by default.

packages/web/app/src/components/target/explorer/enum-type.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { FragmentType, graphql, useFragment } from '@/gql';
33
import { useRouter } from '@tanstack/react-router';
44
import {
55
DeprecationNote,
6-
DescriptionInline,
6+
Description,
77
GraphQLTypeCard,
88
GraphQLTypeCardListItem,
99
LinkToCoordinatePage,
@@ -99,16 +99,16 @@ export function GraphQLEnumTypeComponent(props: {
9999
{value.name}
100100
</LinkToCoordinatePage>
101101
</DeprecationNote>
102-
{value.description ? <DescriptionInline description={value.description} /> : null}
102+
{value.description && <Description description={value.description} />}
103103
</div>
104-
{value.supergraphMetadata ? (
104+
{value.supergraphMetadata && (
105105
<SupergraphMetadataList
106106
targetSlug={props.targetSlug}
107107
projectSlug={props.projectSlug}
108108
organizationSlug={props.organizationSlug}
109109
supergraphMetadata={value.supergraphMetadata}
110110
/>
111-
) : null}
111+
)}
112112
</GraphQLTypeCardListItem>
113113
))}
114114
</div>

packages/web/app/src/components/target/explorer/filter.tsx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ import {
2727
useLocation,
2828
useRouter,
2929
} from '@tanstack/react-router';
30-
import { useArgumentListToggle, usePeriodSelector, useSchemaExplorerContext } from './provider';
30+
import {
31+
useDescriptionsVisibleToggle,
32+
usePeriodSelector,
33+
useSchemaExplorerContext,
34+
} from './provider';
3135

3236
const TypeFilter_AllTypes = graphql(`
3337
query TypeFilter_AllTypes(
@@ -195,28 +199,28 @@ export function DateRangeFilter() {
195199
);
196200
}
197201

198-
export function ArgumentVisibilityFilter() {
199-
const [collapsed, toggleCollapsed] = useArgumentListToggle();
202+
export function DescriptionsVisibilityFilter() {
203+
const { isDescriptionsVisible, toggleDescriptionsVisible } = useDescriptionsVisibleToggle();
200204
return (
201205
<TooltipProvider>
202206
<Tooltip>
203207
<TooltipTrigger asChild>
204208
<div className="bg-secondary flex h-[40px] flex-row items-center gap-x-4 rounded-md border px-3">
205209
<div>
206-
<Label htmlFor="filter-toggle-arguments" className="text-sm font-normal">
207-
All arguments
210+
<Label htmlFor="filter-toggle-descriptions" className="text-sm font-normal">
211+
Show descriptions
208212
</Label>
209213
</div>
210214
<Switch
211-
checked={!collapsed}
212-
onCheckedChange={toggleCollapsed}
213-
id="filter-toggle-arguments"
215+
checked={isDescriptionsVisible}
216+
onCheckedChange={toggleDescriptionsVisible}
217+
id="filter-toggle-descriptions"
214218
/>
215219
</div>
216220
</TooltipTrigger>
217221
<TooltipContent>
218-
List of arguments is collapsed by default. You can toggle this setting to display all
219-
arguments.
222+
Descriptions are not visible by default. You can toggle this setting to display all
223+
descriptions.
220224
</TooltipContent>
221225
</Tooltip>
222226
</TooltipProvider>
@@ -320,7 +324,7 @@ export function MetadataFilter(props: { options: Array<{ name: string; values: s
320324
>
321325
{props.options.map(({ name, values }, i) => (
322326
<React.Fragment key={name}>
323-
{i > 0 ? <DropdownMenuSeparator /> : null}
327+
{i > 0 && <DropdownMenuSeparator />}
324328
<DropdownMenuGroup
325329
className="flex cursor-pointer overflow-x-hidden text-sm text-gray-400 hover:underline"
326330
onClick={() => {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { FragmentType, graphql, useFragment } from '@/gql';
2+
import { DeprecationNote, Description, GraphQLTypeAsLink, LinkToCoordinatePage } from './common';
3+
import { useDescriptionsVisibleToggle } from './provider';
4+
5+
export const GraphQLArguments_ArgumentFragment = graphql(`
6+
fragment GraphQLArguments_ArgumentFragment on GraphQLArgument {
7+
name
8+
description
9+
type
10+
isDeprecated
11+
deprecationReason
12+
}
13+
`);
14+
15+
export function GraphQLArguments(props: {
16+
parentCoordinate: string;
17+
args: FragmentType<typeof GraphQLArguments_ArgumentFragment>[];
18+
styleDeprecated: boolean;
19+
organizationSlug: string;
20+
projectSlug: string;
21+
targetSlug: string;
22+
}) {
23+
const args = useFragment(GraphQLArguments_ArgumentFragment, props.args);
24+
25+
const { isDescriptionsVisible } = useDescriptionsVisibleToggle();
26+
27+
return (
28+
<span className="ml-1 text-gray-400">
29+
<span>(</span>
30+
<div className="pl-4 text-gray-300">
31+
{args.map(arg => {
32+
const coordinate = `${props.parentCoordinate}.${arg.name}`;
33+
return (
34+
<div key={arg.name}>
35+
<DeprecationNote
36+
styleDeprecated={props.styleDeprecated}
37+
deprecationReason={arg.deprecationReason}
38+
>
39+
<LinkToCoordinatePage
40+
organizationSlug={props.organizationSlug}
41+
projectSlug={props.projectSlug}
42+
targetSlug={props.targetSlug}
43+
coordinate={coordinate}
44+
>
45+
{arg.name}
46+
</LinkToCoordinatePage>
47+
</DeprecationNote>
48+
{': '}
49+
<GraphQLTypeAsLink
50+
className="font-medium"
51+
organizationSlug={props.organizationSlug}
52+
projectSlug={props.projectSlug}
53+
targetSlug={props.targetSlug}
54+
type={arg.type}
55+
/>
56+
{arg.description && isDescriptionsVisible && (
57+
<Description description={arg.description} />
58+
)}
59+
</div>
60+
);
61+
})}
62+
</div>
63+
<span>)</span>
64+
</span>
65+
);
66+
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
2+
import { FragmentType, graphql, useFragment } from '@/gql';
3+
import {
4+
DeprecationNote,
5+
Description,
6+
GraphQLTypeAsLink,
7+
GraphQLTypeCardListItem,
8+
LinkToCoordinatePage,
9+
SchemaExplorerUsageStats,
10+
} from './common';
11+
import { GraphQLArguments } from './graphql-arguments';
12+
import { SupergraphMetadataList } from './super-graph-metadata';
13+
import { useExplorerFieldFiltering } from './utils';
14+
15+
const GraphQLFields_FieldFragment = graphql(`
16+
fragment GraphQLFields_FieldFragment on GraphQLField {
17+
name
18+
description
19+
type
20+
isDeprecated
21+
deprecationReason
22+
usage {
23+
total
24+
...SchemaExplorerUsageStats_UsageFragment
25+
}
26+
args {
27+
...GraphQLArguments_ArgumentFragment
28+
}
29+
supergraphMetadata {
30+
...SupergraphMetadataList_SupergraphMetadataFragment
31+
}
32+
}
33+
`);
34+
35+
export function GraphQLFields(props: {
36+
typeName: string;
37+
fields: Array<FragmentType<typeof GraphQLFields_FieldFragment>>;
38+
totalRequests?: number;
39+
targetSlug: string;
40+
projectSlug: string;
41+
organizationSlug: string;
42+
warnAboutUnusedArguments: boolean;
43+
warnAboutDeprecatedArguments: boolean;
44+
styleDeprecated: boolean;
45+
}) {
46+
const { totalRequests } = props;
47+
const fieldsFromFragment = useFragment(GraphQLFields_FieldFragment, props.fields);
48+
49+
const sortedAndFilteredFields = useExplorerFieldFiltering({
50+
fields: fieldsFromFragment,
51+
});
52+
53+
return (
54+
<TooltipProvider delayDuration={0}>
55+
<div className="flex flex-col">
56+
{sortedAndFilteredFields.map((field, i) => {
57+
const coordinate = `${props.typeName}.${field.name}`;
58+
const isUsed = field.usage.total > 0;
59+
const hasArguments = field.args.length > 0;
60+
const showsUnusedSchema = typeof totalRequests !== 'number';
61+
const isDeprecated = field.isDeprecated;
62+
63+
return (
64+
<GraphQLTypeCardListItem key={field.name} index={i}>
65+
<div className="w-full">
66+
<div className="flex w-full flex-row items-baseline justify-between">
67+
<div>
68+
{props.warnAboutUnusedArguments &&
69+
isUsed &&
70+
hasArguments &&
71+
showsUnusedSchema && (
72+
<Tooltip>
73+
<TooltipContent>
74+
This field is used but the presented arguments are not.
75+
</TooltipContent>
76+
<TooltipTrigger>
77+
<span className="mr-1 text-sm text-orange-500">*</span>
78+
</TooltipTrigger>
79+
</Tooltip>
80+
)}
81+
{props.warnAboutDeprecatedArguments && !isDeprecated && (
82+
<Tooltip>
83+
<TooltipContent>
84+
This field is not deprecated but the presented arguments are.
85+
</TooltipContent>
86+
<TooltipTrigger>
87+
<span className="mr-1 text-sm text-orange-500">*</span>
88+
</TooltipTrigger>
89+
</Tooltip>
90+
)}
91+
<DeprecationNote
92+
styleDeprecated={props.styleDeprecated}
93+
deprecationReason={field.deprecationReason}
94+
>
95+
<LinkToCoordinatePage
96+
organizationSlug={props.organizationSlug}
97+
projectSlug={props.projectSlug}
98+
targetSlug={props.targetSlug}
99+
coordinate={coordinate}
100+
className="font-semibold"
101+
>
102+
{field.name}
103+
</LinkToCoordinatePage>
104+
</DeprecationNote>
105+
{field.args.length > 0 && (
106+
<GraphQLArguments
107+
organizationSlug={props.organizationSlug}
108+
projectSlug={props.projectSlug}
109+
targetSlug={props.targetSlug}
110+
styleDeprecated={props.styleDeprecated}
111+
parentCoordinate={coordinate}
112+
args={field.args}
113+
/>
114+
)}
115+
<span className="mr-1">:</span>
116+
<GraphQLTypeAsLink
117+
organizationSlug={props.organizationSlug}
118+
projectSlug={props.projectSlug}
119+
targetSlug={props.targetSlug}
120+
className="font-semibold text-gray-300"
121+
type={field.type}
122+
/>
123+
</div>
124+
<div className="flex flex-row items-center">
125+
{field.supergraphMetadata && (
126+
<div className="ml-1">
127+
<SupergraphMetadataList
128+
targetSlug={props.targetSlug}
129+
projectSlug={props.projectSlug}
130+
organizationSlug={props.organizationSlug}
131+
supergraphMetadata={field.supergraphMetadata}
132+
/>
133+
</div>
134+
)}
135+
{typeof totalRequests === 'number' && (
136+
<SchemaExplorerUsageStats
137+
totalRequests={totalRequests}
138+
usage={field.usage}
139+
targetSlug={props.targetSlug}
140+
projectSlug={props.projectSlug}
141+
organizationSlug={props.organizationSlug}
142+
/>
143+
)}
144+
</div>
145+
</div>
146+
{field.description && <Description description={field.description} />}
147+
</div>
148+
</GraphQLTypeCardListItem>
149+
);
150+
})}
151+
</div>
152+
</TooltipProvider>
153+
);
154+
}

packages/web/app/src/components/target/explorer/interface-type.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { FragmentType, graphql, useFragment } from '@/gql';
2-
import { useRouter } from '@tanstack/react-router';
3-
import { GraphQLFields, GraphQLTypeCard } from './common';
2+
import { GraphQLTypeCard } from './common';
3+
import { GraphQLFields } from './graphql-fields';
44

55
const GraphQLInterfaceTypeComponent_TypeFragment = graphql(`
66
fragment GraphQLInterfaceTypeComponent_TypeFragment on GraphQLInterfaceType {
@@ -29,12 +29,6 @@ export function GraphQLInterfaceTypeComponent(props: {
2929
warnAboutDeprecatedArguments: boolean;
3030
styleDeprecated: boolean;
3131
}) {
32-
const router = useRouter();
33-
const searchObj = router.latestLocation.search;
34-
const search =
35-
'search' in searchObj && typeof searchObj.search === 'string'
36-
? searchObj.search.toLowerCase()
37-
: undefined;
3832
const ttype = useFragment(GraphQLInterfaceTypeComponent_TypeFragment, props.type);
3933
return (
4034
<GraphQLTypeCard
@@ -50,7 +44,6 @@ export function GraphQLInterfaceTypeComponent(props: {
5044
<GraphQLFields
5145
typeName={ttype.name}
5246
fields={ttype.fields}
53-
filterValue={search}
5447
totalRequests={props.totalRequests}
5548
targetSlug={props.targetSlug}
5649
projectSlug={props.projectSlug}

packages/web/app/src/components/target/explorer/object-type.tsx

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { FragmentType, graphql, useFragment } from '@/gql';
2-
import { useRouter } from '@tanstack/react-router';
3-
import { GraphQLFields, GraphQLTypeCard } from './common';
2+
import { GraphQLTypeCard } from './common';
3+
import { GraphQLFields } from './graphql-fields';
44

55
const GraphQLObjectTypeComponent_TypeFragment = graphql(`
66
fragment GraphQLObjectTypeComponent_TypeFragment on GraphQLObjectType {
@@ -22,7 +22,6 @@ const GraphQLObjectTypeComponent_TypeFragment = graphql(`
2222
export function GraphQLObjectTypeComponent(props: {
2323
type: FragmentType<typeof GraphQLObjectTypeComponent_TypeFragment>;
2424
totalRequests?: number;
25-
collapsed?: boolean;
2625
organizationSlug: string;
2726
projectSlug: string;
2827
targetSlug: string;
@@ -31,12 +30,6 @@ export function GraphQLObjectTypeComponent(props: {
3130
styleDeprecated: boolean;
3231
}) {
3332
const ttype = useFragment(GraphQLObjectTypeComponent_TypeFragment, props.type);
34-
const router = useRouter();
35-
const searchObj = router.latestLocation.search;
36-
const search =
37-
'search' in searchObj && typeof searchObj.search === 'string'
38-
? searchObj.search.toLowerCase()
39-
: undefined;
4033

4134
return (
4235
<GraphQLTypeCard
@@ -52,9 +45,7 @@ export function GraphQLObjectTypeComponent(props: {
5245
<GraphQLFields
5346
typeName={ttype.name}
5447
fields={ttype.fields}
55-
filterValue={search}
5648
totalRequests={props.totalRequests}
57-
collapsed={props.collapsed}
5849
targetSlug={props.targetSlug}
5950
projectSlug={props.projectSlug}
6051
organizationSlug={props.organizationSlug}

0 commit comments

Comments
 (0)