Test x gestione dati in refresh continuo

This commit is contained in:
Samuele Locatelli
2023-09-26 13:13:13 +02:00
parent 33383d7573
commit 6f8d569dab
14 changed files with 568 additions and 189 deletions
@@ -1,6 +1,4 @@
<h3>MachineBlock</h3>
@if (RecMSE == null)
@if (RecMSE == null)
{
<div class="card text-white mapBlock rCAll bg-secondary p-0 m-0">
<div class="card-body">
@@ -15,8 +13,8 @@
}
else
{
<div class="card text-white mapBlock rCAll bg-success p-0 m-0">
<div class="card-body @RecMSE.Semaforo">
<div class="card mapBlock rCAll @cssStatus(RecMSE.Semaforo) p-0 m-0">
<div class="card-body ">
<div class="fs-2">
@RecMSE.IdxMacchina
<div class="small">
@@ -30,6 +28,62 @@ else
@code {
[Parameter]
public MappaStatoExpl? RecMSE { get; set; }
public MappaStatoExpl? RecMSE { get; set; } = null;
[Parameter]
public bool DoBlink { get; set; } = false;
[Parameter]
public bool DoAnimate { get; set; } = false;
[Parameter]
public int keepAliveMin { get; set; } = 5;
protected int kaFactor = 60 / 2;
protected override async Task OnParametersSetAsync()
{
Console.WriteLine($"MachineBlock | Parameter SET! | Macc: {RecMSE?.IdxMacchina}");
await InvokeAsync(StateHasChanged);
}
private string cssComStatus(string semaforo, DateTime? lastUpdateN)
{
DateTime lastUpdate = lastUpdateN.HasValue ? (DateTime)lastUpdateN : DateTime.Now.AddHours(-1);
string answ = cssStatus(semaforo);
if (DateTime.Now.Subtract(lastUpdate).TotalSeconds > (keepAliveMin * kaFactor))
{
answ = $"{baseCss}Ro";
// blink se secondo pari...
DateTime adesso = DateTime.Now;
int resto = 0;
Math.DivRem(adesso.Second, 2, out resto);
if (resto == 0)
{
answ += "_b";
}
}
return answ;
}
private string cssStatus(string codSemaforo)
{
// se vuoto --> mostra nero!
if (string.IsNullOrEmpty(codSemaforo))
{
codSemaforo = "sNe";
}
string codColore = codSemaforo.Substring(1, 2);
string answ = $"{baseCss}{codColore}";
if (DoAnimate && codColore != "Ve")
{
if (DoBlink)
{
answ += "_b";
}
}
return answ;
}
protected string baseCss = "sem";
}
@@ -1,4 +1,5 @@
.statusMap {
/* Gestione semafori */
.statusMap {
/*background: rgba(0,0,0,0.3);*/
}
.statusMap .ui-title,
@@ -1,4 +1,6 @@
/* Gestione semafori */
.statusMap {
/*background: rgba(0,0,0,0.3);*/
}
+100 -6
View File
@@ -1,9 +1,16 @@
@attribute [RenderModeAuto]
@using MP.Data.Services;
@using MP.Data;
@using NLog;
@using Newtonsoft.Json;
@inject MonDataFeeder MMDataService
@implements IDisposable
<div class="row">
@if (ListMSE == null || ListMSE.Count == 0)
@if (listMSE == null || listMSE.Count == 0)
{
@for (int i = 0; i < 9; i++)
@for (int i = 0; i < 10; i++)
{
<div class="col-4 my-2">
<MP_TAB.Client.Components.MachineBlock></MP_TAB.Client.Components.MachineBlock>
@@ -12,10 +19,10 @@
}
else
{
@foreach (var item in ListMSE)
@foreach (var item in listMSE)
{
<div class="col-4 my-2">
<MP_TAB.Client.Components.MachineBlock RecMSE="@item"></MP_TAB.Client.Components.MachineBlock>
<MP_TAB.Client.Components.MachineBlock RecMSE="@item" DoBlink="@doBlink"></MP_TAB.Client.Components.MachineBlock>
</div>
}
}
@@ -23,6 +30,93 @@
@code {
[Parameter]
public List<MappaStatoExpl>? ListMSE { get; set; }
private List<MappaStatoExpl>? listMSE { get; set; } = null;
private bool doBlink = false;
public void Dispose()
{
DateTime adesso = DateTime.Now;
if (adesso.Subtract(lastStart).TotalMilliseconds < 800)
{
Log.Debug($"StatusMap | SALTATO dispose");
}
else
{
MMDataService.dataPipe.EA_NewMessage -= DataPipe_EA_NewMessage;
MMDataService.blinkPipe.EA_NewMessage -= BlinkPipe_EA_NewMessage;
MMDataService.stopTimers();
// disposeTimers();
Log.Debug($"StatusMap | richiamato dispose");
}
}
protected override async Task OnInitializedAsync()
{
// MMDataService.dataPipe.EA_NewMessage -= DataPipe_EA_NewMessage;
// MMDataService.blinkPipe.EA_NewMessage -= BlinkPipe_EA_NewMessage;
MMDataService.dataPipe.EA_NewMessage += DataPipe_EA_NewMessage;
MMDataService.blinkPipe.EA_NewMessage += BlinkPipe_EA_NewMessage;
MMDataService.startTimers();
lastStart = DateTime.Now;
await Task.Delay(1);
Log.Debug($"StatusMap | OnInitializedAsync");
// return base.OnInitializedAsync();
}
private DateTime lastStart = DateTime.Now;
private void BlinkPipe_EA_NewMessage(object? sender, EventArgs e)
{
PubSubEventArgs currArgs = (PubSubEventArgs)e;
Log.Trace($"BlinkPipe_EA_NewMessage | messsage received!");
// conversione on-the-fly List<string> --> allarmi
if (!string.IsNullOrEmpty(currArgs.newMessage))
{
try
{
var dataRaw = JsonConvert.DeserializeObject<string>(currArgs.newMessage);
if (dataRaw != null)
{
bool.TryParse($"{dataRaw}", out doBlink);
}
}
catch (Exception exc)
{
Log.Error($"Exception on BlinkPipe_EA_NewMessage{Environment.NewLine}{exc}");
}
}
}
private static NLog.Logger Log = LogManager.GetCurrentClassLogger();
/// <summary>
/// Ricevuto nuovi dati da mostrare!
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <exception cref="NotImplementedException"></exception>
private void DataPipe_EA_NewMessage(object? sender, EventArgs e)
{
PubSubEventArgs currArgs = (PubSubEventArgs)e;
Log.Trace($"DataPipe_EA_NewMessage | messsage received!");
// conversione on-the-fly List<string> --> allarmi
if (!string.IsNullOrEmpty(currArgs.newMessage))
{
listMSE = null;
try
{
var dataList = JsonConvert.DeserializeObject<List<MappaStatoExpl>>(currArgs.newMessage);
if (dataList != null)
{
listMSE = dataList;
InvokeAsync(StateHasChanged);
}
}
catch (Exception exc)
{
Log.Error($"Exception on DataPipe_EA_NewMessage{Environment.NewLine}{exc}");
}
}
}
}
+1 -1
View File
@@ -8,7 +8,7 @@
@* <link rel="stylesheet" href="bootstrap/bootstrap.min.css" /> *@
<link rel="stylesheet" href="lib/font-awesome/css/all.min.css" />
<link rel="stylesheet" href="lib/bootstrap/css/bootstrap.min.css" />
<link rel="stylesheet" href="app.css" />
<link rel="stylesheet" href="app.min.css" />
<link rel="stylesheet" href="MP-TAB.styles.css" />
<link rel="icon" type="image/png" href="favicon.png" />
<HeadOutlet />
@@ -1,8 +1,8 @@
@page "/status-map"
@attribute [StreamRendering(true)]
@* @attribute [StreamRendering(true)] *@
<!-- Temporary workaround until MapRazorComponents supports AddAdditionalAssemblies -->
<!-- Once that is implemented, the main project won't need to include this file -->
<MP_TAB.Client.Pages.StatusMap ListMSE="@listMSE"></MP_TAB.Client.Pages.StatusMap>
<MP_TAB.Client.Pages.StatusMap></MP_TAB.Client.Pages.StatusMap>
+70 -139
View File
@@ -20,22 +20,27 @@ using MP_TAB.Components;
using NLog;
using MP.Data.Conf;
using Newtonsoft.Json;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace MP_TAB.Components.Pages
{
public partial class StatusMap : IDisposable
public partial class StatusMap
{
[Inject]
protected MonDataFeeder MMDataService { get; set; } = null!;
[Inject]
protected NavigationManager NavManager { get; set; } = null!;
#region Protected Fields
protected bool doAnimate = true;
protected int fastRefreshMs = 1000;
protected int keepAliveMin = 1;
protected int maxCol = 6;
protected string showArt = "";
protected int slowRefreshSec = 300;
#endregion Protected Fields
#region Protected Properties
[Inject]
protected MonDataFeeder MMDataService { get; set; } = null!;
protected int slowRefreshMs
{
get
@@ -46,105 +51,9 @@ namespace MP_TAB.Components.Pages
}
}
public void Dispose()
{
disposeTimers();
}
public async void ElapsedSlowTimer(object? source, System.Timers.ElapsedEventArgs e)
{
listMSE = null;
await Task.Delay(10);
Log.Info("Elapsed Slow Timer --> full page reload");
// dispongo i vari timers...
disposeTimers();
await Task.Delay(10);
// reload pagina
NavManager.NavigateTo(NavManager.Uri);
}
#endregion Protected Properties
public void StartTimer()
{
// timer lento
slowTimer = new System.Timers.Timer(slowRefreshMs);
slowTimer.Elapsed += ElapsedSlowTimer;
slowTimer.Enabled = true;
slowTimer.Start();
}
protected override async Task OnInitializedAsync()
{
await setupConf();
MMDataService.dataPipe.EA_NewMessage += DataPipe_EA_NewMessage;
MMDataService.blinkPipe.EA_NewMessage += BlinkPipe_EA_NewMessage;
Random rnd = new Random();
await Task.Delay(rnd.Next(100, 200));
// carico i dati iniziali...
listMSE = await MMDataService.MseGetAll();
StartTimer();
}
private void BlinkPipe_EA_NewMessage(object? sender, EventArgs e)
{
PubSubEventArgs currArgs = (PubSubEventArgs)e;
// conversione on-the-fly List<string> --> allarmi
if (!string.IsNullOrEmpty(currArgs.newMessage))
{
try
{
var dataRaw = JsonConvert.DeserializeObject<string>(currArgs.newMessage);
if (dataRaw != null)
{
bool.TryParse($"{dataRaw}", out doBlink);
}
}
catch
{ }
InvokeAsync(() =>
{
StateHasChanged();
});
}
}
/// <summary>
/// Ricevuto nuovi dati da mostrare!
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <exception cref="NotImplementedException"></exception>
private void DataPipe_EA_NewMessage(object? sender, EventArgs e)
{
PubSubEventArgs currArgs = (PubSubEventArgs)e;
// conversione on-the-fly List<string> --> allarmi
if (!string.IsNullOrEmpty(currArgs.newMessage))
{
try
{
var dataList = JsonConvert.DeserializeObject<List<MappaStatoExpl>>(currArgs.newMessage);
if (dataList != null)
{
listMSE = dataList;
}
}
catch
{ }
}
InvokeAsync(StateHasChanged);
}
private static NLog.Logger Log = LogManager.GetCurrentClassLogger();
private static System.Timers.Timer slowTimer = new System.Timers.Timer(300000);
private List<ConfigModel>? CurrConfig = null;
private bool doBlink = false;
private static List<MappaStatoExpl>? listMSE = null;
private Random rnd = new Random();
private void disposeTimers()
{
slowTimer.Elapsed -= ElapsedSlowTimer;
slowTimer.Stop();
slowTimer.Dispose();
}
#region Protected Methods
/// <summary>
/// Recupera il valore e se trovato aggiorna
@@ -167,6 +76,7 @@ namespace MP_TAB.Components.Pages
}
return answ;
}
/// <summary>
/// Recupera il valore e se trovato aggiorna
/// </summary>
@@ -188,41 +98,6 @@ namespace MP_TAB.Components.Pages
return answ;
}
private async Task setupConf()
{
CurrConfig = await MMDataService.ConfigGetAll();
if (CurrConfig != null && CurrConfig.Count > 0)
{
// sistemo i parametri opzionali...
getConfValInt("keepAliveMin", ref keepAliveMin);
getConfValInt("MON_maxCol", ref maxCol);
int intDoAnim = 0;
getConfValInt("doAnimate", ref intDoAnim);
doAnimate = intDoAnim == 1;
getConfValInt("pageRefreshSec", ref slowRefreshSec);
getConfVal("sART", ref showArt);
Log.Info($"setupConf | Effettuato setup parametri | keepAlive: {keepAliveMin} | MaxCol: {maxCol} | doAnimate: {doAnimate} | slowRefreshSec: {slowRefreshSec} | fastRefreshMs: {fastRefreshMs}");
}
}
/// <summary>
/// Recupera da redis (in una chiamata soltanto) tutti i valori richiesti e compone un
/// dizionario x ottimizzare visualizzazione
/// </summary>
/// <param name="codIob"></param>
/// <returns></returns>
protected Dictionary<string, string> getTagVal(string codIob)
{
Dictionary<string, string> answ = new Dictionary<string, string>();
// recupero conf tags...
var currTags = getIobTag(codIob);
if (currTags != null && currTags.Count > 0)
{
// FIXME TODO !!!! FARE !!!! - da verificare
answ = currTags.ToDictionary(x => x.TagLocation, x => MMDataService.getTagConf(x.TagLocation));
}
return answ;
}
/// <summary>
/// Recupera da conf eventuale setup tag dell'IOB indicato
/// </summary>
@@ -241,5 +116,61 @@ namespace MP_TAB.Components.Pages
}
return answ;
}
/// <summary>
/// Recupera da redis (in una chiamata soltanto) tutti i valori richiesti e compone un
/// dizionario x ottimizzare visualizzazione
/// </summary>
/// <param name="codIob"></param>
/// <returns></returns>
protected Dictionary<string, string> getTagVal(string codIob)
{
Dictionary<string, string> answ = new Dictionary<string, string>();
// recupero conf tags...
var currTags = getIobTag(codIob);
if (currTags != null && currTags.Count > 0)
{
// FIXME TODO !!!! FARE !!!! - da verificare
answ = currTags.ToDictionary(x => x.TagLocation, x => MMDataService.getTagConf(x.TagLocation));
}
return answ;
}
protected override async Task OnInitializedAsync()
{
await setupConf();
}
#endregion Protected Methods
#region Private Fields
private static NLog.Logger Log = LogManager.GetCurrentClassLogger();
private static System.Timers.Timer slowTimer = new System.Timers.Timer(300000);
private List<ConfigModel>? CurrConfig = null;
private Random rnd = new Random();
#endregion Private Fields
#region Private Methods
private async Task setupConf()
{
CurrConfig = await MMDataService.ConfigGetAll();
if (CurrConfig != null && CurrConfig.Count > 0)
{
// sistemo i parametri opzionali...
getConfValInt("keepAliveMin", ref keepAliveMin);
getConfValInt("MON_maxCol", ref maxCol);
int intDoAnim = 0;
getConfValInt("doAnimate", ref intDoAnim);
doAnimate = intDoAnim == 1;
getConfValInt("pageRefreshSec", ref slowRefreshSec);
getConfVal("sART", ref showArt);
Log.Info($"setupConf | Effettuato setup parametri | keepAlive: {keepAliveMin} | MaxCol: {maxCol} | doAnimate: {doAnimate} | slowRefreshSec: {slowRefreshSec}");
}
}
#endregion Private Methods
}
}
+8 -1
View File
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
@@ -8,6 +8,13 @@
<AssemblyName>$(AssemblyName.Replace(' ', '_'))</AssemblyName>
</PropertyGroup>
<ItemGroup>
<Content Remove="compilerconfig.json" />
</ItemGroup>
<ItemGroup>
<None Include="compilerconfig.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MP-TAB.Client\MP-TAB.Client.csproj" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.0-rc.1.23421.29" />
+4 -3
View File
@@ -5,14 +5,15 @@ using StackExchange.Redis;
var builder = WebApplication.CreateBuilder(args);
ConfigurationManager configuration = builder.Configuration;
// REDIS setup
string connStringRedis = configuration.GetConnectionString("Redis");
string redisSrvAddr = connStringRedis.Substring(0, connStringRedis.IndexOf(":"));
var cString = configuration.GetConnectionString("Redis");
string connStringRedis = cString ?? "localhost:6379, DefaultDatabase=1, connectTimeout=5000, syncTimeout=5000, asyncTimeout=5000, abortConnect=false, ssl=false";
//string redisSrvAddr = connStringRedis.Substring(0, connStringRedis.IndexOf(":"));
// avvio oggetto shared x redis...
var redisMultiplexer = ConnectionMultiplexer.Connect(connStringRedis);
// Add services to the container.
builder.Services.AddSingleton<IConnectionMultiplexer>(redisMultiplexer);
builder.Services.AddSingleton<MonDataFeeder>();
builder.Services.AddSingleton<MonDataFeeder>();
// nuova versione contenuti...
builder.Services.AddRazorComponents()
+6
View File
@@ -0,0 +1,6 @@
[
{
"outputFile": "wwwroot/app.css",
"inputFile": "wwwroot/app.less"
}
]
@@ -0,0 +1,71 @@
{
"compilers": {
"less": {
"autoPrefix": "",
"cssComb": "none",
"ieCompat": true,
"math": null,
"strictMath": false,
"strictUnits": false,
"relativeUrls": true,
"rootPath": "",
"sourceMapRoot": "",
"sourceMapBasePath": "",
"sourceMap": false
},
"sass": {
"autoPrefix": "",
"loadPaths": "",
"style": "expanded",
"relativeUrls": true,
"sourceMap": false
},
"nodesass": {
"autoPrefix": "",
"includePath": "",
"indentType": "space",
"indentWidth": 2,
"outputStyle": "nested",
"precision": 5,
"relativeUrls": true,
"sourceMapRoot": "",
"lineFeed": "",
"sourceMap": false
},
"stylus": {
"sourceMap": false
},
"babel": {
"sourceMap": false
},
"coffeescript": {
"bare": false,
"runtimeMode": "node",
"sourceMap": false
},
"handlebars": {
"root": "",
"noBOM": false,
"name": "",
"namespace": "",
"knownHelpersOnly": false,
"forcePartial": false,
"knownHelpers": [],
"commonjs": "",
"amd": false,
"sourceMap": false
}
},
"minifiers": {
"css": {
"enabled": true,
"termSemicolons": true,
"gzip": false
},
"javascript": {
"enabled": true,
"termSemicolons": true,
"gzip": false
}
}
}
+192 -29
View File
@@ -1,47 +1,210 @@
html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
html,
body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
h1:focus {
outline: none;
outline: none;
}
a, .btn-link {
color: #0071c1;
a,
.btn-link {
color: #0071c1;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
.btn:focus,
.btn:active:focus,
.btn-link.nav-link:focus,
.form-control:focus,
.form-check-input:focus {
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}
.content {
padding-top: 1.1rem;
padding-top: 1.1rem;
}
.valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050;
outline: 1px solid #26b050;
}
.invalid {
outline: 1px solid red;
outline: 1px solid red;
}
.validation-message {
color: red;
color: red;
}
.blazor-error-boundary {
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
padding: 1rem 1rem 1rem 3.7rem;
color: white;
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
padding: 1rem 1rem 1rem 3.7rem;
color: white;
}
.blazor-error-boundary::after {
content: "An error has occurred."
}
.blazor-error-boundary::after {
content: "An error has occurred.";
}
/* Gestione semafori */
.statusMap {
/*background: rgba(0,0,0,0.3);*/
}
.statusMap .ui-title,
.statusMap .ui-li-aside {
font-weight: 400;
text-transform: uppercase;
font-size: 2.5em;
line-height: 1.1em;
color: #DEDEDE;
text-shadow: 2px 2px 4px #000;
text-align: center;
background: linear-gradient(270deg, rgba(20, 20, 20, 0.7), rgba(100, 100, 100, 0.7), rgba(20, 20, 20, 0.7));
}
.statusMap .ui-subtitle {
line-height: 1.1em;
color: #DEDEDE;
text-shadow: 2px 2px 4px #000;
text-align: center;
background: linear-gradient(270deg, rgba(0, 0, 0, 0.4), rgba(100, 100, 100, 0.4), rgba(0, 0, 0, 0.4));
}
.statusMap .ui-footer {
color: #CDCDCD;
background: linear-gradient(270deg, rgba(10, 10, 10, 0.7), rgba(80, 80, 80, 0.7), rgba(10, 10, 10, 0.7));
}
.machBlock {
padding: 0 2px 0 2px;
}
/* END: gestione layout dinamico mappa... */
/* area semafori*/
.semBlinkVe,
.semFixVe,
.semFixVe_b,
.semVe,
.sVe,
.semVe_b {
background: #009036;
background: rgba(0, 255, 80, 0.6);
color: #FFFFAA;
}
.semBlinkGr,
.semFixGr,
.semFixGr_b,
.semGr,
.semGr_b {
background-color: #bcbcbc;
background: rgba(180, 180, 180, 0.6);
}
.semGi,
.sGi {
text-align: left;
background: #8a8d27;
background: rgba(230, 210, 0, 0.6);
padding: 0px 4px 0px 4px;
color: #000;
}
.semGi_b,
.semFixGi,
.semFixGi_b {
text-align: left;
background: #f9ff18;
background: rgba(255, 255, 0, 0.8);
padding: 0px 4px 0px 4px;
color: #333;
}
.semBl {
text-align: left;
background: #000E7A;
background: rgba(0, 5, 200, 0.6);
padding: 0px 4px 0px 4px;
color: #959500;
}
.semBl_b,
.semFixBl,
.semFixBl_b {
text-align: left;
background: #243FFF;
background: rgba(60, 80, 255, 0.8);
padding: 0px 4px 0px 4px;
color: #ffff32;
}
.semRo {
text-align: left;
background-color: #7a000e;
background: rgba(200, 0, 5, 0.6);
padding: 0px 4px 0px 4px;
color: #959500;
}
.semRo_b,
.semFixRo,
.semFixRo_b {
text-align: left;
background-color: #ff243f;
background: rgba(255, 60, 80, 0.8);
padding: 0px 4px 0px 4px;
color: #ffff32;
}
/* semafori con animazione blinking */
.no-cpu {
-moz-transform: translateZ(0);
-o-transform: translateZ(0);
-webkit-transform: translateZ(0);
-ms-transform: translateZ(0);
transform: translateZ(0);
}
@-webkit-keyframes blinkBack {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
@-moz-keyframes blinkBack {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
@-o-keyframes blinkBack {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
@keyframes blinkBack {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
.semBlinkGi {
background: linear-gradient(270deg, #8a8d27, #f9ff18);
background-size: 400% 400%;
-webkit-animation: blinkBack 2s ease infinite;
-moz-animation: blinkBack 2s ease infinite;
-o-animation: blinkBack 2s ease infinite;
animation: blinkBack 2s ease infinite;
}
.semBlinkRo {
background: linear-gradient(270deg, #7a000e, #ff243f);
background-size: 400% 400%;
-webkit-animation: blinkBack 2s ease infinite;
-moz-animation: blinkBack 2s ease infinite;
-o-animation: blinkBack 2s ease infinite;
animation: blinkBack 2s ease infinite;
color: Yellow;
}
+48
View File
@@ -0,0 +1,48 @@
html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
h1:focus {
outline: none;
}
a, .btn-link {
color: #0071c1;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}
.content {
padding-top: 1.1rem;
}
.valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050;
}
.invalid {
outline: 1px solid red;
}
.validation-message {
color: red;
}
.blazor-error-boundary {
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
padding: 1rem 1rem 1rem 3.7rem;
color: white;
}
.blazor-error-boundary::after {
content: "An error has occurred."
}
File diff suppressed because one or more lines are too long