Add AI process modal to shipping grid with toolbar button

Added an "AI process" toolbar button to the shipping document grid, styled with a new magic/sparkles icon. Clicking the button opens a large modal (DxWindow) containing an iframe-based AI processing form (AiProcessFormTemplate). The modal reloads grid data on close. Also includes related CSS for the icon, minor grid layout logic improvements, and retains commented file upload code for reference.
This commit is contained in:
Loretta 2025-12-23 15:22:52 +01:00
parent e61c605b11
commit 7efc649d0b
3 changed files with 60 additions and 5 deletions

View File

@ -2,6 +2,7 @@
@using AyCode.Utils.Extensions @using AyCode.Utils.Extensions
@using FruitBank.Common.Dtos @using FruitBank.Common.Dtos
@using FruitBank.Common.Entities @using FruitBank.Common.Entities
@* @using FruitBankHybrid.Shared.Components.FileUploads *@
@using FruitBankHybrid.Shared.Components.Grids.ShippingDocuments @using FruitBankHybrid.Shared.Components.Grids.ShippingDocuments
@using FruitBankHybrid.Shared.Databases @using FruitBankHybrid.Shared.Databases
@using FruitBankHybrid.Shared.Services.SignalRs @using FruitBankHybrid.Shared.Services.SignalRs
@ -99,11 +100,15 @@
{ {
<MgGridToolbarTemplate Grid="Grid" OnReloadDataClick="() => ReloadDataFromDb(true)"> <MgGridToolbarTemplate Grid="Grid" OnReloadDataClick="() => ReloadDataFromDb(true)">
<ToolbarItemsExtended> <ToolbarItemsExtended>
<DxToolbarItem BeginGroup="true"> @* <DxToolbarItem BeginGroup="true">
<Template Context="ctxToolbarItemFileUpload"> <Template Context="ctxToolbarItemFileUpload">
<FileUpload OnFileUploaded="OnFileUploaded"></FileUpload> <FileUpload OnFileUploaded="OnFileUploaded"></FileUpload>
</Template> </Template>
</DxToolbarItem> </DxToolbarItem>
*@
<DxToolbarItem BeginGroup="true" Text="Ai process..." IconCssClass="grid-ai" Click="Callback">
</DxToolbarItem>
</ToolbarItemsExtended> </ToolbarItemsExtended>
</MgGridToolbarTemplate> </MgGridToolbarTemplate>
} }
@ -126,6 +131,25 @@
</ChildContent> </ChildContent>
</MgGridWithInfoPanel> </MgGridWithInfoPanel>
<DxWindow @ref=windowRef
AllowResize="false"
ShowCloseButton="true"
CloseOnEscape="true"
ShowHeader="true"
HeaderText="Ai process..."
ShowFooter="false"
SizeMode="SizeMode.Large"
Width="95vw"
Height="95vh"
Closing="Callback2"
@bind-Visible=windowVisible>
@* <HeaderTemplate Context="dfgsdf">
<DxButton CssClass="popup-button my-1 ms-2" RenderStyle="ButtonRenderStyle.Primary" Text="Bezár" Click="@dfgsdf.CloseCallback" />
</HeaderTemplate>
*@ <BodyContentTemplate Context="ctxAiProcessBody">
<AiProcessFormTemplate />
</BodyContentTemplate>
</DxWindow>
@code { @code {
[Inject] public required DatabaseClient Database { get; set; } [Inject] public required DatabaseClient Database { get; set; }
[Inject] public required LoggedInModel LoggedInModel { get; set; } [Inject] public required LoggedInModel LoggedInModel { get; set; }
@ -148,6 +172,10 @@
string GridSearchText = ""; string GridSearchText = "";
bool EditItemsEnabled { get; set; } = true; bool EditItemsEnabled { get; set; } = true;
int FocusedRowVisibleIndex { get; set; } int FocusedRowVisibleIndex { get; set; }
private DxWindow windowRef;
private bool windowVisible;
public GridShippingDocumentBase Grid { get; set; } public GridShippingDocumentBase Grid { get; set; }
private LoggerClient<GridShippingDocument> _logger = null!; private LoggerClient<GridShippingDocument> _logger = null!;
private int _activeTabIndex; private int _activeTabIndex;
@ -196,7 +224,8 @@
if (Grid == null) return; if (Grid == null) return;
using (await ObjectLock.GetSemaphore<ShippingDocument>().UseWaitAsync()) using (await ObjectLock.GetSemaphore<ShippingDocument>().UseWaitAsync())
if (forceReload) await Grid.ReloadDataSourceAsync(); if (forceReload)
await Grid.ReloadDataSourceAsync();
if (forceReload) Grid.Reload(); if (forceReload) Grid.Reload();
} }
@ -233,4 +262,18 @@
{ {
_activeTabIndex = activeTabIndex; _activeTabIndex = activeTabIndex;
} }
private async Task Callback(ToolbarItemClickEventArgs obj)
{
if (windowVisible)
await windowRef.CloseAsync();
else
await windowRef.ShowAsync();
}
private void Callback2(WindowClosingEventArgs obj)
{
ReloadDataFromDb(true).Forget();
}
} }

