Files
MijnBesluit/src/MijnBesluit.Web/Components/Pages/BeheerVersiehistorie.razor
T
jfandClaude Sonnet 5.5 5446dd4170 Versiehistorie in een tabel, voor site en app
De versiehistorie stond als tekst in zowel de app als de website. Nu staat hij in
tabel version_history, met een beheerpagina (Beheer > Versiehistorie) op de site.
De site leest de tabel rechtstreeks, de app via de nieuwe actie app.versiehistorie.
Startrijen: db/handmatig/22b_versiehistorie_startrijen.sql (als root).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014MGLqt1uKfNARQHut9ifcx
2026-10-20 11:47:06 +00:00

257 lines
9.6 KiB
Plaintext

@page "/beheer/versiehistorie"
@attribute [Authorize]
@inject BeheerService Beheerkant
@inject VersiehistorieService Historie
@rendermode InteractiveServer
<PageTitle>Versiehistorie - Beheer</PageTitle>
@* Het beheerscherm voor de versiehistorie: de lijst "wat is er nieuw" die op de website en in de
app onder "Versiehistorie" staat. Eén tabel voor beide, dus hier een regel toevoegen is genoeg.
Een regel is: een datum, eventueel een appversie, een vet kopje en een tekst. Gewone tekst,
geen opmaak. Wat erin hoort: nieuwe of wezenlijk gewijzigde functies; geen bugfixes.
Een regel verbergen haalt hem weg bij de lezers zonder hem kwijt te raken. Wie de app al
heeft van vóór deze tabel (versiecode 3 of ouder) ziet de tekst die in die app is ingebakken.
Zie docs/Versiehistorie.md. *@
@if (!Magdit)
{
<h1>Niet gevonden</h1>
<p class="zacht">Deze pagina bestaat niet, of hij is niet voor jou.</p>
}
else
{
<h1>Versiehistorie</h1>
<p class="zacht">
Wat er nieuw is, nieuwste bovenaan. Een nieuwe regel staat meteen op de website en in de app,
zonder dat er een nieuwe versie van de app nodig is.
</p>
<p><a href="/beheer">&lsaquo; Terug naar beheer</a></p>
@if (Melding is not null) { <div class="melding @MeldingSoort">@Melding</div> }
@* ------------------------------------------------------------ nieuwe of bestaande regel *@
<div class="kaart">
<h2 style="margin-top:0">@(BewerkId is null ? "Nieuwe regel" : "Regel wijzigen")</h2>
<div class="raster twee">
<div class="veld">
<label for="vh-datum">Datum</label>
<input id="vh-datum" type="date" @bind="Formulier.Datum" />
</div>
<div class="veld">
<label for="vh-versie">Versie (mag leeg)</label>
<input id="vh-versie" type="text" maxlength="20" @bind="Formulier.Versie" @bind:event="oninput"
placeholder="Bijvoorbeeld: 1.2" />
<div class="uitleg">Alleen invullen als dit bij een uitgebrachte versie van de app hoort.</div>
</div>
</div>
<div class="veld">
<label for="vh-kop">Vet kopje</label>
<input id="vh-kop" type="text" maxlength="@VersiehistorieService.MaxKop" @bind="Formulier.Kop" @bind:event="oninput"
placeholder="Bijvoorbeeld: Meer soorten in de kluis." />
</div>
<div class="veld">
<label for="vh-tekst">Tekst</label>
<textarea id="vh-tekst" rows="4" maxlength="@VersiehistorieService.MaxTekst" @bind="Formulier.Tekst" @bind:event="oninput"></textarea>
<div class="uitleg">@Formulier.Tekst.Length van @VersiehistorieService.MaxTekst tekens. Gewone tekst, geen opmaak.</div>
</div>
<div class="keuze">
<input type="checkbox" id="vh-zichtbaar" @bind="Formulier.Zichtbaar" />
<label for="vh-zichtbaar">Zichtbaar voor iedereen</label>
</div>
<div class="rij" style="margin-top:.8rem">
<button class="knop" disabled="@Bezig" @onclick="Opslaan">@(BewerkId is null ? "Regel toevoegen" : "Wijzigingen opslaan")</button>
@if (BewerkId is not null)
{
<button class="knop rustig" disabled="@Bezig" @onclick="Annuleren">Annuleren</button>
}
</div>
</div>
@* ------------------------------------------------------------ de lijst *@
@if (Lijst is null)
{
<p class="zacht">Bezig met laden&hellip;</p>
}
else if (Lijst.Count == 0)
{
<p class="zacht">Er staat nog niets in de versiehistorie.</p>
}
else
{
<div class="stapel">
@foreach (var r in Lijst)
{
<div class="kaart">
<div class="rij">
<div class="groei">
<div class="zacht">
@Datums.Datum(r.Datum)
@if (!string.IsNullOrWhiteSpace(r.Versie)) { <text> &middot; versie @r.Versie</text> }
</div>
<div class="groot">@r.Kop</div>
<div>@r.Tekst</div>
@if (!r.Zichtbaar)
{
<div style="margin-top:.35rem"><span class="label uitgenodigd">Verborgen</span></div>
}
</div>
</div>
<div class="rij" style="margin-top:.6rem">
<button class="knop rustig" disabled="@Bezig" @onclick="() => Wijzigen(r)">Wijzigen</button>
<button class="knop rustig" disabled="@Bezig" @onclick="() => ZichtbaarOmzetten(r)">
@(r.Zichtbaar ? "Verbergen" : "Tonen")
</button>
@if (Weghalen == r.Id)
{
<span class="zacht">Echt verwijderen?</span>
<button class="knop gevaar" disabled="@Bezig" @onclick="() => Verwijderen(r)">Ja, verwijderen</button>
<button class="knop rustig" disabled="@Bezig" @onclick="() => Weghalen = null">Nee</button>
}
else
{
<button class="knop gevaar" disabled="@Bezig" @onclick="() => Weghalen = r.Id">Verwijderen</button>
}
</div>
</div>
}
</div>
}
}
@code {
[CascadingParameter] private Task<AuthenticationState>? AuthState { get; set; }
private long _gebruikerId;
private bool Magdit, Bezig;
private string? Melding, MeldingSoort;
private IReadOnlyList<VersieRegelBeheerbeeld>? Lijst;
private int? BewerkId;
private int? Weghalen;
private RegelFormulier Formulier = NieuwFormulier();
private sealed class RegelFormulier
{
public DateOnly Datum { get; set; }
public string Versie { get; set; } = "";
public string Kop { get; set; } = "";
public string Tekst { get; set; } = "";
public bool Zichtbaar { get; set; } = true;
}
private static RegelFormulier NieuwFormulier() =>
new() { Datum = DateOnly.FromDateTime(DateTime.Today) };
protected override async Task OnInitializedAsync()
{
if (AuthState is null) return;
_gebruikerId = (await AuthState).User.UserId() ?? 0;
Magdit = await Beheerkant.IsBeheerderAsync(_gebruikerId);
if (!Magdit) return;
await Laden();
}
private async Task Laden()
{
var resultaat = await Historie.OverzichtAsync(_gebruikerId);
if (resultaat.Succeeded) Lijst = resultaat.Value;
else Meld(resultaat.Error, false);
}
private void Meld(string? tekst, bool goed)
{
Melding = tekst;
MeldingSoort = goed ? "goed" : "fout";
}
private void Wijzigen(VersieRegelBeheerbeeld r)
{
BewerkId = r.Id;
Weghalen = null;
Melding = null;
Formulier = new RegelFormulier
{
Datum = r.Datum, Versie = r.Versie ?? "", Kop = r.Kop, Tekst = r.Tekst, Zichtbaar = r.Zichtbaar
};
}
private void Annuleren()
{
BewerkId = null;
Formulier = NieuwFormulier();
}
private async Task Opslaan()
{
Bezig = true;
try
{
var versie = string.IsNullOrWhiteSpace(Formulier.Versie) ? null : Formulier.Versie.Trim();
bool gelukt;
string? fout;
if (BewerkId is null)
{
var gemaakt = await Historie.MaakAsync(_gebruikerId, Formulier.Datum, versie, Formulier.Kop,
Formulier.Tekst, Formulier.Zichtbaar);
gelukt = gemaakt.Succeeded;
fout = gemaakt.Error;
}
else
{
var gewijzigd = await Historie.WijzigAsync(_gebruikerId, BewerkId.Value, Formulier.Datum, versie,
Formulier.Kop, Formulier.Tekst, Formulier.Zichtbaar);
gelukt = gewijzigd.Succeeded;
fout = gewijzigd.Error;
}
if (gelukt)
{
Meld(BewerkId is null ? "De regel is toegevoegd." : "De wijziging is opgeslagen.", true);
BewerkId = null;
Formulier = NieuwFormulier();
await Laden();
}
else Meld(fout, false);
}
finally { Bezig = false; }
}
private async Task ZichtbaarOmzetten(VersieRegelBeheerbeeld r)
{
Bezig = true;
try
{
var resultaat = await Historie.WijzigAsync(_gebruikerId, r.Id, r.Datum, r.Versie, r.Kop, r.Tekst, !r.Zichtbaar);
if (resultaat.Succeeded)
{
Meld(r.Zichtbaar ? "De regel is verborgen." : "De regel is weer zichtbaar.", true);
await Laden();
}
else Meld(resultaat.Error, false);
}
finally { Bezig = false; }
}
private async Task Verwijderen(VersieRegelBeheerbeeld r)
{
Bezig = true;
try
{
var resultaat = await Historie.VerwijderAsync(_gebruikerId, r.Id);
if (resultaat.Succeeded)
{
Meld("De regel is verwijderd.", true);
Weghalen = null;
if (BewerkId == r.Id) Annuleren();
await Laden();
}
else Meld(resultaat.Error, false);
}
finally { Bezig = false; }
}
}