Added custom views
This commit is contained in:
35
src/HopFrame.Web/Components/HopFrameCard.razor
Normal file
35
src/HopFrame.Web/Components/HopFrameCard.razor
Normal file
@@ -0,0 +1,35 @@
|
||||
<FluentCard Width="350px" Height="200px" Style="display: flex; flex-direction: column; background-color: var(--neutral-layer-1)">
|
||||
<h3 style="margin-bottom: 0; display: flex; align-items: center; gap: 5px">
|
||||
@if (Icon is not null) {
|
||||
<FluentIcon Value="Icon" Color="Color.Neutral" />
|
||||
}
|
||||
@Title
|
||||
</h3>
|
||||
<FluentLabel Typo="Typography.Body" Color="Color.Info" Style="margin-bottom: 0.5rem">@Subtitle</FluentLabel>
|
||||
<span>@Description</span>
|
||||
<FluentSpacer />
|
||||
<div style="display: flex">
|
||||
<FluentSpacer/>
|
||||
|
||||
<a href="@Href" style="display: inline-block">
|
||||
<FluentButton>Open</FluentButton>
|
||||
</a>
|
||||
</div>
|
||||
</FluentCard>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public required string Title { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string? Subtitle { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public required string Description { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public required string Href { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public Icon? Icon { get; set; }
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
@using HopFrame.Core.Config
|
||||
@using HopFrame.Core.Services
|
||||
@using HopFrame.Web.Models
|
||||
@using Microsoft.Extensions.DependencyInjection
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
@@ -39,10 +40,28 @@
|
||||
|
||||
@code {
|
||||
|
||||
internal static readonly List<CustomView> CustomViews = new();
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
var authorized = await Handler.IsAuthenticatedAsync(Config.BasePolicy);
|
||||
|
||||
var currentUri = "/" + Navigator.ToBaseRelativePath(Navigator.Uri);
|
||||
|
||||
if (authorized) {
|
||||
foreach (var view in CustomViews.Where(view => !string.IsNullOrWhiteSpace(view.Policy))) {
|
||||
switch (view.LinkMatch) {
|
||||
case NavLinkMatch.All when currentUri != view.Url:
|
||||
case NavLinkMatch.Prefix when !currentUri.StartsWith(view.Url):
|
||||
continue;
|
||||
}
|
||||
|
||||
authorized = await Handler.IsAuthenticatedAsync(view.Policy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!authorized) {
|
||||
Navigator.NavigateTo((Config.LoginPageRewrite ?? "/login") + "?redirect=/" + Navigator.ToBaseRelativePath(Navigator.Uri), true);
|
||||
Navigator.NavigateTo((Config.LoginPageRewrite ?? "/login") + "?redirect=" + currentUri, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@using HopFrame.Core.Config
|
||||
@using HopFrame.Core.Services
|
||||
@using HopFrame.Web.Models
|
||||
|
||||
<FluentAppBar Orientation="Orientation.Vertical" PopoverShowSearch="false" Style="background-color: var(--neutral-layer-2); height: auto">
|
||||
<FluentAppBarItem Href="/admin"
|
||||
@@ -11,6 +12,15 @@
|
||||
|
||||
<br>
|
||||
|
||||
@foreach (var view in _views) {
|
||||
<FluentAppBarItem Href="@view.Url"
|
||||
Match="@view.LinkMatch"
|
||||
IconActive="GetLinkIcon(view, IconVariant.Filled)"
|
||||
IconRest="GetLinkIcon(view, IconVariant.Regular)"
|
||||
Text="@view.Name"
|
||||
Style="margin-top: 0.25rem"/>
|
||||
}
|
||||
|
||||
@foreach (var table in _tables.OrderBy(t => t.Order).Select(t => t.DisplayName)) {
|
||||
<FluentAppBarItem Href="@("/admin/" + table.ToLower())"
|
||||
Match="NavLinkMatch.All"
|
||||
@@ -27,6 +37,7 @@
|
||||
@code {
|
||||
|
||||
private readonly List<TableConfig> _tables = [];
|
||||
private readonly List<CustomView> _views = [];
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
foreach (var table in Explorer.GetTables()) {
|
||||
@@ -34,6 +45,21 @@
|
||||
if (!await Handler.IsAuthenticatedAsync(table.ViewPolicy)) continue;
|
||||
_tables.Add(table);
|
||||
}
|
||||
|
||||
foreach (var view in HopFrameLayout.CustomViews) {
|
||||
if (!await Handler.IsAuthenticatedAsync(view.Policy)) continue;
|
||||
_views.Add(view);
|
||||
}
|
||||
}
|
||||
|
||||
internal static Icon GetLinkIcon(CustomView view, IconVariant variant) {
|
||||
var info = new IconInfo {
|
||||
Name = view.Icon,
|
||||
Variant = variant,
|
||||
Size = IconSize.Size24
|
||||
};
|
||||
|
||||
return info.GetInstance();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,28 +1,31 @@
|
||||
@page "/admin"
|
||||
@using HopFrame.Core.Config
|
||||
@using HopFrame.Core.Services
|
||||
@using HopFrame.Web.Models
|
||||
@layout HopFrameLayout
|
||||
|
||||
<PageTitle>HopFrame</PageTitle>
|
||||
|
||||
<div style="padding: 1.5rem 1.5rem;">
|
||||
<h2>Tables</h2>
|
||||
<h2>Pages</h2>
|
||||
|
||||
<FluentStack Orientation="Orientation.Horizontal" Wrap="true" Style="margin-top: 1.5rem">
|
||||
@foreach (var view in _views) {
|
||||
<HopFrameCard
|
||||
Title="@view.Name"
|
||||
Subtitle="@view.Policy"
|
||||
Description="@view.Description"
|
||||
Href="@view.Url"
|
||||
Icon="HopFrameSideMenu.GetLinkIcon(view, IconVariant.Regular)"/>
|
||||
}
|
||||
|
||||
@foreach (var table in _tables.OrderBy(t => t.Order)) {
|
||||
<FluentCard Width="350px" Height="200px" Style="display: flex; flex-direction: column; background-color: var(--neutral-layer-1)">
|
||||
<h3 style="margin-bottom: 0;">@table.DisplayName</h3>
|
||||
<FluentLabel Typo="Typography.Body" Color="Color.Info" Style="margin-bottom: 0.5rem">@table.ViewPolicy</FluentLabel>
|
||||
<span>@table.Description</span>
|
||||
<FluentSpacer />
|
||||
<div style="display: flex">
|
||||
<FluentSpacer/>
|
||||
|
||||
<a href="@("/admin/" + table.DisplayName.ToLower())" style="display: inline-block">
|
||||
<FluentButton>Open</FluentButton>
|
||||
</a>
|
||||
</div>
|
||||
</FluentCard>
|
||||
<HopFrameCard
|
||||
Title="@table.DisplayName"
|
||||
Subtitle="@table.ViewPolicy"
|
||||
Description="@table.Description"
|
||||
Href="@("/admin/" + table.DisplayName.ToLower())"
|
||||
Icon="new Icons.Regular.Size24.Database()"/>
|
||||
}
|
||||
</FluentStack>
|
||||
</div>
|
||||
@@ -33,6 +36,7 @@
|
||||
@code {
|
||||
|
||||
private readonly List<TableConfig> _tables = [];
|
||||
private readonly List<CustomView> _views = [];
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
foreach (var table in Explorer.GetTables()) {
|
||||
@@ -40,6 +44,11 @@
|
||||
if (!await Handler.IsAuthenticatedAsync(table.ViewPolicy)) continue;
|
||||
_tables.Add(table);
|
||||
}
|
||||
|
||||
foreach (var view in HopFrameLayout.CustomViews) {
|
||||
if (!await Handler.IsAuthenticatedAsync(view.Policy)) continue;
|
||||
_views.Add(view);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
32
src/HopFrame.Web/HopFrameConfiguratorExtensions.cs
Normal file
32
src/HopFrame.Web/HopFrameConfiguratorExtensions.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Web.Components.Layout;
|
||||
using HopFrame.Web.Models;
|
||||
|
||||
namespace HopFrame.Web;
|
||||
|
||||
public static class HopFrameConfiguratorExtensions {
|
||||
|
||||
/// <summary>
|
||||
/// Creates an entry to the side menu and dashboard with a custom url
|
||||
/// </summary>
|
||||
/// <param name="configurator">The configurator for the HopFrame config that is being created</param>
|
||||
/// <param name="name">The name of the navigation entry</param>
|
||||
/// <param name="url">The target url of the navigation entry</param>
|
||||
public static CustomViewConfigurator AddCustomView(this HopFrameConfigurator configurator, string name, string url) {
|
||||
var view = new CustomView {
|
||||
Name = name,
|
||||
Url = url
|
||||
};
|
||||
HopFrameLayout.CustomViews.Add(view);
|
||||
return new CustomViewConfigurator(view);
|
||||
}
|
||||
|
||||
/// <param name="configuratorDelegate">The delegate for configuring the view</param>
|
||||
/// <inheritdoc cref="AddCustomView(HopFrame.Core.Config.HopFrameConfigurator,string,string)"/>
|
||||
public static HopFrameConfigurator AddCustomView(this HopFrameConfigurator configurator, string name, string url, Action<CustomViewConfigurator> configuratorDelegate) {
|
||||
var viewConfigurator = AddCustomView(configurator, name, url);
|
||||
configuratorDelegate.Invoke(viewConfigurator);
|
||||
return configurator;
|
||||
}
|
||||
|
||||
}
|
||||
54
src/HopFrame.Web/Models/CustomView.cs
Normal file
54
src/HopFrame.Web/Models/CustomView.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using Microsoft.AspNetCore.Components.Routing;
|
||||
using Microsoft.FluentUI.AspNetCore.Components;
|
||||
|
||||
namespace HopFrame.Web.Models;
|
||||
|
||||
public sealed class CustomView {
|
||||
public required string Name { get; init; }
|
||||
public string? Description { get; set; }
|
||||
public string? Policy { get; set; }
|
||||
public required string Url { get; init; }
|
||||
public string Icon { get; set; } = "Window";
|
||||
public NavLinkMatch LinkMatch { get; set; } = NavLinkMatch.All;
|
||||
}
|
||||
|
||||
public sealed class CustomViewConfigurator(CustomView view) {
|
||||
public CustomView InnerConfig { get; } = view;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the description displayed in the dashboard
|
||||
/// </summary>
|
||||
/// <param name="description">The desired description</param>
|
||||
public CustomViewConfigurator SetDescription(string description) {
|
||||
InnerConfig.Description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the policy needed in order to access the view
|
||||
/// </summary>
|
||||
/// <param name="policy">The desired policy</param>
|
||||
public CustomViewConfigurator SetPolicy(string policy) {
|
||||
InnerConfig.Policy = policy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the icon displayed in the sidebar
|
||||
/// </summary>
|
||||
/// <param name="icon">The desired <see href="https://www.fluentui-blazor.net/Icon#explorer">fluent-icon</see></param>
|
||||
public CustomViewConfigurator SetIcon(string icon) {
|
||||
InnerConfig.Icon = icon;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the rule for sidebar to determine if the link is active
|
||||
/// </summary>
|
||||
/// <param name="match">The desired match rule</param>
|
||||
public CustomViewConfigurator SetLinkMatch(NavLinkMatch match) {
|
||||
InnerConfig.LinkMatch = match;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user