Browse Source

Merge pull request #4377 from abpframework/feat/2445

Eliminated Config Packages & Removed Routes From Config State
pull/4424/head
Mehmet Erim 6 years ago
committed by GitHub
parent
commit
dd1513cc62
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      npm/ng-packs/CONTRIBUTING.md
  2. 148
      npm/ng-packs/angular.json
  3. 9
      npm/ng-packs/apps/dev-app/src/app/app-routing.module.ts
  4. 18
      npm/ng-packs/apps/dev-app/src/app/app.module.ts
  5. 7
      npm/ng-packs/apps/dev-app/src/app/lazy-libs/account-wrapper.module.ts
  6. 7
      npm/ng-packs/apps/dev-app/src/app/lazy-libs/identity-wrapper.module.ts
  7. 7
      npm/ng-packs/apps/dev-app/src/app/lazy-libs/setting-management-wrapper.module.ts
  8. 7
      npm/ng-packs/apps/dev-app/src/app/lazy-libs/tenant-management-wrapper.module.ts
  9. 4
      npm/ng-packs/package.json
  10. 3
      npm/ng-packs/packages/account-config/README.md
  11. 6
      npm/ng-packs/packages/account-config/jest.config.js
  12. 7
      npm/ng-packs/packages/account-config/ng-package.json
  13. 12
      npm/ng-packs/packages/account-config/package.json
  14. 37
      npm/ng-packs/packages/account-config/src/lib/account-config.module.ts
  15. 22
      npm/ng-packs/packages/account-config/src/lib/services/account-config.service.ts
  16. 2
      npm/ng-packs/packages/account-config/src/public-api.ts
  17. 19
      npm/ng-packs/packages/account-config/tsconfig.lib.json
  18. 6
      npm/ng-packs/packages/account-config/tsconfig.lib.prod.json
  19. 11
      npm/ng-packs/packages/account-config/tsconfig.spec.json
  20. 17
      npm/ng-packs/packages/account-config/tslint.json
  21. 7
      npm/ng-packs/packages/account/config/ng-package.json
  22. 12
      npm/ng-packs/packages/account/config/src/account-config.module.ts
  23. 1
      npm/ng-packs/packages/account/config/src/enums/index.ts
  24. 0
      npm/ng-packs/packages/account/config/src/enums/route-names.ts
  25. 1
      npm/ng-packs/packages/account/config/src/providers/index.ts
  26. 39
      npm/ng-packs/packages/account/config/src/providers/route.provider.ts
  27. 3
      npm/ng-packs/packages/account/config/src/public-api.ts
  28. 2
      npm/ng-packs/packages/account/ng-package.json
  29. 1
      npm/ng-packs/packages/account/package.json
  30. 29
      npm/ng-packs/packages/account/src/lib/account.module.ts
  31. 1
      npm/ng-packs/packages/account/src/lib/enums/index.ts
  32. 9
      npm/ng-packs/packages/account/src/lib/tokens/options.token.ts
  33. 8
      npm/ng-packs/packages/account/src/lib/utils/factory-utils.ts
  34. 1
      npm/ng-packs/packages/account/src/lib/utils/index.ts
  35. 14
      npm/ng-packs/packages/core/src/lib/actions/config.actions.ts
  36. 73
      npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts
  37. 22
      npm/ng-packs/packages/core/src/lib/models/common.ts
  38. 6
      npm/ng-packs/packages/core/src/lib/models/config.ts
  39. 98
      npm/ng-packs/packages/core/src/lib/plugins/config.plugin.ts
  40. 19
      npm/ng-packs/packages/core/src/lib/services/config-state.service.ts
  41. 1
      npm/ng-packs/packages/core/src/lib/services/index.ts
  42. 144
      npm/ng-packs/packages/core/src/lib/services/routes.service.ts
  43. 166
      npm/ng-packs/packages/core/src/lib/states/config.state.ts
  44. 17
      npm/ng-packs/packages/core/src/lib/tests/array-utils.spec.ts
  45. 37
      npm/ng-packs/packages/core/src/lib/tests/config-state.service.spec.ts
  46. 363
      npm/ng-packs/packages/core/src/lib/tests/config.plugin.spec.ts
  47. 189
      npm/ng-packs/packages/core/src/lib/tests/config.state.spec.ts
  48. 66
      npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts
  49. 38
      npm/ng-packs/packages/core/src/lib/tests/factory-utils.spec.ts
  50. 60
      npm/ng-packs/packages/core/src/lib/tests/route-utils.spec.ts
  51. 113
      npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts
  52. 77
      npm/ng-packs/packages/core/src/lib/tests/tree-utils.spec.ts
  53. 6
      npm/ng-packs/packages/core/src/lib/utils/array-utils.ts
  54. 31
      npm/ng-packs/packages/core/src/lib/utils/factory-utils.ts
  55. 3
      npm/ng-packs/packages/core/src/lib/utils/index.ts
  56. 87
      npm/ng-packs/packages/core/src/lib/utils/route-utils.ts
  57. 65
      npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts
  58. 3
      npm/ng-packs/packages/identity-config/README.md
  59. 6
      npm/ng-packs/packages/identity-config/jest.config.js
  60. 7
      npm/ng-packs/packages/identity-config/ng-package.json
  61. 12
      npm/ng-packs/packages/identity-config/package.json
  62. 8
      npm/ng-packs/packages/identity-config/src/lib/identity-config.module.ts
  63. 42
      npm/ng-packs/packages/identity-config/src/lib/services/identity-config.service.ts
  64. 2
      npm/ng-packs/packages/identity-config/src/public-api.ts
  65. 19
      npm/ng-packs/packages/identity-config/tsconfig.lib.json
  66. 6
      npm/ng-packs/packages/identity-config/tsconfig.lib.prod.json
  67. 11
      npm/ng-packs/packages/identity-config/tsconfig.spec.json
  68. 17
      npm/ng-packs/packages/identity-config/tslint.json
  69. 7
      npm/ng-packs/packages/identity/config/ng-package.json
  70. 1
      npm/ng-packs/packages/identity/config/src/enums/index.ts
  71. 1
      npm/ng-packs/packages/identity/config/src/enums/route-names.ts
  72. 12
      npm/ng-packs/packages/identity/config/src/identity-config.module.ts
  73. 1
      npm/ng-packs/packages/identity/config/src/providers/index.ts
  74. 37
      npm/ng-packs/packages/identity/config/src/providers/route.provider.ts
  75. 3
      npm/ng-packs/packages/identity/config/src/public-api.ts
  76. 6
      npm/ng-packs/packages/identity/ng-package.json
  77. 1
      npm/ng-packs/packages/identity/package.json
  78. 1
      npm/ng-packs/packages/identity/src/lib/enums/index.ts
  79. 27
      npm/ng-packs/packages/identity/src/lib/identity.module.ts
  80. 3
      npm/ng-packs/packages/setting-management-config/README.md
  81. 6
      npm/ng-packs/packages/setting-management-config/jest.config.js
  82. 7
      npm/ng-packs/packages/setting-management-config/ng-package.json
  83. 12
      npm/ng-packs/packages/setting-management-config/package.json
  84. 37
      npm/ng-packs/packages/setting-management-config/src/lib/services/setting-management-config.service.ts
  85. 8
      npm/ng-packs/packages/setting-management-config/src/lib/setting-management-config.module.ts
  86. 1
      npm/ng-packs/packages/setting-management-config/src/public-api.ts
  87. 19
      npm/ng-packs/packages/setting-management-config/tsconfig.lib.json
  88. 6
      npm/ng-packs/packages/setting-management-config/tsconfig.lib.prod.json
  89. 11
      npm/ng-packs/packages/setting-management-config/tsconfig.spec.json
  90. 17
      npm/ng-packs/packages/setting-management-config/tslint.json
  91. 7
      npm/ng-packs/packages/setting-management/config/ng-package.json
  92. 1
      npm/ng-packs/packages/setting-management/config/src/enums/index.ts
  93. 3
      npm/ng-packs/packages/setting-management/config/src/enums/route-names.ts
  94. 1
      npm/ng-packs/packages/setting-management/config/src/providers/index.ts
  95. 42
      npm/ng-packs/packages/setting-management/config/src/providers/route.provider.ts
  96. 3
      npm/ng-packs/packages/setting-management/config/src/public-api.ts
  97. 12
      npm/ng-packs/packages/setting-management/config/src/setting-management-config.module.ts
  98. 2
      npm/ng-packs/packages/setting-management/ng-package.json
  99. 1
      npm/ng-packs/packages/setting-management/package.json
  100. 4
      npm/ng-packs/packages/setting-management/src/lib/actions/setting-management.actions.ts

4
npm/ng-packs/CONTRIBUTING.md

@ -93,10 +93,6 @@ The following is the list of supported scopes:
- **feature-management**
- **permission-management**
- **setting-management**
- **account-config**
- **identity-config**
- **setting-management-config**
- **tenant-management-config**
There are currently a few exceptions to the "use package name" rule:

148
npm/ng-packs/angular.json

@ -329,152 +329,6 @@
}
}
},
"setting-management-config": {
"projectType": "library",
"root": "packages/setting-management-config",
"sourceRoot": "packages/setting-management-config/src",
"prefix": "abp",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "packages/setting-management-config/tsconfig.lib.json",
"project": "packages/setting-management-config/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "packages/setting-management-config/tsconfig.lib.prod.json"
}
}
},
"test": {
"builder": "@angular-builders/jest:run",
"options": {
"coverage": true,
"passWithNoTests": true
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"packages/setting-management-config/tsconfig.lib.json",
"packages/setting-management-config/tsconfig.spec.json"
]
}
}
}
},
"identity-config": {
"projectType": "library",
"root": "packages/identity-config",
"sourceRoot": "packages/identity-config/src",
"prefix": "abp",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "packages/identity-config/tsconfig.lib.json",
"project": "packages/identity-config/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "packages/identity-config/tsconfig.lib.prod.json"
}
}
},
"test": {
"builder": "@angular-builders/jest:run",
"options": {
"coverage": true,
"passWithNoTests": true
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"packages/identity-config/tsconfig.lib.json",
"packages/identity-config/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**"]
}
}
}
},
"account-config": {
"projectType": "library",
"root": "packages/account-config",
"sourceRoot": "packages/account-config/src",
"prefix": "abp",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "packages/account-config/tsconfig.lib.json",
"project": "packages/account-config/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "packages/account-config/tsconfig.lib.prod.json"
}
}
},
"test": {
"builder": "@angular-builders/jest:run",
"options": {
"coverage": true,
"passWithNoTests": true
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"packages/account-config/tsconfig.lib.json",
"packages/account-config/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**"]
}
}
}
},
"tenant-management-config": {
"projectType": "library",
"root": "packages/tenant-management-config",
"sourceRoot": "packages/tenant-management-config/src",
"prefix": "abp",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "packages/tenant-management-config/tsconfig.lib.json",
"project": "packages/tenant-management-config/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "packages/tenant-management-config/tsconfig.lib.prod.json"
}
}
},
"test": {
"builder": "@angular-builders/jest:run",
"options": {
"coverage": true,
"passWithNoTests": true
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"packages/tenant-management-config/tsconfig.lib.json",
"packages/tenant-management-config/tsconfig.spec.json"
]
}
}
}
},
"dev-app": {
"projectType": "application",
"schematics": {
@ -557,7 +411,7 @@
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumWarning": "1mb",
"maximumError": "5mb"
},
{

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

@ -15,21 +15,22 @@ const routes: Routes = [
},
{
path: 'account',
loadChildren: () => import('./lazy-libs/account-wrapper.module').then(m => m.AccountWrapperModule),
loadChildren: () =>
import('@abp/ng.account').then(m => m.AccountModule.forLazy({ redirectUrl: '/' })),
},
{
path: 'identity',
loadChildren: () => import('./lazy-libs/identity-wrapper.module').then(m => m.IdentityWrapperModule),
loadChildren: () => import('@abp/ng.identity').then(m => m.IdentityModule.forLazy()),
},
{
path: 'tenant-management',
loadChildren: () =>
import('./lazy-libs/tenant-management-wrapper.module').then(m => m.TenantManagementWrapperModule),
import('@abp/ng.tenant-management').then(m => m.TenantManagementModule.forLazy()),
},
{
path: 'setting-management',
loadChildren: () =>
import('./lazy-libs/setting-management-wrapper.module').then(m => m.SettingManagementWrapperModule),
import('@abp/ng.setting-management').then(m => m.SettingManagementModule.forLazy()),
},
];

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

@ -1,4 +1,9 @@
import { AccountConfigModule } from '@abp/ng.account/config';
import { CoreModule } from '@abp/ng.core';
import { IdentityConfigModule } from '@abp/ng.identity/config';
import { SettingManagementConfigModule } from '@abp/ng.setting-management/config';
import { TenantManagementConfigModule } from '@abp/ng.tenant-management/config';
import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@ -8,11 +13,6 @@ import { environment } from '../environments/environment';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { SharedModule } from './shared/shared.module';
import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { AccountConfigModule } from '@abp/ng.account.config';
import { IdentityConfigModule } from '@abp/ng.identity.config';
import { TenantManagementConfigModule } from '@abp/ng.tenant-management.config';
import { SettingManagementConfigModule } from '@abp/ng.setting-management.config';
const LOGGERS = [NgxsLoggerPluginModule.forRoot({ disabled: false })];
@ -27,10 +27,10 @@ const LOGGERS = [NgxsLoggerPluginModule.forRoot({ disabled: false })];
skipGetAppConfiguration: false,
}),
ThemeSharedModule.forRoot(),
AccountConfigModule.forRoot({ redirectUrl: '/' }),
IdentityConfigModule,
TenantManagementConfigModule,
SettingManagementConfigModule,
AccountConfigModule.forRoot(),
IdentityConfigModule.forRoot(),
TenantManagementConfigModule.forRoot(),
SettingManagementConfigModule.forRoot(),
NgxsModule.forRoot(),
SharedModule,
...(environment.production ? [] : LOGGERS),

