public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [PATCH pve_flutter_frontend 0/3] feat: ui: add bottom sheet to show editable options of VMs/CTs
@ 2025-09-23  9:36 Shan Shaji
  2025-09-23  9:36 ` [pve-devel] [PATCH pve_flutter_frontend 1/3] cleanup: run `dart format` on both qemu and lxc options page Shan Shaji
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Shan Shaji @ 2025-09-23  9:36 UTC (permalink / raw)
  To: pve-devel

On the options page for VMs and CTs it was easy to change the
configs by mistake. To avoid that, all currently available 
editable options will be shown inside a bottom sheet. 

The values will only be updated when the update button is pressed. 

Shan Shaji (3):
  cleanup: run `dart format` on both qemu and lxc options page
  feat: ui: add bottom sheet to change VMs/CTs options
  cleanup: remove `PveConfigSwitchListTile` in favor of
    PveConfigListTile

 .../pve_config_switch_form.dart               |  54 +++
 lib/widgets/pve_config_list_tile.dart         | 176 ++++++++++
 lib/widgets/pve_config_switch_list_tile.dart  |  50 ---
 lib/widgets/pve_lxc_options_widget.dart       | 156 +++++----
 lib/widgets/pve_qemu_options_widget.dart      | 315 +++++++++++-------
 5 files changed, 508 insertions(+), 243 deletions(-)
 create mode 100644 lib/widgets/pve_config_forms/pve_config_switch_form.dart
 create mode 100644 lib/widgets/pve_config_list_tile.dart
 delete mode 100644 lib/widgets/pve_config_switch_list_tile.dart

-- 
2.47.2



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


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [pve-devel] [PATCH pve_flutter_frontend 1/3] cleanup: run `dart format` on both qemu and lxc options page
  2025-09-23  9:36 [pve-devel] [PATCH pve_flutter_frontend 0/3] feat: ui: add bottom sheet to show editable options of VMs/CTs Shan Shaji
@ 2025-09-23  9:36 ` Shan Shaji
  2025-09-23  9:36 ` [pve-devel] [PATCH pve_flutter_frontend 2/3] feat: ui: add bottom sheet to change VMs/CTs options Shan Shaji
  2025-09-23  9:36 ` [pve-devel] [PATCH pve_flutter_frontend 3/3] cleanup: remove `PveConfigSwitchListTile` in favor of PveConfigListTile Shan Shaji
  2 siblings, 0 replies; 7+ messages in thread
From: Shan Shaji @ 2025-09-23  9:36 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Shan Shaji <s.shaji@proxmox.com>
---
 lib/widgets/pve_lxc_options_widget.dart  | 138 ++++++------
 lib/widgets/pve_qemu_options_widget.dart | 256 +++++++++++------------
 2 files changed, 197 insertions(+), 197 deletions(-)

