Skip to content

Commit f5e5941

Browse files
committed
Add debug mode for viewing ReactFlow Node ids
1 parent 64a0be1 commit f5e5941

File tree

6 files changed

+145
-68
lines changed

6 files changed

+145
-68
lines changed

.env.example

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,7 @@ VITE_ENABLE_GOOGLE_CLOUD_SUBMITTER=<boolean>
1717

1818
# Github
1919
VITE_REQUIRE_AUTHORIZATION=<boolean>
20-
VITE_GITHUB_CLIENT_ID=<string>
20+
VITE_GITHUB_CLIENT_ID=<string>
21+
22+
# Dev Tools
23+
VITE_ENABLE_DEBUG_MODE=<boolean>

src/components/shared/ReactFlow/FlowCanvas/IONode/IONode.tsx

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,19 @@ import { OutputNameEditor } from "@/components/Editor/IOEditor/OutputNameEditor"
66
import { getOutputConnectedDetails } from "@/components/Editor/utils/getOutputConnectedDetails";
77
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
88
import { BlockStack, InlineStack } from "@/components/ui/layout";
9+
import {
10+
Tooltip,
11+
TooltipContent,
12+
TooltipTrigger,
13+
} from "@/components/ui/tooltip";
914
import { Paragraph } from "@/components/ui/typography";
1015
import { useNodeManager } from "@/hooks/useNodeManager";
1116
import { cn } from "@/lib/utils";
1217
import { useComponentSpec } from "@/providers/ComponentSpecProvider";
1318
import { useContextPanel } from "@/providers/ContextPanelProvider";
1419
import type { IONodeData } from "@/types/nodes";
1520
import { isInputSpec, typeSpecToString } from "@/utils/componentSpec";
21+
import { ENABLE_DEBUG_MODE } from "@/utils/constants";
1622

