mirror of https://github.com/abpframework/abp
				
				
				
			
						commit
						09dccf67da
					
				| @ -0,0 +1,3 @@ | ||||
| # @abp/ng.account.core | ||||
| 
 | ||||
| Visit the [ABP documentation](https://docs.abp.io) | ||||
| @ -0,0 +1,6 @@ | ||||
| const jestConfig = require('../../jest.config'); | ||||
| 
 | ||||
| module.exports = { | ||||
|   ...jestConfig, | ||||
|   name: 'account-core', | ||||
| }; | ||||
| @ -0,0 +1,7 @@ | ||||
| { | ||||
|   "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", | ||||
|   "dest": "../../dist/account-core", | ||||
|   "lib": { | ||||
|     "entryFile": "src/public-api.ts" | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,18 @@ | ||||
| { | ||||
|   "name": "@abp/ng.account.core", | ||||
|   "version": "0.0.1", | ||||
|   "homepage": "https://abp.io", | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
|     "url": "https://github.com/abpframework/abp.git" | ||||
|   }, | ||||
|   "peerDependencies": { | ||||
|     "@angular/common": ">=11.1.2", | ||||
|     "@angular/core": ">=11.1.2", | ||||
|     "@abp/ng.core": "~4.3.3", | ||||
|     "@abp/ng.theme.shared": "~4.3.3" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "tslib": "^2.0.0" | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,16 @@ | ||||
| import { TestBed } from '@angular/core/testing'; | ||||
| 
 | ||||
| import { AuthWrapperService } from './auth-wrapper.service'; | ||||
| 
 | ||||
| describe('AuthWrapperService', () => { | ||||
|   let service: AuthWrapperService; | ||||
| 
 | ||||
|   beforeEach(() => { | ||||
|     TestBed.configureTestingModule({}); | ||||
|     service = TestBed.inject(AuthWrapperService); | ||||
|   }); | ||||
| 
 | ||||
|   it('should be created', () => { | ||||
|     expect(service).toBeTruthy(); | ||||
|   }); | ||||
| }); | ||||
| @ -0,0 +1,16 @@ | ||||
| import { TestBed } from '@angular/core/testing'; | ||||
| 
 | ||||
| import { TenantBoxService } from './tenant-box.service'; | ||||
| 
 | ||||
| describe('TenantBoxService', () => { | ||||
|   let service: TenantBoxService; | ||||
| 
 | ||||
|   beforeEach(() => { | ||||
|     TestBed.configureTestingModule({}); | ||||
|     service = TestBed.inject(TenantBoxService); | ||||
|   }); | ||||
| 
 | ||||
|   it('should be created', () => { | ||||
|     expect(service).toBeTruthy(); | ||||
|   }); | ||||
| }); | ||||
| @ -0,0 +1,6 @@ | ||||
| /* | ||||
|  * Public API Surface of account-core | ||||
|  */ | ||||
| 
 | ||||
| export * from './lib/auth-wrapper.service'; | ||||
| export * from './lib/tenant-box.service'; | ||||
| @ -0,0 +1,26 @@ | ||||
| // This file is required by karma.conf.js and loads recursively all the .spec and framework files
 | ||||
| 
 | ||||
| import 'zone.js/dist/zone'; | ||||
| import 'zone.js/dist/zone-testing'; | ||||
| import { getTestBed } from '@angular/core/testing'; | ||||
| import { | ||||
|   BrowserDynamicTestingModule, | ||||
|   platformBrowserDynamicTesting | ||||
| } from '@angular/platform-browser-dynamic/testing'; | ||||
| 
 | ||||
| declare const require: { | ||||
|   context(path: string, deep?: boolean, filter?: RegExp): { | ||||
|     keys(): string[]; | ||||
|     <T>(id: string): T; | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| // First, initialize the Angular testing environment.
 | ||||
| getTestBed().initTestEnvironment( | ||||
|   BrowserDynamicTestingModule, | ||||
|   platformBrowserDynamicTesting() | ||||
| ); | ||||
| // Then we find all the tests.
 | ||||
| const context = require.context('./', true, /\.spec\.ts$/); | ||||
| // And load the modules.
 | ||||
| context.keys().map(context); | ||||
| @ -0,0 +1,20 @@ | ||||
| /* To learn more about this file see: https://angular.io/config/tsconfig. */ | ||||
| { | ||||
|   "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"] | ||||
| } | ||||
| @ -0,0 +1,6 @@ | ||||
| { | ||||
|   "extends": "./tsconfig.lib.json", | ||||
|   "angularCompilerOptions": { | ||||
|     "enableIvy": false | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,17 @@ | ||||
| /* To learn more about this file see: https://angular.io/config/tsconfig. */ | ||||
| { | ||||
|   "extends": "../../tsconfig.json", | ||||
|   "compilerOptions": { | ||||
|     "outDir": "../../out-tsc/spec", | ||||
|     "types": [ | ||||
|       "jasmine" | ||||
|     ] | ||||
|   }, | ||||
|   "files": [ | ||||
|     "src/test.ts" | ||||
|   ], | ||||
|   "include": [ | ||||
|     "**/*.spec.ts", | ||||
|     "**/*.d.ts" | ||||
|   ] | ||||
| } | ||||
| @ -0,0 +1,17 @@ | ||||
| { | ||||
|   "extends": "../../tslint.json", | ||||
|   "rules": { | ||||
|     "directive-selector": [ | ||||
|       true, | ||||
|       "attribute", | ||||
|       "lib", | ||||
|       "camelCase" | ||||
|     ], | ||||
|     "component-selector": [ | ||||
|       true, | ||||
|       "element", | ||||
|       "lib", | ||||
|       "kebab-case" | ||||
|     ] | ||||
|   } | ||||
| } | ||||
| @ -0,0 +1,62 @@ | ||||
| <nav | ||||
|   class="navbar navbar-expand-lg navbar-dark bg-dark shadow-sm flex-column flex-md-row mb-4" | ||||
|   id="main-navbar" | ||||
|   style="min-height: 4rem" | ||||
| > | ||||
|   <div class="container"> | ||||
|     <abp-logo *abpReplaceableTemplate="{ componentKey: service.logoComponentKey }"></abp-logo> | ||||
|     <button | ||||
|       class="navbar-toggler" | ||||
|       type="button" | ||||
|       [attr.aria-expanded]="!service.isCollapsed" | ||||
|       (click)="service.isCollapsed = !service.isCollapsed" | ||||
|     > | ||||
|       <span class="navbar-toggler-icon"></span> | ||||
|     </button> | ||||
|     <div | ||||
|       class="navbar-collapse" | ||||
|       [class.overflow-hidden]="service.smallScreen" | ||||
|       id="main-navbar-collapse" | ||||
|     > | ||||
|       <ng-container *ngTemplateOutlet="!service.smallScreen ? navigations : null"></ng-container> | ||||
| 
 | ||||
|       <div | ||||
|         *ngIf="service.smallScreen" | ||||
|         [@collapseWithMargin]="service.isCollapsed ? 'collapsed' : 'expanded'" | ||||
|       > | ||||
|         <ng-container *ngTemplateOutlet="navigations"></ng-container> | ||||
|       </div> | ||||
| 
 | ||||
|       <ng-template #navigations> | ||||
|         <abp-routes | ||||
|           *abpReplaceableTemplate="{ | ||||
|             componentKey: service.routesComponentKey, | ||||
|             inputs: { | ||||
|               smallScreen: { value: service.smallScreen } | ||||
|             } | ||||
|           }" | ||||
|           class="mx-auto" | ||||
|           [smallScreen]="service.smallScreen" | ||||
|         ></abp-routes> | ||||
| 
 | ||||
|         <abp-nav-items | ||||
|           *abpReplaceableTemplate="{ | ||||
|             componentKey: service.navItemsComponentKey | ||||
|           }" | ||||
|         ></abp-nav-items> | ||||
|       </ng-template> | ||||
|     </div> | ||||
|   </div> | ||||
| </nav> | ||||
| 
 | ||||
| <!-- [@slideFromBottom]="outlet.isActivated && outlet.activatedRoute?.routeConfig?.path" TODO: throws ExpressionChangedAfterItHasBeenCheck when animation is active. It should be fixed --> | ||||
| <div class="container"> | ||||
|   <abp-page-alert-container></abp-page-alert-container> | ||||
|   <abp-auth-wrapper | ||||
|     *abpReplaceableTemplate="{ | ||||
|       componentKey: authWrapperKey | ||||
|     }" | ||||
|   > | ||||
|     <router-outlet #outlet="outlet"></router-outlet> | ||||
|   </abp-auth-wrapper> | ||||
| </div> | ||||
| @ -1,14 +1,21 @@ | ||||
| import { Component } from '@angular/core'; | ||||
| import { eLayoutType } from '@abp/ng.core'; | ||||
| import { AfterViewInit, Component } from '@angular/core'; | ||||
| import { eLayoutType, SubscriptionService } from '@abp/ng.core'; | ||||
| import { LayoutService } from '../../services/layout.service'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'abp-layout-account', | ||||
|   template: ` | ||||
|     <router-outlet></router-outlet> | ||||
|     <abp-confirmation></abp-confirmation> | ||||
|   `,
 | ||||
|   templateUrl: './account-layout.component.html', | ||||
|   providers: [LayoutService, SubscriptionService], | ||||
| }) | ||||
| export class AccountLayoutComponent { | ||||
| export class AccountLayoutComponent implements AfterViewInit { | ||||
|   // required for dynamic component
 | ||||
|   static type = eLayoutType.account; | ||||
| 
 | ||||
|   authWrapperKey = 'Account.AuthWrapperComponent'; | ||||
| 
 | ||||
|   constructor(public service: LayoutService) {} | ||||
| 
 | ||||
|   ngAfterViewInit() { | ||||
|     this.service.subscribeWindowSize(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,16 +1,18 @@ | ||||
| <div class="row"> | ||||
|   <div class="mx-auto col col-md-5"> | ||||
|     <ng-container *ngIf="(isMultiTenancyEnabled$ | async) && isTenantBoxVisible"> | ||||
|       <abp-tenant-box *abpReplaceableTemplate="{ componentKey: tenantBoxKey }"></abp-tenant-box> | ||||
|     <ng-container *ngIf="(service.isMultiTenancyEnabled$ | async) && service.isTenantBoxVisible"> | ||||
|       <abp-tenant-box | ||||
|         *abpReplaceableTemplate="{ componentKey: service.tenantBoxKey }" | ||||
|       ></abp-tenant-box> | ||||
|     </ng-container> | ||||
| 
 | ||||
|     <div class="abp-account-container"> | ||||
|       <div | ||||
|         *ngIf="enableLocalLogin$ | async; else disableLocalLoginTemplate" | ||||
|         *ngIf="service.enableLocalLogin$ | async; else disableLocalLoginTemplate" | ||||
|         class="card mt-3 shadow-sm rounded" | ||||
|       > | ||||
|         <div class="card-body p-5"> | ||||
|           <router-outlet></router-outlet> | ||||
|           <ng-content></ng-content> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
| @ -0,0 +1,25 @@ | ||||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | ||||
| 
 | ||||
| import { AuthWrapperComponent } from './auth-wrapper.component'; | ||||
| 
 | ||||
| describe('AuthWrapperComponent', () => { | ||||
|   let component: AuthWrapperComponent; | ||||
|   let fixture: ComponentFixture<AuthWrapperComponent>; | ||||
| 
 | ||||
|   beforeEach(async () => { | ||||
|     await TestBed.configureTestingModule({ | ||||
|       declarations: [ AuthWrapperComponent ] | ||||
|     }) | ||||
|     .compileComponents(); | ||||
|   }); | ||||
| 
 | ||||
|   beforeEach(() => { | ||||
|     fixture = TestBed.createComponent(AuthWrapperComponent); | ||||
|     component = fixture.componentInstance; | ||||
|     fixture.detectChanges(); | ||||
|   }); | ||||
| 
 | ||||
|   it('should create', () => { | ||||
|     expect(component).toBeTruthy(); | ||||
|   }); | ||||
| }); | ||||
| @ -0,0 +1,13 @@ | ||||
| import { Component, OnInit } from '@angular/core'; | ||||
| import { AuthWrapperService } from '@abp/ng.account.core'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'abp-auth-wrapper', | ||||
|   templateUrl: './auth-wrapper.component.html', | ||||
|   providers: [AuthWrapperService], | ||||
| }) | ||||
| export class AuthWrapperComponent implements OnInit { | ||||
|   constructor(public service: AuthWrapperService) {} | ||||
| 
 | ||||
|   ngOnInit(): void {} | ||||
| } | ||||
| @ -0,0 +1,25 @@ | ||||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | ||||
| 
 | ||||
| import { TenantBoxComponent } from './tenant-box.component'; | ||||
| 
 | ||||
| describe('TenantBoxComponent', () => { | ||||
|   let component: TenantBoxComponent; | ||||
|   let fixture: ComponentFixture<TenantBoxComponent>; | ||||
| 
 | ||||
|   beforeEach(async () => { | ||||
|     await TestBed.configureTestingModule({ | ||||
|       declarations: [ TenantBoxComponent ] | ||||
|     }) | ||||
|     .compileComponents(); | ||||
|   }); | ||||
| 
 | ||||
|   beforeEach(() => { | ||||
|     fixture = TestBed.createComponent(TenantBoxComponent); | ||||
|     component = fixture.componentInstance; | ||||
|     fixture.detectChanges(); | ||||
|   }); | ||||
| 
 | ||||
|   it('should create', () => { | ||||
|     expect(component).toBeTruthy(); | ||||
|   }); | ||||
| }); | ||||
| @ -0,0 +1,13 @@ | ||||
| import { Component, OnInit } from '@angular/core'; | ||||
| import { TenantBoxService } from '@abp/ng.account.core'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'abp-tenant-box', | ||||
|   templateUrl: './tenant-box.component.html', | ||||
|   providers: [TenantBoxService], | ||||
| }) | ||||
| export class TenantBoxComponent implements OnInit { | ||||
|   constructor(public service: TenantBoxService) {} | ||||
| 
 | ||||
|   ngOnInit(): void {} | ||||
| } | ||||
| @ -1,54 +1,21 @@ | ||||
| import { eLayoutType, SubscriptionService } from '@abp/ng.core'; | ||||
| import { collapseWithMargin, slideFromBottom } from '@abp/ng.theme.shared'; | ||||
| import { AfterViewInit, Component, OnDestroy } from '@angular/core'; | ||||
| import { fromEvent } from 'rxjs'; | ||||
| import { debounceTime } from 'rxjs/operators'; | ||||
| import { eThemeBasicComponents } from '../../enums/components'; | ||||
| import { AfterViewInit, Component } from '@angular/core'; | ||||
| import { LayoutService } from '../../services/layout.service'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'abp-layout-application', | ||||
|   templateUrl: './application-layout.component.html', | ||||
|   animations: [slideFromBottom, collapseWithMargin], | ||||
|   providers: [SubscriptionService], | ||||
|   providers: [LayoutService, SubscriptionService], | ||||
| }) | ||||
| export class ApplicationLayoutComponent implements AfterViewInit, OnDestroy { | ||||
| export class ApplicationLayoutComponent implements AfterViewInit { | ||||
|   // required for dynamic component
 | ||||
|   static type = eLayoutType.application; | ||||
| 
 | ||||
|   isCollapsed = true; | ||||
| 
 | ||||
|   smallScreen: boolean; // do not set true or false
 | ||||
| 
 | ||||
|   logoComponentKey = eThemeBasicComponents.Logo; | ||||
| 
 | ||||
|   routesComponentKey = eThemeBasicComponents.Routes; | ||||
| 
 | ||||
|   navItemsComponentKey = eThemeBasicComponents.NavItems; | ||||
| 
 | ||||
|   constructor(private subscription: SubscriptionService) {} | ||||
| 
 | ||||
|   private checkWindowWidth() { | ||||
|     setTimeout(() => { | ||||
|       if (window.innerWidth < 992) { | ||||
|         if (this.smallScreen === false) { | ||||
|           this.isCollapsed = false; | ||||
|           setTimeout(() => { | ||||
|             this.isCollapsed = true; | ||||
|           }, 100); | ||||
|         } | ||||
|         this.smallScreen = true; | ||||
|       } else { | ||||
|         this.smallScreen = false; | ||||
|       } | ||||
|     }, 0); | ||||
|   } | ||||
|   constructor(public service: LayoutService) {} | ||||
| 
 | ||||
|   ngAfterViewInit() { | ||||
|     this.checkWindowWidth(); | ||||
| 
 | ||||
|     const resize$ = fromEvent(window, 'resize').pipe(debounceTime(150)); | ||||
|     this.subscription.addOne(resize$, () => this.checkWindowWidth()); | ||||
|     this.service.subscribeWindowSize(); | ||||
|   } | ||||
| 
 | ||||
|   ngOnDestroy() {} | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,39 @@ | ||||
| import { ChangeDetectorRef, Injectable } from '@angular/core'; | ||||
| import { eThemeBasicComponents } from '../enums'; | ||||
| import { SubscriptionService } from '@abp/ng.core'; | ||||
| import { fromEvent } from 'rxjs'; | ||||
| import { debounceTime } from 'rxjs/operators'; | ||||
| 
 | ||||
| @Injectable() | ||||
| export class LayoutService { | ||||
|   isCollapsed = true; | ||||
| 
 | ||||
|   smallScreen: boolean; // do not set true or false
 | ||||
| 
 | ||||
|   logoComponentKey = eThemeBasicComponents.Logo; | ||||
| 
 | ||||
|   routesComponentKey = eThemeBasicComponents.Routes; | ||||
| 
 | ||||
|   navItemsComponentKey = eThemeBasicComponents.NavItems; | ||||
| 
 | ||||
|   constructor(private subscription: SubscriptionService, private cdRef: ChangeDetectorRef) {} | ||||
| 
 | ||||
|   private checkWindowWidth() { | ||||
|     const isSmallScreen = window.innerWidth < 992; | ||||
|     if (isSmallScreen && this.smallScreen === false) { | ||||
|       this.isCollapsed = false; | ||||
|       setTimeout(() => { | ||||
|         this.isCollapsed = true; | ||||
|       }, 100); | ||||
|     } | ||||
|     this.smallScreen = isSmallScreen; | ||||
|     this.cdRef.detectChanges(); | ||||
|   } | ||||
| 
 | ||||
|   subscribeWindowSize() { | ||||
|     this.checkWindowWidth(); | ||||
| 
 | ||||
|     const resize$ = fromEvent(window, 'resize').pipe(debounceTime(150)); | ||||
|     this.subscription.addOne(resize$, () => this.checkWindowWidth()); | ||||
|   } | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue
	
	 Mehmet Erim
						Mehmet Erim