Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
fe68fcc
Models, setting providers, controller for external requests (draft)
yuskithedeveloper Nov 12, 2025
57f80d3
Models, setting providers
yuskithedeveloper Nov 13, 2025
b7ac441
Comments
yuskithedeveloper Nov 13, 2025
c89cb63
Api key authorization
yuskithedeveloper Nov 13, 2025
c93b0b1
AbstractTypeFactory
yuskithedeveloper Nov 13, 2025
677b923
Compare client, models, controller (draft)
yuskithedeveloper Nov 13, 2025
b2004ea
Comparison result, models
yuskithedeveloper Nov 14, 2025
c4ad9b7
Hashed api key
yuskithedeveloper Nov 14, 2025
6f3b4a6
Settings comparison
yuskithedeveloper Nov 14, 2025
051a1e2
Api environments list
yuskithedeveloper Nov 14, 2025
ff77414
Hashed api key
yuskithedeveloper Nov 14, 2025
8ae3879
App setting sample
yuskithedeveloper Nov 14, 2025
a703a44
SettingsCompareService logic
yuskithedeveloper Nov 14, 2025
8e0c0da
environments-list blade
yuskithedeveloper Nov 17, 2025
e752d14
environments-comparison blade
yuskithedeveloper Nov 17, 2025
fb5ee38
environments-comparison blade
yuskithedeveloper Nov 17, 2025
1bef81d
environments-comparison blade (table layout)
yuskithedeveloper Nov 17, 2025
bda6b34
environments-comparison blade, error and scope styles
yuskithedeveloper Nov 17, 2025
fa27098
environments-comparison blade, changing comparison base
yuskithedeveloper Nov 17, 2025
58ed2be
environments-comparison blade, changing comparison base
yuskithedeveloper Nov 17, 2025
dae9d09
Numbers comparison fix
yuskithedeveloper Nov 17, 2025
65485f9
Refactoring (SonarQube)
yuskithedeveloper Nov 17, 2025
67868e4
Refactoring (SonarQube)
yuskithedeveloper Nov 17, 2025
c5497b8
Providers support for multiple setting scopes
yuskithedeveloper Nov 18, 2025
9ce39ec
BOPIS secret setting magic literal removed
yuskithedeveloper Nov 18, 2025
8a36f9c
Secret settings null value handling
yuskithedeveloper Nov 18, 2025
698ca73
Settings ordering
yuskithedeveloper Nov 18, 2025
66654ff
ComparableAppSettingsProvider
yuskithedeveloper Nov 18, 2025
ba3bc84
ComparableEnvironmentVariablesProvider
yuskithedeveloper Nov 18, 2025
5b076fb
hosting environment, .net and server info
yuskithedeveloper Nov 18, 2025
cf416a1
ComparableModulesProvider
yuskithedeveloper Nov 18, 2025
7cd6616
Minor UI changes
yuskithedeveloper Nov 18, 2025
8a06a42
Not found settings handling
yuskithedeveloper Nov 18, 2025
ba5a794
Object setting type values handling
yuskithedeveloper Nov 18, 2025
a164139
Showing differences only
yuskithedeveloper Nov 18, 2025
68f5637
Localizations
yuskithedeveloper Nov 18, 2025
58c151a
Minor style changes
yuskithedeveloper Nov 18, 2025
fbd8fdd
Readme (by Cursor)
yuskithedeveloper Nov 18, 2025
1e66ea3
Add screenshot to README
yuskithedeveloper Nov 18, 2025
a7199e2
Settings group empty name workaround
yuskithedeveloper Nov 19, 2025
ece7e92
Merge branch 'feat/VCST-3900-environments-compare-initial' of https:/…
yuskithedeveloper Nov 19, 2025
fc0fd2f
Refactoring
yuskithedeveloper Nov 19, 2025
8af0002
Refactoring
yuskithedeveloper Nov 19, 2025
2ee7a8e
No data label
yuskithedeveloper Nov 19, 2025
db486c8
Refactoring
yuskithedeveloper Nov 19, 2025
d18bab8
Refactoring
yuskithedeveloper Nov 19, 2025
9585d5d
Refactoring
yuskithedeveloper Nov 19, 2025
353fe96
Refactoring
yuskithedeveloper Nov 19, 2025
48a52a8
Export API
yuskithedeveloper Nov 19, 2025
666fbf4
Export blade toolbar button
yuskithedeveloper Nov 20, 2025
e1c4c1e
README.md
yuskithedeveloper Nov 20, 2025
9dde791
Empty appSettings.json section handling
yuskithedeveloper Nov 27, 2025
5944bbf
Add setup and usage guide to README
OlegoO Nov 28, 2025
6b9a82f
Refactor authentication to use Virto Commerce API key-based authentic…
OlegoO Nov 28, 2025
0430038
feat: Add ComparableStoreSettingsProvider to retrieve and compare store
OlegoO Nov 28, 2025
541de19
feat: Add configuration whitelist and refactor settings.
OlegoO Dec 3, 2025
d53a917
Refactor CSS and update environments-list.js
OlegoO Dec 3, 2025
f44dd5a
fix: Add search feature and update permissions.
OlegoO Dec 4, 2025
60f9bdf
settings and ui refactoring
OlegoO Dec 4, 2025
76008bc
Update README with new screenshots
OlegoO Dec 4, 2025
5a3c16c
Update README for environment configuration changes
OlegoO Dec 5, 2025
22ff6ae
Refactor EnvironmentResponseItem instantiation.
OlegoO Dec 5, 2025
1963c98
feat: Add environment settings view
OlegoO Dec 5, 2025
829714d
Add setting descriptions and toggle functionality.
OlegoO Dec 5, 2025
92cb34e
Update yaml settings in README.md
kutasinaelena Dec 10, 2025
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
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace VirtoCommerce.EnvironmentsCompare.Core.Models;

