From ee697f7a3350d0a97bddee4de3a2ae4f9d285052 Mon Sep 17 00:00:00 2001 From: Shlomo Hecht Date: Wed, 2 May 2018 17:36:54 +0300 Subject: merge --- .../Views/MachineTechView.xaml | 6 +- .../Converters/PermissionToVisibilityConverter.cs | 38 +++ .../Tango.MachineStudio.Common/IStudioViewModel.cs | 5 + .../StudioApplication/IStudioApplicationManager.cs | 8 + .../Tango.MachineStudio.Common/StudioViewModel.cs | 89 +++++++ .../Tango.MachineStudio.Common.csproj | 4 + .../Tango.MachineStudio.UI/App.xaml.cs | 51 +++- .../Tango.MachineStudio.UI/Console/CodeTemplate.cs | 23 ++ .../Console/ConsoleManager.cs | 39 ++++ .../Console/ConsoleOnExecuteParameters.cs | 26 +++ .../Console/ConsoleWindow.xaml | 223 ++++++++++++++++++ .../Console/ConsoleWindow.xaml.cs | 43 ++++ .../Console/ConsoleWindowVM.cs | 257 +++++++++++++++++++++ .../Tango.MachineStudio.UI/Images/bug-resolved.png | Bin 0 -> 6496 bytes .../DefaultStudioApplicationManager.cs | 21 ++ .../TFS/SystemInformationModel.cs | 2 + .../TFS/SystemInformationTemplate.cshtml | 25 +- .../TFS/TeamFoundationServiceExtendedClient.cs | 103 ++++++++- .../TFS/WorkItemValidationAttribute.cs | 10 +- .../Tango.MachineStudio.UI.csproj | 24 ++ .../Tango.MachineStudio.UI/ViewModelLocator.cs | 12 +- .../ViewModels/LoadingViewVM.cs | 8 +- .../ViewModels/MainViewVM.cs | 84 ++++++- .../ViewModels/ResolvedIssuesViewVM.cs | 61 +++++ .../Tango.MachineStudio.UI/Views/MainView.xaml | 48 +++- .../Views/ReportIssueView.xaml | 110 +++++---- .../Views/ResolvedIssuesView.xaml | 89 +++++++ .../Views/ResolvedIssuesView.xaml.cs | 28 +++ .../Windows/ExceptionResolutions.cs | 3 +- .../Windows/ExceptionWindow.xaml | 12 +- .../Windows/ExceptionWindow.xaml.cs | 7 +- .../Tango.BL/Enumerations/Permissions.cs | 6 + .../Tango.CodeGeneration/CustomResolver.cs | 20 ++ .../Visual_Studio/Tango.CodeGeneration/Helper.cs | 7 + .../Tango.CodeGeneration.csproj | 1 + .../ExtensionMethods/ObjectExtensions.cs | 25 ++ .../Tango.Core/Helpers/EmbeddedResourceHelper.cs | 10 + .../Tango.Core/Json/DynamicContractResolver.cs | 30 +++ .../Tango.Core/Json/HtmlContractResolver.cs | 39 ++++ .../Visual_Studio/Tango.Core/Tango.Core.csproj | 2 + .../Tango.Emulations/Emulators/MachineEmulator.cs | 14 +- .../Operation/IMachineOperator.cs | 15 ++ .../Tango.Integration/Operation/MachineOperator.cs | 46 +++- .../Tango.PMR/Connection/ConnectResponse.cs | 44 +++- .../Tango.PMR/Connection/DeviceInformation.cs | 216 +++++++++++++++++ .../Diagnostics/PushDiagnosticsResponse.cs | 97 +------- .../Visual_Studio/Tango.PMR/ExtensionMethods.cs | 2 +- Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj | 1 + .../Controls/ScriptEditorControl.xaml.cs | 4 +- .../Tango.TFS/ITeamFoundationServiceClient.cs | 36 +++ Software/Visual_Studio/Tango.TFS/ResolvedReason.cs | 27 +++ Software/Visual_Studio/Tango.TFS/Tango.TFS.csproj | 5 + .../Tango.TFS/TeamFoundationServiceClient.cs | 248 ++++++++++++++++---- Software/Visual_Studio/Tango.TFS/WorkItem.cs | 52 +++++ .../Visual_Studio/Tango.UnitTesting/TFS_TST.cs | 52 ++++- 55 files changed, 2244 insertions(+), 214 deletions(-) create mode 100644 Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Converters/PermissionToVisibilityConverter.cs create mode 100644 Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/CodeTemplate.cs create mode 100644 Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleManager.cs create mode 100644 Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleOnExecuteParameters.cs create mode 100644 Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleWindow.xaml create mode 100644 Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleWindow.xaml.cs create mode 100644 Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleWindowVM.cs create mode 100644 Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Images/bug-resolved.png create mode 100644 Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/ResolvedIssuesViewVM.cs create mode 100644 Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/ResolvedIssuesView.xaml create mode 100644 Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/ResolvedIssuesView.xaml.cs create mode 100644 Software/Visual_Studio/Tango.CodeGeneration/CustomResolver.cs create mode 100644 Software/Visual_Studio/Tango.Core/Json/DynamicContractResolver.cs create mode 100644 Software/Visual_Studio/Tango.Core/Json/HtmlContractResolver.cs create mode 100644 Software/Visual_Studio/Tango.PMR/Connection/DeviceInformation.cs create mode 100644 Software/Visual_Studio/Tango.TFS/ResolvedReason.cs (limited to 'Software/Visual_Studio') diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Views/MachineTechView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Views/MachineTechView.xaml index 3d4ecdac1..53fcafb8f 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Views/MachineTechView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/Views/MachineTechView.xaml @@ -220,9 +220,9 @@ - Version Name: - Version Number: - Build Date: + Version Name: + Version Number: + Build Date: Diagnostics Frame Size: diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Converters/PermissionToVisibilityConverter.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Converters/PermissionToVisibilityConverter.cs new file mode 100644 index 000000000..08e7d1c12 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Converters/PermissionToVisibilityConverter.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Data; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.Core.DI; +using Tango.MachineStudio.Common.Authentication; + +namespace Tango.MachineStudio.Common.Converters +{ + public class PermissionToVisibilityConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + User user = value as User; + + if (user != null) + { + if (user.HasPermission((Permissions)parameter)) + { + return Visibility.Visible; + } + } + + return Visibility.Collapsed; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/IStudioViewModel.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/IStudioViewModel.cs index 35ed50cd9..4203a1e8b 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/IStudioViewModel.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/IStudioViewModel.cs @@ -38,5 +38,10 @@ namespace Tango.MachineStudio.Common /// /// The arguments. void OnModuleRequest(params object[] args); + + /// + /// Called when the application has been started + /// + void OnApplicationStarted(); } } diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/StudioApplication/IStudioApplicationManager.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/StudioApplication/IStudioApplicationManager.cs index be793ac81..1de18ac94 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/StudioApplication/IStudioApplicationManager.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/StudioApplication/IStudioApplicationManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows; using Tango.Integration.Services; namespace Tango.MachineStudio.Common.StudioApplication @@ -53,5 +54,12 @@ namespace Tango.MachineStudio.Common.StudioApplication /// Gets the machine studio application version. /// String Version { get; } + + /// + /// Notify the application manager about an external opened window. + /// When application exists. All registered windows will be closed. + /// + /// The window. + void RegisterOpenedWindow(Window window); } } diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/StudioViewModel.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/StudioViewModel.cs index 9c7e52d23..77fad1fc6 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/StudioViewModel.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/StudioViewModel.cs @@ -7,6 +7,79 @@ using Tango.SharedUI; namespace Tango.MachineStudio.Common { + /// + /// Represents a Machine Studio view model + /// + /// The type of the module. + /// + /// + public abstract class StudioViewModelInternal : ViewModel, IStudioViewModel + { + /// + /// Gets or sets a value indicating whether this view model studio module is currently loaded. + /// + public bool IsModuleLoaded { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + public StudioViewModelInternal() : base() + { + + } + + /// + /// Called when another module has wants to navigate to this module with some arguments. + /// + /// The arguments. + public virtual void OnModuleRequest(params object[] args) + { + + } + + /// + /// Called when the user has navigated out of the module. + /// + public virtual void OnNavigatedFrom() + { + IsModuleLoaded = false; + } + + /// + /// Called when the user has navigated in to the module. + /// + public virtual void OnNavigatedTo() + { + IsModuleLoaded = true; + } + + /// + /// Called before the application is shutting down. + /// Return false to cancel the shutdown in case an important process is in progress. + /// + /// + public virtual Task OnShutdownRequest() + { + return Task.FromResult(true); + } + + /// + /// Called when application is shutting down. + /// + public virtual void OnShuttingDown() + { + + } + + /// + /// Called when the application has been started + /// + public virtual void OnApplicationStarted() + { + + } + } + /// /// Represents a Machine Studio view model /// @@ -70,6 +143,14 @@ namespace Tango.MachineStudio.Common { } + + /// + /// Called when the application has been started + /// + public virtual void OnApplicationStarted() + { + + } } /// @@ -90,6 +171,14 @@ namespace Tango.MachineStudio.Common } + /// + /// Called when the application has been started + /// + public virtual void OnApplicationStarted() + { + + } + /// /// Called when another module has wants to navigate to this module with some arguments. /// diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Tango.MachineStudio.Common.csproj b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Tango.MachineStudio.Common.csproj index e4a2720b9..ac6f84618 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Tango.MachineStudio.Common.csproj +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Tango.MachineStudio.Common.csproj @@ -89,6 +89,7 @@ RealTimeGraphControl.xaml + @@ -287,5 +288,8 @@ True + + + \ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/App.xaml.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/App.xaml.cs index d9c64b9e3..f124ebb54 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/App.xaml.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/App.xaml.cs @@ -15,6 +15,11 @@ using Tango.Settings; using Tango.MachineStudio.Common.EventLogging; using Tango.BL.Enumerations; using Tango.Core.DI; +using Tango.MachineStudio.UI.TFS; +using Tango.TFS; +using Tango.MachineStudio.Common.Notifications; +using Tango.MachineStudio.UI.ViewModels; +using Tango.MachineStudio.UI.Views; namespace Tango.MachineStudio.UI { @@ -82,7 +87,26 @@ namespace Tango.MachineStudio.UI Application.Current.Dispatcher.Invoke(() => { - ExceptionWindow exWin = new ExceptionWindow(e.Exception); + WorkItem bug = null; + TeamFoundationServiceExtendedClient tfsClient = null; + INotificationProvider notification = null; + + try + { + tfsClient = TangoIOC.Default.GetInstance(); + notification = TangoIOC.Default.GetInstance(); + + if (tfsClient != null && tfsClient.IsInitialized) + { + bug = tfsClient.CreateBug(); + } + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + + ExceptionWindow exWin = new ExceptionWindow(e.Exception, bug != null); exWin.ShowDialog(); switch (exWin.Resolution) @@ -100,6 +124,31 @@ namespace Tango.MachineStudio.UI e.TryRecover = false; LogManager.Log("User selection was to shutdown the application. Restarting..."); Environment.Exit(0); + break; + case ExceptionResolutions.Report: + e.TryRecover = true; + LogManager.Log("User selection was to report the issue."); + + if (bug != null) + { + notification.ShowModalDialog(new ReportIssueViewVM(tfsClient.Project, bug), async (vm) => + { + using (notification.PushTaskItem("Uploading bug report...")) + { + try + { + tfsClient.FinalizeBug(vm.WorkItem); + await tfsClient.UploadWorkItem(vm.WorkItem); + } + catch (Exception ex) + { + notification.ShowError("An error occurred while trying to create the issue." + Environment.NewLine + ex.Message); + } + } + + }, null); + } + break; } }); diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/CodeTemplate.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/CodeTemplate.cs new file mode 100644 index 000000000..4b307051f --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/CodeTemplate.cs @@ -0,0 +1,23 @@ +using System; +using System.Text; +using System.Linq; +using System.Drawing; +using System.Diagnostics; +using System.Windows.Forms; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Generic; +using Tango.MachineStudio.Common.Notifications; +using Tango.MachineStudio.UI.Console; + +public void OnExecute(ConsoleManager manager) +{ + manager.InvokeUI(() => + { + + var notification = manager.TangoIOC.GetInstance(); + notification.ShowInfo("Hello world!"); + + }); +} + diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleManager.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleManager.cs new file mode 100644 index 000000000..e2d525d95 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleManager.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.DI; +using Tango.MachineStudio.Common.Modules; + +namespace Tango.MachineStudio.UI.Console +{ + public class ConsoleManager + { + public TangoIOC TangoIOC { get; set; } + private Action _writeLine; + + public ConsoleManager(Action writeLine) + { + _writeLine = writeLine; + TangoIOC = TangoIOC.Default; + } + + public void WriteLine(String text) + { + _writeLine(text); + } + + public void InvokeUI(Action action) + { + Core.Helpers.ThreadsHelper.InvokeUI(action); + } + + public void StartModule(String name) + { + IStudioModuleLoader loader = TangoIOC.Default.GetInstance(); + var module = loader.AllModules.SingleOrDefault(x => x.Name == name); + TangoIOC.Default.GetInstance().StartModule(module); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleOnExecuteParameters.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleOnExecuteParameters.cs new file mode 100644 index 000000000..b06637ccd --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleOnExecuteParameters.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Scripting; + +namespace Tango.MachineStudio.UI.Console +{ + public class ConsoleOnExecuteParameters : OnExecuteParameters + { + /// + /// Provides access to the script stub manager. + /// + public ConsoleManager manager; + + /// + /// Initializes a new instance of the class. + /// + /// The manager. + public ConsoleOnExecuteParameters(ConsoleManager manager) + { + this.manager = manager; + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleWindow.xaml b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleWindow.xaml new file mode 100644 index 000000000..22338fea7 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleWindow.xaml @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LOG + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleWindow.xaml.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleWindow.xaml.cs new file mode 100644 index 000000000..de2c728b0 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleWindow.xaml.cs @@ -0,0 +1,43 @@ +using MahApps.Metro.Controls; +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.Shapes; + +namespace Tango.MachineStudio.UI.Console +{ + /// + /// Interaction logic for ConsoleWindow.xaml + /// + public partial class ConsoleWindow : MetroWindow + { + private ConsoleWindowVM _vm; + + public ConsoleWindow() + { + InitializeComponent(); + + this.Loaded += (_, __) => + { + _vm = this.DataContext as ConsoleWindowVM; + _vm.SetLogTextBox(txtLog); + }; + } + + //Auto scroll to bottom of response log each time it is changed. + private void TextBox_TextChanged(object sender, TextChangedEventArgs e) + { + txtLog.SelectionStart = txtLog.Text.Length; + txtLog.ScrollToEnd(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleWindowVM.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleWindowVM.cs new file mode 100644 index 000000000..a3a0a734e --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Console/ConsoleWindowVM.cs @@ -0,0 +1,257 @@ +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Threading; +using Tango.Core.Commands; +using Tango.Core.Helpers; +using Tango.MachineStudio.Common.Modules; +using Tango.MachineStudio.Common.Notifications; +using Tango.Scripting; +using Tango.SharedUI; + +namespace Tango.MachineStudio.UI.Console +{ + public class ConsoleWindowVM : ViewModel + { + private IStudioModuleLoader _moduleLoader; + private INotificationProvider _notificatrion; + private TextBox _txtLog; + private String _currentFile; + + + /// + /// Gets or sets the additional highlight C# types. + /// + public ObservableCollection> HighlightTypes { get; set; } + + internal void SetLogTextBox(TextBox txtLog) + { + _txtLog = txtLog; + } + + /// + /// Gets or sets the intellisense types. + /// + public ObservableCollection> IntellisenseTypes { get; set; } + + private String _code; + /// + /// Gets or sets the code. + /// + public String Code + { + get { return _code; } + set { _code = value; RaisePropertyChangedAuto(); } + } + + private bool _isRunning; + /// + /// Gets or sets a value indicating whether a stub is currently running. + /// + public bool IsRunning + { + get { return _isRunning; } + set { _isRunning = value; RaisePropertyChanged(nameof(IsRunning)); InvalidateRelayCommands(); } + } + + /// + /// Gets or sets the run command. + /// + public RelayCommand RunCommand { get; set; } + + /// + /// Gets or sets the stop command. + /// + public RelayCommand StopCommand { get; set; } + + /// + /// Gets or sets the clear command. + /// + public RelayCommand ClearCommand { get; set; } + + /// + /// Gets or sets the new command. + /// + public RelayCommand NewCommand { get; set; } + + /// + /// Gets or sets the open command. + /// + public RelayCommand OpenCommand { get; set; } + + /// + /// Gets or sets the save command. + /// + public RelayCommand SaveCommand { get; set; } + + /// + /// Gets or sets the save as command. + /// + public RelayCommand SaveAsCommand { get; set; } + + public ConsoleWindowVM(IStudioModuleLoader moduleLoader, INotificationProvider notification) + { + _moduleLoader = moduleLoader; + _notificatrion = notification; + + RunCommand = new RelayCommand(Run); + StopCommand = new RelayCommand(Stop); + + HighlightTypes = new ObservableCollection>(); + IntellisenseTypes = new ObservableCollection>(); + + IntellisenseTypes.Add(new KeyValuePair("manager", typeof(ConsoleManager))); + + foreach (var moduleType in moduleLoader.UserModules.SelectMany(x => x.MainViewType.Assembly.GetTypes())) + { + if (!moduleType.FullName.Contains("<") && !moduleType.FullName.Contains(">")) + { + HighlightTypes.Add(new KeyValuePair(moduleType.FullName, moduleType)); + } + } + + foreach (var type in this.GetType().Assembly.GetTypes()) + { + if (!type.FullName.Contains("<") && !type.FullName.Contains(">")) + { + HighlightTypes.Add(new KeyValuePair(type.Name, type)); + } + } + + foreach (var type in typeof(INotificationProvider).Assembly.GetTypes()) + { + if (!type.FullName.Contains("<") && !type.FullName.Contains(">")) + { + HighlightTypes.Add(new KeyValuePair(type.Name, type)); + } + } + + HighlightTypes.Add(new KeyValuePair("Thread", typeof(Thread))); + HighlightTypes.Add(new KeyValuePair("DateTime", typeof(DateTime))); + HighlightTypes.Add(new KeyValuePair("TimeSpan", typeof(TimeSpan))); + HighlightTypes.Add(new KeyValuePair("Dispatcher", typeof(Dispatcher))); + HighlightTypes.Add(new KeyValuePair("Task", typeof(Task))); + HighlightTypes.Add(new KeyValuePair("List", typeof(IList))); + HighlightTypes.Add(new KeyValuePair("int", typeof(Int32))); + HighlightTypes.Add(new KeyValuePair("double", typeof(Double))); + HighlightTypes.Add(new KeyValuePair("String", typeof(String))); + HighlightTypes.Add(new KeyValuePair("string", typeof(String))); + + foreach (var item in HighlightTypes) + { + IntellisenseTypes.Add(item); + } + + Code = EmbeddedResourceHelper.GetEmbeddedResourceText("Tango.MachineStudio.UI.Console.CodeTemplate.cs"); + + NewCommand = new RelayCommand(CreateNew); + OpenCommand = new RelayCommand(OpenFile); + SaveCommand = new RelayCommand(SaveFile); + SaveAsCommand = new RelayCommand(SaveAsFile); + ClearCommand = new RelayCommand(ClearLog); + } + + private void Stop() + { + + } + + private async void Run() + { + ScriptEngine engine = new ScriptEngine(new ConsoleOnExecuteParameters(new ConsoleManager(WriteLine))); + engine.Stop(); + engine.ReferencedAssemblies.Add(this.GetType()); + engine.ReferencedAssemblies.Add(typeof(INotificationProvider)); + + foreach (var module in _moduleLoader.AllModules) + { + engine.ReferencedAssemblies.Add(module.GetType()); + } + + await engine.Run(Code); + } + + private void WriteLine(String text) + { + InvokeUI(() => + { + _txtLog.AppendText(text); + }); + } + + /// + /// Clears the log. + /// + private void ClearLog() + { + _txtLog.Clear(); + } + + /// + /// Saves the selected script file. + /// + private void SaveFile() + { + if (_currentFile == null) + { + SaveAsFile(); + } + else + { + File.WriteAllText(_currentFile, Code); + } + } + + /// + /// Saves the selected script file. + /// + private void SaveAsFile() + { + SaveFileDialog dlg = new SaveFileDialog(); + dlg.Filter = "C# Script Files|*.cs"; + dlg.DefaultExt = ".cs"; + if (dlg.ShowDialog().Value) + { + File.WriteAllText(dlg.FileName, Code); + _currentFile = dlg.FileName; + } + } + + /// + /// Opens a script from HD. + /// + private void OpenFile() + { + OpenFileDialog dlg = new OpenFileDialog(); + dlg.Filter = "C# Script Files|*.cs"; + if (dlg.ShowDialog().Value) + { + OpenFile(dlg.FileName); + } + } + + /// + /// Opens the file. + /// + /// The file. + private void OpenFile(String file) + { + Code = File.ReadAllText(file); + _currentFile = file; + } + + private void CreateNew() + { + _txtLog.Clear(); + _currentFile = null; + Code = String.Empty; + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Images/bug-resolved.png b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Images/bug-resolved.png new file mode 100644 index 000000000..e49f62923 Binary files /dev/null and b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Images/bug-resolved.png differ diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/StudioApplication/DefaultStudioApplicationManager.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/StudioApplication/DefaultStudioApplicationManager.cs index 0bbcfd313..4c02be2b2 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/StudioApplication/DefaultStudioApplicationManager.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/StudioApplication/DefaultStudioApplicationManager.cs @@ -42,6 +42,22 @@ namespace Tango.MachineStudio.UI.StudioApplication _moduleLoader = moduleLoader; _navigationManager = navigationManager; _openedWindows = new List(); + + Task.Factory.StartNew(() => + { + while (MainWindow.Instance == null) + { + Thread.Sleep(100); + } + + InvokeUI(() => + { + MainWindow.Instance.ContentRendered += (_, __) => + { + TangoIOC.Default.GetAllInstancesByBase().ToList().ForEach(x => x.OnApplicationStarted()); + }; + }); + }); } /// @@ -229,6 +245,11 @@ namespace Tango.MachineStudio.UI.StudioApplication } } + /// + /// Notify the application manager about an external opened window. + /// When application exists. All registered windows will be closed. + /// + /// The window. public void RegisterOpenedWindow(Window window) { _openedWindows.Add(window); diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/SystemInformationModel.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/SystemInformationModel.cs index eb9ef8012..5dde73744 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/SystemInformationModel.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/SystemInformationModel.cs @@ -15,5 +15,7 @@ namespace Tango.MachineStudio.UI.TFS public String HostName { get; set; } public Machine Machine { get; set; } public String ConfigurationString { get; set; } + public String LoadedHardwareConfigurationString { get; set; } + public String LoadedProcessParametersString { get; set; } } } diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/SystemInformationTemplate.cshtml b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/SystemInformationTemplate.cshtml index 7b0c4a896..54db28e32 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/SystemInformationTemplate.cshtml +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/SystemInformationTemplate.cshtml @@ -60,11 +60,32 @@ -
Configuration
+
Machine Configuration
@vm.ConfigurationString
+ +
Hardware Configuration
+ if (vm.LoadedHardwareConfigurationString != null) + { +
@vm.LoadedHardwareConfigurationString
+ } + else + { +
NOT SET
+ } + +
Process Parameters
+ + if (vm.LoadedProcessParametersString != null) + { +
@vm.LoadedProcessParametersString
+ } + else + { +
NOT SET
+ } } else { -
Not Connected
+
NOT CONNECTED
} \ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/TeamFoundationServiceExtendedClient.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/TeamFoundationServiceExtendedClient.cs index 27b257e61..79572eb71 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/TeamFoundationServiceExtendedClient.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/TeamFoundationServiceExtendedClient.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using System.Windows; using Tango.BL.Entities; @@ -21,6 +23,13 @@ namespace Tango.MachineStudio.UI.TFS { public Project Project { get; private set; } + private ObservableCollection _resolvedWorkItems; + public ObservableCollection ResolvedWorkItems + { + get { return _resolvedWorkItems; } + set { _resolvedWorkItems = value; RaisePropertyChangedAuto(); } + } + private bool _isInitialized; public bool IsInitialized { @@ -30,7 +39,20 @@ namespace Tango.MachineStudio.UI.TFS public TeamFoundationServiceExtendedClient(string collectionURL, string userName, string personalToken) : base(collectionURL, userName, personalToken) { + ResolvedWorkItems = new ObservableCollection(); + TangoIOC.Default.GetInstance().CurrentUserChanged += TeamFoundationServiceExtendedClient_CurrentUserChanged; + } + private void TeamFoundationServiceExtendedClient_CurrentUserChanged(object sender, User user) + { + if (user != null) + { + Task.Factory.StartNew(async () => + { + Thread.Sleep(5000); + await UpdateCurrentUserResolvedWorkItems(); + }); + } } public Task UploadWorkItem(WorkItem workItem) @@ -38,14 +60,53 @@ namespace Tango.MachineStudio.UI.TFS return UploadWorkItem(Project, workItem); } + public async Task UpdateCurrentUserResolvedWorkItems() + { + try + { + IStudioApplicationManager app = TangoIOC.Default.GetInstance(); + var items = await GetWorkItemsCreatedBy(Project, GetUserTeamMember()); + items.Where(x => x.StepsToReproduce != null).ToList().ForEach(x => x.StepsToReproduce = x.StepsToReproduce.Replace("
", "").Replace("
", "")); + ResolvedWorkItems = items.Where(x => x.State == State.Resolved && x.ResolvedReason == ResolvedReason.Fixed && x.IsBuildVersionValid && x.FoundInBuildVersion < Version.Parse(app.Version)).ToObservableCollection(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error getting the current user resolved work items."); + } + } + + public async Task CloseWorkItem(WorkItem workItem) + { + await SetWorkItemState(Project, workItem, State.Closed); + var updated = await AddWorkItemComment(Project, workItem, GetUserTeamMember(), "Bug has been verified and closed by " + GetUserTeamMember().DisplayName + " (via Tango Software)."); + ResolvedWorkItems.Remove(workItem); + return updated; + } + + public async Task ReactivateWorkItem(WorkItem workItem) + { + await SetWorkItemState(Project, workItem, State.New); + var updated = await AddWorkItemComment(Project, workItem, GetUserTeamMember(), "Bug has been reactivated by " + GetUserTeamMember().DisplayName + " (via Tango Software)."); + updated = await SetWorkItemAssignment(Project, updated, workItem.ResolvedBy); + ResolvedWorkItems.Remove(workItem); + return updated; + } + public void Initialize() { Task.Factory.StartNew(() => { if (!IsInitialized) { - Project = GetProject("Tango").Result; - IsInitialized = true; + try + { + Project = GetProject("Tango").Result; + IsInitialized = true; + } + catch (Exception ex) + { + LogManager.Log(ex, "Error initializing the Team Foundation Service client."); + } } }); } @@ -60,7 +121,7 @@ namespace Tango.MachineStudio.UI.TFS item.Area = Project.Areas.FirstOrDefault(); item.Iteration = Project.Iterations.FirstOrDefault(); - TeamMember currentUser = Project.Members.SingleOrDefault(x => x.UniqueName.ToLower().Contains(auth.CurrentUser.Email.ToLower())); + TeamMember currentUser = GetUserTeamMember(); item.CreatedBy = currentUser; item.ChangedBy = currentUser; item.AuthorizedAs = currentUser; @@ -82,6 +143,14 @@ namespace Tango.MachineStudio.UI.TFS Name = "Screen Capture.jpg", }); + return item; + } + + public void FinalizeBug(WorkItem item) + { + IAuthenticationProvider auth = TangoIOC.Default.GetInstance(); + IStudioApplicationManager app = TangoIOC.Default.GetInstance(); + FileLogger appFileLogger = LogManager.Default.RegisteredLoggers.FirstOrDefault(x => x.GetType() == typeof(FileLogger)) as FileLogger; FileLogger embeddedFileLogger = MachineOperator.EmbeddedLogManager.RegisteredLoggers.FirstOrDefault(x => x.GetType() == typeof(FileLogger)) as FileLogger; @@ -113,7 +182,7 @@ namespace Tango.MachineStudio.UI.TFS SystemInformationModel sysModel = new SystemInformationModel(); sysModel.ApplicationVersion = app.Version; - sysModel.EmbeddedVersion = "Fake Version"; + sysModel.EmbeddedVersion = "N/A"; sysModel.HostName = Environment.MachineName; sysModel.UserName = auth.CurrentUser.Contact.FullName; @@ -122,17 +191,18 @@ namespace Tango.MachineStudio.UI.TFS Machine machine = app.ConnectedMachine.Machine; sysModel.Machine = machine; + sysModel.EmbeddedVersion = app.ConnectedMachine.DeviceInformation.Version; MachineDesigner.Views.MainView machineView = new MachineDesigner.Views.MainView(); machineView.Width = 1280; machineView.Height = 1100; - machineView.PanelColumnDefinition.Width = new System.Windows.GridLength(0); + machineView.PanelColumnDefinition.Width = new GridLength(0); machineView.stackHeader.Visibility = Visibility.Collapsed; machineView.Background = System.Windows.Media.Brushes.White; machineView.DataContext = new MachineDesigner.ViewModels.MainViewVM() { SelectedMachine = machine, Configuration = machine.Configuration }; String configImageFile = PathHelper.GetTempFilePath(); - machineView.RenderToFile(configImageFile, System.Drawing.Imaging.ImageFormat.Jpeg, new System.Windows.Size(machineView.Width, machineView.Height), 100); + machineView.RenderToFile(configImageFile, System.Drawing.Imaging.ImageFormat.Jpeg, new Size(machineView.Width, machineView.Height), 100); item.Attachments.Add(new Attachment() { @@ -141,7 +211,17 @@ namespace Tango.MachineStudio.UI.TFS Name = "Machine Configuration.jpg" }); - sysModel.ConfigurationString = machine.Configuration.CloneConfiguration().ToJsonString(); + sysModel.ConfigurationString = machine.Configuration.CloneConfiguration().ToJsonString(nameof(Configuration.MachinesConfigurations), nameof(Configuration.MachineVersions)); + + if (app.ConnectedMachine.CurrentProcessParameters != null) + { + sysModel.LoadedProcessParametersString = app.ConnectedMachine.CurrentProcessParameters.ToJsonString(nameof(ProcessParametersTable.ProcessParametersTablesGroup)); + } + + if (app.ConnectedMachine.CurrentHardwareConfiguration != null) + { + sysModel.LoadedHardwareConfigurationString = app.ConnectedMachine.CurrentHardwareConfiguration.ToJsonString(); + } } String html = String.Empty; @@ -154,7 +234,14 @@ namespace Tango.MachineStudio.UI.TFS item.SystemInformation = CodeGeneration.Helper.Parse(html, sysModel); - return item; + item.StepsToReproduce = String.Format("
{0}
", item.StepsToReproduce); + } + + private TeamMember GetUserTeamMember() + { + IAuthenticationProvider auth = TangoIOC.Default.GetInstance(); + TeamMember currentUser = Project.Members.SingleOrDefault(x => x.UniqueName.ToLower().Contains(auth.CurrentUser.Email.ToLower())); + return currentUser; } } } diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/WorkItemValidationAttribute.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/WorkItemValidationAttribute.cs index 1418d0576..3e85f91b4 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/WorkItemValidationAttribute.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/TFS/WorkItemValidationAttribute.cs @@ -16,13 +16,19 @@ namespace Tango.MachineStudio.UI.TFS if (String.IsNullOrWhiteSpace(item.Title)) { - ErrorMessage = "Title is empty"; + ErrorMessage = "Title is required."; return false; } if (item.AssignedTo == null) { - ErrorMessage = "Assigned To is empty"; + ErrorMessage = "Assigned To field is required."; + return false; + } + + if (String.IsNullOrWhiteSpace(item.StepsToReproduce)) + { + ErrorMessage = "Please enter steps to reproduce."; return false; } diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Tango.MachineStudio.UI.csproj b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Tango.MachineStudio.UI.csproj index 8ab6bb188..5d685c112 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Tango.MachineStudio.UI.csproj +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Tango.MachineStudio.UI.csproj @@ -131,6 +131,13 @@ MSBuild:Compile Designer + + + + + ConsoleWindow.xaml + + HtmlWindow.xaml @@ -161,6 +168,7 @@ + @@ -190,6 +198,9 @@ ReportIssueView.xaml + + ResolvedIssuesView.xaml + ShutdownView.xaml @@ -203,6 +214,10 @@ ModuleWindow.xaml + + Designer + MSBuild:Compile + MSBuild:Compile Designer @@ -270,6 +285,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -355,6 +374,10 @@ {e4927038-348d-4295-aaf4-861c58cb3943} Tango.PMR + + {401989E7-AE1E-4002-B0EE-9A9F63740B97} + Tango.Scripting + {d8f1ad85-526a-4f50-b6dc-d437af63d8d8} Tango.Settings @@ -460,6 +483,7 @@ + diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs index 8e6f11452..931130a05 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModelLocator.cs @@ -13,6 +13,7 @@ using Tango.MachineStudio.Common.Speech; using Tango.MachineStudio.Common.StudioApplication; using Tango.MachineStudio.Common.Video; using Tango.MachineStudio.UI.Authentication; +using Tango.MachineStudio.UI.Console; using Tango.MachineStudio.UI.Html; using Tango.MachineStudio.UI.Modules; using Tango.MachineStudio.UI.Navigation; @@ -64,7 +65,6 @@ namespace Tango.MachineStudio.UI TangoIOC.Default.Unregister(); TangoIOC.Default.Unregister(); - TangoIOC.Default.Register(new TeamFoundationServiceExtendedClient("https://twinetfs.visualstudio.com/DefaultCollection", "Roy", "szzfokrceo4rhd4eqi5qpmxn3pa5iwl3q7tlqd36l2m7smz2ynoa")); TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); @@ -76,6 +76,7 @@ namespace Tango.MachineStudio.UI TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); + TangoIOC.Default.Register(new TeamFoundationServiceExtendedClient("https://twinetfs.visualstudio.com", String.Empty, "szzfokrceo4rhd4eqi5qpmxn3pa5iwl3q7tlqd36l2m7smz2ynoa")); TangoIOC.Default.Register(); TangoIOC.Default.Register(); @@ -85,6 +86,7 @@ namespace Tango.MachineStudio.UI TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); + TangoIOC.Default.Register(); //Register View (Supervising Controller Pattern). //if (!ViewModelBase.IsInDesignModeStatic) @@ -157,5 +159,13 @@ namespace Tango.MachineStudio.UI return TangoIOC.Default.GetInstance(); } } + + public ConsoleWindowVM ConsoleWindowVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } } } \ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/LoadingViewVM.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/LoadingViewVM.cs index 2b2b442f7..29f9102ac 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/LoadingViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/LoadingViewVM.cs @@ -16,6 +16,7 @@ using Tango.BL; using Tango.MachineStudio.Common.EventLogging; using Tango.BL.Enumerations; using Tango.MachineStudio.UI.TFS; +using Tango.MachineStudio.Common; namespace Tango.MachineStudio.UI.ViewModels { @@ -23,7 +24,7 @@ namespace Tango.MachineStudio.UI.ViewModels /// Represents the Machine Studio loading view, view model. ///
/// - public class LoadingViewVM : ViewModel + public class LoadingViewVM : StudioViewModelInternal { private INotificationProvider _notificationProvider; private TeamFoundationServiceExtendedClient _tfs; @@ -55,6 +56,11 @@ namespace Tango.MachineStudio.UI.ViewModels _navigationManager = navigationManager; _studioModuleLoader = studioModuleLoader; _notificationProvider = notificationProvider; + } + + public override void OnApplicationStarted() + { + base.OnApplicationStarted(); Load(); } diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/MainViewVM.cs index 0882267e8..04b973f23 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/MainViewVM.cs @@ -148,6 +148,16 @@ namespace Tango.MachineStudio.UI.ViewModels /// public RelayCommand ReportIssueCommand { get; set; } + /// + /// Gets or sets the open resolved bugs. + /// + public RelayCommand OpenResolvedBugsCommand { get; set; } + + /// + /// Gets or sets the open developer console command. + /// + public RelayCommand OpenDeveloperConsoleCommand { get; set; } + private IAuthenticationProvider _authenticationProvider; /// /// Gets or sets the authentication provider. @@ -302,6 +312,8 @@ namespace Tango.MachineStudio.UI.ViewModels ResolveMachineEventCommand = new RelayCommand(ResolveMachineEvent); ReportIssueCommand = new RelayCommand(ReportIssue); + OpenResolvedBugsCommand = new RelayCommand(OpenResolvedBugs); + OpenDeveloperConsoleCommand = new RelayCommand(OpenDeveloperConsole); } private void MachineEventsStateProvider_EventsResolved(object sender, IEnumerable e) @@ -321,7 +333,7 @@ namespace Tango.MachineStudio.UI.ViewModels { while (!DisableCheckForUpdates) { - Thread.Sleep(TimeSpan.FromMinutes(1)); + Thread.Sleep(TimeSpan.FromMinutes(0.2)); try { @@ -649,10 +661,78 @@ namespace Tango.MachineStudio.UI.ViewModels { using (_notificationProvider.PushTaskItem("Uploading bug report...")) { - await TFSClient.UploadWorkItem(vm.WorkItem); + try + { + TFSClient.FinalizeBug(vm.WorkItem); + await TFSClient.UploadWorkItem(vm.WorkItem); + } + catch (Exception ex) + { + _notificationProvider.ShowError("An error occurred while trying to create the issue." + Environment.NewLine + ex.Message); + } } }, null); } + + private void OpenResolvedBugs() + { + ResolvedIssuesViewVM vm = null; + + vm = new ResolvedIssuesViewVM(TFSClient, async (item) => + { + //Approve + using (_notificationProvider.PushTaskItem("Approving issue...")) + { + vm.IsAvailable = false; + try + { + await TFSClient.CloseWorkItem(item); + } + catch (Exception ex) + { + _notificationProvider.ShowError("An error occurred while trying to update the issue." + Environment.NewLine + ex.Message); + } + vm.IsAvailable = true; + + if (TFSClient.ResolvedWorkItems.Count == 0) + { + vm.Close(); + } + } + }, async (item) => + { + //Decline + using (_notificationProvider.PushTaskItem("Reactivating issue...")) + { + vm.IsAvailable = false; + try + { + await TFSClient.ReactivateWorkItem(item); + } + catch (Exception ex) + { + _notificationProvider.ShowError("An error occurred while trying to update the issue." + Environment.NewLine + ex.Message); + } + + vm.IsAvailable = true; + + if (TFSClient.ResolvedWorkItems.Count == 0) + { + vm.Close(); + } + } + }); + + _notificationProvider.ShowModalDialog(vm, (_) => { }, null); + } + + private void OpenDeveloperConsole() + { + Console.ConsoleWindow console = new Console.ConsoleWindow(); + ApplicationManager.RegisterOpenedWindow(console); + console.Owner = MainWindow.Instance; + console.Show(); + } } } diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/ResolvedIssuesViewVM.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/ResolvedIssuesViewVM.cs new file mode 100644 index 000000000..552880792 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/ResolvedIssuesViewVM.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core.Commands; +using Tango.MachineStudio.Common.Notifications; +using Tango.MachineStudio.UI.TFS; +using Tango.TFS; + +namespace Tango.MachineStudio.UI.ViewModels +{ + public class ResolvedIssuesViewVM : DialogViewVM + { + private Action _onApprove; + private Action _onDecline; + + public TeamFoundationServiceExtendedClient TFSClient { get; set; } + + public RelayCommand ApproveCommand { get; set; } + + public RelayCommand DeclineCommand { get; set; } + + private bool _isAvailable; + + public bool IsAvailable + { + get { return _isAvailable; } + set { _isAvailable = value; RaisePropertyChangedAuto(); } + } + + public ResolvedIssuesViewVM() : base() + { + IsAvailable = true; + ApproveCommand = new RelayCommand(ApproveIssue); + DeclineCommand = new RelayCommand(DeclineIssue); + } + + public ResolvedIssuesViewVM(TeamFoundationServiceExtendedClient tfsClient, Action onApprove, Action onDecline) : this() + { + TFSClient = tfsClient; + _onApprove = onApprove; + _onDecline = onDecline; + } + + private void DeclineIssue(WorkItem workItem) + { + _onDecline(workItem); + } + + private void ApproveIssue(WorkItem workItem) + { + _onApprove(workItem); + } + + public void Close() + { + Accept(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/MainView.xaml b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/MainView.xaml index 86723479b..8417c70c8 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/MainView.xaml +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/MainView.xaml @@ -10,9 +10,11 @@ xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:entities="clr-namespace:Tango.BL.Entities;assembly=Tango.BL" + xmlns:enumerations="clr-namespace:Tango.BL.Enumerations;assembly=Tango.BL" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:db="clr-namespace:Tango.MachineStudio.DB.Views;assembly=Tango.MachineStudio.DB" xmlns:local="clr-namespace:Tango.MachineStudio.UI.Views" + xmlns:commonConverters="clr-namespace:Tango.MachineStudio.Common.Converters;assembly=Tango.MachineStudio.Common" mc:Ignorable="d" d:DesignHeight="720" d:DesignWidth="1270" Background="Transparent" DataContext="{Binding MainViewVM, Source={StaticResource Locator}}"> @@ -22,6 +24,7 @@ + @@ -189,7 +192,16 @@ Speech - + + + + + diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/ReportIssueView.xaml b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/ReportIssueView.xaml index f2e3038b9..37cd0b793 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/ReportIssueView.xaml +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/ReportIssueView.xaml @@ -12,7 +12,7 @@ xmlns:tfs="clr-namespace:Tango.TFS;assembly=Tango.TFS" xmlns:tfss="clr-namespace:Tango.MachineStudio.UI.TFS" xmlns:local="clr-namespace:Tango.MachineStudio.UI.Views" - mc:Ignorable="d" Width="530" Height="650" Background="White" d:DataContext="{d:DesignInstance Type=vm:ReportIssueViewVM, IsDesignTimeCreatable=False}"> + mc:Ignorable="d" Width="530" Height="680" Background="White" d:DataContext="{d:DesignInstance Type=vm:ReportIssueViewVM, IsDesignTimeCreatable=False}"> @@ -36,53 +36,85 @@ - - + + + + + + - - - + + + + - Tags - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + Tags (highlight selected tags) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Steps To Reproduce + + + + + + + + - + - * + * diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/ResolvedIssuesView.xaml b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/ResolvedIssuesView.xaml new file mode 100644 index 000000000..4fb457f87 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/ResolvedIssuesView.xaml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + Resolved Issues + + + + Below you can find issues reported by you that have been flagged as resolved by the development team. + Please verify each one and report back by pressing 'FIXED' or 'NOT FIXED'. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Steps To Reproduce + + + + + + + + + + + diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/ResolvedIssuesView.xaml.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/ResolvedIssuesView.xaml.cs new file mode 100644 index 000000000..7825bf587 --- /dev/null +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/ResolvedIssuesView.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.MachineStudio.UI.Views +{ + /// + /// Interaction logic for ResolvedBugsView.xaml + /// + public partial class ResolvedIssuesView : UserControl + { + public ResolvedIssuesView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Windows/ExceptionResolutions.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Windows/ExceptionResolutions.cs index 2e7327559..e27a84c3b 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Windows/ExceptionResolutions.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Windows/ExceptionResolutions.cs @@ -10,6 +10,7 @@ namespace Tango.MachineStudio.UI.Windows { Shutdown, Restart, - Ignore + Ignore, + Report } } diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Windows/ExceptionWindow.xaml b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Windows/ExceptionWindow.xaml index 892e4944f..147b40892 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Windows/ExceptionWindow.xaml +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Windows/ExceptionWindow.xaml @@ -5,7 +5,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Tango.MachineStudio.UI.Windows" mc:Ignorable="d" - WindowStyle="None" ResizeMode="NoResize" Topmost="True" AllowsTransparency="True" WindowStartupLocation="CenterScreen" d:DesignHeight="300" d:DesignWidth="300" Width="610" Height="410" Background="Transparent" d:DataContext="{d:DesignInstance Type=local:ExceptionWindow, IsDesignTimeCreatable=False}"> + WindowStyle="None" ResizeMode="NoResize" Topmost="True" AllowsTransparency="True" WindowStartupLocation="CenterScreen" Width="800" Height="600" Background="Transparent" d:DataContext="{d:DesignInstance Type=local:ExceptionWindow, IsDesignTimeCreatable=False}"> @@ -48,8 +48,16 @@ - + + + + diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Windows/ExceptionWindow.xaml.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Windows/ExceptionWindow.xaml.cs index 0f74fee17..0a6f2de39 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Windows/ExceptionWindow.xaml.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Windows/ExceptionWindow.xaml.cs @@ -33,10 +33,15 @@ namespace Tango.MachineStudio.UI.Windows DataContext = this; } - public ExceptionWindow(Exception ex) : this() + public ExceptionWindow(Exception ex, bool canReport) : this() { Exception = ex.FlattenException(); ResolveCommand = new RelayCommand(Resolve); + + if (!canReport) + { + btnReport.Visibility = Visibility.Collapsed; + } } private void Resolve(ExceptionResolutions resolution) diff --git a/Software/Visual_Studio/Tango.BL/Enumerations/Permissions.cs b/Software/Visual_Studio/Tango.BL/Enumerations/Permissions.cs index ee77c6f0f..a727bf5e8 100644 --- a/Software/Visual_Studio/Tango.BL/Enumerations/Permissions.cs +++ b/Software/Visual_Studio/Tango.BL/Enumerations/Permissions.cs @@ -75,5 +75,11 @@ namespace Tango.BL.Enumerations [Description("Allows loading the Users & Roles module in machine studio")] RunUsersAndRolesModule = 10, + /// + /// (Allows openning the machine studio developer console) + /// + [Description("Allows openning the machine studio developer console")] + RunDeveloperConsole = 11, + } } diff --git a/Software/Visual_Studio/Tango.CodeGeneration/CustomResolver.cs b/Software/Visual_Studio/Tango.CodeGeneration/CustomResolver.cs new file mode 100644 index 000000000..ee1acccae --- /dev/null +++ b/Software/Visual_Studio/Tango.CodeGeneration/CustomResolver.cs @@ -0,0 +1,20 @@ +using RazorEngine.Compilation; +using RazorEngine.Compilation.ReferenceResolver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.CodeGeneration +{ + internal class CustomResolver : IReferenceResolver + { + public IEnumerable GetReferences(TypeContext context, IEnumerable includeAssemblies) + { + return new UseCurrentAssembliesReferenceResolver() + .GetReferences(context, includeAssemblies) + .Where(f => !f.GetFile().EndsWith(".winmd")); + } + } +} diff --git a/Software/Visual_Studio/Tango.CodeGeneration/Helper.cs b/Software/Visual_Studio/Tango.CodeGeneration/Helper.cs index dfbc893ee..af617fe3e 100644 --- a/Software/Visual_Studio/Tango.CodeGeneration/Helper.cs +++ b/Software/Visual_Studio/Tango.CodeGeneration/Helper.cs @@ -1,4 +1,5 @@ using RazorEngine; +using RazorEngine.Configuration; using RazorEngine.Templating; using System; using System.Collections.Generic; @@ -15,6 +16,12 @@ namespace Tango.CodeGeneration /// public static class Helper { + static Helper() + { + var config = new TemplateServiceConfiguration { Debug = true, ReferenceResolver = new CustomResolver() }; + Engine.Razor = RazorEngineService.Create(config); + } + /// /// Gets a code template by the code object type. /// diff --git a/Software/Visual_Studio/Tango.CodeGeneration/Tango.CodeGeneration.csproj b/Software/Visual_Studio/Tango.CodeGeneration/Tango.CodeGeneration.csproj index db77d9f20..ff83f8ce4 100644 --- a/Software/Visual_Studio/Tango.CodeGeneration/Tango.CodeGeneration.csproj +++ b/Software/Visual_Studio/Tango.CodeGeneration/Tango.CodeGeneration.csproj @@ -63,6 +63,7 @@ + diff --git a/Software/Visual_Studio/Tango.Core/ExtensionMethods/ObjectExtensions.cs b/Software/Visual_Studio/Tango.Core/ExtensionMethods/ObjectExtensions.cs index 87f410542..9d17bd198 100644 --- a/Software/Visual_Studio/Tango.Core/ExtensionMethods/ObjectExtensions.cs +++ b/Software/Visual_Studio/Tango.Core/ExtensionMethods/ObjectExtensions.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; +using Tango.Core.Json; using Tango.Serialization; /// @@ -93,4 +94,28 @@ public static class ObjectExtensions return JsonConvert.SerializeObject(obj, Formatting.Indented); } + + /// + /// Serializes the specified object to indented json string. + /// + /// The object. + /// + public static String ToJsonString(this Object obj, params String[] ignoreProperties) + { + var settings = new JsonSerializerSettings() { ContractResolver = new DynamicContractResolver(ignoreProperties) }; + settings.Converters.Add(new StringEnumConverter { CamelCaseText = false }); + return JsonConvert.SerializeObject(obj, Formatting.Indented, settings); + } + + /// + /// Serializes the specified object to indented json html string. + /// + /// The object. + /// + public static String ToHtmlJsonString(this Object obj, params String[] ignoreProperties) + { + var settings = new JsonSerializerSettings() { ContractResolver = new HtmlContractResolver(ignoreProperties) }; + settings.Converters.Add(new StringEnumConverter { CamelCaseText = false }); + return JsonConvert.SerializeObject(obj, Formatting.Indented, settings); + } } diff --git a/Software/Visual_Studio/Tango.Core/Helpers/EmbeddedResourceHelper.cs b/Software/Visual_Studio/Tango.Core/Helpers/EmbeddedResourceHelper.cs index d1d556296..bdf2cb684 100644 --- a/Software/Visual_Studio/Tango.Core/Helpers/EmbeddedResourceHelper.cs +++ b/Software/Visual_Studio/Tango.Core/Helpers/EmbeddedResourceHelper.cs @@ -15,5 +15,15 @@ namespace Tango.Core.Helpers Assembly asm = Assembly.GetCallingAssembly(); return asm.GetManifestResourceStream(relativePath); } + + public static String GetEmbeddedResourceText(String relativePath) + { + Assembly asm = Assembly.GetCallingAssembly(); + using (Stream st = asm.GetManifestResourceStream(relativePath)) + { + StreamReader reader = new StreamReader(st); + return reader.ReadToEnd(); + } + } } } diff --git a/Software/Visual_Studio/Tango.Core/Json/DynamicContractResolver.cs b/Software/Visual_Studio/Tango.Core/Json/DynamicContractResolver.cs new file mode 100644 index 000000000..293b6947f --- /dev/null +++ b/Software/Visual_Studio/Tango.Core/Json/DynamicContractResolver.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json.Serialization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using System.Reflection; + +namespace Tango.Core.Json +{ + public class DynamicContractResolver : DefaultContractResolver + { + private List _ignoreProperties; + + public DynamicContractResolver(params String[] ignoreProperties) + { + _ignoreProperties = ignoreProperties.ToList(); + } + + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + JsonProperty property = base.CreateProperty(member, memberSerialization); + + property.ShouldSerialize = (x) => !_ignoreProperties.Contains(property.PropertyName); + + return property; + } + } +} diff --git a/Software/Visual_Studio/Tango.Core/Json/HtmlContractResolver.cs b/Software/Visual_Studio/Tango.Core/Json/HtmlContractResolver.cs new file mode 100644 index 000000000..c4affd3ad --- /dev/null +++ b/Software/Visual_Studio/Tango.Core/Json/HtmlContractResolver.cs @@ -0,0 +1,39 @@ +using Newtonsoft.Json.Serialization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using System.Reflection; + +namespace Tango.Core.Json +{ + public class HtmlContractResolver : DefaultContractResolver + { + private List _ignoreProperties; + + public HtmlContractResolver(params String[] ignoreProperties) + { + if (ignoreProperties != null) + { + _ignoreProperties = ignoreProperties.ToList(); + } + else + { + _ignoreProperties = new List(); + } + } + + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + JsonProperty property = base.CreateProperty(member, memberSerialization); + + property.ShouldSerialize = (x) => !_ignoreProperties.Contains(property.PropertyName); + + property.PropertyName = "" + property.PropertyName.Replace("\"", "") + ""; + + return property; + } + } +} diff --git a/Software/Visual_Studio/Tango.Core/Tango.Core.csproj b/Software/Visual_Studio/Tango.Core/Tango.Core.csproj index a9196237b..648137190 100644 --- a/Software/Visual_Studio/Tango.Core/Tango.Core.csproj +++ b/Software/Visual_Studio/Tango.Core/Tango.Core.csproj @@ -91,6 +91,8 @@ + + diff --git a/Software/Visual_Studio/Tango.Emulations/Emulators/MachineEmulator.cs b/Software/Visual_Studio/Tango.Emulations/Emulators/MachineEmulator.cs index a2c53f7b3..0b7ddc9ef 100644 --- a/Software/Visual_Studio/Tango.Emulations/Emulators/MachineEmulator.cs +++ b/Software/Visual_Studio/Tango.Emulations/Emulators/MachineEmulator.cs @@ -301,10 +301,6 @@ namespace Tango.Emulations.Emulators res.Events.AddRange(EventsStates.Where(x => x.IsActive).Select(x => new Event() { Type = x.EventType, Message = "Generated by Tango Embedded Emulator" })); - res.Version = "1.0.0.0"; - res.VersionBuildDate = DateTime.Now.ToString(); - res.VersionName = "Embedded Emulator"; - Transporter.SendResponse(res, request.Container.Token); Thread.Sleep(10); } @@ -648,7 +644,15 @@ namespace Tango.Emulations.Emulators _continousResponseTokens.Clear(); - Transporter.SendResponse(new ConnectResponse(), request.Container.Token, null, request.Message.Password == "1234" ? ErrorCode.None : ErrorCode.UnauthorizedConnection); + Transporter.SendResponse(new ConnectResponse() + { + DeviceInformation = new DeviceInformation() + { + Version = "1.0.0.0", + BuildDate = DateTime.Now.ToString(), + Name = "Machine Emulator", + }, + }, request.Container.Token, null, request.Message.Password == "1234" ? ErrorCode.None : ErrorCode.UnauthorizedConnection); } #endregion diff --git a/Software/Visual_Studio/Tango.Integration/Operation/IMachineOperator.cs b/Software/Visual_Studio/Tango.Integration/Operation/IMachineOperator.cs index 861935e83..efe4fe7af 100644 --- a/Software/Visual_Studio/Tango.Integration/Operation/IMachineOperator.cs +++ b/Software/Visual_Studio/Tango.Integration/Operation/IMachineOperator.cs @@ -63,6 +63,21 @@ namespace Tango.Integration.Operation /// bool EnableEmbeddedDebugging { get; set; } + /// + /// Gets the last process parameters table sent to the embedded device. + /// + ProcessParametersTable CurrentProcessParameters { get; } + + /// + /// Gets the last hardware configuration sent to the embedded device. + /// + HardwareConfiguration CurrentHardwareConfiguration { get; } + + /// + /// Gets or sets the embedded device information. + /// + DeviceInformation DeviceInformation { get; } + /// /// Gets or sets the machine events state provider used to get notifications about current machine events and errors. /// diff --git a/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs b/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs index f7b447843..118bbc38a 100644 --- a/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs +++ b/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs @@ -49,6 +49,7 @@ namespace Tango.Integration.Operation public MachineOperator() : base() { + DeviceInformation = new DeviceInformation(); MachineEventsStateProvider = new DefaultMachineEventsStateProvider(); EnableEmbeddedDebugging = true; LogEmbeddedDebuggingToFile = true; @@ -154,6 +155,27 @@ namespace Tango.Integration.Operation /// public IMachineEventsStateProvider MachineEventsStateProvider { get; set; } + /// + /// Gets the last process parameters table sent to the embedded device. + /// + public ProcessParametersTable CurrentProcessParameters { get; private set; } + + /// + /// Gets the last hardware configuration sent to the embedded device. + /// + public HardwareConfiguration CurrentHardwareConfiguration { get; private set; } + + private DeviceInformation _deviceInformation; + /// + /// Gets or sets the embedded device information. + /// + public DeviceInformation DeviceInformation + { + get { return _deviceInformation; } + set { _deviceInformation = value; RaisePropertyChangedAuto(); } + } + + #endregion #region Virtual Methods @@ -367,6 +389,8 @@ namespace Tango.Integration.Operation var response = await SendRequest(request); LogResponseReceived(response.Message); + DeviceInformation = response.Message.DeviceInformation; + OnEnableDiagnosticsChanged(EnableDiagnostics); OnEnableEmbeddedDebuggingChanged(EnableEmbeddedDebugging); } @@ -391,6 +415,8 @@ namespace Tango.Integration.Operation /// public JobHandler Print(Job job, ProcessParametersTable processParameters) { + CurrentProcessParameters = processParameters; + JobRequest request = new JobRequest(); JobTicket ticket = new JobTicket(); @@ -508,6 +534,7 @@ namespace Tango.Integration.Operation try { + CurrentProcessParameters = processParameters; LogRequestSent(request); response = await SendRequest(request); LogResponseReceived(response); @@ -530,8 +557,23 @@ namespace Tango.Integration.Operation { UploadHardwareConfigurationRequest request = new UploadHardwareConfigurationRequest(); request.HardwareConfiguration = hardwareConfiguration; - LogRequestSent(request); - return await SendRequest(request); + + UploadHardwareConfigurationResponse response = null; + + try + { + CurrentHardwareConfiguration = hardwareConfiguration; + LogRequestSent(request); + response = await SendRequest(request); + LogResponseReceived(response); + } + catch (Exception ex) + { + LogRequestFailed(request, ex); + throw ex; + } + + return response; } /// diff --git a/Software/Visual_Studio/Tango.PMR/Connection/ConnectResponse.cs b/Software/Visual_Studio/Tango.PMR/Connection/ConnectResponse.cs index 1e5562f11..3ff3c91c1 100644 --- a/Software/Visual_Studio/Tango.PMR/Connection/ConnectResponse.cs +++ b/Software/Visual_Studio/Tango.PMR/Connection/ConnectResponse.cs @@ -23,12 +23,14 @@ namespace Tango.PMR.Connection { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "ChVDb25uZWN0UmVzcG9uc2UucHJvdG8SFFRhbmdvLlBNUi5Db25uZWN0aW9u", - "IhEKD0Nvbm5lY3RSZXNwb25zZUIgCh5jb20udHdpbmUudGFuZ28ucG1yLmNv", - "bm5lY3Rpb25iBnByb3RvMw==")); + "GhdEZXZpY2VJbmZvcm1hdGlvbi5wcm90byJVCg9Db25uZWN0UmVzcG9uc2US", + "QgoRRGV2aWNlSW5mb3JtYXRpb24YASABKAsyJy5UYW5nby5QTVIuQ29ubmVj", + "dGlvbi5EZXZpY2VJbmZvcm1hdGlvbkIgCh5jb20udHdpbmUudGFuZ28ucG1y", + "LmNvbm5lY3Rpb25iBnByb3RvMw==")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, - new pbr::FileDescriptor[] { }, + new pbr::FileDescriptor[] { global::Tango.PMR.Connection.DeviceInformationReflection.Descriptor, }, new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { - new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Connection.ConnectResponse), global::Tango.PMR.Connection.ConnectResponse.Parser, null, null, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Connection.ConnectResponse), global::Tango.PMR.Connection.ConnectResponse.Parser, new[]{ "DeviceInformation" }, null, null, null) })); } #endregion @@ -59,6 +61,7 @@ namespace Tango.PMR.Connection { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ConnectResponse(ConnectResponse other) : this() { + DeviceInformation = other.deviceInformation_ != null ? other.DeviceInformation.Clone() : null; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] @@ -66,6 +69,17 @@ namespace Tango.PMR.Connection { return new ConnectResponse(this); } + /// Field number for the "DeviceInformation" field. + public const int DeviceInformationFieldNumber = 1; + private global::Tango.PMR.Connection.DeviceInformation deviceInformation_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Tango.PMR.Connection.DeviceInformation DeviceInformation { + get { return deviceInformation_; } + set { + deviceInformation_ = value; + } + } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ConnectResponse); @@ -79,12 +93,14 @@ namespace Tango.PMR.Connection { if (ReferenceEquals(other, this)) { return true; } + if (!object.Equals(DeviceInformation, other.DeviceInformation)) return false; return true; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; + if (deviceInformation_ != null) hash ^= DeviceInformation.GetHashCode(); return hash; } @@ -95,11 +111,18 @@ namespace Tango.PMR.Connection { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { + if (deviceInformation_ != null) { + output.WriteRawTag(10); + output.WriteMessage(DeviceInformation); + } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; + if (deviceInformation_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DeviceInformation); + } return size; } @@ -108,6 +131,12 @@ namespace Tango.PMR.Connection { if (other == null) { return; } + if (other.deviceInformation_ != null) { + if (deviceInformation_ == null) { + deviceInformation_ = new global::Tango.PMR.Connection.DeviceInformation(); + } + DeviceInformation.MergeFrom(other.DeviceInformation); + } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] @@ -118,6 +147,13 @@ namespace Tango.PMR.Connection { default: input.SkipLastField(); break; + case 10: { + if (deviceInformation_ == null) { + deviceInformation_ = new global::Tango.PMR.Connection.DeviceInformation(); + } + input.ReadMessage(deviceInformation_); + break; + } } } } diff --git a/Software/Visual_Studio/Tango.PMR/Connection/DeviceInformation.cs b/Software/Visual_Studio/Tango.PMR/Connection/DeviceInformation.cs new file mode 100644 index 000000000..0fec71b8b --- /dev/null +++ b/Software/Visual_Studio/Tango.PMR/Connection/DeviceInformation.cs @@ -0,0 +1,216 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: DeviceInformation.proto +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace Tango.PMR.Connection { + + /// Holder for reflection information generated from DeviceInformation.proto + public static partial class DeviceInformationReflection { + + #region Descriptor + /// File descriptor for DeviceInformation.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static DeviceInformationReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChdEZXZpY2VJbmZvcm1hdGlvbi5wcm90bxIUVGFuZ28uUE1SLkNvbm5lY3Rp", + "b24iRQoRRGV2aWNlSW5mb3JtYXRpb24SDAoETmFtZRgBIAEoCRIPCgdWZXJz", + "aW9uGAIgASgJEhEKCUJ1aWxkRGF0ZRgDIAEoCUIgCh5jb20udHdpbmUudGFu", + "Z28ucG1yLmNvbm5lY3Rpb25iBnByb3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Connection.DeviceInformation), global::Tango.PMR.Connection.DeviceInformation.Parser, new[]{ "Name", "Version", "BuildDate" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class DeviceInformation : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DeviceInformation()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::Tango.PMR.Connection.DeviceInformationReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeviceInformation() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeviceInformation(DeviceInformation other) : this() { + name_ = other.name_; + version_ = other.version_; + buildDate_ = other.buildDate_; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DeviceInformation Clone() { + return new DeviceInformation(this); + } + + /// Field number for the "Name" field. + public const int NameFieldNumber = 1; + private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "Version" field. + public const int VersionFieldNumber = 2; + private string version_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Version { + get { return version_; } + set { + version_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "BuildDate" field. + public const int BuildDateFieldNumber = 3; + private string buildDate_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string BuildDate { + get { return buildDate_; } + set { + buildDate_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DeviceInformation); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DeviceInformation other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Name != other.Name) return false; + if (Version != other.Version) return false; + if (BuildDate != other.BuildDate) return false; + return true; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (Version.Length != 0) hash ^= Version.GetHashCode(); + if (BuildDate.Length != 0) hash ^= BuildDate.GetHashCode(); + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Name.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Name); + } + if (Version.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Version); + } + if (BuildDate.Length != 0) { + output.WriteRawTag(26); + output.WriteString(BuildDate); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (Version.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Version); + } + if (BuildDate.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(BuildDate); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(DeviceInformation other) { + if (other == null) { + return; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + if (other.Version.Length != 0) { + Version = other.Version; + } + if (other.BuildDate.Length != 0) { + BuildDate = other.BuildDate; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + Name = input.ReadString(); + break; + } + case 18: { + Version = input.ReadString(); + break; + } + case 26: { + BuildDate = input.ReadString(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/Software/Visual_Studio/Tango.PMR/Diagnostics/PushDiagnosticsResponse.cs b/Software/Visual_Studio/Tango.PMR/Diagnostics/PushDiagnosticsResponse.cs index c266bb0a8..db4479cf6 100644 --- a/Software/Visual_Studio/Tango.PMR/Diagnostics/PushDiagnosticsResponse.cs +++ b/Software/Visual_Studio/Tango.PMR/Diagnostics/PushDiagnosticsResponse.cs @@ -25,19 +25,17 @@ namespace Tango.PMR.Diagnostics { "Ch1QdXNoRGlhZ25vc3RpY3NSZXNwb25zZS5wcm90bxIVVGFuZ28uUE1SLkRp", "YWdub3N0aWNzGhBEaWdpdGFsUGluLnByb3RvGhlWYWx1ZUNvbXBvbmVudFN0", "YXRlLnByb3RvGhlEaWFnbm9zdGljc01vbml0b3JzLnByb3RvGgtFdmVudC5w", - "cm90byLDAgoXUHVzaERpYWdub3N0aWNzUmVzcG9uc2USPAoITW9uaXRvcnMY", + "cm90byKDAgoXUHVzaERpYWdub3N0aWNzUmVzcG9uc2USPAoITW9uaXRvcnMY", "ASABKAsyKi5UYW5nby5QTVIuRGlhZ25vc3RpY3MuRGlhZ25vc3RpY3NNb25p", "dG9ycxI2CgtEaWdpdGFsUGlucxgCIAMoCzIhLlRhbmdvLlBNUi5EaWFnbm9z", "dGljcy5EaWdpdGFsUGluEkQKEENvbXBvbmVudHNTdGF0ZXMYAyADKAsyKi5U", "YW5nby5QTVIuRGlhZ25vc3RpY3MuVmFsdWVDb21wb25lbnRTdGF0ZRIsCgZF", - "dmVudHMYBCADKAsyHC5UYW5nby5QTVIuRGlhZ25vc3RpY3MuRXZlbnQSDwoH", - "VmVyc2lvbhgFIAEoCRITCgtWZXJzaW9uTmFtZRgGIAEoCRIYChBWZXJzaW9u", - "QnVpbGREYXRlGAcgASgJQiEKH2NvbS50d2luZS50YW5nby5wbXIuZGlhZ25v", - "c3RpY3NiBnByb3RvMw==")); + "dmVudHMYBCADKAsyHC5UYW5nby5QTVIuRGlhZ25vc3RpY3MuRXZlbnRCIQof", + "Y29tLnR3aW5lLnRhbmdvLnBtci5kaWFnbm9zdGljc2IGcHJvdG8z")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { global::Tango.PMR.Diagnostics.DigitalPinReflection.Descriptor, global::Tango.PMR.Diagnostics.ValueComponentStateReflection.Descriptor, global::Tango.PMR.Diagnostics.DiagnosticsMonitorsReflection.Descriptor, global::Tango.PMR.Diagnostics.EventReflection.Descriptor, }, new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { - new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Diagnostics.PushDiagnosticsResponse), global::Tango.PMR.Diagnostics.PushDiagnosticsResponse.Parser, new[]{ "Monitors", "DigitalPins", "ComponentsStates", "Events", "Version", "VersionName", "VersionBuildDate" }, null, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::Tango.PMR.Diagnostics.PushDiagnosticsResponse), global::Tango.PMR.Diagnostics.PushDiagnosticsResponse.Parser, new[]{ "Monitors", "DigitalPins", "ComponentsStates", "Events" }, null, null, null) })); } #endregion @@ -72,9 +70,6 @@ namespace Tango.PMR.Diagnostics { digitalPins_ = other.digitalPins_.Clone(); componentsStates_ = other.componentsStates_.Clone(); events_ = other.events_.Clone(); - version_ = other.version_; - versionName_ = other.versionName_; - versionBuildDate_ = other.versionBuildDate_; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] @@ -135,42 +130,6 @@ namespace Tango.PMR.Diagnostics { get { return events_; } } - /// Field number for the "Version" field. - public const int VersionFieldNumber = 5; - private string version_ = ""; - /// - ///Software Information - /// - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string Version { - get { return version_; } - set { - version_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "VersionName" field. - public const int VersionNameFieldNumber = 6; - private string versionName_ = ""; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string VersionName { - get { return versionName_; } - set { - versionName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - - /// Field number for the "VersionBuildDate" field. - public const int VersionBuildDateFieldNumber = 7; - private string versionBuildDate_ = ""; - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] - public string VersionBuildDate { - get { return versionBuildDate_; } - set { - versionBuildDate_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); - } - } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as PushDiagnosticsResponse); @@ -188,9 +147,6 @@ namespace Tango.PMR.Diagnostics { if(!digitalPins_.Equals(other.digitalPins_)) return false; if(!componentsStates_.Equals(other.componentsStates_)) return false; if(!events_.Equals(other.events_)) return false; - if (Version != other.Version) return false; - if (VersionName != other.VersionName) return false; - if (VersionBuildDate != other.VersionBuildDate) return false; return true; } @@ -201,9 +157,6 @@ namespace Tango.PMR.Diagnostics { hash ^= digitalPins_.GetHashCode(); hash ^= componentsStates_.GetHashCode(); hash ^= events_.GetHashCode(); - if (Version.Length != 0) hash ^= Version.GetHashCode(); - if (VersionName.Length != 0) hash ^= VersionName.GetHashCode(); - if (VersionBuildDate.Length != 0) hash ^= VersionBuildDate.GetHashCode(); return hash; } @@ -221,18 +174,6 @@ namespace Tango.PMR.Diagnostics { digitalPins_.WriteTo(output, _repeated_digitalPins_codec); componentsStates_.WriteTo(output, _repeated_componentsStates_codec); events_.WriteTo(output, _repeated_events_codec); - if (Version.Length != 0) { - output.WriteRawTag(42); - output.WriteString(Version); - } - if (VersionName.Length != 0) { - output.WriteRawTag(50); - output.WriteString(VersionName); - } - if (VersionBuildDate.Length != 0) { - output.WriteRawTag(58); - output.WriteString(VersionBuildDate); - } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] @@ -244,15 +185,6 @@ namespace Tango.PMR.Diagnostics { size += digitalPins_.CalculateSize(_repeated_digitalPins_codec); size += componentsStates_.CalculateSize(_repeated_componentsStates_codec); size += events_.CalculateSize(_repeated_events_codec); - if (Version.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(Version); - } - if (VersionName.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(VersionName); - } - if (VersionBuildDate.Length != 0) { - size += 1 + pb::CodedOutputStream.ComputeStringSize(VersionBuildDate); - } return size; } @@ -270,15 +202,6 @@ namespace Tango.PMR.Diagnostics { digitalPins_.Add(other.digitalPins_); componentsStates_.Add(other.componentsStates_); events_.Add(other.events_); - if (other.Version.Length != 0) { - Version = other.Version; - } - if (other.VersionName.Length != 0) { - VersionName = other.VersionName; - } - if (other.VersionBuildDate.Length != 0) { - VersionBuildDate = other.VersionBuildDate; - } } [global::System.Diagnostics.DebuggerNonUserCodeAttribute] @@ -308,18 +231,6 @@ namespace Tango.PMR.Diagnostics { events_.AddEntriesFrom(input, _repeated_events_codec); break; } - case 42: { - Version = input.ReadString(); - break; - } - case 50: { - VersionName = input.ReadString(); - break; - } - case 58: { - VersionBuildDate = input.ReadString(); - break; - } } } } diff --git a/Software/Visual_Studio/Tango.PMR/ExtensionMethods.cs b/Software/Visual_Studio/Tango.PMR/ExtensionMethods.cs index 9707399d9..3a255480d 100644 --- a/Software/Visual_Studio/Tango.PMR/ExtensionMethods.cs +++ b/Software/Visual_Studio/Tango.PMR/ExtensionMethods.cs @@ -13,7 +13,7 @@ namespace Tango.PMR /// /// Contains PMR extension methods. /// - public static class ExtensionMethods + public static class ExtensionMethods { /// /// Gets the protobuf attribute value from the message type. diff --git a/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj b/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj index bab99641a..07098b09f 100644 --- a/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj +++ b/Software/Visual_Studio/Tango.PMR/Tango.PMR.csproj @@ -59,6 +59,7 @@ + diff --git a/Software/Visual_Studio/Tango.SharedUI/Controls/ScriptEditorControl.xaml.cs b/Software/Visual_Studio/Tango.SharedUI/Controls/ScriptEditorControl.xaml.cs index a74e649c0..3fe87c7e2 100644 --- a/Software/Visual_Studio/Tango.SharedUI/Controls/ScriptEditorControl.xaml.cs +++ b/Software/Visual_Studio/Tango.SharedUI/Controls/ScriptEditorControl.xaml.cs @@ -182,7 +182,7 @@ namespace Tango.SharedUI.Controls foreach (var v in variables) { - var hT = IntellisenseTypes.SingleOrDefault(x => x.Value.Name == v.Type); + var hT = IntellisenseTypes.SingleOrDefault(x => x.Key == v.Type); if (hT.Value != null) { @@ -259,7 +259,7 @@ namespace Tango.SharedUI.Controls - foreach (var name in HighlightTypes.Select(x => x.Value).Select(x => x.Name)) + foreach (var name in HighlightTypes.Select(x => x.Key)) { code += String.Format("{0}", name) + Environment.NewLine; } diff --git a/Software/Visual_Studio/Tango.TFS/ITeamFoundationServiceClient.cs b/Software/Visual_Studio/Tango.TFS/ITeamFoundationServiceClient.cs index 51394f663..1fe169218 100644 --- a/Software/Visual_Studio/Tango.TFS/ITeamFoundationServiceClient.cs +++ b/Software/Visual_Studio/Tango.TFS/ITeamFoundationServiceClient.cs @@ -34,6 +34,42 @@ namespace Tango.TFS /// Task GetWorkItem(Project project, int id); + /// + /// Gets all the work items created by the specified team member. + /// + /// The project. + /// The member. + /// + Task> GetWorkItemsCreatedBy(Project project, TeamMember member); + + /// + /// Sets the state of the work item. + /// + /// The project. + /// The item. + /// The state. + /// + Task SetWorkItemState(Project project, WorkItem item, State state); + + /// + /// Sets the work item assignment. + /// + /// The project. + /// The item. + /// The member. + /// + Task SetWorkItemAssignment(Project project, WorkItem item, TeamMember member); + + /// + /// Adds a comment to the work item discussion. + /// + /// The project. + /// The item. + /// Team member + /// The comment. + /// + Task AddWorkItemComment(Project project, WorkItem item, TeamMember teamMember, String comment); + /// /// Deletes the specified work item. /// diff --git a/Software/Visual_Studio/Tango.TFS/ResolvedReason.cs b/Software/Visual_Studio/Tango.TFS/ResolvedReason.cs new file mode 100644 index 000000000..e1af689a2 --- /dev/null +++ b/Software/Visual_Studio/Tango.TFS/ResolvedReason.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.TFS +{ + public enum ResolvedReason + { + [Description("As Designed")] + AsDesigned, + [Description("Cannot Reproduce")] + CannotReproduce, + [Description("Copied To Backlog")] + CopiedToBacklog, + [Description("Deferred")] + Deferred, + [Description("Duplicate")] + Duplicate, + [Description("Fixed")] + Fixed, + [Description("Obsolete")] + Obsolete, + } +} diff --git a/Software/Visual_Studio/Tango.TFS/Tango.TFS.csproj b/Software/Visual_Studio/Tango.TFS/Tango.TFS.csproj index 00c9171c3..cf15c2e9e 100644 --- a/Software/Visual_Studio/Tango.TFS/Tango.TFS.csproj +++ b/Software/Visual_Studio/Tango.TFS/Tango.TFS.csproj @@ -204,6 +204,7 @@ + @@ -244,6 +245,10 @@ {a34ee0f0-649d-41c8-8489-b6f1cc6924ee} Tango.Core + + {bc932dbd-7cdb-488c-99e4-f02cf441f55e} + Tango.Logging + diff --git a/Software/Visual_Studio/Tango.TFS/TeamFoundationServiceClient.cs b/Software/Visual_Studio/Tango.TFS/TeamFoundationServiceClient.cs index e6390260e..6eef1ef92 100644 --- a/Software/Visual_Studio/Tango.TFS/TeamFoundationServiceClient.cs +++ b/Software/Visual_Studio/Tango.TFS/TeamFoundationServiceClient.cs @@ -31,6 +31,9 @@ namespace Tango.TFS public const String PRIORITY = "Microsoft.VSTS.Common.Priority"; public const String STEPS_TO_REP = "Microsoft.VSTS.TCM.ReproSteps"; public const String SYSTEM_INFO = "Microsoft.VSTS.TCM.SystemInfo"; + public const String RESOLVED_BY = "Microsoft.VSTS.Common.ResolvedBy"; + public const String RESOLVED_DATE = "Microsoft.VSTS.Common.ResolvedDate"; + public const String RESOLVED_REASON = "Microsoft.VSTS.Common.ResolvedReason"; } #endregion @@ -86,14 +89,17 @@ namespace Tango.TFS VssConnection connection = CreateConnection(); + LogManager.Log("Retrieving project " + name + " details..."); ProjectHttpClient projectClient = connection.GetClient(); - TeamProjectReference project = projectClient.GetProjects(null).Result.FirstOrDefault(x => x.Name == name); + TeamProjectReference project = projectClient.GetProjects().Result.FirstOrDefault(x => x.Name == name); if (project == null) { - throw new ArgumentException(String.Format("Project '{0}' could not be found.", name)); + throw LogManager.Log(new ArgumentException(String.Format("Project '{0}' could not be found.", name))); } + LogManager.Log("Project details successfully retrieved."); + p.Name = project.Name; p.ID = project.Id; p.URL = project.Url; @@ -128,7 +134,7 @@ namespace Tango.TFS }); } - var projCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(CollectionURL)); + var projCollection = new TfsTeamProjectCollection(new Uri(CollectionURL), connection.Credentials); var store = projCollection.GetService(); WorkItemCollection queryResults = store.Query("Select [State], [Title] " + "From WorkItems " + "Where [Work Item Type] = 'User Story'"); @@ -213,6 +219,17 @@ namespace Tango.TFS }); } + if (!String.IsNullOrWhiteSpace(workItem.Comment)) + { + patchDocument.Add(new JsonPatchOperation + { + Operation = Operation.Add, + Path = GetFieldNameForWrite(CoreField.History), + Value = workItem.Comment, + From = workItem.CreatedBy.AssignName + }); + } + patchDocument.Add(new JsonPatchOperation { Operation = Operation.Add, @@ -367,72 +384,150 @@ namespace Tango.TFS { return Task.Factory.StartNew(() => { - WorkItem workItem = new WorkItem(); - var connection = CreateConnection(); WorkItemTrackingHttpClient witClient = connection.GetClient(); var item = witClient.GetWorkItemAsync(id, expand: Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models.WorkItemExpand.All).Result; - workItem.ID = item.Id.Value; - workItem.Title = item.Fields[GetFieldNameForRead(CoreField.Title)].ToString(); - workItem.Description = TryGetField(item.Fields, GetFieldNameForRead(CoreField.Description)); - workItem.Area = new Area() - { - Path = item.Fields[GetFieldNameForRead(CoreField.AreaPath)].ToString(), - Name = Path.GetFileName(item.Fields[GetFieldNameForRead(CoreField.AreaPath)].ToString()), - }; - workItem.Iteration = new Iteration() - { - Path = item.Fields[GetFieldNameForRead(CoreField.IterationPath)].ToString(), - Name = Path.GetFileName(item.Fields[GetFieldNameForRead(CoreField.IterationPath)].ToString()), - }; + return ConvertToWorkItem(project, item); + }); + } - workItem.AssignedTo = project.Members.SingleOrDefault(x => x.AssignName == TryGetField(item.Fields, GetFieldNameForRead(CoreField.AssignedTo))); - workItem.CreatedBy = project.Members.SingleOrDefault(x => x.AssignName == TryGetField(item.Fields, GetFieldNameForRead(CoreField.CreatedBy))); - workItem.ChangedBy = project.Members.SingleOrDefault(x => x.AssignName == TryGetField(item.Fields, GetFieldNameForRead(CoreField.ChangedBy))); - workItem.AuthorizedAs = project.Members.SingleOrDefault(x => x.AssignName == TryGetField(item.Fields, GetFieldNameForRead(CoreField.AuthorizedAs))); + /// + /// Deletes the specified work item. + /// + /// The project. + /// The identifier. + /// + public Task DeleteWorkItem(Project project, int id) + { + return Task.Factory.StartNew(() => + { + var connection = CreateConnection(); - workItem.Type = (WorkItemType)Enum.Parse(typeof(WorkItemType), item.Fields[GetFieldNameForRead(CoreField.WorkItemType)].ToString()); - workItem.URL = item.Url; + WorkItemTrackingHttpClient witClient = connection.GetClient(); + var result = witClient.DeleteWorkItemAsync(id, true).Result; + }); + } - if (item.Fields.ContainsKey(GetFieldNameForRead(CoreField.Tags))) + /// + /// Gets all the work items created by the specified team member. + /// + /// The project. + /// The member. + /// + public Task> GetWorkItemsCreatedBy(Project project, TeamMember member) + { + return Task.Factory.StartNew>(() => + { + var connection = CreateConnection(); + + var projCollection = new TfsTeamProjectCollection(new Uri(CollectionURL), connection.Credentials); + var store = projCollection.GetService(); + + WorkItemCollection queryResults = store.Query(String.Format("Select [Id]" + "From WorkItems " + "Where [Created By] = '{0}' And [Work Item Type] = 'Bug'", member.AssignName)); + var ids = queryResults.OfType().Where(x => x.Project.Name == project.Name).ToList().Select(x => x.Id).ToList(); + + if (ids.Count == 0) return new List(); + + WorkItemTrackingHttpClient witClient = connection.GetClient(); + + var items = witClient.GetWorkItemsAsync(ids).Result; + + return items.Select(x => ConvertToWorkItem(project, x)).ToList(); + }); + } + + /// + /// Sets the state of the work item. + /// + /// The project. + /// The item. + /// The state. + /// + public Task SetWorkItemState(Project project, WorkItem item, State state) + { + return Task.Factory.StartNew(() => + { + var connection = CreateConnection(); + + WorkItemTrackingHttpClient witClient = connection.GetClient(); + + var patchDocument = new JsonPatchDocument(); + + patchDocument.Add(new JsonPatchOperation { - List tags = item.Fields[GetFieldNameForRead(CoreField.Tags)].ToString().Split(';').Select(x => x.Trim()).ToList(); - workItem.Tags = tags.Select(x => new Tag() { Name = x }).ToList(); - } + Operation = Operation.Replace, + Path = GetFieldNameForWrite(CoreField.State), + Value = state.ToString(), + }); - workItem.FoundInBuild = item.Fields[ExtensionFields.FOUND_IN_BUILD].ToString(); + var updatedItem = witClient.UpdateWorkItemAsync(patchDocument, item.ID).Result; - workItem.State = (State)Enum.Parse(typeof(State), item.Fields[GetFieldNameForRead(CoreField.State)].ToString()); + return ConvertToWorkItem(project, updatedItem); + }); + } - workItem.Severity = ParseEnumByDescription(item.Fields[ExtensionFields.SEVERITY].ToString()); + /// + /// Adds a comment to the work item discussion. + /// + /// The project. + /// The item. + /// Team member + /// The comment. + /// + public Task AddWorkItemComment(Project project, WorkItem item, TeamMember teamMember, String comment) + { + return Task.Factory.StartNew(() => + { + var connection = CreateConnection(); - workItem.Priority = (Priority)int.Parse(item.Fields[ExtensionFields.PRIORITY].ToString()); + WorkItemTrackingHttpClient witClient = connection.GetClient(); - workItem.StepsToReproduce = item.Fields[ExtensionFields.STEPS_TO_REP].ToString(); + var patchDocument = new JsonPatchDocument(); - workItem.SystemInformation = item.Fields[ExtensionFields.SYSTEM_INFO].ToString(); + patchDocument.Add(new JsonPatchOperation + { + Operation = Operation.Add, + Path = GetFieldNameForWrite(CoreField.History), + Value = comment, + From = teamMember.AssignName + }); - return workItem; + var updatedItem = witClient.UpdateWorkItemAsync(patchDocument, item.ID).Result; + + return ConvertToWorkItem(project, updatedItem); }); } /// - /// Deletes the specified work item. + /// Sets the work item assignment. /// /// The project. - /// The identifier. + /// The item. + /// The member. /// - public Task DeleteWorkItem(Project project, int id) + public Task SetWorkItemAssignment(Project project, WorkItem item, TeamMember member) { - return Task.Factory.StartNew(() => + return Task.Factory.StartNew(() => { var connection = CreateConnection(); WorkItemTrackingHttpClient witClient = connection.GetClient(); - var result = witClient.DeleteWorkItemAsync(id, true).Result; + + var patchDocument = new JsonPatchDocument(); + + patchDocument.Add(new JsonPatchOperation + { + Operation = Operation.Replace, + Path = GetFieldNameForWrite(CoreField.AssignedTo), + Value = member.AssignName, + }); + + var updatedItem = witClient.UpdateWorkItemAsync(patchDocument, item.ID).Result; + + return ConvertToWorkItem(project, updatedItem); }); } @@ -446,7 +541,19 @@ namespace Tango.TFS /// private VssConnection CreateConnection() { - VssConnection connection = new VssConnection(new Uri(CollectionURL), new VssBasicCredential(UserName, PersonalToken)); + LogManager.Log("Generating VSTS connection using personal token " + PersonalToken); + VssConnection connection = new VssConnection(new Uri(CollectionURL), new VssBasicCredential(String.Empty, PersonalToken)); + connection.Credentials.PromptType = CredentialPromptType.DoNotPrompt; + connection.ConnectAsync(VssConnectMode.User).SyncResult(); + LogManager.Log("VSS Connection established..."); + + LogManager.Log("Authenticated: " + connection.HasAuthenticated); + + if (connection.HasAuthenticated) + { + LogManager.Log("Authenticated Identity: " + connection.AuthorizedIdentity.DisplayName); + } + return connection; } @@ -514,6 +621,65 @@ namespace Tango.TFS return values[description]; } + private WorkItem ConvertToWorkItem(Project project, Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models.WorkItem item) + { + WorkItem workItem = new WorkItem(); + + + workItem.ID = item.Id.Value; + workItem.Title = item.Fields[GetFieldNameForRead(CoreField.Title)].ToString(); + workItem.CreatedDate = DateTime.Parse(item.Fields[GetFieldNameForRead(CoreField.CreatedDate)].ToString()); + workItem.Description = TryGetField(item.Fields, GetFieldNameForRead(CoreField.Description)); + workItem.Area = new Area() + { + Path = item.Fields[GetFieldNameForRead(CoreField.AreaPath)].ToString(), + Name = Path.GetFileName(item.Fields[GetFieldNameForRead(CoreField.AreaPath)].ToString()), + }; + workItem.Iteration = new Iteration() + { + Path = item.Fields[GetFieldNameForRead(CoreField.IterationPath)].ToString(), + Name = Path.GetFileName(item.Fields[GetFieldNameForRead(CoreField.IterationPath)].ToString()), + }; + + workItem.AssignedTo = project.Members.SingleOrDefault(x => x.AssignName == TryGetField(item.Fields, GetFieldNameForRead(CoreField.AssignedTo))); + workItem.CreatedBy = project.Members.SingleOrDefault(x => x.AssignName == TryGetField(item.Fields, GetFieldNameForRead(CoreField.CreatedBy))); + workItem.ChangedBy = project.Members.SingleOrDefault(x => x.AssignName == TryGetField(item.Fields, GetFieldNameForRead(CoreField.ChangedBy))); + workItem.AuthorizedAs = project.Members.SingleOrDefault(x => x.AssignName == TryGetField(item.Fields, GetFieldNameForRead(CoreField.AuthorizedAs))); + + workItem.ResolvedBy = project.Members.SingleOrDefault(x => x.AssignName == TryGetField(item.Fields, ExtensionFields.RESOLVED_BY)); + + if (item.Fields.ContainsKey(ExtensionFields.RESOLVED_REASON)) + { + workItem.ResolvedReason = ParseEnumByDescription(item.Fields[ExtensionFields.RESOLVED_REASON].ToString()); + workItem.ResolvedDate = DateTime.Parse(item.Fields[ExtensionFields.RESOLVED_DATE].ToString()); + } + + workItem.Type = (WorkItemType)Enum.Parse(typeof(WorkItemType), item.Fields[GetFieldNameForRead(CoreField.WorkItemType)].ToString()); + workItem.URL = item.Url; + + if (item.Fields.ContainsKey(GetFieldNameForRead(CoreField.Tags))) + { + List tags = item.Fields[GetFieldNameForRead(CoreField.Tags)].ToString().Split(';').Select(x => x.Trim()).ToList(); + workItem.Tags = tags.Select(x => new Tag() { Name = x }).ToList(); + } + + workItem.FoundInBuild = TryGetField(item.Fields, ExtensionFields.FOUND_IN_BUILD).ToString(); + + workItem.State = (State)Enum.Parse(typeof(State), item.Fields[GetFieldNameForRead(CoreField.State)].ToString()); + + workItem.Severity = ParseEnumByDescription(item.Fields[ExtensionFields.SEVERITY].ToString()); + + workItem.Priority = (Priority)int.Parse(item.Fields[ExtensionFields.PRIORITY].ToString()); + + workItem.StepsToReproduce = TryGetField(item.Fields, ExtensionFields.STEPS_TO_REP).ToString(); + + workItem.SystemInformation = TryGetField(item.Fields, ExtensionFields.SYSTEM_INFO).ToString(); + + workItem.Comment = TryGetField(item.Fields, GetFieldNameForRead(CoreField.History)).ToString(); + + return workItem; + } + #endregion } } diff --git a/Software/Visual_Studio/Tango.TFS/WorkItem.cs b/Software/Visual_Studio/Tango.TFS/WorkItem.cs index 98ac05191..59f277f2e 100644 --- a/Software/Visual_Studio/Tango.TFS/WorkItem.cs +++ b/Software/Visual_Studio/Tango.TFS/WorkItem.cs @@ -101,6 +101,13 @@ namespace Tango.TFS set { _assignedTo = value; RaisePropertyChangedAuto(); } } + private DateTime _createdDate; + public DateTime CreatedDate + { + get { return _createdDate; } + set { _createdDate = value; RaisePropertyChangedAuto(); } + } + private TeamMember _createdBy; public TeamMember CreatedBy { @@ -115,6 +122,27 @@ namespace Tango.TFS set { _changedBy = value; RaisePropertyChangedAuto(); } } + private TeamMember _resolvedBy; + public TeamMember ResolvedBy + { + get { return _resolvedBy; } + set { _resolvedBy = value; RaisePropertyChangedAuto(); } + } + + private DateTime _resolvedDate; + public DateTime ResolvedDate + { + get { return _resolvedDate; } + set { _resolvedDate = value; RaisePropertyChangedAuto(); } + } + + private ResolvedReason _resolvedReason; + public ResolvedReason ResolvedReason + { + get { return _resolvedReason; } + set { _resolvedReason = value; RaisePropertyChangedAuto(); } + } + private TeamMember _authorizedAs; public TeamMember AuthorizedAs { @@ -140,6 +168,30 @@ namespace Tango.TFS set { _foundInBuild = value; RaisePropertyChangedAuto(); } } + private String _comment; + public String Comment + { + get { return _comment; } + set { _comment = value; RaisePropertyChangedAuto(); } + } + + public bool IsBuildVersionValid + { + get + { + Version v = null; + return Version.TryParse(FoundInBuild, out v); + } + } + + public Version FoundInBuildVersion + { + get + { + return Version.Parse(FoundInBuild); + } + } + public WorkItem() { Attachments = new List(); diff --git a/Software/Visual_Studio/Tango.UnitTesting/TFS_TST.cs b/Software/Visual_Studio/Tango.UnitTesting/TFS_TST.cs index 2727ad00e..3fff8daae 100644 --- a/Software/Visual_Studio/Tango.UnitTesting/TFS_TST.cs +++ b/Software/Visual_Studio/Tango.UnitTesting/TFS_TST.cs @@ -43,11 +43,61 @@ namespace Tango.UnitTesting Assert.IsNotNull(project); - var workItem = client.GetWorkItem(project, 153).Result; + var workItem = client.GetWorkItem(project, 168).Result; Assert.IsNotNull(workItem); } + [TestMethod] + public void Get_Work_Items_Created_By() + { + ITeamFoundationServiceClient client = CreateClient(); + + var project = client.GetProject("Tango").Result; + + Assert.IsNotNull(project); + + var workItems = client.GetWorkItemsCreatedBy(project, project.Members.SingleOrDefault(x => x.AssignName.ToLower().Contains("roy"))).Result; + + Assert.IsTrue(workItems.Count > 0); + } + + [TestMethod] + public void Set_Work_Item_State() + { + ITeamFoundationServiceClient client = CreateClient(); + + var project = client.GetProject("Tango").Result; + + Assert.IsNotNull(project); + + var workItem = client.GetWorkItem(project, 164).Result; + + Assert.IsNotNull(workItem); + + var updated = client.SetWorkItemState(project, workItem, State.Active).Result; + + Assert.IsTrue(updated.State == State.Active); + } + + [TestMethod] + public void Add_Work_Item_Comment() + { + ITeamFoundationServiceClient client = CreateClient(); + + var project = client.GetProject("Tango").Result; + + Assert.IsNotNull(project); + + var workItem = client.GetWorkItem(project, 165).Result; + + Assert.IsNotNull(workItem); + + var updated = client.AddWorkItemComment(project, workItem, project.Members.SingleOrDefault(x => x.AssignName.ToLower().Contains("roy")), "Test Comment").Result; + + Assert.AreEqual(updated.Comment, "Test Comment"); + } + [TestMethod] public void Upload_Work_Item() { -- cgit v1.3.1