Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@ end_of_line = crlf
trim_trailing_whitespace = true

[*.cs]
dotnet_sort_system_directives_first = true
dotnet_sort_system_directives_first = true

# Skyline ignores
dotnet_diagnostic.SLC_SC0001.severity = none
dotnet_diagnostic.SLC_SC0002.severity = none
424 changes: 0 additions & 424 deletions .github/workflows/DataMiner App Packages Master Workflow Custom.yml

This file was deleted.

21 changes: 8 additions & 13 deletions .github/workflows/complete.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ name: Skyline Reusable Quality Workflow
on:
# Triggers the workflow on push or pull request events but only for the master branch
Comment thread
ArneMaes0 marked this conversation as resolved.
push:
branches: []
branches:
- '**'
tags:
- "[0-9]+.[0-9]+.[0-9]+.[0-9]+"
- "[0-9]+.[0-9]+.[0-9]+.[0-9]+-**"
Expand All @@ -18,17 +19,11 @@ on:
jobs:

CI:
uses: SkylineCommunications/Low-Code-App-Editor/.github/workflows/DataMiner App Packages Master Workflow Custom.yml@main
uses: SkylineCommunications/_ReusableWorkflows/.github/workflows/Master Workflow.yml@main
with:
configuration: Release
referenceName: ${{ github.ref_name }}
runNumber: ${{ github.run_number }}
referenceType: ${{ github.ref_type }}
repository: ${{ github.repository }}
owner: ${{ github.repository_owner }}
sonarCloudProjectName: ${{ vars.SONAR_NAME }} # Go to 'https://sonarcloud.io/projects/create' and create a project. Then create a SONAR_NAME variable with the ID of the project as mentioned in the SonarCloud project URL.
# solutionFilterName: "MySolutionFilter.slnf"
sonarcloud-project-name: ${{ vars.SONAR_NAME }} # Go to 'https://sonarcloud.io/projects/create' and create a project. Then create a SONAR_NAME variable with the ID of the project as mentioned in the SonarCloud project URL.
# solution-filter-name: "MySolutionFilter.slnf"
secrets:
dataminerToken: ${{ secrets.DATAMINER_TOKEN }} # The API key: generated in the DCP Admin app (https://admin.dataminer.services/) as authentication for a certain organization.
sonarCloudToken: ${{ secrets.SONAR_TOKEN }} # The API key for access to SonarCloud.
# overrideCatalogDownloadToken: ${{ secrets.OVERRIDE_DATAMINER_TOKEN }} # Override on the dataminerToken for downloading Catalog items: generated in the DCP Admin app (https://admin.dataminer.services/) as authentication for a certain organization.
DATAMINER_TOKEN: ${{ secrets.DATAMINER_TOKEN }} # The API key: generated in the DCP Admin app (https://admin.dataminer.services/) as authentication for a certain organization.
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # The API key for access to SonarCloud.
# OVERRIDE_CATALOG_DOWNLOAD_TOKEN: ${{ secrets.OVERRIDE_DATAMINER_TOKEN }} # Override on the dataminerToken for downloading Catalog items: generated in the DCP Admin app (https://admin.dataminer.services/) as authentication for a certain organization.
2 changes: 2 additions & 0 deletions Documentation/CHANGELOG_1.0.1-CU20.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
**New Feature**
- New option to include or exclude the security config from the export. (not included by default)
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<TargetFramework>net48</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<RootNamespace>Install_1</RootNamespace>
<SonarQubeExclude>true</SonarQubeExclude>
</PropertyGroup>
<PropertyGroup>
<DataMinerType>AutomationScript</DataMinerType>
Expand All @@ -15,7 +16,7 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="Skyline.DataMiner.Core.AppPackageInstaller" Version="4.0.0" />
<PackageReference Include="Skyline.DataMiner.Dev.Automation" Version="10.3.3" />
<PackageReference Include="Skyline.DataMiner.Utils.SecureCoding.Analyzers" Version="2.2.1">
<PackageReference Include="Skyline.DataMiner.Utils.SecureCoding.Analyzers" Version="2.2.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 0 additions & 2 deletions Low Code App Editor Package/Low Code App Editor Package.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,6 @@ public void Install(Engine engine, AppInstallContext context)
var installer = new AppInstaller(Engine.SLNetRaw, context);
installer.InstallDefaultContent();

