Skip to content

Commit 28be2aa

Browse files
committed
Merge branch 'main' of github.com:graphql-hive/console into feat/lab-query-plan
2 parents bc6a84f + 90d4b4b commit 28be2aa

14 files changed

Lines changed: 511 additions & 473 deletions

File tree

.changeset/true-foxes-happen.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@graphql-hive/laboratory': patch
3+
'@graphql-hive/render-laboratory': patch
4+
---
5+
6+
Hive Laboratory renders Hive Router query plan if included in response extensions

docker/configs/otel-collector/extension-hiveauth/go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@ require (
4646
go.opentelemetry.io/otel/trace v1.40.0 // indirect
4747
go.uber.org/multierr v1.11.0 // indirect
4848
go.yaml.in/yaml/v3 v3.0.4 // indirect
49+
golang.org/x/net v0.51.0 // indirect
4950
golang.org/x/sys v0.41.0 // indirect
50-
google.golang.org/grpc v1.79.1 // indirect
51+
golang.org/x/text v0.34.0 // indirect
52+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect
53+
google.golang.org/grpc v1.79.3 // indirect
5154
google.golang.org/protobuf v1.36.11 // indirect
5255
gopkg.in/yaml.v3 v3.0.1 // indirect
5356
)

docker/configs/otel-collector/extension-hiveauth/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:
113113
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
114114
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
115115
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
116+
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
117+
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
116118
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
117119
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
118120
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@
154154
"lodash-es@4.x.x": "^4.17.23",
155155
"lodash@4.x.x": "^4.17.23",
156156
"seroval@<1.4.1": "^1.4.1",
157-
"fast-xml-parser@<5.5.6": "^5.5.6",
157+
"fast-xml-parser@<5.5.7": "^5.5.7",
158158
"minimatch@10.x.x": "^10.2.2",
159159
"amqplib": "^0.8.0",
160160
"minimatch@9.x.x": "^9.0.6",

packages/libraries/laboratory/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
},
4040
"dependencies": {
4141
"@base-ui/react": "^1.1.0",
42-
"dagrejs": "^0.2.1",
4342
"radix-ui": "^1.4.3",
4443
"uuid": "^13.0.0"
4544
},

packages/libraries/laboratory/src/components/flow.tsx

Lines changed: 74 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,10 @@ export const Flow = (props: { nodes: FlowNode[]; graph?: Record<string, any> })
9090
ranksep: 32,
9191
marginx: 32,
9292
marginy: 32,
93-
// graph: 'tight-tree',
93+
graph: 'tight-tree',
9494
})
9595
.setDefaultEdgeLabel(() => ({}));
9696

97-
console.log(props.nodes);
98-
9997
const groups = [...new Set(props.nodes.map(node => node.parent))].filter(Boolean);
10098

10199
for (const node of props.nodes) {
@@ -162,8 +160,6 @@ export const Flow = (props: { nodes: FlowNode[]; graph?: Record<string, any> })
162160
];
163161
}, [nodeSizes, props.nodes, props.graph]);
164162

