feat: show document title and link in competitive signals panel
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/push/build-2 Pipeline was successful
ci/woodpecker/push/build-3 Pipeline was successful
ci/woodpecker/push/build-1 Pipeline was successful
ci/woodpecker/push/finalize Pipeline was successful
Build and Push / lint-and-test (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.adapters.broker_adapter name:broker-adapter]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.aggregation.worker name:aggregation]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.extractor.worker name:extractor]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.ingestion.worker name:ingestion]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.lake_publisher.worker name:lake-publisher]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.parser.worker name:parser]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.recommendation.worker name:recommendation]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.scheduler.app name:scheduler]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.api.app:app --host 0.0.0.0 --port 8000 name:query-api]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.risk.app:app --host 0.0.0.0 --port 8000 name:risk]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.symbol_registry.app:app --host 0.0.0.0 --port 8000 name:symbol-registry]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.trading.app:app --host 0.0.0.0 --port 8000 name:trading-engine]) (push) Has been cancelled
Build and Push / build-dashboard (push) Has been cancelled
Build and Push / build-superset (push) Has been cancelled
Build and Push / integration-test (push) Has been cancelled
Build and Push / beta-gate (push) Has been cancelled

Replace raw UUID with a linked document title in both the collapsed
row (using the empty space on the right) and the expanded detail view.
Uses useDocument hook to fetch the title, falls back to truncated UUID
while loading. Clicking the link navigates to the document detail page.
This commit is contained in:
Celes Renata
2026-04-29 17:29:26 +00:00
parent 97fe2249fe
commit f159b20c87
+37 -9
View File
@@ -1,4 +1,4 @@
import { useParams, useNavigate } from '@tanstack/react-router';
import { useParams, useNavigate, Link } from '@tanstack/react-router';
import { useState } from 'react';
import {
useCompany,
@@ -14,6 +14,7 @@ import {
useTrends,
useTrendHistory,
useMarketPrices,
useDocument,
} from '../api/hooks';
import { StatusBadge, ConfidenceBar, LoadingSpinner, Card } from '../components/ui';
import { DataTable, type Column } from '../components/DataTable';
@@ -444,10 +445,23 @@ function CompetitiveSignalsPanel({ signals }: { signals: CompetitiveSignal[] })
) : (
<div className="space-y-2">
{signals.map((s) => (
<div key={s.id}>
<SignalRow key={s.id} signal={s} expanded={expandedId === s.id} onToggle={() => setExpandedId(expandedId === s.id ? null : s.id)} />
))}
</div>
)}
</div>
);
}
function SignalRow({ signal: s, expanded, onToggle }: { signal: CompetitiveSignal; expanded: boolean; onToggle: () => void }) {
const { data: doc } = useDocument(s.source_document_id);
const docLabel = doc?.title ?? `doc:${s.source_document_id.slice(0, 8)}`;
return (
<div>
<div
className="flex items-center justify-between rounded-lg border border-cyan-700/30 bg-cyan-900/10 p-3 cursor-pointer hover:border-cyan-500/50"
onClick={() => setExpandedId(expandedId === s.id ? null : s.id)}
onClick={onToggle}
>
<div className="flex items-center gap-3">
<span className="rounded bg-cyan-900/40 border border-cyan-700/50 px-1.5 py-0.5 text-[10px] font-medium text-cyan-400">COMPETITIVE</span>
@@ -457,11 +471,20 @@ function CompetitiveSignalsPanel({ signals }: { signals: CompetitiveSignal[] })
<StatusBadge status={s.signal_direction} />
</div>
<div className="flex items-center gap-3">
<Link
to="/documents/$id"
params={{ id: s.source_document_id }}
className="max-w-[180px] truncate text-xs text-brand-400 hover:underline"
onClick={(e) => e.stopPropagation()}
title={doc?.title ?? s.source_document_id}
>
{docLabel}
</Link>
<ConfidenceBar value={s.signal_strength} />
<span className="text-xs text-gray-500">{new Date(s.computed_at).toLocaleDateString()}</span>
</div>
</div>
{expandedId === s.id && (
{expanded && (
<Card className="mt-1 ml-4">
<dl className="grid grid-cols-2 gap-x-6 gap-y-2 text-xs sm:grid-cols-3">
<div>
@@ -490,7 +513,16 @@ function CompetitiveSignalsPanel({ signals }: { signals: CompetitiveSignal[] })
</div>
<div>
<dt className="text-gray-500">Source Document</dt>
<dd className="font-mono text-gray-400 text-[10px]">{s.source_document_id}</dd>
<dd>
<Link
to="/documents/$id"
params={{ id: s.source_document_id }}
className="text-brand-400 hover:underline"
onClick={(e) => e.stopPropagation()}
>
{docLabel}
</Link>
</dd>
</div>
<div>
<dt className="text-gray-500">Computed At</dt>
@@ -500,10 +532,6 @@ function CompetitiveSignalsPanel({ signals }: { signals: CompetitiveSignal[] })
</Card>
)}
</div>
))}
</div>
)}
</div>
);
}