Merge pull request #9395 from abpframework/feat/l41

Create account core package
pull/9423/head
Mehmet Erim 4 years ago committed by GitHub
commit 09dccf67da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -541,6 +541,44 @@
} }
} }
} }
},
"account-core": {
"projectType": "library",
"root": "packages/account-core",
"sourceRoot": "packages/account-core/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "packages/account-core/tsconfig.lib.json",
"project": "packages/account-core/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "packages/account-core/tsconfig.lib.prod.json"
}
}
},
"test": {
"builder": "@angular-builders/jest:run",
"options": {
"tsConfig": "tsconfig.json",
"coverage": true,
"passWithNoTests": true
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"packages/account-core/tsconfig.lib.json",
"packages/account-core/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**"]
}
}
}
} }
}, },
"cli": { "cli": {

@ -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();
});
});

@ -1,17 +1,11 @@
import { ConfigStateService, MultiTenancyService, SubscriptionService } from '@abp/ng.core'; import { Injectable, Injector } from '@angular/core';
import { Component, Injector } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { eAccountComponents } from '../../enums/components';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { ConfigStateService, MultiTenancyService } from '@abp/ng.core';
@Component({ @Injectable()
selector: 'abp-auth-wrapper', export class AuthWrapperService {
templateUrl: './auth-wrapper.component.html',
exportAs: 'abpAuthWrapper',
providers: [SubscriptionService],
})
export class AuthWrapperComponent {
isMultiTenancyEnabled$ = this.configState.getDeep$('multiTenancy.isEnabled'); isMultiTenancyEnabled$ = this.configState.getDeep$('multiTenancy.isEnabled');
get enableLocalLogin$(): Observable<boolean> { get enableLocalLogin$(): Observable<boolean> {
@ -20,7 +14,7 @@ export class AuthWrapperComponent {
.pipe(map(value => value?.toLowerCase() !== 'false')); .pipe(map(value => value?.toLowerCase() !== 'false'));
} }
tenantBoxKey = eAccountComponents.TenantBox; tenantBoxKey = 'Account.TenantBoxComponent';
route: ActivatedRoute; route: ActivatedRoute;
private _tenantBoxVisible = true; private _tenantBoxVisible = true;

@ -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();
});
});

@ -1,3 +1,5 @@
import { Injectable } from '@angular/core';
import { ToasterService } from '@abp/ng.theme.shared';
import { import {
AbpApplicationConfigurationService, AbpApplicationConfigurationService,
AbpTenantService, AbpTenantService,
@ -5,17 +7,10 @@ import {
CurrentTenantDto, CurrentTenantDto,
SessionStateService, SessionStateService,
} from '@abp/ng.core'; } from '@abp/ng.core';
import { ToasterService } from '@abp/ng.theme.shared';
import { Component } from '@angular/core';
import { finalize } from 'rxjs/operators'; import { finalize } from 'rxjs/operators';
import { Account } from '../../models/account';
@Component({ @Injectable()
selector: 'abp-tenant-box', export class TenantBoxService {
templateUrl: './tenant-box.component.html',
})
export class TenantBoxComponent
implements Account.TenantBoxComponentInputs, Account.TenantBoxComponentOutputs {
currentTenant$ = this.sessionState.getTenant$(); currentTenant$ = this.sessionState.getTenant$();
name: string; name: string;

@ -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"
]
}
}

@ -3,4 +3,6 @@ export const enum eAccountRouteNames {
Login = 'AbpAccount::Login', Login = 'AbpAccount::Login',
Register = 'AbpAccount::Register', Register = 'AbpAccount::Register',
ManageProfile = 'AbpAccount::MyAccount', ManageProfile = 'AbpAccount::MyAccount',
ForgotPassword = 'AbpAccount::ForgotPassword',
ResetPassword = 'AbpAccount::ResetPassword',
} }

@ -13,7 +13,7 @@ export function configureRoutes(routes: RoutesService) {
path: undefined, path: undefined,
name: eAccountRouteNames.Account, name: eAccountRouteNames.Account,
invisible: true, invisible: true,
layout: eLayoutType.application, layout: eLayoutType.account,
order: 1, order: 1,
}, },
{ {
@ -32,8 +32,21 @@ export function configureRoutes(routes: RoutesService) {
path: '/account/manage', path: '/account/manage',
name: eAccountRouteNames.ManageProfile, name: eAccountRouteNames.ManageProfile,
parentName: eAccountRouteNames.Account, parentName: eAccountRouteNames.Account,
layout: eLayoutType.application,
order: 3, order: 3,
}, },
{
path: '/account/forgot-password',
parentName: eAccountRouteNames.Account,
name: eAccountRouteNames.ForgotPassword,
invisible: true,
},
{
path: '/account/reset-password',
parentName: eAccountRouteNames.Account,
name: eAccountRouteNames.ResetPassword,
invisible: true,
},
]); ]);
}; };
} }

