diff --git a/dmp-frontend/src/app/models/criteria/BaseCriteria.ts b/dmp-frontend/src/app/models/criteria/BaseCriteria.ts new file mode 100644 index 000000000..f33ba1545 --- /dev/null +++ b/dmp-frontend/src/app/models/criteria/BaseCriteria.ts @@ -0,0 +1,3 @@ +export class BaseCriteria { + public Like: string; +} diff --git a/dmp-frontend/src/app/models/criteria/BaseCriteriaErrorModel.ts b/dmp-frontend/src/app/models/criteria/BaseCriteriaErrorModel.ts new file mode 100644 index 000000000..48ff68405 --- /dev/null +++ b/dmp-frontend/src/app/models/criteria/BaseCriteriaErrorModel.ts @@ -0,0 +1,3 @@ +export class BaseCriteriaErrorModel { + public Like: String; +} diff --git a/dmp-frontend/src/app/models/criteria/data-management-plan/DataManagementPlanCriteria.ts b/dmp-frontend/src/app/models/criteria/data-management-plan/DataManagementPlanCriteria.ts new file mode 100644 index 000000000..d7631c684 --- /dev/null +++ b/dmp-frontend/src/app/models/criteria/data-management-plan/DataManagementPlanCriteria.ts @@ -0,0 +1,6 @@ +import { BaseCriteria } from "./BaseCriteria"; + +export class DataManagementPlanCriteria extends BaseCriteria { + public PeriodStart: Date; + public PeriodEnd: Date; +} diff --git a/dmp-frontend/src/app/models/criteria/data-management-plan/DataManagementPlanCriteriaErrorModel.ts b/dmp-frontend/src/app/models/criteria/data-management-plan/DataManagementPlanCriteriaErrorModel.ts new file mode 100644 index 000000000..6773dbafa --- /dev/null +++ b/dmp-frontend/src/app/models/criteria/data-management-plan/DataManagementPlanCriteriaErrorModel.ts @@ -0,0 +1,6 @@ +import { BaseCriteriaErrorModel } from "../BaseCriteriaErrorModel"; + +export class DataManagementPlanCriteriaErrorModel extends BaseCriteriaErrorModel{ + public PeriodStart: String; + public PeriodEnd: String; +} diff --git a/dmp-frontend/src/app/models/criteria/project/ProjectCriteria.ts b/dmp-frontend/src/app/models/criteria/project/ProjectCriteria.ts new file mode 100644 index 000000000..5bd4287b4 --- /dev/null +++ b/dmp-frontend/src/app/models/criteria/project/ProjectCriteria.ts @@ -0,0 +1,6 @@ +import { BaseCriteria } from "./BaseCriteria"; + +export class ProjectCriteria extends BaseCriteria { + public PeriodStart: Date; + public PeriodEnd: Date; +} diff --git a/dmp-frontend/src/app/models/criteria/project/ProjectCriteriaErrorModel.ts b/dmp-frontend/src/app/models/criteria/project/ProjectCriteriaErrorModel.ts new file mode 100644 index 000000000..1838fd648 --- /dev/null +++ b/dmp-frontend/src/app/models/criteria/project/ProjectCriteriaErrorModel.ts @@ -0,0 +1,6 @@ +import { BaseCriteriaErrorModel } from "../BaseCriteriaErrorModel"; + +export class ProjectCriteriaErrorModel extends BaseCriteriaErrorModel{ + public PeriodStart: String; + public PeriodEnd: String; +} diff --git a/dmp-frontend/src/app/models/data-managemnt-plans/DmpListingModel.ts b/dmp-frontend/src/app/models/data-managemnt-plans/DmpListingModel.ts new file mode 100644 index 000000000..96f214421 --- /dev/null +++ b/dmp-frontend/src/app/models/data-managemnt-plans/DmpListingModel.ts @@ -0,0 +1,27 @@ +import { Serializable } from "../Serializable"; + +export class DmpListingModel implements Serializable { + public id: String; + public label: String; + public abbreviation: String; + public reference: String; + public uri: String; + public status: String; + public startDate: Date; + public endDate: Date; + public description: String; + + fromJSONObject(item: any): DmpListingModel { + this.id = item.id; + this.label = item.label; + this.abbreviation = item.abbreviation; + this.reference = item.reference; + this.uri = item.uri; + this.status = item.status; + this.startDate = item.startDate; + this.endDate = item.endDate; + this.description = item.description; + + return this; + } +} \ No newline at end of file diff --git a/dmp-frontend/src/app/models/data-managemnt-plans/DmpModel.ts b/dmp-frontend/src/app/models/data-managemnt-plans/DmpModel.ts new file mode 100644 index 000000000..f787cfec2 --- /dev/null +++ b/dmp-frontend/src/app/models/data-managemnt-plans/DmpModel.ts @@ -0,0 +1,27 @@ +import { Serializable } from "../Serializable"; + +export class DmpModel implements Serializable { + public id: String; + public label: String; + public abbreviation: String; + public reference: String; + public uri: String; + public status: String; + public startDate: Date; + public endDate: Date; + public description: String; + + fromJSONObject(item: any): DmpModel { + this.id = item.id; + this.label = item.label; + this.abbreviation = item.abbreviation; + this.reference = item.reference; + this.uri = item.uri; + this.status = item.status; + this.startDate = item.startDate; + this.endDate = item.endDate; + this.description = item.description; + + return this; + } +} \ No newline at end of file diff --git a/dmp-frontend/src/app/models/data-table/DataTableData.ts b/dmp-frontend/src/app/models/data-table/DataTableData.ts new file mode 100644 index 000000000..f5a1e78d8 --- /dev/null +++ b/dmp-frontend/src/app/models/data-table/DataTableData.ts @@ -0,0 +1,4 @@ +export class DataTableData { + data = new Array(); + totalCount = 0; +} diff --git a/dmp-frontend/src/app/models/data-table/DataTableRequest.ts b/dmp-frontend/src/app/models/data-table/DataTableRequest.ts new file mode 100644 index 000000000..2210d72db --- /dev/null +++ b/dmp-frontend/src/app/models/data-table/DataTableRequest.ts @@ -0,0 +1,14 @@ +import { ProjectCriteria } from "../criteria/ProjectCriteria"; +import { DataManagementPlanCriteria } from "../criteria/DataManagementPlanCriteria"; + +export class DataTableRequest { + offset = 0; + length = 0; + projectCriteria: ProjectCriteria; + dmpCriteria: DataManagementPlanCriteria; + + constructor(offset: number, length: number) { + this.length = length; + this.offset = offset; + } +} diff --git a/dmp-frontend/src/app/models/error/BaseErrorModel.ts b/dmp-frontend/src/app/models/error/BaseErrorModel.ts new file mode 100644 index 000000000..c2bab43b0 --- /dev/null +++ b/dmp-frontend/src/app/models/error/BaseErrorModel.ts @@ -0,0 +1,3 @@ +export class BaseErrorModel { + +} diff --git a/dmp-frontend/src/app/models/projects/ProjectListingModel.ts b/dmp-frontend/src/app/models/projects/ProjectListingModel.ts new file mode 100644 index 000000000..e3d1d2d62 --- /dev/null +++ b/dmp-frontend/src/app/models/projects/ProjectListingModel.ts @@ -0,0 +1,27 @@ +import { Serializable } from "../Serializable"; + +export class ProjectListingModel implements Serializable { + public id: String; + public label: String; + public abbreviation: String; + public reference: String; + public uri: String; + public status: String; + public startDate: Date; + public endDate: Date; + public description: String; + + fromJSONObject(item: any): ProjectListingModel { + this.id = item.id; + this.label = item.label; + this.abbreviation = item.abbreviation; + this.reference = item.reference; + this.uri = item.uri; + this.status = item.status; + this.startDate = item.startDate; + this.endDate = item.endDate; + this.description = item.description; + + return this; + } +} \ No newline at end of file diff --git a/dmp-frontend/src/app/models/projects/ProjectModel.ts b/dmp-frontend/src/app/models/projects/ProjectModel.ts new file mode 100644 index 000000000..e5d9ecf35 --- /dev/null +++ b/dmp-frontend/src/app/models/projects/ProjectModel.ts @@ -0,0 +1,27 @@ +import { Serializable } from "../Serializable"; + +export class ProjectModel implements Serializable { + public id: String; + public label: String; + public abbreviation: String; + public reference: String; + public uri: String; + public status: String; + public startDate: Date; + public endDate: Date; + public description: String; + + fromJSONObject(item: any): ProjectModel { + this.id = item.id; + this.label = item.label; + this.abbreviation = item.abbreviation; + this.reference = item.reference; + this.uri = item.uri; + this.status = item.status; + this.startDate = item.startDate; + this.endDate = item.endDate; + this.description = item.description; + + return this; + } +} \ No newline at end of file diff --git a/dmp-frontend/src/app/projects/project-listing.component.css b/dmp-frontend/src/app/projects/project-listing.component.css new file mode 100644 index 000000000..957c39499 --- /dev/null +++ b/dmp-frontend/src/app/projects/project-listing.component.css @@ -0,0 +1,20 @@ +.mat-card { + overflow: auto; + padding: 0px; +} + +.mat-table { + margin: 24px; +} + +.mat-progress-bar { + position: absolute; +} + +.mat-fab-bottom-right { + top: auto !important; + right: 20px !important; + bottom: 10px !important; + left: auto !important; + position: fixed !important; +} diff --git a/dmp-frontend/src/app/projects/project.html b/dmp-frontend/src/app/projects/project-listing.component.html similarity index 75% rename from dmp-frontend/src/app/projects/project.html rename to dmp-frontend/src/app/projects/project-listing.component.html index 8824f61f8..8d5c11e1c 100644 --- a/dmp-frontend/src/app/projects/project.html +++ b/dmp-frontend/src/app/projects/project-listing.component.html @@ -1,4 +1,57 @@ - +
+

