M5: Blazor dashboard (MudBlazor + ApexCharts)
- MudBlazor theme (dark default) + responsive drawer/appbar layout + nav. - DashboardService read model: KPIs with period-over-period deltas, category breakdown, "what cost more/less" difference view, monthly trends. - Pages: Overview (KPI cards + DeltaChip + donut + difference table), Trends (range-select bar chart), Meters (list + source status), Import (load reference dataset + CSV dry-run preview), Admin (energy types, tariffs). Charts isolated into components to avoid the ApexCharts/MudBlazor Color/Format name clashes. - ReferenceDataImporter: one-click load of all four sheets as a starter dataset (meters, tank, tariff history, category memberships) — bundled sample CSVs copied to app output. - End-to-end render test: import creates meters + consumption; overview/meters/trends/ import/admin pages all return 200 with KPI cards rendered. 92 tests green (56 Core + 36 integration). Deferred to polish: dedicated PV & oil/consumable panels, meter-detail page, full admin CRUD, prev-year trend overlay. Claude-Session: https://claude.ai/code/session_01WujdMtMJPbxDpDnMeK22rr
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
@page "/admin/energy-types"
|
||||
@rendermode InteractiveServer
|
||||
@inject MeterVault.Infrastructure.Persistence.MeterVaultDbContext Db
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
|
||||
<PageTitle>MeterVault — Energy types</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h4" Class="mb-4">Energy types</MudText>
|
||||
|
||||
@if (_types is null)
|
||||
{
|
||||
<MudProgressLinear Indeterminate="true" Color="Color.Primary" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudTable Items="_types" Dense="true" Hover="true" Elevation="2">
|
||||
<HeaderContent>
|
||||
<MudTh>Key</MudTh>
|
||||
<MudTh>Display name</MudTh>
|
||||
<MudTh>Base unit</MudTh>
|
||||
<MudTh>Default mode</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd DataLabel="Key">@context.Key</MudTd>
|
||||
<MudTd DataLabel="Display name">@context.DisplayName</MudTd>
|
||||
<MudTd DataLabel="Base unit">@context.BaseUnit</MudTd>
|
||||
<MudTd DataLabel="Default mode">@context.DefaultMode</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<EnergyType>? _types;
|
||||
|
||||
protected override async Task OnInitializedAsync() =>
|
||||
_types = await Db.EnergyTypes.AsNoTracking().OrderBy(t => t.Id).ToListAsync();
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
@page "/admin/tariffs"
|
||||
@rendermode InteractiveServer
|
||||
@inject MeterVault.Infrastructure.Persistence.MeterVaultDbContext Db
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
|
||||
<PageTitle>MeterVault — Tariffs</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h4" Class="mb-4">Tariffs</MudText>
|
||||
|
||||
@if (_tariffs is null)
|
||||
{
|
||||
<MudProgressLinear Indeterminate="true" Color="Color.Primary" />
|
||||
}
|
||||
else if (_tariffs.Count == 0)
|
||||
{
|
||||
<MudAlert Severity="Severity.Info">No tariffs yet. Load the reference data from <MudLink Href="/import">Import</MudLink>.</MudAlert>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudTable Items="_tariffs" Dense="true" Hover="true" Elevation="2">
|
||||
<HeaderContent>
|
||||
<MudTh>Scope</MudTh>
|
||||
<MudTh>Component</MudTh>
|
||||
<MudTh>Value</MudTh>
|
||||
<MudTh>Unit</MudTh>
|
||||
<MudTh>Valid from</MudTh>
|
||||
<MudTh>Valid to</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd DataLabel="Scope">@context.ScopeType @(context.ScopeId is { } id ? $"#{id}" : "")</MudTd>
|
||||
<MudTd DataLabel="Component">@context.Component</MudTd>
|
||||
<MudTd DataLabel="Value">@Format.Number(context.Value, 4)</MudTd>
|
||||
<MudTd DataLabel="Unit">@context.Unit</MudTd>
|
||||
<MudTd DataLabel="Valid from">@context.ValidFrom.ToString("yyyy-MM-dd")</MudTd>
|
||||
<MudTd DataLabel="Valid to">@(context.ValidTo?.ToString("yyyy-MM-dd") ?? "open")</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<Tariff>? _tariffs;
|
||||
|
||||
protected override async Task OnInitializedAsync() =>
|
||||
_tariffs = await Db.Tariffs.AsNoTracking()
|
||||
.OrderBy(t => t.Component).ThenBy(t => t.ValidFrom)
|
||||
.ToListAsync();
|
||||
}
|
||||
Reference in New Issue
Block a user