View File

@ -0,0 +1,4 @@
<iframe src="https://localhost:59579/Admin/FileManager/ImageTextExtraction" title="Ai process form" width="100%" height="100%"></iframe>
@code {
}

View File

@ -170,7 +170,8 @@ h1:focus {
.grid-export-pdf, .grid-export-pdf,
.grid-refresh, .grid-refresh,
.grid-fullscreen, .grid-fullscreen,
.grid-fullscreen-exit { .grid-fullscreen-exit,
.grid-ai {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -193,7 +194,8 @@ h1:focus {
.grid-export-pdf::before, .grid-export-pdf::before,
.grid-refresh::before, .grid-refresh::before,
.grid-fullscreen::before, .grid-fullscreen::before,
.grid-fullscreen-exit::before { .grid-fullscreen-exit::before,
.grid-ai::before {
content: ""; content: "";
display: inline-block; display: inline-block;
width: 1.25rem; width: 1.25rem;
@ -316,6 +318,12 @@ h1:focus {
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2'%3E%3Cpolyline points='4 14 10 14 10 20'/%3E%3Cpolyline points='20 10 14 10 14 4'/%3E%3Cline x1='14' y1='10' x2='21' y2='3'/%3E%3Cline x1='3' y1='21' x2='10' y2='14'/%3E%3C/svg%3E"); -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2'%3E%3Cpolyline points='4 14 10 14 10 20'/%3E%3Cpolyline points='20 10 14 10 14 4'/%3E%3Cline x1='14' y1='10' x2='21' y2='3'/%3E%3Cline x1='3' y1='21' x2='10' y2='14'/%3E%3C/svg%3E");
} }
/* AI icon (sparkles/magic) */
.grid-ai::before {
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2'%3E%3Cpath d='M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3z'/%3E%3Cpath d='M5 19l1 3 1-3 3-1-3-1-1-3-1 3-3 1 3 1z'/%3E%3Cpath d='M19 11l.5 1.5 1.5.5-1.5.5-.5 1.5-.5-1.5L17 13l1.5-.5.5-1.5z'/%3E%3C/svg%3E");
-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2'%3E%3Cpath d='M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3z'/%3E%3Cpath d='M5 19l1 3 1-3 3-1-3-1-1-3-1 3-3 1 3 1z'/%3E%3Cpath d='M19 11l.5 1.5 1.5.5-1.5.5-.5 1.5-.5-1.5L17 13l1.5-.5.5-1.5z'/%3E%3C/svg%3E");
}
/* ======================================== /* ========================================
MgGrid Splitter with InfoPanel MgGrid Splitter with InfoPanel
InfoPanel sticky via JavaScript InfoPanel sticky via JavaScript