fix(backup): orthogonal code review fixes + UI/UX overhaul

## Critical fixes
- H1: Fix env_id/env/environment_id triple inconsistency in API route
  (_action_routes.py now passes 'environment_id', matches scheduler)
- H2: Decompose BackupPlugin.execute() — CC 13 → 5 methods, CC ≤ 5 each
- H3: Fix unhandled int() ValueError on non-numeric dashboard_ids
- H4: Add concurrent guard test with API-style params (env key fallback)
- H5: Make RetentionPolicy configurable via StorageConfig
  (retention_daily/weekly/monthly in config model + backend plugin)
- Fix: storage DELETE route missing 'await' on async delete_file (bug)

## UI/UX overhaul
- NEW: centralized cron utility (frontend/src/lib/utils/cron.ts)
  - validateCron(), calcNextCronRun(), formatNextRun()
  - Used by BackupManager, BackupDashboardModal
- BackupManager: replace custom BackupList with shared FileList
  - Adds: download, delete, bulk actions, search, sort, pagination
  - Adds: cron next-run preview below schedule input
  - Adds: auto-open TaskDrawer on backup task creation
- BackupDashboardModal: dead 'Cron Help' button removed
  - Adds: live cron validation + next-run preview
- StorageSettings: adds retention daily/weekly/monthly fields
- BackupCreateRequest type fixed to match actual API contract
- i18n: 7 new keys for en/ru (next_run, retention_*)
This commit is contained in:
2026-07-13 20:58:02 +03:00
parent 2819ca3a15
commit d630573402
20 changed files with 717 additions and 359 deletions

View File

@@ -582,6 +582,25 @@ def test_trigger_backup_other_plugin(service, mock_task_manager):
mock_run.assert_called_once()
# #endregion test_trigger_backup_other_plugin
# #region test_trigger_backup_matches_env_key_fallback [C:2] [TYPE Function]
# @BRIEF _trigger_backup matches existing task by "env" key (backward compat for API-created tasks).
# @TEST_EDGE api_env_key_fallback -> Existing task with params={"env":"env-1"} blocks new trigger.
def test_trigger_backup_matches_env_key_fallback(service, mock_task_manager):
"""Existing task with 'env' key (API-style) should block backup for same env."""
api_task = MagicMock()
api_task.plugin_id = "superset-backup"
api_task.status = "RUNNING"
api_task.params = {"env": "env-1"} # API-created tasks use "env", not "environment_id"
mock_task_manager.get_tasks.return_value = [api_task]
with patch("src.core.scheduler.seed_trace_id"):
with patch("src.core.scheduler.belief_scope") as mock_bs:
mock_bs.return_value.__enter__ = MagicMock()
mock_bs.return_value.__exit__ = MagicMock(return_value=False)
with patch("src.core.scheduler.asyncio.run_coroutine_threadsafe") as mock_run:
service._trigger_backup("env-1")
mock_run.assert_not_called()
# #endregion test_trigger_backup_matches_env_key_fallback
# ══════════════════════════════════════════════════════════════
# SchedulerService.add_validation_job