Started working on editor dialog
This commit is contained in:
@@ -9,6 +9,8 @@ public class DatabaseContext(DbContextOptions<DatabaseContext> options) : DbCont
|
|||||||
|
|
||||||
public DbSet<Post> Posts { get; set; }
|
public DbSet<Post> Posts { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Typer> Typers { get; set; }
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder) {
|
protected override void OnModelCreating(ModelBuilder modelBuilder) {
|
||||||
base.OnModelCreating(modelBuilder);
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
@@ -22,5 +24,8 @@ public class DatabaseContext(DbContextOptions<DatabaseContext> options) : DbCont
|
|||||||
.HasMany(u => u.Posts)
|
.HasMany(u => u.Posts)
|
||||||
.WithOne(p => p.Sender)
|
.WithOne(p => p.Sender)
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
modelBuilder.Entity<Typer>()
|
||||||
|
.HasKey(t => t.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
23
debug/TestApplication/Models/Typer.cs
Normal file
23
debug/TestApplication/Models/Typer.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace TestApplication.Models;
|
||||||
|
|
||||||
|
public class Typer {
|
||||||
|
[Key]
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public int Number { get; set; }
|
||||||
|
public bool Toggle { get; set; }
|
||||||
|
public DateTime DateTime { get; set; }
|
||||||
|
public DateOnly DateOnly { get; set; }
|
||||||
|
public TimeOnly TimeOnly { get; set; }
|
||||||
|
public ListSortDirection SortDirection { get; set; }
|
||||||
|
public string? Text { get; set; }
|
||||||
|
[EmailAddress]
|
||||||
|
public string? Mail { get; set; }
|
||||||
|
public string? LongText { get; set; }
|
||||||
|
public string? Password { get; set; }
|
||||||
|
public string? PhoneNumber { get; set; }
|
||||||
|
public List<string> List { get; set; } = new();
|
||||||
|
public List<ListSortDirection> SortDirections { get; set; } = new();
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using HopFrame.Core.Configuration;
|
||||||
using HopFrame.Core.EFCore;
|
using HopFrame.Core.EFCore;
|
||||||
using HopFrame.Web;
|
using HopFrame.Web;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@@ -30,6 +31,17 @@ builder.Services.AddHopFrame(config => {
|
|||||||
config.Table<Post>(table => {
|
config.Table<Post>(table => {
|
||||||
table.SetDescription("The posts dataset. It contains all posts sent via the application.");
|
table.SetDescription("The posts dataset. It contains all posts sent via the application.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
config.Table<Typer>(table => {
|
||||||
|
table.Property(t => t.LongText)
|
||||||
|
.SetType(PropertyType.TextArea);
|
||||||
|
|
||||||
|
table.Property(t => t.Password)
|
||||||
|
.SetType(PropertyType.Password);
|
||||||
|
|
||||||
|
table.Property(t => t.PhoneNumber)
|
||||||
|
.SetType(PropertyType.PhoneNumber);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public class TableConfigurator<TModel>(TableConfig config) where TModel : class
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="Property(string)"/>
|
/// <inheritdoc cref="Property(string)"/>
|
||||||
public PropertyConfigurator Property(Expression<Func<TModel, object>> propertyExpression) {
|
public PropertyConfigurator Property(Expression<Func<TModel, object?>> propertyExpression) {
|
||||||
var propertyName = ExpressionHelper.GetPropertyInfo(propertyExpression).Name;
|
var propertyName = ExpressionHelper.GetPropertyInfo(propertyExpression).Name;
|
||||||
var prop = Config.Properties.FirstOrDefault(p => p.Identifier == propertyName);
|
var prop = Config.Properties.FirstOrDefault(p => p.Identifier == propertyName);
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ public class TableConfigurator<TModel>(TableConfig config) where TModel : class
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="TableConfig.PreferredProperty"/>
|
/// <inheritdoc cref="TableConfig.PreferredProperty"/>
|
||||||
public TableConfigurator<TModel> SetPreferredProperty(Expression<Func<TModel, object>> propertyExpression) {
|
public TableConfigurator<TModel> SetPreferredProperty(Expression<Func<TModel, object?>> propertyExpression) {
|
||||||
var propertyName = ExpressionHelper.GetPropertyInfo(propertyExpression).Name;
|
var propertyName = ExpressionHelper.GetPropertyInfo(propertyExpression).Name;
|
||||||
var prop = Config.Properties.FirstOrDefault(p => p.Identifier == propertyName);
|
var prop = Config.Properties.FirstOrDefault(p => p.Identifier == propertyName);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<MudDialog>
|
||||||
|
<TitleContent>
|
||||||
|
Confirm
|
||||||
|
</TitleContent>
|
||||||
|
<DialogContent>
|
||||||
|
Do you really want to delete this entry?
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<MudButton OnClick="@(Cancel)">Cancel</MudButton>
|
||||||
|
<MudButton OnClick="@(Submit)" Color="Color.Error">Delete</MudButton>
|
||||||
|
</DialogActions>
|
||||||
|
</MudDialog>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
[CascadingParameter]
|
||||||
|
private IMudDialogInstance MudDialog { get; set; } = null!;
|
||||||
|
|
||||||
|
private void Submit() => MudDialog.Close(DialogResult.Ok(true));
|
||||||
|
|
||||||
|
private void Cancel() => MudDialog.Cancel();
|
||||||
|
|
||||||
|
}
|
||||||
35
src/HopFrame.Web/Components/Components/Editor.razor
Normal file
35
src/HopFrame.Web/Components/Components/Editor.razor
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<MudDrawer
|
||||||
|
Anchor="Anchor.Right"
|
||||||
|
Elevation="1"
|
||||||
|
Variant="DrawerVariant.Temporary"
|
||||||
|
OverlayAutoClose="false"
|
||||||
|
@bind-Open="IsVisible"
|
||||||
|
Width="500px"
|
||||||
|
Breakpoint="Breakpoint.Always"
|
||||||
|
Style="@(IsVisible ? "display: flex" : "display: none")">
|
||||||
|
|
||||||
|
<MudStack Style="padding: 24px; height: 100%" Spacing="10">
|
||||||
|
<MudText Typo="Typo.h6">
|
||||||
|
@if (Mode == EditorMode.Creator) {
|
||||||
|
<span>Add @Config.TableType.Name</span>
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
<span>Edit @Config.TableType.Name</span>
|
||||||
|
}
|
||||||
|
</MudText>
|
||||||
|
|
||||||
|
<MudStack Spacing="5" Style="overflow-y: auto">
|
||||||
|
<MudFocusTrap>
|
||||||
|
@foreach (var property in GetProperties()) {
|
||||||
|
<PropertyInput Config="property" Variant="Variant.Filled" />
|
||||||
|
}
|
||||||
|
</MudFocusTrap>
|
||||||
|
</MudStack>
|
||||||
|
|
||||||
|
<MudStack Row="true" Style="margin-top: auto">
|
||||||
|
<MudButton Color="Color.Primary" OnClick="@(Submit)">Save</MudButton>
|
||||||
|
<MudButton OnClick="@(Cancel)">Cancel</MudButton>
|
||||||
|
</MudStack>
|
||||||
|
</MudStack>
|
||||||
|
|
||||||
|
</MudDrawer>
|
||||||
63
src/HopFrame.Web/Components/Components/Editor.razor.cs
Normal file
63
src/HopFrame.Web/Components/Components/Editor.razor.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using HopFrame.Core.Configuration;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using MudBlazor;
|
||||||
|
|
||||||
|
namespace HopFrame.Web.Components.Components;
|
||||||
|
|
||||||
|
public partial class Editor(IDialogService dialogs) : ComponentBase {
|
||||||
|
|
||||||
|
private enum EditorMode {
|
||||||
|
Editor,
|
||||||
|
Creator
|
||||||
|
}
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public required TableConfig Config { get; set; }
|
||||||
|
|
||||||
|
private bool IsVisible { get; set; }
|
||||||
|
|
||||||
|
private object? Entry { get; set; }
|
||||||
|
|
||||||
|
private EditorMode Mode { get; set; }
|
||||||
|
|
||||||
|
private TaskCompletionSource<object?> Completion { get; set; } = null!;
|
||||||
|
|
||||||
|
public Task<object?> Present(object? entry) {
|
||||||
|
Completion = new ();
|
||||||
|
Mode = entry is null ? EditorMode.Creator : EditorMode.Editor;
|
||||||
|
Entry = entry ?? Activator.CreateInstance(Config.TableType);
|
||||||
|
StateHasChanged();
|
||||||
|
IsVisible = true;
|
||||||
|
return Completion.Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Submit() {
|
||||||
|
var dialog = await dialogs.ShowAsync<ModifyConfirmationDialog>();
|
||||||
|
var result = await dialog.Result;
|
||||||
|
|
||||||
|
if (result is not null && !result.Canceled) {
|
||||||
|
ApplyChanges();
|
||||||
|
IsVisible = false;
|
||||||
|
Completion.SetResult(Entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel() {
|
||||||
|
IsVisible = false;
|
||||||
|
Completion.SetResult(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<PropertyConfig> GetProperties() {
|
||||||
|
var query = (IEnumerable<PropertyConfig>)Config.Properties;
|
||||||
|
|
||||||
|
if (Mode == EditorMode.Creator)
|
||||||
|
query = query.Where(p => p.Creatable);
|
||||||
|
|
||||||
|
return query.OrderBy(p => p.OrderIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyChanges() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<MudDialog>
|
||||||
|
<TitleContent>
|
||||||
|
Confirm
|
||||||
|
</TitleContent>
|
||||||
|
<DialogContent>
|
||||||
|
Do you really want to save the changes?
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<MudButton OnClick="@(Cancel)">Cancel</MudButton>
|
||||||
|
<MudButton OnClick="@(Submit)" Color="Color.Primary">Save</MudButton>
|
||||||
|
</DialogActions>
|
||||||
|
</MudDialog>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
[CascadingParameter]
|
||||||
|
private IMudDialogInstance MudDialog { get; set; } = null!;
|
||||||
|
|
||||||
|
private void Submit() => MudDialog.Close(DialogResult.Ok(true));
|
||||||
|
|
||||||
|
private void Cancel() => MudDialog.Cancel();
|
||||||
|
|
||||||
|
}
|
||||||
106
src/HopFrame.Web/Components/Components/PropertyInput.razor
Normal file
106
src/HopFrame.Web/Components/Components/PropertyInput.razor
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
@using HopFrame.Core.Configuration
|
||||||
|
|
||||||
|
@switch ((PropertyType)((byte)Config.PropertyType & 0x0F)) {
|
||||||
|
case PropertyType.Numeric:
|
||||||
|
<MudNumericField
|
||||||
|
T="double"
|
||||||
|
Label="@Config.DisplayName"
|
||||||
|
Required="@((Config.PropertyType & PropertyType.Nullable) != 0)"
|
||||||
|
Disabled="@(!Config.Editable)"
|
||||||
|
Variant="Variant"/>
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyType.Boolean:
|
||||||
|
<MudSwitch
|
||||||
|
T="bool"
|
||||||
|
Label="@Config.DisplayName"
|
||||||
|
Required="@((Config.PropertyType & PropertyType.Nullable) != 0)"
|
||||||
|
Disabled="@(!Config.Editable)"/>
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyType.DateTime:
|
||||||
|
<MudField Label="@Config.DisplayName" Variant="Variant.Outlined" Style="display: flex">
|
||||||
|
<MudStack Row="true">
|
||||||
|
<MudDatePicker
|
||||||
|
Label="Date"
|
||||||
|
Required="@((Config.PropertyType & PropertyType.Nullable) != 0)"
|
||||||
|
Disabled="@(!Config.Editable)"
|
||||||
|
Variant="Variant"/>
|
||||||
|
|
||||||
|
<MudTimePicker
|
||||||
|
Label="Time"
|
||||||
|
Required="@((Config.PropertyType & PropertyType.Nullable) != 0)"
|
||||||
|
Disabled="@(!Config.Editable)"
|
||||||
|
Variant="Variant"/>
|
||||||
|
</MudStack>
|
||||||
|
</MudField>
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyType.DateOnly:
|
||||||
|
<MudDatePicker
|
||||||
|
Label="@Config.DisplayName"
|
||||||
|
Required="@((Config.PropertyType & PropertyType.Nullable) != 0)"
|
||||||
|
Disabled="@(!Config.Editable)"
|
||||||
|
Variant="Variant"/>
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyType.TimeOnly:
|
||||||
|
<MudTimePicker
|
||||||
|
Label="@Config.DisplayName"
|
||||||
|
Required="@((Config.PropertyType & PropertyType.Nullable) != 0)"
|
||||||
|
Disabled="@(!Config.Editable)"
|
||||||
|
Variant="Variant"/>
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyType.Email:
|
||||||
|
<MudTextField
|
||||||
|
T="string"
|
||||||
|
InputType="InputType.Email"
|
||||||
|
Label="@Config.DisplayName"
|
||||||
|
Required="@((Config.PropertyType & PropertyType.Nullable) != 0)"
|
||||||
|
Disabled="@(!Config.Editable)"
|
||||||
|
Variant="Variant"/>
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyType.Password:
|
||||||
|
<MudTextField
|
||||||
|
T="string"
|
||||||
|
InputType="InputType.Password"
|
||||||
|
Label="@Config.DisplayName"
|
||||||
|
Required="@((Config.PropertyType & PropertyType.Nullable) != 0)"
|
||||||
|
Disabled="@(!Config.Editable)"
|
||||||
|
Variant="Variant"/>
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PropertyType.PhoneNumber:
|
||||||
|
<MudTextField
|
||||||
|
T="string"
|
||||||
|
InputType="InputType.Telephone"
|
||||||
|
Label="@Config.DisplayName"
|
||||||
|
Required="@((Config.PropertyType & PropertyType.Nullable) != 0)"
|
||||||
|
Disabled="@(!Config.Editable)"
|
||||||
|
Variant="Variant"/>
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
<MudTextField
|
||||||
|
T="string"
|
||||||
|
Label="@Config.DisplayName"
|
||||||
|
Required="@((Config.PropertyType & PropertyType.Nullable) != 0)"
|
||||||
|
Disabled="@(!Config.Editable)"
|
||||||
|
Variant="Variant"/>
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public object? Value { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public required PropertyConfig Config { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public Variant Variant { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
@rendermode InteractiveServer
|
@rendermode InteractiveServer
|
||||||
|
|
||||||
<MudTable ServerData="Reload"
|
<MudTable ServerData="ReloadTable"
|
||||||
@ref="Manager"
|
@ref="Manager"
|
||||||
Hover="true"
|
Hover="true"
|
||||||
Breakpoint="Breakpoint.Sm"
|
Breakpoint="Breakpoint.Sm"
|
||||||
@@ -25,7 +25,11 @@
|
|||||||
Clearable="true"
|
Clearable="true"
|
||||||
DebounceInterval="200"
|
DebounceInterval="200"
|
||||||
OnDebounceIntervalElapsed="@(s => OnSearch(s))"/>
|
OnDebounceIntervalElapsed="@(s => OnSearch(s))"/>
|
||||||
<MudButton EndIcon="@Icons.Material.Filled.Add" Style="margin-right: 0.5rem">Add</MudButton>
|
<MudButton EndIcon="@Icons.Material.Filled.Add"
|
||||||
|
Style="margin-right: 0.5rem"
|
||||||
|
OnClick="@(OnAddClick)">
|
||||||
|
Add
|
||||||
|
</MudButton>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
</ToolBarContent>
|
</ToolBarContent>
|
||||||
<HeaderContent>
|
<HeaderContent>
|
||||||
@@ -45,13 +49,13 @@
|
|||||||
</HeaderContent>
|
</HeaderContent>
|
||||||
<RowTemplate>
|
<RowTemplate>
|
||||||
@foreach (var prop in OrderedProperties) {
|
@foreach (var prop in OrderedProperties) {
|
||||||
<MudTd DataLabel="@prop.DisplayName" Style="text-overflow: ellipsis; white-space: nowrap; overflow: hidden; max-width: 500px">@context[prop.Identifier]</MudTd>
|
<MudTd DataLabel="@prop.DisplayName" Style="text-overflow: ellipsis; white-space: nowrap; overflow: hidden; max-width: 500px">@context.Columns[prop.Identifier]</MudTd>
|
||||||
}
|
}
|
||||||
|
|
||||||
<MudTd DataLabel="Actions">
|
<MudTd DataLabel="Actions">
|
||||||
<MudStack Row="true" Spacing="1">
|
<MudStack Row="true" Spacing="1">
|
||||||
<MudIconButton Icon="@Icons.Material.Filled.Edit" Size="Size.Small" />
|
<MudIconButton Icon="@Icons.Material.Filled.Edit" Size="Size.Small" OnClick="@(async () => await OnEditClick(context.Entry))" />
|
||||||
<MudIconButton Icon="@Icons.Material.Filled.Delete" Size="Size.Small" Color="Color.Error" />
|
<MudIconButton Icon="@Icons.Material.Filled.Delete" Size="Size.Small" Color="Color.Error" OnClick="@(async () => await OnDeleteClick(context.Entry))" />
|
||||||
</MudStack>
|
</MudStack>
|
||||||
</MudTd>
|
</MudTd>
|
||||||
</RowTemplate>
|
</RowTemplate>
|
||||||
|
|||||||
@@ -8,14 +8,28 @@ namespace HopFrame.Web.Components.Components;
|
|||||||
|
|
||||||
public partial class Table(IEntityAccessor accessor, IConfigAccessor configAccessor) : ComponentBase {
|
public partial class Table(IEntityAccessor accessor, IConfigAccessor configAccessor) : ComponentBase {
|
||||||
|
|
||||||
|
private readonly struct TableEntry {
|
||||||
|
public object Entry { get; init; }
|
||||||
|
public Dictionary<string, string> Columns { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public required TableConfig Config { get; set; }
|
public required TableConfig Config { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public EventCallback OnAdd { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public EventCallback<object> OnDelete { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public EventCallback<object> OnEdit { get; set; }
|
||||||
|
|
||||||
private IHopFrameRepository Repository { get; set; } = null!;
|
private IHopFrameRepository Repository { get; set; } = null!;
|
||||||
|
|
||||||
private PropertyConfig[] OrderedProperties { get; set; } = null!;
|
private PropertyConfig[] OrderedProperties { get; set; } = null!;
|
||||||
|
|
||||||
private MudTable<Dictionary<string, string>> Manager { get; set; } = null!;
|
private MudTable<TableEntry> Manager { get; set; } = null!;
|
||||||
|
|
||||||
private Dictionary<string, MudTableSortLabel<object>> SortDirections { get; set; } = new();
|
private Dictionary<string, MudTableSortLabel<object>> SortDirections { get; set; } = new();
|
||||||
|
|
||||||
@@ -38,22 +52,18 @@ public partial class Table(IEntityAccessor accessor, IConfigAccessor configAcces
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Dictionary<string, string>> PrepareData(object[] entries) {
|
public Task Reload() => Manager.ReloadServerData();
|
||||||
var list = new List<Dictionary<string, string>>();
|
|
||||||
|
private Dictionary<string, string> PrepareData(object entry) {
|
||||||
foreach (var entry in entries) {
|
var dict = new Dictionary<string, string>();
|
||||||
var dict = new Dictionary<string, string>();
|
foreach (var prop in OrderedProperties) {
|
||||||
foreach (var prop in OrderedProperties) {
|
dict.Add(prop.Identifier, accessor.GetValue(entry, prop) ?? string.Empty);
|
||||||
dict.Add(prop.Identifier, accessor.GetValue(entry, prop) ?? string.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
list.Add(dict);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<TableData<Dictionary<string, string>>> Reload(TableState state, CancellationToken ct) {
|
private async Task<TableData<TableEntry>> ReloadTable(TableState state, CancellationToken ct) {
|
||||||
IEnumerable<object> entries;
|
IEnumerable<object> entries;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(_searchText))
|
if (string.IsNullOrWhiteSpace(_searchText))
|
||||||
@@ -65,11 +75,14 @@ public partial class Table(IEntityAccessor accessor, IConfigAccessor configAcces
|
|||||||
var sortProp = Config.Properties.First(p => p.Identifier == _currentSort.Value.Key);
|
var sortProp = Config.Properties.First(p => p.Identifier == _currentSort.Value.Key);
|
||||||
entries = accessor.SortDataByProperty(entries, sortProp, _currentSort.Value.Value == SortDirection.Descending);
|
entries = accessor.SortDataByProperty(entries, sortProp, _currentSort.Value.Value == SortDirection.Descending);
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = PrepareData(entries.ToArray());
|
var data = entries.Select(e => new TableEntry {
|
||||||
|
Entry = e,
|
||||||
|
Columns = PrepareData(e)
|
||||||
|
});
|
||||||
var total = await Repository.CountAsync(ct);
|
var total = await Repository.CountAsync(ct);
|
||||||
|
|
||||||
return new TableData<Dictionary<string, string>> {
|
return new TableData<TableEntry> {
|
||||||
TotalItems = total,
|
TotalItems = total,
|
||||||
Items = data
|
Items = data
|
||||||
};
|
};
|
||||||
@@ -80,7 +93,11 @@ public partial class Table(IEntityAccessor accessor, IConfigAccessor configAcces
|
|||||||
await Manager.ReloadServerData();
|
await Manager.ReloadServerData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool _currentlyReloading;
|
||||||
private async Task OnSort(PropertyConfig property, SortDirection direction) {
|
private async Task OnSort(PropertyConfig property, SortDirection direction) {
|
||||||
|
if (_currentlyReloading) return;
|
||||||
|
_currentlyReloading = true;
|
||||||
|
|
||||||
if (direction != SortDirection.None) {
|
if (direction != SortDirection.None) {
|
||||||
foreach (var reference in SortDirections
|
foreach (var reference in SortDirections
|
||||||
.Where(d => d.Key != property.Identifier)) {
|
.Where(d => d.Key != property.Identifier)) {
|
||||||
@@ -98,5 +115,21 @@ public partial class Table(IEntityAccessor accessor, IConfigAccessor configAcces
|
|||||||
}
|
}
|
||||||
|
|
||||||
await Manager.ReloadServerData();
|
await Manager.ReloadServerData();
|
||||||
|
_currentlyReloading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnAddClick() {
|
||||||
|
if (OnAdd.HasDelegate)
|
||||||
|
await OnAdd.InvokeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnEditClick(object entry) {
|
||||||
|
if (OnEdit.HasDelegate)
|
||||||
|
await OnEdit.InvokeAsync(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnDeleteClick(object entry) {
|
||||||
|
if (OnDelete.HasDelegate)
|
||||||
|
await OnDelete.InvokeAsync(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,11 +2,19 @@
|
|||||||
@using HopFrame.Web.Components.Components
|
@using HopFrame.Web.Components.Components
|
||||||
@rendermode InteractiveServer
|
@rendermode InteractiveServer
|
||||||
@layout HopFrameLayout
|
@layout HopFrameLayout
|
||||||
|
@inherits CancellableComponent
|
||||||
|
|
||||||
<MudPopoverProvider />
|
<MudPopoverProvider />
|
||||||
<MudDialogProvider />
|
<MudDialogProvider />
|
||||||
<MudSnackbarProvider/>
|
<MudSnackbarProvider />
|
||||||
|
|
||||||
<PageTitle>HopFrame - @Table.DisplayName</PageTitle>
|
<PageTitle>HopFrame - @Table.DisplayName</PageTitle>
|
||||||
|
|
||||||
<Table Config="Table"></Table>
|
<Editor Config="Table" @ref="EditorComponent"></Editor>
|
||||||
|
|
||||||
|
<Table
|
||||||
|
Config="Table"
|
||||||
|
OnAdd="@(OnAdd)"
|
||||||
|
OnEdit="@(OnEdit)"
|
||||||
|
OnDelete="@(OnDelete)"
|
||||||
|
@ref="TableComponent"></Table>
|
||||||
|
|||||||
@@ -1,16 +1,24 @@
|
|||||||
using HopFrame.Core.Configuration;
|
using HopFrame.Core.Configuration;
|
||||||
|
using HopFrame.Core.Repositories;
|
||||||
using HopFrame.Core.Services;
|
using HopFrame.Core.Services;
|
||||||
|
using HopFrame.Web.Components.Components;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using MudBlazor;
|
||||||
|
|
||||||
namespace HopFrame.Web.Components.Pages;
|
namespace HopFrame.Web.Components.Pages;
|
||||||
|
|
||||||
public partial class TablePage(IConfigAccessor accessor, NavigationManager navigator) : ComponentBase {
|
public partial class TablePage(IConfigAccessor accessor, NavigationManager navigator, IDialogService dialogs, ISnackbar snackbar) : CancellableComponent {
|
||||||
private const int PerPage = 25;
|
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string TableRoute { get; set; } = null!;
|
public string TableRoute { get; set; } = null!;
|
||||||
|
|
||||||
public TableConfig Table { get; set; } = null!;
|
private TableConfig Table { get; set; } = null!;
|
||||||
|
|
||||||
|
private IHopFrameRepository Repository { get; set; } = null!;
|
||||||
|
|
||||||
|
private Table TableComponent { get; set; } = null!;
|
||||||
|
|
||||||
|
private Editor EditorComponent { get; set; } = null!;
|
||||||
|
|
||||||
protected override void OnInitialized() {
|
protected override void OnInitialized() {
|
||||||
base.OnInitialized();
|
base.OnInitialized();
|
||||||
@@ -23,5 +31,36 @@ public partial class TablePage(IConfigAccessor accessor, NavigationManager navig
|
|||||||
}
|
}
|
||||||
|
|
||||||
Table = table;
|
Table = table;
|
||||||
|
Repository = accessor.LoadRepository(table);
|
||||||
|
snackbar.Configuration.PositionClass = Defaults.Classes.Position.BottomLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnAdd() {
|
||||||
|
var entry = await EditorComponent.Present(null);
|
||||||
|
if (entry is null) return;
|
||||||
|
|
||||||
|
await Repository.CreateGenericAsync(entry, TokenSource.Token);
|
||||||
|
await TableComponent.Reload();
|
||||||
|
snackbar.Add("Entry added", Severity.Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnEdit(object entry) {
|
||||||
|
var newEntry = await EditorComponent.Present(entry);
|
||||||
|
if (newEntry is null) return;
|
||||||
|
|
||||||
|
await Repository.UpdateGenericAsync(newEntry, TokenSource.Token);
|
||||||
|
await TableComponent.Reload();
|
||||||
|
snackbar.Add("Entry updated", Severity.Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnDelete(object entry) {
|
||||||
|
var dialog = await dialogs.ShowAsync<DeleteConfirmationDialog>();
|
||||||
|
var result = await dialog.Result;
|
||||||
|
|
||||||
|
if (result is not null && !result.Canceled) {
|
||||||
|
await Repository.DeleteGenericAsync(entry, TokenSource.Token);
|
||||||
|
await TableComponent.Reload();
|
||||||
|
snackbar.Add("Entry deleted", Severity.Success);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user