Compare commits

..

2 Commits

Author SHA1 Message Date
taywon18
7b1216eec1 refactoring 2025-02-02 15:32:45 +01:00
taywon18
9787422f65 fixed elem type loading 2025-02-01 18:08:35 +01:00
25 changed files with 347 additions and 145 deletions

View File

@ -71,6 +71,7 @@ public class EventManager
DateTime? to = null, DateTime? to = null,
int? limit = null, int? limit = null,
int? offset = null, int? offset = null,
Event.ValenceType? valenceType = null,
Dictionary<string, object>? filters = null) Dictionary<string, object>? filters = null)
{ {
if(History is null) if(History is null)
@ -92,6 +93,9 @@ public class EventManager
if (to is not null) if (to is not null)
ret = ret.Where(x => x.When <= to); ret = ret.Where(x => x.When <= to);
if (valenceType is not null)
ret = ret.Where(x => x.Valence == valenceType);
if (offset is not null) if (offset is not null)
ret = ret.Skip(offset.Value); ret = ret.Skip(offset.Value);
@ -101,12 +105,14 @@ public class EventManager
foreach (var i in ret) foreach (var i in ret)
yield return i; yield return i;
//TODO: Implement filters //TODO: Implement filters
yield break; yield break;
} }
await foreach (var i in History.GetEvents(subject, from, to, limit, offset, filters)) await foreach (var i in History.GetEvents(subject, from, to, limit, offset, valenceType, filters))
yield return i; yield return i;
} }
} }

View File

@ -31,7 +31,14 @@ public abstract class Persistence
public abstract Task RegisterEvent(Event e); public abstract Task RegisterEvent(Event e);
public abstract Task<Event?> GetEvent(string id); public abstract Task<Event?> GetEvent(string id);
public abstract IAsyncEnumerable<Event> GetEvents(string? subject = null, DateTime? from = null, DateTime? to = null, int? limit = null, int? offset = null, Dictionary<string, object>? filters = null); public abstract IAsyncEnumerable<Event> GetEvents(
string? subject = null,
DateTime? from = null,
DateTime? to = null,
int? limit = null,
int? offset = null,
Event.ValenceType? valenceType = null,
Dictionary<string, object>? filters = null);
protected virtual void ExceptionCatched(Exception e) protected virtual void ExceptionCatched(Exception e)
{ {

View File

@ -2,12 +2,22 @@
public class Event public class Event
{ {
public enum ValenceType
{
Normal,
Error,
Emergency
}
public const string TYPE_STATE_CHANGED = "state_changed"; public const string TYPE_STATE_CHANGED = "state_changed";
public const string TYPE_LOG = "log";
public string UniqueId { get; set; } public string UniqueId { get; set; }
public string ThrowerId { get; set; } public string ThrowerId { get; set; }
public string Type { get; set; } public string Type { get; set; }
public DateTime When { get; set; } = DateTime.Now; public DateTime When { get; set; } = DateTime.Now;
public string Description { get; set; } = "";
public ValenceType Valence { get; set; } = default;
public Dictionary<string, object> Properties { get; protected set; } = new Dictionary<string, object>(); public Dictionary<string, object> Properties { get; protected set; } = new Dictionary<string, object>();
public object? this[string key] public object? this[string key]
@ -32,11 +42,12 @@ public class Event
} }
public Event(string uniqueId, string throwerId, string type, DateTime? when = null) public Event(string uniqueId, string throwerId, string type, string description = "", DateTime? when = null)
{ {
UniqueId = uniqueId; UniqueId = uniqueId;
ThrowerId = throwerId; ThrowerId = throwerId;
Type = type; Type = type;
Description = description;
if(when != null) if(when != null)
When = when.Value; When = when.Value;
} }
@ -44,8 +55,28 @@ public class Event
public static Event FromStateChange(string key, object? value, DateTime when) public static Event FromStateChange(string key, object? value, DateTime when)
{ {
string id = Guid.NewGuid().ToString(); string id = Guid.NewGuid().ToString();
var ret = new Event(id, key, TYPE_STATE_CHANGED, when); var ret = new Event(id, key, TYPE_STATE_CHANGED, when:when);
ret[nameof(Triplet.value)] = value; ret[nameof(Triplet.value)] = value;
return ret; return ret;
} }
public static Event FromLog(
string thrower,
string content,
DateTime? when = null,
int severity = 6,
Exception? exception = null
)
{
if (when == null)
when = DateTime.Now;
string id = Guid.NewGuid().ToString();
var ret = new Event(id, thrower, TYPE_LOG, description: content, when: when);
ret["severity"] = severity;
if (exception is not null && exception.StackTrace is not null)
ret["trace"] = exception.StackTrace;
return ret;
}
} }

