From 0139ee819433699a7c5e54fe3019820e59d7f292 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 7 Apr 2020 11:00:29 +0300 Subject: [PATCH 01/54] docs: add content strategy documentation --- docs/en/UI/Angular/Content-Strategy.md | 95 ++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 docs/en/UI/Angular/Content-Strategy.md diff --git a/docs/en/UI/Angular/Content-Strategy.md b/docs/en/UI/Angular/Content-Strategy.md new file mode 100644 index 0000000000..e3d3ca9849 --- /dev/null +++ b/docs/en/UI/Angular/Content-Strategy.md @@ -0,0 +1,95 @@ +# ContentStrategy + +`ContentStrategy` is an abstract class exposed by @abp/ng.core package. It helps you create inline scripts or styles. + +## API + + +### constructor + +```js +constructor( + public content: string, + protected domStrategy?: DomStrategy, + protected contentSecurityStrategy?: ContentSecurityStrategy +) +``` + +- `content` is set to `` element will place at the **end** of ``. + +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 `` element will place at the **end** of ``. + +Please refer to [ContentStrategy](./Content-Strategy.md) to see all available content strategies and how you can build your own content strategy. + + +## API + + +### inserted + +```js +inserted: Set +``` + +All previously inserted contents are stored via this property as hashes. It is a simple [JavaScript Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set). + + + +### insertContent + +```js +insertContent(strategy: ContentStrategy): void +``` + +`strategy` parameter is the primary focus here and is explained above. + + +## What's Next? + +- [TrackByService](./Track-By-Service.md) diff --git a/docs/en/UI/Angular/Lazy-Load-Service.md b/docs/en/UI/Angular/Lazy-Load-Service.md index 43ee7bc6b8..a03381869e 100644 --- a/docs/en/UI/Angular/Lazy-Load-Service.md +++ b/docs/en/UI/Angular/Lazy-Load-Service.md @@ -210,4 +210,4 @@ load(strategy: LoadingStrategy, retryTimes?: number, retryDelay?: number): Obser ## What's Next? -- [TrackByService](./Track-By-Service.md) +- [DomInsertionService](./Dom-Insertion-Service.md) diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 8034913c4c..471e215e3a 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -349,6 +349,10 @@ "text": "Lazy Loading Scripts & Styles", "path": "UI/Angular/Lazy-Load-Service.md" }, + { + "text": "DomInsertionService", + "path": "UI/Angular/Dom-Insertion-Service.md" + }, { "text": "TrackByService", "path": "UI/Angular/Track-By-Service.md" From 97ee0edf4fa8377e0ec2eb49bc04acea2a243862 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 7 Apr 2020 12:08:42 +0300 Subject: [PATCH 04/54] docs: refactor strategy docs --- .../UI/Angular/Content-Security-Strategy.md | 4 +-- docs/en/UI/Angular/Content-Strategy.md | 10 +++--- docs/en/UI/Angular/Cross-Origin-Strategy.md | 4 +-- docs/en/UI/Angular/Dom-Strategy.md | 32 ++++++++++++++++--- docs/en/UI/Angular/Loading-Strategy.md | 10 +++--- 5 files changed, 41 insertions(+), 19 deletions(-) diff --git a/docs/en/UI/Angular/Content-Security-Strategy.md b/docs/en/UI/Angular/Content-Security-Strategy.md index c45cf23c58..f32317c9ca 100644 --- a/docs/en/UI/Angular/Content-Security-Strategy.md +++ b/docs/en/UI/Angular/Content-Security-Strategy.md @@ -50,7 +50,7 @@ Predefined content security strategies are accessible via `CONTENT_SECURITY_STRA ### Loose ```js -Loose(nonce: string) +CONTENT_SECURITY_STRATEGY.Loose(nonce: string) ``` `nonce` will be set. @@ -59,7 +59,7 @@ Loose(nonce: string) ### None ```js -None() +CONTENT_SECURITY_STRATEGY.None() ``` Nothing will be done. diff --git a/docs/en/UI/Angular/Content-Strategy.md b/docs/en/UI/Angular/Content-Strategy.md index e3d3ca9849..8544042c32 100644 --- a/docs/en/UI/Angular/Content-Strategy.md +++ b/docs/en/UI/Angular/Content-Strategy.md @@ -57,7 +57,7 @@ Predefined content strategies are accessible via `CONTENT_STRATEGY` constant. ### AppendScriptToBody ```js -AppendScriptToBody(content: string) +CONTENT_STRATEGY.AppendScriptToBody(content: string) ``` Creates a `` 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 `` 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. +### How to Project Components & Templates + +If you pass a `ProjectionStrategy` as the first parameter of `projectContent` method, the `DomInsertionService` will resolve the projected component or template and place it at the designated target, such as containers or document body. If provided, it will also pass the component or the template a context. + +```js +const componentRef = this.domInsertionService.projectContent( + PROJECTION_STRATEGY.AppendComponentToBody(SomeOverlayComponent) +); +``` + +In the example above, `SomeOverlayComponent` component will placed at the **end** of `` and a `ComponentRef` will be returned. + +> 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. + +```js +const componentRef = this.domInsertionService.projectContent( + PROJECTION_STRATEGY.ProjectComponentToContainer( + SomeOverlayComponent, + viewContainerRefOfTarget, + { someProp: "SOME_VALUE" } + ) +); +``` + +In this example, the `viewContainerRefOfTarget`, which is a `ViewContainerRef` instance, will be cleared and `SomeOverlayComponent` component will placed inside it. Moreover, the given context will be applied, so `someProp` of the component will be set to `SOME_VALUE`. + +Please refer to [ProjectionStrategy](./Projection-Strategy.md) to see all available projection strategies and how you can build your own projection strategy. ## API ### insertContent ```js -insertContent(strategy: ContentStrategy): void +injectContent(injector: Injector): ComponentRef | EmbeddedViewRef ``` -`strategy` 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? From 31624376c49de3b5f45f564c6d5a79ff629a9072 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 10 Apr 2020 09:20:20 +0300 Subject: [PATCH 35/54] chore: replace tilde with caret for abp versions --- npm/ng-packs/packages/account/package.json | 4 ++-- npm/ng-packs/packages/identity/package.json | 6 +++--- npm/ng-packs/packages/permission-management/package.json | 2 +- npm/ng-packs/packages/setting-management/package.json | 4 ++-- npm/ng-packs/packages/tenant-management/package.json | 6 +++--- npm/ng-packs/packages/theme-basic/package.json | 2 +- npm/ng-packs/packages/theme-shared/package.json | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/npm/ng-packs/packages/account/package.json b/npm/ng-packs/packages/account/package.json index 08c92c1e21..14c3553212 100644 --- a/npm/ng-packs/packages/account/package.json +++ b/npm/ng-packs/packages/account/package.json @@ -7,8 +7,8 @@ "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.account.config": "^2.5.0", - "@abp/ng.theme.shared": "^2.5.0" + "@abp/ng.account.config": "~2.5.0", + "@abp/ng.theme.shared": "~2.5.0" }, "publishConfig": { "access": "public" diff --git a/npm/ng-packs/packages/identity/package.json b/npm/ng-packs/packages/identity/package.json index 023f373ab7..5e9930608e 100644 --- a/npm/ng-packs/packages/identity/package.json +++ b/npm/ng-packs/packages/identity/package.json @@ -7,9 +7,9 @@ "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.identity.config": "^2.5.0", - "@abp/ng.permission-management": "^2.5.0", - "@abp/ng.theme.shared": "^2.5.0" + "@abp/ng.identity.config": "~2.5.0", + "@abp/ng.permission-management": "~2.5.0", + "@abp/ng.theme.shared": "~2.5.0" }, "publishConfig": { "access": "public" diff --git a/npm/ng-packs/packages/permission-management/package.json b/npm/ng-packs/packages/permission-management/package.json index 0b538d00fa..520ec54765 100644 --- a/npm/ng-packs/packages/permission-management/package.json +++ b/npm/ng-packs/packages/permission-management/package.json @@ -7,7 +7,7 @@ "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.theme.shared": "^2.5.0" + "@abp/ng.theme.shared": "~2.5.0" }, "publishConfig": { "access": "public" diff --git a/npm/ng-packs/packages/setting-management/package.json b/npm/ng-packs/packages/setting-management/package.json index 5788bdc72b..716df5385e 100644 --- a/npm/ng-packs/packages/setting-management/package.json +++ b/npm/ng-packs/packages/setting-management/package.json @@ -7,8 +7,8 @@ "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.setting-management.config": "^2.5.0", - "@abp/ng.theme.shared": "^2.5.0" + "@abp/ng.setting-management.config": "~2.5.0", + "@abp/ng.theme.shared": "~2.5.0" }, "publishConfig": { "access": "public" diff --git a/npm/ng-packs/packages/tenant-management/package.json b/npm/ng-packs/packages/tenant-management/package.json index 8c07199b6c..49baed552f 100644 --- a/npm/ng-packs/packages/tenant-management/package.json +++ b/npm/ng-packs/packages/tenant-management/package.json @@ -7,9 +7,9 @@ "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.feature-management": "^2.5.0", - "@abp/ng.tenant-management.config": "^2.5.0", - "@abp/ng.theme.shared": "^2.5.0" + "@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" diff --git a/npm/ng-packs/packages/theme-basic/package.json b/npm/ng-packs/packages/theme-basic/package.json index 3c07884583..bfbe9e170b 100644 --- a/npm/ng-packs/packages/theme-basic/package.json +++ b/npm/ng-packs/packages/theme-basic/package.json @@ -7,7 +7,7 @@ "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.theme.shared": "^2.5.0" + "@abp/ng.theme.shared": "~2.5.0" }, "publishConfig": { "access": "public" diff --git a/npm/ng-packs/packages/theme-shared/package.json b/npm/ng-packs/packages/theme-shared/package.json index 9aece312d3..ce8ee044b9 100644 --- a/npm/ng-packs/packages/theme-shared/package.json +++ b/npm/ng-packs/packages/theme-shared/package.json @@ -7,7 +7,7 @@ "url": "https://github.com/abpframework/abp.git" }, "dependencies": { - "@abp/ng.core": "^2.5.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", From 29c567bedeb100283ca65504dbc0d2553937c75f Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 10 Apr 2020 09:21:37 +0300 Subject: [PATCH 36/54] feat: add components enum to all modules #3425 --- npm/ng-packs/.vscode/settings.json | 4 +++- .../packages/account/src/lib/account-routing.module.ts | 7 ++++--- .../auth-wrapper/auth-wrapper.component.html | 4 +--- .../components/auth-wrapper/auth-wrapper.component.ts | 3 +++ .../src/lib/components/login/login.component.html | 2 +- .../src/lib/components/login/login.component.ts | 3 +++ .../manage-profile/manage-profile.component.html | 4 ++-- .../manage-profile/manage-profile.component.ts | 5 +++++ .../lib/components/register/register.component.html | 2 +- .../src/lib/components/register/register.component.ts | 3 +++ .../packages/account/src/lib/enums/components.ts | 9 +++++++++ npm/ng-packs/packages/account/src/public-api.ts | 1 + npm/ng-packs/packages/feature-management/package.json | 2 +- .../feature-management/src/lib/enums/components.ts | 3 +++ .../packages/feature-management/src/public-api.ts | 1 + .../src/lib/components/roles/roles.component.html | 2 +- .../src/lib/components/roles/roles.component.ts | 3 +++ .../src/lib/components/users/users.component.html | 2 +- .../src/lib/components/users/users.component.ts | 3 +++ .../packages/identity/src/lib/enums/components.ts | 4 ++++ .../identity/src/lib/identity-routing.module.ts | 5 +++-- npm/ng-packs/packages/identity/src/public-api.ts | 1 + .../permission-management/src/lib/enums/components.ts | 3 +++ .../packages/permission-management/src/public-api.ts | 1 + .../setting-management/src/lib/enums/components.ts | 3 +++ .../src/lib/setting-management-routing.module.ts | 3 ++- .../packages/setting-management/src/public-api.ts | 1 + .../src/lib/components/tenants/tenants.component.html | 10 +++++++--- .../src/lib/components/tenants/tenants.component.ts | 3 +++ .../tenant-management/src/lib/enums/components.ts | 3 +++ .../src/lib/tenant-management-routing.module.ts | 3 ++- .../packages/tenant-management/src/public-api.ts | 1 + .../packages/theme-basic/src/lib/enums/components.ts | 5 +++++ .../theme-basic/src/lib/services/initial.service.ts | 7 ++++--- npm/ng-packs/packages/theme-basic/src/public-api.ts | 1 + 35 files changed, 93 insertions(+), 24 deletions(-) create mode 100644 npm/ng-packs/packages/account/src/lib/enums/components.ts create mode 100644 npm/ng-packs/packages/feature-management/src/lib/enums/components.ts create mode 100644 npm/ng-packs/packages/identity/src/lib/enums/components.ts create mode 100644 npm/ng-packs/packages/permission-management/src/lib/enums/components.ts create mode 100644 npm/ng-packs/packages/setting-management/src/lib/enums/components.ts create mode 100644 npm/ng-packs/packages/tenant-management/src/lib/enums/components.ts create mode 100644 npm/ng-packs/packages/theme-basic/src/lib/enums/components.ts diff --git a/npm/ng-packs/.vscode/settings.json b/npm/ng-packs/.vscode/settings.json index 9c2678df08..a04bf7ca0c 100644 --- a/npm/ng-packs/.vscode/settings.json +++ b/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" } diff --git a/npm/ng-packs/packages/account/src/lib/account-routing.module.ts b/npm/ng-packs/packages/account/src/lib/account-routing.module.ts index db4147f2a0..2225e7c592 100644 --- a/npm/ng-packs/packages/account/src/lib/account-routing.module.ts +++ b/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, }, @@ -31,7 +32,7 @@ const routes: Routes = [ component: ReplaceableRouteContainerComponent, data: { replaceableComponent: { - key: 'Account.RegisterComponent', + key: eAccountComponents.Register, defaultComponent: RegisterComponent, } as ReplaceableComponents.RouteData, }, @@ -42,7 +43,7 @@ const routes: Routes = [ canActivate: [AuthGuard], data: { replaceableComponent: { - key: 'Account.ManageProfileComponent', + key: eAccountComponents.ManageProfile, defaultComponent: ManageProfileComponent, } as ReplaceableComponents.RouteData, }, diff --git a/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.html b/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.html index 6e732540d4..3377b74a88 100644 --- a/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.html +++ b/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.html @@ -1,9 +1,7 @@
- +
@@ -44,7 +44,7 @@
diff --git a/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts b/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts index d19a1dcd6a..f9ee2b8ff7 100644 --- a/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts +++ b/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts @@ -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; } diff --git a/npm/ng-packs/packages/account/src/lib/components/register/register.component.html b/npm/ng-packs/packages/account/src/lib/components/register/register.component.html index f803d473cd..58fafdf541 100644 --- a/npm/ng-packs/packages/account/src/lib/components/register/register.component.html +++ b/npm/ng-packs/packages/account/src/lib/components/register/register.component.html @@ -1,6 +1,6 @@ ; diff --git a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html index 38b22789e9..e00dbfe866 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html +++ b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html @@ -262,7 +262,7 @@ visible: { value: visiblePermissions, twoWay: true } }, outputs: { visibleChange: onVisiblePermissionChange }, - componentKey: 'PermissionManagement.PermissionManagementComponent' + componentKey: permissionManagementKey }; let init = initTemplate " diff --git a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts index 1e943a6be6..e208f9ffec 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts +++ b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts @@ -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 = (index, item) => Object.keys(item)[0] || index; onVisiblePermissionChange = event => { diff --git a/npm/ng-packs/packages/identity/src/lib/enums/components.ts b/npm/ng-packs/packages/identity/src/lib/enums/components.ts new file mode 100644 index 0000000000..abadd38955 --- /dev/null +++ b/npm/ng-packs/packages/identity/src/lib/enums/components.ts @@ -0,0 +1,4 @@ +export const enum eIdentityComponents { + Roles = 'Identity.RolesComponent', + Users = 'Identity.UsersComponent', +} diff --git a/npm/ng-packs/packages/identity/src/lib/identity-routing.module.ts b/npm/ng-packs/packages/identity/src/lib/identity-routing.module.ts index eff6a7ce98..f7d5463fcd 100644 --- a/npm/ng-packs/packages/identity/src/lib/identity-routing.module.ts +++ b/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, }, @@ -35,7 +36,7 @@ const routes: Routes = [ data: { requiredPolicy: 'AbpIdentity.Users', replaceableComponent: { - key: 'Identity.UsersComponent', + key: eIdentityComponents.Users, defaultComponent: UsersComponent, } as ReplaceableComponents.RouteData, }, diff --git a/npm/ng-packs/packages/identity/src/public-api.ts b/npm/ng-packs/packages/identity/src/public-api.ts index b401fed1c6..1a2b217931 100644 --- a/npm/ng-packs/packages/identity/src/public-api.ts +++ b/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'; diff --git a/npm/ng-packs/packages/permission-management/src/lib/enums/components.ts b/npm/ng-packs/packages/permission-management/src/lib/enums/components.ts new file mode 100644 index 0000000000..175d39c999 --- /dev/null +++ b/npm/ng-packs/packages/permission-management/src/lib/enums/components.ts @@ -0,0 +1,3 @@ +export const enum ePermissionManagementComponents { + PermissionManagement = 'PermissionManagement.PermissionManagementComponent', +} diff --git a/npm/ng-packs/packages/permission-management/src/public-api.ts b/npm/ng-packs/packages/permission-management/src/public-api.ts index 3182363f25..c9a8445ebd 100644 --- a/npm/ng-packs/packages/permission-management/src/public-api.ts +++ b/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'; diff --git a/npm/ng-packs/packages/setting-management/src/lib/enums/components.ts b/npm/ng-packs/packages/setting-management/src/lib/enums/components.ts new file mode 100644 index 0000000000..7dafe76b7d --- /dev/null +++ b/npm/ng-packs/packages/setting-management/src/lib/enums/components.ts @@ -0,0 +1,3 @@ +export const enum eSettingManagementComponents { + SettingManagement = 'SettingManagement.SettingManagementComponent', +} diff --git a/npm/ng-packs/packages/setting-management/src/lib/setting-management-routing.module.ts b/npm/ng-packs/packages/setting-management/src/lib/setting-management-routing.module.ts index d9a50073e1..f394abc962 100644 --- a/npm/ng-packs/packages/setting-management/src/lib/setting-management-routing.module.ts +++ b/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, }, diff --git a/npm/ng-packs/packages/setting-management/src/public-api.ts b/npm/ng-packs/packages/setting-management/src/public-api.ts index 8027d769f9..ac030c3ccf 100644 --- a/npm/ng-packs/packages/setting-management/src/public-api.ts +++ b/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'; diff --git a/npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html b/npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html index 2b0276ede8..10761a3618 100644 --- a/npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html +++ b/npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.html @@ -141,7 +141,9 @@
- +
- + , }, diff --git a/npm/ng-packs/packages/tenant-management/src/public-api.ts b/npm/ng-packs/packages/tenant-management/src/public-api.ts index 20cecd353f..003074b2c4 100644 --- a/npm/ng-packs/packages/tenant-management/src/public-api.ts +++ b/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'; diff --git a/npm/ng-packs/packages/theme-basic/src/lib/enums/components.ts b/npm/ng-packs/packages/theme-basic/src/lib/enums/components.ts new file mode 100644 index 0000000000..e773e17464 --- /dev/null +++ b/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', +} diff --git a/npm/ng-packs/packages/theme-basic/src/lib/services/initial.service.ts b/npm/ng-packs/packages/theme-basic/src/lib/services/initial.service.ts index 2510b77a8d..c5bc93cbf0 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/services/initial.service.ts +++ b/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, }), ]); diff --git a/npm/ng-packs/packages/theme-basic/src/public-api.ts b/npm/ng-packs/packages/theme-basic/src/public-api.ts index b1316143c0..ee01995829 100644 --- a/npm/ng-packs/packages/theme-basic/src/public-api.ts +++ b/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'; From da2a45b1125c8c69c100a6a3f0e8cb800654ebd1 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 10 Apr 2020 09:48:37 +0300 Subject: [PATCH 37/54] docs: update component replacement doc resolves #3080 --- docs/en/UI/Angular/Component-Replacement.md | 30 ++++++--------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/docs/en/UI/Angular/Component-Replacement.md b/docs/en/UI/Angular/Component-Replacement.md index d718b46117..d1f88c0400 100644 --- a/docs/en/UI/Angular/Component-Replacement.md +++ b/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.AccountLayout, }), ); @@ -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) From bc4c454fe2a863cb2e7d3a4e251040274925e4d4 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 10 Apr 2020 09:53:06 +0300 Subject: [PATCH 38/54] chore: update ng-packs abp versions --- npm/ng-packs/package.json | 26 ++++---- npm/ng-packs/yarn.lock | 132 +++++++++++++++++++------------------- 2 files changed, 79 insertions(+), 79 deletions(-) diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index a2b9011647..4f65497d69 100644 --- a/npm/ng-packs/package.json +++ b/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.1", - "@abp/ng.account.config": "~2.4.1", - "@abp/ng.core": "^2.4.1", - "@abp/ng.feature-management": "^2.4.1", - "@abp/ng.identity": "~2.4.1", - "@abp/ng.identity.config": "~2.4.1", - "@abp/ng.permission-management": "^2.4.1", - "@abp/ng.setting-management": "~2.4.1", - "@abp/ng.setting-management.config": "~2.4.1", - "@abp/ng.tenant-management": "~2.4.1", - "@abp/ng.tenant-management.config": "~2.4.1", - "@abp/ng.theme.basic": "~2.4.1", - "@abp/ng.theme.shared": "^2.4.1", + "@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", diff --git a/npm/ng-packs/yarn.lock b/npm/ng-packs/yarn.lock index 1d93a6ef79..5e156ae867 100644 --- a/npm/ng-packs/yarn.lock +++ b/npm/ng-packs/yarn.lock @@ -2,26 +2,26 @@ # yarn lockfile v1 -"@abp/ng.account.config@^2.4.1", "@abp/ng.account.config@~2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@abp/ng.account.config/-/ng.account.config-2.4.1.tgz#871f3947d7751203ba8fd00902b5e87c2894cca1" - integrity sha512-6ikmQi+hmZi59xtEq54MZftH0i9qzxYWex4lk33woBiNXHYBKA/AzrXkksgjnQgmN5kydxGsHcq2vlAgb+WgSA== +"@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.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@abp/ng.account/-/ng.account-2.4.1.tgz#09c51101b2511f0352ffd3ef56b5f2e74d81cead" - integrity sha512-mFhFPKPsmHNYKBXWxK2ht9TkXccj5xkPfn3PGSkX0QiqJZ+SrJBb3bYa2VOsQ9BstWB1/FEX3ke07MB5h4uRTQ== +"@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.1" - "@abp/ng.theme.shared" "^2.4.1" + "@abp/ng.account.config" "^2.5.0" + "@abp/ng.theme.shared" "^2.5.0" tslib "^1.9.0" -"@abp/ng.core@^2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@abp/ng.core/-/ng.core-2.4.1.tgz#4a568ef1f0d9e33de555a8942a0ef421e754d55f" - integrity sha512-aML9iyneu8UDaKP1x4dBzr20EVXhaVO75g1A235OEqT+qYJ7Z1qXgp01u8DgeNM+jxNWc2UVYgtPf5SbMJsR4Q== +"@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.4.0" "@angular/localize" "~9.1.0" @@ -35,86 +35,86 @@ ts-toolbelt "^6.3.6" tslib "^1.9.0" -"@abp/ng.feature-management@^2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@abp/ng.feature-management/-/ng.feature-management-2.4.1.tgz#4e7f16fcf109d76bd3eadb296a54730da770c8c1" - integrity sha512-adkQKFr1XsYAq/qpXxtLo5ULBuTer12viPLgfldEmsnsGWi/0bCVr0U4Gw+4KdsE2SjmcMriaZnL2/yVJa5rjA== +"@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.1" + "@abp/ng.theme.shared" "^2.5.0" tslib "^1.9.0" -"@abp/ng.identity.config@^2.4.1", "@abp/ng.identity.config@~2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@abp/ng.identity.config/-/ng.identity.config-2.4.1.tgz#74a0c3b18ba1737b83144f1b03c97e75dc1afe0b" - integrity sha512-PeieQ/GeThgxx22n3rBnqPQuCylB5+0Vog53GAhFQFXXH5W0vMDbxTARYnQr74gnAf3UYS48XzEzyvAuIz1MGg== +"@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.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@abp/ng.identity/-/ng.identity-2.4.1.tgz#ede6ebcc1d7d2f15ce9aeeb3ab8b25bb26def5cd" - integrity sha512-4T1BnvL13UggIj0SrV5AWN1VLMnej59jaLEyjAbu1Myry9xeiQ8Grh0GOBJ6euNOKiuYtqwQlFl06NlLdHqu2g== +"@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.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" tslib "^1.9.0" -"@abp/ng.permission-management@^2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@abp/ng.permission-management/-/ng.permission-management-2.4.1.tgz#e58d650fbcf8a161bbce01083b35891cba3e1aa4" - integrity sha512-gNfVmXAIPQP+L5Bq4bj/LAU+mKhJqAd9AQKxDLmqmoXpNjrjxA0Y51bU/XY/mjYx+tZC2i59L+eMIOZfVmn3Dw== +"@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.1" + "@abp/ng.theme.shared" "^2.5.0" tslib "^1.9.0" -"@abp/ng.setting-management.config@^2.4.1", "@abp/ng.setting-management.config@~2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@abp/ng.setting-management.config/-/ng.setting-management.config-2.4.1.tgz#4e643934647aaf5f5ea70045364e8856a1958bf5" - integrity sha512-z76nIPa9NCUqJwS2UYYCNrOsv9r+EfJ+e32iplrN5anqSfi0q2QAbK/Qjo7PIaB6x/JsEER/zQ5gAFKfPle41w== +"@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.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@abp/ng.setting-management/-/ng.setting-management-2.4.1.tgz#b3028d8e65866529c2bb6a22980a110fa5247b67" - integrity sha512-oA6ZUJUQFvmY7QLff/cXnmefN2hGTwhD9iumZSckvl1TitOhzJuj1uQ8kT2c0Az13a5R14Zuk44KYwn2wGFeSg== +"@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.1" - "@abp/ng.theme.shared" "^2.4.1" + "@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.1", "@abp/ng.tenant-management.config@~2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@abp/ng.tenant-management.config/-/ng.tenant-management.config-2.4.1.tgz#fe77a00fee18d2f221e68b7edd1d9d52c4a24595" - integrity sha512-0WsqESU5eXCkH9A4AVSZCOGOTo+pL8jW9raYxCbxp8A6GGxHA78UiqjLO/ZqA9ercXt9lh2s3JIbclhsOJWHBA== +"@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.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@abp/ng.tenant-management/-/ng.tenant-management-2.4.1.tgz#e9bffd96b1805036d840d078a8e7c78dd027c5eb" - integrity sha512-HEyWwXrgKWdrZ84Txw+0k+PGBb/ekqMKmwytOrG3Z7fxTRqWVMP/6QbHcbJD929zR4aehAmEAfvex/210qD1rw== +"@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.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" tslib "^1.9.0" -"@abp/ng.theme.basic@~2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@abp/ng.theme.basic/-/ng.theme.basic-2.4.1.tgz#faf06ea09557323e77ffb648f55ff915ecc252de" - integrity sha512-fV9a6wfeWN5C1UmYGDzaT3bQMfkUzAt0T/JRaAiWTsWTUV/y69prGqD2dMEMvdIAPR3zhKK/125N6+apl/l0iQ== +"@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.1" + "@abp/ng.theme.shared" "^2.5.0" tslib "^1.9.0" -"@abp/ng.theme.shared@^2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@abp/ng.theme.shared/-/ng.theme.shared-2.4.1.tgz#1c0c5c1714099136a6ecd256df66602099721ef3" - integrity sha512-iXqVrpjCYkG8Dc6tocn21qDnu2i9bi625CEk7J+U7O+L0X2ECYqHJXH8DqQrEeQ0F3lun0gOXUc3wo83G15PrA== +"@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.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" From af51255d3dff3c11b9cbfabe18928773f921c65a Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Fri, 10 Apr 2020 09:56:17 +0300 Subject: [PATCH 39/54] refactor: make content projection a separate service --- .../UI/Angular/Content-Projection-Service.md | 78 +++++++++++++++++++ docs/en/UI/Angular/Dom-Insertion-Service.md | 36 +-------- docs/en/docs-nav.json | 4 + .../services/content-projection.service.ts | 14 ++++ .../src/lib/services/dom-insertion.service.ts | 10 +-- .../packages/core/src/lib/services/index.ts | 1 + .../tests/content-projection.service.spec.ts | 38 +++++++++ .../lib/tests/dom-insertion.service.spec.ts | 32 +------- 8 files changed, 143 insertions(+), 70 deletions(-) create mode 100644 docs/en/UI/Angular/Content-Projection-Service.md create mode 100644 npm/ng-packs/packages/core/src/lib/services/content-projection.service.ts create mode 100644 npm/ng-packs/packages/core/src/lib/tests/content-projection.service.spec.ts diff --git a/docs/en/UI/Angular/Content-Projection-Service.md b/docs/en/UI/Angular/Content-Projection-Service.md new file mode 100644 index 0000000000..6bd30e44c6 --- /dev/null +++ b/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 `` 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 placed inside it. Moreover, the given context will be applied, so `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 | TemplateRef>( + projectionStrategy: ProjectionStrategy, + injector = this.injector, +): ComponentRef | EmbeddedViewRef +``` + +- `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) diff --git a/docs/en/UI/Angular/Dom-Insertion-Service.md b/docs/en/UI/Angular/Dom-Insertion-Service.md index 5159ae2c35..d5ea9fe3a2 100644 --- a/docs/en/UI/Angular/Dom-Insertion-Service.md +++ b/docs/en/UI/Angular/Dom-Insertion-Service.md @@ -1,4 +1,4 @@ -# 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. @@ -71,45 +71,17 @@ In the example above, `` 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. -### How to Project Components & Templates - -If you pass a `ProjectionStrategy` as the first parameter of `projectContent` method, the `DomInsertionService` will resolve the projected component or template and place it at the designated target, such as containers or document body. If provided, it will also pass the component or the template a context. - -```js -const componentRef = this.domInsertionService.projectContent( - PROJECTION_STRATEGY.AppendComponentToBody(SomeOverlayComponent) -); -``` - -In the example above, `SomeOverlayComponent` component will placed at the **end** of `` and a `ComponentRef` will be returned. - -> 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. - -```js -const componentRef = this.domInsertionService.projectContent( - PROJECTION_STRATEGY.ProjectComponentToContainer( - SomeOverlayComponent, - viewContainerRefOfTarget, - { someProp: "SOME_VALUE" } - ) -); -``` - -In this example, the `viewContainerRefOfTarget`, which is a `ViewContainerRef` instance, will be cleared and `SomeOverlayComponent` component will placed inside it. Moreover, the given context will be applied, so `someProp` of the component will be set to `SOME_VALUE`. - -Please refer to [ProjectionStrategy](./Projection-Strategy.md) to see all available projection strategies and how you can build your own projection strategy. - ## API ### insertContent ```js -injectContent(injector: Injector): ComponentRef | EmbeddedViewRef +insertContent(contentStrategy: ContentStrategy): void ``` -`injector` parameter is the `Injector` instance you can pass to the projected content. It is not used in `TemplateProjectionStrategy`. +- `contentStrategy` parameter is the primary focus here and is explained above. ## What's Next? -- [TrackByService](./Track-By-Service.md) +- [ContentProjectionService](./Content-Projection-Service.md) diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 471e215e3a..20214b8447 100644 --- a/docs/en/docs-nav.json +++ b/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" diff --git a/npm/ng-packs/packages/core/src/lib/services/content-projection.service.ts b/npm/ng-packs/packages/core/src/lib/services/content-projection.service.ts new file mode 100644 index 0000000000..dfcdea330a --- /dev/null +++ b/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 | TemplateRef>( + projectionStrategy: ProjectionStrategy, + injector = this.injector, + ) { + return projectionStrategy.injectContent(injector); + } +} diff --git a/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts b/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts index 5e53a64995..c10967ebbb 100644 --- a/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts @@ -1,6 +1,5 @@ -import { Injectable, Injector, TemplateRef, Type } from '@angular/core'; +import { Injectable, Injector } from '@angular/core'; import { ContentStrategy } from '../strategies/content.strategy'; -import { ProjectionStrategy } from '../strategies/projection.strategy'; import { generateHash } from '../utils'; @Injectable({ providedIn: 'root' }) @@ -17,11 +16,4 @@ export class DomInsertionService { contentStrategy.insertElement(); this.inserted.add(hash); } - - projectContent | TemplateRef>( - projectionStrategy: ProjectionStrategy, - injector = this.injector, - ) { - return projectionStrategy.injectContent(injector); - } } diff --git a/npm/ng-packs/packages/core/src/lib/services/index.ts b/npm/ng-packs/packages/core/src/lib/services/index.ts index a64e721c67..f8b016bbd1 100644 --- a/npm/ng-packs/packages/core/src/lib/services/index.ts +++ b/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'; diff --git a/npm/ng-packs/packages/core/src/lib/tests/content-projection.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/content-projection.service.spec.ts new file mode 100644 index 0000000000..30f9f92e73 --- /dev/null +++ b/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: '
bar
' }) + class TestComponent {} + + // createServiceFactory does not accept entryComponents directly + @NgModule({ + declarations: [TestComponent], + entryComponents: [TestComponent], + }) + class TestModule {} + + let componentRef: ComponentRef; + let spectator: SpectatorService; + 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'); + }); + }); +}); diff --git a/npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts index 8ae75c2f15..f8e8565496 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts @@ -1,25 +1,11 @@ -import { Component, ComponentRef, NgModule } from '@angular/core'; import { createServiceFactory, SpectatorService } from '@ngneat/spectator'; import { DomInsertionService } from '../services'; -import { CONTENT_STRATEGY, PROJECTION_STRATEGY } from '../strategies'; +import { CONTENT_STRATEGY } from '../strategies'; describe('DomInsertionService', () => { - @Component({ template: '
bar
' }) - class TestComponent {} - - // createServiceFactory does not accept entryComponents directly - @NgModule({ - declarations: [TestComponent], - entryComponents: [TestComponent], - }) - class TestModule {} - - let spectator: SpectatorService; - const createService = createServiceFactory({ - service: DomInsertionService, - imports: [TestModule], - }); let styleElements: NodeListOf; + let spectator: SpectatorService; + const createService = createServiceFactory(DomInsertionService); beforeEach(() => (spectator = createService())); @@ -56,16 +42,4 @@ describe('DomInsertionService', () => { expect(spectator.service.inserted.has(1437348290)).toBe(true); }); }); - - describe('#projectContent', () => { - it('should call injectContent of given projectionStrategy and return what it returns', () => { - const strategy = PROJECTION_STRATEGY.AppendComponentToBody(TestComponent); - const componentRef = spectator.service.projectContent(strategy); - const foo = document.querySelector('body > ng-component > div.foo'); - - expect(componentRef).toBeInstanceOf(ComponentRef); - expect(foo.textContent).toBe('bar'); - componentRef.destroy(); - }); - }); }); From 83d9ad3f08678dfeb3db9b3969ff921a52ec9cb4 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Fri, 10 Apr 2020 10:04:04 +0300 Subject: [PATCH 40/54] refactor: remove unnecessary initializer --- .../packages/core/src/lib/tests/projection.strategy.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/ng-packs/packages/core/src/lib/tests/projection.strategy.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/projection.strategy.spec.ts index 1166d44f57..a0b3bb61bb 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/projection.strategy.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/projection.strategy.spec.ts @@ -213,7 +213,7 @@ describe('TemplateProjectionStrategy', () => { describe('PROJECTION_STRATEGY', () => { const content = undefined; const containerRef = ({ length: 0 } as any) as ViewContainerRef; - let context = undefined; + let context: any; test.each` name | Strategy | containerStrategy From 1b4bfd03f48aadc8ee21a3302c5f962bb1a68899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Levent=20Arman=20=C3=96zak?= Date: Fri, 10 Apr 2020 10:17:16 +0300 Subject: [PATCH 41/54] docs: use ApplicationLayout instead of AccountLayout key --- docs/en/UI/Angular/Component-Replacement.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/UI/Angular/Component-Replacement.md b/docs/en/UI/Angular/Component-Replacement.md index d1f88c0400..fb85aa476e 100644 --- a/docs/en/UI/Angular/Component-Replacement.md +++ b/docs/en/UI/Angular/Component-Replacement.md @@ -71,7 +71,7 @@ export class AppComponent { this.store.dispatch( new AddReplaceableComponent({ component: MyApplicationLayoutComponent, - key: eThemeBasicComponents.AccountLayout, + key: eThemeBasicComponents.ApplicationLayout, }), ); From 6ae41180056d71cf4d12d4a9b2d98adefa7d46a2 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Fri, 10 Apr 2020 10:25:38 +0300 Subject: [PATCH 42/54] refactor: remove unused injector --- .../packages/core/src/lib/services/dom-insertion.service.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts b/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts index c10967ebbb..d4b30b731d 100644 --- a/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/dom-insertion.service.ts @@ -1,4 +1,4 @@ -import { Injectable, Injector } from '@angular/core'; +import { Injectable } from '@angular/core'; import { ContentStrategy } from '../strategies/content.strategy'; import { generateHash } from '../utils'; @@ -6,8 +6,6 @@ import { generateHash } from '../utils'; export class DomInsertionService { readonly inserted = new Set(); - constructor(private injector: Injector) {} - insertContent(contentStrategy: ContentStrategy) { const hash = generateHash(contentStrategy.content); From 0d1295ad7beb32dcc76e4ca5042d70104fd8e127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 10 Apr 2020 10:28:02 +0300 Subject: [PATCH 43/54] Don't add en language file for the timeago. --- .../Mvc/UI/Packages/Timeago/TimeagoScriptContributor.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Timeago/TimeagoScriptContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Timeago/TimeagoScriptContributor.cs index a276849db6..9edbf065cb 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/Timeago/TimeagoScriptContributor.cs +++ b/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) From 0999be319d3a5c6411ed6e679ae5778a7be61a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 10 Apr 2020 12:10:20 +0300 Subject: [PATCH 44/54] Add IHasExtraProperties Interface section --- docs/en/Object-Extensions.md | 106 ++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/docs/en/Object-Extensions.md b/docs/en/Object-Extensions.md index fad3ff2b0c..70a83e8ef2 100644 --- a/docs/en/Object-Extensions.md +++ b/docs/en/Object-Extensions.md @@ -1,3 +1,107 @@ # Object Extensions -TODO \ No newline at end of file +ABP Framework provides an **object extension system** to allow you to **add extra properties** to an existing object **without modifying** the related class. This allows to extend functionalities implemented by a depended [application module](Modules/Index.md), especially when you want to [extend entities](Customizing-Application-Modules-Extending-Entities.md) and [DTOs](Customizing-Application-Modules-Overriding-Services.md) defined by the module. + +> Object extension system is not normally not needed for your own objects since you can easily add regular properties to your own classes. + +## IHasExtraProperties Interface + +This is the interface to make a class extensible. It simply defines a `Dictionary` property: + +````csharp +Dictionary ExtraProperties { get; } +```` + +Then you can add or get extra properties using this dictionary. + +### Base Classes + +`IHasExtraProperties` interface is implemented by several base classes by default: + +* Implemented by the `AggregateRoot` class (see [entities](Entities.md)). +* Implemented by `ExtensibleEntityDto`, `ExtensibleAuditedEntityDto`... base [DTO](Data-Transfer-Objects.md) classes. +* Implemented by the `ExtensibleObject`, which is a simple base class can be inherited for any type of object. + +So, if you inherit from these classes, your class will also be extensible. If not, you can always implement it manually. + +### Fundamental Extension Methods + +While you can directly use the `ExtraProperties` property of a class, it is suggested to use the following extension methods while working with the extra properties. + +#### SetProperty + +Used to set the value of an extra property: + +````csharp +user.SetProperty("Title", "My Title"); +user.SetProperty("IsSuperUser", true); +```` + +`SetProperty` returns the same object, so you can chain it: + +````csharp +user.SetProperty("Title", "My Title") + .SetProperty("IsSuperUser", true); +```` + +#### GetProperty + +Used to read the value of an extra property: + +````csharp +var title = user.GetProperty("Title"); + +if (user.GetProperty("IsSuperUser")) +{ + //... +} +```` + +* `GetProperty` is a generic method and takes the object type as the generic parameter. +* Returns the default value if given property was not set before (default value is `0` for `int`, `false` for `bool`... etc). + +##### Non Primitive Property Types + +If your property type is not a primitive (int, bool, enum, string... etc) type, then you need to use non-generic version of the `GetProperty` which returns an `object`. + +#### HasProperty + +Used to check if the object has a property set before. + +#### RemoveProperty + +Used to remove a property from the object. Use this methods instead of setting a `null` value for the property. + +### Some Best Practices + +Using magic strings for the property names is dangerous since you can easily type the property name wrong - it is not type safe. Instead; + +* Define a constant for your extra property names +* Create extension methods to easily set your extra properties. + +Example: + +````csharp +public static class IdentityUserExtensions +{ + private const string TitlePropertyName = "Title"; + + public static void SetTitle(this IdentityUser user, string title) + { + user.SetProperty(TitlePropertyName, title); + } + + public static string GetTitle(this IdentityUser user) + { + return user.GetProperty(TitlePropertyName); + } +} +```` + +Then you can easily set or get the `Title` property: + +````csharp +user.SetTitle("My Title"); +var title = user.GetTitle(); +```` + From 98f97f0228970c8f8f00554790c70bdddb4b7056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 10 Apr 2020 12:10:40 +0300 Subject: [PATCH 45/54] Rename ExtensibleObjectMapper file. --- .../{ExtendedObjectMapper.cs => ExtensibleObjectMapper.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/{ExtendedObjectMapper.cs => ExtensibleObjectMapper.cs} (100%) diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtendedObjectMapper.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObjectMapper.cs similarity index 100% rename from framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtendedObjectMapper.cs rename to framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObjectMapper.cs From 30622bb8f8a117562d0fd5435c869ec65ddbfe9b Mon Sep 17 00:00:00 2001 From: Mehmet Erim <34455572+mehmet-erim@users.noreply.github.com> Date: Fri, 10 Apr 2020 13:10:59 +0300 Subject: [PATCH 46/54] Update Content-Projection-Service.md --- docs/en/UI/Angular/Content-Projection-Service.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/UI/Angular/Content-Projection-Service.md b/docs/en/UI/Angular/Content-Projection-Service.md index 6bd30e44c6..664123c2fb 100644 --- a/docs/en/UI/Angular/Content-Projection-Service.md +++ b/docs/en/UI/Angular/Content-Projection-Service.md @@ -31,7 +31,7 @@ const strategy = PROJECTION_STRATEGY.AppendComponentToBody( { someOverlayProp: "SOME_VALUE" } ); -const componentRef = this.ContentProjectionService.projectContent(strategy); +const componentRef = this.contentProjectionService.projectContent(strategy); ``` In the example above, `SomeOverlayComponent` component will placed at the **end** of `` and a `ComponentRef` will be returned. Additionally, the given context will be applied, so `someOverlayProp` of the component will be set to `SOME_VALUE`. From d27ddb398b070d7a0b960d0855c7bb43de476142 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 10 Apr 2020 14:29:42 +0300 Subject: [PATCH 47/54] refactor: add undefined control to loading.directive --- .../theme-shared/src/lib/directives/loading.directive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/directives/loading.directive.ts b/npm/ng-packs/packages/theme-shared/src/lib/directives/loading.directive.ts index 40b76cbfc8..bed4fab0da 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/directives/loading.directive.ts +++ b/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).rootNodes[0]; this.targetElement.appendChild(this.rootNode); - } else { + } else if (this.rootNode) { this.renderer.removeChild(this.rootNode.parentElement, this.rootNode); this.rootNode = null; } From 04cd0eae4d82232fc68c2fd99c1d92bfddb4b533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 10 Apr 2020 14:46:11 +0300 Subject: [PATCH 48/54] Update Object-Extensions.md --- docs/en/Object-Extensions.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/en/Object-Extensions.md b/docs/en/Object-Extensions.md index 70a83e8ef2..5841eb739c 100644 --- a/docs/en/Object-Extensions.md +++ b/docs/en/Object-Extensions.md @@ -105,3 +105,15 @@ user.SetTitle("My Title"); var title = user.GetTitle(); ```` +## Object Extension Manager + +While you can set arbitrary properties to an extensible object (which implements the `IHasExtraProperties` interface), `ObjectExtensionManager` is used to explicitly define extra properties for extensible classes. + +Explicitly defining an extra property has some use cases: + +* Allows to control how the extra property is handled on object to object mapping (see the section below). +* Allows to define metadata for the property. For example, you can map an extra property to a table field in the database while using the [EF Core](Entity-Framework-Core.md). + +### AddOrUpdate + +`AddOrUpdate` is the main method to define a new extra property or update an extra property definition. \ No newline at end of file From d316d96e3e11c9160b4da6d53d73e4587cf04b17 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Fri, 10 Apr 2020 14:50:36 +0300 Subject: [PATCH 49/54] docs: fix mistakes in content projection service --- docs/en/UI/Angular/Content-Projection-Service.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/UI/Angular/Content-Projection-Service.md b/docs/en/UI/Angular/Content-Projection-Service.md index 664123c2fb..db7c52be81 100644 --- a/docs/en/UI/Angular/Content-Projection-Service.md +++ b/docs/en/UI/Angular/Content-Projection-Service.md @@ -49,10 +49,10 @@ const strategy = PROJECTION_STRATEGY.ProjectComponentToContainer( { someProp: "SOME_VALUE" } ); -const componentRef = this.ContentProjectionService.projectContent(strategy); +const componentRef = this.contentProjectionService.projectContent(strategy); ``` -In this example, the `viewContainerRefOfTarget`, which is a `ViewContainerRef` instance, will be cleared and `SomeComponent` component will placed inside it. Moreover, the given context will be applied, so `someProp` of the component will be set to `SOME_VALUE`. +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. From 0072dec0b6f782e1a306c0d714dc0dc607efaa52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 10 Apr 2020 16:18:45 +0300 Subject: [PATCH 50/54] complete the object extension manager document. --- docs/en/Object-Extensions.md | 150 +++++++++++++++++- docs/en/docs-nav.json | 4 + .../ObjectExtending/ExtensibleObjectMapper.cs | 2 - 3 files changed, 153 insertions(+), 3 deletions(-) diff --git a/docs/en/Object-Extensions.md b/docs/en/Object-Extensions.md index 5841eb739c..bbcb96374c 100644 --- a/docs/en/Object-Extensions.md +++ b/docs/en/Object-Extensions.md @@ -114,6 +114,154 @@ Explicitly defining an extra property has some use cases: * Allows to control how the extra property is handled on object to object mapping (see the section below). * Allows to define metadata for the property. For example, you can map an extra property to a table field in the database while using the [EF Core](Entity-Framework-Core.md). +> `ObjectExtensionManager` implements the singleton pattern (`ObjectExtensionManager.Instance`) and you should define object extensions before your application startup. The [application startup template](Startup-Templates/Application.md) has some pre-defined static classes to safely define object extensions inside. + ### AddOrUpdate -`AddOrUpdate` is the main method to define a new extra property or update an extra property definition. \ No newline at end of file +`AddOrUpdate` is the main method to define a extra properties or update extra properties for an object. + +Example: Define extra properties for the `IdentityUser` entity: + +````csharp +ObjectExtensionManager.Instance + .AddOrUpdate(options => + { + options.AddOrUpdateProperty("SocialSecurityNumber"); + options.AddOrUpdateProperty("IsSuperUser"); + } + ); +```` + +### AddOrUpdateProperty + +While `AddOrUpdateProperty` can be used on the `options` as shown before, if you want to define a single extra property, you can use the shortcut extension method too: + +````csharp +ObjectExtensionManager.Instance + .AddOrUpdateProperty("SocialSecurityNumber"); +```` + +Sometimes it would be practical to define a single extra property to multiple types. Instead of defining one by one, you can use the following code: + +````csharp +ObjectExtensionManager.Instance + .AddOrUpdateProperty( + new[] + { + typeof(IdentityUserDto), + typeof(IdentityUserCreateDto), + typeof(IdentityUserUpdateDto) + }, + "SocialSecurityNumber" + ); +```` + +#### Property Configuration + +`AddOrUpdateProperty` can also get an action that can perform additional configuration on the property definition. + +Example: + +````csharp +ObjectExtensionManager.Instance + .AddOrUpdateProperty( + "SocialSecurityNumber", + options => + { + options.CheckPairDefinitionOnMapping = false; + }); +```` + +> See the "Object to Object Mapping" section to understand the `CheckPairDefinitionOnMapping` option. + +`options` has a dictionary, named `Configuration` which makes the object extension definitions even extensible. It is used by the EF Core to map extra properties to table fields in the database. See the [extending entities](Customizing-Application-Modules-Extending-Entities.md) document. + +## Object to Object Mapping + +Assume that you've added an extra property to an extensible entity object and used auto [object to object mapping](Object-To-Object-Mapping.md) to map this entity to an extensible DTO class. You need to be careful in such a case, because the extra property may contain a **sensitive data** that should not be available to clients. + +This section offers some **good practices** to control your extra properties on object mapping. + +### MapExtraPropertiesTo + +`MapExtraPropertiesTo` is an extension method provided by the ABP Framework to copy extra properties from an object to another in a controlled manner. Example usage: + +````csharp +identityUser.MapExtraPropertiesTo(identityUserDto); +```` + +`MapExtraPropertiesTo` **requires to define properties** (as described above) in **both sides** (`IdentityUser` and `IdentityUserDto` in this case) in order to copy the value to the target object. Otherwise, it doesn't copy the value even if it does exists in the source object (`identityUser` in this example). There are some ways to overload this restriction. + +#### MappingPropertyDefinitionChecks + +`MapExtraPropertiesTo` gets an additional parameter to control the definition check for a single mapping operation: + +````csharp +identityUser.MapExtraPropertiesTo( + identityUserDto, + MappingPropertyDefinitionChecks.None +); +```` + +> Be careful since `MappingPropertyDefinitionChecks.None` copies all extra properties without any check. `MappingPropertyDefinitionChecks` enum has other members too. + +If you want to completely disable definition check for a property, you can do it while defining the extra property (or update an existing definition) as shown below: + +````csharp +ObjectExtensionManager.Instance + .AddOrUpdateProperty( + "SocialSecurityNumber", + options => + { + options.CheckPairDefinitionOnMapping = false; + }); +```` + +#### Ignored Properties + +You may want to ignore some properties on a specific mapping operation: + +````csharp +identityUser.MapExtraPropertiesTo( + identityUserDto, + ignoredProperties: new[] {"MySensitiveProp"} +); +```` + +Ignored properties are not copied to the target object. + +#### AutoMapper Integration + +If you're using the [AutoMapper](https://automapper.org/) library, the ABP Framework also provides an extension method to utilize the `MapExtraPropertiesTo` method defined above. + +You can use the `MapExtraProperties()` method inside your mapping profile. + +````csharp +public class MyProfile : Profile +{ + public MyProfile() + { + CreateMap() + .MapExtraProperties(); + } +} +```` + +It has the same parameters with the `MapExtraPropertiesTo` method. + +## Entity Framework Core Database Mapping + +If you're using the EF Core, you can map an extra property to a table field in the database. Example: + +````csharp +ObjectExtensionManager.Instance + .AddOrUpdateProperty( + "SocialSecurityNumber", + options => + { + options.MapEfCore(b => b.HasMaxLength(32)); + } + ); +```` + +See the [Entity Framework Core Integration document](Entity-Framework-Core.md) for more. \ No newline at end of file diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 471e215e3a..f45a4192bb 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -155,6 +155,10 @@ { "text": "Data Filtering", "path": "Data-Filtering.md" + }, + { + "text": "Object Extensions", + "path": "Object-Extensions.md" } ] }, diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObjectMapper.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObjectMapper.cs index f2b7aeecdb..671aff40f2 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObjectMapper.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObjectMapper.cs @@ -122,8 +122,6 @@ namespace Volo.Abp.ObjectExtending } } - //TODO: Move these methods to a class like ObjectExtensionHelper - public static bool CanMapProperty( [NotNull] string propertyName, MappingPropertyDefinitionChecks? definitionChecks = null, From 88768be435a86e3ece3e80c5b455fdd81341c04d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 10 Apr 2020 16:31:40 +0300 Subject: [PATCH 51/54] Update best practices guide --- .../en/Best-Practices/Application-Services.md | 26 ++++++++++++------- .../Best-Practices/Data-Transfer-Objects.md | 1 + 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/en/Best-Practices/Application-Services.md b/docs/en/Best-Practices/Application-Services.md index 0979304931..876105c214 100644 --- a/docs/en/Best-Practices/Application-Services.md +++ b/docs/en/Best-Practices/Application-Services.md @@ -17,17 +17,18 @@ ##### Basic DTO -**Do** define a **basic** DTO for an entity. +**Do** define a **basic** DTO for an aggregate root. -- Include all the **primitive properties** directly on the entity. - - Exception: Can **exclude** properties for **security** reasons (like User.Password). +- Include all the **primitive properties** directly on the aggregate root. + - Exception: Can **exclude** properties for **security** reasons (like `User.Password`). - Include all the **sub collections** of the entity where every item in the collection is a simple **relation DTO**. +- Inherit from one of the **extensible entity DTO** classes for aggregate roots (and entities implement the `IHasExtraProperties`). Example: ```c# [Serializable] -public class IssueDto : FullAuditedEntityDto +public class IssueDto : ExtensibleFullAuditedEntityDto { public string Title { get; set; } public string Text { get; set; } @@ -57,7 +58,7 @@ Example: ````C# [Serializable] -public class IssueWithDetailsDto : FullAuditedEntityDto +public class IssueWithDetailsDto : ExtensibleFullAuditedEntityDto { public string Title { get; set; } public string Text { get; set; } @@ -66,14 +67,14 @@ public class IssueWithDetailsDto : FullAuditedEntityDto } [Serializable] -public class MilestoneDto : EntityDto +public class MilestoneDto : ExtensibleEntityDto { public string Name { get; set; } public bool IsClosed { get; set; } } [Serializable] -public class LabelDto : EntityDto +public class LabelDto : ExtensibleEntityDto { public string Name { get; set; } public string Color { get; set; } @@ -120,6 +121,7 @@ Task> GetListAsync(QuestionListQueryDto queryDto); * **Do** use the `CreateAsync` **method name**. * **Do** get a **specialized input** DTO to create the entity. +* **Do** inherit the DTO class from the `ExtensibleObject` (or any other class implements the `IHasExtraProperties`) to allow to pass extra properties if needed. * **Do** use **data annotations** for input validation. * Share constants between domain wherever possible (via constants defined in the **domain shared** package). * **Do** return **the detailed** DTO for new created entity. @@ -135,10 +137,11 @@ The related **DTO**: ````C# [Serializable] -public class CreateQuestionDto +public class CreateQuestionDto : ExtensibleObject { [Required] - [StringLength(QuestionConsts.MaxTitleLength, MinimumLength = QuestionConsts.MinTitleLength)] + [StringLength(QuestionConsts.MaxTitleLength, + MinimumLength = QuestionConsts.MinTitleLength)] public string Title { get; set; } [StringLength(QuestionConsts.MaxTextLength)] @@ -152,6 +155,7 @@ public class CreateQuestionDto - **Do** use the `UpdateAsync` **method name**. - **Do** get a **specialized input** DTO to update the entity. +- **Do** inherit the DTO class from the `ExtensibleObject` (or any other class implements the `IHasExtraProperties`) to allow to pass extra properties if needed. - **Do** get the Id of the entity as a separated primitive parameter. Do not include to the update DTO. - **Do** use **data annotations** for input validation. - Share constants between domain wherever possible (via constants defined in the **domain shared** package). @@ -200,6 +204,10 @@ This method votes a question and returns the current score of the question. * **Do not** use LINQ/SQL for querying data from database inside the application service methods. It's repository's responsibility to perform LINQ/SQL queries from the data source. +#### Extra Properties + +* **Do** use either `MapExtraPropertiesTo` extension method ([see](Object-Extensions.md)) or configure the object mapper (`MapExtraProperties`) to allow application developers to be able to extend the objects and services. + #### Manipulating / Deleting Entities * **Do** always get all the related entities from repositories to perform the operations on them. diff --git a/docs/en/Best-Practices/Data-Transfer-Objects.md b/docs/en/Best-Practices/Data-Transfer-Objects.md index 0c8580abb7..0fca0e86f2 100644 --- a/docs/en/Best-Practices/Data-Transfer-Objects.md +++ b/docs/en/Best-Practices/Data-Transfer-Objects.md @@ -2,6 +2,7 @@ * **Do** define DTOs in the **application contracts** package. * **Do** inherit from the pre-built **base DTO classes** where possible and necessary (like `EntityDto`, `CreationAuditedEntityDto`, `AuditedEntityDto`, `FullAuditedEntityDto` and so on). + * **Do** inherit from the **extensible DTO** classes for the **aggregate roots** (like `ExtensibleAuditedEntityDto`), because aggregate roots are extensible objects and extra properties are mapped to DTOs in this way. * **Do** define DTO members with **public getter and setter**. * **Do** use **data annotations** for **validation** on the properties of DTOs those are inputs of the service. * **Do** not add any **logic** into DTOs except implementing `IValidatableObject` when necessary. From fd8cd3a001acb86af4cdcfc604ce49a24135c279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 10 Apr 2020 16:33:25 +0300 Subject: [PATCH 52/54] remove unused doc --- docs/en/AutoMapper-Integration.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 docs/en/AutoMapper-Integration.md diff --git a/docs/en/AutoMapper-Integration.md b/docs/en/AutoMapper-Integration.md deleted file mode 100644 index d197861f25..0000000000 --- a/docs/en/AutoMapper-Integration.md +++ /dev/null @@ -1,3 +0,0 @@ -## AutoMapper Integration - -TODO \ No newline at end of file From 72c679329115c0d99d43eaf5336129fe395b1001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 10 Apr 2020 16:37:46 +0300 Subject: [PATCH 53/54] Resolved #3405 Document the object extension system. --- docs/en/Object-To-Object-Mapping.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/en/Object-To-Object-Mapping.md b/docs/en/Object-To-Object-Mapping.md index 52260402f1..b7463607e9 100644 --- a/docs/en/Object-To-Object-Mapping.md +++ b/docs/en/Object-To-Object-Mapping.md @@ -145,6 +145,23 @@ options.AddProfile(validate: true); > If you have multiple profiles and need to enable validation only for a few of them, first use `AddMaps` without validation, then use `AddProfile` for each profile you want to validate. +### Mapping the Object Extensions + +[Object extension system](Object-Extensions.md) allows to define extra properties for existing classes. ABP Framework provides a mapping definition extension to properly map extra properties of two objects. + +````csharp +public class MyProfile : Profile +{ + public MyProfile() + { + CreateMap() + .MapExtraProperties(); + } +} +```` + +It is suggested to use the `MapExtraProperties()` method if both classes are extensible objects (implement the `IHasExtraProperties` interface). See the [object extension document](Object-Extensions.md) for more. + ## Advanced Topics ### IObjectMapper Interface From e26e7ab48d81a91dc143afe2c7f9f836873ff430 Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Fri, 10 Apr 2020 18:35:29 +0300 Subject: [PATCH 54/54] fix mac download error --- .../Building/Steps/ProjectReferenceReplaceStep.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs index 63f63bef19..c7a6cc90f0 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ProjectReferenceReplaceStep.cs +++ b/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(Path.GetFileName(oldNodeIncludeValue)))) + if (oldNodeIncludeValue.Contains(_projectName) && _entries.Any(e=>e.Name.EndsWith(GetProjectNameWithExtensionFromProjectReference(oldNodeIncludeValue)))) { continue; } @@ -125,6 +125,16 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps return doc.OuterXml; } + private string GetProjectNameWithExtensionFromProjectReference(string oldNodeIncludeValue) + { + if (string.IsNullOrWhiteSpace(oldNodeIncludeValue)) + { + return oldNodeIncludeValue; + } + + return oldNodeIncludeValue.Split('\\', '/').Last(); + } + protected abstract XmlElement GetNewReferenceNode(XmlDocument doc, string oldNodeIncludeValue);