diff --git a/src/app/system/manage-data-tables/app-table-data.ts b/src/app/system/manage-data-tables/app-table-data.ts
new file mode 100644
index 000000000..5fbd4ace7
--- /dev/null
+++ b/src/app/system/manage-data-tables/app-table-data.ts
@@ -0,0 +1,10 @@
+export const appTableData: { displayValue: string, value: string }[] = [
+ { displayValue: 'Client', value: 'm_client' },
+ { displayValue: 'Group', value: 'm_group' },
+ { displayValue: 'Loan', value: 'm_loan' },
+ { displayValue: 'Center', value: 'm_center' },
+ { displayValue: 'Office', value: 'm_office' },
+ { displayValue: 'Saving Account', value: 'm_savings_account' },
+ { displayValue: 'Product Loan', value: 'm_product_loan' },
+ { displayValue: 'Savings Product', value: 'm_savings_product' }
+ ];
diff --git a/src/app/system/manage-data-tables/column-dialog/column-dialog.component.html b/src/app/system/manage-data-tables/column-dialog/column-dialog.component.html
new file mode 100644
index 000000000..5f7dc6057
--- /dev/null
+++ b/src/app/system/manage-data-tables/column-dialog/column-dialog.component.html
@@ -0,0 +1,54 @@
+
{{ data.columnName ? "Edit" : "Add" }} Column
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/system/manage-data-tables/column-dialog/column-dialog.component.scss b/src/app/system/manage-data-tables/column-dialog/column-dialog.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/app/system/manage-data-tables/column-dialog/column-dialog.component.spec.ts b/src/app/system/manage-data-tables/column-dialog/column-dialog.component.spec.ts
new file mode 100644
index 000000000..a304ea04b
--- /dev/null
+++ b/src/app/system/manage-data-tables/column-dialog/column-dialog.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ColumnDialogComponent } from './column-dialog.component';
+
+describe('ColumnDialogComponent', () => {
+ let component: ColumnDialogComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ColumnDialogComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ColumnDialogComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/system/manage-data-tables/column-dialog/column-dialog.component.ts b/src/app/system/manage-data-tables/column-dialog/column-dialog.component.ts
new file mode 100644
index 000000000..b5d720e4c
--- /dev/null
+++ b/src/app/system/manage-data-tables/column-dialog/column-dialog.component.ts
@@ -0,0 +1,101 @@
+/** Angular Imports */
+import { Component, OnInit, Inject } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+
+/** Data Imports */
+import { columnTypeData } from '../column-type-data';
+
+/**
+ * Column Dialog Component.
+ */
+@Component({
+ selector: 'mifosx-column-dialog',
+ templateUrl: './column-dialog.component.html',
+ styleUrls: ['./column-dialog.component.scss']
+})
+export class ColumnDialogComponent implements OnInit {
+
+ /** Column Form. */
+ columnForm: FormGroup;
+ /** Column Type Data */
+ columnTypeData = columnTypeData;
+
+ /**
+ * @param {MatDialogRef} dialogRef Component reference to dialog.
+ * @param {FormBuilder} formBuilder Form Builder.
+ * @param {any} data Provides the column codes and values for the form (if available).
+ */
+ constructor(public dialogRef: MatDialogRef,
+ public formBuilder: FormBuilder,
+ @Inject(MAT_DIALOG_DATA) public data: any) { }
+
+ /**
+ * Creates the add column form.
+ */
+ ngOnInit() {
+ this.columnForm = this.formBuilder.group({
+ 'name': [this.data ? this.data.columnName : '', Validators.required],
+ 'type': [{ value: this.data ? (this.data.columnDisplayType === '' ? '' : this.getColumnType(this.data.columnDisplayType)) : '', disabled: this.data.type === 'existing' }, Validators.required],
+ 'mandatory': [{ value: this.data ? this.data.isColumnPrimaryKey : false, disabled: this.data.type === 'existing' }],
+ 'length': [{ value: this.data ? +this.data.columnLength : '', disabled: this.getColumnType(this.data.columnDisplayType) !== 'String' || this.data.type === 'existing' }, Validators.required],
+ 'code': [{ value: this.data ? this.data.columnCode : '', disabled: this.getColumnType(this.data.columnDisplayType) !== 'Dropdown' || this.data.type === 'existing' }, Validators.required]
+ });
+ this.onColumnTypeChanges();
+ }
+
+ /**
+ * Returns the modified Column Type.
+ * @param {string} columnDisplayType Column Display Type.
+ * @returns {string} Column Type.
+ */
+ getColumnType(columnDisplayType: string): string {
+ switch (columnDisplayType) {
+ case undefined: {
+ return '';
+ }
+ case 'INTEGER': {
+ return 'Number';
+ }
+ case 'CODELOOKUP': {
+ return 'Dropdown';
+ }
+ default: {
+ return columnDisplayType[0] + columnDisplayType.substr(1).toLowerCase();
+ }
+ }
+ }
+
+ /**
+ * Watches on Column Type field to enable/diable certain fields.
+ */
+ onColumnTypeChanges() {
+ this.columnForm.get('type').valueChanges
+ .subscribe(type => {
+ switch (type) {
+ case 'String': {
+ this.columnForm.get('length').enable();
+ this.columnForm.get('code').disable();
+ break;
+ }
+ case 'Dropdown': {
+ this.columnForm.get('code').enable();
+ this.columnForm.get('length').disable();
+ break;
+ }
+ default: {
+ this.columnForm.get('code').disable();
+ this.columnForm.get('length').disable();
+ }
+ }
+ });
+ }
+
+ /**
+ * Closes the dialog and returns value of the form.
+ */
+ submit() {
+ this.dialogRef.close(this.columnForm.value);
+ }
+
+}
diff --git a/src/app/system/manage-data-tables/column-type-data.ts b/src/app/system/manage-data-tables/column-type-data.ts
new file mode 100644
index 000000000..bc799a050
--- /dev/null
+++ b/src/app/system/manage-data-tables/column-type-data.ts
@@ -0,0 +1,10 @@
+export const columnTypeData: { displayValue: string, value: string }[] = [
+ { displayValue: 'Boolean', value: 'Boolean' },
+ { displayValue: 'Date', value: 'Date' },
+ { displayValue: 'Date and Time', value: 'Datetime' },
+ { displayValue: 'Decimal', value: 'Decimal' },
+ { displayValue: 'Dropdown', value: 'Dropdown' },
+ { displayValue: 'Number', value: 'Number' },
+ { displayValue: 'String', value: 'String' },
+ { displayValue: 'Text', value: 'Text' }
+ ];
diff --git a/src/app/system/manage-data-tables/create-data-table/create-data-table.component.html b/src/app/system/manage-data-tables/create-data-table/create-data-table.component.html
new file mode 100644
index 000000000..f92636ebf
--- /dev/null
+++ b/src/app/system/manage-data-tables/create-data-table/create-data-table.component.html
@@ -0,0 +1,109 @@
+
diff --git a/src/app/system/manage-data-tables/create-data-table/create-data-table.component.scss b/src/app/system/manage-data-tables/create-data-table/create-data-table.component.scss
new file mode 100644
index 000000000..eac57d1fe
--- /dev/null
+++ b/src/app/system/manage-data-tables/create-data-table/create-data-table.component.scss
@@ -0,0 +1,18 @@
+@media (min-width: 992px) {
+
+ .multi-row-wrapper {
+ position: relative;
+
+ .multi-row {
+ padding: 0 0 17.5px 0;
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ }
+ }
+
+}
+
+table {
+ width: 100%;
+}
diff --git a/src/app/system/manage-data-tables/create-data-table/create-data-table.component.spec.ts b/src/app/system/manage-data-tables/create-data-table/create-data-table.component.spec.ts
new file mode 100644
index 000000000..64788c2b2
--- /dev/null
+++ b/src/app/system/manage-data-tables/create-data-table/create-data-table.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CreateDataTableComponent } from './create-data-table.component';
+
+describe('CreateDataTableComponent', () => {
+ let component: CreateDataTableComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ CreateDataTableComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CreateDataTableComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/system/manage-data-tables/create-data-table/create-data-table.component.ts b/src/app/system/manage-data-tables/create-data-table/create-data-table.component.ts
new file mode 100644
index 000000000..c2abe94f2
--- /dev/null
+++ b/src/app/system/manage-data-tables/create-data-table/create-data-table.component.ts
@@ -0,0 +1,188 @@
+/** 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 '../../system.service';
+
+/** Data Imports */
+import { appTableData } from '../app-table-data';
+
+/** Custom Components */
+import { ColumnDialogComponent } from '../column-dialog/column-dialog.component';
+import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
+
+/**
+ * Create Data Table Component.
+ */
+@Component({
+ selector: 'mifosx-create-data-table',
+ templateUrl: './create-data-table.component.html',
+ styleUrls: ['./create-data-table.component.scss']
+})
+export class CreateDataTableComponent implements OnInit {
+
+ /** Data Table Form */
+ dataTableForm: FormGroup;
+ /** Application Table Data */
+ appTableData = appTableData;
+ /** Column Data */
+ columnData: any[] = [];
+ /** Data passed to dialog. */
+ dataForDialog: {
+ columnName: string,
+ columnDisplayType: string,
+ isColumnPrimaryKey: boolean,
+ columnLength: string,
+ columnCode: string,
+ columnCodes: any,
+ type: string
+ } = {
+ columnName: undefined,
+ columnDisplayType: undefined,
+ isColumnPrimaryKey: undefined,
+ columnLength: undefined,
+ columnCode: undefined,
+ columnCodes: undefined,
+ type: undefined
+ };
+ /** Columns to be displayed in columns table. */
+ displayedColumns: string[] = ['name', 'type', 'mandatory', 'length', 'code', 'actions'];
+ /** Data source for columns table. */
+ dataSource: MatTableDataSource;
+ /** Paginator for columns table. */
+ @ViewChild(MatPaginator) paginator: MatPaginator;
+ /** Sorter for columns table. */
+ @ViewChild(MatSort) sort: MatSort;
+
+ /**
+ * Retrieves the column codes 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: { columnCodes: any }) => {
+ this.dataForDialog.columnCodes = data.columnCodes;
+ });
+ }
+
+ /**
+ * Creates data table form and sets columns table.
+ */
+ ngOnInit() {
+ this.createDataTableForm();
+ this.setColumns();
+ }
+
+ /**
+ * Initializes the data source, paginator and sorter for columns table.
+ */
+ setColumns() {
+ this.dataSource = new MatTableDataSource(this.columnData);
+ this.dataSource.paginator = this.paginator;
+ this.dataSource.sort = this.sort;
+ }
+
+ /**
+ * Creates the data table form.
+ */
+ createDataTableForm() {
+ this.dataTableForm = this.formBuilder.group({
+ 'datatableName': ['', Validators.required],
+ 'apptableName': ['', Validators.required],
+ 'multiRow': ['']
+ });
+ }
+
+ /**
+ * Adds a new column.
+ */
+ addColumn() {
+ this.dataForDialog.columnName = undefined;
+ this.dataForDialog.columnDisplayType = undefined;
+ this.dataForDialog.isColumnPrimaryKey = false;
+ this.dataForDialog.columnLength = undefined;
+ this.dataForDialog.columnCode = undefined;
+ this.dataForDialog.type = 'new';
+ const addColumnDialogRef = this.dialog.open(ColumnDialogComponent, {
+ data: this.dataForDialog
+ });
+ addColumnDialogRef.afterClosed().subscribe((response: any) => {
+ if (response !== '') {
+ this.columnData.push({
+ name: response.name,
+ type: response.type,
+ mandatory: response.mandatory,
+ length: response.length,
+ code: response.code
+ });
+ this.dataSource.connect().next(this.columnData);
+ }
+ });
+ }
+
+ /**
+ * Edits column.
+ * @param {any} column Column.
+ */
+ editColumn(column: any) {
+ this.dataForDialog.columnName = column.name;
+ this.dataForDialog.columnDisplayType = column.type;
+ this.dataForDialog.isColumnPrimaryKey = column.mandatory;
+ this.dataForDialog.columnLength = column.length;
+ this.dataForDialog.columnCode = column.code;
+ this.dataForDialog.type = 'new';
+ const editColumnDialogRef = this.dialog.open(ColumnDialogComponent, {
+ data: this.dataForDialog
+ });
+ editColumnDialogRef.afterClosed().subscribe((response: any) => {
+ if (response !== '') {
+ this.columnData[this.columnData.findIndex(newColumn => newColumn.name === column.name)] = {
+ name: response.name,
+ type: response.type,
+ mandatory: response.mandatory,
+ length: response.length,
+ code: response.code
+ };
+ this.dataSource.connect().next(this.columnData);
+ }
+ });
+ }
+
+ /**
+ * Deletes the column.
+ * @param {any} column Column.
+ */
+ deleteColumn(column: any) {
+ const deleteColumnDialogRef = this.dialog.open(DeleteDialogComponent, {
+ data: { deleteContext: `column ${column.name}` }
+ });
+ deleteColumnDialogRef.afterClosed().subscribe((response: any) => {
+ if (response.delete) {
+ this.columnData.splice(this.columnData.indexOf(column), 1);
+ this.dataSource.connect().next(this.columnData);
+ }
+ });
+ }
+
+ /**
+ * Submits the data table form and creates data table,
+ * if successful redirects to view created data table.
+ */
+ submit() {
+ this.dataTableForm.value.columns = this.columnData;
+ this.systemService.createDataTable(this.dataTableForm.value)
+ .subscribe((response: any) => {
+ this.router.navigate(['../', response.resourceIdentifier], { relativeTo: this.route });
+ });
+ }
+}
diff --git a/src/app/system/manage-data-tables/data-table.resolver.ts b/src/app/system/manage-data-tables/data-table.resolver.ts
new file mode 100644
index 000000000..4492da060
--- /dev/null
+++ b/src/app/system/manage-data-tables/data-table.resolver.ts
@@ -0,0 +1,33 @@
+/** 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';
+
+/**
+ * Data Table data resolver.
+ */
+@Injectable()
+export class DataTableResolver implements Resolve