diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj index 056b3767a4c..823656b6e3b 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj +++ b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj @@ -267,6 +267,7 @@ + @@ -980,6 +981,9 @@ MSBuild:Compile Designer + + Designer + Designer MSBuild:Compile diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TabbedCommandBar/TabbedCommandBar.bind b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TabbedCommandBar/TabbedCommandBar.bind new file mode 100644 index 00000000000..66dd11951a9 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TabbedCommandBar/TabbedCommandBar.bind @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TabbedCommandBar/TabbedCommandBar.png b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TabbedCommandBar/TabbedCommandBar.png new file mode 100644 index 00000000000..6477997a952 Binary files /dev/null and b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/TabbedCommandBar/TabbedCommandBar.png differ diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml index 3b7a093050c..c354b2293be 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml @@ -3,6 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ani="using:Microsoft.Toolkit.Uwp.UI.Animations" xmlns:behaviors="using:Microsoft.Toolkit.Uwp.UI.Behaviors" + xmlns:converters="using:Microsoft.Toolkit.Uwp.UI.Converters" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:interactions="using:Microsoft.Xaml.Interactions.Core" xmlns:interactivity="using:Microsoft.Xaml.Interactivity" @@ -17,6 +18,8 @@ + + @@ -34,17 +37,17 @@ - - - - - + + + + + - + diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json index d16fbbaa95c..dc9b13392eb 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json @@ -453,6 +453,15 @@ "XamlCodeFile": "TokenizingTextBoxXaml.bind", "Icon": "/SamplePages/TokenizingTextBox/TokenizingTextBox.png", "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/controls/TokenizingTextBox.md" + }, + { + "Name": "TabbedCommandBar", + "Subcategory": "Menus and Toolbars", + "About": "A control for displaying multiple CommandBars in the same space, like Microsoft Office's ribbon.", + "CodeUrl": "https://github.com/windows-toolkit/WindowsCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar", + "XamlCodeFile": "/SamplePages/TabbedCommandBar/TabbedCommandBar.bind", + "Icon": "/SamplePages/TabbedCommandBar/TabbedCommandBar.png", + "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/controls/TabbedCommandBar.md" } ] }, diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Design/Controls/TabbedCommandBar.Metadata.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Design/Controls/TabbedCommandBar.Metadata.cs new file mode 100644 index 00000000000..557ff70648b --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Design/Controls/TabbedCommandBar.Metadata.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.ComponentModel; + +using Microsoft.Toolkit.Uwp.UI.Controls.Design.Properties; + +using Microsoft.VisualStudio.DesignTools.Extensibility; +using Microsoft.VisualStudio.DesignTools.Extensibility.Metadata; + +namespace Microsoft.Toolkit.Uwp.UI.Controls.Design +{ + internal class TabbedCommandBarMetadata : AttributeTableBuilder + { + public TabbedCommandBarMetadata() + : base() + { + AddCallback(ControlTypes.TabbedCommandBar, + b => + { + b.AddCustomAttributes(nameof(TabbedCommandBar.CollapsedState), new CategoryAttribute(Resources.CategoryAppearance)); + b.AddCustomAttributes(new ToolboxCategoryAttribute(ToolboxCategoryPaths.Toolkit, false)); + } + ); + } + } +} diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Design/Controls/TabbedCommandBar.Typedata.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Design/Controls/TabbedCommandBar.Typedata.cs new file mode 100644 index 00000000000..d37d5eae745 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Design/Controls/TabbedCommandBar.Typedata.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Toolkit.Uwp.UI.Controls.Design +{ + internal static partial class ControlTypes + { + internal const string TabbedCommandBar = RootNamespace + "." + nameof(TabbedCommandBar); + } + + internal static class TabbedCommandBar + { + internal const string CollapsedState = nameof(CollapsedState); + } +} \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Design/Controls/TabbedCommandBarItem.Metadata.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Design/Controls/TabbedCommandBarItem.Metadata.cs new file mode 100644 index 00000000000..1099909bbf8 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Design/Controls/TabbedCommandBarItem.Metadata.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.ComponentModel; + +using Microsoft.Toolkit.Uwp.UI.Controls.Design.Properties; + +using Microsoft.VisualStudio.DesignTools.Extensibility; +using Microsoft.VisualStudio.DesignTools.Extensibility.Metadata; + +namespace Microsoft.Toolkit.Uwp.UI.Controls.Design +{ + internal class TabbedCommandBarItemMetadata : AttributeTableBuilder + { + public TabbedCommandBarItemMetadata() + : base() + { + AddCallback(ControlTypes.TabbedCommandBarItem, + b => + { + // TODO + // b.AddCustomAttributes(nameof(TabbedCommandBarItem.Header), new CategoryAttribute(Resources.CategoryCommon)); + // b.AddCustomAttributes(nameof(TabbedCommandBarItem.Footer), new CategoryAttribute(Resources.CategoryCommon)); + b.AddCustomAttributes(nameof(TabbedCommandBarItem.IsContextual), new CategoryAttribute(Resources.CategoryCommon)); + b.AddCustomAttributes(nameof(TabbedCommandBarItem.OverflowButtonAlignment), + new CategoryAttribute(Resources.CategoryLayout), + new EditorBrowsableAttribute(EditorBrowsableState.Advanced) + ); + b.AddCustomAttributes(new ToolboxCategoryAttribute(ToolboxCategoryPaths.Toolkit, false)); + } + ); + } + } +} diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Design/Controls/TabbedCommandBarItem.Typedata.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Design/Controls/TabbedCommandBarItem.Typedata.cs new file mode 100644 index 00000000000..10a5ec9cdac --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Design/Controls/TabbedCommandBarItem.Typedata.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Toolkit.Uwp.UI.Controls.Design +{ + internal static partial class ControlTypes + { + internal const string TabbedCommandBarItem = RootNamespace + "." + nameof(TabbedCommandBarItem); + } + + internal static class TabbedCommandBarItem + { + internal const string Header = nameof(Header); + internal const string Footer = nameof(Footer); + internal const string IsContextual = nameof(IsContextual); + internal const string OverflowButtonAlignment = nameof(OverflowButtonAlignment); + } +} \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Design/Microsoft.Toolkit.Uwp.UI.Controls.DesignTools.csproj b/Microsoft.Toolkit.Uwp.UI.Controls.Design/Microsoft.Toolkit.Uwp.UI.Controls.DesignTools.csproj index cb7387f0f66..7e97912875b 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Design/Microsoft.Toolkit.Uwp.UI.Controls.DesignTools.csproj +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Design/Microsoft.Toolkit.Uwp.UI.Controls.DesignTools.csproj @@ -119,6 +119,10 @@ + + + + diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/Microsoft.Toolkit.Uwp.UI.Controls.csproj b/Microsoft.Toolkit.Uwp.UI.Controls/Microsoft.Toolkit.Uwp.UI.Controls.csproj index 10577dbb847..aeb9901a367 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/Microsoft.Toolkit.Uwp.UI.Controls.csproj +++ b/Microsoft.Toolkit.Uwp.UI.Controls/Microsoft.Toolkit.Uwp.UI.Controls.csproj @@ -32,6 +32,7 @@ - RemoteDevicePicker: Remote Device Picker Control for Project Rome. - RotatorTile: Rotates through a set of items one-by-one like a live-tile. - StaggeredPanel: Layout of items in a column approach where an item will be added to whichever column has used the least amount of space. + - TabbedCommandBar: A ribbon-like control that displays a tabbed collection of CommandBars - TextToolbar: A Toolbar for Editing Text attached to a RichEditBox. It can format RTF, Markdown, or use a Custom Formatter. - TileControl: A ContentControl that show an image repeated many times. - TokenizingTextBox: An AutoSuggestBox like control which places entered input into easily removed containers for contacts or tags. diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar/TabbedCommandBar.cs b/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar/TabbedCommandBar.cs new file mode 100644 index 00000000000..dcde9b916ad --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar/TabbedCommandBar.cs @@ -0,0 +1,101 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Linq; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Markup; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Media.Animation; + +namespace Microsoft.Toolkit.Uwp.UI.Controls +{ + /// + /// A basic ribbon control that houses s + /// + [ContentProperty(Name = nameof(MenuItems))] + [TemplatePart(Name = "PART_RibbonContent", Type = typeof(ContentControl))] + [TemplatePart(Name = "PART_RibbonContentBorder", Type = typeof(Border))] + [TemplatePart(Name = "PART_TabChangedStoryboard", Type = typeof(Storyboard))] + public class TabbedCommandBar : NavigationView + { + private ContentControl _ribbonContent = null; + private Border _ribbonContentBorder = null; + private Storyboard _tabChangedStoryboard = null; + + /// + /// The last selected . + /// + private TabbedCommandBarItem _previousSelectedItem = null; + private long _visibilityChangedToken; + + /// + /// Initializes a new instance of the class. + /// + public TabbedCommandBar() + { + DefaultStyleKey = typeof(TabbedCommandBar); + + SelectionChanged += SelectedItemChanged; + } + + /// + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + if (_ribbonContent != null) + { + _ribbonContent.Content = null; + } + + // Get RibbonContent first, since setting SelectedItem requires it + _ribbonContent = GetTemplateChild("PART_RibbonContent") as ContentControl; + _ribbonContentBorder = GetTemplateChild("PART_RibbonContentBorder") as Border; + _tabChangedStoryboard = GetTemplateChild("TabChangedStoryboard") as Storyboard; + + SelectedItem = MenuItems.FirstOrDefault(); + } + + private void SelectedItemChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args) + { + var item = sender.SelectedItem as TabbedCommandBarItem; + if (item == null || item.Visibility == Visibility.Collapsed) + { + // If the item is now hidden, select the first item instead. + // I can't think of any way that the visibiltiy would be null + // and still be selectable, but let's handle it just in case. + sender.SelectedItem = sender.MenuItems.FirstOrDefault(); + return; + } + + // Remove the visibility PropertyChanged handler from the + // previously selected item + if (_previousSelectedItem != null) + { + _previousSelectedItem.UnregisterPropertyChangedCallback(TabbedCommandBarItem.VisibilityProperty, _visibilityChangedToken); + } + + // Register a new visibility PropertyChangedcallback for the + // currently selected item + _previousSelectedItem = item; + _visibilityChangedToken = + _previousSelectedItem.RegisterPropertyChangedCallback(TabbedCommandBarItem.VisibilityProperty, SelectedItemVisibilityChanged); + + // Set the ribbon background and start the transition animation + _tabChangedStoryboard?.Begin(); + } + + private void SelectedItemVisibilityChanged(DependencyObject sender, DependencyProperty dp) + { + // If the item is not visible, default to the first tab + if (sender.GetValue(dp) is Visibility vis && vis == Visibility.Collapsed) + { + // FIXME: This will cause WinUI to throw an exception if run + // when the tabs overflow + SelectedItem = MenuItems.FirstOrDefault(); + } + } + } +} diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar/TabbedCommandBar.xaml b/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar/TabbedCommandBar.xaml new file mode 100644 index 00000000000..b4bd56f371e --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar/TabbedCommandBar.xaml @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar/TabbedCommandBarItem.cs b/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar/TabbedCommandBarItem.cs new file mode 100644 index 00000000000..8cf1bb24ba2 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar/TabbedCommandBarItem.cs @@ -0,0 +1,126 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; + +namespace Microsoft.Toolkit.Uwp.UI.Controls +{ + /// + /// A to be displayed in a + /// + [TemplatePart(Name = "PrimaryItemsControl", Type = typeof(ItemsControl))] + [TemplatePart(Name = "MoreButton", Type = typeof(Button))] + public class TabbedCommandBarItem : CommandBar + { + private ItemsControl _primaryItemsControl; + private Button _moreButton; + + /// + /// Initializes a new instance of the class. + /// + public TabbedCommandBarItem() + { + DefaultStyleKey = typeof(TabbedCommandBarItem); + } + + /// + /// Identifies the property. + /// + public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register( + nameof(Header), + typeof(object), + typeof(TabbedCommandBarItem), + new PropertyMetadata(string.Empty)); + + /// + /// Gets or sets the text or to display in the header of this ribbon tab. + /// + public object Header + { + get => (object)GetValue(HeaderProperty); + set => SetValue(HeaderProperty, value); + } + + /// + /// Identifies the property. + /// + public static readonly DependencyProperty IsContextualProperty = DependencyProperty.Register( + nameof(IsContextual), + typeof(bool), + typeof(TabbedCommandBarItem), + new PropertyMetadata(false)); + + /// + /// Gets or sets a value indicating whether this tab is contextual. + /// + public bool IsContextual + { + get => (bool)GetValue(IsContextualProperty); + set => SetValue(IsContextualProperty, value); + } + + /// + /// Identifies the property. + /// + public static readonly DependencyProperty OverflowButtonAlignmentProperty = DependencyProperty.Register( + nameof(OverflowButtonAlignment), + typeof(HorizontalAlignment), + typeof(TabbedCommandBarItem), + new PropertyMetadata(HorizontalAlignment.Left)); + + /// + /// Gets or sets a value indicating the alignment of the command overflow button. + /// + public HorizontalAlignment OverflowButtonAlignment + { + get => (HorizontalAlignment)GetValue(OverflowButtonAlignmentProperty); + set => SetValue(OverflowButtonAlignmentProperty, value); + } + + /// + /// Identifies the property. + /// + public static readonly DependencyProperty CommandAlignmentProperty = DependencyProperty.Register( + nameof(CommandAlignment), + typeof(HorizontalAlignment), + typeof(TabbedCommandBarItem), + new PropertyMetadata(HorizontalAlignment.Stretch)); + + /// + /// Gets or sets a value indicating the alignment of the commands in the . + /// + public HorizontalAlignment CommandAlignment + { + get => (HorizontalAlignment)GetValue(CommandAlignmentProperty); + set => SetValue(CommandAlignmentProperty, value); + } + + /// + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + _primaryItemsControl = GetTemplateChild("PrimaryItemsControl") as ItemsControl; + if (_primaryItemsControl != null) + { + _primaryItemsControl.HorizontalAlignment = CommandAlignment; + RegisterPropertyChangedCallback(CommandAlignmentProperty, (sender, dp) => + { + _primaryItemsControl.HorizontalAlignment = (HorizontalAlignment)sender.GetValue(dp); + }); + } + + _moreButton = GetTemplateChild("MoreButton") as Button; + if (_moreButton != null) + { + _moreButton.HorizontalAlignment = OverflowButtonAlignment; + RegisterPropertyChangedCallback(OverflowButtonAlignmentProperty, (sender, dp) => + { + _moreButton.HorizontalAlignment = (HorizontalAlignment)sender.GetValue(dp); + }); + } + } + } +} \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar/TabbedCommandBarItem.xaml b/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar/TabbedCommandBarItem.xaml new file mode 100644 index 00000000000..d05424ee99e --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar/TabbedCommandBarItem.xaml @@ -0,0 +1,368 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar/TabbedCommandBarItemTemplateSelector.cs b/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar/TabbedCommandBarItemTemplateSelector.cs new file mode 100644 index 00000000000..0c68a9b35f5 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls/TabbedCommandBar/TabbedCommandBarItemTemplateSelector.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; + +namespace Microsoft.Toolkit.Uwp.UI.Controls +{ + /// + /// used by for determining the style of normal vs. contextual s. + /// + public class TabbedCommandBarItemTemplateSelector : DataTemplateSelector + { + /// + /// Gets or sets the of a normal . + /// + public DataTemplate Normal { get; set; } + + /// + /// Gets or sets the of a contextual . + /// + public DataTemplate Contextual { get; set; } + + /// + protected override DataTemplate SelectTemplateCore(object item) + { + return item is TabbedCommandBarItem t && t.IsContextual ? Contextual : Normal; + } + + /// + protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) + { + return SelectTemplateCore(item); + } + } +} diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/Themes/Generic.xaml b/Microsoft.Toolkit.Uwp.UI.Controls/Themes/Generic.xaml index a6c650d3a4b..176af58ede4 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/Themes/Generic.xaml +++ b/Microsoft.Toolkit.Uwp.UI.Controls/Themes/Generic.xaml @@ -31,6 +31,7 @@ + diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/VisualStudioToolsManifest.xml b/Microsoft.Toolkit.Uwp.UI.Controls/VisualStudioToolsManifest.xml index b952e2ec958..479fe150be9 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/VisualStudioToolsManifest.xml +++ b/Microsoft.Toolkit.Uwp.UI.Controls/VisualStudioToolsManifest.xml @@ -31,6 +31,7 @@ +