aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio
diff options
context:
space:
mode:
authorRoy Ben Shabat <Roy.mail.net@gmail.com>2020-07-29 21:12:47 +0300
committerRoy Ben Shabat <Roy.mail.net@gmail.com>2020-07-29 21:12:47 +0300
commit08bd8bac1498b6aa3bd264e5c466dd65a4386fd2 (patch)
tree1fb311c11e4975663957aa218ab818beb90528ac /Software/Visual_Studio
parentbdf7e5a2abc2c9d3b7889d2d71754c33ea3efbf6 (diff)
downloadTango-08bd8bac1498b6aa3bd264e5c466dd65a4386fd2.tar.gz
Tango-08bd8bac1498b6aa3bd264e5c466dd65a4386fd2.zip
Procedures SQL, Resources, Variables.
Diffstat (limited to 'Software/Visual_Studio')
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/IProcedureContext.cs49
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureContext.cs65
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureProject.cs6
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureResource.cs33
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ProcedureVariable.cs14
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Resources/lib_template.csx1
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Resources/main_template.csx1
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/SqlResult.cs19
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Tango.FSE.Procedures.csproj7
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/ViewModels/ProcedureDesignerViewVM.cs109
-rw-r--r--Software/Visual_Studio/FSE/Modules/Tango.FSE.Procedures/Views/ProcedureDesignerView.xaml48
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/IRemoteSqlProvider.cs16
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/RemoteSqlCommand.cs20
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/RemoteSqlCommandMode.cs27
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/SQL/RemoteSqlCommandResult.cs27
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj4
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/SQL/DefaultRemoteSqlProvider.cs210
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj5
-rw-r--r--Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs4
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/DefaultRemoteSqlService.cs76
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/SQL/IRemoteSqlService.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj4
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlRequest.cs13
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/SQL/ExecuteSqlResponse.cs19
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.Shared/Tango.PPC.Shared.csproj2
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/ViewModelLocator.cs3
-rw-r--r--Software/Visual_Studio/PPC/Tango.PPC.UI/app.manifest2
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>