mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-24 04:00:02 +01:00
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR adds three parts of the original big bad global error handler (error report builder, sanitization and internal tools UI). ### Error Report Generation - `ErrorReportBuilder`: Produces a detailed, technical report with system context. - Comprehensive data: OS version, architecture, culture, app version, elevation status, etc. - Exception analysis: Coalesces nested exception messages and HRESULT details for clearer diagnostics. <details><summary>Example</summary> <pre> This is an error report generated by Windows Command Palette. If you are seeing this, it means something went a little sideways in the app. You can help us fix it by filing a report at https://aka.ms/powerToysReportBug. (While you’re at it, give the details below a quick skim — just to make sure there’s nothing personal you’d prefer not to share. It’s rare, but sometimes little surprises sneak in.) ============================================================ Summary: Message: Test exception; thrown from the UI thread Type: System.NotImplementedException Source: Microsoft.CmdPal.UI Time: 2025-08-25 18:54:44.3854569 HRESULT: 0x80004001 (-2147467263) Context: MainThreadException Application: App version: 0.0.1.0 Is elevated: no Environment: OS version: Microsoft Windows 10.0.26120 OS architecture: X64 Runtime identifier: win-x64 Framework: .NET 9.0.8 Process architecture: X64 Culture: cs-CZ UI culture: en-US Stack Trace: at Microsoft.CmdPal.UI.Settings.InternalPage.ThrowPlainMainThreadException_Click(Object sender, RoutedEventArgs e) at WinRT._EventSource_global__Microsoft_UI_Xaml_RoutedEventHandler.EventState.<GetEventInvoke>b__1_0(Object sender, RoutedEventArgs e) at ABI.Microsoft.UI.Xaml.RoutedEventHandler.Do_Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr e) ------------------ Full Exception Details ------------------ System.NotImplementedException: Test exception; thrown from the UI thread at Microsoft.CmdPal.UI.Settings.InternalPage.ThrowPlainMainThreadException_Click(Object sender, RoutedEventArgs e) at WinRT._EventSource_global__Microsoft_UI_Xaml_RoutedEventHandler.EventState.<GetEventInvoke>b__1_0(Object sender, RoutedEventArgs e) at ABI.Microsoft.UI.Xaml.RoutedEventHandler.Do_Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr e) ============================================================ </pre> </details> Real-world example: #41362 ### PII Sanitization Framework - `ErrorReportSanitizer`: Multi-layer sanitization pipeline for sensitive data. - Nine specialized rule providers: - `PiiRuleProvider`: Personally identifiable information (emails, phone numbers, SSNs). - `ProfilePathAndUsernameRuleProvider`: Windows user profiles and usernames. - `NetworkRuleProvider`: IP addresses, MAC addresses, network identifiers. - `SecretKeyValueRulesProvider`: API keys, tokens, passwords in key/value formats. - `FilenameMaskRuleProvider`: Sensitive file paths and extensions. - `UrlRuleProvider`: URLs and web addresses. - `TokenRuleProvider`: JWT and other auth tokens. - `ConnectionStringRuleProvider`: Database connection strings. - `EnvironmentPropertiesRuleProvider`: Environment variables and system properties. ### Internals Tools Page A page in settings available in non-CI-builds: <img width="1305" height="745" alt="image" src="https://github.com/user-attachments/assets/3145ecfd-997f-491d-8c8a-6096634b6045" /> <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] Closes: #xxx <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
155 lines
5.4 KiB
C#
155 lines
5.4 KiB
C#
// Copyright (c) Microsoft Corporation
|
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
// See the LICENSE file in the project root for more information.
|
|
|
|
using CommunityToolkit.Mvvm.Messaging;
|
|
using Microsoft.CmdPal.Core.ViewModels;
|
|
using Microsoft.CmdPal.Core.ViewModels.Messages;
|
|
using Microsoft.CmdPal.UI.Messages;
|
|
using Microsoft.CmdPal.UI.Views;
|
|
using Microsoft.UI.Xaml;
|
|
using Microsoft.UI.Xaml.Controls;
|
|
using Microsoft.UI.Xaml.Controls.Primitives;
|
|
using Windows.System;
|
|
|
|
namespace Microsoft.CmdPal.UI.Controls;
|
|
|
|
public sealed partial class CommandBar : UserControl,
|
|
IRecipient<OpenContextMenuMessage>,
|
|
IRecipient<CloseContextMenuMessage>,
|
|
IRecipient<TryCommandKeybindingMessage>,
|
|
ICurrentPageAware
|
|
{
|
|
public CommandBarViewModel ViewModel { get; } = new();
|
|
|
|
public PageViewModel? CurrentPageViewModel
|
|
{
|
|
get => (PageViewModel?)GetValue(CurrentPageViewModelProperty);
|
|
set => SetValue(CurrentPageViewModelProperty, value);
|
|
}
|
|
|
|
// Using a DependencyProperty as the backing store for CurrentPage. This enables animation, styling, binding, etc...
|
|
public static readonly DependencyProperty CurrentPageViewModelProperty =
|
|
DependencyProperty.Register(nameof(CurrentPageViewModel), typeof(PageViewModel), typeof(CommandBar), new PropertyMetadata(null));
|
|
|
|
public CommandBar()
|
|
{
|
|
this.InitializeComponent();
|
|
|
|
// RegisterAll isn't AOT compatible
|
|
WeakReferenceMessenger.Default.Register<OpenContextMenuMessage>(this);
|
|
WeakReferenceMessenger.Default.Register<CloseContextMenuMessage>(this);
|
|
WeakReferenceMessenger.Default.Register<TryCommandKeybindingMessage>(this);
|
|
}
|
|
|
|
public void Receive(OpenContextMenuMessage message)
|
|
{
|
|
if (message.Element is null)
|
|
{
|
|
// This is invoked from the "More" button on the command bar
|
|
if (!ViewModel.ShouldShowContextMenu)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_ = DispatcherQueue.TryEnqueue(
|
|
() =>
|
|
{
|
|
ContextMenuFlyout.ShowAt(
|
|
MoreCommandsButton,
|
|
new FlyoutShowOptions()
|
|
{
|
|
ShowMode = FlyoutShowMode.Standard,
|
|
Placement = FlyoutPlacementMode.TopEdgeAlignedRight,
|
|
});
|
|
});
|
|
}
|
|
else
|
|
{
|
|
// This is invoked from a specific element
|
|
_ = DispatcherQueue.TryEnqueue(
|
|
() =>
|
|
{
|
|
ContextMenuFlyout.ShowAt(
|
|
message.Element!,
|
|
new FlyoutShowOptions()
|
|
{
|
|
ShowMode = FlyoutShowMode.Standard,
|
|
Placement = (FlyoutPlacementMode)message.FlyoutPlacementMode!,
|
|
Position = message.Point,
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
public void Receive(CloseContextMenuMessage message)
|
|
{
|
|
if (ContextMenuFlyout.IsOpen)
|
|
{
|
|
ContextMenuFlyout.Hide();
|
|
}
|
|
}
|
|
|
|
public void Receive(TryCommandKeybindingMessage msg)
|
|
{
|
|
if (!ViewModel.ShouldShowContextMenu)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var result = ViewModel?.CheckKeybinding(msg.Ctrl, msg.Alt, msg.Shift, msg.Win, msg.Key);
|
|
|
|
if (result == ContextKeybindingResult.Hide)
|
|
{
|
|
msg.Handled = true;
|
|
}
|
|
else if (result == ContextKeybindingResult.KeepOpen)
|
|
{
|
|
WeakReferenceMessenger.Default.Send<OpenContextMenuMessage>(new OpenContextMenuMessage(null, null, null, ContextMenuFilterLocation.Bottom));
|
|
msg.Handled = true;
|
|
}
|
|
else if (result == ContextKeybindingResult.Unhandled)
|
|
{
|
|
msg.Handled = false;
|
|
}
|
|
}
|
|
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "VS has a tendency to delete XAML bound methods over-aggressively")]
|
|
private void PrimaryButton_Clicked(object sender, RoutedEventArgs e)
|
|
{
|
|
ViewModel.InvokePrimaryCommand();
|
|
}
|
|
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "VS has a tendency to delete XAML bound methods over-aggressively")]
|
|
private void SecondaryButton_Clicked(object sender, RoutedEventArgs e)
|
|
{
|
|
ViewModel.InvokeSecondaryCommand();
|
|
}
|
|
|
|
private void SettingsIcon_Clicked(object sender, RoutedEventArgs e)
|
|
{
|
|
WeakReferenceMessenger.Default.Send(new OpenSettingsMessage());
|
|
}
|
|
|
|
private void MoreCommandsButton_Clicked(object sender, RoutedEventArgs e)
|
|
{
|
|
WeakReferenceMessenger.Default.Send<OpenContextMenuMessage>(new OpenContextMenuMessage(null, null, null, ContextMenuFilterLocation.Bottom));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets focus to the "More" button after closing the context menu,
|
|
/// keeping keyboard navigation intuitive.
|
|
/// </summary>
|
|
public void FocusMoreCommandsButton()
|
|
{
|
|
MoreCommandsButton?.Focus(FocusState.Programmatic);
|
|
}
|
|
|
|
private void ContextMenuFlyout_Opened(object sender, object e)
|
|
{
|
|
// We need to wait until our flyout is opened to try and toss focus
|
|
// at its search box. The control isn't in the UI tree before that
|
|
ContextControl.FocusSearchBox();
|
|
}
|
|
}
|