diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainSharedModule.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainSharedModule.cs index 0c9a2e0f26..04edbfbbc2 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainSharedModule.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainSharedModule.cs @@ -1,5 +1,6 @@ using Volo.Abp.FeatureManagement.Localization; using Volo.Abp.Localization; +using Volo.Abp.Localization.ExceptionHandling; using Volo.Abp.Modularity; using Volo.Abp.Validation; using Volo.Abp.Validation.Localization; @@ -27,6 +28,11 @@ namespace Volo.Abp.FeatureManagement typeof(AbpValidationResource) ).AddVirtualJson("Volo/Abp/FeatureManagement/Localization/Domain"); }); + + Configure(options => + { + options.MapCodeNamespace("Volo.Abp.FeatureManagement", typeof(AbpFeatureManagementResource)); + }); } } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/FeatureManagementDomainErrorCodes.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/FeatureManagementDomainErrorCodes.cs index 010c64efbb..9bcfd3290e 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/FeatureManagementDomainErrorCodes.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/FeatureManagementDomainErrorCodes.cs @@ -1,7 +1,9 @@ -namespace Volo.Abp.FeatureManagement +using System; + +namespace Volo.Abp.FeatureManagement { public static class FeatureManagementDomainErrorCodes { - + public const string FeatureValueInvalid = "Volo.Abp.FeatureManagement:InvalidFeatureValue"; } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/FeatureValueInvalidException.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/FeatureValueInvalidException.cs new file mode 100644 index 0000000000..d003295239 --- /dev/null +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/FeatureValueInvalidException.cs @@ -0,0 +1,14 @@ +using System; + +namespace Volo.Abp.FeatureManagement +{ + [Serializable] + public class FeatureValueInvalidException : BusinessException + { + public FeatureValueInvalidException(string name) : + base(FeatureManagementDomainErrorCodes.FeatureValueInvalid) + { + WithData("0", name); + } + } +} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/ar.json b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/ar.json index fcc347b9e3..cc5fae2dff 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/ar.json +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/ar.json @@ -2,6 +2,7 @@ "culture": "ar", "texts": { "Features": "المميزات", - "NoFeatureFoundMessage": "لا توجد أي ميزة متاحة." + "NoFeatureFoundMessage": "لا توجد أي ميزة متاحة.", + "Volo.Abp.FeatureManagement:InvalidFeatureValue" : "{0} قيمة الميزة غير صالحة!" } -} \ No newline at end of file +} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/de.json b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/de.json index 12a4e1aef0..c6d4bb1d07 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/de.json +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/de.json @@ -2,6 +2,7 @@ "culture": "de", "texts": { "Features": "Funktionen", - "NoFeatureFoundMessage": "Es ist keine Funktion verfügbar." + "NoFeatureFoundMessage": "Es ist keine Funktion verfügbar.", + "Volo.Abp.FeatureManagement:InvalidFeatureValue" : "Der {0} -Feature-Wert ist ungültig!" } -} \ No newline at end of file +} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/en.json b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/en.json index 26f5dc736b..c5194de6c7 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/en.json +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/en.json @@ -4,6 +4,7 @@ "Features": "Features", "NoFeatureFoundMessage": "There isn't any available feature.", "Permission:FeatureManagement": "Feature management", - "Permission:FeatureManagement.ManageHostFeatures": "Manage Host features" + "Permission:FeatureManagement.ManageHostFeatures": "Manage Host features", + "Volo.Abp.FeatureManagement:InvalidFeatureValue" : "{0} feature value is not valid!" } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/ru.json b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/ru.json index 3945762269..d232c20060 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/ru.json +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/ru.json @@ -2,6 +2,7 @@ "culture": "ru", "texts": { "Features": "Функциональные возможности", - "NoFeatureFoundMessage": "Нет доступных функциональных возможностей." + "NoFeatureFoundMessage": "Нет доступных функциональных возможностей.", + "Volo.Abp.FeatureManagement:InvalidFeatureValue" : "Недопустимое значение функции {0}!" } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/tr.json b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/tr.json index 8233674933..b69674a620 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/tr.json +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/tr.json @@ -4,6 +4,7 @@ "Features": "Özellikler", "NoFeatureFoundMessage": "Hiç özellik yok.", "Permission:FeatureManagement": "Özellik yönetimi", - "Permission:FeatureManagement.ManageHostFeatures": "Host özelliklerini düzenle" + "Permission:FeatureManagement.ManageHostFeatures": "Host özelliklerini düzenle", + "Volo.Abp.FeatureManagement:InvalidFeatureValue" : "{0} özellik değeri geçerli değil!" } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/zh-Hans.json b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/zh-Hans.json index 9737a9a59c..473f581b34 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/zh-Hans.json +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/zh-Hans.json @@ -4,6 +4,7 @@ "Features": "功能", "NoFeatureFoundMessage": "没有可用的功能.", "Permission:FeatureManagement": "特性管理", - "Permission:FeatureManagement.ManageHostFeatures": "管理Host特性" + "Permission:FeatureManagement.ManageHostFeatures": "管理Host特性", + "Volo.Abp.FeatureManagement:InvalidFeatureValue" : "{0}功能的值无效!" } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/zh-Hant.json b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/zh-Hant.json index 7d68fd5bc2..dc84e7c104 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/zh-Hant.json +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared/Volo/Abp/FeatureManagement/Localization/Domain/zh-Hant.json @@ -4,6 +4,7 @@ "Features": "功能", "NoFeatureFoundMessage": "沒有可用的功能.", "Permission:FeatureManagement": "功能管理", - "Permission:FeatureManagement.ManageHostFeatures": "管理Host功能" + "Permission:FeatureManagement.ManageHostFeatures": "管理Host功能", + "Volo.Abp.FeatureManagement:InvalidFeatureValue" : "{0}功能的值無效!" } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs index 454ade5476..38c61cc743 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; using Volo.Abp.Features; @@ -14,15 +15,18 @@ namespace Volo.Abp.FeatureManagement protected IFeatureDefinitionManager FeatureDefinitionManager { get; } protected List Providers => _lazyProviders.Value; protected FeatureManagementOptions Options { get; } + protected IStringLocalizerFactory StringLocalizerFactory { get; } private readonly Lazy> _lazyProviders; public FeatureManager( IOptions options, IServiceProvider serviceProvider, - IFeatureDefinitionManager featureDefinitionManager) + IFeatureDefinitionManager featureDefinitionManager, + IStringLocalizerFactory stringLocalizerFactory) { FeatureDefinitionManager = featureDefinitionManager; + StringLocalizerFactory = stringLocalizerFactory; Options = options.Value; //TODO: Instead, use IHybridServiceScopeFactory and create a scope..? @@ -57,7 +61,8 @@ namespace Volo.Abp.FeatureManagement .Select(x => new FeatureNameValue(x.Name, x.Value)).ToList(); } - public async Task GetOrNullWithProviderAsync(string name, string providerName, string providerKey, bool fallback = true) + public async Task GetOrNullWithProviderAsync(string name, + string providerName, string providerKey, bool fallback = true) { Check.NotNull(name, nameof(name)); Check.NotNull(providerName, nameof(providerName)); @@ -65,7 +70,8 @@ namespace Volo.Abp.FeatureManagement return await GetOrNullInternalAsync(name, providerName, providerKey, fallback); } - public async Task> GetAllWithProviderAsync(string providerName, string providerKey, bool fallback = true) + public async Task> GetAllWithProviderAsync(string providerName, + string providerKey, bool fallback = true) { Check.NotNull(providerName, nameof(providerName)); @@ -128,6 +134,11 @@ namespace Volo.Abp.FeatureManagement var feature = FeatureDefinitionManager.Get(name); + if (!feature.ValueType.Validator.IsValid(value)) + { + throw new FeatureValueInvalidException(feature.DisplayName.Localize(StringLocalizerFactory)); + } + var providers = Enumerable .Reverse(Providers) .SkipWhile(p => p.Name != providerName) diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml index deb24accc8..a5592c2f28 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml @@ -24,55 +24,80 @@ @if (Model.FeatureListResultDto != null && Model.FeatureListResultDto.Groups.Any()) { + var featureGroups = Model.FeatureListResultDto.Groups; + - @for (var i = 0; i < Model.FeatureListResultDto.Groups.Count; i++) + @for (var i = 0; i < featureGroups.Count; i++) { - -

@Model.FeatureListResultDto.Groups[i].DisplayName

+ +

@featureGroups[i].DisplayName


- @for (var j = 0; j < Model.FeatureListResultDto.Groups[i].Features.Count; j++) + @for (var j = 0; j < featureGroups[i].Features.Count; j++) { - var feature = Model.FeatureListResultDto.Groups[i].Features[j]; + var feature = featureGroups[i].Features[j]; var disabled = Model.IsDisabled(feature.Provider.Name); -
- - @feature.DisplayName @(disabled ? $"({feature.Provider.Name})" : "") +
+ + @if (feature.ValueType is ToggleStringValueType) + { + + + } + @if (feature.ValueType is FreeTextStringValueType) { - - + var type = "text"; + if(feature.ValueType.Validator is NumericValueValidator) + { + type = "number"; + } + + } - @if (feature.ValueType is SelectionStringValueType) + + @if (feature.ValueType is SelectionStringValueType selectType) { - - + @foreach (var item in selectType.ItemSource.Items) { - + if (item.Value == feature.Value) + { + + } + else + { + + } } - } - - } - @if (feature.ValueType is ToggleStringValueType) - { - - + +
} + +
}
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/feature-management-modal.js b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/feature-management-modal.js index 7e4960999c..f9ec7e11fa 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/feature-management-modal.js +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/feature-management-modal.js @@ -3,12 +3,75 @@ abp.modals = abp.modals || {}; abp.modals.FeatureManagement = function () { - $('.FeatureValueCheckbox').change(function () { - if (this.checked) { - $(this).val('true'); - } else { - $(this).val('false'); + function checkParents($tab, $element, className) { + var parentName = $element + .closest(className) + .attr('data-parent-name'); + + if (!parentName) { + return; + } + + $tab.find('.custom-checkbox') + .filter('[data-feature-name="' + parentName + '"]') + .find('input[type="checkbox"]') + .each(function () { + var $parent = $(this); + $parent.prop('checked', true); + checkParents($tab, $parent, className); + }); + } + + function uncheckChildren($tab, $checkBox) { + var featureName = $checkBox + .closest('.custom-checkbox') + .attr('data-feature-name'); + if (!featureName) { + return; } - }); + + $tab.find('.custom-checkbox') + .filter('[data-parent-name="' + featureName + '"]') + .find('input[type="checkbox"]') + .each(function () { + var $child = $(this); + $child.prop('checked', false); + uncheckChildren($tab, $child); + }); + } + + this.initDom = function ($el) { + $el.find('.tab-pane').each(function () { + var $tab = $(this); + $tab.find('input[type="checkbox"]') + .each(function () { + var $checkBox = $(this); + $checkBox.change(function () { + if ($checkBox.is(':checked')) { + checkParents($tab, $checkBox, '.custom-checkbox') + } else { + uncheckChildren($tab, $checkBox); + } + }); + }); + + $tab.find('.form-control') + .each(function () { + var $element = $(this); + $element.change(function () { + checkParents($tab, $element, '.form-group') + }); + }); + }); + + $(function () { + $('.custom-scroll-content').mCustomScrollbar({ + theme: 'minimal-dark', + }); + $('.custom-scroll-container > .col-4').mCustomScrollbar({ + theme: 'minimal-dark', + }); + }); + }; }; })(jQuery);