// Custom installation logic can be added here for each individual install package.

// Create a symbolic link to the WebApiLib.dll
Action<string> logger = installer.Log;
Engine.SLNetRaw.CreateSymbolicLink(WebApiLib_ProtocolScripts_Path, WebApiLib_WebPages_Path, logger);
Expand Down
44 changes: 43 additions & 1 deletion Low Code App Editor Package/Low Code App Editor Package.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<ItemGroup>
<PackageReference Include="Skyline.DataMiner.Core.AppPackageInstaller" Version="4.0.0" />
<PackageReference Include="Skyline.DataMiner.Dev.Automation" Version="10.3.3" />
<PackageReference Include="Skyline.DataMiner.Utils.SecureCoding.Analyzers" Version="2.2.1">
<PackageReference Include="Skyline.DataMiner.Utils.SecureCoding.Analyzers" Version="2.2.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand All @@ -25,4 +25,46 @@
<!-- Exclude the project from analysis -->
<SonarQubeExclude>true</SonarQubeExclude>
</PropertyGroup>

<UsingTask TaskName="RemoveZipEntry" TaskFactory="RoslynCodeTaskFactory" AssemblyFile="$([System.IO.Path]::Combine($(MSBuildToolsPath), 'Microsoft.Build.Tasks.Core.dll'))">
<ParameterGroup>
<ZipFilePath ParameterType="System.String" Required="true" />
<EntryPath ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Using Namespace="System.IO.Compression" />
<Using Namespace="System.Linq" />
<Code Type="Fragment" Language="cs">
<![CDATA[
if (!System.IO.File.Exists(ZipFilePath))
{
Log.LogWarning("dmapp not found, skipping entry removal: " + ZipFilePath);
return true;
}
using (var archive = ZipFile.Open(ZipFilePath, ZipArchiveMode.Update))
{
var normalizedEntry = EntryPath.Replace('\\', '/');
var entry = archive.Entries.FirstOrDefault(e =>
string.Equals(e.FullName.Replace('\\', '/'), normalizedEntry, System.StringComparison.OrdinalIgnoreCase));
if (entry != null)
{
entry.Delete();
Log.LogMessage(MessageImportance.High, "Removed '" + entry.FullName + "' from " + ZipFilePath);
}
else
{
Log.LogMessage(MessageImportance.High, "Entry '" + EntryPath + "' not found in zip, nothing to remove.");
}
}
]]>
</Code>
</Task>
</UsingTask>

