File size: 2,984 Bytes
be99f83
 
 
 
 
b1ea792
8207a08
be99f83
53f091c
09aa395
be99f83
 
 
 
 
 
 
 
 
 
 
38d5a53
 
be99f83
 
 
 
8207a08
be99f83
 
 
 
 
 
 
 
53f091c
be99f83
38d5a53
be99f83
 
 
 
 
 
38d5a53
09aa395
970e973
38d5a53
 
09aa395
38d5a53
 
 
 
 
 
 
 
 
09aa395
38d5a53
 
 
09aa395
 
 
 
 
 
38d5a53
 
 
 
be99f83
 
 
 
 
38d5a53
be99f83
 
 
 
 
 
 
 
 
 
2bdad3e
be99f83
 
 
 
53f091c
 
 
be99f83
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import {
  BaseEdge,
  EdgeLabelRenderer,
  EdgeProps,
  getBezierPath,
} from '@xyflow/react';
import useGraphStore from '../../store';

import { useTheme } from '@/components/theme-provider';
import { useFetchFlow } from '@/hooks/flow-hooks';
import { useMemo } from 'react';
import styles from './index.less';

export function ButtonEdge({
  id,
  sourceX,
  sourceY,
  targetX,
  targetY,
  sourcePosition,
  targetPosition,
  source,
  target,
  style = {},
  markerEnd,
  selected,
}: EdgeProps) {
  const deleteEdgeById = useGraphStore((state) => state.deleteEdgeById);
  const [edgePath, labelX, labelY] = getBezierPath({
    sourceX,
    sourceY,
    sourcePosition,
    targetX,
    targetY,
    targetPosition,
  });
  const { theme } = useTheme();
  const selectedStyle = useMemo(() => {
    return selected ? { strokeWidth: 2, stroke: '#1677ff' } : {};
  }, [selected]);

  const onEdgeClick = () => {
    deleteEdgeById(id);
  };

  // highlight the nodes that the workflow passes through
  const { data: flowDetail } = useFetchFlow();

  const graphPath = useMemo(() => {
    // TODO: this will be called multiple times
    const path = flowDetail?.dsl?.path ?? [];
    // The second to last
    const previousGraphPath: string[] = path.at(-2) ?? [];
    let graphPath: string[] = path.at(-1) ?? [];
    // The last of the second to last article
    const previousLatestElement = previousGraphPath.at(-1);
    if (previousGraphPath.length > 0 && previousLatestElement) {
      graphPath = [previousLatestElement, ...graphPath];
    }
    return graphPath;
  }, [flowDetail.dsl?.path]);

  const highlightStyle = useMemo(() => {
    const idx = graphPath.findIndex((x) => x === source);
    if (idx !== -1) {
      // The set of elements following source
      const slicedGraphPath = graphPath.slice(idx + 1);
      if (slicedGraphPath.some((x) => x === target)) {
        return { strokeWidth: 2, stroke: 'red' };
      }
    }
    return {};
  }, [source, target, graphPath]);

  return (
    <>
      <BaseEdge
        path={edgePath}
        markerEnd={markerEnd}
        style={{ ...style, ...selectedStyle, ...highlightStyle }}
      />
      <EdgeLabelRenderer>
        <div
          style={{
            position: 'absolute',
            transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
            fontSize: 12,
            // everything inside EdgeLabelRenderer has no pointer events by default
            // if you have an interactive element, set pointer-events: all
            pointerEvents: 'all',
            zIndex: 1001, // https://github.com/xyflow/xyflow/discussions/3498
          }}
          className="nodrag nopan"
        >
          <button
            className={
              theme === 'dark' ? styles.edgeButtonDark : styles.edgeButton
            }
            type="button"
            onClick={onEdgeClick}
          >
            ×
          </button>
        </div>
      </EdgeLabelRenderer>
    </>
  );
}