Skip to content

Commit 86d5a8d

Browse files
authored
feat (UI): support onSuccess sink in MonoVertex graph (numaproj#3110)
Signed-off-by: adarsh0728 <gooneriitk@gmail.com>
1 parent 1de6f1d commit 86d5a8d

3 files changed

Lines changed: 221 additions & 40 deletions

File tree

docs/user-guide/sources/kafka.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,4 @@ bin/kafka-consumer-groups.sh --bootstrap-server <BOOTSTRAP_BROKER_LIST> --comman
172172

173173
Reference:
174174
- [How to Use Kafka Tools With Confluent Cloud](https://docs.confluent.io/kafka/operations-tools/use-kafka-tools-ccloud.html#create-a-configuration-file)
175-
- [Apache Kafka Security](https://kafka.apache.org/documentation/#security)
175+
- [Apache Kafka Security](https://kafka.apache.org/41/security/)

ui/src/components/pages/Pipeline/partials/Graph/partials/CustomNode/index.tsx

Lines changed: 186 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,7 @@ const CustomNode: FC<NodeProps> = ({
133133
return style;
134134
};
135135

136-
const nodeStyle = useMemo(() => {
137-
return {
138-
border: `${isSelected(highlightValues[data?.name])} ${getBorderColor(
139-
data?.type
140-
)}`,
141-
...commonStyle,
142-
};
143-
}, [highlightValues, data]);
136+
144137

145138
const genStyle = (text: string) => {
146139
return {
@@ -289,20 +282,72 @@ const CustomNode: FC<NodeProps> = ({
289282
setHighlightValues({});
290283
}, [setHidden, setHighlightValues]);
291284

285+
const formatRate = (rate?: number): string => {
286+
return rate !== undefined && rate >= 0 ? `${rate}/sec` : "Not Available";
287+
};
288+
289+
const hasBothSinks =
290+
data?.nodeInfo?.sink?.onSuccess && data?.nodeInfo?.sink?.fallback;
291+
const wrapperClass = hasBothSinks
292+
? "mono-vertex-img-wrapper-small"
293+
: "mono-vertex-img-wrapper";
294+
const imgClass = hasBothSinks ? "mono-vertex-img-small" : "mono-vertex-img";
295+
const nodeRateWrapperClass = hasBothSinks ? "node-rate-small" : "node-rate";
296+
const nodeRateStyle =
297+
data?.type === "monoVertex" && hasBothSinks
298+
? { bottom: "-1rem" }
299+
: {};
300+
301+
302+
const nodeStyle = useMemo(() => {
303+
return {
304+
border: `${isSelected(highlightValues[data?.name])} ${getBorderColor(
305+
data?.type
306+
)}`,
307+
...(hasBothSinks
308+
? {
309+
display: "flex",
310+
flexDirection: "column",
311+
}
312+
: {}),
313+
...commonStyle,
314+
};
315+
}, [highlightValues, data, hasBothSinks]);
316+
292317
// arrow for containers in monoVertex
293318
const arrowSvg = useMemo(() => {
294319
return (
295-
<svg height="1" width="18">
320+
<svg height="20" width="18">
296321
<line x1="0" y1="10" x2="18" y2="10" stroke="#d1dee9" />
297322
<line x1="14" y1="7" x2="18" y2="10" stroke="#d1dee9" />
298323
<line x1="14" y1="13" x2="18" y2="10" stroke="#d1dee9" />
299324
</svg>
300325
);
326+
});
327+
328+
// up arrow in case both onSuccess and fallback sinks are configured
329+
// will point to onSuccess
330+
const arrowUpSvg = useMemo(() => {
331+
return (
332+
<svg height="16" width="16">
333+
<line x1="0" y1="16" x2="16" y2="8" stroke="#d1dee9" />
334+
<line x1="11.1" y1="7.1" x2="16" y2="8" stroke="#d1dee9" />
335+
<line x1="13.7" y1="12.5" x2="16" y2="8" stroke="#d1dee9" />
336+
</svg>
337+
);
301338
}, []);
302339

303-
const formatRate = (rate?: number): string => {
304-
return rate !== undefined && rate >= 0 ? `${rate}/sec` : "Not Available";
305-
};
340+
// down arrow in case both onSuccess and fallback sinks are configured
341+
// will point to fallback
342+
const arrowDownSvg = useMemo(() => {
343+
return (
344+
<svg height="16" width="16">
345+
<line x1="0" y1="0" x2="16" y2="8" stroke="#d1dee9" />
346+
<line x1="11.1" y1="8.9" x2="16" y2="8" stroke="#d1dee9" />
347+
<line x1="13.7" y1="3.5" x2="16" y2="8" stroke="#d1dee9" />
348+
</svg>
349+
);
350+
}, []);
306351

307352
return (
308353
<Box data-testid={data?.name}>
@@ -317,15 +362,22 @@ const CustomNode: FC<NodeProps> = ({
317362
{data?.type === "monoVertex" && (
318363
<>
319364
<Box className="node-info-mono">{data?.name}</Box>
320-
<Box style={{ display: "flex", justifyContent: "center" }}>
365+
<Box
366+
style={{
367+
display: "flex",
368+
justifyContent: "center",
369+
alignItems: "center",
370+
flex: 1,
371+
}}
372+
>
321373
<Tooltip
322374
title={<Box className={"node-tooltip"}>Source Container</Box>}
323375
arrow
324376
placement={"left"}
325377
>
326-
<Box className={"mono-vertex-img-wrapper"}>
378+
<Box className={wrapperClass}>
327379
<img
328-
className={"mono-vertex-img"}
380+
className={imgClass}
329381
src={source}
330382
alt={"source-container"}
331383
/>
@@ -340,9 +392,9 @@ const CustomNode: FC<NodeProps> = ({
340392
arrow
341393
placement={"bottom"}
342394
>
343-
<Box className={"mono-vertex-img-wrapper"}>
395+
<Box className={wrapperClass}>
344396
<img
345-
className={"mono-vertex-img"}
397+
className={imgClass}
346398
src={transformer}
347399
alt={"transformer-container"}
348400
/>
@@ -358,9 +410,9 @@ const CustomNode: FC<NodeProps> = ({
358410
arrow
359411
placement={"bottom"}
360412
>
361-
<Box className={"mono-vertex-img-wrapper"}>
413+
<Box className={wrapperClass}>
362414
<img
363-
className={"mono-vertex-img"}
415+
className={imgClass}
364416
src={udf}
365417
alt={"udf-container"}
366418
/>
@@ -371,33 +423,128 @@ const CustomNode: FC<NodeProps> = ({
371423
<Tooltip
372424
title={<Box className={"node-tooltip"}>Sink Container</Box>}
373425
arrow
374-
placement={data?.nodeInfo?.sink?.fallback ? "bottom" : "right"}
426+
placement={
427+
data?.nodeInfo?.sink?.fallback ||
428+
data?.nodeInfo?.sink?.onSuccess
429+
? "bottom"
430+
: "right"
431+
}
375432
>
376-
<Box className={"mono-vertex-img-wrapper"}>
433+
<Box className={wrapperClass}>
377434
<img
378-
className={"mono-vertex-img"}
435+
className={imgClass}
379436
src={sink}
380437
alt={"sink-container"}
381438
/>
382439
</Box>
383440
</Tooltip>
384-
{data?.nodeInfo?.sink?.fallback && arrowSvg}
385-
{data?.nodeInfo?.sink?.fallback && (
386-
<Tooltip
387-
title={
388-
<Box className={"node-tooltip"}>Fallback Sink Container</Box>
389-
}
390-
arrow
391-
placement={"right"}
441+
{(data?.nodeInfo?.sink?.fallback ||
442+
data?.nodeInfo?.sink?.onSuccess) && (
443+
<Box
444+
style={{
445+
display: "flex",
446+
flexDirection: "column",
447+
gap: "0.2rem",
448+
}}
392449
>
393-
<Box className={"mono-vertex-img-wrapper"}>
394-
<img
395-
className={"mono-vertex-img"}
396-
src={fallback}
397-
alt={"fallback-sink-container"}
398-
/>
399-
</Box>
400-
</Tooltip>
450+
{data?.nodeInfo?.sink?.onSuccess &&
451+
!data?.nodeInfo?.sink?.fallback && (
452+
<Box style={{ display: "flex", alignItems: "center" }}>
453+
{arrowSvg}
454+
<Tooltip
455+
title={
456+
<Box className={"node-tooltip"}>
457+
OnSuccess Sink Container
458+
</Box>
459+
}
460+
arrow
461+
placement={"right"}
462+
>
463+
<Box className={wrapperClass}>
464+
<img
465+
className={imgClass}
466+
src={sink}
467+
alt={"on-success-sink-container"}
468+
/>
469+
</Box>
470+
</Tooltip>
471+
</Box>
472+
)}
473+
{data?.nodeInfo?.sink?.fallback &&
474+
!data?.nodeInfo?.sink?.onSuccess && (
475+
<Box style={{ display: "flex", alignItems: "center" }}>
476+
{arrowSvg}
477+
<Tooltip
478+
title={
479+
<Box className={"node-tooltip"}>
480+
Fallback Sink Container
481+
</Box>
482+
}
483+
arrow
484+
placement={"right"}
485+
>
486+
<Box className={wrapperClass}>
487+
<img
488+
className={imgClass}
489+
src={fallback}
490+
alt={"fallback-sink-container"}
491+
/>
492+
</Box>
493+
</Tooltip>
494+
</Box>
495+
)}
496+
{data?.nodeInfo?.sink?.onSuccess &&
497+
data?.nodeInfo?.sink?.fallback && (
498+
<Box
499+
style={{
500+
display: "flex",
501+
flexDirection: "column",
502+
gap: 0,
503+
}}
504+
>
505+
<Box style={{ display: "flex", alignItems: "center" }}>
506+
{arrowUpSvg}
507+
<Tooltip
508+
title={
509+
<Box className={"node-tooltip"}>
510+
OnSuccess Sink Container
511+
</Box>
512+
}
513+
arrow
514+
placement={"right"}
515+
>
516+
<Box className={wrapperClass}>
517+
<img
518+
className={imgClass}
519+
src={sink}
520+
alt={"on-success-sink-container"}
521+
/>
522+
</Box>
523+
</Tooltip>
524+
</Box>
525+
<Box style={{ display: "flex", alignItems: "center" }}>
526+
{arrowDownSvg}
527+
<Tooltip
528+
title={
529+
<Box className={"node-tooltip"}>
530+
Fallback Sink Container
531+
</Box>
532+
}
533+
arrow
534+
placement={"right"}
535+
>
536+
<Box className={wrapperClass}>
537+
<img
538+
className={imgClass}
539+
src={fallback}
540+
alt={"fallback-sink-container"}
541+
/>
542+
</Box>
543+
</Tooltip>
544+
</Box>
545+
</Box>
546+
)}
547+
</Box>
401548
)}
402549
</Box>
403550
</>
@@ -449,7 +596,7 @@ const CustomNode: FC<NodeProps> = ({
449596
arrow
450597
placement={"bottom-end"}
451598
>
452-
<Box className={"node-rate"}>
599+
<Box className={nodeRateWrapperClass} style={nodeRateStyle}>
453600
{formatRate(data?.vertexMetrics?.ratePerMin)}
454601
</Box>
455602
</Tooltip>

ui/src/components/pages/Pipeline/partials/Graph/partials/CustomNode/style.css

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,25 @@
1717
right: 8%;
1818
}
1919

20+
.node-rate-small {
21+
display: flex;
22+
min-width: 9rem;
23+
height: 1.8rem;
24+
border-radius: 2rem;
25+
background: #d1dee9;
26+
color: #274c77;
27+
font-family: "IBM Plex Sans", sans-serif;
28+
font-size: 1.2rem;
29+
font-style: normal;
30+
font-weight: 500;
31+
line-height: normal;
32+
justify-content: center;
33+
align-items: center;
34+
position: absolute;
35+
bottom: -12.5%;
36+
right: 8%;
37+
}
38+
2039
.node-pods {
2140
display: flex;
2241
width: 10rem;
@@ -122,6 +141,21 @@
122141
width: 1rem;
123142
}
124143

144+
.mono-vertex-img-wrapper-small {
145+
height: 1.6rem;
146+
width: 1.6rem;
147+
border-radius: 50%;
148+
border: 1px solid #d1dee9;
149+
display: flex;
150+
align-items: center;
151+
justify-content: center;
152+
}
153+
154+
.mono-vertex-img-small {
155+
height: 0.9rem;
156+
width: 0.9rem;
157+
}
158+
125159
.node-icon {
126160
width: 1.144rem;
127161
height: 1.144rem;

0 commit comments

Comments
 (0)