Browse Source

Merge branch 'issue/15467' of https://github.com/abpframework/abp into issue/15467

pull/15585/head
Gizem Mutu Kurt 4 years ago
parent
commit
b540eb1321
  1. 10
      .github/workflows/auto-pr.yml
  2. 8
      docs/en/Themes/LeptonXLite/Angular.md
  3. 27
      docs/en/Tutorials/Todo/Single-Layer/Index.md
  4. 12
      docs/en/UI/Angular/HTTP-Requests.md
  5. 2
      docs/en/UI/Angular/Modal.md
  6. 15
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Security/ApplicationConfigurationChangedService.cs
  7. 20
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs
  8. 2
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs
  9. 12
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularSourceCodeAdder.cs
  10. 2
      framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/Domain/Entities/EntityNotFoundException.cs
  11. 2
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs
  12. 41
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpNullableStringToGuidConverter.cs
  13. 36
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/JsonConverters/AbpStringToGuidConverter.cs
  14. 35
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObjectMapper.cs
  15. 23
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController.cs
  16. 12
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ModelBinding/ModelBindingController_Tests.cs
  17. 85
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpStringToGuid_Tests.cs
  18. 31
      framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions_Tests.cs
  19. 1
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/EntityChange.cs
  20. 1
      modules/audit-logging/test/Volo.Abp.AuditLogging.Tests/Volo/Abp/AuditLogging/MultiTenantAuditLog_Tests.cs
  21. 18
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor.cs
  22. 11
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavToolbar.razor.cs
  23. 15
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Pages/Authentication.razor
  24. 13
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor.cs
  25. 4
      npm/ng-packs/apps/dev-app/src/app/app.module.ts
  26. 30
      npm/ng-packs/packages/core/src/lib/clients/http.client.ts
  27. 1
      npm/ng-packs/packages/core/src/lib/clients/index.ts
  28. 6
      npm/ng-packs/packages/core/src/lib/models/auth.ts
  29. 11
      npm/ng-packs/packages/core/src/lib/providers/include-localization-resources.provider.ts
  30. 2
      npm/ng-packs/packages/core/src/lib/providers/index.ts
  31. 17
      npm/ng-packs/packages/core/src/lib/tests/application-localization.service.spec.ts
  32. 17
      npm/ng-packs/packages/core/src/lib/tests/config-state.service.spec.ts
  33. 2
      npm/ng-packs/packages/core/src/lib/tests/date-utils.spec.ts
  34. 3
      npm/ng-packs/packages/core/src/lib/tests/localization-utils.spec.ts
  35. 9
      npm/ng-packs/packages/core/src/lib/tests/localization.service.spec.ts
  36. 4
      npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts
  37. 3
      npm/ng-packs/packages/core/src/lib/tokens/http-context.token.ts
  38. 6
      npm/ng-packs/packages/core/src/lib/tokens/include-localization-resources.token.ts
  39. 1
      npm/ng-packs/packages/core/src/lib/tokens/index.ts
  40. 3
      npm/ng-packs/packages/core/src/lib/tokens/set-token-response-to-storage.token.ts
  41. 1
      npm/ng-packs/packages/core/src/public-api.ts
  42. 47
      npm/ng-packs/packages/feature-management/proxy/src/lib/proxy/feature-management/features.service.ts
  43. 21
      npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts
  44. 11
      npm/ng-packs/packages/oauth/src/lib/oauth.module.ts
  45. 25
      npm/ng-packs/packages/oauth/src/lib/utils/auth-utils.ts
  46. 18
      npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts
  47. 1
      npm/ng-packs/packages/schematics/src/commands/create-lib/index.ts
  48. 8
      npm/ng-packs/packages/schematics/src/models/model.ts
  49. 2
      npm/ng-packs/packages/schematics/src/utils/angular/generate-from-files.ts
  50. 2
      npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts
  51. 2
      templates/app-nolayers/angular/package.json
  52. 4
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyCompanyName.MyProjectName.Blazor.Server.Mongo.csproj
  53. 4
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj
  54. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyCompanyName.MyProjectName.Host.Mongo.csproj
  55. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj
  56. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyCompanyName.MyProjectName.Mvc.Mongo.csproj
  57. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.Mvc.csproj
  58. 2
      templates/app/angular/package.json
  59. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyCompanyName.MyProjectName.AuthServer.csproj
  60. 4
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyCompanyName.MyProjectName.Blazor.Server.Tiered.csproj
  61. 4
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj
  62. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj
  63. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyCompanyName.MyProjectName.HttpApi.HostWithIds.csproj
  64. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj
  65. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj

10
.github/workflows/auto-pr.yml

@ -1,4 +1,4 @@
name: Merge branch dev with rel-7.0
name: Merge branch rel-7.1 with rel-7.0
on:
push:
branches:
@ -7,7 +7,7 @@ permissions:
contents: read
jobs:
merge-dev-with-rel-6-0:
merge-rel-7-1-with-rel-7-0:
permissions:
contents: write # for peter-evans/create-pull-request to create branch
pull-requests: write # for peter-evans/create-pull-request to create a PR
@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@v2
with:
ref: dev
ref: rel-7.1
- name: Reset promotion branch
run: |
git fetch origin rel-7.0:rel-7.0
@ -24,7 +24,7 @@ jobs:
uses: peter-evans/create-pull-request@v3
with:
branch: auto-merge/rel-7-0/${{github.run_number}}
title: Merge branch dev with rel-7.0
body: This PR generated automatically to merge dev with rel-7.0. Please review the changed files before merging to prevent any errors that may occur.
title: Merge branch rel-7.1 with rel-7.0
body: This PR generated automatically to merge rel-7.1 with rel-7.0. Please review the changed files before merging to prevent any errors that may occur.
reviewers: ${{github.actor}}
token: ${{ github.token }}

