diff --git a/docs/en/Modules/Cms-Kit/Blogging.md b/docs/en/Modules/Cms-Kit/Blogging.md index 12039b1669..91c14d79e8 100644 --- a/docs/en/Modules/Cms-Kit/Blogging.md +++ b/docs/en/Modules/Cms-Kit/Blogging.md @@ -2,6 +2,12 @@ The blogging feature provides the necessary UI to manage and render blogs and blog posts. +## Enabling the Blogging Feature + +By default, CMS Kit features are disabled. Therefore, you need to enable the features you want, before starting to use it. You can use the [Global Feature](../../Global-Features.md) system to enable/disable CMS Kit features on development time. Alternatively, you can use the ABP Framework's [Feature System](https://docs.abp.io/en/abp/latest/Features) to disable a CMS Kit feature on runtime. + +> Check the ["How to Install" section of the CMS Kit Module documentation](Index.md#how-to-install) to see how to enable/disable CMS Kit features on development time. + ## User Interface ### Menu Items diff --git a/docs/en/Modules/Cms-Kit/Comments.md b/docs/en/Modules/Cms-Kit/Comments.md index ef476600eb..26aa7c0398 100644 --- a/docs/en/Modules/Cms-Kit/Comments.md +++ b/docs/en/Modules/Cms-Kit/Comments.md @@ -2,6 +2,12 @@ CMS kit provides a **comment** system to add the comment feature to any kind of resource, like blog posts, products, etc. +## Enabling the Comment Feature + +By default, CMS Kit features are disabled. Therefore, you need to enable the features you want, before starting to use it. You can use the [Global Feature](../../Global-Features.md) system to enable/disable CMS Kit features on development time. Alternatively, you can use the ABP Framework's [Feature System](https://docs.abp.io/en/abp/latest/Features) to disable a CMS Kit feature on runtime. + +> Check the ["How to Install" section of the CMS Kit Module documentation](Index.md#how-to-install) to see how to enable/disable CMS Kit features on development time. + ## Options The comment system provides a mechanism to group comment definitions by entity types. For example, if you want to use the comment system for blog posts and products, you need to define two entity types named `BlogPosts` and `Product`, and add comments under these entity types. @@ -16,7 +22,7 @@ Configure(options => }); ``` -> If you're using the blog feature, the ABP framework defines an entity type for the blog feature automatically. You can easily override or remove the predefined entity types in `Configure` method like shown above. +> If you're using the [Blogging Feature](Blogging.md), the ABP framework defines an entity type for the blog feature automatically. You can easily override or remove the predefined entity types in `Configure` method like shown above. `CmsKitCommentOptions` properties: diff --git a/docs/en/Modules/Cms-Kit/Global-Resources.md b/docs/en/Modules/Cms-Kit/Global-Resources.md index 7f639ad884..5e0e0154a0 100644 --- a/docs/en/Modules/Cms-Kit/Global-Resources.md +++ b/docs/en/Modules/Cms-Kit/Global-Resources.md @@ -2,6 +2,12 @@ CMS Kit Global Resources system allows to add global styles and scripts dynamically. +## Enabling the Global Resources Feature + +By default, CMS Kit features are disabled. Therefore, you need to enable the features you want, before starting to use it. You can use the [Global Feature](../../Global-Features.md) system to enable/disable CMS Kit features on development time. Alternatively, you can use the ABP Framework's [Feature System](https://docs.abp.io/en/abp/latest/Features) to disable a CMS Kit feature on runtime. + +> Check the ["How to Install" section of the CMS Kit Module documentation](Index.md#how-to-install) to see how to enable/disable CMS Kit features on development time. + ## The User Interface ### Menu items diff --git a/docs/en/Modules/Cms-Kit/Index.md b/docs/en/Modules/Cms-Kit/Index.md index 5b7f3b5366..e40f78922e 100644 --- a/docs/en/Modules/Cms-Kit/Index.md +++ b/docs/en/Modules/Cms-Kit/Index.md @@ -16,11 +16,12 @@ The following features are currently available: * Provides a [**global resources**](Global-Resources.md) system to add global styles and scripts dynamically. * Provides a [**Dynamic Widget**](Dynamic-Widget.md) system to create dynamic widgets for page and blog posts. -Click to a feature to understand and learn how to use it. +> You can click on the any feature links above to understand and learn how to use it. -All features are individually usable. If you disable a feature, it completely disappears from your application, even from the database tables, by the help of the [Global Features](../../Global-Features.md) system. +All features are individually usable. If you disable a feature, it completely disappears from your application, even from the database tables, with the help of the [Global Features](../../Global-Features.md) system. ## Pre Requirements + - This module depends on [BlobStoring](../../Blob-Storing.md) module for keeping media content. > Make sure `BlobStoring` module is installed and at least one provider is configured properly. For more information, check the [documentation](../../Blob-Storing.md). @@ -62,7 +63,7 @@ GlobalFeatureManager.Instance.Modules.CmsKit(cmsKit => This module follows the [module development best practices guide](https://docs.abp.io/en/abp/latest/Best-Practices/Index) and consists of several NuGet and NPM packages. See the guide if you want to understand the packages and relations between them. -CMS kit packages are designed for various usage scenarios. If you check the [CMS kit packages](https://www.nuget.org/packages?q=Volo.CmsKit), you will see that some packages have `Admin` and `Public` suffixes. The reason is that the module has two application layers, considering they might be used in different type of applications. These application layers uses a single domain layer. +CMS kit packages are designed for various usage scenarios. If you check the [CMS kit packages](https://www.nuget.org/packages?q=Volo.CmsKit), you will see that some packages have `Admin` and `Public` suffixes. The reason is that the module has two application layers, considering they might be used in different type of applications. These application layers uses a single domain layer: - `Volo.CmsKit.Admin.*` packages contain the functionalities required by admin (back office) applications. - `Volo.CmsKit.Public.*` packages contain the functionalities used in public websites where users read blog posts or leave comments. diff --git a/docs/en/Modules/Cms-Kit/Menus.md b/docs/en/Modules/Cms-Kit/Menus.md index 87486326da..b469c322ab 100644 --- a/docs/en/Modules/Cms-Kit/Menus.md +++ b/docs/en/Modules/Cms-Kit/Menus.md @@ -1,7 +1,13 @@ -# CMS Kit: Pages +# CMS Kit: Menus CMS Kit Menu system allows to manage public menus dynamically. +## Enabling the Menu Feature + +By default, CMS Kit features are disabled. Therefore, you need to enable the features you want, before starting to use it. You can use the [Global Feature](../../Global-Features.md) system to enable/disable CMS Kit features on development time. Alternatively, you can use the ABP Framework's [Feature System](https://docs.abp.io/en/abp/latest/Features) to disable a CMS Kit feature on runtime. + +> Check the ["How to Install" section of the CMS Kit Module documentation](Index.md#how-to-install) to see how to enable/disable CMS Kit features on development time. + ## The User Interface ### Menu items @@ -20,22 +26,18 @@ Menus page is used to manage dynamic public menus in the system. ![cms-kit-menus-page](../../images/cmskit-module-menus-page.png) - - -Created menus will be visible on public site. +The created menu items will be visible on the public-web side, as shown below: ![cms-kit-public-menus](../../images//cmskit-module-menus-public.png) -# Internals +## Internals -## Domain Layer +### Domain Layer #### Aggregates This module follows the [Entity Best Practices & Conventions](https://docs.abp.io/en/abp/latest/Best-Practices/Entities) guide. -##### Menus - - `MenuItem` (aggregate root): A Menu Item presents a single node at menu tree. #### Repositories diff --git a/docs/en/Modules/Cms-Kit/Pages.md b/docs/en/Modules/Cms-Kit/Pages.md index 7945bfd5ff..cc1f5074f4 100644 --- a/docs/en/Modules/Cms-Kit/Pages.md +++ b/docs/en/Modules/Cms-Kit/Pages.md @@ -2,6 +2,12 @@ CMS Kit Page system allows you to create dynamic pages by specifying URLs, which is the fundamental feature of a CMS. +## Enabling the Pages Feature + +By default, CMS Kit features are disabled. Therefore, you need to enable the features you want, before starting to use it. You can use the [Global Feature](../../Global-Features.md) system to enable/disable CMS Kit features on development time. Alternatively, you can use the ABP Framework's [Feature System](https://docs.abp.io/en/abp/latest/Features) to disable a CMS Kit feature on runtime. + +> Check the ["How to Install" section of the CMS Kit Module documentation](Index.md#how-to-install) to see how to enable/disable CMS Kit features on development time. + ## The User Interface ### Menu items @@ -24,5 +30,5 @@ You can create or edit an existing page on this page. ![pages-edit](../../images/cmskit-module-pages-edit.png) -When you create a page, you can access the created page via `/pages/{slug}` URL. +When you create a page, you can access the created page via `/{slug}` URL. diff --git a/docs/en/Modules/Cms-Kit/Ratings.md b/docs/en/Modules/Cms-Kit/Ratings.md index 8702feb24e..db58602c15 100644 --- a/docs/en/Modules/Cms-Kit/Ratings.md +++ b/docs/en/Modules/Cms-Kit/Ratings.md @@ -4,6 +4,12 @@ CMS kit provides a **rating** system to to add ratings feature to any kind of re ![ratings](../../images/cmskit-module-ratings.png) +## Enabling the Rating Feature + +By default, CMS Kit features are disabled. Therefore, you need to enable the features you want, before starting to use it. You can use the [Global Feature](../../Global-Features.md) system to enable/disable CMS Kit features on development time. Alternatively, you can use the ABP Framework's [Feature System](https://docs.abp.io/en/abp/latest/Features) to disable a CMS Kit feature on runtime. + +> Check the ["How to Install" section of the CMS Kit Module documentation](Index.md#how-to-install) to see how to enable/disable CMS Kit features on development time. + ## Options The rating system provides a mechanism to group ratings by entity types. For example, if you want to use the rating system for products, you need to define an entity type named `Product` and then add ratings under the defined entity type. @@ -17,7 +23,7 @@ Configure(options => }); ``` -> If you're using the blog feature, the ABP framework defines an entity type for the blog feature automatically. You can easily override or remove the predefined entity types in `Configure` method like shown above. +> If you're using the [Blogging Feature](Blogging.md), the ABP framework defines an entity type for the blog feature automatically. You can easily override or remove the predefined entity types in `Configure` method like shown above. `CmsKitRatingOptions` properties: diff --git a/docs/en/Modules/Cms-Kit/Reactions.md b/docs/en/Modules/Cms-Kit/Reactions.md index 86da9ccb72..457d5e0f26 100644 --- a/docs/en/Modules/Cms-Kit/Reactions.md +++ b/docs/en/Modules/Cms-Kit/Reactions.md @@ -8,6 +8,12 @@ Reaction component allows users to react to your content via pre-defined icons/e You can also customize the reaction icons shown in the reaction component. +## Enabling the Reaction Feature + +By default, CMS Kit features are disabled. Therefore, you need to enable the features you want, before starting to use it. You can use the [Global Feature](../../Global-Features.md) system to enable/disable CMS Kit features on development time. Alternatively, you can use the ABP Framework's [Feature System](https://docs.abp.io/en/abp/latest/Features) to disable a CMS Kit feature on runtime. + +> Check the ["How to Install" section of the CMS Kit Module documentation](Index.md#how-to-install) to see how to enable/disable CMS Kit features on development time. + ## Options Reaction system provides a mechanism to group reactions by entity types. For example, if you want to use the reaction system for products, you need to define an entity type named `Product`, and then add reactions under the defined entity type. @@ -32,7 +38,7 @@ Configure(options => }); ``` -> If you're using the comment or blog features, the ABP framework defines predefined reactions for these features automatically. +> If you're using the [Comment](Comments.md) or [Blogging](Blogging.md) features, the ABP framework defines predefined reactions for these features automatically. `CmsKitReactionOptions` properties: diff --git a/docs/en/Modules/Cms-Kit/Tags.md b/docs/en/Modules/Cms-Kit/Tags.md index 17bc5cf47f..8f91bc67c7 100644 --- a/docs/en/Modules/Cms-Kit/Tags.md +++ b/docs/en/Modules/Cms-Kit/Tags.md @@ -2,6 +2,12 @@ CMS kit provides a **tag** system to tag any kind of resources, like a blog post. +## Enabling the Tag Management Feature + +By default, CMS Kit features are disabled. Therefore, you need to enable the features you want, before starting to use it. You can use the [Global Feature](../../Global-Features.md) system to enable/disable CMS Kit features on development time. Alternatively, you can use the ABP Framework's [Feature System](https://docs.abp.io/en/abp/latest/Features) to disable a CMS Kit feature on runtime. + +> Check the ["How to Install" section of the CMS Kit Module documentation](Index.md#how-to-install) to see how to enable/disable CMS Kit features on development time. + ## Options The tag system provides a mechanism to group tags by entity types. For example, if you want to use the tag system for blog posts and products, you need to define two entity types named `BlogPosts` and `Product` and add tags under these entity types. @@ -17,7 +23,7 @@ Configure(options => }); ``` -> If you're using the blog feature, the ABP framework defines an entity type for the blog feature automatically. +> If you're using the [Blogging Feature](Blogging.md), the ABP framework defines an entity type for the blog feature automatically. `CmsKitTagOptions` properties: diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnTagHelper.cs index 3d5f94d18b..bbb6afd1ec 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Grid/AbpColumnTagHelper.cs @@ -16,6 +16,8 @@ public class AbpColumnTagHelper : AbpTagHelper ProcessSizeClass(context, output, TagHelper.SizeMd, "-md"); ProcessSizeClass(context, output, TagHelper.SizeLg, "-lg"); ProcessSizeClass(context, output, TagHelper.SizeXl, "-xl"); + ProcessSizeClass(context, output, TagHelper.SizeXxl, "-xxl"); } protected virtual void ProcessOffsetClasses(TagHelperContext context, TagHelperOutput output) @@ -33,6 +34,7 @@ public class AbpColumnTagHelperService : AbpTagHelperService ProcessOffsetClass(context, output, TagHelper.OffsetMd, "-md"); ProcessOffsetClass(context, output, TagHelper.OffsetLg, "-lg"); ProcessOffsetClass(context, output, TagHelper.OffsetXl, "-xl"); + ProcessOffsetClass(context, output, TagHelper.OffsetXxl, "-xxl"); } protected virtual void ProcessSizeClass(TagHelperContext context, TagHelperOutput output, ColumnSize size, string breakpoint) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs index 9777265abd..4fc5a04859 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs @@ -20,6 +20,8 @@ public static class MvcCoreBuilderExtensions options.JsonSerializerOptions.Converters.Add(new AbpStringToEnumFactory()); options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter()); + options.JsonSerializerOptions.Converters.Add(new AbpStringToGuidConverter()); + options.JsonSerializerOptions.Converters.Add(new AbpNullableStringToGuidConverter()); options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter()); options.JsonSerializerOptions.TypeInfoResolver = new AbpDefaultJsonTypeInfoResolver(serviceProvider diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs index 8eccc5e4d8..bc6cf40ebe 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs @@ -83,7 +83,7 @@ public class ChangeThemeStep : ProjectBuildPipelineStep ChangeNamespaceAndKeyword( context, - "/MyCompanyName.MyProjectName.Host/MyProjectNameServerModule.cs", + "/MyCompanyName.MyProjectName.Host/MyProjectNameHostModule.cs", $"Volo.Abp.AspNetCore.Mvc.UI.Theme.{defaultThemeName}.Bundling", "Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling", $"{defaultThemeName}ThemeBundles.Styles.Global", @@ -92,7 +92,7 @@ public class ChangeThemeStep : ProjectBuildPipelineStep ChangeNamespaceAndKeyword( context, - "/MyCompanyName.MyProjectName.Host/MyProjectNameServerModule.cs", + "/MyCompanyName.MyProjectName.Host/MyProjectNameHostModule.cs", $"Volo.Abp.AspNetCore.Mvc.UI.Theme.{defaultThemeName}", "Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic", $"AbpAspNetCoreMvcUi{defaultThemeName}ThemeModule", @@ -209,7 +209,7 @@ public class ChangeThemeStep : ProjectBuildPipelineStep ChangeNamespaceAndKeyword( context, - "/MyCompanyName.MyProjectName.Host/MyProjectNameServerModule.cs", + "/MyCompanyName.MyProjectName.Host/MyProjectNameHostModule.cs", "Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX.Bundling", "Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.Bundling", "LeptonXThemeBundles.Styles.Global", @@ -218,7 +218,7 @@ public class ChangeThemeStep : ProjectBuildPipelineStep ChangeNamespaceAndKeyword( context, - "/MyCompanyName.MyProjectName.Host/MyProjectNameServerModule.cs", + "/MyCompanyName.MyProjectName.Host/MyProjectNameHostModule.cs", "Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX", "Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton", "AbpAspNetCoreMvcUiLeptonXThemeModule", diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs index 32c1acf5be..804f0688a3 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs @@ -174,7 +174,7 @@ public class CmdHelper : ICmdHelper, ITransientDependency { if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - return delaySeconds == null ? "-c \"" + command + "\"" : "-c \"" + $"sleep {delaySeconds}s > /dev/null && " + command + "\""; + return delaySeconds == null ? "-c \"" + command + "\"" : "-c \"" + $"sleep {delaySeconds} > /dev/null && " + command + "\""; } //Windows default. diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs index 50dd47d9e2..f6ef46a4e7 100644 --- a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs @@ -22,6 +22,8 @@ public class AbpJsonSystemTextJsonModule : AbpModule options.JsonSerializerOptions.Converters.Add(new AbpStringToEnumFactory()); options.JsonSerializerOptions.Converters.Add(new AbpStringToBooleanConverter()); + options.JsonSerializerOptions.Converters.Add(new AbpStringToGuidConverter()); + options.JsonSerializerOptions.Converters.Add(new AbpNullableStringToGuidConverter()); options.JsonSerializerOptions.Converters.Add(new ObjectToInferredTypesConverter()); options.JsonSerializerOptions.TypeInfoResolver = new AbpDefaultJsonTypeInfoResolver(serviceProvider diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableStringToGuidConverter.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableStringToGuidConverter.cs new file mode 100644 index 0000000000..c80e5aa9a5 --- /dev/null +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableStringToGuidConverter.cs @@ -0,0 +1,41 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Volo.Abp.Json.SystemTextJson.JsonConverters; + +public class AbpNullableStringToGuidConverter : JsonConverter +{ + private JsonSerializerOptions _writeJsonSerializerOptions; + + public override Guid? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + var guidString = reader.GetString(); + string[] formats = { "N", "D", "B", "P", "X" }; + foreach (var format in formats) + { + if (Guid.TryParseExact(guidString, format, out var guid)) + { + return guid; + } + } + } + + if (reader.TryGetGuid(out var guid2)) + { + return guid2; + } + + return null; + } + + public override void Write(Utf8JsonWriter writer, Guid? value, JsonSerializerOptions options) + { + _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, this); + var entityConverter = (JsonConverter)_writeJsonSerializerOptions.GetConverter(typeof(Guid?)); + + entityConverter.Write(writer, value, _writeJsonSerializerOptions); + } +} diff --git a/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToGuidConverter.cs b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToGuidConverter.cs new file mode 100644 index 0000000000..586e4462cf --- /dev/null +++ b/framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToGuidConverter.cs @@ -0,0 +1,36 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Volo.Abp.Json.SystemTextJson.JsonConverters; + +public class AbpStringToGuidConverter : JsonConverter +{ + private JsonSerializerOptions _writeJsonSerializerOptions; + + public override Guid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + var guidString = reader.GetString(); + string[] formats = { "N", "D", "B", "P", "X" }; + foreach (var format in formats) + { + if (Guid.TryParseExact(guidString, format, out var guid)) + { + return guid; + } + } + } + + return reader.GetGuid(); + } + + public override void Write(Utf8JsonWriter writer, Guid value, JsonSerializerOptions options) + { + _writeJsonSerializerOptions ??= JsonSerializerOptionsHelper.Create(options, this); + var entityConverter = (JsonConverter)_writeJsonSerializerOptions.GetConverter(typeof(Guid)); + + entityConverter.Write(writer, value, _writeJsonSerializerOptions); + } +} diff --git a/framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleDocumentFilter.cs b/framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleDocumentFilter.cs index 5e86c04189..dd1b9705b8 100644 --- a/framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleDocumentFilter.cs +++ b/framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleDocumentFilter.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; @@ -8,7 +10,9 @@ namespace Volo.Abp.Swashbuckle; public class AbpSwashbuckleDocumentFilter : IDocumentFilter { - protected string[] ActionUrlPrefixes = new[] {"Volo."}; + protected virtual string[] ActionUrlPrefixes { get; set; } = new[] { "Volo." }; + + protected virtual string RegexConstraintPattern => @":regex\(([^()]*)\)"; public virtual void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { @@ -17,7 +21,7 @@ public class AbpSwashbuckleDocumentFilter : IDocumentFilter .Where(actionDescriptor => !string.IsNullOrEmpty(actionDescriptor.DisplayName) && ActionUrlPrefixes.Any(actionUrlPrefix => !actionDescriptor.DisplayName.Contains(actionUrlPrefix))) .DistinctBy(actionDescriptor => actionDescriptor.AttributeRouteInfo?.Template) - .Select(actionDescriptor => actionDescriptor.AttributeRouteInfo?.Template?.EnsureStartsWith('/').Replace("?", "")) + .Select(RemoveRouteParameterConstraints) .Where(actionUrl => !string.IsNullOrEmpty(actionUrl)) .ToList(); @@ -25,4 +29,30 @@ public class AbpSwashbuckleDocumentFilter : IDocumentFilter .Paths .RemoveAll(path => !actionUrls.Contains(path.Key)); } + + protected virtual string RemoveRouteParameterConstraints(ActionDescriptor actionDescriptor) + { + var route = actionDescriptor.AttributeRouteInfo?.Template?.EnsureStartsWith('/').Replace("?", ""); + if (string.IsNullOrWhiteSpace(route)) + { + return route; + } + + route = Regex.Replace(route, RegexConstraintPattern, ""); + + while (route.Contains(':')) + { + var startIndex = route.IndexOf(":", StringComparison.Ordinal); + var endIndex = route.IndexOf("}", startIndex); + + if (endIndex == -1) + { + break; + } + + route = route.Remove(startIndex, (endIndex - startIndex)); + } + + return route; + } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs index 471d33261a..6dfe3a7281 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs @@ -49,6 +49,12 @@ public class ModelBindingController : AbpController input.Time3.Value.Kind.ToString().ToLower() + "_" + input.InnerModel.Time4.Kind.ToString().ToLower(); } + + [HttpPost("Guid_Json_Test")] + public GuidJsonModel Guid_Json_Test([FromBody] GuidJsonModel input) + { + return input; + } } public class GetDateTimeKindModel @@ -68,3 +74,20 @@ public class GetDateTimeKindModel public DateTime Time4 { get; set; } } } + +public class GuidJsonModel +{ + public Guid UserId { get; set; } + + public Guid UserId2 { get; set; } + + public Guid UserId3 { get; set; } + + public Guid UserId4 { get; set; } + + public Guid UserId5 { get; set; } + + public Guid? TenantId { get; set; } + + public Guid? TenantId2 { get; set; } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs index befbd169fa..53bfff8b68 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs @@ -106,6 +106,18 @@ public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase var resultAsString = await response.Content.ReadAsStringAsync(); resultAsString.ShouldBe($"local_{Kind.ToString().ToLower()}_{Kind.ToString().ToLower()}_local"); } + + [Fact] + public async Task Guid_Json_Test() + { + var guid = Guid.NewGuid(); + var json = $"{{\"UserId\":\"{guid:B}\",\"UserId2\":\"{guid:N}\",\"UserId3\":\"{guid:D}\",\"UserId4\":\"{guid:P}\",\"UserId5\":\"{guid:x}\",\"TenantId\":null,\"TenantId2\":\"\"}}"; + var response = await Client.PostAsync("/api/model-Binding-test/Guid_Json_Test", new StringContent(json, Encoding.UTF8, MimeTypes.Application.Json)); + + response.StatusCode.ShouldBe(HttpStatusCode.OK); + var resultAsString = await response.Content.ReadAsStringAsync(); + resultAsString.ShouldBe($"{{\"userId\":\"{guid:D}\",\"userId2\":\"{guid:D}\",\"userId3\":\"{guid:D}\",\"userId4\":\"{guid:D}\",\"userId5\":\"{guid:D}\",\"tenantId\":null,\"tenantId2\":null}}"); + } } public class ModelBindingController_Utc_Tests : ModelBindingController_Tests diff --git a/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToGuid_Tests.cs b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToGuid_Tests.cs new file mode 100644 index 0000000000..93918b48c1 --- /dev/null +++ b/framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToGuid_Tests.cs @@ -0,0 +1,85 @@ +using System; +using System.Text.Json; +using Shouldly; +using Volo.Abp.Json.SystemTextJson.JsonConverters; +using Xunit; + +namespace Volo.Abp.Json; + +public class AbpStringToGuid_Tests +{ + [Fact] + public void Test_Read() + { + var options = new JsonSerializerOptions() + { + Converters = + { + new AbpStringToGuidConverter(), + new AbpNullableStringToGuidConverter() + } + }; + + var guid = Guid.Parse("762DDB84-5225-4853-A566-FF0B3AF57585"); + var testClass = JsonSerializer.Deserialize("{" + + $"\"Id\": \"{guid:N}\", " + + $"\"NullableId\": \"{guid:D}\", " + + $"\"NullableId2\": \"{guid:B}\", " + + $"\"NullableId3\": \"{guid:P}\", " + + $"\"NullableId4\": \"{guid:X}\", " + + "\"NullableId5\": \"\", " + + "\"NullableId6\": null}", options); + testClass.ShouldNotBeNull(); + testClass.Id.ShouldBe(guid); + testClass.NullableId.ShouldBe(guid); + testClass.NullableId2.ShouldBe(guid); + testClass.NullableId3.ShouldBe(guid); + testClass.NullableId4.ShouldBe(guid); + testClass.NullableId5.ShouldBeNull(); + testClass.NullableId6.ShouldBeNull(); + } + + [Fact] + public void Test_Write() + { + var options = new JsonSerializerOptions() + { + Converters = + { + new AbpStringToGuidConverter(), + new AbpNullableStringToGuidConverter() + } + }; + + var guid = Guid.Parse("762DDB84-5225-4853-A566-FF0B3AF57585"); + var json = JsonSerializer.Serialize(new TestClass() + { + Id = guid, + NullableId = null, + NullableId2 = guid, + NullableId3 = null, + NullableId4 = guid, + NullableId5 = null, + NullableId6 = guid + }, options); + + json.ShouldBe($"{{\"Id\":\"{guid:D}\",\"NullableId\":null,\"NullableId2\":\"{guid:D}\",\"NullableId3\":null,\"NullableId4\":\"{guid:D}\",\"NullableId5\":null,\"NullableId6\":\"{guid:D}\"}}"); + } + + class TestClass + { + public Guid Id { get; set; } + + public Guid? NullableId { get; set; } + + public Guid? NullableId2 { get; set; } + + public Guid? NullableId3 { get; set; } + + public Guid? NullableId4 { get; set; } + + public Guid? NullableId5 { get; set; } + + public Guid? NullableId6 { get; set; } + } +} diff --git a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/en.json b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/en.json index 0a445a3b8c..19507eb2d6 100644 --- a/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/en.json +++ b/modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared/Volo/Abp/AuditLogging/Localization/en.json @@ -39,6 +39,7 @@ "ExtraProperties": "Extra properties", "MaxDuration": "Max. Duration", "MinDuration": "Min. Duration", + "MinMaxDuration": "Duration (Min. - Max.)", "{0}Milliseconds": "{0} milliseconds", "ExecutionTime": "Time", "Parameters": "Parameters", diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json index d4a32c194f..9bb8dd275c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json +++ b/modules/cms-kit/src/Volo.CmsKit.Domain.Shared/Volo/CmsKit/Localization/Resources/en.json @@ -214,6 +214,8 @@ "Feature:TagEnableDescription": "CMS Kit's tag system that allows tagging entities such as BlogPost.", "DeleteBlogPostMessage": "The blog will be deleted. Are you sure?", "CaptchaCode": "Captcha code", - "CommentTextRequired": "Comment is required" + "CommentTextRequired": "Comment is required", + "CaptchaCodeErrorMessage" : "The answer you entered for the CAPTCHA was not correct. Please try again", + "CaptchaCodeMissingMessage": "The captcha code is missing!" } } \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/CaptchaException.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/CaptchaException.cs deleted file mode 100644 index 7914e85b02..0000000000 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/CaptchaException.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Runtime.Serialization; -using Volo.Abp; - -namespace Volo.CmsKit.Public.Web.Security.Captcha; - -public class CaptchaException : UserFriendlyException -{ - public CaptchaException(string message) : base(message) - { - } - - public CaptchaException(SerializationInfo serializationInfo, StreamingContext context) : base(serializationInfo, context) - { - } -} \ No newline at end of file diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs index ef5a30a055..220e24f892 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Web/Security/Captcha/SimpleMathsCaptchaGenerator.cs @@ -9,6 +9,9 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.Drawing.Processing; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; +using Volo.Abp; +using Volo.CmsKit.Localization; +using Microsoft.Extensions.Localization; using Volo.Abp.DependencyInjection; using Color = SixLabors.ImageSharp.Color; using PointF = SixLabors.ImageSharp.PointF; @@ -17,6 +20,12 @@ namespace Volo.CmsKit.Public.Web.Security.Captcha; public class SimpleMathsCaptchaGenerator : ISingletonDependency { + private readonly IStringLocalizer _localizer; + + public SimpleMathsCaptchaGenerator(IStringLocalizer localizer) + { + _localizer = localizer; + } private static Dictionary Session { get; set; } = new Dictionary(); public CaptchaOutput Generate() @@ -74,7 +83,7 @@ public class SimpleMathsCaptchaGenerator : ISingletonDependency var request = Session[requestId]; if (request.Output.Result != value) { - throw new CaptchaException("The captcha code doesn't match text on the picture! Please try again."); + throw new UserFriendlyException(_localizer["CaptchaCodeErrorMessage"]); } } @@ -86,7 +95,7 @@ public class SimpleMathsCaptchaGenerator : ISingletonDependency } else { - throw new CaptchaException("The captcha code is missing!"); + throw new UserFriendlyException(_localizer["CaptchaCodeMissingMessage"]); } } diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index f76a71d31c..80c9568a96 100644 --- a/npm/ng-packs/package.json +++ b/npm/ng-packs/package.json @@ -106,7 +106,7 @@ "jest-preset-angular": "^12.2.2", "jsonc-parser": "^2.3.0", "just-clone": "^6.1.1", - "just-compare": "^1.4.0", + "just-compare": "^2.3.0", "lerna": "^4.0.0", "lint-staged": "^13.0.3", "ng-packagr": "15.0.1", diff --git a/npm/ng-packs/packages/account-core/src/lib/tenant-box.service.ts b/npm/ng-packs/packages/account-core/src/lib/tenant-box.service.ts index b59191f3d1..bcb37c3d48 100644 --- a/npm/ng-packs/packages/account-core/src/lib/tenant-box.service.ts +++ b/npm/ng-packs/packages/account-core/src/lib/tenant-box.service.ts @@ -12,22 +12,22 @@ import { finalize } from 'rxjs/operators'; export class TenantBoxService { currentTenant$ = this.sessionState.getTenant$(); - name: string; + name?: string; - isModalVisible: boolean; + isModalVisible!: boolean; - modalBusy: boolean; + modalBusy!: boolean; constructor( private toasterService: ToasterService, private tenantService: AbpTenantService, private sessionState: SessionStateService, private configState: ConfigStateService, - ) { } + ) {} onSwitch() { const tenant = this.sessionState.getTenant(); - this.name = tenant?.name; + this.name = tenant?.name || ''; this.isModalVisible = true; } @@ -53,14 +53,14 @@ export class TenantBoxService { }); } - private setTenant(tenant: CurrentTenantDto) { + private setTenant(tenant: CurrentTenantDto | null) { this.sessionState.setTenant(tenant); this.configState.refreshAppState(); } private showError() { this.toasterService.error('AbpUiMultiTenancy::GivenTenantIsNotAvailable', 'AbpUi::Error', { - messageLocalizationParams: [this.name], + messageLocalizationParams: [this.name || ''], }); } } diff --git a/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts b/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts index 13fcfb6b7b..1656694781 100644 --- a/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts +++ b/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts @@ -1,7 +1,12 @@ import { ProfileService } from '@abp/ng.account.core/proxy'; import { getPasswordValidators, ToasterService } from '@abp/ng.theme.shared'; import { Component, Injector, OnInit } from '@angular/core'; -import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; +import { + UntypedFormBuilder, + UntypedFormControl, + UntypedFormGroup, + Validators, +} from '@angular/forms'; import { comparePasswords, Validation } from '@ngx-validate/core'; import { finalize } from 'rxjs/operators'; import { Account } from '../../models/account'; @@ -19,14 +24,14 @@ const PASSWORD_FIELDS = ['newPassword', 'repeatNewPassword']; export class ChangePasswordComponent implements OnInit, Account.ChangePasswordComponentInputs, Account.ChangePasswordComponentOutputs { - form: UntypedFormGroup; + form!: UntypedFormGroup; - inProgress: boolean; + inProgress?: boolean; - hideCurrentPassword: boolean; + hideCurrentPassword?: boolean; mapErrorsFn: Validation.MapErrorsFn = (errors, groupErrors, control) => { - if (PASSWORD_FIELDS.indexOf(String(control.name)) < 0) return errors; + if (PASSWORD_FIELDS.indexOf(String(control?.name)) < 0) return errors; return errors.concat(groupErrors.filter(({ key }) => key === 'passwordMismatch')); }; @@ -73,8 +78,8 @@ export class ChangePasswordComponent this.inProgress = true; this.profileService .changePassword({ - ...(!this.hideCurrentPassword && { currentPassword: this.form.get('password').value }), - newPassword: this.form.get('newPassword').value, + ...(!this.hideCurrentPassword && { currentPassword: this.form.get('password')?.value }), + newPassword: this.form.get('newPassword')?.value, }) .pipe(finalize(() => (this.inProgress = false))) .subscribe({ diff --git a/npm/ng-packs/packages/account/src/lib/components/forgot-password/forgot-password.component.ts b/npm/ng-packs/packages/account/src/lib/components/forgot-password/forgot-password.component.ts index c69fa0082c..e1f460df5a 100644 --- a/npm/ng-packs/packages/account/src/lib/components/forgot-password/forgot-password.component.ts +++ b/npm/ng-packs/packages/account/src/lib/components/forgot-password/forgot-password.component.ts @@ -10,7 +10,7 @@ import { finalize } from 'rxjs/operators'; export class ForgotPasswordComponent { form: UntypedFormGroup; - inProgress: boolean; + inProgress?: boolean; isEmailSent = false; @@ -27,7 +27,7 @@ export class ForgotPasswordComponent { this.accountService .sendPasswordResetCode({ - email: this.form.get('email').value, + email: this.form.get('email')?.value, appName: 'Angular', }) .pipe(finalize(() => (this.inProgress = false))) diff --git a/npm/ng-packs/packages/account/src/lib/components/login/login.component.ts b/npm/ng-packs/packages/account/src/lib/components/login/login.component.ts index 65d759861b..4ea5401092 100644 --- a/npm/ng-packs/packages/account/src/lib/components/login/login.component.ts +++ b/npm/ng-packs/packages/account/src/lib/components/login/login.component.ts @@ -14,9 +14,9 @@ const { maxLength, required } = Validators; templateUrl: './login.component.html', }) export class LoginComponent implements OnInit { - form: UntypedFormGroup; + form!: UntypedFormGroup; - inProgress: boolean; + inProgress?: boolean; isSelfRegistrationEnabled = true; @@ -67,7 +67,7 @@ export class LoginComponent implements OnInit { err.error?.error_description || err.error?.error.message || 'AbpAccount::DefaultErrorMessage', - null, + '', { life: 7000 }, ); return throwError(err); diff --git a/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts b/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts index a10174b2ac..2e31176245 100644 --- a/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts +++ b/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts @@ -26,7 +26,7 @@ export class ManageProfileComponent implements OnInit { profile$ = this.manageProfileState.getProfile$(); - hideChangePasswordTab: boolean; + hideChangePasswordTab?: boolean; constructor( protected profileService: ProfileService, diff --git a/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings-half-row.component.ts b/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings-half-row.component.ts index 6ee50eb33b..1a58950a85 100644 --- a/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings-half-row.component.ts +++ b/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings-half-row.component.ts @@ -27,11 +27,11 @@ export class PersonalSettingsHalfRowComponent { public displayName: string; public name: string; public id: string; - public formGroup: UntypedFormGroup; + public formGroup!: UntypedFormGroup; constructor(@Inject(EXTENSIONS_FORM_PROP) private propData: FormProp) { this.displayName = propData.displayName; this.name = propData.name; - this.id = propData.id; + this.id = propData.id || ''; } } diff --git a/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.ts b/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.ts index 32e5b1e7ab..f41058d06c 100644 --- a/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.ts +++ b/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.ts @@ -31,11 +31,11 @@ export class PersonalSettingsComponent Account.PersonalSettingsComponentInputs, Account.PersonalSettingsComponentOutputs { - selected: ProfileDto; + selected?: ProfileDto; - form: UntypedFormGroup; + form!: UntypedFormGroup; - inProgress: boolean; + inProgress?: boolean; constructor( private fb: UntypedFormBuilder, diff --git a/npm/ng-packs/packages/account/src/lib/components/register/register.component.ts b/npm/ng-packs/packages/account/src/lib/components/register/register.component.ts index 9855f9a283..b535f51fcb 100644 --- a/npm/ng-packs/packages/account/src/lib/components/register/register.component.ts +++ b/npm/ng-packs/packages/account/src/lib/components/register/register.component.ts @@ -15,9 +15,9 @@ const { maxLength, required, email } = Validators; templateUrl: './register.component.html', }) export class RegisterComponent implements OnInit { - form: UntypedFormGroup; + form!: UntypedFormGroup; - inProgress: boolean; + inProgress?: boolean; isSelfRegistrationEnabled = true; @@ -48,7 +48,7 @@ export class RegisterComponent implements OnInit { key: 'AbpAccount::SelfRegistrationDisabledMessage', defaultValue: 'Self registration is disabled.', }, - null, + '', { life: 10000 }, ); return; @@ -69,9 +69,9 @@ export class RegisterComponent implements OnInit { this.inProgress = true; const newUser = { - userName: this.form.get('username').value, - password: this.form.get('password').value, - emailAddress: this.form.get('email').value, + userName: this.form.get('username')?.value, + password: this.form.get('password')?.value, + emailAddress: this.form.get('email')?.value, appName: 'Angular', } as RegisterDto; @@ -90,7 +90,7 @@ export class RegisterComponent implements OnInit { err.error?.error_description || err.error?.error.message || 'AbpAccount::DefaultErrorMessage', - null, + '', { life: 7000 }, ); diff --git a/npm/ng-packs/packages/account/src/lib/components/reset-password/reset-password.component.ts b/npm/ng-packs/packages/account/src/lib/components/reset-password/reset-password.component.ts index 0bcb8a0d8a..8e93b75c06 100644 --- a/npm/ng-packs/packages/account/src/lib/components/reset-password/reset-password.component.ts +++ b/npm/ng-packs/packages/account/src/lib/components/reset-password/reset-password.component.ts @@ -13,14 +13,14 @@ const PASSWORD_FIELDS = ['password', 'confirmPassword']; templateUrl: './reset-password.component.html', }) export class ResetPasswordComponent implements OnInit { - form: UntypedFormGroup; + form!: UntypedFormGroup; inProgress = false; isPasswordReset = false; mapErrorsFn: Validation.MapErrorsFn = (errors, groupErrors, control) => { - if (PASSWORD_FIELDS.indexOf(String(control.name)) < 0) return errors; + if (PASSWORD_FIELDS.indexOf(String(control?.name)) < 0) return errors; return errors.concat(groupErrors.filter(({ key }) => key === 'passwordMismatch')); }; @@ -58,9 +58,9 @@ export class ResetPasswordComponent implements OnInit { this.accountService .resetPassword({ - userId: this.form.get('userId').value, - resetToken: this.form.get('resetToken').value, - password: this.form.get('password').value, + userId: this.form.get('userId')?.value, + resetToken: this.form.get('resetToken')?.value, + password: this.form.get('password')?.value, }) .pipe(finalize(() => (this.inProgress = false))) .subscribe(() => { diff --git a/npm/ng-packs/packages/components/chart.js/src/chart.component.ts b/npm/ng-packs/packages/components/chart.js/src/chart.component.ts index 2ac9e1d057..ac839d86c4 100644 --- a/npm/ng-packs/packages/components/chart.js/src/chart.component.ts +++ b/npm/ng-packs/packages/components/chart.js/src/chart.component.ts @@ -35,7 +35,7 @@ let Chart: any; exportAs: 'abpChart', }) export class ChartComponent implements AfterViewInit, OnDestroy, OnChanges { - @Input() type: string; + @Input() type!: string; @Input() data: any = {}; @@ -43,9 +43,9 @@ export class ChartComponent implements AfterViewInit, OnDestroy, OnChanges { @Input() plugins: any[] = []; - @Input() width: string; + @Input() width?: string; - @Input() height: string; + @Input() height?: string; @Input() responsive = true; @@ -53,7 +53,7 @@ export class ChartComponent implements AfterViewInit, OnDestroy, OnChanges { @Output() initialized = new EventEmitter(); - @ViewChild('canvas') canvas: ElementRef; + @ViewChild('canvas') canvas!: ElementRef; chart: any; @@ -67,7 +67,7 @@ export class ChartComponent implements AfterViewInit, OnDestroy, OnChanges { }); } - onCanvasClick(event) { + onCanvasClick(event: MouseEvent) { if (this.chart) { const element = this.chart.getElementsAtEventForMode( event, diff --git a/npm/ng-packs/packages/components/chart.js/src/widget-utils.ts b/npm/ng-packs/packages/components/chart.js/src/widget-utils.ts index 6e70e2cac5..e9511d6a75 100644 --- a/npm/ng-packs/packages/components/chart.js/src/widget-utils.ts +++ b/npm/ng-packs/packages/components/chart.js/src/widget-utils.ts @@ -1,4 +1,4 @@ -export function getRandomBackgroundColor(count) { +export function getRandomBackgroundColor(count: number) { const colors = []; for (let i = 0; i < count; i++) { diff --git a/npm/ng-packs/packages/components/page/src/page-part.directive.ts b/npm/ng-packs/packages/components/page/src/page-part.directive.ts index c228189e0f..e212cac63c 100644 --- a/npm/ng-packs/packages/components/page/src/page-part.directive.ts +++ b/npm/ng-packs/packages/components/page/src/page-part.directive.ts @@ -27,8 +27,8 @@ export const PAGE_RENDER_STRATEGY = new InjectionToken('PAGE @Directive({ selector: '[abpPagePart]' }) export class PagePartDirective implements OnInit, OnDestroy, OnChanges { hasRendered = false; - type: string; - subscription: Subscription; + type!: string; + subscription!: Subscription; @Input('abpPagePartContext') context: any; @Input() set abpPagePart(type: string) { diff --git a/npm/ng-packs/packages/components/page/src/page.component.html b/npm/ng-packs/packages/components/page/src/page.component.html index 543da2d6ff..5a4a5cc66c 100644 --- a/npm/ng-packs/packages/components/page/src/page.component.html +++ b/npm/ng-packs/packages/components/page/src/page.component.html @@ -25,7 +25,7 @@ - +
diff --git a/npm/ng-packs/packages/components/page/src/page.component.ts b/npm/ng-packs/packages/components/page/src/page.component.ts index 24b6d18ccf..d0a48b145c 100644 --- a/npm/ng-packs/packages/components/page/src/page.component.ts +++ b/npm/ng-packs/packages/components/page/src/page.component.ts @@ -12,11 +12,11 @@ import { encapsulation: ViewEncapsulation.None, }) export class PageComponent { - @Input() title: string; + @Input() title?: string; toolbarVisible = false; _toolbarData: any; - @Input('toolbar') set toolbarData(val: any) { + @Input() set toolbar(val: any) { this._toolbarData = val; this.toolbarVisible = true; } @@ -25,7 +25,7 @@ export class PageComponent { return this._toolbarData; } - @Input('breadcrumb') breadcrumbVisible = true; + @Input() breadcrumb = true; pageParts = { title: PageParts.title, @@ -33,16 +33,16 @@ export class PageComponent { toolbar: PageParts.toolbar, }; - @ContentChild(PageTitleContainerComponent) customTitle: PageTitleContainerComponent; + @ContentChild(PageTitleContainerComponent) customTitle?: PageTitleContainerComponent; @ContentChild(PageBreadcrumbContainerComponent) - customBreadcrumb: PageBreadcrumbContainerComponent; - @ContentChild(PageToolbarContainerComponent) customToolbar: PageToolbarContainerComponent; + customBreadcrumb?: PageBreadcrumbContainerComponent; + @ContentChild(PageToolbarContainerComponent) customToolbar?: PageToolbarContainerComponent; get shouldRenderRow() { return !!( this.title || this.toolbarVisible || - this.breadcrumbVisible || + this.breadcrumb || this.customTitle || this.customBreadcrumb || this.customToolbar diff --git a/npm/ng-packs/packages/core/locale/src/utils/register-locale.ts b/npm/ng-packs/packages/core/locale/src/utils/register-locale.ts index db5d5c6452..97a49066ec 100644 --- a/npm/ng-packs/packages/core/locale/src/utils/register-locale.ts +++ b/npm/ng-packs/packages/core/locale/src/utils/register-locale.ts @@ -8,7 +8,7 @@ export interface LocaleErrorHandlerData { locale: string; } -let localeMap = {}; +let localeMap = {} as { [key: string]: string }; export interface RegisterLocaleData { cultureNameLocaleFileMap?: Record; @@ -51,7 +51,7 @@ export function registerLocale( }; } -const extraLocales = {}; +const extraLocales = {} as { [key: string]: any }; export function storeLocaleData(data: any, localeId: string) { extraLocales[localeId] = data; } @@ -62,7 +62,7 @@ export async function defaultLocalErrorHandlerFn({ locale, resolve }: LocaleErro return; } - if (isDevMode) { + if (isDevMode()) { console.error( `Cannot find the ${locale} locale file. You can check how can add new culture at https://docs.abp.io/en/abp/latest/UI/Angular/Localization#adding-a-new-culture`, ); diff --git a/npm/ng-packs/packages/core/package.json b/npm/ng-packs/packages/core/package.json index a6ec2ad9c2..f2a36b5dd2 100644 --- a/npm/ng-packs/packages/core/package.json +++ b/npm/ng-packs/packages/core/package.json @@ -10,7 +10,7 @@ "@abp/utils": "~7.1.0-rc.1", "angular-oauth2-oidc": "^15.0.1", "just-clone": "^6.1.1", - "just-compare": "^1.4.0", + "just-compare": "^2.3.0", "ts-toolbelt": "6.15.4", "tslib": "^2.0.0" }, diff --git a/npm/ng-packs/packages/core/src/lib/abstracts/ng-model.component.ts b/npm/ng-packs/packages/core/src/lib/abstracts/ng-model.component.ts index cb3fe34f98..0f0eaa3722 100644 --- a/npm/ng-packs/packages/core/src/lib/abstracts/ng-model.component.ts +++ b/npm/ng-packs/packages/core/src/lib/abstracts/ng-model.component.ts @@ -4,16 +4,16 @@ import { ControlValueAccessor } from '@angular/forms'; // Not an abstract class on purpose. Do not change! @Component({ template: '' }) export class AbstractNgModelComponent implements ControlValueAccessor { - protected _value: T; + protected _value!: T; protected cdRef: ChangeDetectorRef; - onChange: (value: T) => void; - onTouched: () => void; + onChange?: (value: T) => void; + onTouched?: () => void; @Input() - disabled: boolean; + disabled?: boolean; @Input() - readonly: boolean; + readonly?: boolean; @Input() valueFn: (value: U, previousValue?: T) => T = value => value as any as T; diff --git a/npm/ng-packs/packages/core/src/lib/clients/http.client.ts b/npm/ng-packs/packages/core/src/lib/clients/http.client.ts index c6e9017be7..299593a970 100644 --- a/npm/ng-packs/packages/core/src/lib/clients/http.client.ts +++ b/npm/ng-packs/packages/core/src/lib/clients/http.client.ts @@ -15,7 +15,7 @@ export class ExternalHttpClient extends HttpClient { ): Observable { if (typeof first === 'string') { this.#setPlaceholderContext(options); - return super.request(first, url, options); + return super.request(first, url || '', options); } this.#setPlaceholderContext(first); diff --git a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts index 5f39e5c865..5adaa0d768 100644 --- a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts +++ b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts @@ -17,8 +17,8 @@ import { TreeNode } from '../utils/tree-utils'; providers: [SubscriptionService], }) export class DynamicLayoutComponent { - layout: Type; - layoutKey: eLayoutType; + layout?: Type; + layoutKey?: eLayoutType; // TODO: Consider a shared enum (eThemeSharedComponents) for known layouts readonly layouts = new Map([ @@ -29,9 +29,9 @@ export class DynamicLayoutComponent { isLayoutVisible = true; - private router: Router; - private route: ActivatedRoute; - private routes: RoutesService; + private router!: Router; + private route!: ActivatedRoute; + private routes!: RoutesService; constructor( injector: Injector, @@ -42,7 +42,7 @@ export class DynamicLayoutComponent { @Optional() @SkipSelf() dynamicLayoutComponent: DynamicLayoutComponent, ) { if (dynamicLayoutComponent) { - if (isDevMode) console.warn('DynamicLayoutComponent must be used only in AppComponent.'); + if (isDevMode()) console.warn('DynamicLayoutComponent must be used only in AppComponent.'); return; } this.route = injector.get(ActivatedRoute); @@ -80,8 +80,10 @@ export class DynamicLayoutComponent { if (this.layoutKey === expectedLayout) return; const key = this.layouts.get(expectedLayout); - this.layout = this.getComponent(key)?.component; - this.layoutKey = expectedLayout; + if (key) { + this.layout = this.getComponent(key)?.component; + this.layoutKey = expectedLayout; + } if(!this.layout){ this.showLayoutNotFoundError(expectedLayout); } @@ -94,7 +96,7 @@ export class DynamicLayoutComponent { } console.warn(message); } - + private listenToLanguageChange() { this.subscription.addOne(this.localizationService.languageChange$, () => { @@ -103,7 +105,7 @@ export class DynamicLayoutComponent { }); } - private getComponent(key: string): ReplaceableComponents.ReplaceableComponent { + private getComponent(key: string): ReplaceableComponents.ReplaceableComponent | undefined { return this.replaceableComponents.get(key); } } diff --git a/npm/ng-packs/packages/core/src/lib/components/replaceable-route-container.component.ts b/npm/ng-packs/packages/core/src/lib/components/replaceable-route-container.component.ts index 9d60fcda84..92d30fdff9 100644 --- a/npm/ng-packs/packages/core/src/lib/components/replaceable-route-container.component.ts +++ b/npm/ng-packs/packages/core/src/lib/components/replaceable-route-container.component.ts @@ -13,11 +13,11 @@ import { SubscriptionService } from '../services/subscription.service'; providers: [SubscriptionService], }) export class ReplaceableRouteContainerComponent implements OnInit { - defaultComponent: Type; + defaultComponent!: Type; - componentKey: string; + componentKey!: string; - externalComponent: Type; + externalComponent?: Type; constructor( private route: ActivatedRoute, diff --git a/npm/ng-packs/packages/core/src/lib/directives/debounce.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/debounce.directive.ts index 431305738a..69a96f95f1 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/debounce.directive.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/debounce.directive.ts @@ -16,7 +16,9 @@ export class InputEventDebounceDirective implements OnInit { constructor(private el: ElementRef, private subscription: SubscriptionService) {} ngOnInit(): void { - const input$ = fromEvent(this.el.nativeElement, 'input').pipe(debounceTime(this.debounce)); + const input$ = fromEvent(this.el.nativeElement, 'input').pipe( + debounceTime(this.debounce), + ); this.subscription.addOne(input$, (event: Event) => { this.debounceEvent.emit(event); diff --git a/npm/ng-packs/packages/core/src/lib/directives/for.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/for.directive.ts index 3e17d0ac3c..1e37e1c908 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/for.directive.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/for.directive.ts @@ -38,32 +38,32 @@ class RecordView { export class ForDirective implements OnChanges { // eslint-disable-next-line @angular-eslint/no-input-rename @Input('abpForOf') - items: any[]; + items!: any[]; @Input('abpForOrderBy') - orderBy: string; + orderBy?: string; @Input('abpForOrderDir') - orderDir: 'ASC' | 'DESC'; + orderDir?: 'ASC' | 'DESC'; @Input('abpForFilterBy') - filterBy: string; + filterBy?: string; @Input('abpForFilterVal') filterVal: any; @Input('abpForTrackBy') - trackBy; + trackBy?: TrackByFunction; @Input('abpForCompareBy') - compareBy: CompareFn; + compareBy?: CompareFn; @Input('abpForEmptyRef') - emptyRef: TemplateRef; + emptyRef?: TemplateRef; - private differ: IterableDiffer; + private differ!: IterableDiffer | null; - private isShowEmptyRef: boolean; + private isShowEmptyRef!: boolean; get compareFn(): CompareFn { return this.compareBy || compare; @@ -83,22 +83,29 @@ export class ForDirective implements OnChanges { const rw: RecordView[] = []; changes.forEachOperation( - (record: IterableChangeRecord, previousIndex: number, currentIndex: number) => { + ( + record: IterableChangeRecord, + previousIndex: number | null, + currentIndex: number | null, + ) => { if (record.previousIndex == null) { const view = this.vcRef.createEmbeddedView( this.tempRef, new AbpForContext(null, -1, -1, this.items), - currentIndex, + currentIndex || 0, ); rw.push(new RecordView(record, view)); - } else if (currentIndex == null) { + } else if (currentIndex == null && previousIndex !== null) { this.vcRef.remove(previousIndex); } else { - const view = this.vcRef.get(previousIndex); - this.vcRef.move(view, currentIndex); - - rw.push(new RecordView(record, view as EmbeddedViewRef)); + if (previousIndex !== null) { + const view = this.vcRef.get(previousIndex); + if (view && currentIndex !== null) { + this.vcRef.move(view, currentIndex); + rw.push(new RecordView(record, view as EmbeddedViewRef)); + } + } } }, ); @@ -117,8 +124,10 @@ export class ForDirective implements OnChanges { } changes.forEachIdentityChange((record: IterableChangeRecord) => { - const viewRef = this.vcRef.get(record.currentIndex) as EmbeddedViewRef; - viewRef.context.$implicit = record.item; + if (record.currentIndex !== null) { + const viewRef = this.vcRef.get(record.currentIndex) as EmbeddedViewRef; + viewRef.context.$implicit = record.item; + } }); } @@ -152,10 +161,9 @@ export class ForDirective implements OnChanges { } private sortItems(items: any[]) { - if (this.orderBy) { - items.sort((a, b) => - a[this.orderBy] > b[this.orderBy] ? 1 : a[this.orderBy] < b[this.orderBy] ? -1 : 0, - ); + const orderBy = this.orderBy; + if (orderBy) { + items.sort((a, b) => (a[orderBy] > b[orderBy] ? 1 : a[orderBy] < b[orderBy] ? -1 : 0)); } else { items.sort(); } @@ -166,13 +174,13 @@ export class ForDirective implements OnChanges { if (!Array.isArray(items)) return; const compareFn = this.compareFn; - + const filterBy = this.filterBy; if ( - typeof this.filterBy !== 'undefined' && + typeof filterBy !== 'undefined' && typeof this.filterVal !== 'undefined' && this.filterVal !== '' ) { - items = items.filter(item => compareFn(item[this.filterBy], this.filterVal)); + items = items.filter(item => compareFn(item[filterBy], this.filterVal)); } switch (this.orderDir) { diff --git a/npm/ng-packs/packages/core/src/lib/directives/form-submit.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/form-submit.directive.ts index ed8b036b67..7562a1b7b7 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/form-submit.directive.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/form-submit.directive.ts @@ -8,7 +8,7 @@ import { Output, Self, } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup, FormGroupDirective } from '@angular/forms'; +import { FormGroupDirective, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; import { fromEvent } from 'rxjs'; import { debounceTime, filter } from 'rxjs/operators'; import { SubscriptionService } from '../services/subscription.service'; @@ -26,8 +26,9 @@ export class FormSubmitDirective implements OnInit { @Input() debounce = 200; + // TODO: Remove unused input @Input() - notValidateOnSubmit: string | boolean; + notValidateOnSubmit?: string | boolean; @Input() markAsDirtyWhenSubmit = true; @@ -41,11 +42,10 @@ export class FormSubmitDirective implements OnInit { private host: ElementRef, private cdRef: ChangeDetectorRef, private subscription: SubscriptionService, - ) { } + ) {} ngOnInit() { this.subscription.addOne(this.formGroupDirective.ngSubmit, () => { - if (this.markAsDirtyWhenSubmit) { this.markAsDirty(); } @@ -53,10 +53,10 @@ export class FormSubmitDirective implements OnInit { this.executedNgSubmit = true; }); - const keyup$ = fromEvent(this.host.nativeElement as HTMLElement, 'keyup').pipe( + const keyup$ = fromEvent(this.host.nativeElement as HTMLElement, 'keyup').pipe( debounceTime(this.debounce), filter(event => !(event.target instanceof HTMLTextAreaElement)), - filter((event: KeyboardEvent) => event && event.key === 'Enter'), + filter(event => event && event.key === 'Enter'), ); this.subscription.addOne(keyup$, () => { diff --git a/npm/ng-packs/packages/core/src/lib/directives/replaceable-template.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/replaceable-template.directive.ts index 59f047093c..9a1bedcd71 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/replaceable-template.directive.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/replaceable-template.directive.ts @@ -1,5 +1,4 @@ import { - ComponentRef, Directive, Injector, Input, @@ -24,7 +23,7 @@ import { SubscriptionService } from '../services/subscription.service'; }) export class ReplaceableTemplateDirective implements OnInit, OnChanges { @Input('abpReplaceableTemplate') - data: ReplaceableComponents.ReplaceableTemplateDirectiveInput; + data!: ReplaceableComponents.ReplaceableTemplateDirectiveInput; providedData = { inputs: {}, @@ -140,11 +139,15 @@ export class ReplaceableTemplateDirective implements OnInit, OnChanges { [key]: { enumerable: true, configurable: true, - get: () => this.data.inputs[key]?.value, - ...(this.data.inputs[key]?.twoWay && { + get: () => this.data.inputs?.[key]?.value, + ...(this.data.inputs?.[key]?.twoWay && { set: (newValue: any) => { - this.data.inputs[key].value = newValue; - this.data.outputs[`${key}Change`](newValue); + if (this.data.inputs?.[key]) { + this.data.inputs[key].value = newValue; + } + if (this.data.outputs?.[`${key}Change`]) { + this.data.outputs[`${key}Change`](newValue); + } }, }), }, diff --git a/npm/ng-packs/packages/core/src/lib/directives/stop-propagation.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/stop-propagation.directive.ts index 52722e95a9..0863d45e88 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/stop-propagation.directive.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/stop-propagation.directive.ts @@ -13,7 +13,7 @@ export class StopPropagationDirective implements OnInit { constructor(private el: ElementRef, private subscription: SubscriptionService) {} ngOnInit(): void { - this.subscription.addOne(fromEvent(this.el.nativeElement, 'click'), (event: MouseEvent) => { + this.subscription.addOne(fromEvent(this.el.nativeElement, 'click'), event => { event.stopPropagation(); this.stopPropEvent.emit(event); }); diff --git a/npm/ng-packs/packages/core/src/lib/handlers/routes.handler.ts b/npm/ng-packs/packages/core/src/lib/handlers/routes.handler.ts index 49bdc745c3..a46f6d9d77 100644 --- a/npm/ng-packs/packages/core/src/lib/handlers/routes.handler.ts +++ b/npm/ng-packs/packages/core/src/lib/handlers/routes.handler.ts @@ -12,16 +12,16 @@ export class RoutesHandler { } addRoutes() { - this.router?.config?.forEach(({ path = '', data }: RouteData) => { - if (!data?.routes) return; - - if (Array.isArray(data.routes)) { - this.routes.add(data.routes); - return; + (this.router?.config as RouteData[])?.forEach(({ path = '', data }: RouteData) => { + const routes = data?.routes; + if (!routes) return; + + if (Array.isArray(routes)) { + this.routes.add(routes); + } else { + const routesFlatten = flatRoutes([{ path, ...routes }], { path: '' }); + this.routes.add(routesFlatten); } - - const routes = flatRoutes([{ path, ...data.routes }], { path: '' }); - this.routes.add(routes); }); } } @@ -39,7 +39,7 @@ function flatRoutes(routes: RouteDef[], parent: any) { acc.push(current, ...flatRoutes(children, current)); return acc; - }, []); + }, [] as ABP.Route[]); } type RouteDef = ABP.Route & { children: RouteDef[] }; diff --git a/npm/ng-packs/packages/core/src/lib/interceptors/api.interceptor.ts b/npm/ng-packs/packages/core/src/lib/interceptors/api.interceptor.ts index 1e85cc4716..9321521159 100644 --- a/npm/ng-packs/packages/core/src/lib/interceptors/api.interceptor.ts +++ b/npm/ng-packs/packages/core/src/lib/interceptors/api.interceptor.ts @@ -10,7 +10,7 @@ export class ApiInterceptor implements IApiInterceptor { constructor(private httpWaitService: HttpWaitService) {} getAdditionalHeaders(existingHeaders?: HttpHeaders) { - return existingHeaders; + return existingHeaders || new HttpHeaders(); } intercept(request: HttpRequest, next: HttpHandler) { diff --git a/npm/ng-packs/packages/core/src/lib/models/auth.ts b/npm/ng-packs/packages/core/src/lib/models/auth.ts index 9c0250d316..dcaf6e7f11 100644 --- a/npm/ng-packs/packages/core/src/lib/models/auth.ts +++ b/npm/ng-packs/packages/core/src/lib/models/auth.ts @@ -12,6 +12,8 @@ export type PipeToLoginFn = ( params: Pick, injector: Injector, ) => UnaryFunction; - -export type SetTokenResponseToStorageFn = (injector: Injector, tokenRes: T) => void; +/** + * @deprecated The interface should not be used anymore. + */ +export type SetTokenResponseToStorageFn = (tokenRes: T) => void; export type CheckAuthenticationStateFn = (injector: Injector) => void; diff --git a/npm/ng-packs/packages/core/src/lib/models/dtos.ts b/npm/ng-packs/packages/core/src/lib/models/dtos.ts index b9b349f513..70aad747b0 100644 --- a/npm/ng-packs/packages/core/src/lib/models/dtos.ts +++ b/npm/ng-packs/packages/core/src/lib/models/dtos.ts @@ -1,17 +1,18 @@ import { ABP } from './common'; +import { checkHasProp } from '../utils/common-utils'; export class ListResultDto { items?: T[]; constructor(initialValues: Partial> = {}) { for (const key in initialValues) { - if (Object.prototype.hasOwnProperty.call(initialValues, key)) { + if (checkHasProp(initialValues, key)) { this[key] = initialValues[key]; } } } } - +type ValueOf = T[keyof T]; export class PagedResultDto extends ListResultDto { totalCount?: number; @@ -25,11 +26,8 @@ export class LimitedResultRequestDto { constructor(initialValues: Partial = {}) { for (const key in initialValues) { - if ( - Object.prototype.hasOwnProperty.call(initialValues, key) && - initialValues[key] !== undefined - ) { - this[key] = initialValues[key]; + if (checkHasProp(initialValues, key) && initialValues[key] !== undefined) { + this[key] = initialValues[key] as ValueOf; } } } @@ -56,7 +54,7 @@ export class EntityDto { constructor(initialValues: Partial> = {}) { for (const key in initialValues) { - if (Object.prototype.hasOwnProperty.call(initialValues, key)) { + if (checkHasProp(initialValues, key)) { this[key] = initialValues[key]; } } @@ -130,11 +128,11 @@ export class FullAuditedEntityWithUserDto< } export class ExtensibleObject { - extraProperties: ABP.Dictionary; + extraProperties?: ABP.Dictionary; constructor(initialValues: Partial = {}) { for (const key in initialValues) { - if (Object.prototype.hasOwnProperty.call(initialValues, key)) { + if (checkHasProp(initialValues, key)) { this[key] = initialValues[key]; } } @@ -142,7 +140,7 @@ export class ExtensibleObject { } export class ExtensibleEntityDto extends ExtensibleObject { - id: TKey; + id?: TKey; constructor(initialValues: Partial> = {}) { super(initialValues); @@ -152,7 +150,7 @@ export class ExtensibleEntityDto extends ExtensibleObject { export class ExtensibleCreationAuditedEntityDto< TPrimaryKey = string, > extends ExtensibleEntityDto { - creationTime: Date | string; + creationTime?: Date | string; creatorId?: string; constructor(initialValues: Partial> = {}) { @@ -175,8 +173,8 @@ export class ExtensibleAuditedEntityWithUserDto< TPrimaryKey = string, TUserDto = any, > extends ExtensibleAuditedEntityDto { - creator: TUserDto; - lastModifier: TUserDto; + creator?: TUserDto; + lastModifier?: TUserDto; constructor(initialValues: Partial> = {}) { super(initialValues); @@ -187,7 +185,7 @@ export class ExtensibleCreationAuditedEntityWithUserDto< TPrimaryKey = string, TUserDto = any, > extends ExtensibleCreationAuditedEntityDto { - creator: TUserDto; + creator?: TUserDto; constructor( initialValues: Partial> = {}, @@ -199,9 +197,9 @@ export class ExtensibleCreationAuditedEntityWithUserDto< export class ExtensibleFullAuditedEntityDto< TPrimaryKey = string, > extends ExtensibleAuditedEntityDto { - isDeleted: boolean; + isDeleted?: boolean; deleterId?: string; - deletionTime: Date | string; + deletionTime?: Date | string; constructor(initialValues: Partial> = {}) { super(initialValues); @@ -212,9 +210,9 @@ export class ExtensibleFullAuditedEntityWithUserDto< TPrimaryKey = string, TUserDto = any, > extends ExtensibleFullAuditedEntityDto { - creator: TUserDto; - lastModifier: TUserDto; - deleter: TUserDto; + creator?: TUserDto; + lastModifier?: TUserDto; + deleter?: TUserDto; constructor(initialValues: Partial> = {}) { super(initialValues); diff --git a/npm/ng-packs/packages/core/src/lib/models/environment.ts b/npm/ng-packs/packages/core/src/lib/models/environment.ts index 252afe1291..78a9294525 100644 --- a/npm/ng-packs/packages/core/src/lib/models/environment.ts +++ b/npm/ng-packs/packages/core/src/lib/models/environment.ts @@ -17,9 +17,10 @@ export interface ApplicationInfo { baseUrl?: string; logoUrl?: string; } - -export interface ApiConfig { +export interface HasAdditional { [key: string]: string; +} +export interface ApiConfig extends Partial{ url: string; rootNamespace?: string; } diff --git a/npm/ng-packs/packages/core/src/lib/models/session.ts b/npm/ng-packs/packages/core/src/lib/models/session.ts index e86e0a2616..fe5d94b6a4 100644 --- a/npm/ng-packs/packages/core/src/lib/models/session.ts +++ b/npm/ng-packs/packages/core/src/lib/models/session.ts @@ -3,6 +3,6 @@ import { CurrentTenantDto } from '../proxy/volo/abp/asp-net-core/mvc/multi-tenan export namespace Session { export interface State { language: string; - tenant: CurrentTenantDto; + tenant: CurrentTenantDto | null; } } diff --git a/npm/ng-packs/packages/core/src/lib/providers/locale.provider.ts b/npm/ng-packs/packages/core/src/lib/providers/locale.provider.ts index b96069e75d..ca90c4bc33 100644 --- a/npm/ng-packs/packages/core/src/lib/providers/locale.provider.ts +++ b/npm/ng-packs/packages/core/src/lib/providers/locale.provider.ts @@ -1,6 +1,7 @@ import { LOCALE_ID, Provider } from '@angular/core'; import { differentLocales } from '../constants/different-locales'; import { LocalizationService } from '../services/localization.service'; +import { checkHasProp } from '../utils/common-utils'; export class LocaleId extends String { constructor(private localizationService: LocalizationService) { @@ -9,7 +10,10 @@ export class LocaleId extends String { toString(): string { const { currentLang } = this.localizationService; - return differentLocales[currentLang] || currentLang; + if (checkHasProp(differentLocales, currentLang)) { + return differentLocales[currentLang]; + } + return currentLang; } valueOf(): string { diff --git a/npm/ng-packs/packages/core/src/lib/services/config-state.service.ts b/npm/ng-packs/packages/core/src/lib/services/config-state.service.ts index 62905c271b..2927b47e5d 100644 --- a/npm/ng-packs/packages/core/src/lib/services/config-state.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/config-state.service.ts @@ -1,5 +1,5 @@ import { Inject, Injectable } from '@angular/core'; -import { Observable, Subject, of } from 'rxjs'; +import { Observable, Subject } from 'rxjs'; import { map, switchMap, take, tap } from 'rxjs/operators'; import { AbpApplicationConfigurationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service'; import { AbpApplicationLocalizationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-localization.service'; @@ -47,6 +47,9 @@ export class ConfigStateService { private getLocalizationAndCombineWithAppState( appState: ApplicationConfigurationDto, ): Observable { + if (!appState.localization.currentCulture.cultureName) { + throw new Error('culture name should defined'); + } return this.getlocalizationResource(appState.localization.currentCulture.cultureName).pipe( map(result => ({ ...appState, localization: { ...appState.localization, ...result } })), ); @@ -77,11 +80,11 @@ export class ConfigStateService { } } - getOne$(key: string) { + getOne$(key: K) { return this.store.sliceState(state => state[key]); } - getOne(key: string) { + getOne(key: K) { return this.store.state[key]; } @@ -138,7 +141,7 @@ export class ConfigStateService { return keys.reduce((acc, key) => ({ ...acc, [key]: features.values[key] }), {}); } - getFeatures$(keys: string[]) { + getFeatures$(keys: string[]): Observable<{[key: string]: string} | undefined> { return this.store.sliceState(({ features }) => { if (!features?.values) return; @@ -164,7 +167,7 @@ export class ConfigStateService { return keysFound.reduce((acc, key) => { acc[key] = settings[key]; return acc; - }, {}); + }, {} as Record); } getSettings$(keyword?: string) { @@ -179,7 +182,7 @@ export class ConfigStateService { return keysFound.reduce((acc, key) => { acc[key] = settings[key]; return acc; - }, {}); + }, {} as Record); }), ); } diff --git a/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts b/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts index 0754205f33..4329a5cb74 100644 --- a/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts @@ -8,7 +8,7 @@ export class DomInsertionService { insertContent( contentStrategy: ContentStrategy, - ): T { + ): T | undefined { const hash = generateHash(contentStrategy.content); if (this.inserted.has(hash)) return; @@ -20,10 +20,11 @@ export class DomInsertionService { } removeContent(element: HTMLScriptElement | HTMLStyleElement) { - const hash = generateHash(element.textContent); - this.inserted.delete(hash); - - element.parentNode.removeChild(element); + if (element.textContent) { + const hash = generateHash(element.textContent); + this.inserted.delete(hash); + element.parentNode?.removeChild(element); + } } has(content: string): boolean { diff --git a/npm/ng-packs/packages/core/src/lib/services/environment.service.ts b/npm/ng-packs/packages/core/src/lib/services/environment.service.ts index a4e74cf16a..ca5d4d79ff 100644 --- a/npm/ng-packs/packages/core/src/lib/services/environment.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/environment.service.ts @@ -4,10 +4,10 @@ import { map } from 'rxjs/operators'; import { Apis, Environment } from '../models/environment'; import { InternalStore } from '../utils/internal-store-utils'; -const mapToApiUrl = (key: string) => (apis: Apis) => - (apis[key] || apis.default).url || apis.default.url; +const mapToApiUrl = (key: string | undefined) => (apis: Apis) => + ((key && apis[key]) || apis.default).url || apis.default.url; -const mapToIssuer = (issuer: string) => { +const mapToIssuer = (issuer: string | undefined) => { if (!issuer) { return issuer; } @@ -30,8 +30,8 @@ export class EnvironmentService { return this.store.state; } - getApiUrl(key: string) { - return mapToApiUrl(key)(this.store.state.apis); + getApiUrl(key: string | undefined) { + return mapToApiUrl(key)(this.store.state?.apis); } getApiUrl$(key: string) { @@ -43,11 +43,12 @@ export class EnvironmentService { } getIssuer() { - const issuer = this.store.state.oAuthConfig.issuer; + const issuer = this.store.state?.oAuthConfig?.issuer; + return mapToIssuer(issuer); } - + getIssuer$() { - return this.store.sliceState(state => state.oAuthConfig.issuer).pipe(map(mapToIssuer)); + return this.store.sliceState(state => state?.oAuthConfig?.issuer).pipe(map(mapToIssuer)); } } diff --git a/npm/ng-packs/packages/core/src/lib/services/http-wait.service.ts b/npm/ng-packs/packages/core/src/lib/services/http-wait.service.ts index 792c67ed70..d80599fc25 100644 --- a/npm/ng-packs/packages/core/src/lib/services/http-wait.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/http-wait.service.ts @@ -86,7 +86,10 @@ export class HttpWaitService { this.store.patch({ filteredRequests }); } - private applyFilter(requests: HttpRequest[]) { + private applyFilter(requests: HttpRequest[] | undefined) { + if (!requests) { + return []; + } const { filteredRequests } = this.store.state; return requests.filter( ({ method, url }) => diff --git a/npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts b/npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts index 3254396b82..f50102e15a 100644 --- a/npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { concat, Observable, of, throwError } from 'rxjs'; +import { concat, Observable, of, pipe, throwError } from 'rxjs'; import { delay, retryWhen, shareReplay, take, tap } from 'rxjs/operators'; import { LoadingStrategy } from '../strategies'; import { ResourceWaitService } from './resource-wait.service'; @@ -15,11 +15,13 @@ export class LazyLoadService { load(strategy: LoadingStrategy, retryTimes?: number, retryDelay?: number): Observable { if (this.loaded.has(strategy.path)) return of(new CustomEvent('load')); this.resourceWaitService.addResource(strategy.path); + const delayOperator = retryDelay ? pipe(delay(retryDelay)) : pipe(); + const takeOp = retryTimes ? pipe(take(retryTimes)) : pipe(); return strategy.createStream().pipe( retryWhen(error$ => concat( - error$.pipe(delay(retryDelay), take(retryTimes)), - throwError(new CustomEvent('error')), + error$.pipe(delayOperator, takeOp), + throwError(() => new CustomEvent('error')), ), ), tap(() => { @@ -36,7 +38,7 @@ export class LazyLoadService { if (!element) return false; - element.parentNode.removeChild(element); + element.parentNode?.removeChild(element); this.loaded.delete(path); return true; } diff --git a/npm/ng-packs/packages/core/src/lib/services/localization.service.ts b/npm/ng-packs/packages/core/src/lib/services/localization.service.ts index 20425460e8..8305c35c9c 100644 --- a/npm/ng-packs/packages/core/src/lib/services/localization.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/localization.service.ts @@ -90,15 +90,16 @@ export class LocalizationService { Object.entries(remote).forEach(entry => { const resourceName = entry[0]; const remoteTexts = entry[1]; - let resource = local.get(resourceName) || {}; + let resource = local?.get(resourceName) || {}; resource = { ...resource, ...remoteTexts }; - local.set(resourceName, resource); + local?.set(resourceName, resource); }); } return local; }), + filter(Boolean) ) .subscribe(val => this.localizations$.next(val)); } @@ -134,6 +135,7 @@ export class LocalizationService { lang => this.configState.getDeep('localization.currentCulture.cultureName') !== lang, ), switchMap(lang => this.configState.refreshAppState().pipe(map(() => lang))), + filter(Boolean), switchMap(lang => from(this.registerLocale(lang).then(() => lang))), ) .subscribe(lang => this._languageChange$.next(lang)); @@ -176,14 +178,14 @@ export class LocalizationService { return this.getLocalization(this.configState.getAll(), key, ...interpolateParams); } - localize(resourceName: string, key: string, defaultValue: string): Observable { + localize(resourceName: string, key: string, defaultValue: string): Observable { return this.configState.getOne$('localization').pipe( map(createLocalizer), map(localize => localize(resourceName, key, defaultValue)), ); } - localizeSync(resourceName: string, key: string, defaultValue: string): string { + localizeSync(resourceName: string, key: string, defaultValue: string): string | null { const localization = this.configState.getOne('localization'); return createLocalizer(localization)(resourceName, key, defaultValue); } @@ -210,7 +212,7 @@ export class LocalizationService { ...interpolateParams: string[] ) { if (!key) key = ''; - let defaultValue: string; + let defaultValue = ''; if (typeof key !== 'string') { defaultValue = key.defaultValue; @@ -219,7 +221,7 @@ export class LocalizationService { const keys = key.split('::') as string[]; const warn = (message: string) => { - if (isDevMode) console.warn(message); + if (isDevMode()) console.warn(message); }; if (keys.length < 2) { @@ -263,7 +265,7 @@ export class LocalizationService { } } -function recursivelyMergeBaseResources(baseResourceName: string, source: ResourceDto) { +function recursivelyMergeBaseResources(baseResourceName: string, source: ResourceDto): ApplicationLocalizationResourceDto { const item = source[baseResourceName]; if (item.baseResources.length === 0) { @@ -278,7 +280,7 @@ function recursivelyMergeBaseResources(baseResourceName: string, source: Resourc } function mergeResourcesWithBaseResource(resource: ResourceDto): ResourceDto { - const entities = Object.keys(resource).map(key => { + const entities: Array<[string, ApplicationLocalizationResourceDto]> = Object.keys(resource).map(key => { const newValue = recursivelyMergeBaseResources(key, resource); return [key, newValue]; }); @@ -296,5 +298,5 @@ function combineLegacyandNewResources( }, legacy); } -type LegacyLanguageDto = Record>; -type ResourceDto = Record; +export type LegacyLanguageDto = Record>; +export type ResourceDto = Record; diff --git a/npm/ng-packs/packages/core/src/lib/services/multi-tenancy.service.ts b/npm/ng-packs/packages/core/src/lib/services/multi-tenancy.service.ts index 979ef3bc43..8fbde5cc8e 100644 --- a/npm/ng-packs/packages/core/src/lib/services/multi-tenancy.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/multi-tenancy.service.ts @@ -12,7 +12,7 @@ import { SessionStateService } from './session-state.service'; @Injectable({ providedIn: 'root' }) export class MultiTenancyService { - domainTenant: CurrentTenantDto = null; + domainTenant: CurrentTenantDto | null = null; isTenantBoxVisible = true; diff --git a/npm/ng-packs/packages/core/src/lib/services/permission.service.ts b/npm/ng-packs/packages/core/src/lib/services/permission.service.ts index a1979bbe1e..70724ac814 100644 --- a/npm/ng-packs/packages/core/src/lib/services/permission.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/permission.service.ts @@ -14,7 +14,7 @@ export class PermissionService { ); } - getGrantedPolicy(key: string) { + getGrantedPolicy(key: string | undefined) { const policies = this.getSnapshot(); return this.isPolicyGranted(key, policies); } @@ -36,7 +36,7 @@ export class PermissionService { ); } - protected isPolicyGranted(key: string, grantedPolicies: Record) { + protected isPolicyGranted(key: string | undefined, grantedPolicies: Record) { if (!key) return true; const orRegexp = /\|\|/g; diff --git a/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts b/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts index e929d489f7..1f02daa389 100644 --- a/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/replaceable-components.service.ts @@ -23,7 +23,7 @@ export class ReplaceableComponentsService { } constructor(private ngZone: NgZone, private router: Router) { - this.store = new InternalStore([]); + this.store = new InternalStore([] as ReplaceableComponents.ReplaceableComponent[]); } add(replaceableComponent: ReplaceableComponents.ReplaceableComponent, reload?: boolean): void { @@ -44,11 +44,11 @@ export class ReplaceableComponentsService { if (reload) reloadRoute(this.router, this.ngZone); } - get(replaceableComponentKey: string): ReplaceableComponents.ReplaceableComponent { + get(replaceableComponentKey: string): ReplaceableComponents.ReplaceableComponent | undefined { return this.replaceableComponents.find(component => component.key === replaceableComponentKey); } - get$(replaceableComponentKey: string): Observable { + get$(replaceableComponentKey: string): Observable { return this.replaceableComponents$.pipe( map(components => components.find(component => component.key === replaceableComponentKey)), ); diff --git a/npm/ng-packs/packages/core/src/lib/services/resource-wait.service.ts b/npm/ng-packs/packages/core/src/lib/services/resource-wait.service.ts index 16351837a2..28f63d7d87 100644 --- a/npm/ng-packs/packages/core/src/lib/services/resource-wait.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/resource-wait.service.ts @@ -20,7 +20,7 @@ export class ResourceWaitService { } updateLoading$() { - return this.store.sliceUpdate(({ resources }) => !!resources.size); + return this.store.sliceUpdate(({ resources }) => !!resources?.size); } clearLoading() { diff --git a/npm/ng-packs/packages/core/src/lib/services/rest.service.ts b/npm/ng-packs/packages/core/src/lib/services/rest.service.ts index 82e2c12707..e9a6e89851 100644 --- a/npm/ng-packs/packages/core/src/lib/services/rest.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/rest.service.ts @@ -20,7 +20,7 @@ export class RestService { protected httpErrorReporter: HttpErrorReporterService, ) {} - protected getApiFromStore(apiName: string): string { + protected getApiFromStore(apiName: string | undefined): string { return this.environment.getApiUrl(apiName); } @@ -51,13 +51,12 @@ export class RestService { } private getParams(params: Rest.Params, encoder?: HttpParameterCodec): HttpParams { - const filteredParams = Object.keys(params).reduce((acc, key) => { - const value = params[key]; + const filteredParams = Object.entries(params).reduce((acc, [key, value]) => { if (isUndefinedOrEmptyString(value)) return acc; if (value === null && !this.options.sendNullsAsQueryParam) return acc; acc[key] = value; return acc; - }, {}); + }, {} as any); return encoder ? new HttpParams({ encoder, fromObject: filteredParams }) : new HttpParams({ fromObject: filteredParams }); diff --git a/npm/ng-packs/packages/core/src/lib/services/router-events.service.ts b/npm/ng-packs/packages/core/src/lib/services/router-events.service.ts index 9acee09aa7..6203bad3bb 100644 --- a/npm/ng-packs/packages/core/src/lib/services/router-events.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/router-events.service.ts @@ -6,6 +6,7 @@ import { NavigationStart, Router, RouterEvent, + Event } from '@angular/router'; import { filter } from 'rxjs/operators'; @@ -23,7 +24,7 @@ export class RouterEvents { getEvents(...eventTypes: T) { type FilteredRouterEvent = T extends Type[] ? Ctor : never; - const filterRouterEvents = (event: RouterEvent): event is FilteredRouterEvent => + const filterRouterEvents = (event: Event): event is FilteredRouterEvent => eventTypes.some(type => event instanceof type); return this.router.events.pipe(filter(filterRouterEvents)); @@ -36,7 +37,7 @@ export class RouterEvents { : never : never; - const filterNavigationEvents = (event: RouterEvent): event is FilteredNavigationEvent => + const filterNavigationEvents = (event: Event): event is FilteredNavigationEvent => navigationEventKeys.some(key => event instanceof NavigationEvent[key]); return this.router.events.pipe(filter(filterNavigationEvents)); diff --git a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts index d2aba62c09..32f8b473d0 100644 --- a/npm/ng-packs/packages/core/src/lib/services/routes.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/routes.service.ts @@ -7,7 +7,7 @@ import { ConfigStateService } from './config-state.service'; import { PermissionService } from './permission.service'; // eslint-disable-next-line @typescript-eslint/ban-types -export abstract class AbstractTreeService { +export abstract class AbstractTreeService { abstract id: string; abstract parentId: string; abstract hide: (item: T) => boolean; @@ -84,7 +84,7 @@ export abstract class AbstractTreeService { } find(predicate: (item: TreeNode) => boolean, tree = this.tree): TreeNode | null { - return tree.reduce( + return tree.reduce | null>( (acc, node) => (acc ? acc : predicate(node) ? node : this.find(predicate, node.children)), null, ); @@ -119,9 +119,9 @@ export abstract class AbstractTreeService { } search(params: Partial, tree = this.tree): TreeNode | null { - const searchKeys = Object.keys(params); + const searchKeys = Object.keys(params) as Array>; - return tree.reduce( + return tree.reduce | null>( (acc, node) => acc ? acc @@ -147,7 +147,7 @@ export abstract class AbstractNavTreeService if (!Number.isInteger(a.order)) return 1; if (!Number.isInteger(b.order)) return -1; - return a.order - b.order; + return (a.order as number) - (b.order as number); }; constructor(protected injector: Injector) { @@ -170,7 +170,7 @@ export abstract class AbstractNavTreeService hasInvisibleChild(identifier: string): boolean { const node = this.find(item => item[this.id] === identifier); - return node?.children?.some(child => child.invisible); + return node?.children?.some(child => child.invisible) || false; } /* istanbul ignore next */ diff --git a/npm/ng-packs/packages/core/src/lib/services/session-state.service.ts b/npm/ng-packs/packages/core/src/lib/services/session-state.service.ts index d0902f40e3..d3bac9a338 100644 --- a/npm/ng-packs/packages/core/src/lib/services/session-state.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/session-state.service.ts @@ -73,7 +73,7 @@ export class SessionStateService { return this.store.sliceState(state => state.tenant); } - setTenant(tenant: CurrentTenantDto) { + setTenant(tenant: CurrentTenantDto | null) { if (compare(tenant, this.store.state.tenant)) return; this.store.set({ ...this.store.state, tenant }); diff --git a/npm/ng-packs/packages/core/src/lib/services/subscription.service.ts b/npm/ng-packs/packages/core/src/lib/services/subscription.service.ts index 129391d40f..c8e31fdbf7 100644 --- a/npm/ng-packs/packages/core/src/lib/services/subscription.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/subscription.service.ts @@ -1,7 +1,7 @@ -import { Injectable } from '@angular/core'; import type { OnDestroy } from '@angular/core'; -import { Subscription } from 'rxjs'; +import { Injectable } from '@angular/core'; import type { Observable, PartialObserver } from 'rxjs'; +import { Subscription } from 'rxjs'; @Injectable() export class SubscriptionService implements OnDestroy { @@ -33,7 +33,9 @@ export class SubscriptionService implements OnDestroy { closeOne(subscription: Subscription | undefined | null) { this.removeOne(subscription); - subscription.unsubscribe(); + if (subscription) { + subscription.unsubscribe(); + } } ngOnDestroy(): void { diff --git a/npm/ng-packs/packages/core/src/lib/strategies/content-security.strategy.ts b/npm/ng-packs/packages/core/src/lib/strategies/content-security.strategy.ts index a848feabe3..0e15955fb8 100644 --- a/npm/ng-packs/packages/core/src/lib/strategies/content-security.strategy.ts +++ b/npm/ng-packs/packages/core/src/lib/strategies/content-security.strategy.ts @@ -10,7 +10,9 @@ export class LooseContentSecurityStrategy extends ContentSecurityStrategy { } applyCSP(element: HTMLScriptElement | HTMLStyleElement) { - element.setAttribute('nonce', this.nonce); + if (this.nonce) { + element.setAttribute('nonce', this.nonce); + } } } diff --git a/npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts b/npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts index 839e867f41..34d8fcbac8 100644 --- a/npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts +++ b/npm/ng-packs/packages/core/src/lib/strategies/content.strategy.ts @@ -1,5 +1,5 @@ -import { ContentSecurityStrategy, CONTENT_SECURITY_STRATEGY } from './content-security.strategy'; -import { DomStrategy, DOM_STRATEGY } from './dom.strategy'; +import { CONTENT_SECURITY_STRATEGY, ContentSecurityStrategy } from './content-security.strategy'; +import { DOM_STRATEGY, DomStrategy } from './dom.strategy'; export type ElementOptions = Partial<{ [key in keyof T]: T[key]; @@ -19,7 +19,11 @@ export abstract class ContentStrategy 0) { - Object.keys(this.options).forEach(key => (element[key] = this.options[key])); + (Object.keys(this.options) as Array>).forEach(key => { + if (this.options[key]) { + element[key] = (this.options as NonNullable)[key]; + } + }); } this.contentSecurityStrategy.applyCSP(element); diff --git a/npm/ng-packs/packages/core/src/lib/strategies/context.strategy.ts b/npm/ng-packs/packages/core/src/lib/strategies/context.strategy.ts index 36676c58a6..35e5f48022 100644 --- a/npm/ng-packs/packages/core/src/lib/strategies/context.strategy.ts +++ b/npm/ng-packs/packages/core/src/lib/strategies/context.strategy.ts @@ -13,7 +13,7 @@ export class NoContextStrategy< T extends Type | TemplateRef = any, > extends ContextStrategy { constructor() { - super(undefined); + super(undefined as unknown as Partial>); } } diff --git a/npm/ng-packs/packages/core/src/lib/strategies/cross-origin.strategy.ts b/npm/ng-packs/packages/core/src/lib/strategies/cross-origin.strategy.ts index d01188ac2e..c57f94be71 100644 --- a/npm/ng-packs/packages/core/src/lib/strategies/cross-origin.strategy.ts +++ b/npm/ng-packs/packages/core/src/lib/strategies/cross-origin.strategy.ts @@ -1,9 +1,14 @@ export class CrossOriginStrategy { - constructor(public crossorigin: 'anonymous' | 'use-credentials', public integrity?: string) {} + constructor( + public crossorigin: 'anonymous' | 'use-credentials' | null, + public integrity?: string, + ) {} setCrossOrigin(element: T) { if (this.integrity) element.setAttribute('integrity', this.integrity); - element.setAttribute('crossorigin', this.crossorigin); + if (this.crossorigin) { + element.setAttribute('crossorigin', this.crossorigin); + } } } diff --git a/npm/ng-packs/packages/core/src/lib/strategies/loading.strategy.ts b/npm/ng-packs/packages/core/src/lib/strategies/loading.strategy.ts index 46961e94ba..069c269d58 100644 --- a/npm/ng-packs/packages/core/src/lib/strategies/loading.strategy.ts +++ b/npm/ng-packs/packages/core/src/lib/strategies/loading.strategy.ts @@ -1,11 +1,11 @@ import { Observable, of } from 'rxjs'; import { switchMap } from 'rxjs/operators'; import { fromLazyLoad } from '../utils'; -import { CrossOriginStrategy, CROSS_ORIGIN_STRATEGY } from './cross-origin.strategy'; -import { DomStrategy, DOM_STRATEGY } from './dom.strategy'; +import { CROSS_ORIGIN_STRATEGY, CrossOriginStrategy } from './cross-origin.strategy'; +import { DOM_STRATEGY, DomStrategy } from './dom.strategy'; export abstract class LoadingStrategy { - element: T; + element!: T; constructor( public path: string, diff --git a/npm/ng-packs/packages/core/src/lib/tokens/localization.token.ts b/npm/ng-packs/packages/core/src/lib/tokens/localization.token.ts index e4fd2eeb3f..6472e7d5f3 100644 --- a/npm/ng-packs/packages/core/src/lib/tokens/localization.token.ts +++ b/npm/ng-packs/packages/core/src/lib/tokens/localization.token.ts @@ -4,10 +4,10 @@ import { ABP } from '../models/common'; export const LOCALIZATIONS = new InjectionToken('LOCALIZATIONS'); -export function localizationContributor(localizations: ABP.Localization[]) { +export function localizationContributor(localizations?: ABP.Localization[]) { if (localizations) { localizations$.next([...localizations$.value, ...localizations]); } } -export const localizations$ = new BehaviorSubject([]); +export const localizations$ = new BehaviorSubject([]); diff --git a/npm/ng-packs/packages/core/src/lib/tokens/set-token-response-to-storage.token.ts b/npm/ng-packs/packages/core/src/lib/tokens/set-token-response-to-storage.token.ts index 0436195654..0cd26708bf 100644 --- a/npm/ng-packs/packages/core/src/lib/tokens/set-token-response-to-storage.token.ts +++ b/npm/ng-packs/packages/core/src/lib/tokens/set-token-response-to-storage.token.ts @@ -1,6 +1,9 @@ import { InjectionToken } from '@angular/core'; import { SetTokenResponseToStorageFn } from '../models'; +/** + * @deprecated The token should not be used anymore. + */ export const SET_TOKEN_RESPONSE_TO_STORAGE_FN_KEY = new InjectionToken( 'SET_TOKEN_RESPONSE_TO_STORAGE_FN_KEY', ); diff --git a/npm/ng-packs/packages/core/src/lib/utils/common-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/common-utils.ts index b373b6c04a..44569c3cfe 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/common-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/common-utils.ts @@ -7,34 +7,38 @@ export function isUndefinedOrEmptyString(value: unknown): boolean { return value === undefined || value === ''; } -export function isNullOrUndefined(obj) { +export function isNullOrUndefined(obj: T) { return obj === null || obj === undefined; } -export function isNullOrEmpty(obj){ +export function isNullOrEmpty(obj: T): boolean { return obj === null || obj === undefined || obj === ''; } -export function exists(obj) { +export function exists(obj: T): obj is T { return !isNullOrUndefined(obj); } -export function isObject(obj) { +export function isObject(obj: T): boolean { return obj instanceof Object; } -export function isArray(obj) { +export function isArray(obj: T): boolean { return Array.isArray(obj); } -export function isObjectAndNotArray(obj) { +export function isObjectAndNotArray(obj: T): boolean { return isObject(obj) && !isArray(obj); } -export function isNode(obj) { +export function isNode(obj: T): boolean { return obj instanceof Node; } -export function isObjectAndNotArrayNotNode(obj) { +export function isObjectAndNotArrayNotNode(obj: T): boolean { return isObjectAndNotArray(obj) && !isNode(obj); } + +export function checkHasProp(object: T, key: string | keyof T): key is keyof T { + return Object.prototype.hasOwnProperty.call(object, key); +} diff --git a/npm/ng-packs/packages/core/src/lib/utils/date-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/date-utils.ts index 2144bf69a1..4201eb92fc 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/date-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/date-utils.ts @@ -13,8 +13,7 @@ export function getShortTimeFormat(configStateService: ConfigStateService) { const dateTimeFormat = configStateService.getDeep( 'localization.currentCulture.dateTimeFormat', ) as DateTimeFormatDto; - - return dateTimeFormat.shortTimePattern.replace('tt', 'a'); + return dateTimeFormat?.shortTimePattern?.replace('tt', 'a'); } export function getShortDateShortTimeFormat(configStateService: ConfigStateService) { @@ -22,5 +21,5 @@ export function getShortDateShortTimeFormat(configStateService: ConfigStateServi 'localization.currentCulture.dateTimeFormat', ) as DateTimeFormatDto; - return `${dateTimeFormat.shortDatePattern} ${dateTimeFormat.shortTimePattern.replace('tt', 'a')}`; + return `${dateTimeFormat.shortDatePattern} ${dateTimeFormat?.shortTimePattern?.replace('tt', 'a')}`; } diff --git a/npm/ng-packs/packages/core/src/lib/utils/environment-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/environment-utils.ts index 9958c97165..8db9b5e02f 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/environment-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/environment-utils.ts @@ -24,19 +24,23 @@ export function getRemoteEnv(injector: Injector, environment: Partial environmentService.setState(mergeEnvironments(environment, env, remoteEnv))), + tap(env => + environmentService.setState( + mergeEnvironments(environment, env || ({} as Environment), remoteEnv as RemoteEnv), + ), + ), ) .toPromise(); } function mergeEnvironments( local: Partial, - remote: any, + remote: Environment, config: RemoteEnv, ): Environment { switch (config.mergeStrategy) { case 'deepmerge': - return deepMerge(local, remote); + return deepMerge(local, remote) as Environment; case 'overwrite': case null: case undefined: diff --git a/npm/ng-packs/packages/core/src/lib/utils/factory-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/factory-utils.ts index c9542f3dba..eb4759bdad 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/factory-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/factory-utils.ts @@ -21,7 +21,7 @@ export class LazyModuleFactory extends NgModuleFactory { create(parentInjector: Injector | null): NgModuleRef { const injector = Injector.create({ - parent: parentInjector, + ...(parentInjector && { parent: parentInjector }), providers: this.moduleWithProviders.providers as StaticProvider[], }); @@ -35,7 +35,7 @@ export class LazyModuleFactory extends NgModuleFactory { export function featuresFactory( configState: ConfigStateService, featureKeys: string[], - mapFn: (features) => any = features => features, + mapFn: (features: { [key: string]: string }) => any = features => features, ) { return configState.getFeatures$(featureKeys).pipe(filter(Boolean), map(mapFn)); } diff --git a/npm/ng-packs/packages/core/src/lib/utils/internal-store-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/internal-store-utils.ts index 27a8e9cbcf..f19ec89f04 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/internal-store-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/internal-store-utils.ts @@ -37,7 +37,8 @@ export class InternalStore { } deepPatch(state: DeepPartial) { - this.state$.next(deepMerge(this.state, state)); + // TODO: Strict improve deepMerge + this.state$.next(deepMerge(this.state, state) as State); this.update$.next(state); } diff --git a/npm/ng-packs/packages/core/src/lib/utils/lazy-load-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/lazy-load-utils.ts index 6bf80143ea..c0ea64f09d 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/lazy-load-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/lazy-load-utils.ts @@ -1,6 +1,6 @@ import { Observable, Observer } from 'rxjs'; -import { CrossOriginStrategy, CROSS_ORIGIN_STRATEGY } from '../strategies/cross-origin.strategy'; -import { DomStrategy, DOM_STRATEGY } from '../strategies/dom.strategy'; +import { CROSS_ORIGIN_STRATEGY, CrossOriginStrategy } from '../strategies/cross-origin.strategy'; +import { DOM_STRATEGY, DomStrategy } from '../strategies/dom.strategy'; export function fromLazyLoad( element: HTMLScriptElement | HTMLLinkElement, @@ -11,9 +11,9 @@ export function fromLazyLoad( domStrategy.insertElement(element); return new Observable((observer: Observer) => { - element.onload = (event: T) => { + element.onload = (event: Event) => { clearCallbacks(element); - observer.next(event); + observer.next(event as T); observer.complete(); }; @@ -32,10 +32,10 @@ export function fromLazyLoad( }); } -function createErrorHandler(observer: Observer, element: HTMLElement) { +function createErrorHandler(observer: Observer, element: HTMLElement) { return function (event: Event | string) { clearCallbacks(element); - element.parentNode.removeChild(element); + element.parentNode?.removeChild(element); observer.error(event); }; } diff --git a/npm/ng-packs/packages/core/src/lib/utils/localization-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/localization-utils.ts index 59a0e99051..890a83c2e4 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/localization-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/localization-utils.ts @@ -10,7 +10,7 @@ export function getLocaleDirection(locale: string): 'ltr' | 'rtl' { } export function createLocalizer(localization: ApplicationLocalizationConfigurationDto) { - return (resourceName: string, key: string, defaultValue: string) => { + return (resourceName: string, key: string, defaultValue: string | null) => { if (resourceName === '_') return key; const resource = localization?.values?.[resourceName]; diff --git a/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts index 0b755cf9b4..a0b5aa89c6 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts @@ -90,18 +90,21 @@ function replaceTenantNameWithinEnvironment( ); } - if (environment.oAuthConfig.redirectUri) { + if (environment.oAuthConfig?.redirectUri) { environment.oAuthConfig.redirectUri = environment.oAuthConfig.redirectUri.replace( placeholder, tenancyName, ); } - environment.oAuthConfig.issuer = environment.oAuthConfig.issuer.replace(placeholder, tenancyName); + if(!environment.oAuthConfig) { + environment.oAuthConfig = {}; + } + environment.oAuthConfig.issuer = (environment.oAuthConfig.issuer || '').replace(placeholder, tenancyName); Object.keys(environment.apis).forEach(api => { Object.keys(environment.apis[api]).forEach(key => { - environment.apis[api][key] = environment.apis[api][key].replace(placeholder, tenancyName); + environment.apis[api][key] = (environment.apis[api][key] || '').replace(placeholder, tenancyName); }); }); diff --git a/npm/ng-packs/packages/core/src/lib/utils/object-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/object-utils.ts index 29382ee738..fe5992777d 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/object-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/object-utils.ts @@ -6,18 +6,25 @@ import { isObject, isObjectAndNotArrayNotNode, } from './common-utils'; +import { DeepPartial } from '../models'; -export function deepMerge(target, source) { +export function deepMerge( + target: DeepPartial | T, + source: DeepPartial | T, +): DeepPartial | T { if (isObjectAndNotArrayNotNode(target) && isObjectAndNotArrayNotNode(source)) { return deepMergeRecursively(target, source); } else if (isNullOrUndefined(target) && isNullOrUndefined(source)) { - return {}; + return {} as T; } else { - return exists(source) ? source : target; + return exists(source) ? (source as T) : target; } } -function deepMergeRecursively(target, source) { +function deepMergeRecursively( + target: DeepPartial | T, + source: DeepPartial | T, +): DeepPartial | T { const shouldNotRecurse = isNullOrUndefined(target) || isNullOrUndefined(source) || // at least one not defined @@ -33,14 +40,17 @@ function deepMergeRecursively(target, source) { * we will prioritize source if it is a defined value. */ if (shouldNotRecurse) { - return exists(source) ? source : target; + return exists(source) ? (source as T) : target; } - const keysOfTarget = Object.keys(target); - const keysOfSource = Object.keys(source); + const keysOfTarget = Object.keys(target as { [key: string]: any }); + const keysOfSource = Object.keys(source as { [key: string]: any }); const uniqueKeys = new Set(keysOfTarget.concat(keysOfSource)); return [...uniqueKeys].reduce((retVal, key) => { - retVal[key] = deepMergeRecursively(target[key], source[key]); + (retVal as any)[key] = deepMergeRecursively( + (target as { [key: string]: any })[key], + (source as { [key: string]: any })[key], + ); return retVal; - }, {}); + }, {} as T); } diff --git a/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts index 07fad6a1fe..bfd6c7a2b5 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/route-utils.ts @@ -1,11 +1,11 @@ import { NgZone } from '@angular/core'; -import { PRIMARY_OUTLET, Router, UrlSegmentGroup } from '@angular/router'; +import { PRIMARY_OUTLET, Router, UrlSegment, UrlSegmentGroup } from "@angular/router"; import { ABP } from '../models/common'; import { RoutesService } from '../services/routes.service'; import { noop } from './common-utils'; import { TreeNode } from './tree-utils'; -export function findRoute(routesService: RoutesService, path: string): TreeNode { +export function findRoute(routesService: RoutesService, path: string): TreeNode | null { const node = routesService.find(route => route.path === path); return node || path === '/' @@ -14,7 +14,7 @@ export function findRoute(routesService: RoutesService, path: string): TreeNode< } export function getRoutePath(router: Router, url = router.url) { - const emptyGroup = { segments: [] } as UrlSegmentGroup; + const emptyGroup = { segments: [] as UrlSegment[] } as UrlSegmentGroup; const primaryGroup = router.parseUrl(url).root.children[PRIMARY_OUTLET]; return '/' + (primaryGroup || emptyGroup).segments.map(({ path }) => path).join('/'); diff --git a/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts index da470c9c3e..bfc938c158 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts @@ -62,7 +62,7 @@ export function createTreeNodeFilterCreator( return (search: string) => { const regex = new RegExp('.*' + search + '.*', 'i'); - return function collectNodes(nodes: TreeNode[], matches = []) { + return function collectNodes(nodes: TreeNode[], matches: TreeNode[] = []) { for (const node of nodes) { if (regex.test(mapperFn(node[key]))) matches.push(node); @@ -82,8 +82,8 @@ export type TreeNode = { parent?: TreeNode; }; -type NodeKey = number | string | symbol | undefined | null; +export type NodeKey = number | string | symbol | undefined | null; -type NodeValue any> = F extends undefined +export type NodeValue any> = F extends undefined ? TreeNode : ReturnType; diff --git a/npm/ng-packs/packages/core/src/lib/validators/range.validator.ts b/npm/ng-packs/packages/core/src/lib/validators/range.validator.ts index 9497ed0407..16b9432a6e 100644 --- a/npm/ng-packs/packages/core/src/lib/validators/range.validator.ts +++ b/npm/ng-packs/packages/core/src/lib/validators/range.validator.ts @@ -21,10 +21,10 @@ export function validateRange({ maximum = Infinity, minimum = 0 }: RangeOptions }; } -function getMaxError(value: number, max: number, min: number): RangeError { +function getMaxError(value: number, max: number, min: number): RangeError | null { return value > max ? { range: { max, min } } : null; } -function getMinError(value: number, min: number, max: number): RangeError { +function getMinError(value: number, min: number, max: number): RangeError | null { return value < min ? { range: { min, max } } : null; } diff --git a/npm/ng-packs/packages/core/src/lib/validators/required.validator.ts b/npm/ng-packs/packages/core/src/lib/validators/required.validator.ts index 4e2b1931db..5e10ff515e 100644 --- a/npm/ng-packs/packages/core/src/lib/validators/required.validator.ts +++ b/npm/ng-packs/packages/core/src/lib/validators/required.validator.ts @@ -16,7 +16,7 @@ export function validateRequired({ allowEmptyStrings }: RequiredOptions = {}): V return required; } -function isValidRequired(value: any, allowEmptyStrings: boolean): boolean { +function isValidRequired(value: any, allowEmptyStrings: boolean | undefined): boolean { if (value || value === 0 || value === false) return true; if (allowEmptyStrings && value === '') return true; diff --git a/npm/ng-packs/packages/core/src/lib/validators/string-length.validator.ts b/npm/ng-packs/packages/core/src/lib/validators/string-length.validator.ts index 934188a4fb..068bdb65bb 100644 --- a/npm/ng-packs/packages/core/src/lib/validators/string-length.validator.ts +++ b/npm/ng-packs/packages/core/src/lib/validators/string-length.validator.ts @@ -27,10 +27,10 @@ export function validateStringLength({ }; } -function getMaxLengthError(value: string, requiredLength: number): StringLengthError { +function getMaxLengthError(value: string, requiredLength: number): StringLengthError | null { return value.length > requiredLength ? { maxlength: { requiredLength } } : null; } -function getMinLengthError(value: string, requiredLength: number): StringLengthError { +function getMinLengthError(value: string, requiredLength: number): StringLengthError | null { return value.length < requiredLength ? { minlength: { requiredLength } } : null; } diff --git a/npm/ng-packs/packages/core/src/lib/validators/username.validator.ts b/npm/ng-packs/packages/core/src/lib/validators/username.validator.ts index 4e943769d2..c238c71119 100644 --- a/npm/ng-packs/packages/core/src/lib/validators/username.validator.ts +++ b/npm/ng-packs/packages/core/src/lib/validators/username.validator.ts @@ -14,7 +14,7 @@ export interface UsernameOptions { const onlyLetterAndNumberRegex = /^[a-zA-Z0-9]+$/; export function validateUsername( - { pattern }: UsernameOptions = { pattern: onlyLetterAndNumberRegex }, + { pattern = /.*/ }: UsernameOptions = { pattern: onlyLetterAndNumberRegex }, ): ValidatorFn { return (control: AbstractControl): UsernamePatternError | null => { const isValid = isValidUserName(control.value, pattern); diff --git a/npm/ng-packs/packages/core/testing/src/lib/services/mock-permission.service.ts b/npm/ng-packs/packages/core/testing/src/lib/services/mock-permission.service.ts index 81bbdcc625..b4d180b17a 100644 --- a/npm/ng-packs/packages/core/testing/src/lib/services/mock-permission.service.ts +++ b/npm/ng-packs/packages/core/testing/src/lib/services/mock-permission.service.ts @@ -27,7 +27,7 @@ export class MockPermissionService extends PermissionService { const grantedPolicies = keys.reduce((policies, key) => { policies[key] = true; return policies; - }, {}); + }, {} as { [key: string]: boolean }); this.configState['store'].deepPatch({ auth: { grantedPolicies } }); } diff --git a/npm/ng-packs/packages/core/testing/src/lib/services/mock-rest.service.ts b/npm/ng-packs/packages/core/testing/src/lib/services/mock-rest.service.ts index b7b4066a4c..65e1763817 100644 --- a/npm/ng-packs/packages/core/testing/src/lib/services/mock-rest.service.ts +++ b/npm/ng-packs/packages/core/testing/src/lib/services/mock-rest.service.ts @@ -1,4 +1,10 @@ -import { ABP, CORE_OPTIONS, EnvironmentService, RestService } from '@abp/ng.core'; +import { + ABP, + CORE_OPTIONS, + EnvironmentService, + HttpErrorReporterService, + RestService, +} from '@abp/ng.core'; import { HttpClient } from '@angular/common/http'; import { Inject, Injectable } from '@angular/core'; import { Observable, throwError } from 'rxjs'; @@ -12,7 +18,7 @@ export class MockRestService extends RestService { protected http: HttpClient, protected environment: EnvironmentService, ) { - super(options, http, environment, null); + super(options, http, environment, null as unknown as HttpErrorReporterService); } handleError(err: any): Observable { diff --git a/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html b/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html index 09dcdb1be3..af51baa372 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html +++ b/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html @@ -1,48 +1,38 @@ -
-
-
-
-
{{ 'AbpIdentity::Roles' | abpLocalization }}
-
-
- -
+ +
+
+
-
- -
-
- - - -

{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewRole') | abpLocalization }}

-
+ + +

{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewRole') | abpLocalization }}

+
- -
- -
-
+ +
+ +
+
- - - {{ - 'AbpIdentity::Save' | abpLocalization - }} - -
+ + + {{ + 'AbpIdentity::Save' | abpLocalization + }} + +
- - + (abpInit)="init(abpPermissionManagement)" + > + + diff --git a/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts b/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts index 3bc940e353..5e2a0e866a 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts +++ b/npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts @@ -26,21 +26,21 @@ import { eIdentityComponents } from '../../enums/components'; export class RolesComponent implements OnInit { data: PagedResultDto = { items: [], totalCount: 0 }; - form: UntypedFormGroup; + form!: UntypedFormGroup; - selected: IdentityRoleDto; + selected?: IdentityRoleDto; - isModalVisible: boolean; + isModalVisible!: boolean; visiblePermissions = false; - providerKey: string; + providerKey?: string; modalBusy = false; permissionManagementKey = ePermissionManagementComponents.PermissionManagement; - onVisiblePermissionChange = event => { + onVisiblePermissionChange = (event: boolean) => { this.visiblePermissions = event; }; @@ -82,7 +82,7 @@ export class RolesComponent implements OnInit { if (!this.form.valid) return; this.modalBusy = true; - const { id } = this.selected; + const { id } = this.selected || {}; (id ? this.service.update(id, { ...this.selected, ...this.form.value }) : this.service.create(this.form.value) @@ -118,7 +118,7 @@ export class RolesComponent implements OnInit { }, 0); } - sort(data) { + sort(data: any) { const { prop, dir } = data.sorts[0]; this.list.sortKey = prop; this.list.sortOrder = dir; diff --git a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html index aba658f0dc..eaf21949f3 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html +++ b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html @@ -1,96 +1,89 @@ -
-
-
-
-
{{ 'AbpIdentity::Users' | abpLocalization }}
-
-
- -
-
-
-
-
-
- + + +
+
+
+
+ +
-
- + +
-
- - -

{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewUser') | abpLocalization }}

-
+ + +

{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewUser') | abpLocalization }}

+
- -
+ + +
+
-
-
+ + + +
+ + - - - {{ - 'AbpIdentity::Save' | abpLocalization - }} - - + + + {{ + 'AbpIdentity::Save' | abpLocalization + }} + + - - + [entityDisplayName]="entityDisplayName" + (abpInit)="init(abpPermissionManagement)" + > + + 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 460e637958..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 @@ -39,31 +39,33 @@ export class UsersComponent implements OnInit { data: PagedResultDto = { items: [], totalCount: 0 }; @ViewChild('modalContent', { static: false }) - modalContent: TemplateRef; + modalContent!: TemplateRef; - form: UntypedFormGroup; + form!: UntypedFormGroup; - selected: IdentityUserDto; + selected?: IdentityUserDto; - selectedUserRoles: IdentityRoleDto[]; + selectedUserRoles?: IdentityRoleDto[]; - roles: IdentityRoleDto[]; + roles?: IdentityRoleDto[]; visiblePermissions = false; - providerKey: string; + providerKey?: string; - isModalVisible: boolean; + isModalVisible?: boolean; modalBusy = false; permissionManagementKey = ePermissionManagementComponents.PermissionManagement; entityDisplayName: string; + inputKey=eFormComponets.FormCheckboxComponent + trackByFn: TrackByFunction = (index, item) => Object.keys(item)[0] || index; - onVisiblePermissionChange = event => { + onVisiblePermissionChange = (event: boolean) => { this.visiblePermissions = event; }; @@ -90,20 +92,22 @@ export class UsersComponent implements OnInit { this.service.getAssignableRoles().subscribe(({ items }) => { this.roles = items; - this.form.addControl( - 'roleNames', - this.fb.array( - this.roles.map(role => - this.fb.group({ - [role.name]: [ - this.selected.id - ? !!this.selectedUserRoles?.find(userRole => userRole.id === role.id) - : role.isDefault, - ], - }), + if (this.roles) { + this.form.addControl( + 'roleNames', + this.fb.array( + this.roles.map(role => + this.fb.group({ + [role.name as string]: [ + this.selected?.id + ? !!this.selectedUserRoles?.find(userRole => userRole.id === role.id) + : role.isDefault, + ], + }), + ), ), - ), - ); + ); + } }); } @@ -137,10 +141,11 @@ export class UsersComponent implements OnInit { const { roleNames = [] } = this.form.value; const mappedRoleNames = - roleNames.filter(role => !!role[Object.keys(role)[0]]).map(role => Object.keys(role)[0]) || - []; + roleNames + .filter((role: { [key: string]: any }) => !!role[Object.keys(role)[0]]) + .map((role: { [key: string]: any }) => Object.keys(role)[0]) || []; - const { id } = this.selected; + const { id } = this.selected || {}; (id ? this.service.update(id, { @@ -166,12 +171,13 @@ export class UsersComponent implements OnInit { if (status === Confirmation.Status.confirm) { this.service.delete(id).subscribe(() => { this.toasterService.success('AbpUi::SuccessfullyDeleted'); - this.list.get()}); + this.list.get(); + }); } }); } - sort(data) { + sort(data: any) { const { prop, dir } = data.sorts[0]; this.list.sortKey = prop; this.list.sortOrder = dir; diff --git a/npm/ng-packs/packages/identity/src/lib/defaults/default-roles-entity-actions.ts b/npm/ng-packs/packages/identity/src/lib/defaults/default-roles-entity-actions.ts index ac48cce799..fe6e0661d5 100644 --- a/npm/ng-packs/packages/identity/src/lib/defaults/default-roles-entity-actions.ts +++ b/npm/ng-packs/packages/identity/src/lib/defaults/default-roles-entity-actions.ts @@ -7,7 +7,7 @@ export const DEFAULT_ROLES_ENTITY_ACTIONS = EntityAction.createMany { const component = data.getInjected(RolesComponent); - component.edit(data.record.id); + component.edit(data.record.id || ''); }, permission: 'AbpIdentity.Roles.Update', }, @@ -15,7 +15,7 @@ export const DEFAULT_ROLES_ENTITY_ACTIONS = EntityAction.createMany { const component = data.getInjected(RolesComponent); - component.openPermissionsModal(data.record.name); + component.openPermissionsModal(data.record.name || ''); }, permission: 'AbpIdentity.Roles.ManagePermissions', }, @@ -23,9 +23,9 @@ export const DEFAULT_ROLES_ENTITY_ACTIONS = EntityAction.createMany { const component = data.getInjected(RolesComponent); - component.delete(data.record.id, data.record.name); + component.delete(data.record.id || '', data.record.name || ''); }, permission: 'AbpIdentity.Roles.Delete', - visible: data => !data.record.isStatic, + visible: data => !data?.record.isStatic, }, ]); diff --git a/npm/ng-packs/packages/identity/src/lib/defaults/default-roles-form-props.ts b/npm/ng-packs/packages/identity/src/lib/defaults/default-roles-form-props.ts index 52fc33d218..129a095a02 100644 --- a/npm/ng-packs/packages/identity/src/lib/defaults/default-roles-form-props.ts +++ b/npm/ng-packs/packages/identity/src/lib/defaults/default-roles-form-props.ts @@ -1,5 +1,5 @@ import { IdentityRoleDto } from '@abp/ng.identity/proxy'; -import { ePropType, FormProp, PropData } from '@abp/ng.theme.shared/extensions'; +import { ePropType, FormProp, PropData, PropPredicate } from "@abp/ng.theme.shared/extensions"; import { Validators } from '@angular/forms'; export const DEFAULT_ROLES_CREATE_FORM_PROPS = FormProp.createMany([ @@ -8,7 +8,7 @@ export const DEFAULT_ROLES_CREATE_FORM_PROPS = FormProp.createMany) => data.record && data.record.isStatic, + disabled: ((data: PropData) => data.record && data.record.isStatic) as PropPredicate, validators: () => [Validators.required], }, { diff --git a/npm/ng-packs/packages/identity/src/lib/defaults/default-users-entity-actions.ts b/npm/ng-packs/packages/identity/src/lib/defaults/default-users-entity-actions.ts index 8f6e3ebcc7..ca0a2edcad 100644 --- a/npm/ng-packs/packages/identity/src/lib/defaults/default-users-entity-actions.ts +++ b/npm/ng-packs/packages/identity/src/lib/defaults/default-users-entity-actions.ts @@ -1,14 +1,14 @@ -import {IdentityUserDto} from '@abp/ng.identity/proxy'; +import { IdentityUserDto } from '@abp/ng.identity/proxy'; import { EntityAction } from '@abp/ng.theme.shared/extensions'; import { UsersComponent } from '../components/users/users.component'; -import {ConfigStateService, CurrentUserDto} from "@abp/ng.core"; +import { ConfigStateService, CurrentUserDto } from '@abp/ng.core'; export const DEFAULT_USERS_ENTITY_ACTIONS = EntityAction.createMany([ { text: 'AbpIdentity::Edit', action: data => { const component = data.getInjected(UsersComponent); - component.edit(data.record.id); + component.edit(data.record.id || ''); }, permission: 'AbpIdentity.Users.Update', }, @@ -16,20 +16,21 @@ export const DEFAULT_USERS_ENTITY_ACTIONS = EntityAction.createMany { const component = data.getInjected(UsersComponent); - component.openPermissionsModal(data.record.id, data.record.userName); + component.openPermissionsModal(data.record.id || '', data.record.userName); }, permission: 'AbpIdentity.Users.ManagePermissions', - }, { + }, + { text: 'AbpIdentity::Delete', action: data => { const component = data.getInjected(UsersComponent); - component.delete(data.record.id, data.record.name || data.record.userName); + component.delete(data.record.id || '', data.record.name || data.record.userName || ''); }, - visible: data => { - const userName = data.record.userName; - const configStateService = data.getInjected(ConfigStateService) - const currentUser = configStateService.getOne("currentUser") as CurrentUserDto; - return userName !== currentUser.userName; + visible: data => { + const userName = data?.record.userName; + const configStateService = data?.getInjected(ConfigStateService); + const currentUser = configStateService?.getOne('currentUser') as CurrentUserDto; + return userName !== currentUser.userName; }, permission: 'AbpIdentity.Users.Delete', }, diff --git a/npm/ng-packs/packages/identity/src/lib/defaults/default-users-form-props.ts b/npm/ng-packs/packages/identity/src/lib/defaults/default-users-form-props.ts index ce0bb03636..ccdf06df24 100644 --- a/npm/ng-packs/packages/identity/src/lib/defaults/default-users-form-props.ts +++ b/npm/ng-packs/packages/identity/src/lib/defaults/default-users-form-props.ts @@ -67,7 +67,7 @@ export const DEFAULT_USERS_EDIT_FORM_PROPS = DEFAULT_USERS_CREATE_FORM_PROPS.map if (prop.name === 'password') { return { ...prop, - validators: data => [...getPasswordValidators({ get: data.getInjected })], + validators: (data: any) => [...getPasswordValidators({ get: data.getInjected })], }; } return prop; diff --git a/npm/ng-packs/packages/identity/src/lib/identity.module.ts b/npm/ng-packs/packages/identity/src/lib/identity.module.ts index e217a710a0..e6c11d195e 100644 --- a/npm/ng-packs/packages/identity/src/lib/identity.module.ts +++ b/npm/ng-packs/packages/identity/src/lib/identity.module.ts @@ -17,6 +17,7 @@ import { IDENTITY_ENTITY_PROP_CONTRIBUTORS, IDENTITY_TOOLBAR_ACTION_CONTRIBUTORS, } from './tokens/extensions.token'; +import { PageModule } from '@abp/ng.components/page'; @NgModule({ declarations: [RolesComponent, UsersComponent], @@ -30,6 +31,7 @@ import { NgbDropdownModule, PermissionManagementModule, NgxValidateCoreModule, + PageModule, ], }) export class IdentityModule { diff --git a/npm/ng-packs/packages/oauth/src/lib/handlers/oauth-configuration.handler.ts b/npm/ng-packs/packages/oauth/src/lib/handlers/oauth-configuration.handler.ts index 7e4cce28e4..a2a9228b78 100644 --- a/npm/ng-packs/packages/oauth/src/lib/handlers/oauth-configuration.handler.ts +++ b/npm/ng-packs/packages/oauth/src/lib/handlers/oauth-configuration.handler.ts @@ -1,5 +1,5 @@ import { Inject, Injectable } from '@angular/core'; -import { OAuthService } from 'angular-oauth2-oidc'; +import { AuthConfig, OAuthService } from "angular-oauth2-oidc"; import compare from 'just-compare'; import { filter, map } from 'rxjs/operators'; import { ABP, EnvironmentService, CORE_OPTIONS } from '@abp/ng.core'; @@ -20,10 +20,10 @@ export class OAuthConfigurationHandler { this.environmentService .createOnUpdateStream(state => state) .pipe( - map(environment => environment.oAuthConfig), + map(environment => environment.oAuthConfig as AuthConfig), filter(config => !compare(config, this.options.environment.oAuthConfig)), ) - .subscribe(config => { + .subscribe((config) => { this.oAuthService.configure(config); }); } diff --git a/npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts b/npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts index f36f966559..e7ee208c47 100644 --- a/npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts +++ b/npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts @@ -3,11 +3,11 @@ import { Inject, Injectable } from '@angular/core'; import { OAuthService } from 'angular-oauth2-oidc'; import { finalize } from 'rxjs/operators'; import { - SessionStateService, HttpWaitService, - TENANT_KEY, IApiInterceptor, IS_EXTERNAL_REQUEST, + SessionStateService, + TENANT_KEY, } from '@abp/ng.core'; @Injectable({ diff --git a/npm/ng-packs/packages/oauth/src/lib/oauth.module.ts b/npm/ng-packs/packages/oauth/src/lib/oauth.module.ts index 753ad815e3..5680b9582d 100644 --- a/npm/ng-packs/packages/oauth/src/lib/oauth.module.ts +++ b/npm/ng-packs/packages/oauth/src/lib/oauth.module.ts @@ -1,4 +1,4 @@ -import { APP_INITIALIZER, Injector, ModuleWithProviders, NgModule } from '@angular/core'; +import { APP_INITIALIZER, ModuleWithProviders, NgModule, Provider } from '@angular/core'; import { CommonModule } from '@angular/common'; import { OAuthModule, OAuthStorage } from 'angular-oauth2-oidc'; import { @@ -7,8 +7,7 @@ import { AuthService, CHECK_AUTHENTICATION_STATE_FN_KEY, noop, - PIPE_TO_LOGIN_FN_KEY, - SET_TOKEN_RESPONSE_TO_STORAGE_FN_KEY, + PIPE_TO_LOGIN_FN_KEY } from '@abp/ng.core'; import { storageFactory } from './utils/storage.factory'; import { AbpOAuthService } from './services'; @@ -17,7 +16,7 @@ import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { OAuthApiInterceptor } from './interceptors/api.interceptor'; import { AbpOAuthGuard } from './guards/oauth.guard'; import { NavigateToManageProfileProvider } from './providers'; -import { checkAccessToken, pipeToLogin, setTokenResponseToStorage } from './utils'; +import { checkAccessToken, pipeToLogin } from './utils'; @NgModule({ imports: [CommonModule, OAuthModule], @@ -43,10 +42,6 @@ export class AbpOAuthModule { provide: PIPE_TO_LOGIN_FN_KEY, useValue: pipeToLogin, }, - { - provide: SET_TOKEN_RESPONSE_TO_STORAGE_FN_KEY, - useValue: setTokenResponseToStorage, - }, { provide: CHECK_AUTHENTICATION_STATE_FN_KEY, useValue: checkAccessToken, @@ -63,7 +58,7 @@ export class AbpOAuthModule { deps: [OAuthConfigurationHandler], useFactory: noop, }, - OAuthModule.forRoot().providers, + OAuthModule.forRoot().providers as Provider[], { provide: OAuthStorage, useFactory: storageFactory }, ], }; diff --git a/npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts b/npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts index e28eebacc4..a8f937e8ca 100644 --- a/npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts +++ b/npm/ng-packs/packages/oauth/src/lib/services/oauth.service.ts @@ -6,13 +6,13 @@ import { IAuthService, LoginParams } from '@abp/ng.core'; import { AuthFlowStrategy } from '../strategies'; import { EnvironmentService } from '@abp/ng.core'; import { AUTH_FLOW_STRATEGY } from '../tokens/auth-flow-strategy'; -import { OAuthService } from 'angular-oauth2-oidc'; +import { AuthConfig, OAuthService } from "angular-oauth2-oidc"; @Injectable({ providedIn: 'root', }) export class AbpOAuthService implements IAuthService { - private strategy: AuthFlowStrategy; + private strategy!: AuthFlowStrategy; get isInternalAuth() { return this.strategy.isInternalAuth; @@ -25,7 +25,7 @@ export class AbpOAuthService implements IAuthService { const result$ = environmentService.getEnvironment$().pipe( map(env => env?.oAuthConfig), - filter(oAuthConfig => !!oAuthConfig), + filter(Boolean), tap(oAuthConfig => { this.strategy = oAuthConfig.responseType === 'code' diff --git a/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts b/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts index 3b5c89d4ac..7a07cb8985 100644 --- a/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts +++ b/npm/ng-packs/packages/oauth/src/lib/strategies/auth-flow-strategy.ts @@ -9,15 +9,16 @@ import { import { Observable, of } from 'rxjs'; import { filter, switchMap, tap } from 'rxjs/operators'; import { - LoginParams, ConfigStateService, EnvironmentService, HttpErrorReporterService, + LoginParams, SessionStateService, TENANT_KEY, } from '@abp/ng.core'; import { clearOAuthStorage } from '../utils/clear-o-auth-storage'; import { oAuthStorage } from '../utils/oauth-storage'; +import { HttpErrorResponse } from '@angular/common/http'; export abstract class AuthFlowStrategy { abstract readonly isInternalAuth: boolean; @@ -26,7 +27,7 @@ export abstract class AuthFlowStrategy { protected environment: EnvironmentService; protected configState: ConfigStateService; protected oAuthService: OAuthService2; - protected oAuthConfig: AuthConfig; + protected oAuthConfig!: AuthConfig; protected sessionState: SessionStateService; protected tenantKey: string; @@ -38,7 +39,7 @@ export abstract class AuthFlowStrategy { abstract login(params?: LoginParams | Params): Observable; - private catchError = err => { + private catchError = (err: HttpErrorResponse) => { this.httpErrorReporter.reportError(err); return of(null); }; @@ -49,18 +50,17 @@ export abstract class AuthFlowStrategy { this.configState = injector.get(ConfigStateService); this.oAuthService = injector.get(OAuthService2); this.sessionState = injector.get(SessionStateService); - this.oAuthConfig = this.environment.getEnvironment().oAuthConfig; + this.oAuthConfig = this.environment.getEnvironment().oAuthConfig || {}; this.tenantKey = injector.get(TENANT_KEY); this.listenToOauthErrors(); } async init(): Promise { - const shouldClear = shouldStorageClear( - this.environment.getEnvironment().oAuthConfig.clientId, - oAuthStorage, - ); - if (shouldClear) clearOAuthStorage(oAuthStorage); + if (this.oAuthConfig.clientId) { + const shouldClear = shouldStorageClear(this.oAuthConfig.clientId, oAuthStorage); + if (shouldClear) clearOAuthStorage(oAuthStorage); + } this.oAuthService.configure(this.oAuthConfig); diff --git a/npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts b/npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts index 74df5ce79b..24f94fe129 100644 --- a/npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts +++ b/npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts @@ -1,4 +1,4 @@ -import { Injector } from '@angular/core'; +import { inject, Injector } from '@angular/core'; import { Router } from '@angular/router'; import { OAuthStorage, TokenResponse } from 'angular-oauth2-oidc'; import { pipe } from 'rxjs'; @@ -29,30 +29,7 @@ export const pipeToLogin: PipeToLoginFn = function ( ); }; -export const setTokenResponseToStorage: SetTokenResponseToStorageFn = function ( - injector: Injector, - tokenRes: TokenResponse, -) { - const { access_token, refresh_token, scope: grantedScopes, expires_in } = tokenRes; - const storage = injector.get(OAuthStorage); - - storage.setItem('access_token', access_token); - storage.setItem('refresh_token', refresh_token); - storage.setItem('access_token_stored_at', '' + Date.now()); - - if (grantedScopes) { - storage.setItem('granted_scopes', JSON.stringify(grantedScopes.split(' '))); - } - - if (expires_in) { - const expiresInMilliSeconds = expires_in * 1000; - const now = new Date(); - const expiresAt = now.getTime() + expiresInMilliSeconds; - storage.setItem('expires_at', '' + expiresAt); - } -}; - -export function setRememberMe(remember: boolean) { +export function setRememberMe(remember: boolean | undefined) { removeRememberMe(); localStorage.setItem(storageKey, 'true'); document.cookie = `${cookieKey}=true; path=/${ 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 3d52624990..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 @@ -49,10 +49,10 @@ export class PermissionManagementComponent PermissionManagement.PermissionManagementComponentOutputs { @Input() - readonly providerName: string; + readonly providerName!: string; @Input() - readonly providerKey: string; + readonly providerKey!: string; @Input() readonly hideBadges = false; @@ -90,13 +90,13 @@ export class PermissionManagementComponent @Output() readonly visibleChange = new EventEmitter(); @ViewChildren('selectAllInThisTabsRef') - selectAllInThisTabsRef: QueryList>; + selectAllInThisTabsRef!: QueryList>; @ViewChildren('selectAllInAllTabsRef') - selectAllInAllTabsRef: QueryList>; + selectAllInAllTabsRef!: QueryList>; - data: GetPermissionListResultDto = { groups: [], entityDisplayName: null }; + data: GetPermissionListResultDto = { groups: [], entityDisplayName: '' }; - selectedGroup: PermissionGroupDto; + selectedGroup?: PermissionGroupDto | null; permissions: PermissionWithGroupName[] = []; @@ -131,16 +131,16 @@ export class PermissionManagementComponent (document.body.dir as LocaleDirection) === 'rtl' ? 'right' : 'left' }.px`; - const permissions = this.data.groups.find( - group => group.name === this.selectedGroup.name, - ).permissions; + const permissions = + (this.data.groups.find(group => group.name === this.selectedGroup?.name) || {}).permissions || + []; this.selectedGroupPermissions = permissions.map( permission => ({ ...permission, style: { [margin]: findMargin(permissions, permission) }, - isGranted: this.permissions.find(per => per.name === permission.name).isGranted, + isGranted: (this.permissions.find(per => per.name === permission.name) || {}).isGranted, } as unknown as PermissionWithStyle), ); } @@ -164,7 +164,7 @@ export class PermissionManagementComponent return false; } - onClickCheckbox(clickedPermission: PermissionGrantInfoDto, value) { + onClickCheckbox(clickedPermission: PermissionGrantInfoDto) { if ( clickedPermission.isGranted && this.isGrantedByOtherProviderName(clickedPermission.grantedProviders) @@ -263,7 +263,7 @@ export class PermissionManagementComponent const changedPermissions: UpdatePermissionDto[] = this.permissions .filter(per => - unchangedPermissions.find(unchanged => unchanged.name === per.name).isGranted === + (unchangedPermissions.find(unchanged => unchanged.name === per.name) || {}).isGranted === per.isGranted ? false : true, @@ -311,7 +311,7 @@ export class PermissionManagementComponent initModal() { // TODO: Refactor setTimeout(() => { - this.setDisabled(this.selectedGroup.permissions); + this.setDisabled(this.selectedGroup?.permissions || []); this.setTabCheckboxState(); this.setGrantCheckboxState(); }); @@ -335,7 +335,10 @@ export class PermissionManagementComponent } } -function findMargin(permissions: PermissionGrantInfoDto[], permission: PermissionGrantInfoDto) { +function findMargin( + permissions: PermissionGrantInfoDto[], + permission: PermissionGrantInfoDto, +): number { const parentPermission = permissions.find(per => per.name === permission.parentName); if (parentPermission && parentPermission.parentName) { @@ -348,7 +351,10 @@ function findMargin(permissions: PermissionGrantInfoDto[], permission: Permissio function getPermissions(groups: PermissionGroupDto[]): PermissionWithGroupName[] { return groups.reduce( - (acc, val) => [...acc, ...val.permissions.map(p => ({ ...p, groupName: val.name }))], - [], + (acc, val) => [ + ...acc, + ...val.permissions.map(p => ({ ...p, groupName: val.name || '' })), + ], + [] as PermissionWithGroupName[], ); } diff --git a/npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html b/npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html index 8f6be17e4d..bb0a27a6b2 100644 --- a/npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html +++ b/npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html @@ -1,63 +1,55 @@ -
-
-
-
-
{{ 'AbpTenantManagement::Tenants' | abpLocalization }}
-
-
- -
-
-
+ -
-
-
- + +
+
+
+
+ +
-
- + +
-
- - -

- {{ + + +

+ {{ (selected?.id ? 'AbpTenantManagement::Edit' : 'AbpTenantManagement::NewTenant') | abpLocalization - }} -

-
+ }} +

+
- -
- -
-
+ +
+ +
+
- - - {{ - 'AbpTenantManagement::Save' | abpLocalization - }} - -
+ + + {{ + 'AbpTenantManagement::Save' | abpLocalization + }} + + - - + [(visible)]="visibleFeatures" + providerName="T" + [providerKey]="providerKey" + > + + diff --git a/npm/ng-packs/packages/tenant-management/src/lib/tenant-management.module.ts b/npm/ng-packs/packages/tenant-management/src/lib/tenant-management.module.ts index 1aca283a29..535ee38aaa 100644 --- a/npm/ng-packs/packages/tenant-management/src/lib/tenant-management.module.ts +++ b/npm/ng-packs/packages/tenant-management/src/lib/tenant-management.module.ts @@ -16,6 +16,7 @@ import { TENANT_MANAGEMENT_ENTITY_PROP_CONTRIBUTORS, TENANT_MANAGEMENT_TOOLBAR_ACTION_CONTRIBUTORS, } from './tokens/extensions.token'; +import { PageModule } from '@abp/ng.components/page'; @NgModule({ declarations: [TenantsComponent], @@ -28,6 +29,7 @@ import { NgbDropdownModule, FeatureManagementModule, UiExtensionsModule, + PageModule, ], }) export class TenantManagementModule { diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/adapters/date-time.adapter.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/adapters/date-time.adapter.ts index cff2d41597..9e33b01de9 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/adapters/date-time.adapter.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/adapters/date-time.adapter.ts @@ -3,9 +3,9 @@ import { NgbDateStruct, NgbTimeStruct } from '@ng-bootstrap/ng-bootstrap'; @Injectable() export class DateTimeAdapter { - value!: NgbDateTimeStruct; + value!: Partial; - fromModel(value: string | Date): NgbDateTimeStruct | null { + fromModel(value: string | Date): Partial | null { if (!value) return null; const date = new Date(value); @@ -24,12 +24,12 @@ export class DateTimeAdapter { return this.value; } - toModel(value: NgbDateTimeStruct | null): string { + toModel(value: Partial | null): string { if (!value) return ''; const now = new Date(); - value = { + const newValue = { // TODO look for strict mode errors year: now.getUTCFullYear(), month: now.getMonth() + 1, @@ -39,11 +39,11 @@ export class DateTimeAdapter { second: 0, ...this.value, ...value, - }; + } as NgbDateTimeStruct; const date = new Date( - value.year, - value.month - 1, + newValue.year, + newValue.month - 1, value.day, value.hour, value.minute, diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/abstract-actions/abstract-actions.component.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/abstract-actions/abstract-actions.component.ts index 285e3fd00a..a7710d16a0 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/abstract-actions/abstract-actions.component.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/abstract-actions/abstract-actions.component.ts @@ -1,5 +1,5 @@ import { Directive, Injector, Input } from '@angular/core'; -import { ActionData, ActionList } from '../../models/actions'; +import { ActionData, ActionList, InferredAction } from '../../models/actions'; import { ExtensionsService } from '../../services/extensions.service'; import { EXTENSIONS_ACTION_TYPE, EXTENSIONS_IDENTIFIER } from '../../tokens/extensions.token'; import { InferredData, InferredRecord } from '../../models/toolbar-actions'; @@ -7,9 +7,9 @@ import { InferredData, InferredRecord } from '../../models/toolbar-actions'; // Fix for https://github.com/angular/angular/issues/23904 // @dynamic @Directive() -export abstract class AbstractActionsComponent> extends ActionData< - InferredRecord -> { +export abstract class AbstractActionsComponent< + L extends ActionList>, +> extends ActionData> { readonly actionList: L; readonly getInjected: InferredData['getInjected']; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts index 815a466c8f..1774289e7a 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts @@ -57,7 +57,7 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit { @ViewChild('field') private fieldRef!: ElementRef; - public injectorForCustomComponent: Injector; + public injectorForCustomComponent?: Injector; asterisk = ''; @@ -95,7 +95,7 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit { ? text$.pipe( debounceTime(300), distinctUntilChanged(), - switchMap(text => this.prop.options(this.data, text)), + switchMap(text => this.prop?.options?.(this.data, text) || of([])), ) : of([]); @@ -109,7 +109,7 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit { get isInvalid() { const control = this.form.get(this.prop.name); - return control.touched && control.invalid; + return control?.touched && control.invalid; } constructor( diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form.component.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form.component.ts index abb90c9cc6..bd6f23591f 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form.component.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form.component.ts @@ -44,7 +44,7 @@ export class ExtensibleFormComponent { } extraPropertiesKey = EXTRA_PROPERTIES_KEY; - groupedPropList: GroupedFormPropList; + groupedPropList!: GroupedFormPropList; record!: R; createGroupedList(propList: FormPropList) { diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.ts index b7685cc10a..6028e7e3ac 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.ts @@ -48,7 +48,7 @@ const DEFAULT_ACTIONS_COLUMN_WIDTH = 150; changeDetection: ChangeDetectionStrategy.OnPush, }) export class ExtensibleTableComponent implements OnChanges { - protected _actionsText: string; + protected _actionsText!: string; @Input() set actionsText(value: string) { this._actionsText = value; @@ -57,13 +57,13 @@ export class ExtensibleTableComponent implements OnChanges { return this._actionsText ?? (this.actionList.length > 1 ? 'AbpUi::Actions' : ''); } - @Input() data: R[]; - @Input() list: ListService; - @Input() recordsTotal: number; + @Input() data!: R[]; + @Input() list!: ListService; + @Input() recordsTotal!: number; @Input() set actionsColumnWidth(width: number) { this.setColumnWidths(width ? Number(width) : undefined); } - @Input() actionsTemplate: TemplateRef; + @Input() actionsTemplate?: TemplateRef; @Output() tableActivate = new EventEmitter(); @@ -73,7 +73,7 @@ export class ExtensibleTableComponent implements OnChanges { entityPropTypeClasses: EntityPropTypeClass; - readonly columnWidths: number[]; + readonly columnWidths!: number[]; readonly propList: EntityPropList; @@ -102,7 +102,7 @@ export class ExtensibleTableComponent implements OnChanges { this.setColumnWidths(DEFAULT_ACTIONS_COLUMN_WIDTH); } - private setColumnWidths(actionsColumn: number) { + private setColumnWidths(actionsColumn: number | undefined) { const widths = [actionsColumn]; this.propList.forEach(({ value: prop }) => { widths.push(prop.columnWidth); @@ -110,8 +110,8 @@ export class ExtensibleTableComponent implements OnChanges { (this.columnWidths as any) = widths; } - private getDate(value: Date, format: string) { - return value ? formatDate(value, format, this.locale) : ''; + private getDate(value: Date | undefined, format: string | undefined) { + return value && format ? formatDate(value, format, this.locale) : ''; } private getIcon(value: boolean) { @@ -122,7 +122,7 @@ export class ExtensibleTableComponent implements OnChanges { private getEnum(rowValue: any, list: Array>) { if (!list) return rowValue; - const { key } = list.find(({ value }) => value === rowValue); + const { key } = list.find(({ value }) => value === rowValue) || {}; return key; } @@ -139,7 +139,7 @@ export class ExtensibleTableComponent implements OnChanges { case ePropType.DateTime: return this.getDate(value, getShortDateShortTimeFormat(this.config)); case ePropType.Enum: - return this.getEnum(value, prop.enumList); + return this.getEnum(value, prop.enumList || []); default: return value; // More types can be handled in the future @@ -151,7 +151,7 @@ export class ExtensibleTableComponent implements OnChanges { ngOnChanges({ data }: SimpleChanges) { if (!data?.currentValue) return; - this.data = data.currentValue.map((record, index) => { + this.data = data.currentValue.map((record: any, index: number) => { this.propList.forEach(prop => { const propData = { getInjected: this.getInjected, record, index } as any; const value = this.getContent(prop.value, propData); diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/grid-actions/grid-actions.component.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/grid-actions/grid-actions.component.ts index 30d36699b6..22b5419b55 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/grid-actions/grid-actions.component.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/grid-actions/grid-actions.component.ts @@ -24,7 +24,7 @@ import { AbstractActionsComponent } from '../abstract-actions/abstract-actions.c export class GridActionsComponent extends AbstractActionsComponent> { @Input() icon = 'fa fa-cog'; - @Input() readonly index: number; + @Input() readonly index?: number; @Input() text = ''; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.html b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.html index dc481700d4..285e0aa94b 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.html +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.html @@ -1,6 +1,6 @@
@@ -13,15 +13,17 @@ - + + + diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.ts index 8015aaa84f..afe421554b 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/components/page-toolbar/page-toolbar.component.ts @@ -1,6 +1,8 @@ import { ChangeDetectionStrategy, Component, Injector, TrackByFunction } from '@angular/core'; import { HasCreateInjectorPipe, + ToolbarAction, + ToolbarActionDefault, ToolbarActionList, ToolbarComponent, } from '../../models/toolbar-actions'; @@ -32,4 +34,10 @@ export class PageToolbarComponent constructor(public readonly injector: Injector) { super(injector); } + + asToolbarAction(value: ToolbarActionDefault): { value: ToolbarAction } { + return { + value: value as ToolbarAction, + }; + } } diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/actions.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/actions.ts index 890899e515..d50d48678f 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/actions.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/actions.ts @@ -1,5 +1,5 @@ import { LinkedList } from '@abp/utils'; -import { InjectFlags, InjectionToken, Type } from '@angular/core'; +import { InjectFlags, InjectionToken, InjectOptions, Type } from '@angular/core'; import { O } from 'ts-toolbelt'; export abstract class ActionList> extends LinkedList {} @@ -8,7 +8,7 @@ export abstract class ActionData { abstract getInjected: ( token: Type | InjectionToken, notFoundValue?: T, - flags?: InjectFlags, + flags?: InjectOptions | InjectFlags, ) => T; index?: number; abstract record: R; @@ -27,8 +27,8 @@ export type ReadonlyActionData = O.Readonly, 'data'> export abstract class Action { constructor( public readonly permission: string, - public readonly visible: ActionPredicate = _ => true, - public readonly action: ActionCallback = _ => {}, + public readonly visible: ActionPredicate = () => true, + public readonly action: ActionCallback = () => {}, ) {} } @@ -46,7 +46,7 @@ export abstract class ActionsFactory> { } } -export abstract class Actions { +export abstract class Actions>> { protected abstract _ctor: Type; get actions(): L { @@ -68,11 +68,14 @@ export abstract class Actions { } } -export type ActionContributorCallbacks> = Record< +export type ActionContributorCallbacks>> = Record< string, ActionContributorCallback[] >; -export type ActionContributorCallback> = (actionList: L) => any; +export type ActionContributorCallback>> = ( + actionList: L, +) => any; type InferredActionList = C extends Actions ? L : never; +export type InferredAction = T extends ActionList ? U : T; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-actions.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-actions.ts index 09dda5127e..99253c0da8 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-actions.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-actions.ts @@ -24,7 +24,7 @@ export class EntityAction extends Action { readonly icon: string; constructor(options: EntityActionOptions) { - super(options.permission, options.visible, options.action); + super(options.permission || '', options.visible, options.action); this.text = options.text; this.icon = options.icon || ''; } diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-props.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-props.ts index dcbd56c07f..3bf4142e75 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-props.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/entity-props.ts @@ -27,16 +27,16 @@ export class EntityProp extends Prop { readonly columnWidth: number | undefined; readonly sortable: boolean; readonly valueResolver: PropCallback>; - readonly action: ActionCallback; - readonly component: Type; - readonly enumList: Array>; + readonly action?: ActionCallback; + readonly component?: Type; + readonly enumList?: Array>; constructor(options: EntityPropOptions) { super( options.type, options.name, - options.displayName, - options.permission, + options.displayName || '', + options.permission || '', options.visible, options.isExtra, ); @@ -44,10 +44,17 @@ export class EntityProp extends Prop { this.columnWidth = options.columnWidth; this.sortable = options.sortable || false; this.valueResolver = - options.valueResolver || (data => of(escapeHtmlChars(data.record[this.name]))); - this.action = options.action; - this.component = options.component; - this.enumList = options.enumList; + options.valueResolver || + (data => of(escapeHtmlChars((data.record as PropDataObject)[this.name]))); + if (options.action) { + this.action = options.action; + } + if (options.component) { + this.component = options.component; + } + if (options.enumList) { + this.enumList = options.enumList; + } } static create(options: EntityPropOptions) { @@ -76,3 +83,4 @@ export type EntityPropOptions = O.Optional< export type EntityPropDefaults = Record[]>; export type EntityPropContributorCallback = PropContributorCallback>; export type EntityPropContributorCallbacks = PropContributorCallbacks>; +type PropDataObject = { [key: string]: any }; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/form-props.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/form-props.ts index af0ae767d7..47a64142e6 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/form-props.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/form-props.ts @@ -18,7 +18,7 @@ import { export class FormPropList extends PropList> {} -export class FormProps extends Props> { +export class FormProps extends Props>> { protected _ctor: Type> = FormPropList; } @@ -46,7 +46,7 @@ export class GroupedFormPropList { } export interface GroupedFormPropItem { - group: FormPropGroup; + group?: FormPropGroup; formPropList: FormPropList; } @@ -76,8 +76,8 @@ export class FormProp extends Prop { super( options.type, options.name, - options.displayName, - options.permission, + options.displayName || '', + options.permission || '', options.visible, options.isExtra, options.template, @@ -94,7 +94,7 @@ export class FormProp extends Prop { this.options = options.options; this.id = options.id || options.name; const defaultValue = options.defaultValue; - this.defaultValue = isFalsyValue(defaultValue) ? defaultValue : defaultValue || null; + this.defaultValue = isFalsyValue(defaultValue) ? (defaultValue as number) : defaultValue || ''; this.displayTextResolver = options.displayTextResolver; } @@ -141,6 +141,6 @@ export type EditFormPropDefaults = Record[]>; export type EditFormPropContributorCallback = PropContributorCallback>; export type EditFormPropContributorCallbacks = PropContributorCallbacks>; -function isFalsyValue(defaultValue: FormProp['defaultValue']): boolean { +function isFalsyValue(defaultValue?: FormProp['defaultValue']): boolean { return [0, '', false].indexOf(defaultValue as any) > -1; } diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/internal/object-extensions.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/internal/object-extensions.ts index 776785ed4c..811b0a04f3 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/internal/object-extensions.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/internal/object-extensions.ts @@ -6,7 +6,7 @@ import { PropContributorCallbacks } from '../props'; export type DisplayNameGeneratorFn = ( displayName: LocalizableStringDto, fallback: LocalizableStringDto, -) => string; +) => string | undefined; export type EntityExtensions = Record; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/props.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/props.ts index a393e7587c..867380e9d8 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/props.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/props.ts @@ -56,7 +56,7 @@ export abstract class PropsFactory> { } } -export abstract class Props { +export abstract class Props>> { protected abstract _ctor: Type; get props(): L { @@ -78,11 +78,14 @@ export abstract class Props { } } -export type PropContributorCallbacks> = Record< +export type PropContributorCallbacks>> = Record< string, PropContributorCallback[] >; -export type PropContributorCallback> = (propList: L) => any; +export type PropContributorCallback>> = ( + propList: L, +) => any; type InferredPropList = C extends Props ? L : never; +export type InferredProp = T extends PropList ? U : T; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/toolbar-actions.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/toolbar-actions.ts index 048ce486c8..02b26a8173 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/toolbar-actions.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/models/toolbar-actions.ts @@ -11,10 +11,7 @@ import { ReadonlyActionData, } from './actions'; -export class ToolbarActionList extends ActionList< - R, - ToolbarAction | ToolbarComponent -> {} +export class ToolbarActionList extends ActionList> {} export class ToolbarActions extends Actions> { protected _ctor: Type> = ToolbarActionList; @@ -84,7 +81,7 @@ export type ToolbarActionContributorCallbacks = ActionContributorCallba ToolbarActionList >; export type InferredData = ActionData>; -export type InferredRecord = L extends ActionList ? R : never; +export type InferredRecord = L extends ActionList ? R : any; export interface HasCreateInjectorPipe { getData: () => ReadonlyActionData; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/pipes/create-injector.pipe.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/pipes/create-injector.pipe.ts index dff92e2c2d..3536fa4dad 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/pipes/create-injector.pipe.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/pipes/create-injector.pipe.ts @@ -25,7 +25,7 @@ export class CreateInjectorPipe implements PipeTransform { options?: InjectOptions | InjectFlags, ) => { const componentData = context.getData(); - const componentDataCallback = data => { + const componentDataCallback = (data: any) => { data = data ?? context.getData(); return action.action(data); }; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/actions.util.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/actions.util.ts index f4501317df..8017afbb31 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/actions.util.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/actions.util.ts @@ -1,4 +1,4 @@ -import { ActionContributorCallback, ActionList, ActionsFactory } from '../models/actions'; +import { ActionContributorCallback, ActionList, ActionsFactory, InferredAction } from "../models/actions"; import { EntityActionContributorCallbacks, EntityActionDefaults, @@ -20,7 +20,7 @@ export function mergeWithDefaultActions>( Object.keys(defaultActions).forEach((name: string) => { const actions: InferredActions = extension.get(name); actions.clearContributors(); - actions.addContributor((actionList: ActionList) => + actions.addContributor((actionList: ActionList>) => actionList.addManyTail(defaultActions[name]), ); contributors.forEach(contributor => diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/enum.util.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/enum.util.ts index 5b4181a0fa..57925956d6 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/enum.util.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/enum.util.ts @@ -1,11 +1,11 @@ -import { ABP, LocalizationService } from '@abp/ng.core'; +import { ABP, ExtensionEnumFieldDto, LocalizationService } from '@abp/ng.core'; import { merge, Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { EXTRA_PROPERTIES_KEY } from '../constants/extra-properties'; import { ObjectExtensions } from '../models/object-extensions'; import { PropCallback } from '../models/props'; -export function createEnum(members: ObjectExtensions.ExtensionEnumFieldDto[]) { +export function createEnum(members: ExtensionEnumFieldDto[]) { const enumObject: any = {}; members.forEach(({ name = '', value }) => { diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/form-props.util.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/form-props.util.ts index 7bdad1f7b2..617770f081 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/form-props.util.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/form-props.util.ts @@ -4,20 +4,20 @@ import { DateAdapter } from '../adapters/date.adapter'; import { TimeAdapter } from '../adapters/time.adapter'; import { EXTRA_PROPERTIES_KEY } from '../constants/extra-properties'; import { ePropType } from '../enums/props.enum'; -import { FormPropList } from '../models/form-props'; -import { PropData } from '../models/props'; +import { FormProp, FormPropList } from "../models/form-props"; +import { InferredProp, PropData } from "../models/props"; import { ExtensionsService } from '../services/extensions.service'; import { EXTENSIONS_IDENTIFIER } from '../tokens/extensions.token'; -export function generateFormFromProps(data: PropData) { - const extensions = data.getInjected(ExtensionsService); +export function generateFormFromProps(data: PropData) { + const extensions = data.getInjected(ExtensionsService); const identifier = data.getInjected(EXTENSIONS_IDENTIFIER); const form = new UntypedFormGroup({}); const extraForm = new UntypedFormGroup({}); form.addControl(EXTRA_PROPERTIES_KEY, extraForm); - const record = data.record || {}; + const record = data.record || {} as {[key:string]: any}; const type = JSON.stringify(record) === '{}' ? 'create' : 'edit'; const props: FormPropList = extensions[`${type}FormProps`].get(identifier).props; const extraProperties = record[EXTRA_PROPERTIES_KEY] || {}; diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/props.util.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/props.util.ts index b750131065..24360dccc1 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/props.util.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/props.util.ts @@ -1,4 +1,4 @@ -import { of } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { EXTRA_PROPERTIES_KEY } from '../constants/extra-properties'; import { EntityPropContributorCallbacks, @@ -15,10 +15,18 @@ import { EditFormPropsFactory, FormProps, } from '../models/form-props'; -import { PropContributorCallback, PropData, PropList, PropsFactory } from '../models/props'; +import { + InferredProp, + PropCallback, + PropContributorCallback, + PropList, + PropsFactory, +} from '../models/props'; -export function createExtraPropertyValueResolver(name: string) { - return (data?: PropData) => of(data.record[EXTRA_PROPERTIES_KEY][name]); +export function createExtraPropertyValueResolver( + name: string, +): PropCallback> { + return (data?) => of((data.record as { [key: string]: any })[EXTRA_PROPERTIES_KEY][name]); } export function mergeWithDefaultProps>( @@ -29,7 +37,9 @@ export function mergeWithDefaultProps>( Object.keys(defaultProps).forEach((name: string) => { const props: InferredProps = extension.get(name); props.clearContributors(); - props.addContributor((propList: PropList) => propList.addManyTail(defaultProps[name])); + props.addContributor((propList: PropList>) => + propList.addManyTail(defaultProps[name]), + ); contributors.forEach(contributor => (contributor[name] || []).forEach((callback: PropContributorCallback) => props.addContributor(callback), diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/state.util.ts b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/state.util.ts index c8e2b03e36..ef5fef48c3 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/state.util.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/lib/utils/state.util.ts @@ -2,29 +2,29 @@ import { ABP, ApplicationLocalizationConfigurationDto, ConfigStateService, + ExtensionEnumDto, ExtensionPropertyUiLookupDto, -} from '@abp/ng.core'; -import { Observable, pipe, zip } from 'rxjs'; -import { filter, map, switchMap, take } from 'rxjs/operators'; -import { ePropType } from '../enums/props.enum'; -import { EntityProp, EntityPropList } from '../models/entity-props'; -import { FormProp, FormPropList } from '../models/form-props'; -import { ObjectExtensions } from '../models/object-extensions'; -import { PropCallback } from '../models/props'; -import { createEnum, createEnumOptions, createEnumValueResolver } from './enum.util'; -import { createDisplayNameLocalizationPipeKeyGenerator } from './localization.util'; -import { createExtraPropertyValueResolver } from './props.util'; + ObjectExtensionsDto +} from "@abp/ng.core"; +import { Observable, pipe, zip } from "rxjs"; +import { filter, map, switchMap, take } from "rxjs/operators"; +import { ePropType } from "../enums/props.enum"; +import { EntityProp, EntityPropList } from "../models/entity-props"; +import { FormProp, FormPropList } from "../models/form-props"; +import { ObjectExtensions } from "../models/object-extensions"; +import { PropCallback } from "../models/props"; +import { createEnum, createEnumOptions, createEnumValueResolver } from "./enum.util"; +import { createDisplayNameLocalizationPipeKeyGenerator } from "./localization.util"; +import { createExtraPropertyValueResolver } from "./props.util"; import { createTypeaheadDisplayNameGenerator, createTypeaheadOptions, getTypeaheadType, - hasTypeaheadTextSuffix, -} from './typeahead.util'; -import { getValidatorsFromProperty } from './validation.util'; + hasTypeaheadTextSuffix +} from "./typeahead.util"; +import { getValidatorsFromProperty } from "./validation.util"; -function selectObjectExtensions( - configState: ConfigStateService, -): Observable { +function selectObjectExtensions(configState: ConfigStateService): Observable { return configState.getOne$('objectExtensions'); } @@ -36,9 +36,9 @@ function selectLocalization( function selectEnums( configState: ConfigStateService, -): Observable> { +): Observable> { return selectObjectExtensions(configState).pipe( - map((extensions: ObjectExtensions.ObjectExtensionsDto) => + map((extensions: ObjectExtensionsDto) => Object.keys(extensions.enums).reduce((acc, key) => { const { fields, localizationResource } = extensions.enums[key]; acc[key] = { @@ -63,7 +63,7 @@ export function getObjectExtensionEntitiesFromStore( return (extensions.modules[moduleKey] || ({} as ObjectExtensions.ModuleExtensionDto)) .entities; }), - map(entities => (isUndefined(entities) ? {} : entities)), + map(entities => (isUndefined(entities) ? ({} as any) : entities)), filter(Boolean), take(1), ); @@ -141,8 +141,8 @@ function createPropertiesToContributorsMapper( if (property.ui.onTable.isVisible) { const sortable = Boolean(property.ui.onTable.isSortable); const columnWidth = type === ePropType.Boolean ? 150 : 250; - const valueResolver = - type === ePropType.Enum + const valueResolver: PropCallback> = + type === ePropType.Enum && property.type ? createEnumValueResolver(property.type, enums[property.type], propName) : createExtraPropertyValueResolver(propName); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts index 68ac0212ff..00c01f630e 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/breadcrumb/breadcrumb.component.ts @@ -1,4 +1,11 @@ -import { ABP, getRoutePath, RouterEvents, RoutesService, SubscriptionService, TreeNode } from '@abp/ng.core'; +import { + ABP, + getRoutePath, + RouterEvents, + RoutesService, + SubscriptionService, + TreeNode, +} from '@abp/ng.core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { map, startWith } from 'rxjs/operators'; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts index 53e09d9788..13c857901c 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/confirmation/confirmation.component.ts @@ -15,7 +15,7 @@ export class ConfirmationComponent { reject = Confirmation.Status.reject; dismiss = Confirmation.Status.dismiss; - confirmation$!: ReplaySubject; + confirmation$!: ReplaySubject; clear!: (status: Confirmation.Status) => void; @@ -30,7 +30,10 @@ export class ConfirmationComponent { if (!this.icons) { return ''; } - return this.icons[severity] || this.icons.default; + if (severity) { + return this.icons[severity]; + } + return this.icons.default; } isCustomIconExists({ options }: Confirmation.DialogData): boolean { diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/password/password.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/password/password.component.ts index 74020240a1..22fcd6e4f5 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/password/password.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/password/password.component.ts @@ -4,7 +4,7 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms'; @Component({ selector: 'abp-password', - templateUrl: `password.component.html`, + templateUrl: `./password.component.html`, providers: [ { provide: NG_VALUE_ACCESSOR, @@ -16,7 +16,7 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms'; export class PasswordComponent extends AbstractNgModelComponent { @Input() inputId!: string; @Input() formControlName!: string; - fieldTextType: boolean; + fieldTextType?: boolean; constructor(injector: Injector) { super(injector); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts b/npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts index 2c3d904a1b..e1048f907e 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/services/abstract-menu.service.ts @@ -1,8 +1,9 @@ import { BehaviorSubject, Observable } from 'rxjs'; import { NavItem } from '../models/nav-item'; +import { Type } from '@angular/core'; export abstract class AbstractMenuService { - protected abstract baseClass; + protected abstract baseClass: Type; protected _items$ = new BehaviorSubject([]); diff --git a/npm/ng-packs/packages/theme-shared/src/lib/services/confirmation.service.ts b/npm/ng-packs/packages/theme-shared/src/lib/services/confirmation.service.ts index f93e850aaf..5eeadb0ab6 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/services/confirmation.service.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/services/confirmation.service.ts @@ -8,7 +8,7 @@ import { Confirmation } from '../models/confirmation'; @Injectable({ providedIn: 'root' }) export class ConfirmationService { status$!: Subject; - confirmation$ = new ReplaySubject(1); + confirmation$ = new ReplaySubject(1); private containerComponentRef!: ComponentRef; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tokens/confirmation-icons.token.ts b/npm/ng-packs/packages/theme-shared/src/lib/tokens/confirmation-icons.token.ts index 0c001cd9d6..6c1ed5b0b5 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tokens/confirmation-icons.token.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tokens/confirmation-icons.token.ts @@ -6,6 +6,7 @@ export interface ConfirmationIcons { warning: string; error: string; default: string; + neutral: string; } export const CONFIRMATION_ICONS = new InjectionToken>( @@ -18,4 +19,5 @@ export const DEFAULT_CONFIRMATION_ICONS: ConfirmationIcons = { warning: 'fa fa-exclamation-triangle', error: 'fa fa-times-circle', default: 'fa fa-question-circle', + neutral: '', }; diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyCompanyName.MyProjectName.Blazor.Server.Mongo.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyCompanyName.MyProjectName.Blazor.Server.Mongo.csproj index b4fd6c7094..bbb8813a90 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyCompanyName.MyProjectName.Blazor.Server.Mongo.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyCompanyName.MyProjectName.Blazor.Server.Mongo.csproj @@ -22,8 +22,8 @@ - - + + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj index c3227aa6c3..693086af4a 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj @@ -22,8 +22,8 @@ - - + + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Client/MyCompanyName.MyProjectName.Blazor.WebAssembly.Client.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Client/MyCompanyName.MyProjectName.Blazor.WebAssembly.Client.csproj index 3f0f414cb0..e4da30cdac 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Client/MyCompanyName.MyProjectName.Blazor.WebAssembly.Client.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Client/MyCompanyName.MyProjectName.Blazor.WebAssembly.Client.csproj @@ -21,7 +21,7 @@ - + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.Mongo.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.Mongo.csproj index 52340a8fb0..8b697fb90c 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.Mongo.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.Mongo.csproj @@ -74,7 +74,7 @@ - + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.csproj index 8616201990..d3a1aab92c 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.csproj @@ -75,7 +75,7 @@ - + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyCompanyName.MyProjectName.Host.Mongo.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyCompanyName.MyProjectName.Host.Mongo.csproj index fa770434b3..cdf830d530 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyCompanyName.MyProjectName.Host.Mongo.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyCompanyName.MyProjectName.Host.Mongo.csproj @@ -70,7 +70,7 @@ - + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj index a096c8ea16..803061603c 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj @@ -71,7 +71,7 @@ - + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyCompanyName.MyProjectName.Mvc.Mongo.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyCompanyName.MyProjectName.Mvc.Mongo.csproj index 81bf1b0dd7..15198564eb 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyCompanyName.MyProjectName.Mvc.Mongo.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyCompanyName.MyProjectName.Mvc.Mongo.csproj @@ -18,7 +18,7 @@ - + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.Mvc.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.Mvc.csproj index bc58acbef5..c80b4393f0 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.Mvc.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.Mvc.csproj @@ -18,7 +18,7 @@ - + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyCompanyName.MyProjectName.AuthServer.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyCompanyName.MyProjectName.AuthServer.csproj index 8d0222ec73..1706fe3360 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyCompanyName.MyProjectName.AuthServer.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyCompanyName.MyProjectName.AuthServer.csproj @@ -44,7 +44,7 @@ - + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyCompanyName.MyProjectName.Blazor.Server.Tiered.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyCompanyName.MyProjectName.Blazor.Server.Tiered.csproj index 2f4ce2c095..3b1ded08fa 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyCompanyName.MyProjectName.Blazor.Server.Tiered.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyCompanyName.MyProjectName.Blazor.Server.Tiered.csproj @@ -30,8 +30,8 @@ - - + + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj index 547486df33..7d8740c809 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj @@ -28,8 +28,8 @@ - - + + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj index 05e9fa2b48..d0384eb228 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj @@ -24,7 +24,7 @@ - + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyCompanyName.MyProjectName.HttpApi.HostWithIds.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyCompanyName.MyProjectName.HttpApi.HostWithIds.csproj index 64e5518d56..bf03c7337f 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyCompanyName.MyProjectName.HttpApi.HostWithIds.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyCompanyName.MyProjectName.HttpApi.HostWithIds.csproj @@ -26,7 +26,7 @@ - + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj index 23de5c2132..96b5b31394 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj @@ -28,7 +28,7 @@ - + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj index 1629ad48c7..5424096c0f 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj @@ -42,7 +42,7 @@ - +