feat: move test buttons to right panel, add user auth dialog for reports

Move Start/Stop/Report buttons from the middle panel to the top of
TestPanelView (automated tests section), matching the old application
layout. Remove inline Operator/Client text fields — operator identity
now comes from a UserCheckDialog (username/password) shown before the
existing ReportDialog. Add credential storage to ConfigurationService.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-11 16:41:20 +02:00
parent d34e81163a
commit 4964806de1
10 changed files with 267 additions and 53 deletions

View File

@@ -94,7 +94,8 @@ namespace HC_APTBS.Services.Impl
new XElement("ReportLogoPath", Settings.ReportLogoPath),
new XElement("KLinePort", Settings.KLinePort),
new XElement("Language", Settings.Language),
new XElement("Relations", RpmVoltageRelation.Serialise(Settings.Relations))
new XElement("Relations", RpmVoltageRelation.Serialise(Settings.Relations)),
new XElement("Users", Settings.Users)
);
new XDocument(root).Save(ConfigXml);
SaveSensors();
@@ -355,6 +356,7 @@ namespace HC_APTBS.Services.Impl
TryString(r, "KLinePort", v => _settings.KLinePort = v);
TryString(r, "Language", v => _settings.Language = v);
TryString(r, "Relations", v => _settings.Relations = RpmVoltageRelation.Deserialise(v));
TryString(r, "Users", v => _settings.Users = v);
}
catch (Exception ex)
{
@@ -640,6 +642,46 @@ namespace HC_APTBS.Services.Impl
try { var v = root.Element(name)?.Value; if (v != null) assign(v); }
catch { }
}
// ── Users ─────────────────────────────────────────────────────────────────
/// <inheritdoc/>
public bool ValidateUser(string username, string password)
{
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
return false;
string check = username + ":" + password;
foreach (string entry in Settings.Users.Split(','))
{
if (entry == check) return true;
}
return false;
}
/// <inheritdoc/>
public IReadOnlyDictionary<string, string> GetUsers()
{
var dict = new Dictionary<string, string>();
foreach (string kv in Settings.Users.Split(','))
{
string[] parts = kv.Split(':');
if (parts.Length == 2 && parts[0].Length > 0)
dict[parts[0]] = parts[1];
}
return dict;
}
/// <inheritdoc/>
public void UpdateUsers(Dictionary<string, string> users)
{
var entries = new List<string>(users.Count);
foreach (var kv in users)
entries.Add(kv.Key + ":" + kv.Value);
Settings.Users = string.Join(",", entries);
SaveSettings();
}
}
// ── XPath extension shim ──────────────────────────────────────────────────────