View File

@ -54,6 +54,12 @@ public class Instance
State.Push(t.key, t.predicate, t.value, t.LastFlush); State.Push(t.key, t.predicate, t.value, t.LastFlush);
} }
public void Add(IEnumerable<Event> events)
{
foreach (var i in events)
Event.Push(i);
}
public T? RetrieveElement<T>(string id) where T : Element public T? RetrieveElement<T>(string id) where T : Element
{ {
var triplets = State.Get(id).ToList(); var triplets = State.Get(id).ToList();

View File

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Title>Salmon.Core</Title>
<Description>Common parts of Salmon</Description>
</PropertyGroup>
</Project>

View File

@ -4,6 +4,11 @@
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Title>Salmon.Core</Title>
<PackageId>Salmon</PackageId>
<Version>0.1.0</Version>
<Description>Common parts of Salmon</Description>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@ -1,7 +1,4 @@
using System.Net.Http.Json; using System.Net.Http.Json;
using System.Security.Cryptography;
using System.Text.Json;
using System.Xml.Linq;
namespace Salmon.Core; namespace Salmon.Core;
@ -17,17 +14,18 @@ public class Transmitter
foreach (Element element in elements) foreach (Element element in elements)
triplets.AddRange(Translator.Encode(element)); triplets.AddRange(Translator.Encode(element));
Console.WriteLine(JsonSerializer.Serialize(triplets));
var result = await Client.PostAsJsonAsync(uri, triplets, cancellationToken: tk); var result = await Client.PostAsJsonAsync(uri, triplets, cancellationToken: tk);
if (!result.IsSuccessStatusCode) if (!result.IsSuccessStatusCode)
throw new Exception($"SendAsync call return code {result.StatusCode} when call {uri}."); throw new Exception($"SendAsync(elements) call return code {result.StatusCode} when call {uri}.");
} }
public async Task SendAsync(Uri uri, IEnumerable<Event> events, CancellationToken tk = default) public async Task SendAsync(Uri uri, IEnumerable<Event> events, CancellationToken tk = default)
{ {
await Client.PostAsJsonAsync(uri, events, cancellationToken: tk); var result = await Client.PostAsJsonAsync(uri, events, cancellationToken: tk);
if (!result.IsSuccessStatusCode)
throw new Exception($"SendAsync(events) call return code {result.StatusCode} when call {uri}.");
} }
public async Task SendAsync(IEnumerable<Element> elements, CancellationToken tk = default) public async Task SendAsync(IEnumerable<Element> elements, CancellationToken tk = default)

View File

