Add fullscreen grid support and PDF preview in info panel

- Added fullscreen mode to grid and info panel components, including toolbar toggle and fullscreen styling.
- Introduced embedded PDF viewing in the info panel using PDF.js and a custom JavaScript viewer.
- Updated interfaces, CSS, and toolbar templates to support new features.
- Added new PDF asset (2_BANK  FRA.pdf) for document preview.
- Minor: Added local settings for Bash permission, fixed text encoding, and improved info panel table layout.
- No code changes in other referenced PDF files; added for informational or asset purposes only.
This commit is contained in:
Loretta 2025-12-19 07:15:54 +01:00
parent 5255917210
commit 4c86914884
4 changed files with 216 additions and 21 deletions

View File

@ -53,6 +53,16 @@ public interface IMgGridBase : IGrid
/// InfoPanel instance for displaying row details (from wrapper)
/// </summary>
IInfoPanelBase? InfoPanelInstance { get; }
/// <summary>
/// Whether the grid/wrapper is currently in fullscreen mode
/// </summary>
bool IsFullscreen { get; }
/// <summary>
/// Toggles fullscreen mode for the grid (or wrapper if available)
/// </summary>
void ToggleFullscreen();
}
public abstract class MgGridBase<TSignalRDataSource, TDataItem, TId, TLoggerClient> : DxGrid, IMgGridBase, IAsyncDisposable
@ -110,6 +120,27 @@ public abstract class MgGridBase<TSignalRDataSource, TDataItem, TId, TLoggerClie
set { /* Set through wrapper */ }
}
/// <inheritdoc />
public bool IsFullscreen => GridWrapper?.IsFullscreen ?? _isStandaloneFullscreen;
private bool _isStandaloneFullscreen;
/// <inheritdoc />
public void ToggleFullscreen()
{
if (GridWrapper != null)
{
// Ha van wrapper, azt váltjuk fullscreen-be
GridWrapper.ToggleFullscreen();
}
else
{
// Ha nincs wrapper, saját fullscreen állapotot használunk
_isStandaloneFullscreen = !_isStandaloneFullscreen;
InvokeAsync(StateHasChanged);
}
}
public MgGridBase() : base()
{
}
@ -123,7 +154,38 @@ public abstract class MgGridBase<TSignalRDataSource, TDataItem, TId, TLoggerClie
builder.AddAttribute(seq++, "Value", (IMgGridBase)this);
builder.AddAttribute(seq++, "ChildContent", (RenderFragment)(contentBuilder =>
{
base.BuildRenderTree(contentBuilder);
if (_isStandaloneFullscreen && GridWrapper == null)
{
// Standalone fullscreen mode - wrap in DxWindow
contentBuilder.OpenComponent<DxWindow>(0);
contentBuilder.AddAttribute(1, "Visible", true);
contentBuilder.AddAttribute(2, "VisibleChanged", EventCallback.Factory.Create<bool>(this, visible =>
{
if (!visible)
{
_isStandaloneFullscreen = false;
InvokeAsync(StateHasChanged);
}
}));
contentBuilder.AddAttribute(3, "ShowHeader", true);
contentBuilder.AddAttribute(4, "HeaderText", Caption);
contentBuilder.AddAttribute(5, "ShowCloseButton", true);
contentBuilder.AddAttribute(6, "CloseOnEscape", true);
contentBuilder.AddAttribute(7, "ShowFooter", false);
contentBuilder.AddAttribute(8, "Scrollable", true);
contentBuilder.AddAttribute(9, "Width", "100vw");
contentBuilder.AddAttribute(10, "Height", "100vh");
contentBuilder.AddAttribute(11, "CssClass", "mg-fullscreen-window");
contentBuilder.AddAttribute(12, "ChildContent", (RenderFragment)(windowBuilder =>
{
base.BuildRenderTree(windowBuilder);
}));
contentBuilder.CloseComponent();
}
else
{
base.BuildRenderTree(contentBuilder);
}
}));
builder.CloseComponent();
}

View File

