refactor(web): MudBlazor → Fluent UI Blazor v5 마이그레이션 완료
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 10s
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 8s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Snapshot Admin Deployment / build-and-deploy (push) Failing after 1m0s
Deploy to Production / Build & Deploy to Production (push) Successful in 1m21s
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 10s
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 8s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Snapshot Admin Deployment / build-and-deploy (push) Failing after 1m0s
Deploy to Production / Build & Deploy to Production (push) Successful in 1m21s
**주요 변경사항:** - NuGet: MudBlazor 6.10.0 → Microsoft.FluentUI.AspNetCore.Components 5.0.0-rc.4-26177.1 변경 - Program.cs: MudBlazor DI → Fluent UI DI 등록 - App.razor: CSS/JS 라이브러리 및 프로바이더 변경 - MainLayout.razor: MudLayout → FluentStack 기반 재구성 - FluentHeader 헤더 적용 - 네비게이션 사이드바 토글 기능 - Flexbox 레이아웃 - NavMenu.razor: MudNavMenu/MudNavLink → FluentNavMenu/FluentNavLink - Dashboard.razor: MudBlazor 모든 컴포넌트 → Fluent UI v5로 변환 - MudCard → FluentCard - MudGrid → FluentStack (Wrap) - MudText → HTML (h1, p, span) - MudChip → FluentBadge - MudTable → FluentDataGrid - MudAlert → div (커스텀 스타일) - Operations.razor: 동일 패턴 적용 - _Imports.razor: Fluent UI 네임스페이스 추가 **빌드 결과:** ✅ SUCCESS (0 errors, 5 warnings) **다음 단계:** Stage 2 - Python → .NET 마이그레이션 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,10 +6,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<base href="/quant/" />
|
||||
<ResourcePreloader />
|
||||
<!-- MudBlazor CSS -->
|
||||
<!-- Fluent UI CSS -->
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
|
||||
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="@Assets["lib/bootstrap/dist/css/bootstrap.min.css"]" />
|
||||
<link href="_content/Microsoft.FluentUI.AspNetCore.Components/css/fluent-components.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="@Assets["app.css"]" />
|
||||
<link rel="stylesheet" href="@Assets["QuantEngine.Web.styles.css"]" />
|
||||
<ImportMap />
|
||||
@@ -18,15 +17,13 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<MudThemeProvider />
|
||||
<MudDialogProvider />
|
||||
<MudSnackbarProvider />
|
||||
<FluentDesignSystemProvider>
|
||||
<Routes />
|
||||
<ReconnectModal />
|
||||
</FluentDesignSystemProvider>
|
||||
|
||||
<Routes />
|
||||
<ReconnectModal />
|
||||
|
||||
<!-- MudBlazor JS -->
|
||||
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
|
||||
<!-- Fluent UI JS -->
|
||||
<script src="_content/Microsoft.FluentUI.AspNetCore.Components/js/fluent-components.js"></script>
|
||||
<script src="@Assets["_framework/blazor.web.js"]"></script>
|
||||
</body>
|
||||
|
||||
|
||||
@@ -2,37 +2,42 @@
|
||||
@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment WebHostEnvironment
|
||||
@using System.IO
|
||||
@using System.Text.Json
|
||||
@using Microsoft.FluentUI.AspNetCore.Components
|
||||
|
||||
<MudLayout>
|
||||
<MudAppBar Elevation="1">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())" />
|
||||
<MudSpacer />
|
||||
<MudText Typo="Typo.h5" Class="ml-3">Quant Engine</MudText>
|
||||
<MudSpacer />
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Settings" Color="Color.Inherit" />
|
||||
</MudAppBar>
|
||||
<FluentStack Orientation="Orientation.Vertical" Class="h-100 w-100">
|
||||
<!-- Header -->
|
||||
<FluentHeader>
|
||||
<FluentStack Orientation="Orientation.Horizontal" VerticalAlignment="VerticalAlignment.Center"
|
||||
Style="width: 100%; padding: 8px 16px; gap: 16px;">
|
||||
<FluentButton OnClick="@(() => navOpen = !navOpen)"
|
||||
Title="Toggle Navigation"
|
||||
Style="background: transparent; border: none; cursor: pointer;">
|
||||
☰
|
||||
</FluentButton>
|
||||
<h1 style="margin: 0; font-size: 20px; font-weight: 600;">QuantEngine v@appVersion</h1>
|
||||
</FluentStack>
|
||||
</FluentHeader>
|
||||
|
||||
<MudDrawer @bind-Open="@drawerOpen" Elevation="1" Class="d-flex flex-column h-100">
|
||||
<MudDrawerHeader>
|
||||
<MudText Typo="Typo.h6">Menu</MudText>
|
||||
</MudDrawerHeader>
|
||||
|
||||
<NavMenu />
|
||||
|
||||
<MudSpacer />
|
||||
|
||||
<div class="px-4 py-3 mt-auto" style="border-top: 1px solid rgba(0,0,0,0.08); font-size: 11px; color: var(--mud-palette-text-secondary); line-height: 1.5; background-color: rgba(0,0,0,0.01);">
|
||||
<div style="font-weight: 500; margin-bottom: 2px;">QuantEngine v@appVersion</div>
|
||||
<div style="font-size: 10px; opacity: 0.85;">배포: @buildTime</div>
|
||||
</div>
|
||||
</MudDrawer>
|
||||
<!-- Main Content Area -->
|
||||
<FluentStack Orientation="Orientation.Horizontal" Class="flex-1" Style="overflow: hidden;">
|
||||
<!-- Navigation Sidebar -->
|
||||
@if (navOpen)
|
||||
{
|
||||
<nav style="width: 240px; background: var(--neutral-layer-1); border-right: 1px solid var(--neutral-stroke-1); padding: 12px; overflow-y: auto;">
|
||||
<NavMenu />
|
||||
<div style="margin-top: auto; padding-top: 12px; border-top: 1px solid var(--neutral-stroke-1); margin-top: 12px; font-size: 11px; color: var(--neutral-foreground-3); line-height: 1.5;">
|
||||
<div style="font-weight: 500; margin-bottom: 2px;">QuantEngine v@appVersion</div>
|
||||
<div style="font-size: 10px; opacity: 0.85;">배포: @buildTime</div>
|
||||
</div>
|
||||
</nav>
|
||||
}
|
||||
|
||||
<MudMainContent>
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="my-4">
|
||||
<!-- Page Content -->
|
||||
<FluentStack Orientation="Orientation.Vertical" Class="flex-1" Style="overflow-y: auto; padding: 24px;">
|
||||
@Body
|
||||
</MudContainer>
|
||||
</MudMainContent>
|
||||
</MudLayout>
|
||||
</FluentStack>
|
||||
</FluentStack>
|
||||
</FluentStack>
|
||||
|
||||
<div id="blazor-error-ui" data-nosnippet>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
@@ -41,16 +46,24 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.h-100 {
|
||||
height: 100%;
|
||||
}
|
||||
.w-100 {
|
||||
width: 100%;
|
||||
}
|
||||
.flex-1 {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
private bool drawerOpen = true;
|
||||
private bool navOpen = true;
|
||||
private string appVersion = "Local Debug";
|
||||
private string buildTime = "N/A";
|
||||
|
||||
private void DrawerToggle()
|
||||
{
|
||||
drawerOpen = !drawerOpen;
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
try
|
||||
@@ -61,7 +74,7 @@
|
||||
var jsonContent = File.ReadAllText(versionFilePath);
|
||||
using var doc = System.Text.Json.JsonDocument.Parse(jsonContent);
|
||||
var root = doc.RootElement;
|
||||
|
||||
|
||||
if (root.TryGetProperty("version", out var versionProp))
|
||||
{
|
||||
appVersion = versionProp.GetString() ?? "Local Debug";
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<MudNavMenu>
|
||||
<MudNavLink Href="/" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Dashboard">
|
||||
@using Microsoft.FluentUI.AspNetCore.Components
|
||||
|
||||
<FluentNavMenu>
|
||||
<FluentNavLink Href="/" Match="NavLinkMatch.All">
|
||||
Dashboard
|
||||
</MudNavLink>
|
||||
<MudNavLink Href="/operations" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Assessment">
|
||||
</FluentNavLink>
|
||||
<FluentNavLink Href="/operations" Match="NavLinkMatch.Prefix">
|
||||
Operations
|
||||
</MudNavLink>
|
||||
</MudNavMenu>
|
||||
</FluentNavLink>
|
||||
</FluentNavMenu>
|
||||
|
||||
@@ -4,117 +4,90 @@
|
||||
|
||||
<PageTitle>Quant Engine - Dashboard</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h4" Class="mb-2">Quant Engine</MudText>
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary" Class="mb-4">
|
||||
<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;">
|
||||
루트 화면은 운영 진입점입니다. 가짜 성과 수치 없이 현재 스냅샷 상태와 리포트 경로만 보여줍니다.
|
||||
</MudText>
|
||||
</p>
|
||||
|
||||
<MudGrid Class="mb-4">
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudCard Class="h-100">
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary">Operational Report</MudText>
|
||||
<MudText Typo="Typo.h6" Class="mt-2">@ReportStateLabel</MudText>
|
||||
<MudText Typo="Typo.caption">@ReportPath</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudCard Class="h-100">
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary">Sections</MudText>
|
||||
<MudText Typo="Typo.h6" Class="mt-2">@SectionCountLabel</MudText>
|
||||
<MudText Typo="Typo.caption">Temp/operational_report.json</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudCard Class="h-100">
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary">Primary Route</MudText>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" Href="/operations" Class="mt-2">
|
||||
Open Operations
|
||||
</MudButton>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
<!-- 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 Class="mb-4">
|
||||
<MudItem xs="12" md="7">
|
||||
<MudCard Class="h-100">
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.h6">Current State</MudText>
|
||||
</CardHeaderContent>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudStack Spacing="2">
|
||||
<MudText Typo="Typo.body2"><strong>Status:</strong> <MudChip Size="Size.Small" Color="@ReportChipColor">@ReportChipLabel</MudChip></MudText>
|
||||
<MudText Typo="Typo.body2"><strong>Generated:</strong> @GeneratedAtLabel</MudText>
|
||||
<MudText Typo="Typo.body2"><strong>Source:</strong> @SourceLabel</MudText>
|
||||
<MudText Typo="Typo.body2"><strong>Decision feed:</strong> @DecisionFeedLabel</MudText>
|
||||
<MudText Typo="Typo.body2"><strong>Factor feed:</strong> @FactorFeedLabel</MudText>
|
||||
<MudText Typo="Typo.body2"><strong>Raw feed:</strong> @RawFeedLabel</MudText>
|
||||
</MudStack>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
<!-- 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>
|
||||
|
||||
<MudItem xs="12" md="5">
|
||||
<MudCard Class="h-100">
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.h6">Routing Notes</MudText>
|
||||
</CardHeaderContent>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudStack Spacing="2">
|
||||
<MudText Typo="Typo.body2">- 운영 데이터는 snapshot 우선입니다.</MudText>
|
||||
<MudText Typo="Typo.body2">- Excel/GAS 의존 문구는 운영 경로에서 제거 대상입니다.</MudText>
|
||||
<MudText Typo="Typo.body2">- 숫자는 provenance 없으면 표시하지 않습니다.</MudText>
|
||||
</MudStack>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
<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;">
|
||||
<li>운영 데이터는 snapshot 우선입니다.</li>
|
||||
<li>Excel/GAS 의존 문구는 운영 경로에서 제거 대상입니다.</li>
|
||||
<li>숫자는 provenance 없으면 표시하지 않습니다.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</FluentCard>
|
||||
</FluentStack>
|
||||
|
||||
<MudCard>
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.h6">Coverage Summary</MudText>
|
||||
</CardHeaderContent>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<!-- 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)
|
||||
{
|
||||
<MudAlert Severity="Severity.Warning" Variant="Variant.Outlined">
|
||||
<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이 비어 있거나 아직 생성되지 않았습니다.
|
||||
</MudAlert>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudTable Items="Sections" Hover="true" Striped="true" Dense="true">
|
||||
<HeaderContent>
|
||||
<MudTh>Name</MudTh>
|
||||
<MudTh>Title</MudTh>
|
||||
<MudTh>Preview</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.Name</MudTd>
|
||||
<MudTd>@context.Title</MudTd>
|
||||
<MudTd>@context.Preview</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
<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>
|
||||
}
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</div>
|
||||
</FluentCard>
|
||||
|
||||
@code {
|
||||
private readonly List<OperationalReportSection> Sections = new();
|
||||
private string ReportStateLabel = "DATA_MISSING";
|
||||
private string ReportChipLabel = "DATA_MISSING";
|
||||
private Color ReportChipColor = Color.Warning;
|
||||
private string SectionCountLabel = "0";
|
||||
private string GeneratedAtLabel = "n/a";
|
||||
private string SourceLabel = "n/a";
|
||||
@@ -133,6 +106,5 @@
|
||||
SourceLabel = report.SourceJson;
|
||||
ReportStateLabel = Sections.Count > 0 ? "READY" : "DATA_MISSING";
|
||||
ReportChipLabel = Sections.Count > 0 ? "READY" : "DATA_MISSING";
|
||||
ReportChipColor = Sections.Count > 0 ? Color.Success : Color.Warning;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,106 +4,85 @@
|
||||
|
||||
<PageTitle>Quant Engine - Operations</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h4" Class="mb-2">Operational Report</MudText>
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary" Class="mb-4">
|
||||
<h1 style="margin: 0 0 8px 0; font-size: 28px; font-weight: 600;">Operational Report</h1>
|
||||
<p style="margin: 0 0 16px 0; color: var(--neutral-foreground-2); font-size: 14px;">
|
||||
이 페이지는 `Temp/operational_report.json`만 읽습니다. DB 연결과 무관하게 동일한 결과를 보여주는 운영 고정 화면입니다.
|
||||
</MudText>
|
||||
</p>
|
||||
|
||||
<MudGrid Class="mb-4">
|
||||
<MudItem xs="12" sm="6" md="3">
|
||||
<MudCard Class="h-100">
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary">Schema</MudText>
|
||||
<MudText Typo="Typo.h6" Class="mt-2">@SchemaVersion</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="3">
|
||||
<MudCard Class="h-100">
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary">Sections</MudText>
|
||||
<MudText Typo="Typo.h6" Class="mt-2">@SectionCountLabel</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="3">
|
||||
<MudCard Class="h-100">
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary">Source</MudText>
|
||||
<MudText Typo="Typo.h6" Class="mt-2">@SourceJson</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="3">
|
||||
<MudCard Class="h-100">
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary">Generated</MudText>
|
||||
<MudText Typo="Typo.h6" Class="mt-2">@GeneratedAt</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
<!-- Metadata Cards -->
|
||||
<FluentStack Orientation="Orientation.Horizontal" HorizontalGap="16" Wrap="true" Style="margin-bottom: 16px;">
|
||||
<FluentCard Style="flex: 1; min-width: 150px;">
|
||||
<div style="padding: 16px;">
|
||||
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Schema</p>
|
||||
<h3 style="margin: 0; font-size: 18px; font-weight: 600;">@SchemaVersion</h3>
|
||||
</div>
|
||||
</FluentCard>
|
||||
<FluentCard Style="flex: 1; min-width: 150px;">
|
||||
<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: 18px; font-weight: 600;">@SectionCountLabel</h3>
|
||||
</div>
|
||||
</FluentCard>
|
||||
<FluentCard Style="flex: 1; min-width: 150px;">
|
||||
<div style="padding: 16px;">
|
||||
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Source</p>
|
||||
<h3 style="margin: 0; font-size: 18px; font-weight: 600;">@SourceJson</h3>
|
||||
</div>
|
||||
</FluentCard>
|
||||
<FluentCard Style="flex: 1; min-width: 150px;">
|
||||
<div style="padding: 16px;">
|
||||
<p style="margin: 0 0 8px 0; color: var(--neutral-foreground-2); font-size: 12px; font-weight: 500;">Generated</p>
|
||||
<h3 style="margin: 0; font-size: 18px; font-weight: 600;">@GeneratedAt</h3>
|
||||
</div>
|
||||
</FluentCard>
|
||||
</FluentStack>
|
||||
|
||||
<MudGrid Class="mb-4">
|
||||
<!-- Highlight Sections Grid -->
|
||||
<FluentStack Orientation="Orientation.Horizontal" HorizontalGap="16" Wrap="true" Style="margin-bottom: 16px;">
|
||||
@foreach (var section in HighlightSections)
|
||||
{
|
||||
<MudItem xs="12" sm="6" lg="3">
|
||||
<MudCard Class="h-100">
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.body2" Color="Color.Secondary">@(section.Name)</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Class="mt-1">@(section.Title)</MudText>
|
||||
<MudText Typo="Typo.caption" Color="Color.Secondary">@(section.Preview)</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
<FluentCard Style="flex: 1; min-width: 200px;">
|
||||
<div style="padding: 16px;">
|
||||
<p style="margin: 0 0 4px 0; color: var(--neutral-foreground-2); font-size: 12px;">@(section.Name)</p>
|
||||
<h3 style="margin: 4px 0; font-size: 16px; font-weight: 600;">@(section.Title)</h3>
|
||||
<p style="margin: 8px 0 0 0; color: var(--neutral-foreground-3); font-size: 12px;">@(section.Preview)</p>
|
||||
</div>
|
||||
</FluentCard>
|
||||
}
|
||||
</MudGrid>
|
||||
</FluentStack>
|
||||
|
||||
<MudCard Class="mb-4">
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.h6">Report Health</MudText>
|
||||
</CardHeaderContent>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudStack Spacing="2">
|
||||
<MudText Typo="Typo.body2"><strong>Status:</strong> <MudChip Size="Size.Small" Color="@HealthColor">@HealthLabel</MudChip></MudText>
|
||||
<MudText Typo="Typo.body2"><strong>Path:</strong> @ReportPath</MudText>
|
||||
<MudText Typo="Typo.body2"><strong>Sections rendered:</strong> @RenderedSectionCountLabel</MudText>
|
||||
</MudStack>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
<!-- Report Health -->
|
||||
<FluentCard Style="margin-bottom: 16px;">
|
||||
<div style="padding: 16px;">
|
||||
<h3 style="margin: 0 0 12px 0; font-size: 16px; font-weight: 600;">Report Health</h3>
|
||||
<FluentStack Orientation="Orientation.Vertical" VerticalGap="8">
|
||||
<p style="margin: 0; font-size: 14px;"><strong>Status:</strong> <FluentBadge Appearance="BadgeAppearance.Filled">@HealthLabel</FluentBadge></p>
|
||||
<p style="margin: 0; font-size: 14px;"><strong>Path:</strong> @ReportPath</p>
|
||||
<p style="margin: 0; font-size: 14px;"><strong>Sections rendered:</strong> @RenderedSectionCountLabel</p>
|
||||
</FluentStack>
|
||||
</div>
|
||||
</FluentCard>
|
||||
|
||||
<MudCard>
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.h6">Sections</MudText>
|
||||
</CardHeaderContent>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<!-- Sections Table -->
|
||||
<FluentCard>
|
||||
<div style="padding: 16px;">
|
||||
<h3 style="margin: 0 0 12px 0; font-size: 16px; font-weight: 600;">Sections</h3>
|
||||
@if (Sections.Count == 0)
|
||||
{
|
||||
<MudAlert Severity="Severity.Warning" Variant="Variant.Outlined">
|
||||
<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에 표시할 섹션이 없습니다.
|
||||
</MudAlert>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudTable Items="Sections" Hover="true" Striped="true" Dense="true">
|
||||
<HeaderContent>
|
||||
<MudTh>Name</MudTh>
|
||||
<MudTh>Title</MudTh>
|
||||
<MudTh>Preview</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.Name</MudTd>
|
||||
<MudTd>@context.Title</MudTd>
|
||||
<MudTd>@context.Preview</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
<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>
|
||||
}
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</div>
|
||||
</FluentCard>
|
||||
|
||||
@code {
|
||||
private readonly List<OperationalReportSection> Sections = new();
|
||||
@@ -114,7 +93,6 @@
|
||||
private string SectionCountLabel = "0";
|
||||
private string RenderedSectionCountLabel = "0";
|
||||
private string HealthLabel = "DATA_MISSING";
|
||||
private Color HealthColor = Color.Warning;
|
||||
private string ReportPath = "n/a";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
@@ -133,6 +111,5 @@
|
||||
SectionCountLabel = report.SectionCount.ToString();
|
||||
RenderedSectionCountLabel = Sections.Count.ToString();
|
||||
HealthLabel = Sections.Count > 0 ? "PASS" : "DATA_MISSING";
|
||||
HealthColor = Sections.Count > 0 ? Color.Success : Color.Warning;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop
|
||||
@using MudBlazor
|
||||
@using Microsoft.FluentUI.AspNetCore.Components
|
||||
@using Microsoft.FluentUI.AspNetCore.Components.Icons
|
||||
@using QuantEngine.Web
|
||||
@using QuantEngine.Web.Components
|
||||
@using QuantEngine.Web.Components.Layout
|
||||
|
||||
Reference in New Issue
Block a user