Browse Source

Merge pull request #5957 from abpframework/feat/4588

feat: add permission service
pull/6074/head
Bunyamin Coskuner 6 years ago
committed by GitHub
parent
commit
c4f27608ea
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      docs/en/UI/Angular/Permission-Management.md
  2. 37
      modules/cms-kit/angular/projects/cms-kit/config/src/providers/route.provider.ts
  3. 4
      modules/cms-kit/angular/projects/dev-app/src/app/route.provider.ts
  4. 4
      npm/ng-packs/apps/dev-app/src/app/route.provider.ts
  5. 4
      npm/ng-packs/packages/account/config/src/providers/route.provider.ts
  6. 4
      npm/ng-packs/packages/core/src/lib/directives/index.ts
  7. 10
      npm/ng-packs/packages/core/src/lib/directives/permission.directive.ts
  8. 13
      npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts
  9. 1
      npm/ng-packs/packages/core/src/lib/services/config-state.service.ts
  10. 1
      npm/ng-packs/packages/core/src/lib/services/index.ts
  11. 60
      npm/ng-packs/packages/core/src/lib/services/permission.service.ts
  12. 18
      npm/ng-packs/packages/core/src/lib/services/routes.service.ts
  13. 3
      npm/ng-packs/packages/core/src/lib/states/config.state.ts
  14. 14
      npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts
  15. 14
      npm/ng-packs/packages/core/src/lib/tests/permission.directive.spec.ts
  16. 16
      npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts
  17. 10
      npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts
  18. 28
      npm/ng-packs/packages/core/src/lib/tests/utils/common.utils.ts
  19. 1
      npm/ng-packs/packages/core/src/lib/tests/utils/index.ts
  20. 7
      npm/ng-packs/packages/core/src/lib/tests/utils/permission-service.spec.utils.ts
  21. 12
      npm/ng-packs/packages/core/src/lib/tests/utils/routes-service.spec.utils.ts
  22. 6
      npm/ng-packs/packages/core/src/lib/utils/route-utils.ts
  23. 4
      npm/ng-packs/packages/identity/config/src/providers/route.provider.ts
  24. 12
      npm/ng-packs/packages/setting-management/config/src/providers/route.provider.ts
  25. 4
      npm/ng-packs/packages/setting-management/src/lib/components/setting-management.component.ts
  26. 2
      npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.html
  27. 4
      npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.ts
  28. 2
      npm/ng-packs/packages/theme-shared/src/lib/directives/loading.directive.ts
  29. 4
      npm/ng-packs/packages/theme-shared/src/lib/providers/route.provider.ts
  30. 10
      npm/ng-packs/packages/theme-shared/src/lib/tests/breadcrumb.component.spec.ts
  31. 4
      templates/app/angular/src/app/route.provider.ts
  32. 4
      templates/module/angular/projects/dev-app/src/app/route.provider.ts
  33. 5
      templates/module/angular/projects/my-project-name/config/src/providers/route.provider.ts

12
docs/en/UI/Angular/Permission-Management.md

@ -2,18 +2,20 @@
A permission is a simple policy that is granted or prohibited for a particular user, role or client. You can read more about [authorization in ABP](../../Authorization.md) document.
You can get permission of authenticated user using `getGrantedPolicy` selector of `ConfigState`.
You can get permission of authenticated user using `getGrantedPolicy` or `getGrantedPolicy$` method of `PermissionService`.
> ConfigState's getGrantedPolicy selector and ConfigStateService's getGrantedPolicy method deprecated. Use permission service's `getGrantedPolicy$` or `getGrantedPolicy`methods instead
You can get permission as boolean value:
```js
import { ConfigStateService } from '@abp/ng.core';
import { PermissionService } from '@abp/ng.core';
export class YourComponent {
constructor(private config: ConfigStateService) {}
constructor(private permissionService: PermissionService) {}
ngOnInit(): void {
const canCreate = this.config.getGrantedPolicy('AbpIdentity.Roles.Create');
const canCreate = this.permissionService.getGrantedPolicy('AbpIdentity.Roles.Create');
}
}
```
@ -59,4 +61,4 @@ Granted Policies are stored in the `auth` property of `ConfigState`.
## What's Next?
* [Multi Tenancy](./Multi-Tenancy.md)
* [Multi Tenancy](./Multi-Tenancy.md)