1723
interface IONodeProps {
1824
type: "input" | "output";
@@ -22,7 +28,7 @@ interface IONodeProps {
2228
}
2329

2430
const IONode = ({ type, data, selected = false }: IONodeProps) => {
25-
const { getHandleNodeId } = useNodeManager();
31+
const { getNodeId, getHandleNodeId } = useNodeManager();
2632
const { graphSpec, componentSpec } = useComponentSpec();
2733
const { setContent, clearContent } = useContextPanel();
2834

@@ -50,6 +56,7 @@ const IONode = ({ type, data, selected = false }: IONodeProps) => {
5056
[componentSpec.outputs, spec.name],
5157
);
5258

59+
const nodeId = getNodeId(spec.name, type);
5360
const handleNodeType = isInput ? "handle-out" : "handle-in";
5461
const nodeHandleId = getHandleNodeId(spec.name, spec.name, handleNodeType);
5562

@@ -103,6 +110,11 @@ const IONode = ({ type, data, selected = false }: IONodeProps) => {
103110
<Card className={cn("border-2 max-w-[300px] p-0", borderColor)}>
104111
<CardHeader className="px-2 py-2.5">
105112
<CardTitle className="break-words">{spec.name}</CardTitle>
113+
{ENABLE_DEBUG_MODE && (
114+
<Paragraph size="xs" tone="subdued">
115+
Node Id: {nodeId}
116+
</Paragraph>
117+
)}
106118
</CardHeader>
107119
<CardContent className="p-2 max-w-[250px]">
108120
<BlockStack gap="2">
@@ -137,12 +149,24 @@ const IONode = ({ type, data, selected = false }: IONodeProps) => {
137149
</Paragraph>
138150
</InlineStack>
139151
</BlockStack>
140-
<Handle
141-
id={nodeHandleId}
142-
type={handleType}
143-
position={handlePosition}
144-
className={cn(handleDefaultClassName, handleClassName)}
145-
/>
152+
<Tooltip>
153+
<TooltipTrigger asChild>
154+
<Handle
155+
id={nodeHandleId}
156+
type={handleType}
157+
position={handlePosition}
158+
className={cn(handleDefaultClassName, handleClassName)}
159+
/>
160+
</TooltipTrigger>
161+
<TooltipContent disabled={!ENABLE_DEBUG_MODE}>
162+
<div className="capitalize">
163+
{type} Name: {spec.name}
164+
</div>
165+
<div>Handle Name: {spec.name}</div>
166+
<div>parentNodeId: {nodeId}</div>
167+
<div>handleNodeId: {nodeHandleId}</div>
168+
</TooltipContent>
169+
</Tooltip>
146170
</CardContent>
147171
</Card>
148172
);

src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskNodeCard/Handles.tsx

Lines changed: 55 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { useNodeManager } from "@/hooks/useNodeManager";
1515
import { cn } from "@/lib/utils";
1616
import { useTaskNode } from "@/providers/TaskNodeProvider";
1717
import type { InputSpec, OutputSpec } from "@/utils/componentSpec";
18+
import { ENABLE_DEBUG_MODE } from "@/utils/constants";
1819

1920
type InputHandleProps = {
2021
input: InputSpec;
@@ -34,7 +35,7 @@ export const InputHandle = ({
3435
onHandleSelectionChange,
3536
}: InputHandleProps) => {
3637
const { getInputHandleNodeId } = useNodeManager();
37-
const { taskId, nodeId, state } = useTaskNode();
38+
const { taskId, nodeId, state, name } = useTaskNode();
3839

3940
const fromHandle = useConnection((connection) => connection.fromHandle?.id);
4041
const toHandle = useConnection((connection) => connection.toHandle?.id);
@@ -131,23 +132,33 @@ export const InputHandle = ({
131132
data-active={active}
132133
>
133134
<div className="absolute -translate-x-6 flex items-center h-3 w-3">
134-
<Handle
135-
ref={handleRef}
136-
type="target"
137-
id={handleId}
138-
position={Position.Left}
139-
isConnectable={true}
140-
className={cn(
141-
"border-0! h-full! w-full! transform-none!",
142-
missing,
143-
(selected || active) && "bg-blue-500!",
144-
highlight && "bg-green-500!",
145-
state.readOnly && "cursor-pointer!",
146-
)}
147-
onClick={handleHandleClick}
148-
data-invalid={invalid}
149-
data-testid={`input-handle-${input.name}`}
150-
/>
135+
<Tooltip>
136+
<TooltipTrigger asChild>
137+
<Handle
138+
ref={handleRef}
139+
type="target"
140+
id={handleId}
141+
position={Position.Left}
142+
isConnectable={true}
143+
className={cn(
144+
"border-0! h-full! w-full! transform-none!",
145+
missing,
146+
(selected || active) && "bg-blue-500!",
147+
highlight && "bg-green-500!",
148+
state.readOnly && "cursor-pointer!",
149+
)}
150+
onClick={handleHandleClick}
151+
data-invalid={invalid}
152+
data-testid={`input-handle-${input.name}`}
153+
/>
154+
</TooltipTrigger>
155+
<TooltipContent disabled={!ENABLE_DEBUG_MODE}>
156+
<div>Task Name: {name}</div>
157+
<div>Handle Name: {input.name}</div>
158+
<div>parentNodeId: {nodeId}</div>
159+
<div>handleNodeId: {handleId}</div>
160+
</TooltipContent>
161+
</Tooltip>
151162
</div>
152163
<div
153164
className={cn(
@@ -221,7 +232,7 @@ export const OutputHandle = ({
221232
onHandleSelectionChange,
222233
}: OutputHandleProps) => {
223234
const { getOutputHandleNodeId } = useNodeManager();
224-
const { taskId, nodeId, state } = useTaskNode();
235+
const { taskId, nodeId, state, name } = useTaskNode();
225236

226237
const fromHandle = useConnection((connection) => connection.fromHandle?.id);
227238
const toHandle = useConnection((connection) => connection.toHandle?.id);
@@ -339,21 +350,31 @@ export const OutputHandle = ({
339350
</div>
340351
)}
341352
</div>
342-
<Handle
343-
ref={handleRef}
344-
type="source"
345-
id={handleId}
346-
position={Position.Right}
347-
isConnectable={true}
348-
onClick={handleHandleClick}
349-
className={cn(
350-
"relative! border-0! !w-[12px] !h-[12px] transform-none! translate-x-6 cursor-pointer bg-gray-500!",
351-
(selected || active) && "bg-blue-500!",
352-
highlight && "bg-green-500!",
353-
state.readOnly && "cursor-pointer!",
354-
)}
355-
data-testid={`output-handle-${output.name}`}
356-
/>
353+
<Tooltip>
354+
<TooltipTrigger asChild>
355+
<Handle
356+
ref={handleRef}
357+
type="source"
358+
id={handleId}
359+
position={Position.Right}
360+
isConnectable={true}
361+
onClick={handleHandleClick}
362+
className={cn(
363+
"relative! border-0! !w-[12px] !h-[12px] transform-none! translate-x-6 cursor-pointer bg-gray-500!",
364+
(selected || active) && "bg-blue-500!",
365+
highlight && "bg-green-500!",
366+
state.readOnly && "cursor-pointer!",
367+
)}
368+
data-testid={`output-handle-${output.name}`}
369+
/>
370+
</TooltipTrigger>
371+
<TooltipContent disabled={!ENABLE_DEBUG_MODE}>
372+
<div>Task Name: {name}</div>
373+
<div>Handle Name: {output.name}</div>
374+
<div>parentNodeId: {nodeId}</div>
375+
<div>handleNodeId: {handleId}</div>
376+
</TooltipContent>
377+
</Tooltip>
357378
</div>
358379
);
359380
};

src/components/shared/ReactFlow/FlowCanvas/TaskNode/TaskNodeCard/TaskNodeCard.tsx

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { cn } from "@/lib/utils";
1616
import { useComponentSpec } from "@/providers/ComponentSpecProvider";
1717
import { useContextPanel } from "@/providers/ContextPanelProvider";
1818
import { useTaskNode } from "@/providers/TaskNodeProvider";
19+
import { ENABLE_DEBUG_MODE } from "@/utils/constants";
1920
import { getSubgraphDescription, isSubgraph } from "@/utils/subgraphUtils";
2021

2122
import {
@@ -242,34 +243,53 @@ const TaskNodeCard = () => {
242243
ref={nodeRef}
243244
onDoubleClick={handleDoubleClick}
244245
>
245-
<CardHeader className="border-b border-slate-200 px-2 py-2.5 flex flex-row justify-between items-start">
246+
<CardHeader className="border-b border-slate-200 px-2 py-2.5 items-start">
246247
<BlockStack>
247-
<InlineStack gap="2" blockAlign="center">
248-
{isSubgraphNode && isSubgraphNavigationEnabled && (
249-
<QuickTooltip content={`Subgraph: ${subgraphDescription}`}>
250-
<Icon name="Workflow" size="sm" className="text-blue-600" />
251-
</QuickTooltip>
252-
)}
253-
<CardTitle className="break-words text-left text-xs text-slate-900">
254-
{name}
255-
</CardTitle>
256-
</InlineStack>
257-
{taskId &&
258-
taskId !== name &&
259-
!taskId.match(new RegExp(`^${name}\\s*\\d+$`)) && (
260-
<Text size="xs" tone="subdued" className="font-light">
261-
{taskId}
262-
</Text>
263-
)}
248+
<BlockStack>
249+
<InlineStack
250+
gap="2"
251+
align="space-between"
252+
blockAlign="start"
253+
wrap="nowrap"
254+
className="w-full"
255+
>
256+
<InlineStack gap="2" blockAlign="center">
257+
{isSubgraphNode && isSubgraphNavigationEnabled && (
258+
<QuickTooltip content={`Subgraph: ${subgraphDescription}`}>
259+
<Icon
260+
name="Workflow"
261+
size="sm"
262+
className="text-blue-600"
263+
/>
264+
</QuickTooltip>
265+
)}
266+
<CardTitle className="break-words text-left text-xs text-slate-900">
267+
{name}
268+
</CardTitle>
269+
</InlineStack>
270+
{isRemoteComponentLibrarySearchEnabled ? (
271+
<PublishedComponentBadge componentRef={taskSpec.componentRef}>
272+
{digestMarkup}
273+
</PublishedComponentBadge>
274+
) : (
275+
digestMarkup
276+
)}
277+
</InlineStack>
278+
{taskId &&
279+
taskId !== name &&
280+
!taskId.match(new RegExp(`^${name}\\s*\\d+$`)) && (
281+
<Text size="xs" tone="subdued" className="font-light">
282+
{taskId}
283+
</Text>
284+
)}
285+
</BlockStack>
286+
287+
{ENABLE_DEBUG_MODE && (
288+
<Text size="xs" tone="subdued">
289+
Node Id: {nodeId}
290+
</Text>
291+
)}
264292
</BlockStack>
265-
266-
{isRemoteComponentLibrarySearchEnabled ? (
267-
<PublishedComponentBadge componentRef={taskSpec.componentRef}>
268-
{digestMarkup}
269-
</PublishedComponentBadge>
270-
) : (
271-
digestMarkup
272-
)}
273293
</CardHeader>
274294
<CardContent className="p-2 flex flex-col gap-2">
275295
<div

src/components/ui/tooltip.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,21 @@ function TooltipTrigger({
4040
interface TooltipContentProps
4141
extends React.ComponentProps<typeof TooltipPrimitive.Content> {
4242
arrowClassName?: string;
43+
disabled?: boolean;
4344
}
4445

4546
function TooltipContent({
4647
className,
4748
sideOffset = 0,
4849
children,
4950
arrowClassName,
51+
disabled,
5052
...props
5153
}: TooltipContentProps) {
54+
if (disabled) {
55+
return null;
56+
}
57+
5258
return (
5359
<TooltipPrimitive.Portal>
5460
<TooltipPrimitive.Content

src/utils/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
/* Environment Config */
2+
export const ENABLE_DEBUG_MODE =
3+
import.meta.env.VITE_ENABLE_DEBUG_MODE === "true";
4+
25
export const ABOUT_URL =
36
import.meta.env.VITE_ABOUT_URL || "https://cloud-pipelines.net/";
47

0 commit comments

Comments
 (0)