ezpm2gui 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,30 +2,55 @@
2
2
 
3
3
  A modern web-based graphical user interface for the PM2 process manager, built with TypeScript and Material UI.
4
4
 
5
- ![ezPM2GUI Dashboard](./screenshots/screenshot-1747156076728.png)
6
-
7
5
  ## Features
8
6
 
9
- - 🔍 **Real-time process monitoring** - Keep track of all your PM2 processes in real-time
10
- - 🎮 **Process management** - Start, stop, restart, and delete processes with one click
11
- - 📊 **System metrics dashboard** - Monitor CPU, memory usage, and uptime
12
- - 📝 **Enhanced log streaming** - View and filter logs from multiple processes simultaneously
13
- - 🔄 **WebSocket for live updates** - Get instant updates without refreshing
14
- - 📈 **Process CPU and memory charts** - Visualize performance metrics over time
15
- - 🔍 **Filter processes by status or name** - Quickly find the processes you need
16
- - 🌙 **Dark mode support** - Easy on the eyes for late-night monitoring
17
- - 🖥️ **Cluster management** - Easily scale your Node.js applications
18
- - 📦 **Application deployment** - Deploy new applications directly from the UI
19
- - ⚙️ **Ecosystem configuration** - Create and manage your PM2 ecosystem files
20
- - 🧩 **PM2 modules support** - Manage and configure PM2 modules
21
- - 🌐 **Modern UI with Material UI components** - Clean and intuitive interface
22
- - 🔒 **Fully typed with TypeScript** - Robust and maintainable codebase
7
+ - **Real-time process monitoring** - Keep track of all your PM2 processes in real-time
8
+ - **Process management** - Start, stop, restart, and delete processes with one click
9
+ - **System metrics dashboard** - Monitor CPU, memory usage, and uptime
10
+ - **Enhanced log streaming** - View and filter logs from multiple processes simultaneously
11
+ - **WebSocket for live updates** - Get instant updates without refreshing
12
+ - **Process CPU and memory charts** - Visualize performance metrics over time
13
+ - **Filter processes by status or name** - Quickly find the processes you need
14
+ - **Dark mode support** - Easy on the eyes for late-night monitoring
15
+ - **Cluster management** - Easily scale your Node.js applications
16
+ - **Application deployment** - Deploy new applications directly from the UI
17
+ - **Ecosystem configuration** - Create and manage your PM2 ecosystem files
18
+ - **PM2 modules support** - Manage and configure PM2 modules
19
+ - **Cron Jobs** - Schedule and manage automated tasks with visual cron expression builder
20
+ - **Remote Server Management** - Connect and manage PM2 on remote servers via SSH
21
+ - **Advanced Monitoring Dashboard** - Real-time performance charts with health scoring
22
+ - **Modern UI with Material UI components** - Clean and intuitive interface
23
+ - **Fully typed with TypeScript** - Robust and maintainable codebase
23
24
 
24
25
  ## Detailed Features
25
26
 
26
27
  ### Process Monitoring
27
28
  Monitor all your PM2 processes in real-time with detailed information on CPU usage, memory consumption, uptime, and status. The intuitive interface makes it easy to identify issues at a glance.
28
29
 
30
+ ### Remote Server Management
31
+ Connect to and manage PM2 processes on remote servers via secure SSH connections:
32
+ - Add multiple remote server connections with SSH credentials
33
+ - View and manage processes on remote servers
34
+ - Stream logs from remote processes in real-time
35
+ - Execute PM2 commands on remote machines
36
+ - Encrypted credential storage for security
37
+
38
+ ### Cron Jobs
39
+ Schedule and automate tasks using PM2's cron restart feature:
40
+ - Visual cron expression builder with common presets
41
+ - Support for Node.js, Python, Shell, and .NET scripts
42
+ - Inline script editor or file-based execution
43
+ - Enable/disable jobs without deleting them
44
+ - View next execution times and job status
45
+
46
+ ### Advanced Monitoring Dashboard
47
+ Get deeper insights into your system and process performance:
48
+ - Real-time performance charts for CPU, memory, and load
49
+ - System health score calculation
50
+ - Historical metrics tracking
51
+ - Process alerts for high resource usage
52
+ - Per-process performance visualization
53
+
29
54
  ### Application Deployment
30
55
  Deploy new Node.js applications to PM2 directly from the UI. Configure all the necessary options including:
31
56
  - Application name and script path
@@ -41,10 +66,11 @@ Easily scale your Node.js applications with the cluster management interface. Ad
41
66
 
