UI Slice 5: Menueleiste (Fenster nebeneinander), sicheres Beenden, Modul-Aktivierung
- Fenster-Menue: WindowMenu fuellt die oberste MenuStrip mit Top-Level-Eintraegen nebeneinander (mit Icon) statt Untermenue "Fenster"; ModuleView.Icon zentral in der App zugewiesen (AssignMenuIcons). Kein miFenster mehr im Launcher-Designer. - Sicheres Beenden: ShutdownConfirmDialog (10s-Timer sperrt "Jetzt beenden", Abbrechen jederzeit) via IModuleUiHost.RequestShutdown(). Nur der Launcher (Hauptprozess) bietet "Beenden"; andere Fenster nur "Fenster schliessen" (kein App-Shutdown, Module laufen weiter). Launcher-Schliessen-X routet ueber dieselbe Abfrage. - Modul-Aktivierung (restart-basiert): ServerSettings.DisabledModules, in Program.Main vor der DI-Registrierung gefiltert -> deaktivierte Module werden nicht geladen. Dashboard-Tab "Module" zeigt Status + schaltet um (Hinweis: greift nach Neustart). Optionaler IPolyTraderModule.GetActivationBlocker fuer "nicht aktivierbar"-Info. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
886de3a85b
commit
039bc240f8
@@ -17,10 +17,13 @@ namespace PolyTrader.Tests
|
||||
public List<string> Opened { get; } = new();
|
||||
public bool MainActivated { get; private set; }
|
||||
|
||||
public bool ShutdownRequested { get; private set; }
|
||||
|
||||
public IReadOnlyList<ModuleView> Views => ViewList;
|
||||
public bool IsOpen(string viewId) => OpenIds.Contains(viewId);
|
||||
public void OpenView(string viewId) => Opened.Add(viewId);
|
||||
public void ActivateMain() => MainActivated = true;
|
||||
public void RequestShutdown() => ShutdownRequested = true;
|
||||
public void RegisterView(ModuleView view) => ViewList.Add(view);
|
||||
public event Action? OpenStateChanged { add { } remove { } }
|
||||
}
|
||||
@@ -35,30 +38,64 @@ namespace PolyTrader.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Populate_lists_launcher_views_and_exit()
|
||||
public void Populate_lists_launcher_views_and_exit_side_by_side()
|
||||
{
|
||||
var host = Host();
|
||||
var fenster = new ToolStripMenuItem("Fenster");
|
||||
var menu = new MenuStrip();
|
||||
|
||||
WindowMenu.Populate(fenster, host, currentViewId: "core.dashboard");
|
||||
// currentViewId == null => Launcher (Hauptprozess): rechte Aktion ist „Beenden".
|
||||
WindowMenu.Populate(menu, host, currentViewId: null);
|
||||
|
||||
var texts = fenster.DropDownItems.OfType<ToolStripMenuItem>().Select(i => i.Text).ToList();
|
||||
Assert.Equal("Launcher", texts[0]);
|
||||
var texts = menu.Items.OfType<ToolStripMenuItem>().Select(i => i.Text).ToList();
|
||||
Assert.Equal("Launcher", texts[0]); // Launcher als erster Top-Level-Eintrag
|
||||
Assert.Contains("Dashboard", texts);
|
||||
Assert.Contains("Terminal / Logs", texts);
|
||||
Assert.Contains("Beenden", texts);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Non_launcher_window_offers_close_window_not_exit()
|
||||
{
|
||||
var host = Host();
|
||||
var menu = new MenuStrip();
|
||||
|
||||
// currentViewId != null => Modul-/Core-Fenster: KEIN „Beenden", nur „Fenster schließen".
|
||||
WindowMenu.Populate(menu, host, currentViewId: "core.dashboard");
|
||||
|
||||
var texts = menu.Items.OfType<ToolStripMenuItem>().Select(i => i.Text).ToList();
|
||||
Assert.Contains("Fenster schließen", texts);
|
||||
Assert.DoesNotContain("Beenden", texts);
|
||||
|
||||
// Klick auf „Fenster schließen" fordert NICHT das App-Shutdown an.
|
||||
menu.Items.OfType<ToolStripMenuItem>().First(i => i.Text == "Fenster schließen").PerformClick();
|
||||
Assert.False(host.ShutdownRequested);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Views_carry_their_icon_in_the_menu()
|
||||
{
|
||||
var host = new FakeUiHost();
|
||||
using var icon = new System.Drawing.Bitmap(16, 16);
|
||||
host.RegisterView(new ModuleView { Id = "core.dashboard", Title = "Dashboard", Order = 1, Icon = icon });
|
||||
var menu = new MenuStrip();
|
||||
|
||||
WindowMenu.Populate(menu, host, currentViewId: null);
|
||||
|
||||
var dashboard = menu.Items.OfType<ToolStripMenuItem>().First(i => i.Text == "Dashboard");
|
||||
Assert.Same(icon, dashboard.Image);
|
||||
Assert.Equal(ToolStripItemDisplayStyle.ImageAndText, dashboard.DisplayStyle);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Current_view_is_bold_and_checked_open_view_is_checked()
|
||||
{
|
||||
var host = Host();
|
||||
var fenster = new ToolStripMenuItem("Fenster");
|
||||
var menu = new MenuStrip();
|
||||
|
||||
WindowMenu.Populate(fenster, host, currentViewId: "core.dashboard");
|
||||
WindowMenu.Populate(menu, host, currentViewId: "core.dashboard");
|
||||
|
||||
var dashboard = fenster.DropDownItems.OfType<ToolStripMenuItem>().First(i => i.Text == "Dashboard");
|
||||
var terminal = fenster.DropDownItems.OfType<ToolStripMenuItem>().First(i => i.Text == "Terminal / Logs");
|
||||
var dashboard = menu.Items.OfType<ToolStripMenuItem>().First(i => i.Text == "Dashboard");
|
||||
var terminal = menu.Items.OfType<ToolStripMenuItem>().First(i => i.Text == "Terminal / Logs");
|
||||
|
||||
Assert.True(dashboard.Checked); // aktuelles Fenster
|
||||
Assert.True(dashboard.Font.Bold);
|
||||
@@ -70,15 +107,27 @@ namespace PolyTrader.Tests
|
||||
public void Clicking_items_navigates()
|
||||
{
|
||||
var host = Host();
|
||||
var fenster = new ToolStripMenuItem("Fenster");
|
||||
WindowMenu.Populate(fenster, host, currentViewId: null);
|
||||
var menu = new MenuStrip();
|
||||
WindowMenu.Populate(menu, host, currentViewId: null);
|
||||
|
||||
var items = fenster.DropDownItems.OfType<ToolStripMenuItem>().ToList();
|
||||
var items = menu.Items.OfType<ToolStripMenuItem>().ToList();
|
||||
items.First(i => i.Text == "Launcher").PerformClick();
|
||||
items.First(i => i.Text == "Terminal / Logs").PerformClick();
|
||||
|
||||
Assert.True(host.MainActivated);
|
||||
Assert.Contains("core.terminal", host.Opened);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Clicking_exit_requests_shutdown_not_immediate_exit()
|
||||
{
|
||||
var host = Host();
|
||||
var menu = new MenuStrip();
|
||||
WindowMenu.Populate(menu, host, currentViewId: null);
|
||||
|
||||
menu.Items.OfType<ToolStripMenuItem>().First(i => i.Text == "Beenden").PerformClick();
|
||||
|
||||
Assert.True(host.ShutdownRequested);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user