Merge branch 'develop' of https://gitlab.steamware.net/etis/lux into develop
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
Task<bool> AddAsync(VocabolarioModel entity);
|
||||
|
||||
/// <summary>
|
||||
/// Clona un Vocabolario dalla linga originale a quella target
|
||||
/// Clona un vocabolario data lingua origine/destinazione
|
||||
/// </summary>
|
||||
/// <param name="linguaOrig"></param>
|
||||
/// <param name="linguaDest"></param>
|
||||
@@ -46,11 +46,28 @@
|
||||
Task<List<VocabolarioModel>> GetByLang(string lingua);
|
||||
|
||||
/// <summary>
|
||||
/// Recuperoelenco lingue
|
||||
/// Recupero elenco lingue
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<LinguaModel>> ListLingueAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Recupera un dizionario lemma->traduzione per una data lingua (sync, via CreateDbContext).
|
||||
/// Usato per caricamenti sincroni da FusionCache factory.
|
||||
/// </summary>
|
||||
Dictionary<string, string> GetDizionarioLinguaSync(string lingua);
|
||||
|
||||
/// <summary>
|
||||
/// Recupera un dizionario lemma->traduzione per una data lingua (async).
|
||||
/// </summary>
|
||||
Task<Dictionary<string, string>> GetDizionarioLinguaAsync(string lingua);
|
||||
|
||||
/// <summary>
|
||||
/// Inserisce un record Vocabolario usando DbContext sincrono.
|
||||
/// Usato per autogrowth del dizionario in Traduci().
|
||||
/// </summary>
|
||||
bool InsertSync(VocabolarioModel entity);
|
||||
|
||||
/// <summary>
|
||||
/// Aggiorna un record Vocabolario esistente nel database.
|
||||
/// </summary>
|
||||
|
||||
@@ -117,6 +117,32 @@
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, string> GetDizionarioLinguaSync(string lingua)
|
||||
{
|
||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
||||
return dbCtx.DbSetVocabolario
|
||||
.Where(x => x.Lingua == lingua)
|
||||
.ToDictionary(d => d.Lemma, d => d.Traduzione);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Dictionary<string, string>> GetDizionarioLinguaAsync(string lingua)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetVocabolario
|
||||
.Where(x => x.Lingua == lingua)
|
||||
.ToDictionaryAsync(d => d.Lemma, d => d.Traduzione);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool InsertSync(VocabolarioModel entity)
|
||||
{
|
||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
||||
dbCtx.DbSetVocabolario.Add(entity);
|
||||
return dbCtx.SaveChanges() > 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> UpdateAsync(VocabolarioModel entity)
|
||||
{
|
||||
|
||||
@@ -30,6 +30,20 @@
|
||||
/// <returns></returns>
|
||||
Task<bool> FlushFusionCacheAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Cancellazione FusionCache dato tag
|
||||
/// </summary>
|
||||
/// <param name="tag"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> FlushFusionCacheAsync(string tag);
|
||||
|
||||
/// <summary>
|
||||
/// Cancellazione FusionCache data lista tag
|
||||
/// </summary>
|
||||
/// <param name="listTags"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> FlushFusionCacheAsync(List<string> listTags);
|
||||
|
||||
/// <summary>
|
||||
/// Recupera un Vocabolario per ID
|
||||
/// </summary>
|
||||
|
||||
@@ -2,11 +2,6 @@
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Services.Admin
|
||||
{
|
||||
/// <summary>
|
||||
/// Service per la gestione del vocabolario traduzioni interfaccia.
|
||||
/// Il dizionario viene caricato in-memory all'avvio dal BackgroundService.
|
||||
/// Ogni modifica CRUD aggiorna il dizionario senza passare per Redis.
|
||||
/// </summary>
|
||||
public class VocabolarioService : BaseServ, IVocabolarioService
|
||||
{
|
||||
#region Public Constructors
|
||||
@@ -14,12 +9,13 @@ namespace EgwCoreLib.Lux.Data.Services.Admin
|
||||
public VocabolarioService(
|
||||
IConfiguration config,
|
||||
IConnectionMultiplexer redis,
|
||||
IFusionCache cache,
|
||||
IDbContextFactory<DataLayerContext> factory) : base(config, redis)
|
||||
IVocabolarioRepository repo,
|
||||
IFusionCache cache) : base(config, redis)
|
||||
{
|
||||
_className = "Vocabolario";
|
||||
slowLogThresh = config.GetValue<double>("ServerConf:slowLogThresh", 1);
|
||||
_repo = repo;
|
||||
_cache = cache;
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
@@ -31,58 +27,27 @@ namespace EgwCoreLib.Lux.Data.Services.Admin
|
||||
{
|
||||
return await TraceAsync($"{_className}.Clone", async (activity) =>
|
||||
{
|
||||
var ctx = await _factory.CreateDbContextAsync();
|
||||
var list = await ctx.DbSetVocabolario
|
||||
.Where(x => x.Lingua == linguaOrig)
|
||||
.ToListAsync();
|
||||
bool result = await _repo.CloneAsync(linguaOrig, linguaDest);
|
||||
|
||||
if (!list.Any()) return false;
|
||||
|
||||
await using var tx = await ctx.Database.BeginTransactionAsync();
|
||||
bool done = false;
|
||||
try
|
||||
if (result)
|
||||
{
|
||||
var recLang = await ctx.DbSetLingua.FirstOrDefaultAsync(x => x.Lingua == linguaDest);
|
||||
if (recLang == null)
|
||||
{
|
||||
recLang = new LinguaModel { Lingua = linguaDest, Note = $"Cloned from {linguaOrig}" };
|
||||
await ctx.DbSetLingua.AddAsync(recLang);
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
|
||||
var listNew = list.Select(x => new VocabolarioModel
|
||||
{
|
||||
Lingua = linguaDest,
|
||||
Lemma = x.Lemma,
|
||||
Traduzione = x.Traduzione
|
||||
}).ToList();
|
||||
|
||||
ctx.DbSetVocabolario.AddRange(listNew);
|
||||
done = await ctx.SaveChangesAsync() > 0;
|
||||
await tx.CommitAsync();
|
||||
await FlushFusionCacheAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
return done;
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> DeleteAsync(VocabolarioModel rec2del)
|
||||
public async Task<bool> DeleteAsync(VocabolarioModel model)
|
||||
{
|
||||
return await TraceAsync($"{_className}.Delete", async (activity) =>
|
||||
{
|
||||
var ctx = await _factory.CreateDbContextAsync();
|
||||
var dbRec = await ctx.DbSetVocabolario
|
||||
.FirstOrDefaultAsync(x => x.Lingua == rec2del.Lingua && x.Lemma == rec2del.Lemma);
|
||||
bool success = await _repo.DeleteAsync(model);
|
||||
|
||||
if (dbRec == null) return false;
|
||||
|
||||
ctx.DbSetVocabolario.Remove(dbRec);
|
||||
bool success = await ctx.SaveChangesAsync() > 0;
|
||||
if (success)
|
||||
{
|
||||
await FlushFusionCacheAsync();
|
||||
}
|
||||
return success;
|
||||
});
|
||||
}
|
||||
@@ -94,67 +59,75 @@ namespace EgwCoreLib.Lux.Data.Services.Admin
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> FlushFusionCacheAsync(string tag)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(tag)) return false;
|
||||
|
||||
await _cache.RemoveByTagAsync(tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> FlushFusionCacheAsync(List<string> listTags)
|
||||
{
|
||||
if (listTags == null || listTags.Count == 0) return false;
|
||||
|
||||
// Generiamo i Task di rimozione ed eseguiamoli in parallelo su Redis/L1
|
||||
var tasks = listTags
|
||||
.Where(tag => !string.IsNullOrWhiteSpace(tag))
|
||||
.Select(tag => _cache.RemoveByTagAsync(tag).AsTask());
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<VocabolarioModel>> GetAllAsync()
|
||||
{
|
||||
return await TraceAsync($"{_className}.GetAllAsync", async (activity) =>
|
||||
{
|
||||
return await GetOrSetCacheAsync(
|
||||
$"{_redisBaseKey}:{_className}:ALL",
|
||||
async () =>
|
||||
{
|
||||
var ctx = await _factory.CreateDbContextAsync();
|
||||
return await ctx.DbSetVocabolario.ToListAsync();
|
||||
}
|
||||
);
|
||||
});
|
||||
return await GetOrFetchAsync(
|
||||
"GetAllAsync",
|
||||
$"{_redisBaseKey}:{_className}:ALL",
|
||||
() => _repo.GetAllAsync(),
|
||||
base.LongCache,
|
||||
_className
|
||||
);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<VocabolarioModel?> GetByIdAsync(string lingua, string lemma)
|
||||
{
|
||||
return await TraceAsync($"{_className}.GetById", async (activity) =>
|
||||
{
|
||||
return await GetOrSetCacheAsync(
|
||||
$"{_redisBaseKey}:{_className}:GetById:{lingua}:{lemma}",
|
||||
async () =>
|
||||
{
|
||||
var ctx = await _factory.CreateDbContextAsync();
|
||||
return await ctx.DbSetVocabolario
|
||||
.FirstOrDefaultAsync(x => x.Lingua == lingua && x.Lemma == lemma);
|
||||
}
|
||||
);
|
||||
});
|
||||
return await GetOrFetchAsync(
|
||||
"GetByIdAsync",
|
||||
$"{_redisBaseKey}:{_className}:GetById:{lingua}:{lemma}",
|
||||
() => _repo.GetByIdAsync(lingua, lemma),
|
||||
base.LongCache,
|
||||
_className
|
||||
);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<VocabolarioModel>> GetByLang(string lingua)
|
||||
{
|
||||
// Fallback: DB + Redis cache
|
||||
return await GetOrSetCacheAsync(
|
||||
return await GetOrFetchAsync(
|
||||
"GetByLang",
|
||||
$"{_redisBaseKey}:{_className}:GetByLang:{lingua}",
|
||||
async () =>
|
||||
{
|
||||
var ctx = await _factory.CreateDbContextAsync();
|
||||
return await ctx.DbSetVocabolario.Where(o => o.Lingua == lingua).ToListAsync();
|
||||
}
|
||||
() => _repo.GetByLang(lingua),
|
||||
base.LongCache,
|
||||
_className
|
||||
);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<LinguaModel>> ListLingueAsync()
|
||||
{
|
||||
return await TraceAsync($"{_className}.ListLingueAsync", async (activity) =>
|
||||
{
|
||||
return await GetOrSetCacheAsync(
|
||||
$"{_redisBaseKey}:{_className}:Lingue",
|
||||
async () =>
|
||||
{
|
||||
var ctx = await _factory.CreateDbContextAsync();
|
||||
return await ctx.DbSetLingua.ToListAsync();
|
||||
}
|
||||
);
|
||||
});
|
||||
return await GetOrFetchAsync(
|
||||
"ListLingueAsync",
|
||||
$"{_redisBaseKey}:{_className}:Lingue",
|
||||
() => _repo.ListLingueAsync(),
|
||||
base.LongCache,
|
||||
_className
|
||||
);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -166,49 +139,46 @@ namespace EgwCoreLib.Lux.Data.Services.Admin
|
||||
string linguaKey = lingua.ToLowerInvariant().Trim();
|
||||
string cacheKey = $"vocab:{linguaKey}";
|
||||
|
||||
var ctx = _factory.CreateDbContext();
|
||||
// preparo opzioni
|
||||
var cacheOptions = new FusionCacheEntryOptions()
|
||||
.SetDuration(TimeSpan.FromMinutes(5))
|
||||
.SetFailSafe(true, TimeSpan.FromMinutes(15));
|
||||
// preparo tags
|
||||
List<string> tagsList = new List<string>() { _className };
|
||||
|
||||
// FusionCache gestisce il lock e recupera l'intero dizionario della lingua.
|
||||
// Se è in L1 (Memory), restituisce l'oggetto C# istantaneamente.
|
||||
// Se non c'è, passa a L2 (Redis) o invoca la factory per caricarlo.
|
||||
// FusionCache gestisce lock + L1 memory + L2 redis
|
||||
// Il factory usa repo.GetDizionarioLinguaSync (CreateDbContext sync)
|
||||
var dizionarioLingua = _cache.GetOrSet<Dictionary<string, string>>(
|
||||
cacheKey,
|
||||
_ => ctx
|
||||
.DbSetVocabolario
|
||||
.Where(x => x.Lingua == linguaKey)
|
||||
.ToDictionary(d => d.Lemma, d => d.Traduzione),
|
||||
options => options
|
||||
//.SetDuration(TimeSpan.FromHours(8)) // Durata logica della cache
|
||||
//.SetFailSafe(true, TimeSpan.FromHours(1)) // Se Redis/DB è giù, usa i vecchi dati L1
|
||||
.SetDuration(TimeSpan.FromMinutes(5)) // Durata logica della cache
|
||||
.SetFailSafe(true, TimeSpan.FromMinutes(15)) // Se Redis/DB è giù, usa i vecchi dati L1
|
||||
_ => _repo.GetDizionarioLinguaSync(linguaKey),
|
||||
options: cacheOptions,
|
||||
tags: tagsList
|
||||
);
|
||||
|
||||
// Ricerca O(1) nel dizionario in memoria
|
||||
if (dizionarioLingua != null && dizionarioLingua.TryGetValue(lemma, out var traduzione))
|
||||
{
|
||||
return traduzione;
|
||||
}
|
||||
|
||||
// Fallback: se la parola non è censita inserisce su DB
|
||||
// Lemma non trovato: inserisco nel DB e aggiornero la cache
|
||||
string answ = $"[[{lingua}_{lemma}]]";
|
||||
var newRec = new VocabolarioModel()
|
||||
{
|
||||
Lingua = lingua,
|
||||
Lemma = lemma,
|
||||
Traduzione = answ
|
||||
};
|
||||
try
|
||||
{
|
||||
ctx.DbSetVocabolario.Add(newRec);
|
||||
ctx.SaveChanges();
|
||||
_repo.InsertSync(new VocabolarioModel
|
||||
{
|
||||
Lingua = lingua,
|
||||
Lemma = lemma,
|
||||
Traduzione = answ
|
||||
});
|
||||
// svuoto cache...
|
||||
//_cache.Clear(allowFailSafe: false);
|
||||
FlushFusionCache(_className);
|
||||
}
|
||||
catch (Exception exc)
|
||||
catch
|
||||
{
|
||||
Log.Error(exc);
|
||||
// Silenzio: il lemma non è stato inserito
|
||||
}
|
||||
|
||||
// ...e restituisce il lemma originale (lingua + lemma)
|
||||
return answ;
|
||||
}
|
||||
|
||||
@@ -217,25 +187,27 @@ namespace EgwCoreLib.Lux.Data.Services.Admin
|
||||
{
|
||||
return await TraceAsync($"{_className}.Upsert", async (activity) =>
|
||||
{
|
||||
var ctx = await _factory.CreateDbContextAsync();
|
||||
var currRec = await ctx.DbSetVocabolario
|
||||
.FirstOrDefaultAsync(x => x.Lingua == upsRec.Lingua && x.Lemma == upsRec.Lemma);
|
||||
var currRec = await _repo.GetByIdAsync(upsRec.Lingua, upsRec.Lemma);
|
||||
|
||||
string operation = "UPDATE";
|
||||
bool success = false;
|
||||
if (currRec != null)
|
||||
{
|
||||
ctx.Entry(currRec).CurrentValues.SetValues(upsRec);
|
||||
success = await ctx.SaveChangesAsync() > 0;
|
||||
success = await _repo.UpdateAsync(upsRec);
|
||||
}
|
||||
else
|
||||
{
|
||||
operation = "INSERT";
|
||||
await ctx.DbSetVocabolario.AddAsync(upsRec);
|
||||
success = await ctx.SaveChangesAsync() > 0;
|
||||
success = await _repo.AddAsync(upsRec);
|
||||
}
|
||||
|
||||
activity?.SetTag("db.operation", operation);
|
||||
|
||||
if (success)
|
||||
{
|
||||
await FlushFusionCacheAsync();
|
||||
}
|
||||
|
||||
return success;
|
||||
});
|
||||
}
|
||||
@@ -245,62 +217,122 @@ namespace EgwCoreLib.Lux.Data.Services.Admin
|
||||
{
|
||||
return await TraceAsync($"{_className}.UpsertMany", async (activity) =>
|
||||
{
|
||||
var ctx = await _factory.CreateDbContextAsync();
|
||||
|
||||
var listLang = upsList.Select(d => d.Lingua).Distinct().ToList();
|
||||
var listLemmi = upsList.Select(d => d.Lemma).Distinct().ToList();
|
||||
var dbList = await ctx.DbSetVocabolario
|
||||
.Where(t => listLang.Contains(t.Lingua) && listLemmi.Contains(t.Lemma))
|
||||
.ToListAsync();
|
||||
|
||||
var listExist = dbList
|
||||
.Where(t => upsList.Any(d => d.Lingua == t.Lingua && d.Lemma == t.Lemma))
|
||||
.ToList();
|
||||
|
||||
foreach (var dto in upsList)
|
||||
{
|
||||
var existing = listExist
|
||||
.FirstOrDefault(r => r.Lingua == dto.Lingua && r.Lemma == dto.Lemma);
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
existing.Traduzione = dto.Traduzione;
|
||||
}
|
||||
else
|
||||
{
|
||||
await ctx.DbSetVocabolario.AddAsync(new VocabolarioModel
|
||||
{
|
||||
Lingua = dto.Lingua,
|
||||
Lemma = dto.Lemma,
|
||||
Traduzione = dto.Traduzione
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
string operation = "MERGE";
|
||||
bool success = await ctx.SaveChangesAsync() > 0;
|
||||
bool success = await _repo.UpsertManyAsync(upsList);
|
||||
|
||||
activity?.SetTag("db.operation", operation);
|
||||
|
||||
if (success)
|
||||
{
|
||||
await FlushFusionCacheAsync();
|
||||
}
|
||||
|
||||
return success;
|
||||
});
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Fields
|
||||
/// <summary>
|
||||
/// Soglia minima (ms) per log timing in console
|
||||
/// </summary>
|
||||
private double slowLogThresh = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Oggetto gestione FusionCache
|
||||
/// Implementa gestione FusionCache+ tracking attività
|
||||
/// - recupero cache da memoria o da obj esterno + cache memoria
|
||||
/// - recupero da fetchFunc se mancasse + store in cache L1/L2
|
||||
/// </summary>
|
||||
protected readonly IFusionCache _cache;
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="fetchFunc"></param>
|
||||
/// <param name="expiration"></param>
|
||||
/// <returns></returns>
|
||||
protected async Task<T> GetOrFetchAsync<T>(string operationName, string cacheKey, Func<Task<T>> fetchFunc, TimeSpan expiration, params string[] tagList)
|
||||
{
|
||||
using var activity = ActivitySource.StartActivity(operationName);
|
||||
string source;
|
||||
var tryGet = await _cache.TryGetAsync<T>(cacheKey);
|
||||
if (tryGet.HasValue)
|
||||
{
|
||||
source = "MEMORY";
|
||||
var result = tryGet.Value!;
|
||||
|
||||
#endregion Protected Fields
|
||||
activity?.SetTag("data.source", source);
|
||||
activity?.Stop();
|
||||
// se supero la soglia loggo...
|
||||
if (activity?.Duration.TotalMilliseconds > slowLogThresh)
|
||||
{
|
||||
LogTrace($"{operationName} | {source} | {activity?.Duration.TotalMilliseconds:F4} ms");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
bool fromDb = false;
|
||||
// cache in redis
|
||||
var cacheOptions = new FusionCacheEntryOptions()
|
||||
.SetDuration(expiration)
|
||||
.SetFailSafe(true);
|
||||
// cache in RAM per 1/3 del tempo x risparmiare risorse
|
||||
cacheOptions.MemoryCacheDuration = expiration / 3;
|
||||
|
||||
var final = await _cache.GetOrSetAsync<T>(
|
||||
cacheKey,
|
||||
async _ =>
|
||||
{
|
||||
fromDb = true;
|
||||
return await fetchFunc();
|
||||
},
|
||||
options: cacheOptions,
|
||||
tags: tagList
|
||||
);
|
||||
|
||||
source = fromDb ? "DB" : "REDIS";
|
||||
activity?.SetTag("data.source", source);
|
||||
activity?.Stop();
|
||||
// switch log in base a source..
|
||||
switch (source)
|
||||
{
|
||||
case "DB":
|
||||
LogTrace($"{operationName} | {source} | {activity?.Duration.TotalMilliseconds:F4} ms", reqLevel: NLog.LogLevel.Info);
|
||||
break;
|
||||
|
||||
case "REDIS":
|
||||
LogTrace($"{operationName} | {source} | {activity?.Duration.TotalMilliseconds:F4} ms", reqLevel: NLog.LogLevel.Debug);
|
||||
break;
|
||||
|
||||
default:
|
||||
LogTrace($"{operationName} | {source} | {activity?.Duration.TotalMilliseconds:F4} ms");
|
||||
break;
|
||||
}
|
||||
return final!;
|
||||
}
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private readonly IFusionCache _cache;
|
||||
|
||||
private readonly string _className;
|
||||
private readonly IDbContextFactory<DataLayerContext> _factory;
|
||||
|
||||
private readonly IVocabolarioRepository _repo;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private bool FlushFusionCache()
|
||||
{
|
||||
_cache.Clear(allowFailSafe: false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool FlushFusionCache(string tag)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(tag)) return false;
|
||||
|
||||
_cache.RemoveByTag(tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,8 @@
|
||||
</div>
|
||||
<div class="px-1">
|
||||
<div class="input-group input-group-sm">
|
||||
<select class="form-select" @bind="@selLingua" @bind:after="FiltLingua">
|
||||
@if (string.IsNullOrEmpty(selLingua))
|
||||
<select class="form-select" @bind="@SelLingua" @bind:after="FiltLingua">
|
||||
@if (string.IsNullOrEmpty(SelLingua))
|
||||
{
|
||||
<option value="">Sel →</option>
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
<option value="@item.Lingua">@item.Lingua</option>
|
||||
}
|
||||
</select>
|
||||
@if (!string.IsNullOrEmpty(selLingua))
|
||||
@if (!string.IsNullOrEmpty(SelLingua))
|
||||
{
|
||||
<button class="btn btn-info" @onclick="DoClone" title="clona su nuova lingua"><i class="fa-solid fa-wand-magic-sparkles"></i></button>
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@ namespace Lux.UI.Components.Compo.Admin
|
||||
[Parameter]
|
||||
public string SearchVal { get; set; } = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string SelLingua { get; set; } = "";
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Protected Methods
|
||||
@@ -36,8 +39,8 @@ namespace Lux.UI.Components.Compo.Admin
|
||||
|
||||
private async Task DoClone()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(selLingua))
|
||||
await EC_ReqClone.InvokeAsync(selLingua);
|
||||
if (!string.IsNullOrEmpty(SelLingua))
|
||||
await EC_ReqClone.InvokeAsync(SelLingua);
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
@@ -49,7 +52,6 @@ namespace Lux.UI.Components.Compo.Admin
|
||||
private bool isLoading = false;
|
||||
private List<VocabolarioModel> ListPaged = new();
|
||||
private int numRecord = 10;
|
||||
private string selLingua = "";
|
||||
|
||||
private int totalCount = 0;
|
||||
|
||||
@@ -97,9 +99,9 @@ namespace Lux.UI.Components.Compo.Admin
|
||||
private void UpdateTable()
|
||||
{
|
||||
ListPaged.Clear();
|
||||
if (!string.IsNullOrEmpty(selLingua))
|
||||
if (!string.IsNullOrEmpty(SelLingua))
|
||||
{
|
||||
var rawList = AllRecord.Where(x => x.Lingua == selLingua).ToList();
|
||||
var rawList = AllRecord.Where(x => x.Lingua == SelLingua).ToList();
|
||||
if (!string.IsNullOrEmpty(SearchVal))
|
||||
{
|
||||
rawList = rawList.Where(x =>
|
||||
|
||||
@@ -39,10 +39,10 @@
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<VocabMan ListLingue="@ListLingue" AllRecord="FullVocab" SearchVal="@SearchVal" EC_Updated="UpdateRec" EC_ReqClone="DoCloneLang"></VocabMan>
|
||||
<VocabMan ListLingue="@ListLingue" AllRecord="FullVocab" SearchVal="@SearchVal" EC_Updated="UpdateRec" EC_ReqClone="DoCloneLang" SelLingua="IT"></VocabMan>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<VocabMan ListLingue="@ListLingue" AllRecord="FullVocab" SearchVal="@SearchVal" EC_Updated="UpdateRec" EC_ReqClone="DoCloneLang"></VocabMan>
|
||||
<VocabMan ListLingue="@ListLingue" AllRecord="FullVocab" SearchVal="@SearchVal" EC_Updated="UpdateRec" EC_ReqClone="DoCloneLang" SelLingua="EN"></VocabMan>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"ChannelPub": "EgwEngineInput",
|
||||
"ChannelSub": "EgwEngineOutput",
|
||||
"Prog.ApiUrl": "https://office.egalware.com/lux/srv/api",
|
||||
"ReportUrl": "https://office.egalware.com/Lux/RepSrv"
|
||||
"ReportUrl": "https://office.egalware.com/Lux/RepSrv",
|
||||
"slowLogThresh": 100
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
"BaseUrl": "/LUX/UI/",
|
||||
"FileSharePath": "\\\\stor01\\TEAM DRIVES\\40_FileUpload\\LuxUploads",
|
||||
"RedisBaseKey": "Lux",
|
||||
"CleanupDayTTL": 180
|
||||
"CleanupDayTTL": 180,
|
||||
"slowLogThresh": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,3 +5,10 @@
|
||||
<changelog>http://nexus.steamware.net/repository/SWS/GPW/stable/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
</item>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>1.1.2606.0411</version>
|
||||
<url>http://nexus.steamware.net/repository/SWS/GPW/stable/GPW.UI.zip</url>
|
||||
<changelog>http://nexus.steamware.net/repository/SWS/GPW/stable/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
</item>
|
||||
|
||||
Reference in New Issue
Block a user