7
npm/ng-packs/apps/dev-app/src/app/lazy-libs/account-wrapper.module.ts

@ -1,7 +0,0 @@
import { NgModule } from '@angular/core';
import { AccountModule } from '@abp/ng.account';
@NgModule({
imports: [AccountModule],
})
export class AccountWrapperModule {}

7
npm/ng-packs/apps/dev-app/src/app/lazy-libs/identity-wrapper.module.ts

@ -1,7 +0,0 @@
import { NgModule } from '@angular/core';
import { IdentityModule } from '@abp/ng.identity';
@NgModule({
imports: [IdentityModule],
})
export class IdentityWrapperModule {}

7
npm/ng-packs/apps/dev-app/src/app/lazy-libs/setting-management-wrapper.module.ts

@ -1,7 +0,0 @@
import { NgModule } from '@angular/core';
import { SettingManagementModule } from '@abp/ng.setting-management';
@NgModule({
imports: [SettingManagementModule],
})
export class SettingManagementWrapperModule {}

7
npm/ng-packs/apps/dev-app/src/app/lazy-libs/tenant-management-wrapper.module.ts

@ -1,7 +0,0 @@
import { NgModule } from '@angular/core';
import { TenantManagementModule } from '@abp/ng.tenant-management';
@NgModule({
imports: [TenantManagementModule],
})
export class TenantManagementWrapperModule {}

4
npm/ng-packs/package.json

@ -24,16 +24,12 @@
},
"devDependencies": {
"@abp/ng.account": "~2.9.0",
"@abp/ng.account.config": "~2.9.0",
"@abp/ng.core": "~2.9.0",
"@abp/ng.feature-management": "~2.9.0",
"@abp/ng.identity": "~2.9.0",
"@abp/ng.identity.config": "~2.9.0",
"@abp/ng.permission-management": "~2.9.0",
"@abp/ng.setting-management": "~2.9.0",
"@abp/ng.setting-management.config": "~2.9.0",
"@abp/ng.tenant-management": "~2.9.0",
"@abp/ng.tenant-management.config": "~2.9.0",
"@abp/ng.theme.basic": "~2.9.0",
"@abp/ng.theme.shared": "~2.9.0",
"@abp/utils": "^2.9.0",

3
npm/ng-packs/packages/account-config/README.md

@ -1,3 +0,0 @@
# @abp/ng.account.config
[docs.abp.io](https://docs.abp.io)

6
npm/ng-packs/packages/account-config/jest.config.js

@ -1,6 +0,0 @@
const jestConfig = require('../../jest.config');
module.exports = {
...jestConfig,
name: 'account-config',
};

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

@ -1,7 +0,0 @@
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/account-config",
"lib": {
"entryFile": "src/public-api.ts"
}
}

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

@ -1,12 +0,0 @@
{
"name": "@abp/ng.account.config",
"version": "2.9.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",
"url": "https://github.com/abpframework/abp.git"
},
"publishConfig": {
"access": "public"
}
}

37
npm/ng-packs/packages/account-config/src/lib/account-config.module.ts

@ -1,37 +0,0 @@
import { CoreModule, noop } from '@abp/ng.core';
import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { APP_INITIALIZER, InjectionToken, ModuleWithProviders, NgModule } from '@angular/core';
import { AccountConfigService } from './services/account-config.service';
export interface AccountConfigOptions {
redirectUrl?: string;
}
export function accountOptionsFactory(options: AccountConfigOptions) {
return {
redirectUrl: '/',
...options,
};
}
export const ACCOUNT_OPTIONS = new InjectionToken('ACCOUNT_OPTIONS');
@NgModule({
imports: [CoreModule, ThemeSharedModule],
providers: [{ provide: APP_INITIALIZER, multi: true, deps: [AccountConfigService], useFactory: noop }],
})
export class AccountConfigModule {
static forRoot(options = {} as AccountConfigOptions): ModuleWithProviders<AccountConfigModule> {
return {
ngModule: AccountConfigModule,
providers: [
{ provide: ACCOUNT_OPTIONS, useValue: options },
{
provide: 'ACCOUNT_OPTIONS',
useFactory: accountOptionsFactory,
deps: [ACCOUNT_OPTIONS],
},
],
};
}
}

22
npm/ng-packs/packages/account-config/src/lib/services/account-config.service.ts

@ -1,22 +0,0 @@
import { addAbpRoutes, eLayoutType } from '@abp/ng.core';
import { Injectable } from '@angular/core';
import { eAccountRouteNames } from '@abp/ng.account';
@Injectable({
providedIn: 'root',
})
export class AccountConfigService {
constructor() {
addAbpRoutes({
name: eAccountRouteNames.Account,
path: 'account',
invisible: true,
layout: eLayoutType.application,
children: [
{ path: 'login', name: eAccountRouteNames.Login, order: 1 },
{ path: 'register', name: eAccountRouteNames.Register, order: 2 },
{ path: 'manage-profile', name: eAccountRouteNames.ManageProfile, order: 3 },
],
});
}
}

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

@ -1,2 +0,0 @@
export * from './lib/services/account-config.service';
export * from './lib/account-config.module';

19
npm/ng-packs/packages/account-config/tsconfig.lib.json

@ -1,19 +0,0 @@
{
"extends": "../../tsconfig.prod.json",
"compilerOptions": {
"outDir": "../../out-tsc/lib",
"target": "es2015",
"declaration": true,
"inlineSources": true,
"types": [],
"lib": ["dom", "es2018"]
},
"angularCompilerOptions": {
"skipTemplateCodegen": true,
"strictMetadataEmit": true,
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true,
"enableResourceInlining": true
},
"exclude": ["src/test.ts", "**/*.spec.ts"]
}

6
npm/ng-packs/packages/account-config/tsconfig.lib.prod.json

@ -1,6 +0,0 @@
{
"extends": "./tsconfig.lib.json",
"angularCompilerOptions": {
"enableIvy": false
}
}

11
npm/ng-packs/packages/account-config/tsconfig.spec.json

@ -1,11 +0,0 @@
{
"extends": "../../tsconfig.prod.json",
"compilerOptions": {
"emitDecoratorMetadata": true,
"esModuleInterop": true,
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": ["**/*.spec.ts", "**/*.d.ts"]
}

17
npm/ng-packs/packages/account-config/tslint.json

@ -1,17 +0,0 @@
{
"extends": "../../tslint.json",
"rules": {
"directive-selector": [
true,
"attribute",
"abp",
"camelCase"
],
"component-selector": [
true,
"element",
"abp",
"kebab-case"
]
}
}

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

@ -0,0 +1,7 @@
{
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/account/config",
"lib": {
"entryFile": "src/public-api.ts"
}
}

12
npm/ng-packs/packages/account/config/src/account-config.module.ts

@ -0,0 +1,12 @@
import { ModuleWithProviders, NgModule } from '@angular/core';
import { ACCOUNT_ROUTE_PROVIDERS } from './providers/route.provider';
@NgModule()
export class AccountConfigModule {
static forRoot(): ModuleWithProviders<AccountConfigModule> {
return {
ngModule: AccountConfigModule,
providers: [ACCOUNT_ROUTE_PROVIDERS],
};
}
}

1
npm/ng-packs/packages/account/config/src/enums/index.ts

@ -0,0 +1 @@
export * from './route-names';

0
npm/ng-packs/packages/account/src/lib/enums/route-names.ts → npm/ng-packs/packages/account/config/src/enums/route-names.ts

1
npm/ng-packs/packages/account/config/src/providers/index.ts

@ -0,0 +1 @@
export * from './route.provider';

39
npm/ng-packs/packages/account/config/src/providers/route.provider.ts

@ -0,0 +1,39 @@
import { eLayoutType, RoutesService } from '@abp/ng.core';
import { APP_INITIALIZER } from '@angular/core';
import { eAccountRouteNames } from '../enums/route-names';
export const ACCOUNT_ROUTE_PROVIDERS = [
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true },
];
export function configureRoutes(routes: RoutesService) {
return () => {
routes.add([
{
path: '/account',
name: eAccountRouteNames.Account,
invisible: true,
layout: eLayoutType.application,
order: 1,
},
{
path: '/account/login',
name: eAccountRouteNames.Login,
parentName: eAccountRouteNames.Account,
order: 1,
},
{
path: '/account/register',
name: eAccountRouteNames.Register,
parentName: eAccountRouteNames.Account,
order: 2,
},
{
path: '/account/manage-profile',
name: eAccountRouteNames.ManageProfile,
parentName: eAccountRouteNames.Account,
order: 3,
},
]);
};
}

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

@ -0,0 +1,3 @@
export * from './account-config.module';
export * from './enums';
export * from './providers';

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

@ -4,5 +4,5 @@
"lib": {
"entryFile": "src/public-api.ts"
},
"whitelistedNonPeerDependencies": ["@abp/ng.theme.shared", "@abp/ng.account.config"]
"whitelistedNonPeerDependencies": ["@abp/ng.theme.shared"]
}

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