<Target Name="RemoveWebApiLibFromDmapp" AfterTargets="DmappCreation">
<PropertyGroup>
<DmappFile>$(MSBuildProjectDirectory)\$(OutputPath)DataMinerBuild\$(AssemblyName).$(Version).dmapp</DmappFile>
</PropertyGroup>
<RemoveZipEntry ZipFilePath="$(DmappFile)" EntryPath="AppInstallContent/Assemblies/ProtocolScripts/DllImport/WebApiLib.dll" />
</Target>
</Project>
76 changes: 60 additions & 16 deletions Low Code App Editor/Controllers/ExportController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class ExportController
{
public static readonly string ScriptPath = @"C:\Skyline DataMiner\Scripts";
public static readonly string DllImportPath = @"C:\Skyline DataMiner\ProtocolScripts\DllImport";
public static readonly string SolutionLibrariesPath = @"C:\Skyline DataMiner\ProtocolScripts\DllImport\SolutionLibraries";
public static readonly string LowCodeAppEditorPath = @"C:\Skyline DataMiner\Documents\Low Code App Editor";
public static readonly string LowCodeAppEditorExportPath = @"C:\Skyline DataMiner\Documents\DMA_COMMON_DOCUMENTS\Low Code Apps Exports";
public static readonly string ThemesPath = @"C:\Skyline DataMiner\dashboards\Themes.json";
Expand All @@ -47,7 +48,7 @@ private static string ExportPackage(IEngine engine, IEnumerable<App> apps, Expor
exportPath = Path.Combine(LowCodeAppEditorExportPath, $"{apps.First().Name}_{now.ToString("yyyy-MM-dd HH-mm-ss")}_App_Export.zip");
}

engine.GenerateInformation($"Export Path: {exportPath}");
engine.Log($"Export Path: {exportPath}");

if (!Directory.Exists(Path.GetDirectoryName(exportPath)))
{
Expand All @@ -57,7 +58,7 @@ private static string ExportPackage(IEngine engine, IEnumerable<App> apps, Expor
using (var fs = new FileStream(exportPath, FileMode.Create))
using (var zip = new ZipArchive(fs, ZipArchiveMode.Create))
{
engine.GenerateInformation($"Adding Package Information");
engine.Log($"Adding Package Information");

// Package Information
var info = apps.Count() == 1 ? PackageInfo.FromApp(apps.First()) : PackageInfo.FromApp();
Expand Down Expand Up @@ -85,47 +86,47 @@ private static string ExportPackage(IEngine engine, IEnumerable<App> apps, Expor
var themes = new List<DMADashboardTheme>();
foreach (var app in apps)
{
engine.GenerateInformation($"Adding App");
engine.Log($"Adding App");

// Add the app as CompanionFiles
AddAppToArchive(zip, app, options);

if (options.ExcludeScripts)
if (!options.ExcludeScripts)
{
engine.GenerateInformation("Skipping Automation Scripts");
engine.Log($"Adding Scripts");
AddScriptsToArchive(zip, app);
}
else
{
engine.GenerateInformation($"Adding Scripts");
AddScriptsToArchive(zip, app);
engine.Log("Skipping Automation Scripts");
}

if (!options.ExcludeDom)
{
// Add Dom definitions
engine.GenerateInformation($"Adding DOM modules, for app '{app.Name}'");
engine.Log($"Adding DOM modules, for app '{app.Name}'");
domModuleIds.AddRangeUnique(app.LatestVersion.GetUsedDomModules());
AddDomToArchive(engine, zip, domModuleIds, options);
}

if (!options.ExcludeImages)
{
// Add Images to companion files
engine.GenerateInformation($"Adding Images, for app '{app.Name}'");
engine.Log($"Adding Images, for app '{app.Name}'");
images.AddRangeUnique(app.LatestVersion.GetUsedImages());
AddImagesToArchive(zip, images);
}

if (!options.ExcludeThemes)
{
// Add Theme
engine.GenerateInformation($"Adding Themes, for app '{app.Name}'");
engine.Log($"Adding Themes, for app '{app.Name}'");
themes.AddRangeUnique(app.LatestVersion.GetUsedThemes());
AddThemesToArchive(zip, themes);
}
}

engine.GenerateInformation($"Adding Installer code");
engine.Log($"Adding Installer code");

// Add custom Low Code App Installer Code
zip.CreateEntryFromDirectory(LowCodeAppEditorPath, "Scripts");
Expand All @@ -148,7 +149,7 @@ private static string ExportPackage(IEngine engine, IEnumerable<App> apps, Expor
sb.AppendLine($"Script\\{Path.GetDirectoryName(file.FullName)}");
}

foreach(var dependency in zip.GetEntries("AppInstallContent\\Assemblies").Where(x => !x.FullName.EndsWith("\\")))
foreach (var dependency in zip.GetEntries("AppInstallContent\\Assemblies").Where(x => !x.FullName.EndsWith("\\")))
{
sb.AppendLine(dependency.FullName);
}
Expand Down Expand Up @@ -178,18 +179,50 @@ private static void AddAppToArchive(ZipArchive zip, App app, ExportOptions optio
app = app ?? throw new ArgumentNullException(nameof(app));
options = options ?? throw new ArgumentNullException(nameof(options));

if (!options.IncludeSecuritySettings)
{
// Strip the security settings from the app settings file before adding to the archive
var appSettingsPath = Path.Combine(app.Path, "App.info.json");
var appSettings = JObject.Parse(File.ReadAllText(appSettingsPath));
if (appSettings.TryGetValue("Security", out var securityToken) &&
securityToken is JObject securitySettings)
{
if (securitySettings.TryGetValue("AllowEdit", out var allowEditToken) &&
allowEditToken is JArray allowEdits &&
allowEdits.Count > 0)
{
allowEdits.Clear();
}

if (securitySettings.TryGetValue("AllowView", out var allowViewToken) &&
allowViewToken is JArray allowViews &&
allowViews.Count > 0)
{
allowViews.Clear();
}
}

zip.CreateEntryFromText(Path.Combine("AppInstallContent", "CompanionFiles", "LCA", app.LatestVersion.ID, "App.info.json"), appSettings.ToString(Formatting.None, Array.Empty<JsonConverter>()));
}
else
{
zip.CreateEntryFromFile(app.PathSettings, Path.Combine("AppInstallContent", "CompanionFiles", "LCA", app.LatestVersion.ID, "App.info.json"));
}

if (!options.IncludeVersions)
{
// Just include the general .json file and the latest version
zip.CreateEntryFromDirectory(app.Path, Path.Combine("AppInstallContent", "CompanionFiles", "LCA", app.LatestVersion.ID), false);
zip.CreateEntryFromDirectory(Path.Combine(app.Path, $"version_{app.LatestVersion.Version} "), Path.Combine("AppInstallContent", "CompanionFiles", "LCA", app.LatestVersion.ID, $"version_{app.LatestVersion.Version}"), true);
if (app.LatestDraftVersion != null)
zip.CreateEntryFromDirectory(Path.Combine(app.Path, $"version_{app.LatestDraftVersion.Version} "), Path.Combine("AppInstallContent", "CompanionFiles", "LCA", app.LatestDraftVersion.ID, $"version_{app.LatestDraftVersion.Version}"), true);
}
else
{
// Include everything
zip.CreateEntryFromDirectory(app.Path, Path.Combine("AppInstallContent", "CompanionFiles", "LCA", app.LatestVersion.ID));
foreach (var directory in Directory.GetDirectories(app.Path, "version_*"))
{
zip.CreateEntryFromDirectory(directory, Path.Combine("AppInstallContent", "CompanionFiles", "LCA", app.LatestVersion.ID, Path.GetFileNameWithoutExtension(directory)), true);
}
Comment thread
ArneMaes0 marked this conversation as resolved.
}
}

Expand All @@ -209,7 +242,7 @@ private static void AddScriptToArchive(ZipArchive zip, App app, string script, L
var scriptPath = Path.Combine(ScriptPath, scriptName);
if (File.Exists(scriptPath))
{
if(addedFiles.Exists(x => x == $"AppInstallContent\\Scripts\\{script}\\Script_{script}.xml"))
if (addedFiles.Exists(x => x == $"AppInstallContent\\Scripts\\{script}\\Script_{script}.xml"))
{
return;
}
Expand Down Expand Up @@ -262,12 +295,18 @@ private static void AddDependenciesToArchive(ZipArchive zip, App app, string scr
var refParams = doc.Descendants(ns + "Param").Where(param => (string)param.Attribute("type") == "ref");
foreach (var reference in refParams.Select(refParam => refParam.Value))
{
if (reference.StartsWith(SolutionLibrariesPath, StringComparison.InvariantCultureIgnoreCase))
{
Comment thread
ArneMaes0 marked this conversation as resolved.
// DevPacks should be excluded
continue;
}

if (addedFiles.Exists(x => x == reference.Replace(@"C:\Skyline DataMiner", "AppInstallContent\\Assemblies")))
{
continue;
}

if (reference.StartsWith(DllImportPath))
if (reference.StartsWith(DllImportPath, StringComparison.InvariantCultureIgnoreCase))
{
zip.CreateEntryFromFile(reference, reference.Replace(@"C:\Skyline DataMiner", "AppInstallContent\\Assemblies"));
addedFiles.Add(reference.Replace(@"C:\Skyline DataMiner", "AppInstallContent\\Assemblies"));
Expand Down Expand Up @@ -347,6 +386,8 @@ public class ExportOptions

public bool OverwriteThemes { get; set; }

public bool IncludeSecuritySettings { get; set; }

public static ExportOptions FromDialog(ExportDialog dialog)
{
return new ExportOptions
Expand All @@ -361,6 +402,9 @@ public static ExportOptions FromDialog(ExportDialog dialog)
SyncImages = dialog.SyncImages.IsChecked,
ExcludeThemes = dialog.ExcludeThemes.IsChecked,
SyncThemes = dialog.SyncThemes.IsChecked,
OverrideImages = dialog.OverwriteImages.IsChecked,
OverwriteThemes = dialog.OverwriteThemes.IsChecked,
IncludeSecuritySettings = dialog.IncludeSecuritySettings.IsChecked,
};
}
}
Expand Down
8 changes: 4 additions & 4 deletions Low Code App Editor/LCA/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Low_Code_App_Editor.LCA

using Newtonsoft.Json;

using Skyline.DataMiner.Utils.SecureCoding.SecureSerialization.Json.Newtonsoft;
using Skyline.DataMiner.Web.Common.v1;

public class App
Expand All @@ -24,14 +25,13 @@ public class App
},
};


public App(string path)
{
Path = path;

// Load general settings file
var settingsFile = File.ReadAllText(System.IO.Path.Combine(path, "App.info.json"));
Settings = JsonConvert.DeserializeObject<DMAApplicationVersionInfo>(settingsFile);
Settings = SecureNewtonsoftDeserialization.DeserializeObject<DMAApplicationVersionInfo>(settingsFile);

// Load version history
var versions = new string[0];
Expand All @@ -49,7 +49,7 @@ public App(string path)
var versionPath = System.IO.Path.Combine(versionDirectory, "App.config.json");
if (File.Exists(versionPath))
{
var version = JsonConvert.DeserializeObject<AppVersion>(File.ReadAllText(versionPath), settings);
var version = SecureNewtonsoftDeserialization.DeserializeObject<AppVersion>(File.ReadAllText(versionPath), settings);
version.Path = versionPath;
Versions.Add(version);
}
Expand All @@ -65,7 +65,7 @@ public App(string path)
var versionPath = System.IO.Path.Combine(versionDirectory, "App.config.json");
if (File.Exists(versionPath))
{
var version = JsonConvert.DeserializeObject<AppVersion>(File.ReadAllText(versionPath), settings);
var version = SecureNewtonsoftDeserialization.DeserializeObject<AppVersion>(File.ReadAllText(versionPath), settings);
version.Path = versionPath;
Versions.Add(version);
}
Expand Down
9 changes: 5 additions & 4 deletions Low Code App Editor/Low Code App Editor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@ Ambachtenstraat 33

DATE VERSION AUTHOR COMMENTS

02/12/2024 1.0.0.16 AMA, Skyline Changed some of the names of the Export Dialog to be more readable.
27/12/2024 1.0.0.17 AMA, Skyline Added extra check before casting to DMADashboardQueryData when exporting apps.
10/04/2025 1.0.0.18 AMA, Skyline Fixed bug where you could import pages/panels from your own app. Added duplicate functionality for pages/panels.
10/04/2025 1.0.0.19 AMA, Skyline Fixed bug when deserializing to dynamic properties. Expanded the DOM module search in queries to also look in joins
05/12/2024 1.0.1-CU15 AMA, Skyline Changed some of the names of the Export Dialog to be more readable.
27/12/2024 1.0.1-CU16 AMA, Skyline Added extra check before casting to DMADashboardQueryData when exporting apps.
10/04/2025 1.0.1-CU17 AMA, Skyline Fixed bug where you could import pages/panels from your own app. Added duplicate functionality for pages/panels.
06/05/2025 1.0.1-CU18 AMA, Skyline Fixed bug when deserializing to dynamic properties. Expanded the DOM module search in queries to also look in joins
14/05/2025 1.0.1-CU19 AMA, Skyline Installer will now create a symbolic link to the WebApiLib.dll
Comment thread
ArneMaes0 marked this conversation as resolved.
****************************************************************************
*/

Expand Down
3 changes: 2 additions & 1 deletion Low Code App Editor/Low Code App Editor.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="Skyline.DataMiner.Dev.Automation" Version="10.3.3" />
<PackageReference Include="Skyline.DataMiner.Utils.InteractiveAutomationScriptToolkit.Preview" Version="0.0.0" />
<PackageReference Include="Skyline.DataMiner.Utils.SecureCoding.Analyzers" Version="2.2.1">
<PackageReference Include="Skyline.DataMiner.Utils.SecureCoding" Version="2.2.3" />
<PackageReference Include="Skyline.DataMiner.Utils.SecureCoding.Analyzers" Version="2.2.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
Loading
Loading