Finished dialog and download of installers and archives

This commit is contained in:
nilsk 2025-05-27 01:11:54 +02:00
parent cecf777827
commit 012b28da27
5 changed files with 115 additions and 52 deletions

View File

@ -1,4 +1,4 @@
<MudTabs @bind-ActivePanelIndex="selectedIndex" PanelClass="code-block" MinimumTabWidth="30px"> <MudTabs @bind-ActivePanelIndex="selectedIndex" PanelClass="code-block" MinimumTabWidth="30px" Class="mt-2">
@foreach (var block in blocks) @foreach (var block in blocks)
{ {
<MudTabPanel Text="@block.Title"> <MudTabPanel Text="@block.Title">

View File

@ -33,39 +33,44 @@
</MudExpansionPanels> </MudExpansionPanels>
</div> </div>
<MudExpansionPanels Class="mb-3" MultiExpansion="@false" Outlined="false" Elevation="0"> <MudExpansionPanels Class="mb-3" MultiExpansion="@false" Outlined="false" Elevation="0">
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.AutoFixHigh" HeaderText="Automatic Installation" IsExpanded="true"> <ExpansionPanel HeaderIcon="@Icons.Material.Filled.AutoFixHigh" HeaderText="Automatic installation" IsExpanded="true">
<MudText Typo="Typo.caption"> <MudText Typo="Typo.caption">
Pandoc is distributed under the Pandoc is distributed under the
<MudLink Typo="Typo.caption" Href="https://github.com/jgm/pandoc/blob/main/COPYRIGHT" <MudLink Typo="Typo.caption" Href="https://github.com/jgm/pandoc/blob/main/COPYRIGHT" Target="_blank">GNU General Public License v2 (GPL)</MudLink>.
Target="_blank">GNU General Public License v2 (GPL)
</MudLink>
.
By clicking "Accept GPL and Install", you agree to the terms of the GPL license <br/> and Pandoc By clicking "Accept GPL and Install", you agree to the terms of the GPL license <br/> and Pandoc
will be installed automatically for you.<br/> will be installed automatically for you.<br/>
</MudText> </MudText>
<MudButton Color="Color.Primary" Class="mt-4" Variant="Variant.Filled" Size="Size.Small" <MudButton OnClick="InstallPandocAsync" Color="Color.Primary" Class="mt-4" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.InstallDesktop">
StartIcon="@Icons.Material.Filled.InstallDesktop">Accept GPL and Install Accept GPL and Install
</MudButton> </MudButton>
</ExpansionPanel> </ExpansionPanel>
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Build" HeaderText="Manual Installation"> <ExpansionPanel HeaderIcon="@Icons.Material.Filled.Build" HeaderText="Manual installation">
<MudText Class="mb-2"> <MudText Class="mb-2">
If you prefer to install Pandoc yourself, please follow one of these two guides. Installers are only available for Windows and Mac. If you prefer to install Pandoc yourself, please follow one of these two guides. Installers are only available for Windows and Mac.
</MudText> </MudText>
<MudExpansionPanels Outlined="false" Elevation="0"> <MudExpansionPanels Outlined="false" Elevation="0">
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.AppRegistration" HeaderText="Download with Installer" IsExpanded="true"> <ExpansionPanel HeaderIcon="@Icons.Material.Filled.AppRegistration" HeaderText="Download with installer" IsExpanded="true">
<MudList T="string"> <MudList T="string">
<MudListItem T="string" Class="mb-4"> <MudListItem T="string" Class="mb-4">
Accept the terms of the GPL license and download the latest installer with the download button below. Accept the terms of the GPL license and download the latest installer with the download button below.
Eventually you need to allow the download of the installer in the download window.
<CodeTabs> <CodeTabs>
<CodeBlock Title="Windows">pandoc-3.7.0-windows-x86_64.msi</CodeBlock> <CodeBlock Title="Windows">pandoc-@(PANDOC_VERSION)-windows-x86_64.msi</CodeBlock>
<CodeBlock Title="Mac OS x86">pandoc-3.7.0.1-x86_64-macOS.pkg</CodeBlock> <CodeBlock Title="Mac OS x86">pandoc-@(PANDOC_VERSION)-x86_64-macOS.pkg</CodeBlock>
<CodeBlock Title="Mac OS ARM">pandoc-3.7.0.1-arm64-macOS.pkg</CodeBlock> <CodeBlock Title="Mac OS ARM">pandoc-@(PANDOC_VERSION)-arm64-macOS.pkg</CodeBlock>
</CodeTabs> </CodeTabs>
</MudListItem> </MudListItem>
<MudListItem T="string"> <MudListItem T="string">
Execute the installer and follow the instructions. Execute the installer and follow the instructions.
</MudListItem> </MudListItem>
</MudList> </MudList>
<MudText Class="mb-3" Typo="Typo.caption">
Pandoc is distributed under the <MudLink Typo="Typo.caption" Href="https://github.com/jgm/pandoc/blob/main/COPYRIGHT" Target="_blank">GNU General Public License v2 (GPL)</MudLink>.
By clicking "Accept GPL and download installer", you agree to the terms of the GPL license.<br/>
</MudText>
<MudButton OnClick="@this.GetInstaller" Color="Color.Secondary" Class="mt-4" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.Downloading">
Accept GPL and download installer
</MudButton>
</ExpansionPanel> </ExpansionPanel>
<ExpansionPanel HeaderIcon="@Icons.Material.Outlined.Archive" HeaderText="Download with archive"> <ExpansionPanel HeaderIcon="@Icons.Material.Outlined.Archive" HeaderText="Download with archive">
<MudList T="string"> <MudList T="string">
@ -81,36 +86,31 @@
</CodeTabs> </CodeTabs>
</MudListItem> </MudListItem>
<MudListItem T="string" Class="mb-4"> <MudListItem T="string" Class="mb-4">
Open the folder and copy the full path to the <code>pandoc.exe</code> file into you Open the folder and copy the full path to the <CodeBlock IsInline="@true">pandoc.exe</CodeBlock> file into your
clipboard. clipboard.
<CodeTabs> <CodeTabs>
<CodeBlock Title="Windows">C:\Users\%USERNAME%\pandoc\pandoc-3.7.0-windows-x86_64\pandoc-3.7.0</CodeBlock> <CodeBlock Title="Windows">C:\Users\%USERNAME%\pandoc\pandoc-@(PANDOC_VERSION)</CodeBlock>
<CodeBlock Title="Mac OS">/usr/local/bin/pandoc/pandoc-3.7.0-x86_64-macOS/pandoc-3.7.0</CodeBlock> <CodeBlock Title="Mac OS">/usr/local/bin/pandoc/pandoc-@(PANDOC_VERSION)</CodeBlock>
<CodeBlock Title="Linux">/usr/local/bin/pandoc/pandoc-3.7.0-linux-amd64/pandoc-3.7.0</CodeBlock> <CodeBlock Title="Linux">/usr/local/bin/pandoc/pandoc-@(PANDOC_VERSION)</CodeBlock>
</CodeTabs> </CodeTabs>
</MudListItem> </MudListItem>
<MudListItem T="string"> <MudListItem T="string">
Add the copied path to your systems environment variables and check the installation Add the copied path to your systems environment variables and check the installation
by typing by typing <br/><CodeBlock IsInline="@true">pandoc --version</CodeBlock>
<CodeBlock IsInline="@true">pandoc --version</CodeBlock>
into your command line interface. into your command line interface.
<CodeTabs> <CodeTabs>
<CodeBlock Title="Windows">> pandoc.exe --version<br/>> pandoc.exe 3.7.0</CodeBlock> <CodeBlock Title="Windows">> pandoc.exe --version<br/>> pandoc.exe @(PANDOC_VERSION)</CodeBlock>
<CodeBlock Title="Mac OS">> pandoc --version<br/>> pandoc.exe 3.7.0</CodeBlock> <CodeBlock Title="Mac OS">> pandoc --version<br/>> pandoc.exe @(PANDOC_VERSION)</CodeBlock>
<CodeBlock Title="Linux">> pandoc --version<br/>> pandoc.exe 3.7.0</CodeBlock> <CodeBlock Title="Linux">> pandoc --version<br/>> pandoc.exe @(PANDOC_VERSION)</CodeBlock>
</CodeTabs> </CodeTabs>
</MudListItem> </MudListItem>
</MudList> </MudList>
<MudText Class="mb-3" Typo="Typo.caption"> <MudText Class="mb-3" Typo="Typo.caption">
Pandoc is distributed under the Pandoc is distributed under the <MudLink Typo="Typo.caption" Href="https://github.com/jgm/pandoc/blob/main/COPYRIGHT" Target="_blank">GNU General Public License v2 (GPL)</MudLink>.
<MudLink Typo="Typo.caption" Href="https://github.com/jgm/pandoc/blob/main/COPYRIGHT" By clicking "Accept GPL and archive", you agree to the terms of the GPL license.<br/>
Target="_blank">GNU General Public License v2 (GPL)
</MudLink>
.
By clicking "Accept GPL and Download", you agree to the terms of the GPL license.
</MudText> </MudText>
<MudButton Color="Color.Secondary" Class="mt-4" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.Downloading"> <MudButton OnClick="@this.GetArchive" Color="Color.Secondary" Class="mt-4" Variant="Variant.Filled" Size="Size.Small" StartIcon="@Icons.Material.Filled.Downloading">
Accept GPL and Download Accept GPL and download archive
</MudButton> </MudButton>
</ExpansionPanel> </ExpansionPanel>
</MudExpansionPanels> </MudExpansionPanels>
@ -122,8 +122,7 @@
} }
else else
{ {
<MudItem Class="pa-6" <MudItem Class="px-8 py-2" Style="height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center;">
Style="height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center;">
@if (showSkeleton) @if (showSkeleton)
{ {
<MudSkeleton SkeletonType="SkeletonType.Circle" Animation="Animation.Pulse" Class="mb-4" <MudSkeleton SkeletonType="SkeletonType.Circle" Animation="Animation.Pulse" Class="mb-4"
@ -141,14 +140,12 @@
} }
else else
{ {
<MudIcon Class="mb-2" Style="width: 2.5em; height: 2.5em;" Icon="@Icons.Material.Filled.Error" <MudIcon Class="mb-2" Style="width: 3.5em; height: 3.5em;" Icon="@Icons.Material.Filled.Error" Color="Color.Error"/>
Color="Color.Error"/> <MudText Class="mb-6" Typo="Typo.subtitle1" Align="Align.Center">
<MudText Class="mb-2" Typo="Typo.subtitle1" Align="Align.Center">
Pandoc ist auf Ihrem System nicht verfügbar Pandoc ist auf Ihrem System nicht verfügbar
</MudText> </MudText>
<MudButton Color="Color.Primary" OnClick="@this.ProceedToInstallation" Variant="Variant.Filled"> <MudButton Color="Color.Primary" OnClick="@this.ProceedToInstallation" Variant="Variant.Filled">
Proceed Proceed to installation
to installation
</MudButton> </MudButton>
} }
</MudItem> </MudItem>

View File

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Components; using AIStudio.Tools.Services;
using Microsoft.AspNetCore.Components;
namespace AIStudio.Dialogs; namespace AIStudio.Dialogs;
@ -7,10 +8,17 @@ public partial class PandocDialog : ComponentBase
[Inject] [Inject]
private HttpClient HttpClient { get; set; } = null!; private HttpClient HttpClient { get; set; } = null!;
[Inject]
private RustService RustService { get; init; } = null!;
[Inject]
protected IJSRuntime JsRuntime { get; init; } = null!;
[CascadingParameter] [CascadingParameter]
private IMudDialogInstance MudDialog { get; set; } = null!; private IMudDialogInstance MudDialog { get; set; } = null!;
private static readonly string LICENCE_URI = "https://raw.githubusercontent.com/jgm/pandoc/master/COPYRIGHT"; private static readonly string LICENCE_URI = "https://raw.githubusercontent.com/jgm/pandoc/master/COPYRIGHT";
private static string PANDOC_VERSION = "1.0.0";
private bool isPandocAvailable; private bool isPandocAvailable;
private bool showSkeleton; private bool showSkeleton;
@ -25,6 +33,7 @@ public partial class PandocDialog : ComponentBase
await base.OnInitializedAsync(); await base.OnInitializedAsync();
this.showSkeleton = true; this.showSkeleton = true;
await this.CheckPandocAvailabilityAsync(); await this.CheckPandocAvailabilityAsync();
PANDOC_VERSION = await Pandoc.FetchLatestVersionAsync();
} }
#endregion #endregion
@ -33,13 +42,36 @@ public partial class PandocDialog : ComponentBase
private async Task CheckPandocAvailabilityAsync() private async Task CheckPandocAvailabilityAsync()
{ {
this.isPandocAvailable = await Pandoc.CheckAvailabilityAsync(); this.isPandocAvailable = await Pandoc.CheckAvailabilityAsync(false);
this.showSkeleton = false; this.showSkeleton = false;
await this.InvokeAsync(this.StateHasChanged); await this.InvokeAsync(this.StateHasChanged);
} }
private async Task InstallPandocAsync() => await Pandoc.InstallAsync(this.RustService);
private void ProceedToInstallation() => this.showInstallPage = true; private void ProceedToInstallation() => this.showInstallPage = true;
private async Task GetInstaller()
{
var uri = await Pandoc.GenerateInstallerUriAsync();
var filename = this.FilenameFromUri(uri);
await this.JsRuntime.InvokeVoidAsync("triggerDownload", uri, filename);
}
private async Task GetArchive()
{
var uri = await Pandoc.GenerateUriAsync();
var filename = this.FilenameFromUri(uri);
await this.JsRuntime.InvokeVoidAsync("triggerDownload", uri, filename);
}
private string FilenameFromUri(string uri)
{
var index = uri.LastIndexOf('/');
return uri[(index + 1)..];
}
private async Task OnExpandedChanged(bool newVal) private async Task OnExpandedChanged(bool newVal)
{ {
if (newVal) if (newVal)
@ -53,8 +85,7 @@ public partial class PandocDialog : ComponentBase
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"Fehler beim Laden des Lizenztexts: {ex.Message}"); this.licenseText = "Error loading license text, please consider following the links to the GPL.";
this.licenseText = "Fehler beim Laden des Lizenztexts.";
} }
finally finally
{ {

View File

@ -10,7 +10,7 @@ namespace AIStudio.Tools;
public static partial class Pandoc public static partial class Pandoc
{ {
private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger("PluginFactory"); private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger("PluginFactory");
private static readonly string DOWNLOAD_URL = "https://github.com/jgm/pandoc/releases/download/"; private static readonly string DOWNLOAD_URL = "https://github.com/jgm/pandoc/releases/download";
private static readonly string LATEST_URL = "https://github.com/jgm/pandoc/releases/latest"; private static readonly string LATEST_URL = "https://github.com/jgm/pandoc/releases/latest";
private static readonly Version MINIMUM_REQUIRED_VERSION = new (3, 6); private static readonly Version MINIMUM_REQUIRED_VERSION = new (3, 6);
private static readonly Version FALLBACK_VERSION = new (3, 6, 4); private static readonly Version FALLBACK_VERSION = new (3, 6, 4);
@ -20,7 +20,7 @@ public static partial class Pandoc
/// Checks if pandoc is available on the system and can be started as a process /// Checks if pandoc is available on the system and can be started as a process
/// </summary> /// </summary>
/// <returns>True, if pandoc is available and the minimum required version is met, else False.</returns> /// <returns>True, if pandoc is available and the minimum required version is met, else False.</returns>
public static async Task<bool> CheckAvailabilityAsync() public static async Task<bool> CheckAvailabilityAsync(bool showMessages = true)
{ {
try try
{ {
@ -35,7 +35,8 @@ public static partial class Pandoc
using var process = Process.Start(startInfo); using var process = Process.Start(startInfo);
if (process == null) if (process == null)
{ {
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Help, "The pandoc process could not be started.")); if (showMessages)
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Help, "The pandoc process could not be started."));
LOG.LogInformation("The pandoc process was not started, it was null"); LOG.LogInformation("The pandoc process was not started, it was null");
return false; return false;
} }
@ -44,7 +45,8 @@ public static partial class Pandoc
await process.WaitForExitAsync(); await process.WaitForExitAsync();
if (process.ExitCode != 0) if (process.ExitCode != 0)
{ {
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Error, $"The pandoc process exited unexpectedly.")); if (showMessages)
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Error, $"The pandoc process exited unexpectedly."));
LOG.LogError("The pandoc process was exited with code {ProcessExitCode}", process.ExitCode); LOG.LogError("The pandoc process was exited with code {ProcessExitCode}", process.ExitCode);
return false; return false;
} }
@ -52,7 +54,8 @@ public static partial class Pandoc
var versionMatch = PandocRegex().Match(output); var versionMatch = PandocRegex().Match(output);
if (!versionMatch.Success) if (!versionMatch.Success)
{ {
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Terminal, $"pandoc --version returned an invalid format.")); if (showMessages)
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Terminal, $"pandoc --version returned an invalid format."));
LOG.LogError("pandoc --version returned an invalid format:\n {Output}", output); LOG.LogError("pandoc --version returned an invalid format:\n {Output}", output);
return false; return false;
} }
@ -63,18 +66,21 @@ public static partial class Pandoc
if (installedVersion >= MINIMUM_REQUIRED_VERSION) if (installedVersion >= MINIMUM_REQUIRED_VERSION)
{ {
await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.CheckCircle, $"Pandoc {installedVersion.ToString()} is installed.")); if (showMessages)
await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.CheckCircle, $"Pandoc {installedVersion.ToString()} is installed."));
return true; return true;
} }
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Build, $"Pandoc {installedVersion.ToString()} is installed, but it doesn't match the required version ({MINIMUM_REQUIRED_VERSION.ToString()}).")); if (showMessages)
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Build, $"Pandoc {installedVersion.ToString()} is installed, but it doesn't match the required version ({MINIMUM_REQUIRED_VERSION.ToString()})."));
LOG.LogInformation("Pandoc {Installed} is installed, but it does not match the required version ({Requirement})", installedVersion.ToString(), MINIMUM_REQUIRED_VERSION.ToString()); LOG.LogInformation("Pandoc {Installed} is installed, but it does not match the required version ({Requirement})", installedVersion.ToString(), MINIMUM_REQUIRED_VERSION.ToString());
return false; return false;
} }
catch (Exception e) catch (Exception e)
{ {
await MessageBus.INSTANCE.SendError(new (@Icons.Material.Filled.AppsOutage, "Pandoc is not installed.")); if (showMessages)
await MessageBus.INSTANCE.SendError(new (@Icons.Material.Filled.AppsOutage, "Pandoc is not installed."));
LOG.LogError("Pandoc is not installed and threw an exception:\n {Message}", e.Message); LOG.LogError("Pandoc is not installed and threw an exception:\n {Message}", e.Message);
return false; return false;
} }
@ -177,7 +183,7 @@ public static partial class Pandoc
} }
// win arm not available // win arm not available
private static async Task<string> GenerateUriAsync() public static async Task<string> GenerateUriAsync()
{ {
var version = await FetchLatestVersionAsync(); var version = await FetchLatestVersionAsync();
var baseUri = $"{DOWNLOAD_URL}/{version}/pandoc-{version}-"; var baseUri = $"{DOWNLOAD_URL}/{version}/pandoc-{version}-";
@ -192,6 +198,25 @@ public static partial class Pandoc
}; };
} }
public static async Task<string> GenerateInstallerUriAsync()
{
var version = await FetchLatestVersionAsync();
var baseUri = $"{DOWNLOAD_URL}/{version}/pandoc-{version}-";
switch (CPU_ARCHITECTURE)
{
case "win-x64":
return $"{baseUri}windows-x86_64.msi";
case "osx-x64":
return $"{baseUri}x86_64-macOS.pkg";
case "osx-arm64":
return $"{baseUri}arm64-macOS.pkg\n";
default:
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Terminal, $"Installers are not available on {CPU_ARCHITECTURE} systems."));
return string.Empty;
}
}
/// <summary> /// <summary>
/// Returns the name of the pandoc executable based on the running operating system /// Returns the name of the pandoc executable based on the running operating system
/// </summary> /// </summary>
@ -200,6 +225,6 @@ public static partial class Pandoc
[GeneratedRegex(@"pandoc(?:\.exe)?\s*([0-9]+\.[0-9]+)")] [GeneratedRegex(@"pandoc(?:\.exe)?\s*([0-9]+\.[0-9]+)")]
private static partial Regex PandocRegex(); private static partial Regex PandocRegex();
[GeneratedRegex(@"pandoc(?:\.exe)?\s*([0-9]+\.[0-9]+\.[0-9]+)")] [GeneratedRegex(@"pandoc(?:\.exe)?\s*([0-9]+\.[0-9]+\.[0-9]+(?:\.[0-9]+)?)")]
private static partial Regex VersionRegex(); private static partial Regex VersionRegex();
} }

View File

@ -26,3 +26,13 @@ window.clearDiv = function (divName) {
window.scrollToBottom = function(element) { window.scrollToBottom = function(element) {
element.scrollIntoView({ behavior: 'smooth', block: 'end', inline: 'nearest' }); element.scrollIntoView({ behavior: 'smooth', block: 'end', inline: 'nearest' });
} }
window.triggerDownload = function(url, filename) {
const a = document.createElement('a');
a.href = url;
a.setAttribute('download', filename);
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}