This commit is contained in:
annampak 2017-12-19 14:47:22 +02:00
commit b9e1270a1b
28 changed files with 294 additions and 651 deletions

View File

@ -0,0 +1,31 @@
.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;
}
.full-width {
width: 100%;
}
.mat-card {
margin: 16px 0;
}
.mat-row {
cursor: pointer;
}
mat-row:hover {
background-color: lightgray;
}

View File

@ -17,7 +17,7 @@ import { DatasetListingModel } from "../models/datasets/DatasetListingModel";
@Component({
selector: 'app-dataset-listing-component',
templateUrl: 'dataset-listing.component.html',
styleUrls: ['./dataset-listing.component.css'],
styleUrls: ['./dataset-listing.component.scss'],
providers: [DatasetService]
})
export class DatasetListingComponent implements OnInit {
@ -95,7 +95,7 @@ export class DatasetDataSource extends DataSource<DatasetListingModel> {
this.isLoadingResults = true;
});
const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
const request = new DataTableRequest(startIndex, this._paginator.pageSize);
const request = new DataTableRequest<DatasetCriteria>(startIndex, this._paginator.pageSize);
request.criteria = this._criteria.criteria;
return this._service.getPaged(request);
})

View File

@ -1,20 +0,0 @@
.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;
}

View File

