diff --git a/app/MindWork AI Studio/Pages/Plugins.razor b/app/MindWork AI Studio/Pages/Plugins.razor index 7e048459..3928fd21 100644 --- a/app/MindWork AI Studio/Pages/Plugins.razor +++ b/app/MindWork AI Studio/Pages/Plugins.razor @@ -5,9 +5,17 @@ @attribute [Route(Routes.PLUGINS)]
- - @T("Plugins") - + + + @T("Plugins") + + + + + @T("Import") + + + diff --git a/app/MindWork AI Studio/Pages/Plugins.razor.cs b/app/MindWork AI Studio/Pages/Plugins.razor.cs index d749479c..4835975b 100644 --- a/app/MindWork AI Studio/Pages/Plugins.razor.cs +++ b/app/MindWork AI Studio/Pages/Plugins.razor.cs @@ -4,6 +4,7 @@ using AIStudio.Dialogs; using AIStudio.Settings.DataModel; using AIStudio.Tools.PluginSystem.Assistants; using AIStudio.Tools.PluginSystem; +using AIStudio.Tools.Rust; using AIStudio.Tools.Services; using Microsoft.AspNetCore.Components; using DialogOptions = AIStudio.Dialogs.DialogOptions; @@ -16,6 +17,7 @@ public partial class Plugins : MSGComponentBase private const string GROUP_DISABLED = "Disabled"; private const string GROUP_INTERNAL = "Internal"; private bool isAutoAuditing; + private bool isImportingAssistantPlugin; private DataAssistantPluginAudit AssistantPluginAuditSettings => this.SettingsManager.ConfigurationData.AssistantPluginAudit; @@ -30,10 +32,23 @@ public partial class Plugins : MSGComponentBase [Inject] private PluginShareService PluginShareService { get; init; } = null!; + [Inject] + private RustService RustService { get; init; } = null!; + + [Inject] + private AssistantPluginInstallService AssistantPluginInstallService { get; init; } = null!; + private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger(nameof(Plugins)); private static bool IS_SHARING_PLUGIN; + private const string IMPORT_ICON = + @" + + + + "; + #region Overrides of ComponentBase protected override async Task OnInitializedAsync() @@ -267,6 +282,42 @@ public partial class Plugins : MSGComponentBase } } + private async Task ImportAssistantPluginAsync() + { + if (this.isImportingAssistantPlugin) + return; + + this.isImportingAssistantPlugin = true; + await this.InvokeAsync(this.StateHasChanged); + + try + { + var selection = await this.RustService.SelectFile(this.T("Import assistant plugin"), [FileTypes.PLUGIN_ARCHIVE]); + if (selection.UserCancelled) + return; + + var result = await this.AssistantPluginInstallService.InstallArchiveAsync(selection.SelectedFilePath, CancellationToken.None); + if (!result.Success) + { + LOG.LogError("Failed to import assistant plugin archive '{ArchivePath}': {Issue}", selection.SelectedFilePath, result.Issue); + await this.MessageBus.SendError(new(Icons.Material.Filled.ReportProblem, string.Format(this.T("The assistant plugin could not be imported: {0}"), result.Issue))); + return; + } + + var message = result.ReplacedExisting + ? this.T("Assistant updated.") + : this.T("Assistant installed."); + await this.MessageBus.SendSuccess(new(Icons.Material.Filled.Extension, message)); + await this.MessageBus.SendMessage(this, Event.PLUGINS_RELOADED); + await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED); + } + finally + { + this.isImportingAssistantPlugin = false; + await this.InvokeAsync(this.StateHasChanged); + } + } + private static bool IsSendingMail(string sourceUrl) => sourceUrl.TrimStart().StartsWith("mailto:", StringComparison.OrdinalIgnoreCase); private PluginAssistants? TryGetAssistantPlugin(Guid pluginId) => PluginFactory.RunningPlugins.OfType().FirstOrDefault(x => x.Id == pluginId);