Allow image previews

This commit is contained in:
Thorsten Sommer 2025-12-30 14:15:13 +01:00
parent 17b5d91a3d
commit 6cf14a57c7
Signed by: tsommer
GPG Key ID: 371BBA77A02C0108
4 changed files with 59 additions and 42 deletions

View File

@ -35,6 +35,11 @@ public record FileAttachment(FileAttachmentType Type, string FileName, string Fi
/// </remarks> /// </remarks>
public bool IsImage { get; } = Type == FileAttachmentType.IMAGE; public bool IsImage { get; } = Type == FileAttachmentType.IMAGE;
/// <summary>
/// Gets the file path formatted as a file URL (file:///).
/// </summary>
public string FilePathAsUrl { get; } = $"file:///{FilePath.Replace('\\', '/')}";
/// <summary> /// <summary>
/// Gets a value indicating whether the file still exists on the file system. /// Gets a value indicating whether the file still exists on the file system.
/// </summary> /// </summary>

View File

@ -219,7 +219,7 @@ public partial class AttachDocuments : MSGComponentBase
{ {
var dialogParameters = new DialogParameters<DocumentCheckDialog> var dialogParameters = new DialogParameters<DocumentCheckDialog>
{ {
{ x => x.FilePath, fileAttachment.FilePath }, { x => x.Document, fileAttachment },
}; };
await this.DialogService.ShowAsync<DocumentCheckDialog>(T("Document Preview"), dialogParameters, DialogOptions.FULLSCREEN); await this.DialogService.ShowAsync<DocumentCheckDialog>(T("Document Preview"), dialogParameters, DialogOptions.FULLSCREEN);

View File

@ -6,7 +6,7 @@
@T("See how we load your file. Review the content before we process it further.") @T("See how we load your file. Review the content before we process it further.")
</MudJustifiedText> </MudJustifiedText>
@if (string.IsNullOrWhiteSpace(this.FilePath)) @if (this.Document is null)
{ {
<ReadFileContent Text="@T("Load file")" @bind-FileContent="@this.FileContent"/> <ReadFileContent Text="@T("Load file")" @bind-FileContent="@this.FileContent"/>
} }
@ -14,7 +14,7 @@
{ {
<MudTextField <MudTextField
T="string" T="string"
@bind-Text="@this.FilePath" Text="@this.Document.FilePath"
AdornmentIcon="@Icons.Material.Filled.FileOpen" AdornmentIcon="@Icons.Material.Filled.FileOpen"
Adornment="Adornment.Start" Adornment="Adornment.Start"
Immediate="@true" Immediate="@true"
@ -28,37 +28,45 @@
} }
<MudTabs Elevation="0" Rounded="true" ApplyEffectsToContainer="true" Outlined="true" PanelClass="pa-2" Class="mb-2"> <MudTabs Elevation="0" Rounded="true" ApplyEffectsToContainer="true" Outlined="true" PanelClass="pa-2" Class="mb-2">
<MudTabPanel Text="@T("Markdown View")" Icon="@Icons.Material.Filled.TextSnippet"> @if (this.Document?.IsImage ?? false)
<MudField {
Variant="Variant.Outlined" <MudTabPanel Text="@T("Image View")" Icon="@Icons.Material.Filled.Image">
AdornmentIcon="@Icons.Material.Filled.Article" <MudImage ObjectFit="ObjectFit.ScaleDown" Src="@this.Document.FilePathAsUrl"/>
Adornment="Adornment.Start" </MudTabPanel>
Label="@T("Loaded Content")" }
FullWidth="true" else
Class="ma-2 pe-4" {
HelperText="@T("This is the content we loaded from your file — including headings, lists, and formatting. Use this to verify your file loads as expected.")" <MudTabPanel Text="@T("Markdown View")" Icon="@Icons.Material.Filled.TextSnippet">
> <MudField
<div style="max-height: 40vh; overflow-y: auto;"> Variant="Variant.Outlined"
<MudMarkdown Value="@this.FileContent" Props="Markdown.DefaultConfig" Styling="@this.MarkdownStyling"/> AdornmentIcon="@Icons.Material.Filled.Article"
</div> Adornment="Adornment.Start"
</MudField> Label="@T("Loaded Content")"
</MudTabPanel> FullWidth="true"
<MudTabPanel Text="@T("Simple View")" Icon="@Icons.Material.Filled.Terminal"> Class="ma-2 pe-4"
<MudTextField HelperText="@T("This is the content we loaded from your file — including headings, lists, and formatting. Use this to verify your file loads as expected.")">
T="string" <div style="max-height: 40vh; overflow-y: auto;">
@bind-Text="@this.FileContent" <MudMarkdown Value="@this.FileContent" Props="Markdown.DefaultConfig" Styling="@this.MarkdownStyling"/>
AdornmentIcon="@Icons.Material.Filled.Article" </div>
Adornment="Adornment.Start" </MudField>
Immediate="@true" </MudTabPanel>
Label="@T("Loaded Content")" <MudTabPanel Text="@T("Simple View")" Icon="@Icons.Material.Filled.Terminal">
Variant="Variant.Outlined" <MudTextField
Lines="6" T="string"
AutoGrow="@true" @bind-Text="@this.FileContent"
MaxLines="25" AdornmentIcon="@Icons.Material.Filled.Article"
ReadOnly="true" Adornment="Adornment.Start"
Class="ma-2" Immediate="@true"
HelperText="@T("This is the content we loaded from your file — including headings, lists, and formatting. Use this to verify your file loads as expected.")"/> Label="@T("Loaded Content")"
</MudTabPanel> Variant="Variant.Outlined"
Lines="6"
AutoGrow="@true"
MaxLines="25"
ReadOnly="true"
Class="ma-2"
HelperText="@T("This is the content we loaded from your file — including headings, lists, and formatting. Use this to verify your file loads as expected.")"/>
</MudTabPanel>
}
</MudTabs> </MudTabs>
</DialogContent> </DialogContent>

View File

@ -1,4 +1,5 @@
using AIStudio.Components; using AIStudio.Chat;
using AIStudio.Components;
using AIStudio.Tools.Services; using AIStudio.Tools.Services;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
@ -13,7 +14,7 @@ public partial class DocumentCheckDialog : MSGComponentBase
private IMudDialogInstance MudDialog { get; set; } = null!; private IMudDialogInstance MudDialog { get; set; } = null!;
[Parameter] [Parameter]
public string FilePath { get; set; } = string.Empty; public FileAttachment? Document { get; set; }
private void Close() => this.MudDialog.Cancel(); private void Close() => this.MudDialog.Cancel();
@ -31,23 +32,26 @@ public partial class DocumentCheckDialog : MSGComponentBase
protected override async Task OnAfterRenderAsync(bool firstRender) protected override async Task OnAfterRenderAsync(bool firstRender)
{ {
if (firstRender && !string.IsNullOrWhiteSpace(this.FilePath)) if (firstRender && this.Document is not null)
{ {
try try
{ {
var fileContent = await UserFile.LoadFileData(this.FilePath, this.RustService, this.DialogService); if (!this.Document.IsImage)
this.FileContent = fileContent; {
this.StateHasChanged(); var fileContent = await UserFile.LoadFileData(this.Document.FilePath, this.RustService, this.DialogService);
this.FileContent = fileContent;
this.StateHasChanged();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
this.Logger.LogError(ex, "Failed to load file content from '{FilePath}'", this.FilePath); this.Logger.LogError(ex, "Failed to load file content from '{FilePath}'", this.Document);
this.FileContent = string.Empty; this.FileContent = string.Empty;
this.StateHasChanged(); this.StateHasChanged();
} }
} }
else if (firstRender) else if (firstRender)
this.Logger.LogWarning("Document check dialog opened without a valid file path"); this.Logger.LogWarning("Document check dialog opened without a valid file path.");
} }
private CodeBlockTheme CodeColorPalette => this.SettingsManager.IsDarkMode ? CodeBlockTheme.Dark : CodeBlockTheme.Default; private CodeBlockTheme CodeColorPalette => this.SettingsManager.IsDarkMode ? CodeBlockTheme.Dark : CodeBlockTheme.Default;