42
67
  ### Log Streaming
43
68
  View and filter logs from multiple processes simultaneously with the enhanced log streaming interface. Features include:
44
- - Real-time log updates
45
- - Filtering by log level or content
69
+ - Real-time log updates via WebSocket
70
+ - Filtering by process, log level, or content
46
71
  - Pausing and resuming log streams
47
- - Log retention configuration
72
+ - Download logs for offline analysis
73
+ - Floating log panel for remote process logs
48
74
 
49
75
  ### Ecosystem Configuration
50
76
  Generate and manage PM2 ecosystem configuration files directly from the UI. This makes it easy to set up complex application deployments and share configurations across your team.
@@ -66,28 +92,6 @@ Customize the ezPM2GUI interface to suit your preferences:
66
92
  - Configure dashboard refresh intervals
67
93
  - Adjust log display settings
68
94
 
69
- ## Screenshots
70
-
71
- ### Process Monitor
72
- The main dashboard provides a comprehensive view of all your PM2 processes, showing CPU usage, memory consumption, uptime, and status at a glance.
73
-
74
- ![Process Monitor](./screenshots/screenshot-1747156076728.png)
75
-
76
- ### System Metrics & Process Management
77
- Monitor your system resources and manage PM2 processes with intuitive controls for start, stop, restart, and delete operations.
78
-
79
- ![System Metrics](./screenshots/screenshot-1747156118224.png)
80
-
81
- ### Deploy New Application
82
- Easily deploy new Node.js applications to PM2 with a user-friendly form interface. Configure all PM2 options including instances, execution mode, working directory, and environment variables.
83
-
84
- ![Deploy Application](./screenshots/screenshot-1747156060890.png)
85
-
86
- ### Application Settings
87
- Customize the ezPM2GUI interface and configure your PM2 connection settings to match your environment.
88
-
89
- ![Application Settings](./screenshots/screenshot-1747156042956.png)
90
-
91
95
  ## Installation
92
96
 
93
97
  ### Global Installation
@@ -0,0 +1,18 @@
1
+ [
2
+ {
3
+ "name": "cv-forge",
4
+ "description": "",
5
+ "scriptType": "shell",
6
+ "scriptMode": "inline",
7
+ "scriptPath": "",
8
+ "inlineScript": "echo \"Installing CV Forge\"\nnpm install -g cv-forge",
9
+ "cronExpression": "* * * * *",
10
+ "args": [],
11
+ "env": {},
12
+ "cwd": "",
13
+ "enabled": true,
14
+ "id": "6d8d5e1d-2bc8-463f-82a6-6c294f2b9dbe",
15
+ "createdAt": "2025-11-03T15:46:21.776Z",
16
+ "updatedAt": "2025-11-03T15:50:34.133Z"
17
+ }
18
+ ]
@@ -0,0 +1,2 @@
1
+ echo "Installing CV Forge"
2
+ npm install -g cv-forge
@@ -0,0 +1,22 @@
1
+ {
2
+ "connections": [
3
+ {
4
+ "id": "192.168.50.100-22-oll-dev",
5
+ "name": "ascend",
6
+ "host": "192.168.50.100",
7
+ "port": 22,
8
+ "username": "oll-dev",
9
+ "password": "42eb428a6d0ca614741be36634da53791a5273626acd5d59502780066ce6005e",
10
+ "useSudo": true
11
+ },
12
+ {
13
+ "id": "172.26.252.123-22-chandan",
14
+ "name": "wsl",
15
+ "host": "172.26.252.123",
16
+ "port": 22,
17
+ "username": "chandan",
18
+ "password": "65350d6eb4851ac4386b23b596ea08ed",
19
+ "useSudo": true
20
+ }
21
+ ]
22
+ }
@@ -14,6 +14,7 @@ const processConfig_1 = __importDefault(require("./routes/processConfig"));
14
14
  const deployApplication_1 = __importDefault(require("./routes/deployApplication"));
15
15
  const modules_1 = __importDefault(require("./routes/modules"));
16
16
  const remoteConnections_1 = __importDefault(require("./routes/remoteConnections"));
17
+ const cronJobs_1 = __importDefault(require("./routes/cronJobs"));
17
18
  const logStreaming_1 = require("./routes/logStreaming");
18
19
  const pm2_connection_1 = require("./utils/pm2-connection");
19
20
  const remote_connection_1 = require("./utils/remote-connection");
