/** * Graph Cohesion — presentational view. Pure: renders the cohesion summary * tiles (entities / connections / triangles), the network averages, and a * brokerage ranking of the loosest-neighbourhood entities. No data fetching, * no clock, no randomness. */ import { useMemo } from 'react'; import { useT } from '../../lib/i18n/I18nContext'; import { type CohesionResult, findBrokers } from '../../lib/memory/graphCohesion'; const MAX_ROWS = 25; interface GraphCohesionPanelProps { result: CohesionResult | null; loading?: boolean; error?: string | null; onRetry?: () => void; } const GraphCohesionPanel = ({ result, loading, error, onRetry }: GraphCohesionPanelProps) => { const { t } = useT(); const brokers = useMemo(() => (result ? findBrokers(result, MAX_ROWS) : []), [result]); const intro = (
{t('graphCohesion.title')}
{t('graphCohesion.intro')}
{t('graphCohesion.errorPrefix')} {error}
{onRetry && ( )}{t('graphCohesion.emptyHint')}
{t('graphCohesion.summaryCaption') .replace('{avg}', result.averageClustering.toFixed(2)) .replace('{transitivity}', result.transitivity.toFixed(2))}
{/* Brokerage ranking: loosest neighbourhoods first (structural holes). */} {brokers.length === 0 ? ({t('graphCohesion.noBrokers')}
) : (| {t('graphCohesion.colRank')} | {t('graphCohesion.colEntity')} | {t('graphCohesion.colCohesion')} | {t('graphCohesion.colLinks')} |
|---|---|---|---|
| {i + 1} | {node.id} {node.localClustering === 0 && ( {t('graphCohesion.brokerBadge')} )} |
|
{node.degree} |