Add user layout management to grids with toolbar actions

- Introduced separate auto-save and user-save layout storage keys
- Added IMgGridBase methods for saving, loading, resetting, and checking user layouts
- Updated grid toolbar with "Layout" menu (load, save, reset) and new icons
- Improved layout persistence logic and default layout restore
- Enabled forced grid re-render on layout reset
- Adjusted grid pager and page size defaults
- Updated related components to use new storage keys
- Fixed minor bugs and set RELEASE log level to Debug
This commit is contained in:
Loretta 2025-12-23 11:10:19 +01:00
parent 22821a4b27
commit 3a14b570ef
7 changed files with 109 additions and 60 deletions

View File

@ -107,7 +107,7 @@ public static class FruitBankConstClient
#if RELEASE
public static string SystemEmailAddress = "test@touriam.com";
public static LogLevel DefaultLogLevelClient = LogLevel.Error;
public static LogLevel DefaultLogLevelClient = LogLevel.Debug;
#else
public static string SystemEmailAddress = "test@touriam.com";
public static LogLevel DefaultLogLevelClient = LogLevel.Detail;

View File

@ -20,7 +20,7 @@
<MgGridWithInfoPanel ShowInfoPanel="@IsMasterGrid">
<GridContent>
<GridProductDto @ref="Grid" DataSource="ProductDtos" CssClass="@GridCss" AutoSaveLayoutName="GridProductDtoTemplate"
Logger="_logger" SignalRClient="FruitBankSignalRClient">
Logger="_logger" SignalRClient="FruitBankSignalRClient" Caption="Termék(ek)">
<Columns>
<MgGridDataColumn FieldName="Id" SortIndex="0" SortOrder="GridColumnSortOrder.Ascending"
UrlLink=@(FruitBankConstClient.BaseUrl + "/Admin/Product/Edit/{Id}") />

View File

@ -73,8 +73,8 @@ public class FruitBankGridBase<TDataItem> : MgGridBase<SignalRDataSourceObservab
AutoCollapseDetailRow = true;
AutoExpandAllGroupRows = false;
PagerVisible = IsMasterGrid;
PageSize = IsMasterGrid ? (SizeMode == DevExpress.Blazor.SizeMode.Small ? 23 : 15) : 50;
PagerVisible = true;//IsMasterGrid;
PageSize = IsMasterGrid ? (SizeMode == DevExpress.Blazor.SizeMode.Small ? 20 : 15) : 10;
AllowColumnReorder = true;
AllowGroup = IsMasterGrid;

View File

@ -22,7 +22,6 @@
Logger="_logger"
CssClass="@GridCss"
ValidationEnabled="false"
ShowInfoPanel="true"
OnGridFocusedRowChanged="Grid_FocusedRowChanged">
<Columns>
<DxGridDataColumn FieldName="Id" SortIndex="0" SortOrder="GridColumnSortOrder.Descending" ReadOnly="true" />

View File

