feat(PBI-78): wire CostAnalysisCard onto insights page (T-904)
- Parse ?period= from searchParams (default 30d, validates against 7d/30d/90d/mtd)
- Parallel-fetch 5 cost queries via Promise.all alongside existing widgets
- New "Cost analyse" section between Sprint Health and Plan-quality
- Existing TokenUsageCard ("Token gebruik" section) stays as sprint detail
verify (lint+typecheck+test) and build pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
814f2191e8
commit
de70ca5de1
1 changed files with 41 additions and 2 deletions
|
|
@ -8,6 +8,14 @@ import { getSprintStatusBreakdown } from '@/lib/insights/sprint-status'
|
|||
import { getVerifyResultStats, getAlignmentTrend } from '@/lib/insights/verify-stats'
|
||||
import { getJobsPerDay } from '@/lib/insights/agent-throughput'
|
||||
import { getTokenStats } from '@/lib/insights/token-stats'
|
||||
import {
|
||||
getCostKpi,
|
||||
getCostByDay,
|
||||
getCostByModel,
|
||||
getCostByKind,
|
||||
getCacheEfficiency,
|
||||
type Period,
|
||||
} from '@/lib/insights/cost-analysis'
|
||||
import { getVelocity } from '@/lib/insights/velocity'
|
||||
import { getBacklogHealth } from '@/lib/insights/backlog-health'
|
||||
import { SprintInfoStrip } from './components/sprint-info-strip'
|
||||
|
|
@ -16,6 +24,7 @@ import { SprintStatusDonut } from './components/sprint-status-donut'
|
|||
import { PlanQualityCard } from './components/plan-quality'
|
||||
import { AlignmentTrend } from './components/alignment-trend'
|
||||
import { AgentThroughputCard } from './components/agent-throughput'
|
||||
import { CostAnalysisCard } from './components/cost-analysis'
|
||||
import { TokenUsageCard } from './components/token-usage'
|
||||
import { VelocityChart } from './components/velocity-chart'
|
||||
import { BacklogHealthCard } from './components/backlog-health'
|
||||
|
|
@ -24,7 +33,13 @@ const DAY_MS = 86_400_000
|
|||
const ASSUMED_SPRINT_DAYS = 14
|
||||
|
||||
interface InsightsPageProps {
|
||||
searchParams: Promise<{ product?: string }>
|
||||
searchParams: Promise<{ product?: string; period?: string }>
|
||||
}
|
||||
|
||||
const VALID_PERIODS = ['7d', '30d', '90d', 'mtd'] as const
|
||||
|
||||
function parsePeriod(raw: string | undefined): Period {
|
||||
return (VALID_PERIODS as readonly string[]).includes(raw ?? '') ? (raw as Period) : '30d'
|
||||
}
|
||||
|
||||
function MissingDatesNotice({ productId, productName }: { productId: string; productName: string }) {
|
||||
|
|
@ -41,7 +56,8 @@ function MissingDatesNotice({ productId, productName }: { productId: string; pro
|
|||
export default async function InsightsPage({ searchParams }: InsightsPageProps) {
|
||||
const session = await getIronSession<SessionData>(await cookies(), sessionOptions)
|
||||
const userId = session.userId!
|
||||
const { product: filterProductId } = await searchParams
|
||||
const { product: filterProductId, period: rawPeriod } = await searchParams
|
||||
const period = parsePeriod(rawPeriod)
|
||||
|
||||
const [
|
||||
burndownSprints,
|
||||
|
|
@ -53,6 +69,11 @@ export default async function InsightsPage({ searchParams }: InsightsPageProps)
|
|||
jobsPerDay,
|
||||
velocity,
|
||||
backlogHealth,
|
||||
costKpi,
|
||||
costByDay,
|
||||
costByModel,
|
||||
costByKind,
|
||||
cacheEff,
|
||||
] = await Promise.all([
|
||||
getBurndownData(userId),
|
||||
getSprintStatusBreakdown(userId),
|
||||
|
|
@ -77,6 +98,11 @@ export default async function InsightsPage({ searchParams }: InsightsPageProps)
|
|||
getJobsPerDay(userId, 14, filterProductId),
|
||||
getVelocity(userId, 5),
|
||||
getBacklogHealth(userId),
|
||||
getCostKpi(userId, period),
|
||||
getCostByDay(userId, period),
|
||||
getCostByModel(userId, period),
|
||||
getCostByKind(userId, period),
|
||||
getCacheEfficiency(userId, period),
|
||||
])
|
||||
|
||||
const activeSprintId = activeSprints.find(s => s.product.id === filterProductId)?.id ?? ''
|
||||
|
|
@ -134,6 +160,19 @@ export default async function InsightsPage({ searchParams }: InsightsPageProps)
|
|||
)}
|
||||
</section>
|
||||
|
||||
{/* Cost analyse */}
|
||||
<section className="space-y-3">
|
||||
<h2 className="text-lg font-medium text-foreground">Cost analyse</h2>
|
||||
<CostAnalysisCard
|
||||
period={period}
|
||||
kpi={costKpi}
|
||||
byDay={costByDay}
|
||||
byModel={costByModel}
|
||||
byKind={costByKind}
|
||||
cache={cacheEff}
|
||||
/>
|
||||
</section>
|
||||
|
||||
{/* Plan-quality */}
|
||||
<section className="space-y-3">
|
||||
<h2 className="text-lg font-medium text-foreground">Plan-quality</h2>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue