feat: make ticker clickable on positions page — links to company detail
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/push/build-3 Pipeline failed
ci/woodpecker/push/build-1 Pipeline was successful
ci/woodpecker/push/build-2 Pipeline was successful
ci/woodpecker/push/finalize unknown status
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

Ticker column now links to /companies/{id} using a ticker→company ID
lookup. Falls back to plain text if company not found.
This commit is contained in:
Celes Renata
2026-04-30 03:15:22 +00:00
parent 13f863ef30
commit 861423c1e3
+33 -2
View File
@@ -1,4 +1,5 @@
import { usePositions } from '../api/hooks';
import { Link } from '@tanstack/react-router';
import { usePositions, useCompanies } from '../api/hooks';
import { DataTable, type Column } from '../components/DataTable';
import { LoadingSpinner } from '../components/ui';
import type { Position } from '../api/hooks';
@@ -25,6 +26,36 @@ const columns: Column<Position>[] = [
export function PositionsPage() {
const { data, isLoading } = usePositions();
const { data: companies } = useCompanies();
// Build ticker → company ID lookup
const tickerToId: Record<string, string> = {};
for (const c of companies ?? []) {
tickerToId[c.ticker] = c.id;
}
const posColumns: Column<Position>[] = [
{
key: 'ticker',
header: 'Ticker',
render: (r) => {
const companyId = tickerToId[r.ticker];
return companyId ? (
<Link to="/companies/$id" params={{ id: companyId }} className="font-mono font-semibold text-brand-300 hover:underline">
{r.ticker}
</Link>
) : (
<span className="font-mono font-semibold text-brand-300">{r.ticker}</span>
);
},
},
{ key: 'quantity', header: 'Qty' },
{ key: 'avg_entry_price', header: 'Entry', render: (r) => <span>{fmtUsd(r.avg_entry_price)}</span> },
{ key: 'current_price', header: 'Current', render: (r) => <span>{fmtUsd(r.current_price)}</span> },
{ key: 'unrealized_pnl', header: 'Unrealized P&L', render: (r) => <span className={pnlColor(r.unrealized_pnl)}>{fmtUsd(r.unrealized_pnl)}</span> },
{ key: 'realized_pnl', header: 'Realized P&L', render: (r) => <span className={pnlColor(r.realized_pnl)}>{fmtUsd(r.realized_pnl)}</span> },
{ key: 'updated_at', header: 'Updated', render: (r) => <span className="text-xs">{new Date(r.updated_at).toLocaleString()}</span> },
];
if (isLoading) return <LoadingSpinner />;
@@ -58,7 +89,7 @@ export function PositionsPage() {
<h1 className="mb-4 text-xl font-semibold text-gray-100">Positions</h1>
<DataTable<Position>
data={positions}
columns={columns}
columns={posColumns}
keyField="id"
footerRow={footer}
/>