8
docs/en/Themes/LeptonXLite/Angular.md

@ -14,11 +14,15 @@ To add `LeptonX-lite` into your project,
- Install `@abp/ng.theme.lepton-x`
`yarn add @abp/ng.theme.lepton-x@preview`
```bash
yarn add @abp/ng.theme.lepton-x
```
- Install `bootstrap-icons`
`yarn add bootstrap-icons`
```bash
yarn add bootstrap-icons
```
- Then, we need to edit the styles array in `angular.json` to replace the existing style with the new one in the following link :

27
docs/en/Tutorials/Todo/Single-Layer/Index.md

@ -14,6 +14,33 @@ This is a single-part quick-start tutorial to build a simple todo application wi
You can find the source code of the completed application [here](https://github.com/abpframework/abp-samples/tree/master/TodoApp-SingleLayer).
This documentation has a video tutorial on **YouTube**!! You can watch it here:
{{if UI=="MVC" && DB =="EF"}}
<iframe width="560" height="315" src="https://www.youtube.com/embed/Z6jZSPB19iw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
{{else if UI=="BlazorServer" && DB=="EF"}}
<iframe width="560" height="315" src="https://www.youtube.com/embed/-ynMYXBIg4Q" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
{{else if UI=="NG" && DB=="EF"}}
<iframe width="560" height="315" src="https://www.youtube.com/embed/Pz4YWsU7CUs" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
{{else if UI=="MVC" && DB=="Mongo"}}
<iframe width="560" height="315" src="https://www.youtube.com/embed/i9oDVl1J7Dk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
{{else if UI=="BlazorServer" && DB=="Mongo"}}
<iframe width="560" height="315" src="https://www.youtube.com/embed/z7YGDjcsTTs" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
{{else if UI=="NG" && DB=="Mongo"}}
<iframe width="560" height="315" src="https://www.youtube.com/embed/LdKlIHi9S8I" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
{{end}}
## Pre-Requirements
* An IDE (e.g. [Visual Studio](https://visualstudio.microsoft.com/vs/)) that supports [.NET 7.0+](https://dotnet.microsoft.com/download/dotnet) development.

12
docs/en/UI/Angular/HTTP-Requests.md

@ -298,3 +298,15 @@ export function handleHttpErrors(injector: Injector, httpError: HttpErrorRespons
return throwError(httpError)
}
```
### How to Skip HTTP interceptors and ABP headers
The ABP Framework adds several HTTP headers to the HttpClient, such as the "Auth token" or "tenant Id".
The ABP Server must possess the information but the ABP user may not want to send this informations to an external server.
ExternalHttpClient and IS EXTERNAL REQUEST HttpContext Token were added in V6.0.4.
The ABP Http interceptors check the value of the `IS_EXTERNAL_REQUEST` token. If the token is True then ABP-specific headers won't be added to Http Request.
The `ExternalHttpClient` extends from `HTTPClient` and sets the `IS_EXTERNAL_REQUEST` context token to true.
When you are using `ExternalHttpClient` as HttpClient in your components, it does not add ABP-specific headers.
Note: With `IS_EXTERNAL_REQUEST` or without it, ABP loading service works.

2
docs/en/UI/Angular/Modal.md

@ -57,7 +57,7 @@ You can add the `abp-modal` to your component very quickly. See an example:
@Component(/* component metadata */)
export class SampleComponent {
isModelOpen = false
isModalOpen = false
}
```

15
framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Security/ApplicationConfigurationChangedService.cs

@ -0,0 +1,15 @@
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Components.Web.Security;
public delegate void ApplicationConfigurationChangedHandler();
public class ApplicationConfigurationChangedService : IScopedDependency
{
public event ApplicationConfigurationChangedHandler Changed;
public void NotifyChanged()
{
Changed?.Invoke();
}
}

20
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs

@ -1,4 +1,6 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Authorization;
using Volo.Abp.AspNetCore.Components.Web.Security;
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ClientProxies;
using Volo.Abp.AspNetCore.Mvc.Client;
@ -10,23 +12,31 @@ namespace Volo.Abp.AspNetCore.Components.WebAssembly;
public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicationConfigurationClient, ITransientDependency
{
protected AbpApplicationConfigurationClientProxy ApplicationConfigurationClientProxy { get; }
protected AbpApplicationLocalizationClientProxy ApplicationLocalizationClientProxy { get; }
protected ApplicationConfigurationCache Cache { get; }
protected ICurrentTenantAccessor CurrentTenantAccessor { get; }
protected ApplicationConfigurationChangedService ApplicationConfigurationChangedService { get; }
protected AuthenticationStateProvider AuthenticationStateProvider { get; }
public WebAssemblyCachedApplicationConfigurationClient(
AbpApplicationConfigurationClientProxy applicationConfigurationClientProxy,
ApplicationConfigurationCache cache,
ICurrentTenantAccessor currentTenantAccessor,
AbpApplicationLocalizationClientProxy applicationLocalizationClientProxy)
ICurrentTenantAccessor currentTenantAccessor,
AbpApplicationLocalizationClientProxy applicationLocalizationClientProxy,
ApplicationConfigurationChangedService applicationConfigurationChangedService,
AuthenticationStateProvider authenticationStateProvider)
{
ApplicationConfigurationClientProxy = applicationConfigurationClientProxy;
Cache = cache;
CurrentTenantAccessor = currentTenantAccessor;
ApplicationLocalizationClientProxy = applicationLocalizationClientProxy;
ApplicationConfigurationChangedService = applicationConfigurationChangedService;
AuthenticationStateProvider = authenticationStateProvider;
}
public virtual async Task InitializeAsync()
@ -45,9 +55,11 @@ public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicatio
);
configurationDto.Localization.Resources = localizationDto.Resources;
Cache.Set(configurationDto);
ApplicationConfigurationChangedService.NotifyChanged();
CurrentTenantAccessor.Current = new BasicTenantInfo(
configurationDto.CurrentTenant.Id,
configurationDto.CurrentTenant.Name

2
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

12
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularSourceCodeAdder.cs

@ -267,11 +267,19 @@ public class AngularSourceCodeAdder : ITransientDependency
var fileContent = File.ReadAllText(filePath);
fileContent = "import { "+moduleName.Split(".").Last()+"Module } from '@"+moduleName.Split(".").Last().ToKebabCase()+"/config';" + Environment.NewLine + fileContent;
var moduleNameAsConfigPath = moduleName.ToKebabCase();
if (moduleName.Contains("."))
{
var moduleNameSplited = moduleName.Split(".");
moduleNameAsConfigPath = moduleNameSplited.Take(moduleNameSplited.Length-1).JoinAsString(".").ToKebabCase() + "/" + moduleNameSplited.Last().ToKebabCase();
}
fileContent = "import { "+moduleName.Split(".").Last()+"ConfigModule } from '@"+moduleNameAsConfigPath+"/config';" + Environment.NewLine + fileContent;
fileContent = Regex.Replace(fileContent, "imports\\s*:\\s*\\[",
"imports: ["+ Environment.NewLine +
" " + moduleName.Split(".").Last() + "Module.forRoot(),");
" " + moduleName.Split(".").Last() + "ConfigModule.forRoot(),");
File.WriteAllText(filePath, fileContent);
}

2
framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/Domain/Entities/EntityNotFoundException.cs

@ -3,7 +3,7 @@
namespace Volo.Abp.Domain.Entities;
/// <summary>
/// This exception is thrown if an entity excepted to be found but not found.
/// This exception is thrown if an entity is expected to be found but not found.
/// </summary>
public class EntityNotFoundException : AbpException
{

2
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

41
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<Guid?>
{
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<Guid?>)_writeJsonSerializerOptions.GetConverter(typeof(Guid?));
entityConverter.Write(writer, value, _writeJsonSerializerOptions);
}
}