@ -1,190 +1,57 @@
<div class="container-fluid">
<h3>{{'DMP-LISTING.TITLE' | translate}}</h3>
<h3>{{'DMP-LISTING.TITLE' | translate}}</h3>
<app-dmp-criteria-component></app-dmp-criteria-component>
<mat-card class="mat-card">
<mat-progress-bar *ngIf="dataSource?.isLoadingResults" mode="query"></mat-progress-bar>
<app-dmp-criteria-component></app-dmp-criteria-component>
<mat-card class="mat-card">
<mat-progress-bar *ngIf="dataSource?.isLoadingResults" mode="query"></mat-progress-bar>
<mat-table [dataSource]="dataSource" matSort>
<mat-table [dataSource]="dataSource" matSort>
<!-- Column Definition: Name -->
<ng-container cdkColumnDef="name">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.NAME' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.name}}</mat-cell>
</ng-container>
<!-- Column Definition: Name -->
<ng-container cdkColumnDef="name">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.NAME' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.label}}</mat-cell>
</ng-container>
<!-- Column Definition: Αbbreviation -->
<ng-container cdkColumnDef="abbreviation">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.ABBREVIATION' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.abbreviation}} </mat-cell>
</ng-container>
<!-- Column Definition: Project -->
<ng-container cdkColumnDef="project">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.PROJECT' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.project}} </mat-cell>
</ng-container>
<!-- Column Definition: Start -->
<ng-container cdkColumnDef="start">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.START' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.start}} </mat-cell>
</ng-container>
<!-- Column Definition: Profile -->
<ng-container cdkColumnDef="profile">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.PROFILE' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.profile}} </mat-cell>
</ng-container>
<!-- Column Definition: End -->
<ng-container cdkColumnDef="end">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.END' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.end}} </mat-cell>
</ng-container>
<!-- Column Definition: Researchers -->
<ng-container cdkColumnDef="researchers">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.RESEARCHERS' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.researchers}} </mat-cell>
</ng-container>
<!-- Column Definition: Submission Time -->
<ng-container cdkColumnDef="actions">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.ACTIONS' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"></mat-cell>
</ng-container>
<!-- Column Definition: Organisations -->
<ng-container cdkColumnDef="organisations">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.ORGANISATIONS' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.organisations}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns" (click)="rowClick(row.id)"></mat-row>
<!-- Column Definition: Version -->
<ng-container cdkColumnDef="version">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.VERSION' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.version}}</mat-cell>
</ng-container>
</mat-table>
<mat-paginator #paginator
[length]="dataSource?.totalCount"
[pageSizeOptions]="[10, 25, 100]">
</mat-paginator>
</mat-card>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns" (click)="rowClick(row.id)"></mat-row>
<button mat-fab class="mat-fab-bottom-right" color="primary" [routerLink]=" ['./new'] ">
<mat-icon class="mat-24">add</mat-icon>
</button>
</mat-table>
<mat-paginator #paginator [length]="dataSource?.totalCount" [pageSizeOptions]="[10, 25, 100]">
</mat-paginator>
</mat-card>
<button mat-fab class="mat-fab-bottom-right" color="primary" [routerLink]=" ['./new'] ">
<mat-icon class="mat-24">add</mat-icon>
</button>
</div>
<!-- <meta name="google-signin-client_id" content="524432312250-vhgidft856v8qftsc81kls4c74v87d8o.apps.googleusercontent.com">
<table class="table table-striped" [mfData]="tableData | projectTableFilter : filterQuery : whoami?.id : onlyMyProjects"
#mf="mfDataTable" [mfRowsOnPage]="rowsOnPage" [(mfSortBy)]="sortBy" [(mfSortOrder)]="sortOrder">
<thead>
<tr>
<th colspan="1">
<input class="form-control" [(ngModel)]="filterQuery" placeholder='Filter' />
</th>
<th style="width:50px;">
<button class="btn btn-default" (click)="getProjects('false')">
<span class="glyphicon glyphicon-refresh"></span>
</button>
</th>
<th colspan="1">
<div class="checkbox">
<label><input type="checkbox" [(ngModel)]="onlyMyProjects" >Show only my projects</label>
</div>
</th>
</tr>
<tr>
<th [ngClass]="{true:'visible', false:'invisible'}[showIDs]">
<mfDefaultSorter by="id">ID</mfDefaultSorter>
</th>
<th>
<mfDefaultSorter by="label">Label</mfDefaultSorter>
</th>
<th>
<mfDefaultSorter by="abbreviation">Αbbreviation</mfDefaultSorter>
</th>
<th>
<mfDefaultSorter by="startdate">Start Date</mfDefaultSorter>
</th>
<th>
<mfDefaultSorter by="enddate">End Date</mfDefaultSorter>
</th>
<th>
<mfDefaultSorter by="status">Status</mfDefaultSorter>
</th>
<th>
<mfDefaultSorter by="description">Description</mfDefaultSorter>
</th>
<th>
<mfDefaultSorter>Actions </mfDefaultSorter>
</th>
</tr>
</thead>
<tbody>
<tr class="grayout-empty-table" *ngIf="!mf.data[0]">
<td colspan="7">No elements</td>
</tr>
<tr *ngFor="let project of mf.data" class="hover">
<td [ngClass]="{true:'visible', false:'invisible'}[showIDs]">{{project?.id}}</td>
<td>{{(project?.label?.length > 40) ? (project?.label | slice:0:40)+'...':(project?.label) }}</td>
<td>{{project?.abbreviation}}</td>
<td>{{project?.startdate | date:'medium' }}</td>
<td>{{project?.enddate | date:'medium'}}</td>
<td>{{project?.status | statusToString}}</td>
<td>{{(project?.description?.length > 40) ? (project?.description | slice:0:40)+'...':(project?.description) }}</td>
<td>
<a [ngClass]="{'not-active': whoami?.id!=project?.creationUser?.id }" class="editGridColumn" (click)="editRow(project, $event)">
<i class="fa fa-pencil fa-fw" data-toggle="tooltip" title="edit properties" id="editDMP" ></i>
</a>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="1">
<button type="button" class="btn btn-info btncustom" (click)="newProject(item)">New Project</button>
</td>
<td colspan="5">
<mfBootstrapPaginator [rowsOnPageSet]="[5,10,20]"></mfBootstrapPaginator>
</td>
</tr>
</tfoot>
</table>
<div class="modal fade" id="newEditProjectModal" tabindex="-1" role="dialog" aria-labelledby="newProjectModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Project</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form #newProjectForm="ngForm" (ngSubmit)="SaveProject()" novalidate>
<label for="label-name" class="form-control-label">Label:</label>
<input type="text" class="form-control" id="label-name" [(ngModel)]= "project.label" name = "label" required>
<div class="form-group">
<label for="abbreviation-text" class="form-control-label">Abbreviation:</label>
<input class="form-control" id="abbreviation-text" [(ngModel)]= "project.abbreviation" name = "abbreviation">
</div>
<div class="form-group">
<label for="reference-text" class="form-control-label">Reference:</label>
<input class="form-control" id="reference-text" [(ngModel)]= "project.reference" name = "reference">
</div>
<div class="form-group">
<label for="uri-text" class="form-control-label">Uri:</label>
<input class="form-control" id="uri-text" [(ngModel)]= "project.uri" name = "uri">
</div>
<div class="form-group">
<label for="start-date" class="form-control-label">Start Date:</label>
<input class="form-control" type='date' class="form-control" [(ngModel)]= "project.startdate" id='start-date' name = "startdate" required/>
</div>
<div class="form-group">
<label for="end-date" class="form-control-label">End Date:</label>
<input class="form-control" type='date' class="form-control" [(ngModel)]= "project.enddate" id='end-date' name = "enddate" required/>
</div>
<div class="form-group">
<label for="status-name" class="col-form-label">Status:</label>
<select class="form-control" id="statusid" [(ngModel)]="project.status" name="statusDropDown">
<option *ngFor="let opt of statusDropDown.options" [value]="opt.key">{{opt.value}}</option>
</select>
</div>
<div class="form-group">
<label for="code-name" class="form-control-label">Description:</label>
<textarea rows="3" class="form-control" name="desc" id="description" [(ngModel)]= "project.description"> </textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary" [disabled]="!newProjectForm.form.valid" (click)="SaveProject();">Save project</button>
</div>
</div>
</div>
</div>
-->

View File

@ -0,0 +1,31 @@
.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;
}
.full-width {
width: 100%;
}
.mat-card {
margin: 16px 0;
}
.mat-row {
cursor: pointer;
}
mat-row:hover {
background-color: lightgray;
}

View File

