From 87179f0195aef8de775c184108cc1628731cdab4 Mon Sep 17 00:00:00 2001 From: Alex Hope-O'Connor Date: Mon, 2 Mar 2026 22:13:07 +1000 Subject: [PATCH] Effective config: empty multi-value UX, clickable changes count - Multi-value: show editable badge next to (none); clicking activates edit and opens add row - List editor: when empty and add allowed, do not show (none) row; auto-focus new-item input on open and when clicking add item - Toolbar: make 'X change(s)' clickable to open save dialog (keyboard accessible) --- .../EffectiveConfigSection.razor.css | 8 +++++ .../Composition/EffectiveConfigToolbar.razor | 16 ++++++++- .../EffectiveConfigMultiValueListEditor.razor | 36 +++++++++++++++++-- .../Fields/EffectiveConfigMultiValueRow.razor | 2 ++ 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/DnsmasqWebUI/Components/EffectiveConfig/Composition/EffectiveConfigSection.razor.css b/src/DnsmasqWebUI/Components/EffectiveConfig/Composition/EffectiveConfigSection.razor.css index f0d8667..2f06ea9 100644 --- a/src/DnsmasqWebUI/Components/EffectiveConfig/Composition/EffectiveConfigSection.razor.css +++ b/src/DnsmasqWebUI/Components/EffectiveConfig/Composition/EffectiveConfigSection.razor.css @@ -38,6 +38,14 @@ margin-left: auto; } +::deep .ec-toolbar-changes-link { + cursor: pointer; +} + +::deep .ec-toolbar-changes-link:hover { + text-decoration: underline; +} + .ec-sections { display: flex; flex-direction: column; diff --git a/src/DnsmasqWebUI/Components/EffectiveConfig/Composition/EffectiveConfigToolbar.razor b/src/DnsmasqWebUI/Components/EffectiveConfig/Composition/EffectiveConfigToolbar.razor index bc7278a..41934fb 100644 --- a/src/DnsmasqWebUI/Components/EffectiveConfig/Composition/EffectiveConfigToolbar.razor +++ b/src/DnsmasqWebUI/Components/EffectiveConfig/Composition/EffectiveConfigToolbar.razor @@ -22,7 +22,13 @@ @if (PendingChangesCount > 0) { - @PendingChangesCount change(s) + + @PendingChangesCount change(s) + } } else @@ -59,4 +65,12 @@ { await SearchTermChanged.InvokeAsync(e.Value?.ToString() ?? ""); } + + private async Task OnChangesLinkKeyDown(KeyboardEventArgs e) + { + if (e.Key == "Enter" || e.Key == " ") + { + await OnOpenSaveModal.InvokeAsync(); + } + } } diff --git a/src/DnsmasqWebUI/Components/EffectiveConfig/Fields/EffectiveConfigMultiValueListEditor.razor b/src/DnsmasqWebUI/Components/EffectiveConfig/Fields/EffectiveConfigMultiValueListEditor.razor index 2e147f5..46f53a0 100644 --- a/src/DnsmasqWebUI/Components/EffectiveConfig/Fields/EffectiveConfigMultiValueListEditor.razor +++ b/src/DnsmasqWebUI/Components/EffectiveConfig/Fields/EffectiveConfigMultiValueListEditor.razor @@ -1,6 +1,8 @@ @namespace DnsmasqWebUI.Components.EffectiveConfig @using DnsmasqWebUI.Models.Dnsmasq @using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig +@using Microsoft.AspNetCore.Components.Web +@inject IJSRuntime JSRuntime
    @@ -53,7 +55,7 @@ } } - else + else if (!AllowAddManagedValue) {
  1. (none) @@ -65,7 +67,7 @@
  2. @if (_addingNew) { - @@ -102,6 +104,35 @@ private int? _editingIndex; private bool _addingNew; private string _draftValue = ""; + private bool _didAutoOpenAdd; + private bool _shouldFocusAddInput; + private ElementReference _addNewInputRef; + + protected override void OnParametersSet() + { + if (!_didAutoOpenAdd && (SourceItems?.Count ?? 0) == 0 && AllowAddManagedValue) + { + _didAutoOpenAdd = true; + _addingNew = true; + _shouldFocusAddInput = true; + } + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (_shouldFocusAddInput && _addingNew) + { + _shouldFocusAddInput = false; + try + { + await _addNewInputRef.FocusAsync(); + } + catch + { + // Focus can fail if the element is not yet in the DOM (e.g. prerender) + } + } + } private void BeginEdit(int index, string current) { @@ -115,6 +146,7 @@ _editingIndex = null; _addingNew = true; _draftValue = ""; + _shouldFocusAddInput = true; } private void CancelInline() diff --git a/src/DnsmasqWebUI/Components/EffectiveConfig/Fields/EffectiveConfigMultiValueRow.razor b/src/DnsmasqWebUI/Components/EffectiveConfig/Fields/EffectiveConfigMultiValueRow.razor index 3044d35..9f47ddf 100644 --- a/src/DnsmasqWebUI/Components/EffectiveConfig/Fields/EffectiveConfigMultiValueRow.razor +++ b/src/DnsmasqWebUI/Components/EffectiveConfig/Fields/EffectiveConfigMultiValueRow.razor @@ -34,6 +34,8 @@ else { (none) + } }