mirror of https://github.com/abpframework/abp.git
committed by
GitHub
144 changed files with 1265 additions and 2096 deletions
@ -1,7 +0,0 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { AccountModule } from '@abp/ng.account'; |
|||
|
|||
@NgModule({ |
|||
imports: [AccountModule], |
|||
}) |
|||
export class AccountWrapperModule {} |
|||
@ -1,7 +0,0 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { IdentityModule } from '@abp/ng.identity'; |
|||
|
|||
@NgModule({ |
|||
imports: [IdentityModule], |
|||
}) |
|||
export class IdentityWrapperModule {} |
|||
@ -1,7 +0,0 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { SettingManagementModule } from '@abp/ng.setting-management'; |
|||
|
|||
@NgModule({ |
|||
imports: [SettingManagementModule], |
|||
}) |
|||
export class SettingManagementWrapperModule {} |
|||
@ -1,7 +0,0 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { TenantManagementModule } from '@abp/ng.tenant-management'; |
|||
|
|||
@NgModule({ |
|||
imports: [TenantManagementModule], |
|||
}) |
|||
export class TenantManagementWrapperModule {} |
|||
@ -1,3 +0,0 @@ |
|||
# @abp/ng.account.config |
|||
|
|||
[docs.abp.io](https://docs.abp.io) |
|||
@ -1,6 +0,0 @@ |
|||
const jestConfig = require('../../jest.config'); |
|||
|
|||
module.exports = { |
|||
...jestConfig, |
|||
name: 'account-config', |
|||
}; |
|||
@ -1,7 +0,0 @@ |
|||
{ |
|||
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json", |
|||
"dest": "../../dist/account-config", |
|||
"lib": { |
|||
"entryFile": "src/public-api.ts" |
|||
} |
|||
} |
|||
@ -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" |
|||
} |
|||
} |
|||
@ -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], |
|||
}, |
|||
], |
|||
}; |
|||
} |
|||
} |
|||
@ -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 }, |
|||
], |
|||
}); |
|||
} |
|||
} |
|||
@ -1,2 +0,0 @@ |
|||
export * from './lib/services/account-config.service'; |
|||
export * from './lib/account-config.module'; |
|||
@ -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"] |
|||
} |
|||
@ -1,6 +0,0 @@ |
|||
{ |
|||
"extends": "./tsconfig.lib.json", |
|||
"angularCompilerOptions": { |
|||
"enableIvy": false |
|||
} |
|||
} |
|||
@ -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"] |
|||
} |
|||
@ -1,17 +0,0 @@ |
|||
{ |
|||
"extends": "../../tslint.json", |
|||
"rules": { |
|||
"directive-selector": [ |
|||
true, |
|||
"attribute", |
|||
"abp", |
|||
"camelCase" |
|||
], |
|||
"component-selector": [ |
|||
true, |
|||
"element", |
|||
"abp", |
|||
"kebab-case" |
|||
] |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
{ |
|||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", |
|||
"dest": "../../dist/account/config", |
|||
"lib": { |
|||
"entryFile": "src/public-api.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], |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1 @@ |
|||
export * from './route-names'; |
|||
@ -0,0 +1 @@ |
|||
export * from './route.provider'; |
|||
@ -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, |
|||
}, |
|||
]); |
|||
}; |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
export * from './account-config.module'; |
|||
export * from './enums'; |
|||
export * from './providers'; |
|||
@ -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'); |
|||
|
|||
@ -0,0 +1,8 @@ |
|||
import { Options } from '../models/options'; |
|||
|
|||
export function accountOptionsFactory(options: Options) { |
|||
return { |
|||
redirectUrl: '/', |
|||
...options, |
|||
}; |
|||
} |
|||
@ -0,0 +1 @@ |
|||
export * from './factory-utils'; |
|||
@ -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)); |
|||
} |
|||
} |
|||
@ -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); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -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); |
|||
}); |
|||
}); |
|||
|
|||
@ -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); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -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); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -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'); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -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; |
|||
} |
|||
@ -0,0 +1,6 @@ |
|||
export function pushValueTo<T extends any>(array: T[]) { |
|||
return (element: T) => { |
|||
array.push(element); |
|||
return array; |
|||
}; |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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('/'); |
|||
} |
|||
|
|||
@ -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>; |
|||
@ -1,3 +0,0 @@ |
|||
# @abp/ng.identity.config |
|||
|
|||
[docs.abp.io](https://docs.abp.io) |
|||
@ -1,6 +0,0 @@ |
|||
const jestConfig = require('../../jest.config'); |
|||
|
|||
module.exports = { |
|||
...jestConfig, |
|||
name: 'identity-config', |
|||
}; |
|||
@ -1,7 +0,0 @@ |
|||
{ |
|||
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json", |
|||
"dest": "../../dist/identity-config", |
|||
"lib": { |
|||
"entryFile": "src/public-api.ts" |
|||
} |
|||
} |
|||
@ -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" |
|||
} |
|||
} |
|||
@ -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 {} |
|||
@ -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', |
|||
}, |
|||
], |
|||
}, |
|||
]); |
|||
} |
|||
} |
|||
@ -1,2 +0,0 @@ |
|||
export * from './lib/services/identity-config.service'; |
|||
export * from './lib/identity-config.module'; |
|||
@ -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"] |
|||
} |
|||
@ -1,6 +0,0 @@ |
|||
{ |
|||
"extends": "./tsconfig.lib.json", |
|||
"angularCompilerOptions": { |
|||
"enableIvy": false |
|||
} |
|||
} |
|||
@ -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"] |
|||
} |
|||
@ -1,17 +0,0 @@ |
|||
{ |
|||
"extends": "../../tslint.json", |
|||
"rules": { |
|||
"directive-selector": [ |
|||
true, |
|||
"attribute", |
|||
"abp", |
|||
"camelCase" |
|||
], |
|||
"component-selector": [ |
|||
true, |
|||
"element", |
|||
"abp", |
|||
"kebab-case" |
|||
] |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
{ |
|||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", |
|||
"dest": "../../dist/identity/config", |
|||
"lib": { |
|||
"entryFile": "src/public-api.ts" |
|||
} |
|||
} |
|||
@ -0,0 +1 @@ |
|||
export * from './route-names'; |
|||
@ -1,5 +1,4 @@ |
|||
export const enum eIdentityRouteNames { |
|||
Administration = 'AbpUiNavigation::Menu:Administration', |
|||
IdentityManagement = 'AbpIdentity::Menu:IdentityManagement', |
|||
Roles = 'AbpIdentity::Roles', |
|||
Users = 'AbpIdentity::Users', |
|||
@ -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], |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1 @@ |
|||
export * from './route.provider'; |
|||
@ -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, |
|||
}, |
|||
]); |
|||
}; |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
export * from './enums'; |
|||
export * from './identity-config.module'; |
|||
export * from './providers'; |
|||
@ -1,3 +0,0 @@ |
|||
# @abp/ng.setting-management.config |
|||
|
|||
[docs.abp.io](https://docs.abp.io) |
|||
@ -1,6 +0,0 @@ |
|||
const jestConfig = require('../../jest.config'); |
|||
|
|||
module.exports = { |
|||
...jestConfig, |
|||
name: 'setting-management-config', |
|||
}; |
|||
@ -1,7 +0,0 @@ |
|||
{ |
|||
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json", |
|||
"dest": "../../dist/setting-management-config", |
|||
"lib": { |
|||
"entryFile": "src/public-api.ts" |
|||
} |
|||
} |
|||
@ -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" |
|||
} |
|||
} |
|||
@ -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 }), |
|||
); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
@ -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 +0,0 @@ |
|||
export * from './lib/setting-management-config.module'; |
|||
@ -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"] |
|||
} |
|||
@ -1,6 +0,0 @@ |
|||
{ |
|||
"extends": "./tsconfig.lib.json", |
|||
"angularCompilerOptions": { |
|||
"enableIvy": false |
|||
} |
|||
} |
|||
@ -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"] |
|||
} |
|||
@ -1,17 +0,0 @@ |
|||
{ |
|||
"extends": "../../tslint.json", |
|||
"rules": { |
|||
"directive-selector": [ |
|||
true, |
|||
"attribute", |
|||
"abp", |
|||
"camelCase" |
|||
], |
|||
"component-selector": [ |
|||
true, |
|||
"element", |
|||
"abp", |
|||
"kebab-case" |
|||
] |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
{ |
|||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", |
|||
"dest": "../../dist/setting-management/config", |
|||
"lib": { |
|||
"entryFile": "src/public-api.ts" |
|||
} |
|||
} |
|||
@ -0,0 +1 @@ |
|||
export * from './route-names'; |
|||
@ -0,0 +1,3 @@ |
|||
export const enum eSettingManagementRouteNames { |
|||
Settings = 'AbpSettingManagement::Settings', |
|||
} |
|||
@ -0,0 +1 @@ |
|||
export * from './route.provider'; |
|||
@ -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 })); |
|||
}; |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
export * from './enums'; |
|||
export * from './providers'; |
|||
export * from './setting-management-config.module'; |
|||
@ -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], |
|||
}; |
|||
} |
|||
} |
|||
@ -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…
Reference in new issue