diff --git a/src/Artemis.Core/Exceptions/ArtemisPluginException.cs b/src/Artemis.Core/Exceptions/ArtemisPluginException.cs
index 6473f0293..547ce8ead 100644
--- a/src/Artemis.Core/Exceptions/ArtemisPluginException.cs
+++ b/src/Artemis.Core/Exceptions/ArtemisPluginException.cs
@@ -44,31 +44,9 @@ public class ArtemisPluginException : Exception
public ArtemisPluginException(string message, Exception inner) : base(message, inner)
{
}
-
- ///
- /// Creates a new instance of the class
- ///
- public ArtemisPluginException(string message, string helpPageId) : base(message)
- {
- HelpPageId = helpPageId;
- }
-
- ///
- /// Creates a new instance of the class
- ///
- public ArtemisPluginException(string message, Exception inner, string helpPageId) : base(message, inner)
- {
- HelpPageId = helpPageId;
- }
///
/// Gets the plugin the error is related to
///
public Plugin? Plugin { get; }
-
- ///
- /// Gets the ID of the help page to display for this exception.
- ///
- public string? HelpPageId { get; }
-
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Plugins/IPluginHelpPage.cs b/src/Artemis.Core/Plugins/IPluginHelpPage.cs
deleted file mode 100644
index 1375d6716..000000000
--- a/src/Artemis.Core/Plugins/IPluginHelpPage.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-namespace Artemis.Core;
-
-///
-/// Represents a plugin related help page
-///
-public interface IPluginHelpPage
-{
- ///
- /// Gets the plugin the help page belongs to.
- ///
- Plugin Plugin { get; }
-
- ///
- /// Gets the title of the help page.
- ///
- public string Title { get; }
-
- ///
- /// An ID used to quickly lead users to the help page in case of an error.
- ///
- public string Id { get; }
-}
\ No newline at end of file
diff --git a/src/Artemis.Core/Plugins/MarkdownPluginHelpPage.cs b/src/Artemis.Core/Plugins/MarkdownPluginHelpPage.cs
deleted file mode 100644
index 09554fa29..000000000
--- a/src/Artemis.Core/Plugins/MarkdownPluginHelpPage.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System.IO;
-
-namespace Artemis.Core;
-
-///
-/// Represents a plugin related help page
-///
-public class MarkdownPluginHelpPage : IPluginHelpPage
-{
- ///
- /// Creates a new instance of the class.
- ///
- /// The plugin to display the markdown for.
- /// A file path relative to the plugin or absolute, pointing to the markdown to display
- /// The ID of the help page, used to quickly lead users to it in case of errors.
- ///
- public MarkdownPluginHelpPage(Plugin plugin, string title, string id, string markdownFile)
- {
- Plugin = plugin;
- Title = title;
- Id = id;
- MarkdownFile = Path.IsPathRooted(markdownFile) ? markdownFile : Plugin.ResolveRelativePath(markdownFile);
-
- if (!File.Exists(MarkdownFile))
- throw new FileNotFoundException($"Could not find markdown file at \"{MarkdownFile}\"");
- }
-
- ///
- public Plugin Plugin { get; }
-
- ///
- public string Title { get; }
-
- ///
- public string Id { get; }
-
- ///
- /// Gets the absolute path to the markdown that is to be displayed.
- ///
- public string MarkdownFile { get; }
-}
\ No newline at end of file
diff --git a/src/Artemis.Core/Plugins/Plugin.cs b/src/Artemis.Core/Plugins/Plugin.cs
index 290db1224..ff90181bc 100644
--- a/src/Artemis.Core/Plugins/Plugin.cs
+++ b/src/Artemis.Core/Plugins/Plugin.cs
@@ -36,7 +36,6 @@ public class Plugin : CorePropertyChanged, IDisposable
Features = new ReadOnlyCollection(_features);
Profilers = new ReadOnlyCollection(_profilers);
- HelpPages = new List();
}
///
@@ -58,9 +57,7 @@ public class Plugin : CorePropertyChanged, IDisposable
/// Gets or sets a configuration dialog for this plugin that is accessible in the UI under Settings > Plugins
///
public IPluginConfigurationDialog? ConfigurationDialog { get; set; }
-
- public List HelpPages { get; }
-
+
///
/// Indicates whether the user enabled the plugin or not
///
diff --git a/src/Artemis.Core/Plugins/PluginInfo.cs b/src/Artemis.Core/Plugins/PluginInfo.cs
index c571518c7..e8c3f5d50 100644
--- a/src/Artemis.Core/Plugins/PluginInfo.cs
+++ b/src/Artemis.Core/Plugins/PluginInfo.cs
@@ -27,6 +27,7 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
private bool _requiresAdmin;
private string _version = null!;
private Uri? _website;
+ private Uri? _helpPage;
internal PluginInfo()
{
@@ -91,6 +92,16 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
get => _repository;
set => SetAndNotify(ref _repository, value);
}
+
+ ///
+ /// Gets or sets the help page of this plugin
+ ///
+ [JsonProperty]
+ public Uri? HelpPage
+ {
+ get => _helpPage;
+ set => SetAndNotify(ref _helpPage, value);
+ }
///
/// The plugins display icon that's shown in the settings see for
@@ -188,9 +199,6 @@ public class PluginInfo : CorePropertyChanged, IPrerequisitesSubject
}
}
- [JsonProperty]
- internal List HelpPages { get; set; } = new();
-
///
/// Gets a boolean indicating whether this plugin is compatible with the current operating system and API version
///
diff --git a/src/Artemis.Core/Plugins/PluginInfoHelpPage.cs b/src/Artemis.Core/Plugins/PluginInfoHelpPage.cs
deleted file mode 100644
index 8f63c1623..000000000
--- a/src/Artemis.Core/Plugins/PluginInfoHelpPage.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using Newtonsoft.Json;
-
-namespace Artemis.Core;
-
-///
-/// Represents basic info about a plugin and contains a reference to the instance of said plugin
-///
-internal class PluginInfoHelpPage
-{
- [JsonConstructor]
- public PluginInfoHelpPage(string title, string markdownFile, string id)
- {
- Title = title;
- MarkdownFile = markdownFile;
- Id = id;
- }
-
- [JsonProperty(Required = Required.Always)]
- public string Title { get; }
-
- [JsonProperty(Required = Required.Always)]
- public string MarkdownFile { get; }
-
- [JsonProperty(Required = Required.Always)]
- public string Id { get; }
-}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs
index e8a7317d3..c03aec7bb 100644
--- a/src/Artemis.Core/Services/PluginManagementService.cs
+++ b/src/Artemis.Core/Services/PluginManagementService.cs
@@ -350,9 +350,6 @@ internal class PluginManagementService : IPluginManagementService
// Load the entity and fall back on creating a new one
Plugin plugin = new(pluginInfo, directory, _pluginRepository.GetPluginByGuid(pluginInfo.Guid));
- foreach (PluginInfoHelpPage pluginInfoHelpPage in pluginInfo.HelpPages)
- plugin.HelpPages.Add(new MarkdownPluginHelpPage(plugin, pluginInfoHelpPage.Title, pluginInfoHelpPage.Id, pluginInfoHelpPage.MarkdownFile));
-
OnPluginLoading(new PluginEventArgs(plugin));
// Locate the main assembly entry
diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj
index ea9845315..a1252420a 100644
--- a/src/Artemis.UI/Artemis.UI.csproj
+++ b/src/Artemis.UI/Artemis.UI.csproj
@@ -52,14 +52,6 @@
UpdatingTabView.axaml
Code
-
- MarkdownPluginHelpPageView.axaml
- Code
-
-
- PluginHelpWindowView.axaml
- Code
-
PluginFeatureView.axaml
Code
diff --git a/src/Artemis.UI/Screens/Plugins/Features/PluginFeatureViewModel.cs b/src/Artemis.UI/Screens/Plugins/Features/PluginFeatureViewModel.cs
index 2df1c64a9..2d83d9e6c 100644
--- a/src/Artemis.UI/Screens/Plugins/Features/PluginFeatureViewModel.cs
+++ b/src/Artemis.UI/Screens/Plugins/Features/PluginFeatureViewModel.cs
@@ -23,7 +23,6 @@ namespace Artemis.UI.Screens.Plugins.Features;
public class PluginFeatureViewModel : ActivatableViewModelBase
{
private readonly ICoreService _coreService;
- private readonly INotificationService _notificationService;
private readonly IPluginManagementService _pluginManagementService;
private readonly IWindowService _windowService;
private bool _enabling;
@@ -32,12 +31,10 @@ public class PluginFeatureViewModel : ActivatableViewModelBase
bool showShield,
ICoreService coreService,
IWindowService windowService,
- INotificationService notificationService,
IPluginManagementService pluginManagementService)
{
_coreService = coreService;
_windowService = windowService;
- _notificationService = notificationService;
_pluginManagementService = pluginManagementService;
FeatureInfo = pluginFeatureInfo;
@@ -176,11 +173,7 @@ public class PluginFeatureViewModel : ActivatableViewModelBase
if (FeatureInfo.Instance == null)
{
this.RaisePropertyChanged(nameof(IsEnabled));
- _notificationService.CreateNotification()
- .WithMessage($"Feature '{FeatureInfo.Name}' is in a broken state and cannot enable.")
- .HavingButton(b => b.WithText("View logs").WithCommand(ShowLogsFolder))
- .WithSeverity(NotificationSeverity.Error)
- .Show();
+ await ShowFailureDialog($"Failed to enable '{FeatureInfo.Name}'", $"Feature '{FeatureInfo.Name}' is in a broken state and cannot enable.");
return;
}
@@ -215,11 +208,7 @@ public class PluginFeatureViewModel : ActivatableViewModelBase
}
catch (Exception e)
{
- _notificationService.CreateNotification()
- .WithMessage($"Failed to enable '{FeatureInfo.Name}'.\r\n{e.Message}")
- .HavingButton(b => b.WithText("View logs").WithCommand(ShowLogsFolder))
- .WithSeverity(NotificationSeverity.Error)
- .Show();
+ await ShowFailureDialog($"Failed to enable '{FeatureInfo.Name}'", e.Message);
}
finally
{
@@ -254,4 +243,17 @@ public class PluginFeatureViewModel : ActivatableViewModelBase
{
this.RaisePropertyChanged(nameof(CanToggleEnabled));
}
+
+ private async Task ShowFailureDialog(string action, string message)
+ {
+ ContentDialogBuilder builder = _windowService.CreateContentDialog()
+ .WithTitle(action)
+ .WithContent(message)
+ .HavingPrimaryButton(b => b.WithText("View logs").WithCommand(ShowLogsFolder));
+ // If available, add a secondary button pointing to the support page
+ if (FeatureInfo.Plugin.Info.HelpPage != null)
+ builder = builder.HavingSecondaryButton(b => b.WithText("Open support page").WithAction(() => Utilities.OpenUrl(FeatureInfo.Plugin.Info.HelpPage.ToString())));
+
+ await builder.ShowAsync();
+ }
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Plugins/Help/MarkdownPluginHelpPageView.axaml b/src/Artemis.UI/Screens/Plugins/Help/MarkdownPluginHelpPageView.axaml
deleted file mode 100644
index e6441425b..000000000
--- a/src/Artemis.UI/Screens/Plugins/Help/MarkdownPluginHelpPageView.axaml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/Artemis.UI/Screens/Plugins/Help/MarkdownPluginHelpPageView.axaml.cs b/src/Artemis.UI/Screens/Plugins/Help/MarkdownPluginHelpPageView.axaml.cs
deleted file mode 100644
index a151841c2..000000000
--- a/src/Artemis.UI/Screens/Plugins/Help/MarkdownPluginHelpPageView.axaml.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Avalonia.Controls;
-using Avalonia.Markup.Xaml;
-using Avalonia.ReactiveUI;
-
-namespace Artemis.UI.Screens.Plugins.Help;
-
-public partial class MarkdownPluginHelpPageView : ReactiveUserControl
-{
- public MarkdownPluginHelpPageView()
- {
- InitializeComponent();
- }
-
- private void InitializeComponent()
- {
- AvaloniaXamlLoader.Load(this);
- }
-}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Plugins/Help/MarkdownPluginHelpPageViewModel.cs b/src/Artemis.UI/Screens/Plugins/Help/MarkdownPluginHelpPageViewModel.cs
deleted file mode 100644
index 69dee5d11..000000000
--- a/src/Artemis.UI/Screens/Plugins/Help/MarkdownPluginHelpPageViewModel.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-using System;
-using System.IO;
-using System.Reactive.Disposables;
-using System.Threading.Tasks;
-using Artemis.Core;
-using Artemis.UI.Shared;
-using ReactiveUI;
-
-namespace Artemis.UI.Screens.Plugins.Help;
-
-public class MarkdownPluginHelpPageViewModel : ActivatableViewModelBase, IPluginHelpPage
-{
- private readonly MarkdownPluginHelpPage _helpPage;
- private string? _markdownText;
-
- public MarkdownPluginHelpPageViewModel(MarkdownPluginHelpPage helpPage)
- {
- _helpPage = helpPage;
- this.WhenActivated(d =>
- {
- FileSystemWatcher watcher = new();
- watcher.Path = Path.GetDirectoryName(_helpPage.MarkdownFile) ?? throw new InvalidOperationException($"Path \"{_helpPage.MarkdownFile}\" does not contain a directory");
- watcher.Filter = Path.GetFileName(_helpPage.MarkdownFile);
- watcher.EnableRaisingEvents = true;
- watcher.Changed += WatcherOnChanged;
- watcher.DisposeWith(d);
-
- LoadMarkdown().DisposeWith(d);
- });
- }
-
- public string? MarkdownText
- {
- get => _markdownText;
- set => RaiseAndSetIfChanged(ref _markdownText, value);
- }
-
- private async void WatcherOnChanged(object sender, FileSystemEventArgs e)
- {
- await LoadMarkdown();
- }
-
- private async Task LoadMarkdown()
- {
- try
- {
- await using FileStream stream = new(_helpPage.MarkdownFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
- using StreamReader reader = new(stream);
- MarkdownText = await reader.ReadToEndAsync();
- }
- catch (Exception e)
- {
- MarkdownText = e.Message;
- }
- }
-
- ///
- public Plugin Plugin => _helpPage.Plugin;
-
- ///
- public string Title => _helpPage.Title;
-
- ///
- public string Id => _helpPage.Id;
-}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Plugins/Help/PluginHelpWindowView.axaml b/src/Artemis.UI/Screens/Plugins/Help/PluginHelpWindowView.axaml
deleted file mode 100644
index 0935be744..000000000
--- a/src/Artemis.UI/Screens/Plugins/Help/PluginHelpWindowView.axaml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Plugins/Help/PluginHelpWindowView.axaml.cs b/src/Artemis.UI/Screens/Plugins/Help/PluginHelpWindowView.axaml.cs
deleted file mode 100644
index c821716bb..000000000
--- a/src/Artemis.UI/Screens/Plugins/Help/PluginHelpWindowView.axaml.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using Artemis.UI.Shared;
-using Avalonia;
-using Avalonia.Controls;
-using Avalonia.Markup.Xaml;
-
-namespace Artemis.UI.Screens.Plugins.Help;
-
-public partial class PluginHelpWindowView : ReactiveAppWindow
-{
- public PluginHelpWindowView()
- {
- InitializeComponent();
-#if DEBUG
- this.AttachDevTools();
-#endif
- }
-
- private void InitializeComponent()
- {
- AvaloniaXamlLoader.Load(this);
- }
-}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Plugins/Help/PluginHelpWindowViewModel.cs b/src/Artemis.UI/Screens/Plugins/Help/PluginHelpWindowViewModel.cs
deleted file mode 100644
index b9ad2b37c..000000000
--- a/src/Artemis.UI/Screens/Plugins/Help/PluginHelpWindowViewModel.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using System.Collections.ObjectModel;
-using System.Linq;
-using Artemis.Core;
-using Artemis.UI.Shared;
-
-namespace Artemis.UI.Screens.Plugins.Help;
-
-public class PluginHelpWindowViewModel : ActivatableViewModelBase
-{
- private IPluginHelpPage? _selectedHelpPage;
-
- public PluginHelpWindowViewModel(Plugin plugin, string? preselectId)
- {
- Plugin = plugin;
- DisplayName = $"{Plugin.Info.Name} | Help";
-
- // Populate help pages by wrapping MarkdownHelpPages into a MarkdownHelpPageViewModel
- // other types are used directly, up to them to implement a VM directly as well
- HelpPages = new ReadOnlyCollection(plugin.HelpPages.Select(p => p is MarkdownPluginHelpPage m ? new MarkdownPluginHelpPageViewModel(m) : p).ToList());
-
- _selectedHelpPage = preselectId != null ? HelpPages.FirstOrDefault(p => p.Id == preselectId) : HelpPages.FirstOrDefault();
- }
-
- public Plugin Plugin { get; }
- public ReadOnlyCollection HelpPages { get; }
-
- public IPluginHelpPage? SelectedHelpPage
- {
- get => _selectedHelpPage;
- set => RaiseAndSetIfChanged(ref _selectedHelpPage, value);
- }
-}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Plugins/PluginView.axaml b/src/Artemis.UI/Screens/Plugins/PluginView.axaml
index 605a44a59..640279366 100644
--- a/src/Artemis.UI/Screens/Plugins/PluginView.axaml
+++ b/src/Artemis.UI/Screens/Plugins/PluginView.axaml
@@ -92,9 +92,9 @@
+ IsVisible="{CompiledBinding Plugin.Info.HelpPage, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
+ NavigateUri="{CompiledBinding Plugin.Info.HelpPage}"
+ ToolTip.Tip="{CompiledBinding Plugin.Info.HelpPage}">
? reload,
@@ -59,7 +56,6 @@ public class PluginViewModel : ActivatableViewModelBase
Reload = reload;
OpenSettings = ReactiveCommand.Create(ExecuteOpenSettings, this.WhenAnyValue(vm => vm.IsEnabled, e => e && Plugin.ConfigurationDialog != null));
- OpenHelp = ReactiveCommand.Create(ExecuteOpenHelp, this.WhenAnyValue(vm => vm.HasHelpPages));
RemoveSettings = ReactiveCommand.CreateFromTask(ExecuteRemoveSettings);
Remove = ReactiveCommand.CreateFromTask(ExecuteRemove);
InstallPrerequisites = ReactiveCommand.CreateFromTask(ExecuteInstallPrerequisites, this.WhenAnyValue(x => x.CanInstallPrerequisites));
@@ -77,14 +73,12 @@ public class PluginViewModel : ActivatableViewModelBase
Plugin.Enabled -= OnPluginToggled;
Plugin.Disabled -= OnPluginToggled;
_settingsWindow?.Close();
- _helpWindow?.Close();
}).DisposeWith(d);
});
}
public ReactiveCommand? Reload { get; }
public ReactiveCommand OpenSettings { get; }
- public ReactiveCommand OpenHelp { get; }
public ReactiveCommand RemoveSettings { get; }
public ReactiveCommand Remove { get; }
public ReactiveCommand InstallPrerequisites { get; }
@@ -108,7 +102,6 @@ public class PluginViewModel : ActivatableViewModelBase
public string Type => Plugin.GetType().BaseType?.Name ?? Plugin.GetType().Name;
public bool IsEnabled => Plugin.IsEnabled;
- public bool HasHelpPages => Plugin.HelpPages.Any();
public bool CanInstallPrerequisites
{
@@ -135,11 +128,7 @@ public class PluginViewModel : ActivatableViewModelBase
}
catch (Exception e)
{
- await Dispatcher.UIThread.InvokeAsync(() => _notificationService.CreateNotification()
- .WithSeverity(NotificationSeverity.Error)
- .WithMessage($"Failed to disable plugin {Plugin.Info.Name}\r\n{e.Message}")
- .HavingButton(b => b.WithText("View logs").WithCommand(ShowLogsFolder))
- .Show());
+ await ShowUpdateEnableFailure(enable, e);
}
finally
{
@@ -174,11 +163,7 @@ public class PluginViewModel : ActivatableViewModelBase
}
catch (Exception e)
{
- await Dispatcher.UIThread.InvokeAsync(() => _notificationService.CreateNotification()
- .WithSeverity(NotificationSeverity.Error)
- .WithMessage($"Failed to enable plugin {Plugin.Info.Name}\r\n{e.Message}")
- .HavingButton(b => b.WithText("View logs").WithCommand(ShowLogsFolder))
- .Show());
+ await ShowUpdateEnableFailure(enable, e);
}
finally
{
@@ -187,7 +172,6 @@ public class PluginViewModel : ActivatableViewModelBase
}
}
-
public void CheckPrerequisites()
{
CanInstallPrerequisites = false;
@@ -228,27 +212,6 @@ public class PluginViewModel : ActivatableViewModelBase
}
}
- private void ExecuteOpenHelp()
- {
- if (_helpWindow != null)
- {
- _helpWindow.WindowState = WindowState.Normal;
- _helpWindow.Activate();
- return;
- }
-
- try
- {
- _helpWindow = _windowService.ShowWindow(new PluginHelpWindowViewModel(Plugin, null));
- _helpWindow.Closed += (_, _) => _helpWindow = null;
- }
- catch (Exception e)
- {
- _windowService.ShowExceptionDialog("An exception occured while trying to show the plugin's help window", e);
- throw;
- }
- }
-
private void ExecuteOpenPluginDirectory()
{
try
@@ -334,6 +297,20 @@ public class PluginViewModel : ActivatableViewModelBase
_windowService.ShowExceptionDialog("Welp, we couldn\'t open the logs folder for you", e);
}
}
+
+ private async Task ShowUpdateEnableFailure(bool enable, Exception e)
+ {
+ string action = enable ? "enable" : "disable";
+ ContentDialogBuilder builder = _windowService.CreateContentDialog()
+ .WithTitle($"Failed to {action} plugin {Plugin.Info.Name}")
+ .WithContent(e.Message)
+ .HavingPrimaryButton(b => b.WithText("View logs").WithCommand(ShowLogsFolder));
+ // If available, add a secondary button pointing to the support page
+ if (Plugin.Info.HelpPage != null)
+ builder = builder.HavingSecondaryButton(b => b.WithText("Open support page").WithAction(() => Utilities.OpenUrl(Plugin.Info.HelpPage.ToString())));
+
+ await builder.ShowAsync();
+ }
private void OnPluginToggled(object? sender, EventArgs e)
{