Skip to content

Commit ca862bf

Browse files
authored
Merge pull request #15 from IsmailBinMujeeb/feat/system-monitor-app
feat(app): add system monitor
2 parents a638867 + e0cfdc9 commit ca862bf

6 files changed

Lines changed: 122 additions & 18 deletions

File tree

src/components/Desktop.js

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import AppRegistry from '@/system/services/AppRegistry';
1414
import NotesApp from '@/pages/apps/notes';
1515
import BrowserApp from '@/pages/apps/browser';
1616
import SettingsApp from '@/pages/apps/settings';
17-
17+
import MonitorApp from '@/pages/apps/monitor';
1818

1919
// --- (REMOVED) ---
2020
// This entire hardcoded array is no longer needed.
@@ -24,26 +24,24 @@ import SettingsApp from '@/pages/apps/settings';
2424
// { id: 'settings', name: 'Settings', icon: '⚙️', component: 'settings' }
2525
// ];
2626

27-
2827
// --- (UNCHANGED) ---
2928
// This mapping is still essential. It connects the string 'notes' from our
3029
// App class instance to the actual React component NotesApp.
3130
const appComponents = {
3231
// These keys MUST match the 'component' field in your App definitions.
33-
notes: NotesApp, // 'notes' (lowercase) matches 'notes' in NotesApp.js
32+
notes: NotesApp, // 'notes' (lowercase) matches 'notes' in NotesApp.js
3433
browser: BrowserApp,
35-
settings: SettingsApp
34+
settings: SettingsApp,
35+
monitor: MonitorApp,
3636
};
3737

