diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json index 0caa284764..34d20a3bda 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json @@ -421,7 +421,7 @@ "ContentCacheSlidingExpirationByDay": "Content Cache Sliding Expiration By Day", "MaxDaysForCaching": "Max Days For Caching", "Enabled": "Enabled", - "Menu:NugetPackagesContentCache": "NuGet Packages Content Cache", + "Menu:NugetPackagesContentCache": "NuGet Cache", "NugetPackagesContentCache": "NuGet Content Cache", "SlidingExpritionByDayInfo": "Gets or sets how long a cache entry can be inactive (e.g. not accessed) before it will be removed. This will not extend the entry lifetime beyond the absolute expiration.", "MaxDaysForCachingInfo": "Gets or sets an absolute expiration time, relative to now.", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json index 89f7648368..246095c064 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json @@ -27,6 +27,7 @@ "Volo.AbpIo.Domain:030010": "To purchase the trial license, you first need to activate your trial license!", "Volo.AbpIo.Domain:030011": "You cannot delete a trial license when it is purchased!", "Volo.AbpIo.Domain:030012": "A user is entitled to have only 1 free trial period. You already used your trial license.", + "Volo.AbpIo.Domain:030013": "A user with an active license cannot start a trial license.", "Volo.AbpIo.Domain:070000": "The organization name can only contain latin letters, numbers, dots and hyphens!", "Volo.AbpIo.Domain:070001": "The company name can only contain latin letters, numbers, dots, space and hyphens!", "WantToLearn?": "Want to learn?", diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json index 6e5e69f079..d4a60bde09 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json @@ -196,7 +196,7 @@ "ChangingDevelopers": "Can I change the registered developers of my organization in the future?", "ChangingDevelopersExplanation": "In addition to adding new developers to your license, you can also change the existing developers (you can remove a developer and add a new one to the same seat) without any additional cost.", "WhatHappensWhenLicenseEnds": "What happens when my license period ends?", - "WhatHappensWhenLicenseEndsExplanation1": "The ABP Commercial license is a perpetual license. After your license expires, you can continue developing your project. And you are not obliged to renew your license. Your license comes with a one-year update and support plan out of the box. In order to continue to get new features, performance enhancements, bug fixes, support and continue using ABP Suite, you need to renew your license. When your license expires, you will not get the following benefits:", + "WhatHappensWhenLicenseEndsExplanation1": "The ABP Commercial license is a perpetual license. After your license expires, you can continue developing your project. And you are not obliged to renew your license. Your license comes with a one-year update and support plan out of the box. In order to continue to get new features, performance enhancements, bug fixes, support and continue using ABP Suite, you need to renew your license. When your license expires;", "WhatHappensWhenLicenseEndsExplanation2": "You can not create new solutions using the ABP Commercial, but you can continue developing your existing applications forever.", "WhatHappensWhenLicenseEndsExplanation3": "You will be able to get updates for the modules and themes within your MINOR version (except RC or Preview versions). For example: if you are using v3.2.0 of a module, you can still get updates for v3.2.x (v3.2.1, v3.2.5... etc.) of that module. But you cannot get updates for the next major or minor version (like v3.3.0, v3.3.3, 4.x.x.. etc.). For example, when your license expired, the latest release was v4.4.3, and later, it published both 4.4.4 version and 4.5.0 version, you would be able to access the v4.4.X but you wouldn't be access the v4.5.X.", "WhatHappensWhenLicenseEndsExplanation4": "You can not install new modules and themes added to the ABP Commercial platform after your license ends.", diff --git a/common.props b/common.props index b0542ba87e..262ed2cf6a 100644 --- a/common.props +++ b/common.props @@ -1,7 +1,7 @@ latest - 7.1.0-rc.2 + 7.2.0 $(NoWarn);CS1591;CS0436 https://abp.io/assets/abp_nupkg.png https://abp.io/ diff --git a/docs/en/Dependency-Injection.md b/docs/en/Dependency-Injection.md index 47e60700bc..206c2c58a4 100644 --- a/docs/en/Dependency-Injection.md +++ b/docs/en/Dependency-Injection.md @@ -440,16 +440,16 @@ Use `ICachedServiceProvider` (instead of `ITransientCachedServiceProvider`) unle ## Advanced Features -### IServiceCollection.OnRegistred Event +### IServiceCollection.OnRegistered Event -You may want to perform an action for every service registered to the dependency injection. In the `PreConfigureServices` method of your module, register a callback using the `OnRegistred` method as shown below: +You may want to perform an action for every service registered to the dependency injection. In the `PreConfigureServices` method of your module, register a callback using the `OnRegistered` method as shown below: ````csharp public class AppModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(ctx => + context.Services.OnRegistered(ctx => { var type = ctx.ImplementationType; //... @@ -465,7 +465,7 @@ public class AppModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(ctx => + context.Services.OnRegistered(ctx => { if (ctx.ImplementationType.IsDefined(typeof(MyLogAttribute), true)) { @@ -478,7 +478,7 @@ public class AppModule : AbpModule This example simply checks if the service class has `MyLogAttribute` attribute and adds `MyLogInterceptor` to the interceptor list if so. -> Notice that `OnRegistred` callback might be called multiple times for the same service class if it exposes more than one service/interface. So, it's safe to use `Interceptors.TryAdd` method instead of `Interceptors.Add` method. See [the documentation](Dynamic-Proxying-Interceptors.md) of dynamic proxying / interceptors. +> Notice that `OnRegistered` callback might be called multiple times for the same service class if it exposes more than one service/interface. So, it's safe to use `Interceptors.TryAdd` method instead of `Interceptors.Add` method. See [the documentation](Dynamic-Proxying-Interceptors.md) of dynamic proxying / interceptors. ## 3rd-Party Providers diff --git a/docs/en/Migration-Guides/IdentityServer4-Step-by-Step.md b/docs/en/Migration-Guides/IdentityServer4-Step-by-Step.md new file mode 100644 index 0000000000..aff389ccf8 --- /dev/null +++ b/docs/en/Migration-Guides/IdentityServer4-Step-by-Step.md @@ -0,0 +1,230 @@ +# Migrating from OpenIddict to IdentityServer4 Step by Step Guide + +ABP startup templates use `OpenIddict` OpenID provider from v6.0.0 by default and `IdentityServer` projects are renamed to `AuthServer` in tiered/separated solutions. Since OpenIddict is the default OpenID provider library for ABP templates since v6.0, you may want to keep using [IdentityServer4](https://github.com/IdentityServer/IdentityServer4) library, even it is **archived and no longer maintained by the owners**. ABP doesn't provide support for newer versions of IdentityServer. This guide provides layer-by-layer guidance for migrating your existing [OpenIddict](https://github.com/openiddict/openiddict-core) application to IdentityServer4. + +## IdentityServer4 Migration Steps + +Use the `abp update` command to update your existing application. See [Upgrading docs](../Upgrading.md) for more info. Apply required migrations by following the [Migration Guides](Index.md) based on your application version. + +### Domain.Shared Layer + +- In **MyApplication.Domain.Shared.csproj** replace **project reference**: + +```csharp + +``` + + with + +```csharp + +``` + +- In **MyApplicationDomainSharedModule.cs** replace usings and **module dependencies:** + +```csharp +using Volo.Abp.OpenIddict; +... +typeof(AbpOpenIddictDomainSharedModule) +``` + + with + +```csharp +using Volo.Abp.IdentityServer; +... +typeof(AbpIdentityServerDomainSharedModule) +``` + +### Domain Layer + +- In **MyApplication.Domain.csproj** replace **project references**: + +```csharp + + +``` + + with + +```csharp + + +``` + +- In **MyApplicationDomainModule.cs** replace usings and **module dependencies**: + +```csharp +using Volo.Abp.OpenIddict; +using Volo.Abp.PermissionManagement.OpenIddict; +... +typeof(AbpOpenIddictDomainModule), +typeof(AbpPermissionManagementDomainOpenIddictModule), +``` + + with + +```csharp +using Volo.Abp.IdentityServer; +using Volo.Abp.PermissionManagement.IdentityServer; +... +typeof(AbpIdentityServerDomainModule), +typeof(AbpPermissionManagementDomainIdentityServerModule), +``` + +#### OpenIddictDataSeedContributor + +DataSeeder is the most important part for starting the application since it seeds the initial data for both OpenID providers. + +- Create a folder named *IdentityServer* under the Domain project and copy the [IdentityServerDataSeedContributor.cs](https://github.com/abpframework/abp-samples/blob/master/Ids2OpenId/src/Ids2OpenId.Domain/IdentityServer/IdentityServerDataSeedContributor.cs) under this folder. **Rename** all the `OpenId2Ids` with your project name. +- Delete *OpenIddict* folder that contains `OpenIddictDataSeedContributor.cs` which is no longer needed. + +### EntityFrameworkCore Layer + +If you are using MongoDB, skip this step and check the *MongoDB* layer section. + +- In **MyApplication.EntityFrameworkCore.csproj** replace **project reference**: + + ```csharp + + ``` + + with + + ```csharp + + ``` + +- In **MyApplicationEntityFrameworkCoreModule.cs** replace usings and **module dependencies**: + +```csharp +using Volo.Abp.OpenIddict.EntityFrameworkCore; +... +typeof(AbpOpenIddictEntityFrameworkCoreModule), +``` + + with + +```csharp +using Volo.Abp.IdentityServer.EntityFrameworkCore; +... +typeof(AbpIdentityServerEntityFrameworkCoreModule), +``` + +- In **MyApplicationDbContext.cs** replace usings and **fluent api configurations**: + + ```csharp + using Volo.Abp.OpenIddict.EntityFrameworkCore; + ... + protected override void OnModelCreating(ModelBuilder builder) + { + base.OnModelCreating(builder); + + /* Include modules to your migration db context */ + + ... + builder.ConfigureOpenIddict(); + ``` + + with + + ```csharp + using Volo.Abp.IdentityServer.EntityFrameworkCore; + ... + using Volo.Abp.OpenIddict.EntityFrameworkCore; + ... + protected override void OnModelCreating(ModelBuilder builder) + { + base.OnModelCreating(builder); + + /* Include modules to your migration db context */ + + ... + builder.ConfigureIdentityServer(); + ``` + +> Not: You need to create new migration after updating the fluent api. Navigate to *EntityFrameworkCore* folder and add a new migration. Ex, `dotnet ef migrations add Updated_To_IdentityServer ` + +### MongoDB Layer + +If you are using EntityFrameworkCore, skip this step and check the *EntityFrameworkCore* layer section. + +- In **MyApplication.MongoDB.csproj** replace **project reference**: + + ```csharp + + ``` + + with + + ```csharp + + ``` + +- In **MyApplicationMongoDbModule.cs** replace usings and **module dependencies**: + +```csharp +using Volo.Abp.OpenIddict.MongoDB; +... +typeof(AbpOpenIddictMongoDbModule), +``` + + with + +```csharp +using Volo.Abp.IdentityServer.MongoDB; +... +typeof(AbpIdentityServerMongoDbModule), +``` + +### DbMigrator Project + +- In `appsettings.json` **replace OpenIddict section with IdentityServer** since IdentityServerDataSeeder will be using these information for initial data seeding: + + ```json + "IdentityServer": { // Rename OpenIddict to IdentityServer + "Clients ": { // Rename Applications to Clients + ... + } + } + ``` + + +### Test Project + +- In **MyApplicationTestBaseModule.cs** **add** the IdentityServer related using and PreConfigurations: + + ```csharp + using Volo.Abp.IdentityServer; + ``` + + and + + ```csharp + PreConfigure(options => + { + options.AddDeveloperSigningCredential = false; + }); + + PreConfigure(identityServerBuilder => + { + identityServerBuilder.AddDeveloperSigningCredential(false, System.Guid.NewGuid().ToString()); + }); + ``` + + to `PreConfigureServices` to run authentication related unit tests. + +### UI Layer + +You can follow the migrations guides from IdentityServer to OpenIddict in **reverse order** to update your UIs. You can also check the source-code for [Index.cshtml.cs](https://github.com/abpframework/abp-samples/blob/master/OpenId2Ids/src/OpenId2Ids.AuthServer/Pages/Index.cshtml) and [Index.cshtml](https://github.com/abpframework/abp-samples/blob/master/OpenId2Ids/src/OpenId2Ids.AuthServer/Pages/Index.cshtml.cs) files for **AuthServer** project. + +- [Angular UI Migration](OpenIddict-Angular.md) +- [MVC/Razor UI Migration](OpenIddict-Mvc.md) +- [Blazor-Server UI Migration](OpenIddict-Blazor-Server.md) +- [Blazor-Wasm UI Migration](OpenIddict-Blazor.md) + +## Source code of samples and module + +* [Open source tiered & separate auth server application migrate OpenIddict to Identity Server](https://github.com/abpframework/abp-samples/tree/master/OpenId2Ids) +* [IdentityServer module document](https://docs.abp.io/en/abp/6.0/Modules/IdentityServer) +* [IdentityServer module source code](https://github.com/abpframework/abp/tree/rel-6.0/modules/identityserver) diff --git a/docs/en/Modules/IdentityServer.md b/docs/en/Modules/IdentityServer.md index f754a29687..90c08f6c6b 100644 --- a/docs/en/Modules/IdentityServer.md +++ b/docs/en/Modules/IdentityServer.md @@ -1,10 +1,12 @@ # IdentityServer Module -IdentityServer module provides a full integration with the [IdentityServer](https://github.com/IdentityServer/IdentityServer4) (IDS) framework, which provides advanced authentication features like single sign-on and API access control. This module persists clients, resources and other IDS-related objects to database. +IdentityServer module provides a full integration with the [IdentityServer4](https://github.com/IdentityServer/IdentityServer4) (IDS) framework, which provides advanced authentication features like single sign-on and API access control. This module persists clients, resources and other IDS-related objects to database. **This module is replaced by** [OpenIddict module](https://docs.abp.io/en/abp/latest/Modules/OpenIddict) after ABP v6.0 in the startup templates. + +> Note: You can not use IdentityServer and OpenIddict modules together. They are separate OpenID provider libraries for the same job. ## How to Install -This module comes as pre-installed (as NuGet/NPM packages). You can continue to use it as package and get updates easily, or you can include its source code into your solution (see `get-source` [CLI](../CLI.md) command) to develop your custom module. +You don't need this module when you are using OpenIddict module. However, if you want to keep using IdentityServer4 for your applications, you can install this module and remove the OpenIddict module. You can continue to use it as package and get updates easily, or you can include its source code into your solution (see `get-source` [CLI](../CLI.md) command) to develop your custom module. ### The Source Code diff --git a/docs/en/UI/Angular/Quick-Start.md b/docs/en/UI/Angular/Quick-Start.md index 768b3b7b67..dd26dd3efe 100644 --- a/docs/en/UI/Angular/Quick-Start.md +++ b/docs/en/UI/Angular/Quick-Start.md @@ -179,7 +179,7 @@ This command will download and start a simple static server, a browser window at Of course, you need your application to run on an optimized web server and become available to everyone. This is quite straight-forward: -1. Create a new static web server instance. You can use a service like [Azure App Service](https://azure.microsoft.com/tr-tr/services/app-service/web/), [Firebase](https://firebase.google.com/docs/hosting), [Netlify](https://www.netlify.com/), [Vercel](https://vercel.com/), or even [GitHub Pages](https://angular.io/guide/deployment#deploy-to-github-pages). Another option is maintaining own web server with [NGINX](https://www.nginx.com/), [IIS](https://www.iis.net/), [Apache HTTP Server](https://httpd.apache.org/), or equivalent. +1. Create a new static web server instance. You can use a service like [Azure App Service](https://azure.microsoft.com/en-us/services/app-service/web/), [Firebase](https://firebase.google.com/docs/hosting), [Netlify](https://www.netlify.com/), [Vercel](https://vercel.com/), or even [GitHub Pages](https://angular.io/guide/deployment#deploy-to-github-pages). Another option is maintaining own web server with [NGINX](https://www.nginx.com/), [IIS](https://www.iis.net/), [Apache HTTP Server](https://httpd.apache.org/), or equivalent. 2. Copy the files from `dist/MyProjectName` [1](#f-dist-folder-name) to a publicly served destination on the server via CLI of the service provider, SSH, or FTP (whichever is available). This step would be defined as a job if you have a CI/CD flow. 3. [Configure the server](https://angular.io/guide/deployment#server-configuration) to redirect all requests to the _index.html_ file. Some services do that automatically. Others require you [to add a file to the bundle via assets](https://angular.io/guide/workspace-config#assets-configuration) which describes the server how to do the redirections. Occasionally, you may need to do manual configuration. diff --git a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md index 8f664a80a5..15a8b0819c 100644 --- a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md +++ b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md @@ -10,7 +10,7 @@ See the [form elements demo page](https://bootstrap-taghelpers.abp.io/Components ## abp-input -`abp-input` tag creates a Bootstrap form input for a given c# property. It uses [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/tr-tr/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-input-tag-helper) in background, so every data annotation attribute of `input` tag helper of Asp.Net Core is also valid for `abp-input`. +`abp-input` tag creates a Bootstrap form input for a given c# property. It uses [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-7.0#the-input-tag-helper) in background, so every data annotation attribute of `input` tag helper of Asp.Net Core is also valid for `abp-input`. Usage: @@ -88,7 +88,7 @@ You can set some of the attributes on your c# property, or directly on html tag. * `label`: Sets the label for input. * `display-required-symbol`: Adds the required symbol (*) to label if input is required. Default `True`. -`asp-format`, `name` and `value` attributes of [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-input-tag-helper) are also valid for `abp-input` tag helper. +`asp-format`, `name` and `value` attributes of [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-7.0#the-input-tag-helper) are also valid for `abp-input` tag helper. ### Label & Localization @@ -100,7 +100,7 @@ You can set label of your input in different ways: ## abp-select -`abp-select` tag creates a Bootstrap form select for a given c# property. It uses [Asp.Net Core Select Tag Helper](https://docs.microsoft.com/tr-tr/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-select-tag-helper) in background, so every data annotation attribute of `select` tag helper of Asp.Net Core is also valid for `abp-select`. +`abp-select` tag creates a Bootstrap form select for a given c# property. It uses [Asp.Net Core Select Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-7.0#the-select-tag-helper) in background, so every data annotation attribute of `select` tag helper of Asp.Net Core is also valid for `abp-select`. `abp-select` tag needs a list of `Microsoft.AspNetCore.Mvc.Rendering.SelectListItem ` to work. It can be provided by `asp-items` attriube on the tag or `[SelectItems()]` attribute on c# property. (if you are using [abp-dynamic-form](Dynamic-forms.md), c# attribute is the only way.) diff --git a/docs/en/UI/Blazor/Basic-Theme.md b/docs/en/UI/Blazor/Basic-Theme.md index 4060f097ba..e4124d9a2c 100644 --- a/docs/en/UI/Blazor/Basic-Theme.md +++ b/docs/en/UI/Blazor/Basic-Theme.md @@ -85,6 +85,27 @@ You can simply override the styles in the Global Styles file of your application See the [Customization / Overriding Components](Customization-Overriding-Components.md) to learn how you can replace components, customize and extend the user interface. +### Overriding the Menu Item +Basic theme supports overriding a single menu item with a custom component. You can create a custom component and call `UseComponent` extension method of Basic Theme in the **MenuContributor**. + +```csharp +using Volo.Abp.AspNetCore.Components.Web.BasicTheme.Navigation; + +//... + +context.Menu.Items.Add( + new ApplicationMenuItem("Custom.1", "My Custom Menu", "#") + .UseComponent(typeof(MyMenuItemComponent))); +``` + +```html + +``` + ### Copy & Customize You can run the following [ABP CLI](../../CLI.md) command in **Blazor{{if UI == "Blazor"}}WebAssembly{{else}} Server{{end}}** project directory to copy the source code to your solution: diff --git a/docs/en/UI/Blazor/Overall.md b/docs/en/UI/Blazor/Overall.md index 835bf4eab6..f38c0c257b 100644 --- a/docs/en/UI/Blazor/Overall.md +++ b/docs/en/UI/Blazor/Overall.md @@ -88,7 +88,7 @@ There are a set of standard libraries that comes pre-installed and supported by * [Twitter Bootstrap](https://getbootstrap.com/) as the fundamental HTML/CSS framework. * [Blazorise](https://github.com/stsrki/Blazorise) as a component library that supports the Bootstrap and adds extra components like Data Grid and Tree. * [FontAwesome](https://fontawesome.com/) as the fundamental CSS font library. -* [Flag Icon](https://github.com/lipis/flag-icon-css) as a library to show flags of countries. +* [Flag Icon](https://github.com/lipis/flag-icons) as a library to show flags of countries. These libraries are selected as the base libraries and available to the applications and modules. diff --git a/docs/en/UI/Blazor/Theming.md b/docs/en/UI/Blazor/Theming.md index d8cec07cb3..2496df9b20 100644 --- a/docs/en/UI/Blazor/Theming.md +++ b/docs/en/UI/Blazor/Theming.md @@ -48,7 +48,7 @@ All the themes must depend on the [Volo.Abp.AspNetCore.Components.Server.Theming * [Twitter Bootstrap](https://getbootstrap.com/) as the fundamental HTML/CSS framework. * [Blazorise](https://github.com/stsrki/Blazorise) as a component library that supports the Bootstrap and adds extra components like Data Grid and Tree. * [FontAwesome](https://fontawesome.com/) as the fundamental CSS font library. -* [Flag Icon](https://github.com/lipis/flag-icon-css) as a library to show flags of countries. +* [Flag Icon](https://github.com/lipis/flag-icons) as a library to show flags of countries. These libraries are selected as the base libraries and available to the applications and modules. diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 351bfde88f..2ce69e69a9 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -1370,16 +1370,22 @@ }, { "text": "IdentityServer", - "path": "Modules/IdentityServer.md" + "path": "Modules/IdentityServer.md", + "items": [ + { + "text": "IdentityServer Migration Guide", + "path": "Migration-Guides/IdentityServer4-Step-by-Step.md" + } + ] }, { "text": "OpenIddict", - "items": [ - { - "text": "OpenIddict Migration Guide", - "path": "Migration-Guides/OpenIddict-Step-by-Step.md" - } - ], + "items": [ + { + "text": "OpenIddict Migration Guide", + "path": "Migration-Guides/OpenIddict-Step-by-Step.md" + } + ], "path": "Modules/OpenIddict.md" }, { diff --git a/docs/zh-Hans/Dependency-Injection.md b/docs/zh-Hans/Dependency-Injection.md index 2264a12930..2c22c123ab 100644 --- a/docs/zh-Hans/Dependency-Injection.md +++ b/docs/zh-Hans/Dependency-Injection.md @@ -270,16 +270,16 @@ using (var scope = _serviceProvider.CreateScope()) ## 高级特性 -### IServiceCollection.OnRegistred 事件 +### IServiceCollection.OnRegistered 事件 -你可能想在注册到依赖注入的每个服务上执行一个操作, 在你的模块的 `PreConfigureServices` 方法中, 使用 `OnRegistred` 方法注册一个回调(callback) , 如下所示: +你可能想在注册到依赖注入的每个服务上执行一个操作, 在你的模块的 `PreConfigureServices` 方法中, 使用 `OnRegistered` 方法注册一个回调(callback) , 如下所示: ````csharp public class AppModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(ctx => + context.Services.OnRegistered(ctx => { var type = ctx.ImplementationType; //... @@ -295,7 +295,7 @@ public class AppModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(ctx => + context.Services.OnRegistered(ctx => { if (ctx.ImplementationType.IsDefined(typeof(MyLogAttribute), true)) { @@ -308,7 +308,7 @@ public class AppModule : AbpModule 这个示例判断一个服务类是否具有 `MyLogAttribute` 特性, 如果有的话就添加一个 `MyLogInterceptor` 到拦截器集合中. -> 注意, 如果服务类公开了多于一个服务或接口, `OnRegistred` 回调(callback)可能被同一服务类多次调用. 因此, 较安全的方法是使用 `Interceptors.TryAdd` 方法而不是 `Interceptors.Add` 方法. 请参阅动态代理(dynamic proxying)/拦截器 [文档](Dynamic-Proxying-Interceptors.md). +> 注意, 如果服务类公开了多于一个服务或接口, `OnRegistered` 回调(callback)可能被同一服务类多次调用. 因此, 较安全的方法是使用 `Interceptors.TryAdd` 方法而不是 `Interceptors.Add` 方法. 请参阅动态代理(dynamic proxying)/拦截器 [文档](Dynamic-Proxying-Interceptors.md). ## 第三方提供程序 diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/FlagIconCss/FlagIconCssStyleContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/FlagIconCss/FlagIconCssStyleContributor.cs index 3181d8e1a2..9e5754f393 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/FlagIconCss/FlagIconCssStyleContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/FlagIconCss/FlagIconCssStyleContributor.cs @@ -7,6 +7,13 @@ public class FlagIconCssStyleContributor : BundleContributor { public override void ConfigureBundle(BundleConfigurationContext context) { - context.Files.AddIfNotContains("/libs/flag-icon-css/css/flag-icons.min.css"); + if (context.FileProvider.GetFileInfo("/libs/flag-icons/css/flag-icons.min.css").Exists) + { + context.Files.AddIfNotContains("/libs/flag-icons/css/flag-icons.min.css"); + } + else if (context.FileProvider.GetFileInfo("/libs/flag-icon-css/css/flag-icons.min.css").Exists) + { + context.Files.AddIfNotContains("/libs/flag-icon-css/css/flag-icons.min.css"); + } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpAspNetCoreMvcUiWidgetsModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpAspNetCoreMvcUiWidgetsModule.cs index 54d766ec08..23b3d08602 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpAspNetCoreMvcUiWidgetsModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpAspNetCoreMvcUiWidgetsModule.cs @@ -39,7 +39,7 @@ public class AbpAspNetCoreMvcUiWidgetsModule : AbpModule { var widgetTypes = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (WidgetAttribute.IsWidget(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs index ec3690ca8e..0a12d0332a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs @@ -43,6 +43,7 @@ using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.UI; using Volo.Abp.UI.Navigation; +using Volo.Abp.Validation.Localization; namespace Volo.Abp.AspNetCore.Mvc; @@ -174,10 +175,17 @@ public class AbpAspNetCoreMvcModule : AbpModule context.Services.Replace(ServiceDescriptor.Singleton()); context.Services.AddSingleton(); - Configure(mvcOptions => - { - mvcOptions.AddAbp(context.Services); - }); + context.Services.AddOptions() + .Configure((mvcOptions, serviceProvider) => + { + mvcOptions.AddAbp(context.Services); + + // serviceProvider is root service provider. + var stringLocalizer = serviceProvider.GetRequiredService>(); + mvcOptions.ModelBindingMessageProvider.SetValueIsInvalidAccessor(_ => stringLocalizer["The value '{0}' is invalid."]); + mvcOptions.ModelBindingMessageProvider.SetNonPropertyValueMustBeANumberAccessor(() => stringLocalizer["The field must be a number."]); + mvcOptions.ModelBindingMessageProvider.SetValueMustBeANumberAccessor(value => stringLocalizer["The field {0} must be a number.", value]); + }); Configure(options => { diff --git a/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpAspNetCoreSignalRModule.cs b/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpAspNetCoreSignalRModule.cs index 903e60a16f..13400a7ff9 100644 --- a/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpAspNetCoreSignalRModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpAspNetCoreSignalRModule.cs @@ -91,7 +91,7 @@ public class AbpAspNetCoreSignalRModule : AbpModule { var hubTypes = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (IsHubClass(context) && !IsDisabledForAutoMap(context)) { diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs index b6527f10c8..7c6fdacc11 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs @@ -24,7 +24,7 @@ public class AbpAuditingModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(AuditingInterceptorRegistrar.RegisterIfNeeded); + context.Services.OnRegistered(AuditingInterceptorRegistrar.RegisterIfNeeded); } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs index 9a1a4c52b4..cb244599c2 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs @@ -22,7 +22,7 @@ public class AbpAuthorizationModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(AuthorizationInterceptorRegistrar.RegisterIfNeeded); + context.Services.OnRegistered(AuthorizationInterceptorRegistrar.RegisterIfNeeded); AutoAddDefinitionProviders(context.Services); } @@ -64,7 +64,7 @@ public class AbpAuthorizationModule : AbpModule { var definitionProviders = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (typeof(IPermissionDefinitionProvider).IsAssignableFrom(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobsAbstractionsModule.cs b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobsAbstractionsModule.cs index 99d4d9e4df..8d3dc6caf5 100644 --- a/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobsAbstractionsModule.cs +++ b/framework/src/Volo.Abp.BackgroundJobs.Abstractions/Volo/Abp/BackgroundJobs/AbpBackgroundJobsAbstractionsModule.cs @@ -21,7 +21,7 @@ public class AbpBackgroundJobsAbstractionsModule : AbpModule { var jobTypes = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (ReflectionHelper.IsAssignableToGenericType(context.ImplementationType, typeof(IBackgroundJob<>)) || ReflectionHelper.IsAssignableToGenericType(context.ImplementationType, typeof(IAsyncBackgroundJob<>))) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs index cc198e877b..ec2074434a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs @@ -58,7 +58,7 @@ public class AuthService : IAuthService, ITransientDependency { if (!response.IsSuccessStatusCode) { - Logger.LogError("Remote server returns '{response.StatusCode}'"); + Logger.LogError($"Remote server returns '{response.StatusCode}'"); return null; } @@ -127,6 +127,26 @@ public class AuthService : IAuthService, ITransientDependency } } + public async Task CheckMultipleOrganizationsAsync(string username) + { + var url = $"{CliUrls.WwwAbpIo}api/license/check-multiple-organizations?username={username}"; + + var client = CliHttpClientFactory.CreateClient(); + + using (var response = await client.GetHttpResponseMessageWithRetryAsync(url, CancellationTokenProvider.Token, Logger)) + { + if (!response.IsSuccessStatusCode) + { + throw new Exception($"ERROR: Remote server returns '{response.StatusCode}'"); + } + + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); + + var responseContent = await response.Content.ReadAsStringAsync(); + return JsonSerializer.Deserialize(responseContent); + } + } + private async Task LogoutAsync(string accessToken) { try diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/IAuthService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/IAuthService.cs index ad2916ca0b..f91fd0dc00 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/IAuthService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/IAuthService.cs @@ -9,4 +9,6 @@ public interface IAuthService Task LoginAsync(string userName, string password, string organizationName = null); Task LogoutAsync(); + + Task CheckMultipleOrganizationsAsync(string username); } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginCommand.cs index a3b6d4a411..0d5b3b31e5 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/LoginCommand.cs @@ -2,13 +2,11 @@ using Microsoft.Extensions.Logging.Abstractions; using System; using System.Text; -using System.Text.Json; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; using Volo.Abp.Cli.Args; using Volo.Abp.Cli.Auth; -using Volo.Abp.Cli.Http; using Volo.Abp.Cli.ProjectBuilding; using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; @@ -26,17 +24,13 @@ public class LoginCommand : IConsoleCommand, ITransientDependency public ICancellationTokenProvider CancellationTokenProvider { get; } public IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; } - private readonly CliHttpClientFactory _cliHttpClientFactory; - public LoginCommand(AuthService authService, ICancellationTokenProvider cancellationTokenProvider, - IRemoteServiceExceptionHandler remoteServiceExceptionHandler, - CliHttpClientFactory cliHttpClientFactory) + IRemoteServiceExceptionHandler remoteServiceExceptionHandler) { AuthService = authService; CancellationTokenProvider = cancellationTokenProvider; RemoteServiceExceptionHandler = remoteServiceExceptionHandler; - _cliHttpClientFactory = cliHttpClientFactory; Logger = NullLogger.Instance; } @@ -111,7 +105,7 @@ public class LoginCommand : IConsoleCommand, ITransientDependency private async Task HasMultipleOrganizationAndThisNotSpecified(CommandLineArgs commandLineArgs, string organization) { if (string.IsNullOrWhiteSpace(organization) && - await CheckMultipleOrganizationsAsync(commandLineArgs.Target)) + await AuthService.CheckMultipleOrganizationsAsync(commandLineArgs.Target)) { Logger.LogError($"You have multiple organizations, please specify your organization with `--organization` parameter."); return true; @@ -168,26 +162,6 @@ public class LoginCommand : IConsoleCommand, ITransientDependency return false; } - private async Task CheckMultipleOrganizationsAsync(string username) - { - var url = $"{CliUrls.WwwAbpIo}api/license/check-multiple-organizations?username={username}"; - - var client = _cliHttpClientFactory.CreateClient(); - - using (var response = await client.GetHttpResponseMessageWithRetryAsync(url, CancellationTokenProvider.Token, Logger)) - { - if (!response.IsSuccessStatusCode) - { - throw new Exception($"ERROR: Remote server returns '{response.StatusCode}'"); - } - - await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(response); - - var responseContent = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize(responseContent); - } - } - public string GetUsageInfo() { var sb = new StringBuilder(); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SuiteAppSettingsService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SuiteAppSettingsService.cs new file mode 100644 index 0000000000..d274234ded --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SuiteAppSettingsService.cs @@ -0,0 +1,94 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Newtonsoft.Json.Linq; +using Volo.Abp.Cli.Utils; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Cli.Commands.Services; + +public class SuiteAppSettingsService : ITransientDependency +{ + private const int DefaultPort = 3000; + + public CmdHelper CmdHelper { get; } + + public SuiteAppSettingsService(CmdHelper cmdHelper) + { + CmdHelper = cmdHelper; + } + + public async Task GetSuitePortAsync() + { + return await GetSuitePortAsync(GetCurrentSuiteVersion()); + } + + public async Task GetSuitePortAsync(string version) + { + var filePath = GetFilePathOrNull(version); + + if (filePath == null) + { + return DefaultPort; + } + + var content = File.ReadAllText(filePath); + + var contentAsJson = JObject.Parse(content); + + var url = contentAsJson["AbpSuite"]?["ApplicationUrl"]?.ToString(); + + if (url == null) + { + return DefaultPort; + } + + return Convert.ToInt32(url.Split(":").Last()); + } + + private string GetFilePathOrNull(string version) + { + if (version == null) + { + return null; + } + + var path = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + ".dotnet", + "tools", + ".store", + "volo.abp.suite", + version, + "volo.abp.suite", + version, + "tools", + "net7.0", + "any", + "appsettings.json" + ); + + if (!File.Exists(path)) + { + return null; + } + + return path; + } + + private string GetCurrentSuiteVersion() + { + var dotnetToolList = CmdHelper.RunCmdAndGetOutput("dotnet tool list -g", out int exitCode); + + var suiteLine = dotnetToolList.Split(Environment.NewLine) + .FirstOrDefault(l => l.ToLower().StartsWith("volo.abp.suite ")); + + if (string.IsNullOrEmpty(suiteLine)) + { + return null; + } + + return suiteLine.Split(" ", StringSplitOptions.RemoveEmptyEntries)[1]; + } +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs index 83c21d4773..b35efb6f36 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SuiteCommand.cs @@ -35,23 +35,26 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency private readonly PackageVersionCheckerService _packageVersionCheckerService; private readonly AuthService _authService; private readonly CliHttpClientFactory _cliHttpClientFactory; + private readonly SuiteAppSettingsService _suiteAppSettingsService; private const string SuitePackageName = "Volo.Abp.Suite"; public ILogger Logger { get; set; } - private const string AbpSuiteHost = "http://localhost:3000"; + private int _abpSuitePort = 3000; public SuiteCommand( AbpNuGetIndexUrlService nuGetIndexUrlService, PackageVersionCheckerService packageVersionCheckerService, ICmdHelper cmdHelper, AuthService authService, - CliHttpClientFactory cliHttpClientFactory) + CliHttpClientFactory cliHttpClientFactory, + SuiteAppSettingsService suiteAppSettingsService) { CmdHelper = cmdHelper; _nuGetIndexUrlService = nuGetIndexUrlService; _packageVersionCheckerService = packageVersionCheckerService; _authService = authService; _cliHttpClientFactory = cliHttpClientFactory; + _suiteAppSettingsService = suiteAppSettingsService; Logger = NullLogger.Instance; } @@ -72,17 +75,20 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency commandLineArgs.Options.ContainsKey(Options.Preview.Long); var version = commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long); + var currentSuiteVersionAsString = GetCurrentSuiteVersion(); switch (operationType) { case "": case null: - await InstallSuiteIfNotInstalledAsync(); + await InstallSuiteIfNotInstalledAsync(currentSuiteVersionAsString); + _abpSuitePort = await _suiteAppSettingsService.GetSuitePortAsync(currentSuiteVersionAsString); RunSuite(); break; case "generate": - await InstallSuiteIfNotInstalledAsync(); + await InstallSuiteIfNotInstalledAsync(currentSuiteVersionAsString); + _abpSuitePort = await _suiteAppSettingsService.GetSuitePortAsync(currentSuiteVersionAsString); var suiteProcess = StartSuite(); System.Threading.Thread.Sleep(500); //wait for initialization of the app await GenerateCrudPageAsync(commandLineArgs); @@ -130,7 +136,7 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency } var IsSolutionBuiltResponse = await client.GetAsync( - $"{AbpSuiteHost}/api/abpSuite/solutions/{solutionId.ToString()}/is-built" + $"http://localhost:{_abpSuitePort}/api/abpSuite/solutions/{solutionId.ToString()}/is-built" ); var IsSolutionBuilt = Convert.ToBoolean(await IsSolutionBuiltResponse.Content.ReadAsStringAsync()); @@ -148,7 +154,7 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency ); var responseMessage = await client.PostAsync( - $"{AbpSuiteHost}/api/abpSuite/crudPageGenerator/{solutionId.ToString()}/save-and-generate-entity", + $"http://localhost:{_abpSuitePort}/api/abpSuite/crudPageGenerator/{solutionId.ToString()}/save-and-generate-entity", entityContent ); @@ -178,7 +184,7 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency } var responseMessage = await client.GetHttpResponseMessageWithRetryAsync( - "http://localhost:3000/api/abpSuite/solutions", + $"http://localhost:{_abpSuitePort}/api/abpSuite/solutions", _cliHttpClientFactory.GetCancellationToken(TimeSpan.FromMinutes(10)), Logger, timeIntervals.ToArray()); @@ -216,7 +222,7 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency ); var responseMessage = await client.PostAsync( - "http://localhost:3000/api/abpSuite/addSolution", + $"http://localhost:{_abpSuitePort}/api/abpSuite/addSolution", entityContent, _cliHttpClientFactory.GetCancellationToken(TimeSpan.FromMinutes(10)) ); @@ -234,11 +240,9 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency } } - private async Task InstallSuiteIfNotInstalledAsync() + private async Task InstallSuiteIfNotInstalledAsync(string currentSuiteVersion) { - var currentSuiteVersionAsString = GetCurrentSuiteVersion(); - - if (string.IsNullOrEmpty(currentSuiteVersionAsString)) + if (string.IsNullOrEmpty(currentSuiteVersion)) { await InstallSuiteAsync(); } @@ -430,6 +434,19 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency Logger.LogWarning("Couldn't check ABP Suite installed status: " + ex.Message); } + if (IsSuiteAlreadyRunning()) + { + Logger.LogInformation("Opening suite..."); + CmdHelper.Open($"http://localhost:{_abpSuitePort}"); + return; + } + + if (IsPortAlreadyInUse()) + { + Logger.LogError($"Port \"{_abpSuitePort}\" is already in use."); + return; + } + CmdHelper.RunCmd("abp-suite"); } @@ -453,23 +470,32 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency return null; } + if (IsPortAlreadyInUse()) + { + Logger.LogError($"Port \"{_abpSuitePort}\" is already in use."); + return null; + } + return CmdHelper.RunCmdAndGetProcess("abp-suite --no-browser"); } private bool IsSuiteAlreadyRunning() + { + return GetProcessesRelatedWithSuite().Any(); + } + + private bool IsPortAlreadyInUse() { var ipGP = IPGlobalProperties.GetIPGlobalProperties(); var endpoints = ipGP.GetActiveTcpListeners(); - return endpoints.Any(e => e.Port == 3000); + return endpoints.Any(e => e.Port == _abpSuitePort); } private void KillSuite() { try { - var suiteProcesses = (from p in Process.GetProcesses() - where p.ProcessName.ToLower().Contains("abp-suite") - select p); + var suiteProcesses = GetProcessesRelatedWithSuite(); foreach (var suiteProcess in suiteProcesses) { @@ -483,6 +509,13 @@ public class SuiteCommand : IConsoleCommand, ITransientDependency } } + private IEnumerable GetProcessesRelatedWithSuite() + { + return (from p in Process.GetProcesses() + where p.ProcessName.ToLower().Contains("abp-suite") + select p); + } + public string GetUsageInfo() { var sb = new StringBuilder(); diff --git a/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionRegistrationActionExtensions.cs b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionRegistrationActionExtensions.cs index 2947526fa5..286cc05210 100644 --- a/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionRegistrationActionExtensions.cs +++ b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionRegistrationActionExtensions.cs @@ -5,9 +5,9 @@ namespace Microsoft.Extensions.DependencyInjection; public static class ServiceCollectionRegistrationActionExtensions { - // OnRegistred + // OnRegistered - public static void OnRegistred(this IServiceCollection services, Action registrationAction) + public static void OnRegistered(this IServiceCollection services, Action registrationAction) { GetOrCreateRegistrationActionList(services).Add(registrationAction); } diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs index 931dc8c07e..b573d7d958 100644 --- a/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs @@ -42,7 +42,7 @@ public class AbpDataModule : AbpModule { var contributors = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (typeof(IDataSeedContributor).IsAssignableFrom(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs index fe3d9f3032..21e663e5e1 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/AbpEventBusModule.cs @@ -47,7 +47,7 @@ public class AbpEventBusModule : AbpModule var localHandlers = new List(); var distributedHandlers = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (ReflectionHelper.IsAssignableToGenericType(context.ImplementationType, typeof(ILocalEventHandler<>))) { diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs index 7411c61fdb..cde88956b5 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs @@ -22,7 +22,7 @@ public class AbpFeaturesModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(FeatureInterceptorRegistrar.RegisterIfNeeded); + context.Services.OnRegistered(FeatureInterceptorRegistrar.RegisterIfNeeded); AutoAddDefinitionProviders(context.Services); } @@ -57,7 +57,7 @@ public class AbpFeaturesModule : AbpModule { var definitionProviders = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (typeof(IFeatureDefinitionProvider).IsAssignableFrom(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs index 14cd0d405b..1a1e2ece3b 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs @@ -124,7 +124,7 @@ public class FeatureDefinition : ICanCreateChildFeature } /// - /// Sets a property in the dictionary. + /// Adds one or more providers to the list. /// This is a shortcut for nested calls on this object. /// public virtual FeatureDefinition WithProviders(params string[] providers) diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/AbpGlobalFeaturesModule.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/AbpGlobalFeaturesModule.cs index 8541d04306..3c8cd5708a 100644 --- a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/AbpGlobalFeaturesModule.cs +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/AbpGlobalFeaturesModule.cs @@ -17,7 +17,7 @@ public class AbpGlobalFeaturesModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(GlobalFeatureInterceptorRegistrar.RegisterIfNeeded); + context.Services.OnRegistered(GlobalFeatureInterceptorRegistrar.RegisterIfNeeded); } public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Security/AbpSecurityModule.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Security/AbpSecurityModule.cs index 75ca252ca7..921aca8d7e 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Security/AbpSecurityModule.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/Security/AbpSecurityModule.cs @@ -63,7 +63,7 @@ public class AbpSecurityModule : AbpModule { var contributorTypes = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (typeof(IAbpClaimsPrincipalContributor).IsAssignableFrom(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/AbpSettingsModule.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/AbpSettingsModule.cs index ebaaef54e1..eb05fbb949 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/AbpSettingsModule.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/AbpSettingsModule.cs @@ -36,7 +36,7 @@ public class AbpSettingsModule : AbpModule { var definitionProviders = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (typeof(ISettingDefinitionProvider).IsAssignableFrom(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingCoreModule.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingCoreModule.cs index 74f0589355..cce61484b3 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingCoreModule.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingCoreModule.cs @@ -23,7 +23,7 @@ public class AbpTextTemplatingCoreModule : AbpModule var definitionProviders = new List(); var contentContributors = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (typeof(ITemplateDefinitionProvider).IsAssignableFrom(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkModule.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkModule.cs index 036e101397..541340183a 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkModule.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AbpUnitOfWorkModule.cs @@ -7,6 +7,6 @@ public class AbpUnitOfWorkModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(UnitOfWorkInterceptorRegistrar.RegisterIfNeeded); + context.Services.OnRegistered(UnitOfWorkInterceptorRegistrar.RegisterIfNeeded); } } diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs index cc29fd23a8..8713b2ec7b 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs @@ -193,7 +193,7 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency if (_databaseApis.ContainsKey(key)) { - throw new AbpException("There is already a database API in this unit of work with given key: " + key); + throw new AbpException("There is already a database API in this unit of work with given key."); } _databaseApis.Add(key, api); @@ -221,7 +221,7 @@ public class UnitOfWork : IUnitOfWork, ITransientDependency if (_transactionApis.ContainsKey(key)) { - throw new AbpException("There is already a transaction API in this unit of work with given key: " + key); + throw new AbpException("There is already a transaction API in this unit of work with given key."); } _transactionApis.Add(key, api); diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationModule.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationModule.cs index 476bf2de06..321599c35c 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationModule.cs +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/AbpValidationModule.cs @@ -16,7 +16,7 @@ public class AbpValidationModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(ValidationInterceptorRegistrar.RegisterIfNeeded); + context.Services.OnRegistered(ValidationInterceptorRegistrar.RegisterIfNeeded); AutoAddObjectValidationContributors(context.Services); } @@ -39,7 +39,7 @@ public class AbpValidationModule : AbpModule { var contributorTypes = new List(); - services.OnRegistred(context => + services.OnRegistered(context => { if (typeof(IObjectValidationContributor).IsAssignableFrom(context.ImplementationType)) { diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ar.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ar.json index 2cdb6999b5..252bee394f 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ar.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ar.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "يجب أن يكون الحقل {0} سلسلة أحرف طولها {1} كحد أدنى و {2} كحد أقصى.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "الحقل {0} ليس عنوانا URL صالحًا مؤهلاً بالكامل سواء كان عنوان http أو https أو ftp", "The field {0} is invalid.": "الحقل {0} غير صالح.", + "The value '{0}' is invalid.": "القيمة '{0}' غير صالحة.", + "The field {0} must be a number.": "يجب أن يكون الحقل {0} رقمًا.", + "The field must be a number.": "يجب أن يكون الحقل رقمًا.", "ThisFieldIsNotAValidCreditCardNumber.": "هذا الحقل لا يمثل رقم بطاقة ائتمان صالح.", "ThisFieldIsNotValid.": "هذا الحقل غير صالح.", "ThisFieldIsNotAValidEmailAddress.": "هذا الحقل لا يمثل عنوان بريد إلكتروني صالح.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json index dce07f8c91..60e2113906 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/cs.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Pole {0} musí být řetězec o minimální délce {2} a maximální délce {1} znaků.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Pole {0} není platná plně kvalifikovaná adresa http, https, nebo ftp URL.", "The field {0} is invalid.": "Pole {0} je neplatné.", + "The value '{0}' is invalid.": "Hodnota '{0}' je neplatná.", + "The field {0} must be a number.": "Pole {0} musí být číslo.", + "The field must be a number.": "Pole musí být číslo.", "ThisFieldIsNotAValidCreditCardNumber.": "V poli {0} není platné číslo kreditní karty.", "ThisFieldIsNotValid.": "{0} není platný.", "ThisFieldIsNotAValidEmailAddress.": "V poli {0} není platný email.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/de.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/de.json index a72a44a3bb..209d8536ae 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/de.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/de.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Das Feld {0} muss eine Zeichenfolge mit einer Mindestlänge von {2} und einer Maximallänge von {1} sein.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Das Feld {0} ist keine gültige, vollqualifizierte http-, https- oder ftp-URL.", "The field {0} is invalid.": "Das Feld {0} ist ungültig.", + "The value '{0}' is invalid.": "Der Wert '{0}' ist ungültig.", + "The field {0} must be a number.": "Das Feld {0} muss eine Zahl sein.", + "The field must be a number.": "Das Feld muss eine Zahl sein.", "ThisFieldIsNotAValidCreditCardNumber.": "Dieses Feld ist keine gültige Kreditkartennummer.", "ThisFieldIsNotValid.": "Dieses Feld ist ungültig.", "ThisFieldIsNotAValidEmailAddress.": "Dieses Feld ist keine gültige E-Mail-Adresse.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/el.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/el.json index e2df0315f3..bed1964ac4 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/el.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/el.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Το πεδίο {0} πρέπει να είναι μια συμβολοσειρά με ελάχιστο μήκος {2} και μέγιστο μήκος {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Το πεδίο {0} δεν είναι έγκυρη πλήρως πιστοποιημένη διεύθυνση URL http, https ή ftp.", "The field {0} is invalid.": "Το πεδίο {0} δεν είναι έγκυρο.", + "The value '{0}' is invalid.": "Η τιμή '{0}' δεν είναι έγκυρη.", + "The field {0} must be a number.": "Το πεδίο {0} πρέπει να είναι αριθμός.", + "The field must be a number.": "Το πεδίο πρέπει να είναι αριθμός.", "ThisFieldIsNotAValidCreditCardNumber.": "Αυτό το πεδίο δεν περιέχει έγκυρο αριθμό πιστωτικής κάρτας.", "ThisFieldIsNotValid.": "Αυτό το πεδίο δεν είναι έγκυρο.", "ThisFieldIsNotAValidEmailAddress.": "Αυτό το πεδίο δεν περιέχει έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en-GB.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en-GB.json index a53b55a853..0874616561 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en-GB.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en-GB.json @@ -17,6 +17,9 @@ "The field {0} is invalid.": "The field {0} is invalid.", "ThisFieldIsNotAValidCreditCardNumber.": "This field is not a valid credit card number.", "ThisFieldIsNotValid.": "This field is not valid.", + "The value '{0}' is invalid.": "The value '{0}' is invalid.", + "The field {0} must be a number.": "The field {0} must be a number.", + "The field must be a number.": "The field must be a number.", "ThisFieldIsNotAValidEmailAddress.": "This field is not a valid e-mail address.", "ThisFieldOnlyAcceptsFilesWithTheFollowingExtensions:{0}": "This field only accepts files with the following extensions: {0}", "ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthOf{0}": "This field must be a string or array type with a maximum length of '{0}'.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json index 29035fb57f..8a866ef936 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/en.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "The {0} field is not a valid fully-qualified http, https, or ftp URL.", "The field {0} is invalid.": "The field {0} is invalid.", + "The value '{0}' is invalid.": "The value '{0}' is invalid.", + "The field {0} must be a number.": "The field {0} must be a number.", + "The field must be a number.": "The field must be a number.", "ThisFieldIsNotAValidCreditCardNumber.": "This field is not a valid credit card number.", "ThisFieldIsNotValid.": "This field is not valid.", "ThisFieldIsNotAValidEmailAddress.": "This field is not a valid e-mail address.", @@ -33,4 +36,4 @@ "ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl": "This field is not a valid fully-qualified http, https, or ftp URL.", "ThisFieldIsInvalid.": "This field is invalid." } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/es.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/es.json index 55884667f6..969cb3f3a9 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/es.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/es.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "El campo {0} debe ser una cadena con una longitud mínima de {2} y máxima de {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "El campo {0} no es una URL (http, https o ftp) valida.", "The field {0} is invalid.": "El campo {0} no es valido.", + "The value '{0}' is invalid.": "El valor '{0}' no es válido.", + "The field {0} must be a number.": "El campo {0} debe ser un número.", + "The field must be a number.": "El campo debe ser un número.", "ThisFieldIsNotAValidCreditCardNumber.": "El campo no es un número de tarjeta de crédito valido.", "ThisFieldIsNotValid.": "Este campo no es valido.", "ThisFieldIsNotAValidEmailAddress.": "Este campo no es una dirección de e-mail valida.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fa.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fa.json index bdec7afe06..39ec042dcb 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fa.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fa.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "فیلد {0} باید رشته ای با حداقل طول {2} و حداکثر باشد طول {1}. ", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "فیلد {0} یک نشانی اینترنتی http ، https ، یا ftp کاملاً واجد شرایط نیست.", "The field {0} is invalid.": "فیلد {0} نامعتبر است.", + "The value '{0}' is invalid.": "مقدار '{0}' نامعتبر است.", + "The field {0} must be a number.": "فیلد {0} باید یک عدد باشد.", + "The field must be a number.": "فیلد باید یک عدد باشد.", "ThisFieldIsNotAValidCreditCardNumber.": "این قسمت شماره کارت اعتباری معتبری نیست.", "ThisFieldIsNotValid.": "این قسمت معتبر نیست.", "ThisFieldIsNotAValidEmailAddress.": "این قسمت آدرس ایمیل معتبری نیست.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fi.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fi.json index f4501b87cf..e73fc5670b 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fi.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fi.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Kentän {0} on oltava merkkijono, jonka vähimmäispituus on {2} ja enimmäispituus {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "{0} -kenttä ei ole kelvollinen täysin hyväksytty http, https tai ftp URL.", "The field {0} is invalid.": "Kenttä {0} on virheellinen.", + "The value '{0}' is invalid.": "Arvo '{0}' on virheellinen.", + "The field {0} must be a number.": "Kentän {0} on oltava numero.", + "The field must be a number.": "Kentän on oltava numero.", "ThisFieldIsNotAValidCreditCardNumber.": "Tämä kenttä ei ole kelvollinen luottokortin numero.", "ThisFieldIsNotValid.": "Tämä kenttä ei kelpaa.", "ThisFieldIsNotAValidEmailAddress.": "Tämä kenttä ei ole kelvollinen sähköpostiosoite.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fr.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fr.json index 558bc9ca11..0adf748127 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fr.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/fr.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Le champ {0} doit être une chaîne d'une longueur minimale de {2} et d'une longueur maximale de {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Le champ {0} n'est pas une URL http, https ou ftp complète valide.", "The field {0} is invalid.": "Le champ {0} n'est pas valide.", + "The value '{0}' is invalid.": "La valeur '{0}' n'est pas valide.", + "The field {0} must be a number.": "Le champ {0} doit être un nombre.", + "The field must be a number.": "Le champ doit être un nombre.", "ThisFieldIsNotAValidCreditCardNumber.": "Ce champ n'est pas un numéro de carte de crédit valide.", "ThisFieldIsNotValid.": "Ce champ n'est pas valide.", "ThisFieldIsNotAValidEmailAddress.": "Ce champ n'est pas une adresse e-mail valide.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hi.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hi.json index fab1a394b4..d7ae279c18 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hi.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hi.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "फ़ील्ड {0} की लंबाई न्यूनतम {2} और अधिकतम लंबाई {1} होनी चाहिए।", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "{0} फ़ील्ड मान्य पूर्णत: योग्य http, https, या ftp URL नहीं है।", "The field {0} is invalid.": "फ़ील्ड {0} अमान्य है।", + "The value '{0}' is invalid.": "मान '{0}' अमान्य है।", + "The field {0} must be a number.": "फ़ील्ड {0} एक संख्या होनी चाहिए।", + "The field must be a number.": "फ़ील्ड एक संख्या होनी चाहिए।", "ThisFieldIsNotAValidCreditCardNumber.": "यह फ़ील्ड मान्य क्रेडिट कार्ड नंबर नहीं है।", "ThisFieldIsNotValid.": "यह फ़ील्ड मान्य नहीं है।", "ThisFieldIsNotAValidEmailAddress.": "यह फ़ील्ड मान्य ई-मेल पता नहीं है।", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hr.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hr.json index 6bb5cf7d5e..dcc01e9b0a 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hr.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hr.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Polje {0} mora biti text sa minimalnom du�inom od {2} i maksimalnom dužinom od {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "{0} nije valjan potpuno kvalificirani http, https, ili ftp URL.", "The field {0} is invalid.": "Polje {0} nije važeće.", + "The value '{0}' is invalid.": "Vrijednost '{0}' nije važeća.", + "The field {0} must be a number.": "Polje {0} mora biti broj.", + "The field must be a number.": "Polje mora biti broj.", "ThisFieldIsNotAValidCreditCardNumber.": "Ovo polje nije važeći broj kreditne kartice.", "ThisFieldIsNotValid.": "Ovo polje nije valjano.", "ThisFieldIsNotAValidEmailAddress.": "Ovo polje nije valjana e-mail adresa.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hu.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hu.json index 3db0f6f5c0..b06d9d3c47 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hu.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/hu.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "A {0} mezőnek szöveget kell tartalmaznia minimum {2} és maximum {1} hosszan.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "A {0} mező nem érvényes fully-qualified http, https, vagy ftp URL cím.", "The field {0} is invalid.": "A {0} mező nem érvényes.", + "The value '{0}' is invalid.": "A(z) '{0}' érték érvénytelen.", + "The field {0} must be a number.": "A(z) {0} mezőnek számnak kell lennie.", + "The field must be a number.": "A mezőnek számnak kell lennie.", "ThisFieldIsNotAValidCreditCardNumber.": "A mező nem érvényes bankkártya számot tartalmaz.", "ThisFieldIsNotValid.": "A mező nem érvényes.", "ThisFieldIsNotAValidEmailAddress.": "A mező nem érvényes email cím.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/is.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/is.json index 8f3ef3ae88..1f9c858d2a 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/is.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/is.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Reiturinn {0} verður að vera strengur með lágmarkslengd {2} og hámarkslengd {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Reiturinn {0} er ekki fullgild http, https, eða ftp slóð.", "The field {0} is invalid.": "Reiturinn {0} er ekki rétt útfylltur.", + "The value '{0}' is invalid.": "Gildið '{0}' er ógilt.", + "The field {0} must be a number.": "Reiturinn {0} verður að vera númer.", + "The field must be a number.": "Reiturinn verður að vera númer.", "ThisFieldIsNotAValidCreditCardNumber.": "Þessi reitur hefur ekki gilt kreditkortanúmer.", "ThisFieldIsNotValid.": "Reiturinn er ekki rétt útfylltur.", "ThisFieldIsNotAValidEmailAddress.": "Þessi reitur hefur ekki gilt netfang.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/it.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/it.json index bad68c117f..4cf02600bc 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/it.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/it.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Il campo {0} deve essere una stringa con una lunghezza minima di {2} e una lunghezza massima di {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Il campo {0} non è un URL http, https o ftp completo e valido.", "The field {0} is invalid.": "Il campo {0} non è valido.", + "The value '{0}' is invalid.": "Il valore '{0}' non è valido.", + "The field {0} must be a number.": "Il campo {0} deve essere un numero.", + "The field must be a number.": "Il campo deve essere un numero.", "ThisFieldIsNotAValidCreditCardNumber.": "Questo campo non è un numero di carta di credito valido.", "ThisFieldIsNotValid.": "Questo campo non è valido.", "ThisFieldIsNotAValidEmailAddress.": "Questo campo non è un indirizzo e-mail valido.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/nl.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/nl.json index ff0edfa54d..096d2fcbc3 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/nl.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/nl.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Het veld {0} moet een tekenreeks zijn met een minimale lengte van {2} en een maximale lengte van {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Het veld {0} is geen geldige, volledig gekwalificeerde http-, https- of ftp-URL.", "The field {0} is invalid.": "Het veld {0} is ongeldig.", + "The value '{0}' is invalid.": "De waarde '{0}' is ongeldig.", + "The field {0} must be a number.": "Het veld {0} moet een getal zijn.", + "The field must be a number.": "Het veld moet een getal zijn.", "ThisFieldIsNotAValidCreditCardNumber.": "Dit veld is geen geldig krediet kaartnummer.", "ThisFieldIsNotValid.": "Dir veld is ongeldig.", "ThisFieldIsNotAValidEmailAddress.": "Dit veld is geen geldig e-mail adres.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pl-PL.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pl-PL.json index c4a6cfe9d6..29baf6efff 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pl-PL.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pl-PL.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Pole {0} musi być łańcuchem znaków o minimalnej długości {2} i maksymalnej długości {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Pole {0} nie jest prawidłowym, w pełni kwalifikowanym adresem URL http, https lub ftp.", "The field {0} is invalid.": "Pole {0} jest niepoprawne.", + "The value '{0}' is invalid.": "Wartość '{0}' jest nieprawidłowa.", + "The field {0} must be a number.": "Pole {0} musi być liczbą.", + "The field must be a number.": "Pole musi być liczbą.", "ThisFieldIsNotAValidCreditCardNumber.": "To pole nie jest prawidłowym numerem karty kredytowej.", "ThisFieldIsNotValid.": "To pole jest nieprawidłowe.", "ThisFieldIsNotAValidEmailAddress.": "To pole nie jest prawidłowym adresem e-mail.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json index 1168a19317..a0bec74d8c 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/pt-BR.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "O campo {0} deve ser uma palavra com o tamanho mínimo de {2} e tamanho máximo de {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "O campo {0} não é um http, https, ou FTP válido.", "The field {0} is invalid.": "O campo {0} é inválido.", + "The value '{0}' is invalid.": "O valor '{0}' é inválido.", + "The field {0} must be a number.": "O campo {0} deve ser um número.", + "The field must be a number.": "O campo deve ser um número.", "ThisFieldIsNotAValidCreditCardNumber.": "Não é um cartão de crédito válido.", "ThisFieldIsNotValid.": "Campo inválido.", "ThisFieldIsNotAValidEmailAddress.": "E-mail inválido.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ro-RO.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ro-RO.json index ce03ecb52b..5fe4e459a2 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ro-RO.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ro-RO.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Câmpul {0} trebuie să fie un string cu lungimea minimă de {2} şi lungimea maximă de {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Câmpul {0} nu este o adresă validă complet http, https sau ftp.", "The field {0} is invalid.": "Câmpul {0} este invalid.", + "The value '{0}' is invalid.": "Valoarea '{0}' este nevalidă.", + "The field {0} must be a number.": "Câmpul {0} trebuie să fie un număr.", + "The field must be a number.": "Câmpul trebuie să fie un număr.", "ThisFieldIsNotAValidCreditCardNumber.": "Acest câmp nu este un număr de card de credit valid.", "ThisFieldIsNotValid.": "Acest câmp nu este valid.", "ThisFieldIsNotAValidEmailAddress.": "Acest câmp nu este o adresă de e-mail validă.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ru.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ru.json index 877a3bb1dc..a52c619933 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ru.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/ru.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Поле {0} должно быть строкой с минимальной длиной {2} и максимальной длиной {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Поле {0} не является действительным полным http, https или ftp адресом.", "The field {0} is invalid.": "Значение в поле {0} недопустимо.", + "The value '{0}' is invalid.": "Значение '{0}' недопустимо.", + "The field {0} must be a number.": "Поле {0} должно быть числом.", + "The field must be a number.": "Поле должно быть числом.", "ThisFieldIsNotAValidCreditCardNumber.": "Это поле не содержит действительный номер кредитной карты.", "ThisFieldIsNotValid.": "Значение в этом поле недействительно.", "ThisFieldIsNotAValidEmailAddress.": "Это поле не содержит действительный адрес электронной почты.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sk.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sk.json index d5f310aa66..856124c31f 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sk.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sk.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Pole {0} musí byť reťazec s minimálnou dĺžkou {2} a maximálnou dĺžkou {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "V poli {0} nie je platná plne kvalifikovaná adresa http, https alebo ftp URL.", "The field {0} is invalid.": "Pole {0} je neplatné.", + "The value '{0}' is invalid.": "Hodnota '{0}' je neplatná.", + "The field {0} must be a number.": "Pole {0} musí byť číslo.", + "The field must be a number.": "Pole musí byť číslo.", "ThisFieldIsNotAValidCreditCardNumber.": "V tomto poli nie je platné číslo kreditnej karty.", "ThisFieldIsNotValid.": "Toto pole nie je platné.", "ThisFieldIsNotAValidEmailAddress.": "V tomto poli nie je platná e-mailová adresa.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sl.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sl.json index 374425728d..0eaa31916b 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sl.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/sl.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Polje {0} mora biti niz z najmanjšo dolžino {2} in največjo dolžino {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Polje {0} ni veljaven popolnoma kvalificiran URL http, https ali ftp.", "The field {0} is invalid.": "Polje {0} ni veljavno.", + "The value '{0}' is invalid.": "Vrednost '{0}' ni veljavna.", + "The field {0} must be a number.": "Polje {0} mora biti številka.", + "The field must be a number.": "Polje mora biti številka.", "ThisFieldIsNotAValidCreditCardNumber.": "To polje ni veljavna številka kreditne kartice.", "ThisFieldIsNotValid.": "To polje ni veljavno.", "ThisFieldIsNotAValidEmailAddress.": "To polje ni veljaven e-poštni naslov.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/tr.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/tr.json index 9d784c57d9..cb30adde0d 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/tr.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/tr.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "{0} alanı en az {2}, en fazla {1} uzunluğunda bir metin olmalıdır.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "{0} alanı geçerli bir http, https, ya da ftp adresi olmalıdır.", "The field {0} is invalid.": "{0} alanı geçerli değil.", + "The value '{0}' is invalid.": "{0} değeri geçerli değil.", + "The field {0} must be a number.": "{0} alanı bir sayı olmalıdır.", + "The field must be a number.": "Bu alan bir sayı olmalıdır.", "ThisFieldIsNotAValidCreditCardNumber.": "Bu alan geçerli bir kredi kartı numarası olmalıdır.", "ThisFieldIsNotValid.": "Bu alan geçerli değil.", "ThisFieldIsNotAValidEmailAddress.": "Bu alan geçerli bir e-posta adresi olmalıdır.", @@ -33,4 +36,4 @@ "ThisFieldMustBeGreaterThanOrEqual{0}": "Bu alan {0}'dan büyük veya eşit olmalıdır.", "ThisFieldMustBeLessOrEqual{0}": "Bu alan {0}'dan küçük veya eşit olmalıdır." } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/vi.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/vi.json index 9bfc2c10ca..984f5c2e2b 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/vi.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/vi.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "Trường {0} phải là một chuỗi với độ dài tối thiểu {2} và tối đa là {1}.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "Trường {0} không phải là một http, https, hoặc ftp URL đủ điều kiện hợp lệ.", "The field {0} is invalid.": "Trường {0} không có hiệu lực", + "The value '{0}' is invalid.": "Giá trị '{0}' không hợp lệ.", + "The field {0} must be a number.": "Trường {0} phải là một số.", + "The field must be a number.": "Trường phải là một số.", "ThisFieldIsNotAValidCreditCardNumber.": "Trường này không phải là số thẻ tín dụng hợp lệ.", "ThisFieldIsNotValid.": "Trường này không hợp lệ.", "ThisFieldIsNotAValidEmailAddress.": "Trường này không phải là địa chỉ e-mail hợp lệ.", diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hans.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hans.json index 3c1a566112..262b2e08fa 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hans.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hans.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "字段{0}必须是最小长度为{2}并且最大长度{1}的字符串.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "字段{0}不是有效的完全限定的http,https或ftp URL.", "The field {0} is invalid.": "字段{0}是无效值.", + "The value '{0}' is invalid.": "'{0}'是无效值", + "The field {0} must be a number.": "字段{0}必须是数字.", + "The field must be a number.": "该字段必须是数字.", "ThisFieldIsNotAValidCreditCardNumber.": "字段不是有效的信用卡号码.", "ThisFieldIsNotValid.": "验证未通过.", "ThisFieldIsNotAValidEmailAddress.": "字段不是有效的邮箱地址.", @@ -33,4 +36,4 @@ "ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl": "字段{0}不是有效的完全限定的http,https或ftp URL.", "ThisFieldIsInvalid.": "该字段无效." } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hant.json b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hant.json index ec0fabd121..0f14ca2a40 100644 --- a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hant.json +++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization/zh-Hant.json @@ -16,6 +16,9 @@ "The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.": "欄位{0}必須是最小長度為{2}並且最大長度{1}的字串.", "The {0} field is not a valid fully-qualified http, https, or ftp URL.": "欄位{0}不是有效的完全限定的http,https或ftp URL.", "The field {0} is invalid.": "此欄位{0}是無效值.", + "The value '{0}' is invalid.": "'{0}'是無效值", + "The field {0} must be a number.": "欄位{0}必須是號碼.", + "The field must be a number.": "此欄位{0}必須是號碼.", "ThisFieldIsNotAValidCreditCardNumber.": "此欄位不是有效的信用卡號碼.", "ThisFieldIsNotValid.": "此驗證未通過.", "ThisFieldIsNotAValidEmailAddress.": "此欄位不是有效的郵箱地址.", diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs index b41ea093ff..7d5d4d0561 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs @@ -14,7 +14,7 @@ public class AbpAuthorizationTestModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { - context.Services.OnRegistred(onServiceRegistredContext => + context.Services.OnRegistered(onServiceRegistredContext => { if (typeof(IMyAuthorizedService1).IsAssignableFrom(onServiceRegistredContext.ImplementationType) && !DynamicProxyIgnoreTypes.Contains(onServiceRegistredContext.ImplementationType)) diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AbpInterceptionTestBase.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AbpInterceptionTestBase.cs index f4b584701f..e244237598 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AbpInterceptionTestBase.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/DynamicProxy/AbpInterceptionTestBase.cs @@ -19,7 +19,7 @@ public abstract class AbpInterceptionTestBase : AbpAsyncIntegrat services.AddTransient(); services.AddTransient(); - services.OnRegistred(registration => + services.OnRegistered(registration => { if (typeof(SimpleInterceptionTargetClass) == registration.ImplementationType) { diff --git a/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs b/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs index 276be829b2..37e6b07b8f 100644 --- a/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs +++ b/framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs @@ -109,7 +109,7 @@ public class ApplicationService_FluentValidation_Tests : AbpIntegratedTest + context.Services.OnRegistered(onServiceRegistredContext => { if (typeof(IMyAppService).IsAssignableFrom(onServiceRegistredContext.ImplementationType) && !DynamicProxyIgnoreTypes.Contains(onServiceRegistredContext.ImplementationType)) diff --git a/framework/test/Volo.Abp.Validation.Tests/Volo/Abp/Validation/ApplicationService_Validation_Tests.cs b/framework/test/Volo.Abp.Validation.Tests/Volo/Abp/Validation/ApplicationService_Validation_Tests.cs index 535e9fb613..f58b000af4 100644 --- a/framework/test/Volo.Abp.Validation.Tests/Volo/Abp/Validation/ApplicationService_Validation_Tests.cs +++ b/framework/test/Volo.Abp.Validation.Tests/Volo/Abp/Validation/ApplicationService_Validation_Tests.cs @@ -201,7 +201,7 @@ public class ApplicationService_Validation_Tests : AbpIntegratedTest + context.Services.OnRegistered(onServiceRegistredContext => { if (typeof(IMyAppService).IsAssignableFrom(onServiceRegistredContext.ImplementationType) && !DynamicProxyIgnoreTypes.Contains(onServiceRegistredContext.ImplementationType)) diff --git a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json index 4a13985c8a..8749163c1d 100644 --- a/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json +++ b/modules/account/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/Localization/Resources/zh-Hant.json @@ -3,16 +3,16 @@ "texts": { "Menu:Account": "帳號", "UserName": "使用者名稱", - "EmailAddress": "電子信箱地址", - "UserNameOrEmailAddress": "使用者名稱或電子信箱地址", + "EmailAddress": "電子郵件地址", + "UserNameOrEmailAddress": "使用者名稱或電子郵件地址", "Password": "密碼", "RememberMe": "記住我", "UseAnotherServiceToLogin": "使用另一個服務登入", "UserLockedOutMessage": "登入失敗,使用者帳號已被鎖定.請稍後再試.", "InvalidUserNameOrPassword": "使用者名稱或密碼錯誤!", - "LoginIsNotAllowed": "無法登入!你的賬號未激活或者需要驗證郵箱地址/手機號碼.", + "LoginIsNotAllowed": "無法登入!你的帳號未啟用或者需要驗證電子郵件地址/手機號碼.", "SelfRegistrationDisabledMessage": "應用程式未開放註冊,請聯絡管理員以加入新使用者.", - "LocalLoginDisabledMessage": "應用程序未開放本地賬戶登錄.", + "LocalLoginDisabledMessage": "應用程式未開放本地帳戶登入.", "Login": "登入", "Cancel": "取消", "Register": "註冊", @@ -26,11 +26,11 @@ "DisplayName:NewPasswordConfirm": "確認新密碼", "PasswordChangedMessage": "你的密碼已修改成功.", "DisplayName:UserName": "使用者名稱", - "DisplayName:Email": "電子信箱", + "DisplayName:Email": "電子郵件信箱", "DisplayName:Name": "名字", "DisplayName:Surname": "姓", "DisplayName:Password": "密碼", - "DisplayName:EmailAddress": "電子信箱地址", + "DisplayName:EmailAddress": "電子郵件地址", "DisplayName:PhoneNumber": "電話號碼", "PersonalSettings": "個人設置", "PersonalSettingsSaved": "個人設置已保存", @@ -38,32 +38,32 @@ "NewPasswordConfirmFailed": "請確認新密碼", "NewPasswordSameAsOld": "新密碼不能與舊密碼相同", "Manage": "管理", - "MyAccount": "我的賬戶", + "MyAccount": "我的帳戶", "DisplayName:Abp.Account.IsSelfRegistrationEnabled": "啟用自行註冊", "Description:Abp.Account.IsSelfRegistrationEnabled": "是否允許使用者自行註冊帳號.", "DisplayName:Abp.Account.EnableLocalLogin": "使用本地帳號進行身分驗證", "Description:Abp.Account.EnableLocalLogin": "伺服器是否允許使用者使用本地帳號進行身份驗證。", "LoggedOutTitle": "註銷", "LoggedOutText": "你已成功註銷並將馬上返回.", - "ReturnToText": "單擊此處返回到應用程序", + "ReturnToText": "點擊此處返回到應用程式", "OrLoginWith": "或是登入用:", "ForgotPassword": "忘記密碼?", - "SendPasswordResetLink_Information": "密碼重置鏈接將發送到您的電子郵件以重置密碼. 如果您在幾分鐘內沒有收到電子郵件,請重試.", + "SendPasswordResetLink_Information": "密碼重置連結將發送到您的電子郵件以重置密碼. 如果您在幾分鐘內沒有收到電子郵件,請重試.", "PasswordResetMailSentMessage": "帳戶恢復電子郵件已發送到您的電子郵件地址. 如果您在15分鐘內未在收件箱中看到此電子郵件,請檢查垃圾郵件,並標記為非垃圾郵件.", "ResetPassword": "重設密碼", "ConfirmPassword": "確認密碼", "ResetPassword_Information": "請輸入您的新密碼.", "YourPasswordIsSuccessfullyReset": "您的密碼已經被重置成功.", - "GoToTheApplication": "轉到應用程序", - "BackToLogin": "返回登錄", + "GoToTheApplication": "轉到應用程式", + "BackToLogin": "返回登入", "ProfileTab:Password": "更改密碼", - "ProfileTab:PersonalInfo": "個人信息", - "ReturnToApplication": "返回到應用程序", + "ProfileTab:PersonalInfo": "個人資訊", + "ReturnToApplication": "返回到應用程式", "Volo.Account:InvalidEmailAddress": "找不到給定的電子郵件地址:{0}", "PasswordReset": "重設密碼", - "PasswordResetInfoInEmail": "我們收到了帳戶恢復請求!如果你發起了此請求,請單擊以下鏈接以重置密碼.", + "PasswordResetInfoInEmail": "我們收到了帳戶恢復請求!如果你發起了此請求,請點擊以下連結以重置密碼.", "ResetMyPassword": "重置我的密碼", "AccessDenied": "拒絕訪問!", "AccessDeniedMessage": "您無權訪問此資源." } -} \ No newline at end of file +} diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs index 1920cdd8ad..ce1ecd0e82 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Logout.cshtml.cs @@ -1,6 +1,8 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Account.Settings; using Volo.Abp.Identity; +using Volo.Abp.Settings; namespace Volo.Abp.Account.Web.Pages.Account; @@ -28,7 +30,12 @@ public class LogoutModel : AccountPageModel return RedirectSafely(ReturnUrl, ReturnUrlHash); } - return RedirectToPage("/Account/Login"); + if (await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin)) + { + return RedirectToPage("/Account/Login"); + } + + return RedirectToPage("/"); } public virtual Task OnPostAsync() diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor index b3ecb41862..1f469a809a 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/FirstLevelNavMenuItem.razor @@ -13,7 +13,7 @@ { } - else if (url != null) + else if (MenuItem.Url != null) { -
diff --git a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts index cb0cdd9755..6dd1ab9f17 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts +++ b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts @@ -1,12 +1,28 @@ -import { ListService, PagedResultDto } from "@abp/ng.core"; -import { GetIdentityUsersInput, IdentityRoleDto, IdentityUserDto, IdentityUserService } from "@abp/ng.identity/proxy"; -import { ePermissionManagementComponents } from "@abp/ng.permission-management"; -import { Confirmation, ConfirmationService, ToasterService } from "@abp/ng.theme.shared"; -import { EXTENSIONS_IDENTIFIER, FormPropData, generateFormFromProps } from "@abp/ng.theme.shared/extensions"; -import { Component, Injector, OnInit, TemplateRef, TrackByFunction, ViewChild } from "@angular/core"; -import { AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from "@angular/forms"; -import { finalize, switchMap, tap } from "rxjs/operators"; -import { eIdentityComponents } from "../../enums/components"; +import { ListService, PagedResultDto } from '@abp/ng.core'; +import { + GetIdentityUsersInput, + IdentityRoleDto, + IdentityUserDto, + IdentityUserService, +} from '@abp/ng.identity/proxy'; +import { ePermissionManagementComponents } from '@abp/ng.permission-management'; +import {Confirmation, ConfirmationService, eFormComponets, ToasterService} from '@abp/ng.theme.shared'; +import { + EXTENSIONS_IDENTIFIER, + FormPropData, + generateFormFromProps, +} from '@abp/ng.theme.shared/extensions'; +import { + Component, + Injector, + OnInit, + TemplateRef, + TrackByFunction, + ViewChild, +} from '@angular/core'; +import { AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { finalize, switchMap, tap } from 'rxjs/operators'; +import { eIdentityComponents } from '../../enums/components'; @Component({ selector: 'abp-users', @@ -43,7 +59,9 @@ export class UsersComponent implements OnInit { permissionManagementKey = ePermissionManagementComponents.PermissionManagement; - entityDisplayName?: string; + entityDisplayName: string; + + inputKey=eFormComponets.FormCheckboxComponent trackByFn: TrackByFunction = (index, item) => Object.keys(item)[0] || index; diff --git a/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts b/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts index 6193a5bc20..5a3373121c 100644 --- a/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts +++ b/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts @@ -81,7 +81,7 @@ export class PermissionManagementComponent }); }); } else { - this.selectedGroup = null; + this.setSelectedGroup(null); this._visible = false; this.visibleChange.emit(false); } @@ -110,10 +110,22 @@ export class PermissionManagementComponent modalBusy = false; + selectedGroupPermissions: PermissionWithStyle[] = []; + trackByFn: TrackByFunction = (_, item) => item.name; - get selectedGroupPermissions(): PermissionWithStyle[] { - if (!this.selectedGroup) return []; + constructor(protected service: PermissionsService, protected configState: ConfigStateService) {} + + getChecked(name: string) { + return (this.permissions.find(per => per.name === name) || { isGranted: false }).isGranted; + } + + setSelectedGroup(group: PermissionGroupDto) { + this.selectedGroup = group; + if (!this.selectedGroup) { + this.selectedGroupPermissions = []; + return; + } const margin = `margin-${ (document.body.dir as LocaleDirection) === 'rtl' ? 'right' : 'left' @@ -123,7 +135,7 @@ export class PermissionManagementComponent (this.data.groups.find(group => group.name === this.selectedGroup?.name) || {}).permissions || []; - return permissions.map( + this.selectedGroupPermissions = permissions.map( permission => ({ ...permission, @@ -133,12 +145,6 @@ export class PermissionManagementComponent ); } - constructor(protected service: PermissionsService, protected configState: ConfigStateService) {} - - getChecked(name: string) { - return (this.permissions.find(per => per.name === name) || { isGranted: false }).isGranted; - } - setDisabled(permissions: PermissionGrantInfoDto[]) { if (permissions.length) { this.disableSelectAllTab = permissions.every( @@ -248,7 +254,7 @@ export class PermissionManagementComponent onChangeGroup(group: PermissionGroupDto) { this.setDisabled(group.permissions); - this.selectedGroup = group; + this.setSelectedGroup(group); this.setTabCheckboxState(); } @@ -291,8 +297,8 @@ export class PermissionManagementComponent return this.service.get(this.providerName, this.providerKey).pipe( tap((permissionRes: GetPermissionListResultDto) => { this.data = permissionRes; - this.selectedGroup = permissionRes.groups[0]; this.permissions = getPermissions(permissionRes.groups); + this.setSelectedGroup(permissionRes.groups[0]); this.disabledSelectAllInAllTabs = this.permissions.every( per => per.isGranted && diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-body.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-body.component.ts new file mode 100644 index 0000000000..b7efd90236 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-body.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'abp-card-body', + template: `
+ +
`, +}) +export class CardBodyComponent {} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-title.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-title.component.ts new file mode 100644 index 0000000000..f629636854 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card-title.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'abp-card-title', + template: `
+ +
`, +}) +export class CardTitleComponent {} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/card/card.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card.component.ts new file mode 100644 index 0000000000..317e5800b9 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card.component.ts @@ -0,0 +1,22 @@ +import { Component, ContentChild, Input } from '@angular/core'; +import { CardBodyComponent } from './card-body.component'; +import { CardTitleComponent } from './card-title.component'; + +@Component({ + selector: 'abp-card', + template: `
+ + +
`, +}) +export class CardComponent { + @Input() cardClass: string; + + @Input() cardStyle: string; + + @ContentChild(CardBodyComponent) + cardBodyTemplate?: CardBodyComponent; + + @ContentChild(CardTitleComponent) + cardTitleTemplate?: CardTitleComponent; +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/card/card.module.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card.module.ts new file mode 100644 index 0000000000..d8050a40cd --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/card/card.module.ts @@ -0,0 +1,14 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { CardBodyComponent } from './card-body.component'; +import { CardTitleComponent } from './card-title.component'; +import { CardComponent } from './card.component'; + +const declarationsWithExports = [CardComponent, CardBodyComponent, CardTitleComponent]; + +@NgModule({ + declarations: [...declarationsWithExports], + imports: [CommonModule], + exports: [...declarationsWithExports], +}) +export class CardModule {} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/card/index.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/card/index.ts new file mode 100644 index 0000000000..8d6bbd86d8 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/card/index.ts @@ -0,0 +1,4 @@ +export * from './card.module'; +export * from './card.component'; +export * from './card-body.component'; +export * from './card-title.component'; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/checkbox/checkbox.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/checkbox/checkbox.component.ts new file mode 100644 index 0000000000..3ead2f929d --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/checkbox/checkbox.component.ts @@ -0,0 +1,45 @@ +import { AbstractNgModelComponent } from '@abp/ng.core'; +import { Component, EventEmitter, forwardRef, Injector, Input, Output } from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; + +@Component({ + selector: 'abp-checkbox', + template: ` +
+ + +
+ `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => FormCheckboxComponent), + multi: true, + }, + ] +}) +export class FormCheckboxComponent extends AbstractNgModelComponent { + + @Input() label?: string; + @Input() labelClass = 'form-check-label'; + @Input() checkboxId!: string; + @Input() checkboxStyle = ''; + @Input() checkboxClass = 'form-check-input'; + @Input() checkboxReadonly = false; + @Output() onBlur = new EventEmitter(); + @Output() onFocus = new EventEmitter(); + + constructor(injector: Injector) { + super(injector); + } + +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/form-input/form-input.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/form-input/form-input.component.ts new file mode 100644 index 0000000000..d7f1f48c9d --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/form-input/form-input.component.ts @@ -0,0 +1,46 @@ +import { AbstractNgModelComponent } from '@abp/ng.core'; +import { Component, EventEmitter, forwardRef, Injector, Input, Output } from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; + +@Component({ + selector: 'abp-form-input', + template: ` +
+ + +
+ `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => FormInputComponent), + multi: true, + }, + ] +}) +export class FormInputComponent extends AbstractNgModelComponent { + @Input() inputId!: string; + @Input() inputReadonly: boolean = false; + @Input() label: string = ''; + @Input() labelClass = 'form-label'; + @Input() inputPlaceholder: string = ''; + @Input() inputType: string = 'text'; + @Input() inputStyle: string = ''; + @Input() inputClass: string = 'form-control'; + @Output() onBlur = new EventEmitter(); + @Output() onFocus = new EventEmitter(); + + constructor(injector: Injector) { + super(injector); + } + +} 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 810d5a991a..095af5ef26 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 @@ -11,3 +11,4 @@ export * from './modal/modal.component'; export * from './toast-container/toast-container.component'; export * from './toast/toast.component'; export * from './password/password.component'; +export * from './card/index'; 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); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/enums/form.ts b/npm/ng-packs/packages/theme-shared/src/lib/enums/form.ts new file mode 100644 index 0000000000..9ccbb93655 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/enums/form.ts @@ -0,0 +1,4 @@ +export enum eFormComponets { + FormInputComponent = 'FormInputComponent', + FormCheckboxComponent = 'FormCheckboxComponent', +} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/enums/index.ts b/npm/ng-packs/packages/theme-shared/src/lib/enums/index.ts index 3bda94b078..9e781067f7 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/enums/index.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/enums/index.ts @@ -1 +1,2 @@ +export * from './form'; export * from './route-names'; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/checkbox.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/checkbox.component.spec.ts new file mode 100644 index 0000000000..e2fba6d0da --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/checkbox.component.spec.ts @@ -0,0 +1,44 @@ +import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; +import { FormCheckboxComponent } from '../components/checkbox/checkbox.component'; + +describe('FormCheckboxComponent', () => { + let spectator: SpectatorHost; + + const createHost = createHostFactory(FormCheckboxComponent); + + beforeEach( + () => + (spectator = createHost( + '', + { + hostProps: { attributes: { autofocus: '', name: 'abp-checkbox' } }, + }, + )), + ); + + it('should display the input', () => { + expect(spectator.query('input')).toBeTruthy(); + }); + + it('should equal the default classes to form-check-input', () => { + expect(spectator.query('input')).toHaveClass('form-check-input'); + }); + + it('should equal the default type to checkbox', () => { + expect(spectator.query('input')).toHaveAttribute('type', 'checkbox'); + }); + + it('should be readonly when checkboxReadonly is true', () => { + spectator.component.checkboxReadonly = true; + spectator.detectComponentChanges(); + expect(spectator.query('[readonly]')).toBeTruthy(); + }); + + it('should not contain readonly when checboxReadonly is false', () => { + spectator.component.checkboxReadonly = false; + spectator.detectComponentChanges(); + expect(spectator.query('[disabled]')).toBeFalsy(); + }); + +}); + diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/form-input.component.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/form-input.component.spec.ts new file mode 100644 index 0000000000..660cb72165 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/form-input.component.spec.ts @@ -0,0 +1,46 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; +import { FormInputComponent } from '../components/form-input/form-input.component'; + + +describe('FormInputComponent', () => { + let spectator: SpectatorHost; + + const createHost = createHostFactory(FormInputComponent); + + beforeEach( + () => + (spectator = createHost( + '', + { + hostProps: { attributes: { autofocus: '', name: 'abp-form-input' } }, + }, + )), + ); + + it('should display the input', () => { + expect(spectator.query('input')).toBeTruthy(); + }); + + it('should equal the default classes to form-control', () => { + expect(spectator.query('input')).toHaveClass('form-control'); + }); + + it('should equal the default type to text', () => { + expect(spectator.query('input')).toHaveAttribute('type', 'text'); + }); + + it('should be readonly when inputReadonly is true', () => { + spectator.component.inputReadonly = true; + spectator.detectComponentChanges(); + expect(spectator.query('[readonly]')).toBeTruthy(); + }); + + it('should not contain readonly when inputReadonly is false', () => { + spectator.component.inputReadonly = false; + spectator.detectComponentChanges(); + expect(spectator.query('[disabled]')).toBeFalsy(); + }); + +}); + diff --git a/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts b/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts index 20c7de13d4..c7dad57f77 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts @@ -36,7 +36,10 @@ import { HTTP_ERROR_CONFIG, httpErrorConfigFactory } from './tokens/http-error.t import { DateParserFormatter } from './utils/date-parser-formatter'; import { CONFIRMATION_ICONS, DEFAULT_CONFIRMATION_ICONS } from './tokens/confirmation-icons.token'; import { PasswordComponent } from './components/password/password.component'; +import { CardModule } from './components/card/card.module'; import { AbpVisibleDirective } from './directives'; +import { FormInputComponent } from './components/form-input/form-input.component'; +import { FormCheckboxComponent } from './components/checkbox/checkbox.component'; const declarationsWithExports = [ BreadcrumbComponent, @@ -54,6 +57,8 @@ const declarationsWithExports = [ LoadingDirective, ModalCloseDirective, AbpVisibleDirective, + FormInputComponent, + FormCheckboxComponent ]; @NgModule({ @@ -63,12 +68,20 @@ const declarationsWithExports = [ NgxValidateCoreModule, NgbPaginationModule, EllipsisModule, + CardModule, + ], declarations: [...declarationsWithExports, HttpErrorWrapperComponent], - exports: [NgxDatatableModule, EllipsisModule, NgxValidateCoreModule, ...declarationsWithExports], + exports: [ + NgxDatatableModule, + EllipsisModule, + NgxValidateCoreModule, + ...declarationsWithExports, + CardModule, + ], providers: [DatePipe], }) -export class BaseThemeSharedModule {} +export class BaseThemeSharedModule { } @NgModule({ imports: [BaseThemeSharedModule], diff --git a/npm/ng-packs/tsconfig.base.json b/npm/ng-packs/tsconfig.base.json index ac29fd53ad..71e32f80ed 100644 --- a/npm/ng-packs/tsconfig.base.json +++ b/npm/ng-packs/tsconfig.base.json @@ -30,6 +30,7 @@ "@abp/ng.identity": ["packages/identity/src/public-api.ts"], "@abp/ng.identity/config": ["packages/identity/config/src/public-api.ts"], "@abp/ng.identity/proxy": ["packages/identity/proxy/src/public-api.ts"], + "@abp/ng.oauth": ["packages/oauth/src/public-api.ts"], "@abp/ng.permission-management": ["packages/permission-management/src/public-api.ts"], "@abp/ng.permission-management/proxy": [ "packages/permission-management/proxy/src/public-api.ts" @@ -43,8 +44,7 @@ "@abp/ng.theme.basic/testing": ["packages/theme-basic/testing/src/public-api.ts"], "@abp/ng.theme.shared": ["packages/theme-shared/src/public-api.ts"], "@abp/ng.theme.shared/extensions": ["packages/theme-shared/extensions/src/public-api.ts"], - "@abp/ng.theme.shared/testing": ["packages/theme-shared/testing/src/public-api.ts"], - "@abp/ng.oauth": ["packages/oauth/src/public-api.ts"] + "@abp/ng.theme.shared/testing": ["packages/theme-shared/testing/src/public-api.ts"] } }, "exclude": ["node_modules", "tmp"] diff --git a/npm/packs/flag-icon-css/abp.resourcemapping.js b/npm/packs/flag-icon-css/abp.resourcemapping.js deleted file mode 100644 index 8c3ae431dd..0000000000 --- a/npm/packs/flag-icon-css/abp.resourcemapping.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - mappings: { - "@node_modules/flag-icon-css/css/*": "@libs/flag-icon-css/css", - "@node_modules/flag-icon-css/flags/1x1/*": "@libs/flag-icon-css/flags/1x1" - } -} \ No newline at end of file diff --git a/npm/packs/flag-icons/abp.resourcemapping.js b/npm/packs/flag-icons/abp.resourcemapping.js new file mode 100644 index 0000000000..377a2aee6f --- /dev/null +++ b/npm/packs/flag-icons/abp.resourcemapping.js @@ -0,0 +1,6 @@ +module.exports = { + mappings: { + "@node_modules/flag-icons/css/*": "@libs/flag-icons/css", + "@node_modules/flag-icons/flags/1x1/*": "@libs/flag-icons/flags/1x1" + } +} \ No newline at end of file diff --git a/npm/packs/flag-icons/package.json b/npm/packs/flag-icons/package.json new file mode 100644 index 0000000000..d77c47197b --- /dev/null +++ b/npm/packs/flag-icons/package.json @@ -0,0 +1,11 @@ +{ + "version": "7.0.1", + "name": "@abp/flag-icons", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "flag-icons": "6.6.6" + }, + "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" +} \ No newline at end of file