Browse Source

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

pull/3970/head
Alper Ebicoglu 6 years ago
parent
commit
46300a0d1c
  1. 4
      README.md
  2. 165
      docs/en/UI/Angular/List-Service.md
  3. 6
      docs/en/UI/Angular/Track-By-Service.md
  4. 4
      docs/en/docs-nav.json
  5. 25
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyAttributeDto.cs
  6. 16
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JQueryFormScriptContributor.cs
  7. 13
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JsTreeOptions.cs
  8. 26
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JsTreeStyleContributor.cs
  9. 22
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs
  10. 95
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyAttributeDtoFactory.cs
  11. 0
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ICachedObjectExtensionsDtoService.cs
  12. 9
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/IExtensionPropertyAttributeDtoFactory.cs
  13. 4
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertyModelBinder.cs
  14. 36
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtendingPropertyInfoExtensions.cs
  15. 13
      framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs
  16. 8
      framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs
  17. 28
      npm/ng-packs/package.json
  18. 2
      npm/ng-packs/packages/core/package.json
  19. 1
      npm/ng-packs/packages/core/src/lib/services/index.ts
  20. 101
      npm/ng-packs/packages/core/src/lib/services/list.service.ts
  21. 153
      npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts
  22. 1
      npm/ng-packs/packages/core/src/lib/tokens/index.ts
  23. 3
      npm/ng-packs/packages/core/src/lib/tokens/list.token.ts
  24. 2
      npm/ng-packs/packages/setting-management/src/lib/setting-management-routing.module.ts
  25. 5
      npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.scss
  26. 63
      npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts
  27. 141
      npm/ng-packs/yarn.lock
  28. 5
      npm/packs/jstree/abp.resourcemapping.js
  29. 12
      npm/packs/jstree/package.json
  30. 16
      templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs

4
README.md

