Browse Source

Merge pull request #475 from ionite34/exception-copy

Add copy button for exception dialog
pull/438/head
Ionite 10 months ago committed by GitHub
parent
commit
d0ecac15b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 9
      StabilityMatrix.Avalonia/Languages/Resources.Designer.cs
  3. 3
      StabilityMatrix.Avalonia/Languages/Resources.resx
  4. 9
      StabilityMatrix.Avalonia/Program.cs
  5. 35
      StabilityMatrix.Avalonia/ViewModels/Dialogs/ExceptionViewModel.cs
  6. 41
      StabilityMatrix.Avalonia/Views/Dialogs/ExceptionDialog.axaml
  7. 12
      StabilityMatrix.Avalonia/Views/Dialogs/ExceptionDialog.axaml.cs

1
CHANGELOG.md

@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2
## v2.8.0-pre.3
### Added
- Added "Config" Shared Model Folder option for Fooocus
- Added "Copy Details" button to Unexpected Error dialog
### Changed
- (Internal) Updated to Avalonia 11.0.7
- Updated French translation (thanks Greg!)

9
StabilityMatrix.Avalonia/Languages/Resources.Designer.cs generated

@ -167,6 +167,15 @@ namespace StabilityMatrix.Avalonia.Languages {
}
}
/// <summary>
/// Looks up a localized string similar to Copy Details.
/// </summary>
public static string Action_CopyDetails {
get {
return ResourceManager.GetString("Action_CopyDetails", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Copy Trigger Words.
/// </summary>

3
StabilityMatrix.Avalonia/Languages/Resources.resx

@ -936,4 +936,7 @@
<data name="Label_NoExtensionsFound" xml:space="preserve">
<value>No extensions found.</value>
</data>
<data name="Action_CopyDetails" xml:space="preserve">
<value>Copy Details</value>
</data>
</root>

9
StabilityMatrix.Avalonia/Program.cs

@ -347,11 +347,13 @@ public static class Program
if (e.ExceptionObject is not Exception ex)
return;
SentryId? sentryId = null;
// Exception automatically logged by Sentry if enabled
if (SentrySdk.IsEnabled)
{
ex.SetSentryMechanism("AppDomain.UnhandledException", handled: false);
SentrySdk.CaptureException(ex);
sentryId = SentrySdk.CaptureException(ex);
SentrySdk.FlushAsync().SafeFireAndForget();
}
else
@ -361,7 +363,10 @@ public static class Program
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime)
{
var dialog = new ExceptionDialog { DataContext = new ExceptionViewModel { Exception = ex } };
var dialog = new ExceptionDialog
{
DataContext = new ExceptionViewModel { Exception = ex, SentryId = sentryId }
};
var mainWindow = lifetime.MainWindow;
// We can only show dialog if main window exists, and is visible

35
StabilityMatrix.Avalonia/ViewModels/Dialogs/ExceptionViewModel.cs

@ -1,4 +1,5 @@
using System;
using Sentry;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.Views.Dialogs;
using StabilityMatrix.Core.Attributes;
@ -12,7 +13,41 @@ public partial class ExceptionViewModel : ViewModelBase
{
public Exception? Exception { get; set; }
public SentryId? SentryId { get; set; }
public string? Message => Exception?.Message;
public string? ExceptionType => Exception?.GetType().Name ?? "";
public string? FormatAsMarkdown()
{
if (Exception is null)
{
return null;
}
var message = $"## Exception\n{ExceptionType}: {Message}\n";
if (SentryId is not null)
{
message += $"### Sentry ID\n```\n{SentryId}\n```\n";
}
if (Exception.StackTrace != null)
{
message += $"### Stack Trace\n```\n{Exception.StackTrace}\n```\n";
}
if (Exception.InnerException is { } innerException)
{
message += $"## Inner Exception\n{innerException.GetType().Name}: {innerException.Message}\n";
if (innerException.StackTrace != null)
{
message += $"### Stack Trace\n```\n{innerException.StackTrace}\n```\n";
}
}
return message;
}
}

41
StabilityMatrix.Avalonia/Views/Dialogs/ExceptionDialog.axaml

@ -6,6 +6,7 @@
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData"
xmlns:controls="clr-namespace:StabilityMatrix.Avalonia.Controls"
xmlns:lang="clr-namespace:StabilityMatrix.Avalonia.Languages"
xmlns:fluentIcons="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent"
d:DataContext="{x:Static mocks:DesignData.ExceptionViewModel}"
x:DataType="dialogs:ExceptionViewModel"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="550"
@ -73,16 +74,38 @@
</ScrollViewer>
</Expander>
</DockPanel>
<!-- Close Button -->
<Button
Name="ExitButton"
IsDefault="True"
Content="{x:Static lang:Resources.Action_ExitApplication}"
Click="ExitButton_OnClick"
Grid.Row="2"
HorizontalAlignment="Right"
<StackPanel
Spacing="12"
Orientation="Horizontal"
Margin="16"
Padding="8" />
HorizontalAlignment="Right"
Grid.Row="2">
<!-- Copy Button -->
<Button
Name="CopyButton"
Click="CopyButton_OnClick"
Padding="12,8">
<StackPanel Spacing="6" Orientation="Horizontal">
<fluentIcons:SymbolIcon
FontSize="15"
Symbol="Copy"
Margin="0,1,0,0"
VerticalAlignment="Center"/>
<TextBlock
Text="{x:Static lang:Resources.Action_CopyDetails}"/>
</StackPanel>
</Button>
<!-- Close Button -->
<Button
Name="ExitButton"
IsDefault="True"
Content="{x:Static lang:Resources.Action_ExitApplication}"
Click="ExitButton_OnClick"
Padding="12,8" />
</StackPanel>
</Grid>
</Grid>

12
StabilityMatrix.Avalonia/Views/Dialogs/ExceptionDialog.axaml.cs

@ -3,6 +3,7 @@ using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using FluentAvalonia.UI.Windowing;
using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.ViewModels.Dialogs;
using StabilityMatrix.Core.Attributes;
namespace StabilityMatrix.Avalonia.Views.Dialogs;
@ -23,6 +24,17 @@ public partial class ExceptionDialog : AppWindowBase
AvaloniaXamlLoader.Load(this);
}
[SuppressMessage("ReSharper", "UnusedParameter.Local")]
private async void CopyButton_OnClick(object? sender, RoutedEventArgs e)
{
var content = (DataContext as ExceptionViewModel)?.FormatAsMarkdown();
if (content is not null && Clipboard is not null)
{
await Clipboard.SetTextAsync(content);
}
}
[SuppressMessage("ReSharper", "UnusedParameter.Local")]
private void ExitButton_OnClick(object? sender, RoutedEventArgs e)
{

Loading…
Cancel
Save