testing remote stuff

This commit is contained in:
kkb 2023-11-17 17:12:41 +01:00
parent 1e05d4576d
commit 3c9ccaafeb
374 changed files with 10526 additions and 2037 deletions

View file

@ -1,4 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Driver;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Driver;

View file

@ -97,9 +97,9 @@
<MudNavLink Href=@Navigation.Management.Hosts.Index Match="NavLinkMatch.Prefix">
Hosts
</MudNavLink>
@*<MudNavLink Href=@Navigation.Management.HostGroups.Index Match="NavLinkMatch.Prefix">
<MudNavLink Href=@Navigation.Management.HostGroups.Index Match="NavLinkMatch.Prefix">
Host Groups
</MudNavLink>*@
</MudNavLink>
<MudNavLink Href=@Navigation.Management.Agents.Index Match="NavLinkMatch.Prefix">
Agents
</MudNavLink>

View file

@ -12,6 +12,5 @@
[CascadingParameter] public IReadOnlyDictionary<string, object>? RouteValues { get; set; }
private bool _open = true;
public void Toggle() => _open = !_open;
}

View file

@ -514,11 +514,23 @@ public static class Navigation
{
public const string Index = "management/hostgroups";
public const string Details = "management/hostgroups/{groupId}";
public const string Hosts = "management/hostgroups/{groupId}/hosts";
public const string HostsAssign = "management/hostgroups/{groupId}/hosts/assign";
public static string DetailsHref(string? groupId)
{
return Details.Replace("{groupId}", groupId);
}
public static string HostsHref(string? groupId)
{
return Hosts.Replace("{groupId}", groupId);
}
public static string HostsAssignHref(string? groupId)
{
return HostsAssign.Replace("{groupId}", groupId);
}
}
}

View file

@ -4,7 +4,7 @@
<TargetFramework>net7.0</TargetFramework>
<Product>Insight</Product>
<AssemblyName>web</AssemblyName>
<AssemblyVersion>2023.9.21.1</AssemblyVersion>
<AssemblyVersion>2023.11.17.0</AssemblyVersion>
<RootNamespace>Insight.Web</RootNamespace>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
@ -28,17 +28,10 @@
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
<PackageReference Include="Blazored.LocalStorage" Version="4.4.0" />
<PackageReference Include="Blazored.SessionStorage" Version="2.4.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.11" />
<PackageReference Include="MudBlazor" Version="6.10.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.13" />
<PackageReference Include="MudBlazor" Version="6.11.0" />
<PackageReference Include="Vaitr.Bus" Version="0.1.3" />
<!--Unix Serilog stuff-->
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
<PackageReference Include="System.Text.Encoding.Extensions" Version="4.3.0" />
<PackageReference Include="System.Runtime.Handles" Version="4.3.0" />
<PackageReference Include="System.IO" Version="4.3.0" />
<PackageReference Include="System.Runtime.InteropServices" Version="4.3.0" />
<PackageReference Include="System.Threading" Version="4.3.0" />
<PackageReference Include="System.Threading.Tasks" Version="4.3.0" />
</ItemGroup>
<ItemGroup>
@ -49,4 +42,10 @@
<Folder Include="wwwroot\media\" />
</ItemGroup>
<ItemGroup>
<None Update="localhost.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View file

@ -0,0 +1,9 @@
using Insight.Web.Network.Remote;
namespace Insight.Web.Messages;
public class RemoteMessages
{
public record RemoteConnected(RemoteSession RemoteSession);
public record RemoteDisconnected(RemoteSession RemoteSession);
}

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Insight.Web.Models.Account;
using Microsoft.AspNetCore.Authentication;

View file

@ -0,0 +1,4 @@
namespace Insight.Web.Models;
public record RemoteClientConnected(string Id);
public record RemoteClientDisconnected(string Id);

View file

