Skip to content

Commit cfc6c86

Browse files
committed
Add technical documentation and refactor components for machine status monitoring dashboard
1 parent 75652bd commit cfc6c86

File tree

7 files changed

+155
-187
lines changed

7 files changed

+155
-187
lines changed

DOCS.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Technical Documentation
2+
3+
## Overview
4+
5+
**MXStatus** is a React-based web dashboard for monitoring the status of multiple machines, with a focus on GPU, user, and network information. The application is designed for clarity, responsiveness, and a "hacker" aesthetic, using a custom dark theme and modern UI/UX practices.
6+
7+
---
8+
9+
## Technical Design Choices
10+
11+
- **Framework**: Built with React (v17), using functional components and React Hooks for state and effect management.
12+
- **State Management**: Local state is managed via React's `useState` and `useEffect`. LocalStorage is used for persisting user preferences (e.g., refresh interval, view key, display options).
13+
- **Data Fetching**: Uses `axios` for HTTP requests to a backend API, with support for custom server endpoints and view keys.
14+
- **Componentization**: The UI is highly modular, with reusable components for cards, badges, copyable text, and more.
15+
- **Responsiveness**: Layouts and controls are responsive, adapting to mobile and desktop via CSS media queries.
16+
- **Performance**: Includes a loading animation and ensures a minimum loading time for smooth transitions. Auto-refresh is supported with configurable intervals.
17+
- **Accessibility**: Uses semantic HTML and accessible form controls, with focus and hover states for interactive elements.
18+
19+
---
20+
21+
## Main Libraries Used
22+
23+
- **React**: Core UI framework.
24+
- **axios**: For HTTP requests to the backend API.
25+
- **react-sortablejs** and **sortablejs**: (Listed as dependencies, but not directly used in the main code; possibly for future drag-and-drop features.)
26+
- **Bootstrap 5**: Included via CDN for grid and utility classes, but most styling is custom.
27+
- **Google Fonts**: "Source Code Pro" (monospace) and "Inter" (UI font) for a modern, technical look.
28+
- **Testing**: `@testing-library/react`, `@testing-library/jest-dom`, and `@testing-library/user-event` for unit and integration tests.
29+
- **web-vitals**: For measuring and reporting performance metrics.
30+
31+
> **Note:** TailwindCSS is listed as a dependency but is not actually used or configured in the codebase. All styling is custom via CSS.
32+
33+
---
34+
35+
## Styling Choices
36+
37+
- **Custom Theme**: All colors, spacing, and typography are defined via CSS variables in `index.css` (e.g., `--hacker-bg`, `--hacker-text-accent`).
38+
- **Dark Mode**: The default and only theme is a dark, "hacker" style with neon green accents (`#00ff41`), inspired by terminal UIs.
39+
- **Responsive Design**: Extensive use of media queries for font sizes, spacing, and layout adjustments on mobile and desktop.
40+
- **Animations**: Subtle animations for loading, hover, and status indicators (e.g., pulse for online status, animated loading spinner).
41+
- **Touch-Friendly**: Larger touch targets and spacing for mobile usability.
42+
- **Custom Components**: Custom cards, badges, and containers with consistent border radius, shadows, and transitions.
43+
- **Minimal Bootstrap**: Bootstrap is loaded but only lightly used; most layout and style is custom.
44+
45+
---
46+
47+
## Website Component Structure
48+
49+
### Top-Level
50+
51+
- **App.js**: Root component. Renders the main page (`PageMain`) and a footer.
52+
53+
### Main Page (`PageMain.js`)
54+
55+
- **CodeFlowBackground**: Animated code lines in the background for the welcome screen.
56+
- **LoadingAnimation**: Full-screen loading spinner and status.
57+
- **ErrorMessage**: Card for displaying connection or data errors.
58+
- **Control Center**: UI for entering the view key, selecting server, toggling auto-refresh, and hiding offline machines.
59+
- **Servers Grid**: Renders a list of `MachineCard` components, one for each machine.
60+
61+
### Machine Display (`MachineCard.js`)
62+
63+
- **Header**: Shows hostname, online/offline badge, GPU count, and a details toggle.
64+
- **Details Section**: Expands to show:
65+
- **Last seen** and **uptime** (with copy-to-clipboard).
66+
- **GPU Information**: Rendered via `GPUv2` (one per GPU).
67+
- **User Information**: Rendered via `UsersLine` (online/offline users).
68+
- **IP Addresses**: Rendered via `IP` and `SingleIP` (with copy-to-clipboard).
69+
- **Status Indicators**: Color-coded badges for online/offline, GPU presence, and more.
70+
71+
### Supporting Components
72+
73+
- **GPUv2**: Shows GPU utilization, temperature, memory usage, and model, with color-coded bars and badges.
74+
- **UsersLine**: Lists online and offline users with `UserBadge` for each.
75+
- **UserBadge**: Visual badge for a user, color-coded by online status.
76+
- **CopyableText**: Inline text with click-to-copy and feedback animation.
77+
- **DisplayPercent / DisplayRAM / DisplayTemp**: Utility components for formatting and color-coding percentages, RAM, and temperature.
78+
- **Footer**: Simple, centered copyright.
79+
80+
---
81+
82+
## File Structure (Key Files)
83+
84+
```
85+
mxstatus/
86+
src/
87+
App.js
88+
App.css
89+
index.js
90+
index.css
91+
components/
92+
PageMain.js
93+
MachineCard.js
94+
GPUv2.js
95+
UsersLine.js
96+
UserBadge.js
97+
CopyableText.js
98+
DisplayPercent.js
99+
DisplayRAM.js
100+
DisplayTemp.js
101+
IP.js
102+
SingleIP.js
103+
Footer.js
104+
```
105+
106+
---
107+
108+
## Notable UI/UX Features
109+
110+
- **Animated Welcome Screen**: With code flow background and smooth transitions.
111+
- **Copy-to-Clipboard**: For hostnames, IPs, and other key data.
112+
- **Auto-Refresh**: User-configurable, with persistent settings.
113+
- **Offline Filtering**: Option to hide offline machines for clarity.
114+
- **Mobile-First**: All controls and cards are touch-friendly and responsive.
115+
- **Status Feedback**: Real-time online/offline, GPU, and user status with color and animation.
116+
117+
---
118+
119+
## Summary
120+
121+
MXStatus is a modern, highly-customized React dashboard for machine status monitoring, with a strong focus on UX, clarity, and a distinctive "hacker" aesthetic. The codebase is modular, maintainable, and ready for extension (e.g., more metrics, drag-and-drop, or additional views).
122+
123+
---

