Some checks failed
Build and Publish Docker Image / build-and-push (push) Has been cancelled
- Implemented CreateInstanceView for creating new instances. - Added HostsView for managing SSH hosts with CRUD operations. - Created InstancesView for displaying and managing instances. - Developed LogsView for viewing operation logs. - Introduced SecretsView for managing secrets associated with hosts. - Established SettingsView for configuring application settings. - Created MainWindow as the main application window with navigation. - Added app manifest and configuration files for logging and settings.
187 lines
6.0 KiB
C#
187 lines
6.0 KiB
C#
using System.Collections.ObjectModel;
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using CommunityToolkit.Mvvm.Input;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using OTSSignsOrchestrator.Core.Data;
|
|
using OTSSignsOrchestrator.Core.Models.Entities;
|
|
using OTSSignsOrchestrator.Core.Services;
|
|
using OTSSignsOrchestrator.Desktop.Services;
|
|
|
|
namespace OTSSignsOrchestrator.Desktop.ViewModels;
|
|
|
|
/// <summary>
|
|
/// ViewModel for listing, viewing, and managing CMS instances.
|
|
/// </summary>
|
|
public partial class InstancesViewModel : ObservableObject
|
|
{
|
|
private readonly IServiceProvider _services;
|
|
|
|
[ObservableProperty] private ObservableCollection<CmsInstance> _instances = new();
|
|
[ObservableProperty] private CmsInstance? _selectedInstance;
|
|
[ObservableProperty] private string _statusMessage = string.Empty;
|
|
[ObservableProperty] private bool _isBusy;
|
|
[ObservableProperty] private string _filterText = string.Empty;
|
|
[ObservableProperty] private ObservableCollection<StackInfo> _remoteStacks = new();
|
|
[ObservableProperty] private ObservableCollection<ServiceInfo> _selectedServices = new();
|
|
|
|
// Available SSH hosts for the dropdown
|
|
[ObservableProperty] private ObservableCollection<SshHost> _availableHosts = new();
|
|
[ObservableProperty] private SshHost? _selectedSshHost;
|
|
|
|
public InstancesViewModel(IServiceProvider services)
|
|
{
|
|
_services = services;
|
|
_ = InitAsync();
|
|
}
|
|
|
|
private async Task InitAsync()
|
|
{
|
|
await LoadHostsAsync();
|
|
await LoadInstancesAsync();
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task LoadHostsAsync()
|
|
{
|
|
using var scope = _services.CreateScope();
|
|
var db = scope.ServiceProvider.GetRequiredService<XiboContext>();
|
|
var hosts = await db.SshHosts.OrderBy(h => h.Label).ToListAsync();
|
|
AvailableHosts = new ObservableCollection<SshHost>(hosts);
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task LoadInstancesAsync()
|
|
{
|
|
IsBusy = true;
|
|
try
|
|
{
|
|
using var scope = _services.CreateScope();
|
|
var db = scope.ServiceProvider.GetRequiredService<XiboContext>();
|
|
|
|
var query = db.CmsInstances.Include(i => i.SshHost).AsQueryable();
|
|
if (!string.IsNullOrWhiteSpace(FilterText))
|
|
{
|
|
query = query.Where(i =>
|
|
i.CustomerName.Contains(FilterText) ||
|
|
i.StackName.Contains(FilterText));
|
|
}
|
|
|
|
var items = await query.OrderByDescending(i => i.CreatedAt).ToListAsync();
|
|
Instances = new ObservableCollection<CmsInstance>(items);
|
|
StatusMessage = $"Loaded {items.Count} instance(s).";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
StatusMessage = $"Error: {ex.Message}";
|
|
}
|
|
finally
|
|
{
|
|
IsBusy = false;
|
|
}
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task RefreshRemoteStacksAsync()
|
|
{
|
|
if (SelectedSshHost == null)
|
|
{
|
|
StatusMessage = "Select an SSH host first.";
|
|
return;
|
|
}
|
|
|
|
IsBusy = true;
|
|
StatusMessage = $"Listing stacks on {SelectedSshHost.Label}...";
|
|
try
|
|
{
|
|
var dockerCli = _services.GetRequiredService<SshDockerCliService>();
|
|
dockerCli.SetHost(SelectedSshHost);
|
|
|
|
var stacks = await dockerCli.ListStacksAsync();
|
|
RemoteStacks = new ObservableCollection<StackInfo>(stacks);
|
|
StatusMessage = $"Found {stacks.Count} stack(s) on {SelectedSshHost.Label}.";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
StatusMessage = $"Error listing stacks: {ex.Message}";
|
|
}
|
|
finally
|
|
{
|
|
IsBusy = false;
|
|
}
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task InspectInstanceAsync()
|
|
{
|
|
if (SelectedInstance == null) return;
|
|
if (SelectedSshHost == null && SelectedInstance.SshHost == null)
|
|
{
|
|
StatusMessage = "No SSH host associated with this instance.";
|
|
return;
|
|
}
|
|
|
|
IsBusy = true;
|
|
try
|
|
{
|
|
var host = SelectedInstance.SshHost ?? SelectedSshHost!;
|
|
var dockerCli = _services.GetRequiredService<SshDockerCliService>();
|
|
dockerCli.SetHost(host);
|
|
|
|
var services = await dockerCli.InspectStackServicesAsync(SelectedInstance.StackName);
|
|
SelectedServices = new ObservableCollection<ServiceInfo>(services);
|
|
StatusMessage = $"Found {services.Count} service(s) in stack '{SelectedInstance.StackName}'.";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
StatusMessage = $"Error inspecting: {ex.Message}";
|
|
}
|
|
finally
|
|
{
|
|
IsBusy = false;
|
|
}
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task DeleteInstanceAsync()
|
|
{
|
|
if (SelectedInstance == null) return;
|
|
|
|
IsBusy = true;
|
|
StatusMessage = $"Deleting {SelectedInstance.StackName}...";
|
|
try
|
|
{
|
|
var host = SelectedInstance.SshHost ?? SelectedSshHost;
|
|
if (host == null)
|
|
{
|
|
StatusMessage = "No SSH host available for deletion.";
|
|
return;
|
|
}
|
|
|
|
// Wire up SSH-based docker services
|
|
var dockerCli = _services.GetRequiredService<SshDockerCliService>();
|
|
dockerCli.SetHost(host);
|
|
var dockerSecrets = _services.GetRequiredService<SshDockerSecretsService>();
|
|
dockerSecrets.SetHost(host);
|
|
|
|
using var scope = _services.CreateScope();
|
|
var instanceSvc = scope.ServiceProvider.GetRequiredService<InstanceService>();
|
|
|
|
var result = await instanceSvc.DeleteInstanceAsync(SelectedInstance.Id);
|
|
StatusMessage = result.Success
|
|
? $"Instance '{SelectedInstance.StackName}' deleted."
|
|
: $"Delete failed: {result.ErrorMessage}";
|
|
|
|
await LoadInstancesAsync();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
StatusMessage = $"Error deleting: {ex.Message}";
|
|
}
|
|
finally
|
|
{
|
|
IsBusy = false;
|
|
}
|
|
}
|
|
}
|