public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: "Michael Köppl" <m.koeppl@proxmox.com>
To: Proxmox VE development discussion <pve-devel@lists.proxmox.com>,
	Alexander Abraham <a.abraham@proxmox.com>
Subject: Re: [pve-devel] [PATCH flutter_frontend 1/1] fix #4976: ui: Nodes offline
Date: Tue, 24 Jun 2025 14:53:46 +0200	[thread overview]
Message-ID: <03cea113-d66c-472c-ae4b-83829e7816b9@proxmox.com> (raw)
In-Reply-To: <3615656b-a9c5-430c-b0c2-57c72ac0854b@proxmox.com>

On 5/2/25 13:32, Michael Köppl wrote:
> On 4/29/25 15:16, Alexander Abraham wrote:
>> diff --git a/lib/bloc/pve_node_overview_bloc.dart b/lib/bloc/
>> pve_node_overview_bloc.dart
>> index 19d6563..98005fd 100644
>> --- a/lib/bloc/pve_node_overview_bloc.dart
>> +++ b/lib/bloc/pve_node_overview_bloc.dart
>> @@ -1,5 +1,5 @@
>>   import 'dart:async';
>> -
>> +import 'package:flutter/material.dart';
>>   import 'package:proxmox_dart_api_client/proxmox_dart_api_client.dart';
>>   import 'package:pve_flutter_frontend/bloc/proxmox_base_bloc.dart';
>>   import 'package:pve_flutter_frontend/states/
>> pve_node_overview_state.dart';
>> @@ -8,12 +8,13 @@ class PveNodeOverviewBloc
>>       extends ProxmoxBaseBloc<PveNodeOverviewEvent,
>> PveNodeOverviewState> {
>>     final ProxmoxApiClient apiClient;
>>     final String nodeID;
>> +  final BuildContext context;
>>     final PveNodeOverviewState init;
>>     @override
>>     PveNodeOverviewState get initialState => init;
>>       PveNodeOverviewBloc(
>> -      {required this.apiClient, required this.nodeID, required
>> this.init});
>> +      {required this.apiClient, required this.nodeID, required
>> this.init, required this.context});
>>       Timer? sTimer;
>>     @override
>> @@ -32,36 +33,56 @@ class PveNodeOverviewBloc
>>     @override
>>     Stream<PveNodeOverviewState> processEvents(
>>         PveNodeOverviewEvent event) async* {
>> -    if (event is UpdateNodeStatus) {
>> -      final status = await apiClient.getNodeStatus(nodeID);
>> -      yield latestState.rebuild((b) => b..status.replace(status));
>> -      final rrdData =
>> -          await apiClient.getNodeRRDdata(nodeID,
>> PveRRDTimeframeType.hour);
>> -      yield latestState.rebuild((b) => b..rrdData.replace(rrdData));
>> -      final services = await apiClient.getNodeServices(nodeID);
>> -      yield latestState.rebuild((b) => b..services.replace(services));
>> -      try {
>> -        final updates = await apiClient.getNodeAptUpdate(nodeID);
>> -        yield latestState.rebuild((b) => b..updates.replace(updates));
>> -        yield latestState
>> -            .rebuild((b) => b..updatesQueryPermissionFailure = false);
>> -      } on ProxmoxApiException catch (e) {
>> -        // only throw on non permission related errors
>> -        if (e.statusCode != 403) {
>> -          rethrow;
>> -        } else {
>> +    PveNodeStatusModel? status;
>> +    try {
>> +      status = await apiClient.getNodeStatus(nodeID);
>> +      if (event is UpdateNodeStatus) {
>> +        yield latestState.rebuild((b) => b..status.replace(status!));
>> +        final rrdData =
>> +        await apiClient.getNodeRRDdata(nodeID,
>> PveRRDTimeframeType.hour);
>> +        yield latestState.rebuild((b) => b..rrdData.replace(rrdData));
>> +        final services = await apiClient.getNodeServices(nodeID);
>> +        yield latestState.rebuild((b) => b..services.replace(services));
>> +        try {
>> +          final updates = await apiClient.getNodeAptUpdate(nodeID);
>> +          yield latestState.rebuild((b) => b..updates.replace(updates));
>>             yield latestState
>> -              .rebuild((b) => b..updatesQueryPermissionFailure = true);
>> +              .rebuild((b) => b..updatesQueryPermissionFailure = false);
>> +        }
>> +        on ProxmoxApiException catch (e) {
>> +            // only throw on non permission related errors
>> +            if (e.statusCode != 403) {
>> +              rethrow;
>> +            }
>> +            else {
>> +              yield latestState
>> +                .rebuild((b) => b..updatesQueryPermissionFailure =
>> true);
>> +            }
>> +          }
>> +          final disks = await apiClient.getNodeDisksList(nodeID);
>> +          yield latestState.rebuild((b) => b..disks.replace(disks));
>> +        }
>> +
>> +        if (event is PerformNodeAction) {
>> +          await apiClient.doResourceAction(
>> +            nodeID,
>> +            '',
>> +            'node',
>> +            event.action,
>> +            parameters: <String, String>{});
>> +          yield latestState;
>>           }
>>         }
>> -      final disks = await apiClient.getNodeDisksList(nodeID);
>> -      yield latestState.rebuild((b) => b..disks.replace(disks));
>> -    }
>> -    if (event is PerformNodeAction) {
>> -      await apiClient.doResourceAction(nodeID, '', 'node', event.action,
>> -          parameters: <String, String>{});
>> -      yield latestState;
>> -    }
>> +      catch(e){
>> +        yield latestState.rebuild(
>> +          (b) => b
>> +            ..updatesQueryPermissionFailure = true
>> +        );
>> +        if (context.mounted){
>> +          Navigator.of(context).pop();
> 
> Instead of navigating back immediately, I think it would make sense to
> instead display an AlertDialog, showing the error message to the user
> and letting them leave the screen through a "Close" button in the
> dialog. Otherwise, it feels a bit like the app is taking control away
> from the user. We use this approach in other places in the app (e.g. .
> What do you think?

Adding to this, I think you could use something similar to what the
PveGuestBackupWidget is using:

  Future<bool?> _showConfirmDialog(
      BuildContext context, String title, String body) async {
    return await showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text(title),
        content: Text(body),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: const Text(
              'Cancel',
              style: TextStyle(fontWeight: FontWeight.bold),
            ),
          ),
          TextButton(
            onPressed: () => Navigator.of(context).pop(true),
            child: const Text(
              'Confirm',
              style: TextStyle(fontWeight: FontWeight.bold),
            ),
          )
        ],
      ),
    );
  }

You could then wrap the Navigator.of(context).pop() like this:
  final confirm = (await _showConfirmDialog(
    context,
    "Node offline",
    "Node is offline. Do you want to navigate back?",
  ))!;
  if (confirm && context.mounted) {
    Navigator.of(context).pop();
  }

I think it would also make sense to have a utils method for opening an
AlertDialog for confirmation. But that could also be done separately in
another patch. I just noticed that we're using this in multiple widgets
already.


_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

      reply	other threads:[~2025-06-24 12:53 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-29 13:16 [pve-devel] [PATCH proxmox_dart_api_client/pve_flutter_frontend_null 0/2] fix #4976 Alexander Abraham
2025-04-29 13:16 ` [pve-devel] [PATCH dart_api_client 1/1] fix #4976: Request errors are Alexander Abraham
2025-05-02 10:19   ` Michael Köppl
2025-05-05 13:03     ` Michael Köppl
2025-04-29 13:16 ` [pve-devel] [PATCH flutter_frontend 1/1] fix #4976: ui: Nodes offline Alexander Abraham
2025-05-02 11:32   ` Michael Köppl
2025-06-24 12:53     ` Michael Köppl [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=03cea113-d66c-472c-ae4b-83829e7816b9@proxmox.com \
    --to=m.koeppl@proxmox.com \
    --cc=a.abraham@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal