- Add app version to sidebar footer with link to GitHub release
- CSS cache busting: append version query string to static assets
- Remove LogEvents; improve startup logging with version, env, paths, uptime
- Settings modal: collapsible groups with search-aware expand/collapse
- Release workflow and publish script: pass version from tag for builds
GitHub can return release body with unescaped control characters (e.g. from
generated release notes); jq rejects them. Sanitize response in fetch_release
and list_releases before piping to jq (keep \n and \r).
- Move Client/Http, Services, Parsers under Infrastructure/ (Client, Services, Parsers)
- Move config helpers (DnsmasqConfKeys, DnsmasqOptionTooltips, DnsmasqFileEncoding, EffectiveConfigFieldBuilder) to Infrastructure/Helpers/Config; ApiJsonOptions to Helpers/Http
- Move Configuration types (ApplicationOptions, DnsmasqOptions, DnsmasqOptionsValidator) to Models/Config
- Merge Models/Status and Models/EffectiveConfig into Models/Dnsmasq and Models/Dnsmasq/EffectiveConfig
- Move Client/Models and Client/Services to Models/Client and Infrastructure/Services
- Move ConfigSetSnapshot, HostsSnapshot, ProcessRunResult, ManagedConfigContent from Infrastructure/Services/Abstractions to Models/Contracts
- Update all namespaces and usings; tests pass
- Use set +e around env/grep/read so grep (no match), read (EOF), and
[ -f ]/[ -s ] do not exit the script when no DNSMASQ_WEBUI_* or --set
- Write env vars to temp file .env then read; only process when file
exists and is non-empty
- Add || true after [ -s CONFIG_SET_FILE ] && cat so empty CONFIG_SET_FILE
does not trigger exit
Fixes install/update with no config (e.g. plain --version/--update --dir)
failing silently under sh (dash).
- Echo 'Installing dnsmasq-webui...' at start of do_install so output is visible
- Use </dev/null on all curl calls so they do not consume stdin; when run
as 'curl | sh' the script was being eaten and exited before any echo
- EnsureManagedConfigHostedService: write conf-file=/absolute/path so
dnsmasq finds the managed file regardless of CWD (e.g. systemd with CWD=/)
- Dnsmasq.razor: show Config files (load order) as single list with all
paths (main, conf-dir, managed); fallback to Main/Managed when set unavailable
- Add DnsmasqFileEncoding.Utf8NoBom for all config and hosts file writes
- Strip BOM from first line when reading main config and managed config
- Prevents 'bad option at line 1' when dnsmasq loads files written by the app
- Add --set KEY=VALUE and env vars DNSMASQ_WEBUI_* to configure app at install
- Write env file for systemd (system: /etc/default/dnsmasq-webui; user: install-dir/dnsmasq-webui.env)
- Default ASPNETCORE_URLS=http://0.0.0.0:8080 so service listens on 8080
- Preserve existing env file on update (only overwrite when new config or first install)
- README: configure-at-install section, --set in options table, update preserves env note
- README: use master branch in raw GitHub URL (repo default branch)
- install.sh: trim repo and asset URLs (fix malformed URL when script has CRLF or trailing whitespace)
- Config set cache: ConfigSetCache, IConfigSetCache, ConfigSetSnapshot. One read of
main + conf-dir + managed config, build snapshot via parser pathToLines overloads.
Watchers (main + managed file), 120s staleness, Invalidate(), NotifyWeWroteManagedConfig.
- Parser: use DnsmasqConfKeys in DnsmasqConfIncludeParser and ConfigSetCache; add
DnsmasqConfKeys.cs and use in DnsmasqConfOptionRegistry.
- ConfigSetSnapshot: add DhcpHostEntries (built from pathToLines). ReadDhcpHostsAsync
and ReadManagedConfigAsync use cache; writes call NotifyWeWroteManagedConfig.
- DnsmasqConfigSetService: use IConfigSetCache only; all data from snapshot.
- Hosts cache: HostsCache, IHostsCache, HostsSnapshot (managed + read-only). Watchers
on managed and system hosts path, staleness, NotifyWeWroteManagedHosts.
- HostsFileService and HostsController: use IHostsCache for ReadAsync and GetReadOnly.
- Tests: DnsmasqConfigSetServiceTests use ConfigSetCache with test options.
- Managed hosts file (zz-dnsmasq-webui.hosts): app reads/writes only this;
addn-hosts in managed config loads it. SystemHostsPath is read-only display.
- Hosts page: editable managed file; then 'Other hosts (read-only)' (system
hosts when configured and !no-hosts, plus addn-hosts excluding managed).
- GET api/hosts/readonly for read-only files; no-hosts hides system hosts.
- HostsFileSection.razor component; fix space before read-only badge.
- Test harness: show container /etc/hosts (default SystemHostsPath).
- Config parsing/sources, tests and client updates for new hosts model.
- Static hosts: read dhcp-host from all config files; show external as read-only
with Source column; IsEditable + SourcePath on DhcpHostEntry; reject save if
managed entry duplicates MAC from another file (400 + message)
- Lease field: single input + datalist (type or select), remove Other dropdown
- MAC field: single input + datalist from current leases, TryFillFromLeaseByMac
- Add host: default Name=*, suggest next free IP from DHCP range
- Leases: configurable refresh polling; Settings modal for interval (client-side)
- DhcpHostsClient: surface 400 error body message on save failure
- App title config (ApplicationOptions), nav/layout/error/hosts tweaks