diff --git a/src/client/gui/lib/catalogue/launch_form.dart b/src/client/gui/lib/catalogue/launch_form.dart index e73bcf869a..2d26ba1923 100644 --- a/src/client/gui/lib/catalogue/launch_form.dart +++ b/src/client/gui/lib/catalogue/launch_form.dart @@ -52,6 +52,7 @@ class _LaunchFormState extends ConsumerState { final imageInfo = ref.watch(launchingImageProvider); final randomName = ref.watch(randomNameProvider); final vmNames = ref.watch(vmNamesProvider); + final deletedVms = ref.watch(deletedVmsProvider); final closeButton = IconButton( icon: const Icon(Icons.close), @@ -63,7 +64,7 @@ class _LaunchFormState extends ConsumerState { autofocus: true, helper: 'Names cannot be changed once an instance is created', hint: randomName, - validator: nameValidator(vmNames), + validator: nameValidator(vmNames, deletedVms), onSaved: (value) => launchRequest.instanceName = value.isNullOrBlank ? randomName : value!, width: 360, @@ -312,7 +313,10 @@ class _LaunchFormState extends ConsumerState { } } -FormFieldValidator nameValidator(Iterable existingNames) { +FormFieldValidator nameValidator( + Iterable existingNames, + Iterable deletedNames, +) { return (String? value) { if (value!.isEmpty) { return null; @@ -332,6 +336,9 @@ FormFieldValidator nameValidator(Iterable existingNames) { if (existingNames.contains(value)) { return 'Name is already in use'; } + if (deletedNames.contains(value)) { + return 'Name is already in use by a deleted instance'; + } return null; }; } diff --git a/src/client/gui/lib/providers.dart b/src/client/gui/lib/providers.dart index 3d2cf6d420..79437af7ef 100644 --- a/src/client/gui/lib/providers.dart +++ b/src/client/gui/lib/providers.dart @@ -43,10 +43,7 @@ final vmInfosStreamProvider = StreamProvider>((ref) async* { while (true) { final timer = Future.delayed(1900.milliseconds); try { - final infos = await grpcClient.info(); - yield infos - .where((info) => info.instanceStatus.status != Status.DELETED) - .toList(); + yield await grpcClient.info(); lastError = null; } catch (error, stackTrace) { if (error != lastError) { @@ -78,7 +75,8 @@ final daemonAvailableProvider = Provider((ref) { }); final vmInfosProvider = Provider((ref) { - return ref.watch(vmInfosStreamProvider).valueOrNull ?? const []; + final vmInfos = ref.watch(vmInfosStreamProvider).valueOrNull ?? const []; + return vmInfos.where((info) => info.instanceStatus.status != Status.DELETED); }); final vmInfosMapProvider = Provider((ref) { @@ -107,6 +105,14 @@ final vmNamesProvider = Provider((ref) { return ref.watch(vmStatusesProvider).keys.toBuiltSet(); }); +final deletedVmsProvider = Provider((ref) { + final vmInfos = ref.watch(vmInfosStreamProvider).valueOrNull ?? const []; + return vmInfos + .where((info) => info.instanceStatus.status == Status.DELETED) + .map((info) => info.name) + .toBuiltSet(); +}); + class ClientSettingNotifier extends AutoDisposeFamilyNotifier { final file = File(settingsFile());