165-
console.log({ nodes, edges });
166-
167163
const findFollowers = useCallback(
168164
(nodeId: string): FlowNode[] => {
169165
const node = nodes.find(node => node.id === nodeId);
@@ -194,46 +190,7 @@ export const Flow = (props: { nodes: FlowNode[]; graph?: Record<string, any> })
194190
return (
195191
<div className={cn('bg-background size-full')}>
196192
<div className={cn('relative size-full overflow-auto')}>
197-
<svg
198-
className="absolute left-0 top-0"
199-
style={{ width: graphSize.width, height: graphSize.height }}
200-
>
201-
{edges.map(edge => {
202-
const fromNode = nodes.find(node => node.id === edge.from);
203-
const toNode = nodes.find(node => node.id === edge.to);
204-
205-
if (!fromNode || !toNode) {
206-
return null;
207-
}
208-
209-
const isHovered = hoveredNodeId === edge.from;
210-
const isFollowingHoveredNode = hoveredNodeFollowers.some(
211-
follower => follower.id === edge.from,
212-
);
213-
214-
return (
215-
<path
216-
key={edge.from + edge.to}
217-
className={cn('stroke-border fill-none stroke-2 transition-all', {
218-
'stroke-primary': isHovered || isFollowingHoveredNode,
219-
})}
220-
d={roundedOrthogonalPath(
221-
orthogonalPoints(
222-
{
223-
x: fromNode.x - fromNode.width / 2,
224-
y: fromNode.y,
225-
},
226-
{
227-
x: toNode.x - toNode.width / 2,
228-
y: toNode.y,
229-
},
230-
),
231-
12,
232-
)}
233-
/>
234-
);
235-
})}
236-
</svg>
193+
<div className="absolute inset-0 h-full w-full bg-[radial-gradient(hsl(var(--border))_1px,transparent_1px)] bg-size-[16px_16px] opacity-50" />
237194
{nodes.map(node => {
238195
const isHovered = hoveredNodeId === node.id;
239196
const isFollowingHoveredNode = hoveredNodeFollowers.some(
@@ -254,11 +211,11 @@ export const Flow = (props: { nodes: FlowNode[]; graph?: Record<string, any> })
254211
}
255212
}}
256213
className={cn(
257-
'bg-card absolute flex w-64 flex-col justify-start gap-2 rounded-lg border p-2 text-sm shadow-sm transition-all',
214+
'bg-card absolute z-20 flex w-64 flex-col justify-start gap-2 rounded-lg border p-2 text-sm shadow-sm transition-all',
258215
{
259216
'border-primary shadow-primary/5 shadow-xl':
260217
(isHovered || isFollowingHoveredNode) && !node.isCluster,
261-
'pointer-events-none -mt-[10px] w-auto rounded-2xl border-dashed bg-transparent':
218+
'bg-card/50 pointer-events-none z-10 -mt-[10px] w-auto rounded-2xl border-dashed':
262219
node.isCluster,
263220
},
264221
)}
@@ -281,7 +238,7 @@ export const Flow = (props: { nodes: FlowNode[]; graph?: Record<string, any> })
281238
{hasFollowers && !node.isCluster && (
282239
<div
283240
className={cn(
284-
'border-border bg-background absolute left-full top-1/2 size-2 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 transition-all',
241+
'border-border bg-background absolute top-1/2 left-full size-2 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 transition-all',
285242
{
286243
'bg-primary': isHovered || isFollowingHoveredNode,
287244
},
@@ -291,7 +248,7 @@ export const Flow = (props: { nodes: FlowNode[]; graph?: Record<string, any> })
291248
{hasPrevious && !node.isCluster && (
292249
<div
293250
className={cn(
294-
'border-border bg-background absolute left-0 top-1/2 size-2 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 transition-all',
251+
'border-border bg-background absolute top-1/2 left-0 size-2 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 transition-all',
295252
{
296253
'bg-primary': isFollowingHoveredNode,
297254
},
@@ -301,6 +258,74 @@ export const Flow = (props: { nodes: FlowNode[]; graph?: Record<string, any> })
301258
</div>
302259
);
303260
})}
261+
<svg
262+
className="pointer-events-none absolute top-0 left-0 z-10"
263+
style={{ width: graphSize.width, height: graphSize.height }}
264+
>
265+
{edges
266+
.sort((a, b) => {
267+
const isHoveredA = hoveredNodeId === a.from;
268+
const isHoveredB = hoveredNodeId === b.from;
269+
const isFollowingHoveredNodeA = hoveredNodeFollowers.some(
270+
follower => follower.id === a.from,
271+
);
272+
const isFollowingHoveredNodeB = hoveredNodeFollowers.some(
273+
follower => follower.id === b.from,
274+
);
275+
276+
if (
277+
(isHoveredA || isFollowingHoveredNodeA) &&
278+
(!isHoveredB || !isFollowingHoveredNodeB)
279+
) {
280+
return 1;
281+
}
282+
283+
if (
284+
(!isHoveredA || !isFollowingHoveredNodeA) &&
285+
(isHoveredB || isFollowingHoveredNodeB)
286+
) {
287+
return -1;
288+
}
289+
290+
return 0;
291+
})
292+
.filter(Boolean)
293+
.map(edge => {
294+
const fromNode = nodes.find(node => node.id === edge.from);
295+
const toNode = nodes.find(node => node.id === edge.to);
296+
297+
if (!fromNode || !toNode) {
298+
return null;
299+
}
300+
301+
const isHovered = hoveredNodeId === edge.from;
302+
const isFollowingHoveredNode = hoveredNodeFollowers.some(
303+
follower => follower.id === edge.from,
304+
);
305+
306+
return (
307+
<path
308+
key={edge.from + edge.to}
309+
className={cn('stroke-border fill-none stroke-2 transition-all', {
310+
'stroke-primary': isHovered || isFollowingHoveredNode,
311+
})}
312+
d={roundedOrthogonalPath(
313+
orthogonalPoints(
314+
{
315+
x: fromNode.x + fromNode.width / 2,
316+
y: fromNode.y,
317+
},
318+
{
319+
x: toNode.x - toNode.width / 2,
320+
y: toNode.y,
321+
},
322+
),
323+
4,
324+
)}
325+
/>
326+
);
327+
})}
328+
</svg>
304329
</div>
305330
</div>
306331
);

packages/libraries/laboratory/src/components/laboratory/laboratory.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ const LaboratoryContent = () => {
250250
}
251251

252252
return (
253-
<Empty className="px-0! w-full">
253+
<Empty className="w-full px-0!">
254254
<EmptyHeader>
255255
<EmptyMedia variant="icon">
256256
<FileIcon className="text-muted-foreground size-6" />
@@ -344,7 +344,7 @@ const LaboratoryContent = () => {
344344
</Tooltip>
345345
<div
346346
className={cn(
347-
'relative z-10 mt-auto flex aspect-square h-12 w-full items-center justify-center border-l-2 border-transparent',
347+
'relative z-100 mt-auto flex aspect-square h-12 w-full items-center justify-center border-l-2 border-transparent',
348348
{
349349
'border-primary': activePanel === 'settings',
350350
},
@@ -402,7 +402,7 @@ const LaboratoryContent = () => {
402402
>
403403
Preflight Script
404404
</DropdownMenuItem>
405-
<DropdownMenuSeparator />
405+
{/* <DropdownMenuSeparator />
406406
<DropdownMenuItem
407407
onSelect={() => {
408408
const tab =
@@ -416,7 +416,7 @@ const LaboratoryContent = () => {
416416
}}
417417
>
418418
Settings
419-
</DropdownMenuItem>
419+
</DropdownMenuItem> */}
420420
</DropdownMenuContent>
421421
</DropdownMenu>
422422
<TooltipContent side="right">Settings</TooltipContent>

0 commit comments

Comments
 (0)