@ -16,20 +16,20 @@ import { DataManagementPlanListingModel } from "../models/data-managemnt-plans/D
@Component({
selector: 'app-dmp-listing-component',
templateUrl: 'dmp-listing.component.html',
styleUrls: ['./dmp-listing.component.css'],
styleUrls: ['./dmp-listing.component.scss'],
providers: [DataManagementPlanService]
})
export class DataManagementPlanListingComponent implements OnInit, AfterViewInit {
export class DataManagementPlanListingComponent implements OnInit {
@ViewChild(MatPaginator) _paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
@ViewChild(DataManagementPlanCriteriaComponent) criteria: DataManagementPlanCriteriaComponent;
dataSource: DataManagementPlanDataSource | null;
displayedColumns: String[] = ['name', 'abbreviation', 'start', 'end'];
displayedColumns: String[] = ['name', 'project', 'profile', 'researchers', 'organisations', 'version'];
constructor(
private projectService: DataManagementPlanService,
private dataManagementPlanService: DataManagementPlanService,
private router: Router,
private languageService: TranslateService,
public snackBar: MatSnackBar,
@ -38,19 +38,17 @@ export class DataManagementPlanListingComponent implements OnInit, AfterViewInit
}
ngOnInit() {
}
ngAfterViewInit() {
this.criteria.setCriteria(this.getDefaultCriteria());
this.refresh();
this.criteria.setRefreshCallback(() => this.refresh());
}
refresh() {
this.dataSource = new DataManagementPlanDataSource(this.projectService, this._paginator, this.sort, this.languageService, this.snackBar, this.criteria, );
this.dataSource = new DataManagementPlanDataSource(this.dataManagementPlanService, this._paginator, this.sort, this.languageService, this.snackBar, this.criteria, );
}
rowClick(rowId: String) {
this.router.navigate(['/forms/' + rowId]);
this.router.navigate(['/dmp/' + rowId]);
}
getDefaultCriteria(): DataManagementPlanCriteria {
@ -97,7 +95,7 @@ export class DataManagementPlanDataSource extends DataSource<DataManagementPlanL
this.isLoadingResults = true;
});
const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
const request = new DataTableRequest(startIndex, this._paginator.pageSize);
const request = new DataTableRequest<DataManagementPlanCriteria>(startIndex, this._paginator.pageSize);
request.criteria = this._criteria.criteria;
return this._service.getPaged(request);
})

View File

@ -1,8 +1,8 @@
<div class="project-editor">
<div class="data-management-plan-editor">
<form *ngIf="formGroup" (ngSubmit)="formSubmit()" [formGroup]="formGroup">
<mat-card>
<mat-card-title *ngIf="isNew">{{'DMP-EDITOR.TITLE.NEW' | translate}}</mat-card-title>
<mat-card-title *ngIf="!isNew">{{'DMP-EDITOR.TITLE.EDIT' | translate}} {{project.label}}</mat-card-title>
<mat-card-title *ngIf="!isNew">{{formGroup.get('label').value}}</mat-card-title>
<mat-card-content>
<mat-form-field>
@ -11,44 +11,6 @@
<mat-error *ngIf="formGroup.get('label').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<!-- <mat-form-field>
<input matInput placeholder="{{'DMP-EDITOR.FIELDS.ABBREVIATION' | translate}}" type="text" name="abbreviation" formControlName="abbreviation"
required>
<mat-error *ngIf="formGroup.get('abbreviation').errors?.backendError">{{baseErrorModel.abbreviation}}</mat-error>
<mat-error *ngIf="formGroup.get('abbreviation').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field>
<input matInput placeholder="{{'DMP-EDITOR.FIELDS.URI' | translate}}" type="text" name="uri" formControlName="uri" required>
<mat-error *ngIf="formGroup.get('uri').errors?.backendError">{{baseErrorModel.uri}}</mat-error>
<mat-error *ngIf="formGroup.get('uri').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> -->
<!-- <table class="input-table full-width">
<tr>
<td>
<mat-form-field>
<input matInput (focus)="startDate.open()" (click)="startDate.open()" placeholder="{{'DMP-EDITOR.FIELDS.START' | translate}}"
class="table-input" [matDatepicker]="startDate" formControlName="startDate" required>
<mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
<mat-datepicker #startDate></mat-datepicker>
<mat-error *ngIf="formGroup.get('startDate').errors?.backendError">{{baseErrorModel.startDate}}</mat-error>
<mat-error *ngIf="formGroup.get('startDate').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</td>
<td>
<mat-form-field>
<input matInput (focus)="endDate.open()" (click)="endDate.open()" placeholder="{{'DMP-EDITOR.FIELDS.END' | translate}}"
class="table-input" [matDatepicker]="endDate" formControlName="endDate" required>
<mat-datepicker-toggle matSuffix [for]="endDate"></mat-datepicker-toggle>
<mat-datepicker #endDate></mat-datepicker>
<mat-error *ngIf="formGroup.get('endDate').errors?.backendError">{{baseErrorModel.endDate}}</mat-error>
<mat-error *ngIf="formGroup.get('endDate').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</td>
</tr>
</table> -->
<mat-form-field class="full-width">
<textarea matInput class="description-area" placeholder="{{'DMP-EDITOR.FIELDS.DESCRIPTION' | translate}}" formControlName="description"
required></textarea>

