Implemented exporting and import of publisher messages

This commit is contained in:
Mark van Renswoude 2022-01-23 20:33:27 +01:00
parent b3c432d629
commit d6b9970d51
20 changed files with 407 additions and 120 deletions

View File

@ -1,4 +1,6 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using PettingZoo.Core.Connection;
namespace PettingZoo.Core.ExportImport.Publisher
@ -11,48 +13,189 @@ namespace PettingZoo.Core.ExportImport.Publisher
public class PublisherMessage
public class PublisherMessage : IEquatable<PublisherMessage>
{
public PublisherMessageType MessageType { get; set; }
public bool SendToExchange { get; set; }
public string? Exchange { get; set; }
public string? RoutingKey { get; set; }
public string? Queue { get; set; }
public bool ReplyToNewSubscriber { get; set; }
public string? ReplyTo { get; set; }
public PublisherMessageType MessageType { get; init; }
public bool SendToExchange { get; init; }
public string? Exchange { get; init; }
public string? RoutingKey { get; init; }
public string? Queue { get; init; }
public bool ReplyToNewSubscriber { get; init; }
public string? ReplyTo { get; init; }
public RawPublisherMessage? RawPublisherMessage { get; set; }
public TapetiPublisherMessage? TapetiPublisherMessage { get; set; }
public RawPublisherMessage? RawPublisherMessage { get; init; }
public TapetiPublisherMessage? TapetiPublisherMessage { get; init; }
public bool Equals(PublisherMessage? other)
{
if (other == null) return false;
if (ReferenceEquals(this, other)) return true;
return MessageType == other.MessageType &&
SendToExchange == other.SendToExchange &&
Exchange == other.Exchange &&
RoutingKey == other.RoutingKey &&
Queue == other.Queue &&
ReplyToNewSubscriber == other.ReplyToNewSubscriber &&
ReplyTo == other.ReplyTo &&
Equals(RawPublisherMessage, other.RawPublisherMessage) &&
Equals(TapetiPublisherMessage, other.TapetiPublisherMessage);
}
public override bool Equals(object? obj)
{
if (obj == null) return false;
if (ReferenceEquals(this, obj)) return true;
return obj is PublisherMessage publisherMessage && Equals(publisherMessage);
}
public override int GetHashCode()
{
var hashCode = new HashCode();
hashCode.Add((int)MessageType);
hashCode.Add(SendToExchange);
hashCode.Add(Exchange);
hashCode.Add(RoutingKey);
hashCode.Add(Queue);
hashCode.Add(ReplyToNewSubscriber);
hashCode.Add(ReplyTo);
hashCode.Add(RawPublisherMessage);
hashCode.Add(TapetiPublisherMessage);
return hashCode.ToHashCode();
}
}
public class RawPublisherMessage
public class RawPublisherMessage : IEquatable<RawPublisherMessage>
{
public MessageDeliveryMode DeliveryMode { get; set; }
public MessageDeliveryMode DeliveryMode { get; init; }
public string? ContentType { get; set; }
public string? CorrelationId { get; set; }
public string? AppId { get; set; }
public string? ContentEncoding { get; set; }
public string? Expiration { get; set; }
public string? MessageId { get; set; }
public string? Priority { get; set; }
public string? Timestamp { get; set; }
public string? TypeProperty { get; set; }
public string? UserId { get; set; }
public string? Payload { get; set; }
public bool EnableMacros { get; set; }
public string? ContentType { get; init; }
public string? CorrelationId { get; init; }
public string? AppId { get; init; }
public string? ContentEncoding { get; init; }
public string? Expiration { get; init; }
public string? MessageId { get; init; }
public string? Priority { get; init; }
public string? Timestamp { get; init; }
public string? TypeProperty { get; init; }
public string? UserId { get; init; }
public string? Payload { get; init; }
public bool EnableMacros { get; init; }
public Dictionary<string, string>? Headers { get; set; }
public Dictionary<string, string>? Headers { get; init; }
public bool Equals(RawPublisherMessage? other)
{
if (other == null) return false;
if (ReferenceEquals(this, other)) return true;
return DeliveryMode == other.DeliveryMode &&
ContentType == other.ContentType &&
CorrelationId == other.CorrelationId &&
AppId == other.AppId &&
ContentEncoding == other.ContentEncoding &&
Expiration == other.Expiration &&
MessageId == other.MessageId &&
Priority == other.Priority &&
Timestamp == other.Timestamp &&
TypeProperty == other.TypeProperty &&
UserId == other.UserId &&
Payload == other.Payload &&
EnableMacros == other.EnableMacros &&
HeadersEquals(other.Headers);
}
private bool HeadersEquals(Dictionary<string, string>? other)
{
if (other == null)
return Headers == null || Headers.Count == 0;
if (Headers == null)
return other.Count == 0;
return other.OrderBy(h => h.Key).SequenceEqual(Headers.OrderBy(h => h.Key));
}
public override bool Equals(object? obj)
{
if (obj == null) return false;
if (ReferenceEquals(this, obj)) return true;
return obj is RawPublisherMessage rawPublisherMessage && Equals(rawPublisherMessage);
}
public override int GetHashCode()
{
var hashCode = new HashCode();
hashCode.Add((int)DeliveryMode);
hashCode.Add(ContentType);
hashCode.Add(CorrelationId);
hashCode.Add(AppId);
hashCode.Add(ContentEncoding);
hashCode.Add(Expiration);
hashCode.Add(MessageId);
hashCode.Add(Priority);
hashCode.Add(Timestamp);
hashCode.Add(TypeProperty);
hashCode.Add(UserId);
hashCode.Add(Payload);
hashCode.Add(EnableMacros);
if (Headers != null)
foreach (var (key, value) in Headers)
{
hashCode.Add(key);
hashCode.Add(value);
}
return hashCode.ToHashCode();
}
}
public class TapetiPublisherMessage
public class TapetiPublisherMessage : IEquatable<TapetiPublisherMessage>
{
public string? CorrelationId { get; set; }
public string? Payload { get; set; }
public bool EnableMacros { get; set; }
public string? ClassName { get; set; }
public string? AssemblyName { get; set; }
public string? CorrelationId { get; init; }
public string? Payload { get; init; }
public bool EnableMacros { get; init; }
public string? ClassName { get; init; }
public string? AssemblyName { get; init; }
public bool Equals(TapetiPublisherMessage? other)
{
if (other == null) return false;
if (ReferenceEquals(this, other)) return true;
return CorrelationId == other.CorrelationId &&
Payload == other.Payload &&
EnableMacros == other.EnableMacros &&
ClassName == other.ClassName &&
AssemblyName == other.AssemblyName;
}
public override bool Equals(object? obj)
{
if (obj == null) return false;
if (ReferenceEquals(this, obj)) return true;
return obj is TapetiPublisherMessage tapetiPublisherMessage && Equals(tapetiPublisherMessage);
}
public override int GetHashCode()
{
return HashCode.Combine(CorrelationId, Payload, EnableMacros, ClassName, AssemblyName);
}
}
}

