UI polish: update check tooltip date, expand/collapse icons, dialog JS

- NavMenu: show short date in update-check tooltip when last check was not today
- Settings modal: expand/collapse all sections with bi-arrows-expand/collapse icons
- Effective config: add Expand all button (bi-arrows-expand), same icon style as toolbar
- Rename settings-modal.js to dialog.js; add config-option-help.js, JS extension helpers
- Config option help modal and client settings/dialog wiring updates
This commit is contained in:
2026-02-13 00:59:33 +10:00
parent e7c2560d07
commit ecd9e5cc7b
17 changed files with 269 additions and 121 deletions
@@ -1,4 +1,5 @@
using System.Text.Json;
using DnsmasqWebUI.Extensions;
using DnsmasqWebUI.Models.Client;
using DnsmasqWebUI.Infrastructure.Services.Abstractions;
using Microsoft.JSInterop;
@@ -46,7 +47,7 @@ public sealed class ClientSettingsService : IClientSettingsService, IAsyncDispos
{
var module = await GetModuleAsync();
if (module == null) return new ClientSettings();
var json = await module.InvokeAsync<string?>("getItem");
var json = await module.InvokeAsyncSafe<string?>("getItem");
if (string.IsNullOrWhiteSpace(json))
{
var defaults = new ClientSettings();
@@ -73,7 +74,7 @@ public sealed class ClientSettingsService : IClientSettingsService, IAsyncDispos
var module = await GetModuleAsync();
if (module == null) return;
var json = JsonSerializer.Serialize(settings, JsonOptions);
await module.InvokeVoidAsync("setItem", json);
await module.InvokeVoidAsyncSafe("setItem", json);
}
/// <summary>
@@ -81,11 +82,7 @@ public sealed class ClientSettingsService : IClientSettingsService, IAsyncDispos
/// </summary>
public async ValueTask DisposeAsync()
{
if (_module == null) return;
try { await _module.DisposeAsync(); }
catch (InvalidOperationException ex) { _logger.LogDebug(ex, "JS module DisposeAsync skipped (prerender)"); }
catch (JSDisconnectedException ex) { _logger.LogDebug(ex, "JS module DisposeAsync skipped: circuit disconnected"); }
catch (JSException ex) { _logger.LogDebug(ex, "JS module DisposeAsync failed"); }
finally { _module = null; }
await _module.DisposeAsyncSafe();
_module = null;
}
}