View File

@ -10,7 +10,7 @@
background: rgba(0, 0, 0, 0.32);
}
.project-editor {
.data-management-plan-editor {
mat-form-field {
width: 100%;
padding: 3px;

View File

@ -0,0 +1,6 @@
import { FormGenerator } from "../../utilities/forms/FormGenerator";
import { BaseCriteriaErrorModel } from "./BaseCriteriaErrorModel";
export class RequestItem<T> {
public criteria: T;
}

View File

@ -1,6 +1,6 @@
import { BaseCriteria } from "../BaseCriteria";
import { ProjectModel } from "../../projects/ProjectModel";
export class DataManagementPlanCriteria extends BaseCriteria {
public PeriodStart: Date;
public PeriodEnd: Date;
public projects: ProjectModel[] = [];
}

View File

@ -1,6 +1,5 @@
import { BaseCriteriaErrorModel } from "../BaseCriteriaErrorModel";
export class DataManagementPlanCriteriaErrorModel extends BaseCriteriaErrorModel{
public PeriodStart: String;
public PeriodEnd: String;
}

View File

@ -3,24 +3,20 @@ import { Serializable } from "../Serializable";
export class DataManagementPlanListingModel implements Serializable<DataManagementPlanListingModel> {
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;
public project: String;
public profile: String;
public researchers: String;
public organisations: String;
public version: number;
fromJSONObject(item: any): DataManagementPlanListingModel {
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;
this.project = item.project;
this.profile = item.profile;
this.researchers = item.researchers;
this.organisations = item.organisations;
this.version = item.version;
return this;
}

View File

@ -5,6 +5,10 @@ import { BackendErrorValidator } from "../../utilities/validators/BackendErrorVa
import { BaseErrorModel } from "../error/BaseErrorModel";
import { AutoCompleteItem } from "../../shared/components/autocomplete/AutoCompleteItem";
import { ExternalSourcesItemModel } from "../external-sources/ExternalSourcesItemModel";
import { ProjectModel } from "../projects/ProjectModel";
import { OrganisationModel } from "../organisation/OrganisationModel";
import { ResearcherModel } from "../researcher/ResearcherModel";
import { JsonSerializer } from "../../utilities/JsonSerializer";
export class DataManagementPlanModel implements Serializable<DataManagementPlanModel> {
public id: String;
@ -13,9 +17,9 @@ export class DataManagementPlanModel implements Serializable<DataManagementPlanM
public version: number;
public status: String;
public description: String;
public selectedProject: AutoCompleteItem;
public organisations: ExternalSourcesItemModel[] = [];
public researchers: ExternalSourcesItemModel[] = [];
public project: ProjectModel;
public organisations: OrganisationModel[] = [];
public researchers: ResearcherModel[] = [];
public errorModel: BaseErrorModel = new BaseErrorModel();
@ -26,6 +30,9 @@ export class DataManagementPlanModel implements Serializable<DataManagementPlanM
this.version = item.version;
this.status = item.status;
this.description = item.description;
this.project = new JsonSerializer<ProjectModel>().fromJSONObject(item.project, ProjectModel);
this.organisations = new JsonSerializer<OrganisationModel>().fromJSONArray(item.organisations, OrganisationModel);
this.researchers = new JsonSerializer<ResearcherModel>().fromJSONArray(item.researchers, ResearcherModel);
return this;
}
@ -39,6 +46,7 @@ export class DataManagementPlanModel implements Serializable<DataManagementPlanM
version: [{ value: this.version, disabled: disabled }, context.getValidation('version').validators],
status: [{ value: this.status, disabled: disabled }, context.getValidation('status').validators],
description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators],
project: [{ value: this.project, disabled: disabled }, context.getValidation('project').validators],
organisations: [{ value: this.organisations, disabled: disabled }, context.getValidation('description').validators],
researchers: [{ value: this.researchers, disabled: disabled }, context.getValidation('researchers').validators],
});
@ -53,6 +61,7 @@ export class DataManagementPlanModel implements Serializable<DataManagementPlanM
baseContext.validation.push({ key: 'version', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'version')] });
baseContext.validation.push({ key: 'status', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'status')] });
baseContext.validation.push({ key: 'description', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'description')] });
baseContext.validation.push({ key: 'project', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'project')] });
baseContext.validation.push({ key: 'organisations', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'organisations')] });
baseContext.validation.push({ key: 'researchers', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'researchers')] });

View File