@ -23,7 +23,9 @@
</BeforeColumnsTemplate> *@
<AfterColumnsTemplate Context="ctx">
@if (ctx is { IsEditMode: false, DataItem: ShippingDocument doc })
@if (ctx.DataItem is not ShippingDocument && ctx.DataItem is not ShippingItem) return;
@if (ctx is { DataItem: ShippingDocument doc, IsEditMode: false })
{
<table class="table table-sm table-bordered table-striped" style="margin-top: 35px;">
<colgroup>
@ -68,16 +70,16 @@
</tr>
</tfoot>
</table>
<MgLazyLoadContent @ref="_lazyContentRef"
MinHeight="800px"
RootMargin="50px"
OnContentVisible="OnPdfContainerVisibleAsync"
ContainerStyle="margin-top: 30px;">
<div id="pdfContainer" style="width: 100%; height: 800px; overflow-y: auto;">
</div>
</MgLazyLoadContent>
}
<MgLazyLoadContent @ref="_lazyContentRef"
MinHeight="800px"
RootMargin="50px"
OnContentVisible="OnPdfContainerVisibleAsync"
ContainerStyle="margin-top: 30px;">
<div id="pdfContainer" style="width: 100%; height: 800px; overflow-y: auto;">
</div>
</MgLazyLoadContent>
</AfterColumnsTemplate>
@* <FooterTemplate Context="ctx">
@ -108,6 +110,8 @@
private async Task OnDataItemChangedAsync(object? dataItem)
{
@if (dataItem is not ShippingDocument && dataItem is not ShippingItem) return;
// Store the PDF to render
_randomPdf = _pdfFiles[Random.Shared.Next(_pdfFiles.Length)];
_currentPdfToRender = $"_content/FruitBankHybrid.Shared/uploads/{_randomPdf}";

View File

@ -47,7 +47,9 @@ public class MgGridBase : DxGrid, IMgGridBase
/// <inheritdoc />
public bool IsFullscreen => false;
public string LayoutStorageKey { get; }
public string AutomaticLayoutStorageKey => $"{AutoSaveLayoutName}_Master_AutoSave_{LoggedInModel.CustomerDto?.Id ?? 0}";
private string UserLayoutStorageKey => AutomaticLayoutStorageKey.Replace("_AutoSave_", "_UserSave_");
/// <inheritdoc />
public void ToggleFullscreen()
@ -141,8 +143,8 @@ public class MgGridBase : DxGrid, IMgGridBase
AutoCollapseDetailRow = true;
AutoExpandAllGroupRows = false;
PagerVisible = IsMasterGrid;
PageSize = IsMasterGrid ? (SizeMode == DevExpress.Blazor.SizeMode.Small ? 23 : 15) : 50;
PagerVisible = true; //IsMasterGrid;
PageSize = IsMasterGrid ? (SizeMode == DevExpress.Blazor.SizeMode.Small ? 20 : 15) : 10;
AllowColumnReorder = true;
AllowGroup = IsMasterGrid;
@ -204,12 +206,12 @@ public class MgGridBase : DxGrid, IMgGridBase
async Task Grid_LayoutAutoLoading(GridPersistentLayoutEventArgs e)
{
e.Layout = await LoadLayoutFromLocalStorageAsync($"{AutoSaveLayoutName}_AutoSave_{LoggedInModel.CustomerDto?.Id ?? 0}");
e.Layout = await LoadLayoutFromLocalStorageAsync(AutomaticLayoutStorageKey);
}
private async Task Grid_LayoutAutoSaving(GridPersistentLayoutEventArgs e)
{
await SaveLayoutToLocalStorageAsync(e.Layout, $"{AutoSaveLayoutName}_AutoSave_{LoggedInModel.CustomerDto?.Id ?? 0}");
await SaveLayoutToLocalStorageAsync(e.Layout, AutomaticLayoutStorageKey);
}
async Task<GridPersistentLayout?> LoadLayoutFromLocalStorageAsync(string localStorageKey)
@ -227,6 +229,7 @@ public class MgGridBase : DxGrid, IMgGridBase
return null;
}
async Task SaveLayoutToLocalStorageAsync(GridPersistentLayout layout, string localStorageKey)
{
try
@ -243,54 +246,49 @@ public class MgGridBase : DxGrid, IMgGridBase
{
try
{
await JSRuntime.InvokeVoidAsync("localStorage.removeItem", AutoSaveLayoutName);
await JSRuntime.InvokeVoidAsync("localStorage.removeItem", AutomaticLayoutStorageKey);
}
catch
{
// Mute exceptions for the server prerender stage
}
}
async Task ReloadPageButton_ClickAsync()
/// <inheritdoc />
public async Task SaveUserLayoutAsync()
{
await JSRuntime.InvokeVoidAsync("location.reload");
var layout = SaveLayout();
await SaveLayoutToLocalStorageAsync(layout, UserLayoutStorageKey);
}
async Task ResetLayoutButton_ClickAsync()
/// <inheritdoc />
public async Task LoadUserLayoutAsync()
{
var layout = await LoadLayoutFromLocalStorageAsync(UserLayoutStorageKey);
if (layout != null)
{
LoadLayout(layout);
}
}
/// <inheritdoc />
public async Task ResetLayoutAsync()
{
await RemoveLayoutFromLocalStorageAsync();
await JSRuntime.InvokeVoidAsync("location.reload");
}
//public RenderFragment AddCommandColumn()
//{
// RenderFragment columns = b =>
// {
// if (!IsMasterGrid)
// {
// b.OpenComponent(0, typeof(DxGridCommandColumn));
// b.CloseComponent();
// }
// };
// this.Columns.ApplyChain(x) = AddCommandColumn();
// return columns;
//}
//private RenderFragment BuildColumnsGrid()
//{
// PropertyInfo[] props = DataSource.FirstOrDefault().GetType().GetProperties();
// RenderFragment columns = b =>
// {
// foreach (var prop in props)
// {
// if (prop.PropertyType == typeof(string))
// {
// b.OpenComponent(0, typeof(DxGridDataColumn));
// b.AddAttribute(0, "FieldName", prop.Name);
// b.CloseComponent();
// }
// }
// };
// return columns;
//}
/// <inheritdoc />
public async Task<bool> HasUserLayoutAsync()
{
try
{
var value = await JSRuntime.InvokeAsync<string>("localStorage.getItem", UserLayoutStorageKey);
return !string.IsNullOrWhiteSpace(value);
}
catch
{
return false;
}
}
}

File diff suppressed because one or more lines are too long