"use client"; import { useEffect, useMemo, useState } from "react"; import type { GraphDataset } from "@/lib/catalog"; import { browserGraphHistory, exportAdjacency, parseGraphSearch, partitionIncident, selectNeighborhood, serializeGraphSearch, type GraphHistory, type GraphLocation, type GraphModel, } from "@/lib/graph"; export function GraphExplorer({ model, initialSearch = "", history, }: { model: GraphDataset; initialSearch?: string; history?: GraphHistory; }) { const viewHistory = useMemo(() => history ?? browserGraphHistory(), [history]); const [search, setSearch] = useState(initialSearch); const knownIds = useMemo(() => model.nodes.map((node) => node.id), [model.nodes]); const graph: GraphModel = useMemo( () => ({ nodes: model.nodes.map((node) => ({ id: node.id, title: node.title })), edges: model.edges, }), [model.edges, model.nodes], ); const byId = useMemo(() => new Map(model.nodes.map((node) => [node.id, node])), [model.nodes]); const location = parseGraphSearch(search, knownIds, model.defaultFocusId); const neighborhood = selectNeighborhood(graph, location.focus, location.hops); const blocks = partitionIncident(location.focus, model.edges, model.labels); const adjacency = exportAdjacency(neighborhood); const focus = byId.get(location.focus); const detail = location.detail ? byId.get(location.detail) : undefined; useEffect(() => { const read = () => setSearch(viewHistory.read()); read(); return viewHistory.subscribe(read); }, [viewHistory]); function commit(next: GraphLocation) { const query = serializeGraphSearch(next); viewHistory.push(query); setSearch(query ? `?${query}` : ""); } return (

{model.dataspaceTitle}

Graph

Focus: {focus?.title ?? location.focus}

{neighborhood.excludedCount} relations outside this neighborhood

Neighborhood

Records

Outgoing

{blocks.outgoing.length === 0 ?

No outgoing relations.

: ( )}

Incoming

{blocks.incoming.length === 0 ?

No incoming relations.

: ( )}
{blocks.remainder > 0 ? (

{blocks.remainder} more relations are not listed.

) : null} {detail ? (

{detail.title}

{detail.summary}

Open record
) : null}

Adjacency

{JSON.stringify(adjacency)}
); }