[ACS-7385][ADF] Break Login dependency on Material Module (#9501)

This commit is contained in:
tamaragruszka
2024-04-09 18:13:19 +02:00
committed by GitHub
parent 5494aa8728
commit a5e7fcc10e
24 changed files with 382 additions and 400 deletions

View File

@@ -5,7 +5,11 @@
[showLoginActions]="false"
[backgroundImageUrl]="''"
(success)="onLoginSuccess($event)">
<adf-login-header><ng-template></ng-template></adf-login-header>
<adf-login-footer><ng-template></ng-template></adf-login-footer>
<adf-login-header>
<ng-template></ng-template>
</adf-login-header>
<adf-login-footer>
<ng-template></ng-template>
</adf-login-footer>
</adf-login>
</div>

View File

@@ -15,13 +15,11 @@
* limitations under the License.
*/
import { BasicAlfrescoAuthService, CoreTestingModule, LoginDialogPanelComponent } from '@alfresco/adf-core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginDialogPanelComponent } from './login-dialog-panel.component';
import { of } from 'rxjs';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { TranslateModule } from '@ngx-translate/core';
import { BasicAlfrescoAuthService } from '../../auth/basic-auth/basic-alfresco-auth.service';
import { OidcAuthenticationService } from '../../auth/services/oidc-authentication.service';
import { of } from 'rxjs';
import { OidcAuthenticationService } from '../../../auth/services/oidc-authentication.service';
describe('LoginDialogPanelComponent', () => {
let component: LoginDialogPanelComponent;
@@ -38,7 +36,7 @@ describe('LoginDialogPanelComponent', () => {
CoreTestingModule
],
providers: [
{ provide: OidcAuthenticationService, useValue: {}}
{ provide: OidcAuthenticationService, useValue: {} }
]
});
fixture = TestBed.createComponent(LoginDialogPanelComponent);

View File

@@ -15,14 +15,22 @@
* limitations under the License.
*/
import { Component, ViewEncapsulation, ViewChild, Output, EventEmitter } from '@angular/core';
import { LoginComponent } from './login.component';
import { LoginSuccessEvent } from '../models/login-success.event';
import { Component, EventEmitter, Output, ViewChild, ViewEncapsulation } from '@angular/core';
import { LoginFooterDirective } from '../../directives/login-footer.directive';
import { LoginHeaderDirective } from '../../directives/login-header.directive';
import { LoginSuccessEvent } from '../../models/login-success.event';
import { LoginComponent } from '../login/login.component';
@Component({
selector: 'adf-login-dialog-panel',
standalone: true,
templateUrl: './login-dialog-panel.component.html',
styleUrls: ['./login-dialog-panel.component.scss'],
imports: [
LoginComponent,
LoginHeaderDirective,
LoginFooterDirective
],
encapsulation: ViewEncapsulation.None
})
export class LoginDialogPanelComponent {

View File

@@ -1,27 +0,0 @@
<header
mat-dialog-title
data-automation-id="login-dialog-title">
{{data?.title}}
</header>
<mat-dialog-content class="adf-login-dialog-content">
<adf-login-dialog-panel #adfLoginPanel (success)="onLoginSuccess($event)">
</adf-login-dialog-panel>
</mat-dialog-content>
<mat-dialog-actions class="adf-login-dialog-content-actions" align="end">
<button
mat-button (click)="close()"
data-automation-id="login-dialog-actions-cancel">
{{ 'LOGIN.DIALOG.CANCEL' | translate }}
</button>
<button
mat-button
class="choose-action"
data-automation-id="login-dialog-actions-perform"
[disabled]="!isFormValid()"
(click)="submitForm()">
{{ buttonActionName | translate}}
</button>
</mat-dialog-actions>

View File

@@ -0,0 +1,24 @@
<header mat-dialog-title
data-automation-id="login-dialog-title">
{{ data?.title }}
</header>
<mat-dialog-content class="adf-login-dialog-content">
<adf-login-dialog-panel #adfLoginPanel (success)="onLoginSuccess($event)">
</adf-login-dialog-panel>
</mat-dialog-content>
<mat-dialog-actions class="adf-login-dialog-content-actions" align="end">
<button mat-button (click)="close()"
data-automation-id="login-dialog-actions-cancel">
{{ 'LOGIN.DIALOG.CANCEL' | translate }}
</button>
<button mat-button
class="choose-action"
data-automation-id="login-dialog-actions-perform"
[disabled]="!isFormValid()"
(click)="submitForm()">
{{ buttonActionName | translate }}
</button>
</mat-dialog-actions>

View File

@@ -15,14 +15,14 @@
* limitations under the License.
*/
import { Meta, moduleMetadata, Story } from '@storybook/angular';
import { CoreStoryModule } from '../../testing/core.story.module';
import { RouterTestingModule } from '@angular/router/testing';
import { LoginModule } from './../login.module';
import { LoginDialogStorybookComponent } from './login-dialog.stories.component';
import { MatButtonModule } from '@angular/material/button';
import { AuthenticationService } from '../../auth/services/authentication.service';
import { AuthenticationMock } from '../../auth/mock/authentication.service.mock';
import { RouterTestingModule } from '@angular/router/testing';
import { Meta, moduleMetadata, Story } from '@storybook/angular';
import { AuthenticationService } from '../../../auth';
import { AuthenticationMock } from '../../../auth/mock/authentication.service.mock';
import { CoreStoryModule } from '../../../testing/core.story.module';
import { LoginModule } from '../../login.module';
import { LoginDialogStorybookComponent } from './login-dialog.stories.component';
export default {
component: LoginDialogStorybookComponent,

View File

@@ -15,14 +15,24 @@
* limitations under the License.
*/
import { Component, Inject, ViewEncapsulation, ViewChild } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { Component, Inject, ViewChild, ViewEncapsulation } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { TranslateModule } from '@ngx-translate/core';
import { LoginDialogPanelComponent } from '../login-dialog-panel/login-dialog-panel.component';
import { LoginDialogComponentData } from './login-dialog-component-data.interface';
import { LoginDialogPanelComponent } from './login-dialog-panel.component';
@Component({
selector: 'adf-login-dialog',
standalone: true,
templateUrl: './login-dialog.component.html',
styleUrls: ['./login-dialog.component.scss'],
imports: [
MatDialogModule,
LoginDialogPanelComponent,
TranslateModule,
MatButtonModule
],
encapsulation: ViewEncapsulation.None
})
export class LoginDialogComponent {

View File

@@ -16,6 +16,7 @@
*/
import { Component, Output, EventEmitter } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDialog } from '@angular/material/dialog';
import { Subject } from 'rxjs';
import { LoginDialogComponent } from './login-dialog.component';
@@ -23,9 +24,14 @@ import { LoginDialogComponentData } from './login-dialog-component-data.interfac
@Component({
selector: 'adf-login-dialog-storybook',
template: `<button mat-raised-button (click)="openLoginDialog()">
Open dialog
</button>`
standalone: true,
imports: [
MatButtonModule
],
template: `
<button mat-raised-button (click)="openLoginDialog()">
Open dialog
</button>`
})
export class LoginDialogStorybookComponent {

View File

@@ -1,218 +0,0 @@
<div class="adf-login-content" [style.background-image]="getBackgroundUrlImageUrl()">
<div class="adf-ie11FixerParent">
<div class="adf-ie11FixerChild">
<mat-card class="adf-login-card-wide">
<form
id="adf-login-form"
[formGroup]="form"
autocomplete="off"
(submit)="onSubmit(form.value)">
<mat-card-header class="adf-login-card-header-text">
<mat-card-title>
<div class="adf-alfresco-logo">
<!--HEADER TEMPLATE-->
<ng-template
*ngIf="headerTemplate"
ngFor
[ngForOf]="[data]"
[ngForTemplate]="headerTemplate">
</ng-template>
<img
*ngIf="!headerTemplate"
id="adf-login-img-logo"
class="adf-img-logo"
[src]="logoImageUrl"
alt="{{'LOGIN.LOGO' | translate }}">
</div>
</mat-card-title>
</mat-card-header>
<mat-card-content class="adf-login-controls">
<!--ERRORS AREA-->
<div class="adf-error-container">
<div
*ngIf="isError"
id="login-error"
data-automation-id="login-error"
class="adf-error adf-error-message">
<mat-icon class="adf-error-icon">warning</mat-icon>
<span class="adf-login-error-message">
{{errorMsg | translate }}
</span>
</div>
</div>
<div *ngIf="!ssoLogin">
<!--USERNAME FIELD-->
<div
class="adf-login__field"
[ngClass]="{'adf-is-invalid': isErrorStyle(form.controls.username)}">
<mat-form-field
class="adf-full-width adf-login-form-field"
floatPlaceholder="never"
color="primary">
<input
matInput
type="text"
class="adf-full-width"
formControlName="username"
id="username"
data-automation-id="username"
placeholder="{{'LOGIN.LABEL.USERNAME' | translate }}"
autocapitalize="none"
(blur)="trimUsername($event)">
</mat-form-field>
<span
*ngIf="formError['username']"
class="adf-login-validation"
for="username">
<span
id="username-error"
class="adf-login-error"
data-automation-id="username-error">
{{formError['username'] | translate}}
</span>
</span>
</div>
<!--PASSWORD FIELD-->
<div class="adf-login__field">
<mat-form-field
class="adf-full-width adf-login-form-field"
floatPlaceholder="never"
color="primary">
<input
matInput
placeholder="{{'LOGIN.LABEL.PASSWORD' | translate }}"
[type]="isPasswordShow ? 'text' : 'password'"
formControlName="password"
id="password"
data-automation-id="password">
<button
matSuffix
mat-icon-button
type="button"
[attr.aria-label]="(isPasswordShow ? 'LOGIN.ARIA-LABEL.HIDE-PASSWORD' : 'LOGIN.ARIA-LABEL.SHOW-PASSWORD') | translate"
(click)="toggleShowPassword($event)"
(keyup.enter)="toggleShowPassword($event)"
[attr.data-automation-id]="isPasswordShow ? 'hide_password' : 'show_password'">
<mat-icon class="adf-login-form-password-icon adf-login-password-icon">
{{ isPasswordShow ? 'visibility' : 'visibility_off' }}
</mat-icon>
</button>
</mat-form-field>
<span
class="adf-login-validation"
for="password"
*ngIf="formError['password']">
<span
id="password-required"
class="adf-login-error"
data-automation-id="password-required">
{{formError['password'] | translate}}
</span>
</span>
</div>
<!--CUSTOM CONTENT-->
<ng-content></ng-content>
<br>
<button
type="submit"
id="login-button"
class="adf-login-button"
mat-raised-button
color="accent"
[class.adf-isChecking]="actualLoginStep === LoginSteps.Checking"
[class.adf-isWelcome]="actualLoginStep === LoginSteps.Welcome"
data-automation-id="login-button"
[disabled]="!form.valid"
[attr.aria-label]="'LOGIN.BUTTON.LOGIN' | translate">
<span
*ngIf="actualLoginStep === LoginSteps.Landing"
class="adf-login-button-label">
{{'LOGIN.BUTTON.LOGIN' | translate }}
</span>
<div
*ngIf="actualLoginStep === LoginSteps.Checking"
class="adf-interactive-login-label">
<span class="adf-login-button-label">
{{ 'LOGIN.BUTTON.CHECKING' | translate}}
</span>
<div class="adf-login-spinner-container">
<mat-spinner
id="checking-spinner"
class="adf-login-checking-spinner"
[strokeWidth]="4"
[diameter]="25">
</mat-spinner>
</div>
</div>
<div
*ngIf="actualLoginStep === LoginSteps.Welcome"
class="adf-interactive-login-label">
<span class="adf-login-button-label">{{ 'LOGIN.BUTTON.WELCOME' | translate }}</span>
<mat-icon class="adf-welcome-icon">done</mat-icon>
</div>
</button>
<div *ngIf="showRememberMe" class="adf-login__remember-me">
<mat-checkbox
id="adf-login-remember"
color="primary"
class="adf-login-remember-me"
[checked]="rememberMe"
(change)="rememberMe = !rememberMe">
<div class="adf-login-remember-me-label">
{{ 'LOGIN.LABEL.REMEMBER' | translate }}
</div>
</mat-checkbox>
</div>
</div>
<div *ngIf="ssoLogin">
<button
type="button"
(click)="implicitLogin()"
id="login-button-sso"
[attr.aria-label]="'LOGIN.BUTTON.SSO' | translate"
class="adf-login-button"
mat-raised-button color="primary"
data-automation-id="login-button-sso">
<span class="adf-login-button-label">{{ 'LOGIN.BUTTON.SSO' | translate }}</span>
</button>
</div>
</mat-card-content>
<mat-card-actions *ngIf="footerTemplate || showLoginActions">
<div class="adf-login-action-container">
<!--FOOTER TEMPLATE-->
<ng-template
*ngIf="footerTemplate"
ngFor
[ngForOf]="[data]"
[ngForTemplate]="footerTemplate">
</ng-template>
<div class="adf-login-action" *ngIf="!footerTemplate && showLoginActions">
<div id="adf-login-action-left" class="adf-login-action-left">
<a href="{{needHelpLink}}">{{'LOGIN.ACTION.HELP' | translate }}</a>
</div>
<div id="adf-login-action-right" class="adf-login-action-right">
<a href="{{registerLink}}">{{'LOGIN.ACTION.REGISTER' | translate }}</a>
</div>
</div>
</div>
</mat-card-actions>
</form>
</mat-card>
<div class="adf-copyright" data-automation-id="login-copyright">
{{ copyrightText }}
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,200 @@
<div class="adf-login-content" [style.background-image]="'url(' + backgroundImageUrl + ')'">
<div class="adf-ie11FixerParent">
<div class="adf-ie11FixerChild">
<mat-card class="adf-login-card-wide">
<form id="adf-login-form"
[formGroup]="form"
autocomplete="off"
(submit)="onSubmit(form.value)">
<mat-card-header class="adf-login-card-header-text">
<mat-card-title>
<div class="adf-alfresco-logo">
<!--HEADER TEMPLATE-->
<ng-template *ngIf="headerTemplate"
ngFor
[ngForOf]="[data]"
[ngForTemplate]="headerTemplate">
</ng-template>
<img *ngIf="!headerTemplate"
id="adf-login-img-logo"
class="adf-img-logo"
[src]="logoImageUrl"
alt="{{ 'LOGIN.LOGO' | translate }}">
</div>
</mat-card-title>
</mat-card-header>
<mat-card-content class="adf-login-controls">
<!--ERRORS AREA-->
<div class="adf-error-container">
<div *ngIf="isError"
id="login-error"
data-automation-id="login-error"
class="adf-error adf-error-message">
<mat-icon class="adf-error-icon">warning</mat-icon>
<span class="adf-login-error-message">
{{ errorMsg | translate }}
</span>
</div>
</div>
<div *ngIf="!ssoLogin">
<!--USERNAME FIELD-->
<div class="adf-login__field"
[ngClass]="{'adf-is-invalid': isErrorStyle(form.controls.username)}">
<mat-form-field class="adf-full-width adf-login-form-field"
floatPlaceholder="never"
color="primary">
<input matInput
type="text"
class="adf-full-width"
formControlName="username"
id="username"
data-automation-id="username"
placeholder="{{'LOGIN.LABEL.USERNAME' | translate }}"
autocapitalize="none"
(blur)="trimUsername($event)">
</mat-form-field>
<span *ngIf="formError['username']"
class="adf-login-validation"
for="username">
<span id="username-error"
class="adf-login-error"
data-automation-id="username-error">
{{ formError['username'] | translate }}
</span>
</span>
</div>
<!--PASSWORD FIELD-->
<div class="adf-login__field">
<mat-form-field class="adf-full-width adf-login-form-field"
floatPlaceholder="never"
color="primary">
<input matInput
placeholder="{{'LOGIN.LABEL.PASSWORD' | translate }}"
[type]="isPasswordShow ? 'text' : 'password'"
formControlName="password"
id="password"
data-automation-id="password">
<button matSuffix
mat-icon-button
type="button"
[attr.aria-label]="(isPasswordShow ? 'LOGIN.ARIA-LABEL.HIDE-PASSWORD' : 'LOGIN.ARIA-LABEL.SHOW-PASSWORD') | translate"
(click)="toggleShowPassword($event)"
(keyup.enter)="toggleShowPassword($event)"
[attr.data-automation-id]="isPasswordShow ? 'hide_password' : 'show_password'">
<mat-icon class="adf-login-form-password-icon adf-login-password-icon">
{{ isPasswordShow ? 'visibility' : 'visibility_off' }}
</mat-icon>
</button>
</mat-form-field>
<span class="adf-login-validation"
for="password"
*ngIf="formError['password']">
<span id="password-required"
class="adf-login-error"
data-automation-id="password-required">
{{ formError['password'] | translate }}
</span>
</span>
</div>
<!--CUSTOM CONTENT-->
<ng-content></ng-content>
<br>
<button type="submit"
id="login-button"
class="adf-login-button"
mat-raised-button
color="accent"
[class.adf-isChecking]="actualLoginStep === LoginSteps.Checking"
[class.adf-isWelcome]="actualLoginStep === LoginSteps.Welcome"
data-automation-id="login-button"
[disabled]="!form.valid"
[attr.aria-label]="'LOGIN.BUTTON.LOGIN' | translate">
<span *ngIf="actualLoginStep === LoginSteps.Landing"
class="adf-login-button-label">
{{ 'LOGIN.BUTTON.LOGIN' | translate }}
</span>
<div *ngIf="actualLoginStep === LoginSteps.Checking"
class="adf-interactive-login-label">
<span class="adf-login-button-label">
{{ 'LOGIN.BUTTON.CHECKING' | translate }}
</span>
<div class="adf-login-spinner-container">
<mat-spinner id="checking-spinner"
class="adf-login-checking-spinner"
[strokeWidth]="4"
[diameter]="25">
</mat-spinner>
</div>
</div>
<div *ngIf="actualLoginStep === LoginSteps.Welcome"
class="adf-interactive-login-label">
<span class="adf-login-button-label">
{{ 'LOGIN.BUTTON.WELCOME' | translate }}
</span>
<mat-icon class="adf-welcome-icon">done</mat-icon>
</div>
</button>
<div *ngIf="showRememberMe" class="adf-login__remember-me">
<mat-checkbox id="adf-login-remember"
color="primary"
class="adf-login-remember-me"
[checked]="rememberMe"
(change)="rememberMe = !rememberMe">
<div class="adf-login-remember-me-label">
{{ 'LOGIN.LABEL.REMEMBER' | translate }}
</div>
</mat-checkbox>
</div>
</div>
<div *ngIf="ssoLogin">
<button type="button"
(click)="implicitLogin()"
id="login-button-sso"
[attr.aria-label]="'LOGIN.BUTTON.SSO' | translate"
class="adf-login-button"
mat-raised-button color="primary"
data-automation-id="login-button-sso">
<span class="adf-login-button-label">
{{ 'LOGIN.BUTTON.SSO' | translate }}
</span>
</button>
</div>
</mat-card-content>
<mat-card-actions *ngIf="footerTemplate || showLoginActions">
<div class="adf-login-action-container">
<!--FOOTER TEMPLATE-->
<ng-template *ngIf="footerTemplate"
ngFor
[ngForOf]="[data]"
[ngForTemplate]="footerTemplate">
</ng-template>
<div class="adf-login-action" *ngIf="!footerTemplate && showLoginActions">
<div id="adf-login-action-left" class="adf-login-action-left">
<a href="{{ needHelpLink }}">{{ 'LOGIN.ACTION.HELP' | translate }}</a>
</div>
<div id="adf-login-action-right" class="adf-login-action-right">
<a href="{{ registerLink }}">{{ 'LOGIN.ACTION.REGISTER' | translate }}</a>
</div>
</div>
</div>
</mat-card-actions>
</form>
</mat-card>
<div class="adf-copyright" data-automation-id="login-copyright">
{{ copyrightText }}
</div>
</div>
</div>
</div>

View File

@@ -1,4 +1,4 @@
@import '../../styles/mixins';
@import '../../../styles/mixins';
.adf-login {
@include flex-column;
@@ -63,7 +63,7 @@
box-sizing: border-box;
}
@media (max-width: 482px) {
@media screen and (width <= 482px) {
.adf-login-card-wide {
width: calc(100% - 32px);
}
@@ -185,6 +185,8 @@
.adf-login__field {
margin: 1em 0 0;
display: block;
padding-bottom: 18px;
font-size: var(--theme-subheading-2-font-size);
& input:-webkit-autofill {
@@ -221,13 +223,6 @@
opacity: 0.87;
}
.adf-login__field {
display: block;
margin-left: auto;
margin-right: auto;
padding-bottom: 18px;
}
.adf-login-remember-me:has(.adf-login-remember-me-label) {
color: var(--adf-theme-foreground-text-color);
}

View File

@@ -15,21 +15,23 @@
* limitations under the License.
*/
import {
AppConfigService,
AuthenticationService,
BasicAlfrescoAuthService,
CoreTestingModule,
LoginErrorEvent,
LoginSuccessEvent,
LogService,
UserPreferencesService
} from '@alfresco/adf-core';
import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing';
import { Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { UserPreferencesService } from '../../common/services/user-preferences.service';
import { AppConfigService } from '../../app-config/app-config.service';
import { AuthenticationService } from '../../auth/services/authentication.service';
import { LoginErrorEvent } from '../models/login-error.event';
import { LoginSuccessEvent } from '../models/login-success.event';
import { LoginComponent } from './login.component';
import { EMPTY, of, throwError } from 'rxjs';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { LogService } from '../../common/services/log.service';
import { BasicAlfrescoAuthService } from '../../auth/basic-auth/basic-alfresco-auth.service';
import { OidcAuthenticationService } from '../../auth/services/oidc-authentication.service';
import { OidcAuthenticationService } from '../../../auth/services/oidc-authentication.service';
import { LoginComponent } from './login.component';
describe('LoginComponent', () => {
let component: LoginComponent;
@@ -65,7 +67,8 @@ describe('LoginComponent', () => {
providers: [
{
provide: OidcAuthenticationService, useValue: {
ssoLogin: () => { },
ssoLogin: () => {
},
isPublicUrl: () => false,
hasValidIdToken: () => false,
isLoggedIn: () => false
@@ -581,7 +584,7 @@ describe('LoginComponent', () => {
loginWithCredentials('fake-username-ECM-access-error', 'fake-password');
}));
});
});
it('should trim the username value', () => {
usernameInput.value = 'username ';
@@ -623,7 +626,7 @@ describe('LoginComponent', () => {
});
loginWithCredentials('fake-username', 'fake-password');
});
});
it('should emit success event after the login has succeeded and discard password', fakeAsync(() => {
spyOn(basicAlfrescoAuthService, 'login').and.returnValue(of({ type: 'type', ticket: 'ticket' }));

View File

@@ -15,13 +15,13 @@
* limitations under the License.
*/
import { Meta, moduleMetadata, Story } from '@storybook/angular';
import { CoreStoryModule } from '../../testing/core.story.module';
import { LoginModule } from '../login.module';
import { LoginComponent } from './login.component';
import { RouterModule } from '@angular/router';
import { AuthenticationService } from './../../auth/services/authentication.service';
import { AuthenticationMock } from '../../auth/mock/authentication.service.mock';
import { Meta, moduleMetadata, Story } from '@storybook/angular';
import { AuthenticationService } from '../../../auth';
import { AuthenticationMock } from '../../../auth/mock/authentication.service.mock';
import { CoreStoryModule } from '../../../testing/core.story.module';
import { LoginModule } from '../../login.module';
import { LoginComponent } from './login.component';
export default {
component: LoginComponent,

View File

@@ -15,22 +15,29 @@
* limitations under the License.
*/
import { Component, EventEmitter, Input, OnInit, Output, TemplateRef, ViewEncapsulation, OnDestroy } from '@angular/core';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { AuthenticationService } from '../../auth/services/authentication.service';
import { TranslationService } from '../../translation/translation.service';
import { UserPreferencesService } from '../../common/services/user-preferences.service';
import { LoginErrorEvent } from '../models/login-error.event';
import { LoginSubmitEvent } from '../models/login-submit.event';
import { LoginSuccessEvent } from '../models/login-success.event';
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
import { DomSanitizer, SafeStyle } from '@angular/platform-browser';
import { CommonModule } from '@angular/common';
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, TemplateRef, ViewEncapsulation } from '@angular/core';
import { AbstractControl, ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { BasicAlfrescoAuthService } from '../../auth/basic-auth/basic-alfresco-auth.service';
import { OidcAuthenticationService } from '../../auth/services/oidc-authentication.service';
import { AppConfigService, AppConfigValues } from '../../../app-config';
import { AuthenticationService, BasicAlfrescoAuthService } from '../../../auth';
import { OidcAuthenticationService } from '../../../auth/services/oidc-authentication.service';
import { UserPreferencesService } from '../../../common';
import { TranslationService } from '../../../translation';
import { LoginErrorEvent } from '../../models/login-error.event';
import { LoginSubmitEvent } from '../../models/login-submit.event';
import { LoginSuccessEvent } from '../../models/login-success.event';
// eslint-disable-next-line no-shadow
enum LoginSteps {
@@ -47,14 +54,27 @@ interface ValidationMessage {
interface LoginFormValues {
username: string;
password: string;
};
}
@Component({
selector: 'adf-login',
standalone: true,
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss'],
encapsulation: ViewEncapsulation.None,
host: {class: 'adf-login'}
imports: [
CommonModule,
MatCardModule,
ReactiveFormsModule,
TranslateModule,
MatIconModule,
MatFormFieldModule,
MatInputModule,
MatButtonModule,
MatProgressSpinnerModule,
MatCheckboxModule
],
host: { class: 'adf-login' }
})
export class LoginComponent implements OnInit, OnDestroy {
isPasswordShow: boolean = false;
@@ -137,8 +157,7 @@ export class LoginComponent implements OnInit, OnDestroy {
private router: Router,
private appConfig: AppConfigService,
private userPreferences: UserPreferencesService,
private route: ActivatedRoute,
private sanitizer: DomSanitizer
private route: ActivatedRoute
) {}
ngOnInit() {
@@ -164,7 +183,7 @@ export class LoginComponent implements OnInit, OnDestroy {
const url = params['redirectUrl'];
const provider = this.appConfig.get<string>(AppConfigValues.PROVIDERS);
this.basicAlfrescoAuthService.setRedirect({provider, url});
this.basicAlfrescoAuthService.setRedirect({ provider, url });
});
}
@@ -197,7 +216,7 @@ export class LoginComponent implements OnInit, OnDestroy {
this.disableError();
const args = new LoginSubmitEvent({
controls: {username: this.form.controls.username}
controls: { username: this.form.controls.username }
});
this.executeSubmit.emit(args);
@@ -243,30 +262,29 @@ export class LoginComponent implements OnInit, OnDestroy {
}
performLogin(values: { username: string; password: string }) {
this.authService.login(values.username, values.password, this.rememberMe)
.subscribe(
async (token: any) => {
const redirectUrl = this.basicAlfrescoAuthService.getRedirect();
this.authService.login(values.username, values.password, this.rememberMe).subscribe(
async (token: any) => {
const redirectUrl = this.basicAlfrescoAuthService.getRedirect();
this.actualLoginStep = LoginSteps.Welcome;
this.userPreferences.setStoragePrefix(values.username);
values.password = null;
this.success.emit(new LoginSuccessEvent(token, values.username, null));
this.actualLoginStep = LoginSteps.Welcome;
this.userPreferences.setStoragePrefix(values.username);
values.password = null;
this.success.emit(new LoginSuccessEvent(token, values.username, null));
if (redirectUrl) {
this.basicAlfrescoAuthService.setRedirect(null);
await this.router.navigateByUrl(redirectUrl);
} else if (this.successRoute) {
await this.router.navigate([this.successRoute]);
}
},
(err: any) => {
this.actualLoginStep = LoginSteps.Landing;
this.displayErrorMessage(err);
this.isError = true;
this.error.emit(new LoginErrorEvent(err));
if (redirectUrl) {
this.basicAlfrescoAuthService.setRedirect(null);
await this.router.navigateByUrl(redirectUrl);
} else if (this.successRoute) {
await this.router.navigate([this.successRoute]);
}
);
},
(err: any) => {
this.actualLoginStep = LoginSteps.Landing;
this.displayErrorMessage(err);
this.isError = true;
this.error.emit(new LoginErrorEvent(err));
}
);
}
/**
@@ -342,10 +360,6 @@ export class LoginComponent implements OnInit, OnDestroy {
event.target.value = event.target.value.trim();
}
getBackgroundUrlImageUrl(): SafeStyle {
return this.sanitizer.bypassSecurityTrustStyle(`url(${this.backgroundImageUrl})`);
}
/**
* Default formError values
*/

View File

@@ -15,10 +15,8 @@
* limitations under the License.
*/
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { LoginComponent } from '../components/login.component';
import { LoginFooterDirective } from './login-footer.directive';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { CoreTestingModule, LoginComponent, LoginFooterDirective } from '@alfresco/adf-core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { OidcAuthenticationService } from '../../auth/services/oidc-authentication.service';

View File

@@ -15,27 +15,18 @@
* limitations under the License.
*/
import {
AfterContentInit,
ContentChild,
Directive,
TemplateRef
} from '@angular/core';
import { LoginComponent } from '../components/login.component';
import { AfterContentInit, ContentChild, Directive, TemplateRef } from '@angular/core';
import { LoginComponent } from '../components/login/login.component';
/**
* Directive selectors without adf- prefix will be deprecated on 3.0.0
*/
@Directive({
selector: 'adf-login-footer, login-footer'
selector: 'adf-login-footer',
standalone: true
})
export class LoginFooterDirective implements AfterContentInit {
@ContentChild(TemplateRef)
template: any;
constructor(
private alfrescoLoginComponent: LoginComponent) {
constructor(private alfrescoLoginComponent: LoginComponent) {
}
ngAfterContentInit() {

View File

@@ -15,10 +15,8 @@
* limitations under the License.
*/
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { LoginComponent } from '../components/login.component';
import { LoginHeaderDirective } from './login-header.directive';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { CoreTestingModule, LoginComponent, LoginHeaderDirective } from '@alfresco/adf-core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { OidcAuthenticationService } from '../../auth/services/oidc-authentication.service';

View File

@@ -15,27 +15,18 @@
* limitations under the License.
*/
import {
AfterContentInit,
ContentChild,
Directive,
TemplateRef
} from '@angular/core';
import { LoginComponent } from '../components/login.component';
import { AfterContentInit, ContentChild, Directive, TemplateRef } from '@angular/core';
import { LoginComponent } from '../components/login/login.component';
/**
* Directive selectors without adf- prefix will be deprecated on 3.0.0
*/
@Directive({
selector: 'adf-login-header, login-header'
selector: 'adf-login-header',
standalone: true
})
export class LoginHeaderDirective implements AfterContentInit {
@ContentChild(TemplateRef)
template: any;
constructor(
private alfrescoLoginComponent: LoginComponent) {
constructor(private alfrescoLoginComponent: LoginComponent) {
}
ngAfterContentInit() {

View File

@@ -15,29 +15,16 @@
* limitations under the License.
*/
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { MaterialModule } from '../material.module';
import { LoginDialogPanelComponent } from './components/login-dialog-panel/login-dialog-panel.component';
import { LoginDialogComponent } from './components/login-dialog/login-dialog.component';
import { LoginComponent } from './components/login.component';
import { LoginComponent } from './components/login/login.component';
import { LoginFooterDirective } from './directives/login-footer.directive';
import { LoginHeaderDirective } from './directives/login-header.directive';
import { LoginDialogComponent } from './components/login-dialog.component';
import { LoginDialogPanelComponent } from './components/login-dialog-panel.component';
@NgModule({
imports: [
RouterModule,
MaterialModule,
FormsModule,
ReactiveFormsModule,
CommonModule,
TranslateModule
],
declarations: [
LoginComponent,
LoginFooterDirective,
LoginHeaderDirective,

View File

@@ -19,6 +19,6 @@ export class LoginSuccessEvent {
constructor(
public token: any,
public username: string,
public password: string) {
}
public password: string
) {}
}

View File

@@ -18,10 +18,10 @@
export * from './directives/login-header.directive';
export * from './directives/login-footer.directive';
export * from './components/login.component';
export * from './components/login-dialog.component';
export * from './components/login-dialog-component-data.interface';
export * from './components/login-dialog-panel.component';
export * from './components/login/login.component';
export * from './components/login-dialog/login-dialog.component';
export * from './components/login-dialog/login-dialog-component-data.interface';
export * from './components/login-dialog-panel/login-dialog-panel.component';
export * from './models/login-error.event';
export * from './models/login-submit.event';