LayerDetails page
All checks were successful
Build Docker Images / test (push) Successful in 1m18s
Build Docker Images / build-and-push (push) Successful in 1m39s

This commit is contained in:
2025-11-20 21:03:19 +01:00
parent 090224b19f
commit 7558bb80e3
9 changed files with 294 additions and 39 deletions

View File

@@ -29,7 +29,7 @@
</MudCardHeader>
<MudCardContent>
<MudText Typo="Typo.body2">
Zalogowano przez Google
Signed in via Google
</MudText>
</MudCardContent>
</MudCard>
@@ -37,6 +37,6 @@
else
{
<MudAlert Severity="Severity.Warning" Class="mt-4">
Nie jesteś zalogowany
You are not logged in
</MudAlert>
}

View File

@@ -1,25 +1,25 @@
@using MudBlazor.Internal
<MudExpansionPanels Class="mb-4">
<MudExpansionPanel Icon="@Icons.Material.Filled.FilterList"
Text="Filtry"
Text="Filters"
Expanded="true">
<MudGrid>
<MudItem xs="12" sm="6" md="4">
<MudTextField @bind-Value="filterRequest.Search"
Label="Szukaj"
Placeholder="Nazwa, numer..."
Label="Search"
Placeholder="Name, number..."
Immediate="true"
DebounceInterval="500"
OnDebounceIntervalElapsed="SearchLayers"
Clearable="true"/>
</MudItem>
<MudItem xs="12" sm="6" md="4">
<MudButton Variant="Variant.Outlined"
OnClick="ClearFilters"
StartIcon="Icons.Material.Filled.Clear">
Wyczyść filtry
Clear filters
</MudButton>
</MudItem>
</MudGrid>
@@ -32,7 +32,10 @@
Dense="true"
Hover="true"
Loading="isLoading"
LoadingProgressColor="Color.Info">
LoadingProgressColor="Color.Info"
OnRowClick="@((TableRowClickEventArgs<LayerDto> args) => OnRowClick(args.Item))"
T="LayerDto"
Style="cursor: pointer;">
<HeaderContent>
<MudTh>Name</MudTh>
<MudTh>Type</MudTh>
@@ -45,7 +48,7 @@
<MudText>No layers to display</MudText>
</NoRecordsContent>
<LoadingContent>
Ładowanie...
Loading...
</LoadingContent>
</MudTable>
@@ -54,8 +57,8 @@
<MudGrid Class="mt-4" AlignItems="Center.Center">
<MudItem xs="12" sm="6">
<MudText Typo="Typo.body2">
Wyniki @((layers.Page - 1) * layers.PageSize + 1) - @Math.Min(layers.Page * layers.PageSize, layers.TotalCount)
z @layers.TotalCount
Results @((layers.Page - 1) * layers.PageSize + 1) - @Math.Min(layers.Page * layers.PageSize, layers.TotalCount)
of @layers.TotalCount
</MudText>
</MudItem>
<MudItem xs="12" sm="6" Class="d-flex justify-end">

View File

@@ -6,10 +6,11 @@ using MudBlazor;
namespace DiunaBI.UI.Shared.Components;
public partial class LayerListComponent : ComponentBase
public partial class LayerListComponent : ComponentBase
{
[Inject] private LayerService LayerService { get; set; } = default!;
[Inject] private ISnackbar Snackbar { get; set; } = default!;
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
private PagedResult<LayerDto> layers = new();
@@ -54,6 +55,11 @@ public partial class LayerListComponent : ComponentBase
private async Task ClearFilters()
{
filterRequest = new LayerFilterRequest();
await LoadLayers();
await LoadLayers();
}
private void OnRowClick(LayerDto layer)
{
NavigationManager.NavigateTo($"/layers/{layer.Id}");
}
}

View File

