+
-@*
-
-
-
- @item.Text
-
-
-
- *@
@@ -43,9 +26,75 @@
-
+
@if (Content is not null)
{
@Content
}
-
\ No newline at end of file
+
+
+@code{
+ [Parameter] public string Title { get; set; } = Global.Name;
+ [Parameter] public List
? Breadcrumbs { get; set; }
+ [Parameter] public RenderFragment? BreadcrumbAction { get; set; }
+ [Parameter] public RenderFragment? Content { get; set; }
+ [Parameter] public Func? LoadData { get; set; }
+ [Parameter] public bool DisableReload { get; set; }
+
+ private bool _disposed;
+
+ private bool _loading;
+ private bool Loading
+ {
+ get => _loading;
+ set
+ {
+ if (value != _loading)
+ {
+ _loading = value;
+ StateHasChanged();
+ }
+ }
+ }
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender) await OnRefreshAsync();
+ }
+
+ private async Task OnRefreshAsync()
+ {
+ if (LoadData is null || Loading) return;
+
+ try
+ {
+ Loading = true;
+ await LoadData();
+ }
+ finally
+ {
+ Loading = false;
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_disposed is false) return;
+ if (disposing is false) return;
+
+ try
+ {
+
+ }
+ finally
+ {
+ _disposed = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Containers/BaseContainer.razor.cs b/src/Web/Insight.Web/Components/Containers/BaseContainer.razor.cs
deleted file mode 100644
index 8f5ab44..0000000
--- a/src/Web/Insight.Web/Components/Containers/BaseContainer.razor.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using Insight.Web.Constants;
-using Microsoft.AspNetCore.Components;
-using MudBlazor;
-
-namespace Insight.Web.Components.Containers;
-
-public partial class BaseContainer
-{
- [Parameter]
- public string Title { get; set; } = Global.Name;
-
- [Parameter]
- public List? Breadcrumbs { get; set; }
-
- [Parameter]
- public RenderFragment? BreadcrumbAction { get; set; }
-
- [Parameter]
- public RenderFragment? Content { get; set; }
-
- [Parameter]
- public Func? LoadData { get; set; }
-
- [Parameter]
- public bool DisableReload { get; set; }
-
-
- private bool _loading;
- private bool Loading
- {
- get
- {
- return _loading;
- }
- set
- {
- if (value != _loading)
- {
- _loading = value;
- StateHasChanged();
- }
- }
- }
-
- protected override async Task OnAfterRenderAsync(bool firstRender)
- {
- if (firstRender)
- {
- await OnRefreshAsync();
- }
- }
-
- private async Task OnRefreshAsync()
- {
- if (LoadData is null || Loading) return;
-
- Loading = true;
- StateHasChanged();
-
- //var start = Stopwatch.GetTimestamp();
-
- await LoadData();
-
- //var time = Stopwatch.GetElapsedTime(start);
-
- //if (time <= TimeSpan.FromSeconds(1))
- //{
- // await Task.Delay(TimeSpan.FromSeconds(1).Subtract(time));
- //}
-
- Loading = false;
- StateHasChanged();
- }
-}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Containers/TableContainer.razor b/src/Web/Insight.Web/Components/Containers/TableContainer.razor
index a7d06ff..faed0f2 100644
--- a/src/Web/Insight.Web/Components/Containers/TableContainer.razor
+++ b/src/Web/Insight.Web/Components/Containers/TableContainer.razor
@@ -1,17 +1,24 @@
-@typeparam T
+@using Insight.Web.Extensions
+
+@typeparam T
+
+@inherits ComponentBase
+@implements IDisposable
+
+@inject NavigationManager NavigationManager
@Title
-
+
@if (OnAdd.HasDelegate)
{
- @if (AddBreadcrumbs is not null)
+ @if (_optionalBreadcrumbs is not null)
{
-
+
}
@@ -25,7 +32,7 @@
-
+
@if (Header is not null)
{
@@ -36,7 +43,7 @@
Filter
-
+
Refresh
@@ -63,4 +70,137 @@
-
\ No newline at end of file
+
+
+@code{
+ [Parameter] public string Title { get; set; } = Global.Name;
+ [Parameter] public List
? Breadcrumbs { get; set; }
+ [Parameter] public Func>>? Data { get; set; }
+ [Parameter] public RenderFragment? Header { get; set; }
+ [Parameter] public RenderFragment? RowTemplate { get; set; }
+ [Parameter] public RenderFragment? ActionTemplate { get; set; }
+ [Parameter] public bool DisableAction { get; set; }
+ [Parameter] public bool DisableRefresh { get; set; }
+ [Parameter] public string? Search
+ {
+ get => _search;
+ set
+ {
+ if (_search == value) return;
+ _search = value;
+
+ SearchChanged.InvokeAsync(value);
+ }
+ }
+ [Parameter] public bool Filtered { get; set; }
+ [Parameter] public EventCallback SearchChanged { get; set; }
+ [Parameter] public EventCallback OnFilter { get; set; }
+ [Parameter] public EventCallback OnAdd { get; set; }
+
+ private List? _optionalBreadcrumbs;
+ private MudTable? _table;
+ private string? _search;
+ private bool _loading;
+ private bool _disposed;
+
+ private bool Loading
+ {
+ get => _loading;
+ set
+ {
+ if (value != _loading)
+ {
+ _loading = value;
+ StateHasChanged();
+ }
+ }
+ }
+
+ protected override void OnInitialized()
+ {
+ if (OnAdd.HasDelegate)
+ {
+ _optionalBreadcrumbs = new List()
+ {
+ new("", "#", true),
+ new("", "#", true)
+ };
+ }
+
+ if (NavigationManager.GetQueryString().TryGetValue("search", out var search))
+ {
+ Search = search.ToString();
+ }
+ }
+
+ private async Task> OnLoadDataAsync(TableState state)
+ {
+ if (Data is null) throw new MissingMethodException(nameof(Data));
+
+ try
+ {
+ Loading = true;
+ return await Data(state);
+ }
+ finally
+ {
+ Loading = false;
+ }
+ }
+
+ public async Task RefreshAsync()
+ {
+ if (Loading || _table is null) return;
+
+ try
+ {
+ Loading = true;
+ await _table.ReloadServerData();
+ }
+ finally
+ {
+ Loading = false;
+ }
+ }
+
+ private async Task SearchAsync(string? text)
+ {
+ Search = text;
+
+ if (Loading) return;
+ await RefreshAsync();
+ }
+
+ private void OnSearchReleased() => NavigationManager.ChangeQueryStringValue("search", Search);
+
+ private async Task OnFilterClick()
+ {
+ if (OnFilter.HasDelegate) await OnFilter.InvokeAsync(this);
+ }
+
+ private async Task OnAddClick()
+ {
+ if (OnAdd.HasDelegate) await OnAdd.InvokeAsync(this);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_disposed is false) return;
+ if (disposing is false) return;
+
+ try
+ {
+
+ }
+ finally
+ {
+ _disposed = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Containers/TableContainer.razor.cs b/src/Web/Insight.Web/Components/Containers/TableContainer.razor.cs
deleted file mode 100644
index bf75e8f..0000000
--- a/src/Web/Insight.Web/Components/Containers/TableContainer.razor.cs
+++ /dev/null
@@ -1,194 +0,0 @@
-using Insight.Web.Constants;
-using Insight.Web.Extensions;
-using Microsoft.AspNetCore.Components;
-using MudBlazor;
-
-namespace Insight.Web.Components.Containers;
-
-public partial class TableContainer
-{
- [Inject] private NavigationManager NavigationManager { get; init; } = default!;
-
-
- [Parameter]
- public string Title { get; set; } = Global.Name;
-
- [Parameter]
- public List? Breadcrumbs { get; set; }
-
- [Parameter]
- public Func>>? Data { get; set; }
-
- [Parameter]
- public RenderFragment? Header { get; set; }
-
- [Parameter]
- public RenderFragment? RowTemplate { get; set; }
-
- [Parameter]
- public RenderFragment? ActionTemplate { get; set; }
-
- [Parameter]
- public bool DisableAction { get; set; }
-
-
- private List? AddBreadcrumbs { get; set; }
- private MudTable? Table { get; set; }
- private bool Loading { get; set; }
-
- private int CurrentPage { get; set; }
- private int CurrentSize { get; set; }
-
- protected override void OnInitialized()
- {
- if (OnAdd.HasDelegate)
- {
- AddBreadcrumbs = new List()
- {
- new BreadcrumbItem("", "#", true),
- new BreadcrumbItem("", "#", true)
- };
- }
-
- if (NavigationManager.GetQueryString().TryGetValue("search", out var search))
- {
- Search = search.ToString();
- }
-
- //if (NavigationManager.GetQueryString().TryGetValue("page", out var pageRaw))
- //{
- // if (int.TryParse(pageRaw, out var page))
- // {
- // CurrentPage = page;
- // }
- //}
-
- //if (NavigationManager.GetQueryString().TryGetValue("size", out var sizeRaw))
- //{
- // if (int.TryParse(sizeRaw, out var size))
- // {
- // CurrentSize = size == 0 ? 100 : size;
- // }
- //}
- }
-
- private async Task> OnLoadDataAsync(TableState state)
- {
- if (Data is null)
- {
- throw new MissingMethodException(nameof(Data));
- }
-
- try
- {
- Loading = true;
-
- //state.Page = CurrentPage;
- //Table.SetRowsPerPage(CurrentSize);
-
- var data = await Data(state);
-
- //CurrentPage = state.Page;
- //CurrentSize = state.PageSize;
-
- //NavigationManager.ChangeQueryStringValue("page", state.Page.ToString());
- //NavigationManager.ChangeQueryStringValue("size", state.PageSize.ToString());
-
- //if (state.SortLabel is not null) NavigationManager.ChangeQueryStringValue("sort", state.SortLabel.ToString());
- //if (state.SortDirection) NavigationManager.ChangeQueryStringValue("direction", state.SortDirection.ToString());
-
- return data;
- }
- finally
- {
- Loading = false;
- }
- }
-
- //
-
- [Parameter]
- public bool DisableRefresh { get; set; }
-
- private string? _search;
-
- [Parameter]
- public string? Search
- {
- get => _search;
- set
- {
- if (_search == value) return;
- _search = value;
-
- SearchChanged.InvokeAsync(value);
- }
- }
-
- [Parameter]
- public EventCallback SearchChanged { get; set; }
-
- private async Task SearchAsync(string? text)
- {
- Search = text;
-
- if (Loading) return;
- await RefreshAsync();
- }
-
- public async Task RefreshAsync()
- {
- if (Loading || Table is null) return;
-
- Loading = true;
- StateHasChanged();
-
- //var start = Stopwatch.GetTimestamp();
-
- await Table.ReloadServerData();
-
- //var time = Stopwatch.GetElapsedTime(start);
-
- //if (time <= TimeSpan.FromSeconds(1))
- //{
- // await Task.Delay(TimeSpan.FromSeconds(1).Subtract(time));
- //}
-
- Loading = false;
- StateHasChanged();
- }
-
- private void OnSearchReleased()
- {
- NavigationManager.ChangeQueryStringValue("search", Search);
- }
-
- //
-
- [Parameter] public EventCallback OnFilter { get; set; }
-
-
- [Parameter]
- public bool Filtered { get; set; }
-
- private async Task OnFilterClick()
- {
- if (OnFilter.HasDelegate)
- {
- await OnFilter.InvokeAsync(this);
- }
- }
-
- //
-
- [Parameter]
- public EventCallback OnAdd { get; set; }
-
- private async Task OnAddClick()
- {
- if (OnAdd.HasDelegate)
- {
- await OnAdd.InvokeAsync(this);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Dialogs/ActionDialog.razor b/src/Web/Insight.Web/Components/Dialogs/ActionDialog.razor
index 660fea5..773d039 100644
--- a/src/Web/Insight.Web/Components/Dialogs/ActionDialog.razor
+++ b/src/Web/Insight.Web/Components/Dialogs/ActionDialog.razor
@@ -1,4 +1,7 @@
-@if (@Actions is not null)
+@inherits ComponentBase
+@implements IDisposable
+
+@if (@Actions is not null)
{
@@ -15,11 +18,59 @@
}
else
{
-
+
@Content
+}
+
+@code{
+ [CascadingParameter] public MudDialogInstance MudDialog { get; set; } = default!;
+
+ [Parameter] public bool Visible
+ {
+ get => _visible;
+ set
+ {
+ if (_visible == value) return;
+ _visible = value;
+
+ VisibleChanged.InvokeAsync(value);
+ }
+ }
+ [Parameter] public EventCallback VisibleChanged { get; set; }
+ [Parameter] public RenderFragment? Content { get; set; }
+ [Parameter] public RenderFragment? Actions { get; set; }
+
+ private bool _visible;
+ private bool _disposed;
+
+ protected override void OnAfterRender(bool firstRender)
+ {
+ if (firstRender is false) return;
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_disposed is false) return;
+ if (disposing is false) return;
+
+ try
+ {
+
+ }
+ finally
+ {
+ _disposed = true;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Dialogs/ActionDialog.razor.cs b/src/Web/Insight.Web/Components/Dialogs/ActionDialog.razor.cs
deleted file mode 100644
index f4734ab..0000000
--- a/src/Web/Insight.Web/Components/Dialogs/ActionDialog.razor.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using Microsoft.AspNetCore.Components;
-
-namespace Insight.Web.Components.Dialogs;
-
-public partial class ActionDialog
-{
- private bool _visible;
-
- [Parameter]
- public bool Visible
- {
- get => _visible;
- set
- {
- if (_visible == value) return;
- _visible = value;
-
- VisibleChanged.InvokeAsync(value);
- }
- }
-
- [Parameter]
- public EventCallback VisibleChanged { get; set; }
-
- [Parameter]
- public RenderFragment? Content { get; set; }
-
- [Parameter]
- public RenderFragment? Actions { get; set; }
-}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor b/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor
index 5aeab56..b974ab4 100644
--- a/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor
+++ b/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor
@@ -11,11 +11,6 @@
- @*
- #
- contacts
- *@
-
@foreach (var user in ChatService.Users.Keys.Where(p => p.Uid != SessionHandler.State.Uid).OrderByDescending(p => p.Online))
diff --git a/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor.cs b/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor.cs
index 57a2a86..c336369 100644
--- a/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor.cs
+++ b/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor.cs
@@ -13,7 +13,7 @@ using static Insight.Web.Constants.Events.Chat;
namespace Insight.Web.Components.Dialogs;
-public partial class ChatDialog
+public partial class ChatDialog : IDisposable
{
[Inject] private Bus Bus { get; init; } = default!;
[Inject] private ChatService ChatService { get; init; } = default!;
@@ -45,10 +45,10 @@ public partial class ChatDialog
private enum Content { Contacts, Chat }
private Content _content = Content.Contacts;
-
private ChatUser? _currentUser;
private ChatSession? _currentSession;
private string? _currentMessage;
+ private bool _disposed;
private readonly List _subscriptions = new();
@@ -194,4 +194,25 @@ public partial class ChatDialog
await InvokeAsync(StateHasChanged);
}
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_disposed is false) return;
+ if (disposing is false) return;
+
+ try
+ {
+
+ }
+ finally
+ {
+ _disposed = true;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Layouts/LoginLayout.razor b/src/Web/Insight.Web/Components/Layouts/LoginLayout.razor
index 4f71777..35f1c0b 100644
--- a/src/Web/Insight.Web/Components/Layouts/LoginLayout.razor
+++ b/src/Web/Insight.Web/Components/Layouts/LoginLayout.razor
@@ -1,8 +1,34 @@
@inherits LayoutComponentBase
+@implements IDisposable
+
-
@Body
-
\ No newline at end of file
+
+
+@code{
+ private bool _disposed;
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_disposed is false) return;
+ if (disposing is false) return;
+
+ try
+ {
+
+ }
+ finally
+ {
+ _disposed = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Layouts/MainLayout.razor b/src/Web/Insight.Web/Components/Layouts/MainLayout.razor
index 672f8c4..ea2781f 100644
--- a/src/Web/Insight.Web/Components/Layouts/MainLayout.razor
+++ b/src/Web/Insight.Web/Components/Layouts/MainLayout.razor
@@ -1,10 +1,19 @@
@using Vaitr.Bus;
+@using Blazored.LocalStorage;
+@using Microsoft.AspNetCore.Identity;
+@using MongoDB.Driver;
+@using Insight.Infrastructure
@inherits LayoutComponentBase
@implements IDisposable
+@inject AuthenticationStateProvider AuthenticationStateProvider
+@inject IServiceScopeFactory ServiceScopeFactory
+@inject ILocalStorageService LocalStorageService
+@inject IMongoDatabase Database
@inject Bus Bus
+
@@ -19,8 +28,11 @@
+ @if (_darkModeSwitch is false)
+ {
+
+ }
-
@@ -40,7 +52,10 @@
@code{
public IReadOnlyDictionary? RouteValues { get; set; }
+ private MudTheme _currentTheme = Themes.Default();
private DrawerProvider? _drawer;
+ private bool _darkMode;
+ private bool _darkModeSwitch;
private bool _disposed;
protected override void OnParametersSet()
@@ -50,6 +65,11 @@
base.OnParametersSet();
}
+ protected override async Task OnInitializedAsync()
+ {
+ await LoadDarkModeAsync();
+ }
+
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
@@ -60,22 +80,85 @@
await Bus.PublishAsync(Events.Layout.Rendered).ConfigureAwait(false);
}
+ private async Task LoadDarkModeAsync()
+ {
+ // local storage
+ var storageDarkMode = await LocalStorageService.GetItemAsync("darkmode");
+ if (storageDarkMode is bool darkmodeValue) _darkMode = darkmodeValue;
+
+ // database override
+ var state = await AuthenticationStateProvider.GetAuthenticationStateAsync();
+
+ if (state?.User.Identity is not null && state.User.Identity.IsAuthenticated)
+ {
+ using var scope = ServiceScopeFactory.CreateScope();
+ var userManager = scope.ServiceProvider.GetRequiredService>();
+
+ if (await userManager.FindByNameAsync(state.User.Identity.Name) is not InsightUser user) return;
+
+ var userPrefs = await Database.UserPreference()
+ .Find(p => p.User == user.Id.ToString())
+ .FirstOrDefaultAsync();
+
+ if (userPrefs is null) return;
+
+ _darkMode = userPrefs.DarkMode;
+
+ await LocalStorageService.SetItemAsync("darkmode", _darkMode);
+ }
+ }
+
+ private async Task OnDarkModeToggleAsync()
+ {
+ // update current
+ _darkMode = !_darkMode;
+
+ // update local storage
+ await LocalStorageService.SetItemAsync("darkmode", _darkMode);
+
+ // update database
+ var state = await AuthenticationStateProvider.GetAuthenticationStateAsync();
+
+ if (state?.User.Identity is not null && state.User.Identity.IsAuthenticated)
+ {
+ using var scope = ServiceScopeFactory.CreateScope();
+ var userManager = scope.ServiceProvider.GetRequiredService>();
+
+ if (await userManager.FindByNameAsync(state.User.Identity.Name) is not InsightUser user) return;
+
+ var date = DateTime.Now;
+
+ var userPrefs = await Database.UserPreference()
+ .UpdateOneAsync(p => p.User == user.Id.ToString(), Builders.Update
+ .SetOnInsert(p => p.User, user.Id.ToString())
+ .SetOnInsert(p => p.Insert, date)
+ .Set(p => p.Update, date)
+ .Set(p => p.DarkMode, _darkMode), new UpdateOptions
+ {
+ IsUpsert = true
+ });
+ }
+
+ await InvokeAsync(StateHasChanged);
+ }
+
public void Dispose()
{
- Dispose(disposing: true);
+ Dispose(true);
GC.SuppressFinalize(this);
}
- protected virtual void Dispose(bool disposing)
+ private void Dispose(bool disposing)
{
- // auto disposed when starved circuit timeouts (disconnects)
- if (_disposed is false)
+ if (_disposed is false) return;
+ if (disposing is false) return;
+
+ try
{
- if (disposing)
- {
-
- }
+ }
+ finally
+ {
_disposed = true;
}
}
diff --git a/src/Web/Insight.Web/Components/Navbars/Account.razor b/src/Web/Insight.Web/Components/Navbars/Account.razor
index 088bc59..92fca5e 100644
--- a/src/Web/Insight.Web/Components/Navbars/Account.razor
+++ b/src/Web/Insight.Web/Components/Navbars/Account.razor
@@ -1,7 +1,36 @@
@inherits ComponentBase
+@implements IDisposable
Account
-Profile
\ No newline at end of file
+Profile
+
+@code{
+ [CascadingParameter] public IReadOnlyDictionary? RouteValues { get; set; }
+
+ private string _title = "Account";
+ private bool _disposed;
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_disposed is false) return;
+ if (disposing is false) return;
+
+ try
+ {
+
+ }
+ finally
+ {
+ _disposed = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Navbars/Account.razor.cs b/src/Web/Insight.Web/Components/Navbars/Account.razor.cs
deleted file mode 100644
index 0a34573..0000000
--- a/src/Web/Insight.Web/Components/Navbars/Account.razor.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using Microsoft.AspNetCore.Components;
-using Microsoft.AspNetCore.Components.Authorization;
-
-namespace Insight.Web.Components.Navbars;
-
-public partial class Account
-{
- [CascadingParameter] public IReadOnlyDictionary? RouteValues { get; set; }
-
- [Inject] private NavigationManager NavigationManager { get; init; } = default!;
- [Inject] private AuthenticationStateProvider AuthenticationStateProvider { get; init; } = default!;
-
- private string Uri { get; set; } = string.Empty;
- private string Title { get; set; } = "Account";
-
- protected override async Task OnInitializedAsync()
- {
- var cp = (await AuthenticationStateProvider.GetAuthenticationStateAsync()).User;
- //Title = $"Account: {cp?.Identity?.Name}";
-
- Uri = NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
- }
-
- protected override void OnAfterRender(bool firstRender)
- {
- Uri = NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
- }
-}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Navbars/Customer.razor b/src/Web/Insight.Web/Components/Navbars/Customer.razor
index 5e1ece7..37a6525 100644
--- a/src/Web/Insight.Web/Components/Navbars/Customer.razor
+++ b/src/Web/Insight.Web/Components/Navbars/Customer.razor
@@ -1,13 +1,70 @@
-@inherits ComponentBase
+@using MongoDB.Driver
+@using Vaitr.Bus
-@*
- @Title
-*@
+@inherits ComponentBase
+@implements IDisposable
-
- @Title
+@inject IMongoDatabase Database
+@inject Bus Bus
+
+
+ @_title
- Hosts
-
\ No newline at end of file
+ Hosts
+
+
+@code{
+ [CascadingParameter] public IReadOnlyDictionary
? RouteValues { get; set; }
+
+ private string? _id;
+ private string _title = "Customer";
+ private IDisposable? _token;
+ private bool _disposed;
+
+ protected override void OnInitialized()
+ {
+ _token = Bus.Subscribe(OnRefresh, p => p == Events.Layout.Rendered);
+ }
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (RouteValues is not null && _id is null)
+ {
+ if (RouteValues.TryGetValue("customerId", out object? rawId) == false) return;
+ _id = rawId?.ToString();
+
+ var entity = await Database.Customer()
+ .Find(p => p.Id == _id)
+ .FirstOrDefaultAsync(default);
+
+ _title = $"{entity?.Name}";
+
+ await InvokeAsync(() => StateHasChanged());
+ }
+ }
+
+ public void OnRefresh(string? message) => InvokeAsync(StateHasChanged);
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_disposed) return;
+ if (disposing is false) return;
+
+ try
+ {
+ _token?.Dispose();
+ }
+ finally
+ {
+ _disposed = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Navbars/Customer.razor.cs b/src/Web/Insight.Web/Components/Navbars/Customer.razor.cs
deleted file mode 100644
index 87a89ae..0000000
--- a/src/Web/Insight.Web/Components/Navbars/Customer.razor.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using Insight.Infrastructure.Entities;
-using Insight.Web.Constants;
-using Microsoft.AspNetCore.Components;
-using MongoDB.Driver;
-using Vaitr.Bus;
-
-namespace Insight.Web.Components.Navbars;
-
-public partial class Customer
-{
- [CascadingParameter] public IReadOnlyDictionary? RouteValues { get; set; }
-
- [Inject] private IMongoDatabase Database { get; set; } = default!;
- [Inject] private Bus Bus { get; init; } = default!;
-
- private string Title { get; set; } = "Customer";
- private string? Id { get; set; }
-
- private IDisposable? Token { get; set; }
- public bool Disposed { get; set; } = false;
-
- protected override void OnInitialized()
- {
- Token = Bus.Subscribe(OnRefresh, p => p == Events.Layout.Rendered);
- }
-
- protected override async Task OnAfterRenderAsync(bool firstRender)
- {
- if (RouteValues is not null && Id is null)
- {
- if (RouteValues.TryGetValue("customerId", out object? rawId) == false) return;
- Id = rawId?.ToString();
-
- var entity = await Database.Customer()
- .Find(p => p.Id == Id)
- .FirstOrDefaultAsync(default);
-
- Title = $"{entity?.Name}";
-
- await InvokeAsync(() => StateHasChanged());
- }
- }
-
- public void OnRefresh(string? message)
- {
- InvokeAsync(() => StateHasChanged());
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- private void Dispose(bool disposing)
- {
- if (Disposed) return;
- if (disposing is false) return;
-
- Token?.Dispose();
- }
-}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Navbars/Host.razor b/src/Web/Insight.Web/Components/Navbars/Host.razor
index 5c394d7..bdf3950 100644
--- a/src/Web/Insight.Web/Components/Navbars/Host.razor
+++ b/src/Web/Insight.Web/Components/Navbars/Host.razor
@@ -1,60 +1,127 @@
-@inherits ComponentBase
+@using MongoDB.Driver
+@using Vaitr.Bus
-@*@if (CustomerEntity is not null)
+@inherits ComponentBase
+@implements IDisposable
+
+@inject IMongoDatabase Database
+@inject Bus Bus
+
+@*@if (_customer is not null)
{
- @CustomerEntity.Name
+ @_customer.Name
}*@
-@if (HostEntity is not null)
+@if (_host is not null)
{
-
- @HostEntity.Name
+
+ @_host.Name
}
- Console
+ Console
- Os
+ Os
- Installed
- Pending
+ Installed
+ Pending
- Sessions
- Software
- Services
- Printers
- Volumes
- Users
- Groups
- Storage Pools
- Virtual Maschines
+ Sessions
+ Software
+ Services
+ Printers
+ Volumes
+ Users
+ Groups
+ Storage Pools
+ Virtual Maschines
- Interfaces
- Addresses
- Nameservers
- Gateways
- Routes
+ Interfaces
+ Addresses
+ Nameservers
+ Gateways
+ Routes
- Mainboard
- Processors
- Memory
- Drives
- Videocards
+ Mainboard
+ Processors
+ Memory
+ Drives
+ Videocards
- Logs
-
\ No newline at end of file
+ Logs
+
+
+@code{
+ [CascadingParameter] public IReadOnlyDictionary? RouteValues { get; set; }
+
+ private string? _id;
+ private CustomerEntity? _customer;
+ private HostEntity? _host;
+ private IDisposable? _token;
+ private bool _disposed;
+
+ protected override void OnInitialized()
+ {
+ _token = Bus?.Subscribe(OnRefresh, p => p == Events.Layout.Rendered);
+ }
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (RouteValues is not null && _id is null)
+ {
+ if (RouteValues.TryGetValue("hostId", out object? rawId) == false) return;
+ _id = rawId?.ToString();
+
+ _host = await Database.Host()
+ .Find(p => p.Id == _id)
+ .FirstOrDefaultAsync(default);
+
+ if (_host is not null)
+ {
+ _customer = await Database.Customer()
+ .Find(p => p.Id == _host.Customer)
+ .FirstOrDefaultAsync(default);
+ }
+
+ await InvokeAsync(() => StateHasChanged());
+ }
+ }
+
+ public void OnRefresh(string? message) => InvokeAsync(StateHasChanged);
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_disposed) return;
+ if (disposing is false) return;
+
+ try
+ {
+ _token?.Dispose();
+ }
+ finally
+ {
+ _disposed = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Navbars/Host.razor.cs b/src/Web/Insight.Web/Components/Navbars/Host.razor.cs
deleted file mode 100644
index 719b30a..0000000
--- a/src/Web/Insight.Web/Components/Navbars/Host.razor.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-using Insight.Infrastructure.Entities;
-using Insight.Web.Constants;
-using Microsoft.AspNetCore.Components;
-using MongoDB.Driver;
-using Vaitr.Bus;
-
-namespace Insight.Web.Components.Navbars;
-
-public partial class Host : IDisposable
-{
- [CascadingParameter] public IReadOnlyDictionary? RouteValues { get; set; }
-
- [Inject] private IMongoDatabase Database { get; init; } = default!;
- [Inject] private Bus Bus { get; init; } = default!;
-
- private CustomerEntity? CustomerEntity { get; set; }
- private HostEntity HostEntity { get; set; }
- private string? Id { get; set; }
-
- private IDisposable? Token { get; set; }
- public bool Disposed { get; set; } = false;
-
- protected override void OnInitialized()
- {
- Token = Bus?.Subscribe(OnRefresh, p => p == Events.Layout.Rendered);
- }
-
- protected override async Task OnAfterRenderAsync(bool firstRender)
- {
- if (RouteValues is not null && Id is null)
- {
- if (RouteValues.TryGetValue("hostId", out object? rawId) == false) return;
- Id = rawId?.ToString();
-
- HostEntity = await Database.Host()
- .Find(p => p.Id == Id)
- .FirstOrDefaultAsync(default);
-
- if (HostEntity is not null)
- {
- CustomerEntity = await Database.Customer()
- .Find(p => p.Id == HostEntity.Customer)
- .FirstOrDefaultAsync(default);
- }
-
- await InvokeAsync(() => StateHasChanged());
- }
- }
-
- public void OnRefresh(string? message)
- {
- InvokeAsync(() => StateHasChanged());
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- private void Dispose(bool disposing)
- {
- if (Disposed) return;
- if (disposing is false) return;
-
- Token?.Dispose();
- }
-}
diff --git a/src/Web/Insight.Web/Components/Navbars/Main.razor b/src/Web/Insight.Web/Components/Navbars/Main.razor
index 66261b4..7281e33 100644
--- a/src/Web/Insight.Web/Components/Navbars/Main.razor
+++ b/src/Web/Insight.Web/Components/Navbars/Main.razor
@@ -1,6 +1,14 @@
-@inherits ComponentBase
+@using MongoDB.Driver
+@using Vaitr.Bus
-
+@inherits ComponentBase
+@implements IDisposable
+
+@inject NavigationManager NavigationManager
+@inject IMongoDatabase Database
+@inject Bus Bus
+
+
@*
Dashboard
*@
@@ -12,7 +20,7 @@
*@
-
+
Os
@@ -84,10 +92,7 @@
-
-
- Overview
-
+
Accounts
@@ -103,10 +108,52 @@
Agents
+
+ Scheduler
+
-@*
-
- Chat
-
-*@
\ No newline at end of file
+@code{
+ private bool ExpandMonitoring => _uri.StartsWith(Navigation.Monitoring.Index);
+ private bool ExpandManagement => _uri.StartsWith(Navigation.Management.Index);
+ private bool ExpandInventory => _uri.StartsWith(Navigation.Inventory.Index);
+ private bool ExpandInventorySystem => _uri.StartsWith(Navigation.Inventory.Systems.Index);
+ private bool ExpandInventoryNetwork => _uri.StartsWith(Navigation.Inventory.Network.Index);
+ private bool ExpandInventoryHardware => _uri.StartsWith(Navigation.Inventory.Hardware.Index);
+ private string _uri = string.Empty;
+ private IDisposable? _token;
+ private bool _disposed;
+
+ protected override void OnInitialized()
+ {
+ _token = Bus?.Subscribe(OnRefresh, p => p == Events.Layout.Rendered);
+ OnRefresh();
+ }
+
+ public void OnRefresh(string? message = null)
+ {
+ _uri = NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
+ InvokeAsync(() => StateHasChanged());
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_disposed is false) return;
+ if (disposing is false) return;
+
+ try
+ {
+ _token?.Dispose();
+ }
+ finally
+ {
+ _disposed = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Navbars/Main.razor.cs b/src/Web/Insight.Web/Components/Navbars/Main.razor.cs
deleted file mode 100644
index f7e3af5..0000000
--- a/src/Web/Insight.Web/Components/Navbars/Main.razor.cs
+++ /dev/null
@@ -1,136 +0,0 @@
-using Insight.Web.Constants;
-using Microsoft.AspNetCore.Components;
-using Vaitr.Bus;
-
-namespace Insight.Web.Components.Navbars;
-
-public partial class Main : IDisposable
-{
- [Inject] private Bus Bus { get; init; } = default!;
- [Inject] private NavigationManager NavigationManager { get; init; } = default!;
-
- private string Uri { get; set; } = string.Empty;
- private IDisposable? Token { get; set; }
- public bool Disposed { get; set; } = false;
-
- protected override void OnInitialized()
- {
- Token = Bus?.Subscribe(OnRefresh, p => p == Events.Layout.Rendered);
- OnRefresh();
- }
-
- public void OnRefresh(string? message = null)
- {
- Uri = NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
- InvokeAsync(() => StateHasChanged());
- }
-
- private bool ExpandMonitoringGroup
- {
- get
- {
- if (Uri.StartsWith(Navigation.Monitoring.Index)) return true;
- return false;
- }
- }
-
- private bool ExpandManagementGroup
- {
- get
- {
- if (Uri.StartsWith(Navigation.Management.Overview.Index)) return true;
- if (Uri.StartsWith(Navigation.Management.Accounts.Index)) return true;
- if (Uri.StartsWith(Navigation.Management.Customers.Index)) return true;
- if (Uri.StartsWith(Navigation.Management.Hosts.Index)) return true;
- if (Uri.StartsWith(Navigation.Management.HostGroups.Index)) return true;
- if (Uri.StartsWith(Navigation.Management.Agents.Index)) return true;
- return false;
- }
- }
-
- private bool ExpandInventoryGroup
- {
- get
- {
- if (ExpandInventorySystem) return true;
- if (ExpandInventoryNetwork) return true;
- if (ExpandInventoryHardware) return true;
- return false;
- }
- }
-
- private bool ExpandInventorySystem
- {
- get
- {
- if (Uri.StartsWith(Navigation.Inventory.Systems.Os.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.Os.Hosts)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.Os.Guests)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.Updates.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.Updates.Hosts)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.Software.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.Software.Hosts)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.Services.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.Services.Hosts)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.Sessions.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.Printers.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.Volumes.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.Users.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.Users.Hosts)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.Groups.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.Groups.Hosts)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.StoragePools.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Systems.VirtualMaschines.Index)) return true;
- return false;
- }
- }
-
- private bool ExpandInventoryNetwork
- {
- get
- {
- if (Uri.StartsWith(Navigation.Inventory.Network.Interfaces.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Network.Addresses.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Network.Addresses.Hosts)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Network.Nameservers.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Network.Nameservers.Hosts)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Network.Gateways.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Network.Gateways.Hosts)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Network.Routes.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Network.Routes.Hosts)) return true;
- return false;
- }
- }
-
- private bool ExpandInventoryHardware
- {
- get
- {
- if (Uri.StartsWith(Navigation.Inventory.Hardware.Mainboards.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Hardware.Mainboards.Hosts)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Hardware.Processors.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Hardware.Processors.Hosts)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Hardware.Memory.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Hardware.Memory.Hosts)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Hardware.Drives.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Hardware.Drives.Hosts)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Hardware.Videocards.Index)) return true;
- if (Uri.StartsWith(Navigation.Inventory.Hardware.Videocards.Hosts)) return true;
- return false;
- }
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- private void Dispose(bool disposing)
- {
- if (Disposed) return;
- if (disposing is false) return;
-
- Token?.Dispose();
- }
-}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Navbars/NavSwitch.razor b/src/Web/Insight.Web/Components/Navbars/NavSwitch.razor
deleted file mode 100644
index 9eb23b4..0000000
--- a/src/Web/Insight.Web/Components/Navbars/NavSwitch.razor
+++ /dev/null
@@ -1,29 +0,0 @@
-@using System.Reflection;
-@inherits ComponentBase
-
-
-
-
- @if (_content == Content.Account)
- {
-
- }
- else if (_content == Content.Host)
- {
-
- }
- else if (_content == Content.Customer)
- {
-
- }
- else
- {
-
- }
-
-
-
-
-
- @(Assembly.GetEntryAssembly()?.GetName().Version)
-
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Navbars/NavSwitch.razor.cs b/src/Web/Insight.Web/Components/Navbars/NavSwitch.razor.cs
deleted file mode 100644
index 2af5b32..0000000
--- a/src/Web/Insight.Web/Components/Navbars/NavSwitch.razor.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using Insight.Web.Constants;
-using Microsoft.AspNetCore.Components;
-using Vaitr.Bus;
-
-namespace Insight.Web.Components.Navbars;
-
-public partial class NavSwitch : IDisposable
-{
- [CascadingParameter] public IReadOnlyDictionary? RouteValues { get; set; }
-
- [Inject] private NavigationManager NavigationManager { get; init; } = default!;
- [Inject] private Bus Bus { get; init; } = default!;
-
- public string Url { get; set; } = string.Empty;
- private IDisposable? Token { get; set; }
- public bool Disposed { get; set; } = false;
-
- private enum Content { Main, Account, Customer, Host }
- private Content _content = Content.Main;
-
- protected override void OnInitialized()
- {
- Token = Bus?.SubscribeAsync(OnRefreshAsync, p => p == Events.Layout.Rendered);
- }
-
- protected override async Task OnAfterRenderAsync(bool firstRender)
- {
- if (firstRender)
- {
- await OnRefreshAsync().ConfigureAwait(false);
- }
- }
-
- public async ValueTask OnRefreshAsync(string? message = null, CancellationToken cancellationToken = default)
- {
- Url = NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
-
- if (Url is null) return;
-
- if (Url.StartsWith($"{Navigation.Account.Index}/")) _content = Content.Account;
- else if (Url.StartsWith($"{Navigation.Management.Customers.Index}/")) _content = Content.Customer;
- else if (Url.StartsWith($"{Navigation.Management.Hosts.Index}/")) _content = Content.Host;
- else _content = Content.Main;
-
- await InvokeAsync(StateHasChanged).ConfigureAwait(false);
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- private void Dispose(bool disposing)
- {
- if (Disposed) return;
- Token?.Dispose();
- }
-}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Navbars/Scheduler.razor b/src/Web/Insight.Web/Components/Navbars/Scheduler.razor
new file mode 100644
index 0000000..024e016
--- /dev/null
+++ b/src/Web/Insight.Web/Components/Navbars/Scheduler.razor
@@ -0,0 +1,37 @@
+@inherits ComponentBase
+@implements IDisposable
+
+@inject NavigationManager NavigationManager
+
+
+ Scheduler
+
+
+Jobs
+Tasks
+Triggers
+
+@code{
+ private bool _disposed;
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_disposed is false) return;
+ if (disposing is false) return;
+
+ try
+ {
+
+ }
+ finally
+ {
+ _disposed = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Providers/ChatProvider.razor b/src/Web/Insight.Web/Components/Providers/ChatProvider.razor
index 0ba0c57..c6f231a 100644
--- a/src/Web/Insight.Web/Components/Providers/ChatProvider.razor
+++ b/src/Web/Insight.Web/Components/Providers/ChatProvider.razor
@@ -2,11 +2,12 @@
@using Vaitr.Bus;
@using static Insight.Web.Constants.Events.Chat;
+@inherits ComponentBase
+@implements IDisposable
+
@inject Bus Bus
@inject SessionHandler SessionHandler
-@implements IDisposable
-
@@ -20,7 +21,7 @@
private readonly ConcurrentBag _subscriptions = new();
- protected override async Task OnInitializedAsync()
+ protected override void OnInitialized()
{
_subscriptions.Add(Bus.SubscribeAsync(async (x, c) => await InvokeAsync(StateHasChanged), p => p == Events.Sessions.Changed));
_subscriptions.Add(Bus.SubscribeAsync(async (x, c) => await InvokeAsync(StateHasChanged), p => p.Message.SenderId != SessionHandler.State.Uid));
@@ -28,21 +29,24 @@
public void Dispose()
{
- Dispose(disposing: true);
+ Dispose(true);
GC.SuppressFinalize(this);
}
- protected virtual void Dispose(bool disposing)
+ private void Dispose(bool disposing)
{
// auto disposed when starved circuit timeouts (disconnects)
- if (_disposed is false)
- {
- if (disposing)
- {
- foreach (var sub in _subscriptions) sub.Dispose();
- _subscriptions.Clear();
- }
+ if (_disposed is false) return;
+ if (disposing is false) return;
+
+ try
+ {
+ foreach (var sub in _subscriptions) sub.Dispose();
+ _subscriptions.Clear();
+ }
+ finally
+ {
_disposed = true;
}
}
diff --git a/src/Web/Insight.Web/Components/Providers/DrawerProvider.razor b/src/Web/Insight.Web/Components/Providers/DrawerProvider.razor
index 22dbe6e..117178d 100644
--- a/src/Web/Insight.Web/Components/Providers/DrawerProvider.razor
+++ b/src/Web/Insight.Web/Components/Providers/DrawerProvider.razor
@@ -1,8 +1,47 @@
-
+@using System.Reflection;
+@using MongoDB.Driver
+@using Vaitr.Bus
+
+@inherits ComponentBase
+@implements IDisposable
+
+@inject NavigationManager NavigationManager
+@inject IMongoDatabase Database
+@inject Bus Bus
+
+
-
+
+
+
+ @if (_content == Content.Account)
+ {
+
+ }
+ else if (_content == Content.Customer)
+ {
+
+ }
+ else if (_content == Content.Host)
+ {
+
+ }
+ else if (_content == Content.Scheduler)
+ {
+
+ }
+ else
+ {
+
+ }
+
+
+
+
+ @(Assembly.GetEntryAssembly()?.GetName().Version)
+
@@ -11,6 +50,57 @@
@code {
[CascadingParameter] public IReadOnlyDictionary? RouteValues { get; set; }
+ private string _uri = string.Empty;
+ private enum Content { Main, Account, Customer, Host, Scheduler }
+ private Content _content = Content.Main;
+ private IDisposable? _token;
private bool _open = true;
+ private bool _disposed;
+
+ protected override void OnInitialized()
+ {
+ _token = Bus?.SubscribeAsync(OnRefreshAsync, p => p == Events.Layout.Rendered);
+ }
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender) await OnRefreshAsync();
+ }
+
public void Toggle() => _open = !_open;
+
+ public async ValueTask OnRefreshAsync(string? message = null, CancellationToken cancellationToken = default)
+ {
+ _uri = NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
+ if (_uri is null) return;
+
+ if (_uri.StartsWith($"{Navigation.Account.Index}/")) _content = Content.Account;
+ else if (_uri.StartsWith($"{Navigation.Management.Customers.Index}/")) _content = Content.Customer;
+ else if (_uri.StartsWith($"{Navigation.Management.Hosts.Index}/")) _content = Content.Host;
+ else if (_uri.StartsWith($"{Navigation.Management.Scheduler.Index}/")) _content = Content.Scheduler;
+ else _content = Content.Main;
+
+ await InvokeAsync(StateHasChanged);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_disposed is false) return;
+ if (disposing is false) return;
+
+ try
+ {
+ _token?.Dispose();
+ }
+ finally
+ {
+ _disposed = true;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Providers/ProfileProvider.razor b/src/Web/Insight.Web/Components/Providers/ProfileProvider.razor
index 2208e1e..5cf99d6 100644
--- a/src/Web/Insight.Web/Components/Providers/ProfileProvider.razor
+++ b/src/Web/Insight.Web/Components/Providers/ProfileProvider.razor
@@ -1,4 +1,7 @@
-@inject NavigationManager NavigationManager
+@inherits ComponentBase
+@implements IDisposable
+
+@inject NavigationManager NavigationManager
@@ -49,6 +52,7 @@
@code{
private MudMenu? _menu;
+ private bool _disposed;
private void OnLogin()
{
@@ -67,4 +71,25 @@
_menu?.CloseMenu();
NavigationManager.NavigateTo(Navigation.Account.Profile, false);
}
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_disposed is false) return;
+ if (disposing is false) return;
+
+ try
+ {
+
+ }
+ finally
+ {
+ _disposed = true;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Providers/SessionProvider.razor b/src/Web/Insight.Web/Components/Providers/SessionProvider.razor
index b5910f5..7cdbfd5 100644
--- a/src/Web/Insight.Web/Components/Providers/SessionProvider.razor
+++ b/src/Web/Insight.Web/Components/Providers/SessionProvider.razor
@@ -1,14 +1,37 @@
@using Vaitr.Bus;
+@inherits ComponentBase
+@implements IDisposable
+
@inject SessionHandler SessionHandler
@inject Bus Bus
@code {
+ private bool _disposed;
+
protected override async Task OnAfterRenderAsync(bool firstRender)
{
- if (firstRender)
+ if (firstRender) await SessionHandler.UpdateStateAsync(default);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_disposed is false) return;
+ if (disposing is false) return;
+
+ try
{
- await SessionHandler.UpdateStateAsync(default);
+
+ }
+ finally
+ {
+ _disposed = true;
}
}
}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Components/Providers/ThemeProvider.razor b/src/Web/Insight.Web/Components/Providers/ThemeProvider.razor
deleted file mode 100644
index f3549d7..0000000
--- a/src/Web/Insight.Web/Components/Providers/ThemeProvider.razor
+++ /dev/null
@@ -1,90 +0,0 @@
-@using Blazored.LocalStorage;
-@using Microsoft.AspNetCore.Identity;
-@using MongoDB.Driver;
-@using Insight.Infrastructure
-
-@inject IServiceScopeFactory ServiceScopeFactory
-@inject ILocalStorageService LocalStorageService
-@inject IMongoDatabase Database
-@inject AuthenticationStateProvider AuthenticationStateProvider
-
-
-
-@if (DisableIcon is false)
-{
-
-}
-
-@code {
- [Parameter] public bool DisableIcon { get; set; }
-
- private MudTheme CurrentTheme { get; } = Themes.Default();
- private bool DarkMode { get; set; }
-
- protected override async Task OnInitializedAsync()
- {
- await LoadDarkModeAsync();
- }
-
- public async Task LoadDarkModeAsync()
- {
- // local storage
- var storageDarkMode = await LocalStorageService.GetItemAsync("darkmode");
- if (storageDarkMode is bool darkmodeValue) DarkMode = darkmodeValue;
-
- // database override
- var state = await AuthenticationStateProvider.GetAuthenticationStateAsync();
-
- if (state?.User.Identity is not null && state.User.Identity.IsAuthenticated)
- {
- using var scope = ServiceScopeFactory.CreateScope();
- var userManager = scope.ServiceProvider.GetRequiredService>();
-
- if (await userManager.FindByNameAsync(state.User.Identity.Name) is not InsightUser user) return;
-
- var userPrefs = await Database.UserPreference()
- .Find(p => p.User == user.Id.ToString())
- .FirstOrDefaultAsync();
-
- if (userPrefs is null) return;
-
- DarkMode = userPrefs.DarkMode;
-
- await LocalStorageService.SetItemAsync("darkmode", DarkMode);
- }
- }
-
- private async Task OnDarkModeToggleAsync()
- {
- // update current
- DarkMode = !DarkMode;
-
- // update local storage
- await LocalStorageService.SetItemAsync("darkmode", DarkMode);
-
- // update database
- var state = await AuthenticationStateProvider.GetAuthenticationStateAsync();
-
- if (state?.User.Identity is not null && state.User.Identity.IsAuthenticated)
- {
- using var scope = ServiceScopeFactory.CreateScope();
- var userManager = scope.ServiceProvider.GetRequiredService>();
-
- if (await userManager.FindByNameAsync(state.User.Identity.Name) is not InsightUser user) return;
-
- var date = DateTime.Now;
-
- var userPrefs = await Database.UserPreference()
- .UpdateOneAsync(p => p.User == user.Id.ToString(), Builders.Update
- .SetOnInsert(p => p.User, user.Id.ToString())
- .SetOnInsert(p => p.Insert, date)
- .Set(p => p.Update, date)
- .Set(p => p.DarkMode, DarkMode), new UpdateOptions
- {
- IsUpsert = true
- });
- }
-
- await InvokeAsync(StateHasChanged);
- }
-}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Constants/Navigation.cs b/src/Web/Insight.Web/Constants/Navigation.cs
index cc2209a..3fcdfd6 100644
--- a/src/Web/Insight.Web/Constants/Navigation.cs
+++ b/src/Web/Insight.Web/Constants/Navigation.cs
@@ -1,4 +1,6 @@
-namespace Insight.Web.Constants;
+using static Insight.Web.Constants.Navigation.Monitoring;
+
+namespace Insight.Web.Constants;
public static class Navigation
{
@@ -13,44 +15,22 @@ public static class Navigation
public static class Account
{
public const string Index = "account";
- public const string Login = "account/login";
- public const string LoginTFA = "account/login/{key:guid}";
- public const string SignIn = "account/signin";
- public const string SignInTFA = "account/signin/2fa";
- public const string Logout = "account/logout";
- public const string Lockout = "account/lockout";
- public const string Profile = "account/profile";
- public const string ChangePassword = "account/changepassword";
+ public const string Login = Index + "/login";
+ public const string LoginTFA = Login + "/{key:guid}";
+ public const string SignIn = Index + "/signin";
+ public const string SignInTFA = SignIn + "/2fa";
+ public const string Logout = Index + "/logout";
+ public const string Lockout = Index + "/lockout";
+ public const string Profile = Index + "/profile";
+ public const string ChangePassword = Index + "/changepassword";
- public static string LoginHref(string redirect)
- {
- if (string.IsNullOrWhiteSpace(redirect))
- {
- return Login;
- }
+ public static string LoginHref(string redirect) => string.IsNullOrWhiteSpace(redirect) ? Login : $"{Login}?redirect={redirect}";
+ public static string LoginTFAHref(Guid key) => LoginTFA.Replace("{key:guid}", key.ToString());
- return $"{Login}?redirect={redirect}";
- }
+ public static string SignInHref(Guid key) => $"{SignIn}?key={key}";
+ public static string SignInTFAHref(Guid key) => $"{SignInTFA}?key={key}";
- public static string LoginTFAHref(Guid key)
- {
- return LoginTFA.Replace("{key:guid}", key.ToString());
- }
-
- public static string SignInHref(Guid key)
- {
- return $"{SignIn}?key={key}";
- }
-
- public static string SignInTFAHref(Guid key)
- {
- return $"{SignInTFA}?key={key}";
- }
-
- public static string ChangePasswordHref(Guid key)
- {
- return $"{ChangePassword}?key={key}";
- }
+ public static string ChangePasswordHref(Guid key) => $"{ChangePassword}?key={key}";
}
public static class Monitoring
@@ -59,36 +39,36 @@ public static class Navigation
public static class Maintenance
{
- public const string Index = "monitoring/maintenance";
+ public const string Index = Monitoring.Index + "/maintenance";
public static class Drives
{
- public const string Index = "monitoring/maintenance/drives";
+ public const string Index = Monitoring.Index + "/drives";
}
public static class StoragePools
{
- public const string Index = "monitoring/maintenance/storagepools";
+ public const string Index = Monitoring.Index + "/storagepools";
}
public static class Volumes
{
- public const string Index = "monitoring/maintenance/volumes";
+ public const string Index = Monitoring.Index + "/volumes";
}
public static class Guests
{
- public const string Index = "monitoring/maintenance/guests";
+ public const string Index = Monitoring.Index + "/guests";
}
public static class Snapshots
{
- public const string Index = "monitoring/maintenance/snapshots";
+ public const string Index = Monitoring.Index + "/snapshots";
}
public static class Updates
{
- public const string Index = "monitoring/maintenance/updates";
+ public const string Index = Monitoring.Index + "/updates";
}
}
}
@@ -97,106 +77,58 @@ public static class Navigation
{
public const string Index = "management";
- public static class Overview
- {
- public const string Index = "management/overview";
- }
-
public static class Accounts
{
- public const string Index = "management/accounts";
- public const string Details = "management/accounts/{accountId}";
+ public const string Index = Management.Index + "/accounts";
+ public const string Details = Index + "/{accountId}";
- public static string DetailsHref(string? accountId)
- {
- return Details.Replace("{accountId}", accountId);
- }
+ public static string DetailsHref(string? accountId) => Details.Replace("{accountId}", accountId);
}
public static class Customers
{
- public const string Index = "management/customers";
- public const string Details = "management/customers/{customerId}";
- public const string Hosts = "management/customers/{customerId}/hosts";
- public const string HostsAssign = "management/customers/{customerId}/hosts/assign";
+ public const string Index = Management.Index + "/customers";
+ public const string Details = Index + "/{customerId}";
+ public const string Hosts = Details + "/hosts";
+ public const string HostsAssign = Hosts + "/assign";
- public static string DetailsHref(string? customerId)
- {
- return Details.Replace("{customerId}", customerId);
- }
-
- public static string HostsHref(string? customerId)
- {
- return Hosts.Replace("{customerId}", customerId);
- }
-
- public static string HostsAssignHref(string? customerId)
- {
- return HostsAssign.Replace("{customerId}", customerId);
- }
+ public static string DetailsHref(string? customerId) => Details.Replace("{customerId}", customerId);
+ public static string HostsHref(string? customerId) => Hosts.Replace("{customerId}", customerId);
+ public static string HostsAssignHref(string? customerId) => HostsAssign.Replace("{customerId}", customerId);
}
public static class Agents
{
- public const string Index = "management/agents";
- public const string Details = "management/agents/{agentId}";
- public const string Logs = "management/agents/{agentId}/logs";
- public const string HostAssign = "management/agents/{agentId}/assign";
+ public const string Index = Management.Index + "/agents";
+ public const string Details = Index + "/{agentId}";
+ public const string Logs = Details + "/logs";
+ public const string HostAssign = Details + "/assign";
- public static string DetailsHref(string? agentId)
- {
- return Details.Replace("{agentId}", agentId);
- }
-
- public static string LogsHref(string? agentId)
- {
- return Logs.Replace("{agentId}", agentId);
- }
-
- public static string HostAssingHref(string? agentId)
- {
- return HostAssign.Replace("{agentId}", agentId);
- }
+ public static string DetailsHref(string? agentId) => Details.Replace("{agentId}", agentId);
+ public static string LogsHref(string? agentId) => Logs.Replace("{agentId}", agentId);
+ public static string HostAssingHref(string? agentId) => HostAssign.Replace("{agentId}", agentId);
}
public static class Hosts
{
- public const string Index = "management/hosts";
- public const string Details = "management/hosts/{hostId}";
- public const string Logs = "management/hosts/{hostId}/logs";
- public const string CustomerAssign = "management/hosts/{hostId}/customer/assign";
- public const string AgentAssign = "management/hosts/{hostId}/agent/assign";
+ public const string Index = Management.Index + "/hosts";
+ public const string Details = Index + "/{hostId}";
+ public const string Logs = Details + "/logs";
+ public const string CustomerAssign = Details + "/customer/assign";
+ public const string AgentAssign = Details + "/agent/assign";
- public static string DetailsHref(string? hostId)
- {
- return Details.Replace("{hostId}", hostId);
- }
-
- public static string LogsHref(string? hostId)
- {
- return Logs.Replace("{hostId}", hostId);
- }
-
- public static string CustomerAssingHref(string? hostId)
- {
- return CustomerAssign.Replace("{hostId}", hostId);
- }
-
- public static string AgentAssingHref(string? hostId)
- {
- return AgentAssign.Replace("{hostId}", hostId);
- }
+ public static string DetailsHref(string? hostId) => Details.Replace("{hostId}", hostId);
+ public static string LogsHref(string? hostId) => Logs.Replace("{hostId}", hostId);
+ public static string CustomerAssingHref(string? hostId) => CustomerAssign.Replace("{hostId}", hostId);
+ public static string AgentAssingHref(string? hostId) => AgentAssign.Replace("{hostId}", hostId);
public static class Actions
{
public static class Console
{
- public const string Index = "management/hosts/{hostId}/console";
+ public const string Index = Hosts.Details + "/console";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
}
}
@@ -204,190 +136,121 @@ public static class Navigation
{
public static class Os
{
- public const string Details = "management/hosts/{hostId}/os";
+ public const string Details = Hosts.Details + "/os";
- public static string DetailsHref(string? hostId)
- {
- return Details.Replace("{hostId}", hostId);
- }
+ public static string DetailsHref(string? hostId) => Details.Replace("{hostId}", hostId);
}
public static class Updates
{
public static class Installed
{
- public const string Index = "management/hosts/{hostId}/updates/installed";
+ public const string Index = Hosts.Details + "/updates/installed";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
}
public static class Pending
{
- public const string Index = "management/hosts/{hostId}/updates/pending";
+ public const string Index = Hosts.Details + "/updates/pending";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
}
}
public static class Sessions
{
- public const string Index = "management/hosts/{hostId}/sessions";
+ public const string Index = Hosts.Details + "/sessions";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
}
public static class Software
{
- public const string Index = "management/hosts/{hostId}/software";
+ public const string Index = Hosts.Details + "/software";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
}
public static class Services
{
- public const string Index = "management/hosts/{hostId}/services";
+ public const string Index = Hosts.Details + "/services";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
}
public static class Printers
{
- public const string Index = "management/hosts/{hostId}/printers";
+ public const string Index = Hosts.Details + "/printers";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
}
public static class Volumes
{
- public const string Index = "management/hosts/{hostId}/volumes";
- public const string Details = "management/hosts/{hostId}/volumes/{volumeId}";
+ public const string Index = Hosts.Details + "/volumes";
+ public const string Details = Index + "/{volumeId}";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
-
- public static string DetailsHref(string? hostId, string? volumeId)
- {
- return Details.Replace("{hostId}", hostId).Replace("{volumeId}", volumeId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
+ public static string DetailsHref(string? hostId, string? volumeId) => Details.Replace("{hostId}", hostId).Replace("{volumeId}", volumeId);
}
public static class Users
{
- public const string Index = "management/hosts/{hostId}/users";
- public const string Details = "management/hosts/{hostId}/users/{userId}";
+ public const string Index = Hosts.Details + "/users";
+ public const string Details = Index + "/{userId}";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
-
- public static string DetailsHref(string? hostId, string? userId)
- {
- return Details.Replace("{hostId}", hostId).Replace("{userId}", userId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
+ public static string DetailsHref(string? hostId, string? userId) => Details.Replace("{hostId}", hostId).Replace("{userId}", userId);
}
public static class Groups
{
- public const string Index = "management/hosts/{hostId}/groups";
+ public const string Index = Hosts.Details + "/groups";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
}
public static class StoragePools
{
- public const string Index = "management/hosts/{hostId}/storagepools";
- public const string Details = "management/hosts/{hostId}/storagepools/{storagePoolId}";
+ public const string Index = Hosts.Details + "/storagepools";
+ public const string Details = Index + "/{storagePoolId}";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
-
- public static string DetailsHref(string? hostId, string? storagePoolId)
- {
- return Details.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
+ public static string DetailsHref(string? hostId, string? storagePoolId) => Details.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId);
public static class VirtualDisks
{
- public const string Index = "management/hosts/{hostId}/storagepools/{storagePoolId}/virtualdisks";
- public const string Details = "management/hosts/{hostId}/storagepools/{storagePoolId}/virtualdisks/{virtualDiskId}";
+ public const string Index = StoragePools.Details + "/virtualdisks";
+ public const string Details = Index + "/{virtualDiskId}";
- public static string IndexHref(string? hostId, string? storagePoolId)
- {
- return Index.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId);
- }
-
- public static string DetailsHref(string? hostId, string? storagePoolId, string? virtualDiskId)
- {
- return Details.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId).Replace("{virtualDiskId}", virtualDiskId);
- }
+ public static string IndexHref(string? hostId, string? storagePoolId) => Index.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId);
+ public static string DetailsHref(string? hostId, string? storagePoolId, string? virtualDiskId) => Details.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId).Replace("{virtualDiskId}", virtualDiskId);
}
public static class PhysicalDisks
{
- public const string Index = "management/hosts/{hostId}/storagepools/{storagePoolId}/physicaldisks";
- public const string Details = "management/hosts/{hostId}/storagepools/{storagePoolId}/physicaldisks/{physicalDiskId}";
+ public const string Index = StoragePools.Details + "/physicaldisks";
+ public const string Details = Index + "/{physicalDiskId}";
- public static string IndexHref(string? hostId, string? storagePoolId)
- {
- return Index.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId);
- }
-
- public static string DetailsHref(string? hostId, string? storagePoolId, string? physicalDiskId)
- {
- return Details.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId).Replace("{physicalDiskId}", physicalDiskId);
- }
+ public static string IndexHref(string? hostId, string? storagePoolId) => Index.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId);
+ public static string DetailsHref(string? hostId, string? storagePoolId, string? physicalDiskId) => Details.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId).Replace("{physicalDiskId}", physicalDiskId);
}
}
public static class VirtualMaschines
{
- public const string Index = "management/hosts/{hostId}/virtualmaschines";
- public const string Details = "management/hosts/{hostId}/virtualmaschines/{virtualMaschineId}";
+ public const string Index = Hosts.Details + "/virtualmaschines";
+ public const string Details = Index + "/{virtualMaschineId}";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
-
- public static string DetailsHref(string? hostId, string? virtualMaschineId)
- {
- return Details.Replace("{hostId}", hostId).Replace("{virtualMaschineId}", virtualMaschineId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
+ public static string DetailsHref(string? hostId, string? virtualMaschineId) => Details.Replace("{hostId}", hostId).Replace("{virtualMaschineId}", virtualMaschineId);
public static class Snapshots
{
- public const string Details = "management/hosts/{hostId}/virtualmaschines/{virtualMaschineId}/snapshots/{snapshotId}";
+ public const string Details = VirtualMaschines.Details + "/snapshots/{snapshotId}";
- public static string DetailsHref(string? hostId, string? virtualMaschineId, string? snapshotId)
- {
- return Details.Replace("{hostId}", hostId).Replace("{virtualMaschineId}", virtualMaschineId).Replace("{snapshotId}", snapshotId);
- }
+ public static string DetailsHref(string? hostId, string? virtualMaschineId, string? snapshotId) => Details.Replace("{hostId}", hostId).Replace("{virtualMaschineId}", virtualMaschineId).Replace("{snapshotId}", snapshotId);
}
}
}
@@ -396,63 +259,44 @@ public static class Navigation
{
public static class Interfaces
{
- public const string Index = "management/hosts/{hostId}/interfaces";
- public const string Details = "management/hosts/{hostId}/interfaces/{interfaceId}";
+ public const string Index = Hosts.Details + "/interfaces";
+ public const string Details = Index + "/{interfaceId}";
- public const string Addresses = "management/hosts/{hostId}/interfaces/{interfaceId}/addresses";
- public const string Nameservers = "management/hosts/{hostId}/interfaces/{interfaceId}/nameservers";
- public const string Gateways = "management/hosts/{hostId}/interfaces/{interfaceId}/gateways";
- public const string Routes = "management/hosts/{hostId}/interfaces/{interfaceId}/routes";
+ public const string Addresses = Details + "/addresses";
+ public const string Nameservers = Details + "/nameservers";
+ public const string Gateways = Details + "/gateways";
+ public const string Routes = Details + "/routes";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
-
- public static string DetailsHref(string? hostId, string? interfaceId)
- {
- return Details.Replace("{hostId}", hostId).Replace("{interfaceId}", interfaceId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
+ public static string DetailsHref(string? hostId, string? interfaceId) => Details.Replace("{hostId}", hostId).Replace("{interfaceId}", interfaceId);
}
public static class Addresses
{
- public const string Index = "management/hosts/{hostId}/addresses";
+ public const string Index = Hosts.Details + "/addresses";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
}
public static class Gateways
{
- public const string Index = "management/hosts/{hostId}/gateways";
+ public const string Index = Details + "/gateways";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
}
public static class Nameservers
{
- public const string Index = "management/hosts/{hostId}/nameservers";
+ public const string Index = Hosts.Details + "/nameservers";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
}
public static class Routes
{
- public const string Index = "management/hosts/{hostId}/routes";
+ public const string Index = Hosts.Details + "/routes";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
}
}
@@ -460,300 +304,264 @@ public static class Navigation
{
public static class Mainboard
{
- public const string Details = "management/hosts/{hostId}/mainboard";
+ public const string Details = Hosts.Details + "/mainboard";
- public static string DetailsHref(string? hostId)
- {
- return Details.Replace("{hostId}", hostId);
- }
+ public static string DetailsHref(string? hostId) => Details.Replace("{hostId}", hostId);
}
public static class Processors
{
- public const string Details = "management/hosts/{hostId}/processors";
+ public const string Details = Hosts.Details + "/processors";
- public static string DetailsHref(string? hostId)
- {
- return Details.Replace("{hostId}", hostId);
- }
+ public static string DetailsHref(string? hostId) => Details.Replace("{hostId}", hostId);
}
public static class Memory
{
- public const string Index = "management/hosts/{hostId}/memory";
+ public const string Index = Hosts.Details + "/memory";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
}
public static class Drives
{
- public const string Index = "management/hosts/{hostId}/drives";
+ public const string Index = Hosts.Details + "/drives";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
}
public static class Videocards
{
- public const string Index = "management/hosts/{hostId}/videocards";
+ public const string Index = Hosts.Details + "/videocards";
- public static string IndexHref(string? hostId)
- {
- return Index.Replace("{hostId}", hostId);
- }
+ public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId);
}
}
}
public static class HostGroups
{
- 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 const string Index = Management.Index + "/hostgroups";
+ public const string Details = Index + "/{groupId}";
+ public const string Hosts = Details + "/hosts";
+ public const string HostsAssign = Details + "/assign";
- public static string DetailsHref(string? groupId)
+ public static string DetailsHref(string? groupId) => Details.Replace("{groupId}", groupId);
+ public static string HostsHref(string? groupId) => Hosts.Replace("{groupId}", groupId);
+ public static string HostsAssignHref(string? groupId) => HostsAssign.Replace("{groupId}", groupId);
+ }
+
+ public static class Scheduler
+ {
+ public const string Index = Management.Index + "/scheduler";
+
+ public static class Jobs
{
- return Details.Replace("{groupId}", groupId);
+ public const string Index = Scheduler.Index + "/jobs";
+ public const string Details = Index + "/{jobId}";
+ public const string Tasks = Details + "/tasks";
+ public const string TasksAssign = Tasks + "/assign";
+ public const string Triggers = Details + "/triggers";
+ public const string TriggersAssign = Triggers + "/assign";
+
+ public static string DetailsHref(string? jobId) => Details.Replace("{jobId}", jobId);
+ public static string TasksHref(string? jobId) => Tasks.Replace("{jobId}", jobId);
+ public static string TasksAssignHref(string? jobId) => TasksAssign.Replace("{jobId}", jobId);
+ public static string TriggersHref(string? jobId) => Triggers.Replace("{jobId}", jobId);
+ public static string TriggersAssignHref(string? jobId) => TriggersAssign.Replace("{jobId}", jobId);
}
- public static string HostsHref(string? groupId)
+ public static class Tasks
{
- return Hosts.Replace("{groupId}", groupId);
+ public const string Index = Scheduler.Index + "/tasks";
+ public const string Details = Index + "/{taskId}";
+ public const string Jobs = Details + "/jobs";
+
+ public static string DetailsHref(string? taskId) => Details.Replace("{taskId}", taskId);
+ public static string JobsHref(string? taskId) => Jobs.Replace("{taskId}", taskId);
}
- public static string HostsAssignHref(string? groupId)
+ public static class Triggers
{
- return HostsAssign.Replace("{groupId}", groupId);
+ public const string Index = Scheduler.Index + "/triggers";
+ public const string Details = Index + "/{triggerId}";
+ public const string Jobs = Details + "/jobs";
+
+ public static string DetailsHref(string? triggerId) => Details.Replace("{triggerId}", triggerId);
+ public static string JobsHref(string? triggerId) => Jobs.Replace("{triggerId}", triggerId);
}
}
}
public static class Inventory
{
+ public const string Index = "inventory";
+
public static class Systems
{
+ public const string Index = Inventory.Index + "/system";
+
public static class Os
{
- public const string Index = "inventory/os";
- public const string Hosts = "inventory/os/{osName}/hosts";
- public const string Guests = "inventory/os/{osName}/guests";
+ public const string Index = Systems.Index + "/os";
+ public const string Hosts = Index + "/{osName}/hosts";
+ public const string Guests = Index + "/{osName}/guests";
- public static string HostsHref(string? osName)
- {
- return Hosts.Replace("{osName}", osName);
- }
-
- public static string GuestsHref(string? osName)
- {
- return Guests.Replace("{osName}", osName);
- }
+ public static string HostsHref(string? osName) => Hosts.Replace("{osName}", osName);
+ public static string GuestsHref(string? osName) => Guests.Replace("{osName}", osName);
}
public static class Updates
{
- public const string Index = "inventory/updates";
- public const string Hosts = "inventory/updates/{updateName}/hosts";
+ public const string Index = Systems.Index + "/updates";
+ public const string Hosts = Index + "/{updateName}/hosts";
- public static string HostsHref(string? updateName)
- {
- return Hosts.Replace("{updateName}", updateName);
- }
+ public static string HostsHref(string? updateName) => Hosts.Replace("{updateName}", updateName);
}
public static class Software
{
- public const string Index = "inventory/software";
- public const string Hosts = "inventory/software/{softwareName}/hosts";
+ public const string Index = Systems.Index + "/software";
+ public const string Hosts = Index + "/{softwareName}/hosts";
- public static string HostsHref(string? software)
- {
- return Hosts.Replace("{softwareName}", software);
- }
+ public static string HostsHref(string? software) => Hosts.Replace("{softwareName}", software);
}
public static class Services
{
- public const string Index = "inventory/services";
- public const string Hosts = "inventory/services/{serviceName}/hosts";
+ public const string Index = Systems.Index + "/services";
+ public const string Hosts = Index + "/{serviceName}/hosts";
- public static string HostsHref(string? serviceName)
- {
- return Hosts.Replace("{serviceName}", serviceName);
- }
+ public static string HostsHref(string? serviceName) => Hosts.Replace("{serviceName}", serviceName);
}
public static class Sessions
{
- public const string Index = "inventory/sessions";
+ public const string Index = Systems.Index + "/sessions";
}
public static class Printers
{
- public const string Index = "inventory/printers";
+ public const string Index = Systems.Index + "/printers";
}
public static class Volumes
{
- public const string Index = "inventory/volumes";
+ public const string Index = Systems.Index + "/volumes";
}
public static class Users
{
- public const string Index = "inventory/users";
- public const string Hosts = "inventory/users/{userName}/hosts";
+ public const string Index = Systems.Index + "/users";
+ public const string Hosts = Index + "/{userName}/hosts";
- public static string HostsHref(string? userName)
- {
- return Hosts.Replace("{userName}", userName);
- }
+ public static string HostsHref(string? userName) => Hosts.Replace("{userName}", userName);
}
public static class Groups
{
- public const string Index = "inventory/groups";
- public const string Hosts = "inventory/groups/{groupName}/hosts";
+ public const string Index = Systems.Index + "/groups";
+ public const string Hosts = Index + "/{groupName}/hosts";
- public static string HostsHref(string? groupName)
- {
- return Hosts.Replace("{groupName}", groupName);
- }
+ public static string HostsHref(string? groupName) => Hosts.Replace("{groupName}", groupName);
}
public static class StoragePools
{
- public const string Index = "inventory/storagepools";
+ public const string Index = Systems.Index + "/storagepools";
}
public static class VirtualMaschines
{
- public const string Index = "inventory/virtualmaschines";
+ public const string Index = Systems.Index + "/virtualmaschines";
}
}
public static class Network
{
+ public const string Index = Inventory.Index + "/network";
+
public static class Interfaces
{
- public const string Index = "inventory/interfaces";
+ public const string Index = Network.Index + "/interfaces";
}
public static class Addresses
{
- public const string Index = "inventory/addresses";
- public const string Hosts = "inventory/addresses/{address}/hosts";
+ public const string Index = Network.Index + "/addresses";
+ public const string Hosts = Index + "/{address}/hosts";
- public static string HostsHref(string? address)
- {
- return Hosts.Replace("{address}", address);
- }
+ public static string HostsHref(string? address) => Hosts.Replace("{address}", address);
}
public static class Nameservers
{
- public const string Index = "inventory/nameservers";
- public const string Hosts = "inventory/nameservers/{nameserverAddress}/hosts";
+ public const string Index = Network.Index + "/nameservers";
+ public const string Hosts = Index + "/{nameserverAddress}/hosts";
- public static string HostsHref(string? nameserverAddress)
- {
- return Hosts.Replace("{nameserverAddress}", nameserverAddress);
- }
+ public static string HostsHref(string? nameserverAddress) => Hosts.Replace("{nameserverAddress}", nameserverAddress);
}
public static class Gateways
{
- public const string Index = "inventory/gateways";
- public const string Hosts = "inventory/gateways/{gatewayAddress}/hosts";
+ public const string Index = Network.Index + "/gateways";
+ public const string Hosts = Index + "/{gatewayAddress}/hosts";
- public static string HostsHref(string? gatewayAddress)
- {
- return Hosts.Replace("{gatewayAddress}", gatewayAddress);
- }
+ public static string HostsHref(string? gatewayAddress) => Hosts.Replace("{gatewayAddress}", gatewayAddress);
}
public static class Routes
{
- public const string Index = "inventory/routes";
- public const string Hosts = "inventory/routes/{routeAddress}/hosts";
+ public const string Index = Network.Index + "/routes";
+ public const string Hosts = Index + "/{routeAddress}/hosts";
- public static string HostsHref(string? routeAddress)
- {
- return Hosts.Replace("{routeAddress}", routeAddress);
- }
+ public static string HostsHref(string? routeAddress) => Hosts.Replace("{routeAddress}", routeAddress);
}
}
public static class Hardware
{
+ public const string Index = Inventory.Index + "/hardware";
+
public static class Mainboards
{
- public const string Index = "inventory/mainboards";
- public const string Hosts = "inventory/mainboards/{mainboardName}/hosts";
+ public const string Index = Hardware.Index + "/mainboards";
+ public const string Hosts = Index + "/{mainboardName}/hosts";
- public static string HostsHref(string? mainboardName)
- {
- return Hosts.Replace("{mainboardName}", mainboardName);
- }
+ public static string HostsHref(string? mainboardName) => Hosts.Replace("{mainboardName}", mainboardName);
}
public static class Processors
{
- public const string Index = "inventory/processors";
- public const string Hosts = "inventory/processors/{processorName}/hosts";
+ public const string Index = Hardware.Index + "/processors";
+ public const string Hosts = Index + "/{processorName}/hosts";
- public static string HostsHref(string? processorName)
- {
- return Hosts.Replace("{processorName}", processorName);
- }
+ public static string HostsHref(string? processorName) => Hosts.Replace("{processorName}", processorName);
}
public static class Memory
{
- public const string Index = "inventory/memory";
- public const string Hosts = "inventory/memory/{memoryName}/hosts";
+ public const string Index = Hardware.Index + "/memory";
+ public const string Hosts = Index + "/{memoryName}/hosts";
- public static string HostsHref(string? memoryName)
- {
- return Hosts.Replace("{memoryName}", memoryName);
- }
+ public static string HostsHref(string? memoryName) => Hosts.Replace("{memoryName}", memoryName);
}
public static class Drives
{
- public const string Index = "inventory/drives";
- public const string Hosts = "inventory/drives/{driveName}/hosts";
+ public const string Index = Hardware.Index + "/drives";
+ public const string Hosts = Index + "/{driveName}/hosts";
- public static string HostsHref(string? driveName)
- {
- return Hosts.Replace("{driveName}", driveName);
- }
+ public static string HostsHref(string? driveName) => Hosts.Replace("{driveName}", driveName);
}
public static class Videocards
{
- public const string Index = "inventory/videocards";
- public const string Hosts = "inventory/videocards/{videocardName}/hosts";
+ public const string Index = Hardware.Index + "/videocards";
+ public const string Hosts = Index + "/{videocardName}/hosts";
- public static string HostsHref(string? videocardName)
- {
- return Hosts.Replace("{videocardName}", videocardName);
- }
+ public static string HostsHref(string? videocardName) => Hosts.Replace("{videocardName}", videocardName);
}
}
}
-
- public static class Communication
- {
- public const string Index = "communication";
-
- public static class Chat
- {
- public const string Index = "communication/chat";
- }
- }
}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Insight.Web.csproj b/src/Web/Insight.Web/Insight.Web.csproj
index 3f387e8..b5226cd 100644
--- a/src/Web/Insight.Web/Insight.Web.csproj
+++ b/src/Web/Insight.Web/Insight.Web.csproj
@@ -4,7 +4,7 @@
net7.0
Insight
web
- 2023.11.17.0
+ 2023.12.14.0
Insight.Web
enable
enable
@@ -29,8 +29,7 @@
-
-
+
diff --git a/src/Web/Insight.Web/Pages/Account/ProfileTwoFactorDialog.razor b/src/Web/Insight.Web/Pages/Account/ProfileTwoFactorDialog.razor
index 5aced2c..a4a26ae 100644
--- a/src/Web/Insight.Web/Pages/Account/ProfileTwoFactorDialog.razor
+++ b/src/Web/Insight.Web/Pages/Account/ProfileTwoFactorDialog.razor
@@ -9,17 +9,11 @@
- @*
-
- @AuthenticatorFormatKey
- *@
- @**@
@_authenticatorFormatKey
- @**@
@if (_content == Content.Options)
@@ -29,13 +23,6 @@
_showQrCode = false;
}
- @*@if (false) // test
- {
-
- Recovery
-
- }*@
-
@if (_enabled)
{
diff --git a/src/Web/Insight.Web/Pages/Index.razor b/src/Web/Insight.Web/Pages/Index.razor
index ff99819..af5963c 100644
--- a/src/Web/Insight.Web/Pages/Index.razor
+++ b/src/Web/Insight.Web/Pages/Index.razor
@@ -1,9 +1,27 @@
-@page "/"
-@inject NavigationManager NavManager
+@inherits ComponentBase
-@code {
- protected override void OnInitialized()
- {
- NavManager.NavigateTo(Navigation.Monitoring.Maintenance.Index);
- }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@code{
+ public long _accounts;
+ public long _customers;
+ public long _hosts;
+ public long _agents;
}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Overview/Index.razor.cs b/src/Web/Insight.Web/Pages/Index.razor.cs
similarity index 81%
rename from src/Web/Insight.Web/Pages/Management/Overview/Index.razor.cs
rename to src/Web/Insight.Web/Pages/Index.razor.cs
index d6401b3..c113f7c 100644
--- a/src/Web/Insight.Web/Pages/Management/Overview/Index.razor.cs
+++ b/src/Web/Insight.Web/Pages/Index.razor.cs
@@ -4,19 +4,18 @@ using Microsoft.AspNetCore.Components;
using MongoDB.Driver;
using MudBlazor;
-namespace Insight.Web.Pages.Management.Overview;
+namespace Insight.Web.Pages;
-[Route(Navigation.Management.Overview.Index)]
+[Route(Navigation.Home)]
public partial class Index
{
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
- private readonly string _title = "Management|Insight";
+ private readonly string _title = "Home|Insight";
private readonly List _breadcrumbs = new()
{
- new BreadcrumbItem("Home", href: Navigation.Home),
- new BreadcrumbItem("Management", href: "#", true)
+ new BreadcrumbItem("Home", href: "#", true),
};
private async Task LoadDataAsync()
diff --git a/src/Web/Insight.Web/Pages/Management/Hosts/Actions/Console/ConsoleOptionDialog.razor b/src/Web/Insight.Web/Pages/Management/Hosts/Actions/Console/ConsoleOptionDialog.razor
new file mode 100644
index 0000000..9c0180c
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Hosts/Actions/Console/ConsoleOptionDialog.razor
@@ -0,0 +1,196 @@
+@using MongoDB.Bson;
+
+@inject ISnackbar Snackbar
+@inject IDialogService Dialog
+
+
+
+
+ Options
+
+
+
+ @if (_content == Content.Menu)
+ {
+
+ Browser
+
+
+ Save
+
+
+ Load
+
+ }
+ else if (_content == Content.Save)
+ {
+
+ }
+ else if (_content == Content.Load)
+ {
+
+ @foreach (var entity in _loadables)
+ {
+
+
+
+ }
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ Store
+ Library
+ Community
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @*
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ *@
+
+
+
+@code {
+ private DialogOptions _browserOptions = new() { FullWidth = false, MaxWidth = MaxWidth.Large, FullScreen = false, NoHeader = true };
+ private bool _browserVisible;
+ private bool _browserDrawer = true;
+
+ //
+
+ [Parameter] public EventCallback OnChanges { get; set; }
+
+ private Content _content = Content.Menu;
+
+ private enum Content { Menu = 0, Save = 1, Load = 3 }
+ private bool _visible;
+ private ScriptItem? _currentItem;
+
+ private List _loadables = new();
+
+ public async Task ToggleAsync(string? id)
+ {
+ _content = Content.Menu;
+ _visible = !_visible;
+
+ await InvokeAsync(StateHasChanged);
+ }
+
+ public async Task ToggleBrowserAsync()
+ {
+ _visible = !_visible;
+ _browserVisible = !_browserVisible;
+ }
+
+ private async Task OnSaveItemAsync(ScriptItem item)
+ {
+ _currentItem = item;
+ _visible = false;
+
+ Notification.Information(Snackbar, $"Save Item ({item.Key})");
+
+ // base64 encode
+ var valueBytes = System.Text.Encoding.UTF8.GetBytes(item.Value);
+ var valueBase64 = System.Convert.ToBase64String(valueBytes);
+
+ // save to database
+
+
+ await OnChanges.InvokeAsync(item);
+ }
+
+ private async Task OnLoadItemAsync(ScriptItem item)
+ {
+ _currentItem = item;
+ _visible = false;
+
+ Notification.Information(Snackbar, $"Load Item ({item.Key})");
+
+ await OnChanges.InvokeAsync(item);
+ }
+
+ protected override void OnInitialized()
+ {
+ _loadables.Add(new ScriptItem { Key = "Date Test", Value = "Get-Date"});
+
+ var ipmi64 = "U3RhcnQtUHJvY2VzcyAtRmlsZVBhdGggIkM6XFxQcm9ncmFtRGF0YVxcV2VibWF0aWNcXEluc2lnaHRcXEFnZW50XFx0b29sc1xcaXBtaVxcaXBtaS5leGUiIC1Bcmd1bWVudExpc3QgIi1wbWluZm8iIC1XYWl0IC1Ob05ld1dpbmRvdyAtUmVkaXJlY3RTdGFuZGFyZE91dHB1dCAiQzpcdGVtcC50eHQiOyAKJGRhdGEgPSBHZXQtQ29udGVudCAiQzpcdGVtcC50eHQiCgokbGluZXMgPSAkZGF0YSAtc3BsaXQgJyxccypcbicgfCBXaGVyZS1PYmplY3QgeyAkXyAtbmUgIiIgfQoKJG1vZHVsZXMgPSBAe30KJGN1cnJlbnRNb2R1bGUgPSAkbnVsbAoKZm9yZWFjaCAoJGxpbmUgaW4gJGxpbmVzKSB7CiAgICBpZiAoJGxpbmUgLW1hdGNoICJcW1NsYXZlQWRkcmVzcyA9IChcdyspXF0iKSB7CiAgICAgICAgJHNsYXZlQWRkcmVzcyA9ICRtYXRjaGVzWzFdCiAgICAgICAgJG1vZHVsZU5hbWUgPSAkbGluZSAtcmVwbGFjZSAiLipcWyhNb2R1bGUgXGQrKVxdIiwgJyQxJwogICAgICAgICRjdXJyZW50TW9kdWxlID0gIiRzbGF2ZUFkZHJlc3MgJG1vZHVsZU5hbWUiCiAgICAgICAgJG1vZHVsZXNbJGN1cnJlbnRNb2R1bGVdID0gQHt9CiAgICB9IGVsc2VpZiAoJGxpbmUgLW5vdG1hdGNoICJeXHMqJHxeSXRlbXxeLS0tLSIgLWFuZCAkY3VycmVudE1vZHVsZSkgewogICAgICAgICRwYXJ0cyA9ICRsaW5lIC1zcGxpdCAnXHwnLCAyCiAgICAgICAgaWYgKCRwYXJ0cy5MZW5ndGggLWVxIDIpIHsKICAgICAgICAgICAgJGtleSA9ICRwYXJ0c1swXS5UcmltKCkKICAgICAgICAgICAgJHZhbHVlID0gJHBhcnRzWzFdLlRyaW0oKQogICAgICAgICAgICAkbW9kdWxlc1skY3VycmVudE1vZHVsZV1bJGtleV0gPSAkdmFsdWUKICAgICAgICB9CiAgICB9Cn0KCiMgQ29udmVydCB0byBKU09OCiRqc29uID0gJG1vZHVsZXMgfCBDb252ZXJ0VG8tSnNvbiAtRGVwdGggMwokanNvbg==";
+ _loadables.Add(new ScriptItem { Key = "IPMI (Power)", Value = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(ipmi64)) });
+ }
+
+ public class ScriptItem
+ {
+ public string Key { get; set; }
+ public string Value { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Hosts/Actions/Console/Index.razor b/src/Web/Insight.Web/Pages/Management/Hosts/Actions/Console/Index.razor
index b1a6f3b..6f993c5 100644
--- a/src/Web/Insight.Web/Pages/Management/Hosts/Actions/Console/Index.razor
+++ b/src/Web/Insight.Web/Pages/Management/Hosts/Actions/Console/Index.razor
@@ -4,23 +4,65 @@
@if (_model is not null)
{
-
-
-
-
+
+ Script
+ Result
+
+
+
+ @if (_running)
+ {
+
+ Processing
+ }
+ else
+ {
+ Execute
+ }
+
+ @if (_running)
+ {
+ Abort
+ }
+
-
+
+ @if (_activeWindow == 0)
+ {
+
+ }
+ else
+ {
@if (_model.Response.ResponseError ?? false)
{
Response contains Errors
}
-
-
-
-
- Query
-
-
+
+ }
+
}
-
\ No newline at end of file
+
+
+
+
+@code{
+ private ConsoleOptionDialog? _optionDialog;
+
+ private int _activeWindow = 0;
+ private bool _running = false;
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Hosts/Actions/Console/Index.razor.cs b/src/Web/Insight.Web/Pages/Management/Hosts/Actions/Console/Index.razor.cs
index 8fb04bd..cd63d1a 100644
--- a/src/Web/Insight.Web/Pages/Management/Hosts/Actions/Console/Index.razor.cs
+++ b/src/Web/Insight.Web/Pages/Management/Hosts/Actions/Console/Index.razor.cs
@@ -7,6 +7,8 @@ using Microsoft.AspNetCore.Components;
using MongoDB.Bson;
using MongoDB.Driver;
using MudBlazor;
+using System.Diagnostics;
+using System.Threading;
using Vaitr.Bus;
using Vaitr.Network;
@@ -27,13 +29,7 @@ public partial class Index
private readonly string _id = ObjectId.GenerateNewId().ToString();
private readonly List _breadcrumbs = new();
- private readonly IndexViewModel _model = new();
- private readonly List _subscriptions = new();
-
- protected override async Task OnInitializedAsync()
- {
- _subscriptions.Add(Bus.SubscribeAsync>(OnQueryResultAsync, p => p.Message?.RequestId == _id));
- }
+ private readonly ViewModel _model = new();
private async Task LoadDataAsync()
{
@@ -72,12 +68,48 @@ public partial class Index
StateHasChanged();
}
- private async Task SubmitAsync()
+ private async Task OnRefreshAsync(ConsoleOptionDialog.ScriptItem item)
{
- if (_model.Request.RequestData is null || WebPool.Any() is false) return;
+ _model.Request.RequestData = item.Value;
+
+ await InvokeAsync(StateHasChanged);
+ }
+
+ private async Task RunAsync(CancellationToken cancellationToken = default)
+ {
+ if (_model.Request.RequestData is null)
+ {
+ Notification.Error(Snackbar, "Invalid Request Data");
+ return;
+ }
+
+ if (WebPool.Any() is false)
+ {
+ Notification.Error(Snackbar, "Client unreachable");
+ return;
+ }
try
{
+ _running = true;
+
+ var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
+ var timeoutTask = Task.Delay(TimeSpan.FromSeconds(30), timeoutCts.Token);
+
+ // subscribe response
+ using var token = Bus.SubscribeAsync>(async (response, ctc) =>
+ {
+ _model.Response.ResponseError = response.Message?.ResponseError;
+ _model.Response.ResponseData = response.Message?.ResponseData;
+
+ timeoutCts.Cancel();
+
+ _activeWindow = 1;
+
+ await InvokeAsync(StateHasChanged);
+ }, p => p.Message?.RequestId == _id);
+
+ // send request
await WebPool.First().Value.SendAsync(new Proxy
{
ProxyId = HostId,
@@ -88,23 +120,21 @@ public partial class Index
}
}, default);
- Notification.Information(Snackbar, "Sent Query Command");
+ Notification.Information(Snackbar, "Sent Script...");
+
+ await Task.WhenAny(timeoutTask);
}
catch (Exception ex)
{
Notification.Error(Snackbar, ex.Message);
}
+ finally
+ {
+ _running = false;
+ }
}
- private async ValueTask OnQueryResultAsync(Proxy proxy, CancellationToken cancellationToken)
- {
- _model.Response.ResponseError = proxy.Message?.ResponseError;
- _model.Response.ResponseData = proxy.Message?.ResponseData;
-
- await InvokeAsync(StateHasChanged);
- }
-
- private class IndexViewModel
+ private class ViewModel
{
public readonly Request Request = new();
public readonly Response Response = new();
diff --git a/src/Web/Insight.Web/Pages/Management/Hosts/Actions/Console/ScriptBrowserDialog.razor b/src/Web/Insight.Web/Pages/Management/Hosts/Actions/Console/ScriptBrowserDialog.razor
new file mode 100644
index 0000000..3d5ce76
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Hosts/Actions/Console/ScriptBrowserDialog.razor
@@ -0,0 +1,16 @@
+
+
+ Script Browser
+
+
+ Cancel
+ Ok
+
+
+
+@code {
+ [CascadingParameter] MudDialogInstance MudDialog { get; set; } = default!;
+
+ void Submit() => MudDialog.Close(DialogResult.Ok(true));
+ void Cancel() => MudDialog.Cancel();
+}
diff --git a/src/Web/Insight.Web/Pages/Management/Hosts/Logs.razor b/src/Web/Insight.Web/Pages/Management/Hosts/Logs.razor
index d835ae8..1141b62 100644
--- a/src/Web/Insight.Web/Pages/Management/Hosts/Logs.razor
+++ b/src/Web/Insight.Web/Pages/Management/Hosts/Logs.razor
@@ -87,7 +87,7 @@
-
+
None
diff --git a/src/Web/Insight.Web/Pages/Management/Index.razor b/src/Web/Insight.Web/Pages/Management/Index.razor
deleted file mode 100644
index 3f51fa1..0000000
--- a/src/Web/Insight.Web/Pages/Management/Index.razor
+++ /dev/null
@@ -1,5 +0,0 @@
-Index
-
-@code {
-
-}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Index.razor.cs b/src/Web/Insight.Web/Pages/Management/Index.razor.cs
deleted file mode 100644
index 3e90061..0000000
--- a/src/Web/Insight.Web/Pages/Management/Index.razor.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using Microsoft.AspNetCore.Components;
-
-namespace Insight.Web.Pages.Management;
-
-//[Route(Navigation.Monitoring.Index)]
-public partial class Index
-{
- [Inject] private NavigationManager NavManager { get; init; } = default!;
-
- protected override void OnInitialized()
- {
- //NavManager.NavigateTo(Navigation.Management.Overview.Index);
- }
-}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Overview/Index.razor b/src/Web/Insight.Web/Pages/Management/Overview/Index.razor
deleted file mode 100644
index af5963c..0000000
--- a/src/Web/Insight.Web/Pages/Management/Overview/Index.razor
+++ /dev/null
@@ -1,27 +0,0 @@
-@inherits ComponentBase
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-@code{
- public long _accounts;
- public long _customers;
- public long _hosts;
- public long _agents;
-}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Details.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Details.razor
new file mode 100644
index 0000000..a10bede
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Details.razor
@@ -0,0 +1,31 @@
+@inherits ComponentBase
+
+@using Vaitr.Scheduler;
+
+
+
+ @if (Job is not null)
+ {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @*
+
+ *@
+
+ }
+
+
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Details.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Details.razor.cs
new file mode 100644
index 0000000..b652160
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Details.razor.cs
@@ -0,0 +1,60 @@
+using Insight.Infrastructure.Entities;
+using Insight.Web.Constants;
+using Microsoft.AspNetCore.Components;
+using MongoDB.Bson;
+using MongoDB.Driver;
+using MudBlazor;
+using static MudBlazor.CategoryTypes;
+
+namespace Insight.Web.Pages.Management.Scheduler.Jobs;
+
+[Route(Navigation.Management.Scheduler.Jobs.Details)]
+public partial class Details
+{
+ [Parameter] public string? JobId { get; set; }
+
+ [Inject] private IMongoDatabase Database { get; init; } = default!;
+ [Inject] private ISnackbar Snackbar { get; init; } = default!;
+ [Inject] private NavigationManager NavigationManager { get; init; } = default!;
+
+ private string Title { get; set; } = Global.Name;
+ private List Breadcrumbs { get; } = new();
+ private JobEntity? Job { get; set; }
+
+ private async Task LoadDataAsync()
+ {
+ Breadcrumbs.Clear();
+ Job = null;
+
+ if (string.IsNullOrWhiteSpace(JobId) || ObjectId.TryParse(JobId, out var jobId) is false)
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Jobs.Index);
+ return;
+ }
+
+ Breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
+ Breadcrumbs.Add(new BreadcrumbItem("Scheduler", href: Navigation.Management.Scheduler.Index));
+ Breadcrumbs.Add(new BreadcrumbItem("Jobs", href: Navigation.Management.Scheduler.Jobs.Index));
+
+ StateHasChanged();
+
+ Job = await Database.Job()
+ .Aggregate()
+ .Match(Builders.Filter.Eq(p => p.Id, JobId))
+ //.Lookup(Database.Host(), p => p.Id, p => p.Customer, p => p.Hosts)
+ .FirstOrDefaultAsync(default);
+
+ if (Job is null)
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Jobs.Index);
+ return;
+ }
+
+ Title = $"Job » {Job.Name ?? Job.Id}|Insight";
+ Breadcrumbs.Add(new BreadcrumbItem(Job.Name ?? Job.Id, href: "#", true));
+
+ StateHasChanged();
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Index.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Index.razor
new file mode 100644
index 0000000..878b8f0
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Index.razor
@@ -0,0 +1,92 @@
+@inherits ComponentBase
+
+
+
+
+
+ Name
+
+
+
+
+ Tasks
+
+
+
+
+ Triggers
+
+
+
+
+ Executed
+
+
+
+
+ State
+
+
+
+
+ Status
+
+
+
+
+
+
+ @context?.Name
+
+
+
+ @{
+
+ @(context.Tasks?.ToString() ?? "0")
+
+ }
+
+
+ @{
+
+ @(context.Triggers?.ToString() ?? "0")
+
+ }
+
+
+ @context?.Executed.ToLocalTime()
+
+
+ @context.State
+
+
+
+ @(context.Disabled ? "Disabled" : "Enabled")
+
+
+
+
+
+ Edit
+
+
+ Delete
+
+
+
+
+
+
+
+
+@code{
+ private JobCreateDialog? _createDialog;
+ private JobEditDialog? _editDialog;
+ private JobDeleteDialog? _deleteDialog;
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Index.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Index.razor.cs
new file mode 100644
index 0000000..5e384d1
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Index.razor.cs
@@ -0,0 +1,119 @@
+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 Vaitr.Scheduler;
+using SortDirection = MudBlazor.SortDirection;
+
+namespace Insight.Web.Pages.Management.Scheduler.Jobs;
+
+[Route(Navigation.Management.Scheduler.Jobs.Index)]
+public partial class Index
+{
+ [Inject] private IMongoDatabase Database { get; init; } = default!;
+ [Inject] private ISnackbar Snackbar { get; init; } = default!;
+
+ private readonly List _breadcrumbs = new();
+
+ private TableContainer? _container;
+ private string _title = Global.Name;
+ private string? _search;
+
+ protected override void OnInitialized()
+ {
+ _title = "Jobs|Insight";
+ _breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
+ _breadcrumbs.Add(new BreadcrumbItem("Scheduler", href: Navigation.Management.Scheduler.Index));
+ _breadcrumbs.Add(new BreadcrumbItem("Jobs", href: Navigation.Management.Scheduler.Jobs.Index, true));
+ }
+
+ private async Task> LoadDataAsync(TableState state)
+ {
+ try
+ {
+ var search = Builders.Filter.Empty;
+
+ if (string.IsNullOrWhiteSpace(_search) is false)
+ {
+ var regex = new BsonRegularExpression(new Regex(_search, RegexOptions.IgnoreCase));
+ search &= Builders.Filter.Regex(x => x.Name, regex);
+ }
+
+ var query = Database.Job()
+ .Aggregate()
+ .Match(search)
+ .AppendStage(new BsonDocument("$lookup", new BsonDocument
+ {
+ { "from", "job_task" },
+ { "localField", "_id" },
+ { "foreignField", "_job" },
+ { "as", "tasks" }
+ }))
+ .AppendStage(new BsonDocument("$addFields",
+ new BsonDocument("tasks", new BsonDocument("$size", "$tasks"))
+ ))
+ .AppendStage(new BsonDocument("$lookup", new BsonDocument
+ {
+ { "from", "job_trigger" },
+ { "localField", "_id" },
+ { "foreignField", "_job" },
+ { "as", "triggers" }
+ }))
+ .AppendStage(new BsonDocument("$addFields",
+ new BsonDocument("triggers", new BsonDocument("$size", "$triggers"))
+ ))
+ .Sort(state.SortDirection switch
+ {
+ SortDirection.Ascending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Ascending("name"),
+ "Description" => Builders.Sort.Ascending("description"),
+ _ => null
+ },
+ SortDirection.Descending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Descending("name"),
+ "Description" => Builders.Sort.Descending("description"),
+ _ => null
+ },
+ _ => Builders.Sort.Ascending("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()
+ {
+ TotalItems = countResult is null ? 0 : (int)countResult.Count,
+ Items = itemResult.Select(x => BsonSerializer.Deserialize(x))
+ };
+ }
+ catch (Exception)
+ {
+ Notification.Error(Snackbar);
+ return new TableData();
+ }
+ }
+
+ private async Task OnRefreshAsync()
+ {
+ if (_container is null) return;
+ await _container.RefreshAsync().ConfigureAwait(false);
+ }
+
+ [BsonIgnoreExtraElements]
+ private class ViewModel : JobEntity
+ {
+ [BsonElement("tasks")]
+ public int? Tasks { get; set; }
+
+ [BsonElement("triggers")]
+ public int? Triggers { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobCreateDialog.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobCreateDialog.razor
new file mode 100644
index 0000000..cc4601f
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobCreateDialog.razor
@@ -0,0 +1,42 @@
+@using MongoDB.Bson;
+@using Insight.Infrastructure.Entities;
+
+
+
+
+ Create Job
+
+
+
+ @if (_model is not null)
+ {
+
+
+
+
+
+ @*
+ @foreach (ScheduleMode state in Enum.GetValues(typeof(ScheduleMode)))
+ {
+
+ @state
+
+ }
+ *@
+
+
+
+ Cancel
+
+
+ Create
+
+
+
+ }
+
+
+
+@code {
+ private bool _visible;
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobCreateDialog.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobCreateDialog.razor.cs
new file mode 100644
index 0000000..b17af52
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobCreateDialog.razor.cs
@@ -0,0 +1,59 @@
+using Insight.Infrastructure.Entities;
+using Insight.Web.Constants;
+using Microsoft.AspNetCore.Components;
+using MongoDB.Driver;
+using MudBlazor;
+
+namespace Insight.Web.Pages.Management.Scheduler.Jobs;
+
+public partial class JobCreateDialog
+{
+ [Parameter] public EventCallback OnChanges { get; set; }
+
+ [Inject] private IMongoDatabase Database { get; init; } = default!;
+ [Inject] private ISnackbar Snackbar { get; init; } = default!;
+ [Inject] private ILogger Logger { get; init; } = default!;
+
+ private JobEntity? _model;
+
+ public async void ToggleAsync()
+ {
+ _model = new();
+ _visible = !_visible;
+
+ await InvokeAsync(StateHasChanged);
+ }
+
+ private async Task SubmitAsync()
+ {
+ if (_model is null) return;
+
+ _model.Insert = DateTime.Now;
+
+ try
+ {
+ await Database.Job()
+ .InsertOneAsync(_model, 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobDeleteDialog.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobDeleteDialog.razor
new file mode 100644
index 0000000..674c134
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobDeleteDialog.razor
@@ -0,0 +1,36 @@
+@using MongoDB.Bson;
+
+
+
+
+ Delete Job
+
+
+
+ @if (_model is not null)
+ {
+
+
+
+
+
+
+ Cancel
+
+
+ Delete
+
+
+
+ }
+
+
+
+@code {
+ private bool _visible;
+ public void Toggle()
+ {
+ _visible = !_visible;
+ StateHasChanged();
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobDeleteDialog.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobDeleteDialog.razor.cs
new file mode 100644
index 0000000..ebee32c
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobDeleteDialog.razor.cs
@@ -0,0 +1,67 @@
+using Insight.Infrastructure.Entities;
+using Insight.Web.Constants;
+using Microsoft.AspNetCore.Components;
+using MongoDB.Driver;
+using MudBlazor;
+
+namespace Insight.Web.Pages.Management.Scheduler.Jobs;
+
+public partial class JobDeleteDialog
+{
+ [Parameter] public EventCallback OnChanges { get; set; }
+
+ [Inject] private IMongoDatabase Database { get; init; } = default!;
+ [Inject] private ISnackbar Snackbar { get; init; } = default!;
+ [Inject] private ILogger Logger { get; init; } = default!;
+
+ private JobEntity? _model;
+
+ public async void ToggleAsync(string? id)
+ {
+ if (id is null) return;
+
+ try
+ {
+ _model = await Database.Job().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.Job()
+ .DeleteOneAsync(Builders
+ .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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobEditDialog.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobEditDialog.razor
new file mode 100644
index 0000000..106359a
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobEditDialog.razor
@@ -0,0 +1,33 @@
+@using MongoDB.Bson;
+
+
+
+
+ Edit Job
+
+
+
+ @if (_model is not null)
+ {
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Edit
+
+
+
+ }
+
+
+
+@code {
+ private bool _visible;
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobEditDialog.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobEditDialog.razor.cs
new file mode 100644
index 0000000..60edad9
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/JobEditDialog.razor.cs
@@ -0,0 +1,70 @@
+using Insight.Infrastructure.Entities;
+using Insight.Web.Constants;
+using Microsoft.AspNetCore.Components;
+using MongoDB.Driver;
+using MudBlazor;
+
+namespace Insight.Web.Pages.Management.Scheduler.Jobs;
+
+public partial class JobEditDialog
+{
+ [Parameter] public EventCallback OnChanges { get; set; }
+
+ [Inject] private IMongoDatabase Database { get; init; } = default!;
+ [Inject] private ISnackbar Snackbar { get; init; } = default!;
+ [Inject] private ILogger Logger { get; init; } = default!;
+
+ private JobEntity? _model;
+
+ public async void ToggleAsync(string? id)
+ {
+ if (id is null) return;
+
+ try
+ {
+ _model = await Database.Job().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.Job()
+ .UpdateOneAsync(Builders
+ .Filter
+ .Eq(p => p.Id, _model.Id), Builders
+ .Update
+ .Set(p => p.Update, DateTime.Now)
+ .Set(p => p.Name, _model.Name), 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Tasks.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Tasks.razor
new file mode 100644
index 0000000..243cdab
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Tasks.razor
@@ -0,0 +1,52 @@
+@inherits ComponentBase
+
+
+
+
+
+ Name
+
+
+
+
+ Description
+
+
+
+
+
+
+ @context?.Name
+
+
+
+ @context?.Description
+
+
+
+
+ Unassign
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Unassign
+
+
+
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Tasks.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Tasks.razor.cs
new file mode 100644
index 0000000..3226d1a
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Tasks.razor.cs
@@ -0,0 +1,185 @@
+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.Driver;
+using MudBlazor;
+using System.Text.RegularExpressions;
+using SortDirection = MudBlazor.SortDirection;
+
+namespace Insight.Web.Pages.Management.Scheduler.Jobs;
+
+[Route(Navigation.Management.Scheduler.Jobs.Tasks)]
+public partial class Tasks
+{
+ [Parameter] public string? JobId { 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? Container { get; set; }
+ private string Title { get; set; } = Global.Name;
+ private List Breadcrumbs { get; } = new();
+ private string? Search { get; set; }
+
+ private TaskEntity? Model { get; set; }
+
+ protected override async Task OnInitializedAsync()
+ {
+ if (string.IsNullOrWhiteSpace(JobId))
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Jobs.Index);
+ return;
+ }
+
+ Breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
+ Breadcrumbs.Add(new BreadcrumbItem("Scheduler", href: Navigation.Management.Scheduler.Index));
+ Breadcrumbs.Add(new BreadcrumbItem("Jobs", href: Navigation.Management.Scheduler.Jobs.Index));
+
+ var job = await Database.Job()
+ .Aggregate()
+ .Match(Builders.Filter.Eq(p => p.Id, JobId))
+ .FirstOrDefaultAsync(default);
+
+ if (job is null)
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Jobs.Index);
+ return;
+ }
+
+ Title = $"Scheduler » Jobs » {job.Name} » Tasks|Insight";
+ Breadcrumbs.Add(new BreadcrumbItem(job.Name, href: Navigation.Management.Scheduler.Jobs.DetailsHref(JobId)));
+ Breadcrumbs.Add(new BreadcrumbItem("Tasks", href: "#", true));
+ }
+
+ private async Task> LoadDataAsync(TableState state)
+ {
+ try
+ {
+ var filter = Builders.Filter.Empty;
+
+ if (string.IsNullOrWhiteSpace(Search) is false)
+ {
+ var regex = new BsonRegularExpression(new Regex(Search, RegexOptions.IgnoreCase));
+
+ filter &= Builders.Filter.Regex("name", regex) |
+ Builders.Filter.Regex("description", regex);
+ }
+
+ var query = Database.JobTask()
+ .Aggregate()
+ .Match(Builders.Filter.Eq(p => p.Job, JobId))
+ .AppendStage(new BsonDocument("$lookup", new BsonDocument
+ {
+ { "from", "task" },
+ { "localField", "_task" },
+ { "foreignField", "_id" },
+ { "as", "tasks" }
+ }))
+ .AppendStage(new BsonDocument("$addFields",
+ new BsonDocument("task", new BsonDocument("$first", "$tasks"))
+ ))
+ .AppendStage(new BsonDocument("$project", new BsonDocument
+ {
+ { "_id", "$task._id" },
+ { "name", "$task.name" },
+ { "description", "$task.description" }
+ }))
+ .Match(filter)
+ .Sort(state.SortDirection switch
+ {
+ SortDirection.Ascending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Ascending("name"),
+ "Description" => Builders.Sort.Ascending("description"),
+ _ => null
+ },
+ SortDirection.Descending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Descending("name"),
+ "Description" => Builders.Sort.Descending("description"),
+ _ => null
+ },
+ _ => Builders.Sort.Ascending("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()
+ {
+ TotalItems = countResult is null ? 0 : (int)countResult.Count,
+ Items = itemResult.Select(x => BsonSerializer.Deserialize(x))
+ };
+ }
+ catch (Exception)
+ {
+ Notification.Error(Snackbar);
+ return new TableData();
+ }
+ }
+
+ private void OnAdd()
+ {
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Jobs.TasksAssignHref(JobId));
+ }
+
+ private bool _unassign;
+ public bool Unassign
+ {
+ get
+ {
+ return _unassign;
+ }
+ set
+ {
+ if (value != _unassign)
+ {
+ _unassign = value;
+ StateHasChanged();
+ }
+ }
+ }
+
+ private void OnUnassign(TaskEntity model)
+ {
+ Model = new TaskEntity
+ {
+ Id = model.Id,
+ Name = model?.Name,
+ Description = model?.Description
+ };
+
+ Unassign = true;
+ }
+
+ private async Task OnUnassignSubmitAsync()
+ {
+ try
+ {
+ await Database.JobTask()
+ .DeleteOneAsync(Builders
+ .Filter.And(Builders.Filter
+ .Eq(p => p.Job, JobId), Builders.Filter
+ .Eq(p => p.Task, Model?.Id)),
+ cancellationToken: default);
+
+ if (Container is not null) await Container.RefreshAsync();
+
+ Notification.Success(Snackbar);
+ }
+ catch (Exception)
+ {
+ Notification.Error(Snackbar);
+ }
+ finally
+ {
+ Unassign = false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/TasksAssign.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/TasksAssign.razor
new file mode 100644
index 0000000..8b706b0
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/TasksAssign.razor
@@ -0,0 +1,51 @@
+@inherits ComponentBase
+
+
+
+
+
+ Name
+
+
+
+
+ Description
+
+
+
+
+
+
+ @context?.Name
+
+
+
+ @context?.Description
+
+
+
+
+ Assign
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Assign
+
+
+
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/TasksAssign.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/TasksAssign.razor.cs
new file mode 100644
index 0000000..0928424
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/TasksAssign.razor.cs
@@ -0,0 +1,177 @@
+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.Driver;
+using MudBlazor;
+using System.Text.RegularExpressions;
+using SortDirection = MudBlazor.SortDirection;
+
+namespace Insight.Web.Pages.Management.Scheduler.Jobs;
+
+[Route(Navigation.Management.Scheduler.Jobs.TasksAssign)]
+public partial class TasksAssign
+{
+ [Parameter] public string? JobId { 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? Container { get; set; }
+ private string Title { get; set; } = Global.Name;
+ private List Breadcrumbs { get; } = new();
+ private string? Search { get; set; }
+
+ private TaskEntity? Model { get; set; }
+
+ protected override async Task OnInitializedAsync()
+ {
+ if (string.IsNullOrWhiteSpace(JobId))
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Jobs.Index);
+ return;
+ }
+
+ var job = await Database.Job()
+ .Aggregate()
+ .Match(Builders.Filter.Eq(p => p.Id, JobId))
+ .FirstOrDefaultAsync(default);
+
+ if (job is null)
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Jobs.Index);
+ return;
+ }
+
+ Breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
+ Breadcrumbs.Add(new BreadcrumbItem("Scheduler", href: Navigation.Management.Scheduler.Index));
+ Breadcrumbs.Add(new BreadcrumbItem("Jobs", href: Navigation.Management.Scheduler.Jobs.Index));
+
+ Title = $"Scheduler » Jobs » {job.Name} » Assign Tasks|Insight";
+ Breadcrumbs.Add(new BreadcrumbItem(job.Name, href: Navigation.Management.Scheduler.Jobs.DetailsHref(JobId)));
+ Breadcrumbs.Add(new BreadcrumbItem("Tasks", href: Navigation.Management.Scheduler.Jobs.TasksHref(JobId)));
+ Breadcrumbs.Add(new BreadcrumbItem("Assign", href: "#", true));
+ }
+
+ private async Task> LoadDataAsync(TableState state)
+ {
+ try
+ {
+ var filter = Builders.Filter.Empty;
+
+ if (string.IsNullOrWhiteSpace(Search) is false)
+ {
+ var regex = new BsonRegularExpression(new Regex(Search, RegexOptions.IgnoreCase));
+ filter &= Builders.Filter.Regex("name", regex) |
+ Builders.Filter.Regex("description", regex);
+ }
+
+ var query = Database.Task()
+ .Aggregate()
+ .AppendStage(new BsonDocument("$lookup", new BsonDocument
+ {
+ { "from", "job_task" },
+ { "localField", "_id" },
+ { "foreignField", "_task" },
+ { "as", "map" }
+ }))
+ .AppendStage(new BsonDocument("$unwind", new BsonDocument
+ {
+ { "path", "$map" },
+ { "preserveNullAndEmptyArrays", true }
+ }))
+ .AppendStage(
+ new BsonDocument("$match",
+ new BsonDocument("map._job", new BsonDocument("$ne", new ObjectId(JobId))))
+ )
+ .Sort(state.SortDirection switch
+ {
+ SortDirection.Ascending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Ascending("name"),
+ "Description" => Builders.Sort.Ascending("description"),
+ _ => null
+ },
+ SortDirection.Descending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Descending("name"),
+ "Description" => Builders.Sort.Descending("description"),
+ _ => null
+ },
+ _ => Builders.Sort.Ascending("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()
+ {
+ TotalItems = countResult is null ? 0 : (int)countResult.Count,
+ Items = itemResult.Select(x => BsonSerializer.Deserialize(x))
+ };
+ }
+ catch (Exception)
+ {
+ Notification.Error(Snackbar);
+ return new TableData();
+ }
+ }
+
+
+ private bool _assign;
+ public bool Assign
+ {
+ get
+ {
+ return _assign;
+ }
+ set
+ {
+ if (value != _assign)
+ {
+ _assign = value;
+ StateHasChanged();
+ }
+ }
+ }
+
+ private void OnAssign(TaskEntity? model)
+ {
+ Model = model;
+ Assign = true;
+ }
+
+ private async Task OnAddSubmitAsync()
+ {
+ try
+ {
+ await Database.JobTask()
+ .InsertOneAsync(new JobTaskEntity
+ {
+ Job = JobId,
+ Task = Model.Id
+ }, cancellationToken: default);
+
+ if (Container is not null)
+ {
+ await Container.RefreshAsync();
+ }
+
+ Notification.Success(Snackbar);
+ }
+ catch (Exception)
+ {
+ Notification.Error(Snackbar);
+ }
+ finally
+ {
+ Assign = false;
+ NavigationManager?.NavigateTo(Navigation.Management.Scheduler.Jobs.TasksHref(JobId));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Triggers.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Triggers.razor
new file mode 100644
index 0000000..2f22d5a
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Triggers.razor
@@ -0,0 +1,52 @@
+@inherits ComponentBase
+
+
+
+
+
+ Name
+
+
+
+
+ Description
+
+
+
+
+
+
+ @context?.Name
+
+
+
+ @context?.Description
+
+
+
+
+ Unassign
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Unassign
+
+
+
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Triggers.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Triggers.razor.cs
new file mode 100644
index 0000000..bb6e9b2
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/Triggers.razor.cs
@@ -0,0 +1,185 @@
+using Insight.Infrastructure.Entities;
+using Insight.Web.Components.Containers;
+using Insight.Web.Constants;
+using Microsoft.AspNetCore.Components;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson;
+using MongoDB.Driver;
+using MudBlazor;
+using System.Text.RegularExpressions;
+using SortDirection = MudBlazor.SortDirection;
+
+namespace Insight.Web.Pages.Management.Scheduler.Jobs;
+
+[Route(Navigation.Management.Scheduler.Jobs.Triggers)]
+public partial class Triggers
+{
+ [Parameter] public string? JobId { 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? Container { get; set; }
+ private string Title { get; set; } = Global.Name;
+ private List Breadcrumbs { get; } = new();
+ private string? Search { get; set; }
+
+ private TriggerEntity? Model { get; set; }
+
+ protected override async Task OnInitializedAsync()
+ {
+ if (string.IsNullOrWhiteSpace(JobId))
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Jobs.Index);
+ return;
+ }
+
+ Breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
+ Breadcrumbs.Add(new BreadcrumbItem("Scheduler", href: Navigation.Management.Scheduler.Index));
+ Breadcrumbs.Add(new BreadcrumbItem("Jobs", href: Navigation.Management.Scheduler.Jobs.Index));
+
+ var job = await Database.Job()
+ .Aggregate()
+ .Match(Builders.Filter.Eq(p => p.Id, JobId))
+ .FirstOrDefaultAsync(default);
+
+ if (job is null)
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Jobs.Index);
+ return;
+ }
+
+ Title = $"Scheduler » Jobs » {job.Name} » Triggers|Insight";
+ Breadcrumbs.Add(new BreadcrumbItem(job.Name, href: Navigation.Management.Scheduler.Jobs.DetailsHref(JobId)));
+ Breadcrumbs.Add(new BreadcrumbItem("Triggers", href: "#", true));
+ }
+
+ private async Task> LoadDataAsync(TableState state)
+ {
+ try
+ {
+ var filter = Builders.Filter.Empty;
+
+ if (string.IsNullOrWhiteSpace(Search) is false)
+ {
+ var regex = new BsonRegularExpression(new Regex(Search, RegexOptions.IgnoreCase));
+
+ filter &= Builders.Filter.Regex("name", regex) |
+ Builders.Filter.Regex("description", regex);
+ }
+
+ var query = Database.JobTrigger()
+ .Aggregate()
+ .Match(Builders.Filter.Eq(p => p.Job, JobId))
+ .AppendStage(new BsonDocument("$lookup", new BsonDocument
+ {
+ { "from", "trigger" },
+ { "localField", "_trigger" },
+ { "foreignField", "_id" },
+ { "as", "triggers" }
+ }))
+ .AppendStage(new BsonDocument("$addFields",
+ new BsonDocument("trigger", new BsonDocument("$first", "$triggers"))
+ ))
+ .AppendStage(new BsonDocument("$project", new BsonDocument
+ {
+ { "_id", "$trigger._id" },
+ { "name", "$trigger.name" },
+ { "description", "$trigger.description" }
+ }))
+ .Match(filter)
+ .Sort(state.SortDirection switch
+ {
+ SortDirection.Ascending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Ascending("name"),
+ "Description" => Builders.Sort.Ascending("description"),
+ _ => null
+ },
+ SortDirection.Descending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Descending("name"),
+ "Description" => Builders.Sort.Descending("description"),
+ _ => null
+ },
+ _ => Builders.Sort.Ascending("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()
+ {
+ TotalItems = countResult is null ? 0 : (int)countResult.Count,
+ Items = itemResult.Select(x => BsonSerializer.Deserialize(x))
+ };
+ }
+ catch (Exception)
+ {
+ Notification.Error(Snackbar);
+ return new TableData();
+ }
+ }
+
+ private void OnAdd()
+ {
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Jobs.TriggersAssignHref(JobId));
+ }
+
+ private bool _unassign;
+ public bool Unassign
+ {
+ get
+ {
+ return _unassign;
+ }
+ set
+ {
+ if (value != _unassign)
+ {
+ _unassign = value;
+ StateHasChanged();
+ }
+ }
+ }
+
+ private void OnUnassign(TriggerEntity model)
+ {
+ Model = new TriggerEntity
+ {
+ Id = model.Id,
+ Name = model?.Name,
+ Description = model?.Description
+ };
+
+ Unassign = true;
+ }
+
+ private async Task OnUnassignSubmitAsync()
+ {
+ try
+ {
+ await Database.JobTrigger()
+ .DeleteOneAsync(Builders
+ .Filter.And(Builders.Filter
+ .Eq(p => p.Job, JobId), Builders.Filter
+ .Eq(p => p.Trigger, Model?.Id)),
+ cancellationToken: default);
+
+ if (Container is not null) await Container.RefreshAsync();
+
+ Notification.Success(Snackbar);
+ }
+ catch (Exception)
+ {
+ Notification.Error(Snackbar);
+ }
+ finally
+ {
+ Unassign = false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/TriggersAssign.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/TriggersAssign.razor
new file mode 100644
index 0000000..488a992
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/TriggersAssign.razor
@@ -0,0 +1,51 @@
+@inherits ComponentBase
+
+
+
+
+
+ Name
+
+
+
+
+ Description
+
+
+
+
+
+
+ @context?.Name
+
+
+
+ @context?.Description
+
+
+
+
+ Assign
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Assign
+
+
+
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/TriggersAssign.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/TriggersAssign.razor.cs
new file mode 100644
index 0000000..7e2b141
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Jobs/TriggersAssign.razor.cs
@@ -0,0 +1,177 @@
+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.Driver;
+using MudBlazor;
+using System.Text.RegularExpressions;
+using SortDirection = MudBlazor.SortDirection;
+
+namespace Insight.Web.Pages.Management.Scheduler.Jobs;
+
+[Route(Navigation.Management.Scheduler.Jobs.TriggersAssign)]
+public partial class TriggersAssign
+{
+ [Parameter] public string? JobId { 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? Container { get; set; }
+ private string Title { get; set; } = Global.Name;
+ private List Breadcrumbs { get; } = new();
+ private string? Search { get; set; }
+
+ private TriggerEntity? Model { get; set; }
+
+ protected override async Task OnInitializedAsync()
+ {
+ if (string.IsNullOrWhiteSpace(JobId))
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Jobs.Index);
+ return;
+ }
+
+ var job = await Database.Job()
+ .Aggregate()
+ .Match(Builders.Filter.Eq(p => p.Id, JobId))
+ .FirstOrDefaultAsync(default);
+
+ if (job is null)
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Jobs.Index);
+ return;
+ }
+
+ Breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
+ Breadcrumbs.Add(new BreadcrumbItem("Scheduler", href: Navigation.Management.Scheduler.Index));
+ Breadcrumbs.Add(new BreadcrumbItem("Jobs", href: Navigation.Management.Scheduler.Jobs.Index));
+
+ Title = $"Scheduler » Jobs » {job.Name} » Assign Triggers|Insight";
+ Breadcrumbs.Add(new BreadcrumbItem(job.Name, href: Navigation.Management.Scheduler.Jobs.DetailsHref(JobId)));
+ Breadcrumbs.Add(new BreadcrumbItem("Triggers", href: Navigation.Management.Scheduler.Jobs.TriggersHref(JobId)));
+ Breadcrumbs.Add(new BreadcrumbItem("Assign", href: "#", true));
+ }
+
+ private async Task> LoadDataAsync(TableState state)
+ {
+ try
+ {
+ var filter = Builders.Filter.Empty;
+
+ if (string.IsNullOrWhiteSpace(Search) is false)
+ {
+ var regex = new BsonRegularExpression(new Regex(Search, RegexOptions.IgnoreCase));
+ filter &= Builders.Filter.Regex("name", regex) |
+ Builders.Filter.Regex("description", regex);
+ }
+
+ var query = Database.Trigger()
+ .Aggregate()
+ .AppendStage(new BsonDocument("$lookup", new BsonDocument
+ {
+ { "from", "job_triggers" },
+ { "localField", "_id" },
+ { "foreignField", "_trigger" },
+ { "as", "map" }
+ }))
+ .AppendStage(new BsonDocument("$unwind", new BsonDocument
+ {
+ { "path", "$map" },
+ { "preserveNullAndEmptyArrays", true }
+ }))
+ .AppendStage(
+ new BsonDocument("$match",
+ new BsonDocument("map._job", new BsonDocument("$ne", new ObjectId(JobId))))
+ )
+ .Sort(state.SortDirection switch
+ {
+ SortDirection.Ascending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Ascending("name"),
+ "Description" => Builders.Sort.Ascending("description"),
+ _ => null
+ },
+ SortDirection.Descending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Descending("name"),
+ "Description" => Builders.Sort.Descending("description"),
+ _ => null
+ },
+ _ => Builders.Sort.Ascending("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()
+ {
+ TotalItems = countResult is null ? 0 : (int)countResult.Count,
+ Items = itemResult.Select(x => BsonSerializer.Deserialize(x))
+ };
+ }
+ catch (Exception)
+ {
+ Notification.Error(Snackbar);
+ return new TableData();
+ }
+ }
+
+
+ private bool _assign;
+ public bool Assign
+ {
+ get
+ {
+ return _assign;
+ }
+ set
+ {
+ if (value != _assign)
+ {
+ _assign = value;
+ StateHasChanged();
+ }
+ }
+ }
+
+ private void OnAssign(TriggerEntity? model)
+ {
+ Model = model;
+ Assign = true;
+ }
+
+ private async Task OnAddSubmitAsync()
+ {
+ try
+ {
+ await Database.JobTrigger()
+ .InsertOneAsync(new JobTriggerEntity
+ {
+ Job = JobId,
+ Trigger = Model.Id
+ }, cancellationToken: default);
+
+ if (Container is not null)
+ {
+ await Container.RefreshAsync();
+ }
+
+ Notification.Success(Snackbar);
+ }
+ catch (Exception)
+ {
+ Notification.Error(Snackbar);
+ }
+ finally
+ {
+ Assign = false;
+ NavigationManager?.NavigateTo(Navigation.Management.Scheduler.Jobs.TriggersHref(JobId));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Details.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Details.razor
new file mode 100644
index 0000000..0f84a27
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Details.razor
@@ -0,0 +1,19 @@
+@inherits ComponentBase
+
+@using Vaitr.Scheduler;
+
+
+
+ @if (Task is not null)
+ {
+
+
+
+
+ @*
+
+ *@
+
+ }
+
+
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Details.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Details.razor.cs
new file mode 100644
index 0000000..56c79b1
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Details.razor.cs
@@ -0,0 +1,56 @@
+using Insight.Infrastructure.Entities;
+using Insight.Web.Constants;
+using Microsoft.AspNetCore.Components;
+using MongoDB.Bson;
+using MongoDB.Driver;
+using MudBlazor;
+
+namespace Insight.Web.Pages.Management.Scheduler.Tasks;
+
+[Route(Navigation.Management.Scheduler.Tasks.Details)]
+public partial class Details
+{
+ [Parameter] public string? TaskId { get; set; }
+
+ [Inject] private IMongoDatabase Database { get; init; } = default!;
+ [Inject] private ISnackbar Snackbar { get; init; } = default!;
+ [Inject] private NavigationManager NavigationManager { get; init; } = default!;
+
+ private string Title { get; set; } = Global.Name;
+ private List Breadcrumbs { get; } = new();
+ private TaskEntity? Task { get; set; }
+
+ private async Task LoadDataAsync()
+ {
+ Breadcrumbs.Clear();
+ Task = null;
+
+ if (string.IsNullOrWhiteSpace(TaskId) || ObjectId.TryParse(TaskId, out var taskId) is false)
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Tasks.Index);
+ return;
+ }
+
+ Task = await Database.Task()
+ .Aggregate()
+ .Match(Builders.Filter.Eq(p => p.Id, TaskId))
+ .FirstOrDefaultAsync(default);
+
+ if (Task is null)
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Tasks.Index);
+ return;
+ }
+
+ Breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
+ Breadcrumbs.Add(new BreadcrumbItem("Scheduler", href: Navigation.Management.Scheduler.Index));
+ Breadcrumbs.Add(new BreadcrumbItem("Tasks", href: Navigation.Management.Scheduler.Tasks.Index));
+
+ Title = $"Task » {Task.Name ?? Task.Id}|Insight";
+ Breadcrumbs.Add(new BreadcrumbItem(Task.Name ?? Task.Id, href: "#", true));
+
+ StateHasChanged();
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Index.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Index.razor
new file mode 100644
index 0000000..3bc02b7
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Index.razor
@@ -0,0 +1,60 @@
+@inherits ComponentBase
+
+
+
+
+
+ Name
+
+
+
+
+ Description
+
+
+
+
+ Jobs
+
+
+
+
+
+
+ @context?.Name
+
+
+
+ @context?.Description
+
+
+
+ @(context.Jobs?.ToString() ?? "0")
+
+
+
+
+
+ Edit
+
+
+ Delete
+
+
+
+
+
+
+
+
+@code{
+ private TaskCreateDialog? _createDialog;
+ private TaskEditDialog? _editDialog;
+ private TaskDeleteDialog? _deleteDialog;
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Index.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Index.razor.cs
new file mode 100644
index 0000000..27f5c3e
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Index.razor.cs
@@ -0,0 +1,105 @@
+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.Scheduler.Tasks;
+
+[Route(Navigation.Management.Scheduler.Tasks.Index)]
+public partial class Index
+{
+ [Inject] private IMongoDatabase Database { get; init; } = default!;
+ [Inject] private ISnackbar Snackbar { get; init; } = default!;
+
+ private readonly List _breadcrumbs = new();
+
+ private TableContainer? _container;
+ private string _title = Global.Name;
+ private string? _search;
+
+ protected override void OnInitialized()
+ {
+ _title = "Tasks|Insight";
+ _breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
+ _breadcrumbs.Add(new BreadcrumbItem("Scheduler", href: Navigation.Management.Scheduler.Index));
+ _breadcrumbs.Add(new BreadcrumbItem("Tasks", href: Navigation.Management.Scheduler.Tasks.Index, true));
+ }
+
+ private async Task> LoadDataAsync(TableState state)
+ {
+ try
+ {
+ var filter = Builders.Filter.Empty;
+
+ if (string.IsNullOrWhiteSpace(_search) is false)
+ {
+ var regex = new BsonRegularExpression(new Regex(_search, RegexOptions.IgnoreCase));
+ filter &= Builders.Filter.Regex(x => x.Name, regex);
+ }
+
+ var query = Database.Task()
+ .Aggregate()
+ .Match(filter)
+ .AppendStage(new BsonDocument("$lookup", new BsonDocument
+ {
+ { "from", "job_task" },
+ { "localField", "_id" },
+ { "foreignField", "_task" },
+ { "as", "jobs" }
+ }))
+ .AppendStage(new BsonDocument("$addFields",
+ new BsonDocument("jobs", new BsonDocument("$size", "$jobs"))
+ ))
+ .Sort(state.SortDirection switch
+ {
+ SortDirection.Ascending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Ascending("name"),
+ "Description" => Builders.Sort.Ascending("description"),
+ _ => null
+ },
+ SortDirection.Descending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Descending("name"),
+ "Description" => Builders.Sort.Descending("description"),
+ _ => null
+ },
+ _ => Builders.Sort.Ascending("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()
+ {
+ TotalItems = countResult is null ? 0 : (int)countResult.Count,
+ Items = itemResult.Select(x => BsonSerializer.Deserialize(x))
+ };
+ }
+ catch (Exception)
+ {
+ Notification.Error(Snackbar);
+ return new TableData();
+ }
+ }
+
+ private async Task OnRefreshAsync()
+ {
+ if (_container is null) return;
+ await _container.RefreshAsync().ConfigureAwait(false);
+ }
+
+ [BsonIgnoreExtraElements]
+ private class ViewModel : TaskEntity
+ {
+ [BsonElement("jobs")]
+ public int? Jobs { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Jobs.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Jobs.razor
new file mode 100644
index 0000000..6c492fe
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Jobs.razor
@@ -0,0 +1,51 @@
+@inherits ComponentBase
+
+
+
+
+
+ Name
+
+
+
+
+ Description
+
+
+
+
+
+
+ @context?.Name
+
+
+
+ @context?.Description
+
+
+
+
+ Unassign
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Unassign
+
+
+
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Jobs.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Jobs.razor.cs
new file mode 100644
index 0000000..ac268d9
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/Jobs.razor.cs
@@ -0,0 +1,180 @@
+using Insight.Infrastructure.Entities;
+using Insight.Web.Components.Containers;
+using Insight.Web.Constants;
+using Microsoft.AspNetCore.Components;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson;
+using MongoDB.Driver;
+using MudBlazor;
+using System.Text.RegularExpressions;
+using SortDirection = MudBlazor.SortDirection;
+
+namespace Insight.Web.Pages.Management.Scheduler.Tasks;
+
+[Route(Navigation.Management.Scheduler.Tasks.Jobs)]
+public partial class Jobs
+{
+ [Parameter] public string? TaskId { 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? Container { get; set; }
+ private string Title { get; set; } = Global.Name;
+ private List Breadcrumbs { get; } = new();
+ private string? Search { get; set; }
+
+ private JobEntity? Model { get; set; }
+
+ protected override async Task OnInitializedAsync()
+ {
+ if (string.IsNullOrWhiteSpace(TaskId))
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Tasks.Index);
+ return;
+ }
+
+ Breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
+ Breadcrumbs.Add(new BreadcrumbItem("Scheduler", href: Navigation.Management.Scheduler.Index));
+ Breadcrumbs.Add(new BreadcrumbItem("Tasks", href: Navigation.Management.Scheduler.Tasks.Index));
+
+ var task = await Database.Task()
+ .Aggregate()
+ .Match(Builders.Filter.Eq(p => p.Id, TaskId))
+ .FirstOrDefaultAsync(default);
+
+ if (task is null)
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Tasks.Index);
+ return;
+ }
+
+ Title = $"Scheduler » Tasks » {task.Name} » Jobs|Insight";
+ Breadcrumbs.Add(new BreadcrumbItem(task.Name, href: Navigation.Management.Scheduler.Tasks.DetailsHref(TaskId)));
+ Breadcrumbs.Add(new BreadcrumbItem("Jobs", href: "#", true));
+ }
+
+ private async Task> LoadDataAsync(TableState state)
+ {
+ try
+ {
+ var filter = Builders.Filter.Empty;
+
+ if (string.IsNullOrWhiteSpace(Search) is false)
+ {
+ var regex = new BsonRegularExpression(new Regex(Search, RegexOptions.IgnoreCase));
+
+ filter &= Builders.Filter.Regex("name", regex) |
+ Builders.Filter.Regex("description", regex);
+ }
+
+ var query = Database.JobTask()
+ .Aggregate()
+ .Match(Builders.Filter.Eq(p => p.Task, TaskId))
+ .AppendStage(new BsonDocument("$lookup", new BsonDocument
+ {
+ { "from", "job" },
+ { "localField", "_job" },
+ { "foreignField", "_id" },
+ { "as", "jobs" }
+ }))
+ .AppendStage(new BsonDocument("$addFields",
+ new BsonDocument("job", new BsonDocument("$first", "$jobs"))
+ ))
+ .AppendStage(new BsonDocument("$project", new BsonDocument
+ {
+ { "_id", "$job._id" },
+ { "name", "$job.name" },
+ { "description", "$job.description" }
+ }))
+ .Match(filter)
+ .Sort(state.SortDirection switch
+ {
+ SortDirection.Ascending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Ascending("name"),
+ "Description" => Builders.Sort.Ascending("description"),
+ _ => null
+ },
+ SortDirection.Descending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Descending("name"),
+ "Description" => Builders.Sort.Descending("description"),
+ _ => null
+ },
+ _ => Builders.Sort.Ascending("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()
+ {
+ TotalItems = countResult is null ? 0 : (int)countResult.Count,
+ Items = itemResult.Select(x => BsonSerializer.Deserialize(x))
+ };
+ }
+ catch (Exception)
+ {
+ Notification.Error(Snackbar);
+ return new TableData();
+ }
+ }
+
+ private bool _unassign;
+ public bool Unassign
+ {
+ get
+ {
+ return _unassign;
+ }
+ set
+ {
+ if (value != _unassign)
+ {
+ _unassign = value;
+ StateHasChanged();
+ }
+ }
+ }
+
+ private void OnUnassign(JobEntity model)
+ {
+ Model = new JobEntity
+ {
+ Id = model.Id,
+ Name = model?.Name,
+ Description = model?.Description
+ };
+
+ Unassign = true;
+ }
+
+ private async Task OnUnassignSubmitAsync()
+ {
+ try
+ {
+ await Database.JobTask()
+ .DeleteOneAsync(Builders
+ .Filter.And(Builders.Filter
+ .Eq(p => p.Task, TaskId), Builders.Filter
+ .Eq(p => p.Job, Model?.Id)),
+ cancellationToken: default);
+
+ if (Container is not null) await Container.RefreshAsync();
+
+ Notification.Success(Snackbar);
+ }
+ catch (Exception)
+ {
+ Notification.Error(Snackbar);
+ }
+ finally
+ {
+ Unassign = false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskCreateDialog.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskCreateDialog.razor
new file mode 100644
index 0000000..159bda2
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskCreateDialog.razor
@@ -0,0 +1,34 @@
+@using MongoDB.Bson;
+@using Insight.Infrastructure.Entities;
+
+
+
+
+ Create Task
+
+
+
+ @if (_model is not null)
+ {
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Create
+
+
+
+ }
+
+
+
+@code {
+ private bool _visible;
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskCreateDialog.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskCreateDialog.razor.cs
new file mode 100644
index 0000000..cd8e8a5
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskCreateDialog.razor.cs
@@ -0,0 +1,59 @@
+using Insight.Infrastructure.Entities;
+using Insight.Web.Constants;
+using Microsoft.AspNetCore.Components;
+using MongoDB.Driver;
+using MudBlazor;
+
+namespace Insight.Web.Pages.Management.Scheduler.Tasks;
+
+public partial class TaskCreateDialog
+{
+ [Parameter] public EventCallback OnChanges { get; set; }
+
+ [Inject] private IMongoDatabase Database { get; init; } = default!;
+ [Inject] private ISnackbar Snackbar { get; init; } = default!;
+ [Inject] private ILogger Logger { get; init; } = default!;
+
+ private TaskEntity? _model;
+
+ public async void ToggleAsync()
+ {
+ _model = new();
+ _visible = !_visible;
+
+ await InvokeAsync(StateHasChanged);
+ }
+
+ private async Task SubmitAsync()
+ {
+ if (_model is null) return;
+
+ _model.Insert = DateTime.Now;
+
+ try
+ {
+ await Database.Task()
+ .InsertOneAsync(_model, 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskDeleteDialog.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskDeleteDialog.razor
new file mode 100644
index 0000000..8d4dc91
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskDeleteDialog.razor
@@ -0,0 +1,36 @@
+@using MongoDB.Bson;
+
+
+
+
+ Delete Task
+
+
+
+ @if (_model is not null)
+ {
+
+
+
+
+
+
+ Cancel
+
+
+ Delete
+
+
+
+ }
+
+
+
+@code {
+ private bool _visible;
+ public void Toggle()
+ {
+ _visible = !_visible;
+ StateHasChanged();
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskDeleteDialog.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskDeleteDialog.razor.cs
new file mode 100644
index 0000000..7545a06
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskDeleteDialog.razor.cs
@@ -0,0 +1,67 @@
+using Insight.Infrastructure.Entities;
+using Insight.Web.Constants;
+using Microsoft.AspNetCore.Components;
+using MongoDB.Driver;
+using MudBlazor;
+
+namespace Insight.Web.Pages.Management.Scheduler.Tasks;
+
+public partial class TaskDeleteDialog
+{
+ [Parameter] public EventCallback OnChanges { get; set; }
+
+ [Inject] private IMongoDatabase Database { get; init; } = default!;
+ [Inject] private ISnackbar Snackbar { get; init; } = default!;
+ [Inject] private ILogger Logger { get; init; } = default!;
+
+ private TaskEntity? _model;
+
+ public async void ToggleAsync(string? id)
+ {
+ if (id is null) return;
+
+ try
+ {
+ _model = await Database.Task().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.Task()
+ .DeleteOneAsync(Builders
+ .Filter.Eq(p => p.Id, _model.Id),
+ 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskEditDialog.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskEditDialog.razor
new file mode 100644
index 0000000..fe87ee6
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskEditDialog.razor
@@ -0,0 +1,33 @@
+@using MongoDB.Bson;
+
+
+
+
+ Edit Task
+
+
+
+ @if (_model is not null)
+ {
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Edit
+
+
+
+ }
+
+
+
+@code {
+ private bool _visible;
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskEditDialog.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskEditDialog.razor.cs
new file mode 100644
index 0000000..bda5fd1
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Tasks/TaskEditDialog.razor.cs
@@ -0,0 +1,70 @@
+using Insight.Infrastructure.Entities;
+using Insight.Web.Constants;
+using Microsoft.AspNetCore.Components;
+using MongoDB.Driver;
+using MudBlazor;
+
+namespace Insight.Web.Pages.Management.Scheduler.Tasks;
+
+public partial class TaskEditDialog
+{
+ [Parameter] public EventCallback OnChanges { get; set; }
+
+ [Inject] private IMongoDatabase Database { get; init; } = default!;
+ [Inject] private ISnackbar Snackbar { get; init; } = default!;
+ [Inject] private ILogger Logger { get; init; } = default!;
+
+ private TaskEntity? _model;
+
+ public async void ToggleAsync(string? id)
+ {
+ if (id is null) return;
+
+ try
+ {
+ _model = await Database.Task().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.Task()
+ .UpdateOneAsync(Builders
+ .Filter
+ .Eq(p => p.Id, _model.Id), Builders
+ .Update
+ .Set(p => p.Update, DateTime.Now)
+ .Set(p => p.Name, _model.Name), 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Details.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Details.razor
new file mode 100644
index 0000000..ca48096
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Details.razor
@@ -0,0 +1,19 @@
+@inherits ComponentBase
+
+@using Vaitr.Scheduler;
+
+
+
+ @if (Trigger is not null)
+ {
+
+
+
+
+ @*
+
+ *@
+
+ }
+
+
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Details.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Details.razor.cs
new file mode 100644
index 0000000..39523fa
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Details.razor.cs
@@ -0,0 +1,56 @@
+using Insight.Infrastructure.Entities;
+using Insight.Web.Constants;
+using Microsoft.AspNetCore.Components;
+using MongoDB.Bson;
+using MongoDB.Driver;
+using MudBlazor;
+
+namespace Insight.Web.Pages.Management.Scheduler.Triggers;
+
+[Route(Navigation.Management.Scheduler.Triggers.Details)]
+public partial class Details
+{
+ [Parameter] public string? TriggerId { get; set; }
+
+ [Inject] private IMongoDatabase Database { get; init; } = default!;
+ [Inject] private ISnackbar Snackbar { get; init; } = default!;
+ [Inject] private NavigationManager NavigationManager { get; init; } = default!;
+
+ private string Title { get; set; } = Global.Name;
+ private List Breadcrumbs { get; } = new();
+ private TriggerEntity? Trigger { get; set; }
+
+ private async Task LoadDataAsync()
+ {
+ Breadcrumbs.Clear();
+ Trigger = null;
+
+ if (string.IsNullOrWhiteSpace(TriggerId) || ObjectId.TryParse(TriggerId, out var triggerId) is false)
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Triggers.Index);
+ return;
+ }
+
+ Trigger = await Database.Trigger()
+ .Aggregate()
+ .Match(Builders.Filter.Eq(p => p.Id, TriggerId))
+ .FirstOrDefaultAsync(default);
+
+ if (Trigger is null)
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Triggers.Index);
+ return;
+ }
+
+ Breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
+ Breadcrumbs.Add(new BreadcrumbItem("Scheduler", href: Navigation.Management.Scheduler.Index));
+ Breadcrumbs.Add(new BreadcrumbItem("Triggers", href: Navigation.Management.Scheduler.Triggers.Index));
+
+ Title = $"Trigger » {Trigger.Name ?? Trigger.Id}|Insight";
+ Breadcrumbs.Add(new BreadcrumbItem(Trigger.Name ?? Trigger.Id, href: "#", true));
+
+ StateHasChanged();
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Index.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Index.razor
new file mode 100644
index 0000000..4fd1bb9
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Index.razor
@@ -0,0 +1,60 @@
+@inherits ComponentBase
+
+
+
+
+
+ Name
+
+
+
+
+ Description
+
+
+
+
+ Jobs
+
+
+
+
+
+
+ @context?.Name
+
+
+
+ @context?.Description
+
+
+
+ @(context.Jobs?.ToString() ?? "0")
+
+
+
+
+
+ Edit
+
+
+ Delete
+
+
+
+
+
+
+
+
+@code {
+ private TriggerCreateDialog? _createDialog;
+ private TriggerEditDialog? _editDialog;
+ private TriggerDeleteDialog? _deleteDialog;
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Index.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Index.razor.cs
new file mode 100644
index 0000000..f833c85
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Index.razor.cs
@@ -0,0 +1,104 @@
+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.Scheduler.Triggers;
+
+[Route(Navigation.Management.Scheduler.Triggers.Index)]
+public partial class Index
+{
+ [Inject] private IMongoDatabase Database { get; init; } = default!;
+ [Inject] private ISnackbar Snackbar { get; init; } = default!;
+
+ private readonly List _breadcrumbs = new();
+
+ private TableContainer? _container;
+ private string _title = Global.Name;
+ private string? _search;
+
+ protected override void OnInitialized()
+ {
+ _title = "Triggers|Insight";
+ _breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
+ _breadcrumbs.Add(new BreadcrumbItem("Triggers", href: Navigation.Management.Scheduler.Triggers.Index, true));
+ }
+
+ private async Task> LoadDataAsync(TableState state)
+ {
+ try
+ {
+ var filter = Builders.Filter.Empty;
+
+ if (string.IsNullOrWhiteSpace(_search) is false)
+ {
+ var regex = new BsonRegularExpression(new Regex(_search, RegexOptions.IgnoreCase));
+ filter &= Builders.Filter.Regex(x => x.Name, regex);
+ }
+
+ var query = Database.Trigger()
+ .Aggregate()
+ .Match(filter)
+ .AppendStage(new BsonDocument("$lookup", new BsonDocument
+ {
+ { "from", "job_trigger" },
+ { "localField", "_id" },
+ { "foreignField", "_trigger" },
+ { "as", "jobs" }
+ }))
+ .AppendStage(new BsonDocument("$addFields",
+ new BsonDocument("jobs", new BsonDocument("$size", "$jobs"))
+ ))
+ .Sort(state.SortDirection switch
+ {
+ SortDirection.Ascending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Ascending("name"),
+ "Description" => Builders.Sort.Ascending("description"),
+ _ => null
+ },
+ SortDirection.Descending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Descending("name"),
+ "Description" => Builders.Sort.Descending("description"),
+ _ => null
+ },
+ _ => Builders.Sort.Ascending("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()
+ {
+ TotalItems = countResult is null ? 0 : (int)countResult.Count,
+ Items = itemResult.Select(x => BsonSerializer.Deserialize(x))
+ };
+ }
+ catch (Exception)
+ {
+ Notification.Error(Snackbar);
+ return new TableData();
+ }
+ }
+
+ private async Task OnRefreshAsync()
+ {
+ if (_container is null) return;
+ await _container.RefreshAsync().ConfigureAwait(false);
+ }
+
+ [BsonIgnoreExtraElements]
+ private class ViewModel : TriggerEntity
+ {
+ [BsonElement("jobs")]
+ public int? Jobs { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Jobs.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Jobs.razor
new file mode 100644
index 0000000..6c492fe
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Jobs.razor
@@ -0,0 +1,51 @@
+@inherits ComponentBase
+
+
+
+
+
+ Name
+
+
+
+
+ Description
+
+
+
+
+
+
+ @context?.Name
+
+
+
+ @context?.Description
+
+
+
+
+ Unassign
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Unassign
+
+
+
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Jobs.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Jobs.razor.cs
new file mode 100644
index 0000000..97bd0c3
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/Jobs.razor.cs
@@ -0,0 +1,180 @@
+using Insight.Infrastructure.Entities;
+using Insight.Web.Components.Containers;
+using Insight.Web.Constants;
+using Microsoft.AspNetCore.Components;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson;
+using MongoDB.Driver;
+using MudBlazor;
+using System.Text.RegularExpressions;
+using SortDirection = MudBlazor.SortDirection;
+
+namespace Insight.Web.Pages.Management.Scheduler.Triggers;
+
+[Route(Navigation.Management.Scheduler.Triggers.Jobs)]
+public partial class Jobs
+{
+ [Parameter] public string? TriggerId { 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? Container { get; set; }
+ private string Title { get; set; } = Global.Name;
+ private List Breadcrumbs { get; } = new();
+ private string? Search { get; set; }
+
+ private JobEntity? Model { get; set; }
+
+ protected override async Task OnInitializedAsync()
+ {
+ if (string.IsNullOrWhiteSpace(TriggerId))
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Triggers.Index);
+ return;
+ }
+
+ Breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
+ Breadcrumbs.Add(new BreadcrumbItem("Scheduler", href: Navigation.Management.Scheduler.Index));
+ Breadcrumbs.Add(new BreadcrumbItem("Triggers", href: Navigation.Management.Scheduler.Triggers.Index));
+
+ var task = await Database.Trigger()
+ .Aggregate()
+ .Match(Builders.Filter.Eq(p => p.Id, TriggerId))
+ .FirstOrDefaultAsync(default);
+
+ if (task is null)
+ {
+ Notification.Error(Snackbar, "Not Found");
+ NavigationManager.NavigateTo(Navigation.Management.Scheduler.Triggers.Index);
+ return;
+ }
+
+ Title = $"Scheduler » Triggers » {task.Name} » Jobs|Insight";
+ Breadcrumbs.Add(new BreadcrumbItem(task.Name, href: Navigation.Management.Scheduler.Triggers.DetailsHref(TriggerId)));
+ Breadcrumbs.Add(new BreadcrumbItem("Jobs", href: "#", true));
+ }
+
+ private async Task> LoadDataAsync(TableState state)
+ {
+ try
+ {
+ var filter = Builders.Filter.Empty;
+
+ if (string.IsNullOrWhiteSpace(Search) is false)
+ {
+ var regex = new BsonRegularExpression(new Regex(Search, RegexOptions.IgnoreCase));
+
+ filter &= Builders.Filter.Regex("name", regex) |
+ Builders.Filter.Regex("description", regex);
+ }
+
+ var query = Database.JobTrigger()
+ .Aggregate()
+ .Match(Builders.Filter.Eq(p => p.Trigger, TriggerId))
+ .AppendStage(new BsonDocument("$lookup", new BsonDocument
+ {
+ { "from", "job" },
+ { "localField", "_job" },
+ { "foreignField", "_id" },
+ { "as", "jobs" }
+ }))
+ .AppendStage(new BsonDocument("$addFields",
+ new BsonDocument("job", new BsonDocument("$first", "$jobs"))
+ ))
+ .AppendStage(new BsonDocument("$project", new BsonDocument
+ {
+ { "_id", "$job._id" },
+ { "name", "$job.name" },
+ { "description", "$job.description" }
+ }))
+ .Match(filter)
+ .Sort(state.SortDirection switch
+ {
+ SortDirection.Ascending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Ascending("name"),
+ "Description" => Builders.Sort.Ascending("description"),
+ _ => null
+ },
+ SortDirection.Descending => state.SortLabel switch
+ {
+ "Name" => Builders.Sort.Descending("name"),
+ "Description" => Builders.Sort.Descending("description"),
+ _ => null
+ },
+ _ => Builders.Sort.Ascending("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()
+ {
+ TotalItems = countResult is null ? 0 : (int)countResult.Count,
+ Items = itemResult.Select(x => BsonSerializer.Deserialize(x))
+ };
+ }
+ catch (Exception)
+ {
+ Notification.Error(Snackbar);
+ return new TableData();
+ }
+ }
+
+ private bool _unassign;
+ public bool Unassign
+ {
+ get
+ {
+ return _unassign;
+ }
+ set
+ {
+ if (value != _unassign)
+ {
+ _unassign = value;
+ StateHasChanged();
+ }
+ }
+ }
+
+ private void OnUnassign(JobEntity model)
+ {
+ Model = new JobEntity
+ {
+ Id = model.Id,
+ Name = model?.Name,
+ Description = model?.Description
+ };
+
+ Unassign = true;
+ }
+
+ private async Task OnUnassignSubmitAsync()
+ {
+ try
+ {
+ await Database.JobTrigger()
+ .DeleteOneAsync(Builders
+ .Filter.And(Builders.Filter
+ .Eq(p => p.Trigger, TriggerId), Builders.Filter
+ .Eq(p => p.Job, Model?.Id)),
+ cancellationToken: default);
+
+ if (Container is not null) await Container.RefreshAsync();
+
+ Notification.Success(Snackbar);
+ }
+ catch (Exception)
+ {
+ Notification.Error(Snackbar);
+ }
+ finally
+ {
+ Unassign = false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerCreateDialog.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerCreateDialog.razor
new file mode 100644
index 0000000..e3fd18e
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerCreateDialog.razor
@@ -0,0 +1,34 @@
+@using MongoDB.Bson;
+@using Insight.Infrastructure.Entities;
+
+
+
+
+ Create Trigger
+
+
+
+ @if (_model is not null)
+ {
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Create
+
+
+
+ }
+
+
+
+@code {
+ private bool _visible;
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerCreateDialog.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerCreateDialog.razor.cs
new file mode 100644
index 0000000..7e3275d
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerCreateDialog.razor.cs
@@ -0,0 +1,59 @@
+using Insight.Infrastructure.Entities;
+using Insight.Web.Constants;
+using Microsoft.AspNetCore.Components;
+using MongoDB.Driver;
+using MudBlazor;
+
+namespace Insight.Web.Pages.Management.Scheduler.Triggers;
+
+public partial class TriggerCreateDialog
+{
+ [Parameter] public EventCallback OnChanges { get; set; }
+
+ [Inject] private IMongoDatabase Database { get; init; } = default!;
+ [Inject] private ISnackbar Snackbar { get; init; } = default!;
+ [Inject] private ILogger Logger { get; init; } = default!;
+
+ private TriggerEntity? _model;
+
+ public async void ToggleAsync()
+ {
+ _model = new();
+ _visible = !_visible;
+
+ await InvokeAsync(StateHasChanged);
+ }
+
+ private async Task SubmitAsync()
+ {
+ if (_model is null) return;
+
+ _model.Insert = DateTime.Now;
+
+ try
+ {
+ await Database.Trigger()
+ .InsertOneAsync(_model, 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerDeleteDialog.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerDeleteDialog.razor
new file mode 100644
index 0000000..032a5c4
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerDeleteDialog.razor
@@ -0,0 +1,36 @@
+@using MongoDB.Bson;
+
+
+
+
+ Delete Trigger
+
+
+
+ @if (_model is not null)
+ {
+
+
+
+
+
+
+ Cancel
+
+
+ Delete
+
+
+
+ }
+
+
+
+@code {
+ private bool _visible;
+ public void Toggle()
+ {
+ _visible = !_visible;
+ StateHasChanged();
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerDeleteDialog.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerDeleteDialog.razor.cs
new file mode 100644
index 0000000..74994ea
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerDeleteDialog.razor.cs
@@ -0,0 +1,67 @@
+using Insight.Infrastructure.Entities;
+using Insight.Web.Constants;
+using Microsoft.AspNetCore.Components;
+using MongoDB.Driver;
+using MudBlazor;
+
+namespace Insight.Web.Pages.Management.Scheduler.Triggers;
+
+public partial class TriggerDeleteDialog
+{
+ [Parameter] public EventCallback OnChanges { get; set; }
+
+ [Inject] private IMongoDatabase Database { get; init; } = default!;
+ [Inject] private ISnackbar Snackbar { get; init; } = default!;
+ [Inject] private ILogger Logger { get; init; } = default!;
+
+ private TriggerEntity? _model;
+
+ public async void ToggleAsync(string? id)
+ {
+ if (id is null) return;
+
+ try
+ {
+ _model = await Database.Trigger().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.Trigger()
+ .DeleteOneAsync(Builders
+ .Filter.Eq(p => p.Id, _model.Id),
+ 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerEditDialog.razor b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerEditDialog.razor
new file mode 100644
index 0000000..c700957
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerEditDialog.razor
@@ -0,0 +1,33 @@
+@using MongoDB.Bson;
+
+
+
+
+ Edit Trigger
+
+
+
+ @if (_model is not null)
+ {
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Edit
+
+
+
+ }
+
+
+
+@code {
+ private bool _visible;
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerEditDialog.razor.cs b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerEditDialog.razor.cs
new file mode 100644
index 0000000..87ccc8d
--- /dev/null
+++ b/src/Web/Insight.Web/Pages/Management/Scheduler/Triggers/TriggerEditDialog.razor.cs
@@ -0,0 +1,70 @@
+using Insight.Infrastructure.Entities;
+using Insight.Web.Constants;
+using Microsoft.AspNetCore.Components;
+using MongoDB.Driver;
+using MudBlazor;
+
+namespace Insight.Web.Pages.Management.Scheduler.Triggers;
+
+public partial class TriggerEditDialog
+{
+ [Parameter] public EventCallback OnChanges { get; set; }
+
+ [Inject] private IMongoDatabase Database { get; init; } = default!;
+ [Inject] private ISnackbar Snackbar { get; init; } = default!;
+ [Inject] private ILogger Logger { get; init; } = default!;
+
+ private TriggerEntity? _model;
+
+ public async void ToggleAsync(string? id)
+ {
+ if (id is null) return;
+
+ try
+ {
+ _model = await Database.Trigger().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.Trigger()
+ .UpdateOneAsync(Builders
+ .Filter
+ .Eq(p => p.Id, _model.Id), Builders
+ .Update
+ .Set(p => p.Update, DateTime.Now)
+ .Set(p => p.Name, _model.Name), 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Monitoring/Index.razor b/src/Web/Insight.Web/Pages/Monitoring/Index.razor
deleted file mode 100644
index b33e032..0000000
--- a/src/Web/Insight.Web/Pages/Monitoring/Index.razor
+++ /dev/null
@@ -1,5 +0,0 @@
-Index
-
-@code {
-
-}
diff --git a/src/Web/Insight.Web/Pages/Monitoring/Index.razor.cs b/src/Web/Insight.Web/Pages/Monitoring/Index.razor.cs
deleted file mode 100644
index b07922a..0000000
--- a/src/Web/Insight.Web/Pages/Monitoring/Index.razor.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Insight.Web.Constants;
-using Microsoft.AspNetCore.Components;
-
-namespace Insight.Web.Pages.Monitoring;
-
-[Route(Navigation.Monitoring.Index)]
-public partial class Index
-{
- [Inject] private NavigationManager NavManager { get; init; } = default!;
-
- protected override void OnInitialized()
- {
- NavManager.NavigateTo(Navigation.Monitoring.Maintenance.Index);
- }
-}
\ No newline at end of file
diff --git a/src/Web/Insight.Web/Pages/Monitoring/Maintenance/Index.razor b/src/Web/Insight.Web/Pages/Monitoring/Maintenance/Index.razor
index 854dc7a..12349a5 100644
--- a/src/Web/Insight.Web/Pages/Monitoring/Maintenance/Index.razor
+++ b/src/Web/Insight.Web/Pages/Monitoring/Maintenance/Index.razor
@@ -1,25 +1,25 @@
@inherits ComponentBase
-
+
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/src/Web/Insight.Web/Pages/Monitoring/Maintenance/Index.razor.cs b/src/Web/Insight.Web/Pages/Monitoring/Maintenance/Index.razor.cs
index e53c595..30d53b2 100644
--- a/src/Web/Insight.Web/Pages/Monitoring/Maintenance/Index.razor.cs
+++ b/src/Web/Insight.Web/Pages/Monitoring/Maintenance/Index.razor.cs
@@ -13,16 +13,17 @@ public partial class Index
[Inject] private IMongoDatabase Database { get; init; } = default!;
[Inject] private ISnackbar Snackbar { get; init; } = default!;
- private string Title { get; set; } = Global.Name;
- private List Breadcrumbs { get; } = new();
- public ViewModel Model { get; } = new();
+ private string _title = Global.Name;
+ private ViewModel _model = new();
+
+ private readonly List _breadcrumbs = new();
protected override void OnInitialized()
{
- Title = $"Monitoring » Maintenance|Insight";
- Breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
- Breadcrumbs.Add(new BreadcrumbItem("Monitoring", href: Navigation.Monitoring.Index));
- Breadcrumbs.Add(new BreadcrumbItem("Maintenance", href: "#", true));
+ _title = $"Monitoring » Maintenance|Insight";
+ _breadcrumbs.Add(new BreadcrumbItem("Home", href: Navigation.Home));
+ _breadcrumbs.Add(new BreadcrumbItem("Monitoring", href: "#", true));
+ _breadcrumbs.Add(new BreadcrumbItem("Maintenance", href: "#", true));
}
private async Task LoadDataAsync()
@@ -39,7 +40,7 @@ public partial class Index
if (drives is not null && drives.Any())
{
- Model.Updates = drives[0].AsInt32;
+ _model.Updates = drives[0].AsInt32;
}
// storage pools (errors)
@@ -52,7 +53,7 @@ public partial class Index
if (storagePools is not null && storagePools.Any())
{
- Model.StoragePools = storagePools[0].AsInt32;
+ _model.StoragePools = storagePools[0].AsInt32;
}
// volumes (freespace)
@@ -78,7 +79,7 @@ public partial class Index
if (freespace is not null && freespace.Any())
{
- Model.Volumes = freespace[0].AsInt32;
+ _model.Volumes = freespace[0].AsInt32;
}
// virtual maschines
@@ -91,7 +92,7 @@ public partial class Index
if (virtualMaschines is not null && virtualMaschines.Any())
{
- Model.Guests = virtualMaschines[0].AsInt32;
+ _model.Guests = virtualMaschines[0].AsInt32;
}
// snapshots (old)
@@ -116,7 +117,7 @@ public partial class Index
if (snapshots is not null && snapshots.Any())
{
- Model.Snapshots = snapshots[0].AsInt32;
+ _model.Snapshots = snapshots[0].AsInt32;
}
// updates (pending)
@@ -129,7 +130,7 @@ public partial class Index
if (updates is not null && updates.Any())
{
- Model.Updates = updates[0].AsInt32;
+ _model.Updates = updates[0].AsInt32;
}
}
catch (Exception ex)