Skip to content

Commit b2dc0a3

Browse files
authored
Merge pull request #68 from fccview/develop
Lift off!!
2 parents 4beb705 + e40b0c0 commit b2dc0a3

21 files changed

Lines changed: 1424 additions & 1068 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ node_modules
1414
.idea
1515
tsconfig.tsbuildinfo
1616
docker-compose.test.yml
17-
/data
17+
/data
18+
claude.md

CONTRIBUTING.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# How to contribute
2+
3+
Hi, it's amazing having a community willing to push new feature to the app, and I am VERY open to contributors pushing their idea, it's what makes open source amazing.
4+
5+
That said for the sake of sanity let's all follow the same structure:
6+
7+
- When creating a new branch, do off from the develop branch, this will always be ahead of main and it's what gets released
8+
- When creating a pull request, direct it back into develop, I'll then review it and merge it. Your code will end up in the next release that way and we all avoid conflicts!
9+
- Please bear with on reviews, it may take a bit of time for me to go through it all on top of life/work/hobbies :)
10+
11+
## Some best practices
12+
13+
### Code Quality
14+
15+
- Follow the existing code style and structure
16+
- Keep files modular and under 250-300 (split into smaller components if needed) lines unless it's a major server action, these can get intense I know
17+
- Avoid code duplication - reuse existing functions and UI components, don't hardcode html when a component already exists (e.g. <button> vs <Button>)
18+
- All imports should be at the top of the file unless it's for specific server actions
19+
- Avoid using `any`
20+
- Don't hardcode colors! Use the theme variables to make sure light/dark mode keep working well
21+
- Make sure the UI is consistent with the current one, look for spacing issues, consistent spacing really makes a difference
22+
23+
### Pull Requests
24+
25+
- Keep PRs focused on a single feature or fix
26+
- Update documentation if your changes affect user-facing features
27+
- Test your changes locally before submitting
28+
29+
### Getting Started
30+
31+
1. Fork the repository
32+
2. Create a feature branch from `develop`
33+
3. Make your changes
34+
4. Test thoroughly
35+
5. Submit a pull request to `develop`
36+
37+
Thank you for contributing! <3

README.md

