From d09fe2aadaaf6f4ec975ce0bf5acdaed3a9a0dc1 Mon Sep 17 00:00:00 2001 From: Maksym Sadovnychyy Date: Sun, 30 Aug 2026 18:01:58 +0200 Subject: [PATCH] (feature): bulk footer actions, origami branding, and sibling release assets --- CHANGELOG.md | 10 + CONTRIBUTING.md | 2 +- README.md | 8 +- src/Directory.Build.props | 2 +- .../ResourceActionBatch.cs | 53 + .../ResourceActionBatchTests.cs | 69 ++ src/MaksIT.ClusterConsole.UI/Assets/icon.ico | Bin 285478 -> 16914 bytes src/MaksIT.ClusterConsole.UI/Assets/icon.png | Bin 4624 -> 11426 bytes src/MaksIT.ClusterConsole.UI/Assets/icon.svg | 33 +- src/MaksIT.ClusterConsole.UI/MainWindow.axaml | 2 + .../MainWindow.axaml.cs | 53 +- .../Themes/Dark.axaml | 27 +- .../ViewModels/ClusterPageViewModel.Chat.cs | 12 +- .../ViewModels/ClusterPageViewModel.cs | 277 ++++-- utils/engines/release/scriptSettings.json | 69 +- utils/modules/Engine/EngineContext.psm1 | 32 + utils/modules/Engine/PluginSupport.psm1 | 4 +- utils/modules/ExternalCommandSupport.psm1 | 2 +- utils/plugins/Desktop/DesktopPackSupport.psm1 | 931 ++++++++++++++++++ utils/plugins/Desktop/FlatpakPack.psm1 | 445 +++++++++ utils/plugins/Desktop/WindowsInstaller.psm1 | 294 ++++++ .../Desktop/brand/HyperlinkSidebarTheme.xml | 139 +++ utils/plugins/Desktop/brand/logo-64.png | Bin 0 -> 2170 bytes utils/plugins/Desktop/brand/mark.ico | Bin 0 -> 23823 bytes utils/plugins/Desktop/brand/mark.png | Bin 0 -> 21108 bytes utils/plugins/Desktop/brand/mark.svg | 27 + utils/plugins/Desktop/brand/sidebar.png | Bin 0 -> 16934 bytes utils/plugins/DotNet/DotNetCreateArchive.psm1 | 43 +- utils/plugins/DotNet/DotNetPublish.psm1 | 178 +++- utils/plugins/DotNet/DotNetTest.psm1 | 5 +- utils/templates/Dockerfile.ci.dotnet | 22 - utils/templates/build/ci-dotnet-pack.sh | 13 - 32 files changed, 2530 insertions(+), 222 deletions(-) create mode 100644 src/MaksIT.ClusterConsole.Shared/ResourceActionBatch.cs create mode 100644 src/MaksIT.ClusterConsole.Tests/ResourceActionBatchTests.cs create mode 100644 utils/plugins/Desktop/DesktopPackSupport.psm1 create mode 100644 utils/plugins/Desktop/FlatpakPack.psm1 create mode 100644 utils/plugins/Desktop/WindowsInstaller.psm1 create mode 100644 utils/plugins/Desktop/brand/HyperlinkSidebarTheme.xml create mode 100644 utils/plugins/Desktop/brand/logo-64.png create mode 100644 utils/plugins/Desktop/brand/mark.ico create mode 100644 utils/plugins/Desktop/brand/mark.png create mode 100644 utils/plugins/Desktop/brand/mark.svg create mode 100644 utils/plugins/Desktop/brand/sidebar.png delete mode 100644 utils/templates/Dockerfile.ci.dotnet delete mode 100644 utils/templates/build/ci-dotnet-pack.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ae2b3d..ce9c326 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ## [Unreleased] +## [0.6.0] - 2026-08-30 + +### Fixed + +- Footer actions that can run independently now apply to every selected table row (Restart, Scale, Delete, Force delete, Force delete namespace, Cordon, Uncordon, Drain, Trigger, Stop port-forward), not only the current row. + +### Changed + +- Dark UI uses the MAKS.IT origami blues (`#33A5CF` highlight, `#006199` accent). Window/installer/Flatpak icon is a faceted cluster of nodes with a console chevron (not the brand M). GitHub release assets are siblings: portable `maksit-cluster-console-{version}.zip` (win-x64 only), Windows setup `maksit-cluster-console-{version}.exe`, and `maksit-cluster-console-{version}.flatpak`. The installer and Flatpak are not packed inside the zip. On Windows the Flatpak bundle is built via WSL Debian. + ## [0.5.1] - 2026-08-24 ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7ac4c6c..072f0e5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,7 +27,7 @@ Coverage shields in `README.md` are rewritten by **CoverageBadges**. 1. Update [CHANGELOG.md](CHANGELOG.md) and bump `` in [src/Directory.Build.props](src/Directory.Build.props). 2. Commit on `main`, tag `v{version}` on HEAD (`v1.2.3` or SemVer prerelease such as `v0.1.0-alpha.1`, `v0.1.0-beta.1`, `v0.1.0-rc.1`). GitHub marks hyphenated versions as prerelease. -3. Run `utils\Invoke-ReleasePackage.bat`. +3. Run `utils\Invoke-ReleasePackage.bat`. GitHub assets are the portable zip (win-x64), Windows setup exe, and Flatpak. ## Commit format diff --git a/README.md b/README.md index bd30eda..7985b9f 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # MaksIT.ClusterConsole -![Line Coverage](https://img.shields.io/badge/Line%20Coverage-54.2%25-yellowgreen) -![Branch Coverage](https://img.shields.io/badge/Branch%20Coverage-45.7%25-yellowgreen) -![Method Coverage](https://img.shields.io/badge/Method%20Coverage-63.1%25-green) +![Line Coverage](https://img.shields.io/badge/Line%20Coverage-54.4%25-yellowgreen) +![Branch Coverage](https://img.shields.io/badge/Branch%20Coverage-45.8%25-yellowgreen) +![Method Coverage](https://img.shields.io/badge/Method%20Coverage-63.4%25-green) ![.NET](https://img.shields.io/badge/.NET-10-512BD4) ![License](https://img.shields.io/badge/License-Apache%202.0-blue) ![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20Linux-0078D6) @@ -98,6 +98,8 @@ Tests use kubeconfig fixtures and do not require a live cluster. Coverage shield 2. Tag `v{version}` on `main`. 3. Run `utils\Invoke-ReleasePackage.bat`. +GitHub assets are siblings: portable `maksit-cluster-console-{version}.zip` (win-x64 only), Windows setup `maksit-cluster-console-{version}.exe`, and `maksit-cluster-console-{version}.flatpak`. The installer and Flatpak are not inside the zip. On Windows the Flatpak bundle is built via WSL Debian. + ## Solution layout ```text diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 65576d6..9aa0312 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -3,7 +3,7 @@ latest enable enable - 0.5.1 + 0.6.0 MaksIT.ClusterConsole MaksIT.ClusterConsole diff --git a/src/MaksIT.ClusterConsole.Shared/ResourceActionBatch.cs b/src/MaksIT.ClusterConsole.Shared/ResourceActionBatch.cs new file mode 100644 index 0000000..39689c9 --- /dev/null +++ b/src/MaksIT.ClusterConsole.Shared/ResourceActionBatch.cs @@ -0,0 +1,53 @@ +using MaksIT.Results; + + +namespace MaksIT.ClusterConsole.Shared; + +public readonly record struct ResourceActionBatchOutcome( + int Succeeded, + int Total, + IReadOnlyList Failures) { + public string Format(string oneDone, string manyDone) { + if (Total <= 0) + return ""; + if (Failures.Count == 0) + return Total == 1 ? oneDone : manyDone; + if (Succeeded == 0) + return string.Join("; ", Failures); + return $"{Succeeded} of {Total} succeeded. {string.Join("; ", Failures)}"; + } +} + +public static class ResourceActionBatch { + public static IReadOnlyList Targets( + IReadOnlyList selectedRows, + ResourceRow? selectedRow) { + if (selectedRows.Count > 0) + return selectedRows; + return selectedRow is null ? [] : [selectedRow]; + } + + public static string Label(ResourceRow row) => + string.IsNullOrEmpty(row.Namespace) ? row.Name : $"{row.Namespace}/{row.Name}"; + + public static async Task RunAsync( + IReadOnlyList rows, + Func> action) { + ArgumentNullException.ThrowIfNull(rows); + ArgumentNullException.ThrowIfNull(action); + + var succeeded = 0; + var failures = new List(); + foreach (var row in rows) { + var result = await action(row); + if (result.IsSuccess) { + succeeded++; + continue; + } + + failures.Add($"{Label(row)}: {string.Join("; ", result.Messages)}"); + } + + return new ResourceActionBatchOutcome(succeeded, rows.Count, failures); + } +} diff --git a/src/MaksIT.ClusterConsole.Tests/ResourceActionBatchTests.cs b/src/MaksIT.ClusterConsole.Tests/ResourceActionBatchTests.cs new file mode 100644 index 0000000..dc6d01d --- /dev/null +++ b/src/MaksIT.ClusterConsole.Tests/ResourceActionBatchTests.cs @@ -0,0 +1,69 @@ +using System.Text.Json.Nodes; +using MaksIT.ClusterConsole.Shared; +using MaksIT.Results; + + +namespace MaksIT.ClusterConsole.Tests; + +public class ResourceActionBatchTests { + [Fact] + public void Targets_falls_back_to_the_current_row() { + var current = Row("web"); + Assert.Equal([current], ResourceActionBatch.Targets([], current)); + } + + [Fact] + public void Targets_uses_every_selected_row() { + var first = Row("web-a"); + var second = Row("web-b"); + Assert.Equal([first, second], ResourceActionBatch.Targets([first, second], first)); + } + + [Fact] + public async Task RunAsync_runs_the_action_for_each_row() { + var names = new List(); + var outcome = await ResourceActionBatch.RunAsync( + [Row("web-a", "apps"), Row("web-b", "apps")], + row => { + names.Add(row.Name); + return Task.FromResult(Result.Ok()); + }); + + Assert.Equal(["web-a", "web-b"], names); + Assert.Equal(2, outcome.Succeeded); + Assert.Equal(2, outcome.Total); + Assert.Empty(outcome.Failures); + Assert.Equal("Restarted 2.", outcome.Format("Restarted.", "Restarted 2.")); + } + + [Fact] + public async Task RunAsync_keeps_going_after_a_failure() { + var outcome = await ResourceActionBatch.RunAsync( + [Row("web-a", "apps"), Row("web-b", "apps")], + row => Task.FromResult( + row.Name == "web-a" + ? Result.InternalServerError("forbidden") + : Result.Ok())); + + Assert.Equal(1, outcome.Succeeded); + Assert.Equal(["apps/web-a: forbidden"], outcome.Failures); + Assert.Equal( + "1 of 2 succeeded. apps/web-a: forbidden", + outcome.Format("Restarted.", "Restarted 2.")); + } + + [Fact] + public void Format_keeps_the_singular_status_for_one_row() { + var outcome = new ResourceActionBatchOutcome(1, 1, []); + Assert.Equal("Restarted.", outcome.Format("Restarted.", "Restarted 2.")); + } + + private static ResourceRow Row(string name, string? ns = null) => + new() { + Uid = name, + Name = name, + Namespace = ns, + Document = new JsonObject(), + Cells = new Dictionary { ["Name"] = name } + }; +} diff --git a/src/MaksIT.ClusterConsole.UI/Assets/icon.ico b/src/MaksIT.ClusterConsole.UI/Assets/icon.ico index fa5ec72c04995612a2584f5c74d7099ff6de395f..40be578070b010d283468c1ff0a8a6612d04b2f5 100644 GIT binary patch literal 16914 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 YH6BB-4rgQNrFxfnb;)7>JfZx50Mx+X#sB~S literal 285478 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 a0U|&IhyW2F0z`la5CI}U1c*T22>d^vc2o5L diff --git a/src/MaksIT.ClusterConsole.UI/Assets/icon.png b/src/MaksIT.ClusterConsole.UI/Assets/icon.png index eb5e63cbf08853365c2ac0497be61141119b5d10..44f042617f58b38cd06264fd4973a9366f45390c 100644 GIT binary patch literal 11426 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 literal 4624 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 - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/MaksIT.ClusterConsole.UI/MainWindow.axaml b/src/MaksIT.ClusterConsole.UI/MainWindow.axaml index 5fab99c..7e5bcd0 100644 --- a/src/MaksIT.ClusterConsole.UI/MainWindow.axaml +++ b/src/MaksIT.ClusterConsole.UI/MainWindow.axaml @@ -547,11 +547,13 @@ diff --git a/src/MaksIT.ClusterConsole.UI/MainWindow.axaml.cs b/src/MaksIT.ClusterConsole.UI/MainWindow.axaml.cs index c20715b..7e279f0 100644 --- a/src/MaksIT.ClusterConsole.UI/MainWindow.axaml.cs +++ b/src/MaksIT.ClusterConsole.UI/MainWindow.axaml.cs @@ -19,7 +19,7 @@ namespace MaksIT.ClusterConsole.UI; public partial class MainWindow : Window { private LayoutPersistence? _layout; - private ClusterPageViewModel? _logsPage; + private ClusterPageViewModel? _activePage; public MainWindow() { InitializeComponent(); @@ -41,9 +41,9 @@ public partial class MainWindow : Window { RebuildColumns(viewModel); if (e.PropertyName == nameof(MainViewModel.ActivePage)) - HookLogsPage(viewModel.ActivePage); + HookActivePage(viewModel.ActivePage); }; - HookLogsPage(viewModel.ActivePage); + HookActivePage(viewModel.ActivePage); viewModel.ConnectionsRequested += async (_, _) => await OpenConnectionsAsync(viewModel); viewModel.VolumeFilesRequested += OpenVolumeFiles; } @@ -53,13 +53,17 @@ public partial class MainWindow : Window { window.Show(this); } - private void HookLogsPage(ClusterPageViewModel? page) { - if (_logsPage is not null) - _logsPage.PropertyChanged -= OnLogsPagePropertyChanged; + private void HookActivePage(ClusterPageViewModel? page) { + if (_activePage is not null) { + _activePage.PropertyChanged -= OnLogsPagePropertyChanged; + _activePage.SelectedRowsRestored -= OnSelectedRowsRestored; + } - _logsPage = page; - if (page is not null) + _activePage = page; + if (page is not null) { page.PropertyChanged += OnLogsPagePropertyChanged; + page.SelectedRowsRestored += OnSelectedRowsRestored; + } } private void OnLogsPagePropertyChanged(object? sender, PropertyChangedEventArgs e) { @@ -83,6 +87,39 @@ public partial class MainWindow : Window { await viewModel.ConnectNamedAsync(connect); } + private void OnResourceGridSelectionChanged(object? sender, SelectionChangedEventArgs e) { + if (DataContext is not MainViewModel { ActivePage: { } page }) + return; + if (page.SyncingSelection || sender is not DataGrid grid) + return; + + page.ReplaceSelectedRows(grid.SelectedItems.OfType()); + } + + private void OnSelectedRowsRestored(IReadOnlyList rows) { + var grid = this.FindControl("ResourceGrid"); + if (grid is null) + return; + + ApplyGridSelection(grid, rows, _activePage?.SelectedRow); + } + + private static void ApplyGridSelection(DataGrid grid, IReadOnlyList rows, ResourceRow? current) { + var wanted = rows.ToHashSet(); + for (var i = grid.SelectedItems.Count - 1; i >= 0; i--) { + if (grid.SelectedItems[i] is not ResourceRow row || !wanted.Contains(row)) + grid.SelectedItems.RemoveAt(i); + } + + foreach (var row in rows) { + if (!grid.SelectedItems.Contains(row)) + grid.SelectedItems.Add(row); + } + + if (current is not null && !ReferenceEquals(grid.SelectedItem, current)) + grid.SelectedItem = current; + } + private void OnResourceGridDoubleTapped(object? sender, TappedEventArgs e) { if (e.Source is not Control { DataContext: ResourceRow }) return; diff --git a/src/MaksIT.ClusterConsole.UI/Themes/Dark.axaml b/src/MaksIT.ClusterConsole.UI/Themes/Dark.axaml index eb8d56d..b390e59 100644 --- a/src/MaksIT.ClusterConsole.UI/Themes/Dark.axaml +++ b/src/MaksIT.ClusterConsole.UI/Themes/Dark.axaml @@ -2,20 +2,23 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="using:MaksIT.ClusterConsole.UI.Controls"> + #33A5CF + #006199 + #002A6A - - - - + + + + @@ -48,7 +51,7 @@