Spaces:
Sleeping
Sleeping
Frontend: Convert metric names to human-readable labels
Browse filesAdd METRIC_LABELS mapping and formatMetricName() function to convert
snake_case metric names (e.g., net_income, trailing_pe) to readable
labels (e.g., "Net Income", "Trailing P/E") in the Quantitative Data table.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
frontend/src/components/MCPDataPanel.tsx
CHANGED
|
@@ -17,6 +17,70 @@ interface MCPDataPanelProps {
|
|
| 17 |
cik?: string
|
| 18 |
}
|
| 19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
// Format numbers for display
|
| 21 |
function formatValue(value: string | number): string {
|
| 22 |
if (value === null || value === undefined) return '—'
|
|
@@ -361,7 +425,7 @@ export function MCPDataPanel({ metrics, rawData, companyName, ticker, exchange,
|
|
| 361 |
{quantitativeRows.map((row, idx) => (
|
| 362 |
<tr key={idx} className="hover:bg-muted/20">
|
| 363 |
<td className="px-3 py-1.5 text-muted-foreground">{idx + 1}</td>
|
| 364 |
-
<td className="px-3 py-1.5">{row.metric}</td>
|
| 365 |
<td className="px-3 py-1.5 text-right font-medium">{row.value}</td>
|
| 366 |
<td className="px-3 py-1.5 text-muted-foreground">{row.dataType}</td>
|
| 367 |
<td className="px-3 py-1.5 text-muted-foreground">{row.asOf}</td>
|
|
|
|
| 17 |
cik?: string
|
| 18 |
}
|
| 19 |
|
| 20 |
+
// Metric name mapping: snake_case → Human Readable
|
| 21 |
+
const METRIC_LABELS: Record<string, string> = {
|
| 22 |
+
// Fundamentals
|
| 23 |
+
revenue: 'Revenue',
|
| 24 |
+
net_income: 'Net Income',
|
| 25 |
+
gross_profit: 'Gross Profit',
|
| 26 |
+
operating_income: 'Operating Income',
|
| 27 |
+
gross_margin_pct: 'Gross Margin %',
|
| 28 |
+
operating_margin_pct: 'Operating Margin %',
|
| 29 |
+
net_margin_pct: 'Net Margin %',
|
| 30 |
+
free_cash_flow: 'Free Cash Flow',
|
| 31 |
+
operating_cash_flow: 'Operating Cash Flow',
|
| 32 |
+
total_assets: 'Total Assets',
|
| 33 |
+
total_liabilities: 'Total Liabilities',
|
| 34 |
+
stockholders_equity: "Stockholders' Equity",
|
| 35 |
+
cash: 'Cash',
|
| 36 |
+
long_term_debt: 'Long-term Debt',
|
| 37 |
+
net_debt: 'Net Debt',
|
| 38 |
+
debt_to_equity: 'Debt to Equity',
|
| 39 |
+
rd_expense: 'R&D Expense',
|
| 40 |
+
eps: 'EPS',
|
| 41 |
+
|
| 42 |
+
// Valuation
|
| 43 |
+
market_cap: 'Market Cap',
|
| 44 |
+
enterprise_value: 'Enterprise Value',
|
| 45 |
+
trailing_pe: 'Trailing P/E',
|
| 46 |
+
forward_pe: 'Forward P/E',
|
| 47 |
+
pb_ratio: 'P/B Ratio',
|
| 48 |
+
ps_ratio: 'P/S Ratio',
|
| 49 |
+
trailing_peg: 'PEG Ratio',
|
| 50 |
+
price_to_fcf: 'Price/FCF',
|
| 51 |
+
ev_ebitda: 'EV/EBITDA',
|
| 52 |
+
ev_revenue: 'EV/Revenue',
|
| 53 |
+
revenue_growth: 'Revenue Growth',
|
| 54 |
+
earnings_growth: 'Earnings Growth',
|
| 55 |
+
|
| 56 |
+
// Volatility
|
| 57 |
+
vix: 'VIX',
|
| 58 |
+
vxn: 'VXN',
|
| 59 |
+
beta: 'Beta',
|
| 60 |
+
historical_volatility: 'Historical Volatility',
|
| 61 |
+
implied_volatility: 'Implied Volatility',
|
| 62 |
+
|
| 63 |
+
// Macro
|
| 64 |
+
gdp_growth: 'GDP Growth',
|
| 65 |
+
interest_rate: 'Interest Rate',
|
| 66 |
+
cpi_inflation: 'CPI Inflation',
|
| 67 |
+
unemployment: 'Unemployment',
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
// Convert snake_case metric name to human-readable label
|
| 71 |
+
function formatMetricName(metric: string): string {
|
| 72 |
+
// Check if we have a predefined label
|
| 73 |
+
if (METRIC_LABELS[metric]) {
|
| 74 |
+
return METRIC_LABELS[metric]
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
// Fallback: convert snake_case to Title Case
|
| 78 |
+
return metric
|
| 79 |
+
.split('_')
|
| 80 |
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
| 81 |
+
.join(' ')
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
// Format numbers for display
|
| 85 |
function formatValue(value: string | number): string {
|
| 86 |
if (value === null || value === undefined) return '—'
|
|
|
|
| 425 |
{quantitativeRows.map((row, idx) => (
|
| 426 |
<tr key={idx} className="hover:bg-muted/20">
|
| 427 |
<td className="px-3 py-1.5 text-muted-foreground">{idx + 1}</td>
|
| 428 |
+
<td className="px-3 py-1.5">{formatMetricName(row.metric)}</td>
|
| 429 |
<td className="px-3 py-1.5 text-right font-medium">{row.value}</td>
|
| 430 |
<td className="px-3 py-1.5 text-muted-foreground">{row.dataType}</td>
|
| 431 |
<td className="px-3 py-1.5 text-muted-foreground">{row.asOf}</td>
|