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);