@ -1,11 +1,12 @@
import { BaseCriteria } from "../criteria/BaseCriteria";
import { RequestItem } from "../criteria/RequestItem";
export class DataTableRequest {
export class DataTableRequest<T> extends RequestItem<T> {
offset = 0;
length = 0;
criteria: BaseCriteria;
constructor(offset: number, length: number) {
super();
this.length = length;
this.offset = offset;
}

View File

@ -0,0 +1,20 @@
import { Serializable } from "../Serializable";
export class OrganisationModel implements Serializable<OrganisationModel> {
public id: String;
public label: String;
public abbreviation: String;
public reference: String;
public uri: String;
fromJSONObject(item: any): OrganisationModel {
this.id = item.id;
this.label = item.label;
this.abbreviation = item.abbreviation;
this.reference = item.reference;
this.uri = item.uri;
return this;
}
}

View File

@ -0,0 +1,17 @@
import { Serializable } from "../Serializable";
export class ResearcherModel implements Serializable<ResearcherModel> {
public id: String;
public label: String;
public uri: String;
public email: String;
fromJSONObject(item: any): ResearcherModel {
this.id = item.id;
this.label = item.label;
this.email = item.email;
this.uri = item.uri;
return this;
}
}

View File

@ -32,10 +32,10 @@
</ng-container>
<!-- Column Definition: Submission Time -->
<ng-container cdkColumnDef="actions">
<!-- <ng-container cdkColumnDef="actions">
<mat-header-cell *matHeaderCellDef>{{'PROJECT-LISTING.COLUMNS.ACTIONS' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"></mat-cell>
</ng-container>
</ng-container> -->
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns" (click)="rowClick(row.id)"></mat-row>
@ -51,140 +51,3 @@
<mat-icon class="mat-24">add</mat-icon>
</button>
</div>
<!-- <meta name="google-signin-client_id" content="524432312250-vhgidft856v8qftsc81kls4c74v87d8o.apps.googleusercontent.com">
<table class="table table-striped" [mfData]="tableData | projectTableFilter : filterQuery : whoami?.id : onlyMyProjects"
#mf="mfDataTable" [mfRowsOnPage]="rowsOnPage" [(mfSortBy)]="sortBy" [(mfSortOrder)]="sortOrder">
<thead>
<tr>
<th colspan="1">
<input class="form-control" [(ngModel)]="filterQuery" placeholder='Filter' />
</th>
<th style="width:50px;">
<button class="btn btn-default" (click)="getProjects('false')">
<span class="glyphicon glyphicon-refresh"></span>
</button>
</th>
<th colspan="1">
<div class="checkbox">
<label><input type="checkbox" [(ngModel)]="onlyMyProjects" >Show only my projects</label>
</div>
</th>
</tr>
<tr>
<th [ngClass]="{true:'visible', false:'invisible'}[showIDs]">
<mfDefaultSorter by="id">ID</mfDefaultSorter>
</th>
<th>
<mfDefaultSorter by="label">Label</mfDefaultSorter>
</th>
<th>
<mfDefaultSorter by="abbreviation">Αbbreviation</mfDefaultSorter>
</th>
<th>
<mfDefaultSorter by="startdate">Start Date</mfDefaultSorter>
</th>
<th>
<mfDefaultSorter by="enddate">End Date</mfDefaultSorter>
</th>
<th>
<mfDefaultSorter by="status">Status</mfDefaultSorter>
</th>
<th>
<mfDefaultSorter by="description">Description</mfDefaultSorter>
</th>
<th>
<mfDefaultSorter>Actions </mfDefaultSorter>
</th>
</tr>
</thead>
<tbody>
<tr class="grayout-empty-table" *ngIf="!mf.data[0]">
<td colspan="7">No elements</td>
</tr>
<tr *ngFor="let project of mf.data" class="hover">
<td [ngClass]="{true:'visible', false:'invisible'}[showIDs]">{{project?.id}}</td>
<td>{{(project?.label?.length > 40) ? (project?.label | slice:0:40)+'...':(project?.label) }}</td>
<td>{{project?.abbreviation}}</td>
<td>{{project?.startdate | date:'medium' }}</td>
<td>{{project?.enddate | date:'medium'}}</td>
<td>{{project?.status | statusToString}}</td>
<td>{{(project?.description?.length > 40) ? (project?.description | slice:0:40)+'...':(project?.description) }}</td>
<td>
<a [ngClass]="{'not-active': whoami?.id!=project?.creationUser?.id }" class="editGridColumn" (click)="editRow(project, $event)">
<i class="fa fa-pencil fa-fw" data-toggle="tooltip" title="edit properties" id="editDMP" ></i>
</a>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="1">
<button type="button" class="btn btn-info btncustom" (click)="newProject(item)">New Project</button>
</td>
<td colspan="5">
<mfBootstrapPaginator [rowsOnPageSet]="[5,10,20]"></mfBootstrapPaginator>
</td>
</tr>
</tfoot>
</table>
<div class="modal fade" id="newEditProjectModal" tabindex="-1" role="dialog" aria-labelledby="newProjectModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Project</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form #newProjectForm="ngForm" (ngSubmit)="SaveProject()" novalidate>
<label for="label-name" class="form-control-label">Label:</label>
<input type="text" class="form-control" id="label-name" [(ngModel)]= "project.label" name = "label" required>
<div class="form-group">
<label for="abbreviation-text" class="form-control-label">Abbreviation:</label>
<input class="form-control" id="abbreviation-text" [(ngModel)]= "project.abbreviation" name = "abbreviation">
</div>
<div class="form-group">
<label for="reference-text" class="form-control-label">Reference:</label>
<input class="form-control" id="reference-text" [(ngModel)]= "project.reference" name = "reference">
</div>
<div class="form-group">
<label for="uri-text" class="form-control-label">Uri:</label>
<input class="form-control" id="uri-text" [(ngModel)]= "project.uri" name = "uri">
</div>
<div class="form-group">
<label for="start-date" class="form-control-label">Start Date:</label>
<input class="form-control" type='date' class="form-control" [(ngModel)]= "project.startdate" id='start-date' name = "startdate" required/>
</div>
<div class="form-group">
<label for="end-date" class="form-control-label">End Date:</label>
<input class="form-control" type='date' class="form-control" [(ngModel)]= "project.enddate" id='end-date' name = "enddate" required/>
</div>
<div class="form-group">
<label for="status-name" class="col-form-label">Status:</label>
<select class="form-control" id="statusid" [(ngModel)]="project.status" name="statusDropDown">
<option *ngFor="let opt of statusDropDown.options" [value]="opt.key">{{opt.value}}</option>
</select>
</div>
<div class="form-group">
<label for="code-name" class="form-control-label">Description:</label>
<textarea rows="3" class="form-control" name="desc" id="description" [(ngModel)]= "project.description"> </textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary" [disabled]="!newProjectForm.form.valid" (click)="SaveProject();">Save project</button>
</div>
</div>
</div>
</div>
-->

View File

@ -21,3 +21,11 @@
.mat-card {
margin: 16px 0;
}
.mat-row {
cursor: pointer;
}
mat-row:hover {
background-color: lightgray;
}

View File

@ -11,8 +11,6 @@ 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',
@ -27,7 +25,7 @@ export class ProjectListingComponent implements OnInit {
@ViewChild(ProjectCriteriaComponent) criteria: ProjectCriteriaComponent;
dataSource: ProjectDataSource | null;
displayedColumns: String[] = ['name', 'abbreviation', 'start', 'end', 'actions'];
displayedColumns: String[] = ['name', 'abbreviation', 'start', 'end'];
constructor(
private projectService: ProjectService,
@ -45,7 +43,7 @@ export class ProjectListingComponent implements OnInit {
}
refresh() {
this.dataSource = new ProjectDataSource(this.projectService, this._paginator, this.sort, this.languageService, this.snackBar, this.criteria );
this.dataSource = new ProjectDataSource(this.projectService, this._paginator, this.sort, this.languageService, this.snackBar, this.criteria);
}
rowClick(rowId: String) {
@ -56,19 +54,6 @@ export class ProjectListingComponent implements OnInit {
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 ProjectDataSource extends DataSource<ProjectListingModel> {
@ -109,7 +94,7 @@ export class ProjectDataSource extends DataSource<ProjectListingModel> {
this.isLoadingResults = true;
});
const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
const request = new DataTableRequest(startIndex, this._paginator.pageSize);
const request = new DataTableRequest<ProjectCriteria>(startIndex, this._paginator.pageSize);
request.criteria = this._criteria.criteria;
return this._service.getPaged(request);
})
@ -139,154 +124,3 @@ export class ProjectDataSource extends DataSource<ProjectListingModel> {
// 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<MenuItem>();
// 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<any>;
// 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);
// }
// */
// }

View File

@ -8,6 +8,7 @@ import { DataTableRequest } from '../../models/data-table/DataTableRequest';
import { DataTableData } from '../../models/data-table/DataTableData';
import { DataManagementPlanModel } from '../../models/data-managemnt-plans/DataManagementPlanModel';
import { DataManagementPlanListingModel } from '../../models/data-managemnt-plans/DataManagementPlanListingModel';
import { DataManagementPlanCriteria } from '../../models/criteria/data-management-plan/DataManagementPlanCriteria';
@Injectable()
@ -25,15 +26,19 @@ export class DataManagementPlanService {
this.headers = this.headers.set('Accept', 'application/json');
}
getPaged(dataTableRequest: DataTableRequest): Observable<DataTableData<DataManagementPlanListingModel>> {
getPaged(dataTableRequest: DataTableRequest<DataManagementPlanCriteria>): Observable<DataTableData<DataManagementPlanListingModel>> {
return this.http.post<DataTableData<DataManagementPlanListingModel>>(this.actionUrl + 'getPaged', dataTableRequest, { headers: this.headers });
}
getSingle(id: string): Observable<DataManagementPlanModel> {
return this.http.get<DataManagementPlanModel>(this.actionUrl + id, { headers: this.headers });
return this.http.get<DataManagementPlanModel>(this.actionUrl + 'getSingle/' + id, { headers: this.headers });
}
createDataManagementPlan(dataManagementPlanModel: DataManagementPlanModel): Observable<DataManagementPlanModel> {
return this.http.post<DataManagementPlanModel>(this.actionUrl + 'add', dataManagementPlanModel, { headers: this.headers });
return this.http.post<DataManagementPlanModel>(this.actionUrl + 'createOrUpdate', dataManagementPlanModel, { headers: this.headers });
}
inactivate(id: String): Observable<DataManagementPlanModel> {
return this.http.delete<DataManagementPlanModel>(this.actionUrl + 'inactivate/' + id, { headers: this.headers });
}
}

View File

@ -8,6 +8,7 @@ import { DataTableRequest } from '../../models/data-table/DataTableRequest';
import { DataTableData } from '../../models/data-table/DataTableData';
import { DatasetListingModel } from '../../models/datasets/DatasetListingModel';
import { DatasetModel } from '../../models/datasets/DatasetModel';
import { DatasetCriteria } from '../../models/criteria/dataset/DatasetCriteria';
@Injectable()
@ -25,7 +26,7 @@ export class DatasetService {
this.headers = this.headers.set('Accept', 'application/json');
}
getPaged(dataTableRequest: DataTableRequest): Observable<DataTableData<DatasetListingModel>> {
getPaged(dataTableRequest: DataTableRequest<DatasetCriteria>): Observable<DataTableData<DatasetListingModel>> {
return this.http.post<DataTableData<DatasetListingModel>>(this.actionUrl + 'getPaged', dataTableRequest, { headers: this.headers });
}

View File

@ -9,6 +9,8 @@ import { DataTableData } from '../../models/data-table/DataTableData';
import { ProjectListingModel } from '../../models/projects/ProjectListingModel';
import { ProjectModel } from '../../models/projects/ProjectModel';
import { BaseHttpResponseModel } from '../../models/http/BaseHttpResponseModel';
import { ProjectCriteria } from '../../models/criteria/project/ProjectCriteria';
import { RequestItem } from '../../models/criteria/RequestItem';
@Injectable()
@ -26,10 +28,14 @@ export class ProjectService {
this.headers = this.headers.set('Accept', 'application/json');
}
getPaged(dataTableRequest: DataTableRequest): Observable<DataTableData<ProjectListingModel>> {
getPaged(dataTableRequest: DataTableRequest<ProjectCriteria>): Observable<DataTableData<ProjectListingModel>> {
return this.http.post<DataTableData<ProjectListingModel>>(this.actionUrl + 'getPaged', dataTableRequest, { headers: this.headers });
}
get(requestItem: RequestItem<ProjectCriteria>): Observable<ProjectModel[]> {
return this.http.post<ProjectModel[]>(this.actionUrl + 'get', requestItem, { headers: this.headers });
}
getSingle(id: string): Observable<ProjectModel> {
return this.http.get<ProjectModel>(this.actionUrl + 'getSingle/' + id, { headers: this.headers });
}
@ -39,6 +45,6 @@ export class ProjectService {
}
inactivate(id: String): Observable<ProjectModel> {
return this.http.delete<ProjectModel>(this.actionUrl + 'inactivate' + id, { headers: this.headers });
return this.http.delete<ProjectModel>(this.actionUrl + 'inactivate/' + id, { headers: this.headers });
}
}

View File

@ -1,34 +1,28 @@
<form class="form-criteria">
<div class="dmp-criteria">
<mat-card class="mat-card">
<div class="row">
<div class="col-sm-6 col-md-2">
<div class="col-md-6">
<mat-form-field>
<input matInput
(focus)="periodStartPicker.open()"
(click)="periodStartPicker.open()"
placeholder=" {{'CRITERIA.FORMS.PERIOD-FROM'| translate}}"
[matDatepicker]="periodStartPicker"
name="projectCriteriaPeriodStart"
[ngModel]="this.criteria.PeriodStart" (ngModelChange)="controlModified()">
<mat-error *ngIf="getFormControl('periodStart').errors?.backendError">{{baseErrorModel['Criteria.PeriodStart']}}</mat-error>
<mat-datepicker-toggle matSuffix [for]="periodStartPicker"></mat-datepicker-toggle>
<mat-datepicker #periodStartPicker></mat-datepicker>
<input matInput placeholder=" {{'CRITERIA.DMP.LIKE'| translate}}" name="projectCriteriaLike" [(ngModel)]="criteria.like"
(ngModelChange)="controlModified()">
<mat-error *ngIf="baseErrorModel?.like">{{baseErrorModel['Criteria.like']}}</mat-error>
</mat-form-field>
</div>
<div class="col-sm-6 col-md-2">
<mat-form-field>
<input matInput
(focus)="periodEndPicker.open()"
(click)="periodEndPicker.open()"
name="projectCriteriaPeriodEnd"
placeholder=" {{'CRITERIA.FORMS.PERIOD-TO'| translate}}"
[matDatepicker]="periodEndPicker"
[ngModel]="this.criteria.PeriodEnd" (ngModelChange)="controlModified()">
<mat-error *ngIf="getFormControl('periodEnd').errors?.backendError">{{baseErrorModel['Criteria.PeriodEnd']}}</mat-error>
<mat-datepicker-toggle matSuffix [for]="periodEndPicker"></mat-datepicker-toggle>
<mat-datepicker #periodEndPicker></mat-datepicker>
</mat-form-field>
<div class="col-md-6">
<td-chips color="accent" [items]="filteredProjects" [(ngModel)]="criteria.projects" (ngModelChange)="controlModified()" placeholder="{{'CRITERIA.DMP.PROJECTS' | translate}}"
(inputChange)="filterProjects($event)" requireMatch>
<ng-template td-chip let-chip="chip">
<div class="tc-grey-100 bgc-teal-700" td-chip-avatar>{{chip.label.substring(0, 1).toUpperCase()}}</div>
{{chip.label}}
</ng-template>
<ng-template td-autocomplete-option let-option="option">
<div layout="row" layout-align="start center">
{{option.label}}
</div>
</ng-template>
<mat-progress-bar [style.height.px]="2" *ngIf="filteringProjectsAsync" mode="indeterminate"></mat-progress-bar>
</td-chips>
</div>
</div>
</mat-card>
</form>
</div>

View File

@ -1,4 +1,4 @@
.form-criteria {
.dmp-criteria {
mat-form-field {
padding-bottom: 5px;
width: 100%;

View File

@ -6,23 +6,28 @@ import { ValidationContext, Validation } from '../../../../utilities/validators/
import { BackendErrorValidator } from '../../../../utilities/validators/BackendErrorValidator';
import { DataManagementPlanCriteria } from '../../../../models/criteria/data-management-plan/DataManagementPlanCriteria';
import { DataManagementPlanCriteriaErrorModel } from '../../../../models/criteria/data-management-plan/DataManagementPlanCriteriaErrorModel';
import { ProjectModel } from '../../../../models/projects/ProjectModel';
import { ProjectService } from '../../../../services/project/project.service';
import { ProjectCriteria } from '../../../../models/criteria/project/ProjectCriteria';
import { RequestItem } from '../../../../models/criteria/RequestItem';
import { create } from 'domain';
@Component({
selector: 'app-dmp-criteria-component',
templateUrl: './dmp-criteria.component.html',
styleUrls: ['./dmp-criteria.component.scss'],
providers: [
]
providers: [ProjectService]
})
export class DataManagementPlanCriteriaComponent extends BaseCriteriaComponent implements OnInit {
// public form: DataManagementPlanType;
// public formStatus: DataManagementPlanStatus;
public criteria: DataManagementPlanCriteria = new DataManagementPlanCriteria();
filteringProjectsAsync: boolean = false;
filteredProjects: ProjectModel[];
constructor(
public language: TranslateService,
public projectService: ProjectService,
public formBuilder: FormBuilder
) {
super(new DataManagementPlanCriteriaErrorModel());
@ -37,30 +42,38 @@ export class DataManagementPlanCriteriaComponent extends BaseCriteriaComponent i
this.criteria = criteria;
}
public fromJSONObject(item: any): DataManagementPlanCriteria {
this.criteria = new DataManagementPlanCriteria();
this.criteria.PeriodStart = new Date(item.PeriodStart);
this.criteria.PeriodEnd = new Date(item.PeriodEnd);
return this.criteria;
onCallbackError(error: any) {
this.setErrorModel(error.error);
}
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],
});
controlModified(): void {
this.clearErrorModel();
if (this.refreshCallback != null &&
(this.criteria.like == null || this.criteria.like.length == 0 || this.criteria.like.length > 2)
) {
this.refreshCallback();
}
}
createValidationContext(): ValidationContext {
const validationContext: ValidationContext = new ValidationContext();
const validationArray: Validation[] = new Array<Validation>();
filterProjects(value: string): void {
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')] });
this.filteredProjects = undefined;
if (value) {
this.filteringProjectsAsync = true;
validationContext.validation = validationArray;
return validationContext;
}
let requestItem: RequestItem<ProjectCriteria> = new RequestItem();
let criteria: ProjectCriteria = new ProjectCriteria();
criteria.like = value;
requestItem.criteria = criteria;
this.projectService.get(requestItem).subscribe(items => {
this.filteredProjects = items;
this.filteringProjectsAsync = false;
// this.filteredProjects = items.filter((filteredObj: any) => {
// return this.objectsModel ? this.objectsModel.indexOf(filteredObj) < 0 : true;
// });
});
}
}
}

View File

@ -27,10 +27,11 @@
"TITLE": "Data Management Plans",
"COLUMNS": {
"NAME": "Name",
"ABBREVIATION": "Abbreviation",
"START": "Start",
"END": "End",
"ACTIONS": "Actions"
"PROJECT": "Project",
"PROFILE": "Profile",
"RESEARCHERS": "Researchers",
"ORGANISATIONS": "Organisations",
"VERSION": "Version"
}
},
"DATASET-LISTING": {
@ -92,6 +93,10 @@
"PERIOD-FROM": "Start",
"PERIOD-TO": "End",
"STATUS": "Status"
},
"DMP": {
"LIKE": "Search",
"PROJECTS": "Projects"
}
},
"DATASET-EDITOR": {

View File

@ -31,9 +31,6 @@
<!-- Nice BS notifications -->
<script src="assets/bootstrap-notify.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
</script>
<script src="https://apis.google.com/js/client:platform.js?onload=start" async defer>
</script>