(props: {
graph: ProjectGraphRecord;
language: SupportedLanguage;
onOpenEvent: (eventId: string) => void;
onOpenEntity: (entityId: string) => void;
})
| 67 | } |
| 68 | |
| 69 | function ProjectGraphCanvas(props: { |
| 70 | graph: ProjectGraphRecord; |
| 71 | language: SupportedLanguage; |
| 72 | onOpenEvent: (eventId: string) => void; |
| 73 | onOpenEntity: (entityId: string) => void; |
| 74 | }) { |
| 75 | const initialEntityIds = useMemo( |
| 76 | () => new Set(props.graph.entities.slice(0, ROOT_ENTITY_LIMIT).map((entity) => entity.id)), |
| 77 | [props.graph.entities] |
| 78 | ); |
| 79 | const [expandedEntityIds, setExpandedEntityIds] = useState<Set<string>>( |
| 80 | () => new Set(props.graph.entities[0] ? [props.graph.entities[0].id] : []) |
| 81 | ); |
| 82 | const [expandedEventIds, setExpandedEventIds] = useState<Set<string>>(new Set()); |
| 83 | const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null); |
| 84 | const expandedEntityIdsRef = useRef(expandedEntityIds); |
| 85 | const expandedEventIdsRef = useRef(expandedEventIds); |
| 86 | const [nodes, setNodes, onNodesChange] = useNodesState<GraphNode>([]); |
| 87 | const [edges, setEdges, onEdgesChange] = useEdgesState<GraphEdge>([]); |
| 88 | const { fitView } = useReactFlow<GraphNode, GraphEdge>(); |
| 89 | const clickTimerRef = useRef<number | null>(null); |
| 90 | const shouldFitViewRef = useRef(true); |
| 91 | |
| 92 | const entityById = useMemo( |
| 93 | () => new Map(props.graph.entities.map((entity) => [entity.id, entity])), |
| 94 | [props.graph.entities] |
| 95 | ); |
| 96 | const eventById = useMemo( |
| 97 | () => new Map(props.graph.events.map((event) => [event.id, event])), |
| 98 | [props.graph.events] |
| 99 | ); |
| 100 | const eventIdsByEntityId = useMemo(() => { |
| 101 | const map = new Map<string, string[]>(); |
| 102 | for (const edge of props.graph.edges) { |
| 103 | const eventIds = map.get(edge.entityId) ?? []; |
| 104 | eventIds.push(edge.eventId); |
| 105 | map.set(edge.entityId, eventIds); |
| 106 | } |
| 107 | for (const [entityId, eventIds] of map.entries()) { |
| 108 | eventIds.sort((a, b) => compareEvents(eventById.get(a), eventById.get(b))); |
| 109 | map.set(entityId, eventIds); |
| 110 | } |
| 111 | return map; |
| 112 | }, [eventById, props.graph.edges]); |
| 113 | const entityIdsByEventId = useMemo(() => { |
| 114 | const map = new Map<string, string[]>(); |
| 115 | for (const edge of props.graph.edges) { |
| 116 | const entityIds = map.get(edge.eventId) ?? []; |
| 117 | entityIds.push(edge.entityId); |
| 118 | map.set(edge.eventId, entityIds); |
| 119 | } |
| 120 | for (const [eventId, entityIds] of map.entries()) { |
| 121 | entityIds.sort((a, b) => compareEntities(entityById.get(a), entityById.get(b))); |
| 122 | map.set(eventId, entityIds); |
| 123 | } |
| 124 | return map; |
| 125 | }, [entityById, props.graph.edges]); |
| 126 | const positionByNodeId = useMemo( |
nothing calls this directly
no test coverage detected