@ -1,9 +1,9 @@
# ABP # ABP
[![Build Status](http://vjenkins.dynu.net:5480/job/abp/badge/icon)](http://ci.volosoft.com:5480/blue/organizations/jenkins/abp/activity) [![Build & Test](https://github.com/abpframework/abp/workflows/Main/badge.svg)](https://github.com/abpframework/abp/actions?query=workflow%3AMain)
[![NuGet](https://img.shields.io/nuget/v/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) [![NuGet](https://img.shields.io/nuget/v/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core)
[![NuGet Download](https://img.shields.io/nuget/dt/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core)
[![MyGet (with prereleases)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds) [![MyGet (with prereleases)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds)
[![NuGet Download](https://img.shields.io/nuget/dt/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core)
This project is the next generation of the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) web application framework. See [the announcement](https://blog.abp.io/abp/Abp-vNext-Announcement). This project is the next generation of the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) web application framework. See [the announcement](https://blog.abp.io/abp/Abp-vNext-Announcement).

165
docs/en/UI/Angular/List-Service.md

@ -0,0 +1,165 @@
# Querying Lists Easily with ListService
`ListService` is a utility service to provide an easy pagination, sorting, and search implementation.
## Getting Started
`ListService` is **not provided in root**. The reason is, this way, it will clear any subscriptions on component destroy. You may use the optional `LIST_QUERY_DEBOUNCE_TIME` token to adjust the debounce behavior.
```js
import { ListService } from '@abp/ng.core';
import { BookDto } from '../models';
import { BookService } from '../services';
@Component({
/* class metadata here */
providers: [
// [Required]
ListService,
// [Optional]
// Provide this token if you want a different debounce time.
// Default is 300. Cannot be 0. Any value below 100 is not recommended.
{ provide: LIST_QUERY_DEBOUNCE_TIME, useValue: 500 },
],
template: `
`,
})
class BookComponent {
items: BookDto[] = [];
count = 0;
constructor(
public readonly list: ListService,
private bookService: BookService,
) {}
ngOnInit() {
// A function that gets query and returns an observable
const bookStreamCreator = query => this.bookService.getList(query);
this.list.hookToQuery(bookStreamCreator).subscribe(
response => {
this.items = response.items;
this.count = response.count;
// If you use OnPush change detection strategy,
// call detectChanges method of ChangeDetectorRef here.
}
); // Subscription is auto-cleared on destroy.
}
}
```
> Noticed `list` is `public` and `readonly`? That is because we will use `ListService` properties directly in the component's template. That may be considered as an anti-pattern, but it is much quicker to implement. You can always use public component properties instead.
Place `ListService` properties into the template like this:
```html
<abp-table
[value]="book.items"
[(page)]="list.page"
[rows]="list.maxResultCount"
[totalRecords]="book.totalCount"
[headerTemplate]="tableHeader"
[bodyTemplate]="tableBody"
[abpLoading]="list.isLoading$ | async"
>
</abp-table>
<ng-template #tableHeader>
<tr>
<th (click)="nameSort.sort('name')">
{%{{{ '::Name' | abpLocalization }}}%}
<abp-sort-order-icon
#nameSort
sortKey="name"
[(selectedSortKey)]="list.sortKey"
[(order)]="list.sortOrder"
></abp-sort-order-icon>
</th>
</tr>
</ng-template>
<ng-template #tableBody let-data>
<tr>
<td>{%{{{ data.name }}}%}</td>
</tr>
</ng-template>
```
## Usage with Observables
You may use observables in combination with [AsyncPipe](https://angular.io/guide/observables-in-angular#async-pipe) of Angular instead. Here are some possibilities:
```ts
book$ = this.list.hookToQuery(query => this.bookService.getListByInput(query));
```
```html
<!-- simplified representation of the template -->
<abp-table
[value]="(book$ | async)?.items || []"
[totalRecords]="(book$ | async)?.totalCount"
>
</abp-table>
<!-- DO NOT WORRY, ONLY ONE REQUEST WILL BE MADE -->
```
...or...
```ts
@Select(BookState.getBooks)
books$: Observable<BookDto[]>;
@Select(BookState.getBookCount)
bookCount$: Observable<number>;
ngOnInit() {
this.list.hookToQuery((query) => this.store.dispatch(new GetBooks(query))).subscribe();
}
```
```html
<!-- simplified representation of the template -->
<abp-table
[value]="books$ | async"
[totalRecords]="bookCount$ | async"
>
</abp-table>
```
## How to Refresh Table on Create/Update/Delete
`ListService` exposes a `get` method to trigger a request with the current query. So, basically, whenever a create, update, or delete action resolves, you can call `this.list.get();` and it will call hooked stream creator again.
```ts
this.store.dispatch(new DeleteBook(id)).subscribe(this.list.get);
```
...or...
```ts
this.bookService.createByInput(form.value)
.subscribe(() => {
this.list.get();
// Other subscription logic here
})
```
## How to Implement Server-Side Search in a Table
`ListService` exposes a `filter` property that will trigger a request with the current query and the given search string. All you need to do is to bind it to an input element with two-way binding.
```html
<!-- simplified representation -->
<input type="text" name="search" [(ngModel)]="list.filter">
```

6
docs/en/UI/Angular/Track-By-Service.md

@ -111,3 +111,9 @@ class DemoComponent {
trackByTenantAccountId = trackByDeep<Item>('tenant', 'account', 'id'); trackByTenantAccountId = trackByDeep<Item>('tenant', 'account', 'id');
} }
``` ```
## What's Next?
- [ListService](./List-Service.md)

4
docs/en/docs-nav.json

@ -383,6 +383,10 @@
{ {
"text": "TrackByService", "text": "TrackByService",
"path": "UI/Angular/Track-By-Service.md" "path": "UI/Angular/Track-By-Service.md"
},
{
"text": "ListService",
"path": "UI/Angular/List-Service.md"
} }
] ]
}, },

25
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyAttributeDto.cs

@ -1,36 +1,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Reflection;
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending
{ {
[Serializable] [Serializable]
public class ExtensionPropertyAttributeDto public class ExtensionPropertyAttributeDto
{ {
public string Type { get; set; }
public string TypeSimple { get; set; } public string TypeSimple { get; set; }
public Dictionary<string, object> Configuration { get; set; }
public static ExtensionPropertyAttributeDto Create(Attribute attribute) public Dictionary<string, object> Config { get; set; }
{
var attributeType = attribute.GetType();
var dto = new ExtensionPropertyAttributeDto
{
Type = TypeHelper.GetFullNameHandlingNullableAndGenerics(attributeType),
TypeSimple = TypeHelper.GetSimplifiedName(attributeType),
Configuration = new Dictionary<string, object>()
};
if (attribute is StringLengthAttribute stringLengthAttribute)
{
dto.Configuration["MaximumLength"] = stringLengthAttribute.MaximumLength;
dto.Configuration["MinimumLength"] = stringLengthAttribute.MinimumLength;
}
//TODO: Others!
return dto;
}
} }
} }

16
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JQueryFormScriptContributor.cs

@ -0,0 +1,16 @@
using System.Collections.Generic;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.JsTree
{
[DependsOn(typeof(JQueryScriptContributor))]
public class JsTreeScriptContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/libs/jstree/jstree.min.js");
}
}
}

13
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JsTreeOptions.cs

@ -0,0 +1,13 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.JsTree
{
public class JsTreeOptions
{
/// <summary>
/// Path of the style file for the JsTree library.
/// Setting to null ignores the style file.
///
/// Default value: "/libs/jstree/themes/default/style.min.css".
/// </summary>
public string StylePath { get; set; } = "/libs/jstree/themes/default/style.min.css";
}
}

26
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/JsTree/JsTreeStyleContributor.cs

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.JsTree
{
public class JsTreeStyleContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
var options = context
.ServiceProvider
.GetRequiredService<IOptions<JsTreeOptions>>()
.Value;
if (options.StylePath.IsNullOrEmpty())
{
return;
}
context.Files.AddIfNotContains(options.StylePath);
}
}
}

22
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs → framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs

@ -10,23 +10,29 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending
{ {
public class CachedObjectExtensionsDtoService : ICachedObjectExtensionsDtoService, ISingletonDependency public class CachedObjectExtensionsDtoService : ICachedObjectExtensionsDtoService, ISingletonDependency
{ {
private volatile ObjectExtensionsDto _cachedValue; protected IExtensionPropertyAttributeDtoFactory ExtensionPropertyAttributeDtoFactory { get; }
private readonly object _syncLock = new object(); protected volatile ObjectExtensionsDto CachedValue;
protected readonly object SyncLock = new object();
public CachedObjectExtensionsDtoService(IExtensionPropertyAttributeDtoFactory extensionPropertyAttributeDtoFactory)
{
ExtensionPropertyAttributeDtoFactory = extensionPropertyAttributeDtoFactory;
}
public virtual ObjectExtensionsDto Get() public virtual ObjectExtensionsDto Get()
{ {
if (_cachedValue == null) if (CachedValue == null)
{ {
lock (_syncLock) lock (SyncLock)
{ {
if (_cachedValue == null) if (CachedValue == null)
{ {
_cachedValue = GenerateCacheValue(); CachedValue = GenerateCacheValue();
} }
} }
} }
return _cachedValue; return CachedValue;
} }
protected virtual ObjectExtensionsDto GenerateCacheValue() protected virtual ObjectExtensionsDto GenerateCacheValue()
@ -137,7 +143,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending
foreach (var attribute in propertyConfig.Attributes) foreach (var attribute in propertyConfig.Attributes)
{ {
extensionPropertyDto.Attributes.Add( extensionPropertyDto.Attributes.Add(
ExtensionPropertyAttributeDto.Create(attribute) ExtensionPropertyAttributeDtoFactory.Create(attribute)
); );
} }

95
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ExtensionPropertyAttributeDtoFactory.cs

@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Reflection;
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending
{
public class ExtensionPropertyAttributeDtoFactory : IExtensionPropertyAttributeDtoFactory, ITransientDependency
{
public virtual ExtensionPropertyAttributeDto Create(Attribute attribute)
{
return new ExtensionPropertyAttributeDto
{
TypeSimple = GetSimplifiedName(attribute),
Config = CreateConfiguration(attribute)
};
}
protected virtual string GetSimplifiedName(Attribute attribute)
{
return attribute.GetType().Name.ToCamelCase().RemovePostFix("Attribute");
}
protected virtual Dictionary<string, object> CreateConfiguration(Attribute attribute)
{
var configuration = new Dictionary<string, object>();
AddPropertiesToConfiguration(attribute, configuration);
return configuration;
}
protected virtual void AddPropertiesToConfiguration(Attribute attribute, Dictionary<string, object> configuration)
{
var properties = attribute
.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var property in properties)
{
if (IgnoreProperty(attribute, property))
{
continue;
}
var value = GetPropertyValue(attribute, property);
if (value == null)
{
continue;
}
configuration[property.Name.ToCamelCase()] = value;
}
}
protected virtual bool IgnoreProperty(Attribute attribute, PropertyInfo property)
{
if (property.DeclaringType == null ||
property.DeclaringType.IsIn(typeof(ValidationAttribute), typeof(Attribute), typeof(object)))
{
return true;
}
if (property.PropertyType == typeof(DisplayFormatAttribute))
{
return true;
}
return false;
}
protected virtual object GetPropertyValue(Attribute attribute, PropertyInfo property)
{
var value = property.GetValue(attribute);
if (value == null)
{
return null;
}
if (property.PropertyType.IsEnum)
{
return Enum.GetName(property.PropertyType, value);
}
if (property.PropertyType == typeof(Type))
{
return TypeHelper.GetSimplifiedName((Type) value);
}
return value;
}
}
}

0
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ICachedObjectExtensionsDtoService.cs → framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ICachedObjectExtensionsDtoService.cs

9
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/IExtensionPropertyAttributeDtoFactory.cs

@ -0,0 +1,9 @@
using System;
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending
{
public interface IExtensionPropertyAttributeDtoFactory
{
ExtensionPropertyAttributeDto Create(Attribute attribute);
}
}

4
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ModelBinding/AbpExtraPropertyModelBinder.cs

@ -1,7 +1,9 @@
using System; using System;
using System.ComponentModel;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using Volo.Abp.ObjectExtending; using Volo.Abp.ObjectExtending;
using Volo.Abp.Reflection;
namespace Volo.Abp.AspNetCore.Mvc.ModelBinding namespace Volo.Abp.AspNetCore.Mvc.ModelBinding
{ {
@ -59,7 +61,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ModelBinding
return value; return value;
} }
return Convert.ChangeType(value, propertyInfo.Type); return TypeHelper.ConvertFromString(propertyInfo.Type, value);
} }
} }
} }

