From 688e456e497d47f24b60753fc4bd1d2986545e35 Mon Sep 17 00:00:00 2001 From: Pulse Monitor Date: Wed, 20 Aug 2025 20:41:53 +0000 Subject: [PATCH] improve: enhance threshold tab layout and fix edit behavior - redesigned global defaults section with compact table layout - fixed bug where editing without changes created unnecessary overrides - improved visual consistency across the alerts interface --- VERSION | 2 +- .../src/components/Alerts/ThresholdsTable.tsx | 361 +++++++++--------- internal/updates/version.go | 2 +- 3 files changed, 192 insertions(+), 173 deletions(-) diff --git a/VERSION b/VERSION index 4297670de..6016e8add 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.5.2-rc.1 \ No newline at end of file +4.6.0 diff --git a/frontend-modern/src/components/Alerts/ThresholdsTable.tsx b/frontend-modern/src/components/Alerts/ThresholdsTable.tsx index 5249280e1..ef1d8b586 100644 --- a/frontend-modern/src/components/Alerts/ThresholdsTable.tsx +++ b/frontend-modern/src/components/Alerts/ThresholdsTable.tsx @@ -149,6 +149,26 @@ export function ThresholdsTable(props: ThresholdsTableProps) { const thresholds = editingThresholds(); + // Check if there are any actual changes from the defaults + const defaultThresholds = resource.type === 'guest' ? props.guestDefaults : props.nodeDefaults; + const hasChanges = Object.keys(thresholds).some(key => { + const editedValue = thresholds[key]; + const defaultValue = defaultThresholds[key as keyof typeof defaultThresholds]; + return editedValue !== defaultValue; + }); + + // If no changes and no existing override, just cancel the edit + if (!hasChanges && !resource.hasOverride) { + cancelEdit(); + return; + } + + // If no changes but there's an existing override, keep it as is + if (!hasChanges && resource.hasOverride) { + cancelEdit(); + return; + } + // Create or update override const override: Override = { id: resourceId, @@ -277,190 +297,189 @@ export function ThresholdsTable(props: ThresholdsTableProps) { -
- {/* Time Threshold */} -
- - { - props.setTimeThreshold(parseInt(e.currentTarget.value) || 0); - props.setHasUnsavedChanges(true); - }} - class="w-20 px-2 py-1 text-sm border border-gray-300 dark:border-gray-600 rounded - bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 - focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> - - seconds {props.timeThreshold() === 0 ? '(disabled)' : ''} - -
- - {/* Default Thresholds Grid */} -
- {/* Guest Defaults */} -
-

VMs & Containers

-
+
+ {/* Compact grid layout */} +
+ {/* Left column - Time threshold and reset button */} +
+
+
- { - props.setGuestDefaults((prev) => ({...prev, cpu: parseInt(e.currentTarget.value) || 0})); + props.setTimeThreshold(parseInt(e.currentTarget.value) || 0); props.setHasUnsavedChanges(true); }} - class="w-16 px-2 py-0.5 text-sm border border-gray-300 dark:border-gray-600 rounded - bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" + class="w-16 px-2 py-1 text-sm border border-gray-300 dark:border-gray-600 rounded + bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 + focus:ring-2 focus:ring-blue-500 focus:border-transparent" /> - % -
-
- - { - props.setGuestDefaults((prev) => ({...prev, memory: parseInt(e.currentTarget.value) || 0})); - props.setHasUnsavedChanges(true); - }} - class="w-16 px-2 py-0.5 text-sm border border-gray-300 dark:border-gray-600 rounded - bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" - /> - % -
-
- - { - props.setGuestDefaults((prev) => ({...prev, disk: parseInt(e.currentTarget.value) || 0})); - props.setHasUnsavedChanges(true); - }} - class="w-16 px-2 py-0.5 text-sm border border-gray-300 dark:border-gray-600 rounded - bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" - /> - % + + sec {props.timeThreshold() === 0 ? '(disabled)' : `(wait ${props.timeThreshold()}s before alerting)`} +
+ +
- {/* Node Defaults */} -
-

