diff --git a/ZA.CoreService.ESBCertificateManager/Form1.cs b/ZA.CoreService.ESBCertificateManager/Form1.cs index 010f4dc..052c989 100644 --- a/ZA.CoreService.ESBCertificateManager/Form1.cs +++ b/ZA.CoreService.ESBCertificateManager/Form1.cs @@ -65,10 +65,9 @@ namespace ZA.CoreService.ESBCertificateManager private Button btnMinimize = null!; private Button btnMaximize = null!; private Button btnClose = null!; - private Button btnValidate = null!; private Button btnDeploy = null!; - private Button btnRestartOnly = null!; private Button btnCancelRun = null!; + private ContextMenuStrip _targetRowMenu = null!; private bool isMaximized = false; private Point dragStartPoint; @@ -1377,6 +1376,55 @@ namespace ZA.CoreService.ESBCertificateManager dgvTargets.Columns.Add("Container", "Neustart-Container"); dgvTargets.Columns.Add("Status", "Status"); + DataGridViewButtonColumn actionsColumn = new DataGridViewButtonColumn + { + Name = "Actions", + HeaderText = "", + Text = "⋮", + UseColumnTextForButtonValue = true, + FillWeight = 18, + FlatStyle = FlatStyle.Flat + }; + actionsColumn.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; + actionsColumn.DefaultCellStyle.ForeColor = MutedTextColor; + actionsColumn.DefaultCellStyle.SelectionForeColor = TextColor; + dgvTargets.Columns.Add(actionsColumn); + + _targetRowMenu = new ContextMenuStrip(); + ToolStripMenuItem restartMenuItem = new ToolStripMenuItem("Manuell neu starten"); + restartMenuItem.Click += async (_, _) => + { + if (_targetRowMenu.Tag is DeploymentTarget target) + { + await RunRestartOnlyAsync([target]); + } + }; + _targetRowMenu.Items.Add(restartMenuItem); + + dgvTargets.CellContentClick += (_, e) => + { + if (e.RowIndex < 0 + || e.ColumnIndex < 0 + || dgvTargets.Columns[e.ColumnIndex].Name != "Actions") + { + return; + } + + if (dgvTargets.Rows[e.RowIndex].Tag is not DeploymentTarget target) + { + return; + } + + _targetRowMenu.Tag = target; + Rectangle cellRect = dgvTargets.GetCellDisplayRectangle( + e.ColumnIndex, + e.RowIndex, + true); + Point screenLocation = dgvTargets.PointToScreen( + new Point(cellRect.Left, cellRect.Bottom)); + _targetRowMenu.Show(screenLocation); + }; + dgvTargets.CurrentCellDirtyStateChanged += (_, _) => { if (dgvTargets.IsCurrentCellDirty @@ -1428,26 +1476,12 @@ namespace ZA.CoreService.ESBCertificateManager SetStatus("Abbruch angefordert…", isError: false); }; - btnValidate = CreateSecondaryButton("Prüfung durchführen"); - btnValidate.Size = new Size(175, 42); - btnValidate.Anchor = AnchorStyles.Top | AnchorStyles.Right; - btnValidate.Click += async (_, _) => await RunValidationAsync(); - - // Primäraktion: Neustart (Deploy vorerst deaktiviert – Design/Layout bleibt) - btnRestartOnly = CreatePrimaryButton("ESB neu starten"); - btnRestartOnly.Size = new Size(170, 42); - btnRestartOnly.Anchor = AnchorStyles.Top | AnchorStyles.Right; - btnRestartOnly.Click += async (_, _) => await RunRestartOnlyAsync(); - btnDeploy = CreatePrimaryButton("Austauschen + Neustart"); - btnDeploy.Size = new Size(190, 42); + btnDeploy.Size = new Size(220, 42); btnDeploy.Anchor = AnchorStyles.Top | AnchorStyles.Right; - btnDeploy.Visible = true; btnDeploy.Click += async (_, _) => await RunDeploymentAsync(); panel.Controls.Add(btnCancelRun); - panel.Controls.Add(btnValidate); - panel.Controls.Add(btnRestartOnly); panel.Controls.Add(btnDeploy); void PositionActionButtons() @@ -1455,12 +1489,8 @@ namespace ZA.CoreService.ESBCertificateManager const int spacing = 12; const int rightMargin = 0; - // Rechts nach links anordnen: - // Deployment | Neustart | Prüfung | Abbrechen btnDeploy.Left = panel.ClientSize.Width - btnDeploy.Width - rightMargin; - btnRestartOnly.Left = btnDeploy.Left - btnRestartOnly.Width - spacing; - btnValidate.Left = btnRestartOnly.Left - btnValidate.Width - spacing; - btnCancelRun.Left = btnValidate.Left - btnCancelRun.Width - spacing; + btnCancelRun.Left = btnDeploy.Left - btnCancelRun.Width - spacing; } panel.Resize += (_, _) => PositionActionButtons(); @@ -1780,14 +1810,13 @@ namespace ZA.CoreService.ESBCertificateManager private void RefreshActionButtonStates() { - if (btnValidate is null || btnDeploy is null || btnCancelRun is null) + if (btnDeploy is null || btnCancelRun is null) { return; } bool idle = !_isOperationRunning; bool hasCertificate = isCertificateFileLoaded && _loadedCertificateInfo is not null; - bool hasTargets = _loadedTargets.Count > 0; bool hasSelection = dgvTargets is not null && GetSelectedTargets().Count > 0; if (btnSelectFile is not null) @@ -1796,14 +1825,7 @@ namespace ZA.CoreService.ESBCertificateManager } btnCancelRun.Enabled = _isOperationRunning; - // Prüfung nur für Neustart-Voraussetzungen (Zertifikat optional) - btnValidate.Enabled = idle && hasTargets; - btnDeploy.Visible = true; btnDeploy.Enabled = idle && hasCertificate && hasSelection; - if (btnRestartOnly is not null) - { - btnRestartOnly.Enabled = idle && hasSelection; - } if (dgvTargets is not null) { @@ -1840,64 +1862,7 @@ namespace ZA.CoreService.ESBCertificateManager MessageBox.Show(this, details, caption, MessageBoxButtons.OK, MessageBoxIcon.Warning); } - private Task RunValidationAsync() - { - if (_orchestrator is null) - { - SetStatus( - "Die Anwendung ist noch nicht vollständig initialisiert.", - isError: true); - - return Task.CompletedTask; - } - if (_isOperationRunning) - { - return Task.CompletedTask; - } - - List selected = GetSelectedTargets(); - PreflightValidationResult result = _orchestrator.ValidateRestartOnly(selected); - - HashSet failedTargetIds = result.Issues - .Where(i => i.TargetId is not null) - .Select(i => i.TargetId!.Value) - .ToHashSet(); - - foreach (DataGridViewRow row in dgvTargets.Rows) - { - if (row.Tag is not DeploymentTarget target) - { - continue; - } - - if (failedTargetIds.Contains(target.Id)) - { - SetTargetRowStatus(target.Id, "Prüfung fehlgeschlagen"); - } - else if (row.Cells["Selected"].Value is true) - { - SetTargetRowStatus(target.Id, "Bereit"); - } - } - - if (!result.IsValid) - { - ShowPreflightIssues(result, "Vorabprüfung fehlgeschlagen.", "Vorabprüfung"); - return Task.CompletedTask; - } - - UpdateToNextStep(3); - SetStatus($"Vorabprüfung ok – {selected.Count} Ziel(e) bereit.", isError: false); - MessageBox.Show( - this, - "Prüfung OK.", - "Vorabprüfung", - MessageBoxButtons.OK, - MessageBoxIcon.Information); - return Task.CompletedTask; - } - - private async Task RunRestartOnlyAsync() + private async Task RunRestartOnlyAsync(IReadOnlyList targets) { if (_orchestrator is null) { @@ -1912,7 +1877,13 @@ namespace ZA.CoreService.ESBCertificateManager return; } - List selected = GetSelectedTargets(); + List selected = [.. targets]; + if (selected.Count == 0) + { + SetStatus("Kein Ziel für den Neustart ausgewählt.", isError: true); + return; + } + PreflightValidationResult preflight = _orchestrator.ValidateRestartOnly(selected); if (!preflight.IsValid) @@ -1920,14 +1891,18 @@ namespace ZA.CoreService.ESBCertificateManager ShowPreflightIssues( preflight, "Neustart blockiert – Vorabprüfung fehlgeschlagen.", - "ESB neu starten"); + "Manuell neu starten"); return; } + string targetLabel = selected.Count == 1 + ? selected[0].Name + : $"{selected.Count} Ziele"; + DialogResult confirm = MessageBox.Show( this, - "Neu starten?", - "ESB neu starten", + $"Container für „{targetLabel}“ neu starten?", + "Manuell neu starten", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); @@ -1940,7 +1915,7 @@ namespace ZA.CoreService.ESBCertificateManager _runCts = new CancellationTokenSource(); SetOperationRunning(true); UpdateToNextStep(3); - SetStatus($"ESB-Neustart läuft für {selected.Count} Ziel(e)…", isError: false); + SetStatus($"Neustart läuft für {selected.Count} Ziel(e)…", isError: false); Progress progress = new(update => { @@ -1969,6 +1944,13 @@ namespace ZA.CoreService.ESBCertificateManager if (runResult.OverallSuccess) { UpdateToNextStep(4); + + HashSet restartedTargetIds = runResult.TargetResults + .Where(result => result.Success) + .Select(result => result.TargetId) + .ToHashSet(); + + await ProbeTargetCertificatesAsync(restartedTargetIds); } else {