diff --git a/.github/actions/spell-check/allow/code.txt b/.github/actions/spell-check/allow/code.txt
index fee0314208..50a4b55e5b 100644
--- a/.github/actions/spell-check/allow/code.txt
+++ b/.github/actions/spell-check/allow/code.txt
@@ -315,6 +315,7 @@ xef
xes
PACKAGEVERSIONNUMBER
APPXMANIFESTVERSION
+PROGMAN
# MRU lists
CACHEWRITE
@@ -325,6 +326,14 @@ REGSTR
# Misc Win32 APIs and PInvokes
INVOKEIDLIST
MEMORYSTATUSEX
+ABE
+HTCAPTION
+POSCHANGED
+QUERYPOS
+SETAUTOHIDEBAR
+WINDOWPOS
+WINEVENTPROC
+WORKERW
# PowerRename metadata pattern abbreviations (used in tests and regex patterns)
DDDD
@@ -349,3 +358,6 @@ nostdin
# Performance counter keys
engtype
Nonpaged
+
+# XAML
+Untargeted
diff --git a/src/modules/cmdpal/.wt.json b/src/modules/cmdpal/.wt.json
index 230329e876..4488d6b025 100644
--- a/src/modules/cmdpal/.wt.json
+++ b/src/modules/cmdpal/.wt.json
@@ -26,6 +26,11 @@
"input": "pushd .\\ExtensionTemplate\\ ; git archive -o ..\\Microsoft.CmdPal.UI.ViewModels\\Assets\\template.zip HEAD -- .\\TemplateCmdPalExtension\\ ; popd",
"name": "Update template project",
"description": "zips up the ExtensionTemplate into our assets. Run this in the cmdpal/ directory."
+ },
+ {
+ "input": " .\\extensionsdk\\nuget\\BuildSDKHelper.ps1 -VersionOfSDK 0.0.1",
+ "name": "Build SDK",
+ "description": "Builds the SDK nuget package with the specified version."
}
]
}
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.Common/CoreLogger.cs b/src/modules/cmdpal/Microsoft.CmdPal.Common/CoreLogger.cs
index 4540544d05..650cebec32 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.Common/CoreLogger.cs
+++ b/src/modules/cmdpal/Microsoft.CmdPal.Common/CoreLogger.cs
@@ -2,8 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-
namespace Microsoft.CmdPal.Common;
public static class CoreLogger
@@ -15,6 +13,8 @@ public static class CoreLogger
private static ILogger? _logger;
+ public static ILogger? Instance => _logger;
+
public static void LogError(string message, Exception ex, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
_logger?.LogError(message, ex, memberName, sourceFilePath, sourceLineNumber);
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.Common/Helpers/PinnedDockItem.cs b/src/modules/cmdpal/Microsoft.CmdPal.Common/Helpers/PinnedDockItem.cs
new file mode 100644
index 0000000000..295ea06232
--- /dev/null
+++ b/src/modules/cmdpal/Microsoft.CmdPal.Common/Helpers/PinnedDockItem.cs
@@ -0,0 +1,24 @@
+// 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 Microsoft.CmdPal.Common.Helpers;
+
+public partial class PinnedDockItem : WrappedDockItem
+{
+ public override string Title => $"{base.Title} ({Properties.Resources.PinnedItemSuffix})";
+
+ public PinnedDockItem(ICommand command)
+ : base(command, command.Name)
+ {
+ }
+
+ public PinnedDockItem(IListItem item, string id)
+ : base([item], id, item.Title)
+ {
+ Icon = item.Icon;
+ }
+}
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.Common/Properties/Resources.Designer.cs b/src/modules/cmdpal/Microsoft.CmdPal.Common/Properties/Resources.Designer.cs
index 2837c1a1bd..f79dbd8817 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.Common/Properties/Resources.Designer.cs
+++ b/src/modules/cmdpal/Microsoft.CmdPal.Common/Properties/Resources.Designer.cs
@@ -72,5 +72,14 @@ namespace Microsoft.CmdPal.Common.Properties {
return ResourceManager.GetString("ErrorReport_Global_Preamble", resourceCulture);
}
}
+
+ ///
+ /// Looks up a localized string similar to Pinned.
+ ///
+ internal static string PinnedItemSuffix {
+ get {
+ return ResourceManager.GetString("PinnedItemSuffix", resourceCulture);
+ }
+ }
}
}
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.Common/Properties/Resources.resx b/src/modules/cmdpal/Microsoft.CmdPal.Common/Properties/Resources.resx
index e2aa867ad2..0939fc052a 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.Common/Properties/Resources.resx
+++ b/src/modules/cmdpal/Microsoft.CmdPal.Common/Properties/Resources.resx
@@ -1,4 +1,4 @@
-
+
-
+
@@ -21,6 +22,7 @@
+
@@ -29,6 +31,12 @@
240
+
+
+
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/App.xaml.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI/App.xaml.cs
index 3e4e4adb65..32f1161e97 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.UI/App.xaml.cs
+++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/App.xaml.cs
@@ -28,6 +28,7 @@ using Microsoft.CmdPal.UI.Helpers;
using Microsoft.CmdPal.UI.Services;
using Microsoft.CmdPal.UI.ViewModels;
using Microsoft.CmdPal.UI.ViewModels.BuiltinCommands;
+using Microsoft.CmdPal.UI.ViewModels.Dock;
using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CmdPal.UI.ViewModels.Services;
using Microsoft.CommandPalette.Extensions;
@@ -220,6 +221,7 @@ public partial class App : Application, IDisposable
// ViewModels
services.AddSingleton();
+ services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
}
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/CommandPaletteContextMenuFactory.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI/CommandPaletteContextMenuFactory.cs
index 36f1c1b8c8..2f15e4b213 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.UI/CommandPaletteContextMenuFactory.cs
+++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/CommandPaletteContextMenuFactory.cs
@@ -6,6 +6,7 @@ using CommunityToolkit.Mvvm.Messaging;
using ManagedCommon;
using Microsoft.CmdPal.UI.ViewModels;
using Microsoft.CmdPal.UI.ViewModels.Messages;
+using Microsoft.CmdPal.UI.ViewModels.Settings;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using RS_ = Microsoft.CmdPal.UI.Helpers.ResourceLoaderInstance;
@@ -23,22 +24,45 @@ internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFac
_topLevelCommandManager = topLevelCommandManager;
}
+ ///
+ /// Constructs the view models for the MoreCommands of a
+ /// CommandItemViewModel. In our case, we can use our settings to add a
+ /// contextually-relevant pin/unpin command to this item.
+ ///
+ /// This is called on all CommandItemViewModels. There are however some
+ /// weird edge cases we need to handle, concerning
+ ///
public List UnsafeBuildAndInitMoreCommands(
IContextItem[] items,
CommandItemViewModel commandItem)
{
var results = DefaultContextMenuFactory.Instance.UnsafeBuildAndInitMoreCommands(items, commandItem);
+ IPageContext? page = null;
+ var succeeded = commandItem.PageContext.TryGetTarget(out page);
+ if (!succeeded || page is null)
+ {
+ return results;
+ }
+
+ var isTopLevelItem = page is TopLevelItemPageContext;
+ if (isTopLevelItem)
+ {
+ // Bail early. We'll handle it below.
+ return results;
+ }
+
List moreCommands = [];
var itemId = commandItem.Command.Id;
+ var providerContext = page.ProviderContext;
+ var supportsPinning = providerContext.SupportsPinning;
- if (commandItem.PageContext.TryGetTarget(out var page) &&
- page.ProviderContext.SupportsPinning &&
+ if (supportsPinning &&
!string.IsNullOrEmpty(itemId))
{
// Add pin/unpin commands for pinning items to the top-level or to
// the dock.
- var providerId = page.ProviderContext.ProviderId;
+ var providerId = providerContext.ProviderId;
if (_topLevelCommandManager.LookupProvider(providerId) is CommandProviderWrapper provider)
{
var providerSettings = _settingsModel.GetProviderSettings(provider);
@@ -51,8 +75,6 @@ internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFac
// We can't look up if this command item is in the top level
// items in the manager, because we are being called _before_ we
// get added to the manager's list of commands.
- var isTopLevelItem = page is TopLevelItemPageContext;
-
if (!isTopLevelItem || alreadyPinnedToTopLevel)
{
var pinToTopLevelCommand = new PinToCommand(
@@ -66,6 +88,8 @@ internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFac
var contextItem = new PinToContextItem(pinToTopLevelCommand, commandItem);
moreCommands.Add(contextItem);
}
+
+ TryAddPinToDockCommand(providerSettings, itemId, providerId, moreCommands, commandItem);
}
}
@@ -79,6 +103,99 @@ internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFac
return results;
}
+ ///
+ /// Called to create the context menu on TopLevelViewModels.
+ ///
+ /// These are handled differently from everyone else. With
+ /// TopLevelViewModels, the ID isn't on the Command, it is on the
+ /// TopLevelViewModel itself. Basically, we can't figure out how to add
+ /// pin/unpin commands directly attached to the ICommandItems that we get
+ /// from the API.
+ ///
+ /// Instead, this method is used to extend the set of IContextItems that are
+ /// added to the TopLevelViewModel itself. This lets us pin/unpin the
+ /// generated ID of the TopLevelViewModel, even if the command didn't have
+ /// one.
+ ///
+ public void AddMoreCommandsToTopLevel(
+ TopLevelViewModel topLevelItem,
+ ICommandProviderContext providerContext,
+ List contextItems)
+ {
+ var itemId = topLevelItem.Id;
+ var supportsPinning = providerContext.SupportsPinning;
+ List moreCommands = [];
+ var commandItem = topLevelItem.ItemViewModel;
+
+ // Add pin/unpin commands for pinning items to the top-level or to
+ // the dock.
+ var providerId = providerContext.ProviderId;
+ if (_topLevelCommandManager.LookupProvider(providerId) is CommandProviderWrapper provider)
+ {
+ var providerSettings = _settingsModel.GetProviderSettings(provider);
+
+ var isPinnedSubCommand = providerSettings.PinnedCommandIds.Contains(itemId);
+ if (isPinnedSubCommand)
+ {
+ var pinToTopLevelCommand = new PinToCommand(
+ commandId: itemId,
+ providerId: providerId,
+ pin: !isPinnedSubCommand,
+ PinLocation.TopLevel,
+ _settingsModel,
+ _topLevelCommandManager);
+
+ var contextItem = new PinToContextItem(pinToTopLevelCommand, commandItem);
+ moreCommands.Add(contextItem);
+ }
+
+ TryAddPinToDockCommand(providerSettings, itemId, providerId, moreCommands, commandItem);
+ }
+
+ if (moreCommands.Count > 0)
+ {
+ moreCommands.Insert(0, new Separator());
+
+ // var moreResults = DefaultContextMenuFactory.Instance.UnsafeBuildAndInitMoreCommands(moreCommands.ToArray(), commandItem);
+ contextItems.AddRange(moreCommands);
+ }
+ }
+
+ private void TryAddPinToDockCommand(
+ ProviderSettings providerSettings,
+ string itemId,
+ string providerId,
+ List moreCommands,
+ CommandItemViewModel commandItem)
+ {
+ if (!_settingsModel.EnableDock)
+ {
+ return;
+ }
+
+ var inStartBands = _settingsModel.DockSettings.StartBands.Any(band => MatchesBand(band, itemId, providerId));
+ var inCenterBands = _settingsModel.DockSettings.CenterBands.Any(band => MatchesBand(band, itemId, providerId));
+ var inEndBands = _settingsModel.DockSettings.EndBands.Any(band => MatchesBand(band, itemId, providerId));
+ var alreadyPinned = inStartBands || inCenterBands || inEndBands; /** &&
+ _settingsModel.DockSettings.PinnedCommands.Contains(this.Id)**/
+ var pinToTopLevelCommand = new PinToCommand(
+ commandId: itemId,
+ providerId: providerId,
+ pin: !alreadyPinned,
+ PinLocation.Dock,
+ _settingsModel,
+ _topLevelCommandManager);
+
+ var contextItem = new PinToContextItem(pinToTopLevelCommand, commandItem);
+ moreCommands.Add(contextItem);
+ }
+
+ internal static bool MatchesBand(DockBandSettings bandSettings, string commandId, string providerId)
+ {
+ return bandSettings.CommandId == commandId &&
+ bandSettings.ProviderId == providerId;
+ }
+
internal enum PinLocation
{
TopLevel,
@@ -119,9 +236,13 @@ internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFac
private readonly bool _pin;
private readonly PinLocation _pinLocation;
+ private bool IsPinToDock => _pinLocation == PinLocation.Dock;
+
public override IconInfo Icon => _pin ? Icons.PinIcon : Icons.UnpinIcon;
- public override string Name => _pin ? RS_.GetString("top_level_pin_command_name") : RS_.GetString("top_level_unpin_command_name");
+ public override string Name => _pin ?
+ (IsPinToDock ? RS_.GetString("dock_pin_command_name") : RS_.GetString("top_level_pin_command_name")) :
+ (IsPinToDock ? RS_.GetString("dock_unpin_command_name") : RS_.GetString("top_level_unpin_command_name"));
internal event EventHandler? PinStateChanged;
@@ -152,10 +273,9 @@ internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFac
PinToTopLevel();
break;
- // TODO: After dock is added:
- // case PinLocation.Dock:
- // PinToDock();
- // break;
+ case PinLocation.Dock:
+ PinToDock();
+ break;
}
}
else
@@ -166,9 +286,9 @@ internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFac
UnpinFromTopLevel();
break;
- // case PinLocation.Dock:
- // UnpinFromDock();
- // break;
+ case PinLocation.Dock:
+ UnpinFromDock();
+ break;
}
}
@@ -188,5 +308,17 @@ internal sealed partial class CommandPaletteContextMenuFactory : IContextMenuFac
UnpinCommandItemMessage message = new(_providerId, _commandId);
WeakReferenceMessenger.Default.Send(message);
}
+
+ private void PinToDock()
+ {
+ PinToDockMessage message = new(_providerId, _commandId, true);
+ WeakReferenceMessenger.Default.Send(message);
+ }
+
+ private void UnpinFromDock()
+ {
+ PinToDockMessage message = new(_providerId, _commandId, false);
+ WeakReferenceMessenger.Default.Send(message);
+ }
}
}
diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/CommandBar.xaml b/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/CommandBar.xaml
index fc265d80bf..f6897a9870 100644
--- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/CommandBar.xaml
+++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/CommandBar.xaml
@@ -97,7 +97,7 @@
+ Visibility="{x:Bind CurrentPageViewModel.IsRootPage, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
\ No newline at end of file
diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/TimeDateCommandsProvider.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/TimeDateCommandsProvider.cs
index 8689d51078..e2012559b8 100644
--- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/TimeDateCommandsProvider.cs
+++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/TimeDateCommandsProvider.cs
@@ -20,6 +20,8 @@ public sealed partial class TimeDateCommandsProvider : CommandProvider
private static readonly TimeDateExtensionPage _timeDateExtensionPage = new(_settingsManager);
private readonly FallbackTimeDateItem _fallbackTimeDateItem = new(_settingsManager);
+ private readonly ListItem _bandItem;
+
public TimeDateCommandsProvider()
{
DisplayName = Resources.Microsoft_plugin_timedate_plugin_name;
@@ -33,6 +35,8 @@ public sealed partial class TimeDateCommandsProvider : CommandProvider
Icon = _timeDateExtensionPage.Icon;
Settings = _settingsManager.Settings;
+
+ _bandItem = new NowDockBand();
}
private string GetTranslatedPluginDescription()
@@ -47,4 +51,85 @@ public sealed partial class TimeDateCommandsProvider : CommandProvider
public override ICommandItem[] TopLevelCommands() => [_command];
public override IFallbackCommandItem[] FallbackCommands() => [_fallbackTimeDateItem];
+
+ public override ICommandItem[] GetDockBands()
+ {
+ var wrappedBand = new WrappedDockItem(
+ [_bandItem],
+ "com.microsoft.cmdpal.timedate.dockBand",
+ Resources.Microsoft_plugin_timedate_dock_band_title);
+
+ return new ICommandItem[] { wrappedBand };
+ }
}
+#pragma warning disable SA1402 // File may only contain a single type
+
+internal sealed partial class NowDockBand : ListItem
+{
+ private static readonly TimeSpan UpdateInterval = TimeSpan.FromSeconds(60);
+ private CopyTextCommand _copyTimeCommand;
+ private CopyTextCommand _copyDateCommand;
+
+ public NowDockBand()
+ {
+ Command = new NoOpCommand() { Id = "com.microsoft.cmdpal.timedate.dockBand" };
+ _copyTimeCommand = new CopyTextCommand(string.Empty) { Name = Resources.timedate_copy_time_command_name };
+ _copyDateCommand = new CopyTextCommand(string.Empty) { Name = Resources.timedate_copy_date_command_name };
+ MoreCommands = [
+ new CommandContextItem(_copyTimeCommand),
+ new CommandContextItem(_copyDateCommand)
+ ];
+ UpdateText();
+
+ // Create a timer to update the time every minute
+ System.Timers.Timer timer = new(UpdateInterval.TotalMilliseconds);
+
+ // but we want it to tick on the minute, so calculate the initial delay
+ var now = DateTime.Now;
+ timer.Interval = UpdateInterval.TotalMilliseconds - ((now.Second * 1000) + now.Millisecond);
+
+ // then after the first tick, set it to 60 seconds
+ timer.Elapsed += Timer_ElapsedFirst;
+ timer.Start();
+ }
+
+ private void Timer_ElapsedFirst(object sender, System.Timers.ElapsedEventArgs e)
+ {
+ // After the first tick, set the interval to 60 seconds
+ if (sender is System.Timers.Timer timer)
+ {
+ timer.Interval = UpdateInterval.TotalMilliseconds;
+ timer.Elapsed -= Timer_ElapsedFirst;
+ timer.Elapsed += Timer_Elapsed;
+
+ // Still call the callback, so that we update the clock
+ Timer_Elapsed(sender, e);
+ }
+ }
+
+ private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
+ {
+ UpdateText();
+ }
+
+ private void UpdateText()
+ {
+ var timeExtended = false; // timeLongFormat ?? settings.TimeWithSecond;
+ var dateExtended = false; // dateLongFormat ?? settings.DateWithWeekday;
+ var dateTimeNow = DateTime.Now;
+
+ var timeString = dateTimeNow.ToString(
+ TimeAndDateHelper.GetStringFormat(FormatStringType.Time, timeExtended, dateExtended),
+ CultureInfo.CurrentCulture);
+ var dateString = dateTimeNow.ToString(
+ TimeAndDateHelper.GetStringFormat(FormatStringType.Date, timeExtended, dateExtended),
+ CultureInfo.CurrentCulture);
+
+ Title = timeString;
+ Subtitle = dateString;
+
+ _copyDateCommand.Text = dateString;
+ _copyTimeCommand.Text = timeString;
+ }
+}
+#pragma warning restore SA1402 // File may only contain a single type
diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WinGet/Pages/WinGetExtensionPage.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WinGet/Pages/WinGetExtensionPage.cs
index e84802b8fa..91a55d935f 100644
--- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WinGet/Pages/WinGetExtensionPage.cs
+++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WinGet/Pages/WinGetExtensionPage.cs
@@ -42,6 +42,7 @@ internal sealed partial class WinGetExtensionPage : DynamicListPage, IDisposable
public WinGetExtensionPage(string tag = "")
{
Icon = tag == ExtensionsTag ? Icons.ExtensionsIcon : Icons.WinGetIcon;
+ Id = tag == ExtensionsTag ? "com.microsoft.cmdpal.winget-extensions" : "com.microsoft.cmdpal.winget";
Name = Properties.Resources.winget_page_name;
_tag = tag;
ShowDetails = true;
diff --git a/src/modules/cmdpal/ext/SamplePagesExtension/SampleButtonsDockBand.cs b/src/modules/cmdpal/ext/SamplePagesExtension/SampleButtonsDockBand.cs
new file mode 100644
index 0000000000..c7012b2d25
--- /dev/null
+++ b/src/modules/cmdpal/ext/SamplePagesExtension/SampleButtonsDockBand.cs
@@ -0,0 +1,30 @@
+// 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 System.Collections.Generic;
+using Microsoft.CommandPalette.Extensions;
+using Microsoft.CommandPalette.Extensions.Toolkit;
+
+namespace SamplePagesExtension;
+
+///
+/// A sample dock band with multiple buttons.
+/// Each button shows a toast message when clicked.
+///
+internal sealed partial class SampleButtonsDockBand : WrappedDockItem
+{
+ public SampleButtonsDockBand()
+ : base([], "com.microsoft.cmdpal.samples.buttons_band", "Sample Buttons Band")
+ {
+ ListItem[] buttons = [
+ new(new ShowToastCommand("Button 1")) { Title = "1" },
+ new(new ShowToastCommand("Button B")) { Icon = new IconInfo("\uF094") }, // B button
+ new(new ShowToastCommand("Button 3")) { Title = "Items have Icons &", Icon = new IconInfo("\uED1E"), Subtitle = "titles & subtitles" }, // Subtitles
+ ];
+ Icon = new IconInfo("\uEECA"); // ButtonView2
+ Items = buttons;
+ }
+}
+
+#pragma warning restore SA1402 // File may only contain a single type
diff --git a/src/modules/cmdpal/ext/SamplePagesExtension/SampleDockBand.cs b/src/modules/cmdpal/ext/SamplePagesExtension/SampleDockBand.cs
new file mode 100644
index 0000000000..b95a50ab69
--- /dev/null
+++ b/src/modules/cmdpal/ext/SamplePagesExtension/SampleDockBand.cs
@@ -0,0 +1,22 @@
+// 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.Toolkit;
+
+namespace SamplePagesExtension;
+#pragma warning disable SA1402 // File may only contain a single type
+
+///
+/// A sample dock band with one button.
+/// Clicking on this button will open the palette to the samples list page
+///
+internal sealed partial class SampleDockBand : WrappedDockItem
+{
+ public SampleDockBand()
+ : base(new SamplesListPage(), "Command Palette Samples")
+ {
+ }
+}
+
+#pragma warning restore SA1402 // File may only contain a single type
diff --git a/src/modules/cmdpal/ext/SamplePagesExtension/SamplePagesCommandsProvider.cs b/src/modules/cmdpal/ext/SamplePagesExtension/SamplePagesCommandsProvider.cs
index e500c25d8d..d24d4964d3 100644
--- a/src/modules/cmdpal/ext/SamplePagesExtension/SamplePagesCommandsProvider.cs
+++ b/src/modules/cmdpal/ext/SamplePagesExtension/SamplePagesCommandsProvider.cs
@@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
@@ -27,4 +28,15 @@ public partial class SamplePagesCommandsProvider : CommandProvider
{
return _commands;
}
+
+ public override ICommandItem[] GetDockBands()
+ {
+ List bands = new()
+ {
+ new SampleDockBand(),
+ new SampleButtonsDockBand(),
+ };
+
+ return bands.ToArray();
+ }
}
diff --git a/src/modules/cmdpal/ext/SamplePagesExtension/ShowToastCommand.cs b/src/modules/cmdpal/ext/SamplePagesExtension/ShowToastCommand.cs
new file mode 100644
index 0000000000..67bbd30fc5
--- /dev/null
+++ b/src/modules/cmdpal/ext/SamplePagesExtension/ShowToastCommand.cs
@@ -0,0 +1,19 @@
+// 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 System.Collections.Generic;
+using Microsoft.CommandPalette.Extensions;
+using Microsoft.CommandPalette.Extensions.Toolkit;
+
+namespace SamplePagesExtension;
+
+internal sealed partial class ShowToastCommand(string message) : InvokableCommand
+{
+ public override ICommandResult Invoke()
+ {
+ return CommandResult.ShowToast(message);
+ }
+}
+
+#pragma warning restore SA1402 // File may only contain a single type