Browse Source

Merge remote-tracking branch 'abpframework/dev' into docs

pull/3547/head
liangshiwei 6 years ago
parent
commit
15da30dd55
  1. 2
      common.props
  2. 2
      docs/en/Customizing-Application-Modules-Extending-Entities.md
  3. 99
      docs/en/Customizing-Application-Modules-Overriding-Services.md
  4. 30
      docs/en/UI/Angular/Component-Replacement.md
  5. 101
      docs/en/UI/Angular/Container-Strategy.md
  6. 78
      docs/en/UI/Angular/Content-Projection-Service.md
  7. 117
      docs/en/UI/Angular/Context-Strategy.md
  8. 14
      docs/en/UI/Angular/Dom-Insertion-Service.md
  9. 1
      docs/en/UI/Angular/Dom-Strategy.md
  10. 2
      docs/en/UI/Angular/Loading-Strategy.md
  11. 200
      docs/en/UI/Angular/Projection-Strategy.md
  12. 4
      docs/en/docs-nav.json
  13. 5
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Timeago/TimeagoScriptContributor.cs
  14. 2
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs
  15. 2
      npm/lerna.json
  16. 4
      npm/ng-packs/.vscode/settings.json
  17. 2
      npm/ng-packs/lerna.version.json
  18. 26
      npm/ng-packs/package.json
  19. 2
      npm/ng-packs/packages/account-config/package.json
  20. 6
      npm/ng-packs/packages/account/package.json
  21. 7
      npm/ng-packs/packages/account/src/lib/account-routing.module.ts
  22. 4
      npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.html
  23. 3
      npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.ts
  24. 2
      npm/ng-packs/packages/account/src/lib/components/login/login.component.html
  25. 3
      npm/ng-packs/packages/account/src/lib/components/login/login.component.ts
  26. 4
      npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.html
  27. 5
      npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts
  28. 2
      npm/ng-packs/packages/account/src/lib/components/register/register.component.html
  29. 3
      npm/ng-packs/packages/account/src/lib/components/register/register.component.ts
  30. 9
      npm/ng-packs/packages/account/src/lib/enums/components.ts
  31. 1
      npm/ng-packs/packages/account/src/public-api.ts
  32. 2
      npm/ng-packs/packages/core/package.json
  33. 1
      npm/ng-packs/packages/core/src/lib/models/index.ts
  34. 4
      npm/ng-packs/packages/core/src/lib/models/utility.ts
  35. 14
      npm/ng-packs/packages/core/src/lib/services/content-projection.service.ts
  36. 2
      npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts
  37. 1
      npm/ng-packs/packages/core/src/lib/services/index.ts
  38. 44
      npm/ng-packs/packages/core/src/lib/strategies/container.strategy.ts
  39. 47
      npm/ng-packs/packages/core/src/lib/strategies/context.strategy.ts
  40. 3
      npm/ng-packs/packages/core/src/lib/strategies/index.ts
  41. 176
      npm/ng-packs/packages/core/src/lib/strategies/projection.strategy.ts
  42. 80
      npm/ng-packs/packages/core/src/lib/tests/container.strategy.spec.ts
  43. 38
      npm/ng-packs/packages/core/src/lib/tests/content-projection.service.spec.ts
  44. 79
      npm/ng-packs/packages/core/src/lib/tests/context.strategy.spec.ts
  45. 36
      npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts
  46. 276
      npm/ng-packs/packages/core/src/lib/tests/projection.strategy.spec.ts
  47. 4
      npm/ng-packs/packages/feature-management/package.json
  48. 3
      npm/ng-packs/packages/feature-management/src/lib/enums/components.ts
  49. 1
      npm/ng-packs/packages/feature-management/src/public-api.ts
  50. 2
      npm/ng-packs/packages/identity-config/package.json
  51. 8
      npm/ng-packs/packages/identity/package.json
  52. 2
      npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html
  53. 3
      npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts
  54. 2
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.html
  55. 3
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts
  56. 4
      npm/ng-packs/packages/identity/src/lib/enums/components.ts
  57. 5
      npm/ng-packs/packages/identity/src/lib/identity-routing.module.ts
  58. 1
      npm/ng-packs/packages/identity/src/public-api.ts
  59. 4
      npm/ng-packs/packages/permission-management/package.json
  60. 3
      npm/ng-packs/packages/permission-management/src/lib/enums/components.ts
  61. 1
      npm/ng-packs/packages/permission-management/src/public-api.ts
  62. 2
      npm/ng-packs/packages/setting-management-config/package.json
  63. 6
      npm/ng-packs/packages/setting-management/package.json
  64. 3
      npm/ng-packs/packages/setting-management/src/lib/enums/components.ts
  65. 3
      npm/ng-packs/packages/setting-management/src/lib/setting-management-routing.module.ts
  66. 1
      npm/ng-packs/packages/setting-management/src/public-api.ts
  67. 2
      npm/ng-packs/packages/tenant-management-config/package.json
  68. 8
      npm/ng-packs/packages/tenant-management/package.json
  69. 10
      npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html
  70. 3
      npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.ts
  71. 3
      npm/ng-packs/packages/tenant-management/src/lib/enums/components.ts
  72. 3
      npm/ng-packs/packages/tenant-management/src/lib/tenant-management-routing.module.ts
  73. 1
      npm/ng-packs/packages/tenant-management/src/public-api.ts
  74. 4
      npm/ng-packs/packages/theme-basic/package.json
  75. 5
      npm/ng-packs/packages/theme-basic/src/lib/enums/components.ts
  76. 7
      npm/ng-packs/packages/theme-basic/src/lib/services/initial.service.ts
  77. 1
      npm/ng-packs/packages/theme-basic/src/public-api.ts
  78. 4
      npm/ng-packs/packages/theme-shared/package.json
  79. 26
      npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.ts
  80. 2
      npm/ng-packs/packages/theme-shared/src/lib/directives/loading.directive.ts
  81. 156
      npm/ng-packs/yarn.lock
  82. 6
      npm/packs/anchor-js/package.json
  83. 6
      npm/packs/aspnetcore.mvc.ui.theme.basic/package.json
  84. 32
      npm/packs/aspnetcore.mvc.ui.theme.shared/package.json
  85. 4
      npm/packs/aspnetcore.mvc.ui/package.json
  86. 10
      npm/packs/blogging/package.json
  87. 4
      npm/packs/bootstrap-datepicker/package.json
  88. 6
      npm/packs/bootstrap/package.json
  89. 4
      npm/packs/chart.js/package.json
  90. 6
      npm/packs/clipboard/package.json
  91. 6
      npm/packs/codemirror/package.json
  92. 4
      npm/packs/core/package.json
  93. 6
      npm/packs/datatables.net-bs4/package.json
  94. 6
      npm/packs/datatables.net/package.json
  95. 14
      npm/packs/docs/package.json
  96. 4
      npm/packs/flag-icon-css/package.json
  97. 6
      npm/packs/font-awesome/package.json
  98. 6
      npm/packs/highlight.js/package.json
  99. 6
      npm/packs/jquery-form/package.json
  100. 6
      npm/packs/jquery-validation-unobtrusive/package.json

2
common.props

@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>2.5.0</Version>
<Version>2.6.0</Version>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<PackageIconUrl>https://abp.io/assets/abp_nupkg.png</PackageIconUrl>
<PackageProjectUrl>https://abp.io</PackageProjectUrl>

2
docs/en/Customizing-Application-Modules-Extending-Entities.md

@ -58,8 +58,6 @@ You can then use the same extra properties system defined in the previous sectio
## Creating a New Entity Maps to the Same Database Table/Collection
While using the extra properties approach is **easy to use** and suitable for some scenarios, it has some drawbacks described in the [entities document](Entities.md).
Another approach can be **creating your own entity** mapped to **the same database table** (or collection for a MongoDB database).
`AppUser` entity in the [application startup template](Startup-Templates/Application.md) already implements this approach. [EF Core Migrations document](Entity-Framework-Core-Migrations.md) describes how to implement it and manage **EF Core database migrations** in such a case. It is also possible for MongoDB, while this time you won't deal with the database migration problems.

99
docs/en/Customizing-Application-Modules-Overriding-Services.md

