Add SourcePathFilter to HostsPageQueryState and apply it in HostsPageProjectionService.
Replace the native select with a grouped menu (managed/system/additional/hostsdir),
per-file non-comment counts, toolbar layout, and full-path labels with end-anchored
ellipsis plus title tooltips. Include HostsSourcePathDisplay helpers, menu models,
and tests for grouping and projection filtering.
- HostEntry.InlineComment; parse at first # on data lines; ToLine + SanitizeInlineComment
- HostsPageRow + HostsCache; pending change equality and save diff include comments
- Hosts table: dedicated Comment column; edit in own cell; empty shown as em dash
- Parser and pending-change tests
GetDomainsFromAddressDirective only considers lines with a non-empty
target after the final slash; address=/domain/ applies to all RR types
and should not require local=. Add tests for trailing-slash and # forms.
- Add FieldKeyForOption() using EffectiveConfigSections.GetSectionId so
cross-option issues match UI field keys; tighten RFC1918 in-addr.arpa
detection for bogus-priv vs server=.
- GetMulti: pending change always wins; empty list when NewValue is not
a string list (with tests).
- EffectiveConfigSection: re-run cross-option when entering edit mode or
continuing after save failure; allow opening save modal when only
validation summary is present.
- Toolbar: validation link aria-label describes opening the summary.
Move cross-option checks to DI-backed rules and shared context so editor and quick-add flows use one validation pipeline. Improve warning copy and save-modal messaging to clarify that validation reflects both on-disk config and pending edits.
Remove the Status column and row-level badges/actions; keep source-level
Editable on group headers. Double-click managed rows to edit; commit staged
drafts when focus leaves the row via isFocusOutsideElement in the shared
scroll-cue module. Hide inactive system-host rows when dnsmasq ignores them
and move system-hosts / expand-hosts notes below the content area.
Memoize VisibleGroups so BuildGroups runs once per render during search.
Move read-ethers metadata to the DHCP section; adjust Hosts page state copy
and related effective-config tooltips/builders where needed.
Redesign the Hosts page around source-aware grouped rows with shared table shell styling, fix effective-config save session synchronization, and move read-ethers into the DHCP model where dnsmasq actually applies it.
- EffectiveConfigFieldRef as value type; PendingDnsmasqChange/PendingOptionChange/PendingManagedHostsChange
- Multi-file save plan (DnsmasqSaveWritePlan, DnsmasqManagedBackup) and backup/restore in save flow
- Hosts integrated into effective-config save; Hosts.razor uses shared save modal
- IEffectiveConfigDescriptorProvider + IEffectiveConfigFieldBuilder (DI); descriptors from EffectiveConfigSections
- IEffectiveConfigPageEditor, shared descriptor resolution; addn-hosts/dhcp-host descriptor fix
- DnsmasqConfText, IEffectiveConfigDirectiveSerializer; DnsmasqConfigService uses serializer for writes
- IStructuredOptionValueHandler/Registry, DhcpHostOptionValueHandler; Dhcp.razor index-based DeleteRow fix
- SaveService: roll back partial writes on failure; SaveModal: WriteFailed shows backups and Restore button
Reduce presentation-focused test churn while adding corpus-based parser, validator, capability-guard, and round-trip save coverage to better protect future refactors.
- Add IOptionSemanticHandler implementations for DNS/DHCP/auth/interface options
- Add shared syntax helpers (DnsmasqRrTypeSyntax, DnsmasqScopedDomainSyntax, etc.)
- Wire semantics and registry for multi/single options; metadata-only semantics
- RaParam: use DnsmasqRelaySyntax.IsInterfaceNameWithOptionalTrailingWildcard so
interface names allow only trailing *, not asterisks in the middle (eth*0, *eth0)
- Tests: RaParam trailing-wildcard and invalid-asterisk cases
Unify parser, editor, and save-time validation around semantic metadata and handlers, add path-aware and structured option checks, and improve effective-config editing placeholders and unset behavior.
- Add dhcp-optsdir support (model, sections, parser, UI multi-value).
- Model leasequery, connmark-allowlist-enable, dhcp-generate-names, dhcp-broadcast,
bootp-dynamic, dnssec-check-unsigned as key-only-or-value with validation.
- Parse compile-time capabilities from dnsmasq --version (DHCP, TFTP, DNSSEC, DBus).
- Expose capabilities via DnsmasqVersionInfo and status API (DnsmasqSupports*).
- Map options to required features; disable unsupported option editors with badge + tooltip.
- Save guard: reject changes for unsupported options; use UnsupportedCapabilities error code.
- MultiKeyOnlyOrValue write path: filter out readonly values to avoid duplicating in managed file.
- User-friendly tooltips for disabled options; dedicated UnsupportedCapabilities vs WriteFailed.
- Add EffectiveConfigContext.DnsRecords and .Filters; map in EffectiveConfigViews
- Add DnsRecords.razor and Filters.razor with context-scoped effective config
- Add nav links for DNS records and Filters (icons: diagram-3-fill, funnel-fill)
- Put effective config block at top of Hosts, DHCP, DNS Records, Filters (no config file list on sub-pages)
- Hosts view: add expand-hosts to allow-list. Filters view: add domain-needed, bogus-priv, filterwin2k, no-round-robin
- Page titles: Hosts Configuration, DHCP Configuration, DNS Records Configuration, Filters Configuration
- Remove 'Config affecting...' subheadings and page intro text; add .page-intro and .page-chip styles
- Add shared .ec-effective-switch styles in app.css for consistent switch look
- Wrap flag and do-0x20-encode checkboxes in form-check form-switch
- Add aria-label and title for accessibility
- Matches existing KeyOnlyOrValueDisplay (use-stale-cache, add-mac, etc.)
- Options: VersionCommand, VersionTimeoutSeconds, MinimumVersion, EnforceMinimumVersion
- Version probe service and parser; startup enforcement when EnforceMinimumVersion
- Save flow: block save on probe failure (VersionProbeFailed) or version below minimum (UnsupportedVersion)
- Status API and Dnsmasq page: show version with tooltip, link to CHANGELOG
- Readiness: GET /healthz/ready (version + dnsmasq running when StatusCommand set)
- MapReadyHealthCheck extension; Dockerfile HEALTHCHECK + curl; compose healthcheck and service_healthy
- Docs: README and agents.md updated
- Fix do-0x20-encode: clearing pending when toggling back to original (Disabled/Default)
- Do0x20EncodeDisplay: uncheck uses pending.OldValue when present
- EffectiveConfigFieldDisplay: use pending.OldValue as _valueAtActivation when re-entering with pending
- Effective config: validation errors/warnings in toolbar and save modal, revert from modal
- Custom displays: Do0x20EncodeDisplay (tri-state), KeyOnlyOrValueDisplay
- ExplicitToggleState, config/apply support for do-0x20-encode, option help and tests
- DnsmasqOptions: set RestartTimeoutSeconds default to 30 to match XML comment
and original reload timeout (avoids halving timeout for restart/reload).
- Save modal: multi-value diff no longer uses set-only Except(); when lists
have same items but different order (or duplicate count), show 'Order or
duplicates changed' with before/after so reorders (e.g. server=) are visible.
- Multi-value items: EditableAsButton=true so 'editable' badge is clickable in view
mode and activates the field like other editable badges.
- Save modal: 'Continue editing' after ValidateFailed/ReloadFailed now discards
session, refreshes config from disk, then re-enters edit mode so remove/UI
work correctly.
- 'Stop editing' after ValidateFailed/ReloadFailed now triggers config refresh
so the invalid value on disk is shown instead of stale UI.
- SaveFlow: HandleCloseAndEndEdit invokes OnSaveCompleted when in failed state;
OnContinueEditing uses EventCallback.Factory.Create to fix method-group
conversion warning.
- All multi fields use EffectiveMultiValueConfigFieldDescriptor; registry has
RegisterMultiDescriptor/RegisterMultiComponent/RegisterMulti; every multi
option registered; plain multi fallback removed (AddMultiDescriptor throws).
- Descriptor-driven validation: base descriptor ValidateValue + Validate();
integer descriptor enforces Min/Max; ListenAddressMultiValidator for
listen-address; single/flag commit uses Descriptor.Validate (no session
field issues for inline edits).
- Multi list editor: local _displayItems so remove/add/edit update UI
immediately; remove button PreventBlurOnMouseDown; inline validation
message under input (ec-multi-list-input-group); root div not span.
- Save flow: on successful backup restore call OnCloseAndEndEdit then
OnSaveCompleted so session and pending changes are cleared and config
is reloaded.
- Server uses descriptor-only (no custom multi component); ServerMultiValueDisplay
removed. RegisterValidatedSingle added for future single-field validation.
- Model conntrack as Flag (parser, config bool, cache, registry FlagValueDisplay)
- Apply: for non-flag options with empty/invalid value, remove existing line
and never write key-only directive (was producing malformed option= without value)
- Flag options: when user toggles value back to original, clear pending change (same as revert button); trigger revert immediately on change so UI updates without blur
- UiContext: add RevertFieldAsync so section can revert a field and refresh; section wires it to Session.RevertChange + StateHasChanged
- RestoreAsync: call config cache Invalidate() after File.Copy so next read sees restored file (fixes validate-fail → restore showing pre-restore data)
- 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)
- Add EffectiveConfigMultiValueListEditor with badge-style actions, draft merge,
and display-mode editable badges; fix row callback capture and bounds checks
- EffectiveConfigFieldDisplay: compute multi-value state in OnParametersSet +
HandleMultiValueChanged; BuildItemsWithSource preserves readonly/editable;
dedupe list on commit; defensive copy for multi-value commit
- DnsmasqConfigService: generic MatchesOption via key parsing; FilterManagedOnly
+ ReadReadonlyMultiValuesByOptionAsync (single-pass readonly); EnsureManagedConfigInvariants
+ EnsureUniqueDirective; fix DHCP write cache notification (re-parse written output)
- EffectiveConfigSaveResult: ErrorCodes constants, IsValidateFailed; set Validated=false
when validation fails; EffectiveConfigSaveFlow use IsValidateFailed; save service
use ErrorCodes
- OptionStateBadge: OnEditableClickRequested for list-editor per-item edit
- Validation service and config save flow updates
- Process: Add IProcessHandle, ProcessOutputLine, StartAsync; RunAsync via StartAsync+WaitForExitAsync. Wait for stdout/stderr stream close before reading to fix empty restart output. ProcessTimeouts; ReloadService/StatusController/LogsService use config timeouts.
- Effective config: Rename reload→restart in save/restore result types and UI. Save modal: show restart output, danger alert, Stop editing/Continue editing (yellow), footer one-line; fallback exit code when no output; ensure pre visibility (CSS). Restore failed: combined output helper.
- Status script: When dnsmasq dead, run dnsmasq --test and show config error in status block (Docker harness; DNSMASQ_CONF).
- listen-address: Allow IPv6 (ValidateDraftValue accepts InterNetworkV6).
- Docker test: RestartCommand uses DnsmasqOptions timeout; DnsmasqOptions RestartTimeoutSeconds.
- Register ISettingsModalService, INotificationService, IUpdateCheckService via assembly scanning (marker interfaces)
- Add IApplicationOptionsValidator<TOptions> marker; scan only those for IValidateOptions registration
- Fix ApplicationLifecycleLoggingHostedService: log RestartCommand/ReloadCommand/StatusCommand (no ApplyCommand)
- NavMenu: spin animation for update-check button icon when checking; single icon with conditional nav-footer-spin class
- Add NotificationHost/NotificationToast components and NotificationService for toasts
- Effective config save flow, restore result, save service; various EffectiveConfig and DnsmasqOptions/validator updates
- Test and script updates; docker-compose.test.yml, appsettings, DnsmasqConfKeys/tooltips/sections
- Move registration marker interfaces to Registration/Abstractions
- Add feature folders with Abstractions subfolders: EffectiveConfig,
Dnsmasq/Config, Dnsmasq/Hosts, Dnsmasq/Leases, Dnsmasq/Reload,
Logs, Updates, UI/Settings, Common/Process
- Place interfaces in each feature's Abstractions namespace; align
implementation namespaces to folder paths
- Update Program, extensions, controllers, hubs, helpers, components,
and tests to use new namespaces
- Remove old flat Services/Abstractions and root-level service files
- Add Components/Shared/StatusBadge + StatusBadgeKind; centralize badge
styles and map Kind to Bootstrap classes. Refactor OptionStateBadge to
compose StatusBadge; add OK/Cancel/Revert when active with
OnConfirm/OnCancel/OnRevert callbacks and exit-action flag in
EffectiveConfigFieldDisplay.
- Fix _valueAtActivation to use Descriptor.GetValue() (persisted value)
so save modal shows correct before/after and no phantom pending on
revert-to-original.
- OptionHelpController: add CancelCloseFromLabelEnter() and call when
opening/switching help so pending 300ms close does not dismiss new help.
- Migrate Dnsmasq.razor and HostsFileSection to StatusBadge; save modal
option chip uses NeutralPill. Centralize badge CSS in StatusBadge.
- Badge styling: font-size/weight/padding, hover lift+shadow, active
press with visible release animation.
- Toolbar: single expand/collapse toggle; change count after Save/Exit.
- Save modal: selective revert per change; modern list styling, empty state;
Session + OnReverted; Save disabled when no changes.
- Cancel: prevent blur-before-click (mousedown preventDefault on cancel
badge); _cancelRequested so cancel never commits.
- DeactivateFieldAsync in UiContext + Section; OptionStateBadge cancel
clears draft and deactivates.
Replace separate Expand all / Collapse all buttons with one toggle button.
Icon and label switch based on AllSectionsExpanded (expand when any
section collapsed, collapse when all expanded).
- Use pending != null ? pending.NewValue : Descriptor.GetValue() so clearing
a value (port, log-queries, local-service) shows '(not set)' instead of
reverting to the old value; fix effective value and commit logic in
EffectiveConfigFieldDisplay.
- Rename ReadonlyBadge to OptionStateBadge; add editable/pending state and
use it from EffectiveConfigOptionItem, EffectiveConfigFieldDisplay,
EffectiveConfigMultiValueItem.
- OptionHelpLabel: default CssClass from HelpKey (EffectiveCssClass).
Add readonly badge/popover guidance, pending change tracking, and save confirmation flow for effective config editing. Update field renderers and config services to commit staged changes, and remove bundled Bootstrap dist assets from wwwroot.
- Add EffectiveConfigOptionKindMap (Single/Multi kind + LastWins/Flag/Multi parser
behavior) and drive field builder + ConfigSetCache from it.
- Single AddDescriptor() in list extensions that dispatches via kind map to
AddSingleDescriptor/AddMultiDescriptor.
- ConfigSetCache: ParseOptionValue/ParseOptionWithSource dispatch by option
name; BuildEffectiveConfig and BuildEffectiveConfigSources use them with
casts; special cases (NoHosts, AddnHosts, server/local, DhcpLeaseFilePath)
remain explicit.
- Add IntegerValueDisplay, LogQueriesDisplay, LocalServiceDisplay; register
integers with bounds/units in EffectiveConfigRenderFragmentRegistry.
- Add EffectiveConfigDescriptorFactory, EffectiveIntegerConfigFieldDescriptor,
IEffectiveConfigFieldDescriptor for integer descriptor metadata.
- 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