feat: create, view, edit, delete for reports

- Add manage-reports
- Add view-report
- Add create-report
- Add edit-report

#174
This commit is contained in:
Chirag
2019-11-28 18:13:35 +05:30
committed by Jivjyot Singh
parent a7affa17cd
commit bab75357b4
27 changed files with 1405 additions and 3 deletions
@@ -0,0 +1,134 @@
<div class="container">
<mat-card>
<form [formGroup]="reportForm" (ngSubmit)="submit()">
<mat-card-content>
<div fxLayout="row wrap" fxLayout.lt-md="column" fxLayoutGap="4%">
<mat-form-field fxFlex="30%">
<mat-label>Report Name</mat-label>
<input matInput required formControlName="reportName">
<mat-error *ngIf="reportForm.controls.reportName.hasError('required')">
Report Name is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="30%">
<mat-label>Report Type</mat-label>
<mat-select required formControlName="reportType">
<mat-option *ngFor="let allowedReportType of reportTemplateData.allowedReportTypes"
[value]="allowedReportType">
{{ allowedReportType }}
</mat-option>
</mat-select>
<mat-error *ngIf="reportForm.controls.reportType.hasError('required')">
Report Type is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="30%">
<mat-label>Report Sub Type</mat-label>
<mat-select formControlName="reportSubType">
<mat-option *ngFor="let allowedReportSubType of reportTemplateData.allowedReportSubTypes"
[value]="allowedReportSubType">
{{ allowedReportSubType }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div fxLayout="row wrap" fxLayout.lt-md="column" fxLayoutGap="4%">
<mat-form-field fxFlex="40%">
<mat-label>Report Category</mat-label>
<input matInput formControlName="reportCategory">
</mat-form-field>
<div fxFlex="10%" class="user-report-wrapper">
<mat-checkbox class="user-report" labelPosition="before" formControlName="useReport">
User Report (UI)
</mat-checkbox>
</div>
</div>
<div fxLayout="column">
<mat-form-field fxFlex="98%">
<mat-label>Description</mat-label>
<textarea matInput formControlName="description"></textarea>
</mat-form-field>
<mat-form-field fxFlex="98%">
<mat-label>SQL</mat-label>
<textarea matInput required formControlName="reportSql"></textarea>
<mat-error *ngIf="reportForm.controls.reportSql.hasError('required')">
SQL is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
<br>
<div fxLayout="row wrap" fxLayoutGap="60%" fxLayout.lt-md="column">
<p fxFlex="20%" class="mat-title">Report Parameters</p>
<button mat-raised-button fxFlex="20%" type="button" color="primary" (click)="addReportParameter()">
<fa-icon icon="plus"></fa-icon>&nbsp;&nbsp;
Add Report Parameter
</button>
</div>
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="parameterName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Parameter </th>
<td mat-cell *matCellDef="let reportParameter"> {{ reportParameter.parameterName }} </td>
</ng-container>
<ng-container matColumnDef="parameterNamePassed">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Parameter Name Passed to Pentaho </th>
<td mat-cell *matCellDef="let reportParameter"> {{ reportParameter.reportParameterName }} </td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let reportParameter" fxLayoutGap="15%">
<button type="button" fxFlex="8%" color="primary" mat-icon-button
(click)="editReportParameter(reportParameter)">
<fa-icon icon="edit" size="lg"></fa-icon>
</button>
<button type="button" fxFlex="8%" color="warn" mat-icon-button
(click)="deleteReportParameter(reportParameter)">
<fa-icon icon="trash" size="lg"></fa-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[10, 25, 50, 100]" showFirstLastButtons></mat-paginator>
</mat-card-content>
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
<button mat-raised-button type="submit" color="primary"
[disabled]="!reportForm.valid && reportParametersData.length === 0">Submit</button>
</mat-card-actions>
</form>
</mat-card>
</div>
@@ -0,0 +1,17 @@
@media (min-width: 992px) {
.user-report-wrapper {
position: relative;
.user-report {
padding: 0 0 17.5px 0;
position: absolute;
bottom: 0;
}
}
}
table {
width: 100%;
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CreateReportComponent } from './create-report.component';
describe('CreateReportComponent', () => {
let component: CreateReportComponent;
let fixture: ComponentFixture<CreateReportComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CreateReportComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CreateReportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,193 @@
/** Angular Imports */
import { Component, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators, FormArray } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { MatTableDataSource, MatPaginator, MatSort, MatDialog } from '@angular/material';
/** Custom Services */
import { SystemService } from 'app/system/system.service';
/** Custom Components */
import { ReportParameterDialogComponent } from '../report-parameter-dialog/report-parameter-dialog.component';
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
/**
* Create Report Component.
*/
@Component({
selector: 'mifosx-create-report',
templateUrl: './create-report.component.html',
styleUrls: ['./create-report.component.scss']
})
export class CreateReportComponent implements OnInit {
/** Report Form. */
reportForm: FormGroup;
/** Report Template Data. */
reportTemplateData: any;
/** Data passed to dialog. */
dataForDialog: { allowedParameters: any[], parameterName: string, reportParameterName: string } =
{
allowedParameters: undefined,
parameterName: undefined,
reportParameterName: undefined
};
/** Columns to be displayed in report parameters table. */
displayedColumns: string[] = ['parameterName', 'parameterNamePassed', 'actions'];
/** Data source for report parameters table. */
dataSource: MatTableDataSource<any>;
/** Report Parameters Data. */
reportParametersData: any[] = [];
/** Paginator for report parameters table. */
@ViewChild(MatPaginator) paginator: MatPaginator;
/** Sorter for report parameters table. */
@ViewChild(MatSort) sort: MatSort;
/**
* Retrieves the report template data from `resolve`.
* @param {FormBuilder} formBuilder Form Builder.
* @param {SystemService} systemService System Service.
* @param {ActivatedRoute} route Activated Route.
* @param {Router} router Router for navigation.
* @param {MatDialog} dialog Dialog Reference.
*/
constructor(private formBuilder: FormBuilder,
private systemService: SystemService,
private route: ActivatedRoute,
private router: Router,
private dialog: MatDialog) {
this.route.data.subscribe((data: { reportTemplate: any }) => {
this.reportTemplateData = data.reportTemplate;
this.dataForDialog.allowedParameters = this.reportTemplateData.allowedParameters;
});
}
/**
* Creates the report form.
*/
ngOnInit() {
this.createReportForm();
this.toggleVisibility();
this.setReportParameters();
}
/**
* Initializes the data source, paginator and sorter for report parameters table.
*/
setReportParameters() {
this.dataSource = new MatTableDataSource(this.reportParametersData);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
/**
* Creates the report form.
*/
createReportForm() {
this.reportForm = this.formBuilder.group({
'reportName': ['', Validators.required],
'reportCategory': [''],
'description': [''],
'reportType': ['', Validators.required],
'reportSubType': [{ value: '', disabled: true }],
'useReport': [false],
'reportSql': ['', Validators.required]
});
}
/**
* Adds a new report parameter.
*/
addReportParameter() {
this.dataForDialog.parameterName = undefined;
this.dataForDialog.reportParameterName = undefined;
const addReportParameterDialogRef = this.dialog.open(ReportParameterDialogComponent, {
data: this.dataForDialog
});
addReportParameterDialogRef.afterClosed().subscribe((response: any) => {
if (response !== '') {
this.reportParametersData.push({ id: '',
parameterName: this.reportTemplateData.allowedParameters.find((allowedParameter: any) => allowedParameter.id === response.parameterName).parameterName,
parameterId: response.parameterName,
reportParameterName: response.reportParameterName });
this.dataSource.connect().next(this.reportParametersData);
}
});
}
/**
* Edits report parameter.
* @param {any} reportParameter Report Parameter.
*/
editReportParameter(reportParameter: any) {
this.dataForDialog.parameterName = reportParameter.parameterId;
this.dataForDialog.reportParameterName = reportParameter.reportParameterName;
const editReportParameterDialogRef = this.dialog.open(ReportParameterDialogComponent, {
data: this.dataForDialog
});
editReportParameterDialogRef.afterClosed().subscribe((response: any) => {
if (response !== '') {
this.reportParametersData[this.reportParametersData.indexOf(reportParameter)] = { id: '',
parameterName: this.reportTemplateData.allowedParameters.find((allowedParameter: any) => allowedParameter.id === response.parameterName).parameterName,
parameterId: response.parameterName,
reportParameterName: response.reportParameterName };
this.dataSource.connect().next(this.reportParametersData);
}
});
}
/**
* Deletes the report parameter.
* @param {any} reportParameter Report Parameter.
*/
deleteReportParameter(reportParameter: any) {
const deleteReportDialogRef = this.dialog.open(DeleteDialogComponent, {
data: { deleteContext: `report parameter ${reportParameter.parameterName}` }
});
deleteReportDialogRef.afterClosed().subscribe((response: any) => {
if (response.delete) {
this.reportParametersData.splice(this.reportParametersData.indexOf(reportParameter), 1);
this.dataSource.connect().next(this.reportParametersData);
}
});
}
/**
* Toggles the visibility status of Report Sub Type dropdown.
*/
toggleVisibility() {
this.reportForm.get('reportType').valueChanges
.subscribe(type => {
switch (type) {
case 'Chart':
this.reportForm.get('reportSubType').enable();
this.reportForm.get('reportSql').enable();
break;
case 'Pentaho':
this.reportForm.get('reportSql').disable();
this.reportForm.get('reportSubType').disable();
break;
default:
this.reportForm.get('reportSql').enable();
this.reportForm.get('reportSubType').disable();
}
});
}
/**
* Submits the report form and creates report,
* if successful redirects to view created report.
*/
submit() {
this.reportForm.value.reportParameters = this.reportParametersData.map( function(reportParameter: any) {
reportParameter.parameterName = undefined;
return reportParameter;
});
this.systemService.createReport(this.reportForm.value)
.subscribe((response: any) => {
// TODO: Implement Maker Checker Component.
this.router.navigate(['../', response.resourceId], { relativeTo: this.route });
});
}
}
@@ -0,0 +1,134 @@
<div class="container">
<mat-card>
<form [formGroup]="reportForm" (ngSubmit)="submit()">
<mat-card-content>
<div fxLayout="row wrap" fxLayout.lt-md="column" fxLayoutGap="4%">
<mat-form-field fxFlex="30%">
<mat-label>Report Name</mat-label>
<input matInput required formControlName="reportName">
<mat-error *ngIf="reportForm.controls.reportName.hasError('required')">
Report Name is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="30%">
<mat-label>Report Type</mat-label>
<mat-select required formControlName="reportType">
<mat-option *ngFor="let allowedReportType of reportData.allowedReportTypes" [value]="allowedReportType">
{{ allowedReportType }}
</mat-option>
</mat-select>
<mat-error *ngIf="reportForm.controls.reportType.hasError('required')">
Report Type is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="30%">
<mat-label>Report Sub Type</mat-label>
<mat-select formControlName="reportSubType">
<mat-option *ngFor="let allowedReportSubType of reportData.allowedReportSubTypes"
[value]="allowedReportSubType">
{{ allowedReportSubType }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div fxLayout="row wrap" fxLayout.lt-md="column" fxLayoutGap="4%">
<mat-form-field fxFlex="40%">
<mat-label>Report Category</mat-label>
<input matInput formControlName="reportCategory">
</mat-form-field>
<div fxFlex="10%" class="user-report-wrapper">
<mat-checkbox class="user-report" labelPosition="before" formControlName="useReport">
User Report (UI)
</mat-checkbox>
</div>
</div>
<div fxLayout="column">
<mat-form-field fxFlex="98%">
<mat-label>Description</mat-label>
<textarea matInput formControlName="description"></textarea>
</mat-form-field>
<mat-form-field fxFlex="98%">
<mat-label>SQL</mat-label>
<textarea matInput required formControlName="reportSql"></textarea>
<mat-error *ngIf="reportForm.controls.reportSql.hasError('required')">
SQL is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
<br>
<div fxLayout="row wrap" fxLayoutGap="60%" fxLayout.lt-md="column">
<p fxFlex="20%" class="mat-title">Report Parameters</p>
<button mat-raised-button fxFlex="20%" type="button" *ngIf="!reportData.coreReport" color="primary"
(click)="addReportParameter()">
<fa-icon icon="plus"></fa-icon>&nbsp;&nbsp;
Add Report Parameter
</button>
</div>
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="parameterName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Parameter </th>
<td mat-cell *matCellDef="let reportParameter"> {{ reportParameter.parameterName }} </td>
</ng-container>
<ng-container matColumnDef="parameterNamePassed">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Parameter Name Passed to Pentaho </th>
<td mat-cell *matCellDef="let reportParameter"> {{ reportParameter.reportParameterName }} </td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let reportParameter" fxLayoutGap="15%">
<button *ngIf="!reportData.coreReport" type="button" fxFlex="8%" color="primary" mat-icon-button
(click)="editReportParameter(reportParameter)">
<fa-icon icon="edit" size="lg"></fa-icon>
</button>
<button *ngIf="!reportData.coreReport" type="button" fxFlex="8%" color="warn" mat-icon-button
(click)="deleteReportParameter(reportParameter)">
<fa-icon icon="trash" size="lg"></fa-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[10, 25, 50, 100]" showFirstLastButtons></mat-paginator>
</mat-card-content>
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
<button mat-raised-button color="primary"
[disabled]="(!reportForm.valid || reportForm.pristine) && !isReportParametersChanged">Submit</button>
</mat-card-actions>
</form>
</mat-card>
</div>
@@ -0,0 +1,17 @@
@media (min-width: 992px) {
.user-report-wrapper {
position: relative;
.user-report {
padding: 0 0 17.5px 0;
position: absolute;
bottom: 0;
}
}
}
table {
width: 100%;
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { EditReportComponent } from './edit-report.component';
describe('EditReportComponent', () => {
let component: EditReportComponent;
let fixture: ComponentFixture<EditReportComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ EditReportComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(EditReportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,208 @@
/** Angular Imports */
import { Component, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { MatTableDataSource, MatPaginator, MatSort, MatDialog } from '@angular/material';
/** Custom Services */
import { SystemService } from 'app/system/system.service';
/** Custom Components */
import { ReportParameterDialogComponent } from '../report-parameter-dialog/report-parameter-dialog.component';
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
/**
* Edit Report Component.
*/
@Component({
selector: 'mifosx-edit-report',
templateUrl: './edit-report.component.html',
styleUrls: ['./edit-report.component.scss']
})
export class EditReportComponent implements OnInit {
/** Report Data. */
reportData: any;
/** Report Template Data. */
reportTemplateData: any;
/** Report Parameters Data. */
reportParametersData: any[] = [];
/** Data passed to dialog. */
dataForDialog: { allowedParameters: any[], parameterName: string, reportParameterName: string } =
{
allowedParameters: undefined,
parameterName: undefined,
reportParameterName: undefined
};
/** Report Form. */
reportForm: FormGroup;
/** Columns to be displayed in report parameters table. */
displayedColumns: string[] = ['parameterName', 'parameterNamePassed', 'actions'];
/** Data source for report parameters table. */
dataSource: MatTableDataSource<any>;
/** Boolean to check if report parameters data is changed or not. */
isReportParametersChanged: Boolean = false;
/** Paginator for report parameters table. */
@ViewChild(MatPaginator) paginator: MatPaginator;
/** Sorter for report parameters table. */
@ViewChild(MatSort) sort: MatSort;
/**
* Retrieves the report and report template data from `resolve`.
* @param {FormBuilder} formBuilder Form Builder.
* @param {SystemService} systemService System Service.
* @param {ActivatedRoute} route Activated Route.
* @param {Router} router Router for navigation.
* @param {MatDialog} dialog Dialog Reference.
*/
constructor(private formBuilder: FormBuilder,
private route: ActivatedRoute,
private router: Router,
private systemService: SystemService,
private dialog: MatDialog) {
this.route.data.subscribe((data: { report: any, reportTemplate: any }) => {
this.reportData = data.report;
this.reportParametersData = data.report.reportParameters ? data.report.reportParameters : [];
this.reportTemplateData = data.reportTemplate;
this.dataForDialog.allowedParameters = this.reportData.allowedParameters;
});
}
/**
* Creates the report form.
*/
ngOnInit() {
this.createReportForm();
this.setReportParameters();
this.toggleVisibility();
}
/**
* Initializes the data source, paginator and sorter for report parameters table.
*/
setReportParameters() {
this.dataSource = new MatTableDataSource(this.reportParametersData);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
/**
* Creates and sets the report form.
*/
createReportForm() {
this.reportForm = this.formBuilder.group({
'reportName': [{ value: this.reportData.reportName, disabled: this.reportData.coreReport }, Validators.required],
'reportCategory': [{ value: this.reportData.reportCategory ? this.reportData.reportCategory : '', disabled: this.reportData.coreReport }],
'description': [{ value: this.reportData.description ? this.reportData.description : '', disabled: this.reportData.coreReport }],
'reportType': [{ value: this.reportData.reportType, disabled: this.reportData.coreReport }, Validators.required],
'reportSubType': [{ value: this.reportData.reportSubType ? this.reportData.reportSubType : '', disabled: this.reportData.reportType !== 'Chart' || this.reportData.coreReport }],
'useReport': [this.reportData.useReport ? this.reportData.useReport : false],
'reportSql': [{ value: this.reportData.reportSql, disabled: this.reportData.coreReport || this.reportData.reportType === 'Pentaho' }, Validators.required]
});
}
/**
* Adds a new report parameter.
*/
addReportParameter() {
this.dataForDialog.parameterName = undefined;
this.dataForDialog.reportParameterName = undefined;
const addReportParameterDialogRef = this.dialog.open(ReportParameterDialogComponent, {
data: this.dataForDialog
});
addReportParameterDialogRef.afterClosed().subscribe((response: any) => {
if (response !== '') {
this.reportParametersData.push({ id: '',
parameterName: this.reportTemplateData.allowedParameters.find((allowedParameter: any) => allowedParameter.id === response.parameterName).parameterName,
parameterId: response.parameterName,
reportParameterName: response.reportParameterName ? response.reportParameterName : undefined });
this.dataSource.connect().next(this.reportParametersData);
this.isReportParametersChanged = true;
}
});
}
/**
* Edits report parameter.
* @param {any} reportParameter Report Parameter.
*/
editReportParameter(reportParameter: any) {
this.dataForDialog.parameterName = reportParameter.parameterId;
this.dataForDialog.reportParameterName = reportParameter.reportParameterName;
const editReportParameterDialogRef = this.dialog.open(ReportParameterDialogComponent, {
data: this.dataForDialog
});
editReportParameterDialogRef.afterClosed().subscribe((response: any) => {
if (response !== '') {
this.reportParametersData[this.reportParametersData.indexOf(reportParameter)] = { id: reportParameter.id,
parameterName: this.reportTemplateData.allowedParameters.find((allowedParameter: any) => allowedParameter.id === response.parameterName).parameterName,
parameterId: response.parameterName,
reportParameterName: response.reportParameterName };
this.dataSource.connect().next(this.reportParametersData);
this.isReportParametersChanged = true;
}
});
}
/**
* Deletes the report parameter.
* @param {any} reportParameter Report Parameter.
*/
deleteReportParameter(reportParameter: any) {
const deleteReportDialogRef = this.dialog.open(DeleteDialogComponent, {
data: { deleteContext: `report parameter ${reportParameter.parameterName}` }
});
deleteReportDialogRef.afterClosed().subscribe((response: any) => {
if (response.delete) {
this.reportParametersData.splice(this.reportParametersData.indexOf(reportParameter), 1);
this.dataSource.connect().next(this.reportParametersData);
this.isReportParametersChanged = true;
}
});
}
/**
* Toggles the visibility status of Report Sub Type dropdown.
*/
toggleVisibility() {
this.reportForm.get('reportType').valueChanges
.subscribe(type => {
switch (type) {
case 'Chart':
this.reportForm.get('reportSubType').enable();
this.reportForm.get('reportSql').enable();
break;
case 'Pentaho':
this.reportForm.get('reportSql').disable();
this.reportForm.get('reportSubType').disable();
break;
default:
this.reportForm.get('reportSql').enable();
this.reportForm.get('reportSubType').disable();
}
});
}
/**
* Submits the report form and updates report,
* if successful redirects to view updated report.
*/
submit() {
console.log(this.reportParametersData);
if (this.reportData.coreReport) {
this.reportForm.value.reportParameters = undefined;
} else {
this.reportForm.value.reportParameters = this.reportParametersData;
this.reportForm.value.reportParameters.map( function(reportParameter: any) {
reportParameter.parameterName = undefined;
return reportParameter;
});
}
this.systemService.updateReport(this.reportData.id, this.reportForm.value)
.subscribe(() => {
this.router.navigate(['../'], { relativeTo: this.route });
});
}
}
@@ -0,0 +1,69 @@
<div class="container m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
<button mat-raised-button color="primary" [routerLink]="['create']">
<fa-icon icon="plus"></fa-icon>&nbsp;&nbsp;
Create Report
</button>
</div>
<div class="container">
<div fxLayout="row">
<mat-form-field fxFlex>
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event.target.value)">
</mat-form-field>
</div>
<div class="mat-elevation-z8">
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="reportName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Report Name </th>
<td mat-cell *matCellDef="let report"> {{ report.reportName }} </td>
</ng-container>
<ng-container matColumnDef="reportType">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Report Type </th>
<td mat-cell *matCellDef="let report"> {{ report.reportType }} </td>
</ng-container>
<ng-container matColumnDef="reportSubType">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Report Sub Type </th>
<td mat-cell *matCellDef="let report"> {{ report.reportSubType }} </td>
</ng-container>
<ng-container matColumnDef="reportCategory">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Report Category </th>
<td mat-cell *matCellDef="let report"> {{ report.reportCategory }} </td>
</ng-container>
<ng-container matColumnDef="coreReport">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Core Report </th>
<td mat-cell *matCellDef="let report">
<fa-icon *ngIf="report.coreReport" icon="check-circle" size="lg" class="true" matTooltip="Yes"
matTooltipPosition="right"></fa-icon>
<fa-icon *ngIf="!report.coreReport" icon="times-circle" size="lg" class="false" matTooltip="No"
matTooltipPosition="right"></fa-icon>
</td>
</ng-container>
<ng-container matColumnDef="userReport">
<th mat-header-cell *matHeaderCellDef mat-sort-header> User Report </th>
<td mat-cell *matCellDef="let report">
<fa-icon *ngIf="report.useReport" icon="check-circle" size="lg" class="true" matTooltip="Yes"
matTooltipPosition="right"></fa-icon>
<fa-icon *ngIf="!report.useReport" icon="times-circle" size="lg" class="false" matTooltip="No"
matTooltipPosition="right"></fa-icon>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="[row.id]"
class="select-row"></tr>
</table>
<mat-paginator [pageSizeOptions]="[10, 25, 50, 100]" showFirstLastButtons></mat-paginator>
</div>
</div>
@@ -0,0 +1,16 @@
table {
width: 100%;
.select-row:hover {
cursor: pointer;
}
}
// TODO: CONFIGURE THESE CLASSES GLOBALLY
.true {
color: #32cd32;
}
.false {
color: #f44366;
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ManageReportsComponent } from './manage-reports.component';
describe('ManageReportsComponent', () => {
let component: ManageReportsComponent;
let fixture: ComponentFixture<ManageReportsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ManageReportsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ManageReportsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,62 @@
/** Angular Imports */
import { Component, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { MatTableDataSource, MatPaginator, MatSort } from '@angular/material';
/**
* Manage Reports Component.
*/
@Component({
selector: 'mifosx-manage-reports',
templateUrl: './manage-reports.component.html',
styleUrls: ['./manage-reports.component.scss']
})
export class ManageReportsComponent implements OnInit {
/** Reports Data. */
reportsData: any;
/** Columns to be displayed in reports table. */
displayedColumns: string[] = ['reportName', 'reportType', 'reportSubType', 'reportCategory', 'coreReport', 'userReport'];
/** Data source for reports table. */
dataSource: MatTableDataSource<any>;
/** Paginator for reports table. */
@ViewChild(MatPaginator) paginator: MatPaginator;
/** Sorter for reports table. */
@ViewChild(MatSort) sort: MatSort;
/**
* Retrieves the reports data from `resolve`.
* @param {ActivatedRoute} route Activated Route.
*/
constructor(private route: ActivatedRoute) {
this.route.data.subscribe((data: { reports: any }) => {
this.reportsData = data.reports;
});
}
/**
* Sets the reports table.
*/
ngOnInit() {
this.setReports();
}
/**
* Initializes the data source, paginator and sorter for reports table.
*/
setReports() {
this.dataSource = new MatTableDataSource(this.reportsData);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
/**
* Filters data in reports table based on passed value.
* @param {string} filterValue Value to filter data.
*/
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
}
}
@@ -0,0 +1,36 @@
<h1 mat-dialog-title>{{ data.parameterName ? "Edit" : "Add" }} Report Parameter</h1>
<mat-dialog-content>
<form [formGroup]="reportParameterForm">
<div fxLayout="column">
<mat-form-field>
<mat-label>Select allowed parameter</mat-label>
<mat-select required formControlName="parameterName">
<mat-option *ngFor="let allowedParameter of data.allowedParameters" [value]="allowedParameter.id">
{{ allowedParameter.parameterName }}
</mat-option>
</mat-select>
<mat-error *ngIf="reportParameterForm.controls.parameterName.hasError('required')">
Report Parameter is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field>
<mat-label>Parameter name passed to Pentaho</mat-label>
<input matInput formControlName="reportParameterName">
</mat-form-field>
</div>
</form>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button mat-dialog-close>Cancel</button>
<button mat-raised-button color="primary"
[disabled]="!reportParameterForm.valid || reportParameterForm.pristine" (click)="submit()">Submit</button>
</mat-dialog-actions>
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ReportParameterDialogComponent } from './report-parameter-dialog.component';
describe('AddReportParameterDialogComponent', () => {
let component: ReportParameterDialogComponent;
let fixture: ComponentFixture<ReportParameterDialogComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ReportParameterDialogComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ReportParameterDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,46 @@
/** Angular Imports */
import { Component, OnInit, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
/**
* Report Parameter Dialog Component.
*/
@Component({
selector: 'mifosx-add-report-parameter-dialog',
templateUrl: './report-parameter-dialog.component.html',
styleUrls: ['./report-parameter-dialog.component.scss']
})
export class ReportParameterDialogComponent implements OnInit {
/** Report Parameter Form. */
reportParameterForm: FormGroup;
/**
* @param {MatDialogRef} dialogRef Component reference to dialog.
* @param {FormBuilder} formBuilder Form Builder.
* @param {any} data Provides the allowed parameters and values for the form (if available).
*/
constructor(public dialogRef: MatDialogRef<ReportParameterDialogComponent>,
public formBuilder: FormBuilder,
@Inject(MAT_DIALOG_DATA) public data: any) {
}
/**
* Creates the add report parameter form.
*/
ngOnInit() {
this.reportParameterForm = this.formBuilder.group({
'parameterName': [this.data.parameterName, Validators.required],
'reportParameterName': [this.data.reportParameterName]
});
}
/**
* Closes the dialog and returns value of the form.
*/
submit() {
this.dialogRef.close(this.reportParameterForm.value);
}
}
@@ -0,0 +1,30 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
/** rxjs Imports */
import { Observable } from 'rxjs';
/** Custom Services */
import { SystemService } from '../system.service';
/**
* Report Template data resolver.
*/
@Injectable()
export class ReportTemplateResolver implements Resolve<Object> {
/**
* @param {SystemService} systemService System service.
*/
constructor(private systemService: SystemService) {}
/**
* Returns the Report Template data.
* @returns {Observable<any>}
*/
resolve(): Observable<any> {
return this.systemService.getReportTemplate();
}
}
@@ -0,0 +1,31 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
import { Observable } from 'rxjs';
/** Custom Services */
import { SystemService } from '../system.service';
/**
* Report data resolver.
*/
@Injectable()
export class ReportResolver implements Resolve<Object> {
/**
* @param {SystemService} systemService System service.
*/
constructor(private systemService: SystemService) {}
/**
* Returns the Report data.
* @returns {Observable<any>}
*/
resolve(route: ActivatedRouteSnapshot): Observable<any> {
const reportId = route.paramMap.get('id');
return this.systemService.getReport(reportId);
}
}
@@ -0,0 +1,30 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
/** rxjs Imports */
import { Observable } from 'rxjs';
/** Custom Services */
import { SystemService } from '../system.service';
/**
* Reports data resolver.
*/
@Injectable()
export class ReportsResolver implements Resolve<Object> {
/**
* @param {SystemService} systemService System service.
*/
constructor(private systemService: SystemService) {}
/**
* Returns the Reports data.
* @returns {Observable<any>}
*/
resolve(): Observable<any> {
return this.systemService.getReports();
}
}
@@ -0,0 +1,69 @@
<div class="container m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
<button mat-raised-button color="primary" [routerLink]="['edit']">
<fa-icon icon="edit"></fa-icon>&nbsp;&nbsp;
Edit
</button>
<button mat-raised-button color="warn" (click)="delete()" *ngIf="!reportData.coreReport">
<fa-icon icon="trash"></fa-icon>&nbsp;&nbsp;
Delete
</button>
</div>
<div class="container">
<mat-card>
<mat-card-title>{{ reportData.reportName }}</mat-card-title>
<mat-card-content>
<div fxLayout="row wrap" class="content">
<div fxFlex="50%" class="mat-body-strong">
Report Type:
</div>
<div fxFlex="50%">
{{ reportData.reportType }}
</div>
<div fxFlex="50%" class="mat-body-strong">
Report Subtype:
</div>
<div fxFlex="50%">
{{ reportData.reportSubType }}
</div>
<div fxFlex="50%" class="mat-body-strong">
Report Category:
</div>
<div fxFlex="50%">
{{ reportData.reportCategory }}
</div>
<div fxFlex="50%" class="mat-body-strong">
Core Report:
</div>
<div fxFlex="50%">
{{ reportData.coreReport ? 'Yes' : 'No' }}
</div>
<div fxFlex="50%" class="mat-body-strong">
User Report:
</div>
<div fxFlex="50%">
{{ reportData.useReport ? 'Yes' : 'No' }}
</div>
</div>
</mat-card-content>
</mat-card>
@@ -0,0 +1,10 @@
.container {
max-width: 37rem;
.content {
div {
margin: 1rem 0;
word-wrap: break-word;
}
}
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ViewReportComponent } from './view-report.component';
describe('ViewReportComponent', () => {
let component: ViewReportComponent;
let fixture: ComponentFixture<ViewReportComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ViewReportComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ViewReportComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,60 @@
/** Angular Imports */
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { MatDialog } from '@angular/material';
/** Custom Services */
import { SystemService } from 'app/system/system.service';
/** Custom Components */
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
/**
* View Report Component.
*/
@Component({
selector: 'mifosx-view-report',
templateUrl: './view-report.component.html',
styleUrls: ['./view-report.component.scss']
})
export class ViewReportComponent implements OnInit {
/** Report Data. */
reportData: any;
/**
* Retrieves the report data from `resolve`.
* @param {ActivatedRoute} route Activated Route.
* @param {SystemService} systemService System Service.
* @param {MatDialog} dialog Dialog Reference.
* @param {Router} router Router for navigation.
*/
constructor(private route: ActivatedRoute,
private systemService: SystemService,
private dialog: MatDialog,
private router: Router) {
this.route.data.subscribe((data: { report: any }) => {
this.reportData = data.report;
});
}
ngOnInit() {
}
/**
* Deletes the current report.
*/
delete() {
const deleteReportDialogRef = this.dialog.open(DeleteDialogComponent, {
data: { deleteContext: `report ${this.reportData.id}` }
});
deleteReportDialogRef.afterClosed().subscribe((response: any) => {
if (response.delete) {
this.systemService.deleteReport(this.reportData.id)
.subscribe(() => {
this.router.navigate(['/system/reports']);
});
}
});
}
}
+54 -1
View File
@@ -31,6 +31,10 @@ import { AccountNumberPreferencesComponent } from './account-number-preferences/
import { CreateAccountNumberPreferenceComponent } from './account-number-preferences/create-account-number-preference/create-account-number-preference.component';
import { ViewAccountNumberPreferenceComponent } from './account-number-preferences/view-account-number-preference/view-account-number-preference.component';
import { EditAccountNumberPreferenceComponent } from './account-number-preferences/edit-account-number-preference/edit-account-number-preference.component';
import { ManageReportsComponent } from './manage-reports/manage-reports.component';
import { EditReportComponent } from './manage-reports/edit-report/edit-report.component';
import { CreateReportComponent } from './manage-reports/create-report/create-report.component';
import { ViewReportComponent } from './manage-reports/view-report/view-report.component';
/** Custom Resolvers */
import { CodesResolver } from './codes/codes.resolver';
@@ -50,6 +54,9 @@ import { NotificationConfigurationResolver } from './external-services/notificat
import { AccountNumberPreferencesResolver } from './account-number-preferences/account-number-preferences.resolver';
import { AccountNumberPreferencesTemplateResolver } from './account-number-preferences/create-account-number-preference/account-number-preferences-template.resolver';
import { AccountNumberPreferenceResolver } from './account-number-preferences/view-account-number-preference/account-number-preference.resolver';
import { ReportsResolver } from './manage-reports/reports.resolver';
import { ReportResolver } from './manage-reports/report.resolver';
import { ReportTemplateResolver } from './manage-reports/report-template.resolver';
const routes: Routes = [
Route.withShell([
@@ -299,6 +306,49 @@ const routes: Routes = [
]
}
]
},
{
path: 'reports',
data: { title: extract('Manage Reports'), breadcrumb: 'Manage Reports' },
children: [
{
path: '',
component: ManageReportsComponent,
resolve: {
reports: ReportsResolver
}
},
{
path: 'create',
component: CreateReportComponent,
data: { title: extract('Create Report'), breadcrumb: 'Create' },
resolve: {
reportTemplate: ReportTemplateResolver
}
},
{
path: ':id',
data: { title: extract('View Report'), routeParamBreadcrumb: 'id' },
children: [
{
path: '',
component: ViewReportComponent,
resolve: {
report: ReportResolver
}
},
{
path: 'edit',
component: EditReportComponent,
data: { title: extract('Edit Report'), routeParamBreadcrumb: false, breadcrumb: 'Edit' },
resolve: {
report: ReportResolver,
reportTemplate: ReportTemplateResolver
}
}
]
}
]
}
]
}
@@ -325,7 +375,10 @@ const routes: Routes = [
NotificationConfigurationResolver,
AccountNumberPreferencesResolver,
AccountNumberPreferencesTemplateResolver,
AccountNumberPreferenceResolver
AccountNumberPreferenceResolver,
ReportsResolver,
ReportResolver,
ReportTemplateResolver
]
})
export class SystemRoutingModule { }
+1 -1
View File
@@ -80,7 +80,7 @@
<p matLine>Audit logs of all the activities, such as create client, disburse loans etc</p>
</mat-list-item>
<mat-list-item>
<mat-list-item [routerLink]="['reports']">
<mat-icon matListIcon>
<fa-icon icon="file-word" size="sm"></fa-icon>
</mat-icon>
+16 -1
View File
@@ -31,6 +31,13 @@ import { AccountNumberPreferencesComponent } from './account-number-preferences/
import { CreateAccountNumberPreferenceComponent } from './account-number-preferences/create-account-number-preference/create-account-number-preference.component';
import { ViewAccountNumberPreferenceComponent } from './account-number-preferences/view-account-number-preference/view-account-number-preference.component';
import { EditAccountNumberPreferenceComponent } from './account-number-preferences/edit-account-number-preference/edit-account-number-preference.component';
import { ManageReportsComponent } from './manage-reports/manage-reports.component';
import { ViewReportComponent } from './manage-reports/view-report/view-report.component';
import { CreateReportComponent } from './manage-reports/create-report/create-report.component';
import { EditReportComponent } from './manage-reports/edit-report/edit-report.component';
/** Dialog Component Imports */
import { ReportParameterDialogComponent } from './manage-reports/report-parameter-dialog/report-parameter-dialog.component';
@NgModule({
imports: [
@@ -62,7 +69,15 @@ import { EditAccountNumberPreferenceComponent } from './account-number-preferenc
AccountNumberPreferencesComponent,
CreateAccountNumberPreferenceComponent,
ViewAccountNumberPreferenceComponent,
EditAccountNumberPreferenceComponent
EditAccountNumberPreferenceComponent,
ManageReportsComponent,
ViewReportComponent,
CreateReportComponent,
EditReportComponent,
ReportParameterDialogComponent
],
entryComponents: [
ReportParameterDialogComponent
]
})
export class SystemModule { }
+47
View File
@@ -224,4 +224,51 @@ export class SystemService {
return this.http.put(`/accountnumberformats/${accountNumberPreferenceId}`, accountNumberPreferenceChanges);
}
/**
* @returns {Observable<any>} Reports.
*/
getReports(): Observable<any> {
return this.http.get('/reports');
}
/**
* @param {string} reportId Report ID.
* @returns {Observable<any>} Report.
*/
getReport(reportId: string): Observable<any> {
return this.http.get(`/reports/${reportId}?template=true`);
}
/**
* @returns {Observable<any>} Report Template.
*/
getReportTemplate(): Observable<any> {
return this.http.get('/reports/template');
}
/**
* @param {any} report Report.
* @returns {Observable<any>}
*/
createReport(report: any): Observable<any> {
return this.http.post('/reports', report);
}
/**
* @param {string} reportId Report ID.
* @param {any} report Report.
* @returns {Observable<any>}
*/
updateReport(reportId: string, report: any): Observable<any> {
return this.http.put(`/reports/${reportId}`, report);
}
/**
* @param {string} reportId Report ID.
* @returns {Observable<any>}
*/
deleteReport(reportId: string): Observable<any> {
return this.http.delete(`/reports/${reportId}`);
}
}