2025-05-30 09:04:16 +00:00
using System.Reflection ;
using AIStudio.Tools.Metadata ;
using AIStudio.Tools.Services ;
2025-05-29 12:01:56 +00:00
using Microsoft.AspNetCore.Components ;
2025-05-30 09:04:16 +00:00
using SharedTools ;
2025-05-29 12:01:56 +00:00
namespace AIStudio.Dialogs ;
public partial class PandocDialog : ComponentBase
{
2025-05-30 09:04:16 +00:00
private static readonly Assembly ASSEMBLY = Assembly . GetExecutingAssembly ( ) ;
private static readonly MetaDataArchitectureAttribute META_DATA_ARCH = ASSEMBLY . GetCustomAttribute < MetaDataArchitectureAttribute > ( ) ! ;
private static readonly RID CPU_ARCHITECTURE = META_DATA_ARCH . Architecture . ToRID ( ) ;
2025-05-29 12:01:56 +00:00
[Inject]
private HttpClient HttpClient { get ; set ; } = null ! ;
[Inject]
private RustService RustService { get ; init ; } = null ! ;
[Inject]
protected IJSRuntime JsRuntime { get ; init ; } = null ! ;
[Inject]
private IDialogService DialogService { get ; init ; } = null ! ;
[CascadingParameter]
private IMudDialogInstance MudDialog { get ; set ; } = null ! ;
private static readonly ILogger LOG = Program . LOGGER_FACTORY . CreateLogger ( "PandocDialog" ) ;
2025-05-29 19:31:41 +00:00
private static readonly string LICENCE_URI = "https://raw.githubusercontent.com/jgm/pandoc/refs/heads/main/COPYING.md" ;
private static string PANDOC_VERSION = string . Empty ;
2025-05-29 12:01:56 +00:00
private bool isPandocAvailable ;
private bool showSkeleton ;
private bool showInstallPage ;
private string? licenseText ;
private bool isLoading ;
2025-05-30 09:16:53 +00:00
private int selectedArchiveIndex = SelectArchiveIndex ( ) ;
2025-05-29 12:01:56 +00:00
#region Overrides of ComponentBase
protected override async Task OnInitializedAsync ( )
{
await base . OnInitializedAsync ( ) ;
2025-05-29 19:32:25 +00:00
2025-05-29 12:01:56 +00:00
this . showSkeleton = true ;
await this . CheckPandocAvailabilityAsync ( ) ;
PANDOC_VERSION = await Pandoc . FetchLatestVersionAsync ( ) ;
}
#endregion
private void Cancel ( ) = > this . MudDialog . Cancel ( ) ;
private async Task CheckPandocAvailabilityAsync ( )
{
2025-05-29 14:12:20 +00:00
var pandocInstallation = await Pandoc . CheckAvailabilityAsync ( this . RustService ) ;
this . isPandocAvailable = pandocInstallation . IsAvailable ;
2025-05-29 12:01:56 +00:00
this . showSkeleton = false ;
2025-05-29 19:32:25 +00:00
2025-05-29 12:01:56 +00:00
await this . InvokeAsync ( this . StateHasChanged ) ;
}
private async Task InstallPandocAsync ( )
{
await Pandoc . InstallAsync ( this . RustService ) ;
this . MudDialog . Close ( DialogResult . Ok ( true ) ) ;
2025-05-29 19:32:25 +00:00
2025-05-29 12:01:56 +00:00
await this . DialogService . ShowAsync < PandocDialog > ( "pandoc dialog" ) ;
}
private void ProceedToInstallation ( ) = > this . showInstallPage = true ;
private async Task GetInstaller ( )
{
var uri = await Pandoc . GenerateInstallerUriAsync ( ) ;
var filename = this . FilenameFromUri ( uri ) ;
2025-05-29 19:32:25 +00:00
2025-05-29 12:01:56 +00:00
await this . JsRuntime . InvokeVoidAsync ( "triggerDownload" , uri , filename ) ;
}
private async Task GetArchive ( )
{
2025-05-29 12:55:09 +00:00
var uri = await Pandoc . GenerateArchiveUriAsync ( ) ;
2025-05-29 12:01:56 +00:00
var filename = this . FilenameFromUri ( uri ) ;
2025-05-29 19:32:25 +00:00
2025-05-29 12:01:56 +00:00
await this . JsRuntime . InvokeVoidAsync ( "triggerDownload" , uri , filename ) ;
}
private async Task RejectLicense ( )
{
var message = "Pandoc is open-source and free of charge, but if you reject Pandoc's license, it can not be installed and some of AIStudios data retrieval features will be disabled (e.g. using Office files like Word)." +
"This decision can be revoked at any time. Are you sure you want to reject the license?" ;
var dialogParameters = new DialogParameters
{
{ "Message" , message } ,
} ;
var dialogReference = await this . DialogService . ShowAsync < ConfirmDialog > ( "Reject Pandoc's licence" , dialogParameters , DialogOptions . FULLSCREEN ) ;
var dialogResult = await dialogReference . Result ;
if ( dialogResult is null | | dialogResult . Canceled )
dialogReference . Close ( ) ;
else
this . Cancel ( ) ;
}
private string FilenameFromUri ( string uri )
{
var index = uri . LastIndexOf ( '/' ) ;
return uri [ ( index + 1 ) . . ] ;
}
private async Task OnExpandedChanged ( bool isExpanded )
{
if ( isExpanded )
{
this . isLoading = true ;
try
{
this . licenseText = await this . LoadLicenseTextAsync ( ) ;
}
catch ( Exception ex )
{
this . licenseText = "Error loading license text, please consider following the links to read the GPL." ;
LOG . LogError ( "Error loading GPL license text:\n{ErrorMessage}" , ex . Message ) ;
}
finally
{
this . isLoading = false ;
}
}
else
{
this . licenseText = string . Empty ;
}
}
private async Task < string > LoadLicenseTextAsync ( )
{
var response = await this . HttpClient . GetAsync ( LICENCE_URI ) ;
response . EnsureSuccessStatusCode ( ) ;
2025-05-29 19:31:41 +00:00
return await response . Content . ReadAsStringAsync ( ) ;
2025-05-29 12:01:56 +00:00
}
2025-05-30 09:04:16 +00:00
// ReSharper disable RedundantSwitchExpressionArms
2025-05-30 09:16:53 +00:00
private static int SelectInstallerIndex ( ) = > CPU_ARCHITECTURE switch
2025-05-30 09:04:16 +00:00
{
RID . OSX_ARM64 = > 1 ,
RID . OSX_X64 = > 2 ,
RID . WIN_ARM64 = > 0 ,
RID . WIN_X64 = > 0 ,
_ = > 0 ,
} ;
2025-05-30 09:16:53 +00:00
private static int SelectArchiveIndex ( ) = > CPU_ARCHITECTURE switch
2025-05-30 09:04:16 +00:00
{
RID . OSX_ARM64 = > 1 ,
RID . OSX_X64 = > 1 ,
RID . WIN_ARM64 = > 0 ,
RID . WIN_X64 = > 0 ,
RID . LINUX_ARM64 = > 2 ,
RID . LINUX_X64 = > 2 ,
_ = > 0 ,
} ;
// ReSharper restore RedundantSwitchExpressionArms
2025-05-29 12:01:56 +00:00
}