@@ -47,6 +48,7 @@ function createServer() {
47
48
  app.use('/api/deploy', deployApplication_1.default);
48
49
  app.use('/api/modules', modules_1.default);
49
50
  app.use('/api/remote', remoteConnections_1.default);
51
+ app.use('/api/cron-jobs', cronJobs_1.default);
50
52
  // Setup log streaming with Socket.IO
51
53
  (0, logStreaming_1.setupLogStreaming)(io); // PM2 API endpoints
52
54
  app.get('/api/processes', async (req, res) => {
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Cron Jobs API Routes
3
+ * Manages scheduled tasks using PM2's cron_restart feature
4
+ */
5
+ import { Router } from 'express';
6
+ declare const router: Router;
7
+ export default router;
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ /**
3
+ * Cron Jobs API Routes
4
+ * Manages scheduled tasks using PM2's cron_restart feature
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ const express_1 = require("express");
11
+ const CronJobService_1 = __importDefault(require("../services/CronJobService"));
12
+ const router = (0, express_1.Router)();
13
+ /**
14
+ * GET /api/cron-jobs
15
+ * Get all cron jobs
16
+ */
17
+ router.get('/', async (req, res) => {
18
+ try {
19
+ const jobs = CronJobService_1.default.getCronJobs();
20
+ res.json({ success: true, data: jobs });
21
+ }
22
+ catch (error) {
23
+ console.error('Error getting cron jobs:', error);
24
+ res.status(500).json({ success: false, error: error.message });
25
+ }
26
+ });
27
+ /**
28
+ * GET /api/cron-jobs/status
29
+ * Get status of all cron jobs including PM2 process info
30
+ */
31
+ router.get('/status', async (req, res) => {
32
+ try {
33
+ const statuses = await CronJobService_1.default.getCronJobsStatus();
34
+ res.json({ success: true, data: statuses });
35
+ }
36
+ catch (error) {
37
+ console.error('Error getting cron job statuses:', error);
38
+ res.status(500).json({ success: false, error: error.message });
39
+ }
40
+ });
41
+ /**
42
+ * GET /api/cron-jobs/:id
43
+ * Get a specific cron job by ID
44
+ */
45
+ router.get('/:id', (req, res) => {
46
+ try {
47
+ const job = CronJobService_1.default.getCronJob(req.params.id);
48
+ if (!job) {
49
+ return res.status(404).json({ success: false, error: 'Cron job not found' });
50
+ }
51
+ res.json({ success: true, data: job });
52
+ }
53
+ catch (error) {
54
+ console.error('Error getting cron job:', error);
55
+ res.status(500).json({ success: false, error: error.message });
56
+ }
57
+ });
58
+ /**
59
+ * POST /api/cron-jobs
60
+ * Create a new cron job
61
+ */
62
+ router.post('/', async (req, res) => {
63
+ try {
64
+ const config = req.body;
65
+ // Validate required fields
66
+ if (!config.name || !config.scriptType || !config.cronExpression) {
67
+ return res.status(400).json({
68
+ success: false,
69
+ error: 'Missing required fields: name, scriptType, cronExpression'
70
+ });
71
+ }
72
+ // Validate script mode specific requirements
73
+ if (config.scriptMode === 'file' && !config.scriptPath) {
74
+ return res.status(400).json({
75
+ success: false,
76
+ error: 'Script path is required when using file mode'
77
+ });
78
+ }
79
+ if (config.scriptMode === 'inline' && !config.inlineScript) {
80
+ return res.status(400).json({
81
+ success: false,
82
+ error: 'Inline script content is required when using inline mode'
83
+ });
84
+ }
85
+ const job = await CronJobService_1.default.createCronJob(config);
86
+ res.json({ success: true, data: job });
87
+ }
88
+ catch (error) {
89
+ console.error('Error creating cron job:', error);
90
+ res.status(400).json({ success: false, error: error.message });
91
+ }
92
+ });
93
+ /**
94
+ * PUT /api/cron-jobs/:id
95
+ * Update a cron job
96
+ */
97
+ router.put('/:id', async (req, res) => {
98
+ try {
99
+ const updates = req.body;
100
+ const job = await CronJobService_1.default.updateCronJob(req.params.id, updates);
101
+ res.json({ success: true, data: job });
102
+ }
103
+ catch (error) {
104
+ console.error('Error updating cron job:', error);
105
+ res.status(400).json({ success: false, error: error.message });
106
+ }
107
+ });
108
+ /**
109
+ * DELETE /api/cron-jobs/:id
110
+ * Delete a cron job
111
+ */
112
+ router.delete('/:id', async (req, res) => {
113
+ try {
114
+ await CronJobService_1.default.deleteCronJob(req.params.id);
115
+ res.json({ success: true, message: 'Cron job deleted successfully' });
116
+ }
117
+ catch (error) {
118
+ console.error('Error deleting cron job:', error);
119
+ res.status(400).json({ success: false, error: error.message });
120
+ }
121
+ });
122
+ /**
123
+ * POST /api/cron-jobs/:id/toggle
124
+ * Toggle cron job enabled state
125
+ */
126
+ router.post('/:id/toggle', async (req, res) => {
127
+ try {
128
+ const job = await CronJobService_1.default.toggleCronJob(req.params.id);
129
+ res.json({ success: true, data: job });
130
+ }
131
+ catch (error) {
132
+ console.error('Error toggling cron job:', error);
133
+ res.status(400).json({ success: false, error: error.message });
134
+ }
135
+ });
136
+ /**
137
+ * POST /api/cron-jobs/:id/start
138
+ * Manually start a cron job
139
+ */
140
+ router.post('/:id/start', async (req, res) => {
141
+ try {
142
+ await CronJobService_1.default.startCronJob(req.params.id);
143
+ res.json({ success: true, message: 'Cron job started successfully' });
144
+ }
145
+ catch (error) {
146
+ console.error('Error starting cron job:', error);
147
+ res.status(400).json({ success: false, error: error.message });
148
+ }
149
+ });
150
+ /**
151
+ * POST /api/cron-jobs/:id/stop
152
+ * Manually stop a cron job
153
+ */
154
+ router.post('/:id/stop', async (req, res) => {
155
+ try {
156
+ await CronJobService_1.default.stopCronJob(req.params.id);
157
+ res.json({ success: true, message: 'Cron job stopped successfully' });
158
+ }
159
+ catch (error) {
160
+ console.error('Error stopping cron job:', error);
161
+ res.status(400).json({ success: false, error: error.message });
162
+ }
163
+ });
164
+ /**
165
+ * POST /api/cron-jobs/validate
166
+ * Validate a cron expression
167
+ */
168
+ router.post('/validate', (req, res) => {
169
+ try {
170
+ const { expression } = req.body;
171
+ if (!expression) {
172
+ return res.status(400).json({ success: false, error: 'Expression is required' });
173
+ }
174
+ const validation = CronJobService_1.default.validateCronExpression(expression);
175
+ const description = CronJobService_1.default.getCronDescription(expression);
176
+ res.json({
177
+ success: true,
178
+ data: {
179
+ ...validation,
180
+ description
181
+ }
182
+ });
183
+ }
184
+ catch (error) {
185
+ console.error('Error validating cron expression:', error);
186
+ res.status(400).json({ success: false, error: error.message });
187
+ }
188
+ });
189
+ exports.default = router;
@@ -606,6 +606,111 @@ router.post('/connections', (req, res) => {
606
606
  });
607
607
  }
608
608
  });