37
modules/cms-kit/angular/projects/cms-kit/config/src/providers/route.provider.ts

@ -1,27 +1,26 @@
import { eLayoutType, RoutesService } from '@abp/ng.core';
import { eThemeSharedRouteNames } from '@abp/ng.theme.shared';
import { APP_INITIALIZER } from '@angular/core';
import { eCmsKitRouteNames } from '../enums/route-names';
export const MY_PROJECT_NAME_ROUTE_PROVIDERS = [
{
provide: APP_INITIALIZER,
useFactory: configureRoutes,
deps: [RoutesService],
multi: true,
},
{
provide: APP_INITIALIZER,
useFactory: configureRoutes,
deps: [RoutesService],
multi: true,
},
];
export function configureRoutes(routes: RoutesService) {
return () => {
routes.add([
{
path: '/cms-kit',
name: eCmsKitRouteNames.CmsKit,
iconClass: 'fas fa-book',
layout: eLayoutType.application,
order: 3,
},
]);
};
export function configureRoutes(routesService: RoutesService) {
return () => {
routesService.add([
{
path: '/cms-kit',
name: eCmsKitRouteNames.CmsKit,
iconClass: 'fas fa-book',
layout: eLayoutType.application,
order: 3,
},
]);
};
}

4
modules/cms-kit/angular/projects/dev-app/src/app/route.provider.ts

@ -10,9 +10,9 @@ export const APP_ROUTE_PROVIDER = [
},
];
function configureRoutes(routes: RoutesService) {
function configureRoutes(routesService: RoutesService) {
return () => {
routes.add([
routesService.add([
{
path: '/',
name: 'Home',

4
npm/ng-packs/apps/dev-app/src/app/route.provider.ts

@ -5,9 +5,9 @@ export const APP_ROUTE_PROVIDER = [
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true },
];
function configureRoutes(routes: RoutesService) {
function configureRoutes(routesService: RoutesService) {
return () => {
routes.add([
routesService.add([
{
path: '/',
name: '::Menu:Home',

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

@ -6,9 +6,9 @@ export const ACCOUNT_ROUTE_PROVIDERS = [
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true },
];
export function configureRoutes(routes: RoutesService) {
export function configureRoutes(routesService: RoutesService) {
return () => {
routes.add([
routesService.add([
{
path: '/account',
name: eAccountRouteNames.Account,

4
npm/ng-packs/packages/core/src/lib/directives/index.ts

@ -1,10 +1,10 @@
export * from './autofocus.directive';
export * from './debounce.directive';
export * from './ellipsis.directive';
export * from './for.directive';
export * from './form-submit.directive';
export * from './init.directive';
export * from './permission.directive';
export * from './replaceable-template.directive';
export * from './visibility.directive';
export * from './debounce.directive';
export * from './stop-propagation.directive';
export * from './visibility.directive';

10
npm/ng-packs/packages/core/src/lib/directives/permission.directive.ts

@ -11,9 +11,8 @@ import {
TemplateRef,
ViewContainerRef,
} from '@angular/core';
import { Store } from '@ngxs/store';
import { Subscription } from 'rxjs';
import { ConfigState } from '../states';
import { PermissionService } from '../services/permission.service';
@Directive({
selector: '[abpPermission]',
@ -26,18 +25,17 @@ export class PermissionDirective implements OnInit, OnDestroy, OnChanges {
constructor(
private elRef: ElementRef,
private renderer: Renderer2,
private store: Store,
@Optional() private templateRef: TemplateRef<any>,
private vcRef: ViewContainerRef,
private permissionService: PermissionService,
) {}
private check() {
if (this.subscription) {
this.subscription.unsubscribe();
}
this.subscription = this.store
.select(ConfigState.getGrantedPolicy(this.condition))
this.subscription = this.permissionService
.getGrantedPolicy$(this.condition)
.subscribe(isGranted => {
if (this.templateRef && isGranted) {
this.vcRef.clear();

13
npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts

@ -5,26 +5,31 @@ import { Observable, of } from 'rxjs';
import { tap } from 'rxjs/operators';
import { RestOccurError } from '../actions/rest.actions';
import { RoutesService } from '../services/routes.service';
import { ConfigState } from '../states/config.state';
import { findRoute, getRoutePath } from '../utils/route-utils';
import { PermissionService } from '../services/permission.service';
@Injectable({
providedIn: 'root',
})
export class PermissionGuard implements CanActivate {
constructor(private router: Router, private routes: RoutesService, private store: Store) {}
constructor(
private router: Router,
private routesService: RoutesService,
private store: Store,
private permissionService: PermissionService,
) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
let { requiredPolicy } = route.data || {};
if (!requiredPolicy) {
const routeFound = findRoute(this.routes, getRoutePath(this.router, state.url));
const routeFound = findRoute(this.routesService, getRoutePath(this.router, state.url));
requiredPolicy = routeFound?.requiredPolicy;
}
if (!requiredPolicy) return of(true);
return this.store.select(ConfigState.getGrantedPolicy(requiredPolicy)).pipe(
return this.permissionService.getGrantedPolicy$(requiredPolicy).pipe(
tap(access => {
if (!access) {
this.store.dispatch(new RestOccurError({ status: 403 }));

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

@ -45,6 +45,7 @@ export class ConfigStateService {
return this.store.selectSnapshot(ConfigState.getSettings(...args));
}
/** @deprecated Use PermissionService's getGrantedPolicySnapshot method */
getGrantedPolicy(...args: Parameters<typeof ConfigState.getGrantedPolicy>) {
return this.store.selectSnapshot(ConfigState.getGrantedPolicy(...args));
}

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

@ -7,6 +7,7 @@ export * from './lazy-load.service';
export * from './list.service';
export * from './localization.service';
export * from './multi-tenancy.service';
export * from './permission.service';
export * from './profile-state.service';
export * from './profile.service';
export * from './replaceable-components.service';

60
npm/ng-packs/packages/core/src/lib/services/permission.service.ts

@ -0,0 +1,60 @@
import { ConfigState } from '../states';
import { Store } from '@ngxs/store';
import { map } from 'rxjs/operators';
import { ApplicationConfiguration } from '../models/application-configuration';
import snq from 'snq';
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class PermissionService {
constructor(private store: Store) {}
getGrantedPolicy$(key: string) {
return this.getStream().pipe(map(policies => this.isPolicyGranted(key, policies)));
}
getGrantedPolicy(key: string) {
const policies = this.getSnapshot();
return this.isPolicyGranted(key, policies);
}
private isPolicyGranted(key: string, policies: ApplicationConfiguration.Policy) {
if (!key) return true;
const orRegexp = /\|\|/g;
const andRegexp = /&&/g;
// TODO: Allow combination of ANDs & ORs
if (orRegexp.test(key)) {
const keys = key.split('||').filter(Boolean);
if (keys.length < 2) return false;
return keys.some(k => this.getPolicy(k.trim(), policies));
} else if (andRegexp.test(key)) {
const keys = key.split('&&').filter(Boolean);
if (keys.length < 2) return false;
return keys.every(k => this.getPolicy(k.trim(), policies));
}
return this.getPolicy(key, policies);
}
private getStream() {
return this.store.select(ConfigState).pipe(map(this.mapToPolicies));
}
private getSnapshot() {
return this.mapToPolicies(this.store.selectSnapshot(ConfigState));
}
private mapToPolicies(applicationConfiguration: ApplicationConfiguration.Response) {
return snq(() => applicationConfiguration.auth.grantedPolicies);
}
private getPolicy(policy: string, policies: ApplicationConfiguration.Policy) {
return snq(() => policies[policy], false);
}
}

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

@ -1,11 +1,11 @@
import { Injectable, OnDestroy } from '@angular/core';
import { Actions, ofActionSuccessful, Store } from '@ngxs/store';
import { Injectable, Injector, OnDestroy } from '@angular/core';
import { Actions, ofActionSuccessful } from '@ngxs/store';
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
import { GetAppConfiguration } from '../actions/config.actions';
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';
import { PermissionService } from './permission.service';
export abstract class AbstractTreeService<T extends object> {
abstract id: string;
@ -134,9 +134,12 @@ export abstract class AbstractTreeService<T extends object> {
}
@Injectable()
export abstract class AbstractNavTreeService<T extends ABP.Nav> extends AbstractTreeService<T>
export abstract class AbstractNavTreeService<T extends ABP.Nav>
extends AbstractTreeService<T>
implements OnDestroy {
protected actions: Actions;
private subscription: Subscription;
private permissionService: PermissionService;
readonly id = 'name';
readonly parentId = 'parentName';
readonly hide = (item: T) => item.invisible || !this.isGranted(item);
@ -147,16 +150,17 @@ export abstract class AbstractNavTreeService<T extends ABP.Nav> extends Abstract
return a.order - b.order;
};
constructor(protected actions: Actions, protected store: Store) {
constructor(protected injector: Injector) {
super();
this.actions = injector.get(Actions);
this.subscription = this.actions
.pipe(ofActionSuccessful(GetAppConfiguration))
.subscribe(() => this.refresh());
this.permissionService = injector.get(PermissionService);
}
protected isGranted({ requiredPolicy }: T): boolean {
return this.store.selectSnapshot(ConfigState.getGrantedPolicy(requiredPolicy));
return this.permissionService.getGrantedPolicy(requiredPolicy);
}
hasChildren(identifier: string): boolean {

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

@ -104,6 +104,9 @@ export class ConfigState {
return selector;
}
/**
* @deprecated use PermissionService's getGrantedPolicyStream or getGrantedPolicy methods.
*/
static getGrantedPolicy(key: string) {
const selector = createSelector([ConfigState], (state: Config.State): boolean => {
if (!key) return true;

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

@ -2,17 +2,16 @@ 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 { Actions, NgxsModule, Store } from '@ngxs/store';
import { NEVER } from 'rxjs';
import { NgxsModule } from '@ngxs/store';
import { DynamicLayoutComponent, RouterOutletComponent } from '../components';
import { eLayoutType } from '../enums/common';
import { ABP } from '../models';
import {
ApplicationConfigurationService,
RoutesService,
ReplaceableComponentsService,
RoutesService,
} from '../services';
import { ReplaceableComponentsState } from '../states';
import { mockRoutesService } from './utils';
@Component({
selector: 'abp-layout-application',
@ -91,12 +90,7 @@ describe('DynamicLayoutComponent', () => {
providers: [
{
provide: RoutesService,
useFactory: () =>
new RoutesService(NEVER, ({
selectSnapshot() {
return true;
},
} as unknown) as Store),
useFactory: () => mockRoutesService(),
},
ReplaceableComponentsService,
],

14
npm/ng-packs/packages/core/src/lib/tests/permission.directive.spec.ts

@ -1,16 +1,20 @@
import { PermissionDirective } from '../directives/permission.directive';
import { SpectatorDirective, createDirectiveFactory, SpyObject } from '@ngneat/spectator/jest';
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/jest';
import { Store } from '@ngxs/store';
import { of, Subject } from 'rxjs';
import { Subject } from 'rxjs';
import { PermissionService } from '../services';
import { mockStore } from './utils/common.utils';
describe('PermissionDirective', () => {
let spectator: SpectatorDirective<PermissionDirective>;
let directive: PermissionDirective;
const grantedPolicy$ = new Subject();
const grantedPolicy$ = new Subject<boolean>();
const createDirective = createDirectiveFactory({
directive: PermissionDirective,
providers: [{ provide: Store, useValue: { select: () => grantedPolicy$ } }],
providers: [
{ provide: Store, useValue: mockStore },
{ provide: PermissionService, useValue: { getGrantedPolicy$: () => grantedPolicy$ } },
],
});
describe('with condition', () => {

16
npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts

@ -7,19 +7,21 @@ import { of } from 'rxjs';
import { RestOccurError } from '../actions';
import { PermissionGuard } from '../guards/permission.guard';
import { RoutesService } from '../services/routes.service';
import { PermissionService } from '../services';
describe('PermissionGuard', () => {
let spectator: SpectatorService<PermissionGuard>;
let guard: PermissionGuard;
let routes: SpyObject<RoutesService>;
let store: SpyObject<Store>;
let permissionService: SpyObject<PermissionService>;
@Component({ template: '' })
class DummyComponent {}
const createService = createServiceFactory({
service: PermissionGuard,
mocks: [Store],
mocks: [PermissionService, Store],
declarations: [DummyComponent],
imports: [
RouterModule.forRoot([
@ -53,10 +55,11 @@ describe('PermissionGuard', () => {
guard = spectator.service;
routes = spectator.inject(RoutesService);
store = spectator.inject(Store);
permissionService = spectator.inject(PermissionService);
});
it('should return true when the grantedPolicy is true', done => {
store.select.andReturn(of(true));
permissionService.getGrantedPolicy$.andReturn(of(true));
const spy = jest.spyOn(store, 'dispatch');
guard.canActivate({ data: { requiredPolicy: 'test' } } as any, null).subscribe(res => {
expect(res).toBe(true);
@ -66,7 +69,7 @@ describe('PermissionGuard', () => {
});
it('should return false and dispatch RestOccurError when the grantedPolicy is false', done => {
store.select.andReturn(of(false));
permissionService.getGrantedPolicy$.andReturn(of(false));
const spy = jest.spyOn(store, 'dispatch');
guard.canActivate({ data: { requiredPolicy: 'test' } } as any, null).subscribe(res => {
expect(res).toBe(false);
@ -84,10 +87,9 @@ describe('PermissionGuard', () => {
requiredPolicy: 'TestPolicy',
},
]);
store.select.andReturn(of(false));
const spy = jest.spyOn(store, 'select');
guard.canActivate({ data: {} } as any, { url: 'test' } as any).subscribe(() => {
expect(spy.mock.calls[0][0]({ auth: { grantedPolicies: { TestPolicy: true } } })).toBe(true);
permissionService.getGrantedPolicy$.mockImplementation(policy => of(policy === 'TestPolicy'));
guard.canActivate({ data: {} } as any, { url: 'test' } as any).subscribe(result => {
expect(result).toBe(true);
done();
});
});

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

@ -3,6 +3,8 @@ import { Subject } from 'rxjs';
import { take } from 'rxjs/operators';
import { GetAppConfiguration } from '../actions';
import { RoutesService } from '../services';
import { mockRoutesService } from './utils';
import { mockActions } from './utils/common.utils';
describe('Routes Service', () => {
let service: RoutesService;
@ -14,15 +16,9 @@ describe('Routes Service', () => {
{ path: '/foo/x', name: 'x', parentName: 'foo', order: 1 },
];
const mockActions = new Subject();
const mockStore = ({
selectSnapshot() {
return true;
},
} as unknown) as Store;
beforeEach(() => {
service = new RoutesService(mockActions, mockStore);
service = mockRoutesService();
});
describe('#add', () => {

28
npm/ng-packs/packages/core/src/lib/tests/utils/common.utils.ts

@ -0,0 +1,28 @@
import { Observable, of, Subject } from 'rxjs';
import { Store } from '@ngxs/store';
import { AbstractType, InjectFlags, InjectionToken, Injector, Type } from '@angular/core';
export const mockActions = new Subject();
export const mockStore = ({
selectSnapshot() {
return true;
},
select(): Observable<any> {
return of(null);
},
} as unknown) as Store;
export class DummyInjector extends Injector {
constructor(public payload: { [key: string]: any }) {
super();
}
get<T>(
token: Type<T> | InjectionToken<T> | AbstractType<T>,
notFoundValue?: T,
flags?: InjectFlags,
): T;
get(token: any, notFoundValue?: any): any;
get(token, notFoundValue?, flags?: InjectFlags): any {
return this.payload[token.name || token];
}
}

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

@ -0,0 +1 @@
export * from './routes-service.spec.utils';

7
npm/ng-packs/packages/core/src/lib/tests/utils/permission-service.spec.utils.ts

@ -0,0 +1,7 @@
import { PermissionService } from '../../services';
import { Subject } from 'rxjs';
export const mockPermissionService = (args = {} as Partial<PermissionService>) => {
const permissionService = { getGrantedPolicy$: new Subject(), getGrantedPolicy: arg => true };
return Object.assign({}, permissionService, args);
};

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

@ -0,0 +1,12 @@
import { RoutesService } from '../../services';
import { mockPermissionService } from './permission-service.spec.utils';
import { DummyInjector, mockActions } from './common.utils';
export const mockRoutesService = (injectorPayload = {} as { [key: string]: any }) => {
const injector = new DummyInjector({
PermissionService: mockPermissionService(),
Actions: mockActions,
...injectorPayload,
});
return new RoutesService(injector);
};

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

@ -5,12 +5,12 @@ import { RoutesService } from '../services/routes.service';
import { noop } from './common-utils';
import { TreeNode } from './tree-utils';
export function findRoute(routes: RoutesService, path: string): TreeNode<ABP.Route> {
const node = routes.find(route => route.path === path);
export function findRoute(routesService: RoutesService, path: string): TreeNode<ABP.Route> {
const node = routesService.find(route => route.path === path);
return node || path === '/'
? node
: findRoute(routes, path.split('/').slice(0, -1).join('/') || '/');
: findRoute(routesService, path.split('/').slice(0, -1).join('/') || '/');
}
export function getRoutePath(router: Router, url = router.url) {

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

@ -8,9 +8,9 @@ export const IDENTITY_ROUTE_PROVIDERS = [
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true },
];
export function configureRoutes(routes: RoutesService) {
export function configureRoutes(routesService: RoutesService) {
return () => {
routes.add([
routesService.add([
{
path: '/identity',
name: eIdentityRouteNames.IdentityManagement,

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

@ -14,9 +14,9 @@ export const SETTING_MANAGEMENT_ROUTE_PROVIDERS = [
},
];
export function configureRoutes(routes: RoutesService) {
export function configureRoutes(routesService: RoutesService) {
return () => {
routes.add([
routesService.add([
{
name: eSettingManagementRouteNames.Settings,
path: '/setting-management',
@ -29,13 +29,15 @@ export function configureRoutes(routes: RoutesService) {
};
}
export function hideRoutes(routes: RoutesService, tabs: SettingTabsService) {
export function hideRoutes(routesService: RoutesService, settingTabsService: SettingTabsService) {
return () => {
tabs.visible$
settingTabsService.visible$
.pipe(
debounceTime(0),
map(nodes => !nodes.length),
)
.subscribe(invisible => routes.patch(eSettingManagementRouteNames.Settings, { invisible }));
.subscribe(invisible =>
routesService.patch(eSettingManagementRouteNames.Settings, { invisible }),
);
};
}

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

@ -24,7 +24,7 @@ export class SettingManagementComponent implements OnDestroy, OnInit {
trackByFn: TrackByFunction<ABP.Tab> = (_, item) => item.name;
constructor(private store: Store, private settingTabs: SettingTabsService) {}
constructor(private store: Store, private settingTabsService: SettingTabsService) {}
ngOnDestroy() {
this.subscription.unsubscribe();
@ -32,7 +32,7 @@ export class SettingManagementComponent implements OnDestroy, OnInit {
ngOnInit() {
this.subscription.add(
this.settingTabs.visible$.subscribe(settings => {
this.settingTabsService.visible$.subscribe(settings => {
this.settings = settings;
if (!this.selected) this.selected = this.settings[0];

2
npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.html

@ -1,6 +1,6 @@
<ul class="navbar-nav">
<ng-container
*ngFor="let route of routes.visible$ | async; trackBy: trackByFn"
*ngFor="let route of routesService.visible$ | async; trackBy: trackByFn"
[ngTemplateOutlet]="isDropdown(route) ? dropdownLink : defaultLink"
[ngTemplateOutletContext]="{ $implicit: route }"
>

4
npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.ts

@ -20,10 +20,10 @@ export class RoutesComponent {
trackByFn: TrackByFunction<TreeNode<ABP.Route>> = (_, item) => item.name;
constructor(public readonly routes: RoutesService, protected renderer: Renderer2) {}
constructor(public readonly routesService: RoutesService, protected renderer: Renderer2) {}
isDropdown(node: TreeNode<ABP.Route>) {
return !node?.isLeaf || this.routes.hasChildren(node.name);
return !node?.isLeaf || this.routesService.hasChildren(node.name);
}
closeDropdown() {

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

@ -7,8 +7,8 @@ import {
HostBinding,
Injector,
Input,
OnInit,
OnDestroy,
OnInit,
Renderer2,
ViewContainerRef,
} from '@angular/core';

4
npm/ng-packs/packages/theme-shared/src/lib/providers/route.provider.ts

@ -6,9 +6,9 @@ export const THEME_SHARED_ROUTE_PROVIDERS = [
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true },
];
export function configureRoutes(routes: RoutesService) {
export function configureRoutes(routesService: RoutesService) {
return () => {
routes.add([
routesService.add([
{
path: undefined,
name: eThemeSharedRouteNames.Administration,

10
npm/ng-packs/packages/theme-shared/src/lib/tests/breadcrumb.component.spec.ts

@ -2,15 +2,9 @@ import { ABP, LocalizationPipe, RouterOutletComponent, RoutesService } from '@ab
import { RouterModule } from '@angular/router';
import { createRoutingFactory, SpectatorRouting, SpyObject } from '@ngneat/spectator/jest';
import { Store } from '@ngxs/store';
import { Subject } from 'rxjs';
import { BreadcrumbComponent } from '../components/breadcrumb/breadcrumb.component';
import { mockRoutesService } from '../../../../core/src/lib/tests/utils';
const mockActions = new Subject();
const mockStore = ({
selectSnapshot() {
return true;
},
} as unknown) as Store;
const mockRoutes: ABP.Route[] = [
{ name: 'Identity', path: '/identity' },
{ name: 'Users', path: '/identity/users', parentName: 'Identity' },
@ -29,7 +23,7 @@ describe('BreadcrumbComponent', () => {
providers: [
{
provide: RoutesService,
useFactory: () => new RoutesService(mockActions, mockStore),
useFactory: () => mockRoutesService(),
},
],
declarations: [LocalizationPipe, BreadcrumbComponent],

4
templates/app/angular/src/app/route.provider.ts

@ -5,9 +5,9 @@ export const APP_ROUTE_PROVIDER = [
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true },
];
function configureRoutes(routes: RoutesService) {
function configureRoutes(routesService: RoutesService) {
return () => {
routes.add([
routesService.add([
{
path: '/',
name: '::Menu:Home',

4
templates/module/angular/projects/dev-app/src/app/route.provider.ts

@ -10,9 +10,9 @@ export const APP_ROUTE_PROVIDER = [
},
];
function configureRoutes(routes: RoutesService) {
function configureRoutes(routesService: RoutesService) {
return () => {
routes.add([
routesService.add([
{
path: '/',
name: 'Home',

5
templates/module/angular/projects/my-project-name/config/src/providers/route.provider.ts

@ -1,5 +1,4 @@
import { eLayoutType, RoutesService } from '@abp/ng.core';
import { eThemeSharedRouteNames } from '@abp/ng.theme.shared';
import { APP_INITIALIZER } from '@angular/core';
import { eMyProjectNameRouteNames } from '../enums/route-names';
@ -12,9 +11,9 @@ export const MY_PROJECT_NAME_ROUTE_PROVIDERS = [
},
];
export function configureRoutes(routes: RoutesService) {
export function configureRoutes(routesService: RoutesService) {
return () => {
routes.add([
routesService.add([
{
path: '/my-project-name',
name: eMyProjectNameRouteNames.MyProjectName,

Loading…
Cancel
Save