public class ComparableEnvironment
{
public string Name { get; set; }

public string Url { get; set; }

public string ApiKey { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Collections.Generic;

namespace VirtoCommerce.EnvironmentsCompare.Core.Models;

public class ComparableEnvironmentSettings
{
public string EnvironmentName { get; set; }

public IList<ComparableSettingScope> SettingScopes { get; set; } = new List<ComparableSettingScope>();

public string ErrorMessage { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace VirtoCommerce.EnvironmentsCompare.Core.Models;

public class ComparableSetting
{
public string Name { get; set; }

public object Value { get; set; }

public bool IsSecret { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;

namespace VirtoCommerce.EnvironmentsCompare.Core.Models;

public class ComparableSettingGroup
{
public string GroupName { get; set; }

public IList<ComparableSetting> Settings { get; set; } = new List<ComparableSetting>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Collections.Generic;

namespace VirtoCommerce.EnvironmentsCompare.Core.Models;

public class ComparableSettingScope
{
/// <summary>
/// Scope of the settings, e.g. "Platform", "AppSettings"
/// </summary>
public string ScopeName { get; set; }

public string ProviderName { get; set; }

public string ErrorMessage { get; set; }

public IList<ComparableSettingGroup> SettingGroups { get; set; } = new List<ComparableSettingGroup>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;

namespace VirtoCommerce.EnvironmentsCompare.Core.Models;

public class ComparedEnvironmentSetting
{
public string Name { get; set; }

public IList<ComparedEnvironmentSettingValue> ComparedValues { get; set; } = new List<ComparedEnvironmentSettingValue>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;

namespace VirtoCommerce.EnvironmentsCompare.Core.Models;

public class ComparedEnvironmentSettingGroup
{
public string GroupName { get; set; }

public IList<ComparedEnvironmentSetting> Settings { get; set; } = new List<ComparedEnvironmentSetting>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;

namespace VirtoCommerce.EnvironmentsCompare.Core.Models;

public class ComparedEnvironmentSettingScope
{
public string ScopeName { get; set; }

public IList<ComparedEnvironmentSettingGroup> SettingGroups { get; set; } = new List<ComparedEnvironmentSettingGroup>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace VirtoCommerce.EnvironmentsCompare.Core.Models;

public class ComparedEnvironmentSettingValue
{
public string EnvironmentName { get; set; }

public object Value { get; set; }

public bool EqualsBaseValue { get; set; }

public string ErrorMessage { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Collections.Generic;

namespace VirtoCommerce.EnvironmentsCompare.Core.Models;

public class SettingsComparisonResult
{
public IList<ComparedEnvironmentSettingScope> SettingScopes { get; set; } = new List<ComparedEnvironmentSettingScope>();
}
8 changes: 8 additions & 0 deletions src/VirtoCommerce.EnvironmentsCompare.Core/ModuleConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,12 @@ public static IEnumerable<SettingDescriptor> AllSettings
}
}
}

public static class EnvironmentsCompare
{
public const string CurrentEnvironmentName = "Current";

public const string ApiKeyHeaderName = "api-key";
public const string SettingsCompareRoute = "api/environments-compare-external";
}
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using VirtoCommerce.EnvironmentsCompare.Core.Models;

namespace VirtoCommerce.EnvironmentsCompare.Core.Services;

public interface IComparableSettingsMasterProvider
{
Task<IList<ComparableSettingScope>> GetAllComparableSettingsAsync();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Threading.Tasks;
using VirtoCommerce.EnvironmentsCompare.Core.Models;

namespace VirtoCommerce.EnvironmentsCompare.Core.Services;

public interface IComparableSettingsProvider
{
Task<ComparableSettingScope> GetComparableSettingsAsync();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using VirtoCommerce.EnvironmentsCompare.Core.Models;

namespace VirtoCommerce.EnvironmentsCompare.Core.Services;

public interface IEnvironmentsCompareClient
{
Task<IList<ComparableEnvironmentSettings>> GetSettingsAsync(IList<ComparableEnvironment> comparableEnvironments);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;
using VirtoCommerce.EnvironmentsCompare.Core.Models;

namespace VirtoCommerce.EnvironmentsCompare.Core.Services;

public interface IEnvironmentsCompareSettingsService
{
string SelfApiKey { get; }
IList<ComparableEnvironment> ComparableEnvironments { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using VirtoCommerce.EnvironmentsCompare.Core.Models;

namespace VirtoCommerce.EnvironmentsCompare.Core.Services;

public interface ISettingsCompareService
{
Task<SettingsComparisonResult> CompareAsync(IList<string> environmentNames, string baseEnvironmentName = null);
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using VirtoCommerce.EnvironmentsCompare.Core.Models;
using VirtoCommerce.EnvironmentsCompare.Core.Services;
using VirtoCommerce.Platform.Core.Common;
using VirtoCommerce.Platform.Core.Settings;

namespace VirtoCommerce.EnvironmentsCompare.Data.Services;

public class ComparableAppSettingsProvider(IConfiguration configuration) : IComparableSettingsProvider
{
public Task<ComparableSettingScope> GetComparableSettingsAsync()
{
var result = AbstractTypeFactory<ComparableSettingScope>.TryCreateInstance();
result.ScopeName = "AppSettings";

var connectionStringsGroup = AbstractTypeFactory<ComparableSettingGroup>.TryCreateInstance();
connectionStringsGroup.GroupName = "ConnectionStrings";
result.SettingGroups.Add(connectionStringsGroup);

var connectionStringSetting = AbstractTypeFactory<ComparableSetting>.TryCreateInstance();
connectionStringSetting.Name = "ConnectionStrings.VirtoCommerce";
connectionStringSetting.Value = configuration.GetValue<string>("ConnectionStrings:VirtoCommerce");
connectionStringSetting.IsSecret = true;
connectionStringsGroup.Settings.Add(connectionStringSetting);

var virtoCommerceGroup = AbstractTypeFactory<ComparableSettingGroup>.TryCreateInstance();
virtoCommerceGroup.GroupName = "VirtoCommerce";
result.SettingGroups.Add(virtoCommerceGroup);

var licenseActivationUrlSetting = AbstractTypeFactory<ComparableSetting>.TryCreateInstance();
licenseActivationUrlSetting.Name = "VirtoCommerce.LicenseActivationUrl";
licenseActivationUrlSetting.Value = configuration.GetValue<string>("VirtoCommerce:LicenseActivationUrl");
licenseActivationUrlSetting.IsSecret = false;
virtoCommerceGroup.Settings.Add(licenseActivationUrlSetting);

return Task.FromResult(result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using VirtoCommerce.EnvironmentsCompare.Core.Models;
using VirtoCommerce.EnvironmentsCompare.Core.Services;
using VirtoCommerce.Platform.Core.Common;
using VirtoCommerce.Platform.Core.Settings;

namespace VirtoCommerce.EnvironmentsCompare.Data.Services;

public class ComparablePlatformSettingsProvider(ISettingsManager settingsManager) : IComparableSettingsProvider
{
public async Task<ComparableSettingScope> GetComparableSettingsAsync()
{
var result = AbstractTypeFactory<ComparableSettingScope>.TryCreateInstance();
result.ScopeName = "PlatformSettings";

foreach (var group in settingsManager.AllRegisteredSettings
.Where(x => !x.GroupName.IsNullOrEmpty())
.GroupBy(x => x.GroupName))
{
var resultGroup = AbstractTypeFactory<ComparableSettingGroup>.TryCreateInstance();
resultGroup.GroupName = group.Key;
result.SettingGroups.Add(resultGroup);

foreach (var setting in group)
{
var resultSetting = AbstractTypeFactory<ComparableSetting>.TryCreateInstance();
resultSetting.Name = setting.Name;
resultSetting.Value = await GetSettingValueAsync(setting);
resultSetting.IsSecret = IsSettingSecret(setting);
resultGroup.Settings.Add(resultSetting);
}
}

return result;
}

protected async Task<object> GetSettingValueAsync(SettingDescriptor settingDescriptor)
{
if (settingDescriptor.ValueType == SettingValueType.Boolean)
{
return await settingsManager.GetValueAsync<bool>(settingDescriptor);
}

if (settingDescriptor.ValueType == SettingValueType.Integer || settingDescriptor.ValueType == SettingValueType.PositiveInteger)
{
return await settingsManager.GetValueAsync<int>(settingDescriptor);
}

if (settingDescriptor.ValueType == SettingValueType.Decimal)
{
return await settingsManager.GetValueAsync<decimal>(settingDescriptor);
}

if (settingDescriptor.ValueType == SettingValueType.DateTime)
{
return await settingsManager.GetValueAsync<DateTime>(settingDescriptor);
}

if (settingDescriptor.ValueType == SettingValueType.Json)
{
return await settingsManager.GetValueAsync<string>(settingDescriptor);
}

if ((settingDescriptor.ValueType == SettingValueType.SecureString || settingDescriptor.ValueType == SettingValueType.ShortText || settingDescriptor.ValueType == SettingValueType.LongText))
{
return await settingsManager.GetValueAsync<string>(settingDescriptor);
}

return null;//TODO: handle other types
}

protected virtual bool IsSettingSecret(SettingDescriptor setting)
{
return setting.ValueType == SettingValueType.SecureString || setting.Name.EqualsIgnoreCase("Shipping.Bopis.GoogleMaps.ApiKey");//TODO: implement some flag in SettingDescriptor
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using VirtoCommerce.EnvironmentsCompare.Core.Models;
using VirtoCommerce.EnvironmentsCompare.Core.Services;
using VirtoCommerce.Platform.Core.Common;

namespace VirtoCommerce.EnvironmentsCompare.Data.Services;

public class ComparableSettingsMasterProvider(IEnumerable<IComparableSettingsProvider> comparableSettingsProviders) : IComparableSettingsMasterProvider
{
public async Task<IList<ComparableSettingScope>> GetAllComparableSettingsAsync()
{
var result = new List<ComparableSettingScope>();

foreach (var provider in comparableSettingsProviders)
{
result.Add(await GetSettingsFromProviderAsync(provider));
}

HideSecretSettings(result.SelectMany(x => x.SettingGroups).SelectMany(x => x.Settings));

return result;
}

protected async Task<ComparableSettingScope> GetSettingsFromProviderAsync(IComparableSettingsProvider comparableSettingsProvider)
{
ComparableSettingScope result;

try
{
result = await comparableSettingsProvider.GetComparableSettingsAsync();

if (result == null)
{
throw new InvalidOperationException("The provider returned null settings group");
}
}
catch (Exception ex)
{
result = AbstractTypeFactory<ComparableSettingScope>.TryCreateInstance();
result.ErrorMessage = ex.Message;
}

result.ProviderName = comparableSettingsProvider.GetType().FullName;

return result;
}

protected virtual void HideSecretSettings(IEnumerable<ComparableSetting> settings)
{
foreach (var setting in settings.Where(x => x.IsSecret))
{
setting.Value = $"HASH: {setting.Value?.GetSHA1Hash()}";
}
}
}
Loading
Loading