diff options
| author | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-07-29 21:12:47 +0300 |
|---|---|---|
| committer | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-07-29 21:12:47 +0300 |
| commit | 08bd8bac1498b6aa3bd264e5c466dd65a4386fd2 (patch) | |
| tree | 1fb311c11e4975663957aa218ab818beb90528ac | |
| parent | bdf7e5a2abc2c9d3b7889d2d71754c33ea3efbf6 (diff) | |
| download | Tango-08bd8bac1498b6aa3bd264e5c466dd65a4386fd2.tar.gz Tango-08bd8bac1498b6aa3bd264e5c466dd65a4386fd2.zip | |
Procedures SQL, Resources, Variables.
27 files changed, 794 insertions, 3 deletions
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/IProcedureContext.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/IProcedureContext.cs index 9b2ccfe2f..0187841c8 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/IProcedureContext.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/IProcedureContext.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using Tango.BL.Entities; using Tango.Core; using Tango.FSE.Common.Connection; using Tango.FSE.Common.Diagnostics; @@ -387,5 +388,53 @@ namespace Tango.FSE.Procedures /// Gets or sets a value indicating whether a machine is currently connected. /// </summary> bool IsConnected { get; } + + /// <summary> + /// Gets the currently connected machine entity. + /// </summary> + Machine ConnectedMachine { get; } + + /// <summary> + /// Gets a registered injected service from the Tango FSE application. + /// </summary> + /// <typeparam name="T">Type of service</typeparam> + /// <returns></returns> + T GetService<T>(); + + /// <summary> + /// Gets the specified resource as byte array. + /// </summary> + /// <param name="resourceName">Name of the resource.</param> + /// <returns></returns> + byte[] GetResourceBytes(String resourceName); + + /// <summary> + /// Gets the specified resource as UTF-8 string. + /// </summary> + /// <param name="resourceName">Name of the resource.</param> + /// <returns></returns> + String GetResourceString(String resourceName); + + /// <summary> + /// Gets the specified procedure variable. + /// </summary> + /// <param name="name">The name of the variable.</param> + /// <returns></returns> + Object GetVariable(String name); + + /// <summary> + /// Gets the specified procedure variable. + /// </summary> + /// <param name="name">The name of the variable.</param> + /// <returns></returns> + T GetVariable<T>(String name); + + /// <summary> + /// Gets the specified procedure variable value as an array. + /// User value must be a comma separated string. + /// </summary> + /// <param name="name">The name of the variable.</param> + /// <returns></returns> + List<T> GetVariableArray<T>(String name); } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureContext.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureContext.cs index 54ae07444..e75a080a1 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureContext.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureContext.cs @@ -14,6 +14,7 @@ using System.Threading; using System.Threading.Tasks; using System.Windows; using Google.Protobuf; +using Tango.BL.Entities; using Tango.Core; using Tango.Core.DI; using Tango.Core.ExtensionMethods; @@ -60,6 +61,11 @@ namespace Tango.FSE.Procedures get { return MachineProvider.IsConnected; } } + public Machine ConnectedMachine + { + get { return MachineProvider.Machine; } + } + public ProcedureContext(ProcedureProject project, IProcedureLogger logger) { _project = project; @@ -692,5 +698,64 @@ namespace Tango.FSE.Procedures return result; } } + + public T GetService<T>() + { + return TangoIOC.Default.GetInstance<T>(); + } + + public byte[] GetResourceBytes(string resourceName) + { + var resource = _project.Resources.SingleOrDefault(x => x.Name.ToLower() == resourceName.ToLower()); + + if (resource == null) + { + throw new FileNotFoundException($"The specified resource '{resourceName}' could not be found on the procedure project."); + } + + return resource.Data; + } + + public string GetResourceString(string resourceName) + { + byte[] data = GetResourceBytes(resourceName); + return Encoding.Default.GetString(data); + } + + public object GetVariable(string name) + { + ProcedureVariable variable = _project.Variables.SingleOrDefault(x => x.Name == name); + + if (variable == null) + { + throw new KeyNotFoundException($"The specified variable '{name}' could not found."); + } + + return variable.Value; + } + + public T GetVariable<T>(string name) + { + object value = GetVariable(name); + + try + { + return (T)Convert.ChangeType(value, typeof(T)); + } + catch + { + throw new InvalidCastException($"Error converting the specified variable value '{value}' to type '{typeof(T).Name}'."); + } + } + + public List<T> GetVariableArray<T>(string name) + { + object value = GetVariable(name); + + String[] arr = value.ToStringSafe().Split(','); + var list = new List<T>(arr.Select(x => (T)Convert.ChangeType(x, typeof(T)))); + + return list; + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureProject.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureProject.cs index 6d6483b3b..65e9a0fff 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureProject.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureProject.cs @@ -21,6 +21,10 @@ namespace Tango.FSE.Procedures public ObservableCollection<ProcedureInput> Inputs { get; set; } + public ObservableCollection<ProcedureVariable> Variables { get; set; } + + public ObservableCollection<ProcedureResource> Resources { get; set; } + public ObservableCollection<ProcedureDialog> Dialogs { get; set; } static ProcedureProject() @@ -36,6 +40,8 @@ namespace Tango.FSE.Procedures { ApartmentState = System.Threading.ApartmentState.STA; Inputs = new ObservableCollection<ProcedureInput>(); + Variables = new ObservableCollection<ProcedureVariable>(); + Resources = new ObservableCollection<ProcedureResource>(); Dialogs = new ObservableCollection<ProcedureDialog>(); } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureResource.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureResource.cs new file mode 100644 index 000000000..bef79db47 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureResource.cs @@ -0,0 +1,33 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media.Imaging; +using Tango.FileSystem; + +namespace Tango.FSE.Procedures +{ + public class ProcedureResource + { + public String Name { get; set; } + public byte[] Data { get; set; } + + private BitmapSource _icon; + [JsonIgnore] + public BitmapSource Icon + { + get + { + if (_icon == null) + { + var fakeFileItem = new FileItem() { Path = Name }; + _icon = fakeFileItem.SmallIcon; + } + + return _icon; + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureVariable.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureVariable.cs new file mode 100644 index 000000000..793e2acfa --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureVariable.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Procedures +{ + public class ProcedureVariable + { + public String Name { get; set; } + public Object Value { get; set; } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Resources/lib_template.csx b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Resources/lib_template.csx index a633ea108..cb99aeffa 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Resources/lib_template.csx +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Resources/lib_template.csx @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using System.Drawing; using Google.Protobuf; +using Tango.BL.Entities; using Tango.BL.Enumerations; using Tango.PMR.Stubs; using Tango.PMR.Diagnostics; diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Resources/main_template.csx b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Resources/main_template.csx index f0987a17d..8a2516cac 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Resources/main_template.csx +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Resources/main_template.csx @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using System.Drawing; using Google.Protobuf; +using Tango.BL.Entities; using Tango.BL.Enumerations; using Tango.PMR.Stubs; using Tango.PMR.Diagnostics; diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/SqlResult.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/SqlResult.cs new file mode 100644 index 000000000..caf4cae32 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/SqlResult.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Procedures +{ + public class SqlResult + { + public int AffectedRecords { get; set; } + public List<Dictionary<String, Object>> Rows { get; set; } + + public SqlResult() + { + Rows = new List<Dictionary<string, object>>(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Tango.FSE.Procedures.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Tango.FSE.Procedures.csproj index c0412ef6a..fcd5c7603 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Tango.FSE.Procedures.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Tango.FSE.Procedures.csproj @@ -149,7 +149,9 @@ <Compile Include="ProcedureDialog.cs" /> <Compile Include="ProcedureInputSelection.cs" /> <Compile Include="ProcedureInputType.cs" /> + <Compile Include="ProcedureResource.cs" /> <Compile Include="ProceduresSettings.cs" /> + <Compile Include="ProcedureVariable.cs" /> <Compile Include="ProjectRunner.cs" /> <Compile Include="ProjectRunnerState.cs" /> <Compile Include="Result.cs" /> @@ -158,6 +160,7 @@ <Compile Include="ProcedureFailedException.cs" /> <Compile Include="ProcedureInput.cs" /> <Compile Include="ProcedureProject.cs" /> + <Compile Include="SqlResult.cs" /> <Compile Include="UserInput.cs" /> <Compile Include="ViewModelLocator.cs" /> <Compile Include="ProceduresModule.cs" /> @@ -255,6 +258,10 @@ <Project>{58e8825f-0c96-449c-b320-1e82b0aa876b}</Project> <Name>Tango.CSV</Name> </ProjectReference> + <ProjectReference Include="..\..\..\Tango.FileSystem\Tango.FileSystem.csproj"> + <Project>{c6ebbbbe-2123-44dc-aef7-a0d47d736ac0}</Project> + <Name>Tango.FileSystem</Name> + </ProjectReference> <ProjectReference Include="..\..\..\Tango.Integration\Tango.Integration.csproj"> <Project>{4206ac58-3b57-4699-8835-90bf6db01a61}</Project> <Name>Tango.Integration</Name> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ViewModels/ProcedureDesignerViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ViewModels/ProcedureDesignerViewVM.cs index 4de9e64f8..f07f0801b 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ViewModels/ProcedureDesignerViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ViewModels/ProcedureDesignerViewVM.cs @@ -3,6 +3,7 @@ using MaterialDesignThemes.Wpf; using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; @@ -17,6 +18,7 @@ using Tango.BL.Enumerations; using Tango.Core; using Tango.Core.Commands; using Tango.Core.ExtensionMethods; +using Tango.Core.Helpers; using Tango.FSE.Common; using Tango.FSE.Common.Navigation; using Tango.FSE.Common.Notifications; @@ -235,6 +237,11 @@ namespace Tango.FSE.Procedures.ViewModels public RelayCommand<ProcedureDialog> EditDialogCommand { get; set; } public RelayCommand<ProcedureDialog> RemoveDialogCommand { get; set; } public RelayCommand<ProcedureInput> ConfigureInputSelectionCommand { get; set; } + public RelayCommand AddResourceCommand { get; set; } + public RelayCommand<ProcedureResource> RenameResourceCommand { get; set; } + public RelayCommand<ProcedureResource> RemoveResourceCommand { get; set; } + public RelayCommand<ProcedureResource> OpenResourceCommand { get; set; } + public RelayCommand<ProcedureResource> ExportResourceCommand { get; set; } #endregion @@ -257,6 +264,7 @@ namespace Tango.FSE.Procedures.ViewModels ScriptEditor.LoadingSymbolsCompleted += ScriptEditor_LoadingSymbolsCompleted; ScriptEditor.BlockedUsingsCache.Add("Tango.FSE.Procedures"); ScriptEditor.BlockedUsingsCache.Add("Tango.PMR.Stubs"); + ScriptEditor.BlockedUsingsCache.Add("Tango.BL.Entities"); ScriptEditor.BlockedUsingsCache.Add("Tango.BL.Enumerations"); ScriptEditor.BlockedUsingsCache.Add("Tango.PMR.Diagnostics"); ScriptEditor.BlockedUsingsCache.Add("Tango.FSE.Common.Connection"); @@ -298,6 +306,11 @@ namespace Tango.FSE.Procedures.ViewModels EditDialogCommand = new RelayCommand<ProcedureDialog>(EditProcedureDialog); RemoveDialogCommand = new RelayCommand<ProcedureDialog>(RemoveProcedureDialog); ConfigureInputSelectionCommand = new RelayCommand<ProcedureInput>(ConfigureInputSelection); + AddResourceCommand = new RelayCommand(AddProcedureResource); + RenameResourceCommand = new RelayCommand<ProcedureResource>(RenameProcedureResource); + RemoveResourceCommand = new RelayCommand<ProcedureResource>(RemoveProcedureResource); + OpenResourceCommand = new RelayCommand<ProcedureResource>(OpenProcedureResource); + ExportResourceCommand = new RelayCommand<ProcedureResource>(ExportProcedureResource); } #endregion @@ -711,6 +724,8 @@ namespace Tango.FSE.Procedures.ViewModels Project.Scripts.ToList().ForEach(x => x.IsChanged = false); _isProjectChanged = false; + + NotificationProvider.PushSnackbarItem(MessageType.Success, "Procedure project saved", false, $"Project '{Project.Name}' saved successfully.", TimeSpan.FromSeconds(1.5)); } catch (Exception ex) { @@ -1116,6 +1131,8 @@ namespace Tango.FSE.Procedures.ViewModels Name = result.Input + ".xaml", Xaml = Properties.Resources.dialog_template }); + + _isProjectChanged = true; } } @@ -1137,6 +1154,8 @@ namespace Tango.FSE.Procedures.ViewModels dialog.Name = vm.Name + ".xaml"; dialog.Xaml = vm.Xaml; + + _isProjectChanged = true; } } @@ -1157,15 +1176,103 @@ namespace Tango.FSE.Procedures.ViewModels { var vm = await NotificationProvider.ShowDialog(new InputSelectionConfigurationDialogViewVM() { - SelectionInputs = input.SelectionInputs.ToList().ToObservableCollection(), + SelectionInputs = input.SelectionInputs.ToList().ToObservableCollection(), }); if (vm.DialogResult) { input.SelectionInputs = vm.SelectionInputs.ToObservableCollection(); + _isProjectChanged = true; + } + } + + #endregion + + #region Resources + + private async void AddProcedureResource() + { + var result = await StorageProvider.OpenFiles("Add procedure resources"); + + if (result.Confirmed) + { + foreach (var file in result.SelectedItems) + { + String name = Path.GetFileName(file); + if (Project.Resources.Any(x => x.Name.ToLower() == name.ToLower())) + { + await NotificationProvider.ShowError($"The procedure already contains a resource named '{name}'. Cannot add resource."); + continue; + } + + long fileSize = (new FileInfo(file).Length / 1024) / 1024; + + if (fileSize > 2) + { + await NotificationProvider.ShowError($"Resource '{name}' exceeds the maximum allowed resource size of 2MB. Cannot add resource."); + continue; + } + + Project.Resources.Add(new ProcedureResource() + { + Name = name, + Data = File.ReadAllBytes(file) + }); + } + + _isProjectChanged = true; + } + } + + private async void RemoveProcedureResource(ProcedureResource resource) + { + if (await NotificationProvider.ShowWarningQuestion($"Are you sure you want to delete resource '{resource.Name}'?")) + { + Project.Resources.Remove(resource); + _isProjectChanged = true; + } + } + + private async void RenameProcedureResource(ProcedureResource resource) + { + var result = await NotificationProvider.ShowInputBox("Rename Resource", "Please specify a new resource name", PackIconKind.Rename, resource.Name, "Resource Name", 100, "RENAME"); + + if (result.Confirmed) + { + if (Project.Resources.Any(x => x != resource && x.Name.ToLower() == result.Input.ToLower())) + { + await NotificationProvider.ShowError($"The project already contains a resource named '{result.Input}'."); + return; + } + + resource.Name = result.Input; + _isProjectChanged = true; } } + public void OpenProcedureResource(ProcedureResource resource) + { + var tempFolder = TemporaryManager.CreateFolder(); + var tempFile = Path.Combine(tempFolder, resource.Name); + File.WriteAllBytes(tempFile, resource.Data); + Process.Start(tempFile); + } + + private async void ExportProcedureResource(ProcedureResource resource) + { + var result = await StorageProvider.SaveFile("Export Procedure Resource", null, resource.Name, Path.GetExtension(resource.Name)); + + if (result.Confirmed) + { + File.WriteAllBytes(result.SelectedItem, resource.Data); + } + + NotificationProvider.PushSnackbarItem(MessageType.Success, "Export Procedure Resource", true, "Procedure resource exported successfully.\nTap to browse the file location.", TimeSpan.FromSeconds(5), null, () => + { + StorageProvider.ShowInExplorer(result.SelectedItem); + }); + } + #endregion } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Views/ProcedureDesignerView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Views/ProcedureDesignerView.xaml index 9b81c598f..b1a5bc9fc 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Views/ProcedureDesignerView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Views/ProcedureDesignerView.xaml @@ -722,6 +722,54 @@ </ListBox> <DockPanel Margin="5 10 0 0"> + <controls:ToggleIconButton Width="20" Height="20" x:Name="chkResources" UncheckedIcon="ChevronRight" CheckedIcon="ChevronDown" Cursor="Hand" IsChecked="True" /> + <controls:IconButton VerticalAlignment="Center" DockPanel.Dock="Right" Icon="Add" Foreground="{StaticResource FSE_GreenBrush}" Command="{Binding AddResourceCommand}" ToolTip="Add Resource" /> + <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Text="Resources"/> + </DockPanel> + + <ListBox Margin="25 5 0 0" ItemsSource="{Binding Project.Resources}" Visibility="{Binding ElementName=chkResources,Path=IsChecked,Converter={StaticResource BooleanToVisibilityConverter}}"> + <ListBox.ItemContainerStyle> + <Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}"> + <Setter Property="ContextMenu"> + <Setter.Value> + <ContextMenu> + <MenuItem MinWidth="180" Header="Open" Command="{Binding Source={StaticResource proxy},Path=Data.OpenResourceCommand}" CommandParameter="{Binding}"> + <MenuItem.Icon> + <material:PackIcon Kind="OpenInApp" /> + </MenuItem.Icon> + </MenuItem> + <MenuItem MinWidth="180" Header="Rename" Command="{Binding Source={StaticResource proxy},Path=Data.RenameResourceCommand}" CommandParameter="{Binding}"> + <MenuItem.Icon> + <material:PackIcon Kind="Rename" /> + </MenuItem.Icon> + </MenuItem> + <MenuItem MinWidth="180" Header="Export To File" Command="{Binding Source={StaticResource proxy},Path=Data.ExportResourceCommand}" CommandParameter="{Binding}"> + <MenuItem.Icon> + <material:PackIcon Kind="Export" /> + </MenuItem.Icon> + </MenuItem> + <Separator/> + <MenuItem MinWidth="180" Header="Delete" Command="{Binding Source={StaticResource proxy},Path=Data.RemoveResourceCommand}" CommandParameter="{Binding}"> + <MenuItem.Icon> + <material:PackIcon Kind="Delete" Foreground="{StaticResource FSE_RedBrush}" /> + </MenuItem.Icon> + </MenuItem> + </ContextMenu> + </Setter.Value> + </Setter> + </Style> + </ListBox.ItemContainerStyle> + <ListBox.ItemTemplate> + <DataTemplate> + <DockPanel> + <Image RenderOptions.BitmapScalingMode="Fant" Source="{Binding Icon}" Stretch="Uniform" Width="16" Height="16" /> + <TextBlock Margin="5 0 0 0" Text="{Binding Name}"></TextBlock> + </DockPanel> + </DataTemplate> + </ListBox.ItemTemplate> + </ListBox> + + <DockPanel Margin="5 10 0 0"> <controls:ToggleIconButton Width="20" Height="20" x:Name="chkDialogs" UncheckedIcon="ChevronRight" CheckedIcon="ChevronDown" Cursor="Hand" IsChecked="True" /> <controls:IconButton VerticalAlignment="Center" DockPanel.Dock="Right" Icon="Add" Foreground="{StaticResource FSE_GreenBrush}" Command="{Binding AddDialogCommand}" ToolTip="Add Dialog" /> <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Text="Dialogs"/> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/IRemoteSqlProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/IRemoteSqlProvider.cs new file mode 100644 index 000000000..d3b6660bf --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/IRemoteSqlProvider.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.PPC.Shared.SQL; + +namespace Tango.FSE.Common.SQL +{ + public interface IRemoteSqlProvider + { + Task<RemoteSqlCommandResult> ExecuteSqlCommandAsync(RemoteSqlCommand command); + + RemoteSqlCommandResult ExecuteSqlCommand(RemoteSqlCommand command); + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/RemoteSqlCommand.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/RemoteSqlCommand.cs new file mode 100644 index 000000000..95f94ad08 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/RemoteSqlCommand.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Common.SQL +{ + public class RemoteSqlCommand + { + public RemoteSqlCommandMode Mode { get; set; } + public String SQL { get; set; } + public int Timeout { get; set; } + + public RemoteSqlCommand() + { + Timeout = 30; + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/RemoteSqlCommandMode.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/RemoteSqlCommandMode.cs new file mode 100644 index 000000000..1b05e8e86 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/RemoteSqlCommandMode.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Common.SQL +{ + /// <summary> + /// Represents an SQL command mode. + /// </summary> + public enum RemoteSqlCommandMode + { + /// <summary> + /// Executes the command against the connected local database. + /// </summary> + Local, + /// <summary> + /// Executes the command against the global Twine's database. + /// </summary> + Global, + /// <summary> + /// Executes the command against the connected machine and the global databases. + /// </summary> + Both + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/RemoteSqlCommandResult.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/RemoteSqlCommandResult.cs new file mode 100644 index 000000000..b4714c1aa --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/RemoteSqlCommandResult.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Common.SQL +{ + public class RemoteSqlCommandResult + { + public int LocalAffectedRecords { get; set; } + public List<Dictionary<String, Object>> LocalRows { get; set; } + public bool HasLocalError { get; set; } + public String LocalError { get; set; } + + public int GlobalAffectedRecords { get; set; } + public List<Dictionary<String, Object>> GlobalRows { get; set; } + public bool HasGlobalError { get; set; } + public String GlobalError { get; set; } + + public RemoteSqlCommandResult() + { + LocalRows = new List<Dictionary<string, object>>(); + GlobalRows = new List<Dictionary<string, object>>(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj index 8a9f617a9..e0c41d7a9 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj @@ -233,6 +233,10 @@ <Compile Include="RemoteJob\RemoteJobProgressEventArgs.cs" /> <Compile Include="RemoteJob\RemoteJobStartedEventArgs.cs" /> <Compile Include="RemoteJob\RemoteJobStoppedEventArgs.cs" /> + <Compile Include="SQL\IRemoteSqlProvider.cs" /> + <Compile Include="SQL\RemoteSqlCommand.cs" /> + <Compile Include="SQL\RemoteSqlCommandMode.cs" /> + <Compile Include="SQL\RemoteSqlCommandResult.cs" /> <Compile Include="Storage\IStorageProvider.cs" /> <Compile Include="Storage\IStorageResult.cs" /> <Compile Include="Storage\SingleStorageResult.cs" /> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/SQL/DefaultRemoteSqlProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/SQL/DefaultRemoteSqlProvider.cs new file mode 100644 index 000000000..19750094e --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/SQL/DefaultRemoteSqlProvider.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.Core; +using Tango.Core.DI; +using Tango.Core.ExtensionMethods; +using Tango.FSE.Common.Connection; +using Tango.FSE.Common.SQL; +using Tango.PPC.Shared.SQL; +using Tango.Transport; + +namespace Tango.FSE.UI.SQL +{ + public class DefaultRemoteSqlProvider : ExtendedObject, IRemoteSqlProvider + { + private List<String> protected_keywords = new List<string>() + { + "DROP", + "DELETE", + "ALTER", + "CREATE" + }; + + private List<String> protected_tables = new List<string>() + { + nameof(DAL.Remote.DB.ACTION_LOGS), + nameof(DAL.Remote.DB.ADDRESS), + nameof(DAL.Remote.DB.APPLICATION_DISPLAY_PANEL_VERSIONS), + nameof(DAL.Remote.DB.APPLICATION_FIRMWARE_VERSIONS), + nameof(DAL.Remote.DB.APPLICATION_OS_VERSIONS), + nameof(DAL.Remote.DB.CARTRIDGE_TYPES), + nameof(DAL.Remote.DB.CCT), + nameof(DAL.Remote.DB.COLOR_CATALOGS), + nameof(DAL.Remote.DB.COLOR_CATALOGS_GROUPS), + nameof(DAL.Remote.DB.COLOR_CATALOGS_ITEMS), + nameof(DAL.Remote.DB.COLOR_CATALOGS_ITEMS_RECIPES), + nameof(DAL.Remote.DB.COLOR_SPACES), + nameof(DAL.Remote.DB.CONTACT), + nameof(DAL.Remote.DB.CUSTOMER), + nameof(DAL.Remote.DB.DISPENSER_TYPES), + nameof(DAL.Remote.DB.EMBEDDED_FIRMWARE_VERSIONS), + nameof(DAL.Remote.DB.EVENT_TYPES), + nameof(DAL.Remote.DB.FIBER_SHAPES), + nameof(DAL.Remote.DB.FIBER_SYNTHS), + nameof(DAL.Remote.DB.FSE_VERSIONS), + nameof(DAL.Remote.DB.HARDWARE_BLOWER_TYPES), + nameof(DAL.Remote.DB.HARDWARE_BREAK_SENSOR_TYPES), + nameof(DAL.Remote.DB.HARDWARE_DANCER_TYPES), + nameof(DAL.Remote.DB.HARDWARE_MOTOR_TYPES), + nameof(DAL.Remote.DB.HARDWARE_PID_CONTROL_TYPES), + nameof(DAL.Remote.DB.HARDWARE_SPEED_SENSOR_TYPES), + nameof(DAL.Remote.DB.HARDWARE_VERSIONS), + nameof(DAL.Remote.DB.HARDWARE_WINDER_TYPES), + nameof(DAL.Remote.DB.IDS_PACK_FORMULAS), + nameof(DAL.Remote.DB.JOB_RUNS), + nameof(DAL.Remote.DB.LINEAR_MASS_DENSITY_UNITS), + nameof(DAL.Remote.DB.LIQUID_TYPES), + nameof(DAL.Remote.DB.LIQUID_TYPES_RMLS), + nameof(DAL.Remote.DB.MACHINES_EVENTS), + nameof(DAL.Remote.DB.MACHINE_STUDIO_VERSIONS), + nameof(DAL.Remote.DB.MACHINE_VERSIONS), + nameof(DAL.Remote.DB.MEDIA_CONDITIONS), + nameof(DAL.Remote.DB.MEDIA_MATERIALS), + nameof(DAL.Remote.DB.MEDIA_PURPOSES), + nameof(DAL.Remote.DB.MID_TANK_TYPES), + nameof(DAL.Remote.DB.PERMISSION), + nameof(DAL.Remote.DB.PROCESS_PARAMETERS_TABLES), + nameof(DAL.Remote.DB.PROCESS_PARAMETERS_TABLES_GROUPS), + nameof(DAL.Remote.DB.PUBLISHED_PROCEDURE_PROJECTS), + nameof(DAL.Remote.DB.PUBLISHED_PROCEDURE_PROJECTS_VERSIONS), + nameof(DAL.Remote.DB.RML), + nameof(DAL.Remote.DB.RMLS_SPOOLS), + nameof(DAL.Remote.DB.ROLE), + nameof(DAL.Remote.DB.ROLES_PERMISSIONS), + nameof(DAL.Remote.DB.SITE), + nameof(DAL.Remote.DB.SITES_CATALOGS), + nameof(DAL.Remote.DB.SITES_RMLS), + nameof(DAL.Remote.DB.SPOOL_TYPES), + nameof(DAL.Remote.DB.TANGO_UPDATES), + nameof(DAL.Remote.DB.TANGO_VERSIONS), + nameof(DAL.Remote.DB.TECH_CONTROLLERS), + nameof(DAL.Remote.DB.TECH_DISPENSERS), + nameof(DAL.Remote.DB.TECH_HEATERS), + nameof(DAL.Remote.DB.TECH_IOS), + nameof(DAL.Remote.DB.TECH_MONITORS), + nameof(DAL.Remote.DB.TECH_VALVES), + nameof(DAL.Remote.DB.USER), + nameof(DAL.Remote.DB.USERS_ROLES), + nameof(DAL.Remote.DB.WINDING_METHODS), + }; + + [TangoInject] + private IMachineProvider MachineProvider { get; set; } + + public async Task<RemoteSqlCommandResult> ExecuteSqlCommandAsync(RemoteSqlCommand command) + { + if (command.Mode == RemoteSqlCommandMode.Global || command.Mode == RemoteSqlCommandMode.Both) + { + ValidateSqlStatement(command.SQL); + } + + LogManager.Log($"Executing remote SQL command:\n{command.ToJsonString()}"); + + RemoteSqlCommandResult result = new RemoteSqlCommandResult(); + + if (command.Mode == RemoteSqlCommandMode.Local || command.Mode == RemoteSqlCommandMode.Both) + { + LogManager.Log("Executing remote SQL command against the remote machine database."); + + try + { + var response = await MachineProvider.MachineOperator.SendGenericRequest<ExecuteSqlRequest, ExecuteSqlResponse>(new ExecuteSqlRequest() + { + SQL = command.SQL + }, new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(command.Timeout) }); + + result.LocalAffectedRecords = response.AffectedRecords; + result.LocalRows = response.Rows.ToList(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Remote SQL command local execution failed."); + result.HasLocalError = true; + result.LocalError = ex.FlattenMessage(); + return result; + } + } + + if (command.Mode == RemoteSqlCommandMode.Global || command.Mode == RemoteSqlCommandMode.Both) + { + LogManager.Log("Executing remote SQL command against the global database."); + + try + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + using (SqlConnection connection = new SqlConnection(db.Database.Connection.ConnectionString)) + { + SqlCommand cmd = new SqlCommand(command.SQL, connection); + cmd.CommandTimeout = command.Timeout; + connection.Open(); + + SqlDataReader reader = await cmd.ExecuteReaderAsync(); + result.GlobalAffectedRecords = reader.RecordsAffected; + + try + { + while (reader.Read()) + { + Dictionary<String, Object> row = new Dictionary<string, object>(); + + for (int i = 0; i < reader.FieldCount; i++) + { + row[reader.GetName(i)] = reader.GetValue(i); + } + + result.GlobalRows.Add(row); + } + } + finally + { + reader.Close(); + } + } + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Remote SQL command remote execution failed."); + result.HasGlobalError = true; + result.GlobalError = ex.FlattenMessage(); + } + } + + LogManager.Log($"Remote SQL command completed with result:\n{result.ToJsonString()}"); + + return result; + } + + private void ValidateSqlStatement(String sql) + { + sql = sql.Trim().ToUpper(); + + foreach (var keyword in protected_keywords) + { + if (sql.Contains(keyword)) + { + throw new InvalidOperationException($"SQL command containing '{keyword}' cannot be executed against the global database."); + } + } + + foreach (var table in protected_tables) + { + if ((sql.Contains("INSERT") || sql.Contains("UPDATE")) && sql.Contains(table)) + { + throw new InvalidOperationException($"SQL command containing INSERT or UPDATE statements cannot be used on table '{table}' when executing against the global database."); + } + } + } + + public RemoteSqlCommandResult ExecuteSqlCommand(RemoteSqlCommand command) + { + return ExecuteSqlCommandAsync(command).Result; + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj b/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj index 99f9d7edd..5c6885c2e 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj @@ -301,6 +301,7 @@ <Compile Include="RemoteUpgrade\DefaultRemoteUpgradeManager.cs" /> <Compile Include="Resolution\DefaultResolutionService.cs" /> <Compile Include="RemoteJob\DefaultRemoteJobProvider.cs" /> + <Compile Include="SQL\DefaultRemoteSqlProvider.cs" /> <Compile Include="Storage\DefaultStorageProvider.cs" /> <Compile Include="Storage\ExplorerControlDialog.xaml.cs"> <DependentUpon>ExplorerControlDialog.xaml</DependentUpon> @@ -596,6 +597,10 @@ <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project> <Name>Tango.Core</Name> </ProjectReference> + <ProjectReference Include="..\..\Tango.DAL.Remote\Tango.DAL.Remote.csproj"> + <Project>{38197109-8610-4d3f-92b9-16d48df94d7c}</Project> + <Name>Tango.DAL.Remote</Name> + </ProjectReference> <ProjectReference Include="..\..\Tango.Emulations\Tango.Emulations.csproj"> <Project>{63561e19-ff5a-414b-a5ef-e30711543e1d}</Project> <Name>Tango.Emulations</Name> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs index 862ade549..13520ec7e 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs @@ -62,6 +62,8 @@ using Tango.FSE.Common.WindowsManager; using Tango.FSE.UI.WindowsManager; using Tango.FSE.Common.DemoMode; using Tango.FSE.UI.DemoMode; +using Tango.FSE.Common.SQL; +using Tango.FSE.UI.SQL; namespace Tango.FSE.UI { @@ -98,6 +100,7 @@ namespace Tango.FSE.UI TangoIOC.Default.Unregister<IRemoteJobProvider>(); TangoIOC.Default.Unregister<IWindowsManager>(); TangoIOC.Default.Unregister<IDemoModeManager>(); + TangoIOC.Default.Unregister<IRemoteSqlProvider>(); //TangoIOC.Default.Unregister<ExternalBridgeScanner>(); //TangoIOC.Default.Unregister<IDiagnosticsFrameProvider>(); //TangoIOC.Default.Unregister<IEventLogger>(); @@ -134,6 +137,7 @@ namespace Tango.FSE.UI TangoIOC.Default.Register<IDashboardManager, DefaultDashboardManager>(); TangoIOC.Default.Register<IWindowsManager, DefaultWindowsManager>(); TangoIOC.Default.Register<IDemoModeManager, DefaultDemoModeManager>(); + TangoIOC.Default.Register<IRemoteSqlProvider, DefaultRemoteSqlProvider>(); TangoIOC.Default.Register<MainWindowVM>(); diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/DefaultRemoteSqlService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/DefaultRemoteSqlService.cs new file mode 100644 index 000000000..986c4d062 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/DefaultRemoteSqlService.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.Core.DI; +using Tango.Integration.ExternalBridge; +using Tango.PPC.Common.ExternalBridge; +using Tango.PPC.Shared.SQL; + +namespace Tango.PPC.Common.SQL +{ + [TangoCreateWhenRegistered] + public class DefaultRemoteSqlService : IRemoteSqlService, IExternalBridgeRequestHandler + { + public bool Enabled { get; set; } = true; + + public DefaultRemoteSqlService(IPPCExternalBridgeService externalBridge) + { + externalBridge.RegisterRequestHandler(this); + } + + [ExternalBridgeRequestHandlerMethod(typeof(ExecuteSqlRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] + public async Task OnExecuteSqlRequest(ExecuteSqlRequest request, String token, ExternalBridgeReceiver receiver) + { + this.ThrowIfDisabled(); + + List<Dictionary<String, Object>> rows = new List<Dictionary<string, object>>(); + int affected = 0; + + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + using (SqlConnection connection = new SqlConnection(db.Database.Connection.ConnectionString)) + { + SqlCommand command = new SqlCommand(request.SQL, connection); + connection.Open(); + + SqlDataReader reader = command.ExecuteReader(); + affected = reader.RecordsAffected; + + try + { + while (reader.Read()) + { + Dictionary<String, Object> row = new Dictionary<string, object>(); + + for (int i = 0; i < reader.FieldCount; i++) + { + row[reader.GetName(i)] = reader.GetValue(i); + } + + rows.Add(row); + } + } + finally + { + reader.Close(); + } + } + } + + await receiver.SendGenericResponse(new ExecuteSqlResponse() + { + Rows = rows, + AffectedRecords = affected + }, token); + } + + public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) + { + + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/IRemoteSqlService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/IRemoteSqlService.cs new file mode 100644 index 000000000..f70589090 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/IRemoteSqlService.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.SQL +{ + public interface IRemoteSqlService : IPPCService + { + + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj b/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj index 6fc24e22a..32f3b865b 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj @@ -176,6 +176,8 @@ <Compile Include="RemoteDesktop\RemoteDesktopClient.cs" /> <Compile Include="RemoteJob\DefaultRemoteJobService.cs" /> <Compile Include="RemoteJob\IRemoteJobService.cs" /> + <Compile Include="SQL\DefaultRemoteSqlService.cs" /> + <Compile Include="SQL\IRemoteSqlService.cs" /> <Compile Include="Synchronization\DefaultMachineDataSynchronizer.cs" /> <Compile Include="Synchronization\IMachineDataSynchronizer.cs" /> <Compile Include="Synchronization\SynchronizationEndedEventArgs.cs" /> @@ -474,7 +476,7 @@ </Target> <ProjectExtensions> <VisualStudio> - <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" /> + <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" /> </VisualStudio> </ProjectExtensions> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlRequest.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlRequest.cs new file mode 100644 index 000000000..7802fc3f7 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlRequest.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.SQL +{ + public class ExecuteSqlRequest + { + public String SQL { get; set; } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlResponse.cs b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlResponse.cs new file mode 100644 index 000000000..4166d8f82 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlResponse.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Shared.SQL +{ + public class ExecuteSqlResponse + { + public int AffectedRecords { get; set; } + public List<Dictionary<String,Object>> Rows { get; set; } + + public ExecuteSqlResponse() + { + Rows = new List<Dictionary<string, object>>(); + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj index 221cea81e..c93aef159 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj +++ b/Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj @@ -88,6 +88,8 @@ <Compile Include="RemoteUpgrade\StartRemoteFirmwareUpgradeResponse.cs" /> <Compile Include="RemoteUpgrade\StartRemoteApplicationUpgradeResponse.cs" /> <Compile Include="RemoteUpgrade\StartRemoteApplicationUpgradeRequest.cs" /> + <Compile Include="SQL\ExecuteSqlRequest.cs" /> + <Compile Include="SQL\ExecuteSqlResponse.cs" /> <Compile Include="Updates\GetUpdatesAndPackagesRequest.cs" /> <Compile Include="Updates\GetUpdatesAndPackagesResponse.cs" /> <Compile Include="Updates\PackageInstallation.cs" /> diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModelLocator.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModelLocator.cs index 95aed6c44..05d844782 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModelLocator.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModelLocator.cs @@ -26,6 +26,7 @@ using Tango.PPC.Common.Printing; using Tango.PPC.Common.RemoteAssistance; using Tango.PPC.Common.RemoteDesktop; using Tango.PPC.Common.RemoteJob; +using Tango.PPC.Common.SQL; using Tango.PPC.Common.Storage; using Tango.PPC.Common.Synchronization; using Tango.PPC.Common.SystemInfo; @@ -90,6 +91,7 @@ namespace Tango.PPC.UI TangoIOC.Default.Unregister<ISystemInfoService>(); TangoIOC.Default.Unregister<IFileSystemService>(); TangoIOC.Default.Unregister<IRemoteJobService>(); + TangoIOC.Default.Unregister<IRemoteSqlService>(); if (App.StartupArgs != null && App.StartupArgs.Contains("-webDebug")) { @@ -129,6 +131,7 @@ namespace Tango.PPC.UI TangoIOC.Default.Register<IFileSystemService, DefaultFileSystemService>(); TangoIOC.Default.Register<IRemoteDesktopService, DefaultRemoteDesktopService>(); TangoIOC.Default.Register<IRemoteJobService, DefaultRemoteJobService>(); + TangoIOC.Default.Register<IRemoteSqlService, DefaultRemoteSqlService>(); TangoIOC.Default.Register<LoadingViewVM>(); TangoIOC.Default.Register<MainViewVM>(); diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/app.manifest b/Software/Visual_Studio/PPC/Tango.PPC.UI/app.manifest index d72e75011..efc5f8179 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/app.manifest +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/app.manifest @@ -16,7 +16,7 @@ Remove this element if your application requires this virtualization for backwards compatibility. --> - <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> + <!--<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />--> </requestedPrivileges> </security> </trustInfo> |