@ -6,7 +6,6 @@ import {
} from '@abp/ng.core'; } from '@abp/ng.core';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { AuthWrapperComponent } from './components/auth-wrapper/auth-wrapper.component';
import { ForgotPasswordComponent } from './components/forgot-password/forgot-password.component'; import { ForgotPasswordComponent } from './components/forgot-password/forgot-password.component';
import { LoginComponent } from './components/login/login.component'; import { LoginComponent } from './components/login/login.component';
import { ManageProfileComponent } from './components/manage-profile/manage-profile.component'; import { ManageProfileComponent } from './components/manage-profile/manage-profile.component';
@ -20,16 +19,6 @@ const routes: Routes = [
{ {
path: '', path: '',
component: DynamicLayoutComponent, component: DynamicLayoutComponent,
children: [
{
path: '',
component: ReplaceableRouteContainerComponent,
data: {
replaceableComponent: {
key: eAccountComponents.AuthWrapper,
defaultComponent: AuthWrapperComponent,
} as ReplaceableComponents.RouteData<AuthWrapperComponent>,
},
children: [ children: [
{ {
path: 'login', path: 'login',
@ -67,7 +56,7 @@ const routes: Routes = [
{ {
path: 'reset-password', path: 'reset-password',
component: ReplaceableRouteContainerComponent, component: ReplaceableRouteContainerComponent,
canActivate: [AuthenticationFlowGuard], canActivate: [],
data: { data: {
tenantBoxVisible: false, tenantBoxVisible: false,
replaceableComponent: { replaceableComponent: {
@ -76,8 +65,6 @@ const routes: Routes = [
} as ReplaceableComponents.RouteData<ResetPasswordComponent>, } as ReplaceableComponents.RouteData<ResetPasswordComponent>,
}, },
}, },
],
},
{ {
path: 'manage', path: 'manage',
component: ReplaceableRouteContainerComponent, component: ReplaceableRouteContainerComponent,

@ -4,13 +4,11 @@ import { ModuleWithProviders, NgModule, NgModuleFactory } from '@angular/core';
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
import { NgxValidateCoreModule } from '@ngx-validate/core'; import { NgxValidateCoreModule } from '@ngx-validate/core';
import { AccountRoutingModule } from './account-routing.module'; import { AccountRoutingModule } from './account-routing.module';
import { AuthWrapperComponent } from './components/auth-wrapper/auth-wrapper.component';
import { ChangePasswordComponent } from './components/change-password/change-password.component'; import { ChangePasswordComponent } from './components/change-password/change-password.component';
import { LoginComponent } from './components/login/login.component'; import { LoginComponent } from './components/login/login.component';
import { ManageProfileComponent } from './components/manage-profile/manage-profile.component'; import { ManageProfileComponent } from './components/manage-profile/manage-profile.component';
import { PersonalSettingsComponent } from './components/personal-settings/personal-settings.component'; import { PersonalSettingsComponent } from './components/personal-settings/personal-settings.component';
import { RegisterComponent } from './components/register/register.component'; import { RegisterComponent } from './components/register/register.component';
import { TenantBoxComponent } from './components/tenant-box/tenant-box.component';
import { AccountConfigOptions } from './models/config-options'; import { AccountConfigOptions } from './models/config-options';
import { ACCOUNT_CONFIG_OPTIONS } from './tokens/config-options.token'; import { ACCOUNT_CONFIG_OPTIONS } from './tokens/config-options.token';
import { accountConfigOptionsFactory } from './utils/factory-utils'; import { accountConfigOptionsFactory } from './utils/factory-utils';
@ -19,10 +17,8 @@ import { ForgotPasswordComponent } from './components/forgot-password/forgot-pas
import { ResetPasswordComponent } from './components/reset-password/reset-password.component'; import { ResetPasswordComponent } from './components/reset-password/reset-password.component';
const declarations = [ const declarations = [
AuthWrapperComponent,
LoginComponent, LoginComponent,
RegisterComponent, RegisterComponent,
TenantBoxComponent,
ChangePasswordComponent, ChangePasswordComponent,
ManageProfileComponent, ManageProfileComponent,
PersonalSettingsComponent, PersonalSettingsComponent,

@ -5,4 +5,3 @@ export * from './manage-profile/manage-profile.component';
export * from './register/register.component'; export * from './register/register.component';
export * from './personal-settings/personal-settings.component'; export * from './personal-settings/personal-settings.component';
export * from './reset-password/reset-password.component'; export * from './reset-password/reset-password.component';
export * from './tenant-box/tenant-box.component';

@ -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 { AfterViewInit, Component } from '@angular/core';
import { eLayoutType } from '@abp/ng.core'; import { eLayoutType, SubscriptionService } from '@abp/ng.core';
import { LayoutService } from '../../services/layout.service';
@Component({ @Component({
selector: 'abp-layout-account', selector: 'abp-layout-account',
template: ` templateUrl: './account-layout.component.html',
<router-outlet></router-outlet> providers: [LayoutService, SubscriptionService],
<abp-confirmation></abp-confirmation>
`,
}) })
export class AccountLayoutComponent { export class AccountLayoutComponent implements AfterViewInit {
// required for dynamic component // required for dynamic component
static type = eLayoutType.account; static type = eLayoutType.account;
authWrapperKey = 'Account.AuthWrapperComponent';
constructor(public service: LayoutService) {}
ngAfterViewInit() {
this.service.subscribeWindowSize();
}
} }

@ -1,16 +1,18 @@
<div class="row"> <div class="row">
<div class="mx-auto col col-md-5"> <div class="mx-auto col col-md-5">
<ng-container *ngIf="(isMultiTenancyEnabled$ | async) && isTenantBoxVisible"> <ng-container *ngIf="(service.isMultiTenancyEnabled$ | async) && service.isTenantBoxVisible">
<abp-tenant-box *abpReplaceableTemplate="{ componentKey: tenantBoxKey }"></abp-tenant-box> <abp-tenant-box
*abpReplaceableTemplate="{ componentKey: service.tenantBoxKey }"
></abp-tenant-box>
</ng-container> </ng-container>
<div class="abp-account-container"> <div class="abp-account-container">
<div <div
*ngIf="enableLocalLogin$ | async; else disableLocalLoginTemplate" *ngIf="service.enableLocalLogin$ | async; else disableLocalLoginTemplate"
class="card mt-3 shadow-sm rounded" class="card mt-3 shadow-sm rounded"
> >
<div class="card-body p-5"> <div class="card-body p-5">
<router-outlet></router-outlet> <ng-content></ng-content>
</div> </div>
</div> </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 {}
}

@ -1,4 +1,4 @@
<ng-container *ngIf="(currentTenant$ | async) || {} as currentTenant"> <ng-container *ngIf="(service.currentTenant$ | async) || {} as currentTenant">
<div class="card shadow-sm rounded mb-3"> <div class="card shadow-sm rounded mb-3">
<div class="card-body px-5"> <div class="card-body px-5">
<div class="row"> <div class="row">
@ -16,7 +16,7 @@
id="AbpTenantSwitchLink" id="AbpTenantSwitchLink"
href="javascript:void(0);" href="javascript:void(0);"
class="btn btn-sm mt-3 btn-outline-primary" class="btn btn-sm mt-3 btn-outline-primary"
(click)="onSwitch()" (click)="service.onSwitch()"
>{{ 'AbpUiMultiTenancy::Switch' | abpLocalization }}</a >{{ 'AbpUiMultiTenancy::Switch' | abpLocalization }}</a
> >
</div> </div>
@ -24,17 +24,17 @@
</div> </div>
</div> </div>
<abp-modal size="md" [(visible)]="isModalVisible" [busy]="modalBusy"> <abp-modal size="md" [(visible)]="service.isModalVisible" [busy]="service.modalBusy">
<ng-template #abpHeader> <ng-template #abpHeader>
<h5>Switch Tenant</h5> <h5>Switch Tenant</h5>
</ng-template> </ng-template>
<ng-template #abpBody> <ng-template #abpBody>
<form (ngSubmit)="save()"> <form (ngSubmit)="service.save()">
<div class="mt-2"> <div class="mt-2">
<div class="form-group"> <div class="form-group">
<label for="name">{{ 'AbpUiMultiTenancy::Name' | abpLocalization }}</label> <label for="name">{{ 'AbpUiMultiTenancy::Name' | abpLocalization }}</label>
<input <input
[(ngModel)]="name" [(ngModel)]="service.name"
type="text" type="text"
id="name" id="name"
name="tenant" name="tenant"
@ -53,8 +53,8 @@
<abp-button <abp-button
type="abp-button" type="abp-button"
iconClass="fa fa-check" iconClass="fa fa-check"
(click)="save()" (click)="service.save()"
[disabled]="currentTenant?.name === name" [disabled]="currentTenant?.name === service.name"
> >
<span>{{ 'AbpTenantManagement::Save' | abpLocalization }}</span> <span>{{ 'AbpTenantManagement::Save' | abpLocalization }}</span>
</abp-button> </abp-button>

@ -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 {}
}

@ -4,37 +4,37 @@
style="min-height: 4rem" style="min-height: 4rem"
> >
<div class="container"> <div class="container">
<abp-logo *abpReplaceableTemplate="{ componentKey: logoComponentKey }"></abp-logo> <abp-logo *abpReplaceableTemplate="{ componentKey: service.logoComponentKey }"></abp-logo>
<button <button
class="navbar-toggler" class="navbar-toggler"
type="button" type="button"
[attr.aria-expanded]="!isCollapsed" [attr.aria-expanded]="!service.isCollapsed"
(click)="isCollapsed = !isCollapsed" (click)="service.isCollapsed = !service.isCollapsed"
> >
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="navbar-collapse" [class.overflow-hidden]="smallScreen" id="main-navbar-collapse"> <div class="navbar-collapse" [class.overflow-hidden]="service.smallScreen" id="main-navbar-collapse">
<ng-container *ngTemplateOutlet="!smallScreen ? navigations : null"></ng-container> <ng-container *ngTemplateOutlet="!service.smallScreen ? navigations : null"></ng-container>
<div *ngIf="smallScreen" [@collapseWithMargin]="isCollapsed ? 'collapsed' : 'expanded'"> <div *ngIf="service.smallScreen" [@collapseWithMargin]="service.isCollapsed ? 'collapsed' : 'expanded'">
<ng-container *ngTemplateOutlet="navigations"></ng-container> <ng-container *ngTemplateOutlet="navigations"></ng-container>
</div> </div>
<ng-template #navigations> <ng-template #navigations>
<abp-routes <abp-routes
*abpReplaceableTemplate="{ *abpReplaceableTemplate="{
componentKey: routesComponentKey, componentKey: service.routesComponentKey,
inputs: { inputs: {
smallScreen: { value: smallScreen } smallScreen: { value: service.smallScreen }
} }
}" }"
class="mx-auto" class="mx-auto"
[smallScreen]="smallScreen" [smallScreen]="service.smallScreen"
></abp-routes> ></abp-routes>
<abp-nav-items <abp-nav-items
*abpReplaceableTemplate="{ *abpReplaceableTemplate="{
componentKey: navItemsComponentKey componentKey: service.navItemsComponentKey
}" }"
></abp-nav-items> ></abp-nav-items>
</ng-template> </ng-template>

@ -1,54 +1,21 @@
import { eLayoutType, SubscriptionService } from '@abp/ng.core'; import { eLayoutType, SubscriptionService } from '@abp/ng.core';
import { collapseWithMargin, slideFromBottom } from '@abp/ng.theme.shared'; import { collapseWithMargin, slideFromBottom } from '@abp/ng.theme.shared';
import { AfterViewInit, Component, OnDestroy } from '@angular/core'; import { AfterViewInit, Component } from '@angular/core';
import { fromEvent } from 'rxjs'; import { LayoutService } from '../../services/layout.service';
import { debounceTime } from 'rxjs/operators';
import { eThemeBasicComponents } from '../../enums/components';
@Component({ @Component({
selector: 'abp-layout-application', selector: 'abp-layout-application',
templateUrl: './application-layout.component.html', templateUrl: './application-layout.component.html',
animations: [slideFromBottom, collapseWithMargin], animations: [slideFromBottom, collapseWithMargin],
providers: [SubscriptionService], providers: [LayoutService, SubscriptionService],
}) })
export class ApplicationLayoutComponent implements AfterViewInit, OnDestroy { export class ApplicationLayoutComponent implements AfterViewInit {
// required for dynamic component // required for dynamic component
static type = eLayoutType.application; static type = eLayoutType.application;
isCollapsed = true; constructor(public service: LayoutService) {}
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);
}
ngAfterViewInit() { ngAfterViewInit() {
this.checkWindowWidth(); this.service.subscribeWindowSize();
const resize$ = fromEvent(window, 'resize').pipe(debounceTime(150));
this.subscription.addOne(resize$, () => this.checkWindowWidth());
} }
ngOnDestroy() {}
} }

@ -1,4 +1,6 @@
export * from './account-layout/account-layout.component'; export * from './account-layout/account-layout.component';
export * from './account-layout/auth-wrapper/auth-wrapper.component';
export * from './account-layout/tenant-box/tenant-box.component';
export * from './application-layout/application-layout.component'; export * from './application-layout/application-layout.component';
export * from './empty-layout/empty-layout.component'; export * from './empty-layout/empty-layout.component';
export * from './logo/logo.component'; export * from './logo/logo.component';

@ -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());
}
}

@ -20,6 +20,8 @@ import { ValidationErrorComponent } from './components/validation-error/validati
import { BASIC_THEME_NAV_ITEM_PROVIDERS } from './providers/nav-item.provider'; import { BASIC_THEME_NAV_ITEM_PROVIDERS } from './providers/nav-item.provider';
import { BASIC_THEME_STYLES_PROVIDERS } from './providers/styles.provider'; import { BASIC_THEME_STYLES_PROVIDERS } from './providers/styles.provider';
import { PageAlertContainerComponent } from './components/page-alert-container/page-alert-container.component'; import { PageAlertContainerComponent } from './components/page-alert-container/page-alert-container.component';
import { TenantBoxComponent } from './components/account-layout/tenant-box/tenant-box.component';
import { AuthWrapperComponent } from './components/account-layout/auth-wrapper/auth-wrapper.component';
export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, EmptyLayoutComponent]; export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, EmptyLayoutComponent];
@ -33,6 +35,8 @@ export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, Empt
CurrentUserComponent, CurrentUserComponent,
LanguagesComponent, LanguagesComponent,
PageAlertContainerComponent, PageAlertContainerComponent,
TenantBoxComponent,
AuthWrapperComponent,
], ],
exports: [ exports: [
...LAYOUTS, ...LAYOUTS,

@ -1,6 +1,5 @@
import program from 'commander'; import program from 'commander';
import execa from 'execa'; import execa from 'execa';
import fse from 'fs-extra';
(async () => { (async () => {
program.option('-i, --noInstall', 'skip updating package.json and installation', false); program.option('-i, --noInstall', 'skip updating package.json and installation', false);
@ -37,7 +36,7 @@ import fse from 'fs-extra';
'--prod', '--prod',
'--no-watch', '--no-watch',
'--packages', '--packages',
'@abp/ng.feature-management,@abp/ng.permission-management', '@abp/ng.feature-management,@abp/ng.permission-management,@abp/ng.account.core',
], ],
{ stdout: 'inherit', cwd: '../' }, { stdout: 'inherit', cwd: '../' },
); );
@ -52,7 +51,7 @@ import fse from 'fs-extra';
'--no-watch', '--no-watch',
'--all-packages', '--all-packages',
'--excluded-packages', '--excluded-packages',
'@abp/ng.schematics,@abp/ng.core,@abp/ng.theme.shared,@abp/ng.components,@abp/ng.feature-management,@abp/ng.permission-management', '@abp/ng.schematics,@abp/ng.core,@abp/ng.theme.shared,@abp/ng.components,@abp/ng.feature-management,@abp/ng.permission-management,@abp/ng.account.core',
], ],
{ stdout: 'inherit', cwd: '../' }, { stdout: 'inherit', cwd: '../' },
); );

@ -26,6 +26,7 @@
"@abp/ng.theme.basic": ["packages/theme-basic/src/public-api.ts"], "@abp/ng.theme.basic": ["packages/theme-basic/src/public-api.ts"],
"@abp/ng.account": ["packages/account/src/public-api.ts"], "@abp/ng.account": ["packages/account/src/public-api.ts"],
"@abp/ng.account/config": ["packages/account/config/src/public-api.ts"], "@abp/ng.account/config": ["packages/account/config/src/public-api.ts"],
"@abp/ng.account.core": ["packages/account-core/src/public-api.ts"],
"@abp/ng.identity": ["packages/identity/src/public-api.ts"], "@abp/ng.identity": ["packages/identity/src/public-api.ts"],
"@abp/ng.identity/config": ["packages/identity/config/src/public-api.ts"], "@abp/ng.identity/config": ["packages/identity/config/src/public-api.ts"],
"@abp/ng.tenant-management": ["packages/tenant-management/src/public-api.ts"], "@abp/ng.tenant-management": ["packages/tenant-management/src/public-api.ts"],

Loading…
Cancel
Save