40 lines
1.6 KiB
Dart
40 lines
1.6 KiB
Dart
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
|
|
import '../../../core/network/api_exception.dart';
|
|
import '../../../core/polling/polling_async_notifier.dart';
|
|
import '../../../data/repositories/node_repository.dart';
|
|
import '../../../data/repositories/services_repository.dart';
|
|
import 'dashboard_summary.dart';
|
|
|
|
part 'dashboard_summary_provider.g.dart';
|
|
|
|
/// Polled every 20s while the Dashboard is mounted — deliberately its own
|
|
/// notifier rather than watching `servicesListProvider`/`currentNodeProvider`
|
|
/// directly, so Dashboard auto-refreshes independent of whether the
|
|
/// Services screen (manual-refresh only) happens to be open too.
|
|
@riverpod
|
|
class DashboardSummaryNotifier extends _$DashboardSummaryNotifier
|
|
with PollingMixin<DashboardSummary> {
|
|
@override
|
|
Duration get interval => const Duration(seconds: 20);
|
|
|
|
@override
|
|
Future<DashboardSummary> fetch() async {
|
|
final servicesRepo = ref.watch(servicesRepositoryProvider);
|
|
final nodeRepo = ref.watch(nodeRepositoryProvider);
|
|
if (servicesRepo == null || nodeRepo == null) {
|
|
// The router redirects to Settings whenever there's no active
|
|
// connection, so reaching this in the UI would mean that redirect
|
|
// hasn't fired yet — an ApiException here (vs. a raw StateError)
|
|
// keeps error handling on the same path as every other screen.
|
|
throw const ApiException.unknown('No active connection.');
|
|
}
|
|
final services = await servicesRepo.getAll();
|
|
final node = await nodeRepo.getNode();
|
|
return DashboardSummary(services: services, node: node);
|
|
}
|
|
|
|
@override
|
|
Future<DashboardSummary> build() => startPolling();
|
|
}
|