609
+ /**
610
+ * Update an existing remote connection configuration
611
+ * PUT /api/remote/connections/:connectionId
612
+ */
613
+ router.put('/connections/:connectionId', async (req, res) => {
614
+ try {
615
+ const { connectionId } = req.params;
616
+ const connectionConfig = req.body;
617
+ if (!connectionConfig.name || !connectionConfig.host || !connectionConfig.username) {
618
+ return res.status(400).json({
619
+ success: false,
620
+ error: 'Missing required connection parameters: name, host, or username'
621
+ });
622
+ }
623
+ // Ensure port is set
624
+ if (!connectionConfig.port) {
625
+ connectionConfig.port = 22;
626
+ }
627
+ // Update the connection
628
+ const success = await remote_connection_1.remoteConnectionManager.updateConnection(connectionId, connectionConfig);
629
+ if (!success) {
630
+ return res.status(404).json({
631
+ success: false,
632
+ error: 'Connection not found'
633
+ });
634
+ }
635
+ res.json({
636
+ success: true,
637
+ message: 'Connection updated successfully'
638
+ });
639
+ }
640
+ catch (error) {
641
+ res.status(500).json({
642
+ success: false,
643
+ error: `Server error: ${error instanceof Error ? error.message : 'Unknown error'}`
644
+ });
645
+ }
646
+ });
647
+ /**
648
+ * Delete a remote connection configuration
649
+ * DELETE /api/remote/connections/:connectionId
650
+ */
651
+ router.delete('/connections/:connectionId', async (req, res) => {
652
+ try {
653
+ const { connectionId } = req.params;
654
+ // Close the connection if it's open
655
+ await remote_connection_1.remoteConnectionManager.closeConnection(connectionId);
656
+ // Delete the connection configuration
657
+ const success = remote_connection_1.remoteConnectionManager.deleteConnection(connectionId);
658
+ if (!success) {
659
+ return res.status(404).json({
660
+ success: false,
661
+ error: 'Connection not found'
662
+ });
663
+ }
664
+ res.json({
665
+ success: true,
666
+ message: 'Connection deleted successfully'
667
+ });
668
+ }
669
+ catch (error) {
670
+ res.status(500).json({
671
+ success: false,
672
+ error: `Server error: ${error instanceof Error ? error.message : 'Unknown error'}`
673
+ });
674
+ }
675
+ });
676
+ /**
677
+ * Install PM2 on a remote server
678
+ * POST /api/remote/:connectionId/install-pm2
679
+ */
680
+ router.post('/:connectionId/install-pm2', async (req, res) => {
681
+ try {
682
+ const { connectionId } = req.params;
683
+ const connection = remote_connection_1.remoteConnectionManager.getConnection(connectionId);
684
+ if (!connection) {
685
+ return res.status(404).json({
686
+ success: false,
687
+ error: 'Connection not found'
688
+ });
689
+ }
690
+ // Install PM2
691
+ const result = await connection.installPM2();
692
+ if (result.code === 0) {
693
+ res.json({
694
+ success: true,
695
+ message: 'PM2 installed successfully',
696
+ output: result.stdout
697
+ });
698
+ }
699
+ else {
700
+ res.status(400).json({
701
+ success: false,
702
+ error: 'Failed to install PM2',
703
+ output: result.stderr || result.stdout
704
+ });
705
+ }
706
+ }
707
+ catch (error) {
708
+ res.status(500).json({
709
+ success: false,
710
+ error: `Failed to install PM2: ${error.message}`
711
+ });
712
+ }
713
+ });
609
714
  /**
610
715
  * Delete a connection configuration
611
716
  * DELETE /api/remote/connections/:connectionId
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Cron Job Service - Manages PM2 processes with cron_restart
3
+ */
4
+ import { CronJobConfig, CronJobStatus } from '../../types/cron';
5
+ export declare class CronJobService {
6
+ private static instance;
7
+ private constructor();
8
+ static getInstance(): CronJobService;
9
+ private ensureConfigFile;
10
+ private readConfig;
11
+ private writeConfig;
12
+ /**
13
+ * Validate cron expression
14
+ */
15
+ validateCronExpression(expression: string): {
16
+ valid: boolean;
17
+ error?: string;
18
+ nextRun?: Date;
19
+ };
20
+ /**
21
+ * Get human-readable description of cron expression
22
+ */
23
+ getCronDescription(expression: string): string;
24
+ /**
25
+ * Get script path for inline scripts (creates temp file)
26
+ */
27
+ private getScriptPath;
28
+ /**
29
+ * Get file extension for script type
30
+ */
31
+ private getScriptExtension;
32
+ /**
33
+ * Convert CronJobConfig to PM2 start options
34
+ */
35
+ private toPM2Options;
36
+ /**
37
+ * Create a new cron job
38
+ */
39
+ createCronJob(config: Omit<CronJobConfig, 'id' | 'createdAt' | 'updatedAt'>): Promise<CronJobConfig>;
40
+ /**
41
+ * Get all cron jobs
42
+ */
43
+ getCronJobs(): CronJobConfig[];
44
+ /**
45
+ * Get a single cron job by ID
46
+ */
47
+ getCronJob(id: string): CronJobConfig | undefined;
48
+ /**
49
+ * Update a cron job
50
+ */
51
+ updateCronJob(id: string, updates: Partial<CronJobConfig>): Promise<CronJobConfig>;
52
+ /**
53
+ * Delete a cron job
54
+ */
55
+ deleteCronJob(id: string): Promise<void>;
56
+ /**
57
+ * Start a cron job (start PM2 process with cron_restart)
58
+ */
59
+ startCronJob(id: string): Promise<void>;
60
+ /**
61
+ * Stop a cron job (delete PM2 process)
62
+ */
63
+ stopCronJob(id: string): Promise<void>;
64
+ /**
65
+ * Get status of all cron jobs (including PM2 process info)
66
+ */
67
+ getCronJobsStatus(): Promise<CronJobStatus[]>;
68
+ /**
69
+ * Toggle cron job enabled state
70
+ */
71
+ toggleCronJob(id: string): Promise<CronJobConfig>;
72
+ }
73
+ declare const _default: CronJobService;
74
+ export default _default;