diff options
| author | Avi Levkovich <avi@twine-s.com> | 2020-05-13 13:27:01 +0300 |
|---|---|---|
| committer | Avi Levkovich <avi@twine-s.com> | 2020-05-13 13:27:01 +0300 |
| commit | 15dfc2cdcbc2e518c09c1ee75f32ff149d4a337d (patch) | |
| tree | 4c0b49773706b85282e6f6b1ec3d2e949d3ca22e /Software/Visual_Studio/FSE/Modules | |
| parent | 6a49e917c587dcbbfe8175b8dde73840b7d105fc (diff) | |
| parent | cd750d626d3780990797faf09446033bbaa4311c (diff) | |
| download | Tango-15dfc2cdcbc2e518c09c1ee75f32ff149d4a337d.tar.gz Tango-15dfc2cdcbc2e518c09c1ee75f32ff149d4a337d.zip | |
commit merge
Diffstat (limited to 'Software/Visual_Studio/FSE/Modules')
95 files changed, 3615 insertions, 171 deletions
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/App.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/App.xaml index 9efba692b..da0a65fc1 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/App.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/App.xaml @@ -10,6 +10,8 @@ <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Images.xaml" /> <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Styles.xaml" /> <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Controls.xaml" /> + + <ResourceDictionary Source="Themes/Generic.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Converters/DoubleToChartValuesConverter.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DecimalPlacesToStringFormatConverter.cs index 1ac86b849..032d0bb1e 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Converters/DoubleToChartValuesConverter.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DecimalPlacesToStringFormatConverter.cs @@ -6,13 +6,18 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Data; -namespace Tango.FSE.PPCConsole.Converters +namespace Tango.FSE.Diagnostics.Converters { - public class DoubleToChartValuesConverter : IValueConverter + public class DecimalPlacesToStringFormatConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return new LiveCharts.ChartValues<double>() { (double)value }; + if (value != null) + { + return $"F{int.Parse(value.ToString())}"; + } + + return value; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DiagnosticsWidgetToSettingsViewConverter.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DiagnosticsWidgetToSettingsViewConverter.cs new file mode 100644 index 000000000..3ba8f2e4b --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DiagnosticsWidgetToSettingsViewConverter.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using Tango.FSE.Diagnostics.Project; + +namespace Tango.FSE.Diagnostics.Converters +{ + public class DiagnosticsWidgetToSettingsViewConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + DiagnosticsConfigurableWidget widget = value as DiagnosticsConfigurableWidget; + + if (widget != null) + { + if (widget.Settings != null) + { + var view = widget.Settings.GetView(); + view.DataContext = widget; + return view; + } + } + + return null; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/PercentageToWidthConverter.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/PercentageToWidthConverter.cs new file mode 100644 index 000000000..2ea6710c7 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/PercentageToWidthConverter.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace Tango.FSE.Diagnostics.Converters +{ + public class PercentageToWidthConverter : IMultiValueConverter + { + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + try + { + double parentWidth = (double)values[0]; + double percentage = (double)values[1]; + + return percentage / 100d * parentWidth; + } + catch + { + if (values.Length > 0) + { + return values[0]; + } + else + { + return 0d; + } + } + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsConfigurableWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsConfigurableWidget.cs new file mode 100644 index 000000000..ac1d29847 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsConfigurableWidget.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Diagnostics.Project +{ + public abstract class DiagnosticsConfigurableWidget : DiagnosticsWidget + { + public DiagnosticsWidgetSettings Settings { get; set; } + } + + public abstract class DiagnosticsConfigurableWidget<T> : DiagnosticsConfigurableWidget where T : DiagnosticsWidgetSettings, new() + { + private T _settings; + public new T Settings + { + get { return _settings; } + set + { + _settings = value; + RaisePropertyChangedAuto(); + + if (_settings != null) + { + base.Settings = value; + OnSettingsChanged(); + _settings.PropertyChanged += _settings_PropertyChanged; + } + } + } + + public DiagnosticsConfigurableWidget() : base() + { + Settings = new T(); + } + + private void _settings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + OnSettingsChanged(); + } + + protected virtual void OnSettingsChanged() + { + + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidget.cs index b91da83c2..c7880909b 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidget.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidget.cs @@ -42,8 +42,11 @@ namespace Tango.FSE.Diagnostics.Project public int Row { get; set; } public int ColumnSpan { get; set; } public int RowSpan { get; set; } + public double Width { get; set; } + public double Height { get; set; } private bool _isVisible; + [JsonIgnore] public bool IsVisible { get { return _isVisible; } @@ -58,8 +61,16 @@ namespace Tango.FSE.Diagnostics.Project } } + [JsonIgnore] + public abstract String DisplayName + { + get; + } + public DiagnosticsWidget() { + Width = 100; + Height = 100; TangoIOC.Default.Inject(this); } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidgetSettings.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidgetSettings.cs new file mode 100644 index 000000000..2fb38ad93 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidgetSettings.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.Core; + +namespace Tango.FSE.Diagnostics.Project +{ + public abstract class DiagnosticsWidgetSettings : ExtendedObject + { + public abstract FrameworkElement GetView(); + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/Images/tft_screen.png b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/Images/tft_screen.png Binary files differnew file mode 100644 index 000000000..268453279 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/Images/tft_screen.png diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidget.cs new file mode 100644 index 000000000..3a2590ca2 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidget.cs @@ -0,0 +1,68 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.BL.Entities; +using Tango.BL.Enumerations; + +namespace Tango.FSE.Diagnostics.Project.Widgets.Monitor +{ + public class MonitorWidget : DiagnosticsConfigurableWidget<MonitorWidgetSettings> + { + public TechMonitors Monitor { get; set; } + + [JsonIgnore] + public TechMonitor TechMonitor { get; private set; } + + [JsonIgnore] + public override string DisplayName + { + get + { + return this.TechMonitor != null ? this.TechMonitor.Description : String.Empty; + } + } + + private String _value; + [JsonIgnore] + public String Value + { + get { return _value; } + set { _value = value; RaisePropertyChangedAuto(); } + } + + public override async Task Init() + { + int monitor = (int)Monitor; + TechMonitor = await Services.TechComponentsService.Monitors.FindOne(x => x.Code == monitor); + } + + public override void OnDiagnosticsData(DiagnosticsPackage package) + { + if (IsVisible) + { + var value = package.GetMonitorLastValue(Monitor); + string format = "0"; + + if (Settings.DecimalPlaces > 0) + { + format = "0." + String.Join("", Enumerable.Range(0, Settings.DecimalPlaces).Select(x => "#")); + } + else + { + format = "0"; + } + + Value = value.ToString(format); + } + } + + public override FrameworkElement GetView() + { + return new MonitorWidgetView() { DataContext = this }; + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetSettings.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetSettings.cs new file mode 100644 index 000000000..3949f1029 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetSettings.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media; + +namespace Tango.FSE.Diagnostics.Project.Widgets.Monitor +{ + public class MonitorWidgetSettings : DiagnosticsWidgetSettings + { + private int _decimalPlaces; + public int DecimalPlaces + { + get { return _decimalPlaces; } + set { _decimalPlaces = value; RaisePropertyChangedAuto(); } + } + + private Color _color; + public Color Color + { + get { return _color; } + set { _color = value; RaisePropertyChangedAuto(); } + } + + public MonitorWidgetSettings() + { + DecimalPlaces = 0; + Color = Colors.Gainsboro; + } + + public override FrameworkElement GetView() + { + return new MonitorWidgetSettingsView() { DataContext = this }; + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetSettingsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetSettingsView.xaml new file mode 100644 index 000000000..9ddaea737 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetSettingsView.xaml @@ -0,0 +1,28 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.Monitor.MonitorWidgetSettingsView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets.Monitor" + xmlns:colorPicker="clr-namespace:Tango;assembly=Tango.ColorPicker" + mc:Ignorable="d" + d:DesignHeight="700" d:DesignWidth="300"> + <Grid> + <StackPanel> + <controls:FSEGroupBox Header="FORMAT" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <StackPanel> + <TextBlock FontSize="{StaticResource FSE_SmallerFontSize}" >Decimal Places</TextBlock> + <mahapps:NumericUpDown Background="Transparent" BorderThickness="0 0 0 1" HorizontalContentAlignment="Left" Minimum="0" Maximum="3" Focusable="False" Value="{Binding Settings.DecimalPlaces,UpdateSourceTrigger=PropertyChanged}" /> + </StackPanel> + </controls:FSEGroupBox> + + <controls:FSEGroupBox Header="COLOR" Margin="0 10 0 0" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <Viewbox> + <colorPicker:ColorCanvas Background="Transparent" BorderThickness="0" FontSize="{StaticResource FSE_SmallerFontSize}" SelectedColor="{Binding Settings.Color,Mode=TwoWay}" /> + </Viewbox> + </controls:FSEGroupBox> + </StackPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetSettingsView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetSettingsView.xaml.cs new file mode 100644 index 000000000..b39d0e146 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetSettingsView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.FSE.Diagnostics.Project.Widgets.Monitor +{ + /// <summary> + /// Interaction logic for MonitorWidgetSettingsView.xaml + /// </summary> + public partial class MonitorWidgetSettingsView : UserControl + { + public MonitorWidgetSettingsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetView.xaml new file mode 100644 index 000000000..1d8ba96a6 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetView.xaml @@ -0,0 +1,32 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.Monitor.MonitorWidgetView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets.Monitor" + mc:Ignorable="d" + d:DesignHeight="250" d:DesignWidth="400" d:DataContext="{d:DesignInstance Type=local:MonitorWidget,IsDesignTimeCreatable=False}"> + <Grid> + <Viewbox Stretch="Fill"> + <StackPanel> + <Grid Grid.Column="1" Grid.Row="1" Width="200" Height="120"> + <Border BorderThickness="0" BorderBrush="{StaticResource AccentColorBrush}"> + <Border.Background> + <ImageBrush ImageSource="../Monitor/Images/tft_screen.png" Opacity="1" /> + </Border.Background> + + <Grid> + <Viewbox Stretch="Uniform" Width="150" VerticalAlignment="Center" Margin="25 10 10 10" HorizontalAlignment="Left"> + <TextBlock FontFamily="{StaticResource digital-7}" TextAlignment="Left" VerticalAlignment="Center" HorizontalAlignment="Left" FontSize="90" Text="{Binding Value,FallbackValue='0000'}"> + <TextBlock.Foreground> + <SolidColorBrush Color="{Binding Settings.Color}"></SolidColorBrush> + </TextBlock.Foreground> + </TextBlock> + </Viewbox> + </Grid> + </Border> + </Grid> + </StackPanel> + </Viewbox> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetView.xaml.cs new file mode 100644 index 000000000..b97823e13 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/Monitor/MonitorWidgetView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.FSE.Diagnostics.Project.Widgets.Monitor +{ + /// <summary> + /// Interaction logic for MonitorWidgetView.xaml + /// </summary> + public partial class MonitorWidgetView : UserControl + { + public MonitorWidgetView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidget.cs new file mode 100644 index 000000000..50693746e --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidget.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; +using RealTimeGraphX.DataPoints; +using RealTimeGraphX.WPF; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.Core.Commands; + +namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph +{ + public class RealTimeGraphWidget : RealTimeGraphWidgetBase<RealTimeGraphWidgetSettings> + { + + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetBase.cs index 3f8a12182..8e79e53e3 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidget.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetBase.cs @@ -11,10 +11,11 @@ using System.Windows; using System.Windows.Media; using Tango.BL.Entities; using Tango.BL.Enumerations; +using Tango.Core.Commands; -namespace Tango.FSE.Diagnostics.Project.Widgets +namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph { - public class RealTimeGraphWidget : DiagnosticsWidget + public abstract class RealTimeGraphWidgetBase<T> : DiagnosticsConfigurableWidget<T> where T : RealTimeGraphWidgetSettings, new() { public TechMonitors Monitor { get; set; } @@ -22,20 +23,41 @@ namespace Tango.FSE.Diagnostics.Project.Widgets public TechMonitor TechMonitor { get; private set; } [JsonIgnore] + public override string DisplayName + { + get + { + return this.TechMonitor != null ? this.TechMonitor.Description : String.Empty; + } + } + + [JsonIgnore] public WpfGraphController<TimeSpanDataPoint, DoubleDataPoint> Controller { get; set; } - public RealTimeGraphWidget() + [JsonIgnore] + public RelayCommand ClearCommand { get; set; } + + public RealTimeGraphWidgetBase() { Controller = new WpfGraphController<TimeSpanDataPoint, DoubleDataPoint>(); - Controller.Range.AutoY = true; - Controller.Range.MaximumX = TimeSpan.FromSeconds(60); + Controller.Range.MinimumY = Settings.Min; + Controller.Range.MaximumY = Settings.Max; + Controller.Range.AutoY = Settings.AutoRange; + Controller.Range.MaximumX = Settings.Duration; Controller.RefreshRate = TimeSpan.FromMilliseconds(100); Controller.DisableRendering = true; Controller.DataSeriesCollection.Add(new WpfGraphDataSeries() { - Stroke = Colors.DodgerBlue + Stroke = Settings.Color }); + + ClearCommand = new RelayCommand(Clear); + } + + public void Clear() + { + Controller?.Clear(); } public override async Task Init() @@ -52,10 +74,27 @@ namespace Tango.FSE.Diagnostics.Project.Widgets protected override void OnVisibleChanged(bool isVisible) { base.OnVisibleChanged(isVisible); - Controller.DisableRendering = !isVisible; } + protected override void OnSettingsChanged() + { + base.OnSettingsChanged(); + + if (Controller != null) + { + Controller.Range.MinimumY = Settings.Min; + Controller.Range.MaximumY = Settings.Max; + Controller.Range.AutoY = Settings.AutoRange; + Controller.Range.MaximumX = Settings.Duration; + + if (Controller.DataSeriesCollection.Count > 0) + { + Controller.DataSeriesCollection[0].Stroke = Settings.Color; + } + } + } + public override void OnDiagnosticsData(DiagnosticsPackage package) { var points = package.GetMonitorArray(Monitor); diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetSettings.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetSettings.cs new file mode 100644 index 000000000..2ebb1f127 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetSettings.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media; +using Tango.Core; + +namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph +{ + public class RealTimeGraphWidgetSettings : DiagnosticsWidgetSettings + { + private TimeSpan _duration; + public TimeSpan Duration + { + get { return _duration; } + set { _duration = value; RaisePropertyChangedAuto(); } + } + + private int _decimalPlaces; + public int DecimalPlaces + { + get { return _decimalPlaces; } + set { _decimalPlaces = value; RaisePropertyChangedAuto(); } + } + + private double _min; + public double Min + { + get { return _min; } + set { _min = value; RaisePropertyChangedAuto(); } + } + + private double _max; + public double Max + { + get { return _max; } + set { _max = value; RaisePropertyChangedAuto(); } + } + + private bool _autoRange; + public bool AutoRange + { + get { return _autoRange; } + set { _autoRange = value; RaisePropertyChangedAuto(); } + } + + private Color _color; + public Color Color + { + get { return _color; } + set { _color = value; RaisePropertyChangedAuto(); } + } + + public RealTimeGraphWidgetSettings() + { + Duration = TimeSpan.FromMinutes(10); + DecimalPlaces = 0; + Min = 0; + Max = 1000; + AutoRange = true; + Color = Colors.DodgerBlue; + } + + public override FrameworkElement GetView() + { + return new RealTimeGraphWidgetSettingsView() { DataContext = this }; + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetSettingsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetSettingsView.xaml new file mode 100644 index 000000000..333f21b76 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetSettingsView.xaml @@ -0,0 +1,66 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph.RealTimeGraphWidgetSettingsView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" + xmlns:colorPicker="clr-namespace:Tango;assembly=Tango.ColorPicker" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph" + mc:Ignorable="d" + d:DesignHeight="1200" d:DesignWidth="600" d:DataContext="{d:DesignInstance Type=local:RealTimeGraphWidget,IsDesignTimeCreatable=False}"> + <Grid> + <StackPanel> + + <controls:FSEGroupBox Header="DURATION" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <StackPanel> + <DockPanel> + <TextBlock DockPanel.Dock="Right" FontSize="{StaticResource FSE_SmallerFontSize}" Text="{Binding Settings.Duration,Mode=OneWay}" /> + <TextBlock FontSize="{StaticResource FSE_SmallerFontSize}">Maximum Visible Time</TextBlock> + </DockPanel> + <Slider Margin="0 5 0 0" Minimum="10" Maximum="3600" IsSnapToTickEnabled="True" Value="{Binding Settings.Duration,Converter={StaticResource TimeSpanToSecondsConverter},Mode=TwoWay}"></Slider> + </StackPanel> + </controls:FSEGroupBox> + + <controls:FSEGroupBox Margin="0 10 0 0" Header="RANGE" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <StackPanel> + <DockPanel> + <TextBlock DockPanel.Dock="Right" FontSize="{StaticResource FSE_SmallerFontSize}" > + <Run Text="{Binding Settings.Min,Mode=OneWay}"></Run> + <Run>-</Run> + <Run Text="{Binding Settings.Max,Mode=OneWay}"></Run> + </TextBlock> + <TextBlock FontSize="{StaticResource FSE_SmallerFontSize}" >Y Min/Max</TextBlock> + </DockPanel> + <mahapps:RangeSlider Margin="0 5 0 0" + Minimum="-100000" + Interval="1" + Maximum="100000" + SmallChange="1" + IsSnapToTickEnabled="True" + AutoToolTipPlacement="None" + LowerValue="{Binding Settings.Min,UpdateSourceTrigger=PropertyChanged}" + UpperValue="{Binding Settings.Max,UpdateSourceTrigger=PropertyChanged}"/> + + <CheckBox Margin="0 10 0 0" IsChecked="{Binding Settings.AutoRange}">Auto Range</CheckBox> + </StackPanel> + </controls:FSEGroupBox> + + <controls:FSEGroupBox Header="FORMAT" Margin="0 10 0 0" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <StackPanel> + <TextBlock FontSize="{StaticResource FSE_SmallerFontSize}" >Decimal Places</TextBlock> + <mahapps:NumericUpDown Background="Transparent" BorderThickness="0 0 0 1" HorizontalContentAlignment="Left" Minimum="0" Maximum="3" Focusable="False" Value="{Binding Settings.DecimalPlaces,UpdateSourceTrigger=PropertyChanged}" /> + </StackPanel> + </controls:FSEGroupBox> + + <controls:FSEGroupBox Header="COLOR" Margin="0 10 0 0" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <Viewbox> + <colorPicker:ColorCanvas Background="Transparent" BorderThickness="0" FontSize="{StaticResource FSE_SmallerFontSize}" SelectedColor="{Binding Settings.Color,Mode=TwoWay}" /> + </Viewbox> + </controls:FSEGroupBox> + + <Button Style="{StaticResource FSE_RaisedButton_Dark_Hover}" Margin="0 20 0 0" Height="50" material:ButtonAssist.CornerRadius="25" Command="{Binding ClearCommand}">CLEAR</Button> + </StackPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetSettingsView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetSettingsView.xaml.cs new file mode 100644 index 000000000..2aefc0835 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetSettingsView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph +{ + /// <summary> + /// Interaction logic for RealTimeGraphWidgetSettingsView.xaml + /// </summary> + public partial class RealTimeGraphWidgetSettingsView : UserControl + { + public RealTimeGraphWidgetSettingsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidgetView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetView.xaml index cd2735e2a..f08274275 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidgetView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetView.xaml @@ -1,13 +1,13 @@ -<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphWidgetView" +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph.RealTimeGraphWidgetView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph" xmlns:graphs="clr-namespace:Tango.FSE.Common.Graphs;assembly=Tango.FSE.Common" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=local:RealTimeGraphWidget,IsDesignTimeCreatable=False}"> <Grid> - <graphs:RealTimeGraph HorizontalTicks="7" VerticalTicks="5" Controller="{Binding Controller}" /> + <graphs:RealTimeGraph Style="{StaticResource FSE_RealTimeGraph_Diagnostics}" StringFormat="{Binding Settings.DecimalPlaces,Converter={StaticResource DecimalPlacesToStringFormatConverter}}" Controller="{Binding Controller}" /> </Grid> </UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidgetView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetView.xaml.cs index 546a55f74..043293c9b 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidgetView.xaml.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraph/RealTimeGraphWidgetView.xaml.cs @@ -13,7 +13,7 @@ using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; -namespace Tango.FSE.Diagnostics.Project.Widgets +namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph { /// <summary> /// Interaction logic for RealTimeGraphWidgetView.xaml diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidget.cs index 25425a683..1ebaa199e 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidget.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidget.cs @@ -8,10 +8,11 @@ using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Media; +using Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph; -namespace Tango.FSE.Diagnostics.Project.Widgets +namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannel { - public class RealTimeGraphMultiChannelWidget : RealTimeGraphWidget + public class RealTimeGraphMultiChannelWidget : RealTimeGraphWidgetBase<RealTimeGraphMultiChannelWidgetSettings> { public async override Task Init() { diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetSettings.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetSettings.cs new file mode 100644 index 000000000..9bc05c74f --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetSettings.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media; +using Tango.Core; +using Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph; + +namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannel +{ + public class RealTimeGraphMultiChannelWidgetSettings : RealTimeGraphWidgetSettings + { + public override FrameworkElement GetView() + { + return new RealTimeGraphMultiChannelWidgetSettingsView() { DataContext = this }; + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetSettingsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetSettingsView.xaml new file mode 100644 index 000000000..0ac731be0 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetSettingsView.xaml @@ -0,0 +1,100 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannel.RealTimeGraphMultiChannelWidgetSettingsView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" + xmlns:colorPicker="clr-namespace:Tango;assembly=Tango.ColorPicker" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannel" + mc:Ignorable="d" + d:DesignHeight="300" d:DesignWidth="600" d:DataContext="{d:DesignInstance Type=local:RealTimeGraphMultiChannelWidget,IsDesignTimeCreatable=False}"> + <Grid> + <StackPanel> + + <controls:FSEGroupBox Header="DURATION" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <StackPanel> + <DockPanel> + <TextBlock DockPanel.Dock="Right" FontSize="{StaticResource FSE_SmallerFontSize}" Text="{Binding Settings.Duration,Mode=OneWay}" /> + <TextBlock FontSize="{StaticResource FSE_SmallerFontSize}">Maximum Visible Time</TextBlock> + </DockPanel> + <Slider Margin="0 5 0 0" Minimum="10" Maximum="3600" IsSnapToTickEnabled="True" Value="{Binding Settings.Duration,Converter={StaticResource TimeSpanToSecondsConverter},Mode=TwoWay}"></Slider> + </StackPanel> + </controls:FSEGroupBox> + + <controls:FSEGroupBox Margin="0 10 0 0" Header="RANGE" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <StackPanel> + <DockPanel> + <TextBlock DockPanel.Dock="Right" FontSize="{StaticResource FSE_SmallerFontSize}" > + <Run Text="{Binding Settings.Min,Mode=OneWay}"></Run> + <Run>-</Run> + <Run Text="{Binding Settings.Max,Mode=OneWay}"></Run> + </TextBlock> + <TextBlock FontSize="{StaticResource FSE_SmallerFontSize}" >Y Min/Max</TextBlock> + </DockPanel> + <mahapps:RangeSlider Margin="0 5 0 0" + Minimum="-100000" + Interval="1" + Maximum="100000" + SmallChange="1" + IsSnapToTickEnabled="True" + AutoToolTipPlacement="None" + LowerValue="{Binding Settings.Min,UpdateSourceTrigger=PropertyChanged}" + UpperValue="{Binding Settings.Max,UpdateSourceTrigger=PropertyChanged}"/> + + <CheckBox Margin="0 10 0 0" IsChecked="{Binding Settings.AutoRange}">Auto Range</CheckBox> + </StackPanel> + </controls:FSEGroupBox> + + <controls:FSEGroupBox Header="FORMAT" Margin="0 10 0 0" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <StackPanel> + <TextBlock FontSize="{StaticResource FSE_SmallerFontSize}" >Decimal Places</TextBlock> + <mahapps:NumericUpDown Background="Transparent" BorderThickness="0 0 0 1" HorizontalContentAlignment="Left" Minimum="0" Maximum="3" Focusable="False" Value="{Binding Settings.DecimalPlaces,UpdateSourceTrigger=PropertyChanged}" /> + </StackPanel> + </controls:FSEGroupBox> + + <controls:FSEGroupBox Header="VISIBILITY" Margin="0 10 0 0" HeaderFontSize="{StaticResource FSE_SmallFontSize}"> + <Border TextElement.FontSize="{StaticResource FSE_SmallFontSize}"> + <ItemsControl ItemsSource="{Binding Controller.DataSeriesCollection}"> + <ItemsControl.ItemTemplate> + <DataTemplate> + <ToggleButton IsChecked="{Binding IsVisible}" Cursor="Hand"> + <ToggleButton.Template> + <ControlTemplate> + <StackPanel Orientation="Horizontal" Margin="0 2" Background="Transparent"> + <Ellipse Width="10" Height="10"> + <Ellipse.Style> + <Style TargetType="Ellipse"> + <Setter Property="Fill" Value="Black"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding IsVisible}" Value="True"> + <Setter Property="Fill"> + <Setter.Value> + <SolidColorBrush Color="{Binding Stroke}" /> + </Setter.Value> + </Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </Ellipse.Style> + </Ellipse> + <TextBlock Margin="5 0 0 0" Text="{Binding Name}"> + <TextBlock.Foreground> + <SolidColorBrush Color="{Binding Stroke}" /> + </TextBlock.Foreground> + </TextBlock> + </StackPanel> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + </Border> + </controls:FSEGroupBox> + + <Button Style="{StaticResource FSE_RaisedButton_Dark_Hover}" Margin="0 20 0 0" Height="50" material:ButtonAssist.CornerRadius="25" Command="{Binding ClearCommand}">CLEAR</Button> + </StackPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetSettingsView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetSettingsView.xaml.cs new file mode 100644 index 000000000..936efc60a --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetSettingsView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannel +{ + /// <summary> + /// Interaction logic for RealTimeGraphWidgetSettingsView.xaml + /// </summary> + public partial class RealTimeGraphMultiChannelWidgetSettingsView : UserControl + { + public RealTimeGraphMultiChannelWidgetSettingsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetView.xaml new file mode 100644 index 000000000..6ff068180 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetView.xaml @@ -0,0 +1,13 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannel.RealTimeGraphMultiChannelWidgetView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannel" + xmlns:graphs="clr-namespace:Tango.FSE.Common.Graphs;assembly=Tango.FSE.Common" + mc:Ignorable="d" + d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=local:RealTimeGraphMultiChannelWidget,IsDesignTimeCreatable=False}"> + <Grid> + <graphs:RealTimeGraph Style="{StaticResource FSE_RealTimeGraph_Diagnostics}" Controller="{Binding Controller}" StringFormat="{Binding Settings.DecimalPlaces,Converter={StaticResource DecimalPlacesToStringFormatConverter}}" /> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidgetView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetView.xaml.cs index 944f73dc3..3c7c061d2 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidgetView.xaml.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannel/RealTimeGraphMultiChannelWidgetView.xaml.cs @@ -13,7 +13,7 @@ using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; -namespace Tango.FSE.Diagnostics.Project.Widgets +namespace Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannel { /// <summary> /// Interaction logic for RealTimeGraphWidgetView.xaml diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidgetView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidgetView.xaml deleted file mode 100644 index a248ac6e4..000000000 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidgetView.xaml +++ /dev/null @@ -1,53 +0,0 @@ -<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannelWidgetView" - xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets" - xmlns:graphs="clr-namespace:Tango.FSE.Common.Graphs;assembly=Tango.FSE.Common" - mc:Ignorable="d" - d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=local:RealTimeGraphMultiChannelWidget,IsDesignTimeCreatable=False}"> - <Grid> - <DockPanel> - <Border Margin="2 0 0 0" DockPanel.Dock="Right" HorizontalAlignment="Right" BorderThickness="1" BorderBrush="{StaticResource FSE_RealTimeGraph_OuterBorderBrush}" Background="{StaticResource FSE_RealTimeGraph_BackgroundBrush}" CornerRadius="5" TextElement.FontSize="{StaticResource FSE_SmallerFontSize}" Padding="5" MaxWidth="83"> - <ItemsControl ItemsSource="{Binding Controller.DataSeriesCollection}"> - <ItemsControl.ItemTemplate> - <DataTemplate> - <ToggleButton IsChecked="{Binding IsVisible}" Cursor="Hand"> - <ToggleButton.Template> - <ControlTemplate> - <StackPanel Orientation="Horizontal" Margin="0 2" Background="Transparent"> - <Ellipse Width="10" Height="10"> - <Ellipse.Style> - <Style TargetType="Ellipse"> - <Setter Property="Fill" Value="Black"></Setter> - <Style.Triggers> - <DataTrigger Binding="{Binding IsVisible}" Value="True"> - <Setter Property="Fill"> - <Setter.Value> - <SolidColorBrush Color="{Binding Stroke}" /> - </Setter.Value> - </Setter> - </DataTrigger> - </Style.Triggers> - </Style> - </Ellipse.Style> - </Ellipse> - <TextBlock Margin="5 0 0 0" Text="{Binding Name}"> - <TextBlock.Foreground> - <SolidColorBrush Color="{Binding Stroke}" /> - </TextBlock.Foreground> - </TextBlock> - </StackPanel> - </ControlTemplate> - </ToggleButton.Template> - </ToggleButton> - </DataTemplate> - </ItemsControl.ItemTemplate> - </ItemsControl> - </Border> - - <graphs:RealTimeGraph Controller="{Binding Controller}" HorizontalTicks="7" VerticalTicks="5" /> - </DockPanel> - </Grid> -</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Tango.FSE.Diagnostics.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Tango.FSE.Diagnostics.csproj index b39213edf..2b3699858 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Tango.FSE.Diagnostics.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Tango.FSE.Diagnostics.csproj @@ -62,6 +62,7 @@ <Reference Include="System" /> <Reference Include="System.ComponentModel.DataAnnotations" /> <Reference Include="System.Data" /> + <Reference Include="System.Drawing" /> <Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <HintPath>..\..\..\packages\ControlzEx.3.0.2.4\lib\net45\System.Windows.Interactivity.dll</HintPath> </Reference> @@ -80,19 +81,41 @@ </ItemGroup> <ItemGroup> <Compile Include="Controls\DiagnosticsGrid.cs" /> + <Compile Include="Converters\DecimalPlacesToStringFormatConverter.cs" /> + <Compile Include="Converters\DiagnosticsWidgetToSettingsViewConverter.cs" /> <Compile Include="Converters\DiagnosticsWidgetToViewConverter.cs" /> + <Compile Include="Converters\PercentageToWidthConverter.cs" /> <Compile Include="DiagnosticsPackage.cs" /> + <Compile Include="Project\DiagnosticsConfigurableWidget.cs" /> <Compile Include="Project\DiagnosticsProject.cs" /> <Compile Include="Project\DiagnosticsProjectTab.cs" /> <Compile Include="Project\DiagnosticsProjectTabColumnDefinition.cs" /> <Compile Include="Project\DiagnosticsProjectTabRowDefinition.cs" /> <Compile Include="Project\DiagnosticsWidget.cs" /> - <Compile Include="Project\Widgets\RealTimeGraphMultiChannelWidget.cs" /> - <Compile Include="Project\Widgets\RealTimeGraphWidget.cs" /> - <Compile Include="Project\Widgets\RealTimeGraphMultiChannelWidgetView.xaml.cs"> + <Compile Include="Project\DiagnosticsWidgetSettings.cs" /> + <Compile Include="Project\Widgets\Monitor\MonitorWidget.cs" /> + <Compile Include="Project\Widgets\Monitor\MonitorWidgetSettings.cs" /> + <Compile Include="Project\Widgets\Monitor\MonitorWidgetSettingsView.xaml.cs"> + <DependentUpon>MonitorWidgetSettingsView.xaml</DependentUpon> + </Compile> + <Compile Include="Project\Widgets\Monitor\MonitorWidgetView.xaml.cs"> + <DependentUpon>MonitorWidgetView.xaml</DependentUpon> + </Compile> + <Compile Include="Project\Widgets\RealTimeGraphMultiChannel\RealTimeGraphMultiChannelWidget.cs" /> + <Compile Include="Project\Widgets\RealTimeGraphMultiChannel\RealTimeGraphMultiChannelWidgetSettingsView.xaml.cs"> + <DependentUpon>RealTimeGraphMultiChannelWidgetSettingsView.xaml</DependentUpon> + </Compile> + <Compile Include="Project\Widgets\RealTimeGraphMultiChannel\RealTimeGraphMultiChannelWidgetSettings.cs" /> + <Compile Include="Project\Widgets\RealTimeGraph\RealTimeGraphWidgetBase.cs" /> + <Compile Include="Project\Widgets\RealTimeGraph\RealTimeGraphWidgetSettings.cs" /> + <Compile Include="Project\Widgets\RealTimeGraph\RealTimeGraphWidget.cs" /> + <Compile Include="Project\Widgets\RealTimeGraphMultiChannel\RealTimeGraphMultiChannelWidgetView.xaml.cs"> <DependentUpon>RealTimeGraphMultiChannelWidgetView.xaml</DependentUpon> </Compile> - <Compile Include="Project\Widgets\RealTimeGraphWidgetView.xaml.cs"> + <Compile Include="Project\Widgets\RealTimeGraph\RealTimeGraphWidgetSettingsView.xaml.cs"> + <DependentUpon>RealTimeGraphWidgetSettingsView.xaml</DependentUpon> + </Compile> + <Compile Include="Project\Widgets\RealTimeGraph\RealTimeGraphWidgetView.xaml.cs"> <DependentUpon>RealTimeGraphWidgetView.xaml</DependentUpon> </Compile> <Compile Include="ViewModelLocator.cs" /> @@ -157,6 +180,10 @@ <Project>{f441feee-322a-4943-b566-110e12fd3b72}</Project> <Name>Tango.BL</Name> </ProjectReference> + <ProjectReference Include="..\..\..\Tango.ColorPicker\Tango.ColorPicker.csproj"> + <Project>{a2f5af44-29ff-45d6-9d25-ecda5cce88b5}</Project> + <Name>Tango.ColorPicker</Name> + </ProjectReference> <ProjectReference Include="..\..\..\Tango.Core\Tango.Core.csproj"> <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project> <Name>Tango.Core</Name> @@ -199,11 +226,31 @@ <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> </Page> - <Page Include="Project\Widgets\RealTimeGraphMultiChannelWidgetView.xaml"> + <Page Include="Project\Widgets\Monitor\MonitorWidgetSettingsView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Project\Widgets\Monitor\MonitorWidgetView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Project\Widgets\RealTimeGraphMultiChannel\RealTimeGraphMultiChannelWidgetView.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + <Page Include="Project\Widgets\RealTimeGraphMultiChannel\RealTimeGraphMultiChannelWidgetSettingsView.xaml"> <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> </Page> - <Page Include="Project\Widgets\RealTimeGraphWidgetView.xaml"> + <Page Include="Project\Widgets\RealTimeGraph\RealTimeGraphWidgetSettingsView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Project\Widgets\RealTimeGraph\RealTimeGraphWidgetView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Themes\Generic.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> @@ -223,7 +270,9 @@ <ItemGroup> <Resource Include="Images\diagnostics.png" /> </ItemGroup> - <ItemGroup /> + <ItemGroup> + <Resource Include="Project\Widgets\Monitor\Images\tft_screen.png" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets" Condition="Exists('..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets')" /> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Themes/Generic.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Themes/Generic.xaml new file mode 100644 index 000000000..2428e9255 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Themes/Generic.xaml @@ -0,0 +1,60 @@ +<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:graphs="clr-namespace:Tango.FSE.Common.Graphs;assembly=Tango.FSE.Common" + xmlns:localConverters="clr-namespace:Tango.FSE.Diagnostics.Converters" + xmlns:realTimeGraphX="clr-namespace:RealTimeGraphX.WPF;assembly=RealTimeGraphX.WPF" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Themes"> + + <localConverters:DecimalPlacesToStringFormatConverter x:Key="DecimalPlacesToStringFormatConverter" /> + + <Style TargetType="{x:Type graphs:RealTimeGraph}" x:Key="FSE_RealTimeGraph_Diagnostics"> + <Setter Property="BorderThickness" Value="1"></Setter> + <Setter Property="BorderBrush" Value="{StaticResource FSE_RealTimeGraph_OuterBorderBrush}"></Setter> + <Setter Property="Padding" Value="20 20 30 20"></Setter> + <Setter Property="FontSize" Value="11"></Setter> + <Setter Property="Foreground" Value="{StaticResource FSE_RealTimeGraph_ForegroundBrush}"></Setter> + <Setter Property="Background" Value="{StaticResource FSE_RealTimeGraph_BackgroundBrush}"></Setter> + <Setter Property="GridLinesBrush" Value="{StaticResource FSE_RealTimeGraph_GridLinesBrush}"></Setter> + <Setter Property="HorizontalTicks" Value="7"></Setter> + <Setter Property="VerticalTicks" Value="5"></Setter> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type graphs:RealTimeGraph}"> + <Grid> + <Border Background="{TemplateBinding Background}" + BorderBrush="{TemplateBinding BorderBrush}" + BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="5" + Padding="{TemplateBinding Padding}"> + <Grid> + <Grid.RowDefinitions> + <RowDefinition Height="1*"/> + <RowDefinition Height="Auto"/> + </Grid.RowDefinitions> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto"/> + <ColumnDefinition Width="1*"/> + </Grid.ColumnDefinitions> + + <Grid Grid.Column="1"> + <realTimeGraphX:WpfGraphGridLines Columns="{TemplateBinding HorizontalTicks}" Rows="{TemplateBinding VerticalTicks}" Controller="{TemplateBinding Controller}" Foreground="{TemplateBinding GridLinesBrush}" /> + <realTimeGraphX:WpfGraphSurface x:Name="surface" Controller="{TemplateBinding Controller}" BorderThickness="1 0 0 1" BorderBrush="{StaticResource FSE_RealTimeGraph_InnerBorderBrush}" /> + </Grid> + + <realTimeGraphX:WpfGraphAxisControl Width="70" Visibility="{TemplateBinding VerticalAxisVisibility}" Orientation="Vertical" Controller="{TemplateBinding Controller}" StringFormat="{TemplateBinding StringFormat}" Ticks="{TemplateBinding VerticalTicks}" /> + <realTimeGraphX:WpfGraphAxisControl Height="35" Visibility="{TemplateBinding HorizontalAxisVisibility}" Orientation="Horizontal" Controller="{TemplateBinding Controller}" Grid.Column="1" Grid.Row="1" Ticks="{TemplateBinding HorizontalTicks}" StringFormat="hh\:mm\:ss"/> + </Grid> + </Border> + <Image HorizontalAlignment="Left" VerticalAlignment="Top" Margin="8" Source="{StaticResource FSE_Screw}" RenderOptions.BitmapScalingMode="Fant" Width="10" Height="10" /> + <Image HorizontalAlignment="Right" VerticalAlignment="Top" Margin="8" Source="{StaticResource FSE_Screw}" RenderOptions.BitmapScalingMode="Fant" Width="10" Height="10" /> + + <Image HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="8" Source="{StaticResource FSE_Screw}" RenderOptions.BitmapScalingMode="Fant" Width="10" Height="10" /> + <Image HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="8" Source="{StaticResource FSE_Screw}" RenderOptions.BitmapScalingMode="Fant" Width="10" Height="10" /> + </Grid> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + +</ResourceDictionary>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsTabViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsTabViewVM.cs index a439eeeee..acea47b10 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsTabViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsTabViewVM.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.Core.Commands; using Tango.FSE.Common; using Tango.FSE.Diagnostics.Project; using Tango.PMR.Diagnostics; @@ -25,6 +26,35 @@ namespace Tango.FSE.Diagnostics.ViewModels set { _isSelected = value; RaisePropertyChangedAuto(); OnIsSelectedChanged(); } } + private DiagnosticsWidget _selectedWidget; + public DiagnosticsWidget SelectedWidget + { + get { return _selectedWidget; } + set { _selectedWidget = value; RaisePropertyChangedAuto(); } + } + + private bool _isWidgetSettingsOpened; + public bool IsWidgetSettingsOpened + { + get { return _isWidgetSettingsOpened; } + set { _isWidgetSettingsOpened = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand<DiagnosticsWidget> OpenWidgetSettingsCommand { get; set; } + + public RelayCommand CloseWidgetSettingsCommand { get; set; } + + public DiagnosticsTabViewVM() + { + OpenWidgetSettingsCommand = new RelayCommand<DiagnosticsWidget>(OpenWidgetSettings); + CloseWidgetSettingsCommand = new RelayCommand(() => IsWidgetSettingsOpened = false); + } + + private void OpenWidgetSettings(DiagnosticsWidget widget) + { + IsWidgetSettingsOpened = true; + } + private void OnIsSelectedChanged() { Tab.Widgets.ToList().ForEach(x => x.IsVisible = IsSelected); diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsViewVM.cs index 9c5ebaa66..75c623c62 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsViewVM.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; +using Tango.Core.Commands; using Tango.FSE.Common; using Tango.FSE.Common.Diagnostics; using Tango.FSE.Diagnostics.Project; @@ -17,6 +18,15 @@ namespace Tango.FSE.Diagnostics.ViewModels { private Dictionary<String, PropertyInfo> _monitorsProperties; private bool _isLoaded; + private string _diagnosticsProjectFile; + private FileSystemWatcher _diagnosticsProjectFileWatcher; + + private bool _isLoadingProject; + public bool IsLoadingProject + { + get { return _isLoadingProject; } + set { _isLoadingProject = value; RaisePropertyChangedAuto(); } + } private DiagnosticsProject _project; public DiagnosticsProject Project @@ -39,6 +49,8 @@ namespace Tango.FSE.Diagnostics.ViewModels set { _selectedTab = value; RaisePropertyChangedAuto(); OnSelectedTabChanged(); } } + public RelayCommand ExportProjectCommand { get; set; } + public DiagnosticsViewVM() { _monitorsProperties = new Dictionary<string, PropertyInfo>(); @@ -50,12 +62,39 @@ namespace Tango.FSE.Diagnostics.ViewModels Tabs = new ObservableCollection<DiagnosticsTabViewVM>(); Project = new DiagnosticsProject(); + + ExportProjectCommand = new RelayCommand(ExportProject); } public override void OnApplicationStarted() { base.OnApplicationStarted(); DiagnosticsProvider.FrameReceived += DiagnosticsProvider_FrameReceived; + + _diagnosticsProjectFileWatcher = new FileSystemWatcher(ApplicationManager.StartPath, "diagnostics.json"); + _diagnosticsProjectFileWatcher.Changed += _diagnosticsProjectFileWatcher_Changed; + _diagnosticsProjectFileWatcher.EnableRaisingEvents = true; + } + + private void _diagnosticsProjectFileWatcher_Changed(object sender, FileSystemEventArgs e) + { + InvokeUI(async () => + { + int selectedIndex = 0; + + if (SelectedTab != null) + { + selectedIndex = Tabs.IndexOf(SelectedTab); + } + + await Task.Delay(200); + await LoadProject(); + + if (selectedIndex > 0 && Tabs.Count > selectedIndex) + { + SelectedTab = Tabs[selectedIndex]; + } + }); } private void DiagnosticsProvider_FrameReceived(object sender, DiagnosticsFrameReceivedEventArgs e) @@ -63,22 +102,26 @@ namespace Tango.FSE.Diagnostics.ViewModels PopulateDiagnosticsData(e.Frame); } - public override void OnApplicationReady() + public async override void OnApplicationReady() { base.OnApplicationReady(); if (!_isLoaded) { - LoadProject(); + _diagnosticsProjectFile = Path.Combine(ApplicationManager.StartPath, "diagnostics.json"); + await LoadProject(); } } - private async void LoadProject() + private async Task LoadProject() { - Project = DiagnosticsProject.FromFile(Path.Combine(ApplicationManager.StartPath, "diagnostics.json")); + Project = DiagnosticsProject.FromFile(_diagnosticsProjectFile); try { + IsLoadingProject = true; + _isLoaded = false; + await Services.TechComponentsService.Preload(); foreach (var widget in Project.Tabs.SelectMany(x => x.Widgets)) @@ -108,16 +151,15 @@ namespace Tango.FSE.Diagnostics.ViewModels NotificationProvider.PushErrorReportingSnackbar(ex, "Diagnostics Module Error", "Error initializing diagnostics module."); return; } + finally + { + IsLoadingProject = false; + } } private void OnSelectedTabChanged() { - //if (SelectedTab != null) - //{ - // Tabs.Where(x => x != SelectedTab).SelectMany(x => x.Tab.Widgets).ToList().ForEach(x => x.IsVisible = false); - // SelectedTab.Tab.Widgets.ToList().ForEach(x => x.IsVisible = true); - //} } private void PopulateDiagnosticsData(DiagnosticsFrame frame) @@ -134,5 +176,23 @@ namespace Tango.FSE.Diagnostics.ViewModels } } } + + private async void ExportProject() + { + var result = await StorageProvider.SaveFile("Export diagnostics project", "Diagnostics Projects|*.json", "diagnostics.json", ".json"); + + if (result.Confirmed) + { + try + { + Project.ToFile(result.SelectedItem); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error exporting diagnostics project."); + await NotificationProvider.ShowError($"Error exporting diagnostics project\n{ex.FlattenMessage()}"); + } + } + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml index c53998f4d..7a8545f86 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml @@ -4,7 +4,10 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:global="clr-namespace:Tango.FSE.Diagnostics" + xmlns:commonControls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" xmlns:vm="clr-namespace:Tango.FSE.Diagnostics.ViewModels" + xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:controls="clr-namespace:Tango.FSE.Diagnostics.Controls" xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Views" xmlns:converters="clr-namespace:Tango.FSE.Diagnostics.Converters" @@ -13,29 +16,100 @@ <UserControl.Resources> <converters:DiagnosticsWidgetToViewConverter x:Key="DiagnosticsWidgetToViewConverter" /> + <converters:DiagnosticsWidgetToSettingsViewConverter x:Key="DiagnosticsWidgetToSettingsViewConverter" /> + <converters:PercentageToWidthConverter x:Key="PercentageToWidthConverter" /> </UserControl.Resources> <Grid> - <ItemsControl ItemsSource="{Binding Tab.Widgets}"> - <ItemsControl.ItemsPanel> + <ListBox HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" ItemsSource="{Binding Tab.Widgets}" SelectedItem="{Binding SelectedWidget,Mode=TwoWay}" Style="{StaticResource FSE_BlankListBox}" ScrollViewer.VerticalScrollBarVisibility="Disabled"> + <ListBox.ItemsPanel> <ItemsPanelTemplate> <controls:DiagnosticsGrid IsItemsHost="True" ShowGridLines="False" Columns="{Binding Tab.Columns}" Rows="{Binding Tab.Rows}"/> </ItemsPanelTemplate> - </ItemsControl.ItemsPanel> - <ItemsControl.ItemContainerStyle> - <Style TargetType="FrameworkElement"> + </ListBox.ItemsPanel> + <ListBox.ItemContainerStyle> + <Style TargetType="ListBoxItem" BasedOn="{StaticResource FSE_BlankListBoxItem}"> <Setter Property="Grid.Column" Value="{Binding Column}"></Setter> <Setter Property="Grid.Row" Value="{Binding Row}"></Setter> <Setter Property="Grid.ColumnSpan" Value="{Binding ColumnSpan}"></Setter> <Setter Property="Grid.RowSpan" Value="{Binding RowSpan}"></Setter> <Setter Property="Margin" Value="5"></Setter> </Style> - </ItemsControl.ItemContainerStyle> + </ListBox.ItemContainerStyle> <ItemsControl.ItemTemplate> <DataTemplate> - <ContentPresenter Content="{Binding Converter={StaticResource DiagnosticsWidgetToViewConverter}}"/> + <Grid x:Name="parentGrid"> + <Grid x:Name="widgetGrid" Background="Transparent" HorizontalAlignment="Center" VerticalAlignment="Center"> + <Grid.Width> + <MultiBinding Converter="{StaticResource PercentageToWidthConverter}"> + <Binding ElementName="parentGrid" Path="ActualWidth" /> + <Binding Path="Width" /> + </MultiBinding> + </Grid.Width> + <Grid.Height> + <MultiBinding Converter="{StaticResource PercentageToWidthConverter}"> + <Binding ElementName="parentGrid" Path="ActualHeight" /> + <Binding Path="Height" /> + </MultiBinding> + </Grid.Height> + + <ContentPresenter Content="{Binding Converter={StaticResource DiagnosticsWidgetToViewConverter}}"/> + + <Grid HorizontalAlignment="Left" VerticalAlignment="Bottom" Width="32" Height="32" Margin="10" Visibility="{Binding Settings,Converter={StaticResource IsNullToVisibilityConverter},FallbackValue='Collapsed',TargetNullValue='Collapsed'}"> + <i:Interaction.Triggers> + <i:EventTrigger EventName="PreviewMouseUp"> + <i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.OpenWidgetSettingsCommand}" CommandParameter="{Binding}" /> + </i:EventTrigger> + </i:Interaction.Triggers> + <Grid Cursor="Hand" Visibility="{Binding ElementName=widgetGrid,Path=IsMouseOver,Converter={StaticResource BooleanToVisibilityConverter}}"> + <Grid.Style> + <Style TargetType="Grid"> + <Setter Property="Opacity" Value="0.6"></Setter> + <Style.Triggers> + <Trigger Property="IsMouseOver" Value="True"> + <Setter Property="Opacity" Value="1"></Setter> + </Trigger> + </Style.Triggers> + </Style> + </Grid.Style> + <Ellipse Fill="#202020"/> + <material:PackIcon HorizontalAlignment="Center" VerticalAlignment="Center" Width="20" Height="20" Kind="SettingsOutline" /> + </Grid> + </Grid> + </Grid> + </Grid> </DataTemplate> </ItemsControl.ItemTemplate> - </ItemsControl> + </ListBox> + + <Grid Margin="20" HorizontalAlignment="Right" Width="300"> + <Grid.Style> + <Style TargetType="Grid"> + <Setter Property="Visibility" Value="Collapsed"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding IsWidgetSettingsOpened}" Value="True"> + <Setter Property="Visibility" Value="Visible"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </Grid.Style> + <Border Background="#B1393939" CornerRadius="5"> + <Border.Effect> + <DropShadowEffect ShadowDepth="0" /> + </Border.Effect> + + <DockPanel> + <Border DockPanel.Dock="Top" Background="{StaticResource FSE_PrimaryBackgroundBrush}" CornerRadius="5 5 0 0"> + <DockPanel Margin="20 10 10 10"> + <commonControls:IconButton Command="{Binding CloseWidgetSettingsCommand}" ToolTip="Close Settings" Icon="Close" DockPanel.Dock="Right" Padding="0" Width="24" Height="24"></commonControls:IconButton> + <TextBlock VerticalAlignment="Center" Text="{Binding SelectedWidget.DisplayName,Mode=OneWay}"></TextBlock> + </DockPanel> + </Border> + <ScrollViewer Padding="10" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled"> + <ContentPresenter Content="{Binding SelectedWidget,Converter={StaticResource DiagnosticsWidgetToSettingsViewConverter}}" /> + </ScrollViewer> + </DockPanel> + </Border> + </Grid> </Grid> </UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.xaml index 5b01eaa1b..96f9e1bf0 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.xaml @@ -10,7 +10,7 @@ mc:Ignorable="d" d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:DiagnosticsViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.DiagnosticsViewVM}" Background="{StaticResource FSE_PrimaryBackgroundBrush}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> <Grid Margin="20"> - <DockPanel> + <DockPanel x:Name="dock"> <Grid DockPanel.Dock="Top" Height="50"> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*" /> @@ -93,28 +93,34 @@ <Rectangle Grid.Column="2" VerticalAlignment="Bottom" StrokeThickness="2" Stroke="{StaticResource FSE_PrimaryAccentDarkBrush}" /> </Grid> - <ItemsControl x:Name="tabControl" Margin="0 0 0 0" ItemsSource="{Binding Tabs}" BorderThickness="0" Background="Transparent"> - <ItemsControl.ItemsPanel> - <ItemsPanelTemplate> - <Grid/> - </ItemsPanelTemplate> - </ItemsControl.ItemsPanel> - <ItemsControl.ItemContainerStyle> - <Style TargetType="FrameworkElement"> - <Setter Property="Visibility" Value="Hidden"></Setter> - <Style.Triggers> - <DataTrigger Binding="{Binding IsSelected}" Value="True"> - <Setter Property="Visibility" Value="Visible"></Setter> - </DataTrigger> - </Style.Triggers> - </Style> - </ItemsControl.ItemContainerStyle> - <ItemsControl.ItemTemplate> - <DataTemplate> - <local:DiagnosticsTabView /> - </DataTemplate> - </ItemsControl.ItemTemplate> - </ItemsControl> + <Grid x:Name="grid"> + <Viewbox Stretch="Fill" Margin="0 0 0 0" VerticalAlignment="Top" Width="{Binding ElementName=grid,Path=ActualWidth}" Height="{Binding ElementName=grid,Path=ActualHeight}"> + <ItemsControl x:Name="tabControl" Width="1810" Height="827" ItemsSource="{Binding Tabs}" BorderThickness="0" Background="Transparent"> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <Grid/> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.ItemContainerStyle> + <Style TargetType="FrameworkElement"> + <Setter Property="Visibility" Value="Hidden"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding IsSelected}" Value="True"> + <Setter Property="Visibility" Value="Visible"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </ItemsControl.ItemContainerStyle> + <ItemsControl.ItemTemplate> + <DataTemplate> + <local:DiagnosticsTabView /> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + </Viewbox> + </Grid> </DockPanel> + + <controls:IconButton HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0 10 0 0" Cursor="Hand" ToolTip="Export diagnostics project" Icon="LightningBolt" Foreground="{StaticResource FSE_OrangeBrush}" Command="{Binding ExportProjectCommand}"></controls:IconButton> </Grid> </UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/diagnostics.json b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/diagnostics.json index 056761391..6baf6b4c2 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/diagnostics.json +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/diagnostics.json @@ -81,7 +81,7 @@ ], "Widgets": [ { - "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphWidget, Tango.FSE.Diagnostics", + "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph.RealTimeGraphWidget, Tango.FSE.Diagnostics", "Monitor": "Dancer2Angle", "Column": 0, "Row": 0, @@ -89,7 +89,7 @@ "RowSpan": 3 }, { - "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphWidget, Tango.FSE.Diagnostics", + "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph.RealTimeGraphWidget, Tango.FSE.Diagnostics", "Monitor": "Dancer2Angle", "Column": 3, "Row": 0, @@ -97,7 +97,7 @@ "RowSpan": 3 }, { - "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphWidget, Tango.FSE.Diagnostics", + "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph.RealTimeGraphWidget, Tango.FSE.Diagnostics", "Monitor": "Dancer2Angle", "Column": 6, "Row": 0, @@ -105,7 +105,7 @@ "RowSpan": 3 }, { - "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphWidget, Tango.FSE.Diagnostics", + "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph.RealTimeGraphWidget, Tango.FSE.Diagnostics", "Monitor": "Dancer2Angle", "Column": 9, "Row": 0, @@ -113,13 +113,23 @@ "RowSpan": 3 }, { - "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannelWidget, Tango.FSE.Diagnostics", + "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannel.RealTimeGraphMultiChannelWidget, Tango.FSE.Diagnostics", "Monitor": "DispensersMotorsFrequency", "Column": 0, "Row": 3, "ColumnSpan": 3, "RowSpan": 3 + }, + { + "$type": "Tango.FSE.Diagnostics.Project.Widgets.Monitor.MonitorWidget, Tango.FSE.Diagnostics", + "Monitor": "Dancer2Angle", + "Column": 0, + "Row": 6, + "ColumnSpan": 3, + "RowSpan": 2, + "Width": 50 } + ] }, { @@ -202,7 +212,7 @@ ], "Widgets": [ { - "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphWidget, Tango.FSE.Diagnostics", + "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraph.RealTimeGraphWidget, Tango.FSE.Diagnostics", "Monitor": "Dancer2Angle", "Column": 2, "Row": 2, diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Firmware/ViewModels/FileSystemViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Firmware/ViewModels/FileSystemViewVM.cs index bb655d27b..6ad02cd49 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Firmware/ViewModels/FileSystemViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Firmware/ViewModels/FileSystemViewVM.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input; +using Tango.BL.Enumerations; using Tango.Core.Commands; using Tango.FileSystem; using Tango.FSE.Common; @@ -160,7 +161,7 @@ namespace Tango.FSE.Firmware.ViewModels private async void MachineProvider_MachineConnected(object sender, MachineConnectedEventArgs e) { - if (e.DifferentFromPrevious) + if (e.DifferentFromPrevious && e.MachineOperator.IsConnected && AuthenticationProvider.CurrentUser.HasPermission(Permissions.FSE_FirmwareFileSystemRead)) { try { diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Firmware/Views/FileSystemView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Firmware/Views/FileSystemView.xaml index d3db0d70b..ff31c4d0e 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Firmware/Views/FileSystemView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Firmware/Views/FileSystemView.xaml @@ -11,7 +11,7 @@ mc:Ignorable="d" d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:FileSystemViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.FileSystemViewVM}"> <Grid IsEnabled="{Binding IsFree}"> - <Grid IsEnabled="{Binding MachineProvider.IsPPCAvailable}"> + <Grid IsEnabled="{Binding MachineProvider.IsConnected}"> <Grid Margin="0 20 0 0"> <Grid.RowDefinitions> <RowDefinition Height="30" /> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj index 3c740f103..af50e4e32 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj @@ -105,7 +105,6 @@ <Reference Include="PresentationFramework" /> </ItemGroup> <ItemGroup> - <Compile Include="Converters\DoubleToChartValuesConverter.cs" /> <Compile Include="Dialogs\MachineUpdateView.xaml.cs"> <DependentUpon>MachineUpdateView.xaml</DependentUpon> </Compile> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MonitoringView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MonitoringView.xaml index 7de5c805d..0af569096 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MonitoringView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MonitoringView.xaml @@ -8,7 +8,6 @@ xmlns:global="clr-namespace:Tango.FSE.PPCConsole" xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf" xmlns:vm="clr-namespace:Tango.FSE.PPCConsole.ViewModels" - xmlns:converters="clr-namespace:Tango.FSE.PPCConsole.Converters" xmlns:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" xmlns:local="clr-namespace:Tango.FSE.PPCConsole.Views" mc:Ignorable="d" @@ -16,8 +15,6 @@ <UserControl.Resources> - <converters:DoubleToChartValuesConverter x:Key="DoubleToChartValuesConverter" /> - <Style x:Key="DynamicResolutionGraph" TargetType="graphs:RealTimeGraph" BasedOn="{StaticResource {x:Type graphs:RealTimeGraph}}"> <Setter Property="VerticalTicks" Value="11"></Setter> <Style.Triggers> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/RemoteDesktopView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/RemoteDesktopView.xaml index 247753801..b3a34c3b9 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/RemoteDesktopView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/RemoteDesktopView.xaml @@ -149,8 +149,8 @@ </Grid> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Height="50"> - <controls:TextIconButton Icon="Stop" Padding="0 12" Width="200" Command="{Binding StopCommand}" IsEnabled="{Binding RemoteDesktopProvider.InSession}" Grid.Column="1" Style="{StaticResource FSE_TextIconButton_Dark}">STOP</controls:TextIconButton> - <controls:TextIconButton Icon="Play" Padding="0 12" Width="200" Command="{Binding StartCommand}" IsEnabled="{Binding RemoteDesktopProvider.CanStartSession}" Grid.Column="2" Margin="10 0 0 0" Height="Auto">START</controls:TextIconButton> + <controls:TextIconButton material:ButtonAssist.CornerRadius="25" Icon="Stop" Padding="0 12" Width="200" Command="{Binding StopCommand}" IsEnabled="{Binding RemoteDesktopProvider.InSession}" Grid.Column="1" Style="{StaticResource FSE_TextIconButton_Dark}">STOP</controls:TextIconButton> + <controls:TextIconButton material:ButtonAssist.CornerRadius="25" Icon="Play" Padding="0 12" Width="200" Command="{Binding StartCommand}" IsEnabled="{Binding RemoteDesktopProvider.CanStartSession}" Grid.Column="2" Margin="10 0 0 0" Height="Auto">START</controls:TextIconButton> </StackPanel> </Grid> <Grid> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Contracts/ITestDesignerView.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Contracts/ITestDesignerView.cs index 97cf9a433..f6566765e 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Contracts/ITestDesignerView.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Contracts/ITestDesignerView.cs @@ -10,7 +10,8 @@ namespace Tango.FSE.Stubs.Contracts public interface ITestDesignerView : IFSEView { void FormatCode(); - void HighlightCode(int position, int length); + void HighlightCode(int position, int length, int line); void InsertCode(String code); + void InvalidateHighlighting(); } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/LoadPublishedProjectView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/LoadPublishedProjectView.xaml index 2289196e7..7bb2af7a7 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/LoadPublishedProjectView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/LoadPublishedProjectView.xaml @@ -57,5 +57,7 @@ </ListBox> </Border> </DockPanel> + + <CheckBox IsChecked="{Binding ShowSuppressedProjects}" VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="10 0 0 -55" Foreground="{StaticResource FSE_GrayBrush}" FontSize="{StaticResource FSE_SmallFontSize}">Show Suppressed Projects</CheckBox> </Grid> </UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/LoadPublishedProjectViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/LoadPublishedProjectViewVM.cs index 5164e3262..c430c3f90 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/LoadPublishedProjectViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/LoadPublishedProjectViewVM.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows.Data; using Tango.BL.Entities; using Tango.FSE.Common; @@ -10,6 +12,8 @@ namespace Tango.FSE.Stubs.Dialogs { public class LoadPublishedProjectViewVM : FSEDialogViewVM { + private ICollectionView _projectsView; + public List<PublishedTestProject> PublishedTestProjects { get; set; } private PublishedTestProject _selectedProject; @@ -19,10 +23,32 @@ namespace Tango.FSE.Stubs.Dialogs set { _selectedProject = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } } + private bool _showSuppressedProjects; + public bool ShowSuppressedProjects + { + get { return _showSuppressedProjects; } + set { _showSuppressedProjects = value; RaisePropertyChangedAuto(); _projectsView?.Refresh(); } + } + public LoadPublishedProjectViewVM(List<PublishedTestProject> projects) { OKText = "LOAD PROJECT"; PublishedTestProjects = projects; + _projectsView = CollectionViewSource.GetDefaultView(PublishedTestProjects); + _projectsView.Filter = (obj) => + { + PublishedTestProject p = obj as PublishedTestProject; + + if (p != null) + { + if (!ShowSuppressedProjects && !p.IsVisible) + { + return false; + } + } + + return true; + }; } protected override bool CanOK() diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/ResultGridView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/ResultGridView.xaml new file mode 100644 index 000000000..0e7a1185b --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/ResultGridView.xaml @@ -0,0 +1,31 @@ +<UserControl x:Class="Tango.FSE.Stubs.Dialogs.ResultGridView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:local="clr-namespace:Tango.FSE.Stubs.Dialogs" + mc:Ignorable="d" + Width="1000" Height="600" d:DataContext="{d:DesignInstance Type=local:ResultGridViewVM, IsDesignTimeCreatable=False}" Background="{StaticResource FSE_PrimaryBackgroundLightBrush}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> + <Grid Margin="10"> + <DockPanel> + <StackPanel DockPanel.Dock="Top" Orientation="Horizontal"> + <material:PackIcon Kind="ViewGrid" Width="32" Height="32" /> + <TextBlock Margin="10 0 0 0" FontSize="{StaticResource FSE_LargeFontSize}" VerticalAlignment="Center" Text="{Binding Result.Name}"></TextBlock> + </StackPanel> + + <Border Margin="0 20 0 0" BorderThickness="1" BorderBrush="{StaticResource FSE_BorderBrush}" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" CornerRadius="5"> + <DataGrid x:Name="grid" + CellStyle="{StaticResource FSE_DataGrid_Cell}" + Style="{StaticResource FSE_DataGrid}" + AutoGenerateColumns="False" + CanUserSortColumns="True" + CanUserReorderColumns="True" + CanUserResizeColumns="True" + CanUserResizeRows="True"> + + </DataGrid> + </Border> + </DockPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/ResultGridView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/ResultGridView.xaml.cs new file mode 100644 index 000000000..ab908f94f --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/ResultGridView.xaml.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.FSE.Stubs.Dialogs +{ + /// <summary> + /// Interaction logic for ResultGridView.xaml + /// </summary> + public partial class ResultGridView : UserControl + { + public class ResultObject + { + public Object V0 { get; set; } + public Object V1 { get; set; } + public Object V2 { get; set; } + public Object V3 { get; set; } + public Object V4 { get; set; } + public Object V5 { get; set; } + public Object V6 { get; set; } + public Object V7 { get; set; } + public Object V8 { get; set; } + public Object V9 { get; set; } + public Object V10 { get; set; } + public Object V11 { get; set; } + public Object V12 { get; set; } + public Object V13 { get; set; } + public Object V14 { get; set; } + } + + public ResultGridView() + { + InitializeComponent(); + + Loaded += ResultGridView_Loaded; + } + + private void ResultGridView_Loaded(object sender, RoutedEventArgs e) + { + var vm = DataContext as ResultGridViewVM; + var results = vm.Items; + + List<ResultObject> objects = new List<ResultObject>(); + + if (results.Count > 0) + { + var model = results.First(); + + if (model.GetType().IsValueTypeOrString()) + { + grid.Columns.Add(new DataGridTextColumn() + { + Header = "Values", + Binding = new Binding("V0"), + }); + + foreach (var item in results) + { + objects.Add(new ResultObject() + { + V0 = item, + }); + } + } + else + { + int columnCount = 0; + + //Generate columns + foreach (var prop in model.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) + { + grid.Columns.Add(new DataGridTextColumn() + { + Header = prop.Name, + Binding = new Binding($"V{columnCount++}"), + }); + } + + foreach (var field in model.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance)) + { + grid.Columns.Add(new DataGridTextColumn() + { + Header = field.Name, + Binding = new Binding($"V{columnCount++}"), + }); + } + + //Generate cells + + foreach (var item in results) + { + ResultObject obj = new ResultObject(); + + var properties = model.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).ToList(); + var fields = model.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance).ToList(); + + int propCount = 0; + + for (int i = 0; i < properties.Count; i++) + { + typeof(ResultObject).GetProperty($"V{i}").SetValue(obj, properties[i].GetValue(item)); + propCount++; + } + + for (int i = 0; i < fields.Count; i++) + { + typeof(ResultObject).GetProperty($"V{i + propCount}").SetValue(obj, fields[i].GetValue(item)); + } + + objects.Add(obj); + } + } + } + + grid.ItemsSource = objects; + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/ResultGridViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/ResultGridViewVM.cs new file mode 100644 index 000000000..b6e45c208 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/ResultGridViewVM.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.FSE.Common; + +namespace Tango.FSE.Stubs.Dialogs +{ + public class ResultGridViewVM : FSEDialogViewVM + { + public Result Result { get; set; } + + public List<Object> Items { get; set; } + + public ResultGridViewVM(Result result) : base() + { + CanCancel = false; + OKText = "CLOSE"; + + Result = result; + Items = new List<object>(); + + foreach (var item in Result.Value as IEnumerable) + { + Items.Add(item); + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Result.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Result.cs index 813f31532..b75bf3c42 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Result.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Result.cs @@ -14,7 +14,7 @@ namespace Tango.FSE.Stubs public String Name { get; set; } public Object Value { get; set; } - internal bool IsValueArray + public bool IsValueArray { get { return Value != null && typeof(IEnumerable).IsAssignableFrom(Value.GetType()) && Value.GetType() != typeof(String); } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Tango.FSE.Stubs.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Tango.FSE.Stubs.csproj index 67bd5dfc8..61dedf949 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Tango.FSE.Stubs.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Tango.FSE.Stubs.csproj @@ -110,6 +110,10 @@ <DependentUpon>LoadPublishedProjectView.xaml</DependentUpon> </Compile> <Compile Include="Dialogs\LoadPublishedProjectViewVM.cs" /> + <Compile Include="Dialogs\ResultGridView.xaml.cs"> + <DependentUpon>ResultGridView.xaml</DependentUpon> + </Compile> + <Compile Include="Dialogs\ResultGridViewVM.cs" /> <Compile Include="Dialogs\UserInputDialogView.xaml.cs"> <DependentUpon>UserInputDialogView.xaml</DependentUpon> </Compile> @@ -247,6 +251,10 @@ <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> </Page> + <Page Include="Dialogs\ResultGridView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> <Page Include="Dialogs\UserInputDialogView.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/MainViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/MainViewVM.cs index 02d2f8b53..49345e413 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/MainViewVM.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.BL.Enumerations; using Tango.FSE.Common; using Tango.FSE.Common.Navigation; using Tango.FSE.Stubs.Views; @@ -14,7 +15,7 @@ namespace Tango.FSE.Stubs.ViewModels [NavigationContainer] public class MainViewVM : FSEViewModel { - public override void OnApplicationStarted() + public override void OnApplicationReady() { InvokeUI(() => { @@ -29,16 +30,19 @@ namespace Tango.FSE.Stubs.ViewModels Image = ResourceHelper.GetImageFromResources("Images/test_runner.png"), }); - NavigationManager.MenuItems.Add(new NavigationMenuItem(() => - { - NavigationManager.NavigateTo<StubsModule>(nameof(TestDesignerView)); - }) + if (AuthenticationProvider.CurrentUser.HasPermission(Permissions.FSE_RunTestDesigner)) { - Name = "Test Designer", - Index = 7, - Description = "Create and test new test runner projects.", - Image = ResourceHelper.GetImageFromResources("Images/test_designer.png"), - }); + NavigationManager.MenuItems.Add(new NavigationMenuItem(() => + { + NavigationManager.NavigateTo<StubsModule>(nameof(TestDesignerView)); + }) + { + Name = "Test Designer", + Index = 7, + Description = "Create and test new test runner projects.", + Image = ResourceHelper.GetImageFromResources("Images/test_designer.png"), + }); + } }); } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestDesignerViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestDesignerViewVM.cs index cc5cdfdc7..8eb71490c 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestDesignerViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestDesignerViewVM.cs @@ -13,6 +13,7 @@ using System.Windows; using System.Windows.Input; using System.Windows.Threading; using Tango.BL.Entities; +using Tango.BL.Enumerations; using Tango.Core; using Tango.Core.Commands; using Tango.Core.ExtensionMethods; @@ -179,6 +180,7 @@ namespace Tango.FSE.Stubs.ViewModels public RelayCommand TogglePublishPanelCommand { get; set; } public RelayCommand<Script> RenameLibraryCommand { get; set; } public RelayCommand<CreateItem> CreateItemCommand { get; set; } + public RelayCommand<Result> DisplayResultGridCommand { get; set; } #endregion @@ -217,12 +219,13 @@ namespace Tango.FSE.Stubs.ViewModels AddLibraryCommand = new RelayCommand(AddNewLibrary); ClearOutputCommand = new RelayCommand(Clear); DeleteLibraryCommand = new RelayCommand<Script>(DeleteLibrary); - PublishProjectCommand = new RelayCommand(PublishProject); + PublishProjectCommand = new RelayCommand(PublishProject,() => CurrentUser.HasPermission(Permissions.FSE_PublishTestProjects)); LoadPublishedProjectCommand = new RelayCommand(LoadPublishedProject); UnPublishProjectCommand = new RelayCommand(UnPublishProject); - TogglePublishPanelCommand = new RelayCommand(() => IsPublishPanelOpened = !IsPublishPanelOpened); + TogglePublishPanelCommand = new RelayCommand(() => IsPublishPanelOpened = !IsPublishPanelOpened, () => CurrentUser.HasPermission(Permissions.FSE_PublishTestProjects)); RenameLibraryCommand = new RelayCommand<Script>(RenameLibrary); CreateItemCommand = new RelayCommand<CreateItem>(AutoCreateItem); + DisplayResultGridCommand = new RelayCommand<Result>(DisplayResultGrid); } #endregion @@ -637,6 +640,8 @@ namespace Tango.FSE.Stubs.ViewModels } InvalidateRelayCommands(); + + View.InvalidateHighlighting(); } private async void OpenProject() @@ -932,7 +937,7 @@ namespace Tango.FSE.Stubs.ViewModels if (errorScript != null) { OpenScript(errorScript); - View.HighlightCode(error.Position, error.Length); + View.HighlightCode(error.Position, error.Length, error.Line); } } @@ -943,6 +948,19 @@ namespace Tango.FSE.Stubs.ViewModels #endregion + #region Results + + private void DisplayResultGrid(Result result) + { + if (result != null) + { + ResultGridViewVM vm = new ResultGridViewVM(result); + NotificationProvider.ShowDialog(vm); + } + } + + #endregion + #region INavigationObjectReceiver public async void OnNavigatedToWithObject(NavigationObject obj) diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestRunnerViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestRunnerViewVM.cs index 6e4ec2b74..54e3d0f6d 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestRunnerViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestRunnerViewVM.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Tango.BL.Entities; using Tango.Core.Commands; using Tango.FSE.Common; +using Tango.FSE.Stubs.Dialogs; using Tango.FSE.Stubs.Messages; using Tango.FSE.Stubs.Views; @@ -82,10 +83,18 @@ namespace Tango.FSE.Stubs.ViewModels set { _failedError = value; RaisePropertyChangedAuto(); } } + private bool _isRunning; + public bool IsRunning + { + get { return _isRunning; } + set { _isRunning = value; RaisePropertyChangedAuto(); } + } + public RelayCommand<PublishedTestProject> EditProjectCommand { get; set; } public RelayCommand<PublishedTestProject> RunProjectCommand { get; set; } public RelayCommand StartProjectCommand { get; set; } public RelayCommand StopProjectCommand { get; set; } + public RelayCommand<Result> DisplayResultGridCommand { get; set; } public TestRunnerViewVM() { @@ -93,6 +102,7 @@ namespace Tango.FSE.Stubs.ViewModels RunProjectCommand = new RelayCommand<PublishedTestProject>(RunProject); StartProjectCommand = new RelayCommand(StartProject, () => ProjectRunner != null && ProjectRunner.CanRun); StopProjectCommand = new RelayCommand(StopProject, () => ProjectRunner != null && ProjectRunner.IsRunning); + DisplayResultGridCommand = new RelayCommand<Result>(DisplayResultGrid); _requiresReloadingOfProjects = true; RegisterForMessage<TestProjectPublishedOrSuppressed>((x) => _requiresReloadingOfProjects = true); @@ -102,6 +112,7 @@ namespace Tango.FSE.Stubs.ViewModels { try { + IsRunning = true; FailedError = null; Results = new List<Result>(); Status = "Running..."; @@ -119,6 +130,10 @@ namespace Tango.FSE.Stubs.ViewModels Status = "Failed"; FailedError = ex.FlattenMessage(); } + finally + { + IsRunning = false; + } } private void StopProject() @@ -187,7 +202,7 @@ namespace Tango.FSE.Stubs.ViewModels public override Task<bool> OnNavigateBackRequest() { - if (SelectedView == RunnerView.TestRunnerExecutionView) + if (SelectedView == RunnerView.TestRunnerExecutionView && !IsRunning) { SelectedView = RunnerView.TestRunnerCatalogView; return Task.FromResult(false); @@ -210,5 +225,14 @@ namespace Tango.FSE.Stubs.ViewModels { //Do nothing } + + private void DisplayResultGrid(Result result) + { + if (result != null) + { + ResultGridViewVM vm = new ResultGridViewVM(result); + NotificationProvider.ShowDialog(vm); + } + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml index 97f8cea6b..29251ca31 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml @@ -219,7 +219,7 @@ <DockPanel> <Grid DockPanel.Dock="Bottom"> <StackPanel VerticalAlignment="Top" Margin="10"> - <Button Margin="0 10 0 0" Height="50" Width="Auto" Foreground="{StaticResource FSE_GreenBrush}" Style="{StaticResource FSE_RaisedButton_Dark_Hover}" Command="{Binding PublishProjectCommand}"> + <Button material:ButtonAssist.CornerRadius="25" Margin="0 10 0 0" Height="50" Width="Auto" Foreground="{StaticResource FSE_GreenBrush}" Style="{StaticResource FSE_RaisedButton_Dark_Hover}" Command="{Binding PublishProjectCommand}"> <DockPanel> <material:PackIcon Kind="Publish" Height="20" Width="20" /> <TextBlock Margin="20 0 0 0" VerticalAlignment="Center" >PUBLISH</TextBlock> @@ -585,7 +585,23 @@ </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTextColumn Header="NAME" Binding="{Binding Name}" /> - <DataGridTextColumn Header="VALUE" Binding="{Binding Value}" Width="1*" /> + <DataGridTemplateColumn Header="VALUE" Width="1*"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <Grid> + <TextBlock Visibility="{Binding IsValueArray,Converter={StaticResource BooleanToVisibilityInverseConverter}}" Text="{Binding Value}"></TextBlock> + <StackPanel Orientation="Horizontal" Visibility="{Binding IsValueArray,Converter={StaticResource BooleanToVisibilityConverter}}"> + <TextBlock Foreground="{StaticResource FSE_GrayBrush}"> + <Run>This test result contains</Run> + <Run Text="{Binding Value.Count,Mode=OneWay}"></Run> + <Run Text="Values."></Run> + </TextBlock> + <Button Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.DisplayResultGridCommand}" CommandParameter="{Binding}" Height="22" Foreground="{StaticResource FSE_PrimaryAccentBrush}" Background="Transparent" BorderBrush="Transparent" Margin="0 -4 0 0">(Grid View)</Button> + </StackPanel> + </Grid> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> </DockPanel> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml.cs index b91ede833..e310afc89 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml.cs @@ -49,14 +49,25 @@ namespace Tango.FSE.Stubs.Views GetCurrentEditor()?.FormatCode(); } - public void HighlightCode(int position, int length) + public void HighlightCode(int position, int length, int line) { - GetCurrentEditor()?.Highlight(position, length); + GetCurrentEditor()?.Highlight(position, length, line); } public void InsertCode(string code) { GetCurrentEditor()?.InsertCode(code); } + + public void InvalidateHighlighting() + { + Dispatcher.BeginInvoke(new Action(() => + { + foreach (var editor in tabControl.FindVisualChildren<ScriptEditor>()) + { + editor.InvalidateHighlighting(); + } + })); + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestRunnerCatalogView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestRunnerCatalogView.xaml index 2af7253ae..f2671a169 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestRunnerCatalogView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestRunnerCatalogView.xaml @@ -58,7 +58,7 @@ <Polygon Fill="{StaticResource FSE_PrimaryBackgroundLighterBrush}" Points="0,0 150,0 0,170"></Polygon> <DockPanel> <Border CornerRadius="0 0 5 5" Padding="8" BorderThickness="0 1 0 0" BorderBrush="{StaticResource FSE_BorderBrush}" DockPanel.Dock="Bottom" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" > - <Button Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.RunProjectCommand}" CommandParameter="{Binding}" Height="30" Width="140" HorizontalContentAlignment="Stretch" HorizontalAlignment="Right" Style="{StaticResource FSE_RaisedButton_Dark_Hover}"> + <Button material:ButtonAssist.CornerRadius="14" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.RunProjectCommand}" CommandParameter="{Binding}" Height="30" Width="140" HorizontalContentAlignment="Stretch" HorizontalAlignment="Right" Style="{StaticResource FSE_RaisedButton_Dark_Hover}"> <DockPanel> <material:PackIcon Kind="Play" Height="24" Width="24" Foreground="{StaticResource FSE_GreenBrush}" /> <TextBlock Margin="20 2 0 0" VerticalAlignment="Center">RUN</TextBlock> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestRunnerExecutionView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestRunnerExecutionView.xaml index 53c0bff56..92f23e4b5 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestRunnerExecutionView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestRunnerExecutionView.xaml @@ -6,6 +6,7 @@ xmlns:global="clr-namespace:Tango.FSE.Stubs" xmlns:vm="clr-namespace:Tango.FSE.Stubs.ViewModels" xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" xmlns:local="clr-namespace:Tango.FSE.Stubs.Views" mc:Ignorable="d" d:DesignHeight="720" d:DesignWidth="1280" d:DesignStyle="{StaticResource FSE_User_Control_Designer}" d:DataContext="{d:DesignInstance Type=vm:TestRunnerViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.TestRunnerViewVM}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> @@ -57,13 +58,13 @@ <StackPanel HorizontalAlignment="Left" Width="1050" Margin="0 20 0 0"> <DockPanel> <Grid Margin="20 0 0 0" DockPanel.Dock="Right" > - <Button Command="{Binding StartProjectCommand}" Visibility="{Binding ProjectRunner.IsRunning,Converter={StaticResource BooleanToVisibilityInverseConverter}}" IsEnabled="{Binding ProjectRunner.CanRun}" Style="{StaticResource FSE_RaisedButton_Dark_Hover}" Width="200" Height="50"> + <Button material:ButtonAssist.CornerRadius="25" Command="{Binding StartProjectCommand}" Visibility="{Binding ProjectRunner.IsRunning,Converter={StaticResource BooleanToVisibilityInverseConverter}}" IsEnabled="{Binding ProjectRunner.CanRun}" Style="{StaticResource FSE_RaisedButton_Dark_Hover}" Width="200" Height="50"> <DockPanel> <material:PackIcon Kind="Play" Foreground="{StaticResource FSE_GreenBrush}" Width="24" Height="24" /> <TextBlock Margin="10 0 0 0" VerticalAlignment="Center">START</TextBlock> </DockPanel> </Button> - <Button Command="{Binding StopProjectCommand}" Visibility="{Binding ProjectRunner.IsRunning,Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource FSE_RaisedButton_Dark_Hover}" Width="200" Height="50"> + <Button material:ButtonAssist.CornerRadius="25" Command="{Binding StopProjectCommand}" Visibility="{Binding ProjectRunner.IsRunning,Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource FSE_RaisedButton_Dark_Hover}" Width="200" Height="50"> <DockPanel> <material:PackIcon Kind="Stop" Foreground="{StaticResource FSE_RedBrush}" Width="24" Height="24" /> <TextBlock Margin="10 0 0 0" VerticalAlignment="Center">STOP</TextBlock> @@ -135,7 +136,18 @@ </material:PackIcon> <StackPanel Margin="15 0 0 0" VerticalAlignment="Center"> <TextBlock Text="{Binding Name}" ></TextBlock> - <TextBlock Margin="0 2 0 0" FontSize="{StaticResource FSE_SmallFontSize}" Foreground="{StaticResource FSE_GrayBrush}" Text="{Binding Value}"></TextBlock> + <Grid Margin="0 2 0 0"> + <TextBlock Visibility="{Binding IsValueArray,Converter={StaticResource BooleanToVisibilityInverseConverter}}" FontSize="{StaticResource FSE_SmallFontSize}" Foreground="{StaticResource FSE_GrayBrush}" Text="{Binding Value}"></TextBlock> + + <StackPanel Orientation="Horizontal" Visibility="{Binding IsValueArray,Converter={StaticResource BooleanToVisibilityConverter}}"> + <TextBlock FontSize="{StaticResource FSE_SmallFontSize}" Foreground="{StaticResource FSE_GrayBrush}"> + <Run>This test result contains</Run> + <Run Text="{Binding Value.Count,Mode=OneWay}"></Run> + <Run Text="Values."></Run> + </TextBlock> + <Button Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.DisplayResultGridCommand}" CommandParameter="{Binding}" Height="22" FontSize="{StaticResource FSE_SmallFontSize}" Foreground="{StaticResource FSE_PrimaryAccentBrush}" Background="Transparent" BorderBrush="Transparent" Margin="0 -4 0 0">(Grid View)</Button> + </StackPanel> + </Grid> </StackPanel> </DockPanel> </DataTemplate> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Images/machine-update_gray.png b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Images/machine-update_gray.png Binary files differnew file mode 100644 index 000000000..6e9bba9b3 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Images/machine-update_gray.png diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Tango.FSE.Upgrade.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Tango.FSE.Upgrade.csproj index afc7344f5..3c145d540 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Tango.FSE.Upgrade.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Tango.FSE.Upgrade.csproj @@ -238,6 +238,9 @@ <Resource Include="Images\flash_drive.png" /> <Resource Include="Images\upgrade_remotely.png" /> </ItemGroup> + <ItemGroup> + <Resource Include="Images\machine-update_gray.png" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets" Condition="Exists('..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets')" /> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/ApplicationUpgradeGeneratedViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/ApplicationUpgradeGeneratedViewVM.cs index 7ea8d49d6..f1737463d 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/ApplicationUpgradeGeneratedViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/ApplicationUpgradeGeneratedViewVM.cs @@ -95,6 +95,14 @@ namespace Tango.FSE.Upgrade.ViewModels set { _isCompleted = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } } + private bool _suppressFirmwareUpgrade; + public bool SuppressFirmwareUpgrade + { + get { return _suppressFirmwareUpgrade; } + set { _suppressFirmwareUpgrade = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand StartUpgradeCommand { get; set; } public RelayCommand SaveTupFileCommand { get; set; } public RelayCommand SelectTupFileLocationCommand { get; set; } @@ -170,7 +178,7 @@ namespace Tango.FSE.Upgrade.ViewModels try { IsFree = false; - Handler = await RemoteUpgradeManager.PerformRemoteApplicationUpgrade(TemporaryTupFile); + Handler = await RemoteUpgradeManager.PerformRemoteApplicationUpgrade(TemporaryTupFile, !SuppressFirmwareUpgrade); await Handler.WaitForCompletion(); IsCompleted = true; await MachineProvider.DisconnectAndWaitForReconnection(TimeSpan.FromSeconds(20), TimeSpan.FromMinutes(1)); diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/MainViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/MainViewVM.cs index 2907d8d5c..b6986e660 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/ViewModels/MainViewVM.cs @@ -12,6 +12,7 @@ using Tango.SharedUI.Helpers; namespace Tango.FSE.Upgrade.ViewModels { + [ModularNavigationContainer] public class MainViewVM : RemoteUpgradeViewModel { public override void OnApplicationReady() diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeGeneratedView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeGeneratedView.xaml index c65744fdc..3c775f3f3 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeGeneratedView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeGeneratedView.xaml @@ -40,6 +40,8 @@ </DockPanel> </RadioButton> + <CheckBox IsEnabled="{Binding ElementName=chkUpgradeNow,Path=IsChecked}" IsChecked="{Binding SuppressFirmwareUpgrade}" ToolTip="Performs an application upgrade while skipping the firmware upgrade" Background="{StaticResource FSE_WarningBrush}" Margin="105 -5 0 0" FontSize="{StaticResource FSE_SmallFontSize}">Suppress firmware upgrade</CheckBox> + <RadioButton x:Name="chkSaveToDisk" Margin="0 20 0 0" IsChecked="{Binding ElementName=chkUpgradeNow,Path=IsChecked,Converter={StaticResource BooleanInverseConverter},Mode=TwoWay}" VerticalContentAlignment="Center" Cursor="Hand" Padding="25 0 0 0"> <DockPanel> <Image Source="../Images/flash_drive.png" Width="48" Height="48" /> @@ -61,13 +63,13 @@ <StackPanel VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="1000"> <DockPanel> <Grid DockPanel.Dock="Right" > - <Button Visibility="{Binding ElementName=chkUpgradeNow,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter}}" Command="{Binding StartUpgradeCommand}" HorizontalAlignment="Right" Width="250" Height="50" Style="{StaticResource FSE_RaisedButton_Dark_Hover}"> + <Button material:ButtonAssist.CornerRadius="25" Visibility="{Binding ElementName=chkUpgradeNow,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter}}" Command="{Binding StartUpgradeCommand}" HorizontalAlignment="Right" Width="250" Height="50"> <StackPanel Orientation="Horizontal"> <material:PackIcon Width="32" Height="28" Kind="ClockFast" /> <TextBlock Margin="10 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource FSE_LargeFontSize}">UPGRADE NOW</TextBlock> </StackPanel> </Button> - <Button Command="{Binding SaveTupFileCommand}" Visibility="{Binding ElementName=chkSaveToDisk,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter}}" DockPanel.Dock="Right" HorizontalAlignment="Right" Width="250" Height="50" Style="{StaticResource FSE_RaisedButton_Dark_Hover}"> + <Button material:ButtonAssist.CornerRadius="25" Command="{Binding SaveTupFileCommand}" Visibility="{Binding ElementName=chkSaveToDisk,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter}}" DockPanel.Dock="Right" HorizontalAlignment="Right" Width="250" Height="50"> <StackPanel Orientation="Horizontal"> <material:PackIcon Width="32" Height="28" Kind="ContentSaveEdit" /> <TextBlock Margin="10 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource FSE_LargeFontSize}">SAVE PACKAGE</TextBlock> @@ -76,7 +78,7 @@ </Grid> <StackPanel VerticalAlignment="Bottom" Margin="0 0 40 0"> - <TextBlock Text="{Binding Handler.Progress.Message}" Style="{StaticResource FSE_HandlerStatusTextBlock}"></TextBlock> + <TextBlock Text="{Binding Handler.Progress.Message}" ToolTip="{Binding Handler.Progress.Message}" TextTrimming="CharacterEllipsis" Style="{StaticResource FSE_HandlerStatusTextBlock}"></TextBlock> <ProgressBar Margin="0 5 0 0" Minimum="0" Maximum="{Binding Handler.Progress.Maximum}" Value="{Binding Handler.Progress.Value}" IsIndeterminate="{Binding Handler.Progress.IsIndeterminate}"></ProgressBar> </StackPanel> </DockPanel> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeView.xaml index 652bce48f..046259d75 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/ApplicationUpgradeView.xaml @@ -76,15 +76,15 @@ <StackPanel HorizontalAlignment="Left" VerticalAlignment="Bottom" Width="1000"> <DockPanel> - <Button Command="{Binding GeneratePackageCommand}" DockPanel.Dock="Right" HorizontalAlignment="Right" Width="250" Height="50" Style="{StaticResource FSE_RaisedButton_Dark_Hover}"> + <Button material:ButtonAssist.CornerRadius="25" Command="{Binding GeneratePackageCommand}" DockPanel.Dock="Right" HorizontalAlignment="Right" Width="250" Height="50"> <StackPanel Orientation="Horizontal"> - <material:PackIcon Width="32" Height="28" Kind="ClockFast" /> + <material:PackIcon Width="32" Height="28" Kind="PackageDown" /> <TextBlock Margin="10 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource FSE_LargeFontSize}">GENERATE PACKAGE</TextBlock> </StackPanel> </Button> <StackPanel VerticalAlignment="Bottom" Margin="0 0 40 0"> - <TextBlock Text="{Binding Handler.Progress.Message}" Style="{StaticResource FSE_HandlerStatusTextBlock}"></TextBlock> + <TextBlock Text="{Binding Handler.Progress.Message}" ToolTip="{Binding Handler.Progress.Message}" TextTrimming="CharacterEllipsis" Style="{StaticResource FSE_HandlerStatusTextBlock}"></TextBlock> <ProgressBar Margin="0 5 0 0" Minimum="0" Maximum="{Binding Handler.Progress.Maximum}" Value="{Binding Handler.Progress.Value}" IsIndeterminate="{Binding Handler.Progress.IsIndeterminate}"></ProgressBar> </StackPanel> </DockPanel> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeGeneratedView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeGeneratedView.xaml index 6ee70f44c..a8739b347 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeGeneratedView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeGeneratedView.xaml @@ -43,7 +43,7 @@ <DockPanel Margin="0 0 0 0"> <controls:IconButton ToolTip="Browse for .tfp file location" Margin="5 0 0 0" DockPanel.Dock="Right" Icon="FolderOpenOutline" Width="38" Height="38" Command="{Binding SelectTfpFileLocationCommand}" /> - <TextBox FontSize="{StaticResource FSE_SmallFontSize}" Foreground="{StaticResource FSE_PrimaryAccentBrush}" IsReadOnly="True" Text="{Binding TfpFileLocationToSave}" FlowDirection="RightToLeft" VerticalContentAlignment="Bottom"></TextBox> + <TextBox FontSize="{StaticResource FSE_SmallFontSize}" Foreground="{StaticResource FSE_PrimaryAccentBrush}" IsReadOnly="True" Text="{Binding TfpFileLocationToSave}" VerticalContentAlignment="Bottom"></TextBox> </DockPanel> </StackPanel> </StackPanel> @@ -52,13 +52,13 @@ <StackPanel VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="1000"> <DockPanel> <Grid DockPanel.Dock="Right" > - <Button Visibility="{Binding ElementName=chkUpgradeNow,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter}}" Command="{Binding StartUpgradeCommand}" HorizontalAlignment="Right" Width="250" Height="50" Style="{StaticResource FSE_RaisedButton_Dark_Hover}"> + <Button material:ButtonAssist.CornerRadius="25" Visibility="{Binding ElementName=chkUpgradeNow,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter}}" Command="{Binding StartUpgradeCommand}" HorizontalAlignment="Right" Width="250" Height="50"> <StackPanel Orientation="Horizontal"> <material:PackIcon Width="32" Height="28" Kind="ClockFast" /> <TextBlock Margin="10 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource FSE_LargeFontSize}">UPGRADE NOW</TextBlock> </StackPanel> </Button> - <Button Command="{Binding SaveTfpFileCommand}" Visibility="{Binding ElementName=chkSaveToDisk,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter}}" DockPanel.Dock="Right" HorizontalAlignment="Right" Width="250" Height="50" Style="{StaticResource FSE_RaisedButton_Dark_Hover}"> + <Button material:ButtonAssist.CornerRadius="25" Command="{Binding SaveTfpFileCommand}" Visibility="{Binding ElementName=chkSaveToDisk,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter}}" DockPanel.Dock="Right" HorizontalAlignment="Right" Width="250" Height="50"> <StackPanel Orientation="Horizontal"> <material:PackIcon Width="32" Height="28" Kind="ContentSaveEdit" /> <TextBlock Margin="10 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource FSE_LargeFontSize}">SAVE PACKAGE</TextBlock> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeView.xaml index 7da85e751..d105c5617 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/FirmwareUpgradeView.xaml @@ -81,14 +81,14 @@ <StackPanel VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="1000"> <DockPanel> <Grid DockPanel.Dock="Right" HorizontalAlignment="Right" > - <Button Visibility="{Binding ElementName=chkDownload,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter}}" Command="{Binding GeneratePackageCommand}" Width="250" Height="50" Style="{StaticResource FSE_RaisedButton_Dark_Hover}"> + <Button material:ButtonAssist.CornerRadius="25" Visibility="{Binding ElementName=chkDownload,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter}}" Command="{Binding GeneratePackageCommand}" Width="250" Height="50"> <StackPanel Orientation="Horizontal"> - <material:PackIcon Width="32" Height="28" Kind="ClockFast" /> + <material:PackIcon Width="32" Height="28" Kind="PackageDown" /> <TextBlock Margin="10 0 0 0" VerticalAlignment="Center" FontSize="{StaticResource FSE_LargeFontSize}" Text="GENERATE PACKAGE"/> </StackPanel> </Button> - <Button Visibility="{Binding ElementName=chkExisting,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter}}" Command="{Binding ContinueCommand}" Width="250" Height="50" Style="{StaticResource FSE_RaisedButton_Dark_Hover}"> + <Button material:ButtonAssist.CornerRadius="25" Visibility="{Binding ElementName=chkExisting,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter}}" Command="{Binding ContinueCommand}" Width="250" Height="50"> <StackPanel Orientation="Horizontal"> <TextBlock VerticalAlignment="Center" FontSize="{StaticResource FSE_LargeFontSize}">CONTINUE</TextBlock> <material:PackIcon Margin="10 -5 0 0" Width="32" Height="28" Kind="ArrowRight" /> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/MainView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/MainView.xaml index 57363eed8..26a3560c2 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/MainView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/MainView.xaml @@ -22,7 +22,7 @@ </UserControl.Resources> <Grid> - <Image Source="../Images/machine-update2.png" HorizontalAlignment="Right" VerticalAlignment="Top" Stretch="Uniform" Width="800" Margin="80" Opacity="0.6" Visibility="{Binding ResolutionService.IsHighResolution,Converter={StaticResource BooleanToVisibilityConverter}}"></Image> + <Image Source="../Images/machine-update_gray.png" HorizontalAlignment="Right" VerticalAlignment="Top" Stretch="Uniform" Width="800" Margin="80" Opacity="0.1" Visibility="{Binding ResolutionService.IsHighResolution,Converter={StaticResource BooleanToVisibilityConverter}}"></Image> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="0.5*" /> @@ -48,7 +48,7 @@ </Grid.Style> <DockPanel> <DockPanel DockPanel.Dock="Top"> - <Image Source="../Images/remote_upgrade_large.png" Stretch="Uniform" Width="90" RenderOptions.BitmapScalingMode="Fant" /> + <Image Source="../Images/remote_upgrade_large.png" Stretch="Uniform" VerticalAlignment="Top" Width="60" RenderOptions.BitmapScalingMode="Fant" /> <StackPanel Margin="20 0 0 0"> <TextBlock FontSize="{StaticResource FSE_ModuleHeaderFontSize}" Foreground="{StaticResource FSE_PrimaryAccentBrush}">Remote Upgrade Wizard</TextBlock> <TextBlock Margin="0 10 0 0" Foreground="{StaticResource FSE_GrayBrush}"> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/WelcomeView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/WelcomeView.xaml index e82173419..83fa278ee 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/WelcomeView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Views/WelcomeView.xaml @@ -44,7 +44,7 @@ </StackPanel> <StackPanel VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="1000"> - <Button Command="{Binding StartUpgradeCommand}" DockPanel.Dock="Right" VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="200" Height="50" Style="{StaticResource FSE_RaisedButton_Dark_Hover}"> + <Button material:ButtonAssist.CornerRadius="25" Command="{Binding StartUpgradeCommand}" DockPanel.Dock="Right" VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="250" Height="50"> <StackPanel Orientation="Horizontal"> <TextBlock VerticalAlignment="Center" FontSize="{StaticResource FSE_LargeFontSize}">CONTINUE</TextBlock> <material:PackIcon Margin="10 -5 0 0" Width="32" Height="28" Kind="ArrowRight" /> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/App.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/App.xaml new file mode 100644 index 000000000..f85429b2a --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/App.xaml @@ -0,0 +1,16 @@ +<Application x:Class="Tango.FSE.UsersAndRoles.App" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> + <Application.Resources> + <ResourceDictionary> + <ResourceDictionary.MergedDictionaries> + <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Converters.xaml" /> + <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Colors.xaml" /> + <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Fonts.xaml" /> + <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Images.xaml" /> + <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Styles.xaml" /> + <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Controls.xaml" /> + </ResourceDictionary.MergedDictionaries> + </ResourceDictionary> + </Application.Resources> +</Application>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Images/users_and_roles.png b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Images/users_and_roles.png Binary files differnew file mode 100644 index 000000000..298dfbda2 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Images/users_and_roles.png diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Images/users_roles_back.png b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Images/users_roles_back.png Binary files differnew file mode 100644 index 000000000..f008b6e08 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Images/users_roles_back.png diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Models/RoleModel.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Models/RoleModel.cs new file mode 100644 index 000000000..266a5c090 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Models/RoleModel.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.Core; + +namespace Tango.FSE.UsersAndRoles.Models +{ + public class RoleModel : ExtendedObject + { + private Role _role; + public Role Role + { + get { return _role; } + set { _role = value; RaisePropertyChangedAuto(); } + } + + private bool _isEnabled; + public bool IsEnabled + { + get { return _isEnabled; } + set { _isEnabled = value; RaisePropertyChangedAuto(); } + } + + private bool _isSelected; + public bool IsSelected + { + get { return _isSelected; } + set { _isSelected = value; RaisePropertyChangedAuto(); } + } + + public List<Roles> Dependencies { get; set; } + + public RoleModel(Role role, params Roles[] dependencies) + { + Role = role; + IsEnabled = true; + Dependencies = new List<Roles>(); + + if (dependencies != null) + { + Dependencies.AddRange(dependencies); + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Models/RolesCollection.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Models/RolesCollection.cs new file mode 100644 index 000000000..b81a76d64 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Models/RolesCollection.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.UsersAndRoles.Models +{ + public class RolesCollection : Collection<RoleModel> + { + private bool _invalidating; + + protected override void InsertItem(int index, RoleModel item) + { + base.InsertItem(index, item); + item.PropertyChanged += Item_PropertyChanged; + Invalidate(); + } + + private void Item_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(RoleModel.IsSelected)) + { + Invalidate(); + } + } + + private void Invalidate() + { + if (!_invalidating) + { + _invalidating = true; + + foreach (var role in Items) + { + foreach (var dependencyRole in role.Dependencies) + { + var dependencyRoleModel = Items.SingleOrDefault(x => x.Role.Code == dependencyRole.ToInt32()); + + if (dependencyRoleModel != null) + { + if (role.IsSelected) + { + dependencyRoleModel.IsSelected = true; + dependencyRoleModel.IsEnabled = false; + } + else + { + dependencyRoleModel.IsEnabled = !Items.Any(x => x.IsSelected && x.Dependencies.Contains(dependencyRole)); + } + } + } + } + + _invalidating = false; + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Navigation/UsersAndRolesNavigationManager.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Navigation/UsersAndRolesNavigationManager.cs new file mode 100644 index 000000000..1a6fe03f4 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Navigation/UsersAndRolesNavigationManager.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.FSE.Common.Navigation; +using Tango.FSE.UsersAndRoles.Navigation; +using Tango.SharedUI.Controls; + +namespace Tango.FSE.UsersAndRoles.Navigation +{ + public class UsersAndRolesNavigationManager : ModularNavigationManager<UsersAndRolesView> + { + public UsersAndRolesNavigationManager(FrameworkElement navigationControlParent) : base(navigationControlParent) + { + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Navigation/UsersAndRolesView.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Navigation/UsersAndRolesView.cs new file mode 100644 index 000000000..f015cbdb6 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Navigation/UsersAndRolesView.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.UsersAndRoles.Navigation +{ + public enum UsersAndRolesView + { + OrganizationSelectionView, + OrganizationUsersView, + UserDetailsView, + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Properties/AssemblyInfo.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..5219b830b --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tango.FSE.UsersAndRoles")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Tango.FSE.UsersAndRoles")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file +//inside a <PropertyGroup>. For example, if you are using US english +//in your source files, set the <UICulture> to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Properties/Resources.Designer.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Properties/Resources.Designer.cs new file mode 100644 index 000000000..dde06bfd9 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace Tango.FSE.UsersAndRoles.Properties +{ + + + /// <summary> + /// A strongly-typed resource class, for looking up localized strings, etc. + /// </summary> + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// <summary> + /// Returns the cached ResourceManager instance used by this class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Tango.FSE.UsersAndRoles.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// <summary> + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Properties/Resources.resx b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Properties/Resources.resx new file mode 100644 index 000000000..af7dbebba --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Properties/Resources.resx @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> +</root>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Properties/Settings.Designer.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Properties/Settings.Designer.cs new file mode 100644 index 000000000..f07016802 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace Tango.FSE.UsersAndRoles.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Properties/Settings.settings b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Properties/Settings.settings new file mode 100644 index 000000000..033d7a5e9 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Properties/Settings.settings @@ -0,0 +1,7 @@ +<?xml version='1.0' encoding='utf-8'?> +<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)"> + <Profiles> + <Profile Name="(Default)" /> + </Profiles> + <Settings /> +</SettingsFile>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Tango.FSE.UsersAndRoles.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Tango.FSE.UsersAndRoles.csproj new file mode 100644 index 000000000..81a628011 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Tango.FSE.UsersAndRoles.csproj @@ -0,0 +1,212 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{D509DDAA-AA70-4B2A-8D6A-8C94F057A9C1}</ProjectGuid> + <OutputType>library</OutputType> + <RootNamespace>Tango.FSE.UsersAndRoles</RootNamespace> + <AssemblyName>Tango.FSE.UsersAndRoles</AssemblyName> + <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <WarningLevel>4</WarningLevel> + <Deterministic>true</Deterministic> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>..\..\..\Build\FSE\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>..\..\..\Build\FSE\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="ControlzEx, Version=3.0.2.4, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\ControlzEx.3.0.2.4\lib\net45\ControlzEx.dll</HintPath> + </Reference> + <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath> + </Reference> + <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll</HintPath> + </Reference> + <Reference Include="Google.Protobuf, Version=3.4.1.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\Google.Protobuf.3.4.1\lib\net45\Google.Protobuf.dll</HintPath> + </Reference> + <Reference Include="MahApps.Metro, Version=1.6.5.1, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\MahApps.Metro.1.6.5\lib\net46\MahApps.Metro.dll</HintPath> + </Reference> + <Reference Include="MaterialDesignColors, Version=1.2.2.920, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\MaterialDesignColors.1.2.2\lib\net45\MaterialDesignColors.dll</HintPath> + </Reference> + <Reference Include="MaterialDesignThemes.Wpf, Version=3.0.1.920, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\MaterialDesignThemes.3.0.1\lib\net45\MaterialDesignThemes.Wpf.dll</HintPath> + </Reference> + <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.ComponentModel.DataAnnotations" /> + <Reference Include="System.Data" /> + <Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\ControlzEx.3.0.2.4\lib\net45\System.Windows.Interactivity.dll</HintPath> + </Reference> + <Reference Include="System.Xml" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Xaml"> + <RequiredTargetFramework>4.0</RequiredTargetFramework> + </Reference> + <Reference Include="WindowsBase" /> + <Reference Include="PresentationCore" /> + <Reference Include="PresentationFramework" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Models\RoleModel.cs" /> + <Compile Include="Models\RolesCollection.cs" /> + <Compile Include="Navigation\UsersAndRolesNavigationManager.cs" /> + <Compile Include="Navigation\UsersAndRolesView.cs" /> + <Compile Include="UsersAndRolesViewModel.cs" /> + <Compile Include="ViewModelLocator.cs" /> + <Compile Include="UsersAndRolesModule.cs" /> + <Compile Include="ViewModels\MainViewVM.cs" /> + <Compile Include="ViewModels\OrganizationSelectionViewVM.cs" /> + <Compile Include="ViewModels\OrganizationUsersViewVM.cs" /> + <Compile Include="ViewModels\UserDetailsViewVM.cs" /> + <Compile Include="Views\MainView.xaml.cs"> + <DependentUpon>MainView.xaml</DependentUpon> + </Compile> + <Compile Include="Views\OrganizationSelectionView.xaml.cs"> + <DependentUpon>OrganizationSelectionView.xaml</DependentUpon> + </Compile> + <Compile Include="Views\OrganizationUsersView.xaml.cs"> + <DependentUpon>OrganizationUsersView.xaml</DependentUpon> + </Compile> + <Compile Include="Views\UserDetailsView.xaml.cs"> + <DependentUpon>UserDetailsView.xaml</DependentUpon> + </Compile> + </ItemGroup> + <ItemGroup> + <Compile Include="Properties\AssemblyInfo.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="Properties\Resources.Designer.cs"> + <AutoGen>True</AutoGen> + <DesignTime>True</DesignTime> + <DependentUpon>Resources.resx</DependentUpon> + </Compile> + <Compile Include="Properties\Settings.Designer.cs"> + <AutoGen>True</AutoGen> + <DependentUpon>Settings.settings</DependentUpon> + <DesignTimeSharedInput>True</DesignTimeSharedInput> + </Compile> + <EmbeddedResource Include="Properties\Resources.resx"> + <Generator>ResXFileCodeGenerator</Generator> + <LastGenOutput>Resources.Designer.cs</LastGenOutput> + </EmbeddedResource> + <None Include="app.config" /> + <None Include="packages.config" /> + <None Include="Properties\Settings.settings"> + <Generator>SettingsSingleFileGenerator</Generator> + <LastGenOutput>Settings.Designer.cs</LastGenOutput> + </None> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\..\SideChains\Tango.AutoComplete\Tango.AutoComplete.csproj"> + <Project>{bb2abb74-ba58-4812-83aa-ec8171f42df4}</Project> + <Name>Tango.AutoComplete</Name> + </ProjectReference> + <ProjectReference Include="..\..\..\Tango.BL\Tango.BL.csproj"> + <Project>{f441feee-322a-4943-b566-110e12fd3b72}</Project> + <Name>Tango.BL</Name> + </ProjectReference> + <ProjectReference Include="..\..\..\Tango.Core\Tango.Core.csproj"> + <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project> + <Name>Tango.Core</Name> + </ProjectReference> + <ProjectReference Include="..\..\..\Tango.Integration\Tango.Integration.csproj"> + <Project>{4206ac58-3b57-4699-8835-90bf6db01a61}</Project> + <Name>Tango.Integration</Name> + </ProjectReference> + <ProjectReference Include="..\..\..\Tango.Logging\Tango.Logging.csproj"> + <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project> + <Name>Tango.Logging</Name> + </ProjectReference> + <ProjectReference Include="..\..\..\Tango.PMR\Tango.PMR.csproj"> + <Project>{e4927038-348d-4295-aaf4-861c58cb3943}</Project> + <Name>Tango.PMR</Name> + </ProjectReference> + <ProjectReference Include="..\..\..\Tango.Settings\Tango.Settings.csproj"> + <Project>{d8f1ad85-526a-4f50-b6dc-d437af63d8d8}</Project> + <Name>Tango.Settings</Name> + </ProjectReference> + <ProjectReference Include="..\..\..\Tango.SharedUI\Tango.SharedUI.csproj"> + <Project>{8491d07b-c1f6-4b62-a412-41b9fd2d6538}</Project> + <Name>Tango.SharedUI</Name> + </ProjectReference> + <ProjectReference Include="..\..\..\Tango.Transport\Tango.Transport.csproj"> + <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project> + <Name>Tango.Transport</Name> + </ProjectReference> + <ProjectReference Include="..\..\Tango.FSE.BL\Tango.FSE.BL.csproj"> + <Project>{834c81c3-09b5-45d7-be12-e7d1e6655a7c}</Project> + <Name>Tango.FSE.BL</Name> + </ProjectReference> + <ProjectReference Include="..\..\Tango.FSE.Common\Tango.FSE.Common.csproj"> + <Project>{bc37cccb-7392-4f78-8d1c-e9629e6e046e}</Project> + <Name>Tango.FSE.Common</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <Page Include="App.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + <Page Include="Views\MainView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Views\OrganizationSelectionView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Views\OrganizationUsersView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Views\UserDetailsView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + </ItemGroup> + <ItemGroup> + <Resource Include="Images\users_and_roles.png" /> + </ItemGroup> + <ItemGroup> + <Resource Include="Images\users_roles_back.png" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Import Project="..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets" Condition="Exists('..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets')" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets'))" /> + </Target> +</Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/UsersAndRolesModule.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/UsersAndRolesModule.cs new file mode 100644 index 000000000..099a36b21 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/UsersAndRolesModule.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media.Imaging; +using Tango.BL.Enumerations; +using Tango.FSE.Common; +using Tango.FSE.UsersAndRoles.Views; + +namespace Tango.FSE.UsersAndRoles +{ + [FSEModule(index: 1)] + public class UsersAndRolesModule : FSEModuleBase + { + public override string Name { get; } = "Users & Roles"; + public override string Description { get; } = "Users & Roles module"; + public override Type MainViewType { get; } = typeof(MainView); + public override Permissions Permission { get; } = Permissions.FSE_RunFSE; + + public override void Dispose() + { + + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/UsersAndRolesViewModel.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/UsersAndRolesViewModel.cs new file mode 100644 index 000000000..3c12d4dc7 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/UsersAndRolesViewModel.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.FSE.Common.Navigation; +using Tango.FSE.UsersAndRoles.Navigation; + +namespace Tango.FSE.UsersAndRoles +{ + public class UsersAndRolesViewModel : ModularNavigationFSEViewModel<UsersAndRolesView> + { + + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModelLocator.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModelLocator.cs new file mode 100644 index 000000000..7c98fb55b --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModelLocator.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.DI; +using Tango.FSE.UsersAndRoles.Navigation; +using Tango.FSE.UsersAndRoles.ViewModels; +using Tango.FSE.UsersAndRoles.Views; + +namespace Tango.FSE.UsersAndRoles +{ + public static class ViewModelLocator + { + static ViewModelLocator() + { + TangoIOC.Default.Register<UsersAndRolesNavigationManager>(new UsersAndRolesNavigationManager(MainView.Instance)); + TangoIOC.Default.Register<MainViewVM>(); + TangoIOC.Default.Register<OrganizationSelectionViewVM>(); + TangoIOC.Default.Register<OrganizationUsersViewVM>(); + TangoIOC.Default.Register<UserDetailsViewVM>(); + } + + public static MainViewVM MainViewVM + { + get + { + return TangoIOC.Default.GetInstance<MainViewVM>(); + } + } + + public static OrganizationSelectionViewVM OrganizationSelectionViewVM + { + get + { + return TangoIOC.Default.GetInstance<OrganizationSelectionViewVM>(); + } + } + + public static OrganizationUsersViewVM OrganizationUsersViewVM + { + get + { + return TangoIOC.Default.GetInstance<OrganizationUsersViewVM>(); + } + } + + public static UserDetailsViewVM UserDetailsViewVM + { + get + { + return TangoIOC.Default.GetInstance<UserDetailsViewVM>(); + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/MainViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/MainViewVM.cs new file mode 100644 index 000000000..fdc9c2000 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/MainViewVM.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.FSE.Common; +using Tango.FSE.Common.Navigation; +using Tango.FSE.UsersAndRoles.Navigation; +using Tango.SharedUI.Helpers; + +namespace Tango.FSE.UsersAndRoles.ViewModels +{ + [ModularNavigationContainer] + public class MainViewVM : UsersAndRolesViewModel + { + public override void OnApplicationReady() + { + if (CurrentUser.HasPermission(Tango.BL.Enumerations.Permissions.FSE_ManageOrganizationUsersAndRoles) || CurrentUser.HasPermission(Tango.BL.Enumerations.Permissions.FSE_ManageAllOrganizationsUsersAndRoles)) + { + InvokeUI(() => + { + NavigationManager.MenuItems.Add(new NavigationMenuItem(() => + { + NavigationManager.NavigateTo<UsersAndRolesModule>(); + }) + { + Name = "Users & Roles", + Index = 10, + Description = "Manage users and their permissions on your organization", + Image = ResourceHelper.GetImageFromResources("Images/users_and_roles.png"), + }); + }); + } + } + + public async override Task<bool> OnApplicationLogout() + { + while (ModularNavigationManager.CurrentView != UsersAndRolesView.OrganizationSelectionView) + { + if (!await ModularNavigationManager.NavigateBack()) + { + return false; + } + } + + return await base.OnApplicationLogout(); + } + + public async override Task<bool> OnNavigateBackRequest() + { + if (ModularNavigationManager.CurrentView == UsersAndRolesView.OrganizationSelectionView) + { + return await base.OnNavigateBackRequest(); + } + else + { + await ModularNavigationManager.NavigateBack(); + return false; + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/OrganizationSelectionViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/OrganizationSelectionViewVM.cs new file mode 100644 index 000000000..9a84cca7d --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/OrganizationSelectionViewVM.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.Core.Commands; +using Tango.FSE.Common; +using Tango.FSE.Common.AutoComplete; +using Tango.FSE.UsersAndRoles.Navigation; +using Tango.FSE.UsersAndRoles.Views; + +namespace Tango.FSE.UsersAndRoles.ViewModels +{ + public class OrganizationSelectionViewVM : UsersAndRolesViewModel + { + /// <summary> + /// Gets or sets the organizations completion source. + /// </summary> + public AutoCompleteSource<Organization> Organizations { get; set; } + + private Organization _selectedOrganization; + /// <summary> + /// Gets or sets the selected organization. + /// </summary> + public Organization SelectedOrganization + { + get { return _selectedOrganization; } + set { _selectedOrganization = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } + } + + /// <summary> + /// Navigates to the organization users list with the specified organization. + /// </summary> + public RelayCommand ManageOrganizationCommand { get; set; } + + /// <summary> + /// Initializes a new instance of the <see cref="OrganizationSelectionViewVM"/> class. + /// </summary> + public OrganizationSelectionViewVM() + { + Organizations = new AutoCompleteSource<Organization>(AutoCompleteOrganizations); + ManageOrganizationCommand = new RelayCommand(ManageSelectedOrganization, () => SelectedOrganization != null); + } + + private void ManageSelectedOrganization() + { + if (SelectedOrganization == null) + { + NotificationProvider.ShowError("No organization selected."); + return; + } + + ModularNavigationManager.NavigateTo(UsersAndRolesView.OrganizationUsersView, new OrganizationUsersViewVM.NavigationObject() + { + Organization = SelectedOrganization + }); + } + + private List<Organization> AutoCompleteOrganizations(string key) + { + key = key ?? String.Empty; + + try + { + return Services.OrganizationsService.GetCurrentUserOrganizations().Result.Where(x => x.Name.ToLower().StartsWith(key.ToLower())).Take(4).ToList(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error on auto complete organizations filter."); + return new List<Organization>(); + } + } + + public async override void OnNavigatedTo() + { + base.OnNavigatedTo(); + + if (SelectedOrganization == null) + { + await Task.Delay(200); + SelectedOrganization = AuthenticationProvider.CurrentUser.Organization; + } + } + + public override Task<bool> OnApplicationLogout() + { + SelectedOrganization = null; + return base.OnApplicationLogout(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/OrganizationUsersViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/OrganizationUsersViewVM.cs new file mode 100644 index 000000000..334c8c263 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/OrganizationUsersViewVM.cs @@ -0,0 +1,230 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using Tango.BL.Entities; +using Tango.Core.Commands; +using Tango.FSE.Common; +using Tango.FSE.Common.Navigation; +using Tango.FSE.UsersAndRoles.Navigation; +using Tango.FSE.UsersAndRoles.Views; +using static Tango.FSE.UsersAndRoles.ViewModels.OrganizationUsersViewVM; + +namespace Tango.FSE.UsersAndRoles.ViewModels +{ + public class OrganizationUsersViewVM : UsersAndRolesViewModel, INavigationObjectReceiver<NavigationObject> + { + public class NavigationObject + { + public Organization Organization { get; set; } + public User SelectedUser { get; set; } + } + + private bool _requiresReloading; + private User _initialUser; + + private Organization _organization; + /// <summary> + /// Gets or sets the organization. + /// </summary> + public Organization Organization + { + get { return _organization; } + set { _organization = value; RaisePropertyChangedAuto(); } + } + + private ObservableCollection<User> _users; + /// <summary> + /// Gets or sets the users. + /// </summary> + public ObservableCollection<User> Users + { + get { return _users; } + set { _users = value; RaisePropertyChangedAuto(); } + } + + private User _selectedUser; + public User SelectedUser + { + get { return _selectedUser; } + set { _selectedUser = value; RaisePropertyChangedAuto(); } + } + + /// <summary> + /// Gets or sets the users view source. + /// </summary> + public ICollectionView UsersView { get; set; } + + private String _filter; + /// <summary> + /// Gets or sets the users search filter. + /// </summary> + public String Filter + { + get { return _filter; } + set { _filter = value; RaisePropertyChangedAuto(); OnFilterChanged(); } + } + + private bool _showDeleted; + public bool ShowDeleted + { + get { return _showDeleted; } + set { _showDeleted = value; RaisePropertyChangedAuto(); UsersView?.Refresh(); } + } + + /// <summary> + /// Navigates to the user details view with the specified user. + /// </summary> + public RelayCommand<User> EditUserCommand { get; set; } + + /// <summary> + /// Removes the specified user. + /// </summary> + public RelayCommand<User> RemoveUserCommand { get; set; } + + /// <summary> + /// Adds a new user. + /// </summary> + public RelayCommand AddUserCommand { get; set; } + + /// <summary> + /// Initializes a new instance of the <see cref="OrganizationUsersViewVM"/> class. + /// </summary> + public OrganizationUsersViewVM() + { + Users = new ObservableCollection<User>(); + EditUserCommand = new RelayCommand<User>(EditUser); + RemoveUserCommand = new RelayCommand<User>(SuspendUser); + AddUserCommand = new RelayCommand(AddUser, () => IsFree); + } + + private void AddUser() + { + ModularNavigationManager.NavigateTo(UsersAndRolesView.UserDetailsView, new UserDetailsViewVM.NavigationObject() + { + IsNewUser = true, + Organization = Organization + }); + } + + private async void SuspendUser(User user) + { + if (await NotificationProvider.ShowWarningQuestion($"Are you sure you want to suspend '{user.Contact.FullName}' ?")) + { + try + { + IsFree = false; + + using (NotificationProvider.PushTaskItem("Suspending account...")) + { + var updatedUser = await Services.OrganizationsService.SuspendUser(user); + Users.Replace(user, updatedUser); + } + + await NotificationProvider.ShowSuccess("The selected user is now suspended and can be reactivated."); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error suspending user '{user.Email}'."); + await NotificationProvider.ShowError($"Error suspending the selected user\n{ex.FlattenMessage()}"); + } + finally + { + IsFree = true; + } + } + } + + private void EditUser(User user) + { + ModularNavigationManager.NavigateTo(UsersAndRolesView.UserDetailsView, new UserDetailsViewVM.NavigationObject() + { + User = user + }); + } + + private async Task LoadUsers() + { + if (Organization != null) + { + try + { + IsFree = false; + var users = await Services.OrganizationsService.GetOrganizationUsers(Organization.Guid, true); + var usersCollection = new ObservableCollection<User>(users); + UsersView = CollectionViewSource.GetDefaultView(usersCollection); + UsersView.Filter = FilterUsers; + Users = usersCollection; + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error loading organization users for organization '{Organization.Name}'."); + await NotificationProvider.ShowError($"Error loading the selected organization users.\n{ex.FlattenMessage()}"); + await NavigationManager.NavigateBack(); + } + finally + { + IsFree = true; + } + } + else + { + await NotificationProvider.ShowError("No organization selected."); + } + } + + private void OnFilterChanged() + { + UsersView?.Refresh(); + } + + private bool FilterUsers(object obj) + { + var user = obj as User; + String filter = Filter ?? String.Empty; + + if (user != null) + { + return (!filter.IsNotNullOrEmpty() || user.Contact.FullName.ToLower().Contains(filter.ToLower()) || user.Email.ToLower().Contains(filter.ToLower())) && (!user.Deleted || ShowDeleted); + } + + return true; + } + + /// <summary> + /// Called when the navigation system has navigated to this VM view. + /// </summary> + public async override void OnNavigatedTo() + { + base.OnNavigatedTo(); + + if (_requiresReloading) + { + await LoadUsers(); + + if (_initialUser != null) + { + SelectedUser = Users.SingleOrDefault(x => x.Guid == _initialUser.Guid); + } + } + + _requiresReloading = false; + _initialUser = null; + } + + /// <summary> + /// Called when navigation system is going to navigate to this instance with the specified object. + /// </summary> + /// <param name="obj">The object.</param> + public void OnNavigatedToWithObject(NavigationObject obj) + { + Organization = obj.Organization; + _initialUser = obj.SelectedUser; + _requiresReloading = true; + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/UserDetailsViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/UserDetailsViewVM.cs new file mode 100644 index 000000000..dec2651d1 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/ViewModels/UserDetailsViewVM.cs @@ -0,0 +1,387 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.Core.Commands; +using Tango.FSE.Common; +using Tango.FSE.Common.Navigation; +using Tango.FSE.UsersAndRoles.Models; +using Tango.FSE.UsersAndRoles.Navigation; +using Tango.FSE.UsersAndRoles.Views; +using Tango.SharedUI.Components; +using static Tango.FSE.UsersAndRoles.ViewModels.UserDetailsViewVM; + +namespace Tango.FSE.UsersAndRoles.ViewModels +{ + public class UserDetailsViewVM : UsersAndRolesViewModel, INavigationObjectReceiver<NavigationObject> + { + private String userToLoadGuid; + private bool _requiresLoading; + + public class NavigationObject + { + public Organization Organization { get; set; } + public User User { get; set; } + public bool IsNewUser { get; set; } + } + + private Organization _organization; + public Organization Organization + { + get { return _organization; } + set { _organization = value; RaisePropertyChangedAuto(); } + } + + private bool _isNewUser; + public bool IsNewUser + { + get { return _isNewUser; } + set { _isNewUser = value; RaisePropertyChangedAuto(); } + } + + private User _user; + public User User + { + get { return _user; } + set { _user = value; RaisePropertyChangedAuto(); OnUserChanged(); } + } + + private String _firstName; + [Required(ErrorMessage = "First name is required")] + public String FirstName + { + get { return _firstName; } + set { _firstName = value; RaisePropertyChangedAuto(); } + } + + private String _lastName; + [Required(ErrorMessage = "Last name is required")] + public String LastName + { + get { return _lastName; } + set { _lastName = value; RaisePropertyChangedAuto(); } + } + + private String _email; + [Required(ErrorMessage = "Email is required")] + [EmailAddress(ErrorMessage = "Please enter a valid email address")] + public String Email + { + get { return _email; } + set { _email = value; RaisePropertyChangedAuto(); OnEmailChanged(); } + } + + private String _password; + public String Password + { + get { return _password; } + set { _password = value; RaisePropertyChangedAuto(); } + } + + private bool _isCheckingEmail; + public bool IsCheckingEmail + { + get { return _isCheckingEmail; } + set { _isCheckingEmail = value; RaisePropertyChangedAuto(); } + } + + private bool _isEmailTaken; + public bool IsEmailTaken + { + get { return _isEmailTaken; } + set { _isEmailTaken = value; RaisePropertyChangedAuto(); } + } + + private RolesCollection _rolesCollection; + public RolesCollection RolesCollection + { + get { return _rolesCollection; } + set { _rolesCollection = value; RaisePropertyChangedAuto(); } + } + + private bool _sendInvitation; + public bool SendInvitation + { + get { return _sendInvitation; } + set { _sendInvitation = value; RaisePropertyChangedAuto(); } + } + + public RelayCommand SaveCommand { get; set; } + + public RelayCommand GeneratePasswordCommand { get; set; } + + public UserDetailsViewVM() + { + SaveCommand = new RelayCommand(Save, () => IsFree); + GeneratePasswordCommand = new RelayCommand(GeneratePassword); + SendInvitation = true; + } + + private void GeneratePassword() + { + if (IsNewUser) + { + Password = Services.OrganizationsService.GenerateRandomPassword(); + } + } + + public async override void OnNavigatedTo() + { + base.OnNavigatedTo(); + + if (!IsNewUser) + { + if (_requiresLoading) + { + await LoadUserDetails(); + } + } + else + { + await CreateNewUser(); + GeneratePassword(); + } + + _requiresLoading = false; + } + + private async Task CreateNewUser() + { + try + { + IsFree = false; + + var user = new User(); + user.Address = new Address(); + user.Contact = new Contact(); + + User = user; + + var roles = await Services.OrganizationsService.GetAllRoles(); + InitRolesCollection(User, roles, true); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error initializing new user creation."); + await NotificationProvider.ShowError($"Error initializing new user details.\n{ex.FlattenMessage()}"); + await NavigationManager.NavigateBack(); + } + finally + { + IsFree = true; + } + } + + private void InitRolesCollection(User user, List<Role> roles, bool isNew = false) + { + bool user_is_current_user_and_fse_admin_and_not_twine_admin = user.Guid == CurrentUser.Guid && user.HasRole(Roles.FSEAdministrator) && !user.HasRole(Roles.FSETwineAdministrator); + + var collection = new RolesCollection(); + collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETechnician)) { IsSelected = isNew }); + collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSEAdvancedTechnician), Roles.FSETechnician)); + collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSEAdministrator), Roles.FSETechnician, Roles.FSEAdvancedTechnician) { IsEnabled = !user_is_current_user_and_fse_admin_and_not_twine_admin }); + + if (CurrentUser.HasRole(Roles.FSETwineAdministrator)) + { + collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineTechnician), Roles.FSETechnician, Roles.FSEAdvancedTechnician)); + collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineAdministrator), Roles.FSETechnician, Roles.FSEAdministrator)); + collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineTestDesigner), Roles.FSETechnician)); + collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineTestPublisher), Roles.FSETechnician, Roles.FSETwineTestDesigner)); + collection.Add(new RoleModel(roles.SingleOrDefault(x => x.RoleEnum == Roles.FSETwineDeveloper), Roles.FSETechnician)); + } + + collection.ToList().ForEach(x => x.IsSelected = user.FSERoles.Any(y => y.Code == x.Role.Code)); + + RolesCollection = collection; + } + + private async Task LoadUserDetails() + { + try + { + IsFree = false; + + User = await Services.OrganizationsService.GetUserDetails(userToLoadGuid); + var roles = await Services.OrganizationsService.GetAllRoles(); + + InitRolesCollection(User, roles); + + Validate(); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error loading user details for user '{userToLoadGuid}'"); + await NotificationProvider.ShowError($"Error loading the selected user details.\n{ex.FlattenMessage()}"); + await NavigationManager.NavigateBack(); + } + finally + { + IsFree = true; + } + } + + private async void Save() + { + try + { + if (!Validate()) return; + + IsFree = false; + + using (var task = NotificationProvider.PushTaskItem("Saving user details...")) + { + var rolesToAdd = RolesCollection.Where(x => x.IsSelected).ToList().Where(x => !User.FSERoles.Exists(y => y.Guid == x.Role.Guid)).ToList(); + var rolesToRemove = User.FSERoles.ToList().Where(x => !RolesCollection.Where(z => z.IsSelected).ToList().Exists(y => y.Role.Guid == x.Guid)).ToList(); + + foreach (var role in rolesToAdd.Select(x => x.Role)) + { + User.UsersRoles.Add(new UsersRole() + { + UserGuid = User.Guid, + RoleGuid = role.Guid, + Role = role, + User = User, + }); + } + + foreach (var role in rolesToRemove) + { + var userRole = User.UsersRoles.SingleOrDefault(x => x.RoleGuid == role.Guid); + if (userRole != null) + { + User.UsersRoles.Remove(userRole); + } + } + + User.Contact.FirstName = FirstName; + User.Contact.LastName = LastName; + + if (!IsNewUser) + { + await Services.OrganizationsService.UpdateUser(User); + } + else + { + User.OrganizationGuid = Organization.Guid; + User.Email = Email; + User.Password = Password; + + await Services.OrganizationsService.InsertUser(User); + + if (SendInvitation) + { + bool invitationSent = false; + task.UpdateProgress("Sending email invitation..."); + + while (!invitationSent) + { + try + { + await Services.OrganizationsService.SendNewUserInvitationEmail(User.Guid, Password); + invitationSent = true; + } + catch (Exception ex) + { + if (!await NotificationProvider.ShowWarningQuestion($"The user was created but an error occurred while trying to send the invitation via email.{ex.Message}\nWould you like to try again?")) + { + break; + } + } + } + } + + await NotificationProvider.ShowSuccess("User created successfully!"); + + IsNewUser = false; + Password = null; + userToLoadGuid = User.Guid; + } + + await LoadUserDetails(); + + await ModularNavigationManager.NavigateTo(UsersAndRolesView.OrganizationUsersView, new OrganizationUsersViewVM.NavigationObject() + { + Organization = User.Organization, + SelectedUser = User + }, false); + } + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error saving user details for '{User.Email}'."); + await NotificationProvider.ShowError($"Error saving user details.\n{ex.FlattenMessage()}"); + } + finally + { + IsFree = true; + } + } + + private void OnUserChanged() + { + if (User != null) + { + FirstName = User.Contact.FirstName; + LastName = User.Contact.LastName; + IsEmailTaken = false; + Email = User.Email; + } + else + { + FirstName = null; + LastName = null; + Email = null; + Password = null; + } + } + + private async void OnEmailChanged() + { + if (IsNewUser && Email.IsNotNullOrEmpty()) + { + try + { + IsCheckingEmail = true; + await Task.Delay(500); + IsEmailTaken = !await Services.OrganizationsService.CheckEmailAvailable(Email); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error checking for email availability."); + IsEmailTaken = false; + } + finally + { + IsCheckingEmail = false; + } + } + } + + protected override void OnValidating() + { + base.OnValidating(); + + if (IsEmailTaken) + { + InsertError(nameof(Email), "Email address is already registered."); + } + } + + public void OnNavigatedToWithObject(NavigationObject obj) + { + User = null; + IsNewUser = obj.IsNewUser; + Organization = obj.Organization; + + if (!IsNewUser) + { + userToLoadGuid = obj.User.Guid; + _requiresLoading = true; + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/MainView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/MainView.xaml new file mode 100644 index 000000000..8e7db0116 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/MainView.xaml @@ -0,0 +1,21 @@ +<UserControl x:Class="Tango.FSE.UsersAndRoles.Views.MainView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:global="clr-namespace:Tango.FSE.UsersAndRoles" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:vm="clr-namespace:Tango.FSE.UsersAndRoles.ViewModels" + xmlns:local="clr-namespace:Tango.FSE.UsersAndRoles.Views" + mc:Ignorable="d" + d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}" Background="{StaticResource FSE_PrimaryBackgroundBrush}"> + <Grid> + <Image Source="../Images/users_roles_back.png" HorizontalAlignment="Right" VerticalAlignment="Bottom" Stretch="None" Opacity="0.05" /> + + <controls:NavigationControl TransitionType="Slide" TransitionDuration="00:00:0.2"> + <local:OrganizationSelectionView/> + <local:OrganizationUsersView/> + <local:UserDetailsView/> + </controls:NavigationControl> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/MainView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/MainView.xaml.cs new file mode 100644 index 000000000..b8c6f7b66 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/MainView.xaml.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.FSE.UsersAndRoles.Views +{ + /// <summary> + /// Interaction logic for MainView.xaml + /// </summary> + public partial class MainView : UserControl + { + public static MainView Instance { get; set; } + + public MainView() + { + Instance = this; + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/OrganizationSelectionView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/OrganizationSelectionView.xaml new file mode 100644 index 000000000..c57ea0ba5 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/OrganizationSelectionView.xaml @@ -0,0 +1,57 @@ +<UserControl x:Class="Tango.FSE.UsersAndRoles.Views.OrganizationSelectionView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:global="clr-namespace:Tango.FSE.UsersAndRoles" + xmlns:vm="clr-namespace:Tango.FSE.UsersAndRoles.ViewModels" + xmlns:local="clr-namespace:Tango.FSE.UsersAndRoles.Views" + xmlns:autoComplete="clr-namespace:Tango.AutoComplete.Editors;assembly=Tango.AutoComplete" + mc:Ignorable="d" + d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:OrganizationSelectionViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.OrganizationSelectionViewVM}" d:DesignStyle="{StaticResource FSE_User_Control_Designer}"> + <Grid> + <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> + + <TextBlock HorizontalAlignment="Center" FontSize="{StaticResource FSE_ModuleHeaderFontSize}">Users & Roles</TextBlock> + <TextBlock TextWrapping="Wrap" Margin="0 20 0 0" TextAlignment="Center" LineHeight="25"> + <Run>As an organization administrator you will be able to manage/create organization users and assigned them appropriate roles.</Run> + </TextBlock> + + <StackPanel Margin="0 40 0 0" Width="500" HorizontalAlignment="Center"> + <Image Source="../Images/users_and_roles.png" Stretch="None" /> + + <TextBlock Margin="60" HorizontalAlignment="Center" FontWeight="SemiBold" Foreground="{StaticResource FSE_PrimaryAccentBrush}" FontSize="{StaticResource FSE_LargerFontSize}">Select Organization</TextBlock> + <autoComplete:AutoCompleteTextBox material:HintAssist.Hint="Name" MaxPopupHeight="300" Margin="0 5 0 0" Provider="{Binding Organizations}" SelectedItem="{Binding SelectedOrganization,Mode=TwoWay}" DisplayMember="Name"> + <autoComplete:AutoCompleteTextBox.SelectedItemTemplate> + <DataTemplate> + <DockPanel VerticalAlignment="Center"> + <material:PackIcon Kind="Company" Width="24" Height="24" /> + <StackPanel VerticalAlignment="Center" Margin="10 0 0 0" Orientation="Horizontal"> + <TextBlock Text="{Binding Name}" FontSize="{StaticResource FSE_LargerFontSize}"></TextBlock> + </StackPanel> + </DockPanel> + </DataTemplate> + </autoComplete:AutoCompleteTextBox.SelectedItemTemplate> + <autoComplete:AutoCompleteTextBox.ItemTemplate> + <DataTemplate> + <DockPanel VerticalAlignment="Center"> + <material:PackIcon Kind="Company" Width="32" Height="32" /> + <StackPanel Margin="5 0 0 0" VerticalAlignment="Center"> + <TextBlock Text="{Binding Name}" FontSize="{StaticResource FSE_LargerFontSize}"></TextBlock> + </StackPanel> + </DockPanel> + </DataTemplate> + </autoComplete:AutoCompleteTextBox.ItemTemplate> + </autoComplete:AutoCompleteTextBox> + + <Button material:ButtonAssist.CornerRadius="25" Command="{Binding ManageOrganizationCommand}" Margin="0 100 0 0" Height="50" Width="250"> + <DockPanel> + <TextBlock>CONTINUE</TextBlock> + <material:PackIcon Margin="10 0 0 0" VerticalAlignment="Center" Kind="ArrowRight" /> + </DockPanel> + </Button> + </StackPanel> + </StackPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/OrganizationSelectionView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/OrganizationSelectionView.xaml.cs new file mode 100644 index 000000000..904700c9c --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/OrganizationSelectionView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.FSE.UsersAndRoles.Views +{ + /// <summary> + /// Interaction logic for OrganizationSelectionView.xaml + /// </summary> + public partial class OrganizationSelectionView : UserControl + { + public OrganizationSelectionView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/OrganizationUsersView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/OrganizationUsersView.xaml new file mode 100644 index 000000000..547243944 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/OrganizationUsersView.xaml @@ -0,0 +1,140 @@ +<UserControl x:Class="Tango.FSE.UsersAndRoles.Views.OrganizationUsersView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:global="clr-namespace:Tango.FSE.UsersAndRoles" + xmlns:helpers="clr-namespace:Tango.SharedUI.Helpers;assembly=Tango.SharedUI" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" + xmlns:vm="clr-namespace:Tango.FSE.UsersAndRoles.ViewModels" + xmlns:local="clr-namespace:Tango.FSE.UsersAndRoles.Views" + mc:Ignorable="d" + d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:OrganizationUsersViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.OrganizationUsersViewVM}" d:DesignStyle="{StaticResource FSE_User_Control_Designer}"> + <Grid Margin="40" IsEnabled="{Binding IsFree}"> + <DockPanel> + <DockPanel DockPanel.Dock="Top" HorizontalAlignment="Left"> + <Image Source="../Images/users_and_roles.png" Stretch="Uniform" Width="48" RenderOptions.BitmapScalingMode="Fant" /> + <TextBlock Margin="20 0 0 0" FontSize="{StaticResource FSE_ModuleHeaderFontSize}" VerticalAlignment="Center"> + <Run Text="{Binding Organization.Name}"></Run> + <Run>Users</Run> + </TextBlock> + </DockPanel> + + <Grid Margin="0 40 0 0"> + <DockPanel> + <Grid DockPanel.Dock="Top" Panel.ZIndex="100"> + <!--TOP BAR--> + + <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 0 20 -45"> + <DockPanel Margin="0 0 20 0" VerticalAlignment="Center"> + <material:PackIcon Kind="Search" Foreground="{StaticResource FSE_PrimaryAccentBrush}" VerticalAlignment="Center" Width="24" Height="24" Margin="0 0 5 0" /> + <TextBox material:HintAssist.Hint="Search" Text="{Binding Filter,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,Delay=500}" Background="{StaticResource FSE_PrimaryBackgroundBrush}" Width="300" Style="{StaticResource FSE_Rounded_Corners_TextBox}" Height="33"></TextBox> + </DockPanel> + <controls:ToggleIconButton IsChecked="{Binding ShowDeleted}" Width="24" Height="24" Cursor="Hand" UncheckedForeground="{StaticResource FSE_GrayBrush}" CheckedForeground="{StaticResource FSE_RedBrush}" ToolTip="Show suspended accounts" Margin="0 0 20 0" UncheckedIcon="EyeOutline" CheckedIcon="EyeCheckOutline"></controls:ToggleIconButton> + <controls:TextIconButton material:ButtonAssist.CornerRadius="15" Command="{Binding AddUserCommand}" Icon="Add" Width="150">ADD USER</controls:TextIconButton> + </StackPanel> + </Grid> + + <Grid> + <Border Background="#8B202020" Padding="0 0 0 5" CornerRadius="5"> + <Grid> + <Border VerticalAlignment="Top" Background="{StaticResource FSE_PrimaryBackgroundLightBrush}" Height="47" CornerRadius="5 5 0 0"> + + </Border> + <DataGrid RowHeight="60" CanUserSortColumns="True" Style="{StaticResource FSE_DataGrid}" CellStyle="{StaticResource FSE_DataGrid_Cell}" ItemsSource="{Binding Users}" SelectedItem="{Binding SelectedUser}" helpers:DataGridHelper.DoubleClickCommand="{Binding EditUserCommand}"> + <DataGrid.Columns> + <DataGridTemplateColumn Width="60"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <material:PackIcon Kind="User" VerticalAlignment="Center" Width="32" Height="32" /> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + + <DataGridTemplateColumn Header="NAME" SortMemberPath="Contact.FullName" Width="120"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <TextBlock VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Text="{Binding Contact.FullName}"></TextBlock> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + + <DataGridTemplateColumn Header="EMAIL" SortMemberPath="Email" Width="210"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <TextBlock VerticalAlignment="Center" Text="{Binding Email}" TextTrimming="CharacterEllipsis"></TextBlock> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + + <DataGridTemplateColumn Header="LAST MODIFIED" SortMemberPath="LastUpdated"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <TextBlock VerticalAlignment="Center" Text="{Binding LastUpdated,Converter={StaticResource DateTimeUtcHumanizeConverter}}"></TextBlock> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + + <DataGridTemplateColumn Header="ROLES" Width="1*"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <ItemsControl ItemsSource="{Binding FSERoles}"> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <StackPanel IsItemsHost="True" Orientation="Horizontal"></StackPanel> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.ItemTemplate> + <DataTemplate> + <TextBlock FontSize="{StaticResource FSE_SmallFontSize}" Foreground="{StaticResource FSE_GrayBrush}" Margin="0 0 5 0" VerticalAlignment="Center"> + <Run Text="{Binding Description}"></Run>, + </TextBlock> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + + <DataGridTemplateColumn Width="180"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <UniformGrid Columns="3"> + <controls:IconButton ToolTip="Edit user details" Cursor="Hand" Width="28" Height="28" Icon="Edit" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.EditUserCommand}" CommandParameter="{Binding}" /> + <material:PackIcon Margin="20 0 0 0" Width="12" Height="12" VerticalAlignment="Center" Kind="Circle" > + <material:PackIcon.Style> + <Style TargetType="material:PackIcon"> + <Setter Property="Foreground" Value="{StaticResource FSE_GreenBrush}"></Setter> + <Setter Property="ToolTip" Value="Activated"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding Deleted}" Value="True"> + <Setter Property="Foreground" Value="{StaticResource FSE_GrayBrush}"></Setter> + <Setter Property="ToolTip" Value="Suspended"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </material:PackIcon.Style> + </material:PackIcon> + <controls:IconButton ToolTip="Suspend account" Cursor="Hand" Width="28" Height="28" Icon="Close" Foreground="{StaticResource FSE_RedBrush}" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.RemoveUserCommand}" CommandParameter="{Binding}" /> + </UniformGrid> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + </DataGrid.Columns> + </DataGrid> + </Grid> + </Border> + </Grid> + </DockPanel> + + <Grid Background="{StaticResource FSE_SemiTransparentBrush}" Visibility="{Binding IsBusy,Converter={StaticResource BooleanToVisibilityConverter},FallbackValue='Visible'}"> + <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> + <ProgressBar IsIndeterminate="{Binding IsBusy}" HorizontalAlignment="Center" Width="150" Height="150" Style="{StaticResource FSE_CircularProgressBar}"></ProgressBar> + <TextBlock HorizontalAlignment="Center" Margin="0 20 0 0">Loading...</TextBlock> + </StackPanel> + </Grid> + </Grid> + </DockPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/OrganizationUsersView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/OrganizationUsersView.xaml.cs new file mode 100644 index 000000000..e3fc173d8 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/OrganizationUsersView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.FSE.UsersAndRoles.Views +{ + /// <summary> + /// Interaction logic for OrganizationUsersView.xaml + /// </summary> + public partial class OrganizationUsersView : UserControl + { + public OrganizationUsersView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/UserDetailsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/UserDetailsView.xaml new file mode 100644 index 000000000..a2ad81cf4 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/UserDetailsView.xaml @@ -0,0 +1,166 @@ +<UserControl x:Class="Tango.FSE.UsersAndRoles.Views.UserDetailsView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:global="clr-namespace:Tango.FSE.UsersAndRoles" + xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:commonControls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" + xmlns:vm="clr-namespace:Tango.FSE.UsersAndRoles.ViewModels" + xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" + xmlns:local="clr-namespace:Tango.FSE.UsersAndRoles.Views" + mc:Ignorable="d" + d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:UserDetailsViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.UserDetailsViewVM}"> + <Grid Margin="40" IsEnabled="{Binding IsFree}"> + <DockPanel> + <DockPanel DockPanel.Dock="Top" HorizontalAlignment="Left"> + <material:PackIcon Height="48" Width="48" Kind="User" /> + <TextBlock Margin="20 0 0 0" FontSize="{StaticResource FSE_ModuleHeaderFontSize}" VerticalAlignment="Center"> + <Run Text="{Binding FirstName}"></Run> + <Run Text="{Binding LastName}"></Run> + </TextBlock> + </DockPanel> + + <Grid Margin="0 40 0 0"> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="700"/> + <ColumnDefinition Width="1*"/> + </Grid.ColumnDefinitions> + <ScrollViewer Grid.ColumnSpan="2" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" FocusVisualStyle="{x:Null}"> + <StackPanel> + <Grid Width="700" HorizontalAlignment="Left"> + <StackPanel> + <DockPanel> + <Border DockPanel.Dock="Top" Padding="10 5 5 5" Background="{StaticResource FSE_PrimaryBackgroundLightBrush}" CornerRadius="5 5 0 0"> + <DockPanel > + <material:PackIcon VerticalAlignment="Top" Kind="UserCardDetailsOutline" Width="32" Height="32" /> + <StackPanel Margin="10 0 0 0" VerticalAlignment="Center"> + <TextBlock FontSize="{StaticResource FSE_LargerFontSize}">Details</TextBlock> + </StackPanel> + </DockPanel> + </Border> + + <Grid> + <Border Background="#8E202020" CornerRadius="0 0 5 5" Padding="0 0 40 40"> + <StackPanel Margin="40 40 0 0"> + <StackPanel> + + <UniformGrid Columns="2"> + <DockPanel> + <Grid Panel.ZIndex="5" DockPanel.Dock="Right" Margin="-16 0 0 -6" Visibility="{Binding IsNewUser,Converter={StaticResource BooleanToVisibilityConverter}}"> + <Grid.Style> + <Style> + <Setter Property="Validation.ErrorTemplate" Value="{x:Null}"></Setter> + </Style> + </Grid.Style> + <ProgressBar HorizontalAlignment="Left" VerticalAlignment="Center" IsIndeterminate="{Binding IsCheckingEmail}" Visibility="{Binding IsCheckingEmail,Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource FSE_CircularProgressBar}" Width="16" Height="16" /> + + <Grid Background="Transparent" Visibility="{Binding IsCheckingEmail,Converter={StaticResource BooleanToVisibilityInverseConverter}}"> + <material:PackIcon Width="16" ToolTip="Email address is already registered" VerticalAlignment="Center" Kind="Exclamation" Foreground="{StaticResource FSE_ErrorBrush}" Visibility="{Binding IsEmailTaken,Converter={StaticResource BooleanToVisibilityConverter}}" /> + <material:PackIcon VerticalAlignment="Center" Kind="Check" Foreground="{StaticResource FSE_SuccessBrush}" Visibility="{Binding IsEmailTaken,Converter={StaticResource BooleanToVisibilityInverseConverter}}" /> + </Grid> + </Grid> + <TextBox material:HintAssist.IsFloating="True" material:HintAssist.Hint="Email" IsReadOnly="{Binding IsNewUser,Converter={StaticResource BooleanInverseConverter}}" Text="{Binding Email,UpdateSourceTrigger=PropertyChanged,Delay=500,NotifyOnValidationError=True,ValidatesOnDataErrors=True,ValidatesOnNotifyDataErrors=True}"></TextBox> + </DockPanel> + </UniformGrid> + + <UniformGrid Columns="2" Margin="0 30 0 0" Visibility="{Binding IsNewUser,Converter={StaticResource BooleanToVisibilityConverter}}"> + <TextBox Margin="0 0 0 0" material:HintAssist.IsFloating="True" material:HintAssist.Hint="Password" IsReadOnly="True" Text="{Binding Password,NotifyOnValidationError=True,ValidatesOnDataErrors=True,ValidatesOnNotifyDataErrors=True}"></TextBox> + + <Button Margin="20 0 0 0" HorizontalAlignment="Left" Width="120" Style="{StaticResource FSE_RaisedButton_Dark_Hover_Accent_Foreground}" Command="{Binding GeneratePasswordCommand}" >GENERATE</Button> + </UniformGrid> + + <UniformGrid Columns="2" Margin="0 30 0 0"> + <TextBox Margin="0 0 0 0" material:HintAssist.IsFloating="True" material:HintAssist.Hint="First Name" Text="{Binding FirstName,NotifyOnValidationError=True,ValidatesOnDataErrors=True,ValidatesOnNotifyDataErrors=True}"></TextBox> + + <TextBox Margin="20 0 0 0" material:HintAssist.IsFloating="True" material:HintAssist.Hint="Last Name" Text="{Binding LastName,NotifyOnValidationError=True,ValidatesOnDataErrors=True,ValidatesOnNotifyDataErrors=True}"></TextBox> + </UniformGrid> + + <UniformGrid Columns="2" Margin="0 30 0 0"> + <TextBox material:HintAssist.IsFloating="True" material:HintAssist.Hint="Phone Number" Text="{Binding User.Contact.PhoneNumber}"></TextBox> + </UniformGrid> + + <UniformGrid Columns="2" Margin="0 30 0 0"> + <TextBox material:HintAssist.IsFloating="True" material:HintAssist.Hint="Fax" Text="{Binding User.Contact.Fax}"></TextBox> + </UniformGrid> + </StackPanel> + </StackPanel> + </Border> + + <Grid Visibility="{Binding IsBusy,Converter={StaticResource BooleanToVisibilityConverter}}"> + <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> + <ProgressBar IsIndeterminate="{Binding IsBusy}" HorizontalAlignment="Center" Width="150" Height="150" Style="{StaticResource FSE_CircularProgressBar}"></ProgressBar> + <TextBlock HorizontalAlignment="Center" Margin="0 20 0 0">Loading...</TextBlock> + </StackPanel> + </Grid> + </Grid> + </DockPanel> + + <DockPanel Margin="0 40 0 0"> + <Border DockPanel.Dock="Top" Padding="10 5 5 5" Background="{StaticResource FSE_PrimaryBackgroundLightBrush}" CornerRadius="5 5 0 0"> + <DockPanel > + <material:PackIcon VerticalAlignment="Top" Kind="UserBadgeOutline" Width="32" Height="32" /> + <StackPanel Margin="10 0 0 0" VerticalAlignment="Center"> + <TextBlock FontSize="{StaticResource FSE_LargerFontSize}">Roles</TextBlock> + </StackPanel> + </DockPanel> + </Border> + + <Border Background="#8E202020" CornerRadius="0 0 5 5" Padding="0 0 40 40"> + <StackPanel Margin="40 40 0 0"> + <StackPanel> + <ListBox ScrollViewer.CanContentScroll="False" ScrollViewer.VerticalScrollBarVisibility="Disabled" Style="{StaticResource FSE_BlankListBox}" ItemsSource="{Binding RolesCollection}"> + <ListBox.ItemTemplate> + <DataTemplate> + <CheckBox Margin="0 10 0 0" IsChecked="{Binding IsSelected}" IsEnabled="{Binding IsEnabled}" Content="{Binding Role.Description}"></CheckBox> + </DataTemplate> + </ListBox.ItemTemplate> + </ListBox> + </StackPanel> + </StackPanel> + </Border> + </DockPanel> + </StackPanel> + + </Grid> + </StackPanel> + </ScrollViewer> + + <StackPanel Margin="20 0 0 0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="380"> + <DockPanel> + <Border DockPanel.Dock="Top" Padding="10 5 5 5" Background="{StaticResource FSE_PrimaryBackgroundLightBrush}" CornerRadius="5 5 0 0"> + <DockPanel> + <material:PackIcon VerticalAlignment="Top" Kind="UserCheck" Width="32" Height="32" /> + <StackPanel Margin="10 0 0 0" VerticalAlignment="Center"> + <TextBlock FontSize="{StaticResource FSE_LargerFontSize}">Status</TextBlock> + </StackPanel> + </DockPanel> + </Border> + + <Border Background="#8E202020" CornerRadius="0 0 5 5" Padding="0 0 40 40" IsEnabled="{Binding IsNewUser,Converter={StaticResource BooleanInverseConverter}}"> + <StackPanel Margin="40 40 0 0"> + <UniformGrid Columns="2"> + <RadioButton x:Name="chkActive" IsChecked="{Binding User.Deleted,Converter={StaticResource BooleanInverseConverter},Mode=TwoWay}">Activated</RadioButton> + <RadioButton IsChecked="{Binding ElementName=chkActive,Path=IsChecked,Converter={StaticResource BooleanInverseConverter},Mode=TwoWay}">Suspended</RadioButton> + </UniformGrid> + </StackPanel> + </Border> + </DockPanel> + + <DockPanel Margin="0 50 0 0" HorizontalAlignment="Center" Visibility="{Binding IsNewUser,Converter={StaticResource BooleanToVisibilityConverter}}"> + <CheckBox IsChecked="{Binding SendInvitation}" ToolTip="Send the new user invitation to login to this system with the initial password" Foreground="{StaticResource FSE_PrimaryAccentBrush}">Send invitation via email</CheckBox> + </DockPanel> + + <Button Margin="0 60 0 0" material:ButtonAssist.CornerRadius="25" Width="250" Height="50" Padding="12" Command="{Binding SaveCommand}"> + <DockPanel> + <material:PackIcon Kind="ContentSave"/> + <TextBlock Margin="10 0 0 0">SAVE</TextBlock> + </DockPanel> + </Button> + </StackPanel> + </Grid> + </Grid> + </DockPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/UserDetailsView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/UserDetailsView.xaml.cs new file mode 100644 index 000000000..8b76c0229 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/Views/UserDetailsView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.FSE.UsersAndRoles.Views +{ + /// <summary> + /// Interaction logic for UserDetailsView.xaml + /// </summary> + public partial class UserDetailsView : UserControl + { + public UserDetailsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/app.config b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/app.config new file mode 100644 index 000000000..36bc04f85 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/app.config @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="utf-8"?> +<configuration> + <configSections> + <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --> + <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> + </configSections> + <runtime> + <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> + <dependentAssembly> + <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-5.0.5.0" newVersion="5.0.5.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-1.2.2.0" newVersion="1.2.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-1.4.2.0" newVersion="1.4.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Console" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Diagnostics.StackTrace" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Data.Services.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Data.OData" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-3.0.3000.0" newVersion="3.0.3000.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" /> + </dependentAssembly> + </assemblyBinding> + </runtime> + <entityFramework> + <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" /> + <providers> + <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> + </providers> + </entityFramework> +</configuration>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/packages.config b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/packages.config new file mode 100644 index 000000000..dd8c723e4 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.UsersAndRoles/packages.config @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="ControlzEx" version="3.0.2.4" targetFramework="net461" /> + <package id="EntityFramework" version="6.2.0" targetFramework="net461" /> + <package id="Google.Protobuf" version="3.4.1" targetFramework="net461" /> + <package id="MahApps.Metro" version="1.6.5" targetFramework="net461" /> + <package id="MaterialDesignColors" version="1.2.2" targetFramework="net461" /> + <package id="MaterialDesignThemes" version="3.0.1" targetFramework="net461" /> + <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" /> +</packages>
\ No newline at end of file |
