Files
MeterVault/src/App/Components/Pages/Admin/Settings.razor
T
schmidt.florian 85d650a8f5
ci / build-test (push) Successful in 1m12s
Fix: enable global interactivity so dialogs/selects actually work
Editing a meter (any admin dialog, select dropdown, snackbar, dark-mode toggle)
did nothing: pages declared @rendermode InteractiveServer individually, but
MainLayout — which hosts MudDialogProvider/MudPopoverProvider/MudSnackbarProvider
— was rendered by <Routes>, which was static. Inline MudDialogs and MudSelect
popovers render through those providers, so with the providers non-interactive no
dialog could ever open.

Set the render mode on <Routes> and <HeadOutlet> in App.razor (global
interactivity) and removed the now-redundant per-page @rendermode declarations
(they would otherwise throw "parent already has a render mode").

Why it slipped through: the integration render tests only issue a GET (static
prerender), which never exercises the SignalR circuit. Verified this fix with a
real headless-browser run (Playwright): the meter edit dialog opens and the
"Sub-meter of (upstream meters)" multi-select opens with options — proving the
layout providers are now interactive. 116 tests still green.

Claude-Session: https://claude.ai/code/session_01Lz2RqAsnQhetqWNoCDfexK
2026-07-14 14:22:15 +02:00

73 lines
3.7 KiB
Plaintext

@page "/admin/settings"
@inject Microsoft.Extensions.Options.IOptions<MeterVault.Infrastructure.Options.MeterVaultOptions> Options
@using MudBlazor
<PageTitle>MeterVault — Settings</PageTitle>
<MudText Typo="Typo.h4" Class="mb-2">Settings</MudText>
<MudAlert Severity="Severity.Info" Class="mb-4" Dense="true">
These are the <b>effective</b> settings the running instance is using. They are configured via environment
variables (<code>MeterVault__Key</code> / <code>Section__Key</code>) or Docker/compose, not stored in the
database — so config stays reproducible and secrets never land in the DB. Change them in your compose/env and restart.
</MudAlert>
<MudGrid>
<MudItem xs="12" md="6">
<MudPaper Class="pa-4" Elevation="2" Style="height:100%">
<MudText Typo="Typo.h6" Class="mb-2">Locale &amp; time</MudText>
<MudSimpleTable Dense="true">
<tbody>
<tr><td>Timezone</td><td style="text-align:right"><code>@_o.TimeZone</code></td></tr>
<tr><td>Locale</td><td style="text-align:right"><code>@_o.Locale</code></td></tr>
<tr><td>Currency</td><td style="text-align:right"><code>@_o.Currency</code></td></tr>
<tr><td>Raw-reading retention</td><td style="text-align:right">@_o.RawRetentionDays days</td></tr>
</tbody>
</MudSimpleTable>
<MudText Typo="Typo.caption" Color="Color.Secondary" Class="mt-2">
Env keys: <code>MeterVault__TimeZone</code>, <code>MeterVault__Locale</code>,
<code>MeterVault__Currency</code>, <code>MeterVault__RawRetentionDays</code>.
</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" md="6">
<MudPaper Class="pa-4" Elevation="2" Style="height:100%">
<MudText Typo="Typo.h6" Class="mb-2">Access &amp; ingestion</MudText>
<MudSimpleTable Dense="true">
<tbody>
<tr>
<td>REST API</td>
<td style="text-align:right">
@if (_o.ApiKeys.Count > 0)
{
<MudChip T="string" Size="Size.Small" Color="Color.Success">@_o.ApiKeys.Count key(s) configured</MudChip>
}
else if (_o.AllowAnonymousApi)
{
<MudChip T="string" Size="Size.Small" Color="Color.Warning">open (anonymous)</MudChip>
}
else
{
<MudChip T="string" Size="Size.Small" Color="Color.Default">closed (401)</MudChip>
}
</td>
</tr>
<tr><td>Reverse-proxy trust</td><td style="text-align:right">@(_o.ReverseProxyTrust ? "on" : "off")</td></tr>
<tr><td>Live ingestion workers</td><td style="text-align:right">@(_o.EnableLiveIngestion ? "on" : "off")</td></tr>
<tr><td>Seed reference data on start</td><td style="text-align:right">@(_o.SeedReferenceData ? "on" : "off")</td></tr>
</tbody>
</MudSimpleTable>
<MudText Typo="Typo.caption" Color="Color.Secondary" Class="mt-2">
Set API keys with <code>MeterVault__ApiKeys__0</code>. Keys themselves are never shown here.
API docs at <MudLink Href="/swagger" Target="_blank">/swagger</MudLink>.
</MudText>
</MudPaper>
</MudItem>
</MudGrid>
@code {
private MeterVault.Infrastructure.Options.MeterVaultOptions _o = new();
protected override void OnInitialized() => _o = Options.Value;
}