mxstatus/src/App.css

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
padding: 0.75rem;
9696
margin-bottom: 0.75rem;
9797
transition: var(--hacker-transition);
98-
cursor: pointer;
98+
/* cursor: pointer; */
9999
}
100100

101101
.hacker-card:hover {
@@ -1059,3 +1059,18 @@ footer:hover {
10591059
background-color: rgba(0, 255, 65, 0.02);
10601060
border-radius: 0.25rem;
10611061
}
1062+
1063+
.details-anim {
1064+
max-height: 0;
1065+
opacity: 0;
1066+
overflow: hidden;
1067+
transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s;
1068+
}
1069+
.details-anim.expanded {
1070+
max-height: 1000px;
1071+
opacity: 1;
1072+
}
1073+
.details-anim.collapsed {
1074+
max-height: 0;
1075+
opacity: 0;
1076+
}

mxstatus/src/components/GPU.js

Lines changed: 0 additions & 41 deletions
This file was deleted.
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import DisplayTemp from './DisplayTemp'
55
import DisplayRAM from './DisplayRAM'
66
import CopyableText from './CopyableText'
77

8-
const GPUv2 = props => {
8+
const GpuCard = props => {
99
const getUtilizationColor = (percent) => {
1010
if (percent < 0.3) return 'var(--hacker-info)'
1111
if (percent < 0.7) return 'var(--hacker-warning)'
@@ -279,11 +279,11 @@ const GPUv2 = props => {
279279
)
280280
}
281281

282-
GPUv2.propTypes = {
282+
GpuCard.propTypes = {
283283
"data": PropTypes.object
284284
}
285285

286-
GPUv2.defaultProps = {
286+
GpuCard.defaultProps = {
287287
"data": {
288288
"index": 0,
289289
"gpu_name": "GeForce RTX xxxx xx",
@@ -295,4 +295,4 @@ GPUv2.defaultProps = {
295295
}
296296
}
297297

298-
export default GPUv2
298+
export default GpuCard
Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import React from 'react'
22
import PropTypes from 'prop-types'
33
import { useState } from 'react'
44
import IP from './IP'
5-
import GPUv2 from './GPUv2'
5+
import GpuCard from './GpuCard'
66
import UsersLine from './UsersLine'
77
import DisplayPercent from './DisplayPercent'
88
import DisplayRAM from './DisplayRAM'
99
import CopyableText from './CopyableText'
1010

11-
const WorkstationV2 = props => {
11+
const MachineCard = props => {
1212

1313
// const secondsToHms = (d) => {
1414
// d = Number(d);
@@ -86,15 +86,6 @@ const WorkstationV2 = props => {
8686
})
8787
}
8888

89-
// Handle card click to toggle details
90-
const handleCardClick = (e) => {
91-
// Don't toggle if clicking on interactive elements
92-
if (e.target.closest('button') || e.target.closest('.CopyableText') || e.target.closest('input') || e.target.closest('.process-item')) {
93-
return
94-
}
95-
handleShowDetails()
96-
}
97-
9889
// Handle click on interactive elements to prevent bubbling
9990
const handleInteractiveClick = (e) => {
10091
e.stopPropagation()
@@ -127,7 +118,7 @@ const WorkstationV2 = props => {
127118
<div className="hacker-card fade-in" style={{
128119
borderLeft: `4px solid ${getStatusColor()}`,
129120
opacity: isOnline() ? 1 : 0.7
130-
}} onClick={handleCardClick}>
121+
}} >
131122
<div className="server-header d-flex align-items-center justify-content-between mb-2">
132123
<div className="d-flex align-items-center gap-2">
133124
<h3 className="mb-0" style={{
@@ -183,12 +174,12 @@ const WorkstationV2 = props => {
183174
background: 'transparent'
184175
}}
185176
>
186-
{showDetails ? 'HIDE' : 'DETAILS'}
177+
{showDetails ? 'HIDE DETAILS' : 'DETAILS'}
187178
</button>
188179
</div>
189180
</div>
190181

191-
{showDetails && (
182+
<div className={`details-anim${showDetails ? ' expanded' : ' collapsed'}`}>
192183
<div className="server-details" style={{
193184
borderTop: '1px solid var(--hacker-border)',
194185
paddingTop: '0.75rem',
@@ -256,11 +247,11 @@ const WorkstationV2 = props => {
256247
</div>
257248
</div>
258249
</div>
259-
)}
250+
</div>
260251

261252
{isEmpty(props.data.gpu_status) || !showDetails ? null :
262253
<div className="gpu-section mt-2">
263-
{props.data.gpu_status.map((gpu_data, idx) => <GPUv2 key={idx} data={gpu_data} />)}
254+
{props.data.gpu_status.map((gpu_data, idx) => <GpuCard key={idx} data={gpu_data} />)}
264255
</div>
265256
}
266257

@@ -610,14 +601,14 @@ const WorkstationV2 = props => {
610601
)
611602
}
612603

613-
WorkstationV2.propTypes = {
604+
MachineCard.propTypes = {
614605
"data": PropTypes.object,
615606
}
616607

617-
WorkstationV2.defaultProps = {
608+
MachineCard.defaultProps = {
618609
"data": {
619610
"gpu_status": []
620611
}
621612
}
622613

623-
export default WorkstationV2
614+
export default MachineCard

mxstatus/src/components/PageMain.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react'
22
import { useState, useEffect, useRef } from 'react'
33

44
// import Workstation from "./Workstation"
5-
import WorkstationV2 from "./WorkstationV2"
5+
import MachineCard from "./MachineCard"
66

77
import axios from "axios";
88

@@ -1089,7 +1089,7 @@ const PageMain = () => {
10891089
<div className="servers-grid">
10901090
{
10911091
filteredMachines.map((data, index) => {
1092-
return <WorkstationV2 data={data} key={index} />
1092+
return <MachineCard data={data} key={index} />
10931093
})
10941094
}
10951095
</div>

0 commit comments

Comments
 (0)