+ ${system.uptime_formatted ? `
+
+
+ ${(nodeData.basic?.flashChipSize || nodeData.resources?.flashChipSize) ? `
+
⚡ CPU
diff --git a/public/scripts/components/NodeDetailsComponent.js b/public/scripts/components/NodeDetailsComponent.js
index 477c3fe..484950b 100644
--- a/public/scripts/components/NodeDetailsComponent.js
+++ b/public/scripts/components/NodeDetailsComponent.js
@@ -25,6 +25,22 @@ class NodeDetailsComponent extends Component {
return (r << 16) + (g << 8) + b;
}
+ // Format flash size in human readable format
+ formatFlashSize(bytes) {
+ if (!bytes || bytes === 0) return 'Unknown';
+
+ const units = ['B', 'KB', 'MB', 'GB'];
+ let size = bytes;
+ let unitIndex = 0;
+
+ while (size >= 1024 && unitIndex < units.length - 1) {
+ size /= 1024;
+ unitIndex++;
+ }
+
+ return `${size.toFixed(1)} ${units[unitIndex]}`;
+ }
+
// Parameter component renderers
renderSelectComponent(p, formId, pidx) {
return `
`;
@@ -333,7 +349,7 @@ class NodeDetailsComponent extends Component {
Flash Size:
- ${Math.round(nodeStatus.flashChipSize / 1024)}KB
+ ${this.formatFlashSize(nodeStatus.flashChipSize)}
`;
diff --git a/public/scripts/view-models.js b/public/scripts/view-models.js
index e6564fc..7657baa 100644
--- a/public/scripts/view-models.js
+++ b/public/scripts/view-models.js
@@ -725,6 +725,7 @@ class MonitoringViewModel extends ViewModel {
nodeResources.set(member.ip, {
...member,
resources: basicResources,
+ basic: member.resources, // Preserve original basic data
hasResources: !!basicResources,
resourceSource: basicResources ? 'basic' : 'none',
error: basicResources ? null : error.message
diff --git a/public/styles/main.css b/public/styles/main.css
index 92ad58c..fe23e35 100644
--- a/public/styles/main.css
+++ b/public/styles/main.css
@@ -782,10 +782,6 @@ p {
.latency-value {
color: var(--text-primary);
font-weight: 600;
- background: var(--bg-secondary);
- padding: 0.2rem 0.5rem;
- border-radius: 4px;
- border: 1px solid var(--border-primary);
}
/* Tab Styles */
@@ -4220,6 +4216,83 @@ html {
margin-bottom: 0.75rem;
}
+.node-uptime {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 0.5rem;
+ padding: 0.25rem 0;
+}
+
+.uptime-label {
+ color: var(--text-secondary);
+ font-size: 0.8rem;
+ font-weight: bold;
+ opacity: 0.8;
+}
+
+.uptime-value {
+ color: var(--text-primary);
+ font-size: 0.8rem;
+ font-weight: 600;
+ font-family: 'Courier New', monospace;
+ opacity: 0.9;
+}
+
+.node-latency {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 0.5rem;
+ padding: 0.25rem 0;
+}
+
+.latency-label {
+ color: var(--text-secondary);
+ font-size: 0.8rem;
+ font-weight: bold;
+ opacity: 0.8;
+}
+
+.latency-value {
+ color: var(--text-primary);
+ font-size: 0.8rem;
+ font-weight: 600;
+ font-family: 'Courier New', monospace;
+ opacity: 0.9;
+}
+
+.latency-divider {
+ height: 1px;
+ background: var(--border-primary);
+ margin: 0.5rem 0;
+ opacity: 0.3;
+}
+
+.node-flash {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 0.75rem;
+ padding: 0.5rem;
+ background: var(--bg-primary);
+ border-radius: 6px;
+ border: 1px solid var(--border-primary);
+}
+
+.flash-label {
+ color: var(--text-secondary);
+ font-size: 0.875rem;
+ font-weight: 500;
+}
+
+.flash-value {
+ color: var(--text-primary);
+ font-size: 0.875rem;
+ font-weight: 600;
+ font-family: 'Courier New', monospace;
+}
+
.status-badge {
display: inline-block;
padding: 0.25rem 0.5rem;