feat(web): add homepage operations map
All checks were successful
CD Pipeline / tests (push) Successful in 1m29s
Code Review / ai-code-review (push) Successful in 12s
CD Pipeline / build-and-deploy (push) Successful in 4m53s
CD Pipeline / post-deploy-checks (push) Successful in 1m36s

This commit is contained in:
Your Name
2026-06-02 12:00:01 +08:00
parent 6b56680e6b
commit 91a956b954
4 changed files with 326 additions and 3 deletions

View File

@@ -1879,6 +1879,60 @@ export default function Home({ params }: { params: { locale: string } }) {
}),
},
]
const productModuleRows: Array<{
key: string
module: string
owns: string
evidence: string
href: string
tone: HomepageWorkTone
}> = [
{
key: 'awooop',
module: tDashboard('homeProductMap.modules.awooop.module'),
owns: tDashboard('homeProductMap.modules.awooop.owns'),
evidence: tDashboard('automationDiagrams.workspace.liveEvidence.intake.metric', {
runs: formatAutomationNumber(automationBrief.runsList?.total, runsListLoaded),
linked: formatAutomationNumber(recurrenceSummary?.linked_run_total, eventRecurrenceLoaded),
}),
href: `/${locale}/awooop/runs?project_id=awoooi`,
tone: 'live',
},
{
key: 'routing',
module: tDashboard('homeProductMap.modules.routing.module'),
owns: tDashboard('homeProductMap.modules.routing.owns'),
evidence: tDashboard('automationDiagrams.workspace.values.aiRoute', {
lane: aiRouteLaneMode,
provider: aiRouteSelectedProvider,
}),
href: `/${locale}/awooop/work-items?project_id=awoooi`,
tone: hasAiRouteStatus ? 'live' : 'watching',
},
{
key: 'execution',
module: tDashboard('homeProductMap.modules.execution.module'),
owns: tDashboard('homeProductMap.modules.execution.owns'),
evidence: tDashboard('automationDiagrams.workspace.values.ansible', {
checkMode: formatAutomationNumber(executionBackend?.ansible_check_mode_total, automationQualityLoaded),
pending: formatAutomationNumber(executionBackend?.ansible_pending_check_mode_total, automationQualityLoaded),
blocker: ansibleRuntimeBlockerLabel,
}),
href: `/${locale}/automation`,
tone: ansibleRuntime?.can_run_check_mode ? 'live' : automationQualityAvailable ? 'blocked' : 'watching',
},
{
key: 'learning',
module: tDashboard('homeProductMap.modules.learning.module'),
owns: tDashboard('homeProductMap.modules.learning.owns'),
evidence: tDashboard('automationDiagrams.workspace.liveEvidence.verify.metric', {
stale: formatAutomationNumber(kmStaleDisplayCount, kmGovernanceLoaded),
ratio: staleRatioLabel,
}),
href: `/${locale}/knowledge-base`,
tone: typeof kmStaleDisplayCount === 'number' && kmStaleDisplayCount > 0 ? 'progress' : hasKmStaleCandidates ? 'live' : 'watching',
},
]
return (
<AppLayout locale={locale} showBackground={false} fullBleed>
@@ -1894,14 +1948,173 @@ export default function Home({ params }: { params: { locale: string } }) {
<div style={{
display: 'flex',
flexDirection: 'column',
height: 'calc(100vh - 68px)',
minHeight: 'calc(100vh - 68px)',
background: '#f5f4ed',
fontFamily: 'var(--font-body), monospace',
overflowX: 'hidden',
overflowY: 'auto',
overscrollBehavior: 'contain',
overflowY: 'visible',
}}>
<section
data-testid="homepage-product-map"
style={{
margin: primarySectionMargin,
background: '#fff',
borderTop: '0.5px solid #d8d3c7',
borderBottom: '0.5px solid #d8d3c7',
flexShrink: 0,
}}
>
<div style={{
display: 'grid',
gridTemplateColumns: compactViewport ? '1fr' : 'minmax(0, 1.4fr) minmax(260px, 0.6fr)',
gap: compactViewport ? 10 : 18,
padding: compactViewport ? '14px 12px' : '18px 20px',
borderBottom: '0.5px solid #e0ddd4',
background: '#fffdf8',
}}>
<div style={{ minWidth: 0 }}>
<div style={{ fontSize: 11, fontWeight: 850, color: '#1f5b9b', textTransform: 'uppercase', letterSpacing: 0.5 }}>
{tDashboard('homeProductMap.eyebrow')}
</div>
<h1 style={{ margin: '5px 0 0', fontSize: compactViewport ? 22 : 28, lineHeight: 1.1, fontWeight: 900, color: '#141413' }}>
{tDashboard('homeProductMap.title')}
</h1>
<p style={{ margin: '8px 0 0', maxWidth: 820, fontSize: 13, lineHeight: 1.65, color: '#4e4a43' }}>
{tDashboard('homeProductMap.subtitle')}
</p>
</div>
<div style={{
alignSelf: 'stretch',
display: 'grid',
gap: 8,
border: `0.5px solid ${automationDeliveryClaimTone.border}`,
background: automationDeliveryClaimTone.bg,
padding: '11px 12px',
}}>
<div style={{ fontSize: 10, fontWeight: 850, color: automationDeliveryClaimTone.color, textTransform: 'uppercase', letterSpacing: 0.5 }}>
{tDashboard('homeProductMap.currentGate')}
</div>
<div style={{ fontSize: 16, fontWeight: 900, color: '#141413', lineHeight: 1.2 }}>
{automationDeliveryHeadline}
</div>
<div style={{ fontSize: 11, lineHeight: 1.5, color: '#5f5b52' }}>
{automationDeliveryClaimDetail}
</div>
</div>
</div>
<div style={{
display: 'grid',
gridTemplateColumns: compactViewport ? '1fr' : 'minmax(0, 1.35fr) minmax(320px, 0.85fr)',
gap: compactViewport ? 10 : 14,
padding: compactViewport ? 12 : 16,
}}>
<div style={{ minWidth: 0 }}>
<div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10, marginBottom: 10 }}>
<h2 style={{ margin: 0, fontSize: 15, fontWeight: 900, color: '#141413' }}>
{tDashboard('homeProductMap.flowTitle')}
</h2>
<a href={`/${locale}/awooop/runs?project_id=awoooi`} style={{ fontSize: 11, fontWeight: 800, color: '#1f5b9b', textDecoration: 'none' }}>
{tDashboard('automationDelivery.openRuns')}
</a>
</div>
<div style={{
display: 'grid',
gridTemplateColumns: compactViewport ? '1fr' : 'repeat(4, minmax(0, 1fr))',
gap: 8,
}}>
{automationFlowStages.map((stage, index) => {
const tone = automationWorkToneStyle[stage.tone]
return (
<a
key={`product-map-${stage.key}`}
href={`/${locale}?blueprint_stage=${stage.key}#homepage-ai-command-map`}
onClick={() => setSelectedBlueprintStageKey(stage.key as HomepageBlueprintStageKey)}
style={{
minWidth: 0,
border: `0.5px solid ${tone.border}`,
background: tone.bg,
padding: '9px 10px',
color: 'inherit',
textDecoration: 'none',
}}
>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
<span style={{ fontSize: 10, fontWeight: 900, color: tone.color, fontFamily: "'JetBrains Mono', monospace" }}>
{String(index + 1).padStart(2, '0')}
</span>
<span style={{ fontSize: 9, fontWeight: 850, color: tone.color, textTransform: 'uppercase', whiteSpace: 'nowrap' }}>
{stage.status}
</span>
</div>
<div style={{ marginTop: 8, fontSize: 12, fontWeight: 900, color: '#141413', lineHeight: 1.25 }}>
{stage.title}
</div>
<div style={{ marginTop: 6, fontSize: 10, lineHeight: 1.45, color: '#5f5b52', minHeight: 30, overflow: 'hidden' }}>
{stage.liveEvidence.metric}
</div>
</a>
)
})}
</div>
</div>
<div style={{ minWidth: 0 }}>
<div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10, marginBottom: 10 }}>
<h2 style={{ margin: 0, fontSize: 15, fontWeight: 900, color: '#141413' }}>
{tDashboard('homeProductMap.moduleTitle')}
</h2>
<a href={`/${locale}/topology`} style={{ fontSize: 11, fontWeight: 800, color: '#1f5b9b', textDecoration: 'none' }}>
{tDashboard('automationDiagrams.openTopology')}
</a>
</div>
<div style={{ display: 'grid', gap: 1, border: '0.5px solid #e0ddd4', background: '#e0ddd4' }}>
{productModuleRows.map((row) => {
const tone = automationWorkToneStyle[row.tone]
return (
<a
key={row.key}
href={row.href}
style={{
display: 'grid',
gridTemplateColumns: compactViewport ? '1fr' : '0.72fr 1fr',
gap: 8,
padding: '9px 10px',
background: '#fff',
color: 'inherit',
textDecoration: 'none',
}}
>
<div style={{ minWidth: 0 }}>
<div style={{ fontSize: 12, fontWeight: 900, color: '#141413' }}>{row.module}</div>
<div style={{ marginTop: 3, fontSize: 10, lineHeight: 1.4, color: '#5f5b52' }}>{row.owns}</div>
</div>
<div style={{ minWidth: 0 }}>
<div style={{
display: 'inline-flex',
maxWidth: '100%',
border: `0.5px solid ${tone.border}`,
background: tone.bg,
color: tone.color,
padding: '2px 7px',
fontSize: 10,
fontWeight: 850,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}}>
{row.evidence}
</div>
</div>
</a>
)
})}
</div>
</div>
</div>
</section>
<section style={{
margin: primarySectionMargin,
background: '#fff',