@@ -8,11 +8,11 @@
<MudCard Class="login-card" Elevation="8">
<MudCardContent Class="pa-8 d-flex flex-column align-center">
<MudText Typo="Typo.h4" Class="mb-4">Witaj w DiunaBI</MudText>
<MudText Typo="Typo.h4" Class="mb-4">Welcome to DiunaBI</MudText>
<MudText Typo="Typo.body1" Class="mb-6 text-center">
Zaloguj się używając konta Google
Sign in using your Google account
</MudText>
<MudButton
Variant="Variant.Filled"
StartIcon="@Icons.Custom.Brands.Google"
@@ -22,11 +22,11 @@
@if (_isLoading)
{
<MudProgressCircular Class="mr-3" Size="Size.Small" Indeterminate="true"></MudProgressCircular>
<span>Weryfikacja...</span>
<span>Verifying...</span>
}
else
{
<span>Zaloguj z Google</span>
<span>Sign in with Google</span>
}
</MudButton>
@@ -76,7 +76,7 @@
}
catch (Exception ex)
{
_errorMessage = "Błąd inicjalizacji Google Sign-In.";
_errorMessage = "Google Sign-In initialization error.";
Console.Error.WriteLine($"❌ Google Sign-In initialization error: {ex.Message}");
Console.Error.WriteLine($"Stack trace: {ex.StackTrace}");
}
@@ -89,12 +89,12 @@
_isLoading = true;
_errorMessage = string.Empty;
StateHasChanged();
await JS.InvokeVoidAsync("requestGoogleSignIn");
}
catch (Exception ex)
{
_errorMessage = "Błąd podczas logowania. Spróbuj ponownie";
_errorMessage = "Login error. Please try again";
_isLoading = false;
StateHasChanged();
}
@@ -124,16 +124,16 @@
{
Console.WriteLine($"❌ Validation failed: {errorMessage}");
_instance._isLoading = false;
_instance._errorMessage = errorMessage ?? "Nie udało się zalogować.";
_instance._errorMessage = errorMessage ?? "Login failed.";
}
await _instance.InvokeAsync(() => _instance.StateHasChanged());
}
catch (Exception ex)
{
Console.Error.WriteLine($"❌ OnGoogleSignInSuccess error: {ex.Message}");
_instance._isLoading = false;
_instance._errorMessage = "Błąd podczas weryfikacji użytkownika.";
_instance._errorMessage = "User verification error.";
await _instance.InvokeAsync(() => _instance.StateHasChanged());
}
}
@@ -147,7 +147,7 @@
if (_instance != null)
{
_instance._isLoading = false;
_instance._errorMessage = "Błąd logowania Google. Spróbuj ponownie";
_instance._errorMessage = "Google login error. Please try again";
await _instance.InvokeAsync(() => _instance.StateHasChanged());
}
}

View File

