diff --git a/docs/en/UI/Angular/Environment.md b/docs/en/UI/Angular/Environment.md index 983f44e647..1b78a11cc6 100644 --- a/docs/en/UI/Angular/Environment.md +++ b/docs/en/UI/Angular/Environment.md @@ -105,4 +105,4 @@ export interface RemoteEnv { ## What's Next? -* [Service Proxies](./Service-Proxies.md) +- [About Feature Libraries](./Feature-Libraries.md) diff --git a/docs/en/UI/Angular/Feature-Libraries.md b/docs/en/UI/Angular/Feature-Libraries.md new file mode 100644 index 0000000000..937bae7245 --- /dev/null +++ b/docs/en/UI/Angular/Feature-Libraries.md @@ -0,0 +1,98 @@ +# About Feature Libraries + +ABP has an ever-growing number of feature modules and [introducing a new one](../../Module-Development-Basics.md) is always possible. When the UI is Angular, these features have modular Angular libraries accompanying them. + +## Feature Library Content + +Each library has at least two modules: + +1. The main module contains all components, services, types, enums, etc. to deliver the required UI when the feature is loaded. From here on, we will refer to these modules as **"feature module"**. +2. There is also a **"config module"** per library which helps us configure applications to run these modules or make them accessible. + +## How to Add a Feature Library to Your Project + + + +The manual setup of a feature library has three steps: + +### 1. Install the Library + +Feature libraries are usually published as an npm package. If a library you want to use does not exist in your project, you may install it via the following command: + +```shell +yarn add @my-company-name/my-project-name +``` + +...or... + +```shell +npm install @my-company-name/my-project-name +``` + +The `my-company-name` and `my-project-name` parts are going to change according to the package you want to use. For example, if we want to install the ABP Identity module, the package installation will be as seen below: + +```shell +yarn add @abp/ng.identity +``` + +> Identity is used just as an example. If you have initiated your project with ABP CLI or ABP Suite, the identity library will already be installed and configured in your project. + +### 2. Import the Config Module + +As of ABP v3.0, every lazy-loaded module has a config module available via a secondary entry point on the same package. Importing them in your root module looks like this: + +```js +import { IdentityConfigModule } from "@abp/ng.identity/config"; + +@NgModule({ + imports: [ + // other imports + IdentityConfigModule.forRoot(), + ], + // providers, declarations, and bootstrap +}) +export class AppModule {} +``` + +We need the config modules for actions required before feature modules are loaded (lazily). For example, the above import configures the menu to display links to identity pages. + +Furthermore, depending on the library, the `.forRoot` static method may receive some options that configure how the feature works. + +### 3. Import the Feature Module + +Finally, the feature module should be [loaded lazily via Angular router](https://angular.io/guide/lazy-loading-ngmodules). If you open the `/src/app/app-routing.module.ts` file, you should see `IdentityModule` is loaded exactly as follows: + +```js +import { NgModule } from "@angular/core"; +import { RouterModule, Routes } from "@angular/router"; + +const routes: Routes = [ + // other routes + { + path: "identity", + loadChildren: () => + import("@abp/ng.identity").then((m) => m.IdentityModule.forLazy()), + }, + // other routes +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule], +}) +export class AppRoutingModule {} +``` + +When you load the identity feature like this, the "Users" page, for example, will have a route path of `/identity/users`. [1](#f-modify-route) + +Depending on the library, the `.forLazy` static method may also receive some options that configure how the feature works. + +--- + +1 _Libraries expect to work at a predefined path. Please check [how to patch a navigation element](./Modifying-the-Menu.md#how-to-patch-or-remove-a-navigation-element), if you want to use a different path from the default one (e.g. '/identity')._ [↩](#a-modify-route) + +--- + +## What's Next? + +- [Service Proxies](./Service-Proxies.md) diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index a70ddea62c..9116fca5a0 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -442,6 +442,10 @@ "text": "Environment Variables", "path": "UI/Angular/Environment.md" }, + { + "text": "About Feature Libraries", + "path": "UI/Angular/Feature-Libraries.md" + }, { "text": "Service Proxies", "path": "UI/Angular/Service-Proxies.md" diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserCreateOrUpdateDtoBase.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserCreateOrUpdateDtoBase.cs index 41981b2ca8..e2fe874dbd 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserCreateOrUpdateDtoBase.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserCreateOrUpdateDtoBase.cs @@ -26,8 +26,6 @@ namespace Volo.Abp.Identity [DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxPhoneNumberLength))] public string PhoneNumber { get; set; } - public bool TwoFactorEnabled { get; set; } - public bool LockoutEnabled { get; set; } [CanBeNull] @@ -35,7 +33,7 @@ namespace Volo.Abp.Identity protected IdentityUserCreateOrUpdateDtoBase() : base(false) { - + } } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserDto.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserDto.cs index 9f94d7b599..f7291a4e82 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserDto.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserDto.cs @@ -23,12 +23,10 @@ namespace Volo.Abp.Identity public bool PhoneNumberConfirmed { get; set; } - public bool TwoFactorEnabled { get; set; } - public bool LockoutEnabled { get; set; } public DateTimeOffset? LockoutEnd { get; set; } public string ConcurrencyStamp { get; set; } } -} \ No newline at end of file +} diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs index 74b210066f..070a452218 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs @@ -162,7 +162,6 @@ namespace Volo.Abp.Identity (await UserManager.SetPhoneNumberAsync(user, input.PhoneNumber)).CheckErrors(); } - (await UserManager.SetTwoFactorEnabledAsync(user, input.TwoFactorEnabled)).CheckErrors(); (await UserManager.SetLockoutEnabledAsync(user, input.LockoutEnabled)).CheckErrors(); user.Name = input.Name; diff --git a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor b/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor index 9feba0eb06..bfbd2150c6 100644 --- a/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor +++ b/modules/identity/src/Volo.Abp.Identity.Blazor/Pages/Identity/UserManagement.razor @@ -121,9 +121,6 @@ @L["DisplayName:LockoutEnabled"] - - @L["DisplayName:TwoFactorEnabled"] - @if (NewUserRoles != null) @@ -197,9 +194,6 @@ @L["DisplayName:LockoutEnabled"] - - @L["DisplayName:TwoFactorEnabled"] - @if (EditUserRoles != null) diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml index b171b785a2..d0b52a345c 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml @@ -26,8 +26,7 @@ - - + @foreach (var propertyInfo in ObjectExtensionManager.Instance.GetProperties()) { if (propertyInfo.Type.IsEnum) @@ -56,4 +55,4 @@ - \ No newline at end of file + diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs index a868890632..03bbd859cc 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs @@ -79,8 +79,6 @@ namespace Volo.Abp.Identity.Web.Pages.Identity.Users [DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxPhoneNumberLength))] public string PhoneNumber { get; set; } - public bool TwoFactorEnabled { get; set; } = true; - public bool LockoutEnabled { get; set; } = true; } diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml index 56ac3929f1..ca404c7e67 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml @@ -28,8 +28,7 @@ - - + @foreach (var propertyInfo in ObjectExtensionManager.Instance.GetProperties()) { if (propertyInfo.Type.IsEnum) @@ -46,7 +45,7 @@ value="@propertyInfo.GetInputValueOrNull(Model.UserInfo.ExtraProperties[propertyInfo.Name])" /> } } - + @for (var i = 0; i < Model.Roles.Length; i++) @@ -59,4 +58,4 @@ - \ No newline at end of file + diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml.cs b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml.cs index a2336c2b8e..29d044f9da 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml.cs +++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml.cs @@ -87,8 +87,6 @@ namespace Volo.Abp.Identity.Web.Pages.Identity.Users [DynamicStringLength(typeof(IdentityUserConsts), nameof(IdentityUserConsts.MaxPhoneNumberLength))] public string PhoneNumber { get; set; } - public bool TwoFactorEnabled { get; set; } - public bool LockoutEnabled { get; set; } } diff --git a/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserAppService_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserAppService_Tests.cs index a56631b2ae..278ef10ced 100644 --- a/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserAppService_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/IdentityUserAppService_Tests.cs @@ -98,7 +98,6 @@ namespace Volo.Abp.Identity { UserName = johnNash.UserName, LockoutEnabled = true, - TwoFactorEnabled = true, PhoneNumber = CreateRandomPhoneNumber(), Password = "123qwe4R*", Email = CreateRandomEmail(), @@ -135,7 +134,7 @@ namespace Volo.Abp.Identity { //Get user var johnNash = await _userAppService.GetAsync(_testData.UserJohnId); - + //Act var input = new IdentityUserUpdateDto @@ -144,7 +143,6 @@ namespace Volo.Abp.Identity Surname = "Nash-updated", UserName = johnNash.UserName, LockoutEnabled = true, - TwoFactorEnabled = true, PhoneNumber = CreateRandomPhoneNumber(), Email = CreateRandomEmail(), RoleNames = new[] { "admin", "moderator" }, diff --git a/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/ExternalLoginProvider_Tests.cs b/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/ExternalLoginProvider_Tests.cs index ee9a56432e..c8d9f37c27 100644 --- a/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/ExternalLoginProvider_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/ExternalLoginProvider_Tests.cs @@ -44,7 +44,6 @@ namespace Volo.Abp.Identity.AspNetCore user.Name.ShouldBe("Test Name"); user.Surname.ShouldBe("Test Surname"); user.EmailConfirmed.ShouldBeTrue(); - user.TwoFactorEnabled.ShouldBeFalse(); user.PhoneNumber.ShouldBe("123"); user.PhoneNumberConfirmed.ShouldBeFalse(); user.IsExternal.ShouldBeTrue();