Merge branch 'claudedo/f359858ac98a439593e459df9c5d0a5d'
This commit is contained in:
@@ -143,6 +143,9 @@ public interface IWorkerClient : INotifyPropertyChanged
|
||||
/// <summary>Raised whenever the worker's usage poller ticks (success or failure).</summary>
|
||||
event Action<UsageSnapshotDto>? UsageUpdatedEvent;
|
||||
Task<UsageSnapshotDto?> GetUsageSnapshotAsync();
|
||||
|
||||
/// <summary>Forces an out-of-band usage poll on the worker and returns the fresh snapshot.</summary>
|
||||
Task<UsageSnapshotDto?> RefreshUsageAsync();
|
||||
Task<IReadOnlyList<ModelUsageRowDto>> GetModelUsageAsync(DateOnly from, DateOnly to);
|
||||
Task<IReadOnlyList<TaskUsageRowDto>> GetTaskUsageAsync(DateOnly from, DateOnly to);
|
||||
}
|
||||
|
||||
@@ -582,6 +582,9 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
|
||||
public Task<UsageSnapshotDto?> GetUsageSnapshotAsync()
|
||||
=> TryInvokeAsync<UsageSnapshotDto>("GetUsageSnapshot");
|
||||
|
||||
public Task<UsageSnapshotDto?> RefreshUsageAsync()
|
||||
=> TryInvokeAsync<UsageSnapshotDto>("RefreshUsage");
|
||||
|
||||
public async Task<IReadOnlyList<ModelUsageRowDto>> GetModelUsageAsync(DateOnly from, DateOnly to)
|
||||
=> await TryInvokeAsync<List<ModelUsageRowDto>>("GetModelUsage", from, to) ?? [];
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ public sealed partial class UsageMonitorModalViewModel : ViewModelBase
|
||||
[NotifyPropertyChangedFor(nameof(ModelsEmpty))]
|
||||
private bool _isBusy;
|
||||
|
||||
[ObservableProperty] private bool _isRefreshing;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(ModelsEmpty))]
|
||||
private IReadOnlyList<ModelUsageDisplayRow> _modelRows = Array.Empty<ModelUsageDisplayRow>();
|
||||
@@ -92,6 +94,28 @@ public sealed partial class UsageMonitorModalViewModel : ViewModelBase
|
||||
|
||||
private void OnUsageUpdated(UsageSnapshotDto snapshot) => Snapshot = snapshot;
|
||||
|
||||
/// <summary>
|
||||
/// Manual refresh: the worker polls usage on a slow cadence (15 min idle / 5 min while a
|
||||
/// task runs) to stay clear of the endpoint's 429s, so this is the way to get a number now.
|
||||
/// </summary>
|
||||
[RelayCommand]
|
||||
private async Task RefreshAsync()
|
||||
{
|
||||
if (IsRefreshing) return;
|
||||
IsRefreshing = true;
|
||||
try
|
||||
{
|
||||
var snapshot = await _worker.RefreshUsageAsync();
|
||||
if (snapshot is not null) Snapshot = snapshot;
|
||||
await LoadUsageDataAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorReported?.Invoke(Loc.T("vm.usageMonitor.refreshFailed", ex.Message));
|
||||
}
|
||||
finally { IsRefreshing = false; }
|
||||
}
|
||||
|
||||
private void ApplyPresetRange(int days)
|
||||
{
|
||||
var today = DateOnly.FromDateTime(DateTime.Today);
|
||||
|
||||
@@ -60,6 +60,18 @@
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Refresh: the worker polls on a slow cadence to avoid the endpoint's 429s -->
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Spacing="8"
|
||||
Margin="20,12,20,0" VerticalAlignment="Center">
|
||||
<Button Classes="btn" Content="{loc:Tr modals.usageMonitor.refresh}"
|
||||
Command="{Binding RefreshCommand}"
|
||||
IsEnabled="{Binding !IsRefreshing}"/>
|
||||
<Ellipse Classes="spinner" Width="14" Height="14" VerticalAlignment="Center"
|
||||
IsVisible="{Binding IsRefreshing}"/>
|
||||
<TextBlock Classes="meta" VerticalAlignment="Center"
|
||||
Text="{loc:Tr modals.usageMonitor.refreshHint}"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Gauges -->
|
||||
<ItemsControl DockPanel.Dock="Top" Margin="20,12,20,0" ItemsSource="{Binding GaugeRows}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
|
||||
Reference in New Issue
Block a user