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).
229 lines
7.1 KiB
C#
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;
|
|
}
|
|
} |