{{'PROJECT-LISTING.TITLE' | translate}}

+ + + + + + + + + + {{'PROJECT-LISTING.COLUMNS.NAME' | translate}} + {{row.name}} + + + + + {{'PROJECT-LISTING.COLUMNS.ABBREVIATION' | translate}} + {{row.abbreviation}} + + + + + {{'PROJECT-LISTING.COLUMNS.START' | translate}} + {{row.start}} + + + + + {{'PROJECT-LISTING.COLUMNS.END' | translate}} + {{row.end}} + + + + + {{'PROJECT-LISTING.COLUMNS.ACTIONS' | translate}} + + + + + + + + + + + + +
+ @@ -139,4 +187,4 @@ - + --> diff --git a/dmp-frontend/src/app/projects/project-listing.component.ts b/dmp-frontend/src/app/projects/project-listing.component.ts new file mode 100644 index 000000000..32c04b497 --- /dev/null +++ b/dmp-frontend/src/app/projects/project-listing.component.ts @@ -0,0 +1,297 @@ +import { Component, ViewChild, OnInit, AfterViewInit } from "@angular/core"; +import { MatPaginator, MatSort, MatSnackBar } from "@angular/material"; +import { Router } from "@angular/router"; +import { TranslateService } from "@ngx-translate/core"; +import { DataSource } from "@angular/cdk/table"; +import { ProjectListingModel } from "../models/projects/ProjectListingModel"; +import { ProjectService } from "../services/project/project.service"; +import { ProjectCriteriaComponent } from "../shared/components/criteria/projects/projects-criteria.component"; +import { ProjectCriteria } from "../models/criteria/project/ProjectCriteria"; +import { Observable } from "rxjs/Observable"; +import { DataTableRequest } from "../models/data-table/DataTableRequest"; +import { SnackBarNotificationComponent } from "../shared/components/notificaiton/snack-bar-notification.component"; + + + +@Component({ + selector: 'app-project-listing-component', + templateUrl: 'project-listing.component.html', + styleUrls: ['./project-listing.component.css'], + providers: [ProjectService] +}) +export class FormsComponent implements OnInit, AfterViewInit { + + @ViewChild(MatPaginator) _paginator: MatPaginator; + @ViewChild(MatSort) sort: MatSort; + @ViewChild(ProjectCriteriaComponent) criteria: ProjectCriteriaComponent; + + dataSource: FormsDataSource | null; + displayedColumns: String[] = ['type', 'projectName', 'submissionTime', 'description', 'status']; + + constructor( + private projectService: ProjectService, + private router: Router, + private languageService: TranslateService, + public snackBar: MatSnackBar, + ) { + + } + + ngOnInit() { + + } + + ngAfterViewInit() { + setTimeout(() => { + this.criteria.setRefreshCallback(() => this.refresh()); + this.criteria.setCriteria(this.getDefaultCriteria()); + this.criteria.controlModified(); + }); + } + + refresh() { + this.dataSource = new FormsDataSource(this.projectService, this._paginator, this.sort, this.languageService, this.snackBar, this.criteria, ); + } + + rowClick(rowId: String) { + this.router.navigate(['/forms/' + rowId]); + } + + getDefaultCriteria(): ProjectCriteria { + const defaultCriteria = new ProjectCriteria(); + return defaultCriteria; + } + + // canShowOwner(): boolean { + // const principal: Principal = this.authentication.current(); + // if (principal) { + // const principalRoles = principal.appRoles; + // for (let i = 0; i < principalRoles.length; i++) { + // if (principalRoles[i] === Principal.AppRole.Admin || principalRoles[i] === Principal.AppRole.BudgetManager) { + // return true; + // } + // } + // } + // return false; + // } +} + +export class FormsDataSource extends DataSource { + + totalCount = 0; + isLoadingResults = false; + + constructor( + private _service: ProjectService, + private _paginator: MatPaginator, + private _sort: MatSort, + private _languageService: TranslateService, + private _snackBar: MatSnackBar, + private _criteria: ProjectCriteriaComponent + ) { + super(); + + //this._paginator.page.subscribe((pageEvent: PageEvent) => { + // this.store.dispatch(new LoadPhotosRequestAction(pageEvent.pageIndex, pageEvent.pageSize)) + //}) + } + + connect(): Observable { + const displayDataChanges = [ + this._paginator.page + //this._sort.matSortChange + ]; + + // If the user changes the sort order, reset back to the first page. + //this._sort.matSortChange.subscribe(() => { + // this._paginator.pageIndex = 0; + //}) + + return Observable.merge(...displayDataChanges) + .startWith(null) + .switchMap(() => { + setTimeout(() => { + this.isLoadingResults = true; + }); + const startIndex = this._paginator.pageIndex * this._paginator.pageSize; + const request = new DataTableRequest(startIndex, this._paginator.pageSize); + request.projectCriteria = this._criteria.getFormData(); + return this._service.getPaged(request); + }) + .catch((error: any) => { + this._snackBar.openFromComponent(SnackBarNotificationComponent, { + data: { message: 'GENERAL.SNACK-BAR.FORMS-BAD-REQUEST', language: this._languageService }, + duration: 3000, + extraClasses: ['snackbar-warning'] + }); + this._criteria.onCallbackError(error); + return Observable.of(null); + }) + .map(result => { + setTimeout(() => { + this.isLoadingResults = false; + }); + return result; + }) + .map(result => { + if (!result) { return []; } + if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; } + return result.data; + }); + } + + disconnect() { + // No-op + } +} +// export class ProjectListingComponent implements OnInit{ + +// // Start ALTERNATIVE +// //whole dmp data model +// tableData : any[] = new Array(); + +// //organisation editor data model +// editingOrganisation: any = {}; +// organisationEditorForm : any; + +// //required by the table +// public filterQuery = ""; +// public rowsOnPage = 10; +// public sortBy = "label"; +// public sortOrder = "asc"; + + +// // for tableIds +// showIDs : boolean = false; + +// statusDropDown: DropdownField; + +// project: any; + +// whoami: any; +// onlyMyProjects : boolean = false; + +// options: DatepickerOptions = { +// minYear: 1900, +// maxYear: 2050, +// displayFormat: 'MMM D[,] YYYY', +// barTitleFormat: 'MMMM YYYY', +// firstCalendarDay: 0 // 0 - Sunday, 1 - Monday +// }; + +// //breadcrumbHome: MenuItem = {icon: 'fa fa-home'}; +// breadcrumbData: MenuItem[] = new Array(); + +// constructor( +// private serverService: ServerService, +// private route: ActivatedRoute, +// private router: Router) { +// this.statusDropDown = new DropdownField(); +// this.statusDropDown.options= [{key:'0', value:"Active"},{key:'1', value:"Inactive"}] +// this.project = this.getEmptyProject(); +// } + +// ngAfterViewInit() { + +// } + +// getEmptyProject(){ +// return { +// label: '', +// abbreviation:'', +// reference:'', +// uri:'', +// description:'', +// enddate:'', +// startdate:'' +// } +// } + + +// ngOnInit() { + +// this.getProjects(); + +// this.serverService.whoami().subscribe( +// response => { +// this.whoami = response; +// console.log(this.whoami) +// }, +// err => { +// simple_notifier("danger",null,"Could not retrieve user config"); +// } +// ); + +// } + + +// getProjects(muted? : boolean){ +// //this.serverService.getProjectsOfUser().subscribe( +// this.serverService.getAllProjects().subscribe( +// response => { +// this.tableData = response; +// if(muted && muted!=true) +// simple_notifier("success",null,"Updated projects table"); +// }, +// err => { +// simple_notifier("danger",null,"Could not retrieve projects"); +// } +// ); +// } + + + +// showDatasets(){ //dmpId, event +// //this.dataSetVisibe = true; + +// } + + +// SaveProject(){ + +// let action : Observable; + +// if(this.project.id == null) //means it's a new one +// action = this.serverService.createProject(this.project); +// else +// action = this.serverService.updateProject(this.project); +// action.subscribe( +// response =>{ +// this.getProjects(); +// simple_notifier("success",null, (this.project.id == null) ? "Created" : "Updated" +" projects table"); +// }, +// error => { +// simple_notifier("danger",null, "Could not "+ (this.project.id == null) ? "create" : "update" + " projects table"); +// } +// ); + +// $("#newEditProjectModal").modal("hide"); +// } + +// newProject(){ +// this.project = this.getEmptyProject(); +// $("#newEditProjectModal").modal("show"); + +// } + +// editRow(item, event){ +// this.project = Object.assign({}, item); //this will have id - that defines whether it's an update or not +// this.project.creationUser = {"id":this.project.creationUser.id}; +// $("#newEditProjectModal").modal("show"); + +// return false; +// } + + +// /* +// markProjectForDelete(project){ +// this.project = project; +// } + +// deleteProject(confirmation){ +// if(confirmation==true) +// this.deleteRow(this.project); +// } +// */ + +// } diff --git a/dmp-frontend/src/app/projects/project.css b/dmp-frontend/src/app/projects/project.css deleted file mode 100644 index 2c6b2c7e6..000000000 --- a/dmp-frontend/src/app/projects/project.css +++ /dev/null @@ -1,62 +0,0 @@ -:host /deep/ .index-column, -:host /deep/ .index-column-header { - text-align: right; -} - -:host /deep/ .data-table .data-table-row.selected { - background-color: #E4EDF9; -} - -a.editGridColumn{ - color: #333; -} - -.invisible { - display:none; -} - -.visible { - display:block; -} - -tr.hover:hover > * { - background-color: #eeeeee; -} - -.editor-container{ - padding-top: 10px; - padding-right: 10px; - padding-bottom: 10px; - padding-left: 10px; -} - -.button-150px { - max-width: 150px; -} - -.ng-template{ - text-align: right; -} - -.grayout-empty-table { - opacity: 0.6; /* Real browsers */ - filter: alpha(opacity = 60); /* MSIE */ - text-align: center; - vertical-align: middle; -} - -.btncustom{ - background-color:#337ab7; - color:white; - margin-top:15px; -} - -a{ - cursor: pointer; -} -.not-active { - pointer-events: none; - cursor:not-allowed; - opacity: 0.5; - filter: alpha(opacity=50); /* For IE8 and earlier */ - } \ No newline at end of file diff --git a/dmp-frontend/src/app/projects/projects.component.ts b/dmp-frontend/src/app/projects/projects.component.ts deleted file mode 100644 index eab4fe99b..000000000 --- a/dmp-frontend/src/app/projects/projects.component.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { Component, OnInit, Input, Output, EventEmitter, ViewChild } from '@angular/core'; -import {Observable} from 'rxjs/Observable'; -import {GoogleSignInSuccess} from 'angular-google-signin'; -import { Router, ActivatedRoute } from '@angular/router'; -import { ServerService } from '../../app/services/server.service'; -import { Project } from '../entities/model/project'; -import { Dmp } from '../entities/model/dmp'; -import { Dataset } from '../entities/model/dataset'; -//import { DataTable, DataTableTranslations, DataTableResource } from 'angular-4-data-table-bootstrap-4'; -import {DataTable} from 'angular2-datatable'; -import { DropdownField } from '../../app/form/fields/dropdown/field-dropdown'; -import { Param } from '../entities/model/param'; -import { ModalComponent } from '../modal/modal.component'; -import { HttpErrorResponse } from '@angular/common/http'; -import { FormGroup, FormControl } from '@angular/forms'; //na dw an xreiazontai -import { NgForm } from '@angular/forms'; -import { DatepickerOptions } from 'ng2-datepicker'; -import { StatusToString} from '../pipes/various/status-to-string'; -import { ConfirmationComponent } from '../widgets/confirmation/confirmation.component'; -import {MenuItem} from 'primeng/primeng'; - -import { ProjectTableFilterPipe } from '../pipes/project-table-filter.pipe'; - - -declare var $ :any; - -import '../../assets/custom.js'; -declare function simple_notifier(type: string, title: string, message:string): any; - - -@Component({ - selector: 'projects', - templateUrl: 'project.html', - styleUrls: ['./project.css'], - providers: [ServerService] -}) - -export class ProjectsComponent implements OnInit{ - -// Start ALTERNATIVE - //whole dmp data model - tableData : any[] = new Array(); - - //organisation editor data model - editingOrganisation: any = {}; - organisationEditorForm : any; - - //required by the table - public filterQuery = ""; - public rowsOnPage = 10; - public sortBy = "label"; - public sortOrder = "asc"; - - - // for tableIds - showIDs : boolean = false; - - statusDropDown: DropdownField; - - project: any; - - whoami: any; - onlyMyProjects : boolean = false; - - options: DatepickerOptions = { - minYear: 1900, - maxYear: 2050, - displayFormat: 'MMM D[,] YYYY', - barTitleFormat: 'MMMM YYYY', - firstCalendarDay: 0 // 0 - Sunday, 1 - Monday - }; - - //breadcrumbHome: MenuItem = {icon: 'fa fa-home'}; - breadcrumbData: MenuItem[] = new Array(); - - constructor( - private serverService: ServerService, - private route: ActivatedRoute, - private router: Router) { - this.statusDropDown = new DropdownField(); - this.statusDropDown.options= [{key:'0', value:"Active"},{key:'1', value:"Inactive"}] - this.project = this.getEmptyProject(); - } - - ngAfterViewInit() { - - } - -getEmptyProject(){ - return { - label: '', - abbreviation:'', - reference:'', - uri:'', - description:'', - enddate:'', - startdate:'' - } -} - - - ngOnInit() { - - this.getProjects(); - - this.serverService.whoami().subscribe( - response => { - this.whoami = response; - console.log(this.whoami) - }, - err => { - simple_notifier("danger",null,"Could not retrieve user config"); - } - ); - - } - - -getProjects(muted? : boolean){ - //this.serverService.getProjectsOfUser().subscribe( - this.serverService.getAllProjects().subscribe( - response => { - this.tableData = response; - if(muted && muted!=true) - simple_notifier("success",null,"Updated projects table"); - }, - err => { - simple_notifier("danger",null,"Could not retrieve projects"); - } -); -} - - - -showDatasets(){ //dmpId, event - //this.dataSetVisibe = true; - -} - - -SaveProject(){ - - let action : Observable; - - if(this.project.id == null) //means it's a new one - action = this.serverService.createProject(this.project); - else - action = this.serverService.updateProject(this.project); - action.subscribe( - response =>{ - this.getProjects(); - simple_notifier("success",null, (this.project.id == null) ? "Created" : "Updated" +" projects table"); - }, - error => { - simple_notifier("danger",null, "Could not "+ (this.project.id == null) ? "create" : "update" + " projects table"); - } - ); - - $("#newEditProjectModal").modal("hide"); -} - - newProject(){ - this.project = this.getEmptyProject(); - $("#newEditProjectModal").modal("show"); - - } - - editRow(item, event){ - this.project = Object.assign({}, item); //this will have id - that defines whether it's an update or not - this.project.creationUser = {"id":this.project.creationUser.id}; - $("#newEditProjectModal").modal("show"); - - return false; - } - - - /* - markProjectForDelete(project){ - this.project = project; - } - - deleteProject(confirmation){ - if(confirmation==true) - this.deleteRow(this.project); - } - */ - -} diff --git a/dmp-frontend/src/app/services/data-management-plan/data-management-plan.service.ts b/dmp-frontend/src/app/services/data-management-plan/data-management-plan.service.ts new file mode 100644 index 000000000..6cc27661a --- /dev/null +++ b/dmp-frontend/src/app/services/data-management-plan/data-management-plan.service.ts @@ -0,0 +1,35 @@ +import 'rxjs/add/operator/map'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { HostConfiguration } from './../../app.constants'; +import { BaseHttpService } from '../../utilities/cite-http-service-module/base-http.service'; +import { Observable } from 'rxjs/Observable'; +import { DataTableRequest } from '../../models/data-table/DataTableRequest'; +import { DataTableData } from '../../models/data-table/DataTableData'; +import { DmpListingModel } from '../../models/data-managemnt-plans/DmpListingModel'; +import { DmpModel } from '../../models/data-managemnt-plans/DmpModel'; + + +@Injectable() +export class DataManagementPlanService { + + private actionUrl: string; + private headers: HttpHeaders; + + constructor(private http: BaseHttpService) { + + this.actionUrl = HostConfiguration.Server + 'api/dmp/'; + + this.headers = new HttpHeaders(); + this.headers = this.headers.set('Content-Type', 'application/json'); + this.headers = this.headers.set('Accept', 'application/json'); + } + + getPaged(dataTableRequest: DataTableRequest): Observable> { + return this.http.post>(this.actionUrl + 'getPaged', JSON.stringify(dataTableRequest), { headers: this.headers }); + } + + getSingle(id: string): Observable { + return this.http.get(this.actionUrl + id, { headers: this.headers }); + } +} diff --git a/dmp-frontend/src/app/services/project/project.service.ts b/dmp-frontend/src/app/services/project/project.service.ts new file mode 100644 index 000000000..153d3cbd6 --- /dev/null +++ b/dmp-frontend/src/app/services/project/project.service.ts @@ -0,0 +1,35 @@ +import 'rxjs/add/operator/map'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { HostConfiguration } from './../../app.constants'; +import { BaseHttpService } from '../../utilities/cite-http-service-module/base-http.service'; +import { Observable } from 'rxjs/Observable'; +import { DataTableRequest } from '../../models/data-table/DataTableRequest'; +import { DataTableData } from '../../models/data-table/DataTableData'; +import { ProjectListingModel } from '../../models/projects/ProjectListingModel'; +import { ProjectModel } from '../../models/projects/ProjectModel'; + + +@Injectable() +export class ProjectService { + + private actionUrl: string; + private headers: HttpHeaders; + + constructor(private http: BaseHttpService) { + + this.actionUrl = HostConfiguration.Server + 'api/project/'; + + this.headers = new HttpHeaders(); + this.headers = this.headers.set('Content-Type', 'application/json'); + this.headers = this.headers.set('Accept', 'application/json'); + } + + getPaged(dataTableRequest: DataTableRequest): Observable> { + return this.http.post>(this.actionUrl + 'getPaged', JSON.stringify(dataTableRequest), { headers: this.headers }); + } + + getSingle(id: string): Observable { + return this.http.get(this.actionUrl + id, { headers: this.headers }); + } +} diff --git a/dmp-frontend/src/app/shared/components/criteria/base/base-criteria.component.ts b/dmp-frontend/src/app/shared/components/criteria/base/base-criteria.component.ts new file mode 100644 index 000000000..51adac6f2 --- /dev/null +++ b/dmp-frontend/src/app/shared/components/criteria/base/base-criteria.component.ts @@ -0,0 +1,102 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { FormControl, FormGroup, NgForm, FormArray, AbstractControl } from '@angular/forms'; +import { CriteriaErrorModel } from '../../../../models/criteria/criteriaErrorModel'; + +@Component({ + selector: 'base-criteria-component', + template: '', + providers: [ + + ] +}) + +export class BaseCriteriaComponent implements OnInit { + + public refreshCallback: Function = null; + public formGroup: FormGroup = null; + + constructor( + public baseErrorModel?: CriteriaErrorModel, + ) { + } + + ngOnInit() { + if (this.baseErrorModel == null) { this.baseErrorModel = new CriteriaErrorModel(); } + } + + controlModified(): void { + this.clearErrorModel(); + if (!this.isFormValid()) { return; } + if (this.refreshCallback != null) { this.refreshCallback(); } + } + + public isFormValid(): boolean { + this.touchAllFormFields(this.formGroup); + this.validateAllFormFields(this.formGroup); + return this.formGroup.valid; + } + + public getFormData(): any { + return this.formGroup.value; + } + + public getFormControl(controlName: string): AbstractControl { + return this.formGroup.get(controlName); + } + + public disableFormFields(formControl: AbstractControl) { + formControl.disable(); + } + + public validateAllFormFields(formControl: AbstractControl) { + if (formControl instanceof FormControl) { + formControl.updateValueAndValidity({ emitEvent: false }) + } else if (formControl instanceof FormGroup) { + Object.keys(formControl.controls).forEach(item => { + const control = formControl.get(item); + this.validateAllFormFields(control); + }) + } else if (formControl instanceof FormArray) { + formControl.controls.forEach(item => { + this.validateAllFormFields(item); + }) + } + } + + public touchAllFormFields(formControl: AbstractControl) { + if (formControl instanceof FormControl) { + formControl.markAsTouched(); + } else if (formControl instanceof FormGroup) { + Object.keys(formControl.controls).forEach(item => { + const control = formControl.get(item); + this.touchAllFormFields(control); + }) + } else if (formControl instanceof FormArray) { + formControl.controls.forEach(item => { + this.touchAllFormFields(item); + }) + } + } + + setRefreshCallback(callback: Function): void { + this.refreshCallback = callback; + } + + onCallbackError(error: any) { + this.setErrorModel(error.error); + this.validateAllFormFields(this.formGroup); + } + + public setErrorModel(errorModel: CriteriaErrorModel) { + Object.keys(errorModel).forEach(item => { + (this.baseErrorModel)[item] = (errorModel)[item]; + }) + } + + public clearErrorModel() { + Object.keys(this.baseErrorModel).forEach(item => { + (this.baseErrorModel)[item] = ''; + }) + } + +} diff --git a/dmp-frontend/src/app/shared/components/criteria/projects/projects-criteria.component.html b/dmp-frontend/src/app/shared/components/criteria/projects/projects-criteria.component.html new file mode 100644 index 000000000..5e5a437df --- /dev/null +++ b/dmp-frontend/src/app/shared/components/criteria/projects/projects-criteria.component.html @@ -0,0 +1,54 @@ +
+ +
+
+ + + {{baseErrorModel['Criteria.PeriodFrom']}} + + + +
+
+ + + {{baseErrorModel['Criteria.PeriodTo']}} + + + +
+
+ + + {{'TYPES.FORM-TYPE.ANY' | translate}} + {{getFormTypeWithLanguage(type)}} + + +
+
+ + + {{getFormStatusWithLanguage(status)}} + + +
+
+
+
\ No newline at end of file diff --git a/dmp-frontend/src/app/shared/components/criteria/projects/projects-criteria.component.scss b/dmp-frontend/src/app/shared/components/criteria/projects/projects-criteria.component.scss new file mode 100644 index 000000000..263cc1548 --- /dev/null +++ b/dmp-frontend/src/app/shared/components/criteria/projects/projects-criteria.component.scss @@ -0,0 +1,10 @@ +.form-criteria { + mat-form-field { + padding-bottom: 5px; + width: 100%; + } + + mat-card { + padding-bottom: 0px; + } +} diff --git a/dmp-frontend/src/app/shared/components/criteria/projects/projects-criteria.component.ts b/dmp-frontend/src/app/shared/components/criteria/projects/projects-criteria.component.ts new file mode 100644 index 000000000..3868df811 --- /dev/null +++ b/dmp-frontend/src/app/shared/components/criteria/projects/projects-criteria.component.ts @@ -0,0 +1,69 @@ +import { TranslateService } from '@ngx-translate/core'; +import { Component, OnInit } from '@angular/core'; +import { FormControl, FormGroup, FormBuilder, Validators } from '@angular/forms'; +import { BaseCriteriaComponent } from '../base/base-criteria.component'; +import { ValidationContext, Validation } from '../../../../utilities/validators/ValidationContext'; +import { BackendErrorValidator } from '../../../../utilities/validators/BackendErrorValidator'; +import { ProjectCriteria } from '../../../../models/criteria/project/ProjectCriteria'; +import { ProjectCriteriaErrorModel } from '../../../../models/criteria/project/ProjectCriteriaErrorModel'; + +@Component({ + selector: 'app-projects-criteria-component', + templateUrl: './projects-criteria.component.html', + styleUrls: ['./projects-criteria.component.scss'], + providers: [ + ] +}) + +export class ProjectCriteriaComponent extends BaseCriteriaComponent implements OnInit { + + // public form: ProjectType; + // public formStatus: ProjectStatus; + public criteria: ProjectCriteria = new ProjectCriteria(); + + constructor( + public language: TranslateService, + public errorModel: ProjectCriteriaErrorModel, + public formBuilder: FormBuilder + ) { + super(errorModel); + } + + ngOnInit() { + super.ngOnInit(); + if (this.criteria == null) { this.criteria = new ProjectCriteria(); } + if (this.formGroup == null) { this.formGroup = this.buildForm(); } + } + + setCriteria(criteria: ProjectCriteria): void { + this.criteria = criteria; + this.formGroup = this.buildForm(); + } + + public fromJSONObject(item: any): ProjectCriteria { + this.criteria = new ProjectCriteria(); + this.criteria.PeriodStart = new Date(item.PeriodStart); + this.criteria.PeriodEnd = new Date(item.PeriodEnd); + return this.criteria; + } + + buildForm(): FormGroup { + const context: ValidationContext = this.createValidationContext(); + + return this.formBuilder.group({ + periodStart: [this.criteria.PeriodStart, context.getValidation('periodStart').validators], + periodEnd: [this.criteria.PeriodEnd, context.getValidation('periodEnd').validators], + }); + } + + createValidationContext(): ValidationContext { + const validationContext: ValidationContext = new ValidationContext(); + const validationArray: Validation[] = new Array(); + + validationArray.push({ key: 'periodStart', validators: [BackendErrorValidator(this.errorModel, 'Criteria.PeriodStart')] }); //must add 'Criteria.' because the criteria validator is inside the request validator + validationArray.push({ key: 'periodEnd', validators: [BackendErrorValidator(this.errorModel, 'Criteria.PeriodEnd')] }); + + validationContext.validation = validationArray; + return validationContext; + } +} diff --git a/dmp-frontend/src/app/utilities/cite-http-service-module/base-http.service.ts b/dmp-frontend/src/app/utilities/cite-http-service-module/base-http.service.ts new file mode 100644 index 000000000..e08c3458f --- /dev/null +++ b/dmp-frontend/src/app/utilities/cite-http-service-module/base-http.service.ts @@ -0,0 +1,84 @@ +import { Injectable } from '@angular/core'; +import { Http, RequestOptions, Response, Headers } from '@angular/http'; +import { Observable } from 'rxjs/Observable'; +import { Router, ActivatedRoute, RouterStateSnapshot } from '@angular/router'; +import { MatSnackBar } from '@angular/material'; +import { TranslateService } from '@ngx-translate/core'; +import { HttpClient } from '@angular/common/http'; +import { AuthService } from '../../services/auth/auth.service'; +import { SnackBarNotificationComponent } from '../../shared/components/notificaiton/snack-bar-notification.component'; + +@Injectable() +export class BaseHttpService { + constructor( + protected http: HttpClient, + private router: Router, + private authService: AuthService, + public language: TranslateService, + public snackBar: MatSnackBar, + + ) { + } + get(url: string, options?: any): Observable { + return this.interceptRepsonse(this.http.get(url, this.buildRequestOptions(options))); + } + post(url: string, body: any, options?: any): Observable { + return this.interceptRepsonse(this.http.post(url, body, this.buildRequestOptions(options))); + } + put(url: string, body: any, options?: any): Observable { + return this.interceptRepsonse(this.http.put(url, body, this.buildRequestOptions(options))); + } + delete(url: string, options?: any): Observable { + return this.interceptRepsonse(this.http.delete(url, this.buildRequestOptions(options))); + } + patch(url: string, body: any, options?: any): Observable { + return this.interceptRepsonse(this.http.patch(url, body, this.buildRequestOptions(options))); + } + head(url: string, options?: any): Observable { + return this.interceptRepsonse(this.http.head(url, this.buildRequestOptions(options))); + } + options(url: string, options?: any): Observable { + return this.interceptRepsonse(this.http.options(url, this.buildRequestOptions(options))); + } + + protected buildRequestOptions(options?: any): Object { + if (options == null) { + options = new RequestOptions(); + } + if (options.headers == null) { + options.headers = new Headers(); + } + if (!options.headers.has('Content-Type')) { + options.headers = options.headers.set('Content-Type', 'application/json'); + } + if (!options.headers.has('Content-Type')) { + options.headers = options.headers.set('Content-Type', 'application/json'); + } + if (!options.headers.has('AuthToken')) { + const principal = this.authService.current(); + if (principal) { + options.headers = options.headers.set('AuthToken', principal.token); + } + } + + return options; + } + + private interceptRepsonse(observable: Observable): Observable { + return observable + .catch((error) => { + if (error.status === 401) { + this.snackBar.openFromComponent(SnackBarNotificationComponent, { + data: { message: 'GENERAL.SNACK-BAR.SUCCESSFUL-LOGOUT', language: this.language }, + duration: 3000, + extraClasses: ['snackbar-success'] + }) + this.router.navigate(['/unauthorized']); + //this.notification.httpError(error); + return Observable.of(); + } else { + return Observable.throw(error); + } + }); + } +} diff --git a/dmp-frontend/src/app/utilities/cite-http-service-module/cite-http.module.ts b/dmp-frontend/src/app/utilities/cite-http-service-module/cite-http.module.ts new file mode 100644 index 000000000..b37b832b7 --- /dev/null +++ b/dmp-frontend/src/app/utilities/cite-http-service-module/cite-http.module.ts @@ -0,0 +1,21 @@ +import { CommonModule } from '@angular/common'; +import { NgModule, ModuleWithProviders } from '@angular/core'; +import { AuthService } from '../../services/auth/auth.service'; +import { BaseHttpService } from './base-http.service'; + +@NgModule({ + imports: [ + CommonModule + ] +}) +export class BaseHttpModule { + static forRoot(): ModuleWithProviders { + return { + ngModule: BaseHttpModule, + providers: [ + AuthService, + BaseHttpService + ] + }; + } +} diff --git a/dmp-frontend/src/app/utilities/validators/BackendErrorValidator.ts b/dmp-frontend/src/app/utilities/validators/BackendErrorValidator.ts new file mode 100644 index 000000000..14adbee9a --- /dev/null +++ b/dmp-frontend/src/app/utilities/validators/BackendErrorValidator.ts @@ -0,0 +1,9 @@ +import { ValidatorFn, AbstractControl } from '@angular/forms'; +import { BaseErrorModel } from '../../models/error/BaseErrorModel'; + +export function BackendErrorValidator(errorModel: BaseErrorModel, propertyName: string): ValidatorFn { + return (control: AbstractControl): { [key: string]: any } => { + const error: string = (errorModel)[propertyName]; + return error ? { 'backendError': { value: error } } : null; + }; +} diff --git a/dmp-frontend/src/app/utilities/validators/ValidationContext.ts b/dmp-frontend/src/app/utilities/validators/ValidationContext.ts new file mode 100644 index 000000000..cf5019697 --- /dev/null +++ b/dmp-frontend/src/app/utilities/validators/ValidationContext.ts @@ -0,0 +1,20 @@ +import { ValidatorFn } from '@angular/forms'; + +export class ValidationContext { + validation: Validation[]; + + getValidation(key: string): Validation { + for (let i = 0; i < this.validation.length; i++) { + if (this.validation[i].key === key) { + return this.validation[i]; + } + } + throw new Error('Key Was Not Found In The Validation Context'); + } +} + +export class Validation { + key: string; + validators?: ValidatorFn[] = new Array(); + descendantValidations?: ValidationContext; +}