36
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/ObjectExtending/ObjectExtendingPropertyInfoExtensions.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -6,6 +7,31 @@ namespace Volo.Abp.ObjectExtending
{ {
public static class ObjectExtensionPropertyInfoAspNetCoreMvcExtensions public static class ObjectExtensionPropertyInfoAspNetCoreMvcExtensions
{ {
private static readonly HashSet<Type> NumberTypes = new HashSet<Type> {
typeof(int),
typeof(long),
typeof(byte),
typeof(sbyte),
typeof(short),
typeof(ushort),
typeof(uint),
typeof(long),
typeof(ulong),
typeof(float),
typeof(double),
typeof(int?),
typeof(long?),
typeof(byte?),
typeof(sbyte?),
typeof(short?),
typeof(ushort?),
typeof(uint?),
typeof(long?),
typeof(ulong?),
typeof(float?),
typeof(double?),
};
public static string GetInputType(this ObjectExtensionPropertyInfo propertyInfo) public static string GetInputType(this ObjectExtensionPropertyInfo propertyInfo)
{ {
foreach (var attribute in propertyInfo.Attributes) foreach (var attribute in propertyInfo.Attributes)
@ -79,15 +105,7 @@ namespace Volo.Abp.ObjectExtending
return "datetime-local"; return "datetime-local";
} }
if (type == typeof(int) || if (NumberTypes.Contains(type))
type == typeof(long) ||
type == typeof(byte) ||
type == typeof(sbyte) ||
type == typeof(short) ||
type == typeof(ushort) ||
type == typeof(uint) ||
type == typeof(long) ||
type == typeof(ulong))
{ {
return "number"; return "number";
} }

13
framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using JetBrains.Annotations; using JetBrains.Annotations;
@ -264,5 +265,17 @@ namespace Volo.Abp.Reflection
return type.FullName; return type.FullName;
} }
public static object ConvertFromString<TTargetType>(string value)
{
return ConvertFromString(typeof(TTargetType), value);
}
public static object ConvertFromString(Type targetType, string value)
{
return TypeDescriptor
.GetConverter(targetType)
.ConvertFromString(value);
}
} }
} }

8
framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/TypeHelper_Tests.cs