@ -1,5 +1,5 @@
{ {
"Url":"http://127.0.0.1:5009/api/", "Url":"http://salmon.voie93quarts.fr/api/",
"Period":15000, "Period":15000,
"Watch":[ "Watch":[
{ {

View File

@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.6.33723.286 VisualStudioVersion = 17.6.33723.286
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Salmon.Model", "Salmon.Model\Salmon.Model.csproj", "{DD4EDB99-A7A9-413F-967B-FE4D0ADD8D0A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Salmon.Core", "Salmon.Core\Salmon.Core.csproj", "{97733A9E-5BBB-484F-B8C7-AF4A6EC41731}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Salmon.Core", "Salmon.Core\Salmon.Core.csproj", "{97733A9E-5BBB-484F-B8C7-AF4A6EC41731}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Salmon.Test", "Salmon.Test\Salmon.Test.csproj", "{CA8F6995-ED22-43BC-BE20-EB9D8477225A}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Salmon.Test", "Salmon.Test\Salmon.Test.csproj", "{CA8F6995-ED22-43BC-BE20-EB9D8477225A}"
@ -13,16 +11,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Salmon.Web", "Salmon.Web\Sa
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Salmon.Service", "Salmon.Service\Salmon.Service.csproj", "{357108AA-4D7C-479D-93AA-9D7FC9455A48}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Salmon.Service", "Salmon.Service\Salmon.Service.csproj", "{357108AA-4D7C-479D-93AA-9D7FC9455A48}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Salmon.Model", "Salmon.Model\Salmon.Model.csproj", "{5F083251-3DD9-4124-B467-B82665C32792}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DD4EDB99-A7A9-413F-967B-FE4D0ADD8D0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DD4EDB99-A7A9-413F-967B-FE4D0ADD8D0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DD4EDB99-A7A9-413F-967B-FE4D0ADD8D0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DD4EDB99-A7A9-413F-967B-FE4D0ADD8D0A}.Release|Any CPU.Build.0 = Release|Any CPU
{97733A9E-5BBB-484F-B8C7-AF4A6EC41731}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {97733A9E-5BBB-484F-B8C7-AF4A6EC41731}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{97733A9E-5BBB-484F-B8C7-AF4A6EC41731}.Debug|Any CPU.Build.0 = Debug|Any CPU {97733A9E-5BBB-484F-B8C7-AF4A6EC41731}.Debug|Any CPU.Build.0 = Debug|Any CPU
{97733A9E-5BBB-484F-B8C7-AF4A6EC41731}.Release|Any CPU.ActiveCfg = Release|Any CPU {97733A9E-5BBB-484F-B8C7-AF4A6EC41731}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -39,6 +35,10 @@ Global
{357108AA-4D7C-479D-93AA-9D7FC9455A48}.Debug|Any CPU.Build.0 = Debug|Any CPU {357108AA-4D7C-479D-93AA-9D7FC9455A48}.Debug|Any CPU.Build.0 = Debug|Any CPU
{357108AA-4D7C-479D-93AA-9D7FC9455A48}.Release|Any CPU.ActiveCfg = Release|Any CPU {357108AA-4D7C-479D-93AA-9D7FC9455A48}.Release|Any CPU.ActiveCfg = Release|Any CPU
{357108AA-4D7C-479D-93AA-9D7FC9455A48}.Release|Any CPU.Build.0 = Release|Any CPU {357108AA-4D7C-479D-93AA-9D7FC9455A48}.Release|Any CPU.Build.0 = Release|Any CPU
{5F083251-3DD9-4124-B467-B82665C32792}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5F083251-3DD9-4124-B467-B82665C32792}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F083251-3DD9-4124-B467-B82665C32792}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F083251-3DD9-4124-B467-B82665C32792}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -0,0 +1,29 @@
@inject IJSRuntime JSRuntime
<button type="button" class="btn" @onclick="CopyTextToClipboard">
@if(Clicked)
{
<i class="bi bi-clipboard-check"></i>
}
else
{
<i class="bi bi-clipboard"></i>
}
</button>
@code {
[Parameter]
public string Value { get; set; }
bool Clicked { get; set; } = false;
private async Task CopyTextToClipboard()
{
if (Value is null)
return;
await JSRuntime.InvokeVoidAsync("clipboardCopy.copyText", Value.ToString());
Clicked = true;
}
}

View File

@ -0,0 +1,40 @@
@inject Salmon.Core.Instance Salmon;
@if(Target is not null)
{
<Card Class="col-6" Style="width:18rem;margin:10px;">
<CardHeader>
<NavLink href=@($"Element/{System.Web.HttpUtility.UrlEncode(Target.UniqueId)}")>
<span class="oi oi-zoom-in" aria-hidden="true"></span>
</NavLink>
@Target.LastType
</CardHeader>
<CardBody>
<CardTitle>@Target.ShortName</CardTitle>
@if (!String.IsNullOrEmpty(Target.LongName))
{
<CardSubTitle>
@Target.LongName
</CardSubTitle>
}
<CardText>@Target.Description</CardText>
</CardBody>
<ul class="list-group list-group-flush">
@foreach (var kv in Target.ImportantProperties())
{
<li class="list-group-item">@kv.Key: @kv.Value</li>
}
<li class="list-group-item"><small>id: @Target.UniqueId</small></li>
</ul>
@if (Salmon.GetLastElementUpdate(Target.UniqueId) is not null)
{
<CardFooter>
<small class="text-muted">Last updated <i>@TimespanHelper.GetReadableTimespan(DateTime.Now - Salmon.GetLastElementUpdate(Target.UniqueId).Value)</i></small>
</CardFooter>
}
</Card>
}
@code {
[Parameter]
public Element? Target { get; set; }
}

View File

@ -0,0 +1,39 @@
@inject Salmon.Core.Instance Salmon;
<div Style="display:flex;flex-wrap:wrap; height:100%;">
@foreach (var e in Elements)
{
<ElementCard Target=e />
}
</div>
@code {
[Parameter]
public string? FilterByParent { get; set; } = null;
List<Element> Elements { get; set; } = new();
private static System.Timers.Timer Time = new System.Timers.Timer(5000);
protected async override Task OnInitializedAsync()
{
await base.OnInitializedAsync();
Time.Elapsed += async (Object? source, System.Timers.ElapsedEventArgs e) =>
{
await InvokeAsync(() => Refresh());
};
Time.AutoReset = true;
Time.Enabled = true;
Refresh();
}
public void Refresh()
{
Elements = Salmon.GetAllElements().ToList();
if (FilterByParent is not null)
Elements = Elements.Where(x => x.ParentId == FilterByParent).ToList();
StateHasChanged();
}
}

View File

@ -0,0 +1,26 @@
@if (Events is not null)
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Type</th>
</tr>
</thead>
<tbody>
@if (Events is not null)
@foreach (var e in Events)
{
<tr>
<td>@e.When</td>
<td>@e.Type</td>
</tr>
}
</tbody>
</table>
}
@code {
[Parameter]
public List<Event>? Events { get; set; } = null;
}

View File

@ -0,0 +1,34 @@
@using Salmon.Core.Cliff
@if(Value is null)
{
<span>(null)</span>
}
else
{
if (Predicate is not null && Predicate == "parent")
{
<a href=@($"Element/{System.Web.HttpUtility.UrlEncode(Value.ToString())}")>@Value.ToString()</a>
}
else if (Predicate is not null && Predicate == "Uri")
{
<a href=@Value.ToString()>@Value.ToString()</a>
}
else
{
<span>@Value.ToString()</span>
}
<CopyButton Value=@Value.ToString() />
}
@code {
[Parameter]
public object? Value { get; set; }
[Parameter]
public string Predicate { get; set; }
}

View File

@ -0,0 +1,34 @@
@if(Triplets is not null)
{
<table class="table">
<thead>
<tr>
<th>Dernier changement</th>
<th>Nom</th>
<th>Valeur</th>
</tr>
</thead>
<tbody>
@if (Triplets is not null)
@foreach (var t in Triplets)
{
<tr>
<td>@t.LastFlush</td>
<td>@t.predicate</td>
<td>
<PrettyValueDisplay Predicate=@t.predicate Value=@t.value />
</td>
</tr>
}
</tbody>
</table>
}
@code {
[Parameter]
public List<Triplet>? Triplets { get; set; } = null;
}

View File

@ -38,5 +38,11 @@ namespace Salmon.Web.Controllers
{ {
Instance.Set(triplets); Instance.Set(triplets);
} }
[HttpPost("Push/Events")]
public void Post([FromBody] IEnumerable<Event> events)
{
Instance.Add(events);
}
} }
} }

