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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.