using ZA.CoreService.ESBCertificateManager.Models; using ZA.CoreService.ESBCertificateManager.Services; namespace ZA.CoreService.ESBCertificateManager.Setup; public sealed class SelectContainersForm : Form { private readonly SetupCoordinator _coordinator; private readonly SonicSystemOption _system; private readonly SonicContainerScanner _scanner; private readonly ComboBox _cmbCompany; private readonly CheckedListBox _lstContainers; private readonly TextBox _txtManual; private readonly TextBox _txtUser; private readonly TextBox _txtPassword; private readonly Label _lblStatus; private readonly Button _btnScan; private readonly Button _btnSave; private bool _running; public int SavedCount { get; private set; } public SelectContainersForm( SetupCoordinator coordinator, SonicSystemOption system) { _coordinator = coordinator; _system = system; _scanner = new SonicContainerScanner(coordinator.Settings.Runtime); Text = "Container auswählen"; StartPosition = FormStartPosition.CenterParent; FormBorderStyle = FormBorderStyle.FixedDialog; MaximizeBox = false; MinimizeBox = false; ShowInTaskbar = false; ClientSize = new Size(640, 620); BackColor = SettingsUi.Background; ForeColor = SettingsUi.Text; Font = new Font("Segoe UI", 10f); Label title = new() { Text = "Container für System", Location = new Point(28, 20), AutoSize = true, Font = new Font("Segoe UI Semibold", 18f, FontStyle.Bold), ForeColor = SettingsUi.Text }; Label subtitle = new() { Text = $"{system.ConnectionName} · {system.ConnectionUrl}" + Environment.NewLine + "Scan von Sonic oder manuell eintragen, dann übernehmen.", Location = new Point(30, 54), Size = new Size(580, 40), ForeColor = SettingsUi.Muted }; Panel card = SettingsUi.CreateCard(); card.Location = new Point(28, 110); card.Size = new Size(584, 430); card.Paint += SettingsUi.PaintCardBorder; _cmbCompany = SettingsUi.CreateComboBox(); _lstContainers = new CheckedListBox { BackColor = Color.FromArgb(12, 28, 48), ForeColor = SettingsUi.Text, BorderStyle = BorderStyle.FixedSingle, CheckOnClick = true, Font = new Font("Segoe UI", 10f) }; _txtManual = SettingsUi.CreateTextBox(); _txtUser = SettingsUi.CreateTextBox(); _txtPassword = SettingsUi.CreateTextBox(); _txtPassword.UseSystemPasswordChar = true; AddField(card, "Company", _cmbCompany, 18, 16, 540); AddField(card, "Gefundene / gewählte Container", _lstContainers, 18, 76, 540, 150); Label manualLabel = SettingsUi.CreateFieldLabel("Manuell hinzufügen"); manualLabel.Location = new Point(18, 240); _txtManual.Location = new Point(18, 262); _txtManual.Width = 400; Button btnAddManual = SettingsUi.CreateGhostButton("+"); btnAddManual.Location = new Point(430, 260); btnAddManual.Size = new Size(50, 32); btnAddManual.Click += (_, _) => AddManualContainer(); Button btnSuggest = SettingsUi.CreateGhostButton("ct-ZADBService"); btnSuggest.Location = new Point(490, 260); btnSuggest.Size = new Size(68, 32); btnSuggest.Font = new Font("Segoe UI", 7.5f, FontStyle.Bold); btnSuggest.Click += (_, _) => { _txtManual.Text = "ct-ZADBService"; AddManualContainer(); }; AddField(card, "Sonic-Benutzer (für Scan)", _txtUser, 18, 308, 250); AddField(card, "Kennwort", _txtPassword, 288, 308, 270); _btnScan = SettingsUi.CreatePrimaryButton("Von Sonic scannen"); _btnScan.Location = new Point(18, 375); _btnScan.Size = new Size(200, 36); _btnScan.Click += async (_, _) => await ScanAsync(); _lblStatus = new Label { Location = new Point(230, 380), Size = new Size(330, 30), ForeColor = SettingsUi.Muted }; card.Controls.Add(manualLabel); card.Controls.Add(_txtManual); card.Controls.Add(btnAddManual); card.Controls.Add(btnSuggest); card.Controls.Add(_btnScan); card.Controls.Add(_lblStatus); _btnSave = SettingsUi.CreatePrimaryButton("Auswahl speichern"); _btnSave.Location = new Point(352, 555); _btnSave.Size = new Size(260, 42); _btnSave.Click += async (_, _) => await SaveAsync(); Button skip = SettingsUi.CreateGhostButton("Später"); skip.Location = new Point(230, 555); skip.Size = new Size(110, 42); skip.Click += (_, _) => { DialogResult = DialogResult.Cancel; Close(); }; Controls.Add(title); Controls.Add(subtitle); Controls.Add(card); Controls.Add(skip); Controls.Add(_btnSave); Shown += async (_, _) => await InitializeAsync(); } private async Task InitializeAsync() { try { IReadOnlyList companies = await _coordinator.LoadCompaniesAsync(); _cmbCompany.Items.Clear(); foreach (CompanyOption company in companies) { _cmbCompany.Items.Add(company); } if (_cmbCompany.Items.Count > 0) { int deIndex = 0; for (int index = 0; index < companies.Count; index++) { if (string.Equals( companies[index].CompanyCode, "DE", StringComparison.OrdinalIgnoreCase)) { deIndex = index; break; } } _cmbCompany.SelectedIndex = deIndex; } IReadOnlyList profiles = await _coordinator.LoadCredentialsAsync( _system.SonicConnectionId); SonicCredentialProfile? profile = profiles.FirstOrDefault(item => item.IsDefault) ?? profiles.FirstOrDefault(); if (profile is not null) { _txtUser.Text = profile.UserName; _txtPassword.Text = profile.Secret; _lblStatus.Text = "Profil geladen — Scan möglich."; _lblStatus.ForeColor = SettingsUi.Green; } else { _lblStatus.Text = "Kein Profil — Benutzer/Kennwort für Scan eingeben oder manuell."; _lblStatus.ForeColor = SettingsUi.Gold; } // Bereits vorhandene Container vorselektieren IReadOnlyList existing = await _coordinator.LoadContainersAsync( _system.SonicConnectionId); foreach (ContainerOption container in existing) { AddContainerName(container.ContainerName, check: true); } } catch (Exception ex) { _lblStatus.Text = ex.Message; _lblStatus.ForeColor = SettingsUi.Red; } } private void AddManualContainer() { string name = _txtManual.Text.Trim(); if (name.Length == 0) { return; } AddContainerName(name, check: true); _txtManual.Clear(); _txtManual.Focus(); } private void AddContainerName(string name, bool check) { for (int index = 0; index < _lstContainers.Items.Count; index++) { if (string.Equals( _lstContainers.Items[index]?.ToString(), name, StringComparison.OrdinalIgnoreCase)) { _lstContainers.SetItemChecked(index, check); return; } } int added = _lstContainers.Items.Add(name); _lstContainers.SetItemChecked(added, check); } private async Task ScanAsync() { if (_running) { return; } _running = true; _btnScan.Enabled = false; _btnSave.Enabled = false; Cursor = Cursors.WaitCursor; _lblStatus.Text = "Scanne Domain…"; _lblStatus.ForeColor = SettingsUi.Muted; try { ContainerScanResult result = await _scanner.ScanAsync( _system, _txtUser.Text, _txtPassword.Text); if (!result.Success) { _lblStatus.Text = result.Message; _lblStatus.ForeColor = SettingsUi.Red; return; } foreach (string container in result.Containers) { AddContainerName(container, check: true); } _lblStatus.Text = result.Containers.Count == 0 ? "Scan OK, aber keine Container gefunden — bitte manuell." : $"{result.Containers.Count} Container gescannt und vorausgewählt."; _lblStatus.ForeColor = result.Containers.Count == 0 ? SettingsUi.Gold : SettingsUi.Green; } catch (Exception ex) { _lblStatus.Text = ex.Message; _lblStatus.ForeColor = SettingsUi.Red; } finally { _running = false; _btnScan.Enabled = true; _btnSave.Enabled = true; Cursor = Cursors.Default; } } private async Task SaveAsync() { if (_running) { return; } if (_cmbCompany.SelectedItem is not CompanyOption company) { MessageBox.Show( this, "Bitte eine Company wählen.", "Container", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } List selected = _lstContainers.CheckedItems .Cast() .Select(item => item.ToString() ?? string.Empty) .Where(name => name.Length > 0) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); if (selected.Count == 0) { MessageBox.Show( this, "Bitte mindestens einen Container angehakt lassen " + "oder manuell hinzufügen.", "Container", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } _running = true; _btnSave.Enabled = false; Cursor = Cursors.WaitCursor; try { IReadOnlyList existing = await _coordinator.LoadContainersAsync( _system.SonicConnectionId); HashSet existingNames = existing .Select(item => item.ContainerName) .ToHashSet(StringComparer.OrdinalIgnoreCase); int created = 0; foreach (string containerName in selected) { if (existingNames.Contains(containerName)) { continue; } await _coordinator.AddSonicContainerAsync( company.CompanyId, _system.SonicConnectionId, containerName, containerDisplayName: null, restartTimeoutSeconds: 180); created++; } SavedCount = created; MessageBox.Show( this, created == 0 ? "Alle gewählten Container waren bereits vorhanden." : $"{created} Container gespeichert und geprüft.", "Prüfung OK", MessageBoxButtons.OK, MessageBoxIcon.Information); DialogResult = DialogResult.OK; Close(); } catch (Exception ex) { MessageBox.Show( this, ex.Message, "Container", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { _running = false; _btnSave.Enabled = true; Cursor = Cursors.Default; } } private static void AddField( Control parent, string label, Control input, int x, int y, int width, int height = 30) { Label fieldLabel = SettingsUi.CreateFieldLabel(label); fieldLabel.Location = new Point(x, y); input.Location = new Point(x, y + 22); input.Width = width; input.Height = height; parent.Controls.Add(fieldLabel); parent.Controls.Add(input); } }