(props: {
data: any;
onOpenNode: (id: any) => void;
onOpenSession: (id: any, opts?: any) => void;
onOpenMessage: (m: any) => void;
})
| 682 | } |
| 683 | |
| 684 | export function NodeDetail(props: { |
| 685 | data: any; |
| 686 | onOpenNode: (id: any) => void; |
| 687 | onOpenSession: (id: any, opts?: any) => void; |
| 688 | onOpenMessage: (m: any) => void; |
| 689 | }): React.ReactElement { |
| 690 | const d = props.data || {}; |
| 691 | const node = d.node; |
| 692 | const onOpenNode = props.onOpenNode; |
| 693 | const onOpenSession = props.onOpenSession; |
| 694 | const onOpenMessage = props.onOpenMessage; |
| 695 | if (!node) return <EmptyState className="hermes-lcm-empty">Node not found</EmptyState>; |
| 696 | const sources = d.sources || {}; |
| 697 | const tags = parseJsonArray(node.tags); |
| 698 | const entities = parseJsonArray(node.entities); |
| 699 | return ( |
| 700 | <div className="hermes-lcm-detail"> |
| 701 | <div className="hermes-lcm-detail-meta"> |
| 702 | <span className="hermes-lcm-tag">{`Depth ${node.depth}`}</span> |
| 703 | {node.category ? <span className="hermes-lcm-tag">{node.category}</span> : null} |
| 704 | <button |
| 705 | type="button" |
| 706 | className="hermes-lcm-btn" |
| 707 | onClick={function () { onOpenSession(node.session_id); }} |
| 708 | >{sessionLabel(node.session_id)}</button> |
| 709 | <span className="hermes-lcm-dim">{`${fmtInt(node.source_token_count)}→${fmtInt(node.token_count)} tok`}</span> |
| 710 | <TimeText className="hermes-lcm-dim" epoch={node.latest_at || node.created_at} /> |
| 711 | </div> |
| 712 | <div className="hermes-lcm-detail-grid"> |
| 713 | <div className="hermes-lcm-detail-cell"> |
| 714 | <div className="hermes-lcm-detail-k">Node id</div> |
| 715 | <div className="hermes-lcm-detail-v">{String(node.node_id)}</div> |
| 716 | </div> |
| 717 | <div className="hermes-lcm-detail-cell"> |
| 718 | <div className="hermes-lcm-detail-k">Source type</div> |
| 719 | <div className="hermes-lcm-detail-v">{sources.type || node.source_type || "—"}</div> |
| 720 | </div> |
| 721 | <div className="hermes-lcm-detail-cell"> |
| 722 | <div className="hermes-lcm-detail-k">Tags</div> |
| 723 | <div className="hermes-lcm-detail-v">{tags.length ? tags.join(", ") : "—"}</div> |
| 724 | </div> |
| 725 | <div className="hermes-lcm-detail-cell"> |
| 726 | <div className="hermes-lcm-detail-k">Entities</div> |
| 727 | <div className="hermes-lcm-detail-v">{entities.length ? entities.join(", ") : "—"}</div> |
| 728 | </div> |
| 729 | </div> |
| 730 | <h4>Summary</h4> |
| 731 | <MarkdownText className="hermes-lcm-summary" text={node.summary} /> |
| 732 | {node.expand_hint ? ( |
| 733 | <div className="hermes-lcm-hint"> |
| 734 | <strong>Expand hint: </strong>{node.expand_hint} |
| 735 | </div> |
| 736 | ) : null} |
| 737 | <h4>{`Source links (${sources.type || "?"}, ${(sources.ids || []).length})`}</h4> |
| 738 | {(() => { |
| 739 | const isNodes = sources.type === "nodes"; |
| 740 | const items = isNodes ? (sources.nodes || []) : (sources.messages || []); |
| 741 | if (!items.length) { |
nothing calls this directly
no test coverage detected