Add edit and delete for systems, containers, and paths in settings.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-31 08:12:15 +02:00
co-authored by Cursor
parent aac71ec2cd
commit 89a694ba21
6 changed files with 979 additions and 98 deletions
@@ -368,8 +368,9 @@ public sealed class SetupWizardForm : Form
"Management-Verbindungen der aktuellen Umgebung.");
Panel toolbar = CreateToolbar(
"+ System hinzufügen",
async () => await AddSystemAsync());
("+ System hinzufügen", async () => await AddSystemAsync(), true, 210),
("Bearbeiten", async () => await EditSelectedSystemAsync(), false, 130),
("Löschen", async () => await DeleteSelectedSystemAsync(), false, 120));
_lvSystems = SettingsUi.CreateListView();
_lvSystems.Dock = DockStyle.Fill;
@@ -379,6 +380,7 @@ public sealed class SetupWizardForm : Form
_lvSystems.Columns.Add("Domain", 180);
_lvSystems.Columns.Add("Protokoll", 80);
_lvSystems.Columns.Add("URL", 180);
_lvSystems.DoubleClick += async (_, _) => await EditSelectedSystemAsync();
FinishPanelLayout(_panelSystems, _lvSystems, toolbar);
}
@@ -390,8 +392,9 @@ public sealed class SetupWizardForm : Form
"Sonic-Container je Company und System.");
Panel toolbar = CreateToolbar(
"+ Container hinzufügen",
async () => await AddContainerAsync());
("+ Container hinzufügen", async () => await AddContainerAsync(), true, 220),
("Bearbeiten", async () => await EditSelectedContainerAsync(), false, 130),
("Löschen", async () => await DeleteSelectedContainerAsync(), false, 120));
_lvContainers = SettingsUi.CreateListView();
_lvContainers.Dock = DockStyle.Fill;
@@ -400,6 +403,7 @@ public sealed class SetupWizardForm : Form
_lvContainers.Columns.Add("Anzeige", 160);
_lvContainers.Columns.Add("System", 160);
_lvContainers.Columns.Add("Timeout", 90);
_lvContainers.DoubleClick += async (_, _) => await EditSelectedContainerAsync();
FinishPanelLayout(_panelContainers, _lvContainers, toolbar);
}
@@ -411,12 +415,10 @@ public sealed class SetupWizardForm : Form
"Dateipfade (UNC/lokal) zum Austausch. Container = nur Neustart-Ziel.");
Panel toolbar = CreateToolbar(
"+ Pfad hinzufügen",
async () => await AddPathAsync(),
"Pfad prüfen",
async () => await ProbeSelectedPathAsync(),
"Pfad löschen",
async () => await DeleteSelectedPathAsync());
("+ Pfad hinzufügen", async () => await AddPathAsync(), true, 190),
("Bearbeiten", async () => await EditSelectedPathAsync(), false, 120),
("Pfad prüfen", async () => await ProbeSelectedPathAsync(), false, 130),
("Löschen", async () => await DeleteSelectedPathAsync(), false, 110));
_lvPaths = SettingsUi.CreateListView();
_lvPaths.Dock = DockStyle.Fill;
@@ -426,17 +428,13 @@ public sealed class SetupWizardForm : Form
_lvPaths.Columns.Add("Ablauf", 140);
_lvPaths.Columns.Add("Backup", 80);
_lvPaths.Columns.Add("System", 120);
_lvPaths.DoubleClick += async (_, _) => await EditSelectedPathAsync();
FinishPanelLayout(_panelPaths, _lvPaths, toolbar);
}
private Panel CreateToolbar(
string addButtonText,
Func<Task> onAdd,
string? secondaryText = null,
Func<Task>? onSecondary = null,
string? tertiaryText = null,
Func<Task>? onTertiary = null)
private static Panel CreateToolbar(
params (string Text, Func<Task> Action, bool Primary, int Width)[] buttons)
{
Panel toolbar = new()
{
@@ -446,32 +444,23 @@ public sealed class SetupWizardForm : Form
Padding = new Padding(8, 8, 8, 8)
};
Button add = SettingsUi.CreatePrimaryButton(addButtonText);
add.Dock = DockStyle.Left;
add.Width = 230;
add.Click += async (_, _) => await onAdd();
if (tertiaryText is not null && onTertiary is not null)
// Dock Left: zuletzt hinzugefügt erscheint ganz links
for (int index = buttons.Length - 1; index >= 0; index--)
{
Button tertiary = SettingsUi.CreateGhostButton(tertiaryText);
tertiary.Dock = DockStyle.Left;
tertiary.Width = 140;
tertiary.Margin = new Padding(8, 0, 0, 0);
tertiary.Click += async (_, _) => await onTertiary();
toolbar.Controls.Add(tertiary);
(string text, Func<Task> action, bool primary, int width) =
buttons[index];
Button button = primary
? SettingsUi.CreatePrimaryButton(text)
: SettingsUi.CreateGhostButton(text);
button.Dock = DockStyle.Left;
button.Width = width;
button.Margin = new Padding(8, 0, 0, 0);
button.Click += async (_, _) => await action();
toolbar.Controls.Add(button);
}
if (secondaryText is not null && onSecondary is not null)
{
Button secondary = SettingsUi.CreateGhostButton(secondaryText);
secondary.Dock = DockStyle.Left;
secondary.Width = 180;
secondary.Margin = new Padding(8, 0, 0, 0);
secondary.Click += async (_, _) => await onSecondary();
toolbar.Controls.Add(secondary);
}
toolbar.Controls.Add(add);
return toolbar;
}
@@ -810,6 +799,90 @@ public sealed class SetupWizardForm : Form
return;
}
await AfterSystemSavedAsync(createdId, created: true);
}
private async Task EditSelectedSystemAsync()
{
if (_lvSystems.SelectedItems.Count == 0
|| _lvSystems.SelectedItems[0].Tag is not SonicSystemOption system)
{
MessageBox.Show(
this,
"Bitte zuerst ein Sonic-System in der Liste wählen.",
"System bearbeiten",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
return;
}
using AddSonicSystemForm dialog = new(_coordinator, system);
if (dialog.ShowDialog(this) != DialogResult.OK
|| dialog.CreatedSonicConnectionId is not int savedId)
{
return;
}
await AfterSystemSavedAsync(savedId, created: false);
}
private async Task DeleteSelectedSystemAsync()
{
if (_lvSystems.SelectedItems.Count == 0
|| _lvSystems.SelectedItems[0].Tag is not SonicSystemOption system)
{
MessageBox.Show(
this,
"Bitte zuerst ein Sonic-System in der Liste wählen.",
"System löschen",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
return;
}
DialogResult confirm = MessageBox.Show(
this,
"Sonic-System wirklich aus der Konfiguration entfernen?\n\n"
+ $"{system.ConnectionName}\n"
+ $"{system.ConnectionUrl}\n\n"
+ "Zugehörige Container und Pfade verschwinden aus den Listen. "
+ "Der Eintrag wird in SQL nur deaktiviert (IsActive=0).",
"System löschen",
MessageBoxButtons.YesNo,
MessageBoxIcon.Warning);
if (confirm != DialogResult.Yes)
{
return;
}
try
{
await _coordinator.DeactivateSonicConnectionAsync(
system.SonicConnectionId);
await LoadSystemsListAsync();
await LoadContainersListAsync();
await LoadPathsListAsync();
await LoadSystemsAsync();
await RefreshAllAsync();
MessageBox.Show(
this,
$"System Id {system.SonicConnectionId} wurde deaktiviert.",
"System gelöscht",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
catch (Exception ex)
{
ShowError(ex.Message);
}
}
private async Task AfterSystemSavedAsync(int systemId, bool created)
{
await LoadSystemsListAsync();
await LoadSystemsAsync();
await RefreshAllAsync();
@@ -818,13 +891,13 @@ public sealed class SetupWizardForm : Form
.Cast<ListViewItem>()
.Any(item =>
item.Tag is SonicSystemOption system
&& system.SonicConnectionId == createdId);
&& system.SonicConnectionId == systemId);
if (!visible)
{
ShowError(
$"Anlage-Prüfung fehlgeschlagen: System-Id {createdId} " +
"ist nach dem Speichern nicht in der Liste.");
$"{(created ? "Anlage" : "Update")}-Prüfung fehlgeschlagen: "
+ $"System-Id {systemId} ist nach dem Speichern nicht in der Liste.");
return;
}
@@ -832,11 +905,13 @@ public sealed class SetupWizardForm : Form
_lvSystems,
item =>
item.Tag is SonicSystemOption system
&& system.SonicConnectionId == createdId);
&& system.SonicConnectionId == systemId);
MessageBox.Show(
this,
$"System wurde gespeichert und geprüft (Id {createdId}).",
created
? $"System wurde gespeichert und geprüft (Id {systemId})."
: $"System wurde aktualisiert und geprüft (Id {systemId}).",
"Prüfung OK",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
@@ -860,6 +935,96 @@ public sealed class SetupWizardForm : Form
return;
}
await AfterContainerSavedAsync(createdId, created: true);
}
private async Task EditSelectedContainerAsync()
{
if (_lvContainers.SelectedItems.Count == 0
|| _lvContainers.SelectedItems[0].Tag is not ContainerOption container)
{
MessageBox.Show(
this,
"Bitte zuerst einen Container in der Liste wählen.",
"Container bearbeiten",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
return;
}
using AddContainerForm dialog = new(
_coordinator,
container.SonicConnectionId,
container);
if (dialog.ShowDialog(this) != DialogResult.OK
|| dialog.CreatedSonicContainerId is not int savedId)
{
return;
}
await AfterContainerSavedAsync(savedId, created: false);
}
private async Task DeleteSelectedContainerAsync()
{
if (_lvContainers.SelectedItems.Count == 0
|| _lvContainers.SelectedItems[0].Tag is not ContainerOption container)
{
MessageBox.Show(
this,
"Bitte zuerst einen Container in der Liste wählen.",
"Container löschen",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
return;
}
string display =
string.IsNullOrWhiteSpace(container.ContainerDisplayName)
? container.ContainerName
: container.ContainerDisplayName;
DialogResult confirm = MessageBox.Show(
this,
"Container wirklich aus der Konfiguration entfernen?\n\n"
+ $"{container.CompanyCode} / {display}\n"
+ $"System: {container.ConnectionName}\n\n"
+ "Zugehörige Zertifikat-Pfade verschwinden aus der Liste. "
+ "Der Eintrag wird in SQL nur deaktiviert (IsActive=0).",
"Container löschen",
MessageBoxButtons.YesNo,
MessageBoxIcon.Warning);
if (confirm != DialogResult.Yes)
{
return;
}
try
{
await _coordinator.DeactivateSonicContainerAsync(
container.SonicContainerId);
await LoadContainersListAsync();
await LoadPathsListAsync();
await RefreshAllAsync();
MessageBox.Show(
this,
$"Container Id {container.SonicContainerId} wurde deaktiviert.",
"Container gelöscht",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
catch (Exception ex)
{
ShowError(ex.Message);
}
}
private async Task AfterContainerSavedAsync(int containerId, bool created)
{
await LoadContainersListAsync();
await LoadSystemsListAsync();
await RefreshAllAsync();
@@ -868,13 +1033,13 @@ public sealed class SetupWizardForm : Form
.Cast<ListViewItem>()
.Any(item =>
item.Tag is ContainerOption container
&& container.SonicContainerId == createdId);
&& container.SonicContainerId == containerId);
if (!visible)
{
ShowError(
$"Anlage-Prüfung fehlgeschlagen: Container-Id {createdId} " +
"ist nach dem Speichern nicht in der Liste.");
$"{(created ? "Anlage" : "Update")}-Prüfung fehlgeschlagen: "
+ $"Container-Id {containerId} ist nach dem Speichern nicht in der Liste.");
return;
}
@@ -882,11 +1047,13 @@ public sealed class SetupWizardForm : Form
_lvContainers,
item =>
item.Tag is ContainerOption container
&& container.SonicContainerId == createdId);
&& container.SonicContainerId == containerId);
MessageBox.Show(
this,
$"Container wurde gespeichert und geprüft (Id {createdId}).",
created
? $"Container wurde gespeichert und geprüft (Id {containerId})."
: $"Container wurde aktualisiert und geprüft (Id {containerId}).",
"Prüfung OK",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
@@ -910,6 +1077,39 @@ public sealed class SetupWizardForm : Form
return;
}
await AfterPathSavedAsync(createdId, created: true);
}
private async Task EditSelectedPathAsync()
{
if (_lvPaths.SelectedItems.Count == 0
|| _lvPaths.SelectedItems[0].Tag is not CertificateTargetOption target)
{
MessageBox.Show(
this,
"Bitte zuerst einen Zertifikat-Pfad in der Liste wählen.",
"Pfad bearbeiten",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
return;
}
using AddTargetPathForm dialog = new(
_coordinator,
target.SonicContainerId,
target);
if (dialog.ShowDialog(this) != DialogResult.OK
|| dialog.CreatedCertificateTargetId is not int savedId)
{
return;
}
await AfterPathSavedAsync(savedId, created: false);
}
private async Task AfterPathSavedAsync(int pathId, bool created)
{
await LoadPathsListAsync();
await RefreshAllAsync();
@@ -917,13 +1117,13 @@ public sealed class SetupWizardForm : Form
.Cast<ListViewItem>()
.Any(item =>
item.Tag is CertificateTargetOption target
&& target.CertificateTargetId == createdId);
&& target.CertificateTargetId == pathId);
if (!visible)
{
ShowError(
$"Anlage-Prüfung fehlgeschlagen: Pfad-Id {createdId} " +
"ist nach dem Speichern nicht in der Liste.");
$"{(created ? "Anlage" : "Update")}-Prüfung fehlgeschlagen: "
+ $"Pfad-Id {pathId} ist nach dem Speichern nicht in der Liste.");
return;
}
@@ -931,11 +1131,13 @@ public sealed class SetupWizardForm : Form
_lvPaths,
item =>
item.Tag is CertificateTargetOption target
&& target.CertificateTargetId == createdId);
&& target.CertificateTargetId == pathId);
MessageBox.Show(
this,
$"Zertifikat-Pfad wurde gespeichert und geprüft (Id {createdId}).",
created
? $"Zertifikat-Pfad wurde gespeichert und geprüft (Id {pathId})."
: $"Zertifikat-Pfad wurde aktualisiert und geprüft (Id {pathId}).",
"Prüfung OK",
MessageBoxButtons.OK,
MessageBoxIcon.Information);