mirror of
https://github.com/alexhopeoconnor/dnsmasq-webui.git
synced 2026-10-04 04:18:13 +10:00
- Split effective-config session into Draft + Ui (IEffectiveConfigDraft, IEffectiveConfigUiState) - Hosts: managed overlay, edit mode from table, validation deferred to blur/Escape/Enter - Managed hosts save modal: line-level diff (add/remove/modify/order) - Hosts group headers: editable/read-only badges, empty-group row, Effective names help - hosts-ui.js for touch vs hover help; table inline bind oninput for live preview - HostsEntryEditValidator and ManagedHostsPendingChangeDiff with tests
69 lines
2.7 KiB
Plaintext
69 lines
2.7 KiB
Plaintext
@namespace DnsmasqWebUI.Components.EffectiveConfig.CustomDisplays
|
|
@using DnsmasqWebUI.Models.Dnsmasq
|
|
@using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig
|
|
@inherits EffectiveConfigValueDisplayBase
|
|
|
|
@* do-0x20-encode / no-0x20-encode: tri-state. Switch shows Enabled vs not-Enabled; uncheck maps back to Default when that was the value at activation, else Disabled. *@
|
|
@if (IsActiveEditor && Descriptor.GetSource()?.IsReadOnly != true)
|
|
{
|
|
var isOn = GetState() == ExplicitToggleState.Enabled;
|
|
<div class="form-check form-switch ec-effective-switch">
|
|
<input type="checkbox"
|
|
class="form-check-input"
|
|
checked="@isOn"
|
|
aria-label="Enable @Descriptor.OptionName"
|
|
title="Set @Descriptor.OptionName"
|
|
@onchange="OnCheckedChange"
|
|
@onfocusout="OnCommitRequested" />
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
@* Intentionally show both Default and Disabled as "Disabled" (product choice: collapse unset and off). Do not "fix" to show "Default" for unset. *@
|
|
@(GetState() == ExplicitToggleState.Enabled ? "Enabled" : "Disabled")
|
|
}
|
|
|
|
@code {
|
|
private ExplicitToggleState _stateAtActivation;
|
|
private bool _wasActiveEditor;
|
|
|
|
private ExplicitToggleState GetState()
|
|
{
|
|
var v = GetEffectiveDisplayValue();
|
|
if (v is ExplicitToggleState s) return s;
|
|
return ExplicitToggleState.Default;
|
|
}
|
|
|
|
protected override void OnParametersSet()
|
|
{
|
|
if (!IsActiveEditor)
|
|
_stateAtActivation = GetState();
|
|
else if (!_wasActiveEditor)
|
|
_stateAtActivation = GetState();
|
|
_wasActiveEditor = IsActiveEditor;
|
|
}
|
|
|
|
private async Task OnCheckedChange(ChangeEventArgs e)
|
|
{
|
|
var isChecked = e.Value is true;
|
|
if (isChecked)
|
|
{
|
|
await NotifyValueChanged(ExplicitToggleState.Enabled);
|
|
return;
|
|
}
|
|
|
|
var pending = Session?.Draft.PendingChanges.OfType<PendingOptionChange>().FirstOrDefault(c =>
|
|
string.Equals(c.SectionId, Descriptor.SectionId, StringComparison.OrdinalIgnoreCase) &&
|
|
string.Equals(c.OptionName, Descriptor.OptionName, StringComparison.OrdinalIgnoreCase));
|
|
if (pending?.OldValue is ExplicitToggleState previousState)
|
|
{
|
|
await NotifyValueChanged(previousState);
|
|
return;
|
|
}
|
|
|
|
// No existing pending edit for this field: map unchecked based on the state at activation.
|
|
// Default and Disabled both display as "Disabled" in view mode, so we preserve true intent here.
|
|
await NotifyValueChanged(_stateAtActivation == ExplicitToggleState.Default ? ExplicitToggleState.Default : ExplicitToggleState.Disabled);
|
|
}
|
|
}
|