Proxmox Nodes

-
-
- - { - props.setNodeDefaults((prev) => ({...prev, cpu: parseInt(e.currentTarget.value) || 0})); - props.setHasUnsavedChanges(true); - }} - class="w-16 px-2 py-0.5 text-sm border border-gray-300 dark:border-gray-600 rounded - bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" - /> - % -
-
- - { - props.setNodeDefaults((prev) => ({...prev, memory: parseInt(e.currentTarget.value) || 0})); - props.setHasUnsavedChanges(true); - }} - class="w-16 px-2 py-0.5 text-sm border border-gray-300 dark:border-gray-600 rounded - bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" - /> - % -
-
- - { - props.setNodeDefaults((prev) => ({...prev, disk: parseInt(e.currentTarget.value) || 0})); - props.setHasUnsavedChanges(true); - }} - class="w-16 px-2 py-0.5 text-sm border border-gray-300 dark:border-gray-600 rounded - bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" - /> - % -
-
+ {/* Right column - Threshold values in compact table */} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeCPU %Memory %Disk %Storage %
VMs & Containers + { + props.setGuestDefaults((prev) => ({...prev, cpu: parseInt(e.currentTarget.value) || 0})); + props.setHasUnsavedChanges(true); + }} + class="w-14 px-1 py-0.5 text-sm text-center border border-gray-300 dark:border-gray-600 rounded + bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" + /> + + { + props.setGuestDefaults((prev) => ({...prev, memory: parseInt(e.currentTarget.value) || 0})); + props.setHasUnsavedChanges(true); + }} + class="w-14 px-1 py-0.5 text-sm text-center border border-gray-300 dark:border-gray-600 rounded + bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" + /> + + { + props.setGuestDefaults((prev) => ({...prev, disk: parseInt(e.currentTarget.value) || 0})); + props.setHasUnsavedChanges(true); + }} + class="w-14 px-1 py-0.5 text-sm text-center border border-gray-300 dark:border-gray-600 rounded + bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" + /> + -
Proxmox Nodes + { + props.setNodeDefaults((prev) => ({...prev, cpu: parseInt(e.currentTarget.value) || 0})); + props.setHasUnsavedChanges(true); + }} + class="w-14 px-1 py-0.5 text-sm text-center border border-gray-300 dark:border-gray-600 rounded + bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" + /> + + { + props.setNodeDefaults((prev) => ({...prev, memory: parseInt(e.currentTarget.value) || 0})); + props.setHasUnsavedChanges(true); + }} + class="w-14 px-1 py-0.5 text-sm text-center border border-gray-300 dark:border-gray-600 rounded + bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" + /> + + { + props.setNodeDefaults((prev) => ({...prev, disk: parseInt(e.currentTarget.value) || 0})); + props.setHasUnsavedChanges(true); + }} + class="w-14 px-1 py-0.5 text-sm text-center border border-gray-300 dark:border-gray-600 rounded + bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" + /> + -
Storage--- + { + props.setStorageDefault(parseInt(e.currentTarget.value) || 0); + props.setHasUnsavedChanges(true); + }} + class="w-14 px-1 py-0.5 text-sm text-center border border-gray-300 dark:border-gray-600 rounded + bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" + /> +
- - {/* Storage Default */} -
-

Storage

-
-
- - { - props.setStorageDefault(parseInt(e.currentTarget.value) || 0); - props.setHasUnsavedChanges(true); - }} - class="w-16 px-2 py-0.5 text-sm border border-gray-300 dark:border-gray-600 rounded - bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" - /> - % -
-
-
-
- -
-
diff --git a/internal/updates/version.go b/internal/updates/version.go index b42e75ab1..029741840 100644 --- a/internal/updates/version.go +++ b/internal/updates/version.go @@ -164,7 +164,7 @@ func GetCurrentVersion() (*VersionInfo, error) { } // Final fallback - version := "4.5.2-rc.1" + version := "4.6.0" channel := "stable" if strings.Contains(strings.ToLower(version), "rc") { channel = "rc"