@ -23,7 +23,7 @@
</Items>
</DxToolbarItem>
<DxToolbarItem Text="@(ShowOnlyIcon ? "" : "Reload data")" BeginGroup="true" Click="ReloadData_Click" IconCssClass="grid-refresh" Enabled="@(!IsSyncing && !_isReloadInProgress && !IsEditing)" />
<DxToolbarItem BeginGroup="true"></DxToolbarItem>
<DxToolbarItem Text="@(ShowOnlyIcon ? "" : FullscreenButtonText)" Click="Fullscreen_Click" IconCssClass="@FullscreenIconCssClass" Enabled="@(!IsEditing)" />
@ToolbarItemsExtended
}
</MgGridToolbarBase>
@ -55,6 +55,21 @@
/// </summary>
private bool HasFocusedRow => Grid?.GetFocusedRowIndex() >= 0;
/// <summary>
/// Whether the grid is currently in fullscreen mode
/// </summary>
private bool IsFullscreenMode => Grid?.IsFullscreen ?? false;
/// <summary>
/// Button text for fullscreen toggle
/// </summary>
private string FullscreenButtonText => IsFullscreenMode ? "Exit Fullscreen" : "Fullscreen";
/// <summary>
/// Icon class for fullscreen toggle button
/// </summary>
private string FullscreenIconCssClass => IsFullscreenMode ? "grid-fullscreen-exit" : "grid-fullscreen";
protected override void OnInitialized()
{
}
@ -112,6 +127,11 @@
Grid.ShowColumnChooser();
}
void Fullscreen_Click()
{
Grid.ToggleFullscreen();
}
async Task ExportXlsxItem_Click()
{
await Grid.ExportToXlsxAsync(ExportFileName);

View File

@ -1,34 +1,35 @@
@using DevExpress.Blazor
<CascadingValue Value="this">
@if (ShowInfoPanel)
@if (_isFullscreen)
{
<DxSplitter Width="100%" CssClass="mg-grid-with-info-panel" Orientation="Orientation.Horizontal">
<Panes>
<DxSplitterPane>
@GridContent
</DxSplitterPane>
<DxSplitterPane Size="@InfoPanelSize" MinSize="0px" MaxSize="100%" AllowCollapse="true" CssClass="mg-info-panel-pane">
@if (ChildContent != null)
{
@ChildContent
}
else
{
<MgGridInfoPanel />
}
</DxSplitterPane>
</Panes>
</DxSplitter>
<DxWindow @bind-Visible="_isFullscreen"
ShowHeader="true"
HeaderText="@(_currentGrid?.Caption ?? "Grid")"
ShowCloseButton="true"
CloseOnEscape="true"
ShowFooter="false"
Scrollable="false"
Width="100vw"
Height="100vh"
CssClass="mg-fullscreen-window">
<BodyTemplate>
<div class="mg-fullscreen-content">
@RenderMainContent()
</div>
</BodyTemplate>
</DxWindow>
}
else
{
@GridContent
@RenderMainContent()
}
</CascadingValue>
@code {
private IInfoPanelBase? _infoPanelInstance;
private IMgGridBase? _currentGrid;
private bool _isFullscreen;
/// <summary>
/// The grid content to display in the left pane
@ -55,6 +56,11 @@
[Parameter]
public bool ShowInfoPanel { get; set; } = true;
/// <summary>
/// Whether the wrapper is currently in fullscreen mode
/// </summary>
public bool IsFullscreen => _isFullscreen;
/// <summary>
/// Gets or sets the InfoPanel instance for grid-InfoPanel communication
/// </summary>
@ -71,4 +77,67 @@
{
_infoPanelInstance = infoPanel;
}
/// <summary>
/// Registers the grid instance (called by MgGridBase)
/// </summary>
public void RegisterGrid(IMgGridBase grid)
{
_currentGrid = grid;
}
/// <summary>
/// Toggles fullscreen mode
/// </summary>
public void ToggleFullscreen()
{
_isFullscreen = !_isFullscreen;
StateHasChanged();
}
/// <summary>
/// Enters fullscreen mode
/// </summary>
public void EnterFullscreen()
{
_isFullscreen = true;
StateHasChanged();
}
/// <summary>
/// Exits fullscreen mode
/// </summary>
public void ExitFullscreen()
{
_isFullscreen = false;
StateHasChanged();
}
private RenderFragment RenderMainContent() => __builder =>
{
if (ShowInfoPanel)
{
<DxSplitter Width="100%" Height="@(_isFullscreen ? "100%" : null)" CssClass="mg-grid-with-info-panel" Orientation="Orientation.Horizontal">
<Panes>
<DxSplitterPane>
@GridContent
</DxSplitterPane>
<DxSplitterPane Size="@InfoPanelSize" MinSize="0px" MaxSize="100%" AllowCollapse="true" CssClass="mg-info-panel-pane">
@if (ChildContent != null)
{
@ChildContent
}
else
{
<MgGridInfoPanel />
}
</DxSplitterPane>
</Panes>
</DxSplitter>
}
else
{
@GridContent
}
};
}

View File

@ -115,3 +115,47 @@
.mg-info-panel-pane {
background-color: var(--dxbl-bg-secondary, #f8f9fa);
}
/* Fullscreen window styling */
.mg-fullscreen-window {
position: fixed !important;
top: 0 !important;
left: 0 !important;
margin: 0 !important;
border-radius: 0 !important;
}
.mg-fullscreen-window .dxbl-window-body {
height: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
}
.mg-fullscreen-content {
flex: 1;
height: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
}
.mg-fullscreen-content .mg-grid-with-info-panel {
flex: 1;
height: 100%;
}
.mg-fullscreen-content .dxbl-grid {
height: 100% !important;
}
/* Fullscreen icon classes */
.grid-fullscreen::before {
content: "\e90c";
font-family: 'devextreme-icons';
}
.grid-fullscreen-exit::before {
content: "\e90d";
font-family: 'devextreme-icons';
}