Skip to content

Commit c099a92

Browse files
committed
Add debug mode for viewing ReactFlow Node ids
1 parent beb93c2 commit c099a92

File tree

6 files changed

+150
-67
lines changed

6 files changed

+150
-67
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: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,31 @@ 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 { cn } from "@/lib/utils";
1116
import { useComponentSpec } from "@/providers/ComponentSpecProvider";
1217
import { useContextPanel } from "@/providers/ContextPanelProvider";
1318
import type { IONodeData } from "@/types/nodes";
1419
import { isInputSpec, typeSpecToString } from "@/utils/componentSpec";
20+
import { ENABLE_DEBUG_MODE } from "@/utils/constants";
21+
import {
22+
inputNameToNodeId,
23+
outputNameToNodeId,
24+
} from "@/utils/nodes/nodeIdUtils";
1525

1626
interface IONodeProps {
27+
type: "input" | "output";
1728
data: IONodeData;
1829
selected: boolean;
1930
deletable: boolean;
2031
}
2132

22-
const IONode = ({ data, selected = false }: IONodeProps) => {
33+
const IONode = ({ type, data, selected = false }: IONodeProps) => {
2334
const { graphSpec, componentSpec } = useComponentSpec();
2435
const { setContent, clearContent } = useContextPanel();
2536

@@ -47,6 +58,12 @@ const IONode = ({ data, selected = false }: IONodeProps) => {
4758
[componentSpec.outputs, spec.name],
4859
);
4960

61+
const nodeId = isInput
62+
? inputNameToNodeId(spec.name)
63+
: outputNameToNodeId(spec.name);
64+
65+
const nodeHandleId = `${nodeId}_handle`;
66+
5067
useEffect(() => {
5168
if (selected) {
5269
if (input && isInput) {
@@ -104,6 +121,11 @@ const IONode = ({ data, selected = false }: IONodeProps) => {
104121
<Card className={cn("border-2 max-w-[300px] p-0", borderColor)}>
105122
<CardHeader className="px-2 py-2.5">
106123
<CardTitle className="break-words">{spec.name}</CardTitle>
124+
{ENABLE_DEBUG_MODE && (
125+
<Paragraph size="xs" tone="subdued">
126+
Node Id: {nodeId}
127+
</Paragraph>
128+
)}
107129
</CardHeader>
108130
<CardContent className="p-2 max-w-[250px]">
109131
<BlockStack gap="2">
@@ -138,11 +160,23 @@ const IONode = ({ data, selected = false }: IONodeProps) => {
138160
</Paragraph>
139161
</InlineStack>
140162
</BlockStack>
141-
<Handle
142-
type={handleType}
143-
position={handlePosition}
144-
className={cn(handleDefaultClassName, handleClassName)}
145-
/>
163+
<Tooltip>
164+
<TooltipTrigger asChild>
165+
<Handle
166+
type={handleType}
167+
position={handlePosition}
168+
className={cn(handleDefaultClassName, handleClassName)}
169+
/>
170+
</TooltipTrigger>
171+
<TooltipContent disabled={!ENABLE_DEBUG_MODE}>
172+
<div className="capitalize">
173+
{type} Name: {spec.name}
174+
</div>
175+
<div>Handle Name: {spec.name}</div>
176+
<div>parentNodeId: {nodeId}</div>
177+
<div>handleNodeId: {nodeHandleId}</div>
178+
</TooltipContent>
179+
</Tooltip>
146180
</CardContent>
147181
</Card>
148182
);

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

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

1819
type InputHandleProps = {
1920
input: InputSpec;
@@ -32,7 +33,7 @@ export const InputHandle = ({
3233
onLabelClick,
3334
onHandleSelectionChange,
3435
}: InputHandleProps) => {
35-
const { nodeId, state } = useTaskNode();
36+
const { nodeId, state, name } = useTaskNode();
3637

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

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

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

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { cn } from "@/lib/utils";
1414
import { useComponentSpec } from "@/providers/ComponentSpecProvider";
1515
import { useContextPanel } from "@/providers/ContextPanelProvider";
1616
import { useTaskNode } from "@/providers/TaskNodeProvider";
17+
import { ENABLE_DEBUG_MODE } from "@/utils/constants";
1718
import { getSubgraphDescription, isSubgraph } from "@/utils/subgraphUtils";
1819

1920
import {
@@ -217,34 +218,49 @@ const TaskNodeCard = () => {
217218
ref={nodeRef}
218219
onDoubleClick={handleDoubleClick}
219220
>
220-
<CardHeader className="border-b border-slate-200 px-2 py-2.5 flex flex-row justify-between items-start">
221+
<CardHeader className="border-b border-slate-200 px-2 py-2.5 items-start">
221222
<BlockStack>
222-
<InlineStack gap="2" blockAlign="center">
223-
{isSubgraphNode && isSubgraphNavigationEnabled && (
224-
<QuickTooltip content={`Subgraph: ${subgraphDescription}`}>
225-
<Icon name="Workflow" size="sm" className="text-blue-600" />
226-
</QuickTooltip>
227-
)}
228-
<CardTitle className="break-words text-left text-xs text-slate-900">
229-
{name}
230-
</CardTitle>
231-
</InlineStack>
232-
{taskId &&
233-
taskId !== name &&
234-
!taskId.match(new RegExp(`^${name}\\s*\\d+$`)) && (
235-
<Text size="xs" tone="subdued" className="font-light">
236-
{taskId}
237-
</Text>
238-
)}
239-
</BlockStack>
223+
<BlockStack>
224+
<InlineStack
225+
gap="2"
226+
align="space-between"
227+
blockAlign="start"
228+
wrap="nowrap"
229+
className="w-full"
230+
>
231+
<InlineStack gap="2" blockAlign="center">
232+
{isSubgraphNode && isSubgraphNavigationEnabled && (
233+
<QuickTooltip content={`Subgraph: ${subgraphDescription}`}>
234+
<Icon name="Workflow" size="sm" className="text-blue-600" />
235+
</QuickTooltip>
236+
)}
237+
<CardTitle className="break-words text-left text-xs text-slate-900">
238+
{name}
239+
</CardTitle>
240+
</InlineStack>
241+
{isRemoteComponentLibrarySearchEnabled ? (
242+
<PublishedComponentBadge componentRef={taskSpec.componentRef}>
243+
{digestMarkup}
244+
</PublishedComponentBadge>
245+
) : (
246+
digestMarkup
247+
)}
248+
</InlineStack>
249+
{taskId &&
250+
taskId !== name &&
251+
!taskId.match(new RegExp(`^${name}\\s*\\d+$`)) && (
252+
<Text size="xs" tone="subdued" className="font-light">
253+
{taskId}
254+
</Text>
255+
)}
256+
</BlockStack>
240257

241-
{isRemoteComponentLibrarySearchEnabled ? (
242-
<PublishedComponentBadge componentRef={taskSpec.componentRef}>
243-
{digestMarkup}
244-
</PublishedComponentBadge>
245-
) : (
246-
digestMarkup
247-
)}
258+
{ENABLE_DEBUG_MODE && (
259+
<Text size="xs" tone="subdued">
260+
Node Id: {nodeId}
261+
</Text>
262+
)}
263+
</BlockStack>
248264
</CardHeader>
249265
<CardContent className="p-2 flex flex-col gap-2">
250266
<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)