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 #if RELEASE
public static string SystemEmailAddress = "test@touriam.com"; public static string SystemEmailAddress = "test@touriam.com";
public static LogLevel DefaultLogLevelClient = LogLevel.Error; public static LogLevel DefaultLogLevelClient = LogLevel.Debug;
#else #else
public static string SystemEmailAddress = "test@touriam.com"; public static string SystemEmailAddress = "test@touriam.com";
public static LogLevel DefaultLogLevelClient = LogLevel.Detail; public static LogLevel DefaultLogLevelClient = LogLevel.Detail;

View File

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

View File

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

View File

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

View File

@ -23,7 +23,9 @@
</BeforeColumnsTemplate> *@ </BeforeColumnsTemplate> *@
<AfterColumnsTemplate Context="ctx"> <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;"> <table class="table table-sm table-bordered table-striped" style="margin-top: 35px;">
<colgroup> <colgroup>
@ -68,16 +70,16 @@
</tr> </tr>
</tfoot> </tfoot>
</table> </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> </AfterColumnsTemplate>
@* <FooterTemplate Context="ctx"> @* <FooterTemplate Context="ctx">
@ -108,6 +110,8 @@
private async Task OnDataItemChangedAsync(object? dataItem) private async Task OnDataItemChangedAsync(object? dataItem)
{ {
@if (dataItem is not ShippingDocument && dataItem is not ShippingItem) return;
// Store the PDF to render // Store the PDF to render
_randomPdf = _pdfFiles[Random.Shared.Next(_pdfFiles.Length)]; _randomPdf = _pdfFiles[Random.Shared.Next(_pdfFiles.Length)];
_currentPdfToRender = $"_content/FruitBankHybrid.Shared/uploads/{_randomPdf}"; _currentPdfToRender = $"_content/FruitBankHybrid.Shared/uploads/{_randomPdf}";

View File

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

File diff suppressed because one or more lines are too long