36
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<Guid>
{
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<Guid>)_writeJsonSerializerOptions.GetConverter(typeof(Guid));
entityConverter.Write(writer, value, _writeJsonSerializerOptions);
}
}

35
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObjectMapper.cs

@ -11,7 +11,7 @@ public static class ExtensibleObjectMapper
/// <summary>
/// Copies extra properties from the <paramref name="source"/> object
/// to the <paramref name="destination"/> object.
///
///
/// Checks property definitions (over the <see cref="ObjectExtensionManager"/>)
/// based on the <paramref name="definitionChecks"/> preference.
/// </summary>
@ -34,14 +34,29 @@ public static class ExtensibleObjectMapper
Check.NotNull(source, nameof(source));
Check.NotNull(destination, nameof(destination));
ExtensibleObjectMapper.MapExtraPropertiesTo(
typeof(TSource),
typeof(TDestination),
source.ExtraProperties,
destination.ExtraProperties,
definitionChecks,
ignoredProperties
);
var sourceType = typeof(TSource);
var destinationType = typeof(TDestination);
Check.AssignableTo<IHasExtraProperties>(sourceType, nameof(sourceType));
Check.AssignableTo<IHasExtraProperties>(destinationType, nameof(destinationType));
Check.NotNull(source.ExtraProperties, nameof(source.ExtraProperties));
Check.NotNull(destination.ExtraProperties, nameof(destination.ExtraProperties));
var sourceObjectExtension = ObjectExtensionManager.Instance.GetOrNull(sourceType);
var destinationObjectExtension = ObjectExtensionManager.Instance.GetOrNull(destinationType);
foreach (var keyValue in source.ExtraProperties)
{
if (CanMapProperty(
keyValue.Key,
sourceObjectExtension,
destinationObjectExtension,
definitionChecks,
ignoredProperties))
{
destination.SetProperty(keyValue.Key, keyValue.Value);
}
}
}
/// <summary>
@ -80,7 +95,7 @@ public static class ExtensibleObjectMapper
/// <summary>
/// Copies extra properties from the <paramref name="sourceDictionary"/> object
/// to the <paramref name="destinationDictionary"/> object.
///
///
/// Checks property definitions (over the <see cref="ObjectExtensionManager"/>)
/// based on the <paramref name="definitionChecks"/> preference.
/// </summary>

23
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; }
}

12
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

85
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<TestClass>("{" +
$"\"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; }
}
}

31
framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions_Tests.cs

@ -1,6 +1,10 @@
using Shouldly;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Shouldly;
using Volo.Abp.Data;
using Volo.Abp.Localization;
using Volo.Abp.ObjectExtending.TestObjects;
using Volo.Abp.Validation;
using Xunit;
namespace Volo.Abp.ObjectExtending;
@ -90,4 +94,29 @@ public class HasExtraPropertiesObjectExtendingExtensions_Tests : AbpObjectExtend
_personDto.GetProperty<string>("Sex").ShouldBe("male");
_personDto.GetProperty<string>("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values
}
[Fact]
public void MapExtraPropertiesTo_Should_Validate_Properties()
{
using (CultureHelper.Use(CultureInfo.InvariantCulture))
{
ObjectExtensionManager.Instance
.AddOrUpdateProperty<ExtensibleTestPersonDto, string>(
"Name",
options =>
{
options.Attributes.Add(new StringLengthAttribute(4));
});
var person = new ExtensibleTestPerson().SetProperty("Name", "John");
var personDto = new ExtensibleTestPersonDto();
person.MapExtraPropertiesTo(personDto);
person.SetProperty("Name", "John Bush");
Assert.Throws<AbpValidationException>(() => person.MapExtraPropertiesTo(personDto)).ValidationErrors.ShouldContain(x => x.ErrorMessage == "The field Name must be a string with a maximum length of 4.");
}
}
}

