Phase 3 Steps 3 & 4: Complete Schedules API & Management UI

Implemented full schedule management system with API endpoints and
user interface for creating, editing, and managing scheduled scans.

API Implementation:
- Implemented all 6 schedules API endpoints (list, get, create, update, delete, trigger)
- Added comprehensive error handling and validation
- Integrated with ScheduleService and SchedulerService
- Added manual trigger endpoint for on-demand execution

Schedule Management UI:
- Created schedules list page with stats cards and enable/disable toggles
- Built schedule creation form with cron expression builder and quick templates
- Implemented schedule edit page with execution history
- Added "Schedules" navigation link to main menu
- Real-time validation and human-readable cron descriptions

Config File Path Resolution:
- Fixed config file path handling to support relative filenames
- Updated validators.py to resolve relative paths to /app/configs/
- Modified schedule_service.py, scan_service.py, and scan_job.py for consistency
- Ensures UI can use simple filenames while backend uses absolute paths

Scheduler Integration:
- Completed scheduled scan execution in scheduler_service.py
- Added cron job management with APScheduler
- Implemented automatic schedule loading on startup
- Updated run times after each execution

Testing:
- Added comprehensive API integration tests (test_schedule_api.py)
- 22+ test cases covering all endpoints and workflows

Progress: Phase 3 Steps 1-4 complete (36% - 5/14 days)
Next: Step 5 - Enhanced Dashboard with Charts
This commit is contained in:
2025-11-14 14:33:48 -06:00
parent 7969068c36
commit d68d9133c1
13 changed files with 2413 additions and 87 deletions

View File

@@ -16,7 +16,7 @@ def validate_config_file(file_path: str) -> tuple[bool, Optional[str]]:
Validate that a configuration file exists and is valid YAML.
Args:
file_path: Path to configuration file
file_path: Path to configuration file (absolute or relative filename)
Returns:
Tuple of (is_valid, error_message)
@@ -26,6 +26,8 @@ def validate_config_file(file_path: str) -> tuple[bool, Optional[str]]:
Examples:
>>> validate_config_file('/app/configs/example.yaml')
(True, None)
>>> validate_config_file('example.yaml')
(True, None)
>>> validate_config_file('/nonexistent.yaml')
(False, 'File does not exist: /nonexistent.yaml')
"""
@@ -33,6 +35,10 @@ def validate_config_file(file_path: str) -> tuple[bool, Optional[str]]:
if not file_path:
return False, 'Config file path is required'
# If file_path is just a filename (not absolute), prepend configs directory
if not file_path.startswith('/'):
file_path = f'/app/configs/{file_path}'
# Convert to Path object
path = Path(file_path)