d042863a56
- Aggiunto supporto schedulazione con intervalli flessibili (secondi/minuti/ore/giorni/settimane/mesi) - Esteso modello ProfileSchedule con campi IntervalValue e IntervalUnit - Ottimizzato ScheduledJobService per controlli ogni 30s con esecuzione parallela - Implementata interfaccia UI completa con anteprima real-time in italiano - Aggiunta migrazione database AddIntervalSchedulingFields - Implementati metodi calcolo NextExecutionTime per intervalli - Aggiunta gestione tracking anti-duplicati e cleanup automatico - Creata documentazione completa (6 file, 2500+ righe) Modifiche tecniche: - ProfileSchedule.cs: Nuovi campi e metodi CalculateNextInterval/GetScheduleDescription - ScheduledJobService.cs: Ridotto check interval a 30s, aggiunto parallel processing - ProfileScheduleService.cs: Supporto calcolo intervalli in UpdateNextExecutionTimeAsync - Scheduling.razor: Aggiunta sezione UI per configurazione intervalli - Scheduling.razor.cs: Implementato GetIntervalPreview() e gestione stato campi
574 lines
21 KiB
Plaintext
574 lines
21 KiB
Plaintext
@inject ILogger<MaintenanceTab> Logger
|
|
|
|
<div class="settings-section">
|
|
<h4>
|
|
<i class="fas fa-tools text-success me-2"></i>
|
|
Manutenzione Sistema
|
|
</h4>
|
|
<p class="text-muted">
|
|
Strumenti per la manutenzione e l'ottimizzazione del sistema.
|
|
</p>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-database text-primary me-2"></i>
|
|
Database
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="card-text">Operazioni di manutenzione del database.</p>
|
|
|
|
<div class="mb-3">
|
|
<h6>Stato Database</h6>
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<span>Dimensione:</span>
|
|
<span class="badge bg-info">@databaseStats.SizeMB MB</span>
|
|
</div>
|
|
<div class="d-flex justify-content-between align-items-center mt-1">
|
|
<span>Ultima ottimizzazione:</span>
|
|
<span class="text-muted">@databaseStats.LastOptimization.ToString("dd/MM/yyyy HH:mm")</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-grid gap-2">
|
|
<button class="btn btn-outline-primary" @onclick="OptimizeDatabase" disabled="@isOptimizing">
|
|
@if (isOptimizing)
|
|
{
|
|
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
|
|
}
|
|
else
|
|
{
|
|
<i class="fas fa-cogs me-1"></i>
|
|
}
|
|
Ottimizza Database
|
|
</button>
|
|
|
|
<button class="btn btn-outline-secondary" @onclick="AnalyzeDatabase" disabled="@isAnalyzing">
|
|
@if (isAnalyzing)
|
|
{
|
|
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
|
|
}
|
|
else
|
|
{
|
|
<i class="fas fa-search me-1"></i>
|
|
}
|
|
Analizza Integrità
|
|
</button>
|
|
|
|
<button class="btn btn-outline-warning" @onclick="CompactDatabase" disabled="@isCompacting">
|
|
@if (isCompacting)
|
|
{
|
|
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
|
|
}
|
|
else
|
|
{
|
|
<i class="fas fa-compress-alt me-1"></i>
|
|
}
|
|
Compatta Database
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-trash-alt text-warning me-2"></i>
|
|
Pulizia Sistema
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="card-text">Strumenti per la pulizia dei dati temporanei.</p>
|
|
|
|
<div class="mb-3">
|
|
<h6>File temporanei</h6>
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<span>Dimensione cache:</span>
|
|
<span class="badge bg-secondary">@cleanupStats.CacheSizeMB MB</span>
|
|
</div>
|
|
<div class="d-flex justify-content-between align-items-center mt-1">
|
|
<span>File di log:</span>
|
|
<span class="badge bg-secondary">@cleanupStats.LogFileCount file</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-grid gap-2">
|
|
<button class="btn btn-outline-warning" @onclick="ClearTempFiles" disabled="@isClearingTemp">
|
|
@if (isClearingTemp)
|
|
{
|
|
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
|
|
}
|
|
else
|
|
{
|
|
<i class="fas fa-broom me-1"></i>
|
|
}
|
|
Pulisci File Temporanei
|
|
</button>
|
|
|
|
<button class="btn btn-outline-secondary" @onclick="ClearOldLogs" disabled="@isClearingLogs">
|
|
@if (isClearingLogs)
|
|
{
|
|
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
|
|
}
|
|
else
|
|
{
|
|
<i class="fas fa-file-alt me-1"></i>
|
|
}
|
|
Pulisci Log Vecchi
|
|
</button>
|
|
|
|
<button class="btn btn-outline-info" @onclick="RefreshStats">
|
|
<i class="fas fa-sync-alt me-1"></i>
|
|
Aggiorna Statistiche
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-4">
|
|
<div class="col-md-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-chart-line text-info me-2"></i>
|
|
Monitoraggio Performance
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h6>Memoria Utilizzata</h6>
|
|
<div class="progress mb-2">
|
|
<div class="progress-bar" role="progressbar" style="width: @(performanceStats.MemoryUsagePercent)%"></div>
|
|
</div>
|
|
<small class="text-muted">@performanceStats.MemoryUsageMB MB / @performanceStats.TotalMemoryMB MB</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h6>CPU</h6>
|
|
<div class="progress mb-2">
|
|
<div class="progress-bar bg-warning" role="progressbar" style="width: @(performanceStats.CpuUsagePercent)%"></div>
|
|
</div>
|
|
<small class="text-muted">@performanceStats.CpuUsagePercent%</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h6>Connessioni Attive</h6>
|
|
<h4 class="text-primary">@performanceStats.ActiveConnections</h4>
|
|
<small class="text-muted">di @performanceStats.MaxConnections max</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center">
|
|
<h6>Uptime</h6>
|
|
<h4 class="text-success">@performanceStats.UptimeHours h</h4>
|
|
<small class="text-muted">@performanceStats.StartTime.ToString("dd/MM HH:mm")</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-3">
|
|
<button class="btn btn-outline-primary" @onclick="GeneratePerformanceReport">
|
|
<i class="fas fa-file-chart-column me-1"></i>
|
|
Genera Report Performance
|
|
</button>
|
|
<button class="btn btn-outline-secondary ms-2" @onclick="RefreshPerformanceStats">
|
|
<i class="fas fa-sync-alt me-1"></i>
|
|
Aggiorna
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-4">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-calendar-check text-primary me-2"></i>
|
|
Manutenzione Programmata
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="card-text">Configurazione delle attività automatiche.</p>
|
|
|
|
<div class="form-check mb-3">
|
|
<input class="form-check-input" type="checkbox" @bind="maintenanceSettings.AutoOptimizeEnabled" id="autoOptimize">
|
|
<label class="form-check-label" for="autoOptimize">
|
|
Ottimizzazione automatica database
|
|
</label>
|
|
</div>
|
|
|
|
<div class="form-check mb-3">
|
|
<input class="form-check-input" type="checkbox" @bind="maintenanceSettings.AutoCleanupEnabled" id="autoCleanup">
|
|
<label class="form-check-label" for="autoCleanup">
|
|
Pulizia automatica file temporanei
|
|
</label>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="maintenanceTime" class="form-label">Orario manutenzione:</label>
|
|
<input type="time" class="form-control" id="maintenanceTime" @bind="maintenanceSettings.ScheduledTime">
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="maintenanceFrequency" class="form-label">Frequenza:</label>
|
|
<select class="form-select" id="maintenanceFrequency" @bind="maintenanceSettings.Frequency">
|
|
<option value="Daily">Giornaliera</option>
|
|
<option value="Weekly">Settimanale</option>
|
|
<option value="Monthly">Mensile</option>
|
|
</select>
|
|
</div>
|
|
|
|
<button class="btn btn-primary" @onclick="SaveMaintenanceSettings">
|
|
<i class="fas fa-save me-1"></i>
|
|
Salva Configurazione
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-history text-info me-2"></i>
|
|
Storico Attività
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="card-text">Ultime operazioni di manutenzione.</p>
|
|
|
|
<div class="maintenance-history">
|
|
@foreach (var activity in maintenanceHistory)
|
|
{
|
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
<div>
|
|
<i class="@GetActivityIcon(activity.Type) me-2"></i>
|
|
@activity.Description
|
|
</div>
|
|
<small class="text-muted">@activity.Timestamp.ToString("dd/MM HH:mm")</small>
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
@if (!maintenanceHistory.Any())
|
|
{
|
|
<div class="text-muted text-center py-3">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
Nessuna attività di manutenzione recente
|
|
</div>
|
|
}
|
|
|
|
<button class="btn btn-outline-secondary btn-sm mt-2" @onclick="ClearMaintenanceHistory">
|
|
<i class="fas fa-trash-alt me-1"></i>
|
|
Pulisci Storico
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@code {
|
|
[Parameter] public EventCallback<(string message, string type)> OnShowToast { get; set; }
|
|
|
|
private bool isOptimizing = false;
|
|
private bool isAnalyzing = false;
|
|
private bool isCompacting = false;
|
|
private bool isClearingTemp = false;
|
|
private bool isClearingLogs = false;
|
|
|
|
private DatabaseStats databaseStats = new()
|
|
{
|
|
SizeMB = 12.5,
|
|
LastOptimization = DateTime.Now.AddDays(-3)
|
|
};
|
|
|
|
private CleanupStats cleanupStats = new()
|
|
{
|
|
CacheSizeMB = 45.2,
|
|
LogFileCount = 127
|
|
};
|
|
|
|
private PerformanceStats performanceStats = new()
|
|
{
|
|
MemoryUsageMB = 234,
|
|
TotalMemoryMB = 512,
|
|
MemoryUsagePercent = 45,
|
|
CpuUsagePercent = 12,
|
|
ActiveConnections = 3,
|
|
MaxConnections = 100,
|
|
UptimeHours = 72,
|
|
StartTime = DateTime.Now.AddHours(-72)
|
|
};
|
|
|
|
private MaintenanceSettings maintenanceSettings = new()
|
|
{
|
|
AutoOptimizeEnabled = true,
|
|
AutoCleanupEnabled = true,
|
|
ScheduledTime = new TimeOnly(2, 0),
|
|
Frequency = "Weekly"
|
|
};
|
|
|
|
private List<MaintenanceActivity> maintenanceHistory = new()
|
|
{
|
|
new MaintenanceActivity { Type = "Optimization", Description = "Database ottimizzato", Timestamp = DateTime.Now.AddHours(-6) },
|
|
new MaintenanceActivity { Type = "Cleanup", Description = "File temporanei rimossi", Timestamp = DateTime.Now.AddDays(-1) },
|
|
new MaintenanceActivity { Type = "Backup", Description = "Backup automatico completato", Timestamp = DateTime.Now.AddDays(-2) }
|
|
};
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
await RefreshStats();
|
|
}
|
|
|
|
private async Task OptimizeDatabase()
|
|
{
|
|
try
|
|
{
|
|
isOptimizing = true;
|
|
StateHasChanged();
|
|
|
|
await Task.Delay(3000); // Simula ottimizzazione
|
|
|
|
databaseStats.LastOptimization = DateTime.Now;
|
|
AddMaintenanceActivity("Optimization", "Database ottimizzato");
|
|
|
|
await OnShowToast.InvokeAsync(("Database ottimizzato con successo", "success"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogError(ex, "Errore ottimizzazione database");
|
|
await OnShowToast.InvokeAsync(("Errore durante l'ottimizzazione", "error"));
|
|
}
|
|
finally
|
|
{
|
|
isOptimizing = false;
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
|
|
private async Task AnalyzeDatabase()
|
|
{
|
|
try
|
|
{
|
|
isAnalyzing = true;
|
|
StateHasChanged();
|
|
|
|
await Task.Delay(2000);
|
|
await OnShowToast.InvokeAsync(("Analisi completata: nessun problema rilevato", "success"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogError(ex, "Errore analisi database");
|
|
await OnShowToast.InvokeAsync(("Errore durante l'analisi", "error"));
|
|
}
|
|
finally
|
|
{
|
|
isAnalyzing = false;
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
|
|
private async Task CompactDatabase()
|
|
{
|
|
try
|
|
{
|
|
isCompacting = true;
|
|
StateHasChanged();
|
|
|
|
await Task.Delay(4000);
|
|
|
|
databaseStats.SizeMB *= 0.8; // Simula riduzione dimensioni
|
|
AddMaintenanceActivity("Compact", "Database compattato");
|
|
|
|
await OnShowToast.InvokeAsync(("Database compattato con successo", "success"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogError(ex, "Errore compattazione database");
|
|
await OnShowToast.InvokeAsync(("Errore durante la compattazione", "error"));
|
|
}
|
|
finally
|
|
{
|
|
isCompacting = false;
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
|
|
private async Task ClearTempFiles()
|
|
{
|
|
try
|
|
{
|
|
isClearingTemp = true;
|
|
StateHasChanged();
|
|
|
|
await Task.Delay(1500);
|
|
|
|
cleanupStats.CacheSizeMB = 0;
|
|
AddMaintenanceActivity("Cleanup", "File temporanei rimossi");
|
|
|
|
await OnShowToast.InvokeAsync(("File temporanei rimossi", "success"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogError(ex, "Errore pulizia file temporanei");
|
|
await OnShowToast.InvokeAsync(("Errore durante la pulizia", "error"));
|
|
}
|
|
finally
|
|
{
|
|
isClearingTemp = false;
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
|
|
private async Task ClearOldLogs()
|
|
{
|
|
try
|
|
{
|
|
isClearingLogs = true;
|
|
StateHasChanged();
|
|
|
|
await Task.Delay(1000);
|
|
|
|
cleanupStats.LogFileCount = Math.Max(0, cleanupStats.LogFileCount - 50);
|
|
AddMaintenanceActivity("LogCleanup", "Log vecchi rimossi");
|
|
|
|
await OnShowToast.InvokeAsync(("Log vecchi rimossi", "success"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogError(ex, "Errore pulizia log");
|
|
await OnShowToast.InvokeAsync(("Errore durante la pulizia log", "error"));
|
|
}
|
|
finally
|
|
{
|
|
isClearingLogs = false;
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
|
|
private async Task RefreshStats()
|
|
{
|
|
await Task.Delay(300);
|
|
// Simula aggiornamento statistiche
|
|
cleanupStats.CacheSizeMB = Random.Shared.Next(20, 80);
|
|
cleanupStats.LogFileCount = Random.Shared.Next(50, 200);
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task RefreshPerformanceStats()
|
|
{
|
|
await Task.Delay(500);
|
|
// Simula aggiornamento performance
|
|
performanceStats.MemoryUsagePercent = Random.Shared.Next(30, 70);
|
|
performanceStats.CpuUsagePercent = Random.Shared.Next(5, 25);
|
|
performanceStats.ActiveConnections = Random.Shared.Next(1, 10);
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task GeneratePerformanceReport()
|
|
{
|
|
await OnShowToast.InvokeAsync(("Report performance generato", "info"));
|
|
}
|
|
|
|
private async Task SaveMaintenanceSettings()
|
|
{
|
|
try
|
|
{
|
|
await Task.Delay(300);
|
|
await OnShowToast.InvokeAsync(("Configurazione manutenzione salvata", "success"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogError(ex, "Errore salvataggio configurazione");
|
|
await OnShowToast.InvokeAsync(("Errore salvataggio configurazione", "error"));
|
|
}
|
|
}
|
|
|
|
private async Task ClearMaintenanceHistory()
|
|
{
|
|
maintenanceHistory.Clear();
|
|
await OnShowToast.InvokeAsync(("Storico attività pulito", "info"));
|
|
StateHasChanged();
|
|
}
|
|
|
|
private void AddMaintenanceActivity(string type, string description)
|
|
{
|
|
maintenanceHistory.Insert(0, new MaintenanceActivity
|
|
{
|
|
Type = type,
|
|
Description = description,
|
|
Timestamp = DateTime.Now
|
|
});
|
|
|
|
// Mantieni solo le ultime 10 attività
|
|
if (maintenanceHistory.Count > 10)
|
|
{
|
|
maintenanceHistory.RemoveAt(maintenanceHistory.Count - 1);
|
|
}
|
|
}
|
|
|
|
private string GetActivityIcon(string type) => type switch
|
|
{
|
|
"Optimization" => "fas fa-cogs text-primary",
|
|
"Cleanup" => "fas fa-broom text-warning",
|
|
"Backup" => "fas fa-download text-success",
|
|
"Compact" => "fas fa-compress-alt text-info",
|
|
"LogCleanup" => "fas fa-file-alt text-secondary",
|
|
_ => "fas fa-cog text-muted"
|
|
};
|
|
|
|
private class DatabaseStats
|
|
{
|
|
public double SizeMB { get; set; }
|
|
public DateTime LastOptimization { get; set; }
|
|
}
|
|
|
|
private class CleanupStats
|
|
{
|
|
public double CacheSizeMB { get; set; }
|
|
public int LogFileCount { get; set; }
|
|
}
|
|
|
|
private class PerformanceStats
|
|
{
|
|
public int MemoryUsageMB { get; set; }
|
|
public int TotalMemoryMB { get; set; }
|
|
public int MemoryUsagePercent { get; set; }
|
|
public int CpuUsagePercent { get; set; }
|
|
public int ActiveConnections { get; set; }
|
|
public int MaxConnections { get; set; }
|
|
public int UptimeHours { get; set; }
|
|
public DateTime StartTime { get; set; }
|
|
}
|
|
|
|
private class MaintenanceSettings
|
|
{
|
|
public bool AutoOptimizeEnabled { get; set; }
|
|
public bool AutoCleanupEnabled { get; set; }
|
|
public TimeOnly ScheduledTime { get; set; }
|
|
public string Frequency { get; set; } = "Weekly";
|
|
}
|
|
|
|
private class MaintenanceActivity
|
|
{
|
|
public string Type { get; set; } = "";
|
|
public string Description { get; set; } = "";
|
|
public DateTime Timestamp { get; set; }
|
|
}
|
|
}
|