diff --git a/npm/ng-packs/angular.json b/npm/ng-packs/angular.json index 8aed0992b2..69119cdb64 100644 --- a/npm/ng-packs/angular.json +++ b/npm/ng-packs/angular.json @@ -184,6 +184,43 @@ } } }, + "account": { + "projectType": "library", + "root": "packages/account", + "sourceRoot": "packages/account/src", + "prefix": "abp", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "packages/account/tsconfig.lib.json", + "project": "packages/account/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "packages/account/tsconfig.lib.prod.json" + } + } + }, + "test": { + "builder": "@angular-builders/jest:run", + "options": { + "coverage": true, + "passWithNoTests": true + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "packages/account/tsconfig.lib.json", + "packages/account/tsconfig.spec.json" + ], + "exclude": ["**/node_modules/**"] + } + } + } + }, "identity": { "projectType": "library", "root": "packages/identity", diff --git a/npm/ng-packs/packages/account/README.md b/npm/ng-packs/packages/account/README.md new file mode 100644 index 0000000000..f3eaaed299 --- /dev/null +++ b/npm/ng-packs/packages/account/README.md @@ -0,0 +1,3 @@ +

@abp/ng.account

+ +[docs.abp.io](https://docs.abp.io) diff --git a/npm/ng-packs/packages/account/config/ng-package.json b/npm/ng-packs/packages/account/config/ng-package.json new file mode 100644 index 0000000000..8bc97815a5 --- /dev/null +++ b/npm/ng-packs/packages/account/config/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/account/config", + "lib": { + "entryFile": "src/public-api.ts" + } +} diff --git a/npm/ng-packs/packages/account/config/src/account-config.module.ts b/npm/ng-packs/packages/account/config/src/account-config.module.ts new file mode 100644 index 0000000000..3041e828d7 --- /dev/null +++ b/npm/ng-packs/packages/account/config/src/account-config.module.ts @@ -0,0 +1,22 @@ +import { noop } from '@abp/ng.core'; +import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core'; +import { SessionHandler } from './handlers/session.handler'; +import { ACCOUNT_ROUTE_PROVIDERS } from './providers/route.provider'; + +@NgModule() +export class AccountConfigModule { + static forRoot(): ModuleWithProviders { + return { + ngModule: AccountConfigModule, + providers: [ + ACCOUNT_ROUTE_PROVIDERS, + { + provide: APP_INITIALIZER, + multi: true, + deps: [SessionHandler], + useFactory: noop, + }, + ], + }; + } +} diff --git a/npm/ng-packs/packages/account/config/src/enums/index.ts b/npm/ng-packs/packages/account/config/src/enums/index.ts new file mode 100644 index 0000000000..3bda94b078 --- /dev/null +++ b/npm/ng-packs/packages/account/config/src/enums/index.ts @@ -0,0 +1 @@ +export * from './route-names'; diff --git a/npm/ng-packs/packages/account/config/src/enums/route-names.ts b/npm/ng-packs/packages/account/config/src/enums/route-names.ts new file mode 100644 index 0000000000..810985e027 --- /dev/null +++ b/npm/ng-packs/packages/account/config/src/enums/route-names.ts @@ -0,0 +1,6 @@ +export const enum eAccountRouteNames { + Account = 'AbpAccount::Menu:Account', + Login = 'AbpAccount::Login', + Register = 'AbpAccount::Register', + ManageProfile = 'AbpAccount::ManageYourProfile', +} diff --git a/npm/ng-packs/packages/account/config/src/handlers/index.ts b/npm/ng-packs/packages/account/config/src/handlers/index.ts new file mode 100644 index 0000000000..3ab2054e88 --- /dev/null +++ b/npm/ng-packs/packages/account/config/src/handlers/index.ts @@ -0,0 +1 @@ +export * from './session.handler'; diff --git a/npm/ng-packs/packages/account/config/src/providers/index.ts b/npm/ng-packs/packages/account/config/src/providers/index.ts new file mode 100644 index 0000000000..fe08efba8c --- /dev/null +++ b/npm/ng-packs/packages/account/config/src/providers/index.ts @@ -0,0 +1 @@ +export * from './route.provider'; diff --git a/npm/ng-packs/packages/account/config/src/providers/route.provider.ts b/npm/ng-packs/packages/account/config/src/providers/route.provider.ts new file mode 100644 index 0000000000..2deb086b10 --- /dev/null +++ b/npm/ng-packs/packages/account/config/src/providers/route.provider.ts @@ -0,0 +1,39 @@ +import { eLayoutType, RoutesService } from '@abp/ng.core'; +import { APP_INITIALIZER } from '@angular/core'; +import { eAccountRouteNames } from '../enums/route-names'; + +export const ACCOUNT_ROUTE_PROVIDERS = [ + { provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true }, +]; + +export function configureRoutes(routes: RoutesService) { + return () => { + routes.add([ + { + path: '/account', + name: eAccountRouteNames.Account, + invisible: true, + layout: eLayoutType.application, + order: 1, + }, + { + path: '/account/login', + name: eAccountRouteNames.Login, + parentName: eAccountRouteNames.Account, + order: 1, + }, + { + path: '/account/register', + name: eAccountRouteNames.Register, + parentName: eAccountRouteNames.Account, + order: 2, + }, + { + path: '/account/manage-profile', + name: eAccountRouteNames.ManageProfile, + parentName: eAccountRouteNames.Account, + order: 3, + }, + ]); + }; +} diff --git a/npm/ng-packs/packages/account/config/src/public-api.ts b/npm/ng-packs/packages/account/config/src/public-api.ts new file mode 100644 index 0000000000..533ef02eb2 --- /dev/null +++ b/npm/ng-packs/packages/account/config/src/public-api.ts @@ -0,0 +1,4 @@ +export * from './account-config.module'; +export * from './enums'; +export * from './providers'; +export * from './handlers'; diff --git a/npm/ng-packs/packages/account/jest.config.js b/npm/ng-packs/packages/account/jest.config.js new file mode 100644 index 0000000000..c9c02c909f --- /dev/null +++ b/npm/ng-packs/packages/account/jest.config.js @@ -0,0 +1,6 @@ +const jestConfig = require('../../jest.config'); + +module.exports = { + ...jestConfig, + name: 'account', +}; diff --git a/npm/ng-packs/packages/account/ng-package.json b/npm/ng-packs/packages/account/ng-package.json new file mode 100644 index 0000000000..9e94619264 --- /dev/null +++ b/npm/ng-packs/packages/account/ng-package.json @@ -0,0 +1,8 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/account", + "lib": { + "entryFile": "src/public-api.ts" + }, + "whitelistedNonPeerDependencies": ["@abp/ng.theme.shared"] +} diff --git a/npm/ng-packs/packages/account/ngcc.config.js b/npm/ng-packs/packages/account/ngcc.config.js new file mode 100644 index 0000000000..e40ad7d892 --- /dev/null +++ b/npm/ng-packs/packages/account/ngcc.config.js @@ -0,0 +1,6 @@ +module.exports = { + entryPoints: { + '.': {}, + './config': {} + }, +}; diff --git a/npm/ng-packs/packages/account/package.json b/npm/ng-packs/packages/account/package.json new file mode 100644 index 0000000000..e667997d9e --- /dev/null +++ b/npm/ng-packs/packages/account/package.json @@ -0,0 +1,16 @@ +{ + "name": "@abp/ng.account", + "version": "4.3.0", + "homepage": "https://abp.io", + "repository": { + "type": "git", + "url": "https://github.com/abpframework/abp.git" + }, + "dependencies": { + "@abp/ng.theme.shared": "~3.3.2", + "tslib": "^2.0.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/npm/ng-packs/packages/account/src/lib/account-routing.module.ts b/npm/ng-packs/packages/account/src/lib/account-routing.module.ts new file mode 100644 index 0000000000..dfc92f41e8 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/account-routing.module.ts @@ -0,0 +1,93 @@ +import { + AuthGuard, + DynamicLayoutComponent, + ReplaceableComponents, + ReplaceableRouteContainerComponent, +} from '@abp/ng.core'; +import { NgModule } from '@angular/core'; +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 { LoginComponent } from './components/login/login.component'; +import { ManageProfileComponent } from './components/manage-profile/manage-profile.component'; +import { RegisterComponent } from './components/register/register.component'; +import { ResetPasswordComponent } from './components/reset-password/reset-password.component'; +import { eAccountComponents } from './enums/components'; +import { AuthenticationFlowGuard } from './guards/authentication-flow.guard'; + +const routes: Routes = [ + { path: '', pathMatch: 'full', redirectTo: 'login' }, + { + path: '', + component: DynamicLayoutComponent, + children: [ + { + path: '', + component: AuthWrapperComponent, + children: [ + { + path: 'login', + component: ReplaceableRouteContainerComponent, + canActivate: [AuthenticationFlowGuard], + data: { + replaceableComponent: { + key: eAccountComponents.Login, + defaultComponent: LoginComponent, + } as ReplaceableComponents.RouteData, + }, + }, + { + path: 'register', + component: ReplaceableRouteContainerComponent, + canActivate: [AuthenticationFlowGuard], + data: { + replaceableComponent: { + key: eAccountComponents.Register, + defaultComponent: RegisterComponent, + } as ReplaceableComponents.RouteData, + }, + }, + { + path: 'forgot-password', + component: ReplaceableRouteContainerComponent, + canActivate: [AuthenticationFlowGuard], + data: { + replaceableComponent: { + key: eAccountComponents.ForgotPassword, + defaultComponent: ForgotPasswordComponent, + } as ReplaceableComponents.RouteData, + }, + }, + { + path: 'reset-password', + component: ReplaceableRouteContainerComponent, + canActivate: [AuthenticationFlowGuard], + data: { + replaceableComponent: { + key: eAccountComponents.ResetPassword, + defaultComponent: ResetPasswordComponent, + } as ReplaceableComponents.RouteData, + }, + }, + ], + }, + { + path: 'manage-profile', + component: ReplaceableRouteContainerComponent, + canActivate: [AuthGuard], + data: { + replaceableComponent: { + key: eAccountComponents.ManageProfile, + defaultComponent: ManageProfileComponent, + } as ReplaceableComponents.RouteData, + }, + }, + ], + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class AccountRoutingModule {} diff --git a/npm/ng-packs/packages/account/src/lib/account.module.ts b/npm/ng-packs/packages/account/src/lib/account.module.ts new file mode 100644 index 0000000000..255a8b3de5 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/account.module.ts @@ -0,0 +1,65 @@ +import { CoreModule, LazyModuleFactory } from '@abp/ng.core'; +import { ThemeSharedModule } from '@abp/ng.theme.shared'; +import { ModuleWithProviders, NgModule, NgModuleFactory } from '@angular/core'; +import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgxValidateCoreModule } from '@ngx-validate/core'; +import { AccountRoutingModule } from './account-routing.module'; +import { AuthWrapperComponent } from './components/auth-wrapper/auth-wrapper.component'; +import { ChangePasswordComponent } from './components/change-password/change-password.component'; +import { LoginComponent } from './components/login/login.component'; +import { ManageProfileComponent } from './components/manage-profile/manage-profile.component'; +import { PersonalSettingsComponent } from './components/personal-settings/personal-settings.component'; +import { RegisterComponent } from './components/register/register.component'; +import { TenantBoxComponent } from './components/tenant-box/tenant-box.component'; +import { Options } from './models/options'; +import { ACCOUNT_OPTIONS } from './tokens/options.token'; +import { accountOptionsFactory } from './utils/factory-utils'; +import { AuthenticationFlowGuard } from './guards/authentication-flow.guard'; +import { AuthenticationService } from './services/authentication.service'; +import { ForgotPasswordComponent } from './components/forgot-password/forgot-password.component'; +import { ResetPasswordComponent } from './components/reset-password/reset-password.component'; + +const declarations = [ + AuthWrapperComponent, + LoginComponent, + RegisterComponent, + TenantBoxComponent, + ChangePasswordComponent, + ManageProfileComponent, + PersonalSettingsComponent, + ForgotPasswordComponent, + ResetPasswordComponent, +]; + +@NgModule({ + declarations: [...declarations], + imports: [ + CoreModule, + AccountRoutingModule, + ThemeSharedModule, + NgbDropdownModule, + NgxValidateCoreModule, + ], + exports: [...declarations], +}) +export class AccountModule { + static forChild(options = {} as Options): ModuleWithProviders { + return { + ngModule: AccountModule, + providers: [ + AuthenticationFlowGuard, + AuthenticationService, + { provide: ACCOUNT_OPTIONS, useValue: options }, + { + provide: 'ACCOUNT_OPTIONS', + useFactory: accountOptionsFactory, + deps: [ACCOUNT_OPTIONS], + }, + ], + }; + } + + static forLazy(options = {} as Options): NgModuleFactory { + return new LazyModuleFactory(AccountModule.forChild(options)); + } +} diff --git a/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.html b/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.html new file mode 100644 index 0000000000..b932025c3d --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.html @@ -0,0 +1,25 @@ +
+
+ + + + + +
+
+ + +
+ {{ 'AbpAccount::InvalidLoginRequest' | abpLocalization }} + {{ 'AbpAccount::ThereAreNoLoginSchemesConfiguredForThisClient' | abpLocalization }} +
+
diff --git a/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.ts b/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.ts new file mode 100644 index 0000000000..245d1c4c25 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.ts @@ -0,0 +1,28 @@ +import { ConfigStateService, MultiTenancyService, SubscriptionService } from '@abp/ng.core'; +import { Component } from '@angular/core'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { eAccountComponents } from '../../enums/components'; + +@Component({ + selector: 'abp-auth-wrapper', + templateUrl: './auth-wrapper.component.html', + exportAs: 'abpAuthWrapper', + providers: [SubscriptionService], +}) +export class AuthWrapperComponent { + isMultiTenancyEnabled$ = this.configState.getDeep$('multiTenancy.isEnabled'); + + get enableLocalLogin$(): Observable { + return this.configState + .getSetting$('Abp.Account.EnableLocalLogin') + .pipe(map(value => value?.toLowerCase() !== 'false')); + } + + tenantBoxKey = eAccountComponents.TenantBox; + + constructor( + public readonly multiTenancy: MultiTenancyService, + private configState: ConfigStateService, + ) {} +} diff --git a/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.html b/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.html new file mode 100644 index 0000000000..37ac7f0175 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.html @@ -0,0 +1,48 @@ +
+
+ * +
+
+ * +
+
+ * +
+ {{ 'AbpIdentity::Save' | abpLocalization }} +
diff --git a/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts b/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts new file mode 100644 index 0000000000..d18bd8b165 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts @@ -0,0 +1,99 @@ +import { Profile, ProfileService } from '@abp/ng.core'; +import { getPasswordValidators, ToasterService } from '@abp/ng.theme.shared'; +import { Component, Injector, Input, OnInit } from '@angular/core'; +import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { comparePasswords, Validation } from '@ngx-validate/core'; +import { finalize } from 'rxjs/operators'; +import snq from 'snq'; +import { Account } from '../../models/account'; +import { ManageProfileStateService } from '../../services/manage-profile.state.service'; + +const { required } = Validators; + +const PASSWORD_FIELDS = ['newPassword', 'repeatNewPassword']; + +@Component({ + selector: 'abp-change-password-form', + templateUrl: './change-password.component.html', + exportAs: 'abpChangePasswordForm', +}) +export class ChangePasswordComponent + implements OnInit, Account.ChangePasswordComponentInputs, Account.ChangePasswordComponentOutputs { + form: FormGroup; + + inProgress: boolean; + + hideCurrentPassword: boolean; + + mapErrorsFn: Validation.MapErrorsFn = (errors, groupErrors, control) => { + if (PASSWORD_FIELDS.indexOf(String(control.name)) < 0) return errors; + + return errors.concat(groupErrors.filter(({ key }) => key === 'passwordMismatch')); + }; + + constructor( + private fb: FormBuilder, + private injector: Injector, + private toasterService: ToasterService, + private profileService: ProfileService, + private manageProfileState: ManageProfileStateService, + ) {} + + ngOnInit(): void { + this.hideCurrentPassword = !this.manageProfileState.getProfile()?.hasPassword; + + const passwordValidations = getPasswordValidators(this.injector); + + this.form = this.fb.group( + { + password: ['', required], + newPassword: [ + '', + { + validators: [required, ...passwordValidations], + }, + ], + repeatNewPassword: [ + '', + { + validators: [required, ...passwordValidations], + }, + ], + }, + { + validators: [comparePasswords(PASSWORD_FIELDS)], + }, + ); + + if (this.hideCurrentPassword) this.form.removeControl('password'); + } + + onSubmit() { + if (this.form.invalid) return; + this.inProgress = true; + this.profileService + .changePassword({ + ...(!this.hideCurrentPassword && { currentPassword: this.form.get('password').value }), + newPassword: this.form.get('newPassword').value, + }) + .pipe(finalize(() => (this.inProgress = false))) + .subscribe({ + next: () => { + this.form.reset(); + this.toasterService.success('AbpAccount::PasswordChangedMessage', '', { + life: 5000, + }); + + if (this.hideCurrentPassword) { + this.hideCurrentPassword = false; + this.form.addControl('password', new FormControl('', [required])); + } + }, + error: err => { + this.toasterService.error( + snq(() => err.error.error.message, 'AbpAccount::DefaultErrorMessage'), + ); + }, + }); + } +} diff --git a/npm/ng-packs/packages/account/src/lib/components/forgot-password/forgot-password.component.html b/npm/ng-packs/packages/account/src/lib/components/forgot-password/forgot-password.component.html new file mode 100644 index 0000000000..9e1b974c43 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/forgot-password/forgot-password.component.html @@ -0,0 +1,40 @@ +

{{ 'AbpAccount::ForgotPassword' | abpLocalization }}

+ +
+

{{ 'AbpAccount::SendPasswordResetLink_Information' | abpLocalization }}

+
+ * + +
+ + {{ 'AbpAccount::Submit' | abpLocalization }} + + {{ 'AbpAccount::Login' | abpLocalization }} +
+ + +

+ {{ 'AbpAccount::PasswordResetMailSentMessage' | abpLocalization }} +

+ + + + +
diff --git a/npm/ng-packs/packages/account/src/lib/components/forgot-password/forgot-password.component.ts b/npm/ng-packs/packages/account/src/lib/components/forgot-password/forgot-password.component.ts new file mode 100644 index 0000000000..8ba5b0c991 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/forgot-password/forgot-password.component.ts @@ -0,0 +1,35 @@ +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { finalize } from 'rxjs/operators'; +import { AccountService } from '../../proxy/account/account.service'; + +@Component({ + selector: 'abp-forgot-password', + templateUrl: 'forgot-password.component.html', +}) +export class ForgotPasswordComponent { + form: FormGroup; + + inProgress: boolean; + + isEmailSent: boolean = false; + + constructor(private fb: FormBuilder, private accountService: AccountService) { + this.form = this.fb.group({ + email: ['', [Validators.required, Validators.email]], + }); + } + + onSubmit() { + if (this.form.invalid) return; + + this.inProgress = true; + + this.accountService + .sendPasswordResetCode({ email: this.form.get('email').value, appName: 'Angular' }) + .pipe(finalize(() => (this.inProgress = false))) + .subscribe(() => { + this.isEmailSent = true; + }); + } +} diff --git a/npm/ng-packs/packages/account/src/lib/components/index.ts b/npm/ng-packs/packages/account/src/lib/components/index.ts new file mode 100644 index 0000000000..458f0623a6 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/index.ts @@ -0,0 +1,8 @@ +export * from './change-password/change-password.component'; +export * from './forgot-password/forgot-password.component'; +export * from './login/login.component'; +export * from './manage-profile/manage-profile.component'; +export * from './register/register.component'; +export * from './personal-settings/personal-settings.component'; +export * from './reset-password/reset-password.component'; +export * from './tenant-box/tenant-box.component'; diff --git a/npm/ng-packs/packages/account/src/lib/components/login/login.component.html b/npm/ng-packs/packages/account/src/lib/components/login/login.component.html new file mode 100644 index 0000000000..061d182ccf --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/login/login.component.html @@ -0,0 +1,60 @@ +

{{ 'AbpAccount::Login' | abpLocalization }}

+ + {{ 'AbpAccount::AreYouANewUser' | abpLocalization }} + {{ + 'AbpAccount::Register' | abpLocalization + }} + +
+
+ + +
+
+ + +
+ +
+
+ +
+ +
+ + + {{ 'AbpAccount::Login' | abpLocalization }} + +
diff --git a/npm/ng-packs/packages/account/src/lib/components/login/login.component.ts b/npm/ng-packs/packages/account/src/lib/components/login/login.component.ts new file mode 100644 index 0000000000..fd45e0cdbd --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/login/login.component.ts @@ -0,0 +1,80 @@ +import { ConfigStateService } from '@abp/ng.core'; +import { ToasterService } from '@abp/ng.theme.shared'; +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngxs/store'; +import { throwError } from 'rxjs'; +import { catchError, finalize } from 'rxjs/operators'; +import snq from 'snq'; +import { eAccountComponents } from '../../enums/components'; +import { AuthenticationService } from '../../services/authentication.service'; + +const { maxLength, minLength, required } = Validators; + +@Component({ + selector: 'abp-login', + templateUrl: './login.component.html', +}) +export class LoginComponent implements OnInit { + form: FormGroup; + + inProgress: boolean; + + isSelfRegistrationEnabled = true; + + authWrapperKey = eAccountComponents.AuthWrapper; + + constructor( + private fb: FormBuilder, + private store: Store, + private toasterService: ToasterService, + private authenticationService: AuthenticationService, + private configState: ConfigStateService, + ) {} + + ngOnInit() { + this.init(); + this.buildForm(); + } + + protected init() { + this.isSelfRegistrationEnabled = + ( + (this.configState.getSetting('Abp.Account.IsSelfRegistrationEnabled') as string) || '' + ).toLowerCase() !== 'false'; + } + + protected buildForm() { + this.form = this.fb.group({ + username: ['', [required, maxLength(255)]], + password: ['', [required, maxLength(128)]], + remember: [false], + }); + } + + onSubmit() { + if (this.form.invalid) return; + + this.inProgress = true; + + const { username, password, remember } = this.form.value; + + this.authenticationService + .login(username, password, remember) + .pipe( + catchError(err => { + this.toasterService.error( + snq(() => err.error.error_description) || + snq(() => err.error.error.message, 'AbpAccount::DefaultErrorMessage'), + 'Error', + { life: 7000 }, + ); + return throwError(err); + }), + finalize(() => (this.inProgress = false)), + ) + .subscribe(() => { + // TODO: this.store.dispatch(new SetRemember(this.form.get('remember').value)); + }); + } +} diff --git a/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.html b/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.html new file mode 100644 index 0000000000..91b635c080 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.html @@ -0,0 +1,62 @@ +
+ +
+
+
+ +
+
+
+

+ {{ 'AbpIdentity::ChangePassword' | abpLocalization }} +
+

+ +
+
+
+
+

+ {{ 'AbpIdentity::PersonalSettings' | abpLocalization }} +
+

+ +
+
+
+
+
+
diff --git a/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts b/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts new file mode 100644 index 0000000000..695bec8d68 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts @@ -0,0 +1,45 @@ +import { Profile, ProfileService } from '@abp/ng.core'; +import { fadeIn } from '@abp/ng.theme.shared'; +import { transition, trigger, useAnimation } from '@angular/animations'; +import { Component, OnInit } from '@angular/core'; +import { eAccountComponents } from '../../enums/components'; +import { ManageProfileStateService } from '../../services/manage-profile.state.service'; + +@Component({ + selector: 'abp-manage-profile', + templateUrl: './manage-profile.component.html', + animations: [trigger('fadeIn', [transition(':enter', useAnimation(fadeIn))])], + styles: [ + ` + .min-h-400 { + min-height: 400px; + } + `, + ], +}) +export class ManageProfileComponent implements OnInit { + selectedTab = 0; + + changePasswordKey = eAccountComponents.ChangePassword; + + personalSettingsKey = eAccountComponents.PersonalSettings; + + profile$ = this.manageProfileState.getProfile$(); + + hideChangePasswordTab: boolean; + + constructor( + protected profileService: ProfileService, + protected manageProfileState: ManageProfileStateService, + ) {} + + ngOnInit() { + this.profileService.get().subscribe(profile => { + this.manageProfileState.setProfile(profile); + if (profile.isExternal) { + this.hideChangePasswordTab = true; + this.selectedTab = 1; + } + }); + } +} diff --git a/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.html b/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.html new file mode 100644 index 0000000000..291d3f1cbd --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.html @@ -0,0 +1,46 @@ +
+
+ * +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ * +
+
+ +
+ + {{ 'AbpIdentity::Save' | abpLocalization }} +
diff --git a/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.ts b/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.ts new file mode 100644 index 0000000000..2330fe54b3 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/personal-settings/personal-settings.component.ts @@ -0,0 +1,60 @@ +import { Profile, ProfileService } from '@abp/ng.core'; +import { ToasterService } from '@abp/ng.theme.shared'; +import { Component, Input, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngxs/store'; +import { finalize } from 'rxjs/operators'; +import { Account } from '../../models/account'; +import { ManageProfileStateService } from '../../services/manage-profile.state.service'; + +const { maxLength, required, email } = Validators; + +@Component({ + selector: 'abp-personal-settings-form', + templateUrl: './personal-settings.component.html', + exportAs: 'abpPersonalSettingsForm', +}) +export class PersonalSettingsComponent + implements + OnInit, + Account.PersonalSettingsComponentInputs, + Account.PersonalSettingsComponentOutputs { + form: FormGroup; + + inProgress: boolean; + + constructor( + private fb: FormBuilder, + private store: Store, + private toasterService: ToasterService, + private profileService: ProfileService, + private manageProfileState: ManageProfileStateService, + ) {} + + ngOnInit() { + this.buildForm(); + } + + buildForm() { + const profile = this.manageProfileState.getProfile(); + this.form = this.fb.group({ + userName: [profile.userName, [required, maxLength(256)]], + email: [profile.email, [required, email, maxLength(256)]], + name: [profile.name || '', [maxLength(64)]], + surname: [profile.surname || '', [maxLength(64)]], + phoneNumber: [profile.phoneNumber || '', [maxLength(16)]], + }); + } + + submit() { + if (this.form.invalid) return; + this.inProgress = true; + this.profileService + .update(this.form.value) + .pipe(finalize(() => (this.inProgress = false))) + .subscribe(profile => { + this.manageProfileState.setProfile(profile); + this.toasterService.success('AbpAccount::PersonalSettingsSaved', 'Success', { life: 5000 }); + }); + } +} diff --git a/npm/ng-packs/packages/account/src/lib/components/register/register.component.html b/npm/ng-packs/packages/account/src/lib/components/register/register.component.html new file mode 100644 index 0000000000..404c453026 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/register/register.component.html @@ -0,0 +1,51 @@ +

{{ 'AbpAccount::Register' | abpLocalization }}

+ + {{ 'AbpAccount::AlreadyRegistered' | abpLocalization }} + {{ + 'AbpAccount::Login' | abpLocalization + }} + +
+
+ * +
+
+ * +
+
+ * +
+ + {{ 'AbpAccount::Register' | abpLocalization }} + +
diff --git a/npm/ng-packs/packages/account/src/lib/components/register/register.component.ts b/npm/ng-packs/packages/account/src/lib/components/register/register.component.ts new file mode 100644 index 0000000000..63454c3233 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/register/register.component.ts @@ -0,0 +1,96 @@ +import { ConfigStateService } from '@abp/ng.core'; +import { getPasswordValidators, ToasterService } from '@abp/ng.theme.shared'; +import { Component, Injector, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { throwError } from 'rxjs'; +import { catchError, finalize, switchMap } from 'rxjs/operators'; +import snq from 'snq'; +import { eAccountComponents } from '../../enums/components'; +import { AccountService } from '../../proxy/account/account.service'; +import { RegisterDto } from '../../proxy/account/models'; +import { AuthenticationService } from '../../services'; +const { maxLength, required, email } = Validators; + +@Component({ + selector: 'abp-register', + templateUrl: './register.component.html', +}) +export class RegisterComponent implements OnInit { + form: FormGroup; + + inProgress: boolean; + + isSelfRegistrationEnabled = true; + + authWrapperKey = eAccountComponents.AuthWrapper; + + constructor( + private fb: FormBuilder, + private accountService: AccountService, + private configState: ConfigStateService, + private toasterService: ToasterService, + private authenticationSerivice: AuthenticationService, + private injector: Injector, + ) {} + + ngOnInit() { + this.init(); + this.buildForm(); + } + + protected init() { + this.isSelfRegistrationEnabled = + (this.configState.getSetting('Abp.Account.IsSelfRegistrationEnabled') || '').toLowerCase() !== + 'false'; + + if (!this.isSelfRegistrationEnabled) { + this.toasterService.warn( + { + key: 'AbpAccount::SelfRegistrationDisabledMessage', + defaultValue: 'Self registration is disabled.', + }, + null, + { life: 10000 }, + ); + return; + } + } + + protected buildForm() { + this.form = this.fb.group({ + username: ['', [required, maxLength(255)]], + password: ['', [required, ...getPasswordValidators(this.injector)]], + email: ['', [required, email]], + }); + } + + onSubmit() { + if (this.form.invalid) return; + + this.inProgress = true; + + const newUser = { + userName: this.form.get('username').value, + password: this.form.get('password').value, + emailAddress: this.form.get('email').value, + appName: 'Angular', + } as RegisterDto; + + this.accountService + .register(newUser) + .pipe( + switchMap(() => this.authenticationSerivice.login(newUser.userName, newUser.password)), + catchError(err => { + this.toasterService.error( + snq(() => err.error.error_description) || + snq(() => err.error.error.message, 'AbpAccount::DefaultErrorMessage'), + 'Error', + { life: 7000 }, + ); + return throwError(err); + }), + finalize(() => (this.inProgress = false)), + ) + .subscribe(); + } +} diff --git a/npm/ng-packs/packages/account/src/lib/components/reset-password/reset-password.component.html b/npm/ng-packs/packages/account/src/lib/components/reset-password/reset-password.component.html new file mode 100644 index 0000000000..404f525111 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/reset-password/reset-password.component.html @@ -0,0 +1,49 @@ +

{{ 'AbpAccount::ResetPassword' | abpLocalization }}

+ +
+

{{ 'AbpAccount::ResetPassword_Information' | abpLocalization }}

+
+ * + +
+
+ * + +
+ + + {{ 'AbpAccount::Submit' | abpLocalization }} + +
+ + +

+ {{ 'AbpAccount::YourPasswordIsSuccessfullyReset' | abpLocalization }} +

+ + + + +
diff --git a/npm/ng-packs/packages/account/src/lib/components/reset-password/reset-password.component.ts b/npm/ng-packs/packages/account/src/lib/components/reset-password/reset-password.component.ts new file mode 100644 index 0000000000..c6b0a669bc --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/reset-password/reset-password.component.ts @@ -0,0 +1,70 @@ +import { getPasswordValidators } from '@abp/ng.theme.shared'; +import { Component, Injector, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; +import { comparePasswords, Validation } from '@ngx-validate/core'; +import { finalize } from 'rxjs/operators'; +import { AccountService } from '../../proxy/account/account.service'; + +const PASSWORD_FIELDS = ['password', 'confirmPassword']; + +@Component({ + selector: 'abp-reset-password', + templateUrl: './reset-password.component.html', +}) +export class ResetPasswordComponent implements OnInit { + form: FormGroup; + + inProgress: boolean = false; + + isPasswordReset: boolean = false; + + mapErrorsFn: Validation.MapErrorsFn = (errors, groupErrors, control) => { + if (PASSWORD_FIELDS.indexOf(String(control.name)) < 0) return errors; + + return errors.concat(groupErrors.filter(({ key }) => key === 'passwordMismatch')); + }; + + constructor( + private fb: FormBuilder, + private accountService: AccountService, + private route: ActivatedRoute, + private router: Router, + private injector: Injector, + ) {} + + ngOnInit(): void { + this.route.queryParams.subscribe(({ userId, resetToken }) => { + if (!userId || !resetToken) this.router.navigateByUrl('/account/login'); + + this.form = this.fb.group( + { + userId: [userId, [Validators.required]], + resetToken: [resetToken, [Validators.required]], + password: ['', [Validators.required, ...getPasswordValidators(this.injector)]], + confirmPassword: ['', [Validators.required, ...getPasswordValidators(this.injector)]], + }, + { + validators: [comparePasswords(PASSWORD_FIELDS)], + }, + ); + }); + } + + onSubmit() { + if (this.form.invalid || this.inProgress) return; + + this.inProgress = true; + + this.accountService + .resetPassword({ + userId: this.form.get('userId').value, + resetToken: this.form.get('resetToken').value, + password: this.form.get('password').value, + }) + .pipe(finalize(() => (this.inProgress = false))) + .subscribe(() => { + this.isPasswordReset = true; + }); + } +} diff --git a/npm/ng-packs/packages/account/src/lib/components/tenant-box/tenant-box.component.html b/npm/ng-packs/packages/account/src/lib/components/tenant-box/tenant-box.component.html new file mode 100644 index 0000000000..e8b2df61e1 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/tenant-box/tenant-box.component.html @@ -0,0 +1,63 @@ + +
+
+
+
+ {{ + 'AbpUiMultiTenancy::Tenant' | abpLocalization + }}
+
+ {{ currentTenant.name || ('AbpUiMultiTenancy::NotSelected' | abpLocalization) }} +
+
+ +
+
+
+ + + +
Switch Tenant
+
+ +
+
+
+ + +
+

{{ 'AbpUiMultiTenancy::SwitchTenantHint' | abpLocalization }}

+
+
+
+ + + + {{ 'AbpTenantManagement::Save' | abpLocalization }} + + +
+
diff --git a/npm/ng-packs/packages/account/src/lib/components/tenant-box/tenant-box.component.ts b/npm/ng-packs/packages/account/src/lib/components/tenant-box/tenant-box.component.ts new file mode 100644 index 0000000000..a1bc72c29e --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/components/tenant-box/tenant-box.component.ts @@ -0,0 +1,75 @@ +import { + AbpApplicationConfigurationService, + AbpTenantService, + ConfigStateService, + CurrentTenantDto, + SessionStateService, +} from '@abp/ng.core'; +import { ToasterService } from '@abp/ng.theme.shared'; +import { Component } from '@angular/core'; +import { Store } from '@ngxs/store'; +import { finalize } from 'rxjs/operators'; +import { Account } from '../../models/account'; + +@Component({ + selector: 'abp-tenant-box', + templateUrl: './tenant-box.component.html', +}) +export class TenantBoxComponent + implements Account.TenantBoxComponentInputs, Account.TenantBoxComponentOutputs { + currentTenant$ = this.sessionState.getTenant$(); + + name: string; + + isModalVisible: boolean; + + modalBusy: boolean; + + constructor( + private store: Store, + private toasterService: ToasterService, + private tenantService: AbpTenantService, + private sessionState: SessionStateService, + private configState: ConfigStateService, + private appConfigService: AbpApplicationConfigurationService, + ) {} + + onSwitch() { + const tenant = this.sessionState.getTenant(); + this.name = tenant?.name; + this.isModalVisible = true; + } + + save() { + if (!this.name) { + this.setTenant(null); + this.isModalVisible = false; + return; + } + + this.modalBusy = true; + this.tenantService + .findTenantByName(this.name, {}) + .pipe(finalize(() => (this.modalBusy = false))) + .subscribe(({ success, ...tenant }) => { + if (!success) { + this.showError(); + return; + } + + this.setTenant({ ...tenant, isAvailable: true }); + this.isModalVisible = false; + }); + } + + private setTenant(tenant: CurrentTenantDto) { + this.sessionState.setTenant(tenant); + this.appConfigService.get().subscribe(res => this.configState.setState(res)); + } + + private showError() { + this.toasterService.error('AbpUiMultiTenancy::GivenTenantIsNotAvailable', 'AbpUi::Error', { + messageLocalizationParams: [this.name], + }); + } +} diff --git a/npm/ng-packs/packages/account/src/lib/enums/components.ts b/npm/ng-packs/packages/account/src/lib/enums/components.ts new file mode 100644 index 0000000000..cebfccc13e --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/enums/components.ts @@ -0,0 +1,11 @@ +export const enum eAccountComponents { + Login = 'Account.LoginComponent', + Register = 'Account.RegisterComponent', + ForgotPassword = 'Account.ForgotPasswordComponent', + ResetPassword = 'Account.ResetPasswordComponent', + ManageProfile = 'Account.ManageProfileComponent', + TenantBox = 'Account.TenantBoxComponent', + AuthWrapper = 'Account.AuthWrapperComponent', + ChangePassword = 'Account.ChangePasswordComponent', + PersonalSettings = 'Account.PersonalSettingsComponent', +} diff --git a/npm/ng-packs/packages/account/src/lib/enums/index.ts b/npm/ng-packs/packages/account/src/lib/enums/index.ts new file mode 100644 index 0000000000..07635cbbc8 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/enums/index.ts @@ -0,0 +1 @@ +export * from './components'; diff --git a/npm/ng-packs/packages/account/src/lib/guards/authentication-flow.guard.ts b/npm/ng-packs/packages/account/src/lib/guards/authentication-flow.guard.ts new file mode 100644 index 0000000000..7cb719628e --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/guards/authentication-flow.guard.ts @@ -0,0 +1,15 @@ +import { AuthService } from '@abp/ng.core'; +import { Injectable } from '@angular/core'; +import { CanActivate } from '@angular/router'; + +@Injectable() +export class AuthenticationFlowGuard implements CanActivate { + constructor(private authService: AuthService) {} + + canActivate() { + if (this.authService.isInternalAuth) return true; + + this.authService.initLogin(); + return false; + } +} diff --git a/npm/ng-packs/packages/account/src/lib/guards/index.ts b/npm/ng-packs/packages/account/src/lib/guards/index.ts new file mode 100644 index 0000000000..382170b2b1 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/guards/index.ts @@ -0,0 +1 @@ +export * from './authentication-flow.guard'; diff --git a/npm/ng-packs/packages/account/src/lib/models/account.ts b/npm/ng-packs/packages/account/src/lib/models/account.ts new file mode 100644 index 0000000000..ef5ad926a2 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/models/account.ts @@ -0,0 +1,12 @@ +import { TemplateRef } from '@angular/core'; + +export namespace Account { + //tslint:disable + export interface TenantBoxComponentInputs {} + export interface TenantBoxComponentOutputs {} + export interface PersonalSettingsComponentInputs {} + export interface PersonalSettingsComponentOutputs {} + export interface ChangePasswordComponentInputs {} + export interface ChangePasswordComponentOutputs {} + // tslint:enable +} diff --git a/npm/ng-packs/packages/account/src/lib/models/index.ts b/npm/ng-packs/packages/account/src/lib/models/index.ts new file mode 100644 index 0000000000..73cf4bcd64 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/models/index.ts @@ -0,0 +1,2 @@ +export * from './account'; +export * from './options'; diff --git a/npm/ng-packs/packages/account/src/lib/models/options.ts b/npm/ng-packs/packages/account/src/lib/models/options.ts new file mode 100644 index 0000000000..f07ccb8900 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/models/options.ts @@ -0,0 +1,3 @@ +export interface Options { + redirectUrl?: string; +} diff --git a/npm/ng-packs/packages/account/src/lib/services/authentication.service.ts b/npm/ng-packs/packages/account/src/lib/services/authentication.service.ts new file mode 100644 index 0000000000..2cd303f373 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/services/authentication.service.ts @@ -0,0 +1,55 @@ +import { Inject, Injectable, Optional } from '@angular/core'; +import { + AbpApplicationConfigurationService, + ConfigStateService, + RestService, + SessionStateService, +} from '@abp/ng.core'; +import { from, Observable } from 'rxjs'; +import { OAuthService } from 'angular-oauth2-oidc'; +import { HttpHeaders } from '@angular/common/http'; +import { switchMap, take, tap } from 'rxjs/operators'; +import { ACCOUNT_OPTIONS } from '../tokens/options.token'; +import { Options } from '../models/options'; +import snq from 'snq'; +import { Router } from '@angular/router'; +import { SessionHandler } from '@abp/ng.account/config'; + +@Injectable() +export class AuthenticationService { + constructor( + protected rest: RestService, + protected sessionState: SessionStateService, + protected oAuthService: OAuthService, + protected appConfigService: AbpApplicationConfigurationService, + protected configState: ConfigStateService, + @Inject(ACCOUNT_OPTIONS) protected options: Options, + protected router: Router, + @Optional() protected sessionHandler: SessionHandler, + ) {} + + login(username: string, password: string, remember = false): Observable { + const tenant = this.sessionState.getTenant(); + + return from( + this.oAuthService.fetchTokenUsingPasswordFlow( + username, + password, + new HttpHeaders({ ...(tenant && tenant.id && { __tenant: tenant.id }) }), + ), + ).pipe( + switchMap(() => this.appConfigService.get()), + tap(res => { + this.configState.setState(res); + + const redirectUrl = + snq(() => window.history.state.redirectUrl) || (this.options || {}).redirectUrl || '/'; + + this.router.navigate([redirectUrl]); + + if (this.sessionHandler) this.sessionHandler.setRememberInfo(remember); + }), + take(1), + ); + } +} diff --git a/npm/ng-packs/packages/account/src/lib/services/index.ts b/npm/ng-packs/packages/account/src/lib/services/index.ts new file mode 100644 index 0000000000..12e6331345 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/services/index.ts @@ -0,0 +1,2 @@ +export * from './authentication.service'; +export * from './manage-profile.state.service'; diff --git a/npm/ng-packs/packages/account/src/lib/services/manage-profile.state.service.ts b/npm/ng-packs/packages/account/src/lib/services/manage-profile.state.service.ts new file mode 100644 index 0000000000..74c58c0674 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/services/manage-profile.state.service.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@angular/core'; +import { InternalStore, Profile } from '@abp/ng.core'; +import { Observable } from 'rxjs'; + +export interface ManageProfileState { + profile: Profile.Response; +} + +@Injectable({ providedIn: 'root' }) +export class ManageProfileStateService { + private readonly store = new InternalStore({} as ManageProfileState); + + get createOnUpdateStream() { + return this.store.sliceUpdate; + } + + getProfile$(): Observable { + return this.store.sliceState(state => state.profile); + } + + getProfile(): Profile.Response { + return this.store.state.profile; + } + + setProfile(profile: Profile.Response) { + this.store.patch({ profile }); + } +} diff --git a/npm/ng-packs/packages/account/src/lib/tokens/index.ts b/npm/ng-packs/packages/account/src/lib/tokens/index.ts new file mode 100644 index 0000000000..683bc4b3db --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/tokens/index.ts @@ -0,0 +1 @@ +export * from './options.token'; diff --git a/npm/ng-packs/packages/account/src/lib/tokens/options.token.ts b/npm/ng-packs/packages/account/src/lib/tokens/options.token.ts new file mode 100644 index 0000000000..a7f29c43b9 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/tokens/options.token.ts @@ -0,0 +1,4 @@ +import { InjectionToken } from '@angular/core'; +import { Options } from '../models/options'; + +export const ACCOUNT_OPTIONS = new InjectionToken('ACCOUNT_OPTIONS'); diff --git a/npm/ng-packs/packages/account/src/lib/utils/factory-utils.ts b/npm/ng-packs/packages/account/src/lib/utils/factory-utils.ts new file mode 100644 index 0000000000..3e7c88f795 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/utils/factory-utils.ts @@ -0,0 +1,8 @@ +import { Options } from '../models/options'; + +export function accountOptionsFactory(options: Options) { + return { + redirectUrl: '/', + ...options, + }; +} diff --git a/npm/ng-packs/packages/account/src/lib/utils/index.ts b/npm/ng-packs/packages/account/src/lib/utils/index.ts new file mode 100644 index 0000000000..ed99d0aaa4 --- /dev/null +++ b/npm/ng-packs/packages/account/src/lib/utils/index.ts @@ -0,0 +1 @@ +export * from './factory-utils'; diff --git a/npm/ng-packs/packages/account/src/public-api.ts b/npm/ng-packs/packages/account/src/public-api.ts new file mode 100644 index 0000000000..c3e80345c5 --- /dev/null +++ b/npm/ng-packs/packages/account/src/public-api.ts @@ -0,0 +1,9 @@ +export * from './lib/account.module'; +export * from './lib/components'; +export * from './lib/enums'; +export * from './lib/guards'; +export * from './lib/models'; +export * from './lib/services'; +export * from './lib/tokens'; +export * from './lib/proxy/account'; +export * from './lib/proxy/identity'; diff --git a/npm/ng-packs/packages/account/tsconfig.lib.json b/npm/ng-packs/packages/account/tsconfig.lib.json new file mode 100644 index 0000000000..4f48db2e46 --- /dev/null +++ b/npm/ng-packs/packages/account/tsconfig.lib.json @@ -0,0 +1,19 @@ +{ + "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"] +} diff --git a/npm/ng-packs/packages/account/tsconfig.lib.prod.json b/npm/ng-packs/packages/account/tsconfig.lib.prod.json new file mode 100644 index 0000000000..b1d501abbc --- /dev/null +++ b/npm/ng-packs/packages/account/tsconfig.lib.prod.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.lib.json", + "angularCompilerOptions": { + "enableIvy": false + } +} \ No newline at end of file diff --git a/npm/ng-packs/packages/account/tsconfig.spec.json b/npm/ng-packs/packages/account/tsconfig.spec.json new file mode 100644 index 0000000000..02f312c262 --- /dev/null +++ b/npm/ng-packs/packages/account/tsconfig.spec.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.prod.json", + "compilerOptions": { + "emitDecoratorMetadata": true, + "esModuleInterop": true, + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": ["**/*.spec.ts", "**/*.d.ts"] +} diff --git a/npm/ng-packs/packages/account/tslint.json b/npm/ng-packs/packages/account/tslint.json new file mode 100644 index 0000000000..8c3919ea62 --- /dev/null +++ b/npm/ng-packs/packages/account/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "abp", + "camelCase" + ], + "component-selector": [ + true, + "element", + "abp", + "kebab-case" + ] + } +} diff --git a/npm/ng-packs/tsconfig.json b/npm/ng-packs/tsconfig.json index c67c628f64..b35406a4db 100644 --- a/npm/ng-packs/tsconfig.json +++ b/npm/ng-packs/tsconfig.json @@ -22,6 +22,8 @@ "@abp/ng.theme.shared/extensions": ["packages/theme-shared/extensions/src/public-api.ts"], "@abp/ng.components/tree": ["packages/components/tree/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/config": ["packages/account/config/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.tenant-management": ["packages/tenant-management/src/public-api.ts"],