View File

@ -218,6 +218,8 @@ public class MongoDbInterface
new KeyValuePair<string, object>("_id", e.UniqueId), new KeyValuePair<string, object>("_id", e.UniqueId),
new KeyValuePair<string, object>("Thrower", e.ThrowerId), new KeyValuePair<string, object>("Thrower", e.ThrowerId),
new KeyValuePair<string, object>("Type", e.Type), new KeyValuePair<string, object>("Type", e.Type),
new KeyValuePair<string, object>("Description", e.Description),
new KeyValuePair<string, object>("Valence", (int)e.Valence),
new KeyValuePair<string, object>("When", e.When), new KeyValuePair<string, object>("When", e.When),
new KeyValuePair<string, object>("Properties", properties), new KeyValuePair<string, object>("Properties", properties),
}); });
@ -232,7 +234,19 @@ public class MongoDbInterface
private Event EventFromBson(BsonDocument bson) private Event EventFromBson(BsonDocument bson)
{ {
Event ret = new(bson["_id"].AsString, bson["Thrower"].AsString, bson["Type"].AsString, bson["When"].ToUniversalTime()); Event ret = new(
bson["_id"].AsString,
bson["Thrower"].AsString,
bson["Type"].AsString,
"",
bson["When"].ToUniversalTime());
if (bson.Contains("Description"))
ret.Description = bson["Description"].ToString() ?? "";
if (bson.Contains("Valence"))
ret.Valence = (Event.ValenceType)bson["Valence"].ToInt32();
foreach (var kv in bson["Properties"].AsBsonDocument) foreach (var kv in bson["Properties"].AsBsonDocument)
ret.Properties.Add(kv.Name, kv.Value); ret.Properties.Add(kv.Name, kv.Value);
@ -247,14 +261,25 @@ public class MongoDbInterface
return false; return false;
} }
public override async IAsyncEnumerable<Event> GetEvents(string? subject = null, DateTime? from = null, DateTime? to = null, int? limit = null, int? offset = null, Dictionary<string, object>? filters = null) public override async IAsyncEnumerable<Event> GetEvents(
string? subject = null,
DateTime? from = null,
DateTime? to = null,
int? limit = null,
int? offset = null,
Event.ValenceType? valenceType = null,
Dictionary<string, object>? filters = null
)
{ {
var conditions = new List<FilterDefinition<BsonDocument>>(); var conditions = new List<FilterDefinition<BsonDocument>>();
if (subject is not null) if (subject is not null)
conditions.Add(Builders<BsonDocument>.Filter.Eq("Thrower", subject)); conditions.Add(Builders<BsonDocument>.Filter.Eq("Thrower", subject));
if(filters is not null) if (valenceType is not null)
conditions.Add(Builders<BsonDocument>.Filter.Eq("Valence", (int)valenceType.Value));
if (filters is not null)
{ {
Func<Constraint, string, object, FilterDefinition<BsonDocument>> createFilter = (Constraint c, string property, object value) => Func<Constraint, string, object, FilterDefinition<BsonDocument>> createFilter = (Constraint c, string property, object value) =>
{ {

View File

@ -1,71 +1,3 @@
@page "/ElementList" @page "/ElementList"
@inject Salmon.Core.Instance Salmon; <ElementDeck />
<h3>Éléments</h3>
<div Style="display:flex;flex-wrap:wrap; height:100%;">
@foreach(var e in Elements)
{
<Card Class="col-6" Style="width:18rem;margin:10px;">
<CardHeader>
<NavLink href=@($"Element/{System.Web.HttpUtility.UrlEncode(e.UniqueId)}")>
<span class="oi oi-zoom-in" aria-hidden="true"></span>
</NavLink>
@e.LastType
</CardHeader>
<CardBody>
<CardTitle>@e.ShortName</CardTitle>
@if(!String.IsNullOrEmpty(e.LongName))
{
<CardSubTitle>
@e.LongName
</CardSubTitle>
}
<CardText>@e.Description</CardText>
</CardBody>
<ul class="list-group list-group-flush">
@foreach(var kv in e.ImportantProperties())
{
<li class="list-group-item">@kv.Key: @kv.Value</li>
}
<li class="list-group-item"><small>id: @e.UniqueId</small></li>
</ul>
@if(Salmon.GetLastElementUpdate(e.UniqueId) is not null)
{
<CardFooter>
<small class="text-muted">Last updated <i>@TimespanHelper.GetReadableTimespan(DateTime.Now - Salmon.GetLastElementUpdate(e.UniqueId).Value)</i></small>
</CardFooter>
}
</Card>
}
</div>
@code {
List<Element> Elements = new();
private static System.Timers.Timer Time = new System.Timers.Timer(5000);
protected async override Task OnInitializedAsync()
{
await base.OnInitializedAsync();
Time.Elapsed += async (Object? source, System.Timers.ElapsedEventArgs e) =>
{
await InvokeAsync(() => Refresh());
};
Time.AutoReset = true;
Time.Enabled = true;
Refresh();
}
public void Refresh()
{
Elements = Salmon.GetAllElements().ToList();
StateHasChanged();
}
}

View File

@ -22,46 +22,13 @@ else
<h3>@ThisElement.LongName</h3> <h3>@ThisElement.LongName</h3>
<h4>Propriétés</h4> <h4>Propriétés</h4>
<table class="table"> <TripletTable Triplets=@Triplets />
<thead>
<tr> <h4>Enfants</h4>
<th>Dernier changement</th> <ElementDeck FilterByParent=@Id />
<th>Nom</th>
<th>Valeur</th>
</tr>
</thead>
<tbody>
@if (Triplets is not null)
@foreach (var t in Triplets)
{
<tr>
<td>@t.LastFlush</td>
<td>@t.predicate</td>
<td>@t.value</td>
</tr>
}
</tbody>
</table>
<h4>Évènements</h4> <h4>Évènements</h4>
<table class="table"> <EventTable Events=@Events />
<thead>
<tr>
<th>Date</th>
<th>Type</th>
</tr>
</thead>
<tbody>
@if(Events is not null)
@foreach (var e in Events)
{
<tr>
<td>@e.When</td>
<td>@e.Type</td>
</tr>
}
</tbody>
</table>
} }
@code { @code {
@ -70,8 +37,8 @@ else
string? Error = $"Chargement..."; string? Error = $"Chargement...";
Salmon.Core.Element? ThisElement = null; Salmon.Core.Element? ThisElement = null;
List<Triplet>? Triplets = null; List<Triplet>? Triplets { get; set; } = null;
List<Event>? Events = null; List<Event>? Events { get; set; } = null;
@ -107,6 +74,8 @@ else
events.Add(e); events.Add(e);
Events = events; Events = events;
StateHasChanged();
} }

View File

@ -15,9 +15,6 @@
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet" /> <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet" />
<link href="_content/Blazor.Bootstrap/blazor.bootstrap.css" rel="stylesheet" /> <link href="_content/Blazor.Bootstrap/blazor.bootstrap.css" rel="stylesheet" />
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" /> <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link href="css/site.css" rel="stylesheet" /> <link href="css/site.css" rel="stylesheet" />
<link href="Salmon.Web.styles.css" rel="stylesheet" /> <link href="Salmon.Web.styles.css" rel="stylesheet" />
@ -47,6 +44,17 @@
<script>
window.clipboardCopy = {
copyText: function (text) {
navigator.clipboard.writeText(text).then(function () {
//alert("Copied to clipboard!");
})
.catch(function (error) {
alert(error);
});
}
};
</script>
</body> </body>
</html> </html>

View File

@ -6,6 +6,8 @@ using System.Text.Json.Serialization;
Salmon.Core.Instance CoreInstance; Salmon.Core.Instance CoreInstance;
Salmon.Model.Monitor.Drive _;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
builder.Services builder.Services
.AddControllers() .AddControllers()

View File

@ -10,6 +10,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Blazor.Bootstrap" Version="2.1.0" /> <PackageReference Include="Blazor.Bootstrap" Version="2.1.0" />
<PackageReference Include="FontAwesome" Version="4.7.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1" />
<PackageReference Include="MongoDB.Driver" Version="2.25.0" /> <PackageReference Include="MongoDB.Driver" Version="2.25.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />

View File

@ -1,5 +1,6 @@
<div class="top-row ps-3 navbar navbar-dark"> <div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid"> <div class="container-fluid">
<img src="favicon.png" style="width:32px; height:32px;" />
<a class="navbar-brand" href="">Salmon.Web</a> <a class="navbar-brand" href="">Salmon.Web</a>
<button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu"> <button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
@ -24,16 +25,6 @@
<span class="oi oi-home" aria-hidden="true"></span> Event List <span class="oi oi-home" aria-hidden="true"></span> Event List
</NavLink> </NavLink>
</div> </div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</NavLink>
</div>
</nav> </nav>
</div> </div>

View File

@ -8,6 +8,7 @@
@using Microsoft.JSInterop @using Microsoft.JSInterop
@using Salmon.Web @using Salmon.Web
@using Salmon.Web.Shared @using Salmon.Web.Shared
@using Salmon.Web.Components
@using Salmon.Core; @using Salmon.Core;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 804 KiB