using CommunityToolkit.Mvvm.ComponentModel; using DashCaddy.Desktop.Models; using DashCaddy.Desktop.Services; using System.Collections.ObjectModel; using System.Collections.Generic; namespace DashCaddy.Desktop.ViewModels; public partial class MainViewModel : ObservableObject { private readonly DockerService _dockerService; private readonly ApiClient _apiClient; private readonly CaddyConfigGenerator _caddyGenerator; private readonly DnsClient _dnsClient; [ObservableProperty] private ObservableCollection _services = new(); [ObservableProperty] private int _servicesHealthy; [ObservableProperty] private int _servicesTotal; [ObservableProperty] private bool _dnsHealthy = true; [ObservableProperty] private bool _certsHealthy = true; [ObservableProperty] private int _certsDaysRemaining = 45; // For dialogs public ObservableCollection Templates { get; } = new(TemplateRegistry.GetAll()); public List TemplateVariables { get; set; } = new(); public Dictionary TemplateVariablesDict { get; set; } = new(); public ServiceTemplate SelectedTemplate { get; set; } public string SelectedComposeFile { get; set; } public object CustomService { get; set; } public string ServicesSummary => $"{ServicesHealthy}/{ServicesTotal} running"; public string CertsSummary => $"{CertsDaysRemaining} days"; public string DashboardUrl => "https://status.local"; public MainViewModel(DockerService dockerService, ApiClient apiClient, CaddyConfigGenerator caddyGenerator, DnsClient dnsClient) { _dockerService = dockerService; _apiClient = apiClient; _caddyGenerator = caddyGenerator; _dnsClient = dnsClient; } public async Task InitializeAsync() { await RefreshServicesAsync(); await CheckHealthAsync(); } public async Task RefreshServicesAsync() { try { var services = await _apiClient.GetServicesAsync(); Services.Clear(); foreach (var svc in services) { Services.Add(new ServiceViewModel { Id = svc.Id, Name = svc.Name, Type = svc.Type, Url = svc.Url, Health = Enum.TryParse(svc.Health, true, out var h) ? h : ServiceHealth.Unknown, IsRunning = svc.State == "running", Port = svc.Port, Host = svc.Host }); } ServicesHealthy = Services.Count(s => s.Health == ServiceHealth.Healthy); ServicesTotal = Services.Count; } catch { await RefreshFromDockerAsync(); } } private async Task RefreshFromDockerAsync() { var containers = await _dockerService.GetContainersAsync("dashcaddy"); Services.Clear(); foreach (var c in containers) { Services.Add(new ServiceViewModel { Id = c.ID[..12], Name = c.Names.FirstOrDefault()?.TrimStart('/') ?? "unknown", Type = "docker", Url = $"http://localhost:{c.Ports.FirstOrDefault()?.PublicPort ?? 0}", Health = c.State == "running" ? ServiceHealth.Healthy : ServiceHealth.Unhealthy, IsRunning = c.State == "running" }); } ServicesHealthy = Services.Count(s => s.Health == ServiceHealth.Healthy); ServicesTotal = Services.Count; } public async Task CheckHealthAsync() { try { var health = await _apiClient.GetHealthAsync(); DnsHealthy = health.Dns == "healthy"; CertsHealthy = health.Certs == "healthy"; CertsDaysRemaining = health.CertsDaysRemaining; } catch { DnsHealthy = false; CertsHealthy = false; } } public async Task StartServiceAsync(string id) => await _dockerService.StartContainerAsync(id); public async Task StopServiceAsync(string id) => await _dockerService.StopContainerAsync(id); public async Task RestartServiceAsync(string id) => await _dockerService.RestartContainerAsync(id); public async Task RemoveServiceAsync(string id) { await _dockerService.RemoveContainerAsync(id); await _apiClient.RemoveServiceAsync(id); _caddyGenerator.RegenerateConfig(Services.Select(s => s.ToServiceModel()).ToList()); await _caddyGenerator.ReloadCaddyAsync(); } public async Task ImportComposeAsync(string filePath) { var json = await File.ReadAllTextAsync(filePath); var services = ComposeParser.ParseJson(json); foreach (var svc in services) { await _apiClient.CreateServiceAsync(svc); await _dockerService.CreateContainerAsync(svc); } _caddyGenerator.RegenerateConfig(Services.Select(s => s.ToServiceModel()).ToList()); await _caddyGenerator.ReloadCaddyAsync(); } public async Task CreateServiceFromTemplateAsync() { if (SelectedTemplate == null) return null; var service = SelectedTemplate.Instantiate(TemplateVariablesDict); await _apiClient.CreateServiceAsync(service); await _dockerService.CreateContainerAsync(service); _caddyGenerator.RegenerateConfig(Services.Select(s => s.ToServiceModel()).ToList()); await _caddyGenerator.ReloadCaddyAsync(); return service; } }