1
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/EntityChange.cs

@ -46,6 +46,7 @@ public class EntityChange : Entity<Guid>, IMultiTenant, IHasExtraProperties
TenantId = tenantId;
ChangeTime = entityChangeInfo.ChangeTime;
ChangeType = entityChangeInfo.ChangeType;
EntityTenantId = entityChangeInfo.EntityTenantId;
EntityId = entityChangeInfo.EntityId.Truncate(EntityChangeConsts.MaxEntityTypeFullNameLength);
EntityTypeFullName = entityChangeInfo.EntityTypeFullName.TruncateFromBeginning(EntityChangeConsts.MaxEntityTypeFullNameLength);

1
modules/audit-logging/test/Volo.Abp.AuditLogging.Tests/Volo/Abp/AuditLogging/MultiTenantAuditLog_Tests.cs

@ -71,5 +71,6 @@ public class MultiTenantAuditLog_Tests : AuditLogsTestBase
auditLog.EntityChanges.Count.ShouldBe(2);
auditLog.EntityChanges.ShouldContain(e => e.EntityId == entityId1.ToString());
auditLog.EntityChanges.ShouldContain(e => e.EntityId == entityId2.ToString());
auditLog.EntityChanges.ShouldContain(e => e.EntityTenantId == tenantId);
}
}

18
modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavMenu.razor.cs

@ -1,7 +1,9 @@
using System;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Volo.Abp.AspNetCore.Components.Web.Security;
using Volo.Abp.UI.Navigation;
namespace Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic;
@ -12,24 +14,24 @@ public partial class NavMenu : IDisposable
protected IMenuManager MenuManager { get; set; }
[Inject]
protected AuthenticationStateProvider AuthenticationStateProvider { get; set; }
protected ApplicationConfigurationChangedService ApplicationConfigurationChangedService { get; set; }
protected ApplicationMenu Menu { get; set; }
protected override async Task OnInitializedAsync()
protected async override Task OnInitializedAsync()
{
Menu = await MenuManager.GetMainMenuAsync();
AuthenticationStateProvider.AuthenticationStateChanged += AuthenticationStateProviderOnAuthenticationStateChanged;
ApplicationConfigurationChangedService.Changed += ApplicationConfigurationChanged;
}
public void Dispose()
private async void ApplicationConfigurationChanged()
{
AuthenticationStateProvider.AuthenticationStateChanged -= AuthenticationStateProviderOnAuthenticationStateChanged;
Menu = await MenuManager.GetMainMenuAsync();
await InvokeAsync(StateHasChanged);
}
private async void AuthenticationStateProviderOnAuthenticationStateChanged(Task<AuthenticationState> task)
public void Dispose()
{
Menu = await MenuManager.GetMainMenuAsync();
await InvokeAsync(StateHasChanged);
ApplicationConfigurationChangedService.Changed -= ApplicationConfigurationChanged;
}
}

11
modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/NavToolbar.razor.cs

@ -4,6 +4,7 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Volo.Abp.AspNetCore.Components.Web.Security;
using Volo.Abp.AspNetCore.Components.Web.Theming.Toolbars;
namespace Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic;
@ -14,14 +15,14 @@ public partial class NavToolbar : IDisposable
private IToolbarManager ToolbarManager { get; set; }
[Inject]
private AuthenticationStateProvider AuthenticationStateProvider { get; set; }
protected ApplicationConfigurationChangedService ApplicationConfigurationChangedService { get; set; }
private List<RenderFragment> ToolbarItemRenders { get; set; } = new List<RenderFragment>();
protected override async Task OnInitializedAsync()
protected async override Task OnInitializedAsync()
{
await GetToolbarItemRendersAsync();
AuthenticationStateProvider.AuthenticationStateChanged += AuthenticationStateProviderOnAuthenticationStateChanged;
ApplicationConfigurationChangedService.Changed += ApplicationConfigurationChanged;
}
private async Task GetToolbarItemRendersAsync()
@ -41,7 +42,7 @@ public partial class NavToolbar : IDisposable
}
}
private async void AuthenticationStateProviderOnAuthenticationStateChanged(Task<AuthenticationState> task)
private async void ApplicationConfigurationChanged()
{
await GetToolbarItemRendersAsync();
await InvokeAsync(StateHasChanged);
@ -49,6 +50,6 @@ public partial class NavToolbar : IDisposable
public void Dispose()
{
AuthenticationStateProvider.AuthenticationStateChanged -= AuthenticationStateProviderOnAuthenticationStateChanged;
ApplicationConfigurationChangedService.Changed -= ApplicationConfigurationChanged;
}
}

15
modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Pages/Authentication.razor

@ -1,7 +1,18 @@
@page "/authentication/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="@Action" />
@using Volo.Abp.AspNetCore.Components.Web.Security
<RemoteAuthenticatorView Action="@Action" OnLogInSucceeded="OnLogInSucceeded" OnLogOutSucceeded="OnLogOutSucceeded" />
@inject WebAssemblyCachedApplicationConfigurationClient WebAssemblyCachedApplicationConfigurationClient
@code{
[Parameter] public string Action { get; set; }
private async Task OnLogInSucceeded(RemoteAuthenticationState state)
{
await WebAssemblyCachedApplicationConfigurationClient.InitializeAsync();
}
private async Task OnLogOutSucceeded(RemoteAuthenticationState state)
{
await WebAssemblyCachedApplicationConfigurationClient.InitializeAsync();
}
}

