Update dashboard navigation and dynamic loading
- Changed NavMenu to link to /dashboards instead of /dashboards/default - Refactored Dashboard.razor to list dashboards from API - Dashboard viewer/designer now loads by selected dashboard ID - Mode toggle preserves selected dashboard and mode - Added DashboardApiClient and DashboardInfoDto for API integration - Registered DashboardApiClient for DI and HTTP client setup in Program.cs
This commit is contained in:
@@ -22,7 +22,7 @@
|
|||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-item px-3">
|
<div class="nav-item px-3">
|
||||||
<NavLink class="nav-link" href="dashboards/default">
|
<NavLink class="nav-link" href="dashboards">
|
||||||
<span class="oi oi-list-rich" aria-hidden="true"></span> Dashboards
|
<span class="oi oi-list-rich" aria-hidden="true"></span> Dashboards
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
7
DbFirst.BlazorWasm/Models/DashboardInfoDto.cs
Normal file
7
DbFirst.BlazorWasm/Models/DashboardInfoDto.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace DbFirst.BlazorWasm.Models;
|
||||||
|
|
||||||
|
public class DashboardInfoDto
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
@page "/dashboards/{DashboardId?}"
|
@page "/dashboards/{DashboardId?}"
|
||||||
@inject Microsoft.Extensions.Configuration.IConfiguration Configuration
|
@inject Microsoft.Extensions.Configuration.IConfiguration Configuration
|
||||||
@inject NavigationManager Navigation
|
@inject NavigationManager Navigation
|
||||||
|
@inject DashboardApiClient DashboardApi
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.dashboard-shell {
|
.dashboard-shell {
|
||||||
@@ -48,7 +49,17 @@
|
|||||||
<div class="dashboard-shell">
|
<div class="dashboard-shell">
|
||||||
<aside class="dashboard-nav">
|
<aside class="dashboard-nav">
|
||||||
<div class="dashboard-nav-title">Dashboards</div>
|
<div class="dashboard-nav-title">Dashboards</div>
|
||||||
<NavLink class="dashboard-nav-link" href="dashboards/default">Default Dashboard</NavLink>
|
@if (dashboards.Count == 0)
|
||||||
|
{
|
||||||
|
<div class="px-3 py-2 text-muted">Keine Dashboards vorhanden.</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@foreach (var dashboard in dashboards)
|
||||||
|
{
|
||||||
|
<NavLink class="dashboard-nav-link" href="@($"dashboards/{dashboard.Id}")">@dashboard.Name</NavLink>
|
||||||
|
}
|
||||||
|
}
|
||||||
</aside>
|
</aside>
|
||||||
<section class="dashboard-content">
|
<section class="dashboard-content">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@@ -56,7 +67,7 @@
|
|||||||
@(IsDesigner ? "Zum Viewer wechseln" : "Zum Designer wechseln")
|
@(IsDesigner ? "Zum Viewer wechseln" : "Zum Designer wechseln")
|
||||||
</DxButton>
|
</DxButton>
|
||||||
</div>
|
</div>
|
||||||
<DxDashboard @key="DashboardKey" Endpoint="@DashboardEndpoint" InitialDashboardId="DefaultDashboard" WorkingMode="@CurrentMode" style="width: 100%; height: 800px;">
|
<DxDashboard @key="DashboardKey" Endpoint="@DashboardEndpoint" InitialDashboardId="@SelectedDashboardId" WorkingMode="@CurrentMode" style="width: 100%; height: 800px;">
|
||||||
</DxDashboard>
|
</DxDashboard>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@@ -65,24 +76,47 @@
|
|||||||
[Parameter] public string? DashboardId { get; set; }
|
[Parameter] public string? DashboardId { get; set; }
|
||||||
[SupplyParameterFromQuery] public string? Mode { get; set; }
|
[SupplyParameterFromQuery] public string? Mode { get; set; }
|
||||||
|
|
||||||
|
private readonly List<DashboardInfoDto> dashboards = new();
|
||||||
|
|
||||||
private bool IsDesigner => !string.Equals(Mode, "viewer", StringComparison.OrdinalIgnoreCase);
|
private bool IsDesigner => !string.Equals(Mode, "viewer", StringComparison.OrdinalIgnoreCase);
|
||||||
private WorkingMode CurrentMode => IsDesigner ? WorkingMode.Designer : WorkingMode.ViewerOnly;
|
private WorkingMode CurrentMode => IsDesigner ? WorkingMode.Designer : WorkingMode.ViewerOnly;
|
||||||
private string DashboardKey => $"DefaultDashboard-{(IsDesigner ? "designer" : "viewer")}";
|
private string SelectedDashboardId { get; set; } = "";
|
||||||
|
private string DashboardKey => $"{SelectedDashboardId}-{(IsDesigner ? "designer" : "viewer")}";
|
||||||
|
|
||||||
private string DashboardEndpoint => $"{Configuration["ApiBaseUrl"]?.TrimEnd('/')}/api/dashboard";
|
private string DashboardEndpoint => $"{Configuration["ApiBaseUrl"]?.TrimEnd('/')}/api/dashboard";
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
if (!string.Equals(DashboardId, "default", StringComparison.OrdinalIgnoreCase))
|
if (dashboards.Count == 0)
|
||||||
{
|
{
|
||||||
Navigation.NavigateTo("dashboards/default", replace: true);
|
dashboards.AddRange(await DashboardApi.GetAllAsync());
|
||||||
|
}
|
||||||
|
|
||||||
|
var requestedId = string.IsNullOrWhiteSpace(DashboardId) || string.Equals(DashboardId, "default", StringComparison.OrdinalIgnoreCase)
|
||||||
|
? null
|
||||||
|
: DashboardId;
|
||||||
|
|
||||||
|
var resolved = !string.IsNullOrWhiteSpace(requestedId)
|
||||||
|
? dashboards.FirstOrDefault(d => string.Equals(d.Id, requestedId, StringComparison.OrdinalIgnoreCase))
|
||||||
|
: dashboards.FirstOrDefault(d => string.Equals(d.Id, "DefaultDashboard", StringComparison.OrdinalIgnoreCase))
|
||||||
|
?? dashboards.FirstOrDefault();
|
||||||
|
|
||||||
|
if (resolved == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedDashboardId = resolved.Id;
|
||||||
|
|
||||||
|
if (!string.Equals(DashboardId, resolved.Id, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
Navigation.NavigateTo($"dashboards/{resolved.Id}?mode={(IsDesigner ? "designer" : "viewer")}", replace: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleMode()
|
private void ToggleMode()
|
||||||
{
|
{
|
||||||
var targetMode = IsDesigner ? "viewer" : "designer";
|
var targetMode = IsDesigner ? "viewer" : "designer";
|
||||||
Navigation.NavigateTo($"dashboards/default?mode={targetMode}", replace: true);
|
Navigation.NavigateTo($"dashboards/{SelectedDashboardId}?mode={targetMode}", replace: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,5 +17,6 @@ builder.Services.AddDevExpressBlazor();
|
|||||||
var apiBaseUrl = builder.Configuration["ApiBaseUrl"] ?? builder.HostEnvironment.BaseAddress;
|
var apiBaseUrl = builder.Configuration["ApiBaseUrl"] ?? builder.HostEnvironment.BaseAddress;
|
||||||
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(apiBaseUrl) });
|
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(apiBaseUrl) });
|
||||||
builder.Services.AddScoped<CatalogApiClient>();
|
builder.Services.AddScoped<CatalogApiClient>();
|
||||||
|
builder.Services.AddScoped<DashboardApiClient>();
|
||||||
|
|
||||||
await builder.Build().RunAsync();
|
await builder.Build().RunAsync();
|
||||||
|
|||||||
21
DbFirst.BlazorWasm/Services/DashboardApiClient.cs
Normal file
21
DbFirst.BlazorWasm/Services/DashboardApiClient.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Net.Http.Json;
|
||||||
|
using DbFirst.BlazorWasm.Models;
|
||||||
|
|
||||||
|
namespace DbFirst.BlazorWasm.Services;
|
||||||
|
|
||||||
|
public class DashboardApiClient
|
||||||
|
{
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
private const string Endpoint = "api/dashboard/dashboards";
|
||||||
|
|
||||||
|
public DashboardApiClient(HttpClient httpClient)
|
||||||
|
{
|
||||||
|
_httpClient = httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<DashboardInfoDto>> GetAllAsync()
|
||||||
|
{
|
||||||
|
var result = await _httpClient.GetFromJsonAsync<List<DashboardInfoDto>>(Endpoint);
|
||||||
|
return result ?? new List<DashboardInfoDto>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav-item px-3">
|
<div class="nav-item px-3">
|
||||||
<NavLink class="nav-link" href="dashboards/default">
|
<NavLink class="nav-link" href="dashboards">
|
||||||
<span class="oi oi-list-rich" aria-hidden="true"></span> Dashboards
|
<span class="oi oi-list-rich" aria-hidden="true"></span> Dashboards
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
@page "/dashboards/{DashboardId?}"
|
@page "/dashboards/{DashboardId?}"
|
||||||
@inject Microsoft.Extensions.Configuration.IConfiguration Configuration
|
@inject Microsoft.Extensions.Configuration.IConfiguration Configuration
|
||||||
@inject NavigationManager Navigation
|
@inject NavigationManager Navigation
|
||||||
|
@inject DashboardApiClient DashboardApi
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.dashboard-shell {
|
.dashboard-shell {
|
||||||
@@ -48,7 +49,17 @@
|
|||||||
<div class="dashboard-shell">
|
<div class="dashboard-shell">
|
||||||
<aside class="dashboard-nav">
|
<aside class="dashboard-nav">
|
||||||
<div class="dashboard-nav-title">Dashboards</div>
|
<div class="dashboard-nav-title">Dashboards</div>
|
||||||
<NavLink class="dashboard-nav-link" href="dashboards/default">Default Dashboard</NavLink>
|
@if (dashboards.Count == 0)
|
||||||
|
{
|
||||||
|
<div class="px-3 py-2 text-muted">Keine Dashboards vorhanden.</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@foreach (var dashboard in dashboards)
|
||||||
|
{
|
||||||
|
<NavLink class="dashboard-nav-link" href="@($"dashboards/{dashboard.Id}")">@dashboard.Name</NavLink>
|
||||||
|
}
|
||||||
|
}
|
||||||
</aside>
|
</aside>
|
||||||
<section class="dashboard-content">
|
<section class="dashboard-content">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@@ -56,7 +67,7 @@
|
|||||||
@(IsDesigner ? "Zum Viewer wechseln" : "Zum Designer wechseln")
|
@(IsDesigner ? "Zum Viewer wechseln" : "Zum Designer wechseln")
|
||||||
</DxButton>
|
</DxButton>
|
||||||
</div>
|
</div>
|
||||||
<DxDashboard @key="DashboardKey" Endpoint="@DashboardEndpoint" InitialDashboardId="DefaultDashboard" WorkingMode="@CurrentMode" style="width: 100%; height: 800px;">
|
<DxDashboard @key="DashboardKey" Endpoint="@DashboardEndpoint" InitialDashboardId="@SelectedDashboardId" WorkingMode="@CurrentMode" style="width: 100%; height: 800px;">
|
||||||
</DxDashboard>
|
</DxDashboard>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@@ -65,22 +76,47 @@
|
|||||||
[Parameter] public string? DashboardId { get; set; }
|
[Parameter] public string? DashboardId { get; set; }
|
||||||
[SupplyParameterFromQuery] public string? Mode { get; set; }
|
[SupplyParameterFromQuery] public string? Mode { get; set; }
|
||||||
|
|
||||||
|
private readonly List<DashboardInfoDto> dashboards = new();
|
||||||
|
|
||||||
private bool IsDesigner => !string.Equals(Mode, "viewer", StringComparison.OrdinalIgnoreCase);
|
private bool IsDesigner => !string.Equals(Mode, "viewer", StringComparison.OrdinalIgnoreCase);
|
||||||
private WorkingMode CurrentMode => IsDesigner ? WorkingMode.Designer : WorkingMode.ViewerOnly;
|
private WorkingMode CurrentMode => IsDesigner ? WorkingMode.Designer : WorkingMode.ViewerOnly;
|
||||||
private string DashboardKey => $"DefaultDashboard-{(IsDesigner ? "designer" : "viewer")}";
|
private string SelectedDashboardId { get; set; } = "";
|
||||||
|
private string DashboardKey => $"{SelectedDashboardId}-{(IsDesigner ? "designer" : "viewer")}";
|
||||||
|
|
||||||
private string DashboardEndpoint => $"{Configuration["ApiBaseUrl"]?.TrimEnd('/')}/api/dashboard";
|
private string DashboardEndpoint => $"{Configuration["ApiBaseUrl"]?.TrimEnd('/')}/api/dashboard";
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
if (!string.Equals(DashboardId, "default", StringComparison.OrdinalIgnoreCase))
|
if (dashboards.Count == 0)
|
||||||
{
|
{
|
||||||
Navigation.NavigateTo("dashboards/default", replace: true);
|
dashboards.AddRange(await DashboardApi.GetAllAsync());
|
||||||
|
}
|
||||||
|
|
||||||
|
var requestedId = string.IsNullOrWhiteSpace(DashboardId) || string.Equals(DashboardId, "default", StringComparison.OrdinalIgnoreCase)
|
||||||
|
? null
|
||||||
|
: DashboardId;
|
||||||
|
|
||||||
|
var resolved = !string.IsNullOrWhiteSpace(requestedId)
|
||||||
|
? dashboards.FirstOrDefault(d => string.Equals(d.Id, requestedId, StringComparison.OrdinalIgnoreCase))
|
||||||
|
: dashboards.FirstOrDefault(d => string.Equals(d.Id, "DefaultDashboard", StringComparison.OrdinalIgnoreCase))
|
||||||
|
?? dashboards.FirstOrDefault();
|
||||||
|
|
||||||
|
if (resolved == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedDashboardId = resolved.Id;
|
||||||
|
|
||||||
|
if (!string.Equals(DashboardId, resolved.Id, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
Navigation.NavigateTo($"dashboards/{resolved.Id}?mode={(IsDesigner ? "designer" : "viewer")}", replace: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleMode()
|
private void ToggleMode()
|
||||||
{
|
{
|
||||||
var targetMode = IsDesigner ? "viewer" : "designer";
|
var targetMode = IsDesigner ? "viewer" : "designer";
|
||||||
Navigation.NavigateTo($"dashboards/default?mode={targetMode}", replace: true);
|
Navigation.NavigateTo($"dashboards/{SelectedDashboardId}?mode={targetMode}", replace: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
7
DbFirst.BlazorWebApp/Models/DashboardInfoDto.cs
Normal file
7
DbFirst.BlazorWebApp/Models/DashboardInfoDto.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace DbFirst.BlazorWebApp.Models;
|
||||||
|
|
||||||
|
public class DashboardInfoDto
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
@@ -17,10 +17,15 @@ if (!string.IsNullOrWhiteSpace(apiBaseUrl))
|
|||||||
{
|
{
|
||||||
client.BaseAddress = new Uri(apiBaseUrl);
|
client.BaseAddress = new Uri(apiBaseUrl);
|
||||||
});
|
});
|
||||||
|
builder.Services.AddHttpClient<DashboardApiClient>(client =>
|
||||||
|
{
|
||||||
|
client.BaseAddress = new Uri(apiBaseUrl);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
builder.Services.AddHttpClient<CatalogApiClient>();
|
builder.Services.AddHttpClient<CatalogApiClient>();
|
||||||
|
builder.Services.AddHttpClient<DashboardApiClient>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|||||||
21
DbFirst.BlazorWebApp/Services/DashboardApiClient.cs
Normal file
21
DbFirst.BlazorWebApp/Services/DashboardApiClient.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Net.Http.Json;
|
||||||
|
using DbFirst.BlazorWebApp.Models;
|
||||||
|
|
||||||
|
namespace DbFirst.BlazorWebApp.Services;
|
||||||
|
|
||||||
|
public class DashboardApiClient
|
||||||
|
{
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
private const string Endpoint = "api/dashboard/dashboards";
|
||||||
|
|
||||||
|
public DashboardApiClient(HttpClient httpClient)
|
||||||
|
{
|
||||||
|
_httpClient = httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<DashboardInfoDto>> GetAllAsync()
|
||||||
|
{
|
||||||
|
var result = await _httpClient.GetFromJsonAsync<List<DashboardInfoDto>>(Endpoint);
|
||||||
|
return result ?? new List<DashboardInfoDto>();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user