Compare commits

...

2 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
018f9417a1 feat(cmdpal): Implement CommandResult.GoToPage()
Add handling for CommandResultKind.GoToPage in the shell, allowing
extensions to navigate to a specific top-level page after a command
completes, with Push, GoBack, or GoHome navigation modes.

Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
Agent-Logs-Url: https://github.com/microsoft/PowerToys/sessions/dfde3ba3-e879-4fd7-ad6d-667e5ba79632
2026-03-24 12:14:45 +00:00
copilot-swe-agent[bot]
658ddead43 Initial plan 2026-03-24 11:57:01 +00:00
7 changed files with 208 additions and 1 deletions

View File

@@ -0,0 +1,7 @@
// 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.
namespace Microsoft.CmdPal.UI.ViewModels.Messages;
public record GoToPageResultMessage(Microsoft.CommandPalette.Extensions.IGoToPageArgs? Args);

View File

@@ -467,6 +467,16 @@ public partial class ShellViewModel : ObservableObject,
UnsafeHandleCommandResult(a.Result);
}
break;
}
case CommandResultKind.GoToPage:
{
if (result.Args is IGoToPageArgs a)
{
WeakReferenceMessenger.Default.Send<GoToPageResultMessage>(new(a));
}
break;
}
}

View File

@@ -51,6 +51,7 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
IRecipient<ShowToastMessage>,
IRecipient<NavigateToPageMessage>,
IRecipient<ShowHideDockMessage>,
IRecipient<GoToPageResultMessage>,
INotifyPropertyChanged,
IDisposable
{
@@ -100,6 +101,7 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
WeakReferenceMessenger.Default.Register<ShowConfirmationMessage>(this);
WeakReferenceMessenger.Default.Register<ShowToastMessage>(this);
WeakReferenceMessenger.Default.Register<NavigateToPageMessage>(this);
WeakReferenceMessenger.Default.Register<GoToPageResultMessage>(this);
WeakReferenceMessenger.Default.Register<ShowHideDockMessage>(this);
@@ -202,6 +204,21 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
});
}
public void Receive(GoToPageResultMessage message)
{
DispatcherQueue.TryEnqueue(() =>
{
try
{
HandleGoToPageOnUiThread(message.Args);
}
catch (Exception ex)
{
Logger.LogError(ex.ToString());
}
});
}
public void Receive(ShowToastMessage message)
{
DispatcherQueue.TryEnqueue(() =>
@@ -265,6 +282,55 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
private void InitializeConfirmationDialog(ConfirmResultViewModel vm) => vm.SafeInitializePropertiesSynchronous();
// This gets called from the UI thread
private void HandleGoToPageOnUiThread(IGoToPageArgs? args)
{
if (args is null)
{
return;
}
var pageId = args.PageId;
var navigationMode = args.NavigationMode;
if (string.IsNullOrEmpty(pageId))
{
Logger.LogWarning("GoToPage: PageId is null or empty");
return;
}
var tlcManager = App.Current.Services.GetService<TopLevelCommandManager>()!;
var topLevelCommand = tlcManager.LookupCommand(pageId);
if (topLevelCommand is null)
{
Logger.LogWarning($"GoToPage: Could not find page with ID '{pageId}'");
return;
}
switch (navigationMode)
{
case NavigationMode.GoHome:
GoHome(withAnimation: false, focusSearch: false);
break;
case NavigationMode.GoBack:
if (RootFrame.CanGoBack)
{
GoBack(withAnimation: false, focusSearch: false);
}
break;
case NavigationMode.Push:
default:
break;
}
var msg = topLevelCommand.GetPerformCommandMessage();
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(msg);
}
public void Receive(OpenSettingsMessage message)
{
_ = DispatcherQueue.TryEnqueue(() =>

View File

@@ -0,0 +1,36 @@
// 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 Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension.Pages;
public sealed partial class SampleGoToLandingPage : ListPage
{
public const string PageId = "com.microsoft.SamplePages.GoToLandingPage";
public SampleGoToLandingPage()
{
Icon = new IconInfo("\uEA37");
Name = "GoToPage Sample: Landing Page";
Id = PageId;
}
public override IListItem[] GetItems()
{
return [
new ListItem(new NoOpCommand())
{
Title = "You have arrived at the landing page!",
Subtitle = "This page was navigated to via CommandResult.GoToPage()",
},
new ListItem(new NoOpCommand())
{
Title = "This is a sample landing page",
Subtitle = "Extensions can use GoToPage to direct users here after completing an action",
},
];
}
}

View File

@@ -0,0 +1,78 @@
// 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 Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension.Pages;
/// <summary>
/// A sample page that demonstrates the CommandResult.GoToPage() feature.
/// It shows three different NavigationMode options:
/// Push - adds the landing page on top of the current stack
/// GoBack - goes back one level, then navigates to the landing page
/// GoHome - clears the entire stack, then navigates to the landing page
/// </summary>
public sealed partial class SampleGoToPage : ListPage
{
public SampleGoToPage()
{
Icon = new IconInfo("\uEA37");
Name = "GoToPage Sample";
}
public override IListItem[] GetItems()
{
var pushArgs = new GoToPageArgs
{
PageId = SampleGoToLandingPage.PageId,
NavigationMode = NavigationMode.Push,
};
var goBackArgs = new GoToPageArgs
{
PageId = SampleGoToLandingPage.PageId,
NavigationMode = NavigationMode.GoBack,
};
var goHomeArgs = new GoToPageArgs
{
PageId = SampleGoToLandingPage.PageId,
NavigationMode = NavigationMode.GoHome,
};
return [
new ListItem(
new AnonymousCommand(() => { })
{
Result = CommandResult.GoToPage(pushArgs),
})
{
Title = "Push: Navigate to landing page (keep back stack)",
Subtitle = "Adds the landing page on top of the current navigation stack",
Icon = new IconInfo("\uEA37"),
},
new ListItem(
new AnonymousCommand(() => { })
{
Result = CommandResult.GoToPage(goBackArgs),
})
{
Title = "GoBack: Go back one level, then navigate to landing page",
Subtitle = "Removes one page from the back stack before navigating",
Icon = new IconInfo("\uE760"),
},
new ListItem(
new AnonymousCommand(() => { })
{
Result = CommandResult.GoToPage(goHomeArgs),
})
{
Title = "GoHome: Clear stack, then navigate to landing page",
Subtitle = "Clears the entire navigation stack before navigating",
Icon = new IconInfo("\uE80F"),
},
];
}
}

View File

@@ -22,6 +22,11 @@ public partial class SamplePagesCommandsProvider : CommandProvider
Title = "Sample Pages",
Subtitle = "View example commands",
},
new CommandItem(new Pages.SampleGoToLandingPage())
{
Title = "GoToPage Sample: Landing Page",
Subtitle = "Target landing page for the GoToPage sample",
},
];
public override ICommandItem[] TopLevelCommands()

View File

@@ -124,7 +124,12 @@ public partial class SamplesListPage : ListPage
{
Title = "Issue-specific samples",
Subtitle = "Samples designed to reproduce specific issues",
}
},
new ListItem(new SampleGoToPage())
{
Title = "GoToPage Sample",
Subtitle = "Demonstrates CommandResult.GoToPage() with Push, GoBack, and GoHome modes",
},
];
public SamplesListPage()