diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/IFeatureAppService.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/IFeatureAppService.cs index 20583f7476..a2fa93cfd2 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/IFeatureAppService.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/IFeatureAppService.cs @@ -9,4 +9,6 @@ public interface IFeatureAppService : IApplicationService Task GetAsync([NotNull] string providerName, string providerKey); Task UpdateAsync([NotNull] string providerName, string providerKey, UpdateFeaturesDto input); + + Task ResetToDefaultAsync([NotNull] string providerName, string providerKey); } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs index c21f40fb65..9d2c3b04a1 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs @@ -6,7 +6,6 @@ using JetBrains.Annotations; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Options; using Volo.Abp.Features; -using Volo.Abp.Localization; namespace Volo.Abp.FeatureManagement; @@ -15,15 +14,18 @@ public class FeatureAppService : FeatureManagementAppServiceBase, IFeatureAppSer { protected FeatureManagementOptions Options { get; } protected IFeatureManager FeatureManager { get; } + protected IFeatureValueRepository FeatureValueRepository { get; } protected IFeatureDefinitionManager FeatureDefinitionManager { get; } public FeatureAppService(IFeatureManager featureManager, IFeatureDefinitionManager featureDefinitionManager, - IOptions options) + IOptions options, + IFeatureValueRepository featureValueRepository) { FeatureManager = featureManager; FeatureDefinitionManager = featureDefinitionManager; Options = options.Value; + FeatureValueRepository = featureValueRepository; } public virtual async Task GetAsync([NotNull] string providerName, string providerKey) @@ -135,4 +137,9 @@ public class FeatureAppService : FeatureManagementAppServiceBase, IFeatureAppSer await AuthorizationService.CheckAsync(policyName); } + + public virtual async Task ResetToDefaultAsync([NotNull] string providerName, string providerKey) + { + await FeatureValueRepository.DeleteAsync(providerName, providerKey); + } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor index 8bc5e9dfe7..4d2c1eed74 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor @@ -97,6 +97,7 @@ } + diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs index 095db9d12b..6dbdd282fe 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs @@ -114,6 +114,16 @@ public partial class FeatureManagementModal } } + public virtual async Task ResetToDefaultAsync([NotNull] string providerName, string providerKey = null) + { + if (!await Message.Confirm(L["AreYouSureToResetToDefault"])) + { + return; + } + await FeatureAppService.ResetToDefaultAsync(ProviderName, ProviderKey); + await Message.Success(L["ResetedToDefault"]); + } + protected virtual string GetNormalizedGroupName(string name) { return "FeatureGroup_" + name.Replace(".", "_"); 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 3615dd764d..54a19b0090 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 @@ -6,7 +6,10 @@ "ManageHostFeatures": "Manage Host features", "Permission:FeatureManagement": "Feature management", "Permission:FeatureManagement.ManageHostFeatures": "Manage Host features", - "Volo.Abp.FeatureManagement:InvalidFeatureValue" : "{0} feature value is not valid!", - "Menu:FeatureManagement": "Feature Management" + "Volo.Abp.FeatureManagement:InvalidFeatureValue": "{0} feature value is not valid!", + "Menu:FeatureManagement": "Feature Management", + "ResetToDefault": "Reset to default", + "ResetedToDefault": "Reseted to default", + "AreYouSureToResetToDefault": "Are you sure to reset to default?" } } 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 c21f59088b..523bb12d84 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 @@ -6,7 +6,10 @@ "ManageHostFeatures": "Host özelliklerini yönetin", "Permission:FeatureManagement": "Özellik yönetimi", "Permission:FeatureManagement.ManageHostFeatures": "Host özelliklerini düzenle", - "Volo.Abp.FeatureManagement:InvalidFeatureValue" : "{0} özellik değeri geçerli değil!", - "Menu:FeatureManagement": "Özellik Yönetimi" + "Volo.Abp.FeatureManagement:InvalidFeatureValue": "{0} özellik değeri geçerli değil!", + "Menu:FeatureManagement": "Özellik Yönetimi", + "ResetToDefault": "Varsayılana sıfırla", + "ResetedToDefault": "Varsayılana sıfırlandı", + "AreYouSureToResetToDefault": "Varsayılana sıfırlamak istediğinizden emin misiniz?" } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureValueRepository.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureValueRepository.cs index 022d8a1394..05a330a1b2 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureValueRepository.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureValueRepository.cs @@ -24,4 +24,9 @@ public interface IFeatureValueRepository : IBasicRepository string providerName, string providerKey, CancellationToken cancellationToken = default); + + Task DeleteAsync( + string providerName, + string providerKey, + CancellationToken cancellationToken = default); } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs index 3ef0cdde96..233ce31edf 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore/Volo/Abp/FeatureManagement/EntityFrameworkCore/EfCoreFeatureValueRepository.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; +using Polly; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; @@ -49,4 +50,12 @@ public class EfCoreFeatureValueRepository : EfCoreRepository s.ProviderName == providerName && s.ProviderKey == providerKey ).ToListAsync(GetCancellationToken(cancellationToken)); } + + public async Task DeleteAsync( + string providerName, + string providerKey, + CancellationToken cancellationToken = default) + { + await DeleteAsync(s => s.ProviderName == providerName && s.ProviderKey == providerKey, cancellationToken: GetCancellationToken(cancellationToken)); + } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi.Client/ClientProxies/FeaturesClientProxy.Generated.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi.Client/ClientProxies/FeaturesClientProxy.Generated.cs index a315445d84..37d30b7c4d 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi.Client/ClientProxies/FeaturesClientProxy.Generated.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi.Client/ClientProxies/FeaturesClientProxy.Generated.cs @@ -33,4 +33,13 @@ public partial class FeaturesClientProxy : ClientProxyBase, { typeof(UpdateFeaturesDto), input } }); } + + public virtual async Task ResetToDefaultAsync(string providerName, string providerKey) + { + await RequestAsync(nameof(ResetToDefaultAsync), new ClientProxyRequestTypeValue + { + { typeof(string), providerName }, + { typeof(string), providerKey } + }); + } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi.Client/ClientProxies/featureManagement-generate-proxy.json b/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi.Client/ClientProxies/featureManagement-generate-proxy.json index 79a8b31a0c..df5f6c0def 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi.Client/ClientProxies/featureManagement-generate-proxy.json +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi.Client/ClientProxies/featureManagement-generate-proxy.json @@ -7,6 +7,8 @@ "Volo.Abp.FeatureManagement.FeaturesController": { "controllerName": "Features", "controllerGroupName": "Features", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.Abp.FeatureManagement.FeaturesController", "interfaces": [ { @@ -147,6 +149,63 @@ }, "allowAnonymous": null, "implementFrom": "Volo.Abp.FeatureManagement.IFeatureAppService" + }, + "ResetToDefaultAsyncByProviderNameAndProviderKey": { + "uniqueName": "ResetToDefaultAsyncByProviderNameAndProviderKey", + "name": "ResetToDefaultAsync", + "httpMethod": null, + "url": "api/feature-management/features", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "providerName", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + }, + { + "name": "providerKey", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "providerName", + "name": "providerName", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + }, + { + "nameOnMethod": "providerKey", + "name": "providerKey", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "System.Void", + "typeSimple": "System.Void" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Abp.FeatureManagement.IFeatureAppService" } } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/FeaturesController.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/FeaturesController.cs index 0514579540..a61fdd0508 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/FeaturesController.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi/Volo/Abp/FeatureManagement/FeaturesController.cs @@ -27,4 +27,9 @@ public class FeaturesController : AbpControllerBase, IFeatureAppService { return FeatureAppService.UpdateAsync(providerName, providerKey, input); } + + public Task ResetToDefaultAsync(string providerName, string providerKey) + { + return FeatureAppService.ResetToDefaultAsync(providerName, providerKey); + } } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs index 9d9071ea1a..4d4fbedcfd 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB/Volo/Abp/FeatureManagement/MongoDB/MongoFeatureValueRepository.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; @@ -49,4 +51,16 @@ public class MongoFeatureValueRepository : .Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey) .ToListAsync(GetCancellationToken(cancellationToken)); } + + public virtual async Task DeleteAsync( + string providerName, + string providerKey, + CancellationToken cancellationToken = default) + { + var dbContext = await GetDbContextAsync(); + + await dbContext.FeatureValues + .DeleteManyAsync(x => x.ProviderName == providerName && x.ProviderKey == providerKey, GetCancellationToken(cancellationToken)); + + } } 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 4ed0012a89..4293620b72 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 @@ -119,7 +119,11 @@ - + + @L["ResetToDefault"] + @L["Cancel"] + @L["Save"] + } else { 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 f4b052a755..25739b8a2d 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 @@ -2,9 +2,26 @@ var abp = abp || {}; (function ($) { abp.modals = abp.modals || {}; + let l = abp.localization.getResource("AbpFeatureManagement"); + + abp.modals.FeatureManagement = function () { + abp.ResourceLoader.loadScript('/client-proxies/featureManagement-proxy.js'); + $('#ResetToDefaults').click(function (e) { + abp.message.confirm(l('AreYouSureToResetToDefault')) + .then(function (confirmed) { + if (confirmed) { + let providerName = $('#ProviderName').val(); + let prodiverKey = $('#ProviderKey').val(); + volo.abp.featureManagement.features.resetToDefault(providerName, prodiverKey).then(function () { + abp.notify.success(l('ResetedToDefault')); + }); + } + }); + }); + function checkParents($tab, $element, className) { - var parentName = $element + let parentName = $element .closest(className) .attr('data-parent-name'); @@ -16,14 +33,14 @@ var abp = abp || {}; .filter('[data-feature-name="' + parentName + '"]') .find('input[type="checkbox"]') .each(function () { - var $parent = $(this); + let $parent = $(this); $parent.prop('checked', true); checkParents($tab, $parent, className); }); } function uncheckChildren($tab, $checkBox) { - var featureName = $checkBox + let featureName = $checkBox .closest('.custom-checkbox') .attr('data-feature-name'); if (!featureName) { @@ -34,7 +51,7 @@ var abp = abp || {}; .filter('[data-parent-name="' + featureName + '"]') .find('input[type="checkbox"]') .each(function () { - var $child = $(this); + let $child = $(this); $child.prop('checked', false); uncheckChildren($tab, $child); }); @@ -42,10 +59,10 @@ var abp = abp || {}; this.initDom = function ($el) { $el.find('.tab-pane').each(function () { - var $tab = $(this); + let $tab = $(this); $tab.find('input[type="checkbox"]') .each(function () { - var $checkBox = $(this); + let $checkBox = $(this); $checkBox.change(function () { if ($checkBox.is(':checked')) { checkParents($tab, $checkBox, '.custom-checkbox') @@ -57,7 +74,7 @@ var abp = abp || {}; $tab.find('.form-control') .each(function () { - var $element = $(this); + let $element = $(this); $element.change(function () { checkParents($tab, $element, '.form-group') }); diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/wwwroot/client-proxies/featureManagement-proxy.js b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/wwwroot/client-proxies/featureManagement-proxy.js index 3c149c0a7f..78d1fe7917 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/wwwroot/client-proxies/featureManagement-proxy.js +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/wwwroot/client-proxies/featureManagement-proxy.js @@ -27,6 +27,14 @@ }, ajaxParams)); }; + volo.abp.featureManagement.features.resetToDefault = function(providerName, providerKey, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/feature-management/features' + abp.utils.buildQueryString([{ name: 'providerName', value: providerName }, { name: 'providerKey', value: providerKey }]) + '', + type: 'POST', + dataType: null + }, ajaxParams)); + }; + })(); })(); diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs index 66023a28f4..7f11e297a3 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs @@ -14,7 +14,6 @@ namespace Volo.Abp.FeatureManagement; public class FeatureAppService_Tests : FeatureManagementApplicationTestBase { private readonly IFeatureAppService _featureAppService; - private readonly IFeatureValueRepository _featureValueRepository; private ICurrentUser _currentUser; private readonly FeatureManagementTestData _testData; @@ -22,7 +21,6 @@ public class FeatureAppService_Tests : FeatureManagementApplicationTestBase public FeatureAppService_Tests() { _featureAppService = GetRequiredService(); - _featureValueRepository = GetRequiredService(); _testData = GetRequiredService(); } @@ -70,6 +68,15 @@ public class FeatureAppService_Tests : FeatureManagementApplicationTestBase } + [Fact] + public async Task ResetToDefaultAsync() + { + Login(_testData.User1Id); + var exception = await Record.ExceptionAsync(async () => + await _featureAppService.ResetToDefaultAsync("test", "test")); + Assert.Null(exception); + } + private void Login(Guid userId) { _currentUser.Id.Returns(userId); diff --git a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureValueRepository_Tests.cs b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureValueRepository_Tests.cs index c2645dd65d..b739cdf7e7 100644 --- a/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureValueRepository_Tests.cs +++ b/modules/feature-management/test/Volo.Abp.FeatureManagement.TestBase/Volo/Abp/FeatureManagement/FeatureValueRepository_Tests.cs @@ -1,7 +1,10 @@ using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Shouldly; using Volo.Abp.Features; using Volo.Abp.Modularity; +using Volo.Abp.Uow; using Xunit; namespace Volo.Abp.FeatureManagement; @@ -72,4 +75,31 @@ public abstract class FeatureValueRepository_Tests : FeatureMana fv.Value == "3" ); } + + [Fact] + public async Task DeleteAsync() + { + var exception = await Record.ExceptionAsync(async () => + await Repository.DeleteAsync(TestFeatureDefinitionProvider.SocialLogins, "true")); + Assert.Null(exception); + } + + [Fact] + public async Task DeleteForProviderNameAndKey() + { + using (var scope = ServiceProvider.CreateScope()) + { + var uowManager = scope.ServiceProvider.GetRequiredService(); + + using (var uow = uowManager.Begin(new AbpUnitOfWorkOptions())) + { + await Repository.DeleteAsync(TestFeatureDefinitionProvider.SocialLogins, "true"); + + await uow.CompleteAsync(); + } + } + + var features = await Repository.GetListAsync(TestFeatureDefinitionProvider.SocialLogins, "true"); + features.ShouldBeEmpty(); + } }