diff --git a/src/app/account-transfers/list-standing-instructions/list-standing-instructions.component.ts b/src/app/account-transfers/list-standing-instructions/list-standing-instructions.component.ts index b0e4f0aff..ae476ad0b 100644 --- a/src/app/account-transfers/list-standing-instructions/list-standing-instructions.component.ts +++ b/src/app/account-transfers/list-standing-instructions/list-standing-instructions.component.ts @@ -68,7 +68,6 @@ export class ListStandingInstructionsComponent implements OnInit { this.standingIntructionsTemplateData = data.standingIntructionsTemplate; if (data.standingIntructionsTemplate.fromClient) { this.clientName = this.standingIntructionsTemplateData.fromClient.displayName; - console.log('here'); this.getStandingInstructions(); } this.setParams(); diff --git a/src/app/core/shell/sidenav/sidenav.component.html b/src/app/core/shell/sidenav/sidenav.component.html index 098736766..4464ae862 100644 --- a/src/app/core/shell/sidenav/sidenav.component.html +++ b/src/app/core/shell/sidenav/sidenav.component.html @@ -97,6 +97,12 @@ Chart of Accounts + + + + + Help + diff --git a/src/app/core/shell/sidenav/sidenav.component.ts b/src/app/core/shell/sidenav/sidenav.component.ts index 917ac279f..3f55f0ae0 100644 --- a/src/app/core/shell/sidenav/sidenav.component.ts +++ b/src/app/core/shell/sidenav/sidenav.component.ts @@ -43,4 +43,8 @@ export class SidenavComponent implements OnInit { .subscribe(() => this.router.navigate(['/login'], { replaceUrl: true })); } + help() { + window.open('https://mifosforge.jira.com/wiki/spaces/docs/pages/52035622/User+Manual', '_blank'); + } + } diff --git a/src/app/core/shell/toolbar/toolbar.component.html b/src/app/core/shell/toolbar/toolbar.component.html index 39e584f33..f947bf1ad 100644 --- a/src/app/core/shell/toolbar/toolbar.component.html +++ b/src/app/core/shell/toolbar/toolbar.component.html @@ -49,6 +49,10 @@ + + + + @@ -100,7 +104,7 @@ Settings - + diff --git a/src/app/core/shell/toolbar/toolbar.component.ts b/src/app/core/shell/toolbar/toolbar.component.ts index 5f5266716..3d164d5c4 100644 --- a/src/app/core/shell/toolbar/toolbar.component.ts +++ b/src/app/core/shell/toolbar/toolbar.component.ts @@ -1,6 +1,6 @@ /** Angular Imports */ import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core'; -import { MatSidenav } from '@angular/material'; +import { MatSidenav, MatDialog } from '@angular/material'; import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; import { Router } from '@angular/router'; @@ -10,6 +10,7 @@ import { map } from 'rxjs/operators'; /** Custom Services */ import { AuthenticationService } from '../../authentication/authentication.service'; +import { KeyboardShortcutsDialogComponent } from 'app/shared/keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component'; /** * Toolbar component. @@ -42,7 +43,8 @@ export class ToolbarComponent implements OnInit { */ constructor(private breakpointObserver: BreakpointObserver, private router: Router, - private authenticationService: AuthenticationService) { } + private authenticationService: AuthenticationService, + private dialog: MatDialog) { } /** * Subscribes to breakpoint for handset. @@ -78,4 +80,9 @@ export class ToolbarComponent implements OnInit { .subscribe(() => this.router.navigate(['/login'], { replaceUrl: true })); } + showKeyboardShortcuts() { + const dialogRef = this.dialog.open(KeyboardShortcutsDialogComponent); + dialogRef.afterClosed().subscribe((response: any) => {}); + } + } diff --git a/src/app/keyboards-shortcut-config.ts b/src/app/keyboards-shortcut-config.ts new file mode 100644 index 000000000..98355d9f4 --- /dev/null +++ b/src/app/keyboards-shortcut-config.ts @@ -0,0 +1,203 @@ +/** Keyboard Shortcuts Button Configuration */ +export class KeyboardShortcutsConfiguration { + + buttonsArray: { + title: string, + ctrlKey: boolean, + shiftKey: boolean, + altKey: boolean, + key: string, + route: string, + id?: string + }[]; + + constructor() { + this.makeCombination(); + } + + makeCombination() { + this.buttonsArray = [ + // Navigation Page - alt + n + { + title: 'Navigation Page', + ctrlKey: false, + shiftKey: false, + altKey: true, + key: 'n', + route: 'navigation' + }, + // Run Report - alt + r + { + title: 'Run Report', + ctrlKey: false, + shiftKey: false, + altKey: true, + key: 'r', + route: '', + id: 'runReport' + }, + // Checker Inbox & Pending Tasks - ctrl + alt + i + // { + // title: 'Checker Inbox & Pending Tasks', + // ctrlKey: true, + // shiftKey: false, + // altKey: true, + // key: 'i, + // route: '' + // }, + // Collection Sheet- ctrl + alt + o + // { + // title: 'Collection Sheet', + // ctrlKey: true, + // shiftKey: false, + // altKey: true, + // key: 'o, + // route: '' + // }, + // Create Client - ctrl + alt + c + { + title: 'Create Client', + ctrlKey: true, + shiftKey: false, + altKey: true, + key: 'c', + route: 'clients/create' + }, + // Create Group - ctrl + alt + g + { + title: 'Create Group', + ctrlKey: true, + shiftKey: false, + altKey: true, + key: 'g', + route: 'groups/create' + }, + // Create Center - ctrl + alt + q + { + title: 'Create Center', + ctrlKey: true, + shiftKey: false, + altKey: true, + key: 'q', + route: 'centers/create' + }, + // Frequent Posting - ctrl + alt + f + { + title: 'Frequent Posting', + ctrlKey: true, + shiftKey: false, + altKey: true, + key: 'f', + route: 'accounting/journal-entries/frequent-postings' + }, + // Closure Entries - ctrl + alt + e + { + title: 'Closure Entries', + ctrlKey: true, + shiftKey: false, + altKey: true, + key: 'e', + route: 'accounting/closing-entries' + }, + // Journal Entry - ctrl + alt + j + { + title: 'Journal Entry', + ctrlKey: true, + shiftKey: false, + altKey: true, + key: 'j', + route: 'accounting/journal-entries/create' + }, + // Reports - ctrl + alt + r + { + title: 'Reports', + ctrlKey: true, + shiftKey: false, + altKey: true, + key: 'r', + route: 'reports' + }, + // Accounting - ctrl + alt + a + { + title: 'Accounting', + ctrlKey: true, + shiftKey: false, + altKey: true, + key: 'a', + route: 'accounting' + }, + // Save/Submit Forms - ctrl + alt + s + { + title: 'Save/Submit Forms', + ctrlKey: true, + shiftKey: false, + altKey: true, + key: 's', + route: '', + id: 'submit' + }, + // Cancel - ctrl + alt + x + { + title: 'Cancel', + ctrlKey: true, + shiftKey: false, + altKey: true, + key: 'x', + route: '', + id: 'cancel' + }, + // Search - alt + x + // { + // title: 'Search' + // ctrlKey: true, + // shiftKey: false, + // altKey: true, + // key: 88, + // route: '' + // }, + // Help - ctrl + alt + h + { + title: 'Help', + ctrlKey: true, + shiftKey: false, + altKey: true, + key: 'h', + route: '', + id: 'help' + }, + // Pagination: Next - ctrl + n + // { + // title: 'Pagination: Next' + // ctrlKey: true, + // shiftKey: false, + // altKey: true, + // key: 'n, + // route: '' + // }, + // Pagination: Previous - ctrl + p + // { + // title: 'Pagination: Previous' + // ctrlKey: true, + // shiftKey: false, + // altKey: true, + // key: 'p, + // route: '' + // }, + // Logout - ctrl + shift + l + { + title: 'Logout', + ctrlKey: true, + shiftKey: true, + altKey: false, + key: 'l', + route: '', + id: 'logout' + } + ]; + } + + get buttonCombinations() { + return this.buttonsArray; + } + +} diff --git a/src/app/reports/run-report/run-report.component.html b/src/app/reports/run-report/run-report.component.html index 27fa3ed18..c8d8f433a 100644 --- a/src/app/reports/run-report/run-report.component.html +++ b/src/app/reports/run-report/run-report.component.html @@ -80,7 +80,7 @@ Cancel - + Run Report diff --git a/src/app/reports/xbrl-report/xbrl-report.component.html b/src/app/reports/xbrl-report/xbrl-report.component.html index e59125996..e58b3a1e6 100644 --- a/src/app/reports/xbrl-report/xbrl-report.component.html +++ b/src/app/reports/xbrl-report/xbrl-report.component.html @@ -24,7 +24,7 @@ Cancel - Run Report + Run Report diff --git a/src/app/shared/keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component.html b/src/app/shared/keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component.html new file mode 100644 index 000000000..238a57038 --- /dev/null +++ b/src/app/shared/keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component.html @@ -0,0 +1,18 @@ +Keyboard Shortcuts + + + + + + + Ctrl + + Shift + + Alt + + {{ item.key }} + + {{ item.title }} + + + + + diff --git a/src/app/shared/keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component.scss b/src/app/shared/keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component.scss new file mode 100644 index 000000000..a45d113be --- /dev/null +++ b/src/app/shared/keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component.scss @@ -0,0 +1,11 @@ +.modifierKey { + border: 1px solid #0000004d; + padding: 0.3rem; + background: #f8f8f8; + font-weight: bold; + border-radius: 0.3rem; +} + +.mat-divider.mat-divider-inset { + margin-left: 0px; +} diff --git a/src/app/shared/keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component.spec.ts b/src/app/shared/keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component.spec.ts new file mode 100644 index 000000000..d5fbea511 --- /dev/null +++ b/src/app/shared/keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { KeyboardShortcutsDialogComponent } from './keyboard-shortcuts-dialog.component'; + +describe('KeyboardShortcutsDialogComponent', () => { + let component: KeyboardShortcutsDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ KeyboardShortcutsDialogComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(KeyboardShortcutsDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component.ts b/src/app/shared/keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component.ts new file mode 100644 index 000000000..f3bd2a90b --- /dev/null +++ b/src/app/shared/keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component.ts @@ -0,0 +1,28 @@ +/** Angular Imports */ +import { Component, OnInit, Inject } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; +import { KeyboardShortcutsConfiguration } from '../../keyboards-shortcut-config'; +/** + * Delete dialog component. + */ +@Component({ + selector: 'mifosx-keyboard-shortcuts-dialog', + templateUrl: './keyboard-shortcuts-dialog.component.html', + styleUrls: ['./keyboard-shortcuts-dialog.component.scss'] +}) +export class KeyboardShortcutsDialogComponent implements OnInit { + + buttonConfig: KeyboardShortcutsConfiguration; + + /** + * @param {MatDialogRef} dialogRef Component reference to dialog. + * @param {any} data Provides a deleteContext. + */ + constructor(public dialogRef: MatDialogRef) { } + + ngOnInit() { + this.dialogRef.updateSize(`800px`); + this.buttonConfig = new KeyboardShortcutsConfiguration(); + } + +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 9ad6b1d6f..2e23e0cbb 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -15,6 +15,7 @@ import { ChangePasswordDialogComponent } from './change-password-dialog/change-p import { EnableDialogComponent } from './enable-dialog/enable-dialog.component'; import { DisableDialogComponent } from './disable-dialog/disable-dialog.component'; import { ConfirmationDialogComponent } from './confirmation-dialog/confirmation-dialog.component'; +import { KeyboardShortcutsDialogComponent } from './keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component'; /** Custom Modules */ import { IconsModule } from './icons.module'; @@ -43,7 +44,8 @@ import { MaterialModule } from './material.module'; ChangePasswordDialogComponent, EnableDialogComponent, DisableDialogComponent, - ConfirmationDialogComponent + ConfirmationDialogComponent, + KeyboardShortcutsDialogComponent ], exports: [ FileUploadComponent, @@ -62,7 +64,8 @@ import { MaterialModule } from './material.module'; ChangePasswordDialogComponent, EnableDialogComponent, DisableDialogComponent, - ConfirmationDialogComponent + ConfirmationDialogComponent, + KeyboardShortcutsDialogComponent ] }) export class SharedModule { } diff --git a/src/app/web-app.component.ts b/src/app/web-app.component.ts index 9c98cdbf6..c86333ce7 100644 --- a/src/app/web-app.component.ts +++ b/src/app/web-app.component.ts @@ -1,5 +1,5 @@ /** Angular Imports */ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, HostListener } from '@angular/core'; import { Router, NavigationEnd, ActivatedRoute } from '@angular/router'; import { Title } from '@angular/platform-browser'; import { MatSnackBar } from '@angular/material'; @@ -19,9 +19,11 @@ import { Logger } from './core/logger/logger.service'; import { I18nService } from './core/i18n/i18n.service'; import { ThemeStorageService } from './shared/theme-picker/theme-storage.service'; import { AlertService } from './core/alert/alert.service'; +import { KeyboardShortcutsConfiguration } from './keyboards-shortcut-config'; /** Custom Models */ import { Alert } from './core/alert/alert.model'; +import { AuthenticationService } from './core/authentication/authentication.service'; /** Initialize Logger */ const log = new Logger('MifosX'); @@ -36,6 +38,8 @@ const log = new Logger('MifosX'); }) export class WebAppComponent implements OnInit { + buttonConfig: KeyboardShortcutsConfiguration; + /** * @param {Router} router Router for navigation. * @param {ActivatedRoute} activatedRoute Activated Route. @@ -45,6 +49,7 @@ export class WebAppComponent implements OnInit { * @param {ThemeStorageService} themeStorageService Theme Storage Service. * @param {MatSnackBar} snackBar Material Snackbar for notifications. * @param {AlertService} alertService Alert Service. + * @param {AuthenticationService} authenticationService Authentication service. */ constructor(private router: Router, private activatedRoute: ActivatedRoute, @@ -53,7 +58,8 @@ export class WebAppComponent implements OnInit { private i18nService: I18nService, private themeStorageService: ThemeStorageService, public snackBar: MatSnackBar, - private alertService: AlertService) { } + private alertService: AlertService, + private authenticationService: AuthenticationService) { } /** * Initial Setup: @@ -126,6 +132,55 @@ export class WebAppComponent implements OnInit { verticalPosition: 'top' }); }); + this.buttonConfig = new KeyboardShortcutsConfiguration(); + } + + logout() { + this.authenticationService.logout() + .subscribe(() => this.router.navigate(['/login'], { replaceUrl: true })); + } + + help() { + window.open('https://mifosforge.jira.com/wiki/spaces/docs/pages/52035622/User+Manual', '_blank'); + } + + // Monitor all keyboard events and excute keyboard shortcuts + @HostListener('window:keydown', ['$event']) + onKeydownHandler(event: KeyboardEvent) { + const routeD = this.buttonConfig.buttonCombinations.find(x => (x.ctrlKey === event.ctrlKey && x.shiftKey === event.shiftKey && x.altKey === event.altKey && x.key === event.key)); + if (!(routeD === undefined)) { + switch (routeD.id) { + case 'logout': + this.logout(); + break; + case 'help': + this.help(); + break; + case 'runReport': + document.getElementById('runReport').click(); + break; + case 'cancel': + const cancelButtons = document.querySelectorAll('button'); + const filteredcancelButtons = Array.prototype.filter.call(cancelButtons, function (el: any) { + return el.textContent.trim() === 'Cancel'; + }); + if (filteredcancelButtons.length > 0) { + filteredcancelButtons[0].click(); + } + break; + case 'submit': + const submitButton = document.querySelectorAll('button'); + const filteredSubmitButton = Array.prototype.filter.call(submitButton, function (el: any) { + return el.textContent.trim() === 'Submit'; + }); + if (filteredSubmitButton.length > 0) { + filteredSubmitButton[0].click(); + } + break; + default: + this.router.navigate([routeD.route], { relativeTo: this.activatedRoute }); + } + } } } diff --git a/src/assets/images/keyboard_placeholder.png b/src/assets/images/keyboard_placeholder.png new file mode 100644 index 000000000..8570ba12f Binary files /dev/null and b/src/assets/images/keyboard_placeholder.png differ