13
modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor.cs

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.JSInterop;
using Volo.Abp.AspNetCore.Components.Web.Security;
using Volo.Abp.UI.Navigation;
namespace Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic;
@ -16,18 +17,17 @@ public partial class LoginDisplay : IDisposable
protected IMenuManager MenuManager { get; set; }
[Inject]
public AuthenticationStateProvider AuthenticationStateProvider { get; set; }
protected ApplicationConfigurationChangedService ApplicationConfigurationChangedService { get; set; }
protected ApplicationMenu Menu { get; set; }
protected override async Task OnInitializedAsync()
protected async override Task OnInitializedAsync()
{
Menu = await MenuManager.GetAsync(StandardMenus.User);
Navigation.LocationChanged += OnLocationChanged;
AuthenticationStateProvider.AuthenticationStateChanged +=
AuthenticationStateProviderOnAuthenticationStateChanged;
ApplicationConfigurationChangedService.Changed += ApplicationConfigurationChanged;
}
protected virtual void OnLocationChanged(object sender, LocationChangedEventArgs e)
@ -35,7 +35,7 @@ public partial class LoginDisplay : IDisposable
InvokeAsync(StateHasChanged);
}
private async void AuthenticationStateProviderOnAuthenticationStateChanged(Task<AuthenticationState> task)
private async void ApplicationConfigurationChanged()
{
Menu = await MenuManager.GetAsync(StandardMenus.User);
await InvokeAsync(StateHasChanged);
@ -44,8 +44,7 @@ public partial class LoginDisplay : IDisposable
public void Dispose()
{
Navigation.LocationChanged -= OnLocationChanged;
AuthenticationStateProvider.AuthenticationStateChanged -=
AuthenticationStateProviderOnAuthenticationStateChanged;
ApplicationConfigurationChangedService.Changed -= ApplicationConfigurationChanged;
}
private async Task NavigateToAsync(string uri, string target = null)

4
npm/ng-packs/apps/dev-app/src/app/app.module.ts

@ -14,7 +14,7 @@ import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { APP_ROUTE_PROVIDER } from './route.provider';
import { FeatureManagementModule } from '@abp/ng.feature-management';
// import { AbpOAuthModule } from '@abp/ng.oauth';
import { AbpOAuthModule } from '@abp/ng.oauth';
@NgModule({
imports: [
@ -27,7 +27,7 @@ import { FeatureManagementModule } from '@abp/ng.feature-management';
sendNullsAsQueryParam: false,
skipGetAppConfiguration: false,
}),
// AbpOAuthModule.forRoot(),
AbpOAuthModule.forRoot(),
ThemeSharedModule.forRoot(),
AccountConfigModule.forRoot(),
IdentityConfigModule.forRoot(),

30
npm/ng-packs/packages/core/src/lib/clients/http.client.ts

@ -0,0 +1,30 @@
import { HttpClient, HttpContext, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { IS_EXTERNAL_REQUEST } from '../tokens/http-context.token';
// source : https://github.com/armanozak/demo-angular-server-specific-interceptors
@Injectable({
providedIn: 'root',
})
export class ExternalHttpClient extends HttpClient {
override request(
first: string | HttpRequest<any>,
url?: string,
options: RequestOptions = {},
): Observable<any> {
if (typeof first === 'string') {
this.#setPlaceholderContext(options);
return super.request(first, url, options);
}
this.#setPlaceholderContext(first);
return super.request(first);
}
#setPlaceholderContext(optionsOrRequest: { context?: HttpContext }) {
optionsOrRequest.context ??= new HttpContext();
optionsOrRequest.context.set(IS_EXTERNAL_REQUEST, true);
}
}
type RequestOptions = Parameters<HttpClient['request']>[2];

1
npm/ng-packs/packages/core/src/lib/clients/index.ts

@ -0,0 +1 @@
export * from './http.client';

6
npm/ng-packs/packages/core/src/lib/models/auth.ts

@ -12,6 +12,8 @@ export type PipeToLoginFn = (
params: Pick<LoginParams, 'redirectUrl' | 'rememberMe'>,
injector: Injector,
) => UnaryFunction<any, any>;
export type SetTokenResponseToStorageFn<T = any> = (injector: Injector, tokenRes: T) => void;
/**
* @deprecated The interface should not be used anymore.
*/
export type SetTokenResponseToStorageFn<T = any> = (tokenRes: T) => void;
export type CheckAuthenticationStateFn = (injector: Injector) => void;

11
npm/ng-packs/packages/core/src/lib/providers/include-localization-resources.provider.ts

@ -1,8 +1,7 @@
import { Provider } from "@angular/core";
import { INCUDE_LOCALIZATION_RESOURCES_TOKEN } from "../tokens/include-localization-resources.token";
import { Provider } from '@angular/core';
import { INCUDE_LOCALIZATION_RESOURCES_TOKEN } from '../tokens/include-localization-resources.token';
export const IncludeLocalizationResourcesProvider: Provider = {
provide: INCUDE_LOCALIZATION_RESOURCES_TOKEN,
useValue: false,
};
provide: INCUDE_LOCALIZATION_RESOURCES_TOKEN,
useValue: false,
};

2
npm/ng-packs/packages/core/src/lib/providers/index.ts

@ -1,3 +1,3 @@
export * from './cookie-language.provider';
export * from './locale.provider';
export * from './include-localization-resources.provider';
export * from './include-localization-resources.provider';

17
npm/ng-packs/packages/core/src/lib/tests/application-localization.service.spec.ts

@ -0,0 +1,17 @@
export const APPLICATION_LOCALIZATION_DATA = {
resources: {
Default: { texts: {}, baseResources: [] },
MyProjectName: {
texts: {
"'{0}' and '{1}' do not match.": "'{0}' and '{1}' do not match.",
},
baseResources: [],
},
AbpIdentity: {
texts: {
Identity: 'identity',
},
baseResources: [],
},
},
};

17
npm/ng-packs/packages/core/src/lib/tests/config-state.service.spec.ts

@ -8,6 +8,9 @@ import {
} from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/models';
import { ConfigStateService } from '../services';
import { CORE_OPTIONS } from '../tokens';
import { IncludeLocalizationResourcesProvider } from '../providers';
import { APPLICATION_LOCALIZATION_DATA } from './application-localization.service.spec';
import { AbpApplicationLocalizationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-localization.service';
export const CONFIG_STATE_DATA = {
environment: {
@ -34,14 +37,7 @@ export const CONFIG_STATE_DATA = {
layouts: [null, null, null],
},
localization: {
values: {
MyProjectName: {
"'{0}' and '{1}' do not match.": "'{0}' and '{1}' do not match.",
},
AbpIdentity: {
Identity: 'identity',
},
},
values: {},
languages: [
{
cultureName: 'cs',
@ -115,6 +111,11 @@ describe('ConfigStateService', () => {
provide: AbpApplicationConfigurationService,
useValue: { get: () => of(CONFIG_STATE_DATA) },
},
{
provide: AbpApplicationLocalizationService,
useValue: { get: () => APPLICATION_LOCALIZATION_DATA },
},
IncludeLocalizationResourcesProvider,
],
});

2
npm/ng-packs/packages/core/src/lib/tests/date-utils.spec.ts

@ -15,7 +15,7 @@ describe('Date Utils', () => {
let config: ConfigStateService;
beforeEach(() => {
config = new ConfigStateService(null);
config = new ConfigStateService(null, null, null);
});
describe('#getShortDateFormat', () => {

3
npm/ng-packs/packages/core/src/lib/tests/localization-utils.spec.ts

@ -57,6 +57,7 @@ describe('Localization Utils', () => {
languages: [],
languageFilesMap: null,
languagesMap: null,
resources: {},
});
test.each`
@ -100,6 +101,7 @@ describe('Localization Utils', () => {
languages: [],
languageFilesMap: null,
languagesMap: null,
resources: {},
});
test.each`
@ -148,6 +150,7 @@ describe('Localization Utils', () => {
languages: [],
languageFilesMap: null,
languagesMap: null,
resources: {},
});
test.each`

9
npm/ng-packs/packages/core/src/lib/tests/localization.service.spec.ts

@ -8,8 +8,12 @@ import { SessionStateService } from '../services/session-state.service';
import { LocalizationService } from '../services/localization.service';
import { CORE_OPTIONS } from '../tokens/options.token';
import { CONFIG_STATE_DATA } from './config-state.service.spec';
import { AbpApplicationLocalizationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-localization.service';
import { APPLICATION_LOCALIZATION_DATA } from './application-localization.service.spec';
import { IncludeLocalizationResourcesProvider } from '../providers';
const appConfigData$ = new BehaviorSubject(CONFIG_STATE_DATA);
const appLocalizationData$ = new BehaviorSubject(APPLICATION_LOCALIZATION_DATA);
describe('LocalizationService', () => {
let spectator: SpectatorService<LocalizationService>;
@ -22,6 +26,7 @@ describe('LocalizationService', () => {
entryComponents: [],
mocks: [Router],
providers: [
IncludeLocalizationResourcesProvider,
{
provide: CORE_OPTIONS,
useValue: { registerLocaleFn: () => Promise.resolve(), cultureNameLocaleFileMap: {} },
@ -30,6 +35,10 @@ describe('LocalizationService', () => {
provide: AbpApplicationConfigurationService,
useValue: { get: () => appConfigData$ },
},
{
provide: AbpApplicationLocalizationService,
useValue: { get: () => appLocalizationData$ },
},
],
});

4
npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts

@ -9,6 +9,7 @@ import { HttpErrorReporterService } from '../services/http-error-reporter.servic
import { PermissionService } from '../services/permission.service';
import { RoutesService } from '../services/routes.service';
import { CORE_OPTIONS } from '../tokens/options.token';
import { IncludeLocalizationResourcesProvider } from '../providers';
describe('PermissionGuard', () => {
let spectator: SpectatorService<PermissionGuard>;
@ -36,7 +37,7 @@ describe('PermissionGuard', () => {
},
},
],
{ relativeLinkResolution: 'legacy' },
{},
),
],
providers: [
@ -45,6 +46,7 @@ describe('PermissionGuard', () => {
useValue: '/',
},
{ provide: CORE_OPTIONS, useValue: { skipGetAppConfiguration: true } },
IncludeLocalizationResourcesProvider,
],
});

3
npm/ng-packs/packages/core/src/lib/tokens/http-context.token.ts

@ -0,0 +1,3 @@
import { HttpContextToken } from '@angular/common/http';
export const IS_EXTERNAL_REQUEST = new HttpContextToken<boolean>(() => false);

6
npm/ng-packs/packages/core/src/lib/tokens/include-localization-resources.token.ts

@ -1,3 +1,5 @@
import { InjectionToken } from "@angular/core";
import { InjectionToken } from '@angular/core';
export const INCUDE_LOCALIZATION_RESOURCES_TOKEN = new InjectionToken<boolean>('INCUDE_LOCALIZATION_RESOURCES_TOKEN');
export const INCUDE_LOCALIZATION_RESOURCES_TOKEN = new InjectionToken<boolean>(
'INCUDE_LOCALIZATION_RESOURCES_TOKEN',
);

1
npm/ng-packs/packages/core/src/lib/tokens/index.ts

@ -11,3 +11,4 @@ export * from './include-localization-resources.token';
export * from './pipe-to-login.token';
export * from './set-token-response-to-storage.token';
export * from './check-authentication-state';
export * from './http-context.token';

3
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<SetTokenResponseToStorageFn>(
'SET_TOKEN_RESPONSE_TO_STORAGE_FN_KEY',
);

1
npm/ng-packs/packages/core/src/public-api.ts

@ -23,3 +23,4 @@ export * from './lib/tokens';
export * from './lib/utils';
export * from './lib/validators';
export * from './lib/interceptors';
export * from './lib/clients';

47
npm/ng-packs/packages/feature-management/proxy/src/lib/proxy/feature-management/features.service.ts

@ -7,34 +7,37 @@ import { Injectable } from '@angular/core';
})
export class FeaturesService {
apiName = 'AbpFeatureManagement';
delete = (providerName: string, providerKey: string) =>
this.restService.request<any, void>({
method: 'DELETE',
url: '/api/feature-management/features',
params: { providerName, providerKey },
},
{ apiName: this.apiName });
this.restService.request<any, void>(
{
method: 'DELETE',
url: '/api/feature-management/features',
params: { providerName, providerKey },
},
{ apiName: this.apiName },
);
get = (providerName: string, providerKey: string) =>
this.restService.request<any, GetFeatureListResultDto>({
method: 'GET',
url: '/api/feature-management/features',
params: { providerName, providerKey },
},
{ apiName: this.apiName });
this.restService.request<any, GetFeatureListResultDto>(
{
method: 'GET',
url: '/api/feature-management/features',
params: { providerName, providerKey },
},
{ apiName: this.apiName },
);
update = (providerName: string, providerKey: string, input: UpdateFeaturesDto) =>
this.restService.request<any, void>({
method: 'PUT',
url: '/api/feature-management/features',
params: { providerName, providerKey },
body: input,
},
{ apiName: this.apiName });
this.restService.request<any, void>(
{
method: 'PUT',
url: '/api/feature-management/features',
params: { providerName, providerKey },
body: input,
},
{ apiName: this.apiName },
);
constructor(private restService: RestService) {}
}

21
npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts

@ -2,7 +2,13 @@ import { HttpHandler, HttpHeaders, HttpRequest } from '@angular/common/http';
import { Inject, Injectable } from '@angular/core';
import { OAuthService } from 'angular-oauth2-oidc';
import { finalize } from 'rxjs/operators';
import { SessionStateService, HttpWaitService, TENANT_KEY, IApiInterceptor } from '@abp/ng.core';
import {
SessionStateService,
HttpWaitService,
TENANT_KEY,
IApiInterceptor,
IS_EXTERNAL_REQUEST,
} from '@abp/ng.core';
@Injectable({
providedIn: 'root',
@ -17,12 +23,15 @@ export class OAuthApiInterceptor implements IApiInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler) {
this.httpWaitService.addRequest(request);
return next
.handle(
request.clone({
const isExternalRequest = request.context?.get(IS_EXTERNAL_REQUEST);
const newRequest = isExternalRequest
? request
: request.clone({
setHeaders: this.getAdditionalHeaders(request.headers),
}),
)
});
return next
.handle(newRequest)
.pipe(finalize(() => this.httpWaitService.deleteRequest(request)));
}

11
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 } 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,

25
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,29 +29,6 @@ export const pipeToLogin: PipeToLoginFn = function (
);
};
export const setTokenResponseToStorage: SetTokenResponseToStorageFn<TokenResponse> = 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) {
removeRememberMe();
localStorage.setItem(storageKey, 'true');

18
npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts

@ -1,13 +1,13 @@
import { ConfigStateService, CurrentUserDto } from "@abp/ng.core";
import { ConfigStateService, CurrentUserDto } from '@abp/ng.core';
import {
GetPermissionListResultDto,
PermissionGrantInfoDto,
PermissionGroupDto,
PermissionsService,
ProviderInfoDto,
UpdatePermissionDto
} from "@abp/ng.permission-management/proxy";
import { LocaleDirection } from "@abp/ng.theme.shared";
UpdatePermissionDto,
} from '@abp/ng.permission-management/proxy';
import { LocaleDirection } from '@abp/ng.theme.shared';
import {
Component,
ElementRef,
@ -16,11 +16,11 @@ import {
Output,
QueryList,
TrackByFunction,
ViewChildren
} from "@angular/core";
import { concat, of } from "rxjs";
import { finalize, switchMap, take, tap } from "rxjs/operators";
import { PermissionManagement } from "../models/permission-management";
ViewChildren,
} from '@angular/core';
import { concat, of } from 'rxjs';
import { finalize, switchMap, take, tap } from 'rxjs/operators';
import { PermissionManagement } from '../models/permission-management';
type PermissionWithStyle = PermissionGrantInfoDto & {
style: string;

1
npm/ng-packs/packages/schematics/src/commands/create-lib/index.ts

@ -246,4 +246,3 @@ export function addRoutingToAppRoutingModule(workspace: WorkspaceDefinition, pac
return;
};
}

8
npm/ng-packs/packages/schematics/src/models/model.ts

@ -45,9 +45,13 @@ abstract class TypeRef {
get default() {
return this._default;
}
set default(value: string) {
set default(value: any) {
if (!value) return;
this._default = ` = ${value}`;
if (typeof value === 'string') {
this._default = ` = "${value}"`;
} else {
this._default = ` = ${value}`;
}
}
constructor(options: TypeRefOptions) {

2
npm/ng-packs/packages/schematics/src/utils/angular/generate-from-files.ts

@ -48,7 +48,7 @@ export function generateFromFiles(
validateClassName(strings.classify(options.name));
const templateSource = apply(url('./files'), [
options.skipTests ? filter((path) => !path.endsWith('.spec.ts.template')) : noop(),
options.skipTests ? filter(path => !path.endsWith('.spec.ts.template')) : noop(),
applyTemplates({
...strings,
...options,

2
npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts

@ -78,7 +78,7 @@ export class ThemeBasicModule {
},
{
provide: VALIDATION_TARGET_SELECTOR,
useValue: '*:has(> .form-control)',
useValue: '.form-group',
},
{
provide: VALIDATION_INVALID_CLASSES,

2
templates/app-nolayers/angular/package.json

@ -20,7 +20,7 @@
"@abp/ng.setting-management": "~7.0.1",
"@abp/ng.tenant-management": "~7.0.1",
"@abp/ng.theme.shared": "~7.0.1",
"@abp/ng.theme.lepton-x": "~2.0.0-rc.4",
"@abp/ng.theme.lepton-x": "~2.0.2",
"@angular/animations": "^15.0.1",
"@angular/common": "^15.0.1",
"@angular/compiler": "^15.0.1",

4
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyCompanyName.MyProjectName.Blazor.Server.Mongo.csproj

@ -21,8 +21,8 @@
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Components.Server.Theming\Volo.Abp.AspNetCore.Components.Server.Theming.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Components.Web.Theming\Volo.Abp.AspNetCore.Components.Web.Theming.csproj" />
<!-- </TEMPLATE-REMOVE> -->
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.*" />
<PackageReference Include="Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme" Version="2.0.*" />
</ItemGroup>
<ItemGroup>

4
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj

@ -21,8 +21,8 @@
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Components.Server.Theming\Volo.Abp.AspNetCore.Components.Server.Theming.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Components.Web.Theming\Volo.Abp.AspNetCore.Components.Web.Theming.csproj" />
<!-- </TEMPLATE-REMOVE> -->
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.*" />
<PackageReference Include="Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme" Version="2.0.*" />
</ItemGroup>
<ItemGroup>

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyCompanyName.MyProjectName.Host.Mongo.csproj

@ -69,7 +69,7 @@
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<!-- </TEMPLATE-REMOVE> -->
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.*" />
</ItemGroup>
<ItemGroup>

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj

@ -70,7 +70,7 @@
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<!-- </TEMPLATE-REMOVE> -->
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.*" />
</ItemGroup>
<ItemGroup>

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyCompanyName.MyProjectName.Mvc.Mongo.csproj

@ -17,7 +17,7 @@
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<!-- </TEMPLATE-REMOVE> -->
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.*" />
</ItemGroup>
<ItemGroup>

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.Mvc.csproj

@ -17,7 +17,7 @@
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<!-- </TEMPLATE-REMOVE> -->
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.*" />
</ItemGroup>
<ItemGroup>

2
templates/app/angular/package.json

@ -20,7 +20,7 @@
"@abp/ng.setting-management": "~7.0.1",
"@abp/ng.tenant-management": "~7.0.1",
"@abp/ng.theme.shared": "~7.0.1",
"@abp/ng.theme.lepton-x": "~2.0.0-rc.4",
"@abp/ng.theme.lepton-x": "~2.0.2",
"@angular/animations": "^15.0.1",
"@angular/common": "^15.0.1",
"@angular/compiler": "^15.0.1",

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyCompanyName.MyProjectName.AuthServer.csproj

@ -43,7 +43,7 @@
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj" />
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<!-- </TEMPLATE-REMOVE> -->
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.*" />
</ItemGroup>
<ItemGroup>

4
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyCompanyName.MyProjectName.Blazor.Server.Tiered.csproj

@ -29,8 +29,8 @@
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.AspNetCore.Components.Server.Theming\Volo.Abp.AspNetCore.Components.Server.Theming.csproj" />
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.AspNetCore.Components.Web.Theming\Volo.Abp.AspNetCore.Components.Web.Theming.csproj" />
<!-- </TEMPLATE-REMOVE> -->
<PackageReference Include="Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme" Version="2.0.*" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.*" />
</ItemGroup>
<ItemGroup>

4
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj

@ -27,8 +27,8 @@
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.AspNetCore.Components.Server.Theming\Volo.Abp.AspNetCore.Components.Server.Theming.csproj" />
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.AspNetCore.Components.Web.Theming\Volo.Abp.AspNetCore.Components.Web.Theming.csproj" />
<!-- </TEMPLATE-REMOVE> -->
<PackageReference Include="Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme" Version="2.0.*" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.*" />
</ItemGroup>
<ItemGroup>

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj

@ -23,7 +23,7 @@
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.Http.Client.IdentityModel.WebAssembly\Volo.Abp.Http.Client.IdentityModel.WebAssembly.csproj" />
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.AspNetCore.Components.Web.Theming\Volo.Abp.AspNetCore.Components.Web.Theming.csproj" />
<!-- </TEMPLATE-REMOVE> -->
<PackageReference Include="Volo.Abp.AspNetCore.Components.WebAssembly.LeptonXLiteTheme" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Components.WebAssembly.LeptonXLiteTheme" Version="2.0.*" />
</ItemGroup>
<ItemGroup>

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyCompanyName.MyProjectName.HttpApi.HostWithIds.csproj

@ -25,7 +25,7 @@
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj" />
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<!-- </TEMPLATE-REMOVE> -->
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.*" />
</ItemGroup>
<ItemGroup>

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj

@ -27,7 +27,7 @@
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj" />
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<!-- </TEMPLATE-REMOVE> -->
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.*" />
</ItemGroup>
<ItemGroup>

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj

@ -41,7 +41,7 @@
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared\Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.csproj" />
<ProjectReference Include="..\..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<!-- </TEMPLATE-REMOVE> -->
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.0-*" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.*" />
</ItemGroup>
<ItemGroup>

Loading…
Cancel
Save