feat(ui): migrate web shell to mudblazor
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 6s
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 11s
Deploy to Production / Build & Deploy to Production (push) Failing after 1m55s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped

This commit is contained in:
2026-07-01 13:24:46 +09:00
parent fe8ff44d3f
commit 28e1a8775f
14 changed files with 285 additions and 589 deletions
@@ -1,89 +1,84 @@
@page "/"
@page "/dashboard"
@attribute [Authorize]
@using QuantEngine.Core.Infrastructure
@inject HttpClient Http
<PageTitle>Quant Engine - Dashboard</PageTitle>
<h1 style="margin: 0 0 8px 0; font-size: 28px; font-weight: 600;">Quant Engine</h1>
<p style="margin: 0 0 16px 0; color: var(--neutral-foreground-2); font-size: 14px;">
루트 화면은 운영 진입점입니다. 가짜 성과 수치 없이 현재 스냅샷 상태와 리포트 경로만 보여줍니다.
</p>
<MudText Typo="Typo.h4" Class="mb-2">Quant Engine</MudText>
<MudText Typo="Typo.body2" Class="mb-4">운영 진입점입니다. 로그인 후 현재 스냅샷 상태와 리포트 경로만 표시합니다.</MudText>
<!-- Top 3 Cards -->
<FluentStack Orientation="Orientation.Horizontal" HorizontalGap="16" Wrap="true" Style="margin-bottom: 16px;">
<FluentCard Style="flex: 1; min-width: 200px;">
<div style="padding: 16px;">
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Operational Report</p>
<h3 style="margin: 0; font-size: 20px; font-weight: 600;">@ReportStateLabel</h3>
<p style="margin: 8px 0 0 0; color: var(--neutral-foreground-3); font-size: 12px;">@ReportPath</p>
</div>
</FluentCard>
<FluentCard Style="flex: 1; min-width: 200px;">
<div style="padding: 16px;">
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Sections</p>
<h3 style="margin: 0; font-size: 20px; font-weight: 600;">@SectionCountLabel</h3>
<p style="margin: 8px 0 0 0; color: var(--neutral-foreground-3); font-size: 12px;">Temp/operational_report.json</p>
</div>
</FluentCard>
<FluentCard Style="flex: 1; min-width: 200px;">
<div style="padding: 16px;">
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Primary Route</p>
<FluentButton Appearance="ButtonAppearance.Primary" Href="/operations" Style="margin-top: 8px;">
Open Operations
</FluentButton>
</div>
</FluentCard>
</FluentStack>
<MudGrid Spacing="2" Class="mb-4">
<MudItem xs="12" sm="4">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.caption">Operational Report</MudText>
<MudText Typo="Typo.h6">@ReportStateLabel</MudText>
<MudText Typo="Typo.body2">@ReportPath</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" sm="4">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.caption">Sections</MudText>
<MudText Typo="Typo.h6">@SectionCountLabel</MudText>
<MudText Typo="Typo.body2">Temp/operational_report.json</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" sm="4">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.caption">Primary Route</MudText>
<MudButton Variant="Variant.Filled" Color="Color.Primary" Href="/operations" Class="mt-2">Open Operations</MudButton>
</MudPaper>
</MudItem>
</MudGrid>
<!-- Current State & Routing Notes -->
<FluentStack Orientation="Orientation.Horizontal" HorizontalGap="16" Wrap="true" Style="margin-bottom: 16px;">
<FluentCard Style="flex: 2; min-width: 300px;">
<div style="padding: 16px;">
<h3 style="margin: 0 0 12px 0; font-size: 16px; font-weight: 600;">Current State</h3>
<FluentStack Orientation="Orientation.Vertical" VerticalGap="8">
<p style="margin: 0; font-size: 14px;"><strong>Status:</strong> <FluentBadge Appearance="BadgeAppearance.Filled">@ReportChipLabel</FluentBadge></p>
<p style="margin: 0; font-size: 14px;"><strong>Generated:</strong> @GeneratedAtLabel</p>
<p style="margin: 0; font-size: 14px;"><strong>Source:</strong> @SourceLabel</p>
<p style="margin: 0; font-size: 14px;"><strong>Decision feed:</strong> @DecisionFeedLabel</p>
<p style="margin: 0; font-size: 14px;"><strong>Factor feed:</strong> @FactorFeedLabel</p>
<p style="margin: 0; font-size: 14px;"><strong>Raw feed:</strong> @RawFeedLabel</p>
</FluentStack>
</div>
</FluentCard>
<FluentCard Style="flex: 1; min-width: 250px;">
<div style="padding: 16px;">
<h3 style="margin: 0 0 12px 0; font-size: 16px; font-weight: 600;">Routing Notes</h3>
<ul style="margin: 0; padding-left: 16px; font-size: 14px;">
<MudGrid Spacing="2" Class="mb-4">
<MudItem xs="12" md="8">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.h6" Class="mb-3">Current State</MudText>
<MudStack Spacing="1">
<MudText Typo="Typo.body2">Status: <MudChip T="string" Color="@(ReportChipLabel == "READY" ? Color.Success : Color.Warning)" Variant="Variant.Filled">@ReportChipLabel</MudChip></MudText>
<MudText Typo="Typo.body2">Generated: @GeneratedAtLabel</MudText>
<MudText Typo="Typo.body2">Source: @SourceLabel</MudText>
<MudText Typo="Typo.body2">Decision feed: @DecisionFeedLabel</MudText>
<MudText Typo="Typo.body2">Factor feed: @FactorFeedLabel</MudText>
<MudText Typo="Typo.body2">Raw feed: @RawFeedLabel</MudText>
</MudStack>
</MudPaper>
</MudItem>
<MudItem xs="12" md="4">
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.h6" Class="mb-3">Routing Notes</MudText>
<ul style="margin: 0; padding-left: 18px;">
<li>운영 데이터는 snapshot 우선입니다.</li>
<li>Excel/GAS 의존 문구는 운영 경로에서 제거 대상입니다.</li>
<li>Excel/GAS 의존 문구는 제거 대상입니다.</li>
<li>숫자는 provenance 없으면 표시하지 않습니다.</li>
</ul>
</div>
</FluentCard>
</FluentStack>
</MudPaper>
</MudItem>
</MudGrid>
<!-- Coverage Summary -->
<FluentCard>
<div style="padding: 16px;">
<h3 style="margin: 0 0 12px 0; font-size: 16px; font-weight: 600;">Coverage Summary</h3>
@if (Sections.Count == 0)
{
<div style="padding: 12px; background: var(--warning-background-1); border: 1px solid var(--warning-stroke-1); border-radius: 4px; color: var(--warning-foreground-1); font-size: 14px;">
DATA_MISSING: operational_report.json이 비어 있거나 아직 생성되지 않았습니다.
</div>
}
else
{
<FluentDataGrid Items="@Sections.AsQueryable()">
<PropertyColumn Property="@(x => x.Name)" Title="Name" />
<PropertyColumn Property="@(x => x.Title)" Title="Title" />
<PropertyColumn Property="@(x => x.Preview)" Title="Preview" />
</FluentDataGrid>
}
</div>
</FluentCard>
<MudPaper Class="pa-4" Elevation="2">
<MudText Typo="Typo.h6" Class="mb-3">Coverage Summary</MudText>
@if (Sections.Count == 0)
{
<MudAlert Severity="Severity.Warning">DATA_MISSING: operational_report.json이 비어 있거나 아직 생성되지 않았습니다.</MudAlert>
}
else
{
<MudTable Items="@Sections" Dense="true" Hover="true">
<HeaderContent>
<MudTh>Name</MudTh>
<MudTh>Title</MudTh>
<MudTh>Preview</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Name">@context.Name</MudTd>
<MudTd DataLabel="Title">@context.Title</MudTd>
<MudTd DataLabel="Preview">@context.Preview</MudTd>
</RowTemplate>
</MudTable>
}
</MudPaper>
@code {
private readonly List<OperationalReportSection> Sections = new();