View File

@ -2,7 +2,7 @@
using Newtonsoft.Json.Linq;
using PettingZoo.Core.ExportImport.Subscriber;
namespace PettingZoo.Tapeti.Export
namespace PettingZoo.Tapeti.ExportImport
{
public abstract class BaseTapetiCmdExportImportFormat : IExportImportFormat
{

View File

@ -10,8 +10,7 @@ using Newtonsoft.Json.Linq;
using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport.Subscriber;
namespace PettingZoo.Tapeti.Export
namespace PettingZoo.Tapeti.ExportImport
{
public class TapetiCmdExportFormat : BaseTapetiCmdExportImportFormat, IExportFormat
{

View File

@ -8,7 +8,7 @@
// </auto-generated>
//------------------------------------------------------------------------------
namespace PettingZoo.Tapeti.Export {
namespace PettingZoo.Tapeti.ExportImport {
using System;
@ -39,7 +39,7 @@ namespace PettingZoo.Tapeti.Export {
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PettingZoo.Tapeti.Export.TapetiCmdImportExportStrings", typeof(TapetiCmdImportExportStrings).Assembly);
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PettingZoo.Tapeti.ExportImport.TapetiCmdImportExportStrings", typeof(TapetiCmdImportExportStrings).Assembly);
resourceMan = temp;
}
return resourceMan;

View File

@ -9,7 +9,7 @@ using Newtonsoft.Json;
using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport.Subscriber;
namespace PettingZoo.Tapeti.Export
namespace PettingZoo.Tapeti.ExportImport
{
public class TapetiCmdImportFormat : BaseTapetiCmdExportImportFormat, IImportFormat
{

View File

@ -33,7 +33,7 @@
<AutoGen>True</AutoGen>
<DependentUpon>AssemblyParserStrings.resx</DependentUpon>
</Compile>
<Compile Update="Export\TapetiCmdImportExportStrings.Designer.cs">
<Compile Update="ExportImport\TapetiCmdImportExportStrings.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>TapetiCmdImportExportStrings.resx</DependentUpon>
@ -60,7 +60,7 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AssemblyParserStrings.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Update="Export\TapetiCmdImportExportStrings.resx">
<EmbeddedResource Update="ExportImport\TapetiCmdImportExportStrings.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>TapetiCmdImportExportStrings.Designer.cs</LastGenOutput>
</EmbeddedResource>

View File

@ -0,0 +1,26 @@
using System.Windows;
using System.Windows.Controls;
namespace PettingZoo.WPF.Controls
{
public class AutoOverflowToolBar : ToolBar
{
public AutoOverflowToolBar()
{
Loaded += (_, _) =>
{
// Hide overflow arrow on the right side of the toolbar when not required
if (Template.FindName("OverflowButton", this) is not FrameworkElement overflowButton)
return;
if (!overflowButton.IsEnabled)
overflowButton.Visibility = Visibility.Hidden;
overflowButton.IsEnabledChanged += (_, _) =>
{
overflowButton.Visibility = overflowButton.IsEnabled ? Visibility.Visible : Visibility.Hidden;
};
};
}
}
}

View File

@ -1,21 +0,0 @@
using System.Windows;
using System.Windows.Controls;
namespace PettingZoo.WPF.Controls
{
public class NoOverflowToolbar : ToolBar
{
public NoOverflowToolbar()
{
Loaded += (_, _) =>
{
// Hide arrow on the right side of the toolbar
if (Template.FindName("OverflowGrid", this) is FrameworkElement overflowGrid)
overflowGrid.Visibility = Visibility.Collapsed;
if (Template.FindName("MainPanelBorder", this) is FrameworkElement mainPanelBorder)
mainPanelBorder.Margin = new Thickness(0);
};
}
}
}

View File

@ -11,7 +11,7 @@ using PettingZoo.Core.Settings;
using PettingZoo.RabbitMQ;
using PettingZoo.Settings.LiteDB;
using PettingZoo.Tapeti;
using PettingZoo.Tapeti.Export;
using PettingZoo.Tapeti.ExportImport;
using PettingZoo.UI.Connection;
using PettingZoo.UI.Main;
using PettingZoo.UI.Subscribe;

View File

@ -12,7 +12,7 @@
WindowStartupLocation="CenterOwner"
Style="{StaticResource WindowStyle}"
Title="{Binding Title}"
FocusManager.FocusedElement="{Binding ElementName=DisplayNameTextBox}"
FocusManager.FocusedElement="{Binding ElementName=ValueTextBox}"
d:DataContext="{d:DesignInstance local:InputDialogViewModel}">
<StackPanel Margin="8">
<TextBox Name="ValueTextBox" Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}" />

View File

@ -25,7 +25,7 @@
<ui:BindingProxy x:Key="ContextMenuProxy" Data="{Binding}" />
</Window.Resources>
<DockPanel>
<controls:NoOverflowToolbar DockPanel.Dock="Top" ToolBarTray.IsLocked="True">
<controls:AutoOverflowToolBar DockPanel.Dock="Top" ToolBarTray.IsLocked="True">
<Button Command="{Binding ConnectCommand}">
<StackPanel Orientation="Horizontal">
<Image Source="{svgc:SvgImage Source=/Images/Connect.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/>
@ -83,7 +83,7 @@
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</controls:NoOverflowToolbar>
</controls:AutoOverflowToolBar>
<StatusBar DockPanel.Dock="Bottom">
<StatusBarItem>
<StackPanel Orientation="Horizontal">

View File

@ -16,7 +16,7 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="300" />
<ColumnDefinition Width="350" />
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Column="0" VerticalScrollBarVisibility="Auto">
@ -95,7 +95,7 @@
<Label Grid.Row="0" Style="{StaticResource HeaderLabel}" Content="{x:Static res:PublisherViewStrings.PanelTitleMessages}"/>
<controls:NoOverflowToolbar Grid.Row="1" ToolBarTray.IsLocked="True" Margin="0,0,0,4">
<controls:AutoOverflowToolBar Grid.Row="1" ToolBarTray.IsLocked="True" Margin="0,0,0,4">
<!-- TODO load button in addition to double-click. I don't like hidden-only functionality -->
<Button Command="{Binding SaveCommand}">
<StackPanel Orientation="Horizontal">
@ -116,8 +116,21 @@
<TextBlock Margin="3,0,0,0" Text="{x:Static res:PublisherViewStrings.ToolbarDelete}" />
</StackPanel>
</Button>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Button Command="{Binding ExportCommand}">
<StackPanel Orientation="Horizontal">
<Image Source="{svgc:SvgImage Source=/Images/Export.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/>
<TextBlock Margin="3,0,0,0" Text="{x:Static res:PublisherViewStrings.ToolbarExport}" />
</StackPanel>
</Button>
<Button Command="{Binding ImportCommand}">
<StackPanel Orientation="Horizontal">
<Image Source="{svgc:SvgImage Source=/Images/Import.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/>
<TextBlock Margin="3,0,0,0" Text="{x:Static res:PublisherViewStrings.ToolbarImport}" />
</StackPanel>
</Button>
<!-- TODO export / import -->
</controls:NoOverflowToolbar>
</controls:AutoOverflowToolBar>
<ListBox Grid.Row="2" ItemsSource="{Binding StoredMessages}" SelectedValue="{Binding SelectedStoredMessage}">
<ListBox.Resources>
@ -147,7 +160,7 @@
</Style>
</TextBlock.Style>
<TextBlock.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding DataContext.LoadStoredMessage, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" />
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding DataContext.LoadStoredMessageCommand, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" />
</TextBlock.InputBindings>
</TextBlock>
</DataTemplate>

View File

@ -1,16 +1,23 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Input;
using Accessibility;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using PettingZoo.Core.Connection;
using PettingZoo.Core.ExportImport.Publisher;
using PettingZoo.Core.Generator;
using PettingZoo.Core.Macros;
using PettingZoo.Core.Settings;
using PettingZoo.WPF.ViewModel;
using UserControl = System.Windows.Controls.UserControl;
namespace PettingZoo.UI.Tab.Publisher
{
@ -46,10 +53,13 @@ namespace PettingZoo.UI.Tab.Publisher
private readonly DelegateCommand saveCommand;
private readonly DelegateCommand saveAsCommand;
private readonly DelegateCommand deleteCommand;
private readonly DelegateCommand loadStoredMessage;
private readonly DelegateCommand loadStoredMessageCommand;
private readonly DelegateCommand exportCommand;
private readonly DelegateCommand importCommand;
private readonly TabToolbarCommand[] toolbarCommands;
private Window? tabHostWindow;
private bool disableCheckCanSave;
public bool SendToExchange
@ -167,12 +177,10 @@ namespace PettingZoo.UI.Tab.Publisher
public StoredPublisherMessage? SelectedStoredMessage
{
get => selectedStoredMessage;
set => SetField(ref selectedStoredMessage, value, delegateCommandsChanged: new[] { deleteCommand });
set => SetField(ref selectedStoredMessage, value, delegateCommandsChanged: new[] { loadStoredMessageCommand, deleteCommand, exportCommand });
}
// TODO detect changes from ActiveStoredMessage and show indication in the UI
public StoredPublisherMessage? ActiveStoredMessage
{
get => activeStoredMessage;
@ -184,7 +192,9 @@ namespace PettingZoo.UI.Tab.Publisher
public ICommand SaveCommand => saveCommand;
public ICommand SaveAsCommand => saveAsCommand;
public ICommand DeleteCommand => deleteCommand;
public ICommand LoadStoredMessage => loadStoredMessage;
public ICommand LoadStoredMessageCommand => loadStoredMessageCommand;
public ICommand ExportCommand => exportCommand;
public ICommand ImportCommand => importCommand;
public string Title => SendToQueue
@ -214,10 +224,12 @@ namespace PettingZoo.UI.Tab.Publisher
this.tabFactory = tabFactory;
publishCommand = new DelegateCommand(PublishExecute, PublishCanExecute);
saveCommand = new DelegateCommand(SaveExecute);
saveCommand = new DelegateCommand(SaveExecute, SaveCanExecute);
saveAsCommand = new DelegateCommand(SaveAsExecute);
deleteCommand = new DelegateCommand(DeleteExecute, DeleteCanExecute);
loadStoredMessage = new DelegateCommand(LoadStoredMessageExecute, LoadStoredMessageCanExecute);
deleteCommand = new DelegateCommand(DeleteExecute, SelectedMessageCanExecute);
loadStoredMessageCommand = new DelegateCommand(LoadStoredMessageExecute, SelectedMessageCanExecute);
exportCommand = new DelegateCommand(ExportExecute, SelectedMessageCanExecute);
importCommand = new DelegateCommand(ImportExecute);
toolbarCommands = new[]
{
@ -229,6 +241,9 @@ namespace PettingZoo.UI.Tab.Publisher
SetMessageTypeControl(fromReceivedMessage);
else
SetMessageTypeControl(PublisherMessageType.Raw);
PropertyChanged += (_, _) => { saveCommand.RaiseCanExecuteChanged(); };
}
@ -268,6 +283,11 @@ namespace PettingZoo.UI.Tab.Publisher
publishCommand.RaiseCanExecuteChanged();
};
// This is becoming a bit messy, find a cleaner way...
// TODO monitor header changes as well, instead of only the collection
rawPublisherViewModel.PropertyChanged += (_, _) => { saveCommand.RaiseCanExecuteChanged(); };
rawPublisherViewModel.Headers.CollectionChanged += (_, _) => { saveCommand.RaiseCanExecuteChanged(); };
rawPublisherView = new RawPublisherView(rawPublisherViewModel);
}
else
@ -287,6 +307,8 @@ namespace PettingZoo.UI.Tab.Publisher
publishCommand.RaiseCanExecuteChanged();
};
tapetiPublisherViewModel.PropertyChanged += (_, _) => { saveCommand.RaiseCanExecuteChanged(); };
tapetiPublisherView = new TapetiPublisherView(tapetiPublisherViewModel);
if (tabHostWindow != null)
@ -356,19 +378,33 @@ namespace PettingZoo.UI.Tab.Publisher
}
private bool SaveCanExecute()
{
if (disableCheckCanSave)
return false;
return ActiveStoredMessage != null && !GetPublisherMessage().Equals(ActiveStoredMessage.Message);
}
private void SaveExecute()
{
storedPublisherMessagesViewModel.Save(SelectedStoredMessage, GetPublisherMessage(), message =>
if (ActiveStoredMessage == null)
return;
storedPublisherMessagesViewModel.Save(ActiveStoredMessage, GetPublisherMessage(), message =>
{
ActiveStoredMessage = message;
SelectedStoredMessage = message;
saveCommand.RaiseCanExecuteChanged();
});
}
private void SaveAsExecute()
{
storedPublisherMessagesViewModel.SaveAs(GetPublisherMessage(), SelectedStoredMessage?.DisplayName, message =>
storedPublisherMessagesViewModel.SaveAs(GetPublisherMessage(), ActiveStoredMessage?.DisplayName, message =>
{
ActiveStoredMessage = message;
SelectedStoredMessage = message;
@ -394,7 +430,7 @@ namespace PettingZoo.UI.Tab.Publisher
}
private bool DeleteCanExecute()
private bool SelectedMessageCanExecute()
{
return SelectedStoredMessage != null;
}
@ -407,37 +443,95 @@ namespace PettingZoo.UI.Tab.Publisher
var message = SelectedStoredMessage.Message;
MessageType = message.MessageType;
SendToExchange = message.SendToExchange;
Exchange = message.Exchange ?? "";
RoutingKey = message.RoutingKey ?? "";
Queue = message.Queue ?? "";
ReplyToNewSubscriber = message.ReplyToNewSubscriber;
ReplyTo = message.ReplyTo ?? "";
// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
switch (message.MessageType)
disableCheckCanSave = true;
try
{
case PublisherMessageType.Raw:
if (message.RawPublisherMessage != null)
rawPublisherViewModel?.LoadPublisherMessage(message.RawPublisherMessage);
MessageType = message.MessageType;
SendToExchange = message.SendToExchange;
Exchange = message.Exchange ?? "";
RoutingKey = message.RoutingKey ?? "";
Queue = message.Queue ?? "";
ReplyToNewSubscriber = message.ReplyToNewSubscriber;
ReplyTo = message.ReplyTo ?? "";
break;
// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
switch (message.MessageType)
{
case PublisherMessageType.Raw:
if (message.RawPublisherMessage != null)
rawPublisherViewModel?.LoadPublisherMessage(message.RawPublisherMessage);
case PublisherMessageType.Tapeti:
if (message.TapetiPublisherMessage != null)
tapetiPublisherViewModel?.LoadPublisherMessage(message.TapetiPublisherMessage);
break;
break;
case PublisherMessageType.Tapeti:
if (message.TapetiPublisherMessage != null)
tapetiPublisherViewModel?.LoadPublisherMessage(message.TapetiPublisherMessage);
break;
}
ActiveStoredMessage = SelectedStoredMessage;
}
finally
{
disableCheckCanSave = false;
saveCommand.RaiseCanExecuteChanged();
}
ActiveStoredMessage = SelectedStoredMessage;
}
private bool LoadStoredMessageCanExecute()
private static readonly JsonSerializerSettings ExportImportSettings = new()
{
return SelectedStoredMessage != null;
Converters = new List<JsonConverter> { new StringEnumConverter() }
};
private void ExportExecute()
{
if (SelectedStoredMessage == null)
return;
var invalidChars = Regex.Escape(new string(Path.GetInvalidFileNameChars()));
var invalidRegStr = string.Format(@"([{0}]*\.+$)|([{0}]+)", invalidChars);
var suggestedFilename = Regex.Replace(SelectedStoredMessage.DisplayName, invalidRegStr, "_");
var dialog = new SaveFileDialog
{
Filter = PublisherViewStrings.StoredMessagesExportImportFilter,
FileName = suggestedFilename
};
if (dialog.ShowDialog() != DialogResult.OK)
return;
File.WriteAllText(dialog.FileName, JsonConvert.SerializeObject(SelectedStoredMessage.Message, ExportImportSettings), Encoding.UTF8);
}
private void ImportExecute()
{
var dialog = new OpenFileDialog
{
Filter = PublisherViewStrings.StoredMessagesExportImportFilter
};
if (dialog.ShowDialog() != DialogResult.OK)
return;
var fileContents = File.ReadAllText(dialog.FileName, Encoding.UTF8);
var message = JsonConvert.DeserializeObject<PublisherMessage>(fileContents, ExportImportSettings);
if (message == null)
return;
var displayName = dialog.FileName.EndsWith(".pubmsg.json")
? Path.GetFileName(dialog.FileName)[..^".pubmsg.json".Length]
: Path.GetFileNameWithoutExtension(dialog.FileName);
storedPublisherMessagesViewModel.SaveAs(message, displayName, storedMessage =>
{
SelectedStoredMessage = storedMessage;
});
}

View File

@ -186,6 +186,15 @@ namespace PettingZoo.UI.Tab.Publisher {
}
}
/// <summary>
/// Looks up a localized string similar to PettingZoo message (*.pubmsg.json)|*.pubmsg.json.
/// </summary>
public static string StoredMessagesExportImportFilter {
get {
return ResourceManager.GetString("StoredMessagesExportImportFilter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Publish: {0}.
/// </summary>
@ -213,6 +222,24 @@ namespace PettingZoo.UI.Tab.Publisher {
}
}
/// <summary>
/// Looks up a localized string similar to Export....
/// </summary>
public static string ToolbarExport {
get {
return ResourceManager.GetString("ToolbarExport", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Import....
/// </summary>
public static string ToolbarImport {
get {
return ResourceManager.GetString("ToolbarImport", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Save.
/// </summary>

View File

@ -159,6 +159,9 @@
<data name="ReplyToCorrelationIdPrefix" xml:space="preserve">
<value>Re: </value>
</data>
<data name="StoredMessagesExportImportFilter" xml:space="preserve">
<value>PettingZoo message (*.pubmsg.json)|*.pubmsg.json</value>
</data>
<data name="TabTitle" xml:space="preserve">
<value>Publish: {0}</value>
</data>
@ -168,6 +171,12 @@
<data name="ToolbarDelete" xml:space="preserve">
<value>Delete</value>
</data>
<data name="ToolbarExport" xml:space="preserve">
<value>Export...</value>
</data>
<data name="ToolbarImport" xml:space="preserve">
<value>Import...</value>
</data>
<data name="ToolbarSave" xml:space="preserve">
<value>Save</value>
</data>

View File

@ -219,9 +219,7 @@ namespace PettingZoo.UI.Tab.Publisher
Payload = Payload,
EnableMacros = EnableMacros,
Headers = Headers.Count > 0
? Headers.ToDictionary(h => h.Key, h => h.Value)
: null
Headers = Headers.Where(h => !h.IsEmpty()).ToDictionary(h => h.Key, h => h.Value)
};
}
@ -243,11 +241,17 @@ namespace PettingZoo.UI.Tab.Publisher
EnableMacros = message.EnableMacros;
if (message.Headers != null)
{
Headers.ReplaceAll(message.Headers.Select(p => new Header
{
Key = p.Key,
Value = p.Value
}));
}
else
Headers.Clear();
AddHeader();
}

View File

@ -32,21 +32,15 @@ namespace PettingZoo.UI.Tab.Publisher
}
public void Save(StoredPublisherMessage? selectedMessage, PublisherMessage message, Action<StoredPublisherMessage> onSaved)
public void Save(StoredPublisherMessage overwriteMessage, PublisherMessage message, Action<StoredPublisherMessage> onSaved)
{
if (selectedMessage == null)
{
SaveAs(message, null, onSaved);
return;
}
Task.Run(async () =>
{
var updatedMessage = await publisherMessagesRepository.Update(selectedMessage.Id, selectedMessage.DisplayName, message);
var updatedMessage = await publisherMessagesRepository.Update(overwriteMessage.Id, overwriteMessage.DisplayName, message);
await Application.Current.Dispatcher.BeginInvoke(() =>
{
var index = StoredMessages.IndexOf(selectedMessage);
var index = StoredMessages.IndexOf(overwriteMessage);
if (index >= 0)
StoredMessages[index] = updatedMessage;
else
@ -75,7 +69,6 @@ namespace PettingZoo.UI.Tab.Publisher
onSaved(storedMessage);
});
});
}

View File

@ -83,14 +83,14 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="200"/>
</Grid.RowDefinitions>
<controls:NoOverflowToolbar Grid.Column="0" Grid.Row="0" ToolBarTray.IsLocked="True" Margin="0,0,0,4" Background="Transparent">
<controls:AutoOverflowToolBar Grid.Column="0" Grid.Row="0" ToolBarTray.IsLocked="True" Margin="0,0,0,4" Background="Transparent">
<Button Command="{Binding CreatePublisherCommand}">
<StackPanel Orientation="Horizontal">
<Image Source="{svgc:SvgImage Source=/Images/Publish.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/>
<TextBlock Margin="3,0,0,0" Text="{x:Static res:SubscriberViewStrings.ContextPublish}" />
</StackPanel>
</Button>
</controls:NoOverflowToolbar>
</controls:AutoOverflowToolBar>
<Border Grid.Column="0" Grid.Row="1" Style="{StaticResource SidePanel}">
<DockPanel>

View File

@ -13,7 +13,7 @@
Width="800"
WindowStyle="ThreeDBorderWindow">
<DockPanel>
<controls:NoOverflowToolbar DockPanel.Dock="Top" ToolBarTray.IsLocked="True">
<controls:AutoOverflowToolBar DockPanel.Dock="Top" ToolBarTray.IsLocked="True">
<Button Command="{Binding DockCommand}">
<StackPanel Orientation="Horizontal">
<Image Source="{svgc:SvgImage Source=/Images/Dock.svg, AppName=PettingZoo}" Width="16" Height="16" Style="{StaticResource ToolbarIcon}"/>
@ -38,7 +38,7 @@
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</controls:NoOverflowToolbar>
</controls:AutoOverflowToolBar>
<ContentControl Content="{Binding Content}" />
</DockPanel>