@ -7,7 +7,6 @@
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
"@abp/ng.account.config": "~2.9.0",
"@abp/ng.theme.shared": "~2.9.0"
},
"publishConfig": {

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

@ -1,9 +1,10 @@
import { CoreModule } from '@abp/ng.core';
import { CoreModule, LazyModuleFactory } from '@abp/ng.core';
import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { NgModule, Provider } from '@angular/core';
import { ModuleWithProviders, NgModule, NgModuleFactory } from '@angular/core';
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
import { NgxValidateCoreModule } from '@ngx-validate/core';
import { AccountRoutingModule } from './account-routing.module';
import { AuthWrapperComponent } from './components/auth-wrapper/auth-wrapper.component';
import { ChangePasswordComponent } from './components/change-password/change-password.component';
import { LoginComponent } from './components/login/login.component';
import { ManageProfileComponent } from './components/manage-profile/manage-profile.component';
@ -11,8 +12,8 @@ import { PersonalSettingsComponent } from './components/personal-settings/person
import { RegisterComponent } from './components/register/register.component';
import { TenantBoxComponent } from './components/tenant-box/tenant-box.component';
import { Options } from './models/options';
import { ACCOUNT_OPTIONS, optionsFactory } from './tokens/options.token';
import { AuthWrapperComponent } from './components/auth-wrapper/auth-wrapper.component';
import { ACCOUNT_OPTIONS } from './tokens/options.token';
import { accountOptionsFactory } from './utils/factory-utils';
@NgModule({
declarations: [
@ -33,4 +34,22 @@ import { AuthWrapperComponent } from './components/auth-wrapper/auth-wrapper.com
],
exports: [],
})
export class AccountModule {}
export class AccountModule {
static forChild(options: Options): ModuleWithProviders<AccountModule> {
return {
ngModule: AccountModule,
providers: [
{ provide: ACCOUNT_OPTIONS, useValue: options },
{
provide: 'ACCOUNT_OPTIONS',
useFactory: accountOptionsFactory,
deps: [ACCOUNT_OPTIONS],
},
],
};
}
static forLazy(options: Options): NgModuleFactory<AccountModule> {
return new LazyModuleFactory(AccountModule.forChild(options));
}
}

1
npm/ng-packs/packages/account/src/lib/enums/index.ts

@ -1,2 +1 @@
export * from './components';
export * from './route-names';

9
npm/ng-packs/packages/account/src/lib/tokens/options.token.ts

@ -1,11 +1,4 @@
import { InjectionToken } from '@angular/core';
import { Options } from '../models/options';
export function optionsFactory(options: Options) {
return {
redirectUrl: '/',
...options,
};
}
export const ACCOUNT_OPTIONS = new InjectionToken('ACCOUNT_OPTIONS');
export const ACCOUNT_OPTIONS = new InjectionToken<Options>('ACCOUNT_OPTIONS');

8
npm/ng-packs/packages/account/src/lib/utils/factory-utils.ts

@ -0,0 +1,8 @@
import { Options } from '../models/options';
export function accountOptionsFactory(options: Options) {
return {
redirectUrl: '/',
...options,
};
}

1
npm/ng-packs/packages/account/src/lib/utils/index.ts

@ -0,0 +1 @@
export * from './factory-utils';

14
npm/ng-packs/packages/core/src/lib/actions/config.actions.ts

@ -1,23 +1,9 @@
import { ABP } from '../models/common';
import { Config } from '../models/config';
export class PatchRouteByName {
static readonly type = '[Config] Patch Route By Name';
constructor(public name: string, public newValue: Partial<ABP.Route>) {}
}
export class GetAppConfiguration {
static readonly type = '[Config] Get App Configuration';
}
/**
* @see usage: https://github.com/abpframework/abp/pull/2425#issue-355018812
*/
export class AddRoute {
static readonly type = '[Config] Add Route';
constructor(public payload: Omit<ABP.Route, 'children'>) {}
}
export class SetEnvironment {
static readonly type = '[Config] Set Environment';
constructor(public environment: Config.Environment) {}

73
npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts

@ -1,13 +1,14 @@
import { Component, OnDestroy, Type } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router, UrlSegment } from '@angular/router';
import { Component, Injector, OnDestroy, Type } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { Store } from '@ngxs/store';
import snq from 'snq';
import { eLayoutType } from '../enums/common';
import { ABP } from '../models/common';
import { ABP } from '../models';
import { ReplaceableComponents } from '../models/replaceable-components';
import { ConfigState } from '../states/config.state';
import { RoutesService } from '../services/routes.service';
import { ReplaceableComponentsState } from '../states/replaceable-components.state';
import { getRoutePath } from '../utils/route-utils';
import { takeUntilDestroy } from '../utils/rxjs-utils';
import { TreeNode } from '../utils/tree-utils';
@Component({
selector: 'abp-dynamic-layout',
@ -22,23 +23,37 @@ import { takeUntilDestroy } from '../utils/rxjs-utils';
export class DynamicLayoutComponent implements OnDestroy {
layout: Type<any>;
constructor(private router: Router, private route: ActivatedRoute, private store: Store) {
const { routes } = this.store.selectSnapshot(ConfigState.getAll);
constructor(
injector: Injector,
private route: ActivatedRoute,
private routes: RoutesService,
private store: Store,
) {
const router = injector.get(Router);
const layouts = {
application: this.getComponent('Theme.ApplicationLayoutComponent'),
account: this.getComponent('Theme.AccountLayoutComponent'),
empty: this.getComponent('Theme.EmptyLayoutComponent'),
};
router.events.pipe(takeUntilDestroy(this)).subscribe(event => {
if (event instanceof NavigationEnd) {
const segments = snq(() => router.parseUrl(event.url).root.children.primary.segments, [
{ path: router.url.replace('/', '') },
] as any);
let expectedLayout = (this.route.snapshot.data || {}).layout;
const path = getRoutePath(router);
const layouts = {
application: this.getComponent('Theme.ApplicationLayoutComponent'),
account: this.getComponent('Theme.AccountLayoutComponent'),
empty: this.getComponent('Theme.EmptyLayoutComponent'),
};
if (!expectedLayout) {
let node = { parent: this.routes.search({ path }) } as TreeNode<ABP.Route>;
while (node.parent) {
node = node.parent;
const expectedLayout =
(this.route.snapshot.data || {}).layout || findLayout(segments, routes);
if (node.layout) {
expectedLayout = node.layout;
break;
}
}
}
if (!expectedLayout) expectedLayout = eLayoutType.empty;
this.layout = layouts[expectedLayout].component;
}
@ -51,27 +66,3 @@ export class DynamicLayoutComponent implements OnDestroy {
ngOnDestroy() {}
}
function findLayout(segments: UrlSegment[], routes: ABP.FullRoute[]): eLayoutType {
let layout = eLayoutType.empty;
const route = routes
.reduce((acc, val) => (val.wrapper ? [...acc, ...val.children] : [...acc, val]), [])
.find(r => r.path === segments[0].path);
if (route) {
if (route.layout) {
layout = route.layout;
}
if (route.children && route.children.length && segments.length > 1) {
const child = route.children.find(c => c.path === segments[1].path);
if (child && child.layout) {
layout = child.layout;
}
}
}
return layout;
}

22
npm/ng-packs/packages/core/src/lib/models/common.ts

@ -1,4 +1,4 @@
import { EventEmitter } from '@angular/core';
import { EventEmitter, Type } from '@angular/core';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';
import { eLayoutType } from '../enums/common';
@ -30,21 +30,25 @@ export namespace ABP {
maxResultCount?: number;
}
export interface Route {
children?: Route[];
invisible?: boolean;
layout?: eLayoutType;
export interface Node {
name: string;
order?: number;
parentName?: string;
order?: number;
invisible?: boolean;
}
export interface Nav extends Node {
path: string;
requiredPolicy?: string;
}
export interface Route extends Nav {
layout?: eLayoutType;
iconClass?: string;
}
export interface FullRoute extends Route {
url?: string;
wrapper?: boolean;
export interface Tab extends Nav {
component: Type<any>;
}
export interface BasicItem {

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

@ -4,11 +4,7 @@ import { ApplicationConfiguration } from './application-configuration';
import { ABP } from './common';
export namespace Config {
export type State = ApplicationConfiguration.Response &
ABP.Root & { environment: Environment } & {
routes: ABP.FullRoute[];
flattedRoutes: ABP.FullRoute[];
};
export type State = ApplicationConfiguration.Response & ABP.Root & { environment: Environment };
export interface Environment {
application: Application;

98
npm/ng-packs/packages/core/src/lib/plugins/config.plugin.ts

@ -1,5 +1,4 @@
import { Inject, Injectable, InjectionToken } from '@angular/core';
import { Router, Routes } from '@angular/router';
import {
actionMatcher,
InitState,
@ -8,10 +7,7 @@ import {
setValue,
UpdateState,
} from '@ngxs/store';
import clone from 'just-clone';
import snq from 'snq';
import { ABP } from '../models/common';
import { getAbpRoutes, organizeRoutes } from '../utils/route-utils';
export const NGXS_CONFIG_PLUGIN_OPTIONS = new InjectionToken('NGXS_CONFIG_PLUGIN_OPTIONS');
@ -19,27 +15,16 @@ export const NGXS_CONFIG_PLUGIN_OPTIONS = new InjectionToken('NGXS_CONFIG_PLUGIN
export class ConfigPlugin implements NgxsPlugin {
private initialized = false;
constructor(
@Inject(NGXS_CONFIG_PLUGIN_OPTIONS) private options: ABP.Root,
private router: Router,
) {}
constructor(@Inject(NGXS_CONFIG_PLUGIN_OPTIONS) private options: ABP.Root) {}
handle(state: any, event: any, next: NgxsNextPluginFn) {
const matches = actionMatcher(event);
const isInitAction = matches(InitState) || matches(UpdateState);
if (isInitAction && !this.initialized) {
const transformedRoutes = transformRoutes(this.router.config);
let { routes, wrappers } = transformedRoutes;
wrappers = reduceWrappers(wrappers);
routes = organizeRoutes(routes, wrappers);
const flattedRoutes = flatRoutes(clone(routes));
state = setValue(state, 'ConfigState', {
...(state.ConfigState && { ...state.ConfigState }),
...this.options,
routes,
flattedRoutes,
});
this.initialized = true;
@ -48,84 +33,3 @@ export class ConfigPlugin implements NgxsPlugin {
return next(state, event);
}
}
function transformRoutes(routes: Routes = [], wrappers: ABP.FullRoute[] = []): any {
const abpRoutes = [...getAbpRoutes()];
wrappers = abpRoutes.filter(ar => ar.wrapper);
const transformed = [] as ABP.FullRoute[];
routes
.filter(route => route.component || route.loadChildren)
.forEach(route => {
const abpPackage = abpRoutes.find(
abp => abp.path.toLowerCase() === route.path.toLowerCase() && !abp.wrapper,
);
const { length } = transformed;
if (abpPackage) {
transformed.push(abpPackage);
}
if (transformed.length === length && (route.data || {}).routes) {
transformed.push({
...route.data.routes,
path: route.path,
name: snq(() => route.data.routes.name, route.path),
children: route.data.routes.children || [],
} as ABP.FullRoute);
}
});
return { routes: setUrls(transformed), wrappers };
}
function setUrls(routes: ABP.FullRoute[], parentUrl?: string): ABP.FullRoute[] {
if (parentUrl) {
// recursive block
return routes.map(route => ({
...route,
url: `${parentUrl}/${route.path}`,
...(route.children &&
route.children.length && {
children: setUrls(route.children, `${parentUrl}/${route.path}`),
}),
}));
}
return routes.map(route => ({
...route,
url: `/${route.path}`,
...(route.children &&
route.children.length && {
children: setUrls(route.children, `/${route.path}`),
}),
}));
}
function flatRoutes(routes: ABP.FullRoute[]): ABP.FullRoute[] {
const flat = (r: ABP.FullRoute[]) => {
return r.reduce((acc, val) => {
let value: ABP.FullRoute[] = [val];
if (val.children) {
val.children = val.children.map(child => ({ ...child, parentName: val.name }));
value = [val, ...flat(val.children)];
}
return [...acc, ...value];
}, []);
};
return flat(routes);
}
function reduceWrappers(wrappers: ABP.FullRoute[] = []) {
const existingWrappers = new Set();
return wrappers.filter(wrapper => {
if (existingWrappers.has(wrapper.name)) return false;
existingWrappers.add(wrapper.name);
return true;
});
}

19
npm/ng-packs/packages/core/src/lib/services/config-state.service.ts

@ -1,11 +1,6 @@
import { Injectable } from '@angular/core';
import { Store } from '@ngxs/store';
import {
AddRoute,
GetAppConfiguration,
PatchRouteByName,
SetEnvironment,
} from '../actions/config.actions';
import { GetAppConfiguration, SetEnvironment } from '../actions/config.actions';
import { ConfigState } from '../states';
@Injectable({
@ -30,10 +25,6 @@ export class ConfigStateService {
return this.store.selectSnapshot(ConfigState.getDeep(...args));
}
getRoute(...args: Parameters<typeof ConfigState.getRoute>) {
return this.store.selectSnapshot(ConfigState.getRoute(...args));
}
getApiUrl(...args: Parameters<typeof ConfigState.getApiUrl>) {
return this.store.selectSnapshot(ConfigState.getApiUrl(...args));
}
@ -58,14 +49,6 @@ export class ConfigStateService {
return this.store.dispatch(new GetAppConfiguration());
}
dispatchPatchRouteByName(...args: ConstructorParameters<typeof PatchRouteByName>) {
return this.store.dispatch(new PatchRouteByName(...args));
}
dispatchAddRoute(...args: ConstructorParameters<typeof AddRoute>) {
return this.store.dispatch(new AddRoute(...args));
}
dispatchSetEnvironment(...args: ConstructorParameters<typeof SetEnvironment>) {
return this.store.dispatch(new SetEnvironment(...args));
}

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

@ -9,5 +9,6 @@ export * from './localization.service';
export * from './profile-state.service';
export * from './profile.service';
export * from './rest.service';
export * from './routes.service';
export * from './session-state.service';
export * from './track-by.service';

144
npm/ng-packs/packages/core/src/lib/services/routes.service.ts

@ -0,0 +1,144 @@
import { Injectable } from '@angular/core';
import { Store } from '@ngxs/store';
import { BehaviorSubject, Observable } from 'rxjs';
import { ABP } from '../models/common';
import { ConfigState } from '../states/config.state';
import { pushValueTo } from '../utils/array-utils';
import { BaseTreeNode, createTreeFromList, TreeNode } from '../utils/tree-utils';
export abstract class AbstractTreeService<T extends object> {
abstract id: string;
abstract parentId: string;
abstract hide: (item: T) => boolean;
abstract sort: (a: T, b: T) => number;
private _flat$ = new BehaviorSubject<T[]>([]);
private _tree$ = new BehaviorSubject<TreeNode<T>[]>([]);
private _visible$ = new BehaviorSubject<TreeNode<T>[]>([]);
get flat(): T[] {
return this._flat$.value;
}
get flat$(): Observable<T[]> {
return this._flat$.asObservable();
}
get tree(): TreeNode<T>[] {
return this._tree$.value;
}
get tree$(): Observable<TreeNode<T>[]> {
return this._tree$.asObservable();
}
get visible(): TreeNode<T>[] {
return this._visible$.value;
}
get visible$(): Observable<TreeNode<T>[]> {
return this._visible$.asObservable();
}
protected createTree(items: T[]): TreeNode<T>[] {
return createTreeFromList<T, TreeNode<T>>(
items,
item => item[this.id],
item => item[this.parentId],
item => BaseTreeNode.create(item),
);
}
private filterWith(setOrMap: Set<string> | Map<string, T>): T[] {
return this._flat$.value.filter(
item => !setOrMap.has(item[this.id]) && !setOrMap.has(item[this.parentId]),
);
}
private publish(flatItems: T[], visibleItems: T[]): T[] {
this._flat$.next(flatItems);
this._tree$.next(this.createTree(flatItems));
this._visible$.next(this.createTree(visibleItems));
return flatItems;
}
add(items: T[]): T[] {
const map = new Map<string, T>();
items.forEach(item => map.set(item[this.id], item));
const flatItems = this.filterWith(map);
map.forEach(pushValueTo(flatItems));
flatItems.sort(this.sort);
const visibleItems = flatItems.filter(item => !this.hide(item));
return this.publish(flatItems, visibleItems);
}
patch(identifier: string, props: Partial<T>): T[] | false {
const flatItems = this._flat$.value;
const index = flatItems.findIndex(item => item[this.id] === identifier);
if (index < 0) return false;
flatItems[index] = { ...flatItems[index], ...props };
flatItems.sort(this.sort);
const visibleItems = flatItems.filter(item => !this.hide(item));
return this.publish(flatItems, visibleItems);
}
remove(identifiers: string[]): T[] {
const set = new Set<string>();
identifiers.forEach(id => set.add(id));
const flatItems = this.filterWith(set);
const visibleItems = flatItems.filter(item => !this.hide(item));
return this.publish(flatItems, visibleItems);
}
search(params: Partial<T>, tree = this.tree): TreeNode<T> {
const searchKeys = Object.keys(params);
return tree.reduce(
(acc, node) =>
acc
? acc
: searchKeys.every(key => node[key] === params[key])
? node
: node.children
? this.search(params, node.children)
: acc,
null,
);
}
}
@Injectable({
providedIn: 'root',
})
export class RoutesService extends AbstractTreeService<ABP.Route> {
readonly id = 'name';
readonly parentId = 'parentName';
readonly hide = (item: ABP.Route) => item.invisible;
readonly sort = (a: ABP.Route, b: ABP.Route) => a.order - b.order;
}
@Injectable({
providedIn: 'root',
})
export class SettingTabsService extends AbstractTreeService<ABP.Tab> {
readonly id = 'name';
readonly parentId = 'parentName';
readonly hide = (setting: ABP.Tab) => setting.invisible || !this.isGranted(setting);
readonly sort = (a: ABP.Tab, b: ABP.Tab) => a.order - b.order;
constructor(private store: Store) {
super();
}
private isGranted(setting: ABP.Tab): boolean {
return this.store.selectSnapshot(ConfigState.getGrantedPolicy(setting.requiredPolicy));
}
}

166
npm/ng-packs/packages/core/src/lib/states/config.state.ts

@ -4,18 +4,11 @@ import { Action, createSelector, Selector, State, StateContext, Store } from '@n
import { of, throwError } from 'rxjs';
import { catchError, switchMap, tap } from 'rxjs/operators';
import snq from 'snq';
import {
AddRoute,
GetAppConfiguration,
PatchRouteByName,
SetEnvironment,
} from '../actions/config.actions';
import { GetAppConfiguration, SetEnvironment } from '../actions/config.actions';
import { RestOccurError } from '../actions/rest.actions';
import { SetLanguage } from '../actions/session.actions';
import { ApplicationConfiguration } from '../models/application-configuration';
import { ABP } from '../models/common';
import { Config } from '../models/config';
import { organizeRoutes } from '../utils/route-utils';
import { SessionState } from './session.state';
@State<Config.State>({
@ -64,23 +57,6 @@ export class ConfigState {
return selector;
}
static getRoute(path?: string, name?: string, url?: string) {
const selector = createSelector([ConfigState], (state: Config.State) => {
const { flattedRoutes } = state;
return (flattedRoutes as ABP.FullRoute[]).find(route => {
if (path && route.path === path) {
return route;
} else if (name && route.name === name) {
return route;
} else if (url && route.url === url) {
return route;
}
});
});
return selector;
}
static getApiUrl(key?: string) {
const selector = createSelector([ConfigState], (state: Config.State): string => {
return (state.environment.apis[key || 'default'] || state.environment.apis.default).url;
@ -246,84 +222,6 @@ export class ConfigState {
);
}
@Action(PatchRouteByName)
patchRoute(
{ patchState, getState }: StateContext<Config.State>,
{ name, newValue }: PatchRouteByName,
) {
let routes: ABP.FullRoute[] = getState().routes;
routes = patchRouteDeep(routes, name, newValue);
const flattedRoutes = getState().flattedRoutes;
const index = flattedRoutes.findIndex(route => route.name === name);
if (index > -1) {
flattedRoutes[index] = { ...flattedRoutes[index], ...newValue } as ABP.FullRoute;
}
return patchState({
routes,
flattedRoutes,
});
}
@Action(AddRoute)
addRoute({ patchState, getState }: StateContext<Config.State>, { payload }: AddRoute) {
let routes: ABP.FullRoute[] = getState().routes;
const flattedRoutes = getState().flattedRoutes;
const route: ABP.FullRoute = { ...payload };
if (route.parentName) {
const index = flattedRoutes.findIndex(r => r.name === route.parentName);
if (index < 0) return;
const parent = flattedRoutes[index];
if ((parent.url || '').replace('/', '')) {
route.url = `${parent.url}/${route.path}`;
} else {
route.url = `/${route.path}`;
}
route.children = route.children || [];
route.order = route.order || route.order === 0 ? route.order : (parent.children || []).length;
parent.children = [...(parent.children || []), route].sort((a, b) => a.order - b.order);
flattedRoutes[index] = parent;
flattedRoutes.push(route);
let parentName = parent.name;
const parentNameArr = [parentName];
while (parentName) {
parentName = snq(() => flattedRoutes.find(r => r.name === parentName).parentName);
if (parentName) {
parentNameArr.unshift(parentName);
}
}
routes = updateRouteDeep(routes, parentNameArr, parent);
} else {
route.url = `/${route.path}`;
if (route.order || route.order === 0) {
routes = [...routes, route].sort((a, b) => a.order - b.order);
} else {
route.order = routes.length;
routes = [...routes, route];
}
flattedRoutes.push(route);
}
return patchState({
routes,
flattedRoutes,
});
}
@Action(SetEnvironment)
setEnvironment({ patchState }: StateContext<Config.State>, { environment }: SetEnvironment) {
return patchState({
@ -331,65 +229,3 @@ export class ConfigState {
});
}
}
function patchRouteDeep(
routes: ABP.FullRoute[],
name: string,
newValue: Partial<ABP.FullRoute>,
parentUrl: string = '',
): ABP.FullRoute[] {
routes = routes.map(route => {
if (route.name === name) {
newValue.url = `${parentUrl}/${(!newValue.path || newValue.path === ''
? route.path
: newValue.path) || ''}`;
if (newValue.children && newValue.children.length) {
newValue.children = newValue.children.map(child => ({
...child,
url: `${newValue.url}/${child.path}`.replace('//', '/'),
}));
}
return { ...route, ...newValue };
} else if (route.children && route.children.length) {
route.children = patchRouteDeep(
route.children,
name,
newValue,
(parentUrl || '/') + route.path,
);
}
return route;
});
if (parentUrl) {
// recursive block
return routes;
}
return organizeRoutes(routes);
}
function updateRouteDeep(
routes: ABP.FullRoute[],
parentNameArr: string[],
newValue: ABP.FullRoute,
parentIndex = 0,
) {
const index = routes.findIndex(route => route.name === parentNameArr[parentIndex]);
if (parentIndex === parentNameArr.length - 1) {
routes[index] = newValue;
} else {
routes[index].children = updateRouteDeep(
routes[index].children,
parentNameArr,
newValue,
parentIndex + 1,
);
}
return routes;
}

17
npm/ng-packs/packages/core/src/lib/tests/array-utils.spec.ts

@ -0,0 +1,17 @@
import { pushValueTo } from '../utils/array-utils';
describe('Array Utils', () => {
describe('#pushValueTo', () => {
test.each`
source | target | expected
${[]} | ${[0, 1, 2, 3]} | ${[0, 1, 2, 3]}
${[3]} | ${[0, 1, 2]} | ${[0, 1, 2, 3]}
${[2, 3]} | ${[0, 1]} | ${[0, 1, 2, 3]}
${[1, 2, 3]} | ${[0]} | ${[0, 1, 2, 3]}
${[0, 1, 2, 3]} | ${[]} | ${[0, 1, 2, 3]}
`('should push $source to $target when called in forEach', ({ source, target, expected }) => {
source.forEach(pushValueTo(target));
expect(target).toEqual(expected);
});
});
});

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

@ -29,43 +29,6 @@ const CONFIG_STATE_DATA = {
requirements: {
layouts: [null, null, null],
},
routes: [
{
name: '::Menu:Home',
path: '',
children: [],
url: '/',
},
{
name: 'AbpAccount::Menu:Account',
path: 'account',
invisible: true,
layout: 'application',
children: [
{
path: 'login',
name: 'AbpAccount::Login',
order: 1,
url: '/account/login',
},
],
url: '/account',
},
],
flattedRoutes: [
{
name: '::Menu:Home',
path: '',
children: [],
url: '/',
},
{
name: '::Menu:Identity',
path: 'identity',
children: [],
url: '/identity',
},
],
localization: {
values: {
MyProjectName: {

363
npm/ng-packs/packages/core/src/lib/tests/config.plugin.spec.ts

@ -1,351 +1,34 @@
import { RouterTestingModule } from '@angular/router/testing';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { NgxsModule, Store } from '@ngxs/store';
import { OAuthModule } from 'angular-oauth2-oidc';
import { environment } from '../../../../../apps/dev-app/src/environments/environment';
import { RouterOutletComponent } from '../components';
import { CoreModule } from '../core.module';
import { eLayoutType } from '../enums/common';
import { InitState } from '@ngxs/store';
import { ABP } from '../models';
import { ConfigPlugin } from '../plugins';
import { ConfigState } from '../states';
import { addAbpRoutes } from '../utils';
addAbpRoutes([
{
name: 'AbpUiNavigation::Menu:Administration',
path: '',
order: 1,
wrapper: true,
const options: ABP.Root = {
environment: {
production: false,
},
{
name: 'AbpIdentity::Menu:IdentityManagement',
path: 'identity',
order: 1,
parentName: 'AbpUiNavigation::Menu:Administration',
layout: eLayoutType.application,
iconClass: 'fa fa-id-card-o',
children: [
{ path: 'roles', name: 'AbpIdentity::Roles', order: 2, requiredPolicy: 'AbpIdentity.Roles' },
{ path: 'users', name: 'AbpIdentity::Users', order: 1, requiredPolicy: 'AbpIdentity.Users' },
],
},
{
name: 'AbpAccount::Menu:Account',
path: 'account',
invisible: true,
layout: eLayoutType.application,
children: [
{ path: 'login', name: 'AbpAccount::Login', order: 1 },
{ path: 'register', name: 'AbpAccount::Register', order: 2 },
],
},
{
name: 'AbpTenantManagement::Menu:TenantManagement',
path: 'tenant-management',
parentName: 'AbpUiNavigation::Menu:Administration',
layout: eLayoutType.application,
iconClass: 'fa fa-users',
children: [
{
path: 'tenants',
name: 'AbpTenantManagement::Tenants',
order: 1,
requiredPolicy: 'AbpTenantManagement.Tenants',
},
],
},
]);
const expectedState = {
environment,
routes: [
{
name: '::Menu:Home',
path: '',
children: [],
url: '/',
order: 1,
},
{
name: 'AbpUiNavigation::Menu:Administration',
path: '',
order: 1,
wrapper: true,
children: [
{
name: 'AbpIdentity::Menu:IdentityManagement',
path: 'identity',
order: 1,
parentName: 'AbpUiNavigation::Menu:Administration',
layout: 'application',
iconClass: 'fa fa-id-card-o',
children: [
{
path: 'users',
name: 'AbpIdentity::Users',
order: 1,
requiredPolicy: 'AbpIdentity.Users',
url: '/identity/users',
},
{
path: 'roles',
name: 'AbpIdentity::Roles',
order: 2,
requiredPolicy: 'AbpIdentity.Roles',
url: '/identity/roles',
},
],
url: '/identity',
},
{
name: 'AbpTenantManagement::Menu:TenantManagement',
path: 'tenant-management',
parentName: 'AbpUiNavigation::Menu:Administration',
layout: 'application',
iconClass: 'fa fa-users',
children: [
{
path: 'tenants',
name: 'AbpTenantManagement::Tenants',
order: 1,
requiredPolicy: 'AbpTenantManagement.Tenants',
url: '/tenant-management/tenants',
},
],
url: '/tenant-management',
order: 2,
},
],
},
{
name: 'AbpAccount::Menu:Account',
path: 'account',
invisible: true,
layout: 'application',
children: [
{
path: 'login',
name: 'AbpAccount::Login',
order: 1,
url: '/account/login',
},
{
path: 'register',
name: 'AbpAccount::Register',
order: 2,
url: '/account/register',
},
],
url: '/account',
order: 2,
},
],
flattedRoutes: [
{
name: '::Menu:Home',
path: '',
children: [],
url: '/',
order: 1,
},
{
name: 'AbpUiNavigation::Menu:Administration',
path: '',
order: 1,
wrapper: true,
children: [
{
name: 'AbpIdentity::Menu:IdentityManagement',
path: 'identity',
order: 1,
parentName: 'AbpUiNavigation::Menu:Administration',
layout: 'application',
iconClass: 'fa fa-id-card-o',
children: [
{
path: 'users',
name: 'AbpIdentity::Users',
order: 1,
parentName: 'AbpIdentity::Menu:IdentityManagement',
requiredPolicy: 'AbpIdentity.Users',
url: '/identity/users',
},
{
path: 'roles',
name: 'AbpIdentity::Roles',
order: 2,
parentName: 'AbpIdentity::Menu:IdentityManagement',
requiredPolicy: 'AbpIdentity.Roles',
url: '/identity/roles',
},
],
url: '/identity',
},
{
name: 'AbpTenantManagement::Menu:TenantManagement',
path: 'tenant-management',
parentName: 'AbpUiNavigation::Menu:Administration',
layout: 'application',
iconClass: 'fa fa-users',
children: [
{
path: 'tenants',
name: 'AbpTenantManagement::Tenants',
order: 1,
parentName: 'AbpTenantManagement::Menu:TenantManagement',
requiredPolicy: 'AbpTenantManagement.Tenants',
url: '/tenant-management/tenants',
},
],
url: '/tenant-management',
order: 2,
},
],
},
{
name: 'AbpIdentity::Menu:IdentityManagement',
path: 'identity',
order: 1,
parentName: 'AbpUiNavigation::Menu:Administration',
layout: 'application',
iconClass: 'fa fa-id-card-o',
children: [
{
path: 'users',
name: 'AbpIdentity::Users',
order: 1,
parentName: 'AbpIdentity::Menu:IdentityManagement',
requiredPolicy: 'AbpIdentity.Users',
url: '/identity/users',
},
{
path: 'roles',
name: 'AbpIdentity::Roles',
order: 2,
parentName: 'AbpIdentity::Menu:IdentityManagement',
requiredPolicy: 'AbpIdentity.Roles',
url: '/identity/roles',
},
],
url: '/identity',
},
{
path: 'users',
name: 'AbpIdentity::Users',
order: 1,
parentName: 'AbpIdentity::Menu:IdentityManagement',
requiredPolicy: 'AbpIdentity.Users',
url: '/identity/users',
},
{
path: 'roles',
name: 'AbpIdentity::Roles',
order: 2,
parentName: 'AbpIdentity::Menu:IdentityManagement',
requiredPolicy: 'AbpIdentity.Roles',
url: '/identity/roles',
},
{
name: 'AbpTenantManagement::Menu:TenantManagement',
path: 'tenant-management',
parentName: 'AbpUiNavigation::Menu:Administration',
layout: 'application',
iconClass: 'fa fa-users',
children: [
{
path: 'tenants',
name: 'AbpTenantManagement::Tenants',
order: 1,
parentName: 'AbpTenantManagement::Menu:TenantManagement',
requiredPolicy: 'AbpTenantManagement.Tenants',
url: '/tenant-management/tenants',
},
],
url: '/tenant-management',
order: 2,
},
{
path: 'tenants',
name: 'AbpTenantManagement::Tenants',
order: 1,
parentName: 'AbpTenantManagement::Menu:TenantManagement',
requiredPolicy: 'AbpTenantManagement.Tenants',
url: '/tenant-management/tenants',
},
{
name: 'AbpAccount::Menu:Account',
path: 'account',
invisible: true,
layout: 'application',
children: [
{
path: 'login',
name: 'AbpAccount::Login',
order: 1,
parentName: 'AbpAccount::Menu:Account',
url: '/account/login',
},
{
path: 'register',
name: 'AbpAccount::Register',
order: 2,
parentName: 'AbpAccount::Menu:Account',
url: '/account/register',
},
],
url: '/account',
order: 2,
},
{
path: 'login',
name: 'AbpAccount::Login',
order: 1,
parentName: 'AbpAccount::Menu:Account',
url: '/account/login',
},
{
path: 'register',
name: 'AbpAccount::Register',
order: 2,
parentName: 'AbpAccount::Menu:Account',
url: '/account/register',
},
],
};
describe('ConfigPlugin', () => {
let spectator: SpectatorService<ConfigPlugin>;
const createService = createServiceFactory({
service: ConfigPlugin,
imports: [
NgxsModule.forRoot([ConfigState]),
CoreModule.forRoot({ environment }),
OAuthModule.forRoot(),
RouterTestingModule.withRoutes([
{
path: '',
component: RouterOutletComponent,
data: {
routes: {
name: '::Menu:Home',
} as ABP.Route,
},
},
{ path: 'identity', component: RouterOutletComponent },
{ path: 'account', component: RouterOutletComponent },
{ path: 'tenant-management', component: RouterOutletComponent },
]),
],
});
const event = new InitState();
beforeEach(() => {
spectator = createService();
});
const state = {
ConfigState: {
foo: 'bar',
...options,
},
};
describe('ConfigPlugin', () => {
it('should ConfigState must be create with correct datas', () => {
const store = spectator.get(Store);
const state = store.selectSnapshot(ConfigState);
expect(state).toEqual(expectedState);
const next = jest.fn();
const plugin = new ConfigPlugin(options);
plugin.handle({ ConfigState: { foo: 'bar' } }, event, next);
expect(next).toHaveBeenCalledWith(state, event);
expect(next).toHaveBeenCalledTimes(1);
next.mockClear();
delete state.ConfigState.environment;
plugin.handle(state, event, next);
expect(next).toHaveBeenCalledWith(state, event);
expect(next).toHaveBeenCalledTimes(1);
});
});

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

@ -1,13 +1,11 @@
import { HttpClient } from '@angular/common/http';
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest';
import { Store } from '@ngxs/store';
import clone from 'just-clone';
import { of, ReplaySubject, timer } from 'rxjs';
import { AddRoute, PatchRouteByName, SetLanguage } from '../actions';
import { ABP } from '../models';
import { SetLanguage } from '../actions';
import { Config } from '../models/config';
import { ApplicationConfigurationService, ConfigStateService } from '../services';
import { ConfigState } from '../states';
import { HttpClient } from '@angular/common/http';
export const CONFIG_STATE_DATA = {
environment: {
@ -33,61 +31,6 @@ export const CONFIG_STATE_DATA = {
requirements: {
layouts: [null, null, null],
},
routes: [
{
name: '::Menu:Home',
path: '',
children: [],
url: '/',
},
{
name: 'AbpAccount::Menu:Account',
path: 'account',
invisible: true,
layout: 'application',
children: [
{
path: 'login',
name: 'AbpAccount::Login',
order: 1,
url: '/account/login',
parentName: 'AbpAccount::Menu:Account',
},
],
url: '/account',
},
],
flattedRoutes: [
{
name: '::Menu:Home',
path: '',
children: [],
url: '/',
},
{
name: 'AbpAccount::Menu:Account',
path: 'account',
invisible: true,
layout: 'application',
children: [
{
path: 'login',
name: 'AbpAccount::Login',
order: 1,
url: '/account/login',
parentName: 'AbpAccount::Menu:Account',
},
],
url: '/account',
},
{
path: 'login',
name: 'AbpAccount::Login',
order: 1,
url: '/account/login',
parentName: 'AbpAccount::Menu:Account',
},
],
localization: {
values: {
MyProjectName: {
@ -208,17 +151,6 @@ describe('ConfigState', () => {
});
});
describe('#getRoute', () => {
it('should return route', () => {
expect(ConfigState.getRoute(null, '::Menu:Home')(CONFIG_STATE_DATA)).toEqual(
CONFIG_STATE_DATA.flattedRoutes[0],
);
expect(ConfigState.getRoute('account')(CONFIG_STATE_DATA)).toEqual(
CONFIG_STATE_DATA.flattedRoutes[1],
);
});
});
describe('#getApiUrl', () => {
it('should return api url', () => {
expect(ConfigState.getApiUrl('other')(CONFIG_STATE_DATA)).toEqual(
@ -330,121 +262,4 @@ describe('ConfigState', () => {
});
});
});
describe('#PatchRouteByName', () => {
it('should patch the route', () => {
let patchStateArg;
const patchState = jest.fn(s => (patchStateArg = s));
const getState = jest.fn(() => clone(CONFIG_STATE_DATA));
state.patchRoute(
{ patchState, getState } as any,
new PatchRouteByName('::Menu:Home', {
name: 'Home',
path: 'home',
children: [{ path: 'dashboard', name: 'Dashboard' }],
}),
);
expect(patchStateArg.routes[0]).toEqual({
name: 'Home',
path: 'home',
url: '/home',
children: [{ path: 'dashboard', name: 'Dashboard', url: '/home/dashboard' }],
});
expect(patchStateArg.flattedRoutes[0]).toEqual({
name: 'Home',
path: 'home',
url: '/home',
children: [{ path: 'dashboard', name: 'Dashboard', url: '/home/dashboard' }],
});
});
it('should patch the route without path', () => {
let patchStateArg;
const patchState = jest.fn(s => (patchStateArg = s));
const getState = jest.fn(() => clone(CONFIG_STATE_DATA));
state.patchRoute(
{ patchState, getState } as any,
new PatchRouteByName('::Menu:Home', {
name: 'Main',
children: [{ path: 'dashboard', name: 'Dashboard' }],
}),
);
expect(patchStateArg.routes[0]).toEqual({
name: 'Main',
path: '',
url: '/',
children: [{ path: 'dashboard', name: 'Dashboard', url: '/dashboard' }],
});
expect(patchStateArg.flattedRoutes[0]).toEqual({
name: 'Main',
path: '',
url: '/',
children: [{ path: 'dashboard', name: 'Dashboard', url: '/dashboard' }],
});
});
});
describe('#AddRoute', () => {
const newRoute = {
name: 'My new page',
children: [],
iconClass: 'fa fa-dashboard',
path: 'page',
invisible: false,
order: 2,
requiredPolicy: 'MyProjectName::MyNewPage',
} as Omit<ABP.Route, 'children'>;
test('should add a new route', () => {
let patchStateArg;
const patchState = jest.fn(s => (patchStateArg = s));
const getState = jest.fn(() => clone(CONFIG_STATE_DATA));
state.addRoute({ patchState, getState } as any, new AddRoute(newRoute));
expect(patchStateArg.routes[CONFIG_STATE_DATA.routes.length]).toEqual({
...newRoute,
url: '/page',
});
expect(patchStateArg.flattedRoutes[CONFIG_STATE_DATA.flattedRoutes.length]).toEqual(
patchStateArg.routes[CONFIG_STATE_DATA.routes.length],
);
});
it('should add a new child route', () => {
let patchStateArg;
const patchState = jest.fn(s => (patchStateArg = s));
const getState = jest.fn(() => clone(CONFIG_STATE_DATA));
state.addRoute(
{ patchState, getState } as any,
new AddRoute({ ...newRoute, parentName: 'AbpAccount::Login' }),
);
expect(patchStateArg.routes[1].children[0].children[0]).toEqual({
...newRoute,
parentName: 'AbpAccount::Login',
url: '/account/login/page',
});
expect(patchStateArg.flattedRoutes[CONFIG_STATE_DATA.flattedRoutes.length]).toEqual(
patchStateArg.routes[1].children[0].children[0],
);
expect(
patchStateArg.flattedRoutes[
CONFIG_STATE_DATA.flattedRoutes.findIndex(route => route.name === 'AbpAccount::Login')
],
).toEqual(patchStateArg.routes[1].children[0]);
});
});
});

66
npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts

@ -1,13 +1,13 @@
import { HttpClient } from '@angular/common/http';
import { Component, NgModule } from '@angular/core';
import { ActivatedRoute, RouterModule } from '@angular/router';
import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator/jest';
import { NgxsModule, Store } from '@ngxs/store';
import { DynamicLayoutComponent, RouterOutletComponent } from '../components';
import { eLayoutType } from '../enums';
import { eLayoutType } from '../enums/common';
import { ABP } from '../models';
import { ConfigState, ReplaceableComponentsState } from '../states';
import { ApplicationConfigurationService } from '../services';
import { HttpClient } from '@angular/common/http';
import { ApplicationConfigurationService, RoutesService } from '../services';
import { ReplaceableComponentsState } from '../states';
@Component({
selector: 'abp-layout-application',
@ -48,28 +48,36 @@ class DummyComponent {
constructor(public route: ActivatedRoute) {}
}
const storeData = {
ConfigState: {
routes: [
{
path: '',
wrapper: true,
children: [
{
path: 'parentWithLayout',
layout: eLayoutType.application,
children: [
{ path: 'childWithoutLayout' },
{ path: 'childWithLayout', layout: eLayoutType.account },
],
},
],
},
{ path: 'withData', layout: eLayoutType.application },
,
] as ABP.FullRoute[],
environment: { application: {} },
const routes: ABP.Route[] = [
{
path: '',
name: 'Root',
},
{
path: '/parentWithLayout',
name: 'ParentWithLayout',
parentName: 'Root',
layout: eLayoutType.application,
},
{
path: '/parentWithLayout/childWithoutLayout',
name: 'ChildWithoutLayout',
parentName: 'ParentWithLayout',
},
{
path: '/parentWithLayout/childWithLayout',
name: 'ChildWithLayout',
parentName: 'ParentWithLayout',
layout: eLayoutType.account,
},
{
path: '/withData',
name: 'WithData',
layout: eLayoutType.application,
},
];
const storeData = {
ReplaceableComponentsState: {
replaceableComponents: [
{
@ -94,11 +102,7 @@ describe('DynamicLayoutComponent', () => {
stubsEnabled: false,
declarations: [DummyComponent, DynamicLayoutComponent],
mocks: [ApplicationConfigurationService, HttpClient],
imports: [
RouterModule,
DummyLayoutModule,
NgxsModule.forRoot([ConfigState, ReplaceableComponentsState]),
],
imports: [RouterModule, DummyLayoutModule, NgxsModule.forRoot([ReplaceableComponentsState])],
routes: [
{ path: '', component: RouterOutletComponent },
{
@ -150,6 +154,8 @@ describe('DynamicLayoutComponent', () => {
beforeEach(async () => {
spectator = createComponent();
store = spectator.get(Store);
const routesService = spectator.get(RoutesService);
routesService.add(routes);
store.reset(storeData);
});

38
npm/ng-packs/packages/core/src/lib/tests/factory-utils.spec.ts

@ -0,0 +1,38 @@
import { Injector, ModuleWithProviders, NgModule } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { LazyModuleFactory } from '../utils/factory-utils';
@NgModule()
class Module {
static forChild(): ModuleWithProviders<Module> {
return {
ngModule: Module,
providers: [{ provide: 'foo', useValue: 'bar' }],
};
}
}
describe('LazyModuleFactory', () => {
const factory = new LazyModuleFactory(Module.forChild());
describe('#moduleType', () => {
it('should return the ngModule property of given ModuleWithProviders', () => {
expect(factory.moduleType).toBe(Module);
});
});
describe('#create', () => {
it('should return an instance of NgModuleRef_', () => {
TestBed.configureTestingModule({});
const injector = TestBed.inject(Injector);
const moduleRef = factory.create(injector);
expect('componentFactoryResolver' in moduleRef).toBe(true);
expect('destroy' in moduleRef).toBe(true);
expect('injector' in moduleRef).toBe(true);
expect('instance' in moduleRef).toBe(true);
expect('onDestroy' in moduleRef).toBe(true);
});
});
});

60
npm/ng-packs/packages/core/src/lib/tests/route-utils.spec.ts

@ -0,0 +1,60 @@
import { Component } from '@angular/core';
import { RouterModule } from '@angular/router';
import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator/jest';
import { RouterOutletComponent } from '../components';
import { getRoutePath } from '../utils/route-utils';
// tslint:disable-next-line
@Component({ template: '' })
class DummyComponent {}
describe('Route Utils', () => {
describe('#getRoutePath', () => {
let spectator: SpectatorRouting<RouterOutletComponent>;
const createRouting = createRoutingFactory({
component: RouterOutletComponent,
stubsEnabled: false,
declarations: [DummyComponent],
imports: [RouterModule],
routes: [
{
path: '',
children: [
{
path: 'foo',
children: [
{
path: 'bar',
children: [
{
path: 'baz',
component: DummyComponent,
},
],
},
],
},
],
},
],
});
beforeEach(async () => {
spectator = createRouting();
});
test.each`
url | expected
${''} | ${'/'}
${'/'} | ${'/'}
${'/foo'} | ${'/foo'}
${'/foo/bar'} | ${'/foo/bar'}
${'/foo/bar/baz'} | ${'/foo/bar/baz'}
${'/foo?bar=baz'} | ${'/foo'}
${'/foo#bar'} | ${'/foo'}
`('should return $expected when url is $url', async ({ url, expected }) => {
await spectator.router.navigateByUrl(url);
expect(getRoutePath(spectator.router)).toBe(expected);
});
});
});

113
npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts

@ -0,0 +1,113 @@
import { take } from 'rxjs/operators';
import { RoutesService } from '../services';
const routes = [
{ path: '/foo', name: 'foo' },
{ path: '/foo/bar', name: 'bar', parentName: 'foo', invisible: true, order: 2 },
{ path: '/foo/bar/baz', name: 'baz', parentName: 'bar', order: 1 },
{ path: '/foo/x', name: 'x', parentName: 'foo', order: 1 },
];
describe('Routes Service', () => {
describe('#add', () => {
it('should add given routes as flat$, tree$, and visible$', async () => {
const service = new RoutesService();
service.add(routes);
const flat = await service.flat$.pipe(take(1)).toPromise();
const tree = await service.tree$.pipe(take(1)).toPromise();
const visible = await service.visible$.pipe(take(1)).toPromise();
expect(flat.length).toBe(4);
expect(flat[0].name).toBe('foo');
expect(flat[1].name).toBe('baz');
expect(flat[2].name).toBe('x');
expect(flat[3].name).toBe('bar');
expect(tree.length).toBe(1);
expect(tree[0].name).toBe('foo');
expect(tree[0].children.length).toBe(2);
expect(tree[0].children[0].name).toBe('x');
expect(tree[0].children[1].name).toBe('bar');
expect(tree[0].children[1].children[0].name).toBe('baz');
expect(visible.length).toBe(1);
expect(visible[0].name).toBe('foo');
expect(visible[0].children.length).toBe(1);
expect(visible[0].children[0].name).toBe('x');
});
});
describe('#remove', () => {
it('should remove routes based on given routeNames', () => {
const service = new RoutesService();
service.add(routes);
service.remove(['bar']);
const flat = service.flat;
const tree = service.tree;
const visible = service.visible;
expect(flat.length).toBe(2);
expect(flat[0].name).toBe('foo');
expect(flat[1].name).toBe('x');
expect(tree.length).toBe(1);
expect(tree[0].name).toBe('foo');
expect(tree[0].children.length).toBe(1);
expect(tree[0].children[0].name).toBe('x');
expect(visible.length).toBe(1);
expect(visible[0].name).toBe('foo');
expect(visible[0].children.length).toBe(1);
expect(visible[0].children[0].name).toBe('x');
});
});
describe('#patch', () => {
it('should patch propeties of routes based on given routeNames', () => {
const service = new RoutesService();
service.add(routes);
service.patch('x', { invisible: true });
const flat = service.flat;
const tree = service.tree;
const visible = service.visible;
expect(flat.length).toBe(4);
expect(flat[0].name).toBe('foo');
expect(flat[1].name).toBe('baz');
expect(flat[2].name).toBe('x');
expect(flat[3].name).toBe('bar');
expect(tree.length).toBe(1);
expect(tree[0].name).toBe('foo');
expect(tree[0].children.length).toBe(2);
expect(tree[0].children[0].name).toBe('x');
expect(tree[0].children[1].name).toBe('bar');
expect(tree[0].children[1].children[0].name).toBe('baz');
expect(visible.length).toBe(1);
expect(visible[0].name).toBe('foo');
expect(visible[0].children.length).toBe(0);
});
it('should return false when route name is not found', () => {
const service = new RoutesService();
service.add(routes);
const result = service.patch('A man has no name.', { invisible: true });
expect(result).toBe(false);
});
});
describe('#search', () => {
it('should return node found when route name is not found', () => {
const service = new RoutesService();
service.add(routes);
const result = service.search({ invisible: true });
expect(result.name).toBe('bar');
expect(result.children.length).toBe(1);
expect(result.children[0].name).toBe('baz');
});
});
});

77
npm/ng-packs/packages/core/src/lib/tests/tree-utils.spec.ts

@ -0,0 +1,77 @@
import { BaseTreeNode, createTreeFromList, TreeNode } from '../utils/tree-utils';
const LIST_1 = [
{ id: 1, pid: null },
{ id: 2, pid: 1 },
];
const LIST_2 = [
{ id: 1, pid: null },
{ id: 2, pid: 1 },
{ id: 3, pid: 1 },
];
const LIST_3 = [
{ id: 1, pid: null },
{ id: 2, pid: 1 },
{ id: 3, pid: 2 },
];
const TREE_1 = [
{ id: 1, pid: null, isLeaf: false, children: [{ id: 2, pid: 1, isLeaf: true, children: [] }] },
];
const TREE_2 = [
{
id: 1,
pid: null,
isLeaf: false,
children: [
{ id: 2, pid: 1, isLeaf: true, children: [] },
{ id: 3, pid: 1, isLeaf: true, children: [] },
],
},
];
const TREE_3 = [
{
id: 1,
pid: null,
isLeaf: false,
children: [
{ id: 2, pid: 1, isLeaf: false, children: [{ id: 3, pid: 2, isLeaf: true, children: [] }] },
],
},
];
describe('Tree Utils', () => {
describe('createTreeFromList', () => {
test.each`
list | expected
${LIST_1} | ${TREE_1}
${LIST_2} | ${TREE_2}
${LIST_3} | ${TREE_3}
`('should return $expected when given $list', ({ list, expected }: TestCreateTreeFromList) => {
const tree = createTreeFromList(
list,
x => x.id,
x => x.pid,
x => BaseTreeNode.create(x),
);
expect(removeParents(tree)).toEqual(expected);
});
});
});
function removeParents(tree: TreeNode<Model>[]) {
return tree.map(v => {
const { parent, ...node } = v;
node.children = removeParents(node.children);
return node;
});
}
interface TestCreateTreeFromList {
list: Model[];
expected: TreeNode<Model>[];
}
interface Model {
id: 1;
pid: null;
}

6
npm/ng-packs/packages/core/src/lib/utils/array-utils.ts

@ -0,0 +1,6 @@
export function pushValueTo<T extends any>(array: T[]) {
return (element: T) => {
array.push(element);
return array;
};
}

31
npm/ng-packs/packages/core/src/lib/utils/factory-utils.ts

@ -0,0 +1,31 @@
import {
Compiler,
Injector,
ModuleWithProviders,
NgModuleFactory,
NgModuleRef,
StaticProvider,
Type,
} from '@angular/core';
export class LazyModuleFactory<T> extends NgModuleFactory<T> {
get moduleType(): Type<T> {
return this.moduleWithProviders.ngModule;
}
constructor(private moduleWithProviders: ModuleWithProviders<T>) {
super();
}
create(parentInjector: Injector | null): NgModuleRef<T> {
const injector = Injector.create({
parent: parentInjector,
providers: this.moduleWithProviders.providers as StaticProvider[],
});
const compiler = injector.get(Compiler);
const factory = compiler.compileModuleSync(this.moduleType);
return factory.create(injector);
}
}

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

@ -1,4 +1,6 @@
export * from './array-utils';
export * from './common-utils';
export * from './factory-utils';
export * from './form-utils';
export * from './generator-utils';
export * from './initial-utils';
@ -7,3 +9,4 @@ export * from './localization-utils';
export * from './number-utils';
export * from './route-utils';
export * from './rxjs-utils';
export * from './tree-utils';

87
npm/ng-packs/packages/core/src/lib/utils/route-utils.ts

@ -1,85 +1,8 @@
import { ABP } from '../models/common';
import { PRIMARY_OUTLET, Router, UrlSegmentGroup } from '@angular/router';
export function organizeRoutes(
routes: ABP.FullRoute[],
wrappers: ABP.FullRoute[] = [],
parentNameArr = [] as ABP.FullRoute[],
parentName: string = null,
): ABP.FullRoute[] {
const filter = route => {
if (route.children && route.children.length) {
route.children = organizeRoutes(route.children, wrappers, parentNameArr, route.name);
}
export function getRoutePath(router: Router) {
const emptyGroup = { segments: [] } as UrlSegmentGroup;
const primaryGroup = router.parseUrl(router.url).root.children[PRIMARY_OUTLET];
if (route.parentName && route.parentName !== parentName) {
parentNameArr.push(route);
return false;
}
return true;
};
if (parentName) {
// recursive block
return routes.filter(filter);
}
const filteredRoutes = routes.filter(filter);
if (parentNameArr.length) {
return sortRoutes(setChildRoute([...filteredRoutes, ...wrappers], parentNameArr));
}
return filteredRoutes;
}
export function setChildRoute(
routes: ABP.FullRoute[],
parentNameArr: ABP.FullRoute[],
): ABP.FullRoute[] {
return routes.map(route => {
if (route.children && route.children.length) {
route.children = setChildRoute(route.children, parentNameArr);
}
const foundedChildren = parentNameArr.filter(parent => parent.parentName === route.name);
if (foundedChildren && foundedChildren.length) {
route.children = [...(route.children || []), ...foundedChildren];
}
return route;
});
}
export function sortRoutes(routes: ABP.FullRoute[] = []): ABP.FullRoute[] {
if (!routes.length) return [];
return routes
.map((route, index) => {
return {
...route,
order: typeof route.order === 'undefined' ? index + 1 : route.order,
};
})
.sort((a, b) => a.order - b.order)
.map(route => {
if (route.children && route.children.length) {
route.children = sortRoutes(route.children);
}
return route;
});
}
const ABP_ROUTES = [] as ABP.FullRoute[];
export function addAbpRoutes(routes: ABP.FullRoute | ABP.FullRoute[]): void {
if (!Array.isArray(routes)) {
routes = [routes];
}
ABP_ROUTES.push(...routes);
}
export function getAbpRoutes(): ABP.FullRoute[] {
return ABP_ROUTES;
return '/' + (primaryGroup || emptyGroup).segments.map(({ path }) => path).join('/');
}

65
npm/ng-packs/packages/core/src/lib/utils/tree-utils.ts

@ -0,0 +1,65 @@
export class BaseTreeNode<T extends object> {
children: TreeNode<T>[] = [];
isLeaf = true;
parent: TreeNode<T>;
constructor(props: T) {
Object.assign(this, props);
}
static create<T extends object>(props: T) {
return new BaseTreeNode<T>(props) as TreeNode<T>;
}
}
export function createTreeFromList<T extends object, R extends unknown>(
list: T[],
keySelector: (item: T) => number | string | symbol,
parentKeySelector: typeof keySelector,
valueMapper: (item: T) => R,
) {
const map = createMapFromList(list, keySelector, valueMapper);
const tree: NodeValue<T, typeof valueMapper>[] = [];
list.forEach(row => {
const id = keySelector(row);
const parentId = parentKeySelector(row);
const node = map.get(id);
if (parentId) {
const parent = map.get(parentId);
if (!parent) return;
(parent as any).children.push(node);
(parent as any).isLeaf = false;
(node as any).parent = parent;
} else {
tree.push(node);
}
});
return tree;
}
export function createMapFromList<T extends object, R extends unknown>(
list: T[],
keySelector: (item: T) => number | string | symbol,
valueMapper: (item: T) => R,
) {
type Key = ReturnType<typeof keySelector>;
type Value = NodeValue<T, typeof valueMapper>;
const map = new Map<Key, Value>();
list.forEach(row => map.set(keySelector(row), valueMapper(row)));
return map;
}
export type TreeNode<T extends object> = {
[K in keyof T]: T[K];
} & {
children: TreeNode<T>[];
isLeaf: boolean;
parent?: TreeNode<T>;
};
type NodeValue<T extends object, F extends (...args: any) => any> = F extends undefined
? TreeNode<T>
: ReturnType<F>;

3
npm/ng-packs/packages/identity-config/README.md

@ -1,3 +0,0 @@
# @abp/ng.identity.config
[docs.abp.io](https://docs.abp.io)

6
npm/ng-packs/packages/identity-config/jest.config.js

@ -1,6 +0,0 @@
const jestConfig = require('../../jest.config');
module.exports = {
...jestConfig,
name: 'identity-config',
};

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

@ -1,7 +0,0 @@
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/identity-config",
"lib": {
"entryFile": "src/public-api.ts"
}
}

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

@ -1,12 +0,0 @@
{
"name": "@abp/ng.identity.config",
"version": "2.9.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",
"url": "https://github.com/abpframework/abp.git"
},
"publishConfig": {
"access": "public"
}
}

8
npm/ng-packs/packages/identity-config/src/lib/identity-config.module.ts

@ -1,8 +0,0 @@
import { noop } from '@abp/ng.core';
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { IdentityConfigService } from './services/identity-config.service';
@NgModule({
providers: [{ provide: APP_INITIALIZER, deps: [IdentityConfigService], useFactory: noop, multi: true }],
})
export class IdentityConfigModule {}

42
npm/ng-packs/packages/identity-config/src/lib/services/identity-config.service.ts

@ -1,42 +0,0 @@
import { addAbpRoutes, eLayoutType } from '@abp/ng.core';
import { Injectable } from '@angular/core';
import { eIdentityRouteNames } from '@abp/ng.identity';
@Injectable({
providedIn: 'root',
})
export class IdentityConfigService {
constructor() {
addAbpRoutes([
{
name: eIdentityRouteNames.Administration,
path: '',
order: 1,
wrapper: true,
iconClass: 'fa fa-wrench',
},
{
name: eIdentityRouteNames.IdentityManagement,
path: 'identity',
order: 1,
parentName: eIdentityRouteNames.Administration,
layout: eLayoutType.application,
iconClass: 'fa fa-id-card-o',
children: [
{
path: 'roles',
name: eIdentityRouteNames.Roles,
order: 1,
requiredPolicy: 'AbpIdentity.Roles',
},
{
path: 'users',
name: eIdentityRouteNames.Users,
order: 2,
requiredPolicy: 'AbpIdentity.Users',
},
],
},
]);
}
}

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

@ -1,2 +0,0 @@
export * from './lib/services/identity-config.service';
export * from './lib/identity-config.module';

19
npm/ng-packs/packages/identity-config/tsconfig.lib.json

@ -1,19 +0,0 @@
{
"extends": "../../tsconfig.prod.json",
"compilerOptions": {
"outDir": "../../out-tsc/lib",
"target": "es2015",
"declaration": true,
"inlineSources": true,
"types": [],
"lib": ["dom", "es2018"]
},
"angularCompilerOptions": {
"skipTemplateCodegen": true,
"strictMetadataEmit": true,
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true,
"enableResourceInlining": true
},
"exclude": ["src/test.ts", "**/*.spec.ts"]
}

6
npm/ng-packs/packages/identity-config/tsconfig.lib.prod.json

@ -1,6 +0,0 @@
{
"extends": "./tsconfig.lib.json",
"angularCompilerOptions": {
"enableIvy": false
}
}

11
npm/ng-packs/packages/identity-config/tsconfig.spec.json

@ -1,11 +0,0 @@
{
"extends": "../../tsconfig.prod.json",
"compilerOptions": {
"emitDecoratorMetadata": true,
"esModuleInterop": true,
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": ["**/*.spec.ts", "**/*.d.ts"]
}

17
npm/ng-packs/packages/identity-config/tslint.json

@ -1,17 +0,0 @@
{
"extends": "../../tslint.json",
"rules": {
"directive-selector": [
true,
"attribute",
"abp",
"camelCase"
],
"component-selector": [
true,
"element",
"abp",
"kebab-case"
]
}
}

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

@ -0,0 +1,7 @@
{
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/identity/config",
"lib": {
"entryFile": "src/public-api.ts"
}
}

1
npm/ng-packs/packages/identity/config/src/enums/index.ts

@ -0,0 +1 @@
export * from './route-names';

1
npm/ng-packs/packages/identity/src/lib/enums/route-names.ts → npm/ng-packs/packages/identity/config/src/enums/route-names.ts

@ -1,5 +1,4 @@
export const enum eIdentityRouteNames {
Administration = 'AbpUiNavigation::Menu:Administration',
IdentityManagement = 'AbpIdentity::Menu:IdentityManagement',
Roles = 'AbpIdentity::Roles',
Users = 'AbpIdentity::Users',

12
npm/ng-packs/packages/identity/config/src/identity-config.module.ts

@ -0,0 +1,12 @@
import { ModuleWithProviders, NgModule } from '@angular/core';
import { IDENTITY_ROUTE_PROVIDERS } from './providers/route.provider';
@NgModule()
export class IdentityConfigModule {
static forRoot(): ModuleWithProviders<IdentityConfigModule> {
return {
ngModule: IdentityConfigModule,
providers: [IDENTITY_ROUTE_PROVIDERS],
};
}
}

1
npm/ng-packs/packages/identity/config/src/providers/index.ts

@ -0,0 +1 @@
export * from './route.provider';

37
npm/ng-packs/packages/identity/config/src/providers/route.provider.ts

@ -0,0 +1,37 @@
import { eLayoutType, RoutesService } from '@abp/ng.core';
import { eThemeSharedRouteNames } from '@abp/ng.theme.shared';
import { APP_INITIALIZER } from '@angular/core';
import { eIdentityRouteNames } from '../enums/route-names';
export const IDENTITY_ROUTE_PROVIDERS = [
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true },
];
export function configureRoutes(routes: RoutesService) {
return () => {
routes.add([
{
path: '/identity',
name: eIdentityRouteNames.IdentityManagement,
parentName: eThemeSharedRouteNames.Administration,
iconClass: 'fa fa-id-card-o',
layout: eLayoutType.application,
order: 1,
},
{
path: '/identity/roles',
name: eIdentityRouteNames.Roles,
parentName: eIdentityRouteNames.IdentityManagement,
requiredPolicy: 'AbpIdentity.Roles',
order: 1,
},
{
path: '/identity/users',
name: eIdentityRouteNames.Users,
parentName: eIdentityRouteNames.IdentityManagement,
requiredPolicy: 'AbpIdentity.Users',
order: 2,
},
]);
};
}

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

@ -0,0 +1,3 @@
export * from './enums';
export * from './identity-config.module';
export * from './providers';

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

@ -4,9 +4,5 @@
"lib": {
"entryFile": "src/public-api.ts"
},
"whitelistedNonPeerDependencies": [
"@abp/ng.theme.shared",
"@abp/ng.permission-management",
"@abp/ng.identity.config"
]
"whitelistedNonPeerDependencies": ["@abp/ng.theme.shared", "@abp/ng.permission-management"]
}

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

@ -7,7 +7,6 @@
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
"@abp/ng.identity.config": "~2.9.0",
"@abp/ng.permission-management": "~2.9.0",
"@abp/ng.theme.shared": "~2.9.0"
},

1
npm/ng-packs/packages/identity/src/lib/enums/index.ts

@ -1,2 +1 @@
export * from './components';
export * from './route-names';

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

@ -1,14 +1,14 @@
import { CoreModule } from '@abp/ng.core';
import { NgModule, Provider } from '@angular/core';
import { CoreModule, LazyModuleFactory } from '@abp/ng.core';
import { PermissionManagementModule } from '@abp/ng.permission-management';
import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { ModuleWithProviders, NgModule, NgModuleFactory } from '@angular/core';
import { NgbDropdownModule, NgbTabsetModule } from '@ng-bootstrap/ng-bootstrap';
import { NgxValidateCoreModule } from '@ngx-validate/core';
import { NgxsModule } from '@ngxs/store';
import { RolesComponent } from './components/roles/roles.component';
import { UsersComponent } from './components/users/users.component';
import { IdentityRoutingModule } from './identity-routing.module';
import { IdentityState } from './states/identity.state';
import { NgbTabsetModule, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { UsersComponent } from './components/users/users.component';
import { PermissionManagementModule } from '@abp/ng.permission-management';
import { NgxValidateCoreModule } from '@ngx-validate/core';
@NgModule({
declarations: [RolesComponent, UsersComponent],
@ -24,4 +24,15 @@ import { NgxValidateCoreModule } from '@ngx-validate/core';
NgxValidateCoreModule,
],
})
export class IdentityModule {}
export class IdentityModule {
static forChild(): ModuleWithProviders<IdentityModule> {
return {
ngModule: IdentityModule,
providers: [],
};
}
static forLazy(): NgModuleFactory<IdentityModule> {
return new LazyModuleFactory(IdentityModule.forChild());
}
}

3
npm/ng-packs/packages/setting-management-config/README.md

@ -1,3 +0,0 @@
# @abp/ng.setting-management.config
[docs.abp.io](https://docs.abp.io)

6
npm/ng-packs/packages/setting-management-config/jest.config.js

@ -1,6 +0,0 @@
const jestConfig = require('../../jest.config');
module.exports = {
...jestConfig,
name: 'setting-management-config',
};

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

@ -1,7 +0,0 @@
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/setting-management-config",
"lib": {
"entryFile": "src/public-api.ts"
}
}

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

@ -1,12 +0,0 @@
{
"name": "@abp/ng.setting-management.config",
"version": "2.9.0",
"homepage": "https://abp.io",
"repository": {
"type": "git",
"url": "https://github.com/abpframework/abp.git"
},
"publishConfig": {
"access": "public"
}
}

37
npm/ng-packs/packages/setting-management-config/src/lib/services/setting-management-config.service.ts

@ -1,37 +0,0 @@
import { Injectable, Injector } from '@angular/core';
import { addAbpRoutes, eLayoutType, PatchRouteByName, ABP } from '@abp/ng.core';
import { getSettingTabs } from '@abp/ng.theme.shared';
import { Store } from '@ngxs/store';
import { eSettingManagementRouteNames } from '@abp/ng.setting-management';
@Injectable({
providedIn: 'root',
})
export class SettingManagementConfigService {
get store(): Store {
return this.injector.get(Store);
}
constructor(private injector: Injector) {
const route = {
name: eSettingManagementRouteNames.Settings,
path: 'setting-management',
parentName: 'AbpUiNavigation::Menu:Administration',
requiredPolicy: 'AbpAccount.SettingManagement',
layout: eLayoutType.application,
order: 6,
iconClass: 'fa fa-cog',
} as ABP.FullRoute;
addAbpRoutes(route);
setTimeout(() => {
const tabs = getSettingTabs();
if (!tabs || !tabs.length) {
this.store.dispatch(
new PatchRouteByName('AbpSettingManagement::Settings', { ...route, invisible: true }),
);
}
});
}
}

8
npm/ng-packs/packages/setting-management-config/src/lib/setting-management-config.module.ts

@ -1,8 +0,0 @@
import { NgModule, APP_INITIALIZER } from '@angular/core';
import { SettingManagementConfigService } from './services/setting-management-config.service';
import { noop } from '@abp/ng.core';
@NgModule({
providers: [{ provide: APP_INITIALIZER, deps: [SettingManagementConfigService], useFactory: noop, multi: true }],
})
export class SettingManagementConfigModule {}

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

@ -1 +0,0 @@
export * from './lib/setting-management-config.module';

19
npm/ng-packs/packages/setting-management-config/tsconfig.lib.json

@ -1,19 +0,0 @@
{
"extends": "../../tsconfig.prod.json",
"compilerOptions": {
"outDir": "../../out-tsc/lib",
"target": "es2015",
"declaration": true,
"inlineSources": true,
"types": [],
"lib": ["dom", "es2018"]
},
"angularCompilerOptions": {
"skipTemplateCodegen": true,
"strictMetadataEmit": true,
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true,
"enableResourceInlining": true
},
"exclude": ["src/test.ts", "**/*.spec.ts"]
}

6
npm/ng-packs/packages/setting-management-config/tsconfig.lib.prod.json

@ -1,6 +0,0 @@
{
"extends": "./tsconfig.lib.json",
"angularCompilerOptions": {
"enableIvy": false
}
}

11
npm/ng-packs/packages/setting-management-config/tsconfig.spec.json

@ -1,11 +0,0 @@
{
"extends": "../../tsconfig.prod.json",
"compilerOptions": {
"emitDecoratorMetadata": true,
"esModuleInterop": true,
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": ["**/*.spec.ts", "**/*.d.ts"]
}

17
npm/ng-packs/packages/setting-management-config/tslint.json

@ -1,17 +0,0 @@
{
"extends": "../../tslint.json",
"rules": {
"directive-selector": [
true,
"attribute",
"abp",
"camelCase"
],
"component-selector": [
true,
"element",
"abp",
"kebab-case"
]
}
}

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

@ -0,0 +1,7 @@
{
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/setting-management/config",
"lib": {
"entryFile": "src/public-api.ts"
}
}

1
npm/ng-packs/packages/setting-management/config/src/enums/index.ts

@ -0,0 +1 @@
export * from './route-names';

3
npm/ng-packs/packages/setting-management/config/src/enums/route-names.ts

@ -0,0 +1,3 @@
export const enum eSettingManagementRouteNames {
Settings = 'AbpSettingManagement::Settings',
}

1
npm/ng-packs/packages/setting-management/config/src/providers/index.ts

@ -0,0 +1 @@
export * from './route.provider';

42
npm/ng-packs/packages/setting-management/config/src/providers/route.provider.ts

@ -0,0 +1,42 @@
import { eLayoutType, RoutesService, SettingTabsService } from '@abp/ng.core';
import { eThemeSharedRouteNames } from '@abp/ng.theme.shared';
import { APP_INITIALIZER } from '@angular/core';
import { debounceTime, map } from 'rxjs/operators';
import { eSettingManagementRouteNames } from '../enums/route-names';
export const SETTING_MANAGEMENT_ROUTE_PROVIDERS = [
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true },
{
provide: APP_INITIALIZER,
useFactory: hideRoutes,
deps: [RoutesService, SettingTabsService],
multi: true,
},
];
export function configureRoutes(routes: RoutesService) {
return () => {
routes.add([
{
name: eSettingManagementRouteNames.Settings,
path: '/setting-management',
parentName: eThemeSharedRouteNames.Administration,
requiredPolicy: 'AbpAccount.SettingManagement',
layout: eLayoutType.application,
order: 6,
iconClass: 'fa fa-cog',
},
]);
};
}
export function hideRoutes(routes: RoutesService, tabs: SettingTabsService) {
return () => {
tabs.visible$
.pipe(
debounceTime(0),
map(nodes => !nodes.length),
)
.subscribe(invisible => routes.patch('AbpSettingManagement::Settings', { invisible }));
};
}

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

@ -0,0 +1,3 @@
export * from './enums';
export * from './providers';
export * from './setting-management-config.module';

12
npm/ng-packs/packages/setting-management/config/src/setting-management-config.module.ts

@ -0,0 +1,12 @@
import { ModuleWithProviders, NgModule } from '@angular/core';
import { SETTING_MANAGEMENT_ROUTE_PROVIDERS } from './providers/route.provider';
@NgModule()
export class SettingManagementConfigModule {
static forRoot(): ModuleWithProviders<SettingManagementConfigModule> {
return {
ngModule: SettingManagementConfigModule,
providers: [SETTING_MANAGEMENT_ROUTE_PROVIDERS],
};
}
}

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

@ -4,5 +4,5 @@
"lib": {
"entryFile": "src/public-api.ts"
},
"whitelistedNonPeerDependencies": ["@abp/ng.theme.shared", "@abp/ng.setting-management.config"]
"whitelistedNonPeerDependencies": ["@abp/ng.theme.shared"]
}

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

@ -7,7 +7,6 @@
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
"@abp/ng.setting-management.config": "~2.9.0",
"@abp/ng.theme.shared": "~2.9.0"
},
"publishConfig": {

4
npm/ng-packs/packages/setting-management/src/lib/actions/setting-management.actions.ts

@ -1,6 +1,6 @@
import { SettingTab } from '@abp/ng.theme.shared';
import { ABP } from '@abp/ng.core';
export class SetSelectedSettingTab {
static readonly type = '[SettingManagement] Set Selected Tab';
constructor(public payload: SettingTab) {}
constructor(public payload: ABP.Tab) {}
}

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

Loading…
Cancel
Save