Aggiornamento main #12
@@ -25,6 +25,7 @@ public partial class ProfileSaver
|
|||||||
[Parameter] public string? DestinationTable { get; set; }
|
[Parameter] public string? DestinationTable { get; set; }
|
||||||
[Parameter] public string? DestinationEndpoint { get; set; }
|
[Parameter] public string? DestinationEndpoint { get; set; }
|
||||||
[Parameter] public List<FieldMappingDto>? FieldMappings { get; set; }
|
[Parameter] public List<FieldMappingDto>? FieldMappings { get; set; }
|
||||||
|
[Parameter] public Dictionary<string, (object? Value, string? Type)>? DefaultValues { get; set; }
|
||||||
[Parameter] public List<ExternalIdRelationshipDto>? ExternalIdRelationships { get; set; }
|
[Parameter] public List<ExternalIdRelationshipDto>? ExternalIdRelationships { get; set; }
|
||||||
[Parameter] public string? SourceKeyField { get; set; }
|
[Parameter] public string? SourceKeyField { get; set; }
|
||||||
[Parameter] public bool UseRecordAssociations { get; set; }
|
[Parameter] public bool UseRecordAssociations { get; set; }
|
||||||
@@ -79,6 +80,7 @@ public partial class ProfileSaver
|
|||||||
DestinationTable = DestinationTable,
|
DestinationTable = DestinationTable,
|
||||||
DestinationEndpoint = DestinationEndpoint,
|
DestinationEndpoint = DestinationEndpoint,
|
||||||
FieldMappings = FieldMappings,
|
FieldMappings = FieldMappings,
|
||||||
|
DefaultValues = DefaultValues,
|
||||||
ExternalIdRelationships = ExternalIdRelationships,
|
ExternalIdRelationships = ExternalIdRelationships,
|
||||||
SourceKeyField = SourceKeyField,
|
SourceKeyField = SourceKeyField,
|
||||||
UseRecordAssociations = UseRecordAssociations
|
UseRecordAssociations = UseRecordAssociations
|
||||||
|
|||||||
Generated
+601
@@ -0,0 +1,601 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using CredentialManager.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace CredentialManager.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(CredentialDbContext))]
|
||||||
|
[Migration("20260216113009_AddDefaultValuesJsonToProfile")]
|
||||||
|
partial class AddDefaultValuesJsonToProfile
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "9.0.6");
|
||||||
|
|
||||||
|
modelBuilder.Entity("CredentialManager.Models.CredentialEntity", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("AdditionalParameters")
|
||||||
|
.HasMaxLength(2000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("CommandTimeout")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(30);
|
||||||
|
|
||||||
|
b.Property<string>("ConnectionString")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("CreatedBy")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DatabaseName")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DatabaseType")
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("EncryptedApiKey")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("EncryptedAuthToken")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("EncryptedPassword")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Headers")
|
||||||
|
.HasMaxLength(2000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Host")
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IgnoreSslErrors")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool>("IsActive")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("OdbcDsnName")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("OdbcMode")
|
||||||
|
.HasMaxLength(20)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("Port")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("RestServiceType")
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("TimeoutSeconds")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(100);
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("DatabaseType");
|
||||||
|
|
||||||
|
b.HasIndex("IsActive");
|
||||||
|
|
||||||
|
b.HasIndex("Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("Type");
|
||||||
|
|
||||||
|
b.ToTable("Credentials", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CredentialManager.Models.DataCouplerProfile", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT")
|
||||||
|
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||||
|
|
||||||
|
b.Property<string>("CreatedBy")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DefaultValuesJson")
|
||||||
|
.HasMaxLength(4000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DeletionAction")
|
||||||
|
.HasMaxLength(20)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DeletionMarkField")
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DeletionMarkValue")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("DestinationCredentialId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("DestinationEndpoint")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DestinationSchema")
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DestinationTable")
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DestinationType")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(20)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ExternalIdRelationshipsJson")
|
||||||
|
.HasMaxLength(4000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("FieldMappingJson")
|
||||||
|
.HasMaxLength(4000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsActive")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LastUsedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("SourceCredentialId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("SourceCustomQuery")
|
||||||
|
.HasMaxLength(2000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SourceDatabaseName")
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SourceFilePath")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SourceKeyField")
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SourceSchema")
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SourceTable")
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SourceType")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(20)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("SyncDeletions")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("UseRecordAssociations")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CreatedAt");
|
||||||
|
|
||||||
|
b.HasIndex("DestinationCredentialId");
|
||||||
|
|
||||||
|
b.HasIndex("DestinationType");
|
||||||
|
|
||||||
|
b.HasIndex("IsActive");
|
||||||
|
|
||||||
|
b.HasIndex("LastUsedAt");
|
||||||
|
|
||||||
|
b.HasIndex("Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("SourceCredentialId");
|
||||||
|
|
||||||
|
b.HasIndex("SourceType");
|
||||||
|
|
||||||
|
b.ToTable("DataCouplerProfiles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CredentialManager.Models.KeyAssociation", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("AdditionalInfo")
|
||||||
|
.HasMaxLength(2000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Data_Hash")
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("DeletionSynced")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletionSyncedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DestinationEntity")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DestinationId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DestinationKeyField")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsActive")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<bool>("IsSourceDeleted")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("KeyValue")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LastVerifiedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("MappedDestinationField")
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("RestCredentialName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SourceKeyField")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SourcesInfo")
|
||||||
|
.HasMaxLength(2000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CreatedAt");
|
||||||
|
|
||||||
|
b.HasIndex("DestinationEntity");
|
||||||
|
|
||||||
|
b.HasIndex("IsActive");
|
||||||
|
|
||||||
|
b.HasIndex("KeyValue")
|
||||||
|
.HasDatabaseName("IX_KeyAssociations_KeyValue");
|
||||||
|
|
||||||
|
b.HasIndex("LastVerifiedAt");
|
||||||
|
|
||||||
|
b.HasIndex("RestCredentialName");
|
||||||
|
|
||||||
|
b.HasIndex("KeyValue", "DestinationEntity", "RestCredentialName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("IX_KeyAssociations_Unique");
|
||||||
|
|
||||||
|
b.ToTable("KeyAssociations", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CredentialManager.Models.ProfileSchedule", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("CreatedBy")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DailyTime")
|
||||||
|
.HasMaxLength(10)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("DayOfMonth")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("DayOfWeek")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DestinationDatabaseOverride")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("EnableDeletionSync")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ExecutionCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("IntervalUnit")
|
||||||
|
.HasMaxLength(20)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("IntervalValue")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsActive")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEnabled")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("LastExecutionMessage")
|
||||||
|
.HasMaxLength(1000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("LastExecutionRecordCount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("LastExecutionStatus")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(20)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LastExecutionTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("NextExecutionTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ScheduleType")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(20)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ScheduledDateTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SourceDatabaseOverride")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId");
|
||||||
|
|
||||||
|
b.ToTable("ProfileSchedules");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CredentialManager.Models.ScheduleExecutionHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("AdditionalInfo")
|
||||||
|
.HasMaxLength(2000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DestinationInfo")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DestinationType")
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("EndTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("ErrorDetails")
|
||||||
|
.HasMaxLength(5000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Message")
|
||||||
|
.HasMaxLength(2000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ProfileName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("RecordsProcessed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("RecordsWithErrors")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ScheduleId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("SourceInfo")
|
||||||
|
.HasMaxLength(500)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SourceType")
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("StartTime")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Status")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(20)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TriggerType")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(20)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TriggeredBy")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId");
|
||||||
|
|
||||||
|
b.HasIndex("ScheduleId");
|
||||||
|
|
||||||
|
b.HasIndex("StartTime");
|
||||||
|
|
||||||
|
b.HasIndex("Status");
|
||||||
|
|
||||||
|
b.HasIndex("TriggerType");
|
||||||
|
|
||||||
|
b.ToTable("ScheduleExecutionHistories", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CredentialManager.Models.DataCouplerProfile", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("CredentialManager.Models.CredentialEntity", "DestinationCredential")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DestinationCredentialId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.HasOne("CredentialManager.Models.CredentialEntity", "SourceCredential")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("SourceCredentialId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("DestinationCredential");
|
||||||
|
|
||||||
|
b.Navigation("SourceCredential");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CredentialManager.Models.ProfileSchedule", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("CredentialManager.Models.DataCouplerProfile", "Profile")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Profile");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("CredentialManager.Models.ScheduleExecutionHistory", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("CredentialManager.Models.ProfileSchedule", "Schedule")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ScheduleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Schedule");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace CredentialManager.Data.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddDefaultValuesJsonToProfile : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "DefaultValuesJson",
|
||||||
|
table: "DataCouplerProfiles",
|
||||||
|
type: "TEXT",
|
||||||
|
maxLength: 4000,
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DefaultValuesJson",
|
||||||
|
table: "DataCouplerProfiles");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -146,6 +146,10 @@ namespace CredentialManager.Migrations
|
|||||||
.HasMaxLength(100)
|
.HasMaxLength(100)
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("DefaultValuesJson")
|
||||||
|
.HasMaxLength(4000)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<string>("DeletionAction")
|
b.Property<string>("DeletionAction")
|
||||||
.HasMaxLength(20)
|
.HasMaxLength(20)
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|||||||
@@ -60,6 +60,11 @@ public class DataCouplerProfile
|
|||||||
[MaxLength(4000)]
|
[MaxLength(4000)]
|
||||||
public string? FieldMappingJson { get; set; }
|
public string? FieldMappingJson { get; set; }
|
||||||
|
|
||||||
|
// Default values per i campi di destinazione salvati come JSON
|
||||||
|
// Formato: { "DestinationField": { "Value": "defaultValue", "Type": "string" } }
|
||||||
|
[MaxLength(4000)]
|
||||||
|
public string? DefaultValuesJson { get; set; }
|
||||||
|
|
||||||
// External ID Relationships per Salesforce salvate come JSON
|
// External ID Relationships per Salesforce salvate come JSON
|
||||||
[MaxLength(4000)]
|
[MaxLength(4000)]
|
||||||
public string? ExternalIdRelationshipsJson { get; set; }
|
public string? ExternalIdRelationshipsJson { get; set; }
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ public class DataCouplerProfileDto
|
|||||||
// Mapping dei campi
|
// Mapping dei campi
|
||||||
public List<FieldMappingDto>? FieldMappings { get; set; }
|
public List<FieldMappingDto>? FieldMappings { get; set; }
|
||||||
|
|
||||||
|
// Default values per campi destinazione (FieldName -> (Value, Type))
|
||||||
|
public Dictionary<string, (object? Value, string? Type)>? DefaultValues { get; set; }
|
||||||
|
|
||||||
// External ID Relationships per Salesforce
|
// External ID Relationships per Salesforce
|
||||||
public List<ExternalIdRelationshipDto>? ExternalIdRelationships { get; set; }
|
public List<ExternalIdRelationshipDto>? ExternalIdRelationships { get; set; }
|
||||||
|
|
||||||
@@ -83,8 +86,15 @@ public class ExternalIdRelationshipDto
|
|||||||
public string SourceField { get; set; } = string.Empty;
|
public string SourceField { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>/// DTO per i valori di default
|
||||||
/// DTO per la visualizzazione di un profilo nella lista
|
/// </summary>
|
||||||
|
public class DefaultValueDto
|
||||||
|
{
|
||||||
|
public object? Value { get; set; }
|
||||||
|
public string? Type { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>/// DTO per la visualizzazione di un profilo nella lista
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DataCouplerProfileSummaryDto
|
public class DataCouplerProfileSummaryDto
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace CredentialManager.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Tipo di mapping field
|
||||||
|
/// </summary>
|
||||||
|
public enum MappingType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Mapping da campo sorgente a campo destinazione
|
||||||
|
/// </summary>
|
||||||
|
FieldMapping,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Valore di default per campo destinazione
|
||||||
|
/// </summary>
|
||||||
|
DefaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rappresenta una voce di mapping che può essere:
|
||||||
|
/// - Un mapping da campo sorgente a campo destinazione
|
||||||
|
/// - Un valore di default per un campo destinazione
|
||||||
|
/// </summary>
|
||||||
|
public class FieldMappingEntry
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Tipo di mapping
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("type")]
|
||||||
|
public MappingType Type { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Nome del campo sorgente (solo per FieldMapping)
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("sourceField")]
|
||||||
|
public string? SourceField { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Nome del campo destinazione
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("destinationField")]
|
||||||
|
public string DestinationField { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Valore di default (solo per DefaultValue)
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("defaultValue")]
|
||||||
|
public object? DefaultValue { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tipo di dato del valore di default (per conversioni corrette)
|
||||||
|
/// Esempi: "string", "int", "decimal", "boolean", "datetime"
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("defaultValueType")]
|
||||||
|
public string? DefaultValueType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Crea un mapping da campo sorgente a campo destinazione
|
||||||
|
/// </summary>
|
||||||
|
public static FieldMappingEntry CreateFieldMapping(string sourceField, string destinationField)
|
||||||
|
{
|
||||||
|
return new FieldMappingEntry
|
||||||
|
{
|
||||||
|
Type = MappingType.FieldMapping,
|
||||||
|
SourceField = sourceField,
|
||||||
|
DestinationField = destinationField
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Crea un valore di default per un campo destinazione
|
||||||
|
/// </summary>
|
||||||
|
public static FieldMappingEntry CreateDefaultValue(string destinationField, object defaultValue, string? valueType = null)
|
||||||
|
{
|
||||||
|
return new FieldMappingEntry
|
||||||
|
{
|
||||||
|
Type = MappingType.DefaultValue,
|
||||||
|
DestinationField = destinationField,
|
||||||
|
DefaultValue = defaultValue,
|
||||||
|
DefaultValueType = valueType ?? InferValueType(defaultValue)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determina automaticamente il tipo del valore
|
||||||
|
/// </summary>
|
||||||
|
private static string InferValueType(object? value)
|
||||||
|
{
|
||||||
|
if (value == null) return "string";
|
||||||
|
|
||||||
|
return value switch
|
||||||
|
{
|
||||||
|
string _ => "string",
|
||||||
|
int _ => "int",
|
||||||
|
long _ => "long",
|
||||||
|
decimal _ => "decimal",
|
||||||
|
double _ => "double",
|
||||||
|
float _ => "float",
|
||||||
|
bool _ => "boolean",
|
||||||
|
DateTime _ => "datetime",
|
||||||
|
DateTimeOffset _ => "datetimeoffset",
|
||||||
|
_ => "string"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ottiene una descrizione user-friendly del mapping
|
||||||
|
/// </summary>
|
||||||
|
public string GetDescription()
|
||||||
|
{
|
||||||
|
return Type switch
|
||||||
|
{
|
||||||
|
MappingType.FieldMapping => $"{SourceField} → {DestinationField}",
|
||||||
|
MappingType.DefaultValue => $"{DestinationField} = {DefaultValue ?? "null"} ({DefaultValueType})",
|
||||||
|
_ => "Unknown"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper per la conversione tra vecchio formato (Dictionary) e nuovo formato (FieldMappingEntry)
|
||||||
|
/// </summary>
|
||||||
|
public static class MappingConverter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converte il vecchio formato Dictionary in lista di FieldMappingEntry
|
||||||
|
/// </summary>
|
||||||
|
public static List<FieldMappingEntry> FromDictionary(Dictionary<string, string> oldMappings)
|
||||||
|
{
|
||||||
|
var entries = new List<FieldMappingEntry>();
|
||||||
|
|
||||||
|
foreach (var mapping in oldMappings)
|
||||||
|
{
|
||||||
|
entries.Add(FieldMappingEntry.CreateFieldMapping(mapping.Key, mapping.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converte una lista di FieldMappingEntry nel vecchio formato Dictionary (solo field mappings)
|
||||||
|
/// </summary>
|
||||||
|
public static Dictionary<string, string> ToDictionary(List<FieldMappingEntry> entries)
|
||||||
|
{
|
||||||
|
var dictionary = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
foreach (var entry in entries.Where(e => e.Type == MappingType.FieldMapping && !string.IsNullOrEmpty(e.SourceField)))
|
||||||
|
{
|
||||||
|
dictionary[entry.SourceField!] = entry.DestinationField;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dictionary;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ottiene solo i valori di default da una lista di entries
|
||||||
|
/// </summary>
|
||||||
|
public static Dictionary<string, (object? Value, string? Type)> GetDefaultValues(List<FieldMappingEntry> entries)
|
||||||
|
{
|
||||||
|
var defaults = new Dictionary<string, (object?, string?)>();
|
||||||
|
|
||||||
|
foreach (var entry in entries.Where(e => e.Type == MappingType.DefaultValue))
|
||||||
|
{
|
||||||
|
defaults[entry.DestinationField] = (entry.DefaultValue, entry.DefaultValueType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaults;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ public class DataCouplerProfileService : IDataCouplerProfileService
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deserializza il JSON delle External ID Relationships
|
/// Deserializza il JSON delle External ID Relationships
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -236,6 +237,64 @@ public class DataCouplerProfileService : IDataCouplerProfileService
|
|||||||
return new List<ExternalIdRelationshipDto>();
|
return new List<ExternalIdRelationshipDto>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serializza i default values in JSON
|
||||||
|
/// </summary>
|
||||||
|
public string SerializeDefaultValues(Dictionary<string, (object? Value, string? Type)>? defaultValues)
|
||||||
|
{
|
||||||
|
if (defaultValues == null || !defaultValues.Any())
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
// Converti in un formato serializzabile (Dictionary<string, DefaultValueDto>)
|
||||||
|
var serializable = new Dictionary<string, DefaultValueDto>();
|
||||||
|
foreach (var entry in defaultValues)
|
||||||
|
{
|
||||||
|
serializable[entry.Key] = new DefaultValueDto
|
||||||
|
{
|
||||||
|
Value = entry.Value.Value,
|
||||||
|
Type = entry.Value.Type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsonSerializer.Serialize(serializable, new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deserializza il JSON dei default values
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, (object? Value, string? Type)> DeserializeDefaultValues(string? json)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(json))
|
||||||
|
return new Dictionary<string, (object?, string?)>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var deserialized = JsonSerializer.Deserialize<Dictionary<string, DefaultValueDto>>(json, new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||||
|
});
|
||||||
|
|
||||||
|
if (deserialized == null)
|
||||||
|
return new Dictionary<string, (object?, string?)>();
|
||||||
|
|
||||||
|
// Converti nel formato tuple
|
||||||
|
var result = new Dictionary<string, (object?, string?)>();
|
||||||
|
foreach (var entry in deserialized)
|
||||||
|
{
|
||||||
|
result[entry.Key] = (entry.Value.Value, entry.Value.Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new Dictionary<string, (object?, string?)>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converte un DataCouplerProfile in DTO
|
/// Converte un DataCouplerProfile in DTO
|
||||||
@@ -262,6 +321,7 @@ public class DataCouplerProfileService : IDataCouplerProfileService
|
|||||||
DestinationTable = profile.DestinationTable,
|
DestinationTable = profile.DestinationTable,
|
||||||
DestinationEndpoint = profile.DestinationEndpoint,
|
DestinationEndpoint = profile.DestinationEndpoint,
|
||||||
FieldMappings = DeserializeFieldMappings(profile.FieldMappingJson),
|
FieldMappings = DeserializeFieldMappings(profile.FieldMappingJson),
|
||||||
|
DefaultValues = DeserializeDefaultValues(profile.DefaultValuesJson),
|
||||||
ExternalIdRelationships = DeserializeExternalIdRelationships(profile.ExternalIdRelationshipsJson),
|
ExternalIdRelationships = DeserializeExternalIdRelationships(profile.ExternalIdRelationshipsJson),
|
||||||
SourceKeyField = profile.SourceKeyField,
|
SourceKeyField = profile.SourceKeyField,
|
||||||
UseRecordAssociations = profile.UseRecordAssociations
|
UseRecordAssociations = profile.UseRecordAssociations
|
||||||
@@ -291,6 +351,7 @@ public class DataCouplerProfileService : IDataCouplerProfileService
|
|||||||
DestinationTable = dto.DestinationTable,
|
DestinationTable = dto.DestinationTable,
|
||||||
DestinationEndpoint = dto.DestinationEndpoint,
|
DestinationEndpoint = dto.DestinationEndpoint,
|
||||||
FieldMappingJson = SerializeFieldMappings(dto.FieldMappings),
|
FieldMappingJson = SerializeFieldMappings(dto.FieldMappings),
|
||||||
|
DefaultValuesJson = SerializeDefaultValues(dto.DefaultValues),
|
||||||
ExternalIdRelationshipsJson = SerializeExternalIdRelationships(dto.ExternalIdRelationships),
|
ExternalIdRelationshipsJson = SerializeExternalIdRelationships(dto.ExternalIdRelationships),
|
||||||
SourceKeyField = dto.SourceKeyField,
|
SourceKeyField = dto.SourceKeyField,
|
||||||
UseRecordAssociations = dto.UseRecordAssociations,
|
UseRecordAssociations = dto.UseRecordAssociations,
|
||||||
|
|||||||
@@ -920,23 +920,80 @@
|
|||||||
<!-- Colonna Centrale: Controlli Mapping -->
|
<!-- Colonna Centrale: Controlli Mapping -->
|
||||||
<div class="col-2 text-center">
|
<div class="col-2 text-center">
|
||||||
<div class="d-flex flex-column justify-content-center h-100">
|
<div class="d-flex flex-column justify-content-center h-100">
|
||||||
<button class="btn btn-success mb-2" @onclick="CreateMapping"
|
<!-- Toggle tra Mapping e Default Value -->
|
||||||
disabled="@(string.IsNullOrEmpty(selectedDbColumn) || string.IsNullOrEmpty(selectedRestProperty))">
|
<div class="btn-group mb-3" role="group">
|
||||||
<i class="fas fa-arrow-right"></i>
|
<button type="button"
|
||||||
<small class="d-block">Map</small>
|
class="btn btn-sm @(isAddingDefaultValue ? "btn-outline-primary" : "btn-primary")"
|
||||||
</button>
|
@onclick="@(() => isAddingDefaultValue = false)">
|
||||||
<button class="btn btn-danger mb-2" @onclick="RemoveMapping"
|
<i class="fas fa-arrows-alt-h"></i>
|
||||||
disabled="@(string.IsNullOrEmpty(selectedDbColumn) || !fieldMappings.ContainsKey(selectedDbColumn))">
|
<small class="d-block">Mapping</small>
|
||||||
<i class="fas fa-times"></i>
|
</button>
|
||||||
<small class="d-block">Remove</small>
|
<button type="button"
|
||||||
</button>
|
class="btn btn-sm @(isAddingDefaultValue ? "btn-warning" : "btn-outline-warning")"
|
||||||
<button class="btn btn-warning mb-2" @onclick="AutoMapFields">
|
@onclick="@(() => isAddingDefaultValue = true)">
|
||||||
<i class="fas fa-magic"></i>
|
<i class="fas fa-file-alt"></i>
|
||||||
<small class="d-block">Auto</small>
|
<small class="d-block">Default</small>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Controlli per Mapping Normale -->
|
||||||
|
@if (!isAddingDefaultValue)
|
||||||
|
{
|
||||||
|
<button class="btn btn-success mb-2" @onclick="CreateMapping"
|
||||||
|
disabled="@(string.IsNullOrEmpty(selectedDbColumn) || string.IsNullOrEmpty(selectedRestProperty))">
|
||||||
|
<i class="fas fa-arrow-right"></i>
|
||||||
|
<small class="d-block">Map</small>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-danger mb-2" @onclick="RemoveMapping"
|
||||||
|
disabled="@(string.IsNullOrEmpty(selectedDbColumn) || !fieldMappings.ContainsKey(selectedDbColumn))">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
<small class="d-block">Remove</small>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-warning mb-2" @onclick="AutoMapFields">
|
||||||
|
<i class="fas fa-magic"></i>
|
||||||
|
<small class="d-block">Auto</small>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<!-- Controlli per Default Value -->
|
||||||
|
<div class="mb-2">
|
||||||
|
<small class="text-muted d-block mb-1">Tipo Valore:</small>
|
||||||
|
<select class="form-select form-select-sm mb-2" @bind="defaultValueType">
|
||||||
|
<option value="string">String</option>
|
||||||
|
<option value="int">Integer</option>
|
||||||
|
<option value="decimal">Decimal</option>
|
||||||
|
<option value="boolean">Boolean</option>
|
||||||
|
<option value="datetime">DateTime</option>
|
||||||
|
</select>
|
||||||
|
<input type="text" class="form-control form-control-sm mb-2"
|
||||||
|
placeholder="Valore default..."
|
||||||
|
@bind="defaultValueInput" />
|
||||||
|
<small class="text-muted d-block mb-2">
|
||||||
|
@if (defaultValueType == "datetime")
|
||||||
|
{
|
||||||
|
<span>Es: @DateTime.Now.ToString("yyyy-MM-dd")</span>
|
||||||
|
}
|
||||||
|
else if (defaultValueType == "boolean")
|
||||||
|
{
|
||||||
|
<span>Es: true o false</span>
|
||||||
|
}
|
||||||
|
else if (defaultValueType == "decimal")
|
||||||
|
{
|
||||||
|
<span>Es: 100.50</span>
|
||||||
|
}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-warning mb-2" @onclick="CreateDefaultValue"
|
||||||
|
disabled="@(string.IsNullOrEmpty(selectedRestProperty) || string.IsNullOrEmpty(defaultValueInput))">
|
||||||
|
<i class="fas fa-check"></i>
|
||||||
|
<small class="d-block">Set Default</small>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
|
||||||
<button class="btn btn-secondary" @onclick="ClearAllMappings">
|
<button class="btn btn-secondary" @onclick="ClearAllMappings">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
<small class="d-block">Clear</small>
|
<small class="d-block">Clear All</small>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -965,6 +1022,10 @@
|
|||||||
{
|
{
|
||||||
<span class="badge bg-success">Mapped</span>
|
<span class="badge bg-success">Mapped</span>
|
||||||
}
|
}
|
||||||
|
@if (defaultValues.ContainsKey(property.Name))
|
||||||
|
{
|
||||||
|
<span class="badge bg-warning text-dark">Default</span>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
@@ -1087,11 +1148,11 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<!-- Sezione Mappature Correnti --> @if (fieldMappings.Any())
|
<!-- Sezione Mappature Correnti --> @if (fieldMappings.Any() || defaultValues.Any())
|
||||||
{
|
{
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
<h6>Mappature Correnti (@fieldMappings.Count)</h6>
|
<h6>Configurazione Mapping (@(fieldMappings.Count + defaultValues.Count) totali)</h6>
|
||||||
@if (keyFields.Any())
|
@if (keyFields.Any())
|
||||||
{
|
{
|
||||||
<small class="text-info">
|
<small class="text-info">
|
||||||
@@ -1099,44 +1160,101 @@
|
|||||||
</small>
|
</small>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-sm table-striped">
|
<!-- Tabella Mapping Campi -->
|
||||||
<thead>
|
@if (fieldMappings.Any())
|
||||||
<tr>
|
{
|
||||||
<th>Campo Database</th>
|
<div class="card mb-3">
|
||||||
<th>Tipo DB</th>
|
<div class="card-header bg-light">
|
||||||
<th>→</th>
|
<i class="fas fa-arrows-alt-h"></i> <strong>Field Mappings</strong> (@fieldMappings.Count)
|
||||||
<th>Proprietà REST</th>
|
</div>
|
||||||
<th>Tipo REST</th>
|
<div class="card-body p-0">
|
||||||
<th>Azioni</th>
|
<div class="table-responsive">
|
||||||
</tr>
|
<table class="table table-sm table-striped mb-0">
|
||||||
</thead>
|
<thead>
|
||||||
<tbody>
|
<tr>
|
||||||
@foreach (var mapping in fieldMappings)
|
<th>Campo Sorgente</th>
|
||||||
{
|
<th>Tipo Sorgente</th>
|
||||||
DbColumnInfo? dbColumn = null;
|
<th>→</th>
|
||||||
if (selectedSourceType == "database" && !string.IsNullOrEmpty(selectedTable))
|
<th>Campo Destinazione</th>
|
||||||
{
|
<th>Tipo Destinazione</th>
|
||||||
dbColumn = databaseTables.ContainsKey(selectedTable) ?
|
<th>Azioni</th>
|
||||||
databaseTables[selectedTable].FirstOrDefault(c => c.Name == mapping.Key) : null;
|
</tr>
|
||||||
}
|
</thead>
|
||||||
var restProperty = restEntityDetails?.Properties.FirstOrDefault(p => p.Name == mapping.Value);
|
<tbody>
|
||||||
<tr>
|
@foreach (var mapping in fieldMappings)
|
||||||
<td><strong>@mapping.Key</strong></td>
|
{
|
||||||
<td><small class="text-muted">@(dbColumn?.DataType ?? (selectedSourceType == "file" ? "Text" : "Unknown"))</small></td>
|
DbColumnInfo? dbColumn = null;
|
||||||
<td><i class="fas fa-arrow-right text-success"></i></td>
|
if (selectedSourceType == "database" && !string.IsNullOrEmpty(selectedTable))
|
||||||
<td><strong>@mapping.Value</strong></td>
|
{
|
||||||
<td><small class="text-muted">@(restProperty?.Type ?? "Unknown")</small></td>
|
dbColumn = databaseTables.ContainsKey(selectedTable) ?
|
||||||
<td>
|
databaseTables[selectedTable].FirstOrDefault(c => c.Name == mapping.Key) : null;
|
||||||
<button class="btn btn-sm btn-danger" @onclick="@(() => RemoveSpecificMapping(mapping.Key))">
|
}
|
||||||
<i class="fas fa-trash"></i>
|
var restProperty = restEntityDetails?.Properties.FirstOrDefault(p => p.Name == mapping.Value);
|
||||||
</button>
|
<tr>
|
||||||
</td>
|
<td><strong>@mapping.Key</strong></td>
|
||||||
</tr>
|
<td><small class="text-muted">@(dbColumn?.DataType ?? (selectedSourceType == "file" ? "Text" : "Unknown"))</small></td>
|
||||||
}
|
<td><i class="fas fa-arrow-right text-success"></i></td>
|
||||||
</tbody>
|
<td><strong>@mapping.Value</strong></td>
|
||||||
</table>
|
<td><small class="text-muted">@(restProperty?.Type ?? "Unknown")</small></td>
|
||||||
</div>
|
<td>
|
||||||
|
<button class="btn btn-sm btn-danger" @onclick="@(() => RemoveSpecificMapping(mapping.Key))">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Tabella Default Values -->
|
||||||
|
@if (defaultValues.Any())
|
||||||
|
{
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header bg-warning text-dark">
|
||||||
|
<i class="fas fa-file-alt"></i> <strong>Default Values</strong> (@defaultValues.Count)
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-sm table-striped mb-0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Campo Destinazione</th>
|
||||||
|
<th>Valore Default</th>
|
||||||
|
<th>Tipo Valore</th>
|
||||||
|
<th>Tipo Campo REST</th>
|
||||||
|
<th>Azioni</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var defaultValue in defaultValues)
|
||||||
|
{
|
||||||
|
var restProperty = restEntityDetails?.Properties.FirstOrDefault(p => p.Name == defaultValue.Key);
|
||||||
|
var (value, valueType) = defaultValue.Value;
|
||||||
|
<tr>
|
||||||
|
<td><strong>@defaultValue.Key</strong></td>
|
||||||
|
<td><code>@(value?.ToString() ?? "null")</code></td>
|
||||||
|
<td>
|
||||||
|
<span class="badge bg-info">@valueType</span>
|
||||||
|
</td>
|
||||||
|
<td><small class="text-muted">@(restProperty?.Type ?? "Unknown")</small></td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-sm btn-danger" @onclick="@(() => RemoveDefaultValue(defaultValue.Key))">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1314,6 +1432,7 @@
|
|||||||
DestinationCredentialName="@selectedRestCredential"
|
DestinationCredentialName="@selectedRestCredential"
|
||||||
DestinationEndpoint="@selectedRestEntity?.Name"
|
DestinationEndpoint="@selectedRestEntity?.Name"
|
||||||
FieldMappings="@GetCurrentFieldMappings()"
|
FieldMappings="@GetCurrentFieldMappings()"
|
||||||
|
DefaultValues="@defaultValues"
|
||||||
ExternalIdRelationships="@externalIdRelationships"
|
ExternalIdRelationships="@externalIdRelationships"
|
||||||
SourceKeyField="@sourceKeyField"
|
SourceKeyField="@sourceKeyField"
|
||||||
UseRecordAssociations="@useRecordAssociations"
|
UseRecordAssociations="@useRecordAssociations"
|
||||||
|
|||||||
@@ -51,10 +51,18 @@ public partial class DataCoupler : ComponentBase
|
|||||||
(int)Math.Ceiling((double)fileData[sheetName].Count / pageSize) : 0;
|
(int)Math.Ceiling((double)fileData[sheetName].Count / pageSize) : 0;
|
||||||
|
|
||||||
// Mapping campi
|
// Mapping campi
|
||||||
private Dictionary<string, string> fieldMappings = new(); // DbColumn -> RestProperty
|
private Dictionary<string, string> fieldMappings = new(); // DbColumn -> RestProperty (legacy)
|
||||||
|
private List<FieldMappingEntry> fieldMappingEntries = new(); // New system: supporta sia mapping che default values
|
||||||
|
private Dictionary<string, (object? Value, string? Type)> defaultValues = new(); // DestinationField -> (DefaultValue, Type)
|
||||||
private HashSet<string> keyFields = new(); // REST properties marked as keys
|
private HashSet<string> keyFields = new(); // REST properties marked as keys
|
||||||
private string selectedDbColumn = "";
|
private string selectedDbColumn = "";
|
||||||
|
|
||||||
|
// UI per configurazione mapping/default value
|
||||||
|
private bool isAddingDefaultValue = false; // Toggle tra mapping normale e default value
|
||||||
|
private string defaultValueField = ""; // Campo destinazione per default value
|
||||||
|
private string defaultValueInput = ""; // Input utente per default value
|
||||||
|
private string defaultValueType = "string"; // Tipo del default value (string, int, decimal, boolean, datetime)
|
||||||
|
|
||||||
// External ID Relationships (Salesforce)
|
// External ID Relationships (Salesforce)
|
||||||
private List<ExternalIdRelationshipDto> externalIdRelationships = new();
|
private List<ExternalIdRelationshipDto> externalIdRelationships = new();
|
||||||
private string selectedRelationshipObject = "";
|
private string selectedRelationshipObject = "";
|
||||||
@@ -345,11 +353,13 @@ public partial class DataCoupler : ComponentBase
|
|||||||
|
|
||||||
// Applica i mapping
|
// Applica i mapping
|
||||||
fieldMappings.Clear();
|
fieldMappings.Clear();
|
||||||
|
fieldMappingEntries.Clear();
|
||||||
keyFields.Clear();
|
keyFields.Clear();
|
||||||
|
|
||||||
foreach (var mapping in mappings)
|
foreach (var mapping in mappings)
|
||||||
{
|
{
|
||||||
fieldMappings[mapping.SourceField] = mapping.DestinationField;
|
fieldMappings[mapping.SourceField] = mapping.DestinationField;
|
||||||
|
fieldMappingEntries.Add(FieldMappingEntry.CreateFieldMapping(mapping.SourceField, mapping.DestinationField));
|
||||||
if (mapping.IsKey)
|
if (mapping.IsKey)
|
||||||
{
|
{
|
||||||
keyFields.Add(mapping.DestinationField);
|
keyFields.Add(mapping.DestinationField);
|
||||||
@@ -370,6 +380,42 @@ public partial class DataCoupler : ComponentBase
|
|||||||
{
|
{
|
||||||
Logger.LogInformation("Nessun mapping campi da applicare");
|
Logger.LogInformation("Nessun mapping campi da applicare");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Step 4.5: Applica default values se disponibili
|
||||||
|
if (!string.IsNullOrEmpty(profile.DefaultValuesJson))
|
||||||
|
{
|
||||||
|
Logger.LogInformation("Step 4.5 - Applicazione default values...");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var deserializedDefaults = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, DefaultValueDto>>(
|
||||||
|
profile.DefaultValuesJson,
|
||||||
|
new System.Text.Json.JsonSerializerOptions { PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase });
|
||||||
|
|
||||||
|
if (deserializedDefaults != null)
|
||||||
|
{
|
||||||
|
defaultValues.Clear();
|
||||||
|
|
||||||
|
foreach (var entry in deserializedDefaults)
|
||||||
|
{
|
||||||
|
defaultValues[entry.Key] = (entry.Value.Value, entry.Value.Type);
|
||||||
|
fieldMappingEntries.Add(FieldMappingEntry.CreateDefaultValue(entry.Key, entry.Value.Value, entry.Value.Type));
|
||||||
|
|
||||||
|
Logger.LogInformation("Default value applicato: {Field} = {Value} ({Type})",
|
||||||
|
entry.Key, entry.Value.Value, entry.Value.Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.LogInformation("Default values applicati - Totale: {Count}", defaultValues.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogWarning(ex, "Errore nel caricamento dei default values dal profilo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.LogInformation("Nessun default value da applicare");
|
||||||
|
}
|
||||||
|
|
||||||
// Step 5: Applica configurazione chiave sorgente
|
// Step 5: Applica configurazione chiave sorgente
|
||||||
if (!string.IsNullOrEmpty(profile.SourceKeyField))
|
if (!string.IsNullOrEmpty(profile.SourceKeyField))
|
||||||
@@ -721,6 +767,8 @@ public partial class DataCoupler : ComponentBase
|
|||||||
ResetSourceState();
|
ResetSourceState();
|
||||||
ResetDestinationState();
|
ResetDestinationState();
|
||||||
fieldMappings.Clear();
|
fieldMappings.Clear();
|
||||||
|
fieldMappingEntries.Clear();
|
||||||
|
defaultValues.Clear();
|
||||||
keyFields.Clear();
|
keyFields.Clear();
|
||||||
externalIdRelationships.Clear(); // Reset relazioni
|
externalIdRelationships.Clear(); // Reset relazioni
|
||||||
transferResults.Clear();
|
transferResults.Clear();
|
||||||
@@ -1328,6 +1376,17 @@ public partial class DataCoupler : ComponentBase
|
|||||||
// Crea il nuovo mapping
|
// Crea il nuovo mapping
|
||||||
fieldMappings[selectedDbColumn] = selectedRestProperty;
|
fieldMappings[selectedDbColumn] = selectedRestProperty;
|
||||||
|
|
||||||
|
// Aggiorna anche la lista FieldMappingEntries
|
||||||
|
var existingEntry = fieldMappingEntries.FirstOrDefault(e =>
|
||||||
|
e.Type == CredentialManager.Models.MappingType.FieldMapping && e.SourceField == selectedDbColumn);
|
||||||
|
|
||||||
|
if (existingEntry != null)
|
||||||
|
{
|
||||||
|
fieldMappingEntries.Remove(existingEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldMappingEntries.Add(FieldMappingEntry.CreateFieldMapping(selectedDbColumn, selectedRestProperty));
|
||||||
|
|
||||||
Logger.LogInformation("Creato mapping: {DbColumn} -> {RestProperty}", selectedDbColumn, selectedRestProperty);
|
Logger.LogInformation("Creato mapping: {DbColumn} -> {RestProperty}", selectedDbColumn, selectedRestProperty);
|
||||||
|
|
||||||
// Deseleziona i campi
|
// Deseleziona i campi
|
||||||
@@ -1335,14 +1394,108 @@ public partial class DataCoupler : ComponentBase
|
|||||||
selectedRestProperty = "";
|
selectedRestProperty = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CreateDefaultValue()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(selectedRestProperty) || string.IsNullOrEmpty(defaultValueInput))
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Converti il valore nel tipo appropriato
|
||||||
|
object? convertedValue = ConvertDefaultValue(defaultValueInput, defaultValueType);
|
||||||
|
|
||||||
|
// Rimuovi eventuale default value esistente per questo campo
|
||||||
|
if (defaultValues.ContainsKey(selectedRestProperty))
|
||||||
|
{
|
||||||
|
defaultValues.Remove(selectedRestProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rimuovi anche dalla lista entries
|
||||||
|
var existingEntry = fieldMappingEntries.FirstOrDefault(e =>
|
||||||
|
e.Type == CredentialManager.Models.MappingType.DefaultValue && e.DestinationField == selectedRestProperty);
|
||||||
|
|
||||||
|
if (existingEntry != null)
|
||||||
|
{
|
||||||
|
fieldMappingEntries.Remove(existingEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggiungi il nuovo default value
|
||||||
|
defaultValues[selectedRestProperty] = (convertedValue, defaultValueType);
|
||||||
|
fieldMappingEntries.Add(FieldMappingEntry.CreateDefaultValue(selectedRestProperty, convertedValue, defaultValueType));
|
||||||
|
|
||||||
|
Logger.LogInformation("Creato default value: {RestProperty} = {Value} ({Type})",
|
||||||
|
selectedRestProperty, convertedValue, defaultValueType);
|
||||||
|
|
||||||
|
// Reset campi
|
||||||
|
selectedRestProperty = "";
|
||||||
|
defaultValueInput = "";
|
||||||
|
isAddingDefaultValue = false;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError(ex, "Errore nella conversione del valore di default");
|
||||||
|
transferMessage = $"Errore: {ex.Message}";
|
||||||
|
transferMessageType = "error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object? ConvertDefaultValue(string input, string type)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(input))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return type.ToLower() switch
|
||||||
|
{
|
||||||
|
"string" => input,
|
||||||
|
"int" => int.Parse(input),
|
||||||
|
"long" => long.Parse(input),
|
||||||
|
"decimal" => decimal.Parse(input, System.Globalization.CultureInfo.InvariantCulture),
|
||||||
|
"double" => double.Parse(input, System.Globalization.CultureInfo.InvariantCulture),
|
||||||
|
"float" => float.Parse(input, System.Globalization.CultureInfo.InvariantCulture),
|
||||||
|
"boolean" => bool.Parse(input),
|
||||||
|
"datetime" => DateTime.Parse(input),
|
||||||
|
"datetimeoffset" => DateTimeOffset.Parse(input),
|
||||||
|
_ => input
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private void RemoveMapping()
|
private void RemoveMapping()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(selectedDbColumn) || !fieldMappings.ContainsKey(selectedDbColumn))
|
if (string.IsNullOrEmpty(selectedDbColumn) || !fieldMappings.ContainsKey(selectedDbColumn))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fieldMappings.Remove(selectedDbColumn);
|
fieldMappings.Remove(selectedDbColumn);
|
||||||
|
|
||||||
|
// Rimuovi anche dalla lista entries
|
||||||
|
var entry = fieldMappingEntries.FirstOrDefault(e =>
|
||||||
|
e.Type == CredentialManager.Models.MappingType.FieldMapping && e.SourceField == selectedDbColumn);
|
||||||
|
if (entry != null)
|
||||||
|
{
|
||||||
|
fieldMappingEntries.Remove(entry);
|
||||||
|
}
|
||||||
|
|
||||||
Logger.LogInformation("Rimosso mapping per campo: {DbColumn}", selectedDbColumn);
|
Logger.LogInformation("Rimosso mapping per campo: {DbColumn}", selectedDbColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RemoveDefaultValue(string destinationField)
|
||||||
|
{
|
||||||
|
if (defaultValues.ContainsKey(destinationField))
|
||||||
|
{
|
||||||
|
defaultValues.Remove(destinationField);
|
||||||
|
|
||||||
|
// Rimuovi anche dalla lista entries
|
||||||
|
var entry = fieldMappingEntries.FirstOrDefault(e =>
|
||||||
|
e.Type == CredentialManager.Models.MappingType.DefaultValue && e.DestinationField == destinationField);
|
||||||
|
if (entry != null)
|
||||||
|
{
|
||||||
|
fieldMappingEntries.Remove(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.LogInformation("Rimosso default value per campo: {Field}", destinationField);
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void RemoveSpecificMapping(string dbColumn)
|
private void RemoveSpecificMapping(string dbColumn)
|
||||||
{
|
{
|
||||||
if (fieldMappings.ContainsKey(dbColumn))
|
if (fieldMappings.ContainsKey(dbColumn))
|
||||||
@@ -1351,20 +1504,22 @@ public partial class DataCoupler : ComponentBase
|
|||||||
Logger.LogInformation("Rimosso mapping specifico per campo: {DbColumn}", dbColumn);
|
Logger.LogInformation("Rimosso mapping specifico per campo: {DbColumn}", dbColumn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger.LogInformation("Rimosso mapping specifico per campo: {DbColumn}", dbColumn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ClearAllMappings()
|
private void ClearAllMappings()
|
||||||
{
|
{
|
||||||
fieldMappings.Clear();
|
fieldMappings.Clear();
|
||||||
|
fieldMappingEntries.Clear();
|
||||||
|
defaultValues.Clear();
|
||||||
selectedDbColumn = "";
|
selectedDbColumn = "";
|
||||||
selectedRestProperty = "";
|
selectedRestProperty = "";
|
||||||
sourceKeyField = "";
|
sourceKeyField = "";
|
||||||
transferMessage = "";
|
transferMessage = "";
|
||||||
transferMessageType = "";
|
transferMessageType = "";
|
||||||
|
isAddingDefaultValue = false;
|
||||||
|
defaultValueField = "";
|
||||||
|
defaultValueInput = "";
|
||||||
externalIdRelationships.Clear(); // Pulisce anche le relazioni
|
externalIdRelationships.Clear(); // Pulisce anche le relazioni
|
||||||
Logger.LogInformation("Tutti i mapping e le configurazioni sono stati cancellati");
|
Logger.LogInformation("Tutti i mapping, default values e le configurazioni sono stati cancellati");
|
||||||
}
|
}
|
||||||
|
|
||||||
// External ID Relationships Methods
|
// External ID Relationships Methods
|
||||||
@@ -2108,6 +2263,7 @@ public partial class DataCoupler : ComponentBase
|
|||||||
.Select(r => r.SourceField)
|
.Select(r => r.SourceField)
|
||||||
.ToHashSet();
|
.ToHashSet();
|
||||||
|
|
||||||
|
// STEP 1: Applica i mapping normali (campo sorgente -> campo destinazione)
|
||||||
foreach (var mapping in fieldMappings)
|
foreach (var mapping in fieldMappings)
|
||||||
{
|
{
|
||||||
string dbColumn = mapping.Key;
|
string dbColumn = mapping.Key;
|
||||||
@@ -2134,7 +2290,29 @@ public partial class DataCoupler : ComponentBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aggiungi External ID Relationships (per Salesforce)
|
// STEP 2: Applica i valori di default per i campi NON ancora popolati
|
||||||
|
foreach (var defaultValue in defaultValues)
|
||||||
|
{
|
||||||
|
string destinationField = defaultValue.Key;
|
||||||
|
var (value, valueType) = defaultValue.Value;
|
||||||
|
|
||||||
|
// Applica il default value solo se il campo non è già stato popolato dal mapping
|
||||||
|
if (!restData.ContainsKey(destinationField))
|
||||||
|
{
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
restData[destinationField] = value;
|
||||||
|
Logger.LogDebug("Applicato default value: {Field} = {Value} ({Type})",
|
||||||
|
destinationField, value, valueType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.LogDebug("Campo {Field} già popolato da mapping, default value ignorato", destinationField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 3: Aggiungi External ID Relationships (per Salesforce)
|
||||||
if (externalIdRelationships.Any())
|
if (externalIdRelationships.Any())
|
||||||
{
|
{
|
||||||
foreach (var relationship in externalIdRelationships)
|
foreach (var relationship in externalIdRelationships)
|
||||||
@@ -2163,9 +2341,10 @@ public partial class DataCoupler : ComponentBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.LogDebug("Record trasformato: {DbColumns} → {RestProperties}",
|
Logger.LogDebug("Record trasformato: {DbColumns} → {RestProperties} (inclusi {DefaultCount} default values)",
|
||||||
string.Join(", ", dbRecord.Keys),
|
string.Join(", ", dbRecord.Keys),
|
||||||
string.Join(", ", restData.Keys));
|
string.Join(", ", restData.Keys),
|
||||||
|
defaultValues.Count(dv => restData.ContainsKey(dv.Key)));
|
||||||
|
|
||||||
return restData;
|
return restData;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user