@ -75,6 +75,14 @@ namespace Volo.Abp.Reflection
TypeHelper.GetDefaultValue(typeof(string)).ShouldBeNull(); TypeHelper.GetDefaultValue(typeof(string)).ShouldBeNull();
} }
[Fact]
public void ConvertFromString()
{
TypeHelper.ConvertFromString<int>("42").ShouldBe(42);
TypeHelper.ConvertFromString<int?>("42").ShouldBe((int?)42);
TypeHelper.ConvertFromString<int?>(null).ShouldBeNull();
}
public class MyDictionary : Dictionary<bool, TypeHelper_Tests> public class MyDictionary : Dictionary<bool, TypeHelper_Tests>
{ {

28
npm/ng-packs/package.json

@ -22,20 +22,20 @@
"generate:changelog": "conventional-changelog -p angular -i CHANGELOG.md -s" "generate:changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
}, },
"devDependencies": { "devDependencies": {
"@abp/ng.account": "~2.6.2", "@abp/ng.account": "~2.7.0",
"@abp/ng.account.config": "~2.6.2", "@abp/ng.account.config": "~2.7.0",
"@abp/ng.core": "^2.6.2", "@abp/ng.core": "^2.7.0",
"@abp/ng.feature-management": "^2.6.2", "@abp/ng.feature-management": "^2.7.0",
"@abp/ng.identity": "~2.6.2", "@abp/ng.identity": "~2.7.0",
"@abp/ng.identity.config": "~2.6.2", "@abp/ng.identity.config": "~2.7.0",
"@abp/ng.permission-management": "^2.6.2", "@abp/ng.permission-management": "~2.7.0",
"@abp/ng.setting-management": "~2.6.2", "@abp/ng.setting-management": "~2.7.0",
"@abp/ng.setting-management.config": "~2.6.2", "@abp/ng.setting-management.config": "~2.7.0",
"@abp/ng.tenant-management": "~2.6.2", "@abp/ng.tenant-management": "~2.7.0",
"@abp/ng.tenant-management.config": "~2.6.2", "@abp/ng.tenant-management.config": "~2.7.0",
"@abp/ng.theme.basic": "~2.6.2", "@abp/ng.theme.basic": "~2.7.0",
"@abp/ng.theme.shared": "^2.6.2", "@abp/ng.theme.shared": "^2.7.0",
"@abp/utils": "^2.6.0", "@abp/utils": "^2.7.0",
"@angular-builders/jest": "^8.2.0", "@angular-builders/jest": "^8.2.0",
"@angular-devkit/build-angular": "~0.803.21", "@angular-devkit/build-angular": "~0.803.21",
"@angular-devkit/build-ng-packagr": "~0.803.21", "@angular-devkit/build-ng-packagr": "~0.803.21",

2
npm/ng-packs/packages/core/package.json

@ -7,7 +7,7 @@
"url": "https://github.com/abpframework/abp.git" "url": "https://github.com/abpframework/abp.git"
}, },
"dependencies": { "dependencies": {
"@abp/utils": "^2.6.0", "@abp/utils": "^2.7.0",
"@angular/localize": "~9.1.0", "@angular/localize": "~9.1.0",
"@ngxs/router-plugin": "^3.6.2", "@ngxs/router-plugin": "^3.6.2",
"@ngxs/storage-plugin": "^3.6.2", "@ngxs/storage-plugin": "^3.6.2",

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

@ -4,6 +4,7 @@ export * from './config-state.service';
export * from './content-projection.service'; export * from './content-projection.service';
export * from './dom-insertion.service'; export * from './dom-insertion.service';
export * from './lazy-load.service'; export * from './lazy-load.service';
export * from './list.service';
export * from './localization.service'; export * from './localization.service';
export * from './profile-state.service'; export * from './profile-state.service';
export * from './profile.service'; export * from './profile.service';

101
npm/ng-packs/packages/core/src/lib/services/list.service.ts

@ -0,0 +1,101 @@
import { Inject, Injectable, OnDestroy, Optional } from '@angular/core';
import { BehaviorSubject, Observable, ReplaySubject } from 'rxjs';
import { debounceTime, shareReplay, switchMap, tap } from 'rxjs/operators';
import { ABP } from '../models/common';
import { PagedResultDto } from '../models/dtos';
import { LIST_QUERY_DEBOUNCE_TIME } from '../tokens/list.token';
import { takeUntilDestroy } from '../utils/rxjs-utils';
@Injectable()
export class ListService implements OnDestroy {
private _filter = '';
set filter(value: string) {
this._filter = value;
this.get();
}
get filter(): string {
return this._filter;
}
private _maxResultCount = 10;
set maxResultCount(value: number) {
this._maxResultCount = value;
this.get();
}
get maxResultCount(): number {
return this._maxResultCount;
}
private _page = 1;
set page(value: number) {
this._page = value;
this.get();
}
get page(): number {
return this._page;
}
private _sortKey = '';
set sortKey(value: string) {
this._sortKey = value;
this.get();
}
get sortKey(): string {
return this._sortKey;
}
private _sortOrder = '';
set sortOrder(value: string) {
this._sortOrder = value;
this.get();
}
get sortOrder(): string {
return this._sortOrder;
}
private _query$ = new ReplaySubject<ABP.PageQueryParams>(1);
get query$(): Observable<ABP.PageQueryParams> {
return this._query$
.asObservable()
.pipe(debounceTime(this.delay || 300), shareReplay({ bufferSize: 1, refCount: true }));
}
private _isLoading$ = new BehaviorSubject(false);
get isLoading$(): Observable<boolean> {
return this._isLoading$.asObservable();
}
get = () => {
this._query$.next({
filter: this._filter || undefined,
maxResultCount: this._maxResultCount,
skipCount: (this._page - 1) * this._maxResultCount,
sorting: this._sortOrder ? `${this._sortKey} ${this._sortOrder}` : undefined,
});
};
constructor(@Optional() @Inject(LIST_QUERY_DEBOUNCE_TIME) private delay: number) {
this.get();
}
hookToQuery<T extends any>(
streamCreatorCallback: QueryStreamCreatorCallback<T>,
): Observable<PagedResultDto<T>> {
this._isLoading$.next(true);
return this.query$.pipe(
switchMap(streamCreatorCallback),
tap(() => this._isLoading$.next(false)),
shareReplay({ bufferSize: 1, refCount: true }),
takeUntilDestroy(this),
);
}
ngOnDestroy() {}
}
export type QueryStreamCreatorCallback<T> = (
query: ABP.PageQueryParams,
) => Observable<PagedResultDto<T>>;

153
npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts

@ -0,0 +1,153 @@
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { of } from 'rxjs';
import { bufferCount, take } from 'rxjs/operators';
import { ABP } from '../models';
import { ListService, QueryStreamCreatorCallback } from '../services/list.service';
import { LIST_QUERY_DEBOUNCE_TIME } from '../tokens';
describe('ListService', () => {
let spectator: SpectatorService<ListService>;
let service: ListService;
const createService = createServiceFactory({
service: ListService,
providers: [
{
provide: LIST_QUERY_DEBOUNCE_TIME,
useValue: 0,
},
],
});
beforeEach(() => {
spectator = createService();
service = spectator.service;
});
describe('#filter', () => {
it('should initially be empty string', () => {
expect(service.filter).toBe('');
});
it('should be changed', () => {
service.filter = 'foo';
expect(service.filter).toBe('foo');
});
});
describe('#maxResultCount', () => {
it('should initially be 10', () => {
expect(service.maxResultCount).toBe(10);
});
it('should be changed', () => {
service.maxResultCount = 20;
expect(service.maxResultCount).toBe(20);
});
});
describe('#page', () => {
it('should initially be 1', () => {
expect(service.page).toBe(1);
});
it('should be changed', () => {
service.page = 9;
expect(service.page).toBe(9);
});
});
describe('#sortKey', () => {
it('should initially be empty string', () => {
expect(service.sortKey).toBe('');
});
it('should be changed', () => {
service.sortKey = 'foo';
expect(service.sortKey).toBe('foo');
});
});
describe('#sortOrder', () => {
it('should initially be empty string', () => {
expect(service.sortOrder).toBe('');
});
it('should be changed', () => {
service.sortOrder = 'foo';
expect(service.sortOrder).toBe('foo');
});
});
describe('#query$', () => {
it('should initially emit default query', done => {
service.query$.pipe(take(1)).subscribe(query => {
expect(query).toEqual({
filter: undefined,
maxResultCount: 10,
skipCount: 0,
sorting: undefined,
});
done();
});
});
it('should emit a query based on params set', done => {
service.filter = 'foo';
service.sortKey = 'bar';
service.sortOrder = 'baz';
service.maxResultCount = 20;
service.page = 9;
service.query$.pipe(take(1)).subscribe(query => {
expect(query).toEqual({
filter: 'foo',
sorting: 'bar baz',
maxResultCount: 20,
skipCount: 160,
});
done();
});
});
});
describe('#hookToQuery', () => {
it('should call given callback with the query', done => {
const callback: QueryStreamCreatorCallback<ABP.PageQueryParams> = query =>
of({ items: [query], totalCount: 1 });
service.hookToQuery(callback).subscribe(({ items: [query] }) => {
expect(query).toEqual({
filter: undefined,
maxResultCount: 10,
skipCount: 0,
sorting: undefined,
});
done();
});
});
it('should emit isLoading as side effect', done => {
const callback: QueryStreamCreatorCallback<ABP.PageQueryParams> = query =>
of({ items: [query], totalCount: 1 });
service.isLoading$.pipe(bufferCount(3)).subscribe(([idle, init, end]) => {
expect(idle).toBe(false);
expect(init).toBe(true);
expect(end).toBe(false);
done();
});
service.hookToQuery(callback).subscribe();
});
});
});

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

@ -1 +1,2 @@
export * from './list.token';
export * from './options.token'; export * from './options.token';

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

@ -0,0 +1,3 @@
import { InjectionToken } from '@angular/core';
export const LIST_QUERY_DEBOUNCE_TIME = new InjectionToken<number>('LIST_QUERY_DEBOUNCE_TIME');

2
npm/ng-packs/packages/setting-management/src/lib/setting-management-routing.module.ts

@ -2,6 +2,7 @@ import {
DynamicLayoutComponent, DynamicLayoutComponent,
ReplaceableComponents, ReplaceableComponents,
ReplaceableRouteContainerComponent, ReplaceableRouteContainerComponent,
AuthGuard,
} from '@abp/ng.core'; } from '@abp/ng.core';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
@ -12,6 +13,7 @@ const routes: Routes = [
{ {
path: '', path: '',
component: DynamicLayoutComponent, component: DynamicLayoutComponent,
canActivate: [AuthGuard],
children: [ children: [
{ {
path: '', path: '',

5
npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.scss

@ -16,6 +16,9 @@
left: 0; left: 0;
position: fixed; position: fixed;
top: 0; top: 0;
transition: width 0.4s ease;
&.progressing {
transition: width 0.4s ease;
}
} }
} }

63
npm/ng-packs/packages/theme-shared/src/lib/components/loader-bar/loader-bar.component.ts

@ -3,7 +3,7 @@ import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular
import { NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router'; import { NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router';
import { takeUntilDestroy } from '@ngx-validate/core'; import { takeUntilDestroy } from '@ngx-validate/core';
import { Actions, ofActionSuccessful } from '@ngxs/store'; import { Actions, ofActionSuccessful } from '@ngxs/store';
import { interval, Subscription, timer } from 'rxjs'; import { Subscription, timer } from 'rxjs';
import { filter } from 'rxjs/operators'; import { filter } from 'rxjs/operators';
@Component({ @Component({
@ -12,6 +12,7 @@ import { filter } from 'rxjs/operators';
<div id="abp-loader-bar" [ngClass]="containerClass" [class.is-loading]="isLoading"> <div id="abp-loader-bar" [ngClass]="containerClass" [class.is-loading]="isLoading">
<div <div
class="abp-progress" class="abp-progress"
[class.progressing]="progressLevel"
[style.width.vw]="progressLevel" [style.width.vw]="progressLevel"
[ngStyle]="{ [ngStyle]="{
'background-color': color, 'background-color': color,
@ -29,6 +30,10 @@ export class LoaderBarComponent implements OnDestroy, OnInit {
@Input() @Input()
color = '#77b6ff'; color = '#77b6ff';
@Input()
filter = (action: StartLoader | StopLoader) =>
action.payload.url.indexOf('openid-configuration') < 0;
@Input() @Input()
isLoading = false; isLoading = false;
@ -40,11 +45,25 @@ export class LoaderBarComponent implements OnDestroy, OnInit {
intervalPeriod = 350; intervalPeriod = 350;
stopDelay = 820; stopDelay = 800;
@Input() private readonly clearProgress = () => {
filter = (action: StartLoader | StopLoader) => this.progressLevel = 0;
action.payload.url.indexOf('openid-configuration') < 0; this.cdRef.detectChanges();
};
private readonly reportProgress = () => {
if (this.progressLevel < 75) {
this.progressLevel += 1 + Math.random() * 9;
} else if (this.progressLevel < 90) {
this.progressLevel += 0.4;
} else if (this.progressLevel < 100) {
this.progressLevel += 0.1;
} else {
this.interval.unsubscribe();
}
this.cdRef.detectChanges();
};
get boxShadow(): string { get boxShadow(): string {
return `0 0 10px rgba(${this.color}, 0.5)`; return `0 0 10px rgba(${this.color}, 0.5)`;
@ -52,7 +71,7 @@ export class LoaderBarComponent implements OnDestroy, OnInit {
constructor(private actions: Actions, private router: Router, private cdRef: ChangeDetectorRef) {} constructor(private actions: Actions, private router: Router, private cdRef: ChangeDetectorRef) {}
ngOnInit() { private subscribeToLoadActions() {
this.actions this.actions
.pipe( .pipe(
ofActionSuccessful(StartLoader, StopLoader), ofActionSuccessful(StartLoader, StopLoader),
@ -63,7 +82,9 @@ export class LoaderBarComponent implements OnDestroy, OnInit {
if (action instanceof StartLoader) this.startLoading(); if (action instanceof StartLoader) this.startLoading();
else this.stopLoading(); else this.stopLoading();
}); });
}
private subscribeToRouterEvents() {
this.router.events this.router.events
.pipe( .pipe(
filter( filter(
@ -80,37 +101,31 @@ export class LoaderBarComponent implements OnDestroy, OnInit {
}); });
} }
ngOnInit() {
this.subscribeToLoadActions();
this.subscribeToRouterEvents();
}
ngOnDestroy() { ngOnDestroy() {
if (this.interval) this.interval.unsubscribe(); if (this.interval) this.interval.unsubscribe();
} }
startLoading() { startLoading() {
if (this.isLoading || this.progressLevel !== 0) return; if (this.isLoading || (this.interval && !this.interval.closed)) return;
this.isLoading = true; this.isLoading = true;
this.interval = interval(this.intervalPeriod).subscribe(() => {
if (this.progressLevel < 75) { this.interval = timer(0, this.intervalPeriod).subscribe(this.reportProgress);
this.progressLevel += Math.random() * 10;
} else if (this.progressLevel < 90) {
this.progressLevel += 0.4;
} else if (this.progressLevel < 100) {
this.progressLevel += 0.1;
} else {
this.interval.unsubscribe();
}
this.cdRef.detectChanges();
});
} }
stopLoading() { stopLoading() {
if (this.interval) this.interval.unsubscribe(); if (this.interval) this.interval.unsubscribe();
this.progressLevel = 100; this.progressLevel = 100;
this.isLoading = false; this.isLoading = false;
if (this.timer && !this.timer.closed) return; if (this.timer && !this.timer.closed) return;
this.timer = timer(this.stopDelay).subscribe(() => { this.timer = timer(this.stopDelay).subscribe(this.clearProgress);
this.progressLevel = 0;
this.cdRef.detectChanges();
});
} }
} }

141
npm/ng-packs/yarn.lock

@ -2,26 +2,26 @@
# yarn lockfile v1 # yarn lockfile v1
"@abp/ng.account.config@^2.6.2", "@abp/ng.account.config@~2.6.2": "@abp/ng.account.config@^2.7.0", "@abp/ng.account.config@~2.7.0":
version "2.6.2" version "2.7.0"
resolved "https://registry.yarnpkg.com/@abp/ng.account.config/-/ng.account.config-2.6.2.tgz#1a3e935b7144525c62f5d08adcd06d2ee12f7c9e" resolved "https://registry.yarnpkg.com/@abp/ng.account.config/-/ng.account.config-2.7.0.tgz#ebd8ccb988668b29017f6e2338f5f72993c93af9"
integrity sha512-dC0/H1dkeQqYbu/dNISQA7NLpdOughhZSxT/7zjq6cBP8gYDceW0wYT5Rh0qIAkYWh2jO4BMXIFqzlH31Jg/XA== integrity sha512-46bCayLnErut8naJORSbht0bfAKRRwsvBc4n6mj1oMKasjxVJC6Qc7P0QgnmuvSC3UZRexc2K9CeC+zLg1E7xQ==
dependencies: dependencies:
tslib "^1.9.0" tslib "^1.9.0"
"@abp/ng.account@~2.6.2": "@abp/ng.account@~2.7.0":
version "2.6.2" version "2.7.0"
resolved "https://registry.yarnpkg.com/@abp/ng.account/-/ng.account-2.6.2.tgz#aac921c49bcd8cdec506bd27d2546193416ea187" resolved "https://registry.yarnpkg.com/@abp/ng.account/-/ng.account-2.7.0.tgz#f211fe8b7aa85c2744ab194189f9b00c601b5b3f"
integrity sha512-s3gLSqNdCW6D+DvuML+aGFT8braCfSXUbxvJ1WRCovd2Ec0jNxPBKj84zgYPYEb3smD294DcXxNx36jtJK+1OA== integrity sha512-C8hlhE2K0dPyHoQlgahPbnK/DefVFTDsdIpzbODywHfKZQN5RcRhESejVE2B0dEzLEXmvDwIMg0rQFt4GV/QEg==
dependencies: dependencies:
"@abp/ng.account.config" "^2.6.2" "@abp/ng.account.config" "^2.7.0"
"@abp/ng.theme.shared" "^2.6.2" "@abp/ng.theme.shared" "^2.7.0"
tslib "^1.9.0" tslib "^1.9.0"
"@abp/ng.core@^2.6.2": "@abp/ng.core@^2.7.0":
version "2.6.2" version "2.7.0"
resolved "https://registry.yarnpkg.com/@abp/ng.core/-/ng.core-2.6.2.tgz#d0e4f6666a9a207fc7425001449bea2cdfe93522" resolved "https://registry.yarnpkg.com/@abp/ng.core/-/ng.core-2.7.0.tgz#1a681deeeca02bcf3bd2722429d1d8d5e5cacc4f"
integrity sha512-e7c82d9VF20d4JFUkyzT5iTqGKnkq5FBHdv6IW6lsVyuz2Zf/p4wNtKATRr2ntM7qNIjIQebtGNFyxxX4nmL+w== integrity sha512-ODy5r1kYcQngR2tHtvauYS5BxT9MhNfOFnEg/1qDuGh90aca6WVRlTTfeeU4/DRbvRVRLnwr/k6fQiwOr+NyAQ==
dependencies: dependencies:
"@abp/utils" "^2.6.0" "@abp/utils" "^2.6.0"
"@angular/localize" "~9.1.0" "@angular/localize" "~9.1.0"
@ -35,86 +35,86 @@
ts-toolbelt "^6.3.6" ts-toolbelt "^6.3.6"
tslib "^1.9.0" tslib "^1.9.0"
"@abp/ng.feature-management@^2.6.2": "@abp/ng.feature-management@^2.7.0":
version "2.6.2" version "2.7.0"
resolved "https://registry.yarnpkg.com/@abp/ng.feature-management/-/ng.feature-management-2.6.2.tgz#da09b07ebe81f09ccf338a7c10c384920375567a" resolved "https://registry.yarnpkg.com/@abp/ng.feature-management/-/ng.feature-management-2.7.0.tgz#a0ebc00ea3fd13e5727bef8c2de503cdbda10c7c"
integrity sha512-JdHuAZk9j9AR1iKU02Xoux40ULOccm+68q7/4L2G1cBET6yTAE8Ua9RPPX9HadmCG0cR8awl3d+5JPwyL3OjFA== integrity sha512-NyoZaBvfeAYvt8PJGekuwC8c0Tv9Yt4nrHT9fOt+P7pWYjoT+q3Q9OZWd6IBpi7o6UVnzk4r1CYZ5rX7kUT3iQ==
dependencies: dependencies:
"@abp/ng.theme.shared" "^2.6.2" "@abp/ng.theme.shared" "^2.7.0"
tslib "^1.9.0" tslib "^1.9.0"
"@abp/ng.identity.config@^2.6.2", "@abp/ng.identity.config@~2.6.2": "@abp/ng.identity.config@^2.7.0", "@abp/ng.identity.config@~2.7.0":
version "2.6.2" version "2.7.0"
resolved "https://registry.yarnpkg.com/@abp/ng.identity.config/-/ng.identity.config-2.6.2.tgz#79384ae4b11e53e8bf9dda25d3400def05c5beb8" resolved "https://registry.yarnpkg.com/@abp/ng.identity.config/-/ng.identity.config-2.7.0.tgz#8ec7c86d586a6ea632bd984f87063194a6098d07"
integrity sha512-jCqt2ZWEkRA9foJjHwRJtw5JNy03OVge9dUj0eAJ7Vo13IrKAT1kCNlD7cRM9xJ42Ga2utEqqz9FCJHgR2IxbQ== integrity sha512-MV3erK39rLMDs+Y29p103k5Pci6MVGcVlgdg29QwBVDzvTKY8NpxP9KTGjqwCHyha8B3lVo39ZqDgJNqOvYhzg==
dependencies: dependencies:
tslib "^1.9.0" tslib "^1.9.0"
"@abp/ng.identity@~2.6.2": "@abp/ng.identity@~2.7.0":
version "2.6.2" version "2.7.0"
resolved "https://registry.yarnpkg.com/@abp/ng.identity/-/ng.identity-2.6.2.tgz#14f83305415d27b67d01405e582978682cfd7f22" resolved "https://registry.yarnpkg.com/@abp/ng.identity/-/ng.identity-2.7.0.tgz#f036d523bec04078fe718af3c460eab3893297ab"
integrity sha512-wzR/QFoSSRhIxfH91QsTSCc0rBsFfsg8aiP5xPheNx3/lZygCnMogH3blRgLiNIoyxuG00MTfp+e9lFIBfDnbQ== integrity sha512-QDrNiUyrLfOA7iDTG7oMcCLpe9CmkhGMKA0fTcxHkwSl39xeED+bd9iGfnVIDiqRFxnp3jQHBhSwaM/Gkh8gnQ==
dependencies: dependencies:
"@abp/ng.identity.config" "^2.6.2" "@abp/ng.identity.config" "^2.7.0"
"@abp/ng.permission-management" "^2.6.2" "@abp/ng.permission-management" "^2.7.0"
"@abp/ng.theme.shared" "^2.6.2" "@abp/ng.theme.shared" "^2.7.0"
tslib "^1.9.0" tslib "^1.9.0"
"@abp/ng.permission-management@^2.6.2": "@abp/ng.permission-management@^2.7.0":
version "2.6.2" version "2.7.0"
resolved "https://registry.yarnpkg.com/@abp/ng.permission-management/-/ng.permission-management-2.6.2.tgz#ba7902256acf3e1ff49552983e4d292f670f9ad8" resolved "https://registry.yarnpkg.com/@abp/ng.permission-management/-/ng.permission-management-2.7.0.tgz#a71f8f31c7ff2875ebaa91acddd035df0b703369"
integrity sha512-6NW5BF+5ZFQI8oLEQWCiJS5iF2v3gHLvohrbN84RsPNTc+ZRDte6MbIOGq2CWxM8qXwisLBiR/RWC4ssgfPqEA== integrity sha512-kQ+LOXS6zzeYJzt7mySNK37kP8ZBBvXIljv93OWoHMjd8ZDMhnpinhlojlVK4AAX85ypnTGFs4ZqCUK5ooFkSQ==
dependencies: dependencies:
"@abp/ng.theme.shared" "^2.6.2" "@abp/ng.theme.shared" "^2.7.0"
tslib "^1.9.0" tslib "^1.9.0"
"@abp/ng.setting-management.config@^2.6.2", "@abp/ng.setting-management.config@~2.6.2": "@abp/ng.setting-management.config@^2.7.0", "@abp/ng.setting-management.config@~2.7.0":
version "2.6.2" version "2.7.0"
resolved "https://registry.yarnpkg.com/@abp/ng.setting-management.config/-/ng.setting-management.config-2.6.2.tgz#43e9e4399d65efc1aee6e314469c303ce22145e9" resolved "https://registry.yarnpkg.com/@abp/ng.setting-management.config/-/ng.setting-management.config-2.7.0.tgz#98b68ddab5797920bc52bdfb3a3c5cb7ecdbeaa5"
integrity sha512-3F0vq5nvBTat2q7S0iBfdEsyPuZHJuL3+9z4Voq4Q9rA2T2VIAUMp9aBsfI2s2ycwGbsb7kCOWTKo/2by1b4AA== integrity sha512-KPDLe36ahJpoVrVEOukhJXMpAPe44KoS4F92eamhtuD51rPwHgzRyAvn/JKT88n/7vtZfPGwt9LhjSBWgJ8Mag==
dependencies: dependencies:
tslib "^1.9.0" tslib "^1.9.0"
"@abp/ng.setting-management@~2.6.2": "@abp/ng.setting-management@~2.7.0":
version "2.6.2" version "2.7.0"
resolved "https://registry.yarnpkg.com/@abp/ng.setting-management/-/ng.setting-management-2.6.2.tgz#f49d361ed8412380fdf2173f28b890115748a52b" resolved "https://registry.yarnpkg.com/@abp/ng.setting-management/-/ng.setting-management-2.7.0.tgz#8f0691b5f1ade31fa414891edb675cbaffc30503"
integrity sha512-0VdGa+t8lEZRsUdKL1EHoZei+ZCDMTu4n3UvXvD0OzRJyYPUjHRrMSSOYifuN4gPatluIe0E2I+tO3lQ3/2tjw== integrity sha512-4WUHMtN6wYmqwBAEwAfazrMnUnco9n8G9ryqZbdcfiiQvK6GpraCvWU3VjuWDm4KaUb9B1cR8kORRmJXeBz+3g==
dependencies: dependencies:
"@abp/ng.setting-management.config" "^2.6.2" "@abp/ng.setting-management.config" "^2.7.0"
"@abp/ng.theme.shared" "^2.6.2" "@abp/ng.theme.shared" "^2.7.0"
tslib "^1.9.0" tslib "^1.9.0"
"@abp/ng.tenant-management.config@^2.6.2", "@abp/ng.tenant-management.config@~2.6.2": "@abp/ng.tenant-management.config@^2.7.0", "@abp/ng.tenant-management.config@~2.7.0":
version "2.6.2" version "2.7.0"
resolved "https://registry.yarnpkg.com/@abp/ng.tenant-management.config/-/ng.tenant-management.config-2.6.2.tgz#9a9365ad59bdd2053d7bd33fb623ce633de40b24" resolved "https://registry.yarnpkg.com/@abp/ng.tenant-management.config/-/ng.tenant-management.config-2.7.0.tgz#6c363edb2c8052c5231ac852e94e0c51a35716f8"
integrity sha512-iZ49Els+J9lbRKTSeNU/KIJuJS7Le3dAk1pdqLg/g5iw7e6uTEih1qeDvJdcXpSKfAZJrOd/KKDjFHIzVrveuA== integrity sha512-QTdd3ibreMHPXIvTJIVODGGmtBwv11dsJw4KNisOAo+D8KcmzK81lgBuYAJEaULnbIMaeEtrI5uNlFqGOKisoQ==
dependencies: dependencies:
tslib "^1.9.0" tslib "^1.9.0"
"@abp/ng.tenant-management@~2.6.2": "@abp/ng.tenant-management@~2.7.0":
version "2.6.2" version "2.7.0"
resolved "https://registry.yarnpkg.com/@abp/ng.tenant-management/-/ng.tenant-management-2.6.2.tgz#6be284fe6691946e2e6766e34ae958d7d2ec5e3a" resolved "https://registry.yarnpkg.com/@abp/ng.tenant-management/-/ng.tenant-management-2.7.0.tgz#8c2e1dc7c7249a44edd5c26de9ad90b8b1d50443"
integrity sha512-BGARok01Eqn1kEltOwjwIpMJ8LD0jtYfbSbnO8V9TRg7f4ZEqFmfXudOIluDIwHjSEkNXk+Cs0/iV53lyi5+lg== integrity sha512-Ksi5zCf1pew2kVuF168BvUcbRZXg4avpQs31xnm8gN+7gA2T9hMVOnhqr0fUP+mymjPtQk3w11Db3ZmH3h9A8A==
dependencies: dependencies:
"@abp/ng.feature-management" "^2.6.2" "@abp/ng.feature-management" "^2.7.0"
"@abp/ng.tenant-management.config" "^2.6.2" "@abp/ng.tenant-management.config" "^2.7.0"
"@abp/ng.theme.shared" "^2.6.2" "@abp/ng.theme.shared" "^2.7.0"
tslib "^1.9.0" tslib "^1.9.0"
"@abp/ng.theme.basic@~2.6.2": "@abp/ng.theme.basic@~2.7.0":
version "2.6.2" version "2.7.0"
resolved "https://registry.yarnpkg.com/@abp/ng.theme.basic/-/ng.theme.basic-2.6.2.tgz#4b0414411e164885b8c467b04d635a0a3c81bd01" resolved "https://registry.yarnpkg.com/@abp/ng.theme.basic/-/ng.theme.basic-2.7.0.tgz#8b01f0742582654f5e326357e7e7322e9e237a5c"
integrity sha512-qgA4hh7ipIWY88JOqjChjoJgFB0csqXbwdb/pabrsFoHYuiFVT3cqvHq6jMfKQHEPBJSEnl6/GUIm+26DQ5eDw== integrity sha512-+FTQRAtJW3ZqI1DVgNeZrrIGARVElSZKCmTcx3Vj2cOWg9TzAY2kQAx5U6ByRLYFfHxN9gVRJTcuTUIN3XqYNQ==
dependencies: dependencies:
"@abp/ng.theme.shared" "^2.6.2" "@abp/ng.theme.shared" "^2.7.0"
tslib "^1.9.0" tslib "^1.9.0"
"@abp/ng.theme.shared@^2.6.2": "@abp/ng.theme.shared@^2.7.0":
version "2.6.2" version "2.7.0"
resolved "https://registry.yarnpkg.com/@abp/ng.theme.shared/-/ng.theme.shared-2.6.2.tgz#9d70b7aab010af4cd5a451c9c2d162d73ec5f9cc" resolved "https://registry.yarnpkg.com/@abp/ng.theme.shared/-/ng.theme.shared-2.7.0.tgz#c491497033975e294a83e29ad8d745b52f638967"
integrity sha512-e3QVsPpmbPGmTpQY9J1RgmWer7Tx7mrsOtxjFvbJGqKVF1UUtU5Kc3VyGPb3JsjQtT+890/9qmAf/YSj3cNPIA== integrity sha512-tk4BUm7B86l3liq1noFvDvAlJn98YxUFceQaItLhz73BwzIvlUXieIQXEni6CjXAyEiPHcnCJ4l4EssyFXmmNA==
dependencies: dependencies:
"@abp/ng.core" "^2.6.2" "@abp/ng.core" "^2.7.0"
"@fortawesome/fontawesome-free" "^5.12.1" "@fortawesome/fontawesome-free" "^5.12.1"
"@ng-bootstrap/ng-bootstrap" "^5.3.0" "@ng-bootstrap/ng-bootstrap" "^5.3.0"
"@ngx-validate/core" "^0.0.7" "@ngx-validate/core" "^0.0.7"
@ -2129,14 +2129,7 @@
tree-kill "1.2.2" tree-kill "1.2.2"
webpack-sources "1.4.3" webpack-sources "1.4.3"
"@ngx-validate/core@^0.0.7": "@ngx-validate/core@^0.0.7", "@ngx-validate/core@^0.0.8":
version "0.0.7"
resolved "https://registry.yarnpkg.com/@ngx-validate/core/-/core-0.0.7.tgz#35a4364e8c8bb43ce1731e8d681ce1ab307c5955"
integrity sha512-APT7kstDaJ0JkC6cDkypbVSXAOAEyPTQ9P8DjEI1szi+Xzuz69XLASK3NdTYjFwogWevhYXoYRaR2Bq9iWzl+g==
dependencies:
tslib "^1.9.0"
"@ngx-validate/core@^0.0.8":
version "0.0.8" version "0.0.8"
resolved "https://registry.yarnpkg.com/@ngx-validate/core/-/core-0.0.8.tgz#8577405eb1af0f5002cdda7a86fbcda56280f116" resolved "https://registry.yarnpkg.com/@ngx-validate/core/-/core-0.0.8.tgz#8577405eb1af0f5002cdda7a86fbcda56280f116"
integrity sha512-caIG5ao76Xhf7T+pNA8crnpAwK0yqj3i0OAUGZRUq1W+kNgz+ZnrSd4F9an/W4g+38u/8gfUVvsfsm07ju6qYA== integrity sha512-caIG5ao76Xhf7T+pNA8crnpAwK0yqj3i0OAUGZRUq1W+kNgz+ZnrSd4F9an/W4g+38u/8gfUVvsfsm07ju6qYA==

5
npm/packs/jstree/abp.resourcemapping.js

@ -0,0 +1,5 @@
module.exports = {
mappings: {
"@node_modules/jstree/dist/**/*.*": "@libs/jstree/"
}
}

12
npm/packs/jstree/package.json

@ -0,0 +1,12 @@
{
"version": "2.7.0",
"name": "@abp/jstree",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/jquery": "^2.7.0",
"jstree": "^3.3.9"
},
"gitHead": "0ea3895f3b0b489e3ea81fc88f8f0896b22b61bd"
}

16
templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs

@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Security.Claims;
using IdentityModel; using IdentityModel;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
@ -170,6 +172,20 @@ namespace MyCompanyName.MyProjectName
{ {
app.UseMultiTenancy(); app.UseMultiTenancy();
} }
app.Use(async (ctx, next) =>
{
var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService<ICurrentPrincipalAccessor>();
var map = new Dictionary<string, string>()
{
{ "sub", AbpClaimTypes.UserId },
{ "role", AbpClaimTypes.Role },
{ "email", AbpClaimTypes.Email },
//any other map
};
var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList();
currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer))));
await next();
});
app.UseAuthorization(); app.UseAuthorization();
app.UseAbpRequestLocalization(); app.UseAbpRequestLocalization();
app.UseSwagger(); app.UseSwagger();

Loading…
Cancel
Save