feat: add Control Room with containers and stacks management
- Add Control Room page with stacks sidebar and containers list - Implement container actions (start/stop/restart) with snackbars - Add container logs viewer dialog - Add search/filter for both stacks and containers lists - Add external links for Portainer and Netdata (url_launcher) - Add VS Code launch configuration for Flutter web debugging 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
dd6bcbdbda
commit
3b89ed8c18
@@ -0,0 +1,92 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
import '../../../stacks/presentation/providers/stacks_provider.dart';
|
||||
import '../../data/repositories/container_repository_impl.dart';
|
||||
import '../../domain/entities/container.dart';
|
||||
|
||||
part 'containers_provider.g.dart';
|
||||
|
||||
/// Provides all containers.
|
||||
@riverpod
|
||||
Future<List<Container>> allContainers(AllContainersRef ref) async {
|
||||
final repository = ref.watch(containerRepositoryProvider);
|
||||
return repository.getContainers();
|
||||
}
|
||||
|
||||
/// Provides containers filtered by the selected stack.
|
||||
@riverpod
|
||||
Future<List<Container>> containers(ContainersRef ref) async {
|
||||
final repository = ref.watch(containerRepositoryProvider);
|
||||
final selectedStack = ref.watch(selectedStackProvider);
|
||||
|
||||
if (selectedStack == null) {
|
||||
return repository.getContainers();
|
||||
}
|
||||
|
||||
return repository.getContainersByStack(selectedStack);
|
||||
}
|
||||
|
||||
/// Provides a single container by ID.
|
||||
@riverpod
|
||||
Future<Container> container(ContainerRef ref, String id) async {
|
||||
final repository = ref.watch(containerRepositoryProvider);
|
||||
return repository.getContainer(id);
|
||||
}
|
||||
|
||||
/// Controller for container actions.
|
||||
@riverpod
|
||||
class ContainerActions extends _$ContainerActions {
|
||||
@override
|
||||
AsyncValue<void> build() => const AsyncValue.data(null);
|
||||
|
||||
Future<void> start(String id) async {
|
||||
state = const AsyncValue.loading();
|
||||
state = await AsyncValue.guard(() async {
|
||||
final repository = ref.read(containerRepositoryProvider);
|
||||
await repository.startContainer(id);
|
||||
ref.invalidate(allContainersProvider);
|
||||
ref.invalidate(containersProvider);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> stop(String id) async {
|
||||
state = const AsyncValue.loading();
|
||||
state = await AsyncValue.guard(() async {
|
||||
final repository = ref.read(containerRepositoryProvider);
|
||||
await repository.stopContainer(id);
|
||||
ref.invalidate(allContainersProvider);
|
||||
ref.invalidate(containersProvider);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> restart(String id) async {
|
||||
state = const AsyncValue.loading();
|
||||
state = await AsyncValue.guard(() async {
|
||||
final repository = ref.read(containerRepositoryProvider);
|
||||
await repository.restartContainer(id);
|
||||
ref.invalidate(allContainersProvider);
|
||||
ref.invalidate(containersProvider);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> remove(String id, {bool force = false}) async {
|
||||
state = const AsyncValue.loading();
|
||||
state = await AsyncValue.guard(() async {
|
||||
final repository = ref.read(containerRepositoryProvider);
|
||||
await repository.removeContainer(id, force: force);
|
||||
ref.invalidate(allContainersProvider);
|
||||
ref.invalidate(containersProvider);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Container logs provider.
|
||||
@riverpod
|
||||
Future<String> containerLogs(
|
||||
ContainerLogsRef ref,
|
||||
String id, {
|
||||
int? tail = 100,
|
||||
}) async {
|
||||
final repository = ref.watch(containerRepositoryProvider);
|
||||
return repository.getContainerLogs(id, tail: tail);
|
||||
}
|
||||
Reference in New Issue
Block a user