From d0a7ce482fcd6b4f4871581784ce53d06990295b Mon Sep 17 00:00:00 2001 From: yubnsbski <132217387+yubnsbski@users.noreply.github.com> Date: Thu, 25 Jun 2026 11:21:37 +0900 Subject: [PATCH] feat(holdings): surface portfolio summary as KPIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Portfolio analysis only showed the market value in the result heading; the rest of the summary (cost basis, P&L, dividend estimate, yield, largest position) was buried in the collapsed JSON. Render a metrics row up front, reusing the existing DetailFact cards. Applies to both 保有分析 and 候補抽出's portfolio simulation, which share AnalysisResult. Co-Authored-By: Claude Opus 4.8 --- web/src/App.tsx | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/web/src/App.tsx b/web/src/App.tsx index a05f654..44637fb 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -2838,6 +2838,9 @@ function PieChart({ slices }: { slices: { label: string; value: number }[] }) { function AnalysisResult({ data }: { data: Json }) { const rows = Array.isArray(data.holdings) ? data.holdings : []; + const summary = asJson(data.summary) ?? {}; + const largest = asJson(summary.largest_position); + const pnlPositive = (Number(summary.unrealized_pnl) || 0) >= 0; const slices = rows .map((row) => ({ label: String(row.name || row.ticker_or_fund_code || "?"), @@ -2846,6 +2849,29 @@ function AnalysisResult({ data }: { data: Json }) { .filter((s) => s.value > 0); return ( + {Object.keys(summary).length > 0 && ( +
+

サマリー

+
+ + + + + + + {largest && ( + + )} +
+
+ )} {slices.length > 0 && ( <>

ポートフォリオ構成比(評価額)