Repository navigation
Expand file tree
/
Copy pathKernelLeaseViewModel.cs
More file actions
106 lines (89 loc) · 3.73 KB
/
Copy pathKernelLeaseViewModel.cs
File metadata and controls
106 lines (89 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MissionController.Host;
namespace MissionController.UI.ViewModels;
/// <summary>
/// The Kernel Lease page: the console's own door onto the daemon under its Linux-lease templates.
/// Every rule about what may be applied lives in <see cref="SubstrateLifecycle"/>, which splat-mcp's
/// doctor, provision and unmount share; this only shows the reports and keeps the buttons honest about
/// what the last plan allows.
/// </summary>
public partial class KernelLeaseViewModel : ObservableObject
{
private readonly SubstrateLifecycle _substrate;
[ObservableProperty]
private string _verdict = "Not checked yet. Check this host to read whether a lease here reaches the kernel.";
[ObservableProperty]
private string _report = string.Empty;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(IsIdle))]
[NotifyPropertyChangedFor(nameof(CanManage))]
[NotifyPropertyChangedFor(nameof(CanApply))]
private bool _isBusy;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanApply))]
[NotifyPropertyChangedFor(nameof(ApplyLabel))]
private SubstrateChange _planned;
public KernelLeaseViewModel(SubstrateLifecycle substrate)
{
_substrate = substrate;
}
public bool IsIdle => !IsBusy;
public bool CanManage => IsIdle && !_substrate.IsManaged;
public bool CanApply => !IsBusy && Planned != SubstrateChange.None;
public string ApplyLabel => Planned switch
{
SubstrateChange.ImportGuest => "Import Lite guest: apply the plan below",
SubstrateChange.Mount => "Mount: apply the plan below",
SubstrateChange.Unmount => "Unmount: apply the plan below",
_ => "Apply (plan first)",
};
[RelayCommand]
public Task CheckAsync() => RunAsync(_substrate.CheckAsync, "Checking this host...");
[RelayCommand]
public Task PlanMountAsync() => RunAsync(_substrate.PlanMountAsync, "Planning a mount. Nothing is changed by a plan...");
[RelayCommand]
public Task PlanUnmountAsync() => RunAsync(_substrate.PlanUnmountAsync, "Planning an unmount. Nothing is changed by a plan...");
[RelayCommand]
public Task ApplyAsync() =>
RunAsync(_substrate.ApplyAsync, Planned switch
{
SubstrateChange.ImportGuest => "Importing the Lite guest...",
SubstrateChange.Unmount => "Unmounting...",
_ => "Mounting...",
});
private async Task RunAsync(Func<CancellationToken, Task<SubstrateReport>> run, string working)
{
IsBusy = true;
Verdict = working;
try
{
SubstrateReport result = await run(CancellationToken.None);
Report = result.Text;
Verdict = LastLine(result.Text);
}
catch (Exception ex)
{
// SubstrateLifecycle reports its own failures; this is for one it could not, so the page
// says what happened instead of the command swallowing it or the window closing on it.
Report = ex.ToString();
Verdict = $"Stopped: {ex.Message}";
}
finally
{
// Read back, never assumed: the lifecycle decides what a report authorizes.
Planned = _substrate.Planned;
IsBusy = false;
}
}
/// <summary>
/// The banner is the report's own last line - every report ends on its verdict - so the page never
/// says more than the report beneath it.
/// </summary>
private static string LastLine(string text) =>
text.Split('\n').Select(line => line.Trim()).LastOrDefault(line => line.Length > 0) ?? "The report was empty.";
}