Files
dashcaddy/desktop/MainWindow.xaml.cs
Hermes 86e4c9fc81 wip: Windows desktop app scaffold (WinUI 3/.NET 8) + NSIS installer + docs
Owner decision pending (STATE.md DC-100 tick): adopt/ship/park.
Preserved from fragile git stash to named branch 2026-08-23.
NOTE: requires a Windows build machine (WinUI XAML compiler + MSIX do not
cross-build on Linux) — see WINDOWS_APP_BUILD.md in this tree.
Secret-scanned clean 2026-08-23 (no keys/tokens/PEM in tree).
2026-08-22 23:50:34 -07:00

229 lines
7.1 KiB
C#

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using DashCaddy.Desktop.ViewModels;
using DashCaddy.Desktop.Models;
using System.Threading.Tasks;
namespace DashCaddy.Desktop;
public sealed partial class MainWindow : Window
{
public MainViewModel ViewModel => App.MainViewModel;
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
await ViewModel.InitializeAsync();
}
// ─── Toolbar Actions ───
private async void AddService_Click(object sender, RoutedEventArgs e)
{
var dialog = new AddServiceDialog(ViewModel);
dialog.XamlRoot = this.Content.XamlRoot;
var result = await dialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
await ViewModel.RefreshServicesAsync();
}
}
private async void ImportCompose_Click(object sender, RoutedEventArgs e)
{
var picker = new Windows.Storage.Pickers.FileOpenPicker();
picker.FileTypeFilter.Add(".yaml");
picker.FileTypeFilter.Add(".yml");
picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.DocumentsLibrary;
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd);
var file = await picker.PickSingleFileAsync();
if (file != null)
{
ShowLoading("Importing Docker Compose...");
try
{
await ViewModel.ImportComposeAsync(file.Path);
await ViewModel.RefreshServicesAsync();
}
finally
{
HideLoading();
}
}
}
private void Templates_Click(object sender, RoutedEventArgs e)
{
var dialog = new TemplatesDialog(ViewModel);
dialog.XamlRoot = this.Content.XamlRoot;
_ = dialog.ShowAsync();
}
// ─── Service Actions ───
private async void ServiceAction_Click(object sender, RoutedEventArgs e)
{
// Handled by Flyout menu items
}
private async void OpenService_Click(object sender, RoutedEventArgs e)
{
if (sender is MenuFlyoutItem item && item.DataContext is ServiceViewModel service)
{
await Windows.System.Launcher.LaunchUriAsync(new System.Uri(service.Url));
}
}
private async void ViewLogs_Click(object sender, RoutedEventArgs e)
{
ServiceViewModel service = null;
if (sender is MenuFlyoutItem item && item.DataContext is ServiceViewModel svc)
{
service = svc;
}
else if (sender is Button)
{
// "View Logs" bottom button - show all logs
var dialog = new LogsDialog(ViewModel);
dialog.XamlRoot = this.Content.XamlRoot;
await dialog.ShowAsync();
return;
}
if (service != null)
{
var dialog = new ServiceLogsDialog(service, ViewModel.DockerService);
dialog.XamlRoot = this.Content.XamlRoot;
await dialog.ShowAsync();
}
}
private async void RestartService_Click(object sender, RoutedEventArgs e)
{
if (sender is MenuFlyoutItem item && item.DataContext is ServiceViewModel service)
{
ShowLoading($"Restarting {service.Name}...");
try
{
await ViewModel.RestartServiceAsync(service.Id);
await ViewModel.RefreshServicesAsync();
}
finally
{
HideLoading();
}
}
}
private async void StopService_Click(object sender, RoutedEventArgs e)
{
if (sender is MenuFlyoutItem item && item.DataContext is ServiceViewModel service)
{
await ViewModel.StopServiceAsync(service.Id);
await ViewModel.RefreshServicesAsync();
}
}
private async void EditService_Click(object sender, RoutedEventArgs e)
{
if (sender is MenuFlyoutItem item && item.DataContext is ServiceViewModel service)
{
var dialog = new EditServiceDialog(service, ViewModel);
dialog.XamlRoot = this.Content.XamlRoot;
var result = await dialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
await ViewModel.RefreshServicesAsync();
}
}
}
private async void RemoveService_Click(object sender, RoutedEventArgs e)
{
if (sender is MenuFlyoutItem item && item.DataContext is ServiceViewModel service)
{
var dialog = new ContentDialog
{
Title = "Remove Service",
Content = $"Are you sure you want to remove '{service.Name}'? This will stop the container and remove the reverse proxy configuration.",
PrimaryButtonText = "Remove",
CloseButtonText = "Cancel",
DefaultButton = ContentDialogButton.Close,
XamlRoot = this.Content.XamlRoot
};
var result = await dialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
ShowLoading($"Removing {service.Name}...");
try
{
await ViewModel.RemoveServiceAsync(service.Id);
await ViewModel.RefreshServicesAsync();
}
finally
{
HideLoading();
}
}
}
}
private async void ServiceToggled(object sender, RoutedEventArgs e)
{
if (sender is ToggleSwitch toggle && toggle.Tag is ServiceViewModel service)
{
if (toggle.IsOn)
{
ShowLoading($"Starting {service.Name}...");
await ViewModel.StartServiceAsync(service.Id);
}
else
{
ShowLoading($"Stopping {service.Name}...");
await ViewModel.StopServiceAsync(service.Id);
}
await ViewModel.RefreshServicesAsync();
HideLoading();
}
}
// ─── Bottom Bar ───
private async void OpenDashboard_Click(object sender, RoutedEventArgs e)
{
await Windows.System.Launcher.LaunchUriAsync(new System.Uri(ViewModel.DashboardUrl));
}
private async void OpenSettings_Click(object sender, RoutedEventArgs e)
{
var dialog = new SettingsDialog(ViewModel);
dialog.XamlRoot = this.Content.XamlRoot;
await dialog.ShowAsync();
}
private async void OpenHelp_Click(object sender, RoutedEventArgs e)
{
await Windows.System.Launcher.LaunchUriAsync(new System.Uri("https://dashcaddy.net/docs"));
}
// ─── Loading Overlay ───
private void ShowLoading(string message)
{
LoadingText.Text = message;
LoadingOverlay.Visibility = Visibility.Visible;
}
private void HideLoading()
{
LoadingOverlay.Visibility = Visibility.Collapsed;
}
}