Compare commits

..

No commits in common. "7b1216eec1909616619c1d45707b4a033c8c813e" and "261d2db417a2709a1ca553040fc63c43ce3f193c" have entirely different histories.

25 changed files with 145 additions and 347 deletions

View File

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

View File

@ -31,14 +31,7 @@ public abstract class Persistence
public abstract Task RegisterEvent(Event e);
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,
Event.ValenceType? valenceType = 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, Dictionary<string, object>? filters = null);
protected virtual void ExceptionCatched(Exception e)
{

View File

@ -2,22 +2,12 @@
public class Event
{
public enum ValenceType
{
Normal,
Error,
Emergency
}
public const string TYPE_STATE_CHANGED = "state_changed";
public const string TYPE_LOG = "log";
public string UniqueId { get; set; }
public string ThrowerId { get; set; }
public string Type { get; set; }
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 object? this[string key]
@ -42,12 +32,11 @@ public class Event
}
public Event(string uniqueId, string throwerId, string type, string description = "", DateTime? when = null)
public Event(string uniqueId, string throwerId, string type, DateTime? when = null)
{
UniqueId = uniqueId;
ThrowerId = throwerId;
Type = type;
Description = description;
if(when != null)
When = when.Value;
}
@ -55,28 +44,8 @@ public class Event
public static Event FromStateChange(string key, object? value, DateTime when)
{
string id = Guid.NewGuid().ToString();
var ret = new Event(id, key, TYPE_STATE_CHANGED, when:when);
var ret = new Event(id, key, TYPE_STATE_CHANGED, when);
ret[nameof(Triplet.value)] = value;
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,12 +54,6 @@ public class Instance
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
{
var triplets = State.Get(id).ToList();

View File

@ -1,12 +0,0 @@
<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

@ -1,14 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<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>
</Project>

View File

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

View File

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

View File

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

View File

@ -1,29 +0,0 @@
@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

@ -1,40 +0,0 @@
@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

@ -1,39 +0,0 @@
@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

@ -1,26 +0,0 @@
@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

@ -1,34 +0,0 @@
@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

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

View File

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

View File

@ -1,3 +1,71 @@
@page "/ElementList"
<ElementDeck />
@inject Salmon.Core.Instance Salmon;
<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,13 +22,46 @@ else
<h3>@ThisElement.LongName</h3>
<h4>Propriétés</h4>
<TripletTable Triplets=@Triplets />
<h4>Enfants</h4>
<ElementDeck FilterByParent=@Id />
<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>@t.value</td>
</tr>
}
</tbody>
</table>
<h4>Évènements</h4>
<EventTable Events=@Events />
<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 {
@ -37,8 +70,8 @@ else
string? Error = $"Chargement...";
Salmon.Core.Element? ThisElement = null;
List<Triplet>? Triplets { get; set; } = null;
List<Event>? Events { get; set; } = null;
List<Triplet>? Triplets = null;
List<Event>? Events = null;
@ -74,8 +107,6 @@ else
events.Add(e);
Events = events;
StateHasChanged();
}

View File

@ -15,6 +15,9 @@
<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 rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link href="css/site.css" rel="stylesheet" />
<link href="Salmon.Web.styles.css" rel="stylesheet" />
@ -44,17 +47,6 @@
<script>
window.clipboardCopy = {
copyText: function (text) {
navigator.clipboard.writeText(text).then(function () {
//alert("Copied to clipboard!");
})
.catch(function (error) {
alert(error);
});
}
};
</script>
</body>
</html>

View File

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

View File

@ -10,7 +10,6 @@
<ItemGroup>
<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="MongoDB.Driver" Version="2.25.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />

View File

@ -1,6 +1,5 @@
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<img src="favicon.png" style="width:32px; height:32px;" />
<a class="navbar-brand" href="">Salmon.Web</a>
<button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
@ -25,6 +24,16 @@
<span class="oi oi-home" aria-hidden="true"></span> Event List
</NavLink>
</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>
</div>

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 804 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB