Login form with Tenant dropdown menu

This commit is contained in:
Jose Alberto Hernandez
2022-11-29 22:18:54 -06:00
parent 8f1c17acdf
commit 7275ba8dda
25 changed files with 189 additions and 20 deletions
+7 -1
View File
@@ -133,11 +133,17 @@ https://localhost:8443
```
FINERACT_PLATFORM_TENANT_IDENTIFIER
```
Fineract Tenant identifier to be used, It must be aligned with the Fineract `tenants` table. Default value:
Fineract Tenant identifier to be used by default, It must be aligned with the Fineract `tenants` table. Default value:
```
default
```
```
FINERACT_PLATFORM_TENANTS_IDENTIFIER
```
Fineract Tenant identifier list to be used, Those must be aligned with the Fineract `tenants` table.
Setting for Languages (i18n) still under development
```
MIFOS_DEFAULT_LANGUAGE=en-US
+4
View File
@@ -1,4 +1,5 @@
# Fineract URLs list delimited by colon
FINERACT_API_URLS=https://dev.mifos.io,https://demo.mifos.io,https://qa.mifos.io,https://staging.mifos.io,https://mobile.mifos.io,https://demo.fineract.dev,https://localhost:8443
FINERACT_API_URL=https://localhost:8443
@@ -9,6 +10,9 @@ FINERACT_API_VERSION=/v1
FINERACT_PLATFORM_TENANT_IDENTIFIER=default
# Tenant Identifiers list delimited by colon
FINERACT_PLATFORM_TENANTS_IDENTIFIER=default
MIFOS_DEFAULT_LANGUAGE=en-US
MIFOS_SUPPORTED_LANGUAGES=en-US,fr-FR
@@ -100,12 +100,12 @@ export class CreateClientComponent {
setDatatables(): void {
this.datatables = [];
let legalFormTypeVal = 'Person';
let legalFormTypeVal = 'person';
if (this.legalFormType === 2) {
legalFormTypeVal = 'Entity';
legalFormTypeVal = 'entity';
}
this.clientTemplate.datatables.forEach((datatable: any) => {
if (datatable.entitySubType === legalFormTypeVal) {
if (datatable.entitySubType.toLowerCase() === legalFormTypeVal) {
this.datatables.push(datatable);
}
});
@@ -5,10 +5,11 @@ import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/c
/** rxjs Imports */
import { Observable } from 'rxjs';
/** Environment Configuration */
/** Custom Imports */
import { environment } from '../../../environments/environment';
import { SettingsService } from 'app/settings/settings.service';
/** Http request options headers. */
/** Http request (default) options headers. */
const httpOptions = {
headers: {
'Fineract-Platform-TenantId': environment.fineractPlatformTenantId
@@ -26,12 +27,15 @@ const twoFactorAccessTokenHeader = 'Fineract-Platform-TFA-Token';
@Injectable()
export class AuthenticationInterceptor implements HttpInterceptor {
constructor() {}
constructor(private settingsService: SettingsService) {}
/**
* Intercepts a Http request and sets the request headers.
*/
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (this.settingsService.tenantIdentifier) {
httpOptions.headers['Fineract-Platform-TenantId'] = this.settingsService.tenantIdentifier;
}
request = request.clone({ setHeaders: httpOptions.headers });
return next.handle(request);
}
@@ -17,7 +17,7 @@
<img src="assets/images/user_placeholder.png" alt="app-user-photo">
</div>
<span class="app-user-name mb-05">
{{ username }}
{{ tenantIdentifier }} / {{ username }}
</span>
<div #userPanel class="app-user-controls">
<button class="xs-button" mat-icon-button matTooltip="{{ 'tooltips.Settings' | translate }}" [routerLink]="['/settings']">
@@ -14,6 +14,7 @@ import { ConfigurationWizardService } from '../../../configuration-wizard/config
/** Custom Imports */
import { frequentActivities } from './frequent-activities';
import { SettingsService } from 'app/settings/settings.service';
/**
* Sidenav component.
@@ -51,12 +52,14 @@ export class SidenavComponent implements OnInit, AfterViewInit {
* @param {Router} router Router for navigation.
* @param {MatDialog} dialog Mat Dialog
* @param {AuthenticationService} authenticationService Authentication Service.
* @param {SettingsService} settingsService Settings Service.
* @param {ConfigurationWizardService} configurationWizardService ConfigurationWizard Service.
* @param {PopoverService} popoverService PopoverService.
*/
constructor(private router: Router,
public dialog: MatDialog,
private authenticationService: AuthenticationService,
private settingsService: SettingsService,
private configurationWizardService: ConfigurationWizardService,
private popoverService: PopoverService) {
this.userActivity = JSON.parse(localStorage.getItem('mifosXLocation'));
@@ -207,4 +210,12 @@ export class SidenavComponent implements OnInit, AfterViewInit {
this.router.onSameUrlNavigation = 'reload';
this.router.navigate(['/home']);
}
get tenantIdentifier(): string {
if (!this.settingsService.tenantIdentifier || this.settingsService.tenantIdentifier === '') {
return 'default';
}
return this.settingsService.tenantIdentifier;
}
}
@@ -1,8 +1,8 @@
<form fxLayout="column" [formGroup]="loginForm" (ngSubmit)="login()" id="login-form">
<mat-form-field fxFlexAlign="center" class="login-input">
<span matPrefix>
<fa-icon icon="user-circle" size="lg"></fa-icon>&nbsp;&nbsp;
<span matPrefix class="m-r-10">
<fa-icon icon="user-circle" size="lg"></fa-icon>
</span>
<mat-label>{{ 'labels.inputs.Username' | translate }}</mat-label>
<input matInput type="text" autocomplete="off" formControlName="username">
@@ -12,8 +12,8 @@
</mat-form-field>
<mat-form-field fxFlexAlign="center" class="login-input">
<span matPrefix>
<fa-icon icon="lock" size="lg"></fa-icon>&nbsp;&nbsp;
<span matPrefix class="m-r-10">
<fa-icon icon="lock" size="lg"></fa-icon>
</span>
<mat-label>{{ 'labels.inputs.Password' | translate }}</mat-label>
<input matInput type="{{ passwordInputType }}" formControlName="password">
+5
View File
@@ -43,6 +43,11 @@
<img src="assets/images/mifos-logo-flat.png" alt="{{ 'APP_NAME' | translate }} Logo" class="img-container">
</div>
<!-- Tenant Identifier Name -->
<div fxLayout="row" fxLayoutAlign="center center" fxFlex="1 0 auto">
<mifosx-tenant-selector></mifosx-tenant-selector>
</div>
<!--
Type of Form:
Login
@@ -76,7 +76,7 @@ export class AllocateCashComponent implements OnInit {
const locale = this.settingsService.language.code;
const dateFormat = this.settingsService.dateFormat;
const txnDate = this.allocateCashForm.value.txnDate;
if (allocateCashFormData.closureDate instanceof Date) {
if (allocateCashFormData.txnDate instanceof Date) {
allocateCashFormData.txnDate = this.dateUtils.formatDate(txnDate, dateFormat);
}
const data = {
@@ -114,7 +114,7 @@
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" class="select-row" [routerLink]="[row.id]"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
+9 -1
View File
@@ -16,6 +16,14 @@
<div fxLayout="row wrap" class="content">
<div fxFlex="50%" class="header">
Tenant Id
</div>
<div fxFlex="50%">
{{ tenantIdentifier }}
</div>
<div fxFlex="50%" class="header">
User Id
</div>
@@ -81,4 +89,4 @@
</mat-card>
</div>
</div>
+9 -3
View File
@@ -8,6 +8,7 @@ import { Router } from '@angular/router';
import { AuthenticationService } from 'app/core/authentication/authentication.service';
import { ChangePasswordDialogComponent } from 'app/shared/change-password-dialog/change-password-dialog.component';
import { UserService } from 'app/self-service/users/user.service';
import { SettingsService } from 'app/settings/settings.service';
/**
* Profile Component.
@@ -36,9 +37,10 @@ export class ProfileComponent implements OnInit {
* @param {MatDialog} dialog Mat Dialog
*/
constructor(private authenticationService: AuthenticationService,
private userService: UserService,
private router: Router,
public dialog: MatDialog) {
private settingsService: SettingsService,
private userService: UserService,
private router: Router,
public dialog: MatDialog) {
this.profileData = authenticationService.getCredentials();
}
@@ -66,4 +68,8 @@ export class ProfileComponent implements OnInit {
});
}
get tenantIdentifier(): string {
return this.settingsService.tenantIdentifier || 'default';
}
}
+30
View File
@@ -63,6 +63,22 @@ export class SettingsService {
localStorage.setItem('mifosXServers', JSON.stringify(list));
}
/**
* Sets Tenant Identifiers list setting throughout the app.
* @param {string[]} list List of default tenants
*/
setTenantIdentifiers(list: string[]) {
localStorage.setItem('mifosXTenantIdentifiers', JSON.stringify(list));
}
/**
* Sets Tenant Identifier setting throughout the app.
* @param {string} Tenant Identifier
*/
setTenantIdentifier(tenantIdentifier: string) {
localStorage.setItem('mifosXTenantIdentifier', tenantIdentifier);
}
/**
* Sets server Date setting for max datepicker, default today
* @param {string} date
@@ -141,6 +157,20 @@ export class SettingsService {
return this.maxAllowedDate;
}
/**
* Returns list of Tenant Identifiers
*/
get tenantIdentifiers(): any {
return JSON.parse(localStorage.getItem('mifosXTenantIdentifiers'));
}
/**
* Returns Tenant Identifier
*/
get tenantIdentifier(): string {
return localStorage.getItem('mifosXTenantIdentifier');
}
/**
* Validate If the enable_business_date configuration is enabled or disabled.
*/
+5 -2
View File
@@ -21,6 +21,7 @@ import { NotificationsTrayComponent } from './notifications-tray/notifications-t
import { SearchToolComponent } from './search-tool/search-tool.component';
import { KeyboardShortcutsDialogComponent } from './keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component';
import { ServerSelectorComponent } from './server-selector/server-selector.component';
import { TenantSelectorComponent } from './tenant-selector/tenant-selector.component';
/** Custom Modules */
import { IconsModule } from './icons.module';
@@ -57,7 +58,8 @@ import { TranslateModule } from '@ngx-translate/core';
ErrorDialogComponent,
NotificationsTrayComponent,
SearchToolComponent,
ServerSelectorComponent
ServerSelectorComponent,
TenantSelectorComponent
],
exports: [
FileUploadComponent,
@@ -73,7 +75,8 @@ import { TranslateModule } from '@ngx-translate/core';
MaterialModule,
FormsModule,
ReactiveFormsModule,
TranslateModule
TranslateModule,
TenantSelectorComponent
]
})
export class SharedModule { }
@@ -0,0 +1,11 @@
<mat-form-field fxFlexAlign="center" id="tenant-selector">
<span matPrefix class="m-r-10">
<fa-icon icon="building" size="lg"></fa-icon>
</span>
<mat-label>{{ 'labels.inputs.Tenant' | translate }}</mat-label>
<mat-select [disabled]="!allowSelection()" [formControl]="tenantSelector" (selectionChange)="setTenantIdentifier()" class="tenantselector">
<mat-option *ngFor="let tenant of tenants" [value]="tenant">
{{ tenant }}
</mat-option>
</mat-select>
</mat-form-field>
@@ -0,0 +1,5 @@
#tenant-selector,
.tenantselector {
width: 14rem;
margin-bottom: 0.6rem;
}
@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TenantSelectorComponent } from './tenant-selector.component';
describe('TenantSelectorComponent', () => {
let component: TenantSelectorComponent;
let fixture: ComponentFixture<TenantSelectorComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ TenantSelectorComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(TenantSelectorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,42 @@
import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { SettingsService } from 'app/settings/settings.service';
@Component({
selector: 'mifosx-tenant-selector',
templateUrl: './tenant-selector.component.html',
styleUrls: ['./tenant-selector.component.scss']
})
export class TenantSelectorComponent implements OnInit {
/** Tenant selector form control. */
tenantSelector = new FormControl();
/**
* Sets the Tenant Identifier of the application in the selector on initial setup.
* @param {SettingsService} settingsService Settings Service.
*/
constructor(private settingsService: SettingsService) {
this.tenantSelector.setValue(this.settingsService.tenantIdentifier);
}
ngOnInit(): void {
}
/**
* Returns all the languages supported by the application.
* @return {string[]} Supported languages.
*/
get tenants(): string[] {
return this.settingsService.tenantIdentifiers || [];
}
setTenantIdentifier(): void {
this.settingsService.setTenantIdentifier(this.tenantSelector.value);
}
allowSelection(): boolean {
return (this.tenants.length > 1);
}
}
+3
View File
@@ -150,6 +150,9 @@ export class WebAppComponent implements OnInit {
this.settingsService.setBusinessDate(this.dateUtils.formatDate(new Date(), SettingsService.businessDateFormat));
// Set the server list from the env var FINERACT_API_URLS
this.settingsService.setServers(environment.baseApiUrls.split(','));
// Set the Tenant Identifier(s) list from the env var
this.settingsService.setTenantIdentifier(environment.fineractPlatformTenantId || 'default');
this.settingsService.setTenantIdentifiers(environment.fineractPlatformTenantIds.split(','));
}
logout() {
+1
View File
@@ -9,6 +9,7 @@
window["env"]["apiVersion"] = '$FINERACT_API_VERSION';
window["env"]["fineractPlatformTenantId"] = '$FINERACT_PLATFORM_TENANT_IDENTIFIER';
window["env"]["fineractPlatformTenantIds"] = '$FINERACT_PLATFORM_TENANTS_IDENTIFIER';
// Language Environment variables
window["env"]["defaultLanguage"] = '$MIFOS_DEFAULT_LANGUAGE';
+1
View File
@@ -23,6 +23,7 @@
"is required": "is required"
},
"inputs": {
"Tenant": "Tenant",
"Language": "Language",
"Server": "Server",
"Url": "Url",
+1
View File
@@ -23,6 +23,7 @@
"is required": "es requerido"
},
"inputs": {
"Tenant": "Entidad",
"Language": "Lenguaje",
"Server": "Servidor",
"Url": "Url",
+1
View File
@@ -23,6 +23,7 @@
"is required": "is required"
},
"inputs": {
"Tenant": "Tenant",
"Language": "Language",
"Server": "Server",
"Url": "Url",
+1
View File
@@ -7,6 +7,7 @@ export const environment = {
hash: env.mifos_x.hash,
// For connecting to server running elsewhere update the tenant identifier
fineractPlatformTenantId: window['env']['fineractPlatformTenantId'] || 'default',
fineractPlatformTenantIds: window['env']['fineractPlatformTenantIds'] || 'default',
// For connecting to others servers running elsewhere update the base API URL
baseApiUrls: window['env']['fineractApiUrls'] ||
'https://dev.mifos.io,https://demo.mifos.io,https://qa.mifos.io,https://staging.mifos.io,https://mobile.mifos.io,https://demo.fineract.dev,https://localhost:8443',
+1
View File
@@ -12,6 +12,7 @@ export const environment = {
hash: env.mifos_x.hash,
// For connecting to server running elsewhere update the tenant identifier
fineractPlatformTenantId: window['env']['fineractPlatformTenantId'] || 'default',
fineractPlatformTenantIds: window['env']['fineractPlatformTenantIds'] || 'default',
// For connecting to others servers running elsewhere update the base API URL
baseApiUrls: window['env']['fineractApiUrls'] ||
'https://dev.mifos.io,https://demo.mifos.io,https://qa.mifos.io,https://staging.mifos.io,https://mobile.mifos.io,https://demo.fineract.dev,https://localhost:8443',