Merge branch 'release/AddConfMan_01'

This commit is contained in:
2025-01-21 12:22:25 +01:00
19 changed files with 489 additions and 18 deletions
+39 -2
View File
@@ -1,5 +1,7 @@
using System;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Core
{
@@ -73,39 +75,74 @@ namespace Core
{ "WinApp", "WinApp" }
};
#if false
[JsonConverter(typeof(StringEnumConverter))]
public enum AppType
{
None,
Cli,
Machine,
WebApp,
WinApp,
LicenceApp
}
#endif
/// <summary>
/// Elenco tipi di azioni che si possono chiedere ad EgwACC
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum EgwAccTask
{
/// <summary>
/// Non definito (init)
/// </summary>
ND = 0,
/// <summary>
/// Richiesta ricerca generica app da sorgenti mappate (registro, path...) ricevute in input
/// </summary>
AppSearch,
/// <summary>
/// Richiesta info device (analoghe a quelle del setup iniziale in Enroll)
/// </summary>
DeviceInfoGet,
/// <summary>
/// Richiesta verifica forzata da remoto
/// </summary>
ForceCheck,
/// <summary>
/// Richiede reload forzato (come da tray menu con Reload senza check update)
/// </summary>
ForceReload,
/// <summary>
/// Richiede update forzato (come da tray menu con restart tramite bootstrap process esterno)
/// </summary>
ForceUpdate,
/// <summary>
/// Info tipo License (Oxysec key)
/// </summary>
OxyLicenseGet,
/// <summary>
/// Forza Reset parametri opzionali impostabili da remoto
/// </summary>
ParamDictReset,
/// <summary>
/// Upsert di parametri operativi (gestiti in remoto)
/// </summary>
ParamUpsert
ParamUpsert,
/// <summary>
/// Upsert valori TargetList (gestiti in remoto)
/// </summary>
TargetListUpsert
}
}
}
+45
View File
@@ -0,0 +1,45 @@
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Core.Models
{
public class ControlTarget
{
[Key]
public int Idx { get; set; } = 0;
/// <summary>
/// Tipo applicazione da monitorare
/// </summary>
public string ApplicationType { get; set; } = "";
#if false
[JsonConverter(typeof(StringEnumConverter))]
public CoreEnum.AppType ApplicationType { get; set; } = CoreEnum.AppType.None;
#endif
/// <summary>
/// Path di base da monitorare
/// </summary>
public string BasePath { get; set; } = "";
/// <summary>
/// Pattern di ricerca
/// </summary>
public string SearchPattern { get; set; } = "";
/// <summary>
/// Indica se il path sia abilitato
/// </summary>
public bool IsEnabled { get; set; } = true;
/// <summary>
/// Indica se sia abilitato l'update x l'item
/// </summary>
public bool UpdateEnabled { get; set; } = false;
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>License Manager</i>
<h4>Versione: 2.1.2501.2019</h4>
<h4>Versione: 2.1.2501.2110</h4>
<br /> Note di rilascio:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
2.1.2501.2019
2.1.2501.2110
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>2.1.2501.2019</version>
<version>2.1.2501.2110</version>
<url>https://nexus.steamware.net/repository/SWS/LiMan/stable/LAST/LiMan.UI.zip</url>
<changelog>https://nexus.steamware.net/repository/SWS/LiMan/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>License Manager</i>
<h4>Versione: 2.1.2501.2018</h4>
<h4>Versione: 2.1.2501.2109</h4>
<br />
Note di rilascio:
<ul>
+1 -1
View File
@@ -1 +1 @@
2.1.2501.2018
2.1.2501.2109
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>2.1.2501.2018</version>
<version>2.1.2501.2109</version>
<url>https://nexus.steamware.net/repository/SWS/LiMan/stable/LAST/LiMan.Transfer.zip</url>
<changelog>https://nexus.steamware.net/repository/SWS/LiMan/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>
@@ -102,6 +102,7 @@ namespace LiMan.UI.Components
MServ.UsrParamSet("PcInst", "");
MServ.UsrParamSet("PcRestart", "");
MServ.UsrParamSet("PcIP", "");
MServ.UsrParamSet("Version", "");
// Richiedo azione x gestione dettaglio info
MServ.ReportSelCodInst();
}
@@ -119,6 +120,7 @@ namespace LiMan.UI.Components
MServ.UsrParamSet("PcInst", "");
MServ.UsrParamSet("PcRestart", "");
MServ.UsrParamSet("PcIP", "");
MServ.UsrParamSet("Version", "");
// Richiedo azione x gestione dettaglio info
MServ.ReportSelCodImp();
}
@@ -138,6 +140,7 @@ namespace LiMan.UI.Components
MServ.UsrParamSet("PcInst", "");
MServ.UsrParamSet("PcRestart", "");
MServ.UsrParamSet("PcIP", "");
MServ.UsrParamSet("Version", "");
// Richiedo azione x gestione dettaglio info
MServ.ReportSelCodInst();
// se era selezionato impianto lo deseleziona...
@@ -173,6 +176,7 @@ namespace LiMan.UI.Components
MServ.UsrParamSet("PcInst", currRec.PcInst);
MServ.UsrParamSet("PcRestart", "");
MServ.UsrParamSet("PcIP", "");
MServ.UsrParamSet("Version", "");
ReloadTaskStatus();
ReloadTaskResults();
// cerco in stats info
@@ -182,6 +186,10 @@ namespace LiMan.UI.Components
{
MServ.UsrParamSet("PcRestart", RunStats["Startup"]);
}
if (RunStats.ContainsKey("Version"))
{
MServ.UsrParamSet("Version", RunStats["Version"]);
}
}
// cerco nei device info
if (DevInfo != null && DevInfo.Count > 0)
@@ -1,13 +1,10 @@
using LiMan.DB.DTO;
using LiMan.UI.Data;
using Microsoft.AspNetCore.Components;
using System;
using System.Collections.Generic;
using System.Linq;
using static EgwCoreLib.Razor.Sorter;
using System.Threading.Tasks;
using LiMan.UI.Data;
using Org.BouncyCastle.Asn1.IsisMtt.X509;
using Newtonsoft.Json.Linq;
namespace LiMan.UI.Components
{
+20 -1
View File
@@ -62,6 +62,25 @@
}
else
{
@if (DoEditConfig)
{
<div class="modal modal-xl fade show" tabindex="-1" style="display:block; background-color: rgba(10,10,10,.6);" aria-modal="true" role="dialog" data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="exampleModalLabel">Remote setup | <b>@DevName</b></h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" title="Chiudi" @onclick="ToggleParamConfig"></button>
</div>
<div class="modal-body">
<TargetSetup TargetListRaw="@TgtListRaw" EC_SaveConfig="ConfigUpdated"></TargetSetup>
</div>
@* <div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal" @onclick="ToggleParamConfig">Close</button>
</div> *@
</div>
</div>
</div>
}
<div class="row">
<div class="col-2 px-1">
<ul class="list-group shadow">
@@ -109,7 +128,7 @@
{
<div class="card shadow mt-2">
<div class="card-header px-2">
<div class="py-0">
<div class="py-0 small">
@foreach (var item in DetailFilt)
{
<div class="d-flex justify-content-between align-items-start">
+31 -1
View File
@@ -1,9 +1,11 @@
using Core.Models;
using LiMan.DB;
using LiMan.DB.DBModels;
using LiMan.DB.DTO;
using LiMan.UI.Data;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -124,6 +126,11 @@ namespace LiMan.UI.Components
/// </summary>
private Dictionary<string, string> TaskRun = new Dictionary<string, string>();
/// <summary>
/// Versione raw serializzata della conf impianto (immutabile x modifica)
/// </summary>
private string TgtListRaw = "";
#endregion Private Fields
#region Private Properties
@@ -132,6 +139,7 @@ namespace LiMan.UI.Components
/// Impianto selezionato
/// </summary>
private string CodImpSel { get; set; } = "";
private string DevName { get; set; } = "";
private string codTipoApp { get; set; } = "";
@@ -198,7 +206,9 @@ namespace LiMan.UI.Components
HasFiltImpiego = !string.IsNullOrEmpty(CodImpSel);
DetailFilt.Clear();
DetailFilt.Add("Cliente", MServ.UsrParamGet("Cliente"));
DetailFilt.Add("PC", MServ.UsrParamGet("PcInst"));
DevName = MServ.UsrParamGet("PcInst");
DetailFilt.Add("PC", DevName);
DetailFilt.Add("SW ver.", MServ.UsrParamGet("Version"));
DetailFilt.Add("IP", MServ.UsrParamGet("PcIP"));
DetailFilt.Add("Started", MServ.UsrParamGet("PcRestart"));
ReloadTaskStatus();
@@ -280,11 +290,17 @@ namespace LiMan.UI.Components
TaskReq = new Dictionary<string, string>();
TaskRun = new Dictionary<string, string>();
TaskDone = new Dictionary<string, string>();
TgtListRaw = "";
if (!string.IsNullOrEmpty(CodImpSel))
{
TaskReq = LMDService.TaskReqGet(CodImpSel);
TaskRun = LMDService.TaskRunGet(CodImpSel);
TaskDone = LMDService.TaskDoneGet(CodImpSel);
// è uno dei task done l'elenco target...
if (TaskDone.ContainsKey("TargetList"))
{
TgtListRaw = TaskDone["TargetList"];
}
}
}
@@ -365,6 +381,20 @@ namespace LiMan.UI.Components
}
}
/// <summary>
/// Ricezione configurazione serializzata da inviare al device
/// </summary>
/// <param name="reqSent"></param>
private void ConfigUpdated(string newData)
{
if(!string.IsNullOrEmpty(newData))
{
// invio task update configurazione
LMDService.TaskReqAdd(CodImpSel, EgwAccTask.TargetListUpsert, newData);
}
DoEditConfig = false;
}
#endregion Private Methods
}
}
+140
View File
@@ -0,0 +1,140 @@
<div class="card shadow">
<div class="card-header">
<div class="d-flex justify-content-between">
<div class="p-0 d-flex">
<div class="px-0 d-flex">
<div class="px-0">
<h5>Remote Config</h5>
</div>
<div class="px-2">
<div class="input-group">
@if (string.IsNullOrEmpty(CodTipoApp))
{
<btn class="btn btn-sm btn-secondary disabled">Add New <i class="fa-solid fa-plus"></i></btn>
}
else
{
<btn class="btn btn-sm btn-success" @onclick="AddNewTarget">Add New <i class="fa-solid fa-plus"></i></btn>
}
<select @bind="@CodTipoApp" class="form-select form-select-sm">
@foreach (var item in Core.Enum.AppType)
{
<option value="@item.Key">@item.Value</option>
}
</select>
</div>
</div>
</div>
@if (RemoteCallActive)
{
<div class="px-2">
<i class="fa-solid fa-cloud-arrow-down fs-4 text-success"></i>
</div>
}
</div>
<div class="p-0 d-flex">
<div class="px-1">
<div class="input-group">
<button class="btn btn-sm btn-outline-success shadow" @onclick="DoSave" title="Save All Changes"><i class="fa-regular fa-floppy-disk"></i> Save</button>
<button class="btn btn-sm btn-outline-secondary shadow" @onclick="DoReset" title="Reset to Device Data"><i class="fa-solid fa-rotate"></i> Reset</button>
</div>
</div>
</div>
</div>
</div>
<div class="card-body py-0 px-2">
<div class="row py-0">
<div class="col-12 my-1">
@if (isLoading)
{
<LoadingData></LoadingData>
}
else
{
<table class="table table-striped table-sm text-start shadow border mb-0">
<thead>
<tr class="bg-dark bg-gradient text-light">
<th class="text-center" style="width: 6rem;"></th>
<th>App Type</th>
<th>Path</th>
<th class="text-end" style="width: 3rem;">Enabled</th>
<th class="text-end" style="width: 3rem;">Update</th>
<th class="text-end" style="width: 3rem;"></th>
</tr>
</thead>
<tbody>
@foreach (var item in ListRecords)
{
<tr>
<td class="text-center">
@if (item.Idx == 1)
{
<button class="btn btn-sm btn-light text-secondary opacity-50 disabled"><i class="fa-solid fa-caret-up"></i></button>
}
else
{
<button class="btn btn-sm btn-light text-primary" title="Sposta in alto" @onclick="() => MoveUp(item)"><i class="fa-solid fa-caret-up"></i></button>
}
<span class="px-2">@item.Idx</span>
@if (item.Idx == totalCount)
{
<button class="btn btn-sm btn-light text-secondary opacity-50 disabled"><i class="fa-solid fa-caret-down"></i></button>
}
else
{
<button class="btn btn-sm btn-light text-primary" title="Sposta in basso" @onclick="() => MoveDown(item)"><i class="fa-solid fa-caret-down"></i></button>
}
</td>
<td style="width: 8rem;">
<select @bind="@item.ApplicationType" class="form-select form-select-sm">
@foreach (var iType in Core.Enum.AppType)
{
if (!string.IsNullOrEmpty(iType.Key))
{
<option value="@iType.Key">@iType.Value</option>
}
}
</select>
</td>
<td>
<input type="text" class="form-control form-control-sm" @bind="@item.BasePath" />
</td>
<td class="text-end">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" @bind="@item.IsEnabled">
</div>
</td>
<td class="text-end">
<div class="form-check form-switch">
@if (item.ApplicationType == "WinApp")
{
<input class="form-check-input" type="checkbox" @bind="@item.UpdateEnabled">
}
else
{
<input class="form-check-input" type="checkbox" @bind="@item.UpdateEnabled" disabled>
}
</div>
</td>
<td class="text-end">
<button class="btn btn-sm btn-danger" title="Elimina record" @onclick="() => DeleteRec(item)"><i class="fa-solid fa-trash-can"></i></button>
</td>
</tr>
}
</tbody>
</table>
}
</div>
</div>
</div>
@if (totalCount > 5)
{
<div class="card-footer py-0 align-middle">
<EgwCoreLib.Razor.DataPager PageSize="@numRecord" currPage="@currPage" numRecordChanged="SetNumRec" numPageChanged="SetPage" totalCount="@totalCount" showLoading="@isLoading"></EgwCoreLib.Razor.DataPager>
</div>
}
</div>
+194
View File
@@ -0,0 +1,194 @@
using EgwCoreLib.Utils;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Threading.Tasks;
using System;
using System.Linq;
using Core.Models;
using Newtonsoft.Json;
using Microsoft.JSInterop;
namespace LiMan.UI.Components
{
public partial class TargetSetup
{
#region Public Properties
[Parameter]
public string TargetListRaw { get; set; } = "";
[Parameter]
public EventCallback<string> EC_SaveConfig { get; set; }
#endregion Public Properties
#region Protected Properties
protected bool RemoteCallActive { get; set; } = false;
#endregion Protected Properties
#region Protected Methods
private string CodTipoApp = "";
protected void DoReset()
{
ReloadData(true);
}
protected async Task DoSave()
{
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Sicuro di voler inviare la configurazione corrente al Device? L'operazione verrà messa in coda alle richieste per EgwAppControlCenter ed eseguita appena possibile."))
return;
// preparo versioen serializzata dei dati
string newData = JsonConvert.SerializeObject(SearchRecords);
// sollevo evento x chiusura
await EC_SaveConfig.InvokeAsync(newData);
}
[Inject]
protected IJSRuntime JSRuntime { get; set; } = null!;
protected override void OnParametersSet()
{
ReloadData(true);
}
protected void SetNumRec(int newNum)
{
numRecord = newNum;
currPage = 1;
ReloadData(false);
}
protected void SetPage(int newNum)
{
currPage = newNum;
ReloadData(false);
}
#endregion Protected Methods
#region Private Fields
private bool remoteCalling = false;
private bool ReqSetup = true;
#endregion Private Fields
#region Private Properties
private string CodImpiego { get; set; } = "";
private int currPage { get; set; } = 1;
private bool isLoading { get; set; } = false;
private List<ControlTarget> ListRecords { get; set; } = new List<ControlTarget>();
private int numRecord { get; set; } = 10;
private List<ControlTarget> SearchRecords { get; set; } = new List<ControlTarget>();
private string SetupPwd { get; set; } = "";
private void DeleteRec(ControlTarget rec2del)
{
if (rec2del != null)
{
SearchRecords.Remove(rec2del);
// ricalcolo ID record...
var newList = new List<ControlTarget>();
int idx = 1;
foreach (ControlTarget rec in SearchRecords)
{
rec.Idx= idx++;
newList.Add(rec);
}
SearchRecords = newList;
// aggiorno display
UpdateTable();
}
}
private void MoveDown(ControlTarget rec2move)
{
if (rec2move != null)
{
var otherRec = SearchRecords.FirstOrDefault(x => x.Idx == rec2move.Idx + 1);
otherRec.Idx--;
rec2move.Idx++;
// aggiorno display
UpdateTable();
}
}
private void MoveUp(ControlTarget rec2move)
{
if (rec2move != null)
{
var otherRec = SearchRecords.FirstOrDefault(x => x.Idx == rec2move.Idx - 1);
otherRec.Idx++;
rec2move.Idx--;
// aggiorno display
UpdateTable();
}
}
private SubLicManager SLicManager { get; set; } = new SubLicManager();
private int totalCount { get; set; } = 0;
#endregion Private Properties
#region Private Methods
private void ReloadData(bool forceReload)
{
// deserializzo ed assegno...
if (!string.IsNullOrEmpty(TargetListRaw))
{
if (SearchRecords.Count == 0 || forceReload)
{
SearchRecords = JsonConvert.DeserializeObject<List<ControlTarget>>(TargetListRaw);
}
}
UpdateTable();
}
private void UpdateTable()
{
isLoading = true;
ListRecords = new List<ControlTarget>();
totalCount = SearchRecords.Count;
ListRecords = SearchRecords
.OrderBy(x => x.Idx)
.Skip(numRecord * (currPage - 1))
.Take(numRecord)
.ToList();
isLoading = false;
}
private void AddNewTarget()
{
//await Task.Delay(1);
//isLoading = true;
//await InvokeAsync(StateHasChanged);
// aggiungo un record popolato secondo tipo con il primo codice libero...
ControlTarget newRec = new ControlTarget()
{
Idx = totalCount + 1,
ApplicationType = CodTipoApp,
BasePath = "C:\\ProgramData\\",
IsEnabled = CodTipoApp == "LicenceApp" || CodTipoApp == "Machine" || CodTipoApp == "WinApp",
UpdateEnabled = CodTipoApp == "WinApp"
};
// aggiungo..
SearchRecords.Add(newRec);
// torno a pag 1...
currPage = 1;
UpdateTable();
//isLoading = false;
//await InvokeAsync(StateHasChanged);
}
#endregion Private Methods
}
}
+1
View File
@@ -1,5 +1,6 @@
using Core;
using Core.DTO;
using Core.Models;
using Liman.CadCam.DbModel;
using LiMan.DB;
using LiMan.DB.Controllers;
+1 -1
View File
@@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Version>2.1.2501.2019</Version>
<Version>2.1.2501.2112</Version>
<RootNamespace>LiMan.UI</RootNamespace>
<AssemblyName>LiMan.UI</AssemblyName>
</PropertyGroup>
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>License Manager</i>
<h4>Versione: 2.1.2501.2019</h4>
<h4>Versione: 2.1.2501.2112</h4>
<br /> Note di rilascio:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
2.1.2501.2019
2.1.2501.2112
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>2.1.2501.2019</version>
<version>2.1.2501.2112</version>
<url>https://nexus.steamware.net/repository/SWS/LiMan/stable/LAST/LiMan.UI.zip</url>
<changelog>https://nexus.steamware.net/repository/SWS/LiMan/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>