diff --git a/lib/widgets/pve_lxc_options_widget.dart b/lib/widgets/pve_lxc_options_widget.dart
index 7ad0224..5b6e009 100644
--- a/lib/widgets/pve_lxc_options_widget.dart
+++ b/lib/widgets/pve_lxc_options_widget.dart
@@ -16,76 +16,76 @@ class PveLxcOptions extends StatelessWidget {
           final config = state.config;
           if (config != null) {
             return Scaffold(
-                appBar: AppBar(),
-                body: SingleChildScrollView(
-                  child: Column(
-                    children: <Widget>[
-                      ListTile(
-                        title: const Text("Name"),
-                        subtitle: Text(config.hostname ?? 'undefined'),
-                      ),
-                      PveConfigSwitchListTile(
-                        title: const Text("Start on boot"),
-                        value: config.onboot,
-                        defaultValue: false,
-                        pending: config.getPending('onboot'),
-                        onChanged: (v) => lxcBloc!.events
-                            .add(UpdateLxcConfigBool('onboot', v)),
-                        onDeleted: () => lxcBloc!.events
-                            .add(RevertPendingLxcConfig('onboot')),
-                      ),
-                      ListTile(
-                        title: const Text("Start/Shutdown order"),
-                        subtitle: Text(config.startup ?? "Default (any)"),
-                      ),
-                      ListTile(
-                        title: const Text("OS Type"),
-                        subtitle: Text("${config.ostype}"),
-                      ),
-                      ListTile(
-                        title: const Text("Architecture"),
-                        subtitle: Text("${config.arch}"),
-                      ),
-                      PveConfigSwitchListTile(
-                        title: const Text("/dev/console"),
-                        value: config.console,
-                        defaultValue: true,
-                        pending: config.getPending('console'),
-                        onChanged: (v) => lxcBloc!.events
-                            .add(UpdateLxcConfigBool('console', v)),
-                        onDeleted: () => lxcBloc!.events
-                            .add(RevertPendingLxcConfig('console')),
-                      ),
-                      ListTile(
-                        title: const Text("TTY Count"),
-                        subtitle: Text("${config.tty ?? 2}"),
-                      ),
-                      ListTile(
-                        title: const Text("Console Mode"),
-                        subtitle: Text(config.cmode?.name ?? 'tty'),
-                      ),
-                      PveConfigSwitchListTile(
-                        title: const Text("Protection"),
-                        value: config.protection,
-                        defaultValue: false,
-                        pending: config.getPending('protection'),
-                        onChanged: (v) => lxcBloc!.events
-                            .add(UpdateLxcConfigBool('protection', v)),
-                        onDeleted: () => lxcBloc!.events
-                            .add(RevertPendingLxcConfig('protection')),
-                      ),
-                      ListTile(
-                        title: const Text("Unprivileged"),
-                        subtitle:
-                            Text(config.unprivileged ?? false ? 'Yes' : 'No'),
-                      ),
-                      ListTile(
-                        title: const Text("Features"),
-                        subtitle: Text(config.features?.toString() ?? 'none'),
-                      ),
-                    ],
-                  ),
+              appBar: AppBar(),
+              body: SingleChildScrollView(
+                child: Column(
+                  children: <Widget>[
+                    ListTile(
+                      title: const Text("Name"),
+                      subtitle: Text(config.hostname ?? 'undefined'),
+                    ),
+                    PveConfigSwitchListTile(
+                      title: const Text("Start on boot"),
+                      value: config.onboot,
+                      defaultValue: false,
+                      pending: config.getPending('onboot'),
+                      onChanged: (v) =>
+                          lxcBloc!.events.add(UpdateLxcConfigBool('onboot', v)),
+                      onDeleted: () =>
+                          lxcBloc!.events.add(RevertPendingLxcConfig('onboot')),
+                    ),
+                    ListTile(
+                      title: const Text("Start/Shutdown order"),
+                      subtitle: Text(config.startup ?? "Default (any)"),
+                    ),
+                    ListTile(
+                      title: const Text("OS Type"),
+                      subtitle: Text("${config.ostype}"),
+                    ),
+                    ListTile(
+                      title: const Text("Architecture"),
+                      subtitle: Text("${config.arch}"),
+                    ),
+                    PveConfigSwitchListTile(
+                      title: const Text("/dev/console"),
+                      value: config.console,
+                      defaultValue: true,
+                      pending: config.getPending('console'),
+                      onChanged: (v) => lxcBloc!.events
+                          .add(UpdateLxcConfigBool('console', v)),
+                      onDeleted: () => lxcBloc!.events
+                          .add(RevertPendingLxcConfig('console')),
+                    ),
+                    ListTile(
+                      title: const Text("TTY Count"),
+                      subtitle: Text("${config.tty ?? 2}"),
+                    ),
+                    ListTile(
+                      title: const Text("Console Mode"),
+                      subtitle: Text(config.cmode?.name ?? 'tty'),
+                    ),
+                    PveConfigSwitchListTile(
+                      title: const Text("Protection"),
+                      value: config.protection,
+                      defaultValue: false,
+                      pending: config.getPending('protection'),
+                      onChanged: (v) => lxcBloc!.events
+                          .add(UpdateLxcConfigBool('protection', v)),
+                      onDeleted: () => lxcBloc!.events
+                          .add(RevertPendingLxcConfig('protection')),
+                    ),
+                    ListTile(
+                      title: const Text("Unprivileged"),
+                      subtitle:
+                          Text(config.unprivileged ?? false ? 'Yes' : 'No'),
+                    ),
+                    ListTile(
+                      title: const Text("Features"),
+                      subtitle: Text(config.features?.toString() ?? 'none'),
+                    ),
+                  ],
                 ),
+              ),
             );
           }
           return const Center(
diff --git a/lib/widgets/pve_qemu_options_widget.dart b/lib/widgets/pve_qemu_options_widget.dart
index 7ed0a3e..992a382 100644
--- a/lib/widgets/pve_qemu_options_widget.dart
+++ b/lib/widgets/pve_qemu_options_widget.dart
@@ -19,137 +19,137 @@ class PveQemuOptions extends StatelessWidget {
           if (state.config != null) {
             final config = state.config!;
             return Scaffold(
-                appBar: AppBar(
-                  leading: IconButton(
-                    icon: const Icon(Icons.close),
-                    onPressed: () => Navigator.of(context).pop(),
-                  ),
+              appBar: AppBar(
+                leading: IconButton(
+                  icon: const Icon(Icons.close),
+                  onPressed: () => Navigator.of(context).pop(),
                 ),
-                body: SingleChildScrollView(
-                  child: Form(
-                    key: _formKey,
-                    onChanged: () {},
-                    child: Column(
-                      children: <Widget>[
-                        ListTile(
-                          title: const Text("Name"),
-                          subtitle: Text(config.name ?? 'VM$guestID'),
-                        ),
-                        PveConfigSwitchListTile(
-                          title: const Text("Start on boot"),
-                          value: config.onboot,
-                          defaultValue: false,
-                          pending: config.getPending('onboot'),
-                          onChanged: (v) => bloc.events
-                              .add(UpdateQemuConfigBool('onboot', v)),
-                          onDeleted: () => bloc.events
-                              .add(RevertPendingQemuConfig('onboot')),
-                        ),
-                        ListTile(
-                          title: const Text("Start/Shutdown order"),
-                          subtitle: Text(config.startup ?? "Default (any)"),
-                        ),
-                        ListTile(
-                          title: const Text("OS Type"),
-                          subtitle: Text(config.ostype != null
-                              ? "${config.ostype!.type} ${config.ostype!.description}"
-                              : "Other"),
-                        ),
-                        //TODO add better ui component e.g. collapseable
-                        ListTile(
-                          title: const Text("Boot Device"),
-                          subtitle: Text(config.boot ?? 'Disk, Network, USB'),
-                        ),
-                        PveConfigSwitchListTile(
-                          title: const Text("Use tablet for pointer"),
-                          value: config.tablet,
-                          defaultValue: true,
-                          pending: config.getPending('tablet'),
-                          onChanged: (v) => bloc.events
-                              .add(UpdateQemuConfigBool('tablet', v)),
-                          onDeleted: () => bloc.events
-                              .add(RevertPendingQemuConfig('tablet')),
-                        ),
-                        ListTile(
-                          title: const Text("Hotplug"),
-                          subtitle: Text(config.hotplug ?? 'disk,network,usb'),
-                        ),
-                        PveConfigSwitchListTile(
-                          title: const Text("ACPI support"),
-                          value: config.acpi,
-                          defaultValue: true,
-                          pending: config.getPending('acpi'),
-                          onChanged: (v) =>
-                              bloc.events.add(UpdateQemuConfigBool('acpi', v)),
-                          onDeleted: () =>
-                              bloc.events.add(RevertPendingQemuConfig('acpi')),
-                        ),
-                        PveConfigSwitchListTile(
-                          title: const Text("KVM hardware virtualization"),
-                          value: config.kvm,
-                          defaultValue: true,
-                          pending: config.getPending('kvm'),
-                          onChanged: (v) =>
-                              bloc.events.add(UpdateQemuConfigBool('kvm', v)),
-                          onDeleted: () =>
-                              bloc.events.add(RevertPendingQemuConfig('kvm')),
-                        ),
-                        PveConfigSwitchListTile(
-                          title: const Text("Freeze CPU on startup"),
-                          value: config.freeze,
-                          defaultValue: false,
-                          pending: config.getPending('freeze'),
-                          onChanged: (v) => bloc.events
-                              .add(UpdateQemuConfigBool('freeze', v)),
-                          onDeleted: () => bloc.events
-                              .add(RevertPendingQemuConfig('freeze')),
-                        ),
-                        PveConfigSwitchListTile(
-                          title: const Text("Use local time for RTC"),
-                          value: config.localtime,
-                          defaultValue: false,
-                          pending: config.getPending('localtime'),
-                          onChanged: (v) => bloc.events
-                              .add(UpdateQemuConfigBool('localtime', v)),
-                          onDeleted: () => bloc.events
-                              .add(RevertPendingQemuConfig('localtime')),
-                        ),
-                        ListTile(
-                          title: const Text("RTC start date"),
-                          subtitle: Text(config.startdate ?? 'now'),
-                        ),
-                        ListTile(
-                          title: const Text("SMBIOS settings (type1)"),
-                          subtitle: Text(config.smbios1 ?? ''),
-                        ),
-                        //Todo enhance UI
-                        ListTile(
-                          title: const Text("QEMU Guest Agent"),
-                          subtitle: Text(config.agent ?? 'Default (disabled)'),
-                        ),
-                        PveConfigSwitchListTile(
-                          title: const Text("Protection"),
-                          value: config.protection,
-                          defaultValue: false,
-                          pending: config.getPending('protection'),
-                          onChanged: (v) => bloc.events
-                              .add(UpdateQemuConfigBool('protection', v)),
-                          onDeleted: () => bloc.events
-                              .add(RevertPendingQemuConfig('protection')),
-                        ),
-                        ListTile(
-                          title: const Text("Spice Enhancements"),
-                          subtitle: Text(
-                              config.spiceEnhancements ?? 'No enhancements'),
-                        ),
-                        ListTile(
-                          title: const Text("VM State Storage"),
-                          subtitle: Text(config.vmstatestorage ?? 'Automatic'),
-                        ),
-                      ],
-                    ),
+              ),
+              body: SingleChildScrollView(
+                child: Form(
+                  key: _formKey,
+                  onChanged: () {},
+                  child: Column(
+                    children: <Widget>[
+                      ListTile(
+                        title: const Text("Name"),
+                        subtitle: Text(config.name ?? 'VM$guestID'),
+                      ),
+                      PveConfigSwitchListTile(
+                        title: const Text("Start on boot"),
+                        value: config.onboot,
+                        defaultValue: false,
+                        pending: config.getPending('onboot'),
+                        onChanged: (v) =>
+                            bloc.events.add(UpdateQemuConfigBool('onboot', v)),
+                        onDeleted: () =>
+                            bloc.events.add(RevertPendingQemuConfig('onboot')),
+                      ),
+                      ListTile(
+                        title: const Text("Start/Shutdown order"),
+                        subtitle: Text(config.startup ?? "Default (any)"),
+                      ),
+                      ListTile(
+                        title: const Text("OS Type"),
+                        subtitle: Text(config.ostype != null
+                            ? "${config.ostype!.type} ${config.ostype!.description}"
+                            : "Other"),
+                      ),
+                      //TODO add better ui component e.g. collapseable
+                      ListTile(
+                        title: const Text("Boot Device"),
+                        subtitle: Text(config.boot ?? 'Disk, Network, USB'),
+                      ),
+                      PveConfigSwitchListTile(
+                        title: const Text("Use tablet for pointer"),
+                        value: config.tablet,
+                        defaultValue: true,
+                        pending: config.getPending('tablet'),
+                        onChanged: (v) =>
+                            bloc.events.add(UpdateQemuConfigBool('tablet', v)),
+                        onDeleted: () =>
+                            bloc.events.add(RevertPendingQemuConfig('tablet')),
+                      ),
+                      ListTile(
+                        title: const Text("Hotplug"),
+                        subtitle: Text(config.hotplug ?? 'disk,network,usb'),
+                      ),
+                      PveConfigSwitchListTile(
+                        title: const Text("ACPI support"),
+                        value: config.acpi,
+                        defaultValue: true,
+                        pending: config.getPending('acpi'),
+                        onChanged: (v) =>
+                            bloc.events.add(UpdateQemuConfigBool('acpi', v)),
+                        onDeleted: () =>
+                            bloc.events.add(RevertPendingQemuConfig('acpi')),
+                      ),
+                      PveConfigSwitchListTile(
+                        title: const Text("KVM hardware virtualization"),
+                        value: config.kvm,
+                        defaultValue: true,
+                        pending: config.getPending('kvm'),
+                        onChanged: (v) =>
+                            bloc.events.add(UpdateQemuConfigBool('kvm', v)),
+                        onDeleted: () =>
+                            bloc.events.add(RevertPendingQemuConfig('kvm')),
+                      ),
+                      PveConfigSwitchListTile(
+                        title: const Text("Freeze CPU on startup"),
+                        value: config.freeze,
+                        defaultValue: false,
+                        pending: config.getPending('freeze'),
+                        onChanged: (v) =>
+                            bloc.events.add(UpdateQemuConfigBool('freeze', v)),
+                        onDeleted: () =>
+                            bloc.events.add(RevertPendingQemuConfig('freeze')),
+                      ),
+                      PveConfigSwitchListTile(
+                        title: const Text("Use local time for RTC"),
+                        value: config.localtime,
+                        defaultValue: false,
+                        pending: config.getPending('localtime'),
+                        onChanged: (v) => bloc.events
+                            .add(UpdateQemuConfigBool('localtime', v)),
+                        onDeleted: () => bloc.events
+                            .add(RevertPendingQemuConfig('localtime')),
+                      ),
+                      ListTile(
+                        title: const Text("RTC start date"),
+                        subtitle: Text(config.startdate ?? 'now'),
+                      ),
+                      ListTile(
+                        title: const Text("SMBIOS settings (type1)"),
+                        subtitle: Text(config.smbios1 ?? ''),
+                      ),
+                      //Todo enhance UI
+                      ListTile(
+                        title: const Text("QEMU Guest Agent"),
+                        subtitle: Text(config.agent ?? 'Default (disabled)'),
+                      ),
+                      PveConfigSwitchListTile(
+                        title: const Text("Protection"),
+                        value: config.protection,
+                        defaultValue: false,
+                        pending: config.getPending('protection'),
+                        onChanged: (v) => bloc.events
+                            .add(UpdateQemuConfigBool('protection', v)),
+                        onDeleted: () => bloc.events
+                            .add(RevertPendingQemuConfig('protection')),
+                      ),
+                      ListTile(
+                        title: const Text("Spice Enhancements"),
+                        subtitle:
+                            Text(config.spiceEnhancements ?? 'No enhancements'),
+                      ),
+                      ListTile(
+                        title: const Text("VM State Storage"),
+                        subtitle: Text(config.vmstatestorage ?? 'Automatic'),
+                      ),
+                    ],
                   ),
                 ),
+              ),
             );
           }
           return const Center(
-- 
2.47.2



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


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [pve-devel] [PATCH pve_flutter_frontend 2/3] feat: ui: add bottom sheet to change VMs/CTs options
  2025-09-23  9:36 [pve-devel] [PATCH pve_flutter_frontend 0/3] feat: ui: add bottom sheet to show editable options of VMs/CTs Shan Shaji
  2025-09-23  9:36 ` [pve-devel] [PATCH pve_flutter_frontend 1/3] cleanup: run `dart format` on both qemu and lxc options page Shan Shaji
@ 2025-09-23  9:36 ` Shan Shaji
  2025-09-23 12:03   ` Thomas Lamprecht
  2025-09-23  9:36 ` [pve-devel] [PATCH pve_flutter_frontend 3/3] cleanup: remove `PveConfigSwitchListTile` in favor of PveConfigListTile Shan Shaji
  2 siblings, 1 reply; 7+ messages in thread
From: Shan Shaji @ 2025-09-23  9:36 UTC (permalink / raw)
  To: pve-devel

On the options page for VMs and CTs it was easy to change the configs by
mistake. To avoid add a bottom sheet to show the editable option.

The value will only be updated when the `update` button is pressed.

Signed-off-by: Shan Shaji <s.shaji@proxmox.com>
---
 .../pve_config_switch_form.dart               |  54 ++++++
 lib/widgets/pve_config_list_tile.dart         | 176 +++++++++++++++++
 lib/widgets/pve_lxc_options_widget.dart       |  78 +++++---
 lib/widgets/pve_qemu_options_widget.dart      | 177 ++++++++++++------
 4 files changed, 400 insertions(+), 85 deletions(-)
 create mode 100644 lib/widgets/pve_config_forms/pve_config_switch_form.dart
 create mode 100644 lib/widgets/pve_config_list_tile.dart

diff --git a/lib/widgets/pve_config_forms/pve_config_switch_form.dart b/lib/widgets/pve_config_forms/pve_config_switch_form.dart
new file mode 100644
index 0000000..61ae014
--- /dev/null
+++ b/lib/widgets/pve_config_forms/pve_config_switch_form.dart
@@ -0,0 +1,54 @@
+import 'package:flutter/material.dart';
+import 'package:pve_flutter_frontend/widgets/pve_config_tile.dart';
+
+class PveConfigSwitchForm extends StatefulWidget {
+  const PveConfigSwitchForm({
+    super.key,
+    required this.value,
+    required this.title,
+    required this.controller,
+  });
+
+  final bool value;
+  final String title;
+  final PveConfigEditorController<bool> controller;
+
+  @override
+  State<PveConfigSwitchForm> createState() => _PveConfigSwitchFormState();
+}
+
+class _PveConfigSwitchFormState extends State<PveConfigSwitchForm> {
+  late bool _currentValue;
+
+  bool get _isDirty => _currentValue != widget.value;
+
+  @override
+  void initState() {
+    super.initState();
+    _currentValue = widget.value;
+
+    widget.controller
+      ..setValue(_currentValue)
+      ..setDirty(false);
+  }
+
+  void _handleChanged(bool value) {
+    setState(() {
+      _currentValue = value;
+    });
+
+    widget.controller
+      ..setValue(_currentValue)
+      ..setDirty(_isDirty);
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return SwitchListTile(
+      contentPadding: EdgeInsets.zero,
+      title: Text(widget.title),
+      value: _currentValue,
+      onChanged: _handleChanged,
+    );
+  }
+}
diff --git a/lib/widgets/pve_config_list_tile.dart b/lib/widgets/pve_config_list_tile.dart
new file mode 100644
index 0000000..84c4694
--- /dev/null
+++ b/lib/widgets/pve_config_list_tile.dart
@@ -0,0 +1,176 @@
+import 'package:flutter/material.dart';
+
+typedef PveConfigEditorBuilder<T> = Widget Function(
+  BuildContext context,
+  PveConfigEditorController<T> controller,
+);
+
+class PveConfigEditorController<T> {
+  PveConfigEditorController({
+    required void Function(bool) onDirtyChanged,
+    required void Function(T) onValueChanged,
+  })  : _onDirtyChanged = onDirtyChanged,
+        _onValueChanged = onValueChanged;
+
+  final void Function(bool) _onDirtyChanged;
+  final void Function(T) _onValueChanged;
+
+  void setDirty(bool value) => _onDirtyChanged(value);
+  void setValue(T value) => _onValueChanged(value);
+}
+
+class PveConfigListTile<T> extends StatelessWidget {
+  const PveConfigListTile({
+    super.key,
+    required this.title,
+    required this.editorBuilder,
+    required this.onSubmit,
+    this.subtitle,
+    this.trailingText,
+    this.pending,
+    this.onCancelEdit,
+  });
+
+  final String title;
+  final String? subtitle;
+  final String? trailingText;
+  final PveConfigEditorBuilder<T> editorBuilder;
+  final void Function(T value) onSubmit;
+  final VoidCallback? onCancelEdit;
+  final int? pending;
+
+  static void _showBottomSheet(
+    BuildContext context, {
+    required Widget Function(BuildContext) builder,
+  }) {
+    showModalBottomSheet(
+      context: context,
+      builder: builder,
+      useSafeArea: true,
+    );
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return ListTile(
+      enabled: pending == null,
+      title: pending != null
+          ? Column(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                Text(title),
+                Chip(
+                  label: const Text('pending'),
+                  backgroundColor: Colors.red,
+                  onDeleted: onCancelEdit,
+                ),
+              ],
+            )
+          : Text(title),
+      subtitle: subtitle == null ? null : Text(subtitle!),
+      trailing: trailingText != null
+          ? Text(
+              trailingText!,
+              style: const TextStyle(fontSize: 14),
+            )
+          : null,
+      onTap: pending != null
+          ? null
+          : () {
+              _showBottomSheet(
+                context,
+                builder: (_) {
+                  return _PveConfigEditorForm(
+                    title: 'Edit: $title',
+                    editorBuilder: editorBuilder,
+                    onSubmit: onSubmit,
+                  );
+                },
+              );
+            },
+    );
+  }
+}
+
+class _PveConfigEditorForm<T> extends StatefulWidget {
+  const _PveConfigEditorForm({
+    required this.title,
+    required this.editorBuilder,
+    required this.onSubmit,
+  });
+
+  final String title;
+  final PveConfigEditorBuilder<T> editorBuilder;
+  final void Function(T value) onSubmit;
+
+  @override
+  State<_PveConfigEditorForm<T>> createState() =>
+      _PveConfigEditorFormState<T>();
+}
+
+class _PveConfigEditorFormState<T> extends State<_PveConfigEditorForm<T>> {
+  bool _isDirty = false;
+  late T _currentValue;
+
+  late final PveConfigEditorController<T> _controller =
+      PveConfigEditorController<T>(
+    onDirtyChanged: _handleDirtyChanged,
+    onValueChanged: _handleValueChanged,
+  );
+
+  void _handleDirtyChanged(bool value) {
+    if (_isDirty != value) {
+      setState(() {
+        _isDirty = value;
+      });
+    }
+  }
+
+  void _handleValueChanged(T value) {
+    _currentValue = value;
+  }
+
+  void _submit() {
+    widget.onSubmit(_currentValue);
+    Navigator.of(context).pop();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(horizontal: 12),
+      child: Column(
+        mainAxisSize: MainAxisSize.min,
+        spacing: 8,
+        children: [
+          Row(
+            mainAxisAlignment: MainAxisAlignment.spaceBetween,
+            children: [
+              Text(
+                widget.title,
+                style: const TextStyle(
+                  fontWeight: FontWeight.bold,
+                  fontSize: 16,
+                ),
+              ),
+              TextButton(
+                onPressed: () => Navigator.pop(context),
+                child: const Text('Close'),
+              ),
+            ],
+          ),
+          widget.editorBuilder(context, _controller),
+          const SizedBox(height: 12),
+          Align(
+            alignment: Alignment.bottomRight,
+            child: FilledButton(
+              onPressed: _isDirty ? _submit : null,
+              child: const Text('Update'),
+            ),
+          ),
+          const SizedBox(height: 8),
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/widgets/pve_lxc_options_widget.dart b/lib/widgets/pve_lxc_options_widget.dart
index 5b6e009..4bd263e 100644
--- a/lib/widgets/pve_lxc_options_widget.dart
+++ b/lib/widgets/pve_lxc_options_widget.dart
@@ -2,7 +2,8 @@ import 'package:flutter/material.dart';
 import 'package:pve_flutter_frontend/bloc/pve_lxc_overview_bloc.dart';
 import 'package:pve_flutter_frontend/states/pve_lxc_overview_state.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_stream_builder_widget.dart';
-import 'package:pve_flutter_frontend/widgets/pve_config_switch_list_tile.dart';
+import 'package:pve_flutter_frontend/widgets/pve_config_forms/pve_config_switch_form.dart';
+import 'package:pve_flutter_frontend/widgets/pve_config_list_tile.dart';
 
 class PveLxcOptions extends StatelessWidget {
   final PveLxcOverviewBloc? lxcBloc;
@@ -24,15 +25,26 @@ class PveLxcOptions extends StatelessWidget {
                       title: const Text("Name"),
                       subtitle: Text(config.hostname ?? 'undefined'),
                     ),
-                    PveConfigSwitchListTile(
-                      title: const Text("Start on boot"),
-                      value: config.onboot,
-                      defaultValue: false,
+                    PveConfigListTile<bool>(
+                      title: "Start on boot",
+                      trailingText: config.onboot == true ? 'Yes' : 'No',
                       pending: config.getPending('onboot'),
-                      onChanged: (v) =>
-                          lxcBloc!.events.add(UpdateLxcConfigBool('onboot', v)),
-                      onDeleted: () =>
-                          lxcBloc!.events.add(RevertPendingLxcConfig('onboot')),
+                      onSubmit: (value) => lxcBloc!.events.add(
+                        UpdateLxcConfigBool(
+                          'onboot',
+                          value,
+                        ),
+                      ),
+                      editorBuilder: (_, controller) {
+                        return PveConfigSwitchForm(
+                          title: "Start on boot",
+                          value: config.onboot == true,
+                          controller: controller,
+                        );
+                      },
+                      onCancelEdit: () => lxcBloc!.events.add(
+                        RevertPendingLxcConfig('onboot'),
+                      ),
                     ),
                     ListTile(
                       title: const Text("Start/Shutdown order"),
@@ -46,15 +58,23 @@ class PveLxcOptions extends StatelessWidget {
                       title: const Text("Architecture"),
                       subtitle: Text("${config.arch}"),
                     ),
-                    PveConfigSwitchListTile(
-                      title: const Text("/dev/console"),
-                      value: config.console,
-                      defaultValue: true,
+                    PveConfigListTile<bool>(
+                      title: "/dev/console",
+                      trailingText: config.console == true ? 'Yes' : 'No',
                       pending: config.getPending('console'),
-                      onChanged: (v) => lxcBloc!.events
-                          .add(UpdateLxcConfigBool('console', v)),
-                      onDeleted: () => lxcBloc!.events
-                          .add(RevertPendingLxcConfig('console')),
+                      onSubmit: (v) => lxcBloc!.events.add(
+                        UpdateLxcConfigBool('console', v),
+                      ),
+                      editorBuilder: (_, controller) {
+                        return PveConfigSwitchForm(
+                          title: "/dev/console",
+                          value: config.console == true,
+                          controller: controller,
+                        );
+                      },
+                      onCancelEdit: () => lxcBloc!.events.add(
+                        RevertPendingLxcConfig('console'),
+                      ),
                     ),
                     ListTile(
                       title: const Text("TTY Count"),
@@ -64,15 +84,23 @@ class PveLxcOptions extends StatelessWidget {
                       title: const Text("Console Mode"),
                       subtitle: Text(config.cmode?.name ?? 'tty'),
                     ),
-                    PveConfigSwitchListTile(
-                      title: const Text("Protection"),
-                      value: config.protection,
-                      defaultValue: false,
+                    PveConfigListTile<bool>(
+                      title: "Protection",
+                      trailingText: config.protection == true ? 'Yes' : 'No',
                       pending: config.getPending('protection'),
-                      onChanged: (v) => lxcBloc!.events
-                          .add(UpdateLxcConfigBool('protection', v)),
-                      onDeleted: () => lxcBloc!.events
-                          .add(RevertPendingLxcConfig('protection')),
+                      onSubmit: (v) => lxcBloc!.events.add(
+                        UpdateLxcConfigBool('protection', v),
+                      ),
+                      editorBuilder: (_, controller) {
+                        return PveConfigSwitchForm(
+                          title: "Protection",
+                          value: config.protection == true,
+                          controller: controller,
+                        );
+                      },
+                      onCancelEdit: () => lxcBloc!.events.add(
+                        RevertPendingLxcConfig('protection'),
+                      ),
                     ),
                     ListTile(
                       title: const Text("Unprivileged"),
diff --git a/lib/widgets/pve_qemu_options_widget.dart b/lib/widgets/pve_qemu_options_widget.dart
index 992a382..f8cb000 100644
--- a/lib/widgets/pve_qemu_options_widget.dart
+++ b/lib/widgets/pve_qemu_options_widget.dart
@@ -3,7 +3,8 @@ import 'package:provider/provider.dart';
 import 'package:pve_flutter_frontend/bloc/pve_qemu_overview_bloc.dart';
 import 'package:pve_flutter_frontend/states/pve_qemu_overview_state.dart';
 import 'package:pve_flutter_frontend/widgets/proxmox_stream_builder_widget.dart';
-import 'package:pve_flutter_frontend/widgets/pve_config_switch_list_tile.dart';
+import 'package:pve_flutter_frontend/widgets/pve_config_forms/pve_config_switch_form.dart';
+import 'package:pve_flutter_frontend/widgets/pve_config_list_tile.dart';
 
 class PveQemuOptions extends StatelessWidget {
   final String guestID;
@@ -35,15 +36,23 @@ class PveQemuOptions extends StatelessWidget {
                         title: const Text("Name"),
                         subtitle: Text(config.name ?? 'VM$guestID'),
                       ),
-                      PveConfigSwitchListTile(
-                        title: const Text("Start on boot"),
-                        value: config.onboot,
-                        defaultValue: false,
+                      PveConfigListTile<bool>(
+                        title: "Start on boot",
+                        trailingText: config.onboot == true ? 'Yes' : 'No',
                         pending: config.getPending('onboot'),
-                        onChanged: (v) =>
-                            bloc.events.add(UpdateQemuConfigBool('onboot', v)),
-                        onDeleted: () =>
-                            bloc.events.add(RevertPendingQemuConfig('onboot')),
+                        onSubmit: (v) => bloc.events.add(
+                          UpdateQemuConfigBool('onboot', v),
+                        ),
+                        editorBuilder: (_, controller) {
+                          return PveConfigSwitchForm(
+                            title: "Start on boot",
+                            value: config.onboot == true,
+                            controller: controller,
+                          );
+                        },
+                        onCancelEdit: () => bloc.events.add(
+                          RevertPendingQemuConfig('onboot'),
+                        ),
                       ),
                       ListTile(
                         title: const Text("Start/Shutdown order"),
@@ -60,59 +69,99 @@ class PveQemuOptions extends StatelessWidget {
                         title: const Text("Boot Device"),
                         subtitle: Text(config.boot ?? 'Disk, Network, USB'),
                       ),
-                      PveConfigSwitchListTile(
-                        title: const Text("Use tablet for pointer"),
-                        value: config.tablet,
-                        defaultValue: true,
+                      PveConfigListTile<bool>(
+                        title: "Use tablet for pointer",
+                        trailingText: config.tablet == true ? 'Yes' : 'No',
                         pending: config.getPending('tablet'),
-                        onChanged: (v) =>
-                            bloc.events.add(UpdateQemuConfigBool('tablet', v)),
-                        onDeleted: () =>
-                            bloc.events.add(RevertPendingQemuConfig('tablet')),
+                        onSubmit: (v) => bloc.events.add(
+                          UpdateQemuConfigBool('tablet', v),
+                        ),
+                        editorBuilder: (_, controller) {
+                          return PveConfigSwitchForm(
+                            title: "Use tablet for pointer",
+                            value: config.tablet == true,
+                            controller: controller,
+                          );
+                        },
+                        onCancelEdit: () => bloc.events.add(
+                          RevertPendingQemuConfig('tablet'),
+                        ),
                       ),
                       ListTile(
                         title: const Text("Hotplug"),
                         subtitle: Text(config.hotplug ?? 'disk,network,usb'),
                       ),
-                      PveConfigSwitchListTile(
-                        title: const Text("ACPI support"),
-                        value: config.acpi,
-                        defaultValue: true,
+                      PveConfigListTile<bool>(
+                        title: "ACPI support",
+                        trailingText: config.acpi == true ? 'Yes' : 'No',
                         pending: config.getPending('acpi'),
-                        onChanged: (v) =>
-                            bloc.events.add(UpdateQemuConfigBool('acpi', v)),
-                        onDeleted: () =>
-                            bloc.events.add(RevertPendingQemuConfig('acpi')),
-                      ),
-                      PveConfigSwitchListTile(
-                        title: const Text("KVM hardware virtualization"),
-                        value: config.kvm,
-                        defaultValue: true,
+                        onSubmit: (v) => bloc.events.add(
+                          UpdateQemuConfigBool('acpi', v),
+                        ),
+                        editorBuilder: (_, controller) {
+                          return PveConfigSwitchForm(
+                            title: "ACPI support",
+                            value: config.acpi == true,
+                            controller: controller,
+                          );
+                        },
+                        onCancelEdit: () => bloc.events.add(
+                          RevertPendingQemuConfig('acpi'),
+                        ),
+                      ),
+                      PveConfigListTile<bool>(
+                        title: "KVM hardware virtualization",
+                        trailingText: config.kvm == true ? 'Yes' : 'No',
                         pending: config.getPending('kvm'),
-                        onChanged: (v) =>
-                            bloc.events.add(UpdateQemuConfigBool('kvm', v)),
-                        onDeleted: () =>
-                            bloc.events.add(RevertPendingQemuConfig('kvm')),
-                      ),
-                      PveConfigSwitchListTile(
-                        title: const Text("Freeze CPU on startup"),
-                        value: config.freeze,
-                        defaultValue: false,
+                        onSubmit: (v) => bloc.events.add(
+                          UpdateQemuConfigBool('kvm', v),
+                        ),
+                        editorBuilder: (_, controller) {
+                          return PveConfigSwitchForm(
+                            title: "KVM hardware virtualization",
+                            value: config.kvm == true,
+                            controller: controller,
+                          );
+                        },
+                        onCancelEdit: () => bloc.events.add(
+                          RevertPendingQemuConfig('kvm'),
+                        ),
+                      ),
+                      PveConfigListTile<bool>(
+                        title: "Freeze CPU on startup",
+                        trailingText: config.freeze == true ? 'Yes' : 'No',
                         pending: config.getPending('freeze'),
-                        onChanged: (v) =>
-                            bloc.events.add(UpdateQemuConfigBool('freeze', v)),
-                        onDeleted: () =>
-                            bloc.events.add(RevertPendingQemuConfig('freeze')),
-                      ),
-                      PveConfigSwitchListTile(
-                        title: const Text("Use local time for RTC"),
-                        value: config.localtime,
-                        defaultValue: false,
+                        onSubmit: (v) => bloc.events.add(
+                          UpdateQemuConfigBool('freeze', v),
+                        ),
+                        editorBuilder: (_, controller) {
+                          return PveConfigSwitchForm(
+                            title: "Freeze CPU on startup",
+                            value: config.freeze == true,
+                            controller: controller,
+                          );
+                        },
+                        onCancelEdit: () => bloc.events.add(
+                          RevertPendingQemuConfig('freeze'),
+                        ),
+                      ),
+                      PveConfigListTile<bool>(
+                        title: "Use local time for RTC",
+                        trailingText: config.localtime == true ? 'Yes' : 'No',
                         pending: config.getPending('localtime'),
-                        onChanged: (v) => bloc.events
-                            .add(UpdateQemuConfigBool('localtime', v)),
-                        onDeleted: () => bloc.events
-                            .add(RevertPendingQemuConfig('localtime')),
+                        onSubmit: (v) => bloc.events.add(
+                          UpdateQemuConfigBool('localtime', v),
+                        ),
+                        editorBuilder: (_, controller) {
+                          return PveConfigSwitchForm(
+                            title: "Use local time for RTC",
+                            value: config.localtime == true,
+                            controller: controller,
+                          );
+                        },
+                        onCancelEdit: () => bloc.events.add(
+                          RevertPendingQemuConfig('localtime'),
+                        ),
                       ),
                       ListTile(
                         title: const Text("RTC start date"),
@@ -127,15 +176,23 @@ class PveQemuOptions extends StatelessWidget {
                         title: const Text("QEMU Guest Agent"),
                         subtitle: Text(config.agent ?? 'Default (disabled)'),
                       ),
-                      PveConfigSwitchListTile(
-                        title: const Text("Protection"),
-                        value: config.protection,
-                        defaultValue: false,
+                      PveConfigListTile<bool>(
+                        title: "Protection",
+                        trailingText: config.protection == true ? 'Yes' : 'No',
                         pending: config.getPending('protection'),
-                        onChanged: (v) => bloc.events
-                            .add(UpdateQemuConfigBool('protection', v)),
-                        onDeleted: () => bloc.events
-                            .add(RevertPendingQemuConfig('protection')),
+                        onSubmit: (v) => bloc.events.add(
+                          UpdateQemuConfigBool('protection', v),
+                        ),
+                        editorBuilder: (_, controller) {
+                          return PveConfigSwitchForm(
+                            title: "Protection",
+                            value: config.protection == true,
+                            controller: controller,
+                          );
+                        },
+                        onCancelEdit: () => bloc.events.add(
+                          RevertPendingQemuConfig('protection'),
+                        ),
                       ),
                       ListTile(
                         title: const Text("Spice Enhancements"),
-- 
2.47.2



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


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [pve-devel] [PATCH pve_flutter_frontend 3/3] cleanup: remove `PveConfigSwitchListTile` in favor of PveConfigListTile
  2025-09-23  9:36 [pve-devel] [PATCH pve_flutter_frontend 0/3] feat: ui: add bottom sheet to show editable options of VMs/CTs Shan Shaji
  2025-09-23  9:36 ` [pve-devel] [PATCH pve_flutter_frontend 1/3] cleanup: run `dart format` on both qemu and lxc options page Shan Shaji
  2025-09-23  9:36 ` [pve-devel] [PATCH pve_flutter_frontend 2/3] feat: ui: add bottom sheet to change VMs/CTs options Shan Shaji
@ 2025-09-23  9:36 ` Shan Shaji
  2 siblings, 0 replies; 7+ messages in thread
From: Shan Shaji @ 2025-09-23  9:36 UTC (permalink / raw)
  To: pve-devel

Signed-off-by: Shan Shaji <s.shaji@proxmox.com>
---
 lib/widgets/pve_config_switch_list_tile.dart | 50 --------------------
 1 file changed, 50 deletions(-)
 delete mode 100644 lib/widgets/pve_config_switch_list_tile.dart

diff --git a/lib/widgets/pve_config_switch_list_tile.dart b/lib/widgets/pve_config_switch_list_tile.dart
deleted file mode 100644
index c209fbe..0000000
--- a/lib/widgets/pve_config_switch_list_tile.dart
+++ /dev/null
@@ -1,50 +0,0 @@
-import 'package:flutter/material.dart';
-
-class PveConfigSwitchListTile extends StatelessWidget {
-  final bool? value;
-  final int? pending;
-  final bool? defaultValue;
-  final Widget? title;
-  final ValueChanged<bool>? onChanged;
-  final VoidCallback? onDeleted;
-
-  const PveConfigSwitchListTile({
-    super.key,
-    this.value,
-    this.pending,
-    this.defaultValue,
-    this.title,
-    this.onChanged,
-    this.onDeleted,
-  });
-  @override
-  Widget build(BuildContext context) {
-    bool? pBool;
-    if (pending != null) {
-      pBool = pending == 0 ? false : true;
-    }
-    return SwitchListTile(
-      title: _getTitle(),
-      value: pBool ?? value ?? defaultValue!,
-      onChanged: pending != null ? null : onChanged,
-    );
-  }
-
-  Widget? _getTitle() {
-    if (pending != null) {
-      return Column(
-        crossAxisAlignment: CrossAxisAlignment.start,
-        children: [
-          title!,
-          Chip(
-            label: const Text('pending'),
-            backgroundColor: Colors.red,
-            onDeleted: onDeleted,
-          )
-        ],
-      );
-    } else {
-      return title;
-    }
-  }
-}
-- 
2.47.2



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


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [pve-devel] [PATCH pve_flutter_frontend 2/3] feat: ui: add bottom sheet to change VMs/CTs options
  2025-09-23  9:36 ` [pve-devel] [PATCH pve_flutter_frontend 2/3] feat: ui: add bottom sheet to change VMs/CTs options Shan Shaji
@ 2025-09-23 12:03   ` Thomas Lamprecht
  2025-09-23 12:12     ` Shan Shaji
  0 siblings, 1 reply; 7+ messages in thread
From: Thomas Lamprecht @ 2025-09-23 12:03 UTC (permalink / raw)
  To: Proxmox VE development discussion, Shan Shaji

Am 23.09.25 um 11:37 schrieb Shan Shaji:
> On the options page for VMs and CTs it was easy to change the configs by
> mistake. To avoid add a bottom sheet to show the editable option.
> 
> The value will only be updated when the `update` button is pressed.
> 
> Signed-off-by: Shan Shaji <s.shaji@proxmox.com>
> ---
>  .../pve_config_switch_form.dart               |  54 ++++++
>  lib/widgets/pve_config_list_tile.dart         | 176 +++++++++++++++++
>  lib/widgets/pve_lxc_options_widget.dart       |  78 +++++---
>  lib/widgets/pve_qemu_options_widget.dart      | 177 ++++++++++++------
>  4 files changed, 400 insertions(+), 85 deletions(-)
>  create mode 100644 lib/widgets/pve_config_forms/pve_config_switch_form.dart
>  create mode 100644 lib/widgets/pve_config_list_tile.dart
> 
> diff --git a/lib/widgets/pve_config_forms/pve_config_switch_form.dart b/lib/widgets/pve_config_forms/pve_config_switch_form.dart
> new file mode 100644
> index 0000000..61ae014
> --- /dev/null
> +++ b/lib/widgets/pve_config_forms/pve_config_switch_form.dart
> @@ -0,0 +1,54 @@
> +import 'package:flutter/material.dart';
> +import 'package:pve_flutter_frontend/widgets/pve_config_tile.dart';

Above does not exist, should probably be the newly added "pve_config_list_tile.dart" file?
I.e.:

diff --git a/lib/widgets/pve_config_forms/pve_config_switch_form.dart b/lib/widgets/pve_config_forms/pve_config_switch_form.dart
index 61ae014..40bef8c 100644
--- a/lib/widgets/pve_config_forms/pve_config_switch_form.dart
+++ b/lib/widgets/pve_config_forms/pve_config_switch_form.dart
@@ -1,5 +1,5 @@
 import 'package:flutter/material.dart';
-import 'package:pve_flutter_frontend/widgets/pve_config_tile.dart';
+import 'package:pve_flutter_frontend/widgets/pve_config_list_tile.dart';
 
 class PveConfigSwitchForm extends StatefulWidget {
   const PveConfigSwitchForm({




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


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [pve-devel] [PATCH pve_flutter_frontend 2/3] feat: ui: add bottom sheet to change VMs/CTs options
  2025-09-23 12:03   ` Thomas Lamprecht
@ 2025-09-23 12:12     ` Shan Shaji
  2025-09-23 12:24       ` Shan Shaji
  0 siblings, 1 reply; 7+ messages in thread
From: Shan Shaji @ 2025-09-23 12:12 UTC (permalink / raw)
  To: Thomas Lamprecht, Proxmox VE development discussion

Thanks @Thomas for spotting that. I will send a v2 with the fix. 

On Tue Sep 23, 2025 at 2:03 PM CEST, Thomas Lamprecht wrote:
> Am 23.09.25 um 11:37 schrieb Shan Shaji:
>> On the options page for VMs and CTs it was easy to change the configs by
>> mistake. To avoid add a bottom sheet to show the editable option.
>> 
>> The value will only be updated when the `update` button is pressed.
>> 
>> Signed-off-by: Shan Shaji <s.shaji@proxmox.com>
>> ---
>>  .../pve_config_switch_form.dart               |  54 ++++++
>>  lib/widgets/pve_config_list_tile.dart         | 176 +++++++++++++++++
>>  lib/widgets/pve_lxc_options_widget.dart       |  78 +++++---
>>  lib/widgets/pve_qemu_options_widget.dart      | 177 ++++++++++++------
>>  4 files changed, 400 insertions(+), 85 deletions(-)
>>  create mode 100644 lib/widgets/pve_config_forms/pve_config_switch_form.dart
>>  create mode 100644 lib/widgets/pve_config_list_tile.dart
>> 
>> diff --git a/lib/widgets/pve_config_forms/pve_config_switch_form.dart b/lib/widgets/pve_config_forms/pve_config_switch_form.dart
>> new file mode 100644
>> index 0000000..61ae014
>> --- /dev/null
>> +++ b/lib/widgets/pve_config_forms/pve_config_switch_form.dart
>> @@ -0,0 +1,54 @@
>> +import 'package:flutter/material.dart';
>> +import 'package:pve_flutter_frontend/widgets/pve_config_tile.dart';
>
> Above does not exist, should probably be the newly added "pve_config_list_tile.dart" file?
> I.e.:
>
> diff --git a/lib/widgets/pve_config_forms/pve_config_switch_form.dart b/lib/widgets/pve_config_forms/pve_config_switch_form.dart
> index 61ae014..40bef8c 100644
> --- a/lib/widgets/pve_config_forms/pve_config_switch_form.dart
> +++ b/lib/widgets/pve_config_forms/pve_config_switch_form.dart
> @@ -1,5 +1,5 @@
>  import 'package:flutter/material.dart';
> -import 'package:pve_flutter_frontend/widgets/pve_config_tile.dart';
> +import 'package:pve_flutter_frontend/widgets/pve_config_list_tile.dart';
>  
>  class PveConfigSwitchForm extends StatefulWidget {
>    const PveConfigSwitchForm({



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


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [pve-devel] [PATCH pve_flutter_frontend 2/3] feat: ui: add bottom sheet to change VMs/CTs options
  2025-09-23 12:12     ` Shan Shaji
@ 2025-09-23 12:24       ` Shan Shaji
  0 siblings, 0 replies; 7+ messages in thread
From: Shan Shaji @ 2025-09-23 12:24 UTC (permalink / raw)
  To: Shan Shaji, Thomas Lamprecht, Proxmox VE development discussion

superseded by v2: https://lore.proxmox.com/pve-devel/20250923122334.301053-1-s.shaji@proxmox.com/T/#t


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


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-09-23 12:24 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-09-23  9:36 [pve-devel] [PATCH pve_flutter_frontend 0/3] feat: ui: add bottom sheet to show editable options of VMs/CTs Shan Shaji
2025-09-23  9:36 ` [pve-devel] [PATCH pve_flutter_frontend 1/3] cleanup: run `dart format` on both qemu and lxc options page Shan Shaji
2025-09-23  9:36 ` [pve-devel] [PATCH pve_flutter_frontend 2/3] feat: ui: add bottom sheet to change VMs/CTs options Shan Shaji
2025-09-23 12:03   ` Thomas Lamprecht
2025-09-23 12:12     ` Shan Shaji
2025-09-23 12:24       ` Shan Shaji
2025-09-23  9:36 ` [pve-devel] [PATCH pve_flutter_frontend 3/3] cleanup: remove `PveConfigSwitchListTile` in favor of PveConfigListTile Shan Shaji

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