diff --git a/CLAUDE.md b/CLAUDE.md index 94fde81..96d821f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -364,3 +364,49 @@ NEVER implement code without first getting explicit user agreement on the approa - ✅ "Implement maintenance mode for backup operations" - ✅ "Restructure storage widget with improved layout" - ✅ "Update CPU thresholds to production values" + +## NixOS Configuration Updates + +When code changes are made to cm-dashboard, the NixOS configuration at `~/nixosbox` must be updated to deploy the changes. + +### Update Process + +1. **Get Latest Commit Hash** + ```bash + git log -1 --format="%H" + ``` + +2. **Update NixOS Configuration** + Edit `~/nixosbox/hosts/common/cm-dashboard.nix`: + ```nix + src = pkgs.fetchgit { + url = "https://gitea.cmtec.se/cm/cm-dashboard.git"; + rev = "NEW_COMMIT_HASH_HERE"; + sha256 = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # Placeholder + }; + ``` + +3. **Get Correct Source Hash** + Build with placeholder hash to get the actual hash: + ```bash + cd ~/nixosbox + nix-build --no-out-link -E 'with import {}; fetchgit { + url = "https://gitea.cmtec.se/cm/cm-dashboard.git"; + rev = "NEW_COMMIT_HASH"; + sha256 = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; + }' 2>&1 | grep "got:" + ``` + +4. **Update Configuration with Correct Hash** + Replace the placeholder with the hash from the error message. + +5. **Commit NixOS Configuration** + ```bash + cd ~/nixosbox + git add hosts/common/cm-dashboard.nix + git commit -m "Update cm-dashboard to latest version (SHORT_HASH)" + git push + ``` + +6. **Rebuild System** + The user handles the system rebuild step - this cannot be automated. diff --git a/dashboard/src/ui/services.rs b/dashboard/src/ui/services.rs index d2a7ce1..a25f7b0 100644 --- a/dashboard/src/ui/services.rs +++ b/dashboard/src/ui/services.rs @@ -50,7 +50,7 @@ fn render_metrics( let mut data = WidgetData::new( title, Some(WidgetStatus::new(widget_status)), - vec!["Service".to_string(), "RAM".to_string(), "CPU".to_string(), "Disk".to_string(), "SB".to_string()] + vec!["Service".to_string(), "RAM".to_string(), "CPU".to_string(), "Disk".to_string()] ); @@ -63,7 +63,6 @@ fn render_metrics( "".to_string(), "".to_string(), "".to_string(), - "".to_string(), ], ); render_widget_data(frame, area, data); @@ -115,7 +114,6 @@ fn render_metrics( "".to_string(), "".to_string(), "".to_string(), - "".to_string(), ], svc.sub_service.clone(), ); @@ -129,7 +127,6 @@ fn render_metrics( format_memory_value(svc.memory_used_mb, svc.memory_quota_mb), format_cpu_value(svc.cpu_percent), format_disk_value(svc.disk_used_gb, svc.disk_quota_gb), - format_sandbox_value(svc.is_sandboxed, svc.is_sandbox_excluded), ], ); } @@ -144,11 +141,11 @@ fn format_bytes(mb: f32) -> String { if mb < 0.1 { "0".to_string() } else if mb < 1.0 { - format!("{:.0} kB", mb * 1000.0) + format!("{:.0}kB", mb * 1000.0) } else if mb < 1000.0 { - format!("{:.0} MB", mb) + format!("{:.0}MB", mb) } else { - format!("{:.1} GB", mb / 1000.0) + format!("{:.1}GB", mb / 1000.0) } } @@ -157,7 +154,13 @@ fn format_memory_value(used: f32, quota: f32) -> String { if quota > 0.05 { let quota_gb = quota / 1000.0; - format!("{} ({}G)", used_value, quota_gb as u32) + // Format quota nicely - show decimals only if needed + let quota_str = if quota_gb.fract() == 0.0 { + format!("{}G", quota_gb as u32) + } else { + format!("{:.1}G", quota_gb) + }; + format!("{} ({})", used_value, quota_str) } else { used_value } @@ -175,19 +178,16 @@ fn format_disk_value(used: f32, quota: f32) -> String { let used_value = format_bytes(used * 1000.0); // Convert GB to MB for format_bytes if quota > 0.05 { - format!("{} ({}G)", used_value, quota as u32) + // Format quota nicely - show decimals only if needed + let quota_str = if quota.fract() == 0.0 { + format!("{}G", quota as u32) + } else { + format!("{:.1}G", quota) + }; + format!("{} ({})", used_value, quota_str) } else { used_value } } -fn format_sandbox_value(is_sandboxed: bool, is_excluded: bool) -> String { - if is_sandboxed { - "yes".to_string() - } else if is_excluded { - "-".to_string() // Excluded services don't need sandboxing - } else { - "no".to_string() // Services that should be sandboxed but aren't - } -} diff --git a/dashboard/src/ui/storage.rs b/dashboard/src/ui/storage.rs index 0b40fe0..56ccf3b 100644 --- a/dashboard/src/ui/storage.rs +++ b/dashboard/src/ui/storage.rs @@ -109,13 +109,13 @@ fn format_percent(value: f32) -> String { fn format_usage(used: Option, capacity: Option) -> String { match (used, capacity) { (Some(used_gb), Some(total_gb)) if used_gb > 0.0 && total_gb > 0.0 => { - format!("{:.0}G/{:.0}G", used_gb, total_gb) + format!("{:.0}GB ({:.0}GB)", used_gb, total_gb) } (Some(used_gb), None) if used_gb > 0.0 => { - format!("{:.0}G", used_gb) + format!("{:.0}GB", used_gb) } (None, Some(total_gb)) if total_gb > 0.0 => { - format!("—/{:.0}G", total_gb) + format!("— ({:.0}GB)", total_gb) } _ => "—".to_string(), }