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
This commit is contained in:
@@ -0,0 +1,256 @@
|
||||
@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">‹ 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…</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> · 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; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user