38-
3938
export default function Desktop() {
4039
const { state } = useApp();
4140

4241
// --- (ADDED) ---
4342
// We now get our list of apps dynamically from the single source of truth.
4443
const desktopApps = AppRegistry.getAllApps();
4544

46-
4745
// --- (UNCHANGED) ---
4846
// This function works perfectly as is.
4947
const renderAppContent = (app) => {
@@ -66,13 +64,13 @@ export default function Desktop() {
6664

6765
{/* --- (UNCHANGED) --- */}
6866
{/* This logic is based on the global context and doesn't need to change. */}
69-
{state.openApps.map(app => (
67+
{state.openApps.map((app) => (
7068
<Window key={app.id} app={app}>
7169
{renderAppContent(app)}
7270
</Window>
7371
))}
74-
72+
7573
<Taskbar />
7674
</div>
7775
);
78-
}
76+
}

src/pages/apps/monitor.js

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import React, { useEffect, useState } from 'react';
2+
import { useApp } from '@/context/AppContext';
3+
4+
// Fake system stats generator
5+
function getFakeStats() {
6+
return {
7+
cpu: (Math.random() * 100).toFixed(1),
8+
ram: (Math.random() * 16).toFixed(1),
9+
storage: (Math.random() * 512).toFixed(1),
10+
};
11+
}
12+
13+
export default function Monitor() {
14+
const [stats, setStats] = useState(getFakeStats());
15+
const [dateTime, setDateTime] = useState(new Date());
16+
const { state, dispatch } = useApp();
17+
const { openApps } = state;
18+
19+
useEffect(() => {
20+
const statsInterval = setInterval(() => {
21+
setStats(getFakeStats());
22+
}, 1500);
23+
24+
const clockInterval = setInterval(() => {
25+
setDateTime(new Date());
26+
}, 1000);
27+
28+
return () => {
29+
clearInterval(statsInterval);
30+
clearInterval(clockInterval);
31+
};
32+
}, []);
33+
34+
return (
35+
<div>
36+
<div className="flex flex-col gap-8 p-4 relative">
37+
<div className="my-2">
38+
<h4 className="text-lg font-semibold mb-3">Running Processes</h4>
39+
<div className="overflow-hidden rounded-lg border border-gray-300 shadow-sm">
40+
<table className="w-full text-left text-sm">
41+
<thead className="bg-gray-200">
42+
<tr>
43+
<th className="px-3 py-2 font-medium">App</th>
44+
<th className="px-3 py-2 font-medium">PID</th>
45+
<th className="px-3 py-2 font-medium">Actions</th>
46+
</tr>
47+
</thead>
48+
<tbody className="divide-y divide-gray-200 bg-white">
49+
{openApps.map((app) => (
50+
<tr key={app.id} className="hover:bg-gray-50">
51+
<td className="px-3 py-2">{app.name}</td>
52+
<td className="px-3 py-2">{app.processId}</td>
53+
<td
54+
className="px-3 py-2 text-red-500 cursor-pointer"
55+
onClick={() =>
56+
dispatch({ type: 'CLOSE_APP', payload: app.id })
57+
}
58+
>
59+
close app
60+
</td>
61+
</tr>
62+
))}
63+
{openApps.length === 0 && (
64+
<tr>
65+
<td
66+
colSpan={3}
67+
className="px-3 py-4 text-center text-gray-500 italic"
68+
>
69+
No apps running
70+
</td>
71+
</tr>
72+
)}
73+
</tbody>
74+
</table>
75+
</div>
76+
</div>
77+
{/* System Stats */}
78+
<div className="absolute top-0 grid grid-cols-3 gap-4">
79+
<div className="flex items-center gap-2 rounded-lg text-center">
80+
<div className="text-sm text-gray-500">CPU Usage</div>
81+
<div className="text-sm">{stats.cpu}%</div>
82+
</div>
83+
<div className="flex items-center gap-2 rounded-lg text-center">
84+
<div className="text-sm text-gray-500">RAM Usage</div>
85+
<div className="text-sm">{stats.ram} GB</div>
86+
</div>
87+
<div className="flex items-center gap-2 rounded-lg text-center">
88+
<div className="text-sm text-gray-500">Storage Used</div>
89+
<div className="text-sm">{stats.storage} GB</div>
90+
</div>
91+
</div>
92+
</div>
93+
{/* Clock (fixed at bottom right) */}
94+
<div className="absolute bottom-0 right-0 m-4 flex items-center gap-2 text-sm bg-white px-3 py-1 rounded-lg shadow">
95+
<span>{dateTime.toLocaleTimeString()}</span>
96+
<span className="text-gray-400">|</span>
97+
<span>{dateTime.toLocaleDateString()}</span>
98+
</div>
99+
</div>
100+
);
101+
}

src/system/apps/App.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ export default class App {
1414
*/
1515
constructor({ id, name, icon, component }) {
1616
this.id = id;
17+
this.processId = Math.random().toString(10).substring(16);
1718
this.name = name;
1819
this.icon = icon;
1920
this.component = component;
2021
}
21-
}
22+
}

src/system/apps/BrowserApp.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ import App from './App';
22
export default new App({
33
id: 'browser',
44
name: 'Browser',
5-
icon: '🌐',
5+
icon: '🌐',
66
component: 'browser',
7-
});
7+
});

src/system/apps/MonitorApp.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import App from './App';
2+
export default new App({
3+
id: 'monitor',
4+
name: 'System Monitor',
5+
icon: '/icons/monitor.png',
6+
component: 'monitor',
7+
});

src/system/services/AppRegistry.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import NotesApp from '../apps/NotesApp';
44
import SettingsApp from '../apps/SettingsApp';
55
import BrowserApp from '../apps/BrowserApp';
6+
import MonitorApp from '../apps/MonitorApp';
67

78
/**
89
* A central registry for all available applications.
@@ -11,11 +12,7 @@ import BrowserApp from '../apps/BrowserApp';
1112
*/
1213
class AppRegistry {
1314
constructor() {
14-
this.apps = [
15-
NotesApp,
16-
SettingsApp,
17-
BrowserApp,
18-
];
15+
this.apps = [NotesApp, SettingsApp, BrowserApp, MonitorApp];
1916
}
2017

2118
/**
@@ -27,4 +24,4 @@ class AppRegistry {
2724
}
2825
}
2926

30-
export default new AppRegistry();
27+
export default new AppRegistry();

0 commit comments

Comments
 (0)