@ -1,22 +1,22 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Messages;
using Insight.Domain.Messages.Agent;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Vaitr.Bus;
namespace Insight.Web.Network.Handlers;
namespace Insight.Web.Network.Broker.Handlers;
public class ConsoleHandler : IMessageHandler<WebSession>
public class AgentHandler : IMessageHandler<WebSession>
{
private readonly Bus _bus;
public ConsoleHandler(Bus bus)
public AgentHandler(Bus bus)
{
_bus = bus;
}
public async ValueTask HandleAsync<TMessage>(WebSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
if (message is Proxy<ConsoleQuery> consoleQuery)
if (message is Proxy<Response> consoleQuery)
{
await _bus.PublishAsync(consoleQuery, cancellationToken);
}

View file

@ -1,8 +1,8 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Messages;
using Insight.Domain.Network;
using Vaitr.Network;
namespace Insight.Web.Network;
namespace Insight.Web.Network.Broker;
public class WebSession : TcpSession<IMessage>
{

View file

@ -0,0 +1,107 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Remote.Messages;
using Vaitr.Bus;
using Vaitr.Network;
namespace Insight.Web.Network.Remote.Handlers;
public class RemoteHandler : IMessageHandler<RemoteSession>
{
private readonly Bus _bus;
private readonly ISessionPool<RemoteSession, IMessage> _remotePool;
private readonly ILogger<RemoteHandler> _logger;
public RemoteHandler(Bus bus, ISessionPool<RemoteSession, IMessage> remotePool, ILogger<RemoteHandler> logger)
{
_bus = bus;
_remotePool = remotePool;
_logger = logger;
}
public async ValueTask HandleAsync<TMessage>(RemoteSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
if (message is RemoteSessionRequest sessionRequest)
{
await OnSessionRequest(sender, sessionRequest, cancellationToken);
}
else if (message is CastRequestResponse castRequestResponse)
{
await OnCastRequestResponse(sender, castRequestResponse, cancellationToken);
}
else if (message is CastMetric metricData)
{
await OnMetricData(sender, metricData, cancellationToken);
}
else if (message is CastScreen screenData)
{
await OnScreenData(sender, screenData, cancellationToken);
}
else if (message is CastCursor cursorData)
{
await OnCursorData(sender, cursorData, cancellationToken);
}
else if (message is CastClipboardReceived clipboardData)
{
await OnClipboardData(sender, clipboardData, cancellationToken);
}
else if (message is CastAudio audioData)
{
await OnAudioData(sender, audioData, cancellationToken);
}
}
private async Task OnSessionRequest(RemoteSession session, RemoteSessionRequest sessionRequest, CancellationToken cancellationToken)
{
_logger.LogInformation($"Remote {session.Id} => SessionRequest");
session.Mode = sessionRequest.Mode;
await session.SendAsync(new RemoteSessionResponse
{
SessionId = session.Id
}, cancellationToken);
}
private async Task OnCastRequestResponse(RemoteSession session, CastRequestResponse castRequestResponse, CancellationToken cancellationToken)
{
_logger.LogInformation($"Remote {castRequestResponse.Id} => CastRequestResponse");
await _bus.PublishAsync(castRequestResponse, cancellationToken);
}
private async Task OnMetricData(RemoteSession session, CastMetric streamMetrics, CancellationToken cancellationToken)
{
//_logger.LogInformation($"Remote {streamMetrics.Id} => MetricData");
await _bus.PublishAsync(streamMetrics, cancellationToken);
}
private async Task OnScreenData(RemoteSession session, CastScreen screenData, CancellationToken cancellationToken)
{
//_logger.LogInformation($"Remote {screenData.Id} => ScreenData");
await _bus.PublishAsync(screenData, cancellationToken);
}
private async Task OnCursorData(RemoteSession session, CastCursor cursorChanged, CancellationToken cancellationToken)
{
//_logger.LogInformation($"Remote {cursorChanged.Id} => CursorData");
await _bus.PublishAsync(cursorChanged, cancellationToken);
}
private async Task OnClipboardData(RemoteSession session, CastClipboardReceived clipboardChanged, CancellationToken cancellationToken)
{
_logger.LogInformation($"Remote {session.Id} => ClipboardData");
await _bus.PublishAsync(clipboardChanged, cancellationToken);
}
private async Task OnAudioData(RemoteSession session, CastAudio audioSample, CancellationToken cancellationToken)
{
_logger.LogInformation($"Remote {session.Id} => AudioData");
await _bus.PublishAsync(audioSample, cancellationToken);
}
}

View file

@ -0,0 +1,87 @@
using Insight.Domain.Enums;
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Remote.Messages;
using Vaitr.Bus;
using Vaitr.Network;
using static Insight.Web.Messages.RemoteMessages;
namespace Insight.Web.Network.Remote;
public class RemoteSession : TcpSession<IMessage>
{
public string Id { get; }
public RemoteControlMode Mode { get; set; }
private readonly Bus _bus;
private readonly IEnumerable<IMessageHandler<RemoteSession>> _handlers;
public RemoteSession(
Bus bus,
IEnumerable<IMessageHandler<RemoteSession>> handlers,
ISerializer<IMessage> serializer,
ILogger<RemoteSession> logger) : base(serializer, logger)
{
Id = GenerateRandomId();
_bus = bus;
_handlers = handlers;
}
protected override async ValueTask OnConnectedAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Remote ({ep?}) connected", RemoteEndPoint);
//return;
await _bus.PublishAsync(new RemoteDisconnected(this), default);
}
protected override async ValueTask OnDisconnectedAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Remote ({ep?}) disconnected", RemoteEndPoint);
await _bus.PublishAsync(new RemoteDisconnected(this), default);
}
protected override async ValueTask OnSentAsync(IPacketContext<IMessage> context, CancellationToken cancellationToken)
{
//await base.OnSentAsync(context, cancellationToken);
}
protected override async ValueTask OnReceivedAsync(IPacketContext<IMessage> context, CancellationToken cancellationToken)
{
//await base.OnReceivedAsync(context, cancellationToken);
foreach (var handler in _handlers)
{
try
{
await handler.HandleAsync(this, context.Packet, cancellationToken);
}
catch (Exception ex)
{
_logger.LogWarning("Remote ({ep?}) {ex}", RemoteEndPoint, ex.ToString());
}
}
}
protected override async ValueTask OnHeartbeatAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Remote ({ep?}) Heartbeat", RemoteEndPoint);
}
public async Task ScreenDataAckAsync(CastScreen screenData, CancellationToken cancellationToken)
{
await SendAsync(new CastScreenReceived(screenData), cancellationToken);
}
private static string GenerateRandomId()
{
var random = new Random();
string? sessionId = string.Empty;
for (var i = 0; i < 3; i++) sessionId += random.Next(0, 999).ToString().PadLeft(3, '0');
return sessionId;
}
}

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;
@ -66,7 +65,7 @@ public partial class Hosts
var query = Database.HostSystemGroup()
.Aggregate()
.Match(Builders<HostGroupEntity>.Filter.Eq(p => p.Name, GroupName))
.Match(Builders<HostSysGroupEntity>.Filter.Eq(p => p.Name, GroupName))
.Lookup("host", "_host", "_id", "hosts")
.Match(new BsonDocument("hosts", new BsonDocument
{

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
@ -36,12 +35,12 @@ public partial class Index
{
try
{
var filter = Builders<HostGroupEntity>.Filter.Empty;
var filter = Builders<HostSysGroupEntity>.Filter.Empty;
if (string.IsNullOrWhiteSpace(Search) is false)
{
var regex = new BsonRegularExpression(new Regex(Search, RegexOptions.IgnoreCase));
filter &= Builders<HostGroupEntity>.Filter.Regex(x => x.Name, regex);
filter &= Builders<HostSysGroupEntity>.Filter.Regex(x => x.Name, regex);
}
var query = Database.HostSystemGroup()

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;

View file

@ -4,7 +4,7 @@
@ref="Container"
@bind-Search="Search"
Title="@Title"
Breadcrumbs="@Breadcrumbs"
Breadcrumbs="@_breadcrumbs"
Data="LoadDataAsync">
<Header>
<MudTh>

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;
@ -24,18 +23,19 @@ public partial class Hosts
[Inject] private ISnackbar Snackbar { get; init; } = default!;
[Inject] private NavigationManager NavigationManager { get; init; } = default!;
private TableContainer<ViewModel>? Container { get; set; }
private readonly List<BreadcrumbItem> _breadcrumbs = new();
private string Title { get; set; } = Global.Name;
private List<BreadcrumbItem> Breadcrumbs { get; } = new();
private TableContainer<ViewModel>? Container { get; set; }
private string? Search { get; set; }
protected override void OnInitialized()
{
OsName = OsName.UriEscape(true);
Breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
Breadcrumbs.Add(new BreadcrumbItem("Inventory", href: "#", true));
Breadcrumbs.Add(new BreadcrumbItem("OS", href: Navigation.Inventory.Systems.Os.Index));
_breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
_breadcrumbs.Add(new BreadcrumbItem("Inventory", href: "#", true));
_breadcrumbs.Add(new BreadcrumbItem("OS", href: Navigation.Inventory.Systems.Os.Index));
if (string.IsNullOrWhiteSpace(OsName))
{
@ -45,8 +45,9 @@ public partial class Hosts
}
Title = $"Inventory » OS » {OsName} » HostsInsight";
Breadcrumbs.Add(new BreadcrumbItem(OsName, href: "#", true));
Breadcrumbs.Add(new BreadcrumbItem("Hosts", href: "#", true));
_breadcrumbs.Add(new BreadcrumbItem(OsName, href: "#", true));
_breadcrumbs.Add(new BreadcrumbItem("Hosts", href: "#", true));
}
private async Task<TableData<ViewModel>> LoadDataAsync(TableState state)

View file

@ -1,4 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,4 +1,4 @@
@using static Insight.Domain.Messages.Agent.StoragePool;
@using static Insight.Domain.Network.Agent.Messages.StoragePool;
@inherits ComponentBase
<TableContainer T="ViewModel"

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,4 +1,4 @@
@using static Insight.Domain.Messages.Agent.Update;
@using static Insight.Domain.Network.Agent.Messages.Update;
@inherits ComponentBase
<TableContainer T="ViewModel"

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Insight.Web.Extensions;
@ -68,7 +67,7 @@ public partial class Hosts
var query = Database.HostSystemUser()
.Aggregate()
.Match(Builders<HostUserEntity>.Filter.Eq(p => p.Name, UserName))
.Match(Builders<HostSysUserEntity>.Filter.Eq(p => p.Name, UserName))
.Lookup("host", "_host", "_id", "hosts")
.Match(new BsonDocument("hosts", new BsonDocument
{

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
@ -36,12 +35,12 @@ public partial class Index
{
try
{
var filter = Builders<HostUserEntity>.Filter.Empty;
var filter = Builders<HostSysUserEntity>.Filter.Empty;
if (string.IsNullOrWhiteSpace(Search) is false)
{
var regex = new BsonRegularExpression(new Regex(Search, RegexOptions.IgnoreCase));
filter &= Builders<HostUserEntity>.Filter.Regex(x => x.Name, regex);
filter &= Builders<HostSysUserEntity>.Filter.Regex(x => x.Name, regex);
}
var query = Database.HostSystemUser()

View file

@ -1,4 +1,4 @@
@using static Insight.Domain.Messages.Agent.VirtualMaschine;
@using static Insight.Domain.Network.Agent.Messages.VirtualMaschine;
@inherits ComponentBase
<TableContainer T="ViewModel"

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -7,14 +7,14 @@
</MudText>
</MudDrawerHeader>
<MudStack Class="px-6">
@if (Account is not null)
@if (_model is not null)
{
<EditForm Model="@Account" OnValidSubmit="SubmitAsync">
<MudTextField T="string" Label="E-Mail" Variant="Variant.Text" Margin="Margin.Dense" @bind-Value="Account.Email" For="@(() => Account.Email)" Required="true" />
<MudTextField T="string" Label="E-Mail (Confirmation)" Variant="Variant.Text" Margin="Margin.Dense" @bind-Value="Account.EmailConfirm" For="@(() => Account.EmailConfirm)" Required="true" />
<MudTextField T="string" Label="Password" Variant="Variant.Text" Margin="Margin.Dense" @bind-Value="Account.Password" For="@(() => Account.Password)" Required="true"
<EditForm Model="@_model" OnValidSubmit="SubmitAsync">
<MudTextField T="string" Label="E-Mail" Variant="Variant.Text" Margin="Margin.Dense" @bind-Value="_model.Email" For="@(() => _model.Email)" Required="true" />
<MudTextField T="string" Label="E-Mail (Confirmation)" Variant="Variant.Text" Margin="Margin.Dense" @bind-Value="_model.EmailConfirm" For="@(() => _model.EmailConfirm)" Required="true" />
<MudTextField T="string" Label="Password" Variant="Variant.Text" Margin="Margin.Dense" @bind-Value="_model.Password" For="@(() => _model.Password)" Required="true"
InputType="@PasswordInput" Adornment="Adornment.End" AdornmentIcon="@PasswordIcon" OnAdornmentClick="TogglePasswordVisible" />
<MudTextField T="string" Label="Password (Confirmation)" Variant="Variant.Text" Margin="Margin.Dense" @bind-Value="Account.PasswordConfirm" For="@(() => Account.PasswordConfirm)" Required="true"
<MudTextField T="string" Label="Password (Confirmation)" Variant="Variant.Text" Margin="Margin.Dense" @bind-Value="_model.PasswordConfirm" For="@(() => _model.PasswordConfirm)" Required="true"
InputType="@PasswordConfirmInput" Adornment="Adornment.End" AdornmentIcon="@PasswordConfirmIcon" OnAdornmentClick="TogglePasswordConfirmVisible" />
<MudStack Justify="Justify.Center" Row Class="mt-7">
@ -39,12 +39,6 @@
private InputType PasswordInput { get; set; } = InputType.Password;
private InputType PasswordConfirmInput { get; set; } = InputType.Password;
public void Toggle()
{
_visible = !_visible;
StateHasChanged();
}
private void TogglePasswordVisible()
{
if (PasswordVisible)

View file

@ -14,26 +14,34 @@ public partial class AccountCreateDialog
[Inject] private ISnackbar Snackbar { get; init; } = default!;
[Inject] private ILogger<AccountCreateDialog> Logger { get; init; } = default!;
private IndexCreateDialogModel? Account { get; set; } = new();
private IndexCreateDialogModel? _model;
public async Task ToggleAsync()
{
_model = new();
_visible = !_visible;
await InvokeAsync(StateHasChanged);
}
private async Task SubmitAsync()
{
if (Account is null) return;
if (_model is null) return;
try
{
if (string.IsNullOrWhiteSpace(Account.Email) is false && Account.Email != Account.EmailConfirm)
if (string.IsNullOrWhiteSpace(_model.Email) is false && _model.Email != _model.EmailConfirm)
{
Notification.Error(Snackbar, "Email not matching");
return;
}
if (string.IsNullOrWhiteSpace(Account.Password) is false && Account.Password != Account.PasswordConfirm)
if (string.IsNullOrWhiteSpace(_model.Password) is false && _model.Password != _model.PasswordConfirm)
{
Notification.Error(Snackbar, "Password not matching");
return;
}
var result = await IdentityService.CreateUserAsync(Account.Email, Account.Password);
var result = await IdentityService.CreateUserAsync(_model.Email, _model.Password);
if (result.Succeeded is false)
{
@ -57,7 +65,7 @@ public partial class AccountCreateDialog
}
finally
{
Account = new();
_model = new();
_visible = false;
}
}

View file

@ -7,11 +7,11 @@
</MudText>
</MudDrawerHeader>
<MudStack Class="px-6">
@if (Account is not null)
@if (_model is not null)
{
<EditForm Model="@Account" OnValidSubmit="SubmitAsync">
<EditForm Model="@_model" OnValidSubmit="SubmitAsync">
<MudStack Spacing="5">
<MudTextField T="string" @bind-Value="Account.Email" For="()=>Account.Email" Label="E-Mail" Variant="Variant.Text" Margin="Margin.Dense" ReadOnly />
<MudTextField T="string" @bind-Value="_model.Email" For="()=>_model.Email" Label="E-Mail" Variant="Variant.Text" Margin="Margin.Dense" ReadOnly />
</MudStack>
<MudStack Justify="Justify.Center" Row Class="mt-7">
<MudButton OnClick="()=>_visible = false" Variant="Variant.Outlined" DisableElevation Size="Size.Large" Color="Color.Surface">
@ -28,9 +28,4 @@
@code {
private bool _visible;
public void Toggle()
{
_visible = !_visible;
StateHasChanged();
}
}

View file

@ -1,7 +1,7 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Bson;
using MongoDB.Driver;
using MudBlazor;
@ -9,22 +9,40 @@ namespace Insight.Web.Pages.Management.Accounts;
public partial class AccountDeleteDialog
{
[CascadingParameter(Name = "Account")] public InsightUser? Account { get; set; }
[Parameter] public EventCallback OnChanges { get; set; }
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
[Inject] private ILogger<AccountDeleteDialog> Logger { get; init; } = default!;
private InsightUser? _model;
public async void ToggleAsync(string? id)
{
if (id is null) return;
try
{
_model = await Database.User().Find(p => p.Id == new ObjectId(id)).FirstAsync();
_visible = !_visible;
}
catch (Exception)
{
Notification.Error(Snackbar);
}
await InvokeAsync(StateHasChanged);
}
private async Task SubmitAsync()
{
if (Account is null) return;
if (_model is null) return;
try
{
await Database.User()
.DeleteOneAsync(Builders<InsightUser>
.Filter.Eq(p => p.Id, Account.Id),
.Filter.Eq(p => p.Id, _model.Id),
cancellationToken: default).ConfigureAwait(false);
Notification.Success(Snackbar);

View file

@ -7,11 +7,11 @@
</MudText>
</MudDrawerHeader>
<MudStack Class="px-6">
@if (Account is not null)
@if (_model is not null)
{
<EditForm Model="@Account" OnValidSubmit="SubmitAsync">
<EditForm Model="@_model" OnValidSubmit="SubmitAsync">
<MudStack Spacing="5">
<MudTextField T="string" @bind-Value="Account.Email" For="()=>Account.Email" Label="E-Mail" Variant="Variant.Text" Margin="Margin.Dense" AutoFocus Clearable />
<MudTextField T="string" @bind-Value="_model.Email" For="()=>_model.Email" Label="E-Mail" Variant="Variant.Text" Margin="Margin.Dense" AutoFocus Clearable />
</MudStack>
<MudStack Justify="Justify.Center" Row Class="mt-7">
<MudButton OnClick="()=>_visible = false" Variant="Variant.Outlined" DisableElevation Size="Size.Large" Color="Color.Surface">
@ -28,9 +28,4 @@
@code {
private bool _visible;
public void Toggle()
{
_visible = !_visible;
StateHasChanged();
}
}

View file

@ -1,6 +1,7 @@
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Bson;
using MongoDB.Driver;
using MudBlazor;
@ -8,28 +9,47 @@ namespace Insight.Web.Pages.Management.Accounts;
public partial class AccountEditDialog
{
[CascadingParameter(Name = "Account")] public InsightUser? Account { get; set; }
[Parameter] public EventCallback OnChanges { get; set; }
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
[Inject] private ILogger<AccountEditDialog> Logger { get; init; } = default!;
private async Task SubmitAsync()
private InsightUser? _model;
public async void ToggleAsync(string? id)
{
if (Account is null) return;
if (id is null) return;
try
{
//await Database.Users()
// .UpdateOneAsync(Builders<InsightUser>
// .Filter
// .Eq(p => p.Id, Account.Id), Builders<InsightUser>
// .Update
// .Set(p => p.Updated, DateTime.Now)
// .Set(p => p.Name, Host.Name)
// .Set(p => p.Description, Host.Description),
// cancellationToken: default);
_model = await Database.User().Find(p => p.Id == new ObjectId(id)).FirstAsync();
_visible = !_visible;
}
catch (Exception)
{
Notification.Error(Snackbar);
}
await InvokeAsync(StateHasChanged);
}
private async Task SubmitAsync()
{
if (_model is null) return;
try
{
await Database.User()
.UpdateOneAsync(Builders<InsightUser>
.Filter
.Eq(p => p.Id, _model.Id), Builders<InsightUser>
.Update
.Set(p => p.Email, _model.Email)
.Set(p => p.NormalizedEmail, _model.Email.ToUpperInvariant())
.Set(p => p.UserName, _model.Email)
.Set(p => p.NormalizedUserName, _model.Email.ToUpperInvariant()),
cancellationToken: default);
Notification.Success(Snackbar);

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Bson;

View file

@ -7,7 +7,7 @@
Title="@_title"
Breadcrumbs="@_breadcrumbs"
Data="LoadDataAsync"
OnAdd="()=>_createDialog?.Toggle()">
OnAdd="()=>_createDialog?.ToggleAsync()">
<Header>
<MudTh>
<MudTableSortLabel SortLabel="Email" T="InsightUser">
@ -39,35 +39,21 @@
</MudTd>
</RowTemplate>
<ActionTemplate>
<MudMenuItem OnClick="@(()=>OnEdit(context))">
<MudMenuItem OnClick="@(()=>_editDialog?.ToggleAsync(context.Id.ToString()))">
Edit
</MudMenuItem>
<MudMenuItem OnClick="@(()=>OnDelete(context))">
<MudMenuItem OnClick="@(()=>_deleteDialog?.ToggleAsync(context.Id.ToString()))">
Delete
</MudMenuItem>
</ActionTemplate>
</TableContainer>
<CascadingValue Name="Account" Value="@_selected">
<AccountCreateDialog @ref="_createDialog" OnChanges="OnRefreshAsync" />
<AccountEditDialog @ref="_editDialog" OnChanges="OnRefreshAsync" />
<AccountDeleteDialog @ref="_deleteDialog" OnChanges="OnRefreshAsync" />
</CascadingValue>
<AccountCreateDialog @ref="_createDialog" OnChanges="OnRefreshAsync" />
<AccountEditDialog @ref="_editDialog" OnChanges="OnRefreshAsync" />
<AccountDeleteDialog @ref="_deleteDialog" OnChanges="OnRefreshAsync" />
@code {
private AccountCreateDialog? _createDialog;
private AccountEditDialog? _editDialog;
private AccountDeleteDialog? _deleteDialog;
private void OnEdit(InsightUser model)
{
_selected = model;
_editDialog?.Toggle();
}
private void OnDelete(InsightUser model)
{
_selected = model;
_deleteDialog?.Toggle();
}
}

View file

@ -20,7 +20,6 @@ public partial class Index
private TableContainer<InsightUser>? _container;
private string? _search;
private InsightUser? _selected;
private readonly string _title = "AccountsInsight";
private readonly List<BreadcrumbItem> _breadcrumbs = new()

View file

@ -7,11 +7,11 @@
</MudText>
</MudDrawerHeader>
<MudStack Class="px-6">
@if (Agent is not null)
@if (_model is not null)
{
<EditForm Model="@Agent" OnValidSubmit="SubmitAsync">
<EditForm Model="@_model" OnValidSubmit="SubmitAsync">
<MudStack Spacing="5">
<MudTextField T="string" @bind-Value="Agent.Serial" For="()=>Agent.Serial" Label="Serial" Variant="Variant.Text" Margin="Margin.Dense" ReadOnly />
<MudTextField T="string" @bind-Value="_model.Serial" For="()=>_model.Serial" Label="Serial" Variant="Variant.Text" Margin="Margin.Dense" ReadOnly />
</MudStack>
<MudStack Justify="Justify.Center" Row Class="mt-7">
<MudButton OnClick="()=>_visible = false" Variant="Variant.Outlined" DisableElevation Size="Size.Large" Color="Color.Surface">
@ -28,9 +28,4 @@
@code {
private bool _visible;
public void Toggle()
{
_visible = !_visible;
StateHasChanged();
}
}

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Driver;
@ -9,29 +8,46 @@ namespace Insight.Web.Pages.Management.Agents;
public partial class AgentDeleteDialog
{
[CascadingParameter(Name = "Agent")] public ViewModel? Agent { get; set; }
[Parameter] public EventCallback OnChanges { get; set; }
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
[Inject] private ILogger<AgentDeleteDialog> Logger { get; init; } = default!;
private AgentEntity? _model;
public async void ToggleAsync(string? id)
{
if (id is null) return;
try
{
_model = await Database.Agent().Find(p => p.Id == id).FirstAsync();
_visible = !_visible;
}
catch (Exception)
{
Notification.Error(Snackbar);
}
await InvokeAsync(StateHasChanged);
}
private async Task SubmitAsync()
{
if (Agent is null) return;
if (_model is null) return;
try
{
await Database.Agent()
.DeleteOneAsync(Builders<AgentEntity>
.Filter.Eq(p => p.Id, Agent.Id),
.Filter.Eq(p => p.Id, _model.Id),
cancellationToken: default).ConfigureAwait(false);
await Database.Host()
.UpdateOneAsync(Builders<HostEntity>
.Filter
.Eq(p => p.Agent, Agent.Id), Builders<HostEntity>
.Eq(p => p.Agent, _model.Id), Builders<HostEntity>
.Update
.Set(p => p.Agent, null))
.ConfigureAwait(false);

View file

@ -7,12 +7,12 @@
</MudText>
</MudDrawerHeader>
<MudStack Class="px-6">
@if (Agent is not null)
@if (_model is not null)
{
@if (Agent.Hosts is not null && Agent.Hosts.Any())
@if (_model.Hosts is not null && _model.Hosts.Any())
{
<MudStack Justify="Justify.Center">
<MudButton Href="@Navigation.Management.Hosts.DetailsHref(Agent?.Hosts?.FirstOrDefault()?.Id?.ToString())" Variant="Variant.Filled" Size="Size.Large" Color="Color.Info" DisableElevation="true">
<MudButton Href="@Navigation.Management.Hosts.DetailsHref(_model?.Hosts?.FirstOrDefault()?.Id)" Variant="Variant.Filled" Size="Size.Large" Color="Color.Info" DisableElevation="true">
Select
</MudButton>
<MudButton OnClick="UnassignAsync" Variant="Variant.Filled" DisableElevation Size="Size.Large" Color="Color.Error">
@ -26,7 +26,7 @@
else
{
<MudStack Justify="Justify.Center">
<MudButton Href="@Navigation.Management.Agents.HostAssingHref(Agent.Id?.ToString())" Variant="Variant.Filled" DisableElevation Size="Size.Large" Color="Color.Error">
<MudButton Href="@Navigation.Management.Agents.HostAssingHref(_model.Id)" Variant="Variant.Filled" DisableElevation Size="Size.Large" Color="Color.Error">
Assign
</MudButton>
<MudButton OnClick="()=>_visible = false" Variant="Variant.Outlined" DisableElevation Size="Size.Large" Color="Color.Surface">
@ -40,10 +40,4 @@
@code {
private bool _visible;
public void Toggle()
{
_visible = !_visible;
StateHasChanged();
}
}

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Driver;
@ -9,7 +8,6 @@ namespace Insight.Web.Pages.Management.Agents;
public partial class AgentHostDialog
{
[CascadingParameter(Name = "Agent")] public AgentEntity? Agent { get; set; }
[Parameter] public EventCallback OnChanges { get; set; }
[Inject] private IMongoDatabase Database { get; init; } = default!;
@ -18,13 +16,37 @@ public partial class AgentHostDialog
private enum Content { Unassign, Assign }
private async Task UnassignAsync()
private AgentEntity? _model;
public async void ToggleAsync(string? id)
{
if (Agent is null) return;
if (id is null) return;
try
{
await Database.Host().UpdateOneAsync(p => p.Agent == Agent.Id.ToString(), Builders<HostEntity>
_model = await Database.Agent()
.Aggregate()
.Match(Builders<AgentEntity>.Filter.Eq(p => p.Id, id))
.Lookup<AgentEntity, HostEntity, AgentEntity>(Database.Host(), p => p.Id, p => p.Agent, p => p.Hosts)
.FirstOrDefaultAsync(default);
_visible = !_visible;
}
catch (Exception)
{
Notification.Error(Snackbar);
}
await InvokeAsync(StateHasChanged);
}
private async Task UnassignAsync()
{
if (_model is null) return;
try
{
await Database.Host().UpdateOneAsync(p => p.Agent == _model.Id, Builders<HostEntity>
.Update.Set(p => p.Agent, null));
Notification.Success(Snackbar);

View file

@ -13,7 +13,7 @@
</MudItem>
<MudItem xs="12" sm="6" md="6" lg="3">
<KeyValueCard T="string" OnClick="()=>_hostDialog?.Toggle()" Key="Host" Value="@(_agent?.Hosts?.FirstOrDefault()?.Name ?? "-")" Icon="@Icons.Material.Outlined.Devices" IconColor="@Color.Primary" />
<KeyValueCard T="string" OnClick="()=>_hostDialog?.ToggleAsync(_agent?.Id)" Key="Host" Value="@(_agent?.Hosts?.FirstOrDefault()?.Name ?? "-")" Icon="@Icons.Material.Outlined.Devices" IconColor="@Color.Primary" />
</MudItem>
<MudItem xs="12" sm="6" md="6" lg="3">
@ -75,9 +75,7 @@
</Content>
</BaseContainer>
<CascadingValue Name="Agent" Value="@_agent">
<AgentHostDialog @ref="_hostDialog" OnChanges="OnRefreshAsync" />
</CascadingValue>
<AgentHostDialog @ref="_hostDialog" OnChanges="OnRefreshAsync" />
@code {
private AgentHostDialog? _hostDialog;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -7,7 +7,7 @@
Title="@Title"
Breadcrumbs="@Breadcrumbs"
Data="LoadDataAsync"
OnAdd="()=>_createDialog?.Toggle()">
OnAdd="()=>_createDialog?.ToggleAsync()">
<Header>
<MudTh>
<MudTableSortLabel SortLabel="Name" T="HostEntity">

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -57,7 +57,7 @@
</MudTd>
</RowTemplate>
<ActionTemplate>
<MudMenuItem OnClick="@(()=>OnDelete(context))">
<MudMenuItem OnClick="@(()=>_deleteDialog?.ToggleAsync(context.Id))">
Delete
</MudMenuItem>
</ActionTemplate>
@ -79,9 +79,7 @@
</Actions>
</ActionDialog>
<CascadingValue Name="Agent" Value="@Model">
<AgentDeleteDialog @ref="_deleteDialog" OnChanges="OnRefreshAsync" />
</CascadingValue>
<AgentDeleteDialog @ref="_deleteDialog" OnChanges="OnRefreshAsync" />
@code {
private AgentDeleteDialog? _deleteDialog;

View file

@ -137,17 +137,6 @@ public partial class Index
await Container.RefreshAsync().ConfigureAwait(false);
}
private void OnDelete(ViewModel model)
{
Model = new ViewModel
{
Id = model.Id,
Serial = model?.Serial
};
_deleteDialog?.Toggle();
}
private bool _filter;
private bool Filter
{

View file

@ -1,5 +1,4 @@
using Insight.Domain.Enums;
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;

View file

@ -7,13 +7,13 @@
</MudText>
</MudDrawerHeader>
<MudStack Class="px-6">
@if (Customer is not null)
@if (_model is not null)
{
<EditForm Model="@Customer" OnValidSubmit="SubmitAsync">
<EditForm Model="@_model" OnValidSubmit="SubmitAsync">
<DataAnnotationsValidator />
<MudStack Spacing="5">
<MudTextField T="string" @bind-Value="Customer.Name" For="()=>Customer.Name" Label="Name" Variant="Variant.Text" Margin="Margin.Dense" AutoFocus Clearable />
<MudTextField T="string" @bind-Value="Customer.Tag" For="()=>Customer.Tag" Label="Tag" Variant="Variant.Text" Margin="Margin.Dense" Clearable />
<MudTextField T="string" @bind-Value="_model.Name" For="()=>_model.Name" Label="Name" Variant="Variant.Text" Margin="Margin.Dense" AutoFocus Clearable />
<MudTextField T="string" @bind-Value="_model.Tag" For="()=>_model.Tag" Label="Tag" Variant="Variant.Text" Margin="Margin.Dense" Clearable />
</MudStack>
<MudStack Justify="Justify.Center" Row Class="mt-7">
<MudButton OnClick="()=>_visible = false" Variant="Variant.Outlined" DisableElevation Size="Size.Large" Color="Color.Surface">
@ -30,9 +30,4 @@
@code {
private bool _visible;
public void Toggle()
{
_visible = !_visible;
StateHasChanged();
}
}

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Driver;
@ -15,17 +14,26 @@ public partial class CustomerCreateDialog
[Inject] private ISnackbar Snackbar { get; init; } = default!;
[Inject] private ILogger<CustomerCreateDialog> Logger { get; init; } = default!;
private CustomerEntity? Customer { get; set; } = new();
private CustomerEntity? _model;
public async void ToggleAsync()
{
_model = new();
_visible = !_visible;
await InvokeAsync(StateHasChanged);
}
private async Task SubmitAsync()
{
if (Customer is null) return;
Customer.Insert = DateTime.Now;
if (_model is null) return;
_model.Insert = DateTime.Now;
try
{
await Database.Customer()
.InsertOneAsync(Customer, cancellationToken: default)
.InsertOneAsync(_model, cancellationToken: default)
.ConfigureAwait(false);
Notification.Success(Snackbar);
@ -45,7 +53,6 @@ public partial class CustomerCreateDialog
}
finally
{
Customer = new();
_visible = false;
}
}

View file

@ -7,12 +7,12 @@
</MudText>
</MudDrawerHeader>
<MudStack Class="px-6">
@if (Customer is not null)
@if (_model is not null)
{
<EditForm Model="@Customer" OnValidSubmit="SubmitAsync">
<EditForm Model="@_model" OnValidSubmit="SubmitAsync">
<MudStack Spacing="5">
<MudTextField T="string" @bind-Value="Customer.Name" For="()=>Customer.Name" Label="Name" Variant="Variant.Text" Margin="Margin.Dense" ReadOnly />
<MudTextField T="string" @bind-Value="Customer.Tag" For="()=>Customer.Tag" Label="Tag" Variant="Variant.Text" Margin="Margin.Dense" ReadOnly />
<MudTextField T="string" @bind-Value="_model.Name" For="()=>_model.Name" Label="Name" Variant="Variant.Text" Margin="Margin.Dense" ReadOnly />
<MudTextField T="string" @bind-Value="_model.Tag" For="()=>_model.Tag" Label="Tag" Variant="Variant.Text" Margin="Margin.Dense" ReadOnly />
</MudStack>
<MudStack Justify="Justify.Center" Row Class="mt-7">
<MudButton OnClick="()=>_visible = false" Variant="Variant.Outlined" DisableElevation Size="Size.Large" Color="Color.Surface">

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Driver;
@ -9,22 +8,40 @@ namespace Insight.Web.Pages.Management.Customers;
public partial class CustomerDeleteDialog
{
[CascadingParameter(Name = "Customer")] public CustomerEntity? Customer { get; set; }
[Parameter] public EventCallback OnChanges { get; set; }
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
[Inject] private ILogger<CustomerDeleteDialog> Logger { get; init; } = default!;
private CustomerEntity? _model;
public async void ToggleAsync(string? id)
{
if (id is null) return;
try
{
_model = await Database.Customer().Find(p => p.Id == id).FirstAsync();
_visible = !_visible;
}
catch (Exception)
{
Notification.Error(Snackbar);
}
await InvokeAsync(StateHasChanged);
}
private async Task SubmitAsync()
{
if (Customer is null) return;
if (_model is null) return;
try
{
await Database.Customer()
.DeleteOneAsync(Builders<CustomerEntity>
.Filter.Eq(p => p.Id, Customer.Id),
.Filter.Eq(p => p.Id, _model.Id),
cancellationToken: default).ConfigureAwait(false);
Notification.Success(Snackbar);

View file

@ -7,21 +7,13 @@
</MudText>
</MudDrawerHeader>
<MudStack Class="px-6">
@if (Customer is not null)
@if (_model is not null)
{
<EditForm Model="@Customer" OnValidSubmit="SubmitAsync">
<EditForm Model="@_model" OnValidSubmit="SubmitAsync">
<DataAnnotationsValidator />
@*<MudStack Spacing="2">
<MudTextField T="ObjectId?" @bind-Value="Customer.DocumentId" Label="Id" Variant="Variant.Text" Margin="Margin.Dense" DisableUnderLine Disabled ReadOnly />
<MudStack Row>
<MudTextField T="string" Text="@($"{Customer.Created?.ToLocalTime().ToString() ?? "-"}")" Label="Created" Variant="Variant.Text" Margin="Margin.Dense" DisableUnderLine Disabled ReadOnly />
<MudTextField T="string" Text="@($"{Customer.Updated?.ToLocalTime().ToString() ?? "-"}")" Label="Updated" Variant="Variant.Text" Margin="Margin.Dense" DisableUnderLine Disabled ReadOnly />
</MudStack>
</MudStack>
<MudDivider />*@
<MudStack Spacing="5">
<MudTextField T="string" @bind-Value="Customer.Name" For="()=>Customer.Name" Label="Name" Variant="Variant.Text" Margin="Margin.Dense" AutoFocus Clearable />
<MudTextField T="string" @bind-Value="Customer.Tag" For="()=>Customer.Tag" Label="Tag" Variant="Variant.Text" Margin="Margin.Dense" Clearable />
<MudTextField T="string" @bind-Value="_model.Name" For="()=>_model.Name" Label="Name" Variant="Variant.Text" Margin="Margin.Dense" AutoFocus Clearable />
<MudTextField T="string" @bind-Value="_model.Tag" For="()=>_model.Tag" Label="Tag" Variant="Variant.Text" Margin="Margin.Dense" Clearable />
</MudStack>
<MudStack Justify="Justify.Center" Row Class="mt-7">
@ -39,9 +31,4 @@
@code {
private bool _visible;
public void Toggle()
{
_visible = !_visible;
StateHasChanged();
}
}

View file

@ -1,56 +1,71 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Driver;
using MudBlazor;
namespace Insight.Web.Pages.Management.Customers
namespace Insight.Web.Pages.Management.Customers;
public partial class CustomerEditDialog
{
public partial class CustomerEditDialog
[Parameter] public EventCallback OnChanges { get; set; }
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
[Inject] private ILogger<CustomerEditDialog> Logger { get; init; } = default!;
private CustomerEntity? _model;
public async void ToggleAsync(string? id)
{
[CascadingParameter(Name = "Customer")] public CustomerEntity? Customer { get; set; }
[Parameter] public EventCallback OnChanges { get; set; }
if (id is null) return;
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
[Inject] private ILogger<CustomerEditDialog> Logger { get; init; } = default!;
private async Task SubmitAsync()
try
{
if (Customer is null) return;
Customer.Update = DateTime.Now;
_model = await Database.Customer().Find(p => p.Id == id).FirstAsync();
_visible = !_visible;
}
catch (Exception)
{
Notification.Error(Snackbar);
}
try
await InvokeAsync(StateHasChanged);
}
private async Task SubmitAsync()
{
if (_model is null) return;
try
{
await Database.Customer()
.UpdateOneAsync(Builders<CustomerEntity>
.Filter
.Eq(p => p.Id, _model.Id), Builders<CustomerEntity>
.Update
.Set(p => p.Update, DateTime.Now)
.Set(p => p.Name, _model.Name)
.Set(p => p.Tag, _model.Tag), default).ConfigureAwait(false);
Notification.Success(Snackbar);
if (OnChanges.HasDelegate)
{
await Database.Customer()
.UpdateOneAsync(Builders<CustomerEntity>
.Filter
.Eq(p => p.Id, Customer.Id), Builders<CustomerEntity>
.Update
.Set(p => p.Update, DateTime.Now)
.Set(p => p.Name, Customer.Name)
.Set(p => p.Tag, Customer.Tag), default).ConfigureAwait(false);
Notification.Success(Snackbar);
if (OnChanges.HasDelegate)
await InvokeAsync(async () =>
{
await InvokeAsync(async () =>
{
await OnChanges.InvokeAsync(this);
});
}
}
catch (Exception ex)
{
Notification.Error(Snackbar);
Logger.LogError(ex.ToString());
}
finally
{
_visible = false;
await OnChanges.InvokeAsync(this);
});
}
}
catch (Exception ex)
{
Notification.Error(Snackbar);
Logger.LogError(ex.ToString());
}
finally
{
_visible = false;
}
}
}

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Bson;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;

View file

@ -1,12 +1,12 @@
@inherits ComponentBase
<TableContainer T="CustomerEntity"
@ref="Container"
@bind-Search="Search"
Title="@Title"
Breadcrumbs="@Breadcrumbs"
@ref="_container"
@bind-Search="_search"
Title="@_title"
Breadcrumbs="@_breadcrumbs"
Data="LoadDataAsync"
OnAdd="OnCreate">
OnAdd="()=>_createDialog?.ToggleAsync()">
<Header>
<MudTh>
<MudTableSortLabel SortLabel="Name" T="CustomerEntity">
@ -49,20 +49,18 @@
</MudTd>
</RowTemplate>
<ActionTemplate>
<MudMenuItem OnClick="@(()=>OnEdit(context))">
<MudMenuItem OnClick="@(()=>_editDialog?.ToggleAsync(context.Id))">
Edit
</MudMenuItem>
<MudMenuItem OnClick="@(()=>OnDelete(context))">
<MudMenuItem OnClick="@(()=>_deleteDialog?.ToggleAsync(context.Id))">
Delete
</MudMenuItem>
</ActionTemplate>
</TableContainer>
<CascadingValue Name="Customer" Value="@Model">
<CustomerCreateDialog @ref="_createDialog" OnChanges="OnRefreshAsync" />
<CustomerEditDialog @ref="_editDialog" OnChanges="OnRefreshAsync" />
<CustomerDeleteDialog @ref="_deleteDialog" OnChanges="OnRefreshAsync" />
</CascadingValue>
<CustomerCreateDialog @ref="_createDialog" OnChanges="OnRefreshAsync" />
<CustomerEditDialog @ref="_editDialog" OnChanges="OnRefreshAsync" />
<CustomerDeleteDialog @ref="_deleteDialog" OnChanges="OnRefreshAsync" />
@code{
private CustomerCreateDialog? _createDialog;

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
@ -17,18 +16,17 @@ public partial class Index
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
private TableContainer<CustomerEntity>? Container { get; set; }
private string Title { get; set; } = Global.Name;
private List<BreadcrumbItem> Breadcrumbs { get; } = new();
private string? Search { get; set; }
private readonly List<BreadcrumbItem> _breadcrumbs = new();
private CustomerEntity? Model { get; set; }
private TableContainer<CustomerEntity>? _container;
private string _title = Global.Name;
private string? _search;
protected override void OnInitialized()
{
Title = "CustomersInsight";
Breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
Breadcrumbs.Add(new BreadcrumbItem("Customers", href: Navigation.Management.Customers.Index, true));
_title = "CustomersInsight";
_breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
_breadcrumbs.Add(new BreadcrumbItem("Customers", href: Navigation.Management.Customers.Index, true));
}
private async Task<TableData<CustomerEntity>> LoadDataAsync(TableState state)
@ -37,9 +35,9 @@ public partial class Index
{
var filter = Builders<CustomerEntity>.Filter.Empty;
if (string.IsNullOrWhiteSpace(Search) is false)
if (string.IsNullOrWhiteSpace(_search) is false)
{
var regex = new BsonRegularExpression(new Regex(Search, RegexOptions.IgnoreCase));
var regex = new BsonRegularExpression(new Regex(_search, RegexOptions.IgnoreCase));
filter &= Builders<CustomerEntity>.Filter.Regex(x => x.Name, regex) |
Builders<CustomerEntity>.Filter.Regex(x => x.Tag, regex) |
Builders<CustomerEntity>.Filter.Regex(x => x.Hosts, regex);
@ -85,40 +83,7 @@ public partial class Index
private async Task OnRefreshAsync()
{
if (Container is null) return;
await Container.RefreshAsync().ConfigureAwait(false);
}
private void OnCreate()
{
_createDialog?.Toggle();
}
private void OnEdit(CustomerEntity model)
{
Model = new CustomerEntity
{
Id = model.Id,
Insert = model?.Insert,
Update = model?.Update,
Name = model?.Name,
Tag = model?.Tag
};
_editDialog?.Toggle();
}
private void OnDelete(CustomerEntity model)
{
Model = new CustomerEntity
{
Id = model.Id,
Insert = model?.Insert,
Update = model?.Update,
Name = model?.Name,
Tag = model?.Tag
};
_deleteDialog?.Toggle();
if (_container is null) return;
await _container.RefreshAsync().ConfigureAwait(false);
}
}

View file

@ -0,0 +1,20 @@
@inherits ComponentBase
<BaseContainer Title="@_title" Breadcrumbs="@_breadcrumbs" LoadData="LoadDataAsync">
<Content>
<MudGrid>
@if (_model is not null)
{
<MudItem xs="12" sm="6" md="6" lg="3">
<KeyValueCard T="string" Key="Name" Value="@_model.Name" Icon="@Icons.Material.Outlined.Grain" />
</MudItem>
@if (string.IsNullOrWhiteSpace(_model?.Description) is false)
{
<MudItem xs="12" sm="12" md="12" lg="12">
<InfoCard Key="Description" Lines="3" Text="@(_model.Description ?? "-")" />
</MudItem>
}
}
</MudGrid>
</Content>
</BaseContainer>

View file

@ -0,0 +1,57 @@
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Driver;
using MudBlazor;
namespace Insight.Web.Pages.Management.HostGroups;
[Route(Navigation.Management.HostGroups.Details)]
public partial class Details
{
[Parameter] public string? GroupId { get; set; }
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
[Inject] private NavigationManager NavigationManager { get; init; } = default!;
private readonly List<BreadcrumbItem> _breadcrumbs = new();
private string _title = Global.Name;
private HostGroupEntity? _model;
private async Task LoadDataAsync()
{
_model = null;
_breadcrumbs.Clear();
_breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
_breadcrumbs.Add(new BreadcrumbItem("Host Groups", href: Navigation.Management.HostGroups.Index));
StateHasChanged();
if (string.IsNullOrWhiteSpace(GroupId))
{
Notification.Error(Snackbar, "Not Found");
NavigationManager.NavigateTo(Navigation.Management.HostGroups.Index);
return;
}
_model = await Database.HostGroup()
.Aggregate()
.Match(Builders<HostGroupEntity>.Filter.Eq(p => p.Id, GroupId))
.FirstOrDefaultAsync(default);
if (_model is null)
{
Notification.Error(Snackbar, "Not Found");
NavigationManager.NavigateTo(Navigation.Management.HostGroups.Index);
return;
}
_title = $"Host Groups » {_model.Name}Insight";
_breadcrumbs.Add(new BreadcrumbItem(_model.Name, href: "#", true));
await InvokeAsync(StateHasChanged);
}
}

View file

@ -0,0 +1,38 @@
@inherits ComponentBase
<TableContainer T="ViewModel"
@ref="Container"
@bind-Search="Search"
Title="@Title"
Breadcrumbs="@Breadcrumbs"
Data="LoadDataAsync">
<Header>
<MudTh>
<MudTableSortLabel SortLabel="Customer" T="HostEntity">
Customer
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortLabel="Host" T="HostEntity">
Host
</MudTableSortLabel>
</MudTh>
</Header>
<RowTemplate>
<MudTd DataLabel="Customer">
<MudLink Href="@Navigation.Management.Customers.DetailsHref(context?.CustomerId)" Typo="Typo.inherit" Underline="Underline.None">
@context?.CustomerName
</MudLink>
</MudTd>
<MudTd DataLabel="Host">
<MudLink Href="@Navigation.Management.Hosts.DetailsHref(context?.HostId)" Typo="Typo.inherit" Underline="Underline.None">
@context?.HostName
</MudLink>
</MudTd>
</RowTemplate>
<ActionTemplate>
<MudMenuItem OnClick="@(()=>OnAssignAsync(context.HostId))">
Assign
</MudMenuItem>
</ActionTemplate>
</TableContainer>

View file

@ -0,0 +1,178 @@
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;
using MudBlazor;
using System.Text.RegularExpressions;
using SortDirection = MudBlazor.SortDirection;
namespace Insight.Web.Pages.Management.HostGroups;
[Route(Navigation.Management.HostGroups.HostsAssign)]
public partial class HostAssign
{
[Parameter] public string? GroupId { get; set; }
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private NavigationManager NavigationManager { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
private TableContainer<ViewModel>? Container { get; set; }
private string Title { get; set; } = Global.Name;
private List<BreadcrumbItem> Breadcrumbs { get; } = new();
private string? Search { get; set; }
protected override async Task OnInitializedAsync()
{
if (string.IsNullOrWhiteSpace(GroupId) || ObjectId.TryParse(GroupId, out var groupId) is false)
{
Notification.Error(Snackbar, "Not Found");
NavigationManager.NavigateTo(Navigation.Management.HostGroups.Index);
return;
}
var hostgroup = await Database.HostGroup()
.Aggregate()
.Match(Builders<HostGroupEntity>.Filter.Eq(p => p.Id, GroupId))
.FirstOrDefaultAsync(default);
if (hostgroup is null)
{
Notification.Error(Snackbar, "Not Found");
NavigationManager.NavigateTo(Navigation.Management.HostGroups.Index);
return;
}
Title = $"Host Groups » {hostgroup.Name} » Hosts » AssignInsight";
Breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
Breadcrumbs.Add(new BreadcrumbItem("Host Groups", href: Navigation.Management.HostGroups.Index));
Breadcrumbs.Add(new BreadcrumbItem(hostgroup.Name, href: Navigation.Management.HostGroups.DetailsHref(GroupId)));
Breadcrumbs.Add(new BreadcrumbItem("Hosts", href: Navigation.Management.HostGroups.HostsHref(GroupId)));
Breadcrumbs.Add(new BreadcrumbItem("Assign", href: "#", true));
}
private async Task<TableData<ViewModel>> LoadDataAsync(TableState state)
{
try
{
var search = Builders<BsonDocument>.Filter.Empty;
if (string.IsNullOrWhiteSpace(Search) is false)
{
var regex = new BsonRegularExpression(new Regex(Search, RegexOptions.IgnoreCase));
search &= Builders<BsonDocument>.Filter.Regex("customerName", regex) |
Builders<BsonDocument>.Filter.Regex("hostName", regex);
}
var query = Database.Host()
.Aggregate()
.AppendStage<BsonDocument>(new BsonDocument("$lookup", new BsonDocument
{
{ "from", "hostgroup_host" },
{ "localField", "_id" },
{ "foreignField", "_host" },
{ "as", "map" }
}))
.AppendStage<BsonDocument>(new BsonDocument("$project", new BsonDocument
{
{ "_id", 0 },
{ "hostId", "$_id" },
{ "hostName", "$name" },
{ "customerId", "$_customer" },
{ "hostgroup", new BsonDocument("$first", "$map._hostgroup") }
}))
.AppendStage<BsonDocument>(
new BsonDocument("$match",
new BsonDocument("hostgroup", new BsonDocument("$ne", new ObjectId(GroupId))))
)
.AppendStage<BsonDocument>(new BsonDocument("$lookup", new BsonDocument
{
{ "from", "customer" },
{ "localField", "customerId" },
{ "foreignField", "_id" },
{ "as", "customerName" }
}))
.AppendStage<BsonDocument>(new BsonDocument("$addFields",
new BsonDocument("customerName", new BsonDocument("$first", "$customerName.name"))))
.Match(search)
.Sort(state.SortDirection switch
{
SortDirection.Ascending => state.SortLabel switch
{
"Customer" => Builders<BsonDocument>.Sort.Ascending("customer.name"),
"Name" => Builders<BsonDocument>.Sort.Ascending("name"),
_ => null
},
SortDirection.Descending => state.SortLabel switch
{
"Customer" => Builders<BsonDocument>.Sort.Descending("customer.name"),
"Name" => Builders<BsonDocument>.Sort.Descending("name"),
_ => null
},
_ => Builders<BsonDocument>.Sort.Ascending("customer.name")
});
var countResult = await query.Count().FirstOrDefaultAsync(default);
var itemResult = await query.Skip(state.Page * state.PageSize).Limit(state.PageSize).ToListAsync(default);
return new TableData<ViewModel>()
{
TotalItems = countResult is null ? 0 : (int)countResult.Count,
Items = itemResult.Select(x => BsonSerializer.Deserialize<ViewModel>(x))
};
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Notification.Error(Snackbar);
return new TableData<ViewModel>();
}
}
private async Task OnAssignAsync(string? hostId)
{
try
{
await Database.HostGroupHost()
.InsertOneAsync(new HostGroupHostEntity
{
Insert = DateTime.Now,
HostGroup = GroupId,
Host = hostId
}, null, default);
Container?.RefreshAsync();
Notification.Success(Snackbar);
}
catch (Exception)
{
Notification.Error(Snackbar);
}
finally
{
NavigationManager?.NavigateTo(Navigation.Management.HostGroups.HostsHref(GroupId));
}
}
[BsonIgnoreExtraElements]
public class ViewModel
{
[BsonElement("customerId"), BsonRepresentation(BsonType.ObjectId)]
public string? CustomerId { get; set; }
[BsonElement("customerName")]
public string? CustomerName { get; set; }
[BsonElement("hostId"), BsonRepresentation(BsonType.ObjectId)]
public string? HostId { get; set; }
[BsonElement("hostName")]
public string? HostName { get; set; }
}
}

View file

@ -0,0 +1,33 @@
@using MongoDB.Bson;
<MudDrawer @bind-Open="_visible" Anchor="Anchor.End" Elevation="0" Variant="@DrawerVariant.Temporary" ClipMode="DrawerClipMode.Always" Width="400px" Style="max-width:auto;">
<MudDrawerHeader>
<MudText Typo="Typo.h6">
Create Host Group
</MudText>
</MudDrawerHeader>
<MudStack Class="px-6">
@if (_model is not null)
{
<EditForm Model="@_model" OnValidSubmit="SubmitAsync">
<DataAnnotationsValidator />
<MudStack Spacing="5">
<MudTextField T="string" @bind-Value="_model.Name" For="()=>_model.Name" Label="Name" Variant="Variant.Text" Margin="Margin.Dense" AutoFocus Clearable />
<MudTextField T="string" @bind-Value="_model.Description" For="()=>_model.Description" Label="Description" Variant="Variant.Text" Margin="Margin.Dense" Clearable />
</MudStack>
<MudStack Justify="Justify.Center" Row Class="mt-7">
<MudButton OnClick="()=>_visible = false" Variant="Variant.Outlined" DisableElevation Size="Size.Large" Color="Color.Surface">
Cancel
</MudButton>
<MudButton ButtonType="ButtonType.Submit" Variant="Variant.Filled" DisableElevation Size="Size.Large" Color="Color.Success" Style="width: 100%;">
Create
</MudButton>
</MudStack>
</EditForm>
}
</MudStack>
</MudDrawer>
@code {
private bool _visible;
}

View file

@ -0,0 +1,61 @@
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Driver;
using MudBlazor;
namespace Insight.Web.Pages.Management.HostGroups;
public partial class HostGroupCreateDialog
{
[Parameter] public EventCallback OnChanges { get; set; }
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
[Inject] private ILogger<HostGroupCreateDialog> Logger { get; init; } = default!;
private HostGroupEntity? _model;
public async void ToggleAsync()
{
_model = new();
_visible = !_visible;
await InvokeAsync(StateHasChanged);
}
private async Task SubmitAsync()
{
try
{
await Database.HostGroup()
.InsertOneAsync(new HostGroupEntity
{
Insert = DateTime.Now,
Name = _model?.Name,
Description = _model?.Description,
}, cancellationToken: default)
.ConfigureAwait(false);
Notification.Success(Snackbar);
if (OnChanges.HasDelegate)
{
await InvokeAsync(async () =>
{
await OnChanges.InvokeAsync(this);
});
}
}
catch (Exception ex)
{
Notification.Error(Snackbar);
Logger.LogError(ex.ToString());
}
finally
{
_model = new();
_visible = false;
}
}
}

View file

@ -0,0 +1,32 @@
@using MongoDB.Bson;
<MudDrawer @bind-Open="_visible" Anchor="Anchor.End" Elevation="0" Variant="@DrawerVariant.Temporary" ClipMode="DrawerClipMode.Always" Width="400px" Style="max-width:auto;">
<MudDrawerHeader>
<MudText Typo="Typo.h6">
Delete Host Group
</MudText>
</MudDrawerHeader>
<MudStack Class="px-6">
@if (_model is not null)
{
<EditForm Model="@_model" OnValidSubmit="SubmitAsync">
<MudStack Spacing="5">
<MudTextField T="string" @bind-Value="_model.Name" For="()=>_model.Name" Label="Name" Variant="Variant.Text" Margin="Margin.Dense" ReadOnly />
<MudTextField T="string" @bind-Value="_model.Description" For="()=>_model.Description" Label="Description" Variant="Variant.Text" Margin="Margin.Dense" ReadOnly />
</MudStack>
<MudStack Justify="Justify.Center" Row Class="mt-7">
<MudButton OnClick="()=>_visible = false" Variant="Variant.Outlined" DisableElevation Size="Size.Large" Color="Color.Surface">
Cancel
</MudButton>
<MudButton ButtonType="ButtonType.Submit" Variant="Variant.Filled" DisableElevation Size="Size.Large" Color="Color.Error" Style="width: 100%;">
Delete
</MudButton>
</MudStack>
</EditForm>
}
</MudStack>
</MudDrawer>
@code {
private bool _visible;
}

View file

@ -0,0 +1,66 @@
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Driver;
using MudBlazor;
namespace Insight.Web.Pages.Management.HostGroups;
public partial class HostGroupDeleteDialog
{
[Parameter] public EventCallback OnChanges { get; set; }
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
[Inject] private ILogger<HostGroupDeleteDialog> Logger { get; init; } = default!;
private HostGroupEntity? _model;
public async void ToggleAsync(string? id)
{
if (id is null) return;
try
{
_model = await Database.HostGroup().Find(p => p.Id == id).FirstAsync();
_visible = !_visible;
}
catch (Exception)
{
Notification.Error(Snackbar);
}
await InvokeAsync(StateHasChanged);
}
private async Task SubmitAsync()
{
if (_model is null) return;
try
{
await Database.HostGroup().DeleteOneAsync(Builders<HostGroupEntity>
.Filter.Eq(p => p.Id, _model.Id),
cancellationToken: default).ConfigureAwait(false);
Notification.Success(Snackbar);
if (OnChanges.HasDelegate)
{
await InvokeAsync(async () =>
{
await OnChanges.InvokeAsync(this);
});
}
}
catch (Exception ex)
{
Notification.Error(Snackbar);
Logger.LogError(ex.ToString());
}
finally
{
_visible = false;
}
}
}

View file

@ -0,0 +1,41 @@
@using MongoDB.Bson;
<MudDrawer @bind-Open="_visible" Anchor="Anchor.End" Elevation="0" Variant="@DrawerVariant.Temporary" ClipMode="DrawerClipMode.Always" Width="400px" Style="max-width:auto;">
<MudDrawerHeader>
<MudText Typo="Typo.h6">
Edit Host Group
</MudText>
</MudDrawerHeader>
<MudStack Class="px-6">
@if (_model is not null)
{
<EditForm Model="@_model" OnValidSubmit="SubmitAsync">
<DataAnnotationsValidator />
@*<MudStack Spacing="2">
<MudTextField T="ObjectId?" @bind-Value="Customer.DocumentId" Label="Id" Variant="Variant.Text" Margin="Margin.Dense" DisableUnderLine Disabled ReadOnly />
<MudStack Row>
<MudTextField T="string" Text="@($"{Customer.Created?.ToLocalTime().ToString() ?? "-"}")" Label="Created" Variant="Variant.Text" Margin="Margin.Dense" DisableUnderLine Disabled ReadOnly />
<MudTextField T="string" Text="@($"{Customer.Updated?.ToLocalTime().ToString() ?? "-"}")" Label="Updated" Variant="Variant.Text" Margin="Margin.Dense" DisableUnderLine Disabled ReadOnly />
</MudStack>
</MudStack>
<MudDivider />*@
<MudStack Spacing="5">
<MudTextField T="string" @bind-Value="_model.Name" For="()=>_model.Name" Label="Name" Variant="Variant.Text" Margin="Margin.Dense" AutoFocus Clearable />
<MudTextField T="string" @bind-Value="_model.Description" For="()=>_model.Description" Label="Description" Variant="Variant.Text" Margin="Margin.Dense" Clearable />
</MudStack>
<MudStack Justify="Justify.Center" Row Class="mt-7">
<MudButton OnClick="()=>_visible = false" Variant="Variant.Outlined" DisableElevation Size="Size.Large" Color="Color.Surface">
Cancel
</MudButton>
<MudButton ButtonType="ButtonType.Submit" Variant="Variant.Filled" DisableElevation Size="Size.Large" Color="Color.Secondary" Style="width: 100%;">
Edit
</MudButton>
</MudStack>
</EditForm>
}
</MudStack>
</MudDrawer>
@code {
private bool _visible;
}

View file

@ -0,0 +1,71 @@
using Insight.Infrastructure.Entities;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Driver;
using MudBlazor;
namespace Insight.Web.Pages.Management.HostGroups;
public partial class HostGroupEditDialog
{
[Parameter] public EventCallback OnChanges { get; set; }
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
[Inject] private ILogger<HostGroupEditDialog> Logger { get; init; } = default!;
private HostGroupEntity? _model;
public async void ToggleAsync(string? id)
{
if (id is null) return;
try
{
_model = await Database.HostGroup().Find(p => p.Id == id).FirstAsync();
_visible = !_visible;
}
catch (Exception)
{
Notification.Error(Snackbar);
}
await InvokeAsync(StateHasChanged);
}
private async Task SubmitAsync()
{
if (_model is null) return;
try
{
await Database.HostGroup().UpdateOneAsync(Builders<HostGroupEntity>
.Filter
.Eq(p => p.Id, _model.Id), Builders<HostGroupEntity>
.Update
.Set(p => p.Update, DateTime.Now)
.Set(p => p.Name, _model.Name)
.Set(p => p.Description, _model.Description),
cancellationToken: default);
Notification.Success(Snackbar);
if (OnChanges.HasDelegate)
{
await InvokeAsync(async () =>
{
await OnChanges.InvokeAsync(this);
});
}
}
catch (Exception ex)
{
Notification.Error(Snackbar);
Logger.LogError(ex.ToString());
}
finally
{
_visible = false;
}
}
}

View file

@ -0,0 +1,39 @@
@inherits ComponentBase
<TableContainer T="ViewModel"
@ref="_container"
@bind-Search="_search"
Title="@_title"
Breadcrumbs="@_breadcrumbs"
Data="LoadDataAsync"
OnAdd="()=>NavigationManager.NavigateTo(Navigation.Management.HostGroups.HostsAssignHref(GroupId))">
<Header>
<MudTh>
<MudTableSortLabel SortLabel="Customer" T="ViewModel">
Customer
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortLabel="Host" T="ViewModel">
Host
</MudTableSortLabel>
</MudTh>
</Header>
<RowTemplate>
<MudTd DataLabel="Customer">
<MudLink Href="@Navigation.Management.Customers.DetailsHref(@context?.Customers?.Id)" Typo="Typo.inherit" Underline="Underline.None">
@context?.Customers?.Name
</MudLink>
</MudTd>
<MudTd DataLabel="Host">
<MudLink Href="@Navigation.Management.Hosts.DetailsHref(@context?.Hosts?.Id)" Typo="Typo.inherit" Underline="Underline.None">
@context?.Hosts?.Name
</MudLink>
</MudTd>
</RowTemplate>
<ActionTemplate>
<MudMenuItem OnClick="@(()=>OnUnassignAsync(context.Hosts.Id))">
Unassign
</MudMenuItem>
</ActionTemplate>
</TableContainer>

View file

@ -0,0 +1,157 @@
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;
using MudBlazor;
using System.Text.RegularExpressions;
using SortDirection = MudBlazor.SortDirection;
namespace Insight.Web.Pages.Management.HostGroups;
[Route(Navigation.Management.HostGroups.Hosts)]
public partial class Hosts
{
[Parameter] public string? GroupId { get; set; }
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
[Inject] private NavigationManager NavigationManager { get; init; } = default!;
private TableContainer<ViewModel>? _container;
private string _title = Global.Name;
private string? _search;
private HostGroupEntity? _model;
private readonly List<BreadcrumbItem> _breadcrumbs = new();
protected override async Task OnInitializedAsync()
{
_breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
_breadcrumbs.Add(new BreadcrumbItem("Host Groups", href: Navigation.Management.HostGroups.Index));
if (string.IsNullOrWhiteSpace(GroupId))
{
Notification.Error(Snackbar, "Not Found");
NavigationManager.NavigateTo(Navigation.Management.HostGroups.Index);
return;
}
_model = await Database.HostGroup()
.Aggregate()
.Match(Builders<HostGroupEntity>.Filter.Eq(p => p.Id, GroupId))
.FirstOrDefaultAsync(default);
if (_model is null)
{
Notification.Error(Snackbar, "Not Found");
NavigationManager.NavigateTo(Navigation.Management.HostGroups.Index);
return;
}
_title = $"Host Groups » {_model.Name} » HostsInsight";
_breadcrumbs.Add(new BreadcrumbItem(_model.Name, href: Navigation.Management.HostGroups.DetailsHref(GroupId)));
_breadcrumbs.Add(new BreadcrumbItem("Hosts", href: "#", true));
await InvokeAsync(StateHasChanged);
}
private async Task<TableData<ViewModel>> LoadDataAsync(TableState state)
{
try
{
var filter = Builders<BsonDocument>.Filter.Empty;
if (string.IsNullOrWhiteSpace(_search) is false)
{
var regex = new BsonRegularExpression(new Regex(_search, RegexOptions.IgnoreCase));
filter &= Builders<BsonDocument>.Filter.Regex("customer.name", regex) |
Builders<BsonDocument>.Filter.Regex("host.name", regex);
}
var query = Database.HostGroupHost()
.Aggregate()
.Match(Builders<HostGroupHostEntity>.Filter.Eq(p => p.HostGroup, GroupId))
.Lookup("host", "_host", "_id", "hosts")
.Match(new BsonDocument("hosts", new BsonDocument
{
{ "$exists", true },
{ "$ne", new BsonArray() }
}))
.Lookup("customer", "hosts._customer", "_id", "customers")
.Project(new BsonDocument
{
{ "_id", 0 },
{ "host", new BsonDocument("$first", "$hosts") },
{ "customer", new BsonDocument("$first", "$customers") }
})
.Match(filter)
.Sort(state.SortDirection switch
{
SortDirection.Ascending => state.SortLabel switch
{
"Customer" => Builders<BsonDocument>.Sort.Ascending("customer.name"),
"Host" => Builders<BsonDocument>.Sort.Ascending("host.name"),
_ => null
},
SortDirection.Descending => state.SortLabel switch
{
"Customer" => Builders<BsonDocument>.Sort.Descending("customer.name"),
"Host" => Builders<BsonDocument>.Sort.Descending("host.name"),
_ => null
},
_ => Builders<BsonDocument>.Sort.Ascending("customer.name")
});
var countResult = await query.Count().FirstOrDefaultAsync(default);
var itemResult = await query.Skip(state.Page * state.PageSize).Limit(state.PageSize).ToListAsync(default);
return new TableData<ViewModel>()
{
TotalItems = countResult is null ? 0 : (int)countResult.Count,
Items = itemResult.Select(x => BsonSerializer.Deserialize<ViewModel>(x))
};
}
catch (Exception)
{
Notification.Error(Snackbar);
return new TableData<ViewModel>();
}
}
private async Task OnUnassignAsync(string? hostId)
{
try
{
await Database.HostGroupHost()
.DeleteOneAsync(Builders<HostGroupHostEntity>
.Filter.Eq(p => p.Host, hostId), default);
_container?.RefreshAsync();
Notification.Success(Snackbar);
}
catch (Exception)
{
Notification.Error(Snackbar);
}
finally
{
NavigationManager?.NavigateTo(Navigation.Management.HostGroups.HostsHref(GroupId));
}
}
[BsonIgnoreExtraElements]
public class ViewModel
{
[BsonElement("customer")]
public CustomerEntity? Customers { get; set; }
[BsonElement("host")]
public HostEntity? Hosts { get; set; }
}
}

View file

@ -1,14 +1,12 @@
@inherits ComponentBase
<TableContainer T="IndexViewModel"
@ref="Container"
@bind-Search="Search"
Title="@Title"
Breadcrumbs="@Breadcrumbs"
@ref="_container"
@bind-Search="_search"
Title="@_title"
Breadcrumbs="@_breadcrumbs"
Data="LoadDataAsync"
OnFilter="()=>Filter = true"
Filtered="Filtered"
OnAdd="()=>Create = true">
OnAdd="()=>_createDialog?.ToggleAsync()">
<Header>
<MudTh>
<MudTableSortLabel SortLabel="Name" T="IndexViewModel">
@ -16,128 +14,49 @@
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortLabel="Customer" T="IndexViewModel">
Customer
<MudTableSortLabel SortLabel="Description" T="IndexViewModel">
Description
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortLabel="Agent" T="IndexViewModel">
Agent
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortLabel="Online" T="IndexViewModel">
Online
<MudTableSortLabel SortLabel="Hosts" T="IndexViewModel">
Hosts
</MudTableSortLabel>
</MudTh>
</Header>
<RowTemplate>
<MudTd DataLabel="Name">
<MudLink Href="@Navigation.Management.Hosts.DetailsHref(context.Id.ToString())" Typo="Typo.inherit" Underline="Underline.None">
<MudLink Href="@Navigation.Management.HostGroups.DetailsHref(context.Id.ToString())" Typo="Typo.inherit" Underline="Underline.None">
@context?.Name
</MudLink>
</MudTd>
<MudTd DataLabel="Customer">
<MudLink Href="@Navigation.Management.Customers.DetailsHref(context.Customer?.Id)" Typo="Typo.inherit" Underline="Underline.None">
@context.Customer?.Name
</MudLink>
</MudTd>
<MudTd DataLabel="Agent">
<MudLink Href="@Navigation.Management.Agents.DetailsHref(context?.Agent?.Id?.ToString())" Typo="Typo.inherit" Underline="Underline.None">
@context?.Agent?.Serial
</MudLink>
</MudTd>
<MudTd DataLabel="Online">
<MudText Color="(context.Online ? Color.Success : Color.Error)" Typo="Typo.inherit">
@(context.Online ? "Online" : "Offline")
<MudTd DataLabel="Description">
<MudText>
@context.Description
</MudText>
</MudTd>
<MudTd DataLabel="Hosts">
<MudLink Href="@Navigation.Management.HostGroups.HostsHref(context.Id.ToString())" Typo="Typo.inherit" Underline="Underline.None">
@context.Hosts
</MudLink>
</MudTd>
</RowTemplate>
<ActionTemplate>
<MudMenuItem OnClick="@(()=>OnEdit(context))">
<MudMenuItem OnClick="@(()=>_editDialog?.ToggleAsync(context.Id?.ToString()))">
Edit
</MudMenuItem>
<MudMenuItem OnClick="@(()=>OnDelete(context))">
<MudMenuItem OnClick="@(()=>_deleteDialog?.ToggleAsync(context.Id?.ToString()))">
Delete
</MudMenuItem>
</ActionTemplate>
</TableContainer>
<ActionDialog @bind-Visible="Filter">
<Content>
<MudSwitch @bind-Checked="FilterUnassignedCustomer" Color="Color.Primary">
Unassigned Customer
</MudSwitch>
<MudSwitch @bind-Checked="FilterUnassignedAgent" Color="Color.Secondary">
Unassigned Agent
</MudSwitch>
</Content>
<Actions>
<MudButton OnClick="OnFilterReset">
Reset
</MudButton>
<MudButton OnClick="() => Filter = false" Color="Color.Secondary">
Done
</MudButton>
</Actions>
</ActionDialog>
<HostGroupCreateDialog @ref="_createDialog" OnChanges="OnRefreshAsync" />
<HostGroupEditDialog @ref="_editDialog" OnChanges="OnRefreshAsync" />
<HostGroupDeleteDialog @ref="_deleteDialog" OnChanges="OnRefreshAsync" />
<ActionDialog @bind-Visible="Create">
<Content>
<MudItem xs="12" md="12" lg="12" Style="mt-2">
<MudTextField T="string" @bind-Value="Model.Name" Label="Name" Variant="Variant.Text" AutoFocus Clearable />
</MudItem>
<MudItem xs="12" md="12" lg="12" Style="mt-2">
<MudTextField T="string" @bind-Value="Model.Description" Label="Description" Variant="Variant.Text" Clearable />
</MudItem>
</Content>
<Actions>
<MudButton OnClick="()=>Create = false">
Cancel
</MudButton>
<MudButton OnClick="OnCreateSubmitAsync" Color="Color.Secondary">
Create
</MudButton>
</Actions>
</ActionDialog>
<ActionDialog @bind-Visible="Edit">
<Content>
<MudItem xs="12" md="12" lg="12" Style="mt-2">
<MudTextField T="string" @bind-Value="Model.Name" Label="Name" Variant="Variant.Text" AutoFocus Clearable />
</MudItem>
<MudItem xs="12" md="12" lg="12" Style="mt-2">
<MudTextField T="string" @bind-Value="Model.Description" Label="Description" Variant="Variant.Text" Clearable />
</MudItem>
</Content>
<Actions>
<MudButton OnClick="()=>Edit = false">
Cancel
</MudButton>
<MudButton OnClick="OnEditSubmitAsync" Color="Color.Secondary">
Edit
</MudButton>
</Actions>
</ActionDialog>
<ActionDialog @bind-Visible="Delete">
<Content>
<MudItem xs="12" md="12" lg="12">
<MudTextField T="string" Text="@Model?.Customer?.Name" Label="Customer" Variant="Variant.Text" ReadOnly />
</MudItem>
<MudItem xs="12" md="12" lg="12" Style="mt-2">
<MudTextField T="string" @bind-Value="Model.Name" Label="Name" Variant="Variant.Text" ReadOnly />
</MudItem>
<MudItem xs="12" md="12" lg="12" Style="mt-2">
<MudTextField T="string" @bind-Value="Model.Description" Label="Description" Variant="Variant.Text" ReadOnly />
</MudItem>
</Content>
<Actions>
<MudButton OnClick="()=>Delete = false">
Cancel
</MudButton>
<MudButton OnClick="OnDeleteSubmitAsync" Color="Color.Secondary">
Delete
</MudButton>
</Actions>
</ActionDialog>
@code {
private HostGroupCreateDialog? _createDialog;
private HostGroupEditDialog? _editDialog;
private HostGroupDeleteDialog? _deleteDialog;
}

View file

@ -1,5 +1,4 @@
using Insight.Infrastructure;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Entities;
using Insight.Web.Components.Containers;
using Insight.Web.Constants;
using Microsoft.AspNetCore.Components;
@ -19,131 +18,121 @@ public partial class Index
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
private TableContainer<IndexViewModel>? Container { get; set; }
private string Title { get; set; } = Global.Name;
private List<BreadcrumbItem> Breadcrumbs { get; } = new();
private string? Search { get; set; }
private readonly string _title = "Host GroupsInsight";
private readonly List<BreadcrumbItem> _breadcrumbs = new();
private IndexViewModel? Model { get; set; }
private TableContainer<IndexViewModel>? _container;
private string? _search;
protected override void OnInitialized()
{
Title = "Host GroupsInsight";
Breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
Breadcrumbs.Add(new BreadcrumbItem("Host Groups", href: Navigation.Management.HostGroups.Index, true));
_breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
_breadcrumbs.Add(new BreadcrumbItem("Host Groups", href: Navigation.Management.HostGroups.Index, true));
}
private async Task<TableData<IndexViewModel>> LoadDataAsync(TableState state)
{
try
{
var filter = Builders<HostEntity>.Filter.Empty;
if (FilterUnassignedCustomer)
{
filter &= Builders<HostEntity>.Filter.Eq(p => p.Customer, null);
}
if (FilterUnassignedAgent)
{
filter &= Builders<HostEntity>.Filter.Eq(p => p.Agent, null);
}
var filter = Builders<HostGroupEntity>.Filter.Empty;
var search = Builders<BsonDocument>.Filter.Empty;
if (string.IsNullOrWhiteSpace(Search) is false)
if (string.IsNullOrWhiteSpace(_search) is false)
{
var regex = new BsonRegularExpression(new Regex(Search, RegexOptions.IgnoreCase));
var regex = new BsonRegularExpression(new Regex(_search, RegexOptions.IgnoreCase));
search &= Builders<BsonDocument>.Filter.Regex("name", regex) |
Builders<BsonDocument>.Filter.Regex("description", regex) |
Builders<BsonDocument>.Filter.Regex("customer.name", regex) |
Builders<BsonDocument>.Filter.Regex("agent.serial", regex);
Builders<BsonDocument>.Filter.Regex("description", regex);
}
var query = Database.Host()
var query = Database.HostGroup()
.Aggregate()
.Match(filter)
.AppendStage<BsonDocument>(new BsonDocument("$lookup", new BsonDocument
{
{ "from", "agent" },
{ "localField", "agent" },
{ "foreignField", "_id" },
{ "pipeline", new BsonArray
{
new BsonDocument("$project", new BsonDocument
{
{ "serial", 1 },
{ "last_activity", 1 }
})
}
},
{ "as", "agents" }
{ "from", "hostgroup_host" },
{ "localField", "_id" },
{ "foreignField", "_hostgroup" },
//{ "pipeline", new BsonArray
// {
// new BsonDocument("$project", new BsonDocument
// {
// { "serial", 1 },
// { "last_activity", 1 }
// })
// }
//},
{ "as", "hosts" }
}))
.AppendStage<BsonDocument>(new BsonDocument("$lookup", new BsonDocument
{
{ "from", "customer" },
{ "localField", "customer" },
{ "foreignField", "_id" },
{ "pipeline", new BsonArray
{
new BsonDocument("$project",
new BsonDocument("name", 1))
}
},
{ "as", "customers" }
}))
.AppendStage<BsonDocument>(new BsonDocument("$project", new BsonDocument
.Project(new BsonDocument
{
{ "_id", 1 },
{ "name", 1 },
{ "description", 1 },
{ "agent", new BsonDocument("$first", "$agents") },
{ "customer", new BsonDocument("$first", "$customers") }
}))
.AppendStage<BsonDocument>(new BsonDocument("$addFields",
new BsonDocument("online_diff",
new BsonDocument("$subtract", new BsonArray
{
DateTime.Now,
"$agent.last_activity"
}))
))
.AppendStage<BsonDocument>(new BsonDocument("$addFields",
new BsonDocument("online",
new BsonDocument("$and", new BsonArray
{
new BsonDocument("$cond",
new BsonArray
{
new BsonDocument("$isNumber",
new BsonArray
{
"$online_diff"
}), 1, 0
}), new BsonDocument("$lt",
new BsonArray
{
"$online_diff",
10000
})
}))
))
{ "hosts", new BsonDocument("$size", "$hosts") }
})
//.AppendStage<BsonDocument>(new BsonDocument("$lookup", new BsonDocument
//{
// { "from", "customer" },
// { "localField", "customer" },
// { "foreignField", "_id" },
// { "pipeline", new BsonArray
// {
// new BsonDocument("$project",
// new BsonDocument("name", 1))
// }
// },
// { "as", "customers" }
//}))
//.AppendStage<BsonDocument>(new BsonDocument("$project", new BsonDocument
//{
// { "name", 1 },
// { "description", 1 },
// { "hosts", new BsonDocument("$first", "$agents") },
// { "customer", new BsonDocument("$first", "$customers") }
//}))
//.AppendStage<BsonDocument>(new BsonDocument("$addFields",
// new BsonDocument("online_diff",
// new BsonDocument("$subtract", new BsonArray
// {
// DateTime.Now,
// "$agent.last_activity"
// }))
//))
//.AppendStage<BsonDocument>(new BsonDocument("$addFields",
// new BsonDocument("online",
// new BsonDocument("$and", new BsonArray
// {
// new BsonDocument("$cond",
// new BsonArray
// {
// new BsonDocument("$isNumber",
// new BsonArray
// {
// "$online_diff"
// }), 1, 0
// }), new BsonDocument("$lt",
// new BsonArray
// {
// "$online_diff",
// 10000
// })
// }))
//))
.Match(search)
.Sort(state.SortDirection switch
{
SortDirection.Ascending => state.SortLabel switch
{
"Name" => Builders<BsonDocument>.Sort.Ascending("name"),
"Customer" => Builders<BsonDocument>.Sort.Ascending("customer.name"),
"Agent" => Builders<BsonDocument>.Sort.Ascending("agent.serial"),
"Online" => Builders<BsonDocument>.Sort.Ascending("online"),
"Description" => Builders<BsonDocument>.Sort.Ascending("description"),
"Hosts" => Builders<BsonDocument>.Sort.Ascending("hosts"),
_ => null
},
SortDirection.Descending => state.SortLabel switch
{
"Name" => Builders<BsonDocument>.Sort.Descending("name"),
"Customer" => Builders<BsonDocument>.Sort.Descending("customer.name"),
"Agent" => Builders<BsonDocument>.Sort.Descending("agent.serial"),
"Online" => Builders<BsonDocument>.Sort.Descending("online"),
"Description" => Builders<BsonDocument>.Sort.Descending("description"),
"Hosts" => Builders<BsonDocument>.Sort.Descending("hosts"),
_ => null
},
_ => Builders<BsonDocument>.Sort.Ascending("name")
@ -165,239 +154,12 @@ public partial class Index
}
}
private bool _create;
public bool Create
private async Task OnRefreshAsync()
{
get
{
return _create;
}
set
{
if (value != _create)
{
_create = value;
if (value)
{
Model = new();
}
StateHasChanged();
}
}
if (_container is null) return;
await _container.RefreshAsync().ConfigureAwait(false);
}
private async Task OnCreateSubmitAsync()
{
try
{
await Database.Host()
.InsertOneAsync(new HostEntity
{
Name = Model?.Name,
Description = Model?.Description,
}, cancellationToken: default);
Container?.RefreshAsync();
Notification.Success(Snackbar);
}
catch (Exception)
{
Notification.Error(Snackbar);
}
finally
{
Create = false;
}
}
private bool _edit;
public bool Edit
{
get
{
return _edit;
}
set
{
if (value != _edit)
{
_edit = value;
StateHasChanged();
Container?.RefreshAsync();
}
}
}
private void OnEdit(IndexViewModel model)
{
Model = model;
Edit = true;
}
private async Task OnEditSubmitAsync()
{
try
{
await Database.Host()
.UpdateOneAsync(Builders<HostEntity>
.Filter
.Eq(p => p.Id, Model?.Id?.ToString()), Builders<HostEntity>
.Update
.Set(p => p.Name, Model.Name)
.Set(p => p.Description, Model.Description),
cancellationToken: default);
if (Container is not null)
{
_ = Container.RefreshAsync();
}
Notification.Success(Snackbar);
}
catch (Exception)
{
Notification.Error(Snackbar);
}
finally
{
Edit = false;
}
}
private bool _delete;
public bool Delete
{
get
{
return _delete;
}
set
{
if (value != _delete)
{
_delete = value;
StateHasChanged();
Container?.RefreshAsync();
}
}
}
private void OnDelete(IndexViewModel model)
{
Model = model;
Delete = true;
}
private async Task OnDeleteSubmitAsync()
{
try
{
await Database.Host()
.DeleteOneAsync(Builders<HostEntity>
.Filter.Eq(p => p.Id, Model?.Id?.ToString()),
cancellationToken: default);
Notification.Success(Snackbar);
}
catch (Exception)
{
Notification.Error(Snackbar);
}
finally
{
Delete = false;
}
if (Container is not null)
{
_ = Container.RefreshAsync();
}
}
private bool _filter;
private bool Filter
{
get
{
return _filter;
}
set
{
if (value != _filter)
{
_filter = value;
StateHasChanged();
}
}
}
private bool Filtered => FilterUnassignedCustomer || FilterUnassignedAgent;
private bool _filterUnassignedCustomer;
public bool FilterUnassignedCustomer
{
get
{
return _filterUnassignedCustomer;
}
set
{
if (value != _filterUnassignedCustomer)
{
_filterUnassignedCustomer = value;
Container?.RefreshAsync();
if (value)
{
Notification.Warning(Snackbar, "Filtered");
}
}
}
}
private bool _filterUnassignedAgent;
public bool FilterUnassignedAgent
{
get
{
return _filterUnassignedAgent;
}
set
{
if (value != _filterUnassignedAgent)
{
_filterUnassignedAgent = value;
if (Container is not null)
{
_ = Container.RefreshAsync();
}
if (value)
{
Notification.Warning(Snackbar, "Filtered");
}
}
}
}
private void OnFilterReset()
{
FilterUnassignedCustomer = false;
FilterUnassignedAgent = false;
}
[BsonIgnoreExtraElements]
public class IndexViewModel
{
@ -410,13 +172,7 @@ public partial class Index
[BsonElement("description")]
public string? Description { get; set; }
[BsonElement("agent")]
public AgentEntity? Agent { get; set; }
[BsonElement("customer")]
public CustomerEntity? Customer { get; set; }
[BsonElement("online")]
public bool Online { get; set; }
[BsonElement("hosts")]
public int? Hosts { get; set; }
}
}

View file

@ -6,18 +6,15 @@
{
<MudGrid>
<MudItem xs="12" sm="12" md="12" lg="12">
<MudTextField T="string" Label="Query" Variant="Variant.Outlined" @bind-Text="_model.Request.Query" Lines="20" />
<MudTextField T="string" Label="Request" Variant="Variant.Outlined" @bind-Text="_model.Request.RequestData" Lines="10" />
</MudItem>
<MudItem xs="12" sm="12" md="12" lg="12">
@if (_model.Response.HadErrors is false)
@if (_model.Response.ResponseError ?? false)
{
<MudTextField T="string" Label="Data" Variant="Variant.Outlined" @bind-Text="_model.Response.Data" Lines="20" />
}
else
{
<MudTextField T="string" Label="Errors" Variant="Variant.Outlined" @bind-Text="_model.Response.Errors" Lines="20" />
<MudText>Response contains Errors</MudText>
}
<MudTextField T="string" Label="Response" Variant="Variant.Outlined" @bind-Text="_model.Response.ResponseData" Lines="10" />
</MudItem>
<MudItem xs="12" md="12" lg="12" Class="d-flex justify-center">

Some files were not shown because too many files have changed in this diff Show more