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:
@@ -1,61 +1,90 @@
|
||||
@* De versiehistorie: nieuwe of wezenlijk gewijzigde functies, nieuwste bovenaan.
|
||||
@* De versiehistorie: nieuwe of wezenlijk gewijzigde functies, nieuwste bovenaan.
|
||||
|
||||
Zelfde opzet als Productuitleg.razor en Privacytekst.razor: op de website een popup vanaf
|
||||
het overzicht, in de app hetzelfde. Dit bestand staat twee keer op schijf - de app en de site
|
||||
delen geen project - en een zelfcontrole vergelijkt ze letterlijk.
|
||||
De regels staan in een tabel op de server (version_history) en worden beheerd op de website
|
||||
onder Beheer > Versiehistorie. Site en app lezen dezelfde tabel; dit bestand bevat zelf geen
|
||||
tekst meer, dus een nieuwe regel vraagt geen nieuwe versie van de app. Zie docs/Versiehistorie.md.
|
||||
|
||||
Wat hier NIET in hoort: bugfixes, tekstuele correcties, opmaak die is rechtgezet. Dit is voor
|
||||
Wat daar NIET in hoort: bugfixes, tekstuele correcties, opmaak die is rechtgezet. Dit is voor
|
||||
"wat kan ik nu wat ik eerst niet kon", niet een logboek van elke wijziging in de code. *@
|
||||
@inject AppToestand Toestand
|
||||
|
||||
<p class="zacht" style="margin-top:0">
|
||||
Nieuwe of wezenlijk gewijzigde functies, nieuwste bovenaan.
|
||||
</p>
|
||||
|
||||
<h2 style="margin-top:0">20 oktober 2026 · versie 1.1</h2>
|
||||
<ul style="padding-left:1.2rem">
|
||||
<li>
|
||||
<strong>Meer soorten in de kluis.</strong> Naast wachtwoorden, polissen en uitvaartwensen
|
||||
kan er voortaan een nieuwe soort bijkomen, met eigen invulvelden, zonder dat je de app
|
||||
daarvoor opnieuw hoeft te updaten. Je bestaande kluisitems blijven zoals ze waren.
|
||||
</li>
|
||||
</ul>
|
||||
@if (Fout)
|
||||
{
|
||||
<p class="zacht">De versiehistorie kon niet worden opgehaald. Probeer het later nog eens.</p>
|
||||
}
|
||||
else if (Regels is null)
|
||||
{
|
||||
<p class="zacht">Bezig met laden…</p>
|
||||
}
|
||||
else if (Regels.Count == 0)
|
||||
{
|
||||
<p class="zacht">Er staat nog niets in de versiehistorie.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
@foreach (var groep in Groepen())
|
||||
{
|
||||
<h2 style="@(groep.Eerste ? "margin-top:0" : null)">@groep.Kop</h2>
|
||||
<ul style="padding-left:1.2rem">
|
||||
@foreach (var regel in groep.Regels)
|
||||
{
|
||||
<li style="margin-bottom:.5rem"><strong>@Punt(regel.Kop)</strong> @regel.Tekst</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
}
|
||||
|
||||
<h2>20 september 2026</h2>
|
||||
<ul style="padding-left:1.2rem">
|
||||
<li style="margin-bottom:.5rem">
|
||||
<strong>Rijbewijs en paspoort in de kluis.</strong> Twee nieuwe categorieën, met een
|
||||
knop om meteen de voor- en achterkant (rijbewijs) of de foto-pagina (paspoort) te maken
|
||||
of te kiezen.
|
||||
</li>
|
||||
<li style="margin-bottom:.5rem">
|
||||
<strong>Mijn profiel als pop-up.</strong> Je eigen profiel bewerk je nu in dezelfde
|
||||
pop-up met vaste "Opslaan"-knop onderin als bij de andere mensen in je familie, in de
|
||||
app en op de website.
|
||||
</li>
|
||||
<li style="margin-bottom:.5rem">
|
||||
<strong>Duidelijker voor de nalatenschapsbeheerder.</strong> Bij "Aan mij toevertrouwd"
|
||||
zie je nu meteen hoeveel meldingen er nodig zijn en hoe lang de bezwaartermijn is.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Muziek en verdere wensen groeien mee.</strong> Die velden bij een kluisitem
|
||||
passen zich nu vanzelf aan de lengte van de tekst aan, ook op de website.
|
||||
</li>
|
||||
</ul>
|
||||
@code {
|
||||
private IReadOnlyList<VersieRegel>? Regels;
|
||||
private bool Fout;
|
||||
|
||||
<h2>19 september 2026</h2>
|
||||
<ul style="padding-left:1.2rem">
|
||||
<li style="margin-bottom:.5rem">
|
||||
<strong>Met mij gedeeld, ook in de app.</strong> Heeft iemand een kluisitem rechtstreeks
|
||||
met jou gedeeld om het vast te bespreken - bijvoorbeeld een uitvaartwens - dan zie je
|
||||
dat voortaan ook op je telefoon, niet meer alleen op de website.
|
||||
</li>
|
||||
<li style="margin-bottom:.5rem">
|
||||
<strong>Een gedeeld of nagelaten kluisitem bekijken.</strong> Dat opent nu als pop-up in
|
||||
dezelfde opmaak als het invulformulier, inclusief de foto's en documenten die erbij
|
||||
horen.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Met de vinger naar beneden trekken ververst het scherm.</strong> Werkt op Kluis,
|
||||
Mijn mensen, Momenten en Nalatenschap.
|
||||
</li>
|
||||
</ul>
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var uitkomst = await Toestand.Client.VersiehistorieAsync();
|
||||
if (uitkomst.Gelukt) Regels = uitkomst.Waarde;
|
||||
else Fout = true;
|
||||
}
|
||||
|
||||
private sealed record Groep(string Kop, bool Eerste, List<VersieRegel> Regels);
|
||||
|
||||
/// <summary>
|
||||
/// Opeenvolgende regels met dezelfde dag (en dezelfde versie) vormen samen één kop. De volgorde
|
||||
/// komt van de server: nieuwste dag bovenaan, binnen een dag in de volgorde van invoer.
|
||||
/// </summary>
|
||||
private IEnumerable<Groep> Groepen()
|
||||
{
|
||||
var uit = new List<Groep>();
|
||||
string? vorige = null;
|
||||
foreach (var r in Regels!)
|
||||
{
|
||||
var kop = Koptekst(r);
|
||||
if (kop != vorige)
|
||||
{
|
||||
uit.Add(new Groep(kop, uit.Count == 0, new List<VersieRegel>()));
|
||||
vorige = kop;
|
||||
}
|
||||
uit[^1].Regels.Add(r);
|
||||
}
|
||||
return uit;
|
||||
}
|
||||
|
||||
private static string Koptekst(VersieRegel r)
|
||||
{
|
||||
var dag = DateOnly.TryParseExact(r.Datum, "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture,
|
||||
System.Globalization.DateTimeStyles.None, out var d)
|
||||
? $"{d.Day} {Datums.Maanden[d.Month - 1]} {d.Year}"
|
||||
: r.Datum;
|
||||
return string.IsNullOrWhiteSpace(r.Versie) ? dag : $"{dag} \u00b7 versie {r.Versie}";
|
||||
}
|
||||
|
||||
/// <summary>De kop eindigt op een punt, zodat de tekst erachter als gewone zin leest.</summary>
|
||||
private static string Punt(string kop)
|
||||
{
|
||||
var k = kop.Trim();
|
||||
return k.Length == 0 || ".!?".Contains(k[^1]) ? k : k + ".";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,8 +174,7 @@
|
||||
</Popup>
|
||||
}
|
||||
|
||||
@* Zelfde tekst als op de website - Versiehistorie.razor staat twee keer op schijf en een
|
||||
zelfcontrole vergelijkt ze letterlijk. *@
|
||||
@* De tekst komt van de server (tabel version_history), net als op de website. *@
|
||||
@if (VersiehistorieOpen)
|
||||
{
|
||||
<Popup Titel="Versiehistorie" Bevestigtekst="Sluiten" AlleenSluiten="true"
|
||||
|
||||
@@ -287,6 +287,21 @@ public interface IVaultCategoryRepository
|
||||
void Remove(VaultCategoryField veld);
|
||||
}
|
||||
|
||||
/// <summary>De versiehistorie: één tabel voor site en app. Zie docs/Versiehistorie.md.</summary>
|
||||
public interface IVersiehistorieRepository
|
||||
{
|
||||
/// <summary>Nieuwste dag bovenaan; binnen één dag in de volgorde van invoer.</summary>
|
||||
Task<IReadOnlyList<VersieRegel>> ListAsync(bool alleenZichtbaar, CancellationToken ct = default);
|
||||
|
||||
Task<VersieRegel?> FindAsync(int id, CancellationToken ct = default);
|
||||
|
||||
/// <summary>Is er al een regel met dezelfde datum en kop (behalve de regel met dit nummer)?</summary>
|
||||
Task<bool> BestaatAsync(DateOnly datum, string kop, int? behalveId, CancellationToken ct = default);
|
||||
|
||||
void Add(VersieRegel regel);
|
||||
void Remove(VersieRegel regel);
|
||||
}
|
||||
|
||||
/// <summary>Versturen van uitnodigingen en meldingen.</summary>
|
||||
/// <summary>
|
||||
/// Adverteerders, hun campagnes en de tellers per uur. Zie docs/Adverteren.md.
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace MijnBesluit.Application.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Een regel van de versiehistorie zoals een gebruiker die ziet. Dit is ook wat er over de lijn
|
||||
/// naar de app gaat; de datum is als tekst (jjjj-mm-dd) om tijdzones buiten de deur te houden:
|
||||
/// 20 oktober is 20 oktober, waar je ook bent.
|
||||
/// </summary>
|
||||
public record VersieRegelWeergave(string Datum, string? Versie, string Kop, string Tekst);
|
||||
|
||||
/// <summary>Een regel in het beheerscherm, ook als hij verborgen is.</summary>
|
||||
public record VersieRegelBeheerbeeld(int Id, DateOnly Datum, string? Versie, string Kop, string Tekst, bool Zichtbaar);
|
||||
@@ -0,0 +1,157 @@
|
||||
using System.Globalization;
|
||||
using MijnBesluit.Application.Abstractions;
|
||||
using MijnBesluit.Application.Models;
|
||||
using MijnBesluit.Domain.Entities;
|
||||
using MijnBesluit.Domain.Enums;
|
||||
|
||||
namespace MijnBesluit.Application.Services;
|
||||
|
||||
/// <summary>
|
||||
/// De versiehistorie: wat er nieuw is in MijnBesluit, voor wie dat wil lezen. De lijst staat in de
|
||||
/// database en wordt door de beheerder onderhouden, zodat de website en de app dezelfde bron
|
||||
/// hebben en een nieuwe regel meteen overal staat - ook in een app die al in de winkel staat.
|
||||
///
|
||||
/// Twee regels:
|
||||
///
|
||||
/// 1. Alleen een beheerder maakt, wijzigt of verwijdert. Een gebruiker kan alleen lezen, en ziet
|
||||
/// dan alleen de regels die zichtbaar zijn.
|
||||
/// 2. Platte tekst. Wat hier staat wordt door de schermen als tekst getoond, nooit als opmaak;
|
||||
/// zo kan een typefout of een geplakte tekst het scherm niet stukmaken.
|
||||
/// </summary>
|
||||
public class VersiehistorieService
|
||||
{
|
||||
public const int MaxKop = 120;
|
||||
public const int MaxTekst = 1000;
|
||||
public const int MaxVersie = 20;
|
||||
|
||||
private readonly IVersiehistorieRepository _regels;
|
||||
private readonly IUserRepository _users;
|
||||
private readonly IAuditLog _audit;
|
||||
private readonly IUnitOfWork _uow;
|
||||
private readonly IClock _clock;
|
||||
|
||||
public VersiehistorieService(IVersiehistorieRepository regels, IUserRepository users, IAuditLog audit,
|
||||
IUnitOfWork uow, IClock clock)
|
||||
{
|
||||
_regels = regels; _users = users; _audit = audit; _uow = uow; _clock = clock;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ voor gebruikers
|
||||
|
||||
/// <summary>
|
||||
/// De zichtbare regels, de nieuwste dag bovenaan. Binnen een dag staan ze in de volgorde waarin
|
||||
/// ze zijn ingevoerd.
|
||||
/// </summary>
|
||||
public async Task<IReadOnlyList<VersieRegelWeergave>> ZichtbaarAsync(CancellationToken ct = default) =>
|
||||
(await _regels.ListAsync(alleenZichtbaar: true, ct))
|
||||
.Select(r => new VersieRegelWeergave(Dag(r.Datum), r.Versie, r.Kop, r.Tekst))
|
||||
.ToList();
|
||||
|
||||
// ------------------------------------------------------------------ voor de beheerder
|
||||
|
||||
/// <summary>Alle regels, ook de verborgen. Alleen voor beheerders.</summary>
|
||||
public async Task<Result<IReadOnlyList<VersieRegelBeheerbeeld>>> OverzichtAsync(long currentUserId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
if (!await IsBeheerderAsync(currentUserId, ct))
|
||||
return Result<IReadOnlyList<VersieRegelBeheerbeeld>>.Fail("Je bent geen beheerder.");
|
||||
|
||||
var lijst = (await _regels.ListAsync(alleenZichtbaar: false, ct))
|
||||
.Select(r => new VersieRegelBeheerbeeld(r.Id, r.Datum, r.Versie, r.Kop, r.Tekst, r.Zichtbaar))
|
||||
.ToList();
|
||||
return Result<IReadOnlyList<VersieRegelBeheerbeeld>>.Ok(lijst);
|
||||
}
|
||||
|
||||
/// <summary>Voegt een regel toe. Hij is meteen zichtbaar tenzij je hem verbergt.</summary>
|
||||
public async Task<Result<int>> MaakAsync(long currentUserId, DateOnly datum, string? versie, string kop,
|
||||
string tekst, bool zichtbaar = true, CancellationToken ct = default)
|
||||
{
|
||||
if (!await IsBeheerderAsync(currentUserId, ct)) return Result<int>.Fail("Je bent geen beheerder.");
|
||||
|
||||
var fout = await ControleerAsync(null, datum, versie, kop, tekst, ct);
|
||||
if (fout is not null) return Result<int>.Fail(fout);
|
||||
|
||||
var nu = _clock.UtcNow;
|
||||
var regel = new VersieRegel
|
||||
{
|
||||
Datum = datum, Versie = SchoneVersie(versie), Kop = kop.Trim(), Tekst = tekst.Trim(),
|
||||
Zichtbaar = zichtbaar, AangemaaktOp = nu, GewijzigdOp = nu
|
||||
};
|
||||
|
||||
_regels.Add(regel);
|
||||
await _uow.SaveChangesAsync(ct);
|
||||
await _audit.WriteAsync(AuditAction.VersiehistorieBeheerd, currentUserId, nameof(VersieRegel), regel.Id,
|
||||
$"gemaakt: {Dag(datum)} {regel.Kop}", ct);
|
||||
await _uow.SaveChangesAsync(ct);
|
||||
return Result<int>.Ok(regel.Id);
|
||||
}
|
||||
|
||||
/// <summary>Wijzigt een regel, en kan hem verbergen of weer tonen.</summary>
|
||||
public async Task<Result> WijzigAsync(long currentUserId, int id, DateOnly datum, string? versie, string kop,
|
||||
string tekst, bool zichtbaar, CancellationToken ct = default)
|
||||
{
|
||||
if (!await IsBeheerderAsync(currentUserId, ct)) return Result.Fail("Je bent geen beheerder.");
|
||||
|
||||
var regel = await _regels.FindAsync(id, ct);
|
||||
if (regel is null) return Result.Fail("Deze regel bestaat niet.");
|
||||
|
||||
var fout = await ControleerAsync(id, datum, versie, kop, tekst, ct);
|
||||
if (fout is not null) return Result.Fail(fout);
|
||||
|
||||
regel.Datum = datum;
|
||||
regel.Versie = SchoneVersie(versie);
|
||||
regel.Kop = kop.Trim();
|
||||
regel.Tekst = tekst.Trim();
|
||||
regel.Zichtbaar = zichtbaar;
|
||||
regel.GewijzigdOp = _clock.UtcNow;
|
||||
|
||||
await _audit.WriteAsync(AuditAction.VersiehistorieBeheerd, currentUserId, nameof(VersieRegel), id,
|
||||
$"gewijzigd: {Dag(datum)} {regel.Kop}", ct);
|
||||
await _uow.SaveChangesAsync(ct);
|
||||
return Result.Ok();
|
||||
}
|
||||
|
||||
/// <summary>Haalt een regel weg. Wil je hem alleen even niet tonen, verberg hem dan.</summary>
|
||||
public async Task<Result> VerwijderAsync(long currentUserId, int id, CancellationToken ct = default)
|
||||
{
|
||||
if (!await IsBeheerderAsync(currentUserId, ct)) return Result.Fail("Je bent geen beheerder.");
|
||||
|
||||
var regel = await _regels.FindAsync(id, ct);
|
||||
if (regel is null) return Result.Fail("Deze regel bestaat niet.");
|
||||
|
||||
await _audit.WriteAsync(AuditAction.VersiehistorieBeheerd, currentUserId, nameof(VersieRegel), id,
|
||||
$"verwijderd: {Dag(regel.Datum)} {regel.Kop}", ct);
|
||||
_regels.Remove(regel);
|
||||
await _uow.SaveChangesAsync(ct);
|
||||
return Result.Ok();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ hulp
|
||||
|
||||
private static string Dag(DateOnly datum) => datum.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
|
||||
|
||||
private static string? SchoneVersie(string? versie) =>
|
||||
string.IsNullOrWhiteSpace(versie) ? null : versie.Trim();
|
||||
|
||||
private async Task<bool> IsBeheerderAsync(long userId, CancellationToken ct) =>
|
||||
(await _users.FindByIdAsync(userId, ct))?.IsBeheerder == true;
|
||||
|
||||
private async Task<string?> ControleerAsync(int? eigenId, DateOnly datum, string? versie, string? kop,
|
||||
string? tekst, CancellationToken ct)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(kop)) return "Geef de regel een kop.";
|
||||
if (kop.Trim().Length > MaxKop) return $"De kop is te lang (hoogstens {MaxKop} tekens).";
|
||||
if (string.IsNullOrWhiteSpace(tekst)) return "Schrijf er een uitleg bij.";
|
||||
if (tekst.Trim().Length > MaxTekst) return $"De uitleg is te lang (hoogstens {MaxTekst} tekens).";
|
||||
if (versie is not null && versie.Trim().Length > MaxVersie) return $"Het versienummer is te lang (hoogstens {MaxVersie} tekens).";
|
||||
|
||||
// Een jaar vooruit mag, voor wie een regel klaarzet; verder is het een typefout.
|
||||
var vandaag = DateOnly.FromDateTime(_clock.UtcNow);
|
||||
if (datum.Year < 2020 || datum > vandaag.AddYears(1)) return "Deze datum klopt niet.";
|
||||
|
||||
if (await _regels.BestaatAsync(datum, kop.Trim(), eigenId, ct))
|
||||
return "Op deze dag staat al een regel met precies deze kop.";
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -348,6 +348,13 @@ public class MijnBesluitClient : IAsyncDisposable
|
||||
public Task<Uitkomst<KluisSoort>> KluisSoortAsync(int soortId, CancellationToken ct = default) =>
|
||||
StuurAsync<KluisSoort>(SocketActions.VaultCategory, new { id = soortId }, ct);
|
||||
|
||||
/// <summary>
|
||||
/// De versiehistorie zoals de server die bijhoudt, nieuwste dag bovenaan. Een oudere server
|
||||
/// kent de actie niet; het scherm toont dan een melding in plaats van een lijst.
|
||||
/// </summary>
|
||||
public Task<Uitkomst<IReadOnlyList<VersieRegel>>> VersiehistorieAsync(CancellationToken ct = default) =>
|
||||
StuurAsync<IReadOnlyList<VersieRegel>>(SocketActions.Versiehistorie, null, ct);
|
||||
|
||||
public Task<Uitkomst<KluisInhoud>> KluisOpenenAsync(long itemId, CancellationToken ct = default) =>
|
||||
StuurAsync<KluisInhoud>(SocketActions.VaultOpen, new { id = itemId }, ct);
|
||||
|
||||
|
||||
@@ -277,6 +277,12 @@ public record KluisVeld(string Sleutel, string Label, string Soort, IReadOnlyLis
|
||||
public const string Uitleg = "uitleg";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eén regel van de versiehistorie. <c>Datum</c> staat als jjjj-mm-dd; <c>Versie</c> is leeg als
|
||||
/// de regel niet bij een uitgebrachte appversie hoort.
|
||||
/// </summary>
|
||||
public record VersieRegel(string Datum, string? Versie, string Kop, string Tekst);
|
||||
|
||||
/// <summary>
|
||||
/// De ingebouwde soorten kluisitems, voor als de server er geen lijst van geeft: een oudere
|
||||
/// server, of geen verbinding op het moment dat het scherm opent. Dezelfde nummers, namen en
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
namespace MijnBesluit.Domain.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Eén regel in de versiehistorie: een nieuwe of wezenlijk gewijzigde functie, zoals een gebruiker
|
||||
/// die zou willen lezen ("wat kan ik nu wat ik eerst niet kon"). Geen bugfixes, geen opmaak die
|
||||
/// rechtgezet is.
|
||||
///
|
||||
/// De lijst staat in de database en wordt door de beheerder onderhouden; de website leest hem
|
||||
/// rechtstreeks en de app vraagt hem aan de server. Regels met dezelfde datum en versie worden
|
||||
/// samen onder één kop getoond.
|
||||
/// </summary>
|
||||
public class VersieRegel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>De dag waarop de functie er kwam.</summary>
|
||||
public DateOnly Datum { get; set; }
|
||||
|
||||
/// <summary>Het versienummer van de app, bijvoorbeeld "1.1". Leeg als het alleen de website betreft.</summary>
|
||||
public string? Versie { get; set; }
|
||||
|
||||
/// <summary>Het vette stukje: wat kun je nu.</summary>
|
||||
public string Kop { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>De uitleg erachter. Platte tekst.</summary>
|
||||
public string Tekst { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Een verborgen regel ziet alleen de beheerder; handig voor iets dat nog niet live is.</summary>
|
||||
public bool Zichtbaar { get; set; } = true;
|
||||
|
||||
public DateTime AangemaaktOp { get; set; } = DateTime.UtcNow;
|
||||
public DateTime GewijzigdOp { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -74,7 +74,8 @@ public enum AuditAction
|
||||
NalatenschapToegangVerleend = 60,
|
||||
AdvertentieIngediend = 70, AdvertentieBetaald = 71, AdvertentieGoedgekeurd = 72,
|
||||
AdvertentieAfgewezen = 73, AdvertentieGestopt = 74,
|
||||
KluisSoortBeheerd = 80
|
||||
KluisSoortBeheerd = 80,
|
||||
VersiehistorieBeheerd = 81
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -94,6 +94,7 @@ public static class DependencyInjection
|
||||
services.AddScoped<IInvitationRepository, InvitationRepository>();
|
||||
services.AddScoped<IVaultRepository, VaultRepository>();
|
||||
services.AddScoped<IVaultCategoryRepository, VaultCategoryRepository>();
|
||||
services.AddScoped<IVersiehistorieRepository, VersiehistorieRepository>();
|
||||
services.AddScoped<IMessageRepository, MessageRepository>();
|
||||
services.AddScoped<ILegacyRepository, LegacyRepository>();
|
||||
services.AddScoped<IToestelRepository, ToestelRepository>();
|
||||
@@ -105,6 +106,7 @@ public static class DependencyInjection
|
||||
|
||||
services.AddScoped<AccountService>();
|
||||
services.AddScoped<VaultCategoryService>();
|
||||
services.AddScoped<VersiehistorieService>();
|
||||
services.AddScoped<VaultService>();
|
||||
// De link naar de landingspagina voor iemand zonder account moet naar de echte site wijzen.
|
||||
services.AddScoped(sp =>
|
||||
|
||||
@@ -20,6 +20,7 @@ public class MijnBesluitDbContext : DbContext
|
||||
public DbSet<VaultFile> VaultFiles => Set<VaultFile>();
|
||||
public DbSet<VaultCategoryDefinition> VaultCategories => Set<VaultCategoryDefinition>();
|
||||
public DbSet<VaultCategoryField> VaultCategoryFields => Set<VaultCategoryField>();
|
||||
public DbSet<VersieRegel> VersieRegels => Set<VersieRegel>();
|
||||
public DbSet<Toestel> Toestellen => Set<Toestel>();
|
||||
public DbSet<Sessie> Sessies => Set<Sessie>();
|
||||
public DbSet<ContentGrant> ContentGrants => Set<ContentGrant>();
|
||||
@@ -220,6 +221,19 @@ public class MijnBesluitDbContext : DbContext
|
||||
e.HasOne(x => x.VaultFile).WithMany().HasForeignKey(x => x.VaultFileId);
|
||||
});
|
||||
|
||||
b.Entity<VersieRegel>(e =>
|
||||
{
|
||||
e.ToTable("version_history");
|
||||
e.Property(x => x.Id).HasColumnName("id");
|
||||
e.Property(x => x.Datum).HasColumnName("datum");
|
||||
e.Property(x => x.Versie).HasColumnName("versie").HasMaxLength(20);
|
||||
e.Property(x => x.Kop).HasColumnName("kop").HasMaxLength(120).IsRequired();
|
||||
e.Property(x => x.Tekst).HasColumnName("tekst").HasMaxLength(1000).IsRequired();
|
||||
e.Property(x => x.Zichtbaar).HasColumnName("zichtbaar");
|
||||
e.Property(x => x.AangemaaktOp).HasColumnName("aangemaakt_op");
|
||||
e.Property(x => x.GewijzigdOp).HasColumnName("gewijzigd_op");
|
||||
});
|
||||
|
||||
b.Entity<VaultCategoryDefinition>(e =>
|
||||
{
|
||||
e.ToTable("vault_categories");
|
||||
|
||||
@@ -267,6 +267,26 @@ public class VaultCategoryRepository : IVaultCategoryRepository
|
||||
public void Remove(VaultCategoryField veld) => _db.VaultCategoryFields.Remove(veld);
|
||||
}
|
||||
|
||||
/// <summary>De versiehistorie; zie <see cref="IVersiehistorieRepository"/>.</summary>
|
||||
public class VersiehistorieRepository : IVersiehistorieRepository
|
||||
{
|
||||
private readonly MijnBesluitDbContext _db;
|
||||
public VersiehistorieRepository(MijnBesluitDbContext db) => _db = db;
|
||||
|
||||
public async Task<IReadOnlyList<VersieRegel>> ListAsync(bool alleenZichtbaar, CancellationToken ct = default) =>
|
||||
await _db.VersieRegels.Where(r => !alleenZichtbaar || r.Zichtbaar)
|
||||
.OrderByDescending(r => r.Datum).ThenBy(r => r.Id).ToListAsync(ct);
|
||||
|
||||
public Task<VersieRegel?> FindAsync(int id, CancellationToken ct = default) =>
|
||||
_db.VersieRegels.FirstOrDefaultAsync(r => r.Id == id, ct);
|
||||
|
||||
public Task<bool> BestaatAsync(DateOnly datum, string kop, int? behalveId, CancellationToken ct = default) =>
|
||||
_db.VersieRegels.AnyAsync(r => r.Datum == datum && r.Kop == kop && (behalveId == null || r.Id != behalveId), ct);
|
||||
|
||||
public void Add(VersieRegel regel) => _db.VersieRegels.Add(regel);
|
||||
public void Remove(VersieRegel regel) => _db.VersieRegels.Remove(regel);
|
||||
}
|
||||
|
||||
public class VaultRepository : IVaultRepository
|
||||
{
|
||||
private readonly MijnBesluitDbContext _db;
|
||||
|
||||
@@ -111,6 +111,12 @@ public static class SocketActions
|
||||
/// </summary>
|
||||
public const string VaultCategory = "vault.category";
|
||||
|
||||
/// <summary>
|
||||
/// De versiehistorie: de zichtbare regels, nieuwste dag bovenaan. Staat in een tabel op de
|
||||
/// server, zodat een nieuwe regel zonder nieuwe app te zien is. Zie docs/Versiehistorie.md.
|
||||
/// </summary>
|
||||
public const string Versiehistorie = "app.versiehistorie";
|
||||
|
||||
/// <summary>Nalatenschappen die aan jou zijn toevertrouwd, en wat daarvan is vrijgegeven.</summary>
|
||||
public const string LegacyEntrusted = "legacy.entrusted";
|
||||
public const string LegacyEntrustedItems = "legacy.entrusted-items";
|
||||
|
||||
@@ -21,6 +21,9 @@ public class RequestScope
|
||||
/// </summary>
|
||||
public VaultCategoryService? Soorten { get; init; }
|
||||
|
||||
/// <summary>Optioneel: zonder deze dienst geeft de versiehistorie een lege lijst.</summary>
|
||||
public VersiehistorieService? Versiehistorie { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Voor het samenvoegen van dubbele profielen. Optioneel: zonder deze dienst werkt alles,
|
||||
/// alleen wordt een tweede uitnodiging dan geweigerd in plaats van samengevoegd.
|
||||
@@ -493,6 +496,14 @@ public class SocketDispatcher
|
||||
return SocketResponse.Ok(id, lijst);
|
||||
}
|
||||
|
||||
case SocketActions.Versiehistorie:
|
||||
{
|
||||
var lijst = scope.Versiehistorie is null
|
||||
? Array.Empty<VersieRegelWeergave>()
|
||||
: (await scope.Versiehistorie.ZichtbaarAsync(ct)).ToArray();
|
||||
return SocketResponse.Ok(id, lijst);
|
||||
}
|
||||
|
||||
case SocketActions.VaultOpen:
|
||||
{
|
||||
var p = request.PayloadAs<IdPayload>();
|
||||
|
||||
@@ -45,6 +45,7 @@ public class SocketServerService : BackgroundService
|
||||
Families = scope.ServiceProvider.GetRequiredService<FamilyService>(),
|
||||
Vault = scope.ServiceProvider.GetRequiredService<VaultService>(),
|
||||
Soorten = scope.ServiceProvider.GetRequiredService<VaultCategoryService>(),
|
||||
Versiehistorie = scope.ServiceProvider.GetRequiredService<VersiehistorieService>(),
|
||||
Messages = scope.ServiceProvider.GetRequiredService<MessageService>(),
|
||||
Legacy = scope.ServiceProvider.GetRequiredService<LegacyService>(),
|
||||
Meldingen = scope.ServiceProvider.GetRequiredService<MeldingService>(),
|
||||
|
||||
@@ -1,61 +1,89 @@
|
||||
@* De versiehistorie: nieuwe of wezenlijk gewijzigde functies, nieuwste bovenaan.
|
||||
@* De versiehistorie: nieuwe of wezenlijk gewijzigde functies, nieuwste bovenaan.
|
||||
|
||||
Zelfde opzet als Productuitleg.razor en Privacytekst.razor: op de website een popup vanaf
|
||||
het overzicht, in de app hetzelfde. Dit bestand staat twee keer op schijf - de app en de site
|
||||
delen geen project - en een zelfcontrole vergelijkt ze letterlijk.
|
||||
De regels staan in een tabel op de server (version_history) en worden beheerd op de website
|
||||
onder Beheer > Versiehistorie. Site en app lezen dezelfde tabel; dit bestand bevat zelf geen
|
||||
tekst meer, dus een nieuwe regel vraagt geen nieuwe versie van de app. Zie docs/Versiehistorie.md.
|
||||
|
||||
Wat hier NIET in hoort: bugfixes, tekstuele correcties, opmaak die is rechtgezet. Dit is voor
|
||||
Wat daar NIET in hoort: bugfixes, tekstuele correcties, opmaak die is rechtgezet. Dit is voor
|
||||
"wat kan ik nu wat ik eerst niet kon", niet een logboek van elke wijziging in de code. *@
|
||||
@inject VersiehistorieService Historie
|
||||
|
||||
<p class="zacht" style="margin-top:0">
|
||||
Nieuwe of wezenlijk gewijzigde functies, nieuwste bovenaan.
|
||||
</p>
|
||||
|
||||
<h2 style="margin-top:0">20 oktober 2026 · versie 1.1</h2>
|
||||
<ul style="padding-left:1.2rem">
|
||||
<li>
|
||||
<strong>Meer soorten in de kluis.</strong> Naast wachtwoorden, polissen en uitvaartwensen
|
||||
kan er voortaan een nieuwe soort bijkomen, met eigen invulvelden, zonder dat je de app
|
||||
daarvoor opnieuw hoeft te updaten. Je bestaande kluisitems blijven zoals ze waren.
|
||||
</li>
|
||||
</ul>
|
||||
@if (Fout)
|
||||
{
|
||||
<p class="zacht">De versiehistorie kon niet worden opgehaald. Probeer het later nog eens.</p>
|
||||
}
|
||||
else if (Regels is null)
|
||||
{
|
||||
<p class="zacht">Bezig met laden…</p>
|
||||
}
|
||||
else if (Regels.Count == 0)
|
||||
{
|
||||
<p class="zacht">Er staat nog niets in de versiehistorie.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
@foreach (var groep in Groepen())
|
||||
{
|
||||
<h2 style="@(groep.Eerste ? "margin-top:0" : null)">@groep.Kop</h2>
|
||||
<ul style="padding-left:1.2rem">
|
||||
@foreach (var regel in groep.Regels)
|
||||
{
|
||||
<li style="margin-bottom:.5rem"><strong>@Punt(regel.Kop)</strong> @regel.Tekst</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
}
|
||||
|
||||
<h2>20 september 2026</h2>
|
||||
<ul style="padding-left:1.2rem">
|
||||
<li style="margin-bottom:.5rem">
|
||||
<strong>Rijbewijs en paspoort in de kluis.</strong> Twee nieuwe categorieën, met een
|
||||
knop om meteen de voor- en achterkant (rijbewijs) of de foto-pagina (paspoort) te maken
|
||||
of te kiezen.
|
||||
</li>
|
||||
<li style="margin-bottom:.5rem">
|
||||
<strong>Mijn profiel als pop-up.</strong> Je eigen profiel bewerk je nu in dezelfde
|
||||
pop-up met vaste "Opslaan"-knop onderin als bij de andere mensen in je familie, in de
|
||||
app en op de website.
|
||||
</li>
|
||||
<li style="margin-bottom:.5rem">
|
||||
<strong>Duidelijker voor de nalatenschapsbeheerder.</strong> Bij "Aan mij toevertrouwd"
|
||||
zie je nu meteen hoeveel meldingen er nodig zijn en hoe lang de bezwaartermijn is.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Muziek en verdere wensen groeien mee.</strong> Die velden bij een kluisitem
|
||||
passen zich nu vanzelf aan de lengte van de tekst aan, ook op de website.
|
||||
</li>
|
||||
</ul>
|
||||
@code {
|
||||
private IReadOnlyList<VersieRegelWeergave>? Regels;
|
||||
private bool Fout;
|
||||
|
||||
<h2>19 september 2026</h2>
|
||||
<ul style="padding-left:1.2rem">
|
||||
<li style="margin-bottom:.5rem">
|
||||
<strong>Met mij gedeeld, ook in de app.</strong> Heeft iemand een kluisitem rechtstreeks
|
||||
met jou gedeeld om het vast te bespreken - bijvoorbeeld een uitvaartwens - dan zie je
|
||||
dat voortaan ook op je telefoon, niet meer alleen op de website.
|
||||
</li>
|
||||
<li style="margin-bottom:.5rem">
|
||||
<strong>Een gedeeld of nagelaten kluisitem bekijken.</strong> Dat opent nu als pop-up in
|
||||
dezelfde opmaak als het invulformulier, inclusief de foto's en documenten die erbij
|
||||
horen.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Met de vinger naar beneden trekken ververst het scherm.</strong> Werkt op Kluis,
|
||||
Mijn mensen, Momenten en Nalatenschap.
|
||||
</li>
|
||||
</ul>
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try { Regels = await Historie.ZichtbaarAsync(); }
|
||||
catch { Fout = true; }
|
||||
}
|
||||
|
||||
private sealed record Groep(string Kop, bool Eerste, List<VersieRegelWeergave> Regels);
|
||||
|
||||
/// <summary>
|
||||
/// Opeenvolgende regels met dezelfde dag (en dezelfde versie) vormen samen één kop. De volgorde
|
||||
/// komt van de server: nieuwste dag bovenaan, binnen een dag in de volgorde van invoer.
|
||||
/// </summary>
|
||||
private IEnumerable<Groep> Groepen()
|
||||
{
|
||||
var uit = new List<Groep>();
|
||||
string? vorige = null;
|
||||
foreach (var r in Regels!)
|
||||
{
|
||||
var kop = Koptekst(r);
|
||||
if (kop != vorige)
|
||||
{
|
||||
uit.Add(new Groep(kop, uit.Count == 0, new List<VersieRegelWeergave>()));
|
||||
vorige = kop;
|
||||
}
|
||||
uit[^1].Regels.Add(r);
|
||||
}
|
||||
return uit;
|
||||
}
|
||||
|
||||
private static string Koptekst(VersieRegelWeergave r)
|
||||
{
|
||||
var dag = DateOnly.TryParseExact(r.Datum, "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture,
|
||||
System.Globalization.DateTimeStyles.None, out var d)
|
||||
? $"{d.Day} {Datums.Maanden[d.Month - 1]} {d.Year}"
|
||||
: r.Datum;
|
||||
return string.IsNullOrWhiteSpace(r.Versie) ? dag : $"{dag} \u00b7 versie {r.Versie}";
|
||||
}
|
||||
|
||||
/// <summary>De kop eindigt op een punt, zodat de tekst erachter als gewone zin leest.</summary>
|
||||
private static string Punt(string kop)
|
||||
{
|
||||
var k = kop.Trim();
|
||||
return k.Length == 0 || ".!?".Contains(k[^1]) ? k : k + ".";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,9 @@ else
|
||||
Ook een eigen scherm: dat is inrichten, geen terugdraaien. *@
|
||||
<p><a href="/beheer/soorten">Kluissoorten beheren ›</a></p>
|
||||
|
||||
@* Versiehistorie: de lijst "wat is er nieuw" op de website en in de app. Eén tabel voor beide. *@
|
||||
<p><a href="/beheer/versiehistorie">Versiehistorie beheren ›</a></p>
|
||||
|
||||
@if (Melding is not null) { <div class="melding @MeldingSoort">@Melding</div> }
|
||||
|
||||
@* ------------------------------------------------------------ statistieken *@
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -178,8 +178,7 @@
|
||||
</Popup>
|
||||
}
|
||||
|
||||
@* Zelfde tekst als in de app: Versiehistorie.razor staat twee keer op schijf en een
|
||||
zelfcontrole vergelijkt ze letterlijk. *@
|
||||
@* De tekst komt uit de tabel version_history, net als in de app. *@
|
||||
@if (VersiehistorieOpen)
|
||||
{
|
||||
<Popup Titel="Versiehistorie" Bevestigtekst="Sluiten" AlleenSluiten="true"
|
||||
|
||||
Reference in New Issue
Block a user