@@ -2,7 +2,7 @@
@inherits LayoutComponentBase
<AuthGuard>
<MudThemeProvider/>
<MudThemeProvider Theme="_theme"/>
<MudDialogProvider/>
<MudSnackbarProvider/>
@@ -44,6 +44,18 @@
private bool _drawerOpen = true;
private DrawerVariant _drawerVariant = DrawerVariant.Persistent;
private MudTheme _theme = new MudTheme()
{
PaletteLight = new PaletteLight()
{
Primary = "#e7163d",
PrimaryDarken = "#c01234",
PrimaryLighten = "#f04366",
Secondary = "#424242",
AppbarBackground = "#e7163d",
}
};
void ToggleDrawer()
{
Console.WriteLine($"ToogleDrawer clickkk {DateTime.Now}");

View File

@@ -0,0 +1,112 @@
@page "/layers/{id:guid}"
@using DiunaBI.UI.Shared.Services
@using DiunaBI.Application.DTOModels
@using MudBlazor
@inject LayerService LayerService
@inject NavigationManager NavigationManager
<MudCard>
<MudCardHeader>
<CardHeaderContent>
<MudText Typo="Typo.h5">Layer Details</MudText>
</CardHeaderContent>
<CardHeaderActions>
<MudButton Variant="Variant.Text" OnClick="Export">Export</MudButton>
@if (layer != null && layer.Type == LayerType.Administration)
{
<MudButton Variant="Variant.Text" Href="@($"/layers/edit/{layer.Id}/duplicate")">Duplicate</MudButton>
<MudButton Variant="Variant.Text" Href="@($"/layers/edit/{layer.Id}")">Edit</MudButton>
}
@if (layer != null && layer.Type == LayerType.Processed)
{
<MudButton Variant="Variant.Text" OnClick="ProcessLayer">Process Layer</MudButton>
}
</CardHeaderActions>
</MudCardHeader>
<MudCardContent>
@if (isLoading)
{
<MudProgressLinear Color="Color.Primary" Indeterminate="true" />
}
else if (layer == null)
{
<MudAlert Severity="Severity.Error">Layer not found</MudAlert>
}
else
{
<MudGrid>
<MudItem xs="12" md="6">
<MudTextField @bind-Value="layer.Name"
Label="Name"
Variant="Variant.Outlined"
ReadOnly="true"
FullWidth="true"/>
</MudItem>
<MudItem xs="12" md="6">
@if (layer.IsCancelled)
{
<MudAlert Severity="Severity.Warning" Dense="true">
This layer is cancelled. Will not be used in any further processing.
</MudAlert>
}
</MudItem>
<MudItem xs="12" md="6">
<MudTextField Value="@layer.CreatedAt.ToString("g")"
Label="Created"
Variant="Variant.Outlined"
ReadOnly="true"
FullWidth="true"
Adornment="Adornment.End"
AdornmentText="@(layer.CreatedBy?.Username ?? "")"/>
</MudItem>
<MudItem xs="12" md="6">
<MudTextField Value="@layer.ModifiedAt.ToString("g")"
Label="Modified"
Variant="Variant.Outlined"
ReadOnly="true"
FullWidth="true"
Adornment="Adornment.End"
AdornmentText="@(layer.ModifiedBy?.Username ?? "")"/>
</MudItem>
</MudGrid>
<MudDivider Class="my-4"/>
<MudTable Items="@records"
Dense="true"
Striped="true"
FixedHeader="true"
FixedFooter="true"
Height="600px">
<HeaderContent>
<MudTh>Code</MudTh>
@foreach (var column in displayedColumns)
{
<MudTh>@column</MudTh>
}
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Code">@context.Code</MudTd>
@foreach (var column in displayedColumns)
{
<MudTd DataLabel="@column">@GetRecordValue(context, column)</MudTd>
}
</RowTemplate>
<FooterContent>
<MudTd><b>Value1 sum</b></MudTd>
@foreach (var column in displayedColumns)
{
@if (column == "Value1")
{
<MudTd><b>@valueSum.ToString("N2")</b></MudTd>
}
else
{
<MudTd></MudTd>
}
}
</FooterContent>
</MudTable>
}
</MudCardContent>
</MudCard>

View File

@@ -0,0 +1,122 @@
using DiunaBI.Application.DTOModels;
using Microsoft.AspNetCore.Components;
using MudBlazor;
using System.Reflection;
namespace DiunaBI.UI.Shared.Pages;
public partial class LayerDetailPage : ComponentBase
{
[Parameter]
public Guid Id { get; set; }
[Inject]
private ISnackbar Snackbar { get; set; } = null!;
private LayerDto? layer;
private List<RecordDto> records = new();
private List<string> displayedColumns = new();
private double valueSum = 0;
private bool isLoading = false;
protected override async Task OnInitializedAsync()
{
await LoadLayer();
}
protected override async Task OnParametersSetAsync()
{
await LoadLayer();
}
private async Task LoadLayer()
{
isLoading = true;
StateHasChanged();
try
{
layer = await LayerService.GetLayerByIdAsync(Id);
if (layer != null && layer.Records != null)
{
records = layer.Records;
CalculateDisplayedColumns();
CalculateValueSum();
}
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error loading layer: {ex.Message}");
Snackbar.Add("Error loading layer", Severity.Error);
}
finally
{
isLoading = false;
StateHasChanged();
}
}
private void CalculateDisplayedColumns()
{
displayedColumns.Clear();
// Check which Value columns have data
for (int i = 1; i <= 32; i++)
{
var columnName = $"Value{i}";
var hasData = records.Any(r => GetRecordValueByName(r, columnName) != null);
if (hasData)
{
displayedColumns.Add(columnName);
}
}
// Check if Desc1 has data
if (records.Any(r => !string.IsNullOrEmpty(r.Desc1)))
{
displayedColumns.Add("Description1");
}
}
private void CalculateValueSum()
{
valueSum = records
.Where(r => r.Value1.HasValue)
.Sum(r => r.Value1!.Value);
}
private string GetRecordValue(RecordDto record, string columnName)
{
if (columnName == "Description1")
{
return record.Desc1 ?? string.Empty;
}
var value = GetRecordValueByName(record, columnName);
return value.HasValue ? value.Value.ToString("N2") : string.Empty;
}
private double? GetRecordValueByName(RecordDto record, string columnName)
{
var property = typeof(RecordDto).GetProperty(columnName, BindingFlags.Public | BindingFlags.Instance);
if (property != null && property.PropertyType == typeof(double?))
{
return property.GetValue(record) as double?;
}
return null;
}
private void Export()
{
// TODO: Implement export functionality
Snackbar.Add("Export functionality coming soon", Severity.Error);
}
private void ProcessLayer()
{
// TODO: Implement process layer functionality
Snackbar.Add("Process layer functionality coming soon", Severity.Error);
}
}

View File

@@ -68,25 +68,25 @@ public class AuthService
else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
Console.WriteLine("❌ User not found in DiunaBI database");
return (false, "Użytkownik nie istnieje w bazie DiunaBI.");
return (false, "User does not exist in DiunaBI database.");
}
else
{
Console.WriteLine($"❌ Backend error: {response.StatusCode}");
return (false, "Błąd serwera DiunaBI. Spróbuj ponownie.");
return (false, "DiunaBI server error. Please try again.");
}
return (false, "Nieoczekiwany błąd.");
return (false, "Unexpected error.");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"❌ Network error: {ex.Message}");
return (false, "Nie można połączyć się z serwerem DiunaBI.");
return (false, "Cannot connect to DiunaBI server.");
}
catch (Exception ex)
{
Console.WriteLine($"❌ Validation error: {ex.Message}");
return (false, "Błąd podczas weryfikacji użytkownika.");
return (false, "User verification error.");
}
}
@@ -105,9 +105,9 @@ public class AuthService
{
_apiToken = token;
_userInfo = JsonSerializer.Deserialize<UserInfo>(userInfoJson);
// Przywróć header
_httpClient.DefaultRequestHeaders.Authorization =
// Restore header
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _apiToken);
Console.WriteLine($"✅ Session restored: {_userInfo?.Email}");

View File

@@ -3,17 +3,17 @@ html, body {
}
a, .btn-link {
color: #006bb7;
color: #e7163d;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
background-color: #e7163d;
border-color: #c01234;
}
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #e7163d;
}
.content {