From a28c624dc8d671931a54d6a317c41397ed74498c Mon Sep 17 00:00:00 2001 From: Washington Acero M Date: Sun, 29 Jan 2023 12:36:09 -0800 Subject: [PATCH 01/29] aded localization fir dynamic resource for select2 --- .../Packages/Select2/Select2ScriptContributor.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Select2/Select2ScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Select2/Select2ScriptContributor.cs index 4818158a97..0dfd981b26 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Select2/Select2ScriptContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Select2/Select2ScriptContributor.cs @@ -2,15 +2,29 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Packages.Core; using Volo.Abp.Modularity; +using Volo.Abp.Localization; namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Select2; [DependsOn(typeof(CoreScriptContributor))] public class Select2ScriptContributor : BundleContributor { + public const string PackageName = "select2"; public override void ConfigureBundle(BundleConfigurationContext context) { - //TODO: Add select2.full.min.js or localize! + //TODO: Add select2.full.min.js context.Files.AddIfNotContains("/libs/select2/js/select2.min.js"); } + public override void ConfigureDynamicResources(BundleConfigurationContext context) + { + var fileName = context.LazyServiceProvider + .LazyGetRequiredService>() + .Value + .GetCurrentUICultureLanguageFilesMap(PackageName); + var filePath = $"/libs/select2/js/i18n/{fileName}.js"; + if (context.FileProvider.GetFileInfo(filePath).Exists) + { + context.Files.AddIfNotContains(filePath); + } + } } From e6afa1f30cc90355412f39275416ea0a2f0be037 Mon Sep 17 00:00:00 2001 From: Washington Acero M Date: Sun, 29 Jan 2023 12:41:09 -0800 Subject: [PATCH 02/29] aded localization languaje for select2 for aded localization languaje for select2 to display in different languages --- .../bootstrap/dom-event-handlers.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js index d1cbfa6b6b..6a9e6f7d80 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js @@ -105,6 +105,7 @@ $select.select2({ ajax: { url: url, + delay: 250, dataType: "json", data: function (params) { let query = {}; @@ -132,6 +133,7 @@ width: '100%', dropdownParent: parentSelector ? $(parentSelector) : $('body'), allowClear: allowClear, + language: abp.localization.currentCulture.cultureName, placeholder: { id: '-1', text: placeholder From 1e1b1176466246726605af9e78e5642273c9e3ca Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 20 Feb 2023 20:23:18 +0800 Subject: [PATCH 03/29] Update Select2ScriptContributor.cs --- .../Mvc/UI/Packages/Select2/Select2ScriptContributor.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Select2/Select2ScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Select2/Select2ScriptContributor.cs index 0dfd981b26..b18767050b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Select2/Select2ScriptContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Select2/Select2ScriptContributor.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Packages.Core; using Volo.Abp.Modularity; @@ -17,10 +18,7 @@ public class Select2ScriptContributor : BundleContributor } public override void ConfigureDynamicResources(BundleConfigurationContext context) { - var fileName = context.LazyServiceProvider - .LazyGetRequiredService>() - .Value - .GetCurrentUICultureLanguageFilesMap(PackageName); + var fileName = context.LazyServiceProvider.LazyGetRequiredService>().Value.GetCurrentUICultureLanguageFilesMap(PackageName); var filePath = $"/libs/select2/js/i18n/{fileName}.js"; if (context.FileProvider.GetFileInfo(filePath).Exists) { From eb255189799b6015b2c2098f69c6ded3072ea1e3 Mon Sep 17 00:00:00 2001 From: maliming Date: Sat, 4 Mar 2023 20:42:34 +0800 Subject: [PATCH 04/29] Check the token when refreshing the blazor server page. --- .../CookieAuthenticationOptionsExtensions.cs | 50 +++++++++++++++++++ ...lo.Abp.AspNetCore.Components.Server.csproj | 12 +++-- 2 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs new file mode 100644 index 0000000000..fbca58cd5a --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs @@ -0,0 +1,50 @@ +using System; +using IdentityModel.Client; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Authentication.Cookies; + +public static class CookieAuthenticationOptionsExtensions +{ + public static CookieAuthenticationOptions IntrospectAccessToken(this CookieAuthenticationOptions options, string oidcAuthenticationScheme = "oidc") + { + var originalHandler = options.Events.OnValidatePrincipal; + options.Events.OnValidatePrincipal = async principalContext => + { + originalHandler?.Invoke(principalContext); + + if (principalContext.Principal != null && principalContext.Principal.Identity != null && principalContext.Principal.Identity.IsAuthenticated) + { + var accessToken = principalContext.Properties.GetTokenValue("access_token"); + if (!accessToken.IsNullOrWhiteSpace()) + { + var openIdConnectOptions = principalContext.HttpContext.RequestServices.GetRequiredService>().Get(oidcAuthenticationScheme); + if (openIdConnectOptions.Configuration == null && openIdConnectOptions.ConfigurationManager != null) + { + openIdConnectOptions.Configuration = await openIdConnectOptions.ConfigurationManager.GetConfigurationAsync(principalContext.HttpContext.RequestAborted); + } + + var response = await openIdConnectOptions.Backchannel.IntrospectTokenAsync(new TokenIntrospectionRequest + { + Address = openIdConnectOptions.Configuration?.IntrospectionEndpoint ?? openIdConnectOptions.Authority.EnsureEndsWith('/') + "connect/introspect", + ClientId = openIdConnectOptions.ClientId, + ClientSecret = openIdConnectOptions.ClientSecret, + Token = accessToken + }); + + if (response.IsActive) + { + return; + } + } + + principalContext.RejectPrincipal(); + await principalContext.HttpContext.SignOutAsync(principalContext.Scheme.Name); + } + }; + + return options; + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj index 09c743bc2a..297b2a8576 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj @@ -12,11 +12,13 @@ - - - - - + + + + + + + From 4d534b942e8739fd6f8986251e6899cb34cf2273 Mon Sep 17 00:00:00 2001 From: maliming Date: Sat, 4 Mar 2023 20:57:23 +0800 Subject: [PATCH 05/29] `IntrospectAccessToken` in `Blazor.Server.Tiered`. --- .../Cookies/CookieAuthenticationOptionsExtensions.cs | 6 ++++++ .../MyProjectNameBlazorModule.cs | 2 ++ 2 files changed, 8 insertions(+) diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs index fbca58cd5a..61c064b376 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Microsoft/AspNetCore/Authentication/Cookies/CookieAuthenticationOptionsExtensions.cs @@ -8,6 +8,12 @@ namespace Microsoft.AspNetCore.Authentication.Cookies; public static class CookieAuthenticationOptionsExtensions { + /// + /// Introspect access token on validating the principal. + /// + /// + /// + /// public static CookieAuthenticationOptions IntrospectAccessToken(this CookieAuthenticationOptions options, string oidcAuthenticationScheme = "oidc") { var originalHandler = options.Events.OnValidatePrincipal; diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs index 1033c73a57..fa55b7d44f 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs @@ -4,6 +4,7 @@ using Blazorise.Bootstrap5; using Blazorise.Icons.FontAwesome; using Medallion.Threading; using Medallion.Threading.Redis; +using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; @@ -163,6 +164,7 @@ public class MyProjectNameBlazorModule : AbpModule .AddCookie("Cookies", options => { options.ExpireTimeSpan = TimeSpan.FromDays(365); + options.IntrospectAccessToken(); }) .AddAbpOpenIdConnect("oidc", options => { From 3218f2eb2a2de1f75ba243227a868c40f9df40c2 Mon Sep 17 00:00:00 2001 From: Merijn Geurts Date: Sat, 4 Mar 2023 14:50:06 +0100 Subject: [PATCH 06/29] Update AbpStringExtensions.ReplaceFirst, to spans --- .../Volo.Abp.Core/System/AbpStringExtensions.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs b/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs index c7e1bef3b2..a77458f78c 100644 --- a/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs +++ b/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs @@ -209,7 +209,22 @@ public static class AbpStringExtensions return str; } - return str.Substring(0, pos) + replace + str.Substring(pos + search.Length); + var searchLength = search.Length; + var replaceLength = replace.Length; + var newLength = str.Length - searchLength + replaceLength; + + Span buffer = stackalloc char[newLength]; + + // Copy the part of the original string before the search term + str.AsSpan(0, pos).CopyTo(buffer); + + // Copy the replacement text + replace.AsSpan().CopyTo(buffer.Slice(pos)); + + // Copy the remainder of the original string + str.AsSpan(pos + searchLength).CopyTo(buffer.Slice(pos + replaceLength)); + + return buffer.ToString(); } /// From 20c3e16e33073de8425c247375f4b0c963b30ddf Mon Sep 17 00:00:00 2001 From: Merijn Geurts Date: Mon, 6 Mar 2023 18:26:14 +0100 Subject: [PATCH 07/29] ReplaceFirst: StackAllock till 1KB --- framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs b/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs index a77458f78c..57f2c59d57 100644 --- a/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs +++ b/framework/src/Volo.Abp.Core/System/AbpStringExtensions.cs @@ -213,7 +213,7 @@ public static class AbpStringExtensions var replaceLength = replace.Length; var newLength = str.Length - searchLength + replaceLength; - Span buffer = stackalloc char[newLength]; + Span buffer = newLength <= 1024 ? stackalloc char[newLength] : new char[newLength]; // Copy the part of the original string before the search term str.AsSpan(0, pos).CopyTo(buffer); From 8b8c750dc08553dbee1c1c138bbd87d66534271e Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 7 Mar 2023 10:46:57 +0800 Subject: [PATCH 08/29] Add `GetListByIdsAsync` method to `IIdentityUserRepository`. --- .../Volo/Abp/Identity/IIdentityUserRepository.cs | 6 ++++++ .../EfCoreIdentityLinkUserRepository.cs | 6 ++++-- .../EntityFrameworkCore/EfCoreIdentityUserRepository.cs | 8 ++++++++ .../Abp/Identity/MongoDB/MongoIdentityUserRepository.cs | 7 +++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs index d2a049dd84..d8b3543703 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IIdentityUserRepository.cs @@ -125,4 +125,10 @@ public interface IIdentityUserRepository : IBasicRepository bool includeDetails = true, CancellationToken cancellationToken = default ); + + Task> GetListByIdsAsync( + IEnumerable ids, + bool includeDetails = false, + CancellationToken cancellationToken = default + ); } diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs index 6a0245fa4f..035904120c 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityLinkUserRepository.cs @@ -20,6 +20,7 @@ public class EfCoreIdentityLinkUserRepository : EfCoreRepository FindAsync(IdentityLinkUserInfo sourceLinkUserInfo, IdentityLinkUserInfo targetLinkUserInfo, CancellationToken cancellationToken = default) { return await (await GetDbSetAsync()) + .AsNoTracking() .OrderBy(x => x.Id).FirstOrDefaultAsync(x => x.SourceUserId == sourceLinkUserInfo.UserId && x.SourceTenantId == sourceLinkUserInfo.TenantId && x.TargetUserId == targetLinkUserInfo.UserId && x.TargetTenantId == targetLinkUserInfo.TenantId || @@ -31,7 +32,8 @@ public class EfCoreIdentityLinkUserRepository : EfCoreRepository> GetListAsync(IdentityLinkUserInfo linkUserInfo, List excludes = null, CancellationToken cancellationToken = default) { - IQueryable query = (await GetDbSetAsync()) + var query = (await GetDbSetAsync()) + .AsNoTracking() .Where(x => x.SourceUserId == linkUserInfo.UserId && x.SourceTenantId == linkUserInfo.TenantId || x.TargetUserId == linkUserInfo.UserId && x.TargetTenantId == linkUserInfo.TenantId); @@ -51,7 +53,7 @@ public class EfCoreIdentityLinkUserRepository : EfCoreRepository + var linkUsers = await (await GetDbSetAsync()).AsNoTracking().Where(x => x.SourceUserId == linkUserInfo.UserId && x.SourceTenantId == linkUserInfo.TenantId || x.TargetUserId == linkUserInfo.UserId && x.TargetTenantId == linkUserInfo.TenantId) .ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs index e2527555b2..60abbb3054 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs @@ -348,4 +348,12 @@ public class EfCoreIdentityUserRepository : EfCoreRepository> GetListByIdsAsync(IEnumerable ids, bool includeDetails = false, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .IncludeDetails(includeDetails) + .Where(x => ids.Contains(x.Id)) + .ToListAsync(GetCancellationToken(cancellationToken)); + } } diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs index ac2ab63809..ae805d9a03 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs @@ -316,4 +316,11 @@ public class MongoIdentityUserRepository : MongoDbRepository> GetListByIdsAsync(IEnumerable ids, bool includeDetails = false, CancellationToken cancellationToken = default) + { + return await (await GetMongoQueryableAsync(cancellationToken)) + .Where(x => ids.Contains(x.Id)) + .ToListAsync(GetCancellationToken(cancellationToken)); + } } From 0fad93868f28494ad217587b1a2ca0be90bbe98f Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 7 Mar 2023 11:37:50 +0800 Subject: [PATCH 09/29] Add `BlazorWebAssemblyCurrentApplicationConfigurationCacheResetService`. Resovle #15887 --- ...plicationConfigurationCacheResetService.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Configuration/BlazorWebAssemblyCurrentApplicationConfigurationCacheResetService.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Configuration/BlazorWebAssemblyCurrentApplicationConfigurationCacheResetService.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Configuration/BlazorWebAssemblyCurrentApplicationConfigurationCacheResetService.cs new file mode 100644 index 0000000000..40ac508030 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/Configuration/BlazorWebAssemblyCurrentApplicationConfigurationCacheResetService.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Components.Web.Configuration; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.Components.WebAssembly.Configuration; + +[Dependency(ReplaceServices = true)] +public class BlazorWebAssemblyCurrentApplicationConfigurationCacheResetService : + ICurrentApplicationConfigurationCacheResetService, + ITransientDependency +{ + private readonly WebAssemblyCachedApplicationConfigurationClient _webAssemblyCachedApplicationConfigurationClient; + + public BlazorWebAssemblyCurrentApplicationConfigurationCacheResetService(WebAssemblyCachedApplicationConfigurationClient webAssemblyCachedApplicationConfigurationClient) + { + _webAssemblyCachedApplicationConfigurationClient = webAssemblyCachedApplicationConfigurationClient; + } + + public async Task ResetAsync() + { + await _webAssemblyCachedApplicationConfigurationClient.InitializeAsync(); + } +} From 6aaea0f1869a03279acbb0ace66be31c98a52b74 Mon Sep 17 00:00:00 2001 From: Hamza Albreem <94292623+braim23@users.noreply.github.com> Date: Tue, 7 Mar 2023 17:13:01 +0300 Subject: [PATCH 10/29] tiny fix for the List Service doc --- docs/en/UI/Angular/List-Service.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/UI/Angular/List-Service.md b/docs/en/UI/Angular/List-Service.md index 2f0eb9fc57..8df8b945d7 100644 --- a/docs/en/UI/Angular/List-Service.md +++ b/docs/en/UI/Angular/List-Service.md @@ -201,4 +201,4 @@ You may use observables in combination with [AsyncPipe](https://angular.io/guide ``` -ABP doesn't have a built-in filtering mechanism. You need to implement yourself and handle `filter` property in backend. +ABP doesn't have a built-in filtering mechanism. You need to implement it yourself and handle the `filter` property in the backend. From 2899ecac8ccc60b57a7736aead007259bd9b69c1 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Wed, 8 Mar 2023 11:13:18 +0800 Subject: [PATCH 11/29] Define groups for menu items --- .../Volo/Abp/Ui/Navigation/ApplicationMenu.cs | 19 +++++- .../Navigation/ApplicationMenuExtensions.cs | 50 ++++++++++++++ .../Abp/Ui/Navigation/ApplicationMenuGroup.cs | 67 +++++++++++++++++++ .../Ui/Navigation/ApplicationMenuGroupList.cs | 36 ++++++++++ .../Abp/Ui/Navigation/ApplicationMenuItem.cs | 7 ++ .../Volo/Abp/Ui/Navigation/IHasMenuGroups.cs | 9 +++ .../Volo/Abp/Ui/Navigation/MenuManager.cs | 18 +++++ .../Navigation/AbpUiNavigationTestModule.cs | 1 + .../Abp/Ui/Navigation/MenuManager_Tests.cs | 46 ++++++++++++- 9 files changed, 250 insertions(+), 3 deletions(-) create mode 100644 framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuGroup.cs create mode 100644 framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuGroupList.cs create mode 100644 framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/IHasMenuGroups.cs diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenu.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenu.cs index 1a69de7f2c..9f48aebf97 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenu.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenu.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using JetBrains.Annotations; using Volo.Abp.Data; @@ -5,7 +6,7 @@ using Volo.Abp.UI.Navigation; namespace Volo.Abp.UI.Navigation; -public class ApplicationMenu : IHasMenuItems +public class ApplicationMenu : IHasMenuItems, IHasMenuGroups { /// /// Unique name of the menu in the application. @@ -31,6 +32,10 @@ public class ApplicationMenu : IHasMenuItems [NotNull] public ApplicationMenuItemList Items { get; } + /// + [NotNull] + public ApplicationMenuGroupList Groups { get; } + /// /// Can be used to store a custom object related to this menu. /// @@ -47,6 +52,7 @@ public class ApplicationMenu : IHasMenuItems DisplayName = displayName ?? Name; Items = new ApplicationMenuItemList(); + Groups = new ApplicationMenuGroupList(); } /// @@ -60,6 +66,17 @@ public class ApplicationMenu : IHasMenuItems return this; } + /// + /// Adds a to . + /// + /// to be added + /// This object + public ApplicationMenu AddGroup([NotNull] ApplicationMenuGroup group) + { + Groups.Add(group); + return this; + } + /// /// Adds a custom data item to with given key & value. /// diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuExtensions.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuExtensions.cs index eec549cf9c..624abde425 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuExtensions.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuExtensions.cs @@ -64,4 +64,54 @@ public static class ApplicationMenuExtensions return menuWithItems; } + + [NotNull] + public static ApplicationMenuGroup GetMenuGroup( + [NotNull] this IHasMenuGroups menuWithGroups, + string groupName) + { + var menuGroup = menuWithGroups.GetMenuGroupOrNull(groupName); + if (menuGroup == null) + { + throw new AbpException($"Could not find a group item with given name: {groupName}"); + } + + return menuGroup; + } + + [CanBeNull] + public static ApplicationMenuGroup GetMenuGroupOrNull( + [NotNull] this IHasMenuGroups menuWithGroups, + string menuGroupName) + { + Check.NotNull(menuWithGroups, nameof(menuWithGroups)); + + return menuWithGroups.Groups.FirstOrDefault(group => group.Name == menuGroupName); + } + + public static bool TryRemoveMenuGroup( + [NotNull] this IHasMenuGroups menuWithGroups, + string menuGroupName) + { + Check.NotNull(menuWithGroups, nameof(menuWithGroups)); + + return menuWithGroups.Groups.RemoveAll(group => group.Name == menuGroupName) > 0; + } + + [NotNull] + public static IHasMenuGroups SetMenuGroupOrder( + [NotNull] this IHasMenuGroups menuWithGroups, + string menuGroupName, + int order) + { + Check.NotNull(menuWithGroups, nameof(menuWithGroups)); + + var menuGroup = menuWithGroups.GetMenuGroupOrNull(menuGroupName); + if (menuGroup != null) + { + menuGroup.Order = order; + } + + return menuWithGroups; + } } diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuGroup.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuGroup.cs new file mode 100644 index 0000000000..469c0ad355 --- /dev/null +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuGroup.cs @@ -0,0 +1,67 @@ +using JetBrains.Annotations; + +namespace Volo.Abp.UI.Navigation; + +public class ApplicationMenuGroup +{ + private string _displayName; + + /// + /// Default value of a group item. + /// + public const int DefaultOrder = 1000; + + /// + /// Unique name of the group in the application. + /// + [NotNull] + public string Name { get; } + + /// + /// Display name of the group. + /// + [NotNull] + public string DisplayName { + get { return _displayName; } + set { + Check.NotNullOrWhiteSpace(value, nameof(value)); + _displayName = value; + } + } + + /// + /// Can be used to render the element with a specific Id for DOM selections. + /// + public string ElementId { get; set; } + + /// + /// The Display order of the group. + /// Default value: 1000. + /// + public int Order { get; set; } + + public ApplicationMenuGroup( + [NotNull] string name, + [NotNull] string displayName, + string elementId = null, + int order = DefaultOrder) + { + Check.NotNullOrWhiteSpace(name, nameof(name)); + Check.NotNullOrWhiteSpace(displayName, nameof(displayName)); + + Name = name; + DisplayName = displayName; + ElementId = elementId; + Order = order; + } + + private string GetDefaultElementId() + { + return "MenuGroup_" + Name; + } + + public override string ToString() + { + return $"[ApplicationMenuGroup] Name = {Name}"; + } +} diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuGroupList.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuGroupList.cs new file mode 100644 index 0000000000..f280f5d4f9 --- /dev/null +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuGroupList.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Volo.Abp.UI.Navigation; + +public class ApplicationMenuGroupList: List +{ + public ApplicationMenuGroupList() + { + + } + + public ApplicationMenuGroupList(int capacity) + : base(capacity) + { + + } + + public ApplicationMenuGroupList(IEnumerable collection) + : base(collection) + { + + } + + public void Normalize() + { + Order(); + } + + private void Order() + { + var orderedItems = this.OrderBy(item => item.Order).ToArray(); + Clear(); + AddRange(orderedItems); + } +} diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs index 32241ba7ac..dc1614e3e5 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs @@ -92,6 +92,11 @@ public class ApplicationMenuItem : IHasMenuItems, IHasSimpleStateCheckers public string CssClass { get; set; } + /// + /// Can be used to group menu items. + /// + public string GroupName { get; set; } + public ApplicationMenuItem( [NotNull] string name, [NotNull] string displayName, @@ -101,6 +106,7 @@ public class ApplicationMenuItem : IHasMenuItems, IHasSimpleStateCheckers>(); Items = new ApplicationMenuItemList(); diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/IHasMenuGroups.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/IHasMenuGroups.cs new file mode 100644 index 0000000000..fbbe7a63a4 --- /dev/null +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/IHasMenuGroups.cs @@ -0,0 +1,9 @@ +namespace Volo.Abp.UI.Navigation; + +public interface IHasMenuGroups +{ + /// + /// Menu groups. + /// + ApplicationMenuGroupList Groups { get; } +} diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs index aa933c6e09..4f655509b9 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs @@ -96,6 +96,7 @@ public class MenuManager : IMenuManager, ITransientDependency } NormalizeMenu(menu); + NormalizeMenuGroup(menu); return menu; } @@ -159,4 +160,21 @@ public class MenuManager : IMenuManager, ITransientDependency menuWithItems.Items.Normalize(); } + + protected virtual void NormalizeMenuGroup(ApplicationMenu applicationMenu) + { + foreach (var menuGroup in applicationMenu.Items.Where(x => !x.GroupName.IsNullOrWhiteSpace()).GroupBy(x => x.GroupName)) + { + var group = applicationMenu.GetMenuGroupOrNull(menuGroup.First().GroupName); + if (group != null) + { + continue; + } + + foreach (var menuItem in menuGroup) + { + menuItem.GroupName = null; + } + } + } } diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs index 6088984cb9..c482963d75 100644 --- a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/AbpUiNavigationTestModule.cs @@ -16,6 +16,7 @@ public class AbpUiNavigationTestModule : AbpModule options.MenuContributors.Add(new MenuManager_Tests.TestMenuContributor1()); options.MenuContributors.Add(new MenuManager_Tests.TestMenuContributor2()); options.MenuContributors.Add(new MenuManager_Tests.TestMenuContributor3()); + options.MenuContributors.Add(new MenuManager_Tests.TestMenuContributor4()); options.MainMenuNames.Add(MenuManager_Tests.TestMenuContributor3.MenuName); }); diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs index b27de60c10..421e072b0f 100644 --- a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs @@ -46,7 +46,7 @@ public class MenuManager_Tests : AbpIntegratedTest mainMenu.Name.ShouldBe(StandardMenus.Main); mainMenu.DisplayName.ShouldBe("Main Menu"); - mainMenu.Items.Count.ShouldBe(2); + mainMenu.Items.Count.ShouldBe(5); mainMenu.Items[0].Name.ShouldBe("Dashboard"); mainMenu.Items[1].Name.ShouldBe(DefaultMenuNames.Application.Main.Administration); mainMenu.Items[1].Items[0].Name.ShouldBe("Administration.UserManagement"); @@ -63,12 +63,29 @@ public class MenuManager_Tests : AbpIntegratedTest mainMenu.Name.ShouldBe(StandardMenus.Main); - mainMenu.Items.Count.ShouldBe(3); + mainMenu.Items.Count.ShouldBe(6); mainMenu.Items.ShouldContain(x => x.Name == "Products"); mainMenu.Items.ShouldContain(x => x.Name == "Dashboard"); } + [Fact] + public async Task GetMainMenuAsync_GroupMenuItems() + { + var mainMenu = await _menuManager.GetMainMenuAsync(); + + mainMenu.Name.ShouldBe(StandardMenus.Main); + mainMenu.Items.Count.ShouldBe(6); + + mainMenu.Items[2].GroupName.ShouldBe("Layouts"); + mainMenu.Items[3].GroupName.ShouldBe("Layouts"); + mainMenu.Items[4].GroupName.ShouldBe(null); // No group defined + + var layoutsGroup = mainMenu.GetMenuGroup("Layouts"); + layoutsGroup.Name.ShouldBe("Layouts"); + layoutsGroup.DisplayName.ShouldBe("Layouts"); + } + /* Adds menu items: * - Administration * - User Management @@ -149,4 +166,29 @@ public class MenuManager_Tests : AbpIntegratedTest return Task.CompletedTask; } } + + /* Adds group and menu items: + * - Layouts + * - Toolbars + * - Page Header + */ + public class TestMenuContributor4 : IMenuContributor + { + public Task ConfigureMenuAsync(MenuConfigurationContext context) + { + if (context.Menu.Name != StandardMenus.Main) + { + return Task.CompletedTask; + } + + context.Menu.AddGroup(new ApplicationMenuGroup("Layouts", "Layouts")); + + context.Menu.AddItem(new ApplicationMenuItem("Toolbars", "Toolbars", url: "/layouts/toolbars", groupName: "Layouts")); + context.Menu.AddItem(new ApplicationMenuItem("PageHeader", "Page Header", url: "/layouts/page-header", groupName: "Layouts")); + + context.Menu.AddItem(new ApplicationMenuItem("Branding", "Branding", url: "/layouts/branding", groupName: "NotDefinedGroup")); + + return Task.CompletedTask; + } + } } From c6a9bec5fe0ed3e58675c489dd0f35c23ba03348 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Wed, 8 Mar 2023 11:20:58 +0800 Subject: [PATCH 12/29] Update MenuManager.cs --- .../Volo/Abp/Ui/Navigation/MenuManager.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs index 4f655509b9..349aa8e5a5 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs @@ -176,5 +176,7 @@ public class MenuManager : IMenuManager, ITransientDependency menuItem.GroupName = null; } } + + applicationMenu.Groups.Normalize(); } } From d1b45465cbc21840443c2e072a941d8753656e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20P=C4=B1=C3=A7akc=C4=B1?= Date: Wed, 8 Mar 2023 08:27:00 +0300 Subject: [PATCH 13/29] localization changed --- .../AbpIoLocalization/Commercial/Localization/Resources/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json index 8ba77e32a9..d06e505e40 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json @@ -208,7 +208,7 @@ "WhenShouldIRenewMyLicense": "When should I renew my license?", "WhenShouldIRenewMyLicenseExplanation": "If you renew your license within 1 month after your license expires, the following discounts will be applied: Team License {0}; Business License {1}; Enterprise License {2}. However, if you renew your license after 1 month since the expiry date of your license, the renewal price will be the same as the license purchase price and there will be no discount on your renewal.", "TrialPlan": "Do you have a trial plan?", - "TrialPlanExplanation": "It has a 14 days trial period for the ABP Commercial team license. For more information visit here. Furthermore, for the Team licenses we provide a 30 days money-back guarantee. You can just request a refund in the first 30 days. For the Business and Enterprise licenses, we provide 60% refund in 30 days. This is because Business and Enterprise licenses include the full source code of all the modules and the themes.", + "TrialPlanExplanation": "No, there is no trial version for ABP Commercial. You can check the community edition to understand the code quality and approaches. We also offer a 30-day money-back guarantee for the Team license, no questions asked! You can request a refund within the first 30 days. We provide a 60% refund within 30 days for Business and Enterprise licenses. This is because the Business and Enterprise licenses contain the full source-code of all the modules and themes.", "DoYouAcceptBankWireTransfer": "Do you accept bank wire transfers?", "DoYouAcceptBankWireTransferExplanation": "Yes, we accept bank wire transfers.
After sending the license fee via bank transfer, send your receipt and requested license type to accounting@volosoft.com.
Our international bank account information:", "HowToUpgrade": "How to upgrade existing applications when a new version is available?", From 1402db4e3d6b5e9c81234b892322b7db9dd6dfa6 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 8 Mar 2023 16:31:52 +0800 Subject: [PATCH 14/29] Disable dynamic permissions and features in unit test. --- .../MyProjectNameEntityFrameworkCoreTestModule.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.EntityFrameworkCore.Tests/EntityFrameworkCore/MyProjectNameEntityFrameworkCoreTestModule.cs b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.EntityFrameworkCore.Tests/EntityFrameworkCore/MyProjectNameEntityFrameworkCoreTestModule.cs index 846df976e0..a1a28b4e6d 100644 --- a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.EntityFrameworkCore.Tests/EntityFrameworkCore/MyProjectNameEntityFrameworkCoreTestModule.cs +++ b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.EntityFrameworkCore.Tests/EntityFrameworkCore/MyProjectNameEntityFrameworkCoreTestModule.cs @@ -6,7 +6,9 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.Sqlite; +using Volo.Abp.FeatureManagement; using Volo.Abp.Modularity; +using Volo.Abp.PermissionManagement; using Volo.Abp.Uow; namespace MyCompanyName.MyProjectName.EntityFrameworkCore; @@ -22,7 +24,18 @@ public class MyProjectNameEntityFrameworkCoreTestModule : AbpModule public override void ConfigureServices(ServiceConfigurationContext context) { + Configure(options => + { + options.SaveStaticFeaturesToDatabase = false; + options.IsDynamicFeatureStoreEnabled = false; + }); + Configure(options => + { + options.SaveStaticPermissionsToDatabase = false; + options.IsDynamicPermissionStoreEnabled = false; + }); context.Services.AddAlwaysDisableUnitOfWorkTransaction(); + ConfigureInMemorySqlite(context.Services); } From ea254d3a5e7a8feee359cd1ed794e4818ed30e99 Mon Sep 17 00:00:00 2001 From: Mahmut Gundogdu Date: Wed, 8 Mar 2023 12:07:39 +0300 Subject: [PATCH 15/29] ng add @nguniversal/express-engine --- npm/ng-packs/packages/theme-shared/src/lib/components/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts index 095af5ef26..238bc19589 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/index.ts @@ -12,3 +12,5 @@ export * from './toast-container/toast-container.component'; export * from './toast/toast.component'; export * from './password/password.component'; export * from './card/index'; +export * from './checkbox/checkbox.component'; +export * from './form-input/form-input.component'; From 481707426e4e4c52fde8bec89d72318621081fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Can=20Y=C4=B1lmaz?= <30300440+bariscanyilmaz@users.noreply.github.com> Date: Wed, 8 Mar 2023 15:44:42 +0300 Subject: [PATCH 16/29] create local storage service --- .../packages/core/src/lib/services/index.ts | 1 + .../src/lib/services/local-storage.service.ts | 28 +++++++++++++++++++ .../lib/tests/local-storage.service.spec.ts | 16 +++++++++++ 3 files changed, 45 insertions(+) create mode 100644 npm/ng-packs/packages/core/src/lib/services/local-storage.service.ts create mode 100644 npm/ng-packs/packages/core/src/lib/tests/local-storage.service.spec.ts diff --git a/npm/ng-packs/packages/core/src/lib/services/index.ts b/npm/ng-packs/packages/core/src/lib/services/index.ts index 209d2a881e..fefc9931eb 100644 --- a/npm/ng-packs/packages/core/src/lib/services/index.ts +++ b/npm/ng-packs/packages/core/src/lib/services/index.ts @@ -18,3 +18,4 @@ export * from './routes.service'; export * from './session-state.service'; export * from './subscription.service'; export * from './track-by.service'; +export * from './local-storage.service'; diff --git a/npm/ng-packs/packages/core/src/lib/services/local-storage.service.ts b/npm/ng-packs/packages/core/src/lib/services/local-storage.service.ts new file mode 100644 index 0000000000..15ae8d53a3 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/services/local-storage.service.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root', +}) +export class AbpLocalStorageService implements Storage { + constructor() {} + [name: string]: any; + get length(): number { + return localStorage.length; + } + + clear(): void { + localStorage.clear(); + } + getItem(key: string): string { + return localStorage.getItem(key); + } + key(index: number): string { + return localStorage.key(index); + } + removeItem(key: string): void { + localStorage.removeItem(key); + } + setItem(key: string, value: string): void { + localStorage.setItem(key, value); + } +} diff --git a/npm/ng-packs/packages/core/src/lib/tests/local-storage.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/local-storage.service.spec.ts new file mode 100644 index 0000000000..204c052d21 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/tests/local-storage.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { AbpLocalStorageService } from '../services/local-storage.service'; + +describe('LocalStorageService', () => { + let service: AbpLocalStorageService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(AbpLocalStorageService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); From d3cfc33c792bd85c5197d2a6abfbea16bfcfc79a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Can=20Y=C4=B1lmaz?= <30300440+bariscanyilmaz@users.noreply.github.com> Date: Wed, 8 Mar 2023 15:47:31 +0300 Subject: [PATCH 17/29] use localstorage service --- .../src/lib/services/session-state.service.ts | 10 +++++++--- .../packages/oauth/src/lib/oauth.module.ts | 6 +++--- .../src/lib/strategies/auth-flow-strategy.ts | 3 +++ .../strategies/auth-password-flow-strategy.ts | 8 ++++---- .../oauth/src/lib/utils/auth-utils.ts | 19 +++++++++++-------- 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/session-state.service.ts b/npm/ng-packs/packages/core/src/lib/services/session-state.service.ts index d3bac9a338..36f7c9e94a 100644 --- a/npm/ng-packs/packages/core/src/lib/services/session-state.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/session-state.service.ts @@ -5,6 +5,7 @@ import { Session } from '../models/session'; import { CurrentTenantDto } from '../proxy/volo/abp/asp-net-core/mvc/multi-tenancy/models'; import { InternalStore } from '../utils/internal-store-utils'; import { ConfigStateService } from './config-state.service'; +import { AbpLocalStorageService } from './local-storage.service'; @Injectable({ providedIn: 'root', @@ -13,16 +14,19 @@ export class SessionStateService { private readonly store = new InternalStore({} as Session.State); private updateLocalStorage = () => { - localStorage.setItem('abpSession', JSON.stringify(this.store.state)); + this.localStorageService.setItem('abpSession', JSON.stringify(this.store.state)); }; - constructor(private configState: ConfigStateService) { + constructor( + private configState: ConfigStateService, + private localStorageService: AbpLocalStorageService, + ) { this.init(); this.setInitialLanguage(); } private init() { - const session = localStorage.getItem('abpSession'); + const session = this.localStorageService.getItem('abpSession'); if (session) { this.store.set(JSON.parse(session)); } diff --git a/npm/ng-packs/packages/oauth/src/lib/oauth.module.ts b/npm/ng-packs/packages/oauth/src/lib/oauth.module.ts index 5680b9582d..ac800e7c8f 100644 --- a/npm/ng-packs/packages/oauth/src/lib/oauth.module.ts +++ b/npm/ng-packs/packages/oauth/src/lib/oauth.module.ts @@ -2,14 +2,14 @@ import { APP_INITIALIZER, ModuleWithProviders, NgModule, Provider } from '@angul import { CommonModule } from '@angular/common'; import { OAuthModule, OAuthStorage } from 'angular-oauth2-oidc'; import { + AbpLocalStorageService, ApiInterceptor, AuthGuard, AuthService, CHECK_AUTHENTICATION_STATE_FN_KEY, noop, - PIPE_TO_LOGIN_FN_KEY + PIPE_TO_LOGIN_FN_KEY, } from '@abp/ng.core'; -import { storageFactory } from './utils/storage.factory'; import { AbpOAuthService } from './services'; import { OAuthConfigurationHandler } from './handlers/oauth-configuration.handler'; import { HTTP_INTERCEPTORS } from '@angular/common/http'; @@ -59,7 +59,7 @@ export class AbpOAuthModule { useFactory: noop, }, OAuthModule.forRoot().providers as Provider[], - { provide: OAuthStorage, useFactory: storageFactory }, + { provide: OAuthStorage, useClass: AbpLocalStorageService }, ], }; } diff --git a/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts b/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts index 7a07cb8985..c1bf50e0b5 100644 --- a/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts +++ b/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts @@ -9,6 +9,7 @@ import { import { Observable, of } from 'rxjs'; import { filter, switchMap, tap } from 'rxjs/operators'; import { + AbpLocalStorageService, ConfigStateService, EnvironmentService, HttpErrorReporterService, @@ -29,6 +30,7 @@ export abstract class AuthFlowStrategy { protected oAuthService: OAuthService2; protected oAuthConfig!: AuthConfig; protected sessionState: SessionStateService; + protected localStorageService: AbpLocalStorageService; protected tenantKey: string; abstract checkIfInternalAuth(queryParams?: Params): boolean; @@ -50,6 +52,7 @@ export abstract class AuthFlowStrategy { this.configState = injector.get(ConfigStateService); this.oAuthService = injector.get(OAuthService2); this.sessionState = injector.get(SessionStateService); + this.localStorageService = injector.get(AbpLocalStorageService); this.oAuthConfig = this.environment.getEnvironment().oAuthConfig || {}; this.tenantKey = injector.get(TENANT_KEY); diff --git a/npm/ng-packs/packages/oauth/src/lib/strategies/auth-password-flow-strategy.ts b/npm/ng-packs/packages/oauth/src/lib/strategies/auth-password-flow-strategy.ts index 2e2e278985..fab747fe90 100644 --- a/npm/ng-packs/packages/oauth/src/lib/strategies/auth-password-flow-strategy.ts +++ b/npm/ng-packs/packages/oauth/src/lib/strategies/auth-password-flow-strategy.ts @@ -4,7 +4,7 @@ import { Params, Router } from '@angular/router'; import { from, Observable, pipe } from 'rxjs'; import { HttpHeaders } from '@angular/common/http'; import { AuthFlowStrategy } from './auth-flow-strategy'; -import { pipeToLogin, removeRememberMe, setRememberMe } from '../utils/auth-utils'; +import { pipeToLogin, removeRememberMe } from '../utils/auth-utils'; import { LoginParams } from '@abp/ng.core'; import { clearOAuthStorage } from '../utils/clear-o-auth-storage'; @@ -33,7 +33,7 @@ export class AuthPasswordFlowStrategy extends AuthFlowStrategy { this.refreshToken(); } else { this.oAuthService.logOut(); - removeRememberMe(); + removeRememberMe(this.localStorageService); this.configState.refreshAppState().subscribe(); } }); @@ -74,7 +74,7 @@ export class AuthPasswordFlowStrategy extends AuthFlowStrategy { switchMap(() => this.configState.refreshAppState()), tap(() => { router.navigateByUrl('/'); - removeRememberMe(); + removeRememberMe(this.localStorageService); }), ); } @@ -82,7 +82,7 @@ export class AuthPasswordFlowStrategy extends AuthFlowStrategy { protected refreshToken() { return this.oAuthService.refreshToken().catch(() => { clearOAuthStorage(); - removeRememberMe(); + removeRememberMe(this.localStorageService); }); } } diff --git a/npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts b/npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts index 24f94fe129..f1dc5b6106 100644 --- a/npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts +++ b/npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts @@ -7,7 +7,7 @@ import { ConfigStateService, LoginParams, PipeToLoginFn, - SetTokenResponseToStorageFn, + AbpLocalStorageService, } from '@abp/ng.core'; const cookieKey = 'rememberMe'; @@ -19,25 +19,28 @@ export const pipeToLogin: PipeToLoginFn = function ( ) { const configState = injector.get(ConfigStateService); const router = injector.get(Router); - + const localStorage = injector.get(AbpLocalStorageService); return pipe( switchMap(() => configState.refreshAppState()), tap(() => { - setRememberMe(params.rememberMe); + setRememberMe(params.rememberMe, localStorage); if (params.redirectUrl) router.navigate([params.redirectUrl]); }), ); }; -export function setRememberMe(remember: boolean | undefined) { - removeRememberMe(); - localStorage.setItem(storageKey, 'true'); +export function setRememberMe( + remember: boolean | undefined, + localStorageService: AbpLocalStorageService, +) { + removeRememberMe(localStorageService); + localStorageService.setItem(storageKey, 'true'); document.cookie = `${cookieKey}=true; path=/${ remember ? ' ;expires=Fri, 31 Dec 9999 23:59:59 GMT' : '' }`; } -export function removeRememberMe() { - localStorage.removeItem(storageKey); +export function removeRememberMe(localStorageService: AbpLocalStorageService) { + localStorageService.removeItem(storageKey); document.cookie = cookieKey + '= ; path=/; expires = Thu, 01 Jan 1970 00:00:00 GMT'; } From f39ec4797190242e7c5bb52c915e2d1948bf0ecf Mon Sep 17 00:00:00 2001 From: Berkan Sasmaz Date: Wed, 8 Mar 2023 17:01:35 +0300 Subject: [PATCH 18/29] CLI: Add user id to LoginInfo --- .../src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/LoginInfo.cs | 5 ++++- .../Volo/Abp/Cli/Commands/LoginInfoCommand.cs | 5 ++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/LoginInfo.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/LoginInfo.cs index aacb26e5f4..3b14c96330 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/LoginInfo.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/LoginInfo.cs @@ -1,8 +1,11 @@ - +using System; + namespace Volo.Abp.Cli.Auth; public class LoginInfo { + public Guid? Id { get; set; } + public string Name { get; set; } public string Surname { get; set; } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginInfoCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginInfoCommand.cs index 9d17bf4c4f..d8f007dc2c 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginInfoCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginInfoCommand.cs @@ -1,5 +1,4 @@ -using System; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using System.Text; using System.Threading.Tasks; @@ -41,7 +40,7 @@ public class LoginInfoCommand : IConsoleCommand, ITransientDependency var sb = new StringBuilder(); sb.AppendLine(""); - sb.AppendLine($"Login info:"); + sb.AppendLine("Login info:"); sb.AppendLine($"Name: {loginInfo.Name}"); sb.AppendLine($"Surname: {loginInfo.Surname}"); sb.AppendLine($"Username: {loginInfo.Username}"); From f0120d121fc8c374eaeff8b3141d94cfbd60ea04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Can=20Y=C4=B1lmaz?= <30300440+bariscanyilmaz@users.noreply.github.com> Date: Wed, 8 Mar 2023 18:12:51 +0300 Subject: [PATCH 19/29] implement primitive tests --- .../lib/tests/local-storage.service.spec.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/npm/ng-packs/packages/core/src/lib/tests/local-storage.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/local-storage.service.spec.ts index 204c052d21..ad51bbda2b 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/local-storage.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/local-storage.service.spec.ts @@ -13,4 +13,40 @@ describe('LocalStorageService', () => { it('should be created', () => { expect(service).toBeTruthy(); }); + + it('should be called getItem', () => { + const spy = jest.spyOn(service, 'getItem'); + service.getItem('test'); + expect(spy).toHaveBeenCalled(); + }); + + it('should be called setItem', () => { + const spy = jest.spyOn(service, 'setItem'); + service.setItem('test', 'value'); + expect(spy).toHaveBeenCalled(); + }); + + it('should be called removeItem', () => { + const spy = jest.spyOn(service, 'removeItem'); + service.removeItem('test'); + expect(spy).toHaveBeenCalled(); + }); + + it('should be called clear', () => { + const spy = jest.spyOn(service, 'clear'); + service.clear(); + expect(spy).toHaveBeenCalled(); + }); + + it('should be called key', () => { + const spy = jest.spyOn(service, 'key'); + service.key(0); + expect(spy).toHaveBeenCalled(); + }); + + it('should be called length', () => { + const spy = jest.spyOn(service, 'length', 'get'); + service.length; + expect(spy).toHaveBeenCalled(); + }); }); From 3e8b2bfa2e2a0e06e3daa2c99aee2d5a81723e2a Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Thu, 9 Mar 2023 15:50:54 +0800 Subject: [PATCH 20/29] Document: Define groups for menu items --- docs/en/UI/AspNetCore/Navigation-Menu.md | 58 +++++++++++++++++++++++- docs/en/UI/Blazor/Navigation-Menu.md | 53 ++++++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/docs/en/UI/AspNetCore/Navigation-Menu.md b/docs/en/UI/AspNetCore/Navigation-Menu.md index f0776f47ec..2fcf641413 100644 --- a/docs/en/UI/AspNetCore/Navigation-Menu.md +++ b/docs/en/UI/AspNetCore/Navigation-Menu.md @@ -104,6 +104,7 @@ There are more options of a menu item (the constructor of the `ApplicationMenuIt * `target` (`string`): Target of the menu item. Can be `null` (default), "\_*blank*", "\_*self*", "\_*parent*", "\_*top*" or a frame name for web applications. * `elementId` (`string`): Can be used to render the element with a specific HTML `id` attribute. * `cssClass` (`string`): Additional string classes for the menu item. +* `groupName` (`string`): Can be used to group menu items. ### Authorization @@ -179,6 +180,58 @@ userMenu.Icon = "fa fa-users"; > `context.Menu` gives you ability to access to all the menu items those have been added by the previous menu contributors. +### Menu Groups + +You can define groups and associate menu items with a group. + +Example: + +```csharp +using System.Threading.Tasks; +using MyProject.Localization; +using Volo.Abp.UI.Navigation; + +namespace MyProject.Web.Menus +{ + public class MyProjectMenuContributor : IMenuContributor + { + public async Task ConfigureMenuAsync(MenuConfigurationContext context) + { + if (context.Menu.Name == StandardMenus.Main) + { + await ConfigureMainMenuAsync(context); + } + } + + private async Task ConfigureMainMenuAsync(MenuConfigurationContext context) + { + var l = context.GetLocalizer(); + + context.Menu.AddGroup( + new ApplicationMenuGroup( + name: "Main", + displayName: l["Main"] + ) + ) + context.Menu.AddItem( + new ApplicationMenuItem("MyProject.Crm", l["Menu:CRM"], groupName: "Main") + .AddItem(new ApplicationMenuItem( + name: "MyProject.Crm.Customers", + displayName: l["Menu:Customers"], + url: "/crm/customers") + ).AddItem(new ApplicationMenuItem( + name: "MyProject.Crm.Orders", + displayName: l["Menu:Orders"], + url: "/crm/orders") + ) + ); + } + } +} +``` + +> The UI theme will decide to render groups or not, and if it decides to render, it is up to theme how to render. Only the LeptonX theme implements menu group. + ## Standard Menus A menu is a **named** component. An application may contain more than one menus with different, unique names. There are two pre-defined standard menus: @@ -199,6 +252,10 @@ if (context.Menu.Name == StandardMenus.User) } ``` +### Menu Groups + + + ## IMenuManager `IMenuManager` is generally used by the UI [theme](Theming.md) to render the menu items on the UI. So, **you generally don't need to directly use** the `IMenuManager`. @@ -233,4 +290,3 @@ namespace MyProject.Web.Pages } } ``` - diff --git a/docs/en/UI/Blazor/Navigation-Menu.md b/docs/en/UI/Blazor/Navigation-Menu.md index 7f09a65dbb..287226183d 100644 --- a/docs/en/UI/Blazor/Navigation-Menu.md +++ b/docs/en/UI/Blazor/Navigation-Menu.md @@ -104,6 +104,7 @@ There are more options of a menu item (the constructor of the `ApplicationMenuIt * `target` (`string`): Target of the menu item. Can be `null` (default), "\_*blank*", "\_*self*", "\_*parent*", "\_*top*" or a frame name for web applications. * `elementId` (`string`): Can be used to render the element with a specific HTML `id` attribute. * `cssClass` (`string`): Additional string classes for the menu item. +* `groupName` (`string`): Can be used to group menu items. ### Authorization @@ -160,6 +161,58 @@ userMenu.Icon = "fa fa-users"; > `context.Menu` gives you ability to access to all the menu items those have been added by the previous menu contributors. +### Menu Groups + +You can define groups and associate menu items with a group. + +Example: + +```csharp +using System.Threading.Tasks; +using MyProject.Localization; +using Volo.Abp.UI.Navigation; + +namespace MyProject.Web.Menus +{ + public class MyProjectMenuContributor : IMenuContributor + { + public async Task ConfigureMenuAsync(MenuConfigurationContext context) + { + if (context.Menu.Name == StandardMenus.Main) + { + await ConfigureMainMenuAsync(context); + } + } + + private async Task ConfigureMainMenuAsync(MenuConfigurationContext context) + { + var l = context.GetLocalizer(); + + context.Menu.AddGroup( + new ApplicationMenuGroup( + name: "Main", + displayName: l["Main"] + ) + ) + context.Menu.AddItem( + new ApplicationMenuItem("MyProject.Crm", l["Menu:CRM"], groupName: "Main") + .AddItem(new ApplicationMenuItem( + name: "MyProject.Crm.Customers", + displayName: l["Menu:Customers"], + url: "/crm/customers") + ).AddItem(new ApplicationMenuItem( + name: "MyProject.Crm.Orders", + displayName: l["Menu:Orders"], + url: "/crm/orders") + ) + ); + } + } +} +``` + +> The UI theme will decide to render groups or not, and if it decides to render, it is up to theme how to render. Only the LeptonX theme implements menu group. + ## Standard Menus A menu is a **named** component. An application may contain more than one menus with different, unique names. There are two pre-defined standard menus: From 56655e425406025ce4528b567a478d53345fbb5b Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Thu, 9 Mar 2023 15:52:28 +0800 Subject: [PATCH 21/29] Update Navigation-Menu.md --- docs/en/UI/AspNetCore/Navigation-Menu.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/en/UI/AspNetCore/Navigation-Menu.md b/docs/en/UI/AspNetCore/Navigation-Menu.md index 2fcf641413..13997a9e67 100644 --- a/docs/en/UI/AspNetCore/Navigation-Menu.md +++ b/docs/en/UI/AspNetCore/Navigation-Menu.md @@ -252,10 +252,6 @@ if (context.Menu.Name == StandardMenus.User) } ``` -### Menu Groups - - - ## IMenuManager `IMenuManager` is generally used by the UI [theme](Theming.md) to render the menu items on the UI. So, **you generally don't need to directly use** the `IMenuManager`. From 8b894b0178813ca2bbe8b3d11047893653662d46 Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Thu, 9 Mar 2023 14:19:46 +0300 Subject: [PATCH 22/29] extra slash issue fixed in angular from rel-7 (@abp/ng.oauth) --- .../lib/providers/navigate-to-manage-profile.provider.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/npm/ng-packs/packages/oauth/src/lib/providers/navigate-to-manage-profile.provider.ts b/npm/ng-packs/packages/oauth/src/lib/providers/navigate-to-manage-profile.provider.ts index e20bf62fc2..e1c6d458a4 100644 --- a/npm/ng-packs/packages/oauth/src/lib/providers/navigate-to-manage-profile.provider.ts +++ b/npm/ng-packs/packages/oauth/src/lib/providers/navigate-to-manage-profile.provider.ts @@ -12,10 +12,10 @@ export const NavigateToManageProfileProvider: Provider = { console.warn('The oAuthConfig env is missing on environment.ts'); return; } - window.open( - `${env.oAuthConfig.issuer}/Account/Manage?returnUrl=${window.location.href}`, - '_self', - ); + + const { issuer } = env.oAuthConfig; + const path = issuer.endsWith('/') ? issuer : `${issuer}/`; + window.open(`${path}Account/Manage?returnUrl=${window.location.href}`, '_self'); }; }, }; From f8bc3db8f25939967ddc33a09a292b8faa41da01 Mon Sep 17 00:00:00 2001 From: Hamza Albreem <94292623+braim23@users.noreply.github.com> Date: Thu, 9 Mar 2023 16:26:14 +0300 Subject: [PATCH 23/29] Update Navigation-Menu.md --- docs/en/UI/AspNetCore/Navigation-Menu.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/UI/AspNetCore/Navigation-Menu.md b/docs/en/UI/AspNetCore/Navigation-Menu.md index 13997a9e67..60621f9906 100644 --- a/docs/en/UI/AspNetCore/Navigation-Menu.md +++ b/docs/en/UI/AspNetCore/Navigation-Menu.md @@ -230,7 +230,7 @@ namespace MyProject.Web.Menus } ``` -> The UI theme will decide to render groups or not, and if it decides to render, it is up to theme how to render. Only the LeptonX theme implements menu group. +> The UI theme will decide whether to render the groups or not, and if it decides to render, the way it's rendered is up to the theme. Only the LeptonX theme implements the menu group. ## Standard Menus From 377c8c9c8e891e0b98ed1c28b774a762b3b633ba Mon Sep 17 00:00:00 2001 From: Hamza Albreem <94292623+braim23@users.noreply.github.com> Date: Thu, 9 Mar 2023 16:27:19 +0300 Subject: [PATCH 24/29] Update Navigation-Menu.md --- docs/en/UI/Blazor/Navigation-Menu.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/UI/Blazor/Navigation-Menu.md b/docs/en/UI/Blazor/Navigation-Menu.md index 287226183d..0abac5fc68 100644 --- a/docs/en/UI/Blazor/Navigation-Menu.md +++ b/docs/en/UI/Blazor/Navigation-Menu.md @@ -211,7 +211,7 @@ namespace MyProject.Web.Menus } ``` -> The UI theme will decide to render groups or not, and if it decides to render, it is up to theme how to render. Only the LeptonX theme implements menu group. +> The UI theme will decide whether to render the groups or not, and if it decides to render, the way it's rendered is up to the theme. Only the LeptonX theme implements the menu group. ## Standard Menus From 472f923471baf00397b1b08cbd982de99a4d4b2b Mon Sep 17 00:00:00 2001 From: masumulu28 Date: Fri, 10 Mar 2023 10:28:59 +0300 Subject: [PATCH 25/29] Lint exception fixed in theme-shard --- .../theme-shared/src/lib/directives/visible.directive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/directives/visible.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/directives/visible.directive.ts index 9c2c408d0e..9613779472 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/directives/visible.directive.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/directives/visible.directive.ts @@ -8,7 +8,7 @@ export class AbpVisibleDirective implements OnDestroy, OnInit { conditionSubscription: Subscription | undefined; isVisible: boolean | undefined; - @Input('abpVisible') set abpVisible( + @Input() set abpVisible( value: boolean | Promise | Observable | undefined | null, ) { this.condition$ = checkType(value); From bbd93e3839de915e9b8dc4c50def84418cf58627 Mon Sep 17 00:00:00 2001 From: MrXhh <2791341417@qq.com> Date: Sun, 12 Mar 2023 21:54:21 +0800 Subject: [PATCH 26/29] Quick fix for the Tutorials/Part-10 doc --- docs/en/Tutorials/Part-10.md | 2 +- docs/zh-Hans/Tutorials/Part-10.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/Tutorials/Part-10.md b/docs/en/Tutorials/Part-10.md index 6178ebbb8e..e71beccd6f 100644 --- a/docs/en/Tutorials/Part-10.md +++ b/docs/en/Tutorials/Part-10.md @@ -361,7 +361,7 @@ public class BookAppService : GetListPolicyName = BookStorePermissions.Books.Default; CreatePolicyName = BookStorePermissions.Books.Create; UpdatePolicyName = BookStorePermissions.Books.Edit; - DeletePolicyName = BookStorePermissions.Books.Create; + DeletePolicyName = BookStorePermissions.Books.Delete; } public override async Task GetAsync(Guid id) diff --git a/docs/zh-Hans/Tutorials/Part-10.md b/docs/zh-Hans/Tutorials/Part-10.md index 170e3106a1..da5c23c78f 100644 --- a/docs/zh-Hans/Tutorials/Part-10.md +++ b/docs/zh-Hans/Tutorials/Part-10.md @@ -367,7 +367,7 @@ namespace Acme.BookStore.Books GetListPolicyName = BookStorePermissions.Books.Default; CreatePolicyName = BookStorePermissions.Books.Create; UpdatePolicyName = BookStorePermissions.Books.Edit; - DeletePolicyName = BookStorePermissions.Books.Create; + DeletePolicyName = BookStorePermissions.Books.Delete; } public override async Task GetAsync(Guid id) From d3c04576e83e34704f599cb63e115e84932509c3 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 13 Mar 2023 10:57:12 +0800 Subject: [PATCH 27/29] Upgrade `Autofac` to 7.0.0. Resolve #15942 --- framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj b/framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj index d8d2b83e5a..e03023a72a 100644 --- a/framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj +++ b/framework/src/Volo.Abp.Autofac/Volo.Abp.Autofac.csproj @@ -15,7 +15,7 @@ - + From 0a7c93521ee738dfd05c55b2039c9088b1203284 Mon Sep 17 00:00:00 2001 From: Salih Date: Mon, 13 Mar 2023 13:14:55 +0300 Subject: [PATCH 28/29] Update en.json --- .../Community/Localization/Resources/en.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json index 8cfb154295..953625f9cd 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/en.json @@ -184,6 +184,8 @@ "Layout_MetaDescription": "ABP Community is an environment where people can share posts about ABP framework and follows the projects.", "Index_Page_CommunityIntroduction": "This is a hub for ABP Framework, .NET and software development. You can read the articles, watch the video tutorials, get informed about ABP’s development progress and ABP-related events, help other developers and share your expertise with the ABP community.", "TagsInArticle": "Tags in article", - "IConsentToMedium": "I consent to the publication of this post at https://medium.com/volosoft." + "IConsentToMedium": "I consent to the publication of this post at https://medium.com/volosoft.", + "SearchResultsFor": "Search results for \"{0}\"", + "SeeMoreVideos": "See more videos" } } From c365ced19074027a020bc117f187ce899fa4f676 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 14 Mar 2023 10:06:41 +0800 Subject: [PATCH 29/29] Use EF 7 compatible `Devart.Data.Oracle.EFCore` package. Resolve #14412 --- .../Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj index 9cf92a3f77..2ead0da1f3 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart/Volo.Abp.EntityFrameworkCore.Oracle.Devart.csproj @@ -19,8 +19,7 @@ - - +