Lines changed: 5 additions & 215 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
- [Local Development](#local-development)
1414
- [Environment Variables](howto/ENV_VARIABLES.md)
1515
- [Authentication](#authentication)
16-
- [REST API](#rest-api)
1716
- [Usage](#usage)
1817
- [Viewing System Information](#viewing-system-information)
1918
- [Managing Cron Jobs](#managing-cron-jobs)
@@ -28,7 +27,7 @@
2827
## Features
2928

3029
- **Modern UI**: Beautiful, responsive interface with dark/light mode.
31-
- **System Information**: Display hostname, IP address, uptime, memory, network and CPU info.
30+
- **System Information**: Display uptime, memory, network, CPU, and GPU info.
3231
- **Cron Job Management**: View, create, and delete cron jobs with comments.
3332
- **Script management**: View, create, and delete bash scripts on the go to use within your cron jobs.
3433
- **Job Execution Logging**: Optional logging for cronjobs with automatic cleanup, capturing stdout, stderr, exit codes, and timestamps.
@@ -115,7 +114,7 @@ services:
115114

116115
## API
117116

118-
`cr*nmaster` includes a REST API for programmatic access to your checklists and notes. This is perfect for integrations.
117+
`cr*nmaster` includes a REST API for programmatic access to your cron jobs and system information. This is perfect for integrations.
119118

120119
📖 **For the complete API documentation, see [howto/API.md](howto/API.md)**
121120

@@ -131,7 +130,7 @@ services:
131130

132131
## Localization
133132

134-
`cr*nmaster` officially support [some languages](app/_transations) and allows you to create your custom translations locally on your own machine.
133+
`cr*nmaster` officially support [some languages](app/_translations) and allows you to create your custom translations locally on your own machine.
135134

136135
📖 **For the complete Translations documentation, see [howto/TRANSLATIONS.md](howto/TRANSLATIONS.md)**
137136

@@ -229,82 +228,11 @@ Cr\*nMaster supports SSO via OIDC (OpenID Connect), compatible with providers li
229228
- Entra ID (Azure AD)
230229
- And many more!
231230

232-
For detailed setup instructions, see **[README_SSO.md](README_SSO.md)**
233-
234-
Quick example:
235-
236-
```yaml
237-
environment:
238-
- SSO_MODE=oidc
239-
- OIDC_ISSUER=https://your-sso-provider.com
240-
- OIDC_CLIENT_ID=your_client_id
241-
- APP_URL=https://your-cronmaster-domain.com
242-
```
243-
244-
### Combined Authentication
245-
246231
You can enable **both** password and SSO authentication simultaneously:
247232

248-
```yaml
249-
environment:
250-
- AUTH_PASSWORD=your_password
251-
- SSO_MODE=oidc
252-
- OIDC_ISSUER=https://your-sso-provider.com
253-
- OIDC_CLIENT_ID=your_client_id
254-
```
255-
256233
The login page will display both options, allowing users to choose their preferred method.
257234

258-
### Security Features
259-
260-
- ✅ **Secure session management** with cryptographically random session IDs
261-
- ✅ **30-day session expiration** with automatic cleanup
262-
- ✅ **HTTP-only cookies** to prevent XSS attacks
263-
- ✅ **Proper JWT verification** for OIDC tokens using provider's public keys (JWKS)
264-
- ✅ **PKCE support** for OIDC authentication (or confidential client mode)
265-
266-
<a id="rest-api"></a>
267-
268-
## REST API
269-
270-
Cr\*nMaster provides a full REST API for programmatic access. Perfect for:
271-
272-
- External monitoring tools
273-
- Automation scripts
274-
- CI/CD integrations
275-
- Custom dashboards
276-
277-
### API Authentication
278-
279-
Protect your API with an optional API key:
280-
281-
```yaml
282-
environment:
283-
- API_KEY=your-secret-api-key-here
284-
```
285-
286-
Use the API key in your requests:
287-
288-
```bash
289-
curl -H "Authorization: Bearer YOUR_API_KEY" \
290-
https://your-domain.com/api/cronjobs
291-
```
292-
293-
For complete API documentation with examples, see **[howto/API.md](howto/API.md)**
294-
295-
### Available Endpoints
296-
297-
- `GET /api/cronjobs` - List all cron jobs
298-
- `POST /api/cronjobs` - Create a new cron job
299-
- `GET /api/cronjobs/:id` - Get a specific cron job
300-
- `PATCH /api/cronjobs/:id` - Update a cron job
301-
- `DELETE /api/cronjobs/:id` - Delete a cron job
302-
- `POST /api/cronjobs/:id/execute` - Manually execute a job
303-
- `GET /api/scripts` - List all scripts
304-
- `POST /api/scripts` - Create a new script
305-
- `GET /api/system-stats` - Get system statistics
306-
- `GET /api/logs/stream?runId=xxx` - Stream job logs
307-
- `GET /api/events` - SSE stream for real-time updates
235+
**For detailed setup instructions, see **[howto/SSO.md](howto/SSO.md)**
308236

309237
<a id="usage"></a>
310238

@@ -337,125 +265,7 @@ The application automatically detects your operating system and displays:
337265

338266
### Job Execution Logging
339267

340-
CronMaster includes an optional logging feature that captures detailed execution information for your cronjobs:
341-
342-
#### How It Works
343-
344-
When you enable logging for a cronjob, CronMaster automatically wraps your command with a log wrapper script. This wrapper:
345-
346-
- Captures **stdout** and **stderr** output
347-
- Records the **exit code** of your command
348-
- Timestamps the **start and end** of execution
349-
- Calculates **execution duration**
350-
- Stores all this information in organized log files
351-
352-
#### Enabling Logs
353-
354-
1. When creating or editing a cronjob, check the "Enable Logging" checkbox
355-
2. The wrapper is automatically added to your crontab entry
356-
3. Jobs run independently - they continue to work even if CronMaster is offline
357-
358-
#### Log Storage
359-
360-
Logs are stored in the `./data/logs/` directory with descriptive folder names:
361-
362-
- If a job has a **description/comment**: `{sanitized-description}_{jobId}/`
363-
- If a job has **no description**: `{jobId}/`
364-
365-
Example structure:
366-
367-
```
368-
./data/logs/
369-
├── backup-database_root-0/
370-
│ ├── 2025-11-10_14-30-00.log
371-
│ ├── 2025-11-10_15-30-00.log
372-
│ └── 2025-11-10_16-30-00.log
373-
├── daily-cleanup_root-1/
374-
│ └── 2025-11-10_14-35-00.log
375-
├── root-2/ (no description provided)
376-
│ └── 2025-11-10_14-40-00.log
377-
```
378-
379-
**Note**: Folder names are sanitized to be filesystem-safe (lowercase, alphanumeric with hyphens, max 50 chars for the description part).
380-
381-
#### Log Format
382-
383-
Each log file includes:
384-
385-
```
386-
==========================================
387-
=== CronMaster Job Execution Log ===
388-
==========================================
389-
Log Folder: backup-database_root-0
390-
Command: bash /app/scripts/backup.sh
391-
Started: 2025-11-10 14:30:00
392-
==========================================
393-
394-
[command output here]
395-
396-
==========================================
397-
=== Execution Summary ===
398-
==========================================
399-
Completed: 2025-11-10 14:30:45
400-
Duration: 45 seconds
401-
Exit code: 0
402-
==========================================
403-
```
404-
405-
#### Automatic Cleanup
406-
407-
Logs are automatically cleaned up to prevent disk space issues:
408-
409-
- **Maximum logs per job**: 50 log files
410-
- **Maximum age**: 30 days
411-
- **Cleanup trigger**: When viewing logs or after manual execution
412-
- **Method**: Oldest logs are deleted first when limits are exceeded
413-
414-
#### Custom Wrapper Script
415-
416-
You can override the default log wrapper by creating your own at `./data/wrapper-override.sh`. This allows you to:
417-
418-
- Customize log format
419-
- Add additional metadata
420-
- Integrate with external logging services
421-
- Implement custom retention policies
422-
423-
**Example custom wrapper**:
424-
425-
```bash
426-
#!/bin/bash
427-
JOB_ID="$1"
428-
shift
429-
430-
# Your custom logic here
431-
LOG_FILE="/custom/path/${JOB_ID}_$(date '+%Y%m%d').log"
432-
433-
{
434-
echo "=== Custom Log Format ==="
435-
echo "Job: $JOB_ID"
436-
"$@"
437-
echo "Exit: $?"
438-
} >> "$LOG_FILE" 2>&1
439-
```
440-
441-
#### Docker Considerations
442-
443-
- Mount the `./data` directory to persist logs on the host
444-
- The wrapper script location: `./data/cron-log-wrapper.sh`. This will be generated automatically the first time you enable logging.
445-
446-
#### Non-Docker Considerations
447-
448-
- Logs are stored at `./data/logs/` relative to the project directory
449-
- The codebase wrapper script location: `./app/_scripts/cron-log-wrapper.sh`
450-
- The running wrapper script location: `./data/cron-log-wrapper.sh`
451-
452-
#### Important Notes
453-
454-
- Logging is **optional** and disabled by default
455-
- Jobs with logging enabled are marked with a blue "Logged" badge in the UI
456-
- Logs are captured for both scheduled runs and manual executions
457-
- Commands with file redirections (>, >>) may conflict with logging
458-
- The crontab stores the **wrapped command**, so jobs run independently of CronMaster
268+
📖 **For complete logging documentation, see [howto/LOGS.md](howto/LOGS.md)**
459269

460270
### Cron Schedule Format
461271

@@ -477,26 +287,6 @@ The application uses standard cron format: `* * * * *`
477287
4. **Delete Scripts**: Remove unwanted scripts (this won't delete the cronjob, you will need to manually remove these yourself)
478288
5. **Clone Scripts**: Clone scripts to quickly edit them in case they are similar to one another.
479289

480-
<a id="technologies-used"></a>
481-
482-
## Technologies Used
483-
484-
- **Next.js 14**: React framework with App Router
485-
- **TypeScript**: Type-safe JavaScript
486-
- **Tailwind CSS**: Utility-first CSS framework
487-
- **Lucide React**: Beautiful icons
488-
- **next-themes**: Dark/light mode support
489-
- **Docker**: Containerization
490-
491-
<a id="contributing"></a>
492-
493-
## Contributing
494-
495-
1. Fork the repository
496-
2. Create a feature branch from the `develop` branch
497-
3. Make your changes
498-
4. Submit a pull request to the `develop` branch
499-
500290
## Community shouts
501291

502292
I would like to thank the following members for raising issues and help test/debug them!

app/_components/FeatureComponents/Modals/CreateTaskModal.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,10 @@ export const CreateTaskModal = ({
6464
}, [selectedScript]);
6565

6666
const handleScriptSelect = async (script: Script) => {
67+
const scriptPath = await getHostScriptPath(script.filename);
6768
onFormChange({
6869
selectedScriptId: script.id,
69-
command: await getHostScriptPath(script.filename),
70+
command: scriptPath,
7071
});
7172
};
7273

@@ -123,11 +124,10 @@ export const CreateTaskModal = ({
123124
<button
124125
type="button"
125126
onClick={handleCustomCommand}
126-
className={`p-4 rounded-lg border-2 transition-all ${
127-
!form.selectedScriptId
127+
className={`p-4 rounded-lg border-2 transition-all ${!form.selectedScriptId
128128
? "border-primary bg-primary/5 text-primary"
129129
: "border-border bg-muted/30 text-muted-foreground hover:border-border/60"
130-
}`}
130+
}`}
131131
>
132132
<div className="flex items-center gap-3">
133133
<Terminal className="h-5 w-5" />
@@ -145,11 +145,10 @@ export const CreateTaskModal = ({
145145
<button
146146
type="button"
147147
onClick={() => setIsSelectScriptModalOpen(true)}
148-
className={`p-4 rounded-lg border-2 transition-all ${
149-
form.selectedScriptId
148+
className={`p-4 rounded-lg border-2 transition-all ${form.selectedScriptId
150149
? "border-primary bg-primary/5 text-primary"
151150
: "border-border bg-muted/30 text-muted-foreground hover:border-border/60"
152-
}`}
151+
}`}
153152
>
154153
<div className="flex items-center gap-3">
155154
<FileText className="h-5 w-5" />

0 commit comments

Comments
 (0)