From: Shan Shaji <s.shaji@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH pve_flutter_frontend 3/3] cleanup: run dart format
Date: Fri, 23 Oct 2026 13:40:36 +0200 [thread overview]
Message-ID: <20261023114036.70719-4-s.shaji@proxmox.com> (raw)
In-Reply-To: <20261023114036.70719-1-s.shaji@proxmox.com>
Signed-off-by: Shan Shaji <s.shaji@proxmox.com>
---
lib/utils/links.dart | 4 +-
.../firstWelcomeScreen/pve_welcome_faq.dart | 5 +-
lib/widgets/pve_lxc_overview.dart | 316 ++++----
lib/widgets/pve_node_overview.dart | 707 +++++++++---------
lib/widgets/pve_qemu_overview.dart | 301 ++++----
5 files changed, 664 insertions(+), 669 deletions(-)
diff --git a/lib/utils/links.dart b/lib/utils/links.dart
index a161d36..708f732 100644
--- a/lib/utils/links.dart
+++ b/lib/utils/links.dart
@@ -9,8 +9,8 @@ Future<bool> tryLaunchUrl(Uri url) async {
}
class Links {
- static final pvePricing =
- Uri.parse('https://www.proxmox.com/en/products/proxmox-virtual-environment/pricing');
+ static final pvePricing = Uri.parse(
+ 'https://www.proxmox.com/en/products/proxmox-virtual-environment/pricing');
static final proxmoxForum = Uri.parse('https://forum.proxmox.com');
static final pveUserList =
Uri.parse('https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-user');
diff --git a/lib/widgets/firstWelcomeScreen/pve_welcome_faq.dart b/lib/widgets/firstWelcomeScreen/pve_welcome_faq.dart
index b34c4f5..0c76bbb 100644
--- a/lib/widgets/firstWelcomeScreen/pve_welcome_faq.dart
+++ b/lib/widgets/firstWelcomeScreen/pve_welcome_faq.dart
@@ -39,7 +39,7 @@ class PveWelcomePageFAQ extends StatelessWidget {
),
const PveAnswer(
text:
- "Spice is currently supported, and we also support VNC through noVNC." ),
+ "Spice is currently supported, and we also support VNC through noVNC."),
const PveQuestion(text: "Which Spice client works?"),
const PveAnswer(
text:
@@ -47,7 +47,8 @@ class PveWelcomePageFAQ extends StatelessWidget {
Center(
child: OutlinedButton(
onPressed: () {
- final link = Platform.isIOS ? Links.aSpiceClient : Links.opaqueApp;
+ final link =
+ Platform.isIOS ? Links.aSpiceClient : Links.opaqueApp;
launchUrl(link);
},
style: OutlinedButton.styleFrom(
diff --git a/lib/widgets/pve_lxc_overview.dart b/lib/widgets/pve_lxc_overview.dart
index b0b210a..d6cc721 100644
--- a/lib/widgets/pve_lxc_overview.dart
+++ b/lib/widgets/pve_lxc_overview.dart
@@ -66,190 +66,190 @@ class PveLxcOverview extends StatelessWidget {
),
backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
body: SingleChildScrollView(
- child: Column(
- children: <Widget>[
- PveGuestOverviewHeader(
- background: !(status?.template ?? false)
- ? PveGuestHeaderRRDPageView(
- rrdData: state.rrdData,
- )
- : Center(
- child: Text(
- "TEMPLATE",
- style: TextStyle(
- color: Theme.of(context)
- .colorScheme
- .onSurfaceVariant,
- ),
+ child: Column(
+ children: <Widget>[
+ PveGuestOverviewHeader(
+ background: !(status?.template ?? false)
+ ? PveGuestHeaderRRDPageView(
+ rrdData: state.rrdData,
+ )
+ : Center(
+ child: Text(
+ "TEMPLATE",
+ style: TextStyle(
+ color: Theme.of(context)
+ .colorScheme
+ .onSurfaceVariant,
),
),
- width: width,
- guestID: guestID,
- guestStatus: status?.getLxcStatus(),
- guestName: config?.hostname ?? 'CT $guestID',
- guestNodeID: state.nodeID,
- guestType: 'lxc',
- ha: status?.ha,
- template: status?.template ?? false,
- ),
- ProxmoxStreamBuilder<PveTaskLogBloc, PveTaskLogState>(
- bloc: taskBloc,
- builder: (context, taskState) {
- if (taskState.tasks.isNotEmpty) {
- return PveTaskExpansionTile(
- task: taskState.tasks.first,
- showMorePage: Provider<PveTaskLogBloc>(
- create: (context) => PveTaskLogBloc(
- apiClient: taskBloc.apiClient,
- init: PveTaskLogState.init(state.nodeID),
+ ),
+ width: width,
+ guestID: guestID,
+ guestStatus: status?.getLxcStatus(),
+ guestName: config?.hostname ?? 'CT $guestID',
+ guestNodeID: state.nodeID,
+ guestType: 'lxc',
+ ha: status?.ha,
+ template: status?.template ?? false,
+ ),
+ ProxmoxStreamBuilder<PveTaskLogBloc, PveTaskLogState>(
+ bloc: taskBloc,
+ builder: (context, taskState) {
+ if (taskState.tasks.isNotEmpty) {
+ return PveTaskExpansionTile(
+ task: taskState.tasks.first,
+ showMorePage: Provider<PveTaskLogBloc>(
+ create: (context) => PveTaskLogBloc(
+ apiClient: taskBloc.apiClient,
+ init: PveTaskLogState.init(state.nodeID),
+ )
+ ..events.add(
+ FilterTasksByGuestID(
+ guestID: guestID,
+ ),
)
- ..events.add(
- FilterTasksByGuestID(
- guestID: guestID,
- ),
- )
- ..events.add(LoadTasks()),
- dispose: (context, bloc) => bloc.dispose(),
- child: const PveTaskLog(),
- ),
- );
- }
- return Container();
- },
- ),
- SizedBox(
- height: 130,
- child: SingleChildScrollView(
- scrollDirection: Axis.horizontal,
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: <Widget>[
- if (!(status?.template ?? false))
- ActionCard.withIcon(
- 'Power Settings',
- Icons.power_settings_new,
- () => showPowerMenuBottomSheet(
- context, lxcBloc)),
- if (!(status?.template ?? false))
- ActionCard.withIcon(
- 'Console',
- Icons.queue_play_next,
- () => showConsoleMenuBottomSheet(
- context,
- lxcBloc.apiClient,
- guestID,
- state.nodeID,
- 'lxc')),
+ ..events.add(LoadTasks()),
+ dispose: (context, bloc) => bloc.dispose(),
+ child: const PveTaskLog(),
+ ),
+ );
+ }
+ return Container();
+ },
+ ),
+ SizedBox(
+ height: 130,
+ child: SingleChildScrollView(
+ scrollDirection: Axis.horizontal,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: <Widget>[
+ if (!(status?.template ?? false))
+ ActionCard.withIcon(
+ 'Power Settings',
+ Icons.power_settings_new,
+ () => showPowerMenuBottomSheet(
+ context, lxcBloc)),
+ if (!(status?.template ?? false))
ActionCard.withIcon(
- 'Options',
- Icons.settings,
- () => Navigator.of(context)
- .push(MaterialPageRoute(
- builder: (context) => PveLxcOptions(
- lxcBloc: lxcBloc,
- ),
- fullscreenDialog: true))),
- if (!resourceBloc.latestState.isStandalone)
- ActionCard.withFaIcon(
- 'Migrate',
- FontAwesomeIcons.paperPlane,
- () => Navigator.of(context).push(
- _createMigrationRoute(
- guestID,
- state.nodeID,
- resourceBloc.apiClient!))),
+ 'Console',
+ Icons.queue_play_next,
+ () => showConsoleMenuBottomSheet(
+ context,
+ lxcBloc.apiClient,
+ guestID,
+ state.nodeID,
+ 'lxc')),
+ ActionCard.withIcon(
+ 'Options',
+ Icons.settings,
+ () => Navigator.of(context)
+ .push(MaterialPageRoute(
+ builder: (context) => PveLxcOptions(
+ lxcBloc: lxcBloc,
+ ),
+ fullscreenDialog: true))),
+ if (!resourceBloc.latestState.isStandalone)
ActionCard.withFaIcon(
- 'Backup',
- FontAwesomeIcons.floppyDisk,
+ 'Migrate',
+ FontAwesomeIcons.paperPlane,
() => Navigator.of(context).push(
- _createBackupRoute(guestID, state.nodeID,
+ _createMigrationRoute(
+ guestID,
+ state.nodeID,
resourceBloc.apiClient!))),
- ],
+ ActionCard.withFaIcon(
+ 'Backup',
+ FontAwesomeIcons.floppyDisk,
+ () => Navigator.of(context).push(
+ _createBackupRoute(guestID, state.nodeID,
+ resourceBloc.apiClient!))),
+ ],
+ ),
+ ),
+ ),
+ if (config != null) ...[
+ PveResourceDataCardWidget(
+ title: const Text(
+ 'Resources',
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: 20,
),
),
+ children: <Widget>[
+ ListTile(
+ leading: const FaIcon(FontAwesomeIcons.memory),
+ title: Text('${config.memory}'),
+ subtitle: const Text('Memory'),
+ dense: true,
+ ),
+ ListTile(
+ leading: const Icon(Icons.cached),
+ title: Text('${config.swap}'),
+ subtitle: const Text('Swap'),
+ dense: true,
+ ),
+ ListTile(
+ leading: const Icon(Icons.memory),
+ title: Text('${config.cores ?? 'unlimited'}'),
+ subtitle: const Text('Cores'),
+ dense: true,
+ ),
+ ListTile(
+ leading: const FaIcon(FontAwesomeIcons.hardDrive),
+ dense: true,
+ title: Text('${config.rootfs}'),
+ ),
+ ],
),
- if (config != null) ...[
- PveResourceDataCardWidget(
+ PveResourceDataCardWidget(
title: const Text(
- 'Resources',
+ 'Network',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
children: <Widget>[
- ListTile(
- leading: const FaIcon(FontAwesomeIcons.memory),
- title: Text('${config.memory}'),
- subtitle: const Text('Memory'),
- dense: true,
- ),
- ListTile(
- leading: const Icon(Icons.cached),
- title: Text('${config.swap}'),
- subtitle: const Text('Swap'),
- dense: true,
+ for (var net in config.net!)
+ ListTile(
+ leading:
+ const FaIcon(FontAwesomeIcons.ethernet),
+ dense: true,
+ title: Text(net),
+ ),
+ ]),
+ PveResourceDataCardWidget(
+ title: const Text(
+ 'DNS',
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: 20,
),
+ ),
+ children: <Widget>[
ListTile(
- leading: const Icon(Icons.memory),
- title: Text('${config.cores ?? 'unlimited'}'),
- subtitle: const Text('Cores'),
+ leading: const FaIcon(FontAwesomeIcons.globe),
dense: true,
+ title: Text(
+ config.searchdomain ?? 'Use host settings'),
+ subtitle: const Text('DNS Domain'),
),
ListTile(
- leading: const FaIcon(FontAwesomeIcons.hardDrive),
+ leading: const FaIcon(
+ FontAwesomeIcons.magnifyingGlass),
dense: true,
- title: Text('${config.rootfs}'),
+ title: Text(
+ config.nameserver ?? 'Use host settings'),
+ subtitle: const Text('DNS Server'),
),
- ],
- ),
- PveResourceDataCardWidget(
- title: const Text(
- 'Network',
- style: TextStyle(
- fontWeight: FontWeight.bold,
- fontSize: 20,
- ),
- ),
- children: <Widget>[
- for (var net in config.net!)
- ListTile(
- leading:
- const FaIcon(FontAwesomeIcons.ethernet),
- dense: true,
- title: Text(net),
- ),
- ]),
- PveResourceDataCardWidget(
- title: const Text(
- 'DNS',
- style: TextStyle(
- fontWeight: FontWeight.bold,
- fontSize: 20,
- ),
- ),
- children: <Widget>[
- ListTile(
- leading: const FaIcon(FontAwesomeIcons.globe),
- dense: true,
- title: Text(
- config.searchdomain ?? 'Use host settings'),
- subtitle: const Text('DNS Domain'),
- ),
- ListTile(
- leading: const FaIcon(
- FontAwesomeIcons.magnifyingGlass),
- dense: true,
- title: Text(
- config.nameserver ?? 'Use host settings'),
- subtitle: const Text('DNS Server'),
- ),
- ]),
- ],
- SizedBox(height: MediaQuery.of(context).viewPadding.bottom)
+ ]),
],
- ),
+ SizedBox(height: MediaQuery.of(context).viewPadding.bottom)
+ ],
),
+ ),
);
}),
);
diff --git a/lib/widgets/pve_node_overview.dart b/lib/widgets/pve_node_overview.dart
index 4ecdede..b9cc4db 100644
--- a/lib/widgets/pve_node_overview.dart
+++ b/lib/widgets/pve_node_overview.dart
@@ -63,391 +63,388 @@ class PveNodeOverview extends StatelessWidget {
),
backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
body: SingleChildScrollView(
- child: Column(
- children: <Widget>[
- if (rrd.isNotEmpty)
- Container(
- height: 200,
- color: Theme.of(context).colorScheme.primary,
- child: ScrollConfiguration(
- behavior: PVEScrollBehavior(),
- child: PageView.builder(
- itemCount: 4,
- itemBuilder: (context, item) {
- final page = item + 1;
- final pageIndicator = Text(
- '$page of 4',
- style: const TextStyle(
- color: Colors.white54,
- fontWeight: FontWeight.w500,
- ),
- );
- double? lastCpu = rrd.last.cpu;
- String lastCpuText = lastCpu != null
- ? "${(lastCpu * 100.0).toStringAsFixed(2)} %"
- : "";
- return Column(
- children: [
- if (item == 0)
- Expanded(
- child: PveRRDChart(
- title:
- 'CPU (${state.status?.cpuinfo.cpus ?? '-'})',
- subtitle: lastCpuText,
- data: rrd.where((e) => e.cpu != null).map(
- (e) => Point(
- e.time!.millisecondsSinceEpoch,
- (e.cpu ?? 0) * 100.0)),
- icon: Icon(Icons.memory, color: fgColor),
- bottomRight: pageIndicator,
- dataRenderer: (data) =>
- '${data.toStringAsFixed(2)} %',
- ),
+ child: Column(
+ children: <Widget>[
+ if (rrd.isNotEmpty)
+ Container(
+ height: 200,
+ color: Theme.of(context).colorScheme.primary,
+ child: ScrollConfiguration(
+ behavior: PVEScrollBehavior(),
+ child: PageView.builder(
+ itemCount: 4,
+ itemBuilder: (context, item) {
+ final page = item + 1;
+ final pageIndicator = Text(
+ '$page of 4',
+ style: const TextStyle(
+ color: Colors.white54,
+ fontWeight: FontWeight.w500,
+ ),
+ );
+ double? lastCpu = rrd.last.cpu;
+ String lastCpuText = lastCpu != null
+ ? "${(lastCpu * 100.0).toStringAsFixed(2)} %"
+ : "";
+ return Column(
+ children: [
+ if (item == 0)
+ Expanded(
+ child: PveRRDChart(
+ title:
+ 'CPU (${state.status?.cpuinfo.cpus ?? '-'})',
+ subtitle: lastCpuText,
+ data: rrd.where((e) => e.cpu != null).map(
+ (e) => Point(
+ e.time!.millisecondsSinceEpoch,
+ (e.cpu ?? 0) * 100.0)),
+ icon: Icon(Icons.memory, color: fgColor),
+ bottomRight: pageIndicator,
+ dataRenderer: (data) =>
+ '${data.toStringAsFixed(2)} %',
),
- if (item == 1)
- Expanded(
- child: PveRRDChart(
- title: 'Memory',
- subtitle: Renderers.formatSize(
- rrd.last.memused ?? 0),
- data: rrd.map((e) => Point(
- e.time!.millisecondsSinceEpoch,
- e.memused ?? 0)),
- icon: FaIcon(FontAwesomeIcons.memory,
- color: fgColor),
- bottomRight: pageIndicator,
- dataRenderer: (data) =>
- Renderers.formatSize(data),
- ),
+ ),
+ if (item == 1)
+ Expanded(
+ child: PveRRDChart(
+ title: 'Memory',
+ subtitle: Renderers.formatSize(
+ rrd.last.memused ?? 0),
+ data: rrd.map((e) => Point(
+ e.time!.millisecondsSinceEpoch,
+ e.memused ?? 0)),
+ icon: FaIcon(FontAwesomeIcons.memory,
+ color: fgColor),
+ bottomRight: pageIndicator,
+ dataRenderer: (data) =>
+ Renderers.formatSize(data),
),
- if (item == 2)
- Expanded(
- child: PveRRDChart(
- title: 'I/O wait',
- subtitle:
- rrd.last.iowait?.toStringAsFixed(2) ??
- '0',
- data: rrd.map((e) => Point(
- e.time!.millisecondsSinceEpoch,
- e.iowait ?? 0)),
- icon: Icon(Icons.timer, color: fgColor),
- bottomRight: pageIndicator,
- dataRenderer: (data) =>
- data.toStringAsFixed(3),
- ),
+ ),
+ if (item == 2)
+ Expanded(
+ child: PveRRDChart(
+ title: 'I/O wait',
+ subtitle:
+ rrd.last.iowait?.toStringAsFixed(2) ??
+ '0',
+ data: rrd.map((e) => Point(
+ e.time!.millisecondsSinceEpoch,
+ e.iowait ?? 0)),
+ icon: Icon(Icons.timer, color: fgColor),
+ bottomRight: pageIndicator,
+ dataRenderer: (data) =>
+ data.toStringAsFixed(3),
),
- if (item == 3)
- Expanded(
- child: PveRRDChart(
- title: 'Load',
- subtitle: rrd.last.loadavg
- ?.toStringAsFixed(2) ??
- '0',
- data: rrd.map((e) => Point(
- e.time!.millisecondsSinceEpoch,
- e.loadavg ?? 0)),
- icon: Icon(Icons.show_chart,
- color: fgColor),
- bottomRight: pageIndicator,
- dataRenderer: (data) =>
- data.toStringAsFixed(2),
- ),
+ ),
+ if (item == 3)
+ Expanded(
+ child: PveRRDChart(
+ title: 'Load',
+ subtitle:
+ rrd.last.loadavg?.toStringAsFixed(2) ??
+ '0',
+ data: rrd.map((e) => Point(
+ e.time!.millisecondsSinceEpoch,
+ e.loadavg ?? 0)),
+ icon:
+ Icon(Icons.show_chart, color: fgColor),
+ bottomRight: pageIndicator,
+ dataRenderer: (data) =>
+ data.toStringAsFixed(2),
),
- ],
- );
- },
- ),
+ ),
+ ],
+ );
+ },
),
),
- ProxmoxStreamBuilder<PveTaskLogBloc, PveTaskLogState>(
- bloc: tBloc,
- builder: (context, taskState) {
- if (taskState.tasks.isNotEmpty) {
- return Padding(
- padding: const EdgeInsets.all(4.0),
- child: PveTaskExpansionTile(
- task: taskState.tasks.first,
- showMorePage: Provider<PveTaskLogBloc>(
- create: (context) => PveTaskLogBloc(
- apiClient: tBloc.apiClient,
- init: PveTaskLogState.init(nodeID),
- )..events.add(LoadTasks()),
- dispose: (context, bloc) => bloc.dispose(),
- child: const PveTaskLog(),
- ),
- ),
- );
- }
- return Container();
- },
),
- SizedBox(
- height: 130,
- child: SingleChildScrollView(
- scrollDirection: Axis.horizontal,
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: <Widget>[
- ActionCard(
- icon: const Icon(
- Icons.power_settings_new,
- size: 55,
- color: Colors.white24,
- ),
- title: 'Power Settings',
- onTap: () =>
- showPowerMenuBottomSheet(context, nBloc),
+ ProxmoxStreamBuilder<PveTaskLogBloc, PveTaskLogState>(
+ bloc: tBloc,
+ builder: (context, taskState) {
+ if (taskState.tasks.isNotEmpty) {
+ return Padding(
+ padding: const EdgeInsets.all(4.0),
+ child: PveTaskExpansionTile(
+ task: taskState.tasks.first,
+ showMorePage: Provider<PveTaskLogBloc>(
+ create: (context) => PveTaskLogBloc(
+ apiClient: tBloc.apiClient,
+ init: PveTaskLogState.init(nodeID),
+ )..events.add(LoadTasks()),
+ dispose: (context, bloc) => bloc.dispose(),
+ child: const PveTaskLog(),
),
- ActionCard(
- icon: const Icon(
- Icons.queue_play_next,
- size: 55,
- color: Colors.white24,
- ),
- title: 'Console',
- onTap: () => showConsoleMenuBottomSheet(
- context, nBloc.apiClient, null, nodeID, 'node'),
+ ),
+ );
+ }
+ return Container();
+ },
+ ),
+ SizedBox(
+ height: 130,
+ child: SingleChildScrollView(
+ scrollDirection: Axis.horizontal,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: <Widget>[
+ ActionCard(
+ icon: const Icon(
+ Icons.power_settings_new,
+ size: 55,
+ color: Colors.white24,
),
- ],
- ),
+ title: 'Power Settings',
+ onTap: () => showPowerMenuBottomSheet(context, nBloc),
+ ),
+ ActionCard(
+ icon: const Icon(
+ Icons.queue_play_next,
+ size: 55,
+ color: Colors.white24,
+ ),
+ title: 'Console',
+ onTap: () => showConsoleMenuBottomSheet(
+ context, nBloc.apiClient, null, nodeID, 'node'),
+ ),
+ ],
),
),
- PveResourceDataCardWidget(
- expandable: false,
- showTitleTrailing: true,
- title: const Text(
- 'Summary',
- style: TextStyle(
- fontWeight: FontWeight.bold,
- fontSize: 20,
- ),
+ ),
+ PveResourceDataCardWidget(
+ expandable: false,
+ showTitleTrailing: true,
+ title: const Text(
+ 'Summary',
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: 20,
+ ),
+ ),
+ titleTrailing: Text(Renderers.renderDuration(
+ Duration(seconds: status?.uptime ?? 0))),
+ subtitle: Text(status?.pveversion ?? ''),
+ children: [
+ ListTile(
+ dense: true,
+ title: Text(status?.kversion ?? 'unknown'),
+ subtitle: const Text('Kernel'),
),
- titleTrailing: Text(Renderers.renderDuration(
- Duration(seconds: status?.uptime ?? 0))),
- subtitle: Text(status?.pveversion ?? ''),
- children: [
+ if (status?.cpuinfo != null)
ListTile(
dense: true,
- title: Text(status?.kversion ?? 'unknown'),
- subtitle: const Text('Kernel'),
+ title: Text(
+ '${status!.cpuinfo.cpus} x ${status.cpuinfo.model}'),
+ subtitle: Text(
+ 'CPU Information (Socket: ${status.cpuinfo.sockets})'),
),
- if (status?.cpuinfo != null)
- ListTile(
- dense: true,
- title: Text(
- '${status!.cpuinfo.cpus} x ${status.cpuinfo.model}'),
- subtitle: Text(
- 'CPU Information (Socket: ${status.cpuinfo.sockets})'),
- ),
- if (status?.ksm.shared ?? false)
- CheckboxListTile(
- dense: true,
- value: status?.ksm.shared ?? false,
- title: const Text('Kernel same-page merging (KSM)',
- style: TextStyle(color: Colors.black)),
- onChanged: null,
- ),
- if (status?.rootfs != null) ...[
- const Divider(
- indent: 10,
- endIndent: 10,
- ),
- Padding(
- padding: const EdgeInsets.symmetric(vertical: 8.0),
- child: ListTile(
- title: const Text('HD space (root)'),
- subtitle: ProxmoxCapacityIndicator(
- icon: FaIcon(
- FontAwesomeIcons.solidHardDrive,
- color: Colors.blueGrey[300],
- ),
- usedValue:
- Renderers.formatSize(status!.rootfs.used),
- totalValue:
- Renderers.formatSize(status.rootfs.total),
- usedPercent:
- (status.rootfs.used) / (status.rootfs.total),
+ if (status?.ksm.shared ?? false)
+ CheckboxListTile(
+ dense: true,
+ value: status?.ksm.shared ?? false,
+ title: const Text('Kernel same-page merging (KSM)',
+ style: TextStyle(color: Colors.black)),
+ onChanged: null,
+ ),
+ if (status?.rootfs != null) ...[
+ const Divider(
+ indent: 10,
+ endIndent: 10,
+ ),
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 8.0),
+ child: ListTile(
+ title: const Text('HD space (root)'),
+ subtitle: ProxmoxCapacityIndicator(
+ icon: FaIcon(
+ FontAwesomeIcons.solidHardDrive,
+ color: Colors.blueGrey[300],
),
+ usedValue:
+ Renderers.formatSize(status!.rootfs.used),
+ totalValue:
+ Renderers.formatSize(status.rootfs.total),
+ usedPercent:
+ (status.rootfs.used) / (status.rootfs.total),
),
),
- ],
- ],
- ),
- PveResourceDataCardWidget(
- expandable: true,
- showTitleTrailing: !state.allServicesRunning,
- titleTrailing: const Icon(Icons.warning),
- title: const Text(
- 'Services',
- style: TextStyle(
- fontWeight: FontWeight.bold,
- fontSize: 20,
),
+ ],
+ ],
+ ),
+ PveResourceDataCardWidget(
+ expandable: true,
+ showTitleTrailing: !state.allServicesRunning,
+ titleTrailing: const Icon(Icons.warning),
+ title: const Text(
+ 'Services',
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: 20,
),
- subtitle: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- if (state.allServicesRunning) const Text('All running'),
- if (!state.allServicesRunning)
- const Text('One or more not running'),
- const Divider(),
- ],
- ),
- children: state.services
- .map(
- (s) => ListTile(
- dense: true,
- title: Text(s.name),
- subtitle: Text(s.desc),
- trailing: getServiceStateIcon(context, s),
- ),
- )
- .toList()
- ..sort((a, b) => (a.title as Text)
- .data!
- .compareTo((b.title as Text).data!)),
),
- PveResourceDataCardWidget(
- expandable: !state.updatesQueryPermissionFailure,
- showTitleTrailing: state.updates.isNotEmpty,
- titleTrailing: const Icon(Icons.info_outline),
- title: const Text(
- 'Updates',
- style: TextStyle(
- fontWeight: FontWeight.bold,
- fontSize: 20,
- ),
- ),
- subtitle: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- if (state.updatesQueryPermissionFailure)
- const Text('Lacking permission to query updates'),
- if (state.updates.isEmpty &&
- !state.updatesQueryPermissionFailure)
- const Text('No updates available'),
- if (state.updates.isNotEmpty)
- Text(
- '${state.updates.length} packages are ready to update'),
- if (!state.updatesQueryPermissionFailure)
- const Divider(),
- ],
+ subtitle: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: <Widget>[
+ if (state.allServicesRunning) const Text('All running'),
+ if (!state.allServicesRunning)
+ const Text('One or more not running'),
+ const Divider(),
+ ],
+ ),
+ children: state.services
+ .map(
+ (s) => ListTile(
+ dense: true,
+ title: Text(s.name),
+ subtitle: Text(s.desc),
+ trailing: getServiceStateIcon(context, s),
+ ),
+ )
+ .toList()
+ ..sort((a, b) => (a.title as Text)
+ .data!
+ .compareTo((b.title as Text).data!)),
+ ),
+ PveResourceDataCardWidget(
+ expandable: !state.updatesQueryPermissionFailure,
+ showTitleTrailing: state.updates.isNotEmpty,
+ titleTrailing: const Icon(Icons.info_outline),
+ title: const Text(
+ 'Updates',
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: 20,
),
- children: state.updates
- .map(
- (s) => ListTile(
- dense: true,
- title: Text(s.title),
- subtitle: Text(
- '${s.package}: ${s.oldVersion ?? ''} -> ${s.version}'),
- trailing: IconButton(
- icon: const Icon(
- Icons.info,
- ),
- onPressed: () => showDialog(
- context: context,
- builder: (context) => SimpleDialog(
- title: const Text('Description'),
- contentPadding: const EdgeInsets.all(24),
- children: <Widget>[
- Text(
- s.description ?? '',
- style: const TextStyle(fontSize: 12),
- )
- ],
- ),
+ ),
+ subtitle: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: <Widget>[
+ if (state.updatesQueryPermissionFailure)
+ const Text('Lacking permission to query updates'),
+ if (state.updates.isEmpty &&
+ !state.updatesQueryPermissionFailure)
+ const Text('No updates available'),
+ if (state.updates.isNotEmpty)
+ Text(
+ '${state.updates.length} packages are ready to update'),
+ if (!state.updatesQueryPermissionFailure) const Divider(),
+ ],
+ ),
+ children: state.updates
+ .map(
+ (s) => ListTile(
+ dense: true,
+ title: Text(s.title),
+ subtitle: Text(
+ '${s.package}: ${s.oldVersion ?? ''} -> ${s.version}'),
+ trailing: IconButton(
+ icon: const Icon(
+ Icons.info,
+ ),
+ onPressed: () => showDialog(
+ context: context,
+ builder: (context) => SimpleDialog(
+ title: const Text('Description'),
+ contentPadding: const EdgeInsets.all(24),
+ children: <Widget>[
+ Text(
+ s.description ?? '',
+ style: const TextStyle(fontSize: 12),
+ )
+ ],
),
),
),
- )
- .toList()
- ..sort((a, b) => (a.title as Text)
- .data!
- .compareTo((b.title as Text).data!)),
- ),
- PveResourceDataCardWidget(
- expandable: false,
- title: const Text(
- 'Disks',
- style: TextStyle(
- fontWeight: FontWeight.bold,
- fontSize: 20,
- ),
+ ),
+ )
+ .toList()
+ ..sort((a, b) => (a.title as Text)
+ .data!
+ .compareTo((b.title as Text).data!)),
+ ),
+ PveResourceDataCardWidget(
+ expandable: false,
+ title: const Text(
+ 'Disks',
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: 20,
),
- showTitleTrailing: !state.allDisksHealthy,
- titleTrailing: const Icon(Icons.warning),
- subtitle: state.allDisksHealthy
- ? const Text('No health issues')
- : const Text('Check disks, health error indicated!'),
- children: state.disks
- .map(
- (d) => ListTile(
- dense: true,
- leading: FaIcon(FontAwesomeIcons.solidHardDrive,
- color: state.isDiskHealthy(d)
- ? Colors.grey
- : Colors.red),
- title:
- Text('${d.type!.toUpperCase()}: ${d.devPath}'),
- subtitle: Text(
- 'Usage: ${d.used} ${Renderers.formatSize(d.size ?? 0)}'),
- trailing: IconButton(
- icon: const Icon(
- Icons.info,
- ),
- onPressed: () => showDialog(
- context: context,
- builder: (context) => SimpleDialog(
- title: const Text('Details'),
- contentPadding: const EdgeInsets.all(24),
- children: <Widget>[
- ListTile(
- title: const Text("Device"),
- subtitle: Text(d.devPath!),
- ),
- ListTile(
- title: const Text("Type"),
- subtitle: Text(d.type!),
- ),
- ListTile(
- title: const Text("Usage"),
- subtitle: Text(d.used!),
- ),
- ListTile(
- title: const Text("GPT"),
- subtitle: Text(d.gpt.toString()),
- ),
- ListTile(
- title: const Text("Model"),
- subtitle: Text(d.model!),
- ),
- ListTile(
- title: const Text("Serial"),
- subtitle: Text(d.serial!),
- ),
- ListTile(
- title: const Text("S.M.A.R.T"),
- subtitle: Text(d.health!),
- ),
- ListTile(
- title: const Text("Wearout"),
- subtitle: Text(d.wearoutPercentage),
- )
- ],
- ),
+ ),
+ showTitleTrailing: !state.allDisksHealthy,
+ titleTrailing: const Icon(Icons.warning),
+ subtitle: state.allDisksHealthy
+ ? const Text('No health issues')
+ : const Text('Check disks, health error indicated!'),
+ children: state.disks
+ .map(
+ (d) => ListTile(
+ dense: true,
+ leading: FaIcon(FontAwesomeIcons.solidHardDrive,
+ color: state.isDiskHealthy(d)
+ ? Colors.grey
+ : Colors.red),
+ title: Text('${d.type!.toUpperCase()}: ${d.devPath}'),
+ subtitle: Text(
+ 'Usage: ${d.used} ${Renderers.formatSize(d.size ?? 0)}'),
+ trailing: IconButton(
+ icon: const Icon(
+ Icons.info,
+ ),
+ onPressed: () => showDialog(
+ context: context,
+ builder: (context) => SimpleDialog(
+ title: const Text('Details'),
+ contentPadding: const EdgeInsets.all(24),
+ children: <Widget>[
+ ListTile(
+ title: const Text("Device"),
+ subtitle: Text(d.devPath!),
+ ),
+ ListTile(
+ title: const Text("Type"),
+ subtitle: Text(d.type!),
+ ),
+ ListTile(
+ title: const Text("Usage"),
+ subtitle: Text(d.used!),
+ ),
+ ListTile(
+ title: const Text("GPT"),
+ subtitle: Text(d.gpt.toString()),
+ ),
+ ListTile(
+ title: const Text("Model"),
+ subtitle: Text(d.model!),
+ ),
+ ListTile(
+ title: const Text("Serial"),
+ subtitle: Text(d.serial!),
+ ),
+ ListTile(
+ title: const Text("S.M.A.R.T"),
+ subtitle: Text(d.health!),
+ ),
+ ListTile(
+ title: const Text("Wearout"),
+ subtitle: Text(d.wearoutPercentage),
+ )
+ ],
),
),
),
- )
- .toList()
- ..sort((a, b) => (a.title as Text)
- .data!
- .compareTo((b.title as Text).data!)),
- ),
- SizedBox(height: MediaQuery.of(context).viewPadding.bottom)
- ],
- ),
+ ),
+ )
+ .toList()
+ ..sort((a, b) => (a.title as Text)
+ .data!
+ .compareTo((b.title as Text).data!)),
+ ),
+ SizedBox(height: MediaQuery.of(context).viewPadding.bottom)
+ ],
),
+ ),
);
},
);
diff --git a/lib/widgets/pve_qemu_overview.dart b/lib/widgets/pve_qemu_overview.dart
index 2f366a8..322fcf7 100644
--- a/lib/widgets/pve_qemu_overview.dart
+++ b/lib/widgets/pve_qemu_overview.dart
@@ -67,176 +67,173 @@ class PveQemuOverview extends StatelessWidget {
),
backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
body: SingleChildScrollView(
- child: Column(
- children: <Widget>[
- PveGuestOverviewHeader(
- background: !(status?.template ?? false)
- ? PveGuestHeaderRRDPageView(
- rrdData: rrdData,
- )
- : const Center(
- child: Text(
- "TEMPLATE",
- style: TextStyle(
- color: Colors.white,
- ),
+ child: Column(
+ children: <Widget>[
+ PveGuestOverviewHeader(
+ background: !(status?.template ?? false)
+ ? PveGuestHeaderRRDPageView(
+ rrdData: rrdData,
+ )
+ : const Center(
+ child: Text(
+ "TEMPLATE",
+ style: TextStyle(
+ color: Colors.white,
),
),
- width: width,
- guestID: guestID,
- guestStatus: status?.getQemuStatus(),
- guestName: config?.name ?? 'VM $guestID',
- guestNodeID: state.nodeID,
- guestType: 'qemu',
- ha: status?.ha,
- template: status?.template ?? false,
- ),
- ProxmoxStreamBuilder<PveTaskLogBloc, PveTaskLogState>(
- bloc: taskBloc,
- builder: (context, taskState) {
- if (taskState.tasks.isNotEmpty) {
- return PveTaskExpansionTile(
- headerColor:
- Theme.of(context).colorScheme.onSurfaceVariant,
- task: taskState.tasks.first,
- showMorePage: Provider<PveTaskLogBloc>(
- create: (context) => PveTaskLogBloc(
- apiClient: taskBloc.apiClient,
- init: PveTaskLogState.init(state.nodeID),
+ ),
+ width: width,
+ guestID: guestID,
+ guestStatus: status?.getQemuStatus(),
+ guestName: config?.name ?? 'VM $guestID',
+ guestNodeID: state.nodeID,
+ guestType: 'qemu',
+ ha: status?.ha,
+ template: status?.template ?? false,
+ ),
+ ProxmoxStreamBuilder<PveTaskLogBloc, PveTaskLogState>(
+ bloc: taskBloc,
+ builder: (context, taskState) {
+ if (taskState.tasks.isNotEmpty) {
+ return PveTaskExpansionTile(
+ headerColor:
+ Theme.of(context).colorScheme.onSurfaceVariant,
+ task: taskState.tasks.first,
+ showMorePage: Provider<PveTaskLogBloc>(
+ create: (context) => PveTaskLogBloc(
+ apiClient: taskBloc.apiClient,
+ init: PveTaskLogState.init(state.nodeID),
+ )
+ ..events.add(
+ FilterTasksByGuestID(
+ guestID: guestID,
+ ),
)
- ..events.add(
- FilterTasksByGuestID(
- guestID: guestID,
- ),
- )
- ..events.add(LoadTasks()),
- dispose: (context, bloc) => bloc.dispose(),
- child: const PveTaskLog(),
- ),
- );
- }
- return Container();
- },
- ),
- SizedBox(
- height: 130,
- child: SingleChildScrollView(
- scrollDirection: Axis.horizontal,
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: <Widget>[
- if (!(status?.template ?? false))
- ActionCard.withIcon(
- 'Power Settings',
- Icons.power_settings_new,
- () =>
- showPowerMenuBottomSheet(context, bloc)),
- if (!(status?.template ?? false))
- ActionCard.withIcon(
- 'Console',
- Icons.queue_play_next,
- () => showConsoleMenuBottomSheet(
- context,
- bloc.apiClient,
- guestID,
- state.nodeID,
- 'qemu',
- allowSpice: status?.spice ?? false,
- )),
+ ..events.add(LoadTasks()),
+ dispose: (context, bloc) => bloc.dispose(),
+ child: const PveTaskLog(),
+ ),
+ );
+ }
+ return Container();
+ },
+ ),
+ SizedBox(
+ height: 130,
+ child: SingleChildScrollView(
+ scrollDirection: Axis.horizontal,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: <Widget>[
+ if (!(status?.template ?? false))
+ ActionCard.withIcon(
+ 'Power Settings',
+ Icons.power_settings_new,
+ () => showPowerMenuBottomSheet(context, bloc)),
+ if (!(status?.template ?? false))
ActionCard.withIcon(
- 'Options',
- Icons.settings,
- () => Navigator.of(context)
- .push(_createOptionsRoute(bloc))),
- if (!rBloc.latestState.isStandalone)
- ActionCard.withFaIcon(
- 'Migrate',
- FontAwesomeIcons.paperPlane,
- () => Navigator.of(context).push(
- _createMigrationRoute(guestID,
- state.nodeID, bloc.apiClient))),
+ 'Console',
+ Icons.queue_play_next,
+ () => showConsoleMenuBottomSheet(
+ context,
+ bloc.apiClient,
+ guestID,
+ state.nodeID,
+ 'qemu',
+ allowSpice: status?.spice ?? false,
+ )),
+ ActionCard.withIcon(
+ 'Options',
+ Icons.settings,
+ () => Navigator.of(context)
+ .push(_createOptionsRoute(bloc))),
+ if (!rBloc.latestState.isStandalone)
ActionCard.withFaIcon(
- 'Backup',
- FontAwesomeIcons.floppyDisk,
+ 'Migrate',
+ FontAwesomeIcons.paperPlane,
() => Navigator.of(context).push(
- _createBackupRoute(guestID, state.nodeID,
+ _createMigrationRoute(guestID, state.nodeID,
bloc.apiClient))),
- ],
- ),
+ ActionCard.withFaIcon(
+ 'Backup',
+ FontAwesomeIcons.floppyDisk,
+ () => Navigator.of(context).push(
+ _createBackupRoute(
+ guestID, state.nodeID, bloc.apiClient))),
+ ],
),
),
- if (config != null)
- PveResourceDataCardWidget(
- expandable: false,
- title: const Text(
- 'Hardware',
- style: TextStyle(
- fontWeight: FontWeight.bold,
- fontSize: 20,
- ),
+ ),
+ if (config != null)
+ PveResourceDataCardWidget(
+ expandable: false,
+ title: const Text(
+ 'Hardware',
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: 20,
),
- children: [
- ListTile(
- leading: const FaIcon(FontAwesomeIcons.memory),
- title: Text('${config.memory}'),
- subtitle: const Text('Memory'),
- dense: true,
- ),
- ListTile(
- leading: const Icon(Icons.memory),
- title: Text(
- '${config.cores} Cores ${config.sockets} Socket'),
- subtitle: const Text('Processor'),
- dense: true,
- ),
+ ),
+ children: [
+ ListTile(
+ leading: const FaIcon(FontAwesomeIcons.memory),
+ title: Text('${config.memory}'),
+ subtitle: const Text('Memory'),
+ dense: true,
+ ),
+ ListTile(
+ leading: const Icon(Icons.memory),
+ title: Text(
+ '${config.cores} Cores ${config.sockets} Socket'),
+ subtitle: const Text('Processor'),
+ dense: true,
+ ),
+ ListTile(
+ leading: const FaIcon(FontAwesomeIcons.microchip),
+ title:
+ Text(config.bios?.name ?? 'Default (SeaBIOS)'),
+ subtitle: const Text('BIOS'),
+ dense: true,
+ ),
+ ListTile(
+ leading: const FaIcon(FontAwesomeIcons.gears),
+ dense: true,
+ title: Text(config.machine ?? 'Default (i440fx)'),
+ subtitle: const Text('Machine Type'),
+ ),
+ ListTile(
+ leading: const FaIcon(FontAwesomeIcons.database),
+ title:
+ Text(config.scsihw?.name ?? 'Default (i440fx)'),
+ subtitle: const Text('SCSI Controller'),
+ dense: true,
+ ),
+ for (var ide in config.ide!)
ListTile(
- leading: const FaIcon(FontAwesomeIcons.microchip),
- title: Text(
- config.bios?.name ?? 'Default (SeaBIOS)'),
- subtitle: const Text('BIOS'),
+ leading:
+ const FaIcon(FontAwesomeIcons.compactDisc),
+ title: Text(ide),
+ subtitle: const Text('CD/DVD Drive'),
dense: true,
),
+ for (var scsi in config.scsi!)
ListTile(
- leading: const FaIcon(FontAwesomeIcons.gears),
+ leading: const FaIcon(FontAwesomeIcons.hardDrive),
+ title: Text(scsi),
+ subtitle: const Text('Hard Disk'),
dense: true,
- title: Text(config.machine ?? 'Default (i440fx)'),
- subtitle: const Text('Machine Type'),
),
+ for (var net in config.net!)
ListTile(
- leading: const FaIcon(FontAwesomeIcons.database),
- title: Text(
- config.scsihw?.name ?? 'Default (i440fx)'),
- subtitle: const Text('SCSI Controller'),
+ leading: const FaIcon(FontAwesomeIcons.ethernet),
dense: true,
- ),
- for (var ide in config.ide!)
- ListTile(
- leading:
- const FaIcon(FontAwesomeIcons.compactDisc),
- title: Text(ide),
- subtitle: const Text('CD/DVD Drive'),
- dense: true,
- ),
- for (var scsi in config.scsi!)
- ListTile(
- leading:
- const FaIcon(FontAwesomeIcons.hardDrive),
- title: Text(scsi),
- subtitle: const Text('Hard Disk'),
- dense: true,
- ),
- for (var net in config.net!)
- ListTile(
- leading:
- const FaIcon(FontAwesomeIcons.ethernet),
- dense: true,
- subtitle: const Text('Network Device'),
- title: Text(net),
- )
- ]),
- SizedBox(height: MediaQuery.of(context).viewPadding.bottom)
- ],
- )),
+ subtitle: const Text('Network Device'),
+ title: Text(net),
+ )
+ ]),
+ SizedBox(height: MediaQuery.of(context).viewPadding.bottom)
+ ],
+ )),
);
}),
);
--
2.50.1
prev parent reply other threads:[~2026-10-23 11:41 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-23 11:40 [PATCH pve_flutter_frontend 0/3] fix: ui: clipping of ui elements in iPhone duo Shan Shaji
2026-10-23 11:40 ` [PATCH pve_flutter_frontend 1/3] fix: ui being inconsistent in overview pages Shan Shaji
2026-10-23 11:40 ` [PATCH pve_flutter_frontend 2/3] fix: ui: bottom overflow on apple's duo device Shan Shaji
2026-10-23 11:40 ` Shan Shaji [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=20261023114036.70719-4-s.shaji@proxmox.com \
--to=s.shaji@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