feat: Aggiunto sistema completo di gestione profili per Data Coupler

- Creata nuova libreria Components con componenti Blazor riutilizzabili
  * ProfileSelector: dropdown per selezione profili salvati
  * ProfileSaver: componente per salvare configurazioni correnti come profili
  * ProfileManagement: modale per gestione profili salvati
  * ProfileQuickActions: bottoni azioni rapide per operazioni sui profili

- Esteso CredentialManager con entità e servizi per DataCouplerProfile
  * Aggiunto modello DataCouplerProfile con configurazioni mapping e metadati
  * Implementata migrazione Entity Framework per memorizzazione profili
  * Creato DataCouplerProfileService per operazioni CRUD
  * Aggiunto CredentialDbContextFactory per operazioni database design-time

- Migliorato componente principale DataCoupler con integrazione profili
  * Integrata funzionalità caricamento/salvataggio profili
  * Aggiunto selettore profili nella parte superiore dell'interfaccia
  * Mantenuta retrocompatibilità con funzionalità esistenti
  * Migliorata esperienza utente con gestione configurazioni salvate

- Aggiornata struttura progetto e dipendenze
  * Aggiunto progetto Components alla soluzione
  * Aggiornati riferimenti progetti e import
  * Rimosso progetto obsoleto TestDatabaseFix

Questo aggiornamento migliora significativamente il flusso di lavoro permettendo agli utenti di salvare, caricare e gestire configurazioni complete di accoppiamento dati come
This commit is contained in:
2025-07-02 00:00:05 +02:00
parent 1435c013d3
commit 7e450a358b
34 changed files with 2430 additions and 422 deletions
+145
View File
@@ -0,0 +1,145 @@
using Microsoft.AspNetCore.Components;
using CredentialManager.Models;
namespace Components;
public partial class ProfileManagement
{
[Parameter] public bool ShowModal { get; set; }
[Parameter] public List<DataCouplerProfile>? Profiles { get; set; }
[Parameter] public EventCallback OnCloseModal { get; set; }
[Parameter] public EventCallback<DataCouplerProfile> OnProfileLoaded { get; set; }
[Parameter] public EventCallback<int> OnProfileDeleted { get; set; }
[Parameter] public bool IsLoading { get; set; }
private string SearchTerm { get; set; } = "";
private string Message { get; set; } = "";
private string MessageType { get; set; } = "info";
private bool ShowDeleteConfirm { get; set; } = false;
private bool IsDeleting { get; set; } = false;
private DataCouplerProfile? ProfileToDelete { get; set; }
private void FilterProfiles(ChangeEventArgs e)
{
SearchTerm = e.Value?.ToString() ?? "";
}
private IEnumerable<DataCouplerProfile> GetFilteredProfiles()
{
if (Profiles == null)
return Enumerable.Empty<DataCouplerProfile>();
if (string.IsNullOrWhiteSpace(SearchTerm))
return Profiles;
var searchLower = SearchTerm.ToLower();
return Profiles.Where(p =>
p.Name.ToLower().Contains(searchLower) ||
(!string.IsNullOrEmpty(p.Description) && p.Description.ToLower().Contains(searchLower))
);
}
private string GetTypeLabel(string type)
{
return type switch
{
"database" => "DB",
"file" => "File",
"rest" => "REST",
_ => type.ToUpper()
};
}
private string GetProfileSummary(DataCouplerProfile profile)
{
var parts = new List<string>();
// Fonte
if (!string.IsNullOrEmpty(profile.SourceTable))
parts.Add($"da {profile.SourceTable}");
else if (!string.IsNullOrEmpty(profile.SourceFilePath))
parts.Add($"da {Path.GetFileName(profile.SourceFilePath)}");
// Destinazione
if (!string.IsNullOrEmpty(profile.DestinationTable))
parts.Add($"verso {profile.DestinationTable}");
else if (!string.IsNullOrEmpty(profile.DestinationEndpoint))
parts.Add($"verso {profile.DestinationEndpoint}");
return string.Join(" ", parts);
}
private async Task CloseModal()
{
SearchTerm = "";
Message = "";
await OnCloseModal.InvokeAsync();
}
private async Task LoadProfile(DataCouplerProfile profile)
{
Message = $"Caricamento profilo '{profile.Name}'...";
MessageType = "info";
await OnProfileLoaded.InvokeAsync(profile);
Message = $"Profilo '{profile.Name}' caricato con successo!";
MessageType = "success";
// Chiudi il modal dopo un breve delay
await Task.Delay(1000);
await CloseModal();
}
private void ConfirmDelete(DataCouplerProfile profile)
{
ProfileToDelete = profile;
ShowDeleteConfirm = true;
Message = "";
}
private void CancelDelete()
{
ProfileToDelete = null;
ShowDeleteConfirm = false;
}
private async Task DeleteProfile()
{
if (ProfileToDelete == null)
return;
IsDeleting = true;
try
{
await OnProfileDeleted.InvokeAsync(ProfileToDelete.Id);
Message = $"Profilo '{ProfileToDelete.Name}' eliminato con successo.";
MessageType = "success";
ShowDeleteConfirm = false;
ProfileToDelete = null;
}
catch (Exception ex)
{
Message = $"Errore nell'eliminazione: {ex.Message}";
MessageType = "danger";
}
finally
{
IsDeleting = false;
}
}
public void SetMessage(string message, string type = "info")
{
Message = message;
MessageType = type;
}
public void ClearMessage()
{
Message = "";
}
}