@ -161,6 +161,105 @@ Check the [localization system](Localization.md) to learn how to localize the er
Overriding controllers, framework services, view component classes and any other type of classes registered to dependency injection can be overridden just like the examples above.
## Extending Data Transfer Objects
**Extending [entities](Entities.md)** is possible as described in the [Extending Entities document](Customizing-Application-Modules-Extending-Entities.md). In this way, you can add **custom properties** to entities and perform **additional business logic** by overriding the related services as described above.
It is also possible to extend Data Transfer Objects (**DTOs**) used by the application services. In this way, you can get extra properties from the UI (or client) and return extra properties from the service.
### Example
Assuming that you've already added a `SocialSecurityNumber` as described in the [Extending Entities document](Customizing-Application-Modules-Extending-Entities.md) and want to include this information while getting the list of users from the `GetListAsync` method of the `IdentityUserAppService`.
You can use the [object extension system](Object-Extensions.md) to add the property to the `IdentityUserDto`. Write this code inside the `YourProjectNameDtoExtensions` class comes with the application startup template:
````csharp
ObjectExtensionManager.Instance
.AddOrUpdateProperty<IdentityUserDto, string>(
"SocialSecurityNumber"
);
````
This code defines a `SocialSecurityNumber` to the `IdentityUserDto` class as a `string` type. That's all. Now, if you call the `/api/identity/users` HTTP API (which uses the `IdentityUserAppService` internally) from a REST API client, you will see the `SocialSecurityNumber` value in the `extraProperties` section.
````json
{
"totalCount": 1,
"items": [{
"tenantId": null,
"userName": "admin",
"name": "admin",
"surname": null,
"email": "admin@abp.io",
"emailConfirmed": false,
"phoneNumber": null,
"phoneNumberConfirmed": false,
"twoFactorEnabled": false,
"lockoutEnabled": true,
"lockoutEnd": null,
"concurrencyStamp": "b4c371a0ab604de28af472fa79c3b70c",
"isDeleted": false,
"deleterId": null,
"deletionTime": null,
"lastModificationTime": "2020-04-09T21:25:47.0740706",
"lastModifierId": null,
"creationTime": "2020-04-09T21:25:46.8308744",
"creatorId": null,
"id": "8edecb8f-1894-a9b1-833b-39f4725db2a3",
"extraProperties": {
"SocialSecurityNumber": "123456789"
}
}]
}
````
Manually added the `123456789` value to the database for now.
All pre-built modules support extra properties in their DTOs, so you can configure easily.
### Definition Check
When you [define](Customizing-Application-Modules-Extending-Entities.md) an extra property for an entity, it doesn't automatically appear in all the related DTOs, because of the security. The extra property may contain a sensitive data and you may not want to expose it to the clients by default.
So, you need to explicitly define the same property for the corresponding DTO if you want to make it available for the DTO (as just done above). If you want to allow to set it on user creation, you also need to define it for the `IdentityUserCreateDto`.
If the property is not so secure, this can be tedious. Object extension system allows you to ignore this definition check for a desired property. See the example below:
````csharp
ObjectExtensionManager.Instance
.AddOrUpdateProperty<IdentityUser, string>(
"SocialSecurityNumber",
options =>
{
options.MapEfCore(b => b.HasMaxLength(32));
options.CheckPairDefinitionOnMapping = false;
}
);
````
This is another approach to define a property for an entity (`ObjectExtensionManager` has more, see [its document](Object-Extensions.md)). This time, we set `CheckPairDefinitionOnMapping` to false to skip definition check while mapping entities to DTOs and vice verse.
If you don't like this approach but want to add a single property to multiple objects (DTOs) easier, `AddOrUpdateProperty` can get an array of types to add the extra property:
````csharp
ObjectExtensionManager.Instance
.AddOrUpdateProperty<string>(
new[]
{
typeof(IdentityUserDto),
typeof(IdentityUserCreateDto),
typeof(IdentityUserUpdateDto)
},
"SocialSecurityNumber"
);
````
### About the User Interface
This system allows you to add extra properties to entities and DTOs and execute custom business code, however it does nothing related to the User Interface.
See [Overriding the User Interface](Customizing-Application-Modules-Overriding-User-Interface.md) guide for the UI part.
## How to Find the Services?
[Module documents](Modules/Index.md) includes the list of the major services they define. In addition, you can investigate [their source code](https://github.com/abpframework/abp/tree/dev/modules) to explore all the services.

30
docs/en/UI/Angular/Component-Replacement.md

@ -11,15 +11,18 @@ Create a new component that you want to use instead of an ABP component. Add tha
Then, open the `app.component.ts` and dispatch the `AddReplaceableComponent` action to replace your component with an ABP component as shown below:
```js
import { ..., AddReplaceableComponent } from '@abp/ng.core';
import { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent action
import { eIdentityComponents } from '@abp/ng.identity'; // imported eIdentityComponents enum
import { Store } from '@ngxs/store'; // imported Store
//...
export class AppComponent {
constructor(..., private store: Store) {}
constructor(..., private store: Store) {} // injected Store
ngOnInit() {
this.store.dispatch(
new AddReplaceableComponent({
component: YourNewRoleComponent,
key: 'Identity.RolesComponent',
key: eIdentityComponents.Roles,
}),
);
//...
@ -56,6 +59,7 @@ Open the `app.component.ts` and add the below content:
```js
import { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent
import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeBasicComponents enum for component keys
import { MyApplicationLayoutComponent } from './shared/my-application-layout/my-application-layout.component'; // imported MyApplicationLayoutComponent
import { Store } from '@ngxs/store'; // imported Store
//...
@ -67,7 +71,7 @@ export class AppComponent {
this.store.dispatch(
new AddReplaceableComponent({
component: MyApplicationLayoutComponent,
key: 'Theme.ApplicationLayoutComponent',
key: eThemeBasicComponents.ApplicationLayout,
}),
);
@ -76,24 +80,6 @@ export class AppComponent {
}
```
### Available Replaceable Components
| Component key | Description |
| -------------------------------------------------- | --------------------------------------------- |
| Account.LoginComponent | Login page |
| Account.RegisterComponent | Register page |
| Account.ManageProfileComponent | Manage Profile page |
| Account.AuthWrapperComponent | This component wraps register and login pages |
| Account.ChangePasswordComponent | Change password form |
| Account.PersonalSettingsComponent | Personal settings form |
| Account.TenantBoxComponentInputs | Tenant changing box |
| FeatureManagement.FeatureManagementComponent | Features modal |
| Identity.UsersComponent | Users page |
| Identity.RolesComponent | Roles page |
| PermissionManagement.PermissionManagementComponent | Permissions modal |
| SettingManagement.SettingManagementComponent | Setting Management page |
| TenantManagement.TenantsComponent | Tenants page |
## What's Next?
- [Custom Setting Page](./Custom-Setting-Page.md)

101
docs/en/UI/Angular/Container-Strategy.md

@ -0,0 +1,101 @@
# ContainerStrategy
`ContainerStrategy` is an abstract class exposed by @abp/ng.core package. There are two container strategies extending it: `ClearContainerStrategy` and `InsertIntoContainerStrategy`. Implementing the same methods and properties, both of these strategies help you define how your containers will be prepared and where your content will be projected.
## API
`ClearContainerStrategy` is a class that extends `ContainerStrategy`. It lets you **clear a container before projecting content in it**.
### constructor
```js
constructor(
public containerRef: ViewContainerRef,
private index?: number, // works only in InsertIntoContainerStrategy
)
```
- `containerRef` is the `ViewContainerRef` that will be used when projecting the content.
### getIndex
```js
getIndex(): number
```
This method return the given index clamped by `0` and `length` of the `containerRef`. For strategies without an index, it returns `0`.
### prepare
```js
prepare(): void
```
This method is called before content projection. Based on used container strategy, it either clears the container or does nothing (noop).
## ClearContainerStrategy
`ClearContainerStrategy` is a class that extends `ContainerStrategy`. It lets you **clear a container before projecting content in it**.
## InsertIntoContainerStrategy
`InsertIntoContainerStrategy` is a class that extends `ContainerStrategy`. It lets you **project your content at a specific node index in the container**.
## Predefined Container Strategies
Predefined container strategies are accessible via `CONTAINER_STRATEGY` constant.
### Clear
```js
CONTAINER_STRATEGY.Clear(containerRef: ViewContainerRef)
```
Clears given container before content projection.
### Append
```js
CONTAINER_STRATEGY.Append(containerRef: ViewContainerRef)
```
Projected content will be appended to the container.
### Prepend
```js
CONTAINER_STRATEGY.Prepend(containerRef: ViewContainerRef)
```
Projected content will be prepended to the container.
### Insert
```js
CONTAINER_STRATEGY.Insert(
containerRef: ViewContainerRef,
index: number,
)
```
Projected content will be inserted into to the container at given index (clamped by `0` and `length` of the `containerRef`).
## See Also
- [ProjectionStrategy](./Projection-Strategy.md)

78
docs/en/UI/Angular/Content-Projection-Service.md

@ -0,0 +1,78 @@
# Content Projection
You can use the `ContentProjectionService` in @abp/ng.core package in order to project content in an easy and explicit way.
## Getting Started
You do not have to provide the `ContentProjectionService` at module or component level, because it is already **provided in root**. You can inject and start using it immediately in your components, directives, or services.
```js
import { ContentProjectionService } from '@abp/ng.core';
@Component({
/* class metadata here */
})
class DemoComponent {
constructor(private contentProjectionService: ContentProjectionService) {}
}
```
## Usage
You can use the `projectContent` method of `ContentProjectionService` to render components and templates dynamically in your project.
### How to Project Components to Root Level
If you pass a `RootComponentProjectionStrategy` as the first parameter of `projectContent` method, the `ContentProjectionService` will resolve the projected component and place it at the root level. If provided, it will also pass the component a context.
```js
const strategy = PROJECTION_STRATEGY.AppendComponentToBody(
SomeOverlayComponent,
{ someOverlayProp: "SOME_VALUE" }
);
const componentRef = this.contentProjectionService.projectContent(strategy);
```
In the example above, `SomeOverlayComponent` component will placed at the **end** of `<body>` and a `ComponentRef` will be returned. Additionally, the given context will be applied, so `someOverlayProp` of the component will be set to `SOME_VALUE`.
> You should keep the returned `ComponentRef` instance, as it is a reference to the projected component and you will need that reference to destroy the projected view and the component instance.
### How to Project Components and Templates into a Container
If you pass a `ComponentProjectionStrategy` or `TemplateProjectionStrategy` as the first parameter of `projectContent` method, and a `ViewContainerRef` as the second parameter of that strategy, the `ContentProjectionService` will project the component or template to the given container. If provided, it will also pass the component or the template a context.
```js
const strategy = PROJECTION_STRATEGY.ProjectComponentToContainer(
SomeComponent,
viewContainerRefOfTarget,
{ someProp: "SOME_VALUE" }
);
const componentRef = this.contentProjectionService.projectContent(strategy);
```
In this example, the `viewContainerRefOfTarget`, which is a `ViewContainerRef` instance, will be cleared and `SomeComponent` component will be placed inside it. In addition, the given context will be applied and `someProp` of the component will be set to `SOME_VALUE`.
> You should keep the returned `ComponentRef` or `EmbeddedViewRef`, as they are a reference to the projected content and you will need them to destroy it when necessary.
Please refer to [ProjectionStrategy](./Projection-Strategy.md) to see all available projection strategies and how you can build your own projection strategy.
## API
### projectContent
```js
projectContent<T extends Type<any> | TemplateRef<any>>(
projectionStrategy: ProjectionStrategy<T>,
injector = this.injector,
): ComponentRef<C> | EmbeddedViewRef<C>
```
- `projectionStrategy` parameter is the primary focus here and is explained above.
- `injector` parameter is the `Injector` instance you can pass to the projected content. It is not used in `TemplateProjectionStrategy`.
## What's Next?
- [TrackByService](./Track-By-Service.md)

117
docs/en/UI/Angular/Context-Strategy.md

@ -0,0 +1,117 @@
# ContextStrategy
`ContextStrategy` is an abstract class exposed by @abp/ng.core package. There are three context strategies extending it: `ComponentContextStrategy`, `TemplateContextStrategy`, and `NoContextStrategy`. Implementing the same methods and properties, all of these strategies help you define how projected content will get their context.
## ComponentContextStrategy
`ComponentContextStrategy` is a class that extends `ContextStrategy`. It lets you **pass context to a projected component**.
### constructor
```js
constructor(public context: Partial<InferredInstanceOf<T>>) {}
```
- `T` refers to component type here, i.e. `Type<C>`.
- `InferredInstanceOf` is a utility type exposed by @abp/ng.core package. It infers component shape.
- `context` will be mapped to properties of the projected component.
### setContext
```js
setContext(componentRef: ComponentRef<InferredInstanceOf<T>>): Partial<InferredInstanceOf<T>>
```
This method maps each prop of the context to the component property with the same name and calls change detection. It returns the context after mapping.
## TemplateContextStrategy
`TemplateContextStrategy` is a class that extends `ContextStrategy`. It lets you **pass context to a projected template**.
### constructor
```js
constructor(public context: Partial<InferredContextOf<T>>) {}
```
- `T` refers to template context type here, i.e. `TemplateRef<C>`.
- `InferredContextOf` is a utility type exposed by @abp/ng.core package. It infers context shape.
- `context` will be mapped to properties of the projected template.
### setContext
```js
setContext(): Partial<InferredContextOf<T>>
```
This method does nothing and only returns the context, because template context is not mapped but passed in as parameter to `createEmbeddedView` method.
## NoContextStrategy
`NoContextStrategy` is a class that extends `ContextStrategy`. It lets you **skip passing any context to projected content**.
### constructor
```js
constructor()
```
Unlike other context strategies, `NoContextStrategy` contructor takes no parameters.
### setContext
```js
setContext(): undefined
```
Since there is no context, this method gets no parameters and will return `undefined`.
## Predefined Context Strategies
Predefined context strategies are accessible via `CONTEXT_STRATEGY` constant.
### None
```js
CONTEXT_STRATEGY.None()
```
This strategy will not pass any context to the projected content.
### Component
```js
CONTEXT_STRATEGY.Component(context: Partial<InferredContextOf<T>>)
```
This strategy will help you pass the given context to the projected component.
### Template
```js
CONTEXT_STRATEGY.Template(context: Partial<InferredContextOf<T>>)
```
This strategy will help you pass the given context to the projected template.
## See Also
- [ProjectionStrategy](./Projection-Strategy.md)

14
docs/en/UI/Angular/Dom-Insertion-Service.md

@ -1,8 +1,7 @@
# How to Insert Scripts and Styles
# Dom Insertion (of Scripts and Styles)
You can use the `DomInsertionService` in @abp/ng.core package in order to insert scripts and styles in an easy and explicit way.
## Getting Started
You do not have to provide the `DomInsertionService` at module or component level, because it is already **provided in root**. You can inject and start using it immediately in your components, directives, or services.
@ -20,8 +19,7 @@ class DemoComponent {
## Usage
You can use the `insertContent` method of `DomInsertionService` to create a `<script>` or `<style>` element with given content in the DOM at the desired position.
You can use the `insertContent` method of `DomInsertionService` to create a `<script>` or `<style>` element with given content in the DOM at the desired position. There is also the `projectContent` method for dynamically rendering components and templates.
### How to Insert Scripts
@ -48,7 +46,6 @@ In the example above, `<script>alert()</script>` element will place at the **end
Please refer to [ContentStrategy](./Content-Strategy.md) to see all available content strategies and how you can build your own content strategy.
### How to Insert Styles
If you pass a `StyleContentStrategy` instance as the first parameter of `insertContent` method, the `DomInsertionService` will create a `<style>` element with given `content` and place it in the designated DOM position.
@ -74,18 +71,17 @@ In the example above, `<style>body {margin: 0;}</style>` element will place at t
Please refer to [ContentStrategy](./Content-Strategy.md) to see all available content strategies and how you can build your own content strategy.
## API
### insertContent
```js
insertContent(strategy: ContentStrategy): void
insertContent(contentStrategy: ContentStrategy): void
```
`strategy` parameter is the primary focus here and is explained above.
- `contentStrategy` parameter is the primary focus here and is explained above.
## What's Next?
- [TrackByService](./Track-By-Service.md)
- [ContentProjectionService](./Content-Projection-Service.md)

1
docs/en/UI/Angular/Dom-Strategy.md

@ -87,3 +87,4 @@ DOM_STRATEGY.BeforeElement(target: HTMLElement)
- [LazyLoadService](./Lazy-Load-Service.md)
- [LoadingStrategy](./Loading-Strategy.md)
- [ContentStrategy](./Content-Strategy.md)
- [ProjectionStrategy](./Projection-Strategy.md)

2
docs/en/UI/Angular/Loading-Strategy.md

@ -57,7 +57,7 @@ This method creates and returns an observable stream that emits on success and t
## Predefined Loading Strategies
Predefined content security strategies are accessible via `LOADING_STRATEGY` constant.
Predefined loading strategies are accessible via `LOADING_STRATEGY` constant.
### AppendAnonymousScriptToHead

200
docs/en/UI/Angular/Projection-Strategy.md

@ -0,0 +1,200 @@
# ProjectionStrategy
`ProjectionStrategy` is an abstract class exposed by @abp/ng.core package. There are three projection strategies extending it: `ComponentProjectionStrategy`, `RootComponentProjectionStrategy`, and `TemplateProjectionStrategy`. Implementing the same methods and properties, all of these strategies help you define how your content projection will work.
## ComponentProjectionStrategy
`ComponentProjectionStrategy` is a class that extends `ProjectionStrategy`. It lets you **project a component into a container**.
### constructor
```js
constructor(
component: T,
private containerStrategy: ContainerStrategy,
private contextStrategy?: ContextStrategy,
)
```
- `component` is class of the component you would like to project.
- `containerStrategy` is the `ContainerStrategy` that will be used when projecting the component.
- `contextStrategy` is the `ContextStrategy` that will be used on the projected component. (_default: None_)
Please refer to [ContainerStrategy](./Container-Strategy.md) and [ContextStrategy](./Context-Strategy.md) documentation for their usage.
### injectContent
```js
injectContent(injector: Injector): ComponentRef<T>
```
This method prepares the container, resolves the component, sets its context, and projects it to the container. It returns a `ComponentRef` instance, which you should keep in order to clear projected components later on.
## RootComponentProjectionStrategy
`RootComponentProjectionStrategy` is a class that extends `ProjectionStrategy`. It lets you **project a component into the document**, such as appending it to `<body>`.
### constructor
```js
constructor(
component: T,
private contextStrategy?: ContextStrategy,
private domStrategy?: DomStrategy,
)
```
- `component` is class of the component you would like to project.
- `contextStrategy` is the `ContextStrategy` that will be used on the projected component. (_default: None_)
- `domStrategy` is the `DomStrategy` that will be used when inserting component. (_default: AppendToBody_)
Please refer to [ContextStrategy](./Context-Strategy.md) and [DomStrategy](./Dom-Strategy.md) documentation for their usage.
### injectContent
```js
injectContent(injector: Injector): ComponentRef<T>
```
This method resolves the component, sets its context, and projects it to the document. It returns a `ComponentRef` instance, which you should keep in order to clear projected components later on.
## TemplateProjectionStrategy
`TemplateProjectionStrategy` is a class that extends `ProjectionStrategy`. It lets you **project a template into a container**.
### constructor
```js
constructor(
template: T,
private containerStrategy: ContainerStrategy,
private contextStrategy?: ContextStrategy,
)
```
- `template` is `TemplateRef` you would like to project.
- `containerStrategy` is the `ContainerStrategy` that will be used when projecting the component.
- `contextStrategy` is the `ContextStrategy` that will be used on the projected component. (_default: None_)
Please refer to [ContainerStrategy](./Container-Strategy.md) and [ContextStrategy](./Context-Strategy.md) documentation for their usage.
### injectContent
```js
injectContent(): EmbeddedViewRef<T>
```
This method prepares the container, and projects the template together with the defined context to it. It returns an `EmbeddedViewRef`, which you should keep in order to clear projected templates later on.
## Predefined Projection Strategies
Predefined projection strategies are accessible via `PROJECTION_STRATEGY` constant.
### AppendComponentToBody
```js
PROJECTION_STRATEGY.AppendComponentToBody(
component: T,
contextStrategy?: ComponentContextStrategy<T>,
)
```
Sets given context to the component and places it at the **end** of `<body>` tag in the document.
### AppendComponentToContainer
```js
PROJECTION_STRATEGY.AppendComponentToContainer(
component: T,
containerRef: ViewContainerRef,
contextStrategy?: ComponentContextStrategy<T>,
)
```
Sets given context to the component and places it at the **end** of the container.
### AppendTemplateToContainer
```js
PROJECTION_STRATEGY.AppendTemplateToContainer(
templateRef: T,
containerRef: ViewContainerRef,
contextStrategy?: ComponentContextStrategy<T>,
)
```
Sets given context to the template and places it at the **end** of the container.
### PrependComponentToContainer
```js
PROJECTION_STRATEGY.PrependComponentToContainer(
component: T,
containerRef: ViewContainerRef,
contextStrategy?: ComponentContextStrategy<T>,
)
```
Sets given context to the component and places it at the **beginning** of the container.
### PrependTemplateToContainer
```js
PROJECTION_STRATEGY.PrependTemplateToContainer(
templateRef: T,
containerRef: ViewContainerRef,
contextStrategy?: ComponentContextStrategy<T>,
)
```
Sets given context to the template and places it at the **beginning** of the container.
### ProjectComponentToContainer
```js
PROJECTION_STRATEGY.ProjectComponentToContainer(
component: T,
containerRef: ViewContainerRef,
contextStrategy?: ComponentContextStrategy<T>,
)
```
Clears the container, sets given context to the component, and places it **in the cleared** the container.
### ProjectTemplateToContainer
```js
PROJECTION_STRATEGY.ProjectTemplateToContainer(
templateRef: T,
containerRef: ViewContainerRef,
contextStrategy?: ComponentContextStrategy<T>,
)
```
Clears the container, sets given context to the template, and places it **in the cleared** the container.
## See Also
- [DomInsertionService](./Dom-Insertion-Service.md)

4
docs/en/docs-nav.json

@ -353,6 +353,10 @@
"text": "DomInsertionService",
"path": "UI/Angular/Dom-Insertion-Service.md"
},
{
"text": "ContentProjectionService",
"path": "UI/Angular/Content-Projection-Service.md"
},
{
"text": "TrackByService",
"path": "UI/Angular/Track-By-Service.md"

5
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Timeago/TimeagoScriptContributor.cs

@ -17,6 +17,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Timeago
public override void ConfigureDynamicResources(BundleConfigurationContext context)
{
var cultureName = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
if (cultureName.StartsWith("en"))
{
return;
}
var cultureFileName = $"/libs/timeago/locales/jquery.timeago.{cultureName}.js";
if (context.FileProvider.GetFileInfo(cultureFileName).Exists)

2
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs

@ -110,7 +110,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps
var oldNodeIncludeValue = oldNode.Attributes["Include"].Value;
// ReSharper disable once PossibleNullReferenceException : Can not be null because nodes are selected with include attribute filter in previous method
if (oldNodeIncludeValue.Contains(_projectName) && _entries.Any(e=>e.Name.EndsWith($"{oldNodeIncludeValue}.csproj")))
if (oldNodeIncludeValue.Contains(_projectName) && _entries.Any(e=>e.Name.EndsWith(Path.GetFileName(oldNodeIncludeValue))))
{
continue;
}

2
npm/lerna.json

@ -1,5 +1,5 @@
{
"version": "2.4.1",
"version": "2.5.0",
"packages": [
"packs/*"
],

4
npm/ng-packs/.vscode/settings.json

@ -18,7 +18,9 @@
"titleBar.inactiveForeground": "#e7e7e799",
"statusBar.background": "#1d70a2",
"statusBarItem.hoverBackground": "#258ecd",
"statusBar.foreground": "#e7e7e7"
"statusBar.foreground": "#e7e7e7",
"statusBar.border": "#1d70a2",
"titleBar.border": "#1d70a2"
},
"peacock.color": "#1D70A2"
}

2
npm/ng-packs/lerna.version.json

@ -1,5 +1,5 @@
{
"version": "2.4.1",
"version": "2.5.0",
"packages": [
"packages/*"
],

26
npm/ng-packs/package.json

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

2
npm/ng-packs/packages/account-config/package.json

@ -1,6 +1,6 @@
{
"name": "@abp/ng.account.config",
"version": "2.4.1",
"version": "2.5.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",

6
npm/ng-packs/packages/account/package.json

@ -1,14 +1,14 @@
{
"name": "@abp/ng.account",
"version": "2.4.1",
"version": "2.5.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
"@abp/ng.account.config": "^2.4.1",
"@abp/ng.theme.shared": "^2.4.1"
"@abp/ng.account.config": "~2.5.0",
"@abp/ng.theme.shared": "~2.5.0"
},
"publishConfig": {
"access": "public"

7
npm/ng-packs/packages/account/src/lib/account-routing.module.ts

@ -9,6 +9,7 @@ import { RouterModule, Routes } from '@angular/router';
import { LoginComponent } from './components/login/login.component';
import { ManageProfileComponent } from './components/manage-profile/manage-profile.component';
import { RegisterComponent } from './components/register/register.component';
import { eAccountComponents } from './enums/components';
const routes: Routes = [
{ path: '', pathMatch: 'full', redirectTo: 'login' },
@ -21,7 +22,7 @@ const routes: Routes = [
component: ReplaceableRouteContainerComponent,
data: {
replaceableComponent: {
key: 'Account.LoginComponent',
key: eAccountComponents.Login,
defaultComponent: LoginComponent,
} as ReplaceableComponents.RouteData<LoginComponent>,
},
@ -31,7 +32,7 @@ const routes: Routes = [
component: ReplaceableRouteContainerComponent,
data: {
replaceableComponent: {
key: 'Account.RegisterComponent',
key: eAccountComponents.Register,
defaultComponent: RegisterComponent,
} as ReplaceableComponents.RouteData<RegisterComponent>,
},
@ -42,7 +43,7 @@ const routes: Routes = [
canActivate: [AuthGuard],
data: {
replaceableComponent: {
key: 'Account.ManageProfileComponent',
key: eAccountComponents.ManageProfile,
defaultComponent: ManageProfileComponent,
} as ReplaceableComponents.RouteData<ManageProfileComponent>,
},

4
npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.html

@ -1,9 +1,7 @@
<div class="row">
<div class="mx-auto col col-md-5">
<ng-container *ngIf="isMultiTenancyEnabled$ | async">
<abp-tenant-box
*abpReplaceableTemplate="{ componentKey: 'Account.TenantBoxComponent' }"
></abp-tenant-box>
<abp-tenant-box *abpReplaceableTemplate="{ componentKey: tenantBoxKey }"></abp-tenant-box>
</ng-container>
<div class="abp-account-container">

3
npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.ts

@ -3,6 +3,7 @@ import { Component, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core'
import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs';
import { Account } from '../../models/account';
import { eAccountComponents } from '../../enums/components';
@Component({
selector: 'abp-auth-wrapper',
@ -26,6 +27,8 @@ export class AuthWrapperComponent
enableLocalLogin = true;
tenantBoxKey = eAccountComponents.TenantBox;
constructor(private store: Store) {}
ngOnInit() {

2
npm/ng-packs/packages/account/src/lib/components/login/login.component.html

@ -1,6 +1,6 @@
<abp-auth-wrapper
*abpReplaceableTemplate="{
componentKey: 'Account.AuthWrapperComponent',
componentKey: authWrapperKey,
inputs: {
mainContentRef: { value: mainContentRef },
cancelContentRef: { value: cancelContentRef }

3
npm/ng-packs/packages/account/src/lib/components/login/login.component.ts

@ -7,6 +7,7 @@ import { OAuthService } from 'angular-oauth2-oidc';
import { throwError } from 'rxjs';
import { catchError, finalize } from 'rxjs/operators';
import snq from 'snq';
import { eAccountComponents } from '../../enums/components';
const { maxLength, minLength, required } = Validators;
@ -21,6 +22,8 @@ export class LoginComponent implements OnInit {
isSelfRegistrationEnabled = true;
authWrapperKey = eAccountComponents.AuthWrapper;
constructor(
private fb: FormBuilder,
private oauthService: OAuthService,

4
npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.html

@ -33,7 +33,7 @@
<hr />
</h4>
<abp-change-password-form
*abpReplaceableTemplate="{ componentKey: 'Account.ChangePasswordComponent' }"
*abpReplaceableTemplate="{ componentKey: changePasswordKey }"
></abp-change-password-form>
</div>
</div>
@ -44,7 +44,7 @@
<hr />
</h4>
<abp-personal-settings-form
*abpReplaceableTemplate="{ componentKey: 'Account.PersonalSettingsComponent' }"
*abpReplaceableTemplate="{ componentKey: personalSettingsKey }"
></abp-personal-settings-form>
</div>
</div>

5
npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts

@ -1,6 +1,7 @@
import { fadeIn } from '@abp/ng.theme.shared';
import { transition, trigger, useAnimation } from '@angular/animations';
import { Component } from '@angular/core';
import { eAccountComponents } from '../../enums/components';
@Component({
selector: 'abp-manage-profile',
@ -9,4 +10,8 @@ import { Component } from '@angular/core';
})
export class ManageProfileComponent {
selectedTab = 0;
changePasswordKey = eAccountComponents.ChangePassword;
personalSettingsKey = eAccountComponents.PersonalSettings;
}

2
npm/ng-packs/packages/account/src/lib/components/register/register.component.html

@ -1,6 +1,6 @@
<abp-auth-wrapper
*abpReplaceableTemplate="{
componentKey: 'Account.AuthWrapperComponent',
componentKey: authWrapperKey,
inputs: {
mainContentRef: { value: mainContentRef }
}

3
npm/ng-packs/packages/account/src/lib/components/register/register.component.ts

@ -9,6 +9,7 @@ import { catchError, finalize, switchMap } from 'rxjs/operators';
import snq from 'snq';
import { RegisterRequest } from '../../models';
import { AccountService } from '../../services/account.service';
import { eAccountComponents } from '../../enums/components';
const { maxLength, required, email } = Validators;
@Component({
@ -22,6 +23,8 @@ export class RegisterComponent implements OnInit {
isSelfRegistrationEnabled = true;
authWrapperKey = eAccountComponents.AuthWrapper;
constructor(
private fb: FormBuilder,
private accountService: AccountService,

9
npm/ng-packs/packages/account/src/lib/enums/components.ts

@ -0,0 +1,9 @@
export const enum eAccountComponents {
Login = 'Account.LoginComponent',
Register = 'Account.RegisterComponent',
ManageProfile = 'Account.ManageProfileComponent',
TenantBox = 'Account.TenantBoxComponent',
AuthWrapper = 'Account.AuthWrapperComponent',
ChangePassword = 'Account.ChangePasswordComponent',
PersonalSettings = 'Account.PersonalSettingsComponent',
}

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

@ -1,5 +1,6 @@
export * from './lib/account.module';
export * from './lib/components';
export * from './lib/enums/components';
export * from './lib/tokens';
export * from './lib/models';
export * from './lib/services';

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

@ -1,6 +1,6 @@
{
"name": "@abp/ng.core",
"version": "2.4.1",
"version": "2.5.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",

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

@ -6,3 +6,4 @@ export * from './profile';
export * from './replaceable-components';
export * from './rest';
export * from './session';
export * from './utility';

4
npm/ng-packs/packages/core/src/lib/models/utility.ts

@ -0,0 +1,4 @@
import { TemplateRef, Type } from '@angular/core';
export type InferredInstanceOf<T> = T extends Type<infer U> ? U : never;
export type InferredContextOf<T> = T extends TemplateRef<infer U> ? U : never;

14
npm/ng-packs/packages/core/src/lib/services/content-projection.service.ts

@ -0,0 +1,14 @@
import { Injectable, Injector, TemplateRef, Type } from '@angular/core';
import { ProjectionStrategy } from '../strategies/projection.strategy';
@Injectable({ providedIn: 'root' })
export class ContentProjectionService {
constructor(private injector: Injector) {}
projectContent<T extends Type<any> | TemplateRef<any>>(
projectionStrategy: ProjectionStrategy<T>,
injector = this.injector,
) {
return projectionStrategy.injectContent(injector);
}
}

2
npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts

@ -4,7 +4,7 @@ import { generateHash } from '../utils';
@Injectable({ providedIn: 'root' })
export class DomInsertionService {
readonly inserted = new Set();
readonly inserted = new Set<number>();
insertContent(contentStrategy: ContentStrategy) {
const hash = generateHash(contentStrategy.content);

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

@ -1,6 +1,7 @@
export * from './application-configuration.service';
export * from './auth.service';
export * from './config-state.service';
export * from './content-projection.service';
export * from './dom-insertion.service';
export * from './lazy-load.service';
export * from './localization.service';

44
npm/ng-packs/packages/core/src/lib/strategies/container.strategy.ts

@ -0,0 +1,44 @@
import { ViewContainerRef } from '@angular/core';
export abstract class ContainerStrategy {
constructor(public containerRef: ViewContainerRef) {}
abstract getIndex(): number;
prepare(): void {}
}
export class ClearContainerStrategy extends ContainerStrategy {
getIndex(): number {
return 0;
}
prepare() {
this.containerRef.clear();
}
}
export class InsertIntoContainerStrategy extends ContainerStrategy {
constructor(containerRef: ViewContainerRef, private index: number) {
super(containerRef);
}
getIndex() {
return Math.min(Math.max(0, this.index), this.containerRef.length);
}
}
export const CONTAINER_STRATEGY = {
Clear(containerRef: ViewContainerRef) {
return new ClearContainerStrategy(containerRef);
},
Append(containerRef: ViewContainerRef) {
return new InsertIntoContainerStrategy(containerRef, containerRef.length);
},
Prepend(containerRef: ViewContainerRef) {
return new InsertIntoContainerStrategy(containerRef, 0);
},
Insert(containerRef: ViewContainerRef, index: number) {
return new InsertIntoContainerStrategy(containerRef, index);
},
};

47
npm/ng-packs/packages/core/src/lib/strategies/context.strategy.ts

@ -0,0 +1,47 @@
import { ComponentRef, TemplateRef, Type } from '@angular/core';
import { InferredContextOf, InferredInstanceOf } from '../models';
export abstract class ContextStrategy<T = any> {
constructor(public context: Partial<ContextType<T>>) {}
/* tslint:disable-next-line:no-unused-variable */
setContext(componentRef?: ComponentRef<InferredInstanceOf<T>>): Partial<ContextType<T>> {
return this.context;
}
}
export class NoContextStrategy<
T extends Type<any> | TemplateRef<any> = any
> extends ContextStrategy<T> {
constructor() {
super(undefined);
}
}
export class ComponentContextStrategy<T extends Type<any> = any> extends ContextStrategy<T> {
setContext(componentRef: ComponentRef<InferredInstanceOf<T>>): Partial<InferredInstanceOf<T>> {
Object.keys(this.context).forEach(key => (componentRef.instance[key] = this.context[key]));
componentRef.changeDetectorRef.detectChanges();
return this.context;
}
}
export class TemplateContextStrategy<T extends TemplateRef<any> = any> extends ContextStrategy<T> {
setContext(): Partial<InferredContextOf<T>> {
return this.context;
}
}
export const CONTEXT_STRATEGY = {
None<T extends Type<any> | TemplateRef<any> = any>() {
return new NoContextStrategy<T>();
},
Component<T extends Type<any> = any>(context: Partial<InferredInstanceOf<T>>) {
return new ComponentContextStrategy<T>(context);
},
Template<T extends TemplateRef<any> = any>(context: Partial<InferredContextOf<T>>) {
return new TemplateContextStrategy<T>(context);
},
};
type ContextType<T> = T extends Type<infer U> | TemplateRef<infer U> ? U : never;

3
npm/ng-packs/packages/core/src/lib/strategies/index.ts

@ -1,5 +1,8 @@
export * from './container.strategy';
export * from './content-security.strategy';
export * from './content.strategy';
export * from './context.strategy';
export * from './cross-origin.strategy';
export * from './dom.strategy';
export * from './loading.strategy';
export * from './projection.strategy';

176
npm/ng-packs/packages/core/src/lib/strategies/projection.strategy.ts

@ -0,0 +1,176 @@
import {
ApplicationRef,
ComponentFactoryResolver,
ComponentRef,
EmbeddedViewRef,
Injector,
TemplateRef,
Type,
ViewContainerRef,
} from '@angular/core';
import { InferredContextOf, InferredInstanceOf } from '../models/utility';
import { ContainerStrategy, CONTAINER_STRATEGY } from './container.strategy';
import { ContextStrategy, CONTEXT_STRATEGY } from './context.strategy';
import { DomStrategy, DOM_STRATEGY } from './dom.strategy';
export abstract class ProjectionStrategy<T = any> {
constructor(public content: T) {}
abstract injectContent(injector: Injector): ComponentRefOrEmbeddedViewRef<T>;
}
export class ComponentProjectionStrategy<T extends Type<any>> extends ProjectionStrategy<T> {
constructor(
component: T,
private containerStrategy: ContainerStrategy,
private contextStrategy: ContextStrategy = CONTEXT_STRATEGY.None(),
) {
super(component);
}
injectContent(injector: Injector) {
this.containerStrategy.prepare();
const resolver = injector.get(ComponentFactoryResolver) as ComponentFactoryResolver;
const factory = resolver.resolveComponentFactory<InferredInstanceOf<T>>(this.content);
const componentRef = this.containerStrategy.containerRef.createComponent(
factory,
this.containerStrategy.getIndex(),
injector,
);
this.contextStrategy.setContext(componentRef);
return componentRef as ComponentRefOrEmbeddedViewRef<T>;
}
}
export class RootComponentProjectionStrategy<T extends Type<any>> extends ProjectionStrategy<T> {
constructor(
component: T,
private contextStrategy: ContextStrategy = CONTEXT_STRATEGY.None(),
private domStrategy: DomStrategy = DOM_STRATEGY.AppendToBody(),
) {
super(component);
}
injectContent(injector: Injector) {
const appRef = injector.get(ApplicationRef);
const resolver = injector.get(ComponentFactoryResolver) as ComponentFactoryResolver;
const componentRef = resolver
.resolveComponentFactory<InferredInstanceOf<T>>(this.content)
.create(injector);
this.contextStrategy.setContext(componentRef);
appRef.attachView(componentRef.hostView);
const element: HTMLElement = (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0];
this.domStrategy.insertElement(element);
return componentRef as ComponentRefOrEmbeddedViewRef<T>;
}
}
export class TemplateProjectionStrategy<T extends TemplateRef<any>> extends ProjectionStrategy<T> {
constructor(
templateRef: T,
private containerStrategy: ContainerStrategy,
private contextStrategy = CONTEXT_STRATEGY.None(),
) {
super(templateRef);
}
injectContent() {
this.containerStrategy.prepare();
const embeddedViewRef = this.containerStrategy.containerRef.createEmbeddedView(
this.content,
this.contextStrategy.context,
this.containerStrategy.getIndex(),
);
embeddedViewRef.detectChanges();
return embeddedViewRef as ComponentRefOrEmbeddedViewRef<T>;
}
}
export const PROJECTION_STRATEGY = {
AppendComponentToBody<T extends Type<unknown>>(component: T, context?: InferredInstanceOf<T>) {
return new RootComponentProjectionStrategy<T>(
component,
context && CONTEXT_STRATEGY.Component(context),
);
},
AppendComponentToContainer<T extends Type<unknown>>(
component: T,
containerRef: ViewContainerRef,
context?: InferredInstanceOf<T>,
) {
return new ComponentProjectionStrategy<T>(
component,
CONTAINER_STRATEGY.Append(containerRef),
context && CONTEXT_STRATEGY.Component(context),
);
},
AppendTemplateToContainer<T extends TemplateRef<unknown>>(
templateRef: T,
containerRef: ViewContainerRef,
context?: InferredContextOf<T>,
) {
return new TemplateProjectionStrategy<T>(
templateRef,
CONTAINER_STRATEGY.Append(containerRef),
context && CONTEXT_STRATEGY.Template(context),
);
},
PrependComponentToContainer<T extends Type<unknown>>(
component: T,
containerRef: ViewContainerRef,
context?: InferredInstanceOf<T>,
) {
return new ComponentProjectionStrategy<T>(
component,
CONTAINER_STRATEGY.Prepend(containerRef),
context && CONTEXT_STRATEGY.Component(context),
);
},
PrependTemplateToContainer<T extends TemplateRef<unknown>>(
templateRef: T,
containerRef: ViewContainerRef,
context?: InferredContextOf<T>,
) {
return new TemplateProjectionStrategy<T>(
templateRef,
CONTAINER_STRATEGY.Prepend(containerRef),
context && CONTEXT_STRATEGY.Template(context),
);
},
ProjectComponentToContainer<T extends Type<unknown>>(
component: T,
containerRef: ViewContainerRef,
context?: InferredInstanceOf<T>,
) {
return new ComponentProjectionStrategy<T>(
component,
CONTAINER_STRATEGY.Clear(containerRef),
context && CONTEXT_STRATEGY.Component(context),
);
},
ProjectTemplateToContainer<T extends TemplateRef<unknown>>(
templateRef: T,
containerRef: ViewContainerRef,
context?: InferredContextOf<T>,
) {
return new TemplateProjectionStrategy<T>(
templateRef,
CONTAINER_STRATEGY.Clear(containerRef),
context && CONTEXT_STRATEGY.Template(context),
);
},
};
type ComponentRefOrEmbeddedViewRef<T> = T extends Type<infer U>
? ComponentRef<U>
: T extends TemplateRef<infer C>
? EmbeddedViewRef<C>
: never;

80
npm/ng-packs/packages/core/src/lib/tests/container.strategy.spec.ts

@ -0,0 +1,80 @@
import { ViewContainerRef } from '@angular/core';
import {
ClearContainerStrategy,
CONTAINER_STRATEGY,
InsertIntoContainerStrategy,
} from '../strategies';
describe('ClearContainerStrategy', () => {
const containerRef = ({
clear: jest.fn(),
length: 7,
} as any) as ViewContainerRef;
describe('#getIndex', () => {
it('should return 0', () => {
const strategy = new ClearContainerStrategy(containerRef);
expect(strategy.getIndex()).toBe(0);
});
});
describe('#prepare', () => {
it('should call clear method of containerRef once', () => {
const strategy = new ClearContainerStrategy(containerRef);
strategy.prepare();
expect(strategy.getIndex()).toBe(0);
expect(containerRef.clear).toHaveBeenCalledTimes(1);
});
});
});
describe('InsertIntoContainerStrategy', () => {
const containerRef = ({
clear: jest.fn(),
length: 7,
} as any) as ViewContainerRef;
describe('#getIndex', () => {
test.each`
index | expected
${0} | ${0}
${4} | ${4}
${9} | ${7}
${-1} | ${0}
${Infinity} | ${7}
`(
'should return $expected when index is given $index',
({ index, expected }: { index: number; expected: number }) => {
const strategy = new InsertIntoContainerStrategy(containerRef, index);
expect(strategy.getIndex()).toBe(expected);
},
);
});
describe('#prepare', () => {
it('should not call clear method of containerRef', () => {
const strategy = new InsertIntoContainerStrategy(containerRef, 0);
strategy.prepare();
expect(containerRef.clear).not.toHaveBeenCalled();
});
});
});
describe('CONTAINER_STRATEGY', () => {
const containerRef = ({
clear: jest.fn(),
length: 7,
} as any) as ViewContainerRef;
test.each`
name | Strategy | index
${'Clear'} | ${ClearContainerStrategy} | ${undefined}
${'Append'} | ${InsertIntoContainerStrategy} | ${containerRef.length}
${'Prepend'} | ${InsertIntoContainerStrategy} | ${0}
${'Insert'} | ${InsertIntoContainerStrategy} | ${4}
`('should successfully map $name to $Strategy.name', ({ name, Strategy, index }) => {
expect(CONTAINER_STRATEGY[name](containerRef, index)).toEqual(
new Strategy(containerRef, index),
);
});
});

38
npm/ng-packs/packages/core/src/lib/tests/content-projection.service.spec.ts

@ -0,0 +1,38 @@
import { Component, ComponentRef, NgModule } from '@angular/core';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
import { ContentProjectionService } from '../services';
import { PROJECTION_STRATEGY } from '../strategies';
describe('ContentProjectionService', () => {
@Component({ template: '<div class="foo">bar</div>' })
class TestComponent {}
// createServiceFactory does not accept entryComponents directly
@NgModule({
declarations: [TestComponent],
entryComponents: [TestComponent],
})
class TestModule {}
let componentRef: ComponentRef<TestComponent>;
let spectator: SpectatorService<ContentProjectionService>;
const createService = createServiceFactory({
service: ContentProjectionService,
imports: [TestModule],
});
beforeEach(() => (spectator = createService()));
afterEach(() => componentRef.destroy());
describe('#projectContent', () => {
it('should call injectContent of given projectionStrategy and return what it returns', () => {
const strategy = PROJECTION_STRATEGY.AppendComponentToBody(TestComponent);
componentRef = spectator.service.projectContent(strategy);
const foo = document.querySelector('body > ng-component > div.foo');
expect(componentRef).toBeInstanceOf(ComponentRef);
expect(foo.textContent).toBe('bar');
});
});
});

79
npm/ng-packs/packages/core/src/lib/tests/context.strategy.spec.ts

@ -0,0 +1,79 @@
import { ComponentRef } from '@angular/core';
import {
ComponentContextStrategy,
CONTEXT_STRATEGY,
NoContextStrategy,
TemplateContextStrategy,
} from '../strategies';
import { uuid } from '../utils';
describe('ComponentContextStrategy', () => {
describe('#setContext', () => {
let componentRef: ComponentRef<any>;
beforeEach(
() =>
(componentRef = {
instance: {
x: '',
y: '',
z: '',
},
changeDetectorRef: {
detectChanges: jest.fn(),
},
} as any),
);
test.each`
props | values
${['x']} | ${[uuid()]}
${['x', 'y']} | ${[uuid(), uuid()]}
${['x', 'y', 'z']} | ${[uuid(), uuid(), uuid()]}
`(
'should set $props as $values and call detectChanges once',
({ props, values }: { props: string[]; values: string[] }) => {
const context = {};
props.forEach((prop, i) => {
context[prop] = values[i];
});
const strategy = new ComponentContextStrategy(context);
strategy.setContext(componentRef);
expect(props.every(prop => componentRef.instance[prop] === context[prop])).toBe(true);
expect(componentRef.changeDetectorRef.detectChanges).toHaveBeenCalledTimes(1);
},
);
});
});
describe('NoContextStrategy', () => {
describe('#setContext', () => {
it('should return undefined', () => {
const strategy = new NoContextStrategy();
expect(strategy.setContext(null)).toBeUndefined();
});
});
});
describe('TemplateContextStrategy', () => {
describe('#setContext', () => {
it('should return context', () => {
const context = { x: uuid() };
const strategy = new TemplateContextStrategy(context);
expect(strategy.setContext()).toEqual(context);
});
});
});
describe('CONTEXT_STRATEGY', () => {
test.each`
name | Strategy
${'Component'} | ${ComponentContextStrategy}
${'None'} | ${NoContextStrategy}
${'Template'} | ${TemplateContextStrategy}
`('should successfully map $name to $Strategy.name', ({ name, Strategy }) => {
expect(CONTEXT_STRATEGY[name](undefined)).toEqual(new Strategy(undefined));
});
});

36
npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts

@ -3,13 +3,43 @@ import { DomInsertionService } from '../services';
import { CONTENT_STRATEGY } from '../strategies';
describe('DomInsertionService', () => {
let styleElements: NodeListOf<HTMLStyleElement>;
let spectator: SpectatorService<DomInsertionService>;
const createService = createServiceFactory(DomInsertionService);
beforeEach(() => (spectator = createService()));
it('should be insert an element', () => {
spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead('.test {}'));
expect(spectator.service.inserted.has(1437348290)).toBe(true);
afterEach(() => styleElements.forEach(element => element.remove()));
describe('#insertContent', () => {
it('should be able to insert given content', () => {
spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead('.test {}'));
styleElements = document.head.querySelectorAll('style');
expect(styleElements.length).toBe(1);
expect(styleElements[0].textContent).toBe('.test {}');
});
it('should insert only once', () => {
expect(spectator.service.inserted.has(1437348290)).toBe(false);
spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead('.test {}'));
styleElements = document.head.querySelectorAll('style');
expect(styleElements.length).toBe(1);
expect(styleElements[0].textContent).toBe('.test {}');
expect(spectator.service.inserted.has(1437348290)).toBe(true);
spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead('.test {}'));
styleElements = document.head.querySelectorAll('style');
expect(styleElements.length).toBe(1);
expect(styleElements[0].textContent).toBe('.test {}');
expect(spectator.service.inserted.has(1437348290)).toBe(true);
});
it('should be able to insert given content', () => {
spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead('.test {}'));
expect(spectator.service.inserted.has(1437348290)).toBe(true);
});
});
});

276
npm/ng-packs/packages/core/src/lib/tests/projection.strategy.spec.ts

@ -0,0 +1,276 @@
import {
Component,
ComponentRef,
EmbeddedViewRef,
TemplateRef,
ViewChild,
ViewContainerRef,
} from '@angular/core';
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
import {
ComponentProjectionStrategy,
ContainerStrategy,
CONTAINER_STRATEGY,
CONTEXT_STRATEGY,
DOM_STRATEGY,
PROJECTION_STRATEGY,
RootComponentProjectionStrategy,
TemplateProjectionStrategy,
} from '../strategies';
describe('ComponentProjectionStrategy', () => {
@Component({
template: '<div class="foo">{{ bar || baz }}</div>',
})
class TestComponent {
bar: string;
baz = 'baz';
}
@Component({
template: '<ng-container #container></ng-container>',
})
class HostComponent {
@ViewChild('container', { static: true, read: ViewContainerRef })
containerRef: ViewContainerRef;
}
let containerStrategy: ContainerStrategy;
let spectator: Spectator<HostComponent>;
let componentRef: ComponentRef<TestComponent>;
const createComponent = createComponentFactory({
component: HostComponent,
entryComponents: [TestComponent],
});
beforeEach(() => {
spectator = createComponent({});
containerStrategy = CONTAINER_STRATEGY.Clear(spectator.component.containerRef);
});
afterEach(() => {
componentRef.destroy();
spectator.detectChanges();
});
describe('#injectContent', () => {
it('should should insert content into container and return a ComponentRef', () => {
const strategy = new ComponentProjectionStrategy(TestComponent, containerStrategy);
componentRef = strategy.injectContent(spectator);
spectator.detectChanges();
const div = spectator.query('div.foo');
expect(div.textContent).toBe('baz');
expect(componentRef).toBeInstanceOf(ComponentRef);
});
it('should be able to map context to projected component', () => {
const contextStrategy = CONTEXT_STRATEGY.Component({ bar: 'bar' });
const strategy = new ComponentProjectionStrategy(
TestComponent,
containerStrategy,
contextStrategy,
);
componentRef = strategy.injectContent(spectator);
spectator.detectChanges();
const div = spectator.query('div.foo');
expect(div.textContent).toBe('bar');
expect(componentRef.instance.bar).toBe('bar');
});
});
});
describe('RootComponentProjectionStrategy', () => {
@Component({
template: '<div class="foo">{{ bar || baz }}</div>',
})
class TestComponent {
bar: string;
baz = 'baz';
}
@Component({ template: '' })
class HostComponent {}
let spectator: Spectator<HostComponent>;
let componentRef: ComponentRef<TestComponent>;
const createComponent = createComponentFactory({
component: HostComponent,
entryComponents: [TestComponent],
});
beforeEach(() => {
spectator = createComponent({});
});
afterEach(() => {
componentRef.destroy();
spectator.detectChanges();
});
describe('#injectContent', () => {
it('should should insert content into body and return a ComponentRef', () => {
const strategy = new RootComponentProjectionStrategy(TestComponent);
componentRef = strategy.injectContent(spectator);
spectator.detectChanges();
const div = document.querySelector('body > ng-component > div.foo');
expect(div.textContent).toBe('baz');
expect(componentRef).toBeInstanceOf(ComponentRef);
componentRef.destroy();
spectator.detectChanges();
});
it('should be able to map context to projected component', () => {
const contextStrategy = CONTEXT_STRATEGY.Component({ bar: 'bar' });
const strategy = new RootComponentProjectionStrategy(TestComponent, contextStrategy);
componentRef = strategy.injectContent(spectator);
spectator.detectChanges();
const div = document.querySelector('body > ng-component > div.foo');
expect(div.textContent).toBe('bar');
expect(componentRef.instance.bar).toBe('bar');
});
});
});
describe('TemplateProjectionStrategy', () => {
@Component({
template: `
<ng-template #template let-bar>
<div class="foo">{{ bar || baz }}</div>
</ng-template>
<ng-container #container></ng-container>
`,
})
class HostComponent {
@ViewChild('container', { static: true, read: ViewContainerRef })
containerRef: ViewContainerRef;
@ViewChild('template', { static: true })
templateRef: TemplateRef<{ $implicit?: string }>;
baz = 'baz';
}
let containerStrategy: ContainerStrategy;
let spectator: Spectator<HostComponent>;
let embeddedViewRef: EmbeddedViewRef<{ $implicit?: string }>;
const createComponent = createComponentFactory({
component: HostComponent,
});
beforeEach(() => {
spectator = createComponent({});
containerStrategy = CONTAINER_STRATEGY.Clear(spectator.component.containerRef);
});
afterEach(() => {
embeddedViewRef.destroy();
spectator.detectChanges();
});
describe('#injectContent', () => {
it('should should insert content into container and return an EmbeddedViewRef', () => {
const templateRef = spectator.component.templateRef;
const strategy = new TemplateProjectionStrategy(templateRef, containerStrategy);
embeddedViewRef = strategy.injectContent();
spectator.detectChanges();
const div = spectator.query('div.foo');
expect(div.textContent).toBe('baz');
expect(embeddedViewRef).toHaveProperty('detectChanges');
expect(embeddedViewRef).toHaveProperty('markForCheck');
expect(embeddedViewRef).toHaveProperty('detach');
expect(embeddedViewRef).toHaveProperty('reattach');
expect(embeddedViewRef).toHaveProperty('destroy');
expect(embeddedViewRef).toHaveProperty('rootNodes');
expect(embeddedViewRef).toHaveProperty('context');
});
it('should be able to map context to projected template', () => {
const templateRef = spectator.component.templateRef;
const contextStrategy = CONTEXT_STRATEGY.Template<typeof templateRef>({ $implicit: 'bar' });
const strategy = new TemplateProjectionStrategy(
templateRef,
containerStrategy,
contextStrategy,
);
embeddedViewRef = strategy.injectContent();
spectator.detectChanges();
const div = spectator.query('div.foo');
expect(div.textContent).toBe('bar');
expect(embeddedViewRef.context).toEqual(contextStrategy.context);
});
});
});
describe('PROJECTION_STRATEGY', () => {
const content = undefined;
const containerRef = ({ length: 0 } as any) as ViewContainerRef;
let context: any;
test.each`
name | Strategy | containerStrategy
${'AppendComponentToContainer'} | ${ComponentProjectionStrategy} | ${CONTAINER_STRATEGY.Append}
${'AppendTemplateToContainer'} | ${TemplateProjectionStrategy} | ${CONTAINER_STRATEGY.Append}
${'PrependComponentToContainer'} | ${ComponentProjectionStrategy} | ${CONTAINER_STRATEGY.Prepend}
${'PrependTemplateToContainer'} | ${TemplateProjectionStrategy} | ${CONTAINER_STRATEGY.Prepend}
${'ProjectComponentToContainer'} | ${ComponentProjectionStrategy} | ${CONTAINER_STRATEGY.Clear}
${'ProjectTemplateToContainer'} | ${TemplateProjectionStrategy} | ${CONTAINER_STRATEGY.Clear}
`(
'should successfully map $name to $Strategy.name with $containerStrategy.name container strategy and $contextStrategy.name context strategy',
({ name, Strategy, containerStrategy }) => {
expect(PROJECTION_STRATEGY[name](content, containerRef, context)).toEqual(
new Strategy(content, containerStrategy(containerRef), CONTEXT_STRATEGY.None()),
);
},
);
test.each`
name | Strategy | domStrategy
${'AppendComponentToBody'} | ${RootComponentProjectionStrategy} | ${DOM_STRATEGY.AppendToBody}
`(
'should successfully map $name to $Strategy.name with $domStrategy.name dom strategy',
({ name, Strategy, domStrategy }) => {
expect(PROJECTION_STRATEGY[name](content, context)).toEqual(
new Strategy(content, CONTEXT_STRATEGY.None(), domStrategy()),
);
},
);
test.each`
name | Strategy | containerStrategy | contextStrategy
${'AppendComponentToContainer'} | ${ComponentProjectionStrategy} | ${CONTAINER_STRATEGY.Append} | ${CONTEXT_STRATEGY.Component}
${'AppendTemplateToContainer'} | ${TemplateProjectionStrategy} | ${CONTAINER_STRATEGY.Append} | ${CONTEXT_STRATEGY.Template}
${'PrependComponentToContainer'} | ${ComponentProjectionStrategy} | ${CONTAINER_STRATEGY.Prepend} | ${CONTEXT_STRATEGY.Component}
${'PrependTemplateToContainer'} | ${TemplateProjectionStrategy} | ${CONTAINER_STRATEGY.Prepend} | ${CONTEXT_STRATEGY.Template}
${'ProjectComponentToContainer'} | ${ComponentProjectionStrategy} | ${CONTAINER_STRATEGY.Clear} | ${CONTEXT_STRATEGY.Component}
${'ProjectTemplateToContainer'} | ${TemplateProjectionStrategy} | ${CONTAINER_STRATEGY.Clear} | ${CONTEXT_STRATEGY.Template}
`(
'should successfully map $name to $Strategy.name with $containerStrategy.name container strategy and $contextStrategy.name context strategy',
({ name, Strategy, containerStrategy, contextStrategy }) => {
context = { x: true };
expect(PROJECTION_STRATEGY[name](content, containerRef, context)).toEqual(
new Strategy(content, containerStrategy(containerRef), contextStrategy(context)),
);
},
);
test.each`
name | Strategy | contextStrategy | domStrategy
${'AppendComponentToBody'} | ${RootComponentProjectionStrategy} | ${CONTEXT_STRATEGY.Component} | ${DOM_STRATEGY.AppendToBody}
`(
'should successfully map $name to $Strategy.name with $contextStrategy.name context strategy and $domStrategy.name dom strategy',
({ name, Strategy, domStrategy, contextStrategy }) => {
context = { x: true };
expect(PROJECTION_STRATEGY[name](content, context)).toEqual(
new Strategy(content, contextStrategy(context), domStrategy()),
);
},
);
});

4
npm/ng-packs/packages/feature-management/package.json

@ -1,13 +1,13 @@
{
"name": "@abp/ng.feature-management",
"version": "2.4.1",
"version": "2.5.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
"@abp/ng.theme.shared": "^2.4.1"
"@abp/ng.theme.shared": "~2.5.0"
},
"publishConfig": {
"access": "public"

3
npm/ng-packs/packages/feature-management/src/lib/enums/components.ts

@ -0,0 +1,3 @@
export const enum eFeatureManagementComponents {
FeatureManagement = 'FeatureManagement.FeatureManagementComponent',
}

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

@ -1,2 +1,3 @@
export * from './lib/feature-management.module';
export * from './lib/components';
export * from './lib/enums/components';

2
npm/ng-packs/packages/identity-config/package.json

@ -1,6 +1,6 @@
{
"name": "@abp/ng.identity.config",
"version": "2.4.1",
"version": "2.5.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",

8
npm/ng-packs/packages/identity/package.json

@ -1,15 +1,15 @@
{
"name": "@abp/ng.identity",
"version": "2.4.1",
"version": "2.5.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
"@abp/ng.identity.config": "^2.4.1",
"@abp/ng.permission-management": "^2.4.1",
"@abp/ng.theme.shared": "^2.4.1"
"@abp/ng.identity.config": "~2.5.0",
"@abp/ng.permission-management": "~2.5.0",
"@abp/ng.theme.shared": "~2.5.0"
},
"publishConfig": {
"access": "public"

2
npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.html

@ -166,7 +166,7 @@
hideBadges: { value: true }
},
outputs: { visibleChange: onVisiblePermissionChange },
componentKey: 'PermissionManagement.PermissionManagementComponent'
componentKey: permissionManagementKey
};
let init = initTemplate
"

3
npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts

@ -14,6 +14,7 @@ import {
} from '../../actions/identity.actions';
import { Identity } from '../../models/identity';
import { IdentityState } from '../../states/identity.state';
import { ePermissionManagementComponents } from '@abp/ng.permission-management';
@Component({
selector: 'abp-roles',
@ -46,6 +47,8 @@ export class RolesComponent implements OnInit {
sortKey = '';
permissionManagementKey = ePermissionManagementComponents.PermissionManagement;
@ViewChild('formRef', { static: false, read: ElementRef })
formRef: ElementRef<HTMLFormElement>;

2
npm/ng-packs/packages/identity/src/lib/components/users/users.component.html

@ -262,7 +262,7 @@
visible: { value: visiblePermissions, twoWay: true }
},
outputs: { visibleChange: onVisiblePermissionChange },
componentKey: 'PermissionManagement.PermissionManagementComponent'
componentKey: permissionManagementKey
};
let init = initTemplate
"

3
npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts

@ -24,6 +24,7 @@ import {
import { Identity } from '../../models/identity';
import { IdentityService } from '../../services/identity.service';
import { IdentityState } from '../../states/identity.state';
import { ePermissionManagementComponents } from '@abp/ng.permission-management';
@Component({
selector: 'abp-users',
templateUrl: './users.component.html',
@ -62,6 +63,8 @@ export class UsersComponent implements OnInit {
sortKey = '';
permissionManagementKey = ePermissionManagementComponents.PermissionManagement;
trackByFn: TrackByFunction<AbstractControl> = (index, item) => Object.keys(item)[0] || index;
onVisiblePermissionChange = event => {

4
npm/ng-packs/packages/identity/src/lib/enums/components.ts

@ -0,0 +1,4 @@
export const enum eIdentityComponents {
Roles = 'Identity.RolesComponent',
Users = 'Identity.UsersComponent',
}

5
npm/ng-packs/packages/identity/src/lib/identity-routing.module.ts

@ -10,6 +10,7 @@ import { NgModule, Type } from '@angular/core';
import { RouterModule, Routes, Router, ActivatedRoute } from '@angular/router';
import { RolesComponent } from './components/roles/roles.component';
import { UsersComponent } from './components/users/users.component';
import { eIdentityComponents } from './enums/components';
const routes: Routes = [
{ path: '', redirectTo: 'roles', pathMatch: 'full' },
@ -24,7 +25,7 @@ const routes: Routes = [
data: {
requiredPolicy: 'AbpIdentity.Roles',
replaceableComponent: {
key: 'Identity.RolesComponent',
key: eIdentityComponents.Roles,
defaultComponent: RolesComponent,
} as ReplaceableComponents.RouteData<RolesComponent>,
},
@ -35,7 +36,7 @@ const routes: Routes = [
data: {
requiredPolicy: 'AbpIdentity.Users',
replaceableComponent: {
key: 'Identity.UsersComponent',
key: eIdentityComponents.Users,
defaultComponent: UsersComponent,
} as ReplaceableComponents.RouteData<UsersComponent>,
},

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

@ -4,6 +4,7 @@
export * from './lib/identity.module';
export * from './lib/actions/identity.actions';
export * from './lib/enums/components';
export * from './lib/components';
export * from './lib/models/identity';
export * from './lib/services';

4
npm/ng-packs/packages/permission-management/package.json

@ -1,13 +1,13 @@
{
"name": "@abp/ng.permission-management",
"version": "2.4.1",
"version": "2.5.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
"@abp/ng.theme.shared": "^2.4.1"
"@abp/ng.theme.shared": "~2.5.0"
},
"publishConfig": {
"access": "public"

3
npm/ng-packs/packages/permission-management/src/lib/enums/components.ts

@ -0,0 +1,3 @@
export const enum ePermissionManagementComponents {
PermissionManagement = 'PermissionManagement.PermissionManagementComponent',
}

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

@ -5,6 +5,7 @@
export * from './lib/permission-management.module';
export * from './lib/actions';
export * from './lib/components';
export * from './lib/enums/components';
export * from './lib/models';
export * from './lib/services';
export * from './lib/states';

2
npm/ng-packs/packages/setting-management-config/package.json

@ -1,6 +1,6 @@
{
"name": "@abp/ng.setting-management.config",
"version": "2.4.1",
"version": "2.5.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",

6
npm/ng-packs/packages/setting-management/package.json

@ -1,14 +1,14 @@
{
"name": "@abp/ng.setting-management",
"version": "2.4.1",
"version": "2.5.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
"@abp/ng.setting-management.config": "^2.4.1",
"@abp/ng.theme.shared": "^2.4.1"
"@abp/ng.setting-management.config": "~2.5.0",
"@abp/ng.theme.shared": "~2.5.0"
},
"publishConfig": {
"access": "public"

3
npm/ng-packs/packages/setting-management/src/lib/enums/components.ts

@ -0,0 +1,3 @@
export const enum eSettingManagementComponents {
SettingManagement = 'SettingManagement.SettingManagementComponent',
}

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

@ -6,6 +6,7 @@ import {
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { SettingManagementComponent } from './components/setting-management.component';
import { eSettingManagementComponents } from './enums/components';
const routes: Routes = [
{
@ -18,7 +19,7 @@ const routes: Routes = [
data: {
requiredPolicy: 'AbpAccount.SettingManagement',
replaceableComponent: {
key: 'SettingManagement.SettingManagementComponent',
key: eSettingManagementComponents.SettingManagement,
defaultComponent: SettingManagementComponent,
} as ReplaceableComponents.RouteData,
},

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

@ -1,2 +1,3 @@
export * from './lib/setting-management.module';
export * from './lib/components/setting-management.component';
export * from './lib/enums/components';

2
npm/ng-packs/packages/tenant-management-config/package.json

@ -1,6 +1,6 @@
{
"name": "@abp/ng.tenant-management.config",
"version": "2.4.1",
"version": "2.5.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",

8
npm/ng-packs/packages/tenant-management/package.json

@ -1,15 +1,15 @@
{
"name": "@abp/ng.tenant-management",
"version": "2.4.1",
"version": "2.5.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
"@abp/ng.feature-management": "^2.4.1",
"@abp/ng.tenant-management.config": "^2.4.1",
"@abp/ng.theme.shared": "^2.4.1"
"@abp/ng.feature-management": "~2.5.0",
"@abp/ng.tenant-management.config": "~2.5.0",
"@abp/ng.theme.shared": "~2.5.0"
},
"publishConfig": {
"access": "public"

10
npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html

@ -141,7 +141,9 @@
<input type="text" id="name" class="form-control" formControlName="name" autofocus />
</div>
<div class="form-group" *ngIf="tenantForm.controls.adminEmailAddress">
<label for="name">{{ 'AbpTenantManagement::DisplayName:AdminEmailAddress' | abpLocalization }}</label>
<label for="name">{{
'AbpTenantManagement::DisplayName:AdminEmailAddress' | abpLocalization
}}</label>
<input
autocomplete="email"
type="email"
@ -151,7 +153,9 @@
/>
</div>
<div class="form-group" *ngIf="tenantForm.controls.adminPassword">
<label for="name">{{ 'AbpTenantManagement::DisplayName:AdminPassword' | abpLocalization }}</label>
<label for="name">{{
'AbpTenantManagement::DisplayName:AdminPassword' | abpLocalization
}}</label>
<input
autocomplete="new-password"
type="password"
@ -203,7 +207,7 @@
visible: { value: visibleFeatures, twoWay: true }
},
outputs: { visibleChange: onVisibleFeaturesChange },
componentKey: 'FeatureManagement.FeatureManagementComponent'
componentKey: featureManagementKey
}"
[(visible)]="visibleFeatures"
providerName="T"

3
npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.ts

@ -14,6 +14,7 @@ import {
} from '../../actions/tenant-management.actions';
import { TenantManagementService } from '../../services/tenant-management.service';
import { TenantManagementState } from '../../states/tenant-management.state';
import { eFeatureManagementComponents } from '@abp/ng.feature-management';
interface SelectedModalContent {
type: 'saveConnStr' | 'saveTenant';
@ -60,6 +61,8 @@ export class TenantsComponent implements OnInit {
sortKey = '';
featureManagementKey = eFeatureManagementComponents.FeatureManagement;
get hasSelectedTenant(): boolean {
return Boolean(this.selected.id);
}

3
npm/ng-packs/packages/tenant-management/src/lib/enums/components.ts

@ -0,0 +1,3 @@
export const enum eTenantManagementComponents {
Tenants = 'TenantManagement.TenantsComponent',
}

3
npm/ng-packs/packages/tenant-management/src/lib/tenant-management-routing.module.ts

@ -8,6 +8,7 @@ import {
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { TenantsComponent } from './components/tenants/tenants.component';
import { eTenantManagementComponents } from './enums/components';
const routes: Routes = [
{ path: '', redirectTo: 'tenants', pathMatch: 'full' },
@ -22,7 +23,7 @@ const routes: Routes = [
data: {
requiredPolicy: 'AbpTenantManagement.Tenants',
replaceableComponent: {
key: 'TenantManagement.TenantsComponent',
key: eTenantManagementComponents.Tenants,
defaultComponent: TenantsComponent,
} as ReplaceableComponents.RouteData<TenantsComponent>,
},

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

@ -1,6 +1,7 @@
export * from './lib/tenant-management.module';
export * from './lib/actions';
export * from './lib/components';
export * from './lib/enums/components';
export * from './lib/models';
export * from './lib/services';
export * from './lib/states';

4
npm/ng-packs/packages/theme-basic/package.json

@ -1,13 +1,13 @@
{
"name": "@abp/ng.theme.basic",
"version": "2.4.1",
"version": "2.5.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
"@abp/ng.theme.shared": "^2.4.1"
"@abp/ng.theme.shared": "~2.5.0"
},
"publishConfig": {
"access": "public"

5
npm/ng-packs/packages/theme-basic/src/lib/enums/components.ts

@ -0,0 +1,5 @@
export const enum eThemeBasicComponents {
ApplicationLayout = 'Theme.ApplicationLayoutComponent',
AccountLayout = 'Theme.AccountLayoutComponent',
EmptyLayout = 'Theme.EmptyLayoutComponent',
}

7
npm/ng-packs/packages/theme-basic/src/lib/services/initial.service.ts

@ -5,6 +5,7 @@ import styles from '../constants/styles';
import { ApplicationLayoutComponent } from '../components/application-layout/application-layout.component';
import { AccountLayoutComponent } from '../components/account-layout/account-layout.component';
import { EmptyLayoutComponent } from '../components/empty-layout/empty-layout.component';
import { eThemeBasicComponents } from '../enums/components';
@Injectable({ providedIn: 'root' })
export class InitialService {
@ -13,15 +14,15 @@ export class InitialService {
this.store.dispatch([
new AddReplaceableComponent({
key: 'Theme.ApplicationLayoutComponent',
key: eThemeBasicComponents.ApplicationLayout,
component: ApplicationLayoutComponent,
}),
new AddReplaceableComponent({
key: 'Theme.AccountLayoutComponent',
key: eThemeBasicComponents.AccountLayout,
component: AccountLayoutComponent,
}),
new AddReplaceableComponent({
key: 'Theme.EmptyLayoutComponent',
key: eThemeBasicComponents.EmptyLayout,
component: EmptyLayoutComponent,
}),
]);

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

@ -5,5 +5,6 @@
export * from './lib/theme-basic.module';
export * from './lib/actions';
export * from './lib/components';
export * from './lib/enums/components';
export * from './lib/models';
export * from './lib/states';

4
npm/ng-packs/packages/theme-shared/package.json

@ -1,13 +1,13 @@
{
"name": "@abp/ng.theme.shared",
"version": "2.4.1",
"version": "2.5.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
"@abp/ng.core": "^2.4.1",
"@abp/ng.core": "~2.5.0",
"@fortawesome/fontawesome-free": "^5.12.1",
"@ng-bootstrap/ng-bootstrap": "^5.3.0",
"@ngx-validate/core": "^0.0.7",

26
npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.ts

@ -102,17 +102,7 @@ export class ModalComponent implements OnDestroy {
destroy$ = new Subject<void>();
get isFormDirty(): boolean {
let node: HTMLDivElement;
if (!this.modalContent) {
node = document.getElementById('modal-container') as HTMLDivElement;
}
const nodes = getFlatNodes(
((node || this.modalContent.nativeElement).querySelector('#abp-modal-body') as HTMLElement)
.childNodes,
);
return hasNgDirty(nodes);
return Boolean(document.querySelector('.modal-dialog .ng-dirty'));
}
constructor(private renderer: Renderer2, private confirmationService: ConfirmationService) {}
@ -178,17 +168,3 @@ export class ModalComponent implements OnDestroy {
this.init.emit();
}
}
function getFlatNodes(nodes: NodeList): HTMLElement[] {
return Array.from(nodes).reduce(
(acc, val) => [
...acc,
...(val.childNodes && val.childNodes.length ? getFlatNodes(val.childNodes) : [val]),
],
[],
);
}
function hasNgDirty(nodes: HTMLElement[]) {
return nodes.findIndex(node => (node.className || '').indexOf('ng-dirty') > -1) > -1;
}

2
npm/ng-packs/packages/theme-shared/src/lib/directives/loading.directive.ts

@ -54,7 +54,7 @@ export class LoadingDirective implements OnInit, OnDestroy {
if (newValue && !this.rootNode) {
this.rootNode = (this.componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0];
this.targetElement.appendChild(this.rootNode);
} else {
} else if (this.rootNode) {
this.renderer.removeChild(this.rootNode.parentElement, this.rootNode);
this.rootNode = null;
}

156
npm/ng-packs/yarn.lock

@ -2,119 +2,119 @@
# yarn lockfile v1
"@abp/ng.account.config@^2.4.0", "@abp/ng.account.config@~2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@abp/ng.account.config/-/ng.account.config-2.4.0.tgz#1319fe8eb3eb61c4787e69b3abaa589f9d3ce578"
integrity sha512-y+VDH9gDCoVYIGVB60HrWBm0W8GuwRrXZj8WSABUNdWF+6LmIKEs7dAHj0NQAbePqdiDrFgIMLCAxqTctIVveA==
"@abp/ng.account.config@^2.5.0", "@abp/ng.account.config@~2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@abp/ng.account.config/-/ng.account.config-2.5.0.tgz#08122916985765f62b0cd9ef2d9a8609a485131b"
integrity sha512-Ld7nsGOw3TafWaJ64umHB3NwI4tgeLKkhU6IO7/Dbx0UZvcRepND07pLPAbpgxPxSffNDmREHnA+lrtP1i96vA==
dependencies:
tslib "^1.9.0"
"@abp/ng.account@~2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@abp/ng.account/-/ng.account-2.4.0.tgz#f8d86f1bc352278c7fdbfed5d8b68f66da7f6c9e"
integrity sha512-tgnwX625ALauTU63CLkFyboVw1Z73/Ax7hFliP1wLZap1PbYsowijWtA2rN8qxYIjNTD9F7IIgELzMcnMcac0A==
"@abp/ng.account@~2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@abp/ng.account/-/ng.account-2.5.0.tgz#b5271da490136f7e23cbae21588e9fd6f8f398c7"
integrity sha512-C6RD9L0+gkyjuCSUGP9C55h+oMIoPNkSe3fF4RWkLaqb1hLriIEqyeTODHnhdV4TfEVkVCmhS88XhoNGwmFz/g==
dependencies:
"@abp/ng.account.config" "^2.4.0"
"@abp/ng.theme.shared" "^2.4.0"
"@abp/ng.account.config" "^2.5.0"
"@abp/ng.theme.shared" "^2.5.0"
tslib "^1.9.0"
"@abp/ng.core@^2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@abp/ng.core/-/ng.core-2.4.0.tgz#e666445048e0e35d805957a959d51002d4444342"
integrity sha512-+scZSdVA6Lcp7N+91w/d/EaaKDhBbEeXJpvxa6PooWSTACHzmmMk8uIKLvDC/LHtoyzNXkETA8beHCtpb0mhYw==
"@abp/ng.core@^2.5.0", "@abp/ng.core@~2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@abp/ng.core/-/ng.core-2.5.0.tgz#e7168615b4078e3fa494c4efcc69842acbd2c627"
integrity sha512-opYkOFCKeU17YvNJhfcG1dOwZZ4F2QGspTNTagNZ9fepmeNl0yqFamFdRM6irfEEL3cOBQhUpI2NQZP+ugLOEg==
dependencies:
"@abp/utils" "~2.3.0"
"@angular/localize" "~9.0.2"
"@abp/utils" "^2.4.0"
"@angular/localize" "~9.1.0"
"@ngxs/router-plugin" "^3.6.2"
"@ngxs/storage-plugin" "^3.6.2"
"@ngxs/store" "^3.6.2"
angular-oauth2-oidc "^8.0.4"
just-clone "3.1.0"
just-clone "^3.1.0"
just-compare "^1.3.0"
snq "^1.0.3"
ts-toolbelt "^6.3.6"
tslib "^1.9.0"
"@abp/ng.feature-management@^2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@abp/ng.feature-management/-/ng.feature-management-2.4.0.tgz#305e6566cc379071dfb7699e7033dd9077fd79ff"
integrity sha512-Td4xEx/KuHq2O2Vzaclsw1py+enaerc7Mmyr0gingDLbdndj/8Sh+iwtGOW3OnacMdzELN5sm7cXdDU//5kpSQ==
"@abp/ng.feature-management@^2.5.0", "@abp/ng.feature-management@~2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@abp/ng.feature-management/-/ng.feature-management-2.5.0.tgz#3bc4501a2abbe6b6447e5b4a2b2d86fb07ce8a59"
integrity sha512-keZ3gCDMvU/e17tsBBrZpLmpIpDm/2TTSAmCoRRy3GH4BQICXr/XJmssStNx7V7sdo6vAPiW9pcM9zI/C8IrBw==
dependencies:
"@abp/ng.theme.shared" "^2.4.0"
"@abp/ng.theme.shared" "^2.5.0"
tslib "^1.9.0"
"@abp/ng.identity.config@^2.4.0", "@abp/ng.identity.config@~2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@abp/ng.identity.config/-/ng.identity.config-2.4.0.tgz#a8b0e975277d4e41b1c628f75c2228bee26742ee"
integrity sha512-Co7PjGrkJux3TwjoX51inZ6JZDNcHr5Cm1Ac6gkQOZYzzUX0Hes6tEOBirs81PwFTARPXz7lqXfbKMmvYkAF7Q==
"@abp/ng.identity.config@^2.5.0", "@abp/ng.identity.config@~2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@abp/ng.identity.config/-/ng.identity.config-2.5.0.tgz#d5daad786ae8c6d61e887f4ec52497635abfff94"
integrity sha512-nvVkRzT3gsLZTzjjMkR20FjmmnxDC7viUNRSjp4ufGqHfWbUaNS16chrWqvr+0f7JEzeULKWfXQEjWafqLWBbg==
dependencies:
tslib "^1.9.0"
"@abp/ng.identity@~2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@abp/ng.identity/-/ng.identity-2.4.0.tgz#8d628316d07891338b6c8c743a2f66398aa6cbe2"
integrity sha512-O8S3kinhQ0qGDMWdwkOpWci8WF0z8YraZmw3TsPHOwaaU3IHJqKZ66ycZUmWGeeF8dPY+AwExyK0RxSTI9wVgA==
"@abp/ng.identity@~2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@abp/ng.identity/-/ng.identity-2.5.0.tgz#b2e2dea559ce89dce52a82cf02d612864076ab2c"
integrity sha512-RIZnYRhNMbyjaX/Nb43fgG8/hBcvfBLpd3ZpP6arJDUY4YLvN3zvGJ9d52+3nGgj9WpXZTm+/X7c8Iuu5a2ocA==
dependencies:
"@abp/ng.identity.config" "^2.4.0"
"@abp/ng.permission-management" "^2.4.0"
"@abp/ng.theme.shared" "^2.4.0"
"@abp/ng.identity.config" "^2.5.0"
"@abp/ng.permission-management" "^2.5.0"
"@abp/ng.theme.shared" "^2.5.0"
tslib "^1.9.0"
"@abp/ng.permission-management@^2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@abp/ng.permission-management/-/ng.permission-management-2.4.0.tgz#a9978fc94d9a4a638effc1334d98727da9eef415"
integrity sha512-fxJIKL+WaNyQrUHMICEOWxRKMlowCmU/Cmptl/XF3WoScsMDuvCqXBZRdFJWYoBQBC0lWA9CyXFIGMBKb+kghQ==
"@abp/ng.permission-management@^2.5.0", "@abp/ng.permission-management@~2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@abp/ng.permission-management/-/ng.permission-management-2.5.0.tgz#c769a97aee8517ec724dc5b7756e1dfc8fe7fcf1"
integrity sha512-grmJ46Qf26cwGfDt5acL6eXXWBDgjvL/04/ZLtxsP4Hf+tSlnL/1rWz5fxMF8548sQ6vZlVIdrSa4Tz/Dh0WLw==
dependencies:
"@abp/ng.theme.shared" "^2.4.0"
"@abp/ng.theme.shared" "^2.5.0"
tslib "^1.9.0"
"@abp/ng.setting-management.config@^2.4.0", "@abp/ng.setting-management.config@~2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@abp/ng.setting-management.config/-/ng.setting-management.config-2.4.0.tgz#fea07f79124c921f5ea0cd04ffdba99f9b8d9df6"
integrity sha512-H2PNtudIDMLeW4gZrCjdjs5ugeWMLEgaNZ342mDa3yU/Is4sgcOfyPQ+b0b1mmf0ggxJfEHsOoAAnvHLivcx0Q==
"@abp/ng.setting-management.config@^2.5.0", "@abp/ng.setting-management.config@~2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@abp/ng.setting-management.config/-/ng.setting-management.config-2.5.0.tgz#4841d73b9df7763084dcac45bd656fbee87c4602"
integrity sha512-mSihz0aoB5Ly+tanPE4Vh3Aam9g3nDtSQelUuFJoyRnw1HSmMmWOqnJi9UEguhCEBtww9G5P6OC8/icpHaq/3Q==
dependencies:
tslib "^1.9.0"
"@abp/ng.setting-management@~2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@abp/ng.setting-management/-/ng.setting-management-2.4.0.tgz#46163c5a85c97d1773b8be10ddf1e976667f7f7d"
integrity sha512-ZQa4AhcI8LPI4FmijQs75FKYb44tvpvL+9kApT5seYF/h5gDHXRwgUEjzubtI8z1tdsIJYKhEKTEiZB2nThAPQ==
"@abp/ng.setting-management@~2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@abp/ng.setting-management/-/ng.setting-management-2.5.0.tgz#32291ebc6610838f825cc79d091700d578586e0a"
integrity sha512-maamVGc5L/44XsRANXaVYLn9uocGUH8RUtKXZT9iKdlcsemKa7xEMzZ84lzoiAu+xAfqfJm/R7TolC/gWonUDg==
dependencies:
"@abp/ng.setting-management.config" "^2.4.0"
"@abp/ng.theme.shared" "^2.4.0"
"@abp/ng.setting-management.config" "^2.5.0"
"@abp/ng.theme.shared" "^2.5.0"
tslib "^1.9.0"
"@abp/ng.tenant-management.config@^2.4.0", "@abp/ng.tenant-management.config@~2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@abp/ng.tenant-management.config/-/ng.tenant-management.config-2.4.0.tgz#46ef1ace585686b7de642417cd335cadd9f0515b"
integrity sha512-cnS5liA9/oWsPuKL7TbngO22s+buZcSHTzNMvn6voEloBgt2kUNLoDblQF0Z55o3XQq16jdxPMv666bZb/PDvA==
"@abp/ng.tenant-management.config@^2.5.0", "@abp/ng.tenant-management.config@~2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@abp/ng.tenant-management.config/-/ng.tenant-management.config-2.5.0.tgz#00b3abae5d513d61fcc0aae6c73d64a61d087e5f"
integrity sha512-gaW9n+Fo9AH2OPw3V3qaxTvG8zIe4jjMXKIvzqk+e4djXVjLHZ3fdP+uyJqpMmaypyd2REoVCARqVFHgvZBzaA==
dependencies:
tslib "^1.9.0"
"@abp/ng.tenant-management@~2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@abp/ng.tenant-management/-/ng.tenant-management-2.4.0.tgz#3e70bb32a45d3ac0962782d0c22db9891c46a757"
integrity sha512-iKOWU0aRTUwGujdQprluAW3aAb6OuAtxB09FI7fmWyK5svVzamLfHa12tl+f4nNpJ7U9de/4zMc3R6LQNnvp/A==
"@abp/ng.tenant-management@~2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@abp/ng.tenant-management/-/ng.tenant-management-2.5.0.tgz#7452ab92d9d7f2bf1200a956e7ad8800c4ccebb1"
integrity sha512-7O7tsJl2OVbEIiSJ17r+ZJFcynOo89el0RREwihACkBz+2TeQoHo2ycZ7oPXauMy1aRjsjpkmbCJGP28OD0a6w==
dependencies:
"@abp/ng.feature-management" "^2.4.0"
"@abp/ng.tenant-management.config" "^2.4.0"
"@abp/ng.theme.shared" "^2.4.0"
"@abp/ng.feature-management" "^2.5.0"
"@abp/ng.tenant-management.config" "^2.5.0"
"@abp/ng.theme.shared" "^2.5.0"
tslib "^1.9.0"
"@abp/ng.theme.basic@~2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@abp/ng.theme.basic/-/ng.theme.basic-2.4.0.tgz#a9b8b93e92f4a0307ca73d79f5b8bf6163be4740"
integrity sha512-+bkOC+nm8FXZx/emGrKxVBPJNRsd/jGCzc98B9YS9mGMncKGWXxS27pAfxB7XxYxALrQL3Kp8Ptuwx5Jkw/t8g==
"@abp/ng.theme.basic@~2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@abp/ng.theme.basic/-/ng.theme.basic-2.5.0.tgz#ef13f448ea6f356a5571d364da00e971e715cfec"
integrity sha512-+q22k5AfxgFRtGP4YO602jmeeuH2pfVBzCcJUmwRzE2xiINx4e55zCwKiFl5YvNUttcKkaNNhj9LcOXU6W42rw==
dependencies:
"@abp/ng.theme.shared" "^2.4.0"
"@abp/ng.theme.shared" "^2.5.0"
tslib "^1.9.0"
"@abp/ng.theme.shared@^2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@abp/ng.theme.shared/-/ng.theme.shared-2.4.0.tgz#b9e4cda7b0c5ae95e00ca2ffa35d7a4b94ad2ee2"
integrity sha512-CnKPUzfiNWhnKs93YhUJxgotAqmJnZYht6IiyPc0Ymtu6pJsk+lQLLuKC3cFbzkq9ORoqJydBb1JZWwccDbDuA==
"@abp/ng.theme.shared@^2.5.0", "@abp/ng.theme.shared@~2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@abp/ng.theme.shared/-/ng.theme.shared-2.5.0.tgz#a9c53f95f1a0bdf2fe046838e64c658ce54c5655"
integrity sha512-iRft0LWh9dzpnrKxmo0AuAXND6+o3Eov6LFpNbZD7guuZfeFVehcSX/X0ZYIpq1a/A7cfegtMEokdwRb0cGdGA==
dependencies:
"@abp/ng.core" "^2.4.0"
"@abp/ng.core" "^2.5.0"
"@fortawesome/fontawesome-free" "^5.12.1"
"@ng-bootstrap/ng-bootstrap" "^5.3.0"
"@ngx-validate/core" "^0.0.7"
@ -129,13 +129,6 @@
dependencies:
just-compare "^1.3.0"
"@abp/utils@~2.3.0":
version "2.3.1"
resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-2.3.1.tgz#728b978d598a98b643562250be54c92988b986e5"
integrity sha512-sZ1nrl8pV1Zx3WAqHRUQ2V3aJlsjaq1ggg2VIPYY4FjCYHFZ3L+Fkq5cPPZb/MczG1YZpAQiMtCJ/+8slvPHHQ==
dependencies:
just-compare "^1.3.0"
"@angular-builders/jest@^8.2.0":
version "8.3.2"
resolved "https://registry.yarnpkg.com/@angular-builders/jest/-/jest-8.3.2.tgz#669c350c9df2e3afc9ae048c5067759c36113728"
@ -362,15 +355,6 @@
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-8.2.14.tgz#e18b27a6841577ce489ad31540150da5a444ca37"
integrity sha512-7EhN9JJbAJcH2xCa+rIOmekjiEuB0qwPdHuD5qn/wwMfRzMZo+Db4hHbR9KHrLH6H82PTwYKye/LLpDaZqoHOA==
"@angular/localize@~9.0.2":
version "9.0.2"
resolved "https://registry.yarnpkg.com/@angular/localize/-/localize-9.0.2.tgz#0139ad35fda754b8730fae20c87feb1a85457a9e"
integrity sha512-Dd/aNZXPSVIU5+AuX25Qm8fBCN95eL9fad6K+tNY+hdF6ruz8u2R4AVTHtTKtM6gzWeG8rJ/rt+7qh667HV09A==
dependencies:
"@babel/core" "7.8.3"
glob "7.1.2"
yargs "13.1.0"
"@angular/localize@~9.1.0":
version "9.1.1"
resolved "https://registry.yarnpkg.com/@angular/localize/-/localize-9.1.1.tgz#267d7cecb288b3019482744330da0ef9e049c85d"
@ -7605,7 +7589,7 @@ jszip@^3.1.3:
readable-stream "~2.3.6"
set-immediate-shim "~1.0.1"
just-clone@3.1.0, just-clone@^3.1.0:
just-clone@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/just-clone/-/just-clone-3.1.0.tgz#10efc422e9b041355c43b8076d7b768b7a09fbbd"
integrity sha512-sROn15yHaeNYSTG49HmfbQLtsZvMBb2COvVofNXbeUXx6GkERkdjG3dfejD0fe78gdHJLyS+fOz897H73S8LqA==

6
npm/packs/anchor-js/package.json

@ -1,12 +1,12 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/anchor-js",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/core": "^2.4.1",
"@abp/core": "^2.5.0",
"anchor-js": "^4.2.2"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

6
npm/packs/aspnetcore.mvc.ui.theme.basic/package.json

@ -1,11 +1,11 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/aspnetcore.mvc.ui.theme.basic",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/aspnetcore.mvc.ui.theme.shared": "^2.4.1"
"@abp/aspnetcore.mvc.ui.theme.shared": "^2.5.0"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

32
npm/packs/aspnetcore.mvc.ui.theme.shared/package.json

@ -1,24 +1,24 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/aspnetcore.mvc.ui.theme.shared",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/aspnetcore.mvc.ui": "^2.4.1",
"@abp/bootstrap": "^2.4.1",
"@abp/bootstrap-datepicker": "^2.4.1",
"@abp/datatables.net-bs4": "^2.4.1",
"@abp/font-awesome": "^2.4.1",
"@abp/jquery-form": "^2.4.1",
"@abp/jquery-validation-unobtrusive": "^2.4.1",
"@abp/lodash": "^2.4.1",
"@abp/luxon": "^2.4.1",
"@abp/malihu-custom-scrollbar-plugin": "^2.4.1",
"@abp/select2": "^2.4.1",
"@abp/sweetalert": "^2.4.1",
"@abp/timeago": "^2.4.1",
"@abp/toastr": "^2.4.1"
"@abp/aspnetcore.mvc.ui": "^2.5.0",
"@abp/bootstrap": "^2.5.0",
"@abp/bootstrap-datepicker": "^2.5.0",
"@abp/datatables.net-bs4": "^2.5.0",
"@abp/font-awesome": "^2.5.0",
"@abp/jquery-form": "^2.5.0",
"@abp/jquery-validation-unobtrusive": "^2.5.0",
"@abp/lodash": "^2.5.0",
"@abp/luxon": "^2.5.0",
"@abp/malihu-custom-scrollbar-plugin": "^2.5.0",
"@abp/select2": "^2.5.0",
"@abp/sweetalert": "^2.5.0",
"@abp/timeago": "^2.5.0",
"@abp/toastr": "^2.5.0"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

4
npm/packs/aspnetcore.mvc.ui/package.json

@ -1,5 +1,5 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/aspnetcore.mvc.ui",
"publishConfig": {
"access": "public"
@ -12,5 +12,5 @@
"path": "^0.12.7",
"rimraf": "^3.0.0"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

10
npm/packs/blogging/package.json

@ -1,13 +1,13 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/blogging",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/aspnetcore.mvc.ui.theme.shared": "^2.4.1",
"@abp/owl.carousel": "^2.4.1",
"@abp/tui-editor": "^2.4.1"
"@abp/aspnetcore.mvc.ui.theme.shared": "^2.5.0",
"@abp/owl.carousel": "^2.5.0",
"@abp/tui-editor": "^2.5.0"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

4
npm/packs/bootstrap-datepicker/package.json

@ -1,5 +1,5 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/bootstrap-datepicker",
"publishConfig": {
"access": "public"
@ -7,5 +7,5 @@
"dependencies": {
"bootstrap-datepicker": "^1.9.0"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

6
npm/packs/bootstrap/package.json

@ -1,12 +1,12 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/bootstrap",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/core": "^2.4.1",
"@abp/core": "^2.5.0",
"bootstrap": "^4.3.1"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

4
npm/packs/chart.js/package.json

@ -1,5 +1,5 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/chart.js",
"publishConfig": {
"access": "public"
@ -7,5 +7,5 @@
"dependencies": {
"chart.js": "^2.9.3"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

6
npm/packs/clipboard/package.json

@ -1,12 +1,12 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/clipboard",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/core": "^2.4.1",
"@abp/core": "^2.5.0",
"clipboard": "^2.0.4"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

6
npm/packs/codemirror/package.json

@ -1,12 +1,12 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/codemirror",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/core": "^2.4.1",
"@abp/core": "^2.5.0",
"codemirror": "^5.49.2"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

4
npm/packs/core/package.json

@ -1,8 +1,8 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/core",
"publishConfig": {
"access": "public"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

6
npm/packs/datatables.net-bs4/package.json

@ -1,12 +1,12 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/datatables.net-bs4",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/datatables.net": "^2.4.1",
"@abp/datatables.net": "^2.5.0",
"datatables.net-bs4": "^1.10.20"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

6
npm/packs/datatables.net/package.json

@ -1,12 +1,12 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/datatables.net",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/core": "^2.4.1",
"@abp/core": "^2.5.0",
"datatables.net": "^1.10.20"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

14
npm/packs/docs/package.json

@ -1,15 +1,15 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/docs",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/anchor-js": "^2.4.1",
"@abp/clipboard": "^2.4.1",
"@abp/malihu-custom-scrollbar-plugin": "^2.4.1",
"@abp/popper.js": "^2.4.1",
"@abp/prismjs": "^2.4.1"
"@abp/anchor-js": "^2.5.0",
"@abp/clipboard": "^2.5.0",
"@abp/malihu-custom-scrollbar-plugin": "^2.5.0",
"@abp/popper.js": "^2.5.0",
"@abp/prismjs": "^2.5.0"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

4
npm/packs/flag-icon-css/package.json

@ -1,5 +1,5 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/flag-icon-css",
"publishConfig": {
"access": "public"
@ -7,5 +7,5 @@
"dependencies": {
"flag-icon-css": "^3.4.5"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

6
npm/packs/font-awesome/package.json

@ -1,12 +1,12 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/font-awesome",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/core": "^2.4.1",
"@abp/core": "^2.5.0",
"@fortawesome/fontawesome-free": "^5.11.2"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

6
npm/packs/highlight.js/package.json

@ -1,11 +1,11 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/highlight.js",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/core": "^2.4.1"
"@abp/core": "^2.5.0"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

6
npm/packs/jquery-form/package.json

@ -1,12 +1,12 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/jquery-form",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/jquery": "^2.4.1",
"@abp/jquery": "^2.5.0",
"jquery-form": "^4.2.2"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

6
npm/packs/jquery-validation-unobtrusive/package.json

@ -1,12 +1,12 @@
{
"version": "2.4.1",
"version": "2.5.0",
"name": "@abp/jquery-validation-unobtrusive",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/jquery-validation": "^2.4.1",
"@abp/jquery-validation": "^2.5.0",
"jquery-validation-unobtrusive": "^3.2.11"
},
"gitHead": "0c72682d406026760da2f832a493145beae3a5c0"
"gitHead": "a9a36b8a4681df04377497addf94b15e6c521664"
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save