From 8ff927a4a71c90f76273beaece866bd4d58cf619 Mon Sep 17 00:00:00 2001 From: Diamadis Tziotzios Date: Mon, 18 Dec 2017 12:01:22 +0200 Subject: [PATCH] no message --- dmp-frontend/.angular-cli.json | 5 +- dmp-frontend/package-lock.json | 8 + dmp-frontend/package.json | 1 + dmp-frontend/src/app/app.constants.ts | 2 +- .../src/app/dmps/dmp-listing.component.ts | 2 +- .../app/dmps/editor/dmp-editor.component.css | 20 -- .../app/dmps/editor/dmp-editor.component.html | 259 +++++------------- .../app/dmps/editor/dmp-editor.component.scss | 35 +++ .../app/dmps/editor/dmp-editor.component.ts | 105 ++++++- .../DataManagementPlanModel.ts | 56 +++- .../app/models/data-table/DataTableRequest.ts | 6 +- .../editor/project-editor.component.css | 20 -- .../editor/project-editor.component.html | 22 +- .../editor/project-editor.component.scss | 35 +++ .../editor/project-editor.component.ts | 57 +++- .../projects/project-listing.component.css | 20 -- .../projects/project-listing.component.scss | 23 ++ .../app/projects/project-listing.component.ts | 11 +- .../data-management-plan.service.ts | 6 +- .../external-sources.service.ts | 43 +++ .../app/services/project/project.service.ts | 7 +- dmp-frontend/src/app/services/rest-base.ts | 2 +- .../autocomplete/AutoCompleteConfiguration.ts | 10 + .../autocomplete/AutoCompleteItem.ts | 23 ++ .../autocomplete/autocomplete.component.html | 25 ++ .../autocomplete/autocomplete.component.scss | 30 ++ .../autocomplete/autocomplete.component.ts | 120 ++++++++ .../app/shared/material/material.module.ts | 5 +- dmp-frontend/src/assets/lang/en.json | 18 ++ dmp-frontend/src/styles.css | 103 ------- dmp-frontend/src/styles.scss | 3 + dmp-frontend/yarn.lock | 6 + 32 files changed, 686 insertions(+), 402 deletions(-) delete mode 100644 dmp-frontend/src/app/dmps/editor/dmp-editor.component.css create mode 100644 dmp-frontend/src/app/dmps/editor/dmp-editor.component.scss delete mode 100644 dmp-frontend/src/app/projects/editor/project-editor.component.css create mode 100644 dmp-frontend/src/app/projects/editor/project-editor.component.scss delete mode 100644 dmp-frontend/src/app/projects/project-listing.component.css create mode 100644 dmp-frontend/src/app/projects/project-listing.component.scss create mode 100644 dmp-frontend/src/app/services/external-sources/external-sources.service.ts create mode 100644 dmp-frontend/src/app/shared/components/autocomplete/AutoCompleteConfiguration.ts create mode 100644 dmp-frontend/src/app/shared/components/autocomplete/AutoCompleteItem.ts create mode 100644 dmp-frontend/src/app/shared/components/autocomplete/autocomplete.component.html create mode 100644 dmp-frontend/src/app/shared/components/autocomplete/autocomplete.component.scss create mode 100644 dmp-frontend/src/app/shared/components/autocomplete/autocomplete.component.ts delete mode 100644 dmp-frontend/src/styles.css create mode 100644 dmp-frontend/src/styles.scss diff --git a/dmp-frontend/.angular-cli.json b/dmp-frontend/.angular-cli.json index d2bdb2410..b6bd82a36 100644 --- a/dmp-frontend/.angular-cli.json +++ b/dmp-frontend/.angular-cli.json @@ -19,10 +19,7 @@ "testTsconfig": "tsconfig.spec.json", "prefix": "app", "styles": [ - "../node_modules/primeng/resources/themes/omega/theme.css" , - "../node_modules/primeng/resources/primeng.css", - "./../node_modules/bootstrap/dist/css/bootstrap.min.css", - "styles.css" + "styles.scss" ], "scripts": [ "./../node_modules/bootstrap/dist/js/bootstrap.min.js", diff --git a/dmp-frontend/package-lock.json b/dmp-frontend/package-lock.json index eb24a5a4f..211aebeca 100644 --- a/dmp-frontend/package-lock.json +++ b/dmp-frontend/package-lock.json @@ -277,6 +277,14 @@ "tslib": "1.7.1" } }, + "@covalent/core": { + "version": "1.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@covalent/core/-/core-1.0.0-rc.1.tgz", + "integrity": "sha1-majfr1PoModZlV7EBM4KwMjmDSU=", + "requires": { + "tslib": "1.7.1" + } + }, "@ng-bootstrap/ng-bootstrap": { "version": "1.0.0-beta.7", "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-1.0.0-beta.7.tgz", diff --git a/dmp-frontend/package.json b/dmp-frontend/package.json index cf9691d40..b5947ff71 100644 --- a/dmp-frontend/package.json +++ b/dmp-frontend/package.json @@ -23,6 +23,7 @@ "@angular/platform-browser": "5.1.1", "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", + "@covalent/core": "^1.0.0-rc.1", "@ng-bootstrap/ng-bootstrap": "1.0.0-beta.7", "@ngui/auto-complete": "^0.16.0", "@ngx-translate/core": "^9.0.1", diff --git a/dmp-frontend/src/app/app.constants.ts b/dmp-frontend/src/app/app.constants.ts index c33d7a2ef..83a2f6222 100644 --- a/dmp-frontend/src/app/app.constants.ts +++ b/dmp-frontend/src/app/app.constants.ts @@ -1,5 +1,5 @@ export const HostConfiguration = { - Server: 'http://192.168.32.103:8080/', + Server: 'http://192.168.32.171:8080/', //CASHost: 'https://login-devel.uoa.gr/login', //Service: 'http://elkefinman/login' } \ No newline at end of file diff --git a/dmp-frontend/src/app/dmps/dmp-listing.component.ts b/dmp-frontend/src/app/dmps/dmp-listing.component.ts index 850ccd527..8df801cb8 100644 --- a/dmp-frontend/src/app/dmps/dmp-listing.component.ts +++ b/dmp-frontend/src/app/dmps/dmp-listing.component.ts @@ -115,7 +115,7 @@ export class DataManagementPlanDataSource extends DataSource { diff --git a/dmp-frontend/src/app/dmps/editor/dmp-editor.component.css b/dmp-frontend/src/app/dmps/editor/dmp-editor.component.css deleted file mode 100644 index 957c39499..000000000 --- a/dmp-frontend/src/app/dmps/editor/dmp-editor.component.css +++ /dev/null @@ -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; -} diff --git a/dmp-frontend/src/app/dmps/editor/dmp-editor.component.html b/dmp-frontend/src/app/dmps/editor/dmp-editor.component.html index 8d5c11e1c..510f59135 100644 --- a/dmp-frontend/src/app/dmps/editor/dmp-editor.component.html +++ b/dmp-frontend/src/app/dmps/editor/dmp-editor.component.html @@ -1,190 +1,83 @@ -
-

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

+
+
+ + {{'PROJECT-EDITOR.TITLE.NEW' | translate}} + {{'PROJECT-EDITOR.TITLE.EDIT' | translate}} {{project.label}} + - - - + + + {{baseErrorModel.label}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + - + - - {{'PROJECT-LISTING.COLUMNS.NAME' | translate}} - {{row.name}} - + + + {{baseErrorModel.uri}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + --> - - - {{'PROJECT-LISTING.COLUMNS.ABBREVIATION' | translate}} - {{row.abbreviation}} - + - - - {{'PROJECT-LISTING.COLUMNS.START' | translate}} - {{row.start}} - + + + {{errorModel.description}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + - - - {{'PROJECT-LISTING.COLUMNS.END' | translate}} - {{row.end}} - - - - - {{'PROJECT-LISTING.COLUMNS.ACTIONS' | translate}} - - - - - - - - - - - - -
- + {{chip.name}} + + +
+ {{option.name}}
-
- - -
- -
- - - - - --> + + + + +
+ + + +
+ + + + + \ No newline at end of file diff --git a/dmp-frontend/src/app/dmps/editor/dmp-editor.component.scss b/dmp-frontend/src/app/dmps/editor/dmp-editor.component.scss new file mode 100644 index 000000000..31e8a8de3 --- /dev/null +++ b/dmp-frontend/src/app/dmps/editor/dmp-editor.component.scss @@ -0,0 +1,35 @@ +.full-width { + width: 100%; +} + +.input-table { + table-layout: fixed; +} + +.table-card .mat-grid-tile { + background: rgba(0, 0, 0, 0.32); +} + +.project-editor { + mat-form-field { + width: 100%; + padding: 3px; + } + + .mat-card { + margin: 16px 0; + } + + p { + margin: 16px; + } + + .left-button { + float: left; + } + + .description-area { + height: 100px; + } + +} diff --git a/dmp-frontend/src/app/dmps/editor/dmp-editor.component.ts b/dmp-frontend/src/app/dmps/editor/dmp-editor.component.ts index 481d06eab..5cb78099b 100644 --- a/dmp-frontend/src/app/dmps/editor/dmp-editor.component.ts +++ b/dmp-frontend/src/app/dmps/editor/dmp-editor.component.ts @@ -1,34 +1,119 @@ -import { Component, ViewChild, OnInit, AfterViewInit } from "@angular/core"; +import { Component, ViewChild, OnInit, AfterViewInit, ViewEncapsulation } from "@angular/core"; import { MatPaginator, MatSort, MatSnackBar } from "@angular/material"; -import { Router } from "@angular/router"; +import { Router, ActivatedRoute, Params } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; import { DataSource } from "@angular/cdk/table"; import { Observable } from "rxjs/Observable"; +import { JsonSerializer } from "../../utilities/JsonSerializer"; +import { FormGroup } from "@angular/forms"; +import { SnackBarNotificationComponent } from "../../shared/components/notificaiton/snack-bar-notification.component"; +import { BaseErrorModel } from "../../models/error/BaseErrorModel"; import { DataManagementPlanService } from "../../services/data-management-plan/data-management-plan.service"; +import { DataManagementPlanModel } from "../../models/data-managemnt-plans/DataManagementPlanModel"; +import { ServerService } from "../../services/server.service"; +import { ExternalSourcesService } from "../../services/external-sources/external-sources.service"; @Component({ selector: 'app-dmp-editor-component', templateUrl: 'dmp-editor.component.html', - styleUrls: ['./dmp-editor.component.css'], + styleUrls: ['./dmp-editor.component.scss'], + providers: [DataManagementPlanService, ExternalSourcesService], + encapsulation: ViewEncapsulation.None }) -export class DataManagementPlanEditorComponent implements OnInit, AfterViewInit { +export class DataManagementPlanEditorComponent implements AfterViewInit { + + isNew = true; + dataManagementPlan: DataManagementPlanModel; + formGroup: FormGroup = null; + + filteringOrganisationsAsync: boolean = false; + filteringResearchersAsync: boolean = false; + filteredOrganisations: string[]; + filteredResearchers: string[]; + + filterOrganisations(value: string): void { + this.filteredOrganisations = undefined; + if (value) { + this.filteringOrganisationsAsync = true; + + this.externalSourcesService.searchDMPOrganizations(value).subscribe(organizations => { + this.filteredOrganisations = organizations; + this.filteringOrganisationsAsync = false; + }); + } + } constructor( - private projectService: DataManagementPlanService, - private router: Router, - private languageService: TranslateService, - public snackBar: MatSnackBar + private dataManagementPlanService: DataManagementPlanService, + private externalSourcesService: ExternalSourcesService, + private route: ActivatedRoute, + public snackBar: MatSnackBar, + public router: Router, + public language: TranslateService, ) { } - ngOnInit() { + ngAfterViewInit() { + this.route.params.subscribe((params: Params) => { + const itemId = params['id']; + if (itemId != null) { + this.isNew = false; + this.dataManagementPlanService.getSingle(itemId).map(data => data as DataManagementPlanModel) + .subscribe(data => { + this.dataManagementPlan = new JsonSerializer().fromJSONObject(data, DataManagementPlanModel); + this.formGroup = this.dataManagementPlan.buildForm(); + }); + } else { + this.dataManagementPlan = new DataManagementPlanModel(); + setTimeout(() => { + this.formGroup = this.dataManagementPlan.buildForm(); + }); + } + }); } - ngAfterViewInit() { + formSubmit(): void { + //this.touchAllFormFields(this.formGroup); + if (!this.isFormValid()) { return; } + this.onSubmit(); + } + public isFormValid() { + return this.formGroup.valid; + } + + onSubmit(): void { + this.dataManagementPlanService.createDataManagementPlan(this.formGroup.value).subscribe( + complete => this.onCallbackSuccess(), + error => this.onCallbackError(error) + ); + } + + onCallbackSuccess(): void { + this.snackBar.openFromComponent(SnackBarNotificationComponent, { + data: { message: this.isNew ? 'GENERAL.SNACK-BAR.SUCCESSFUL-CREATION' : 'GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE', language: this.language }, + duration: 3000, + extraClasses: ['snackbar-success'] + }) + this.router.navigate(['/dataManagementPlans']); + } + + onCallbackError(error: any) { + this.setErrorModel(error.error); + //this.validateAllFormFields(this.formGroup); + } + + public setErrorModel(errorModel: BaseErrorModel) { + Object.keys(errorModel).forEach(item => { + (this.dataManagementPlan.errorModel)[item] = (errorModel)[item]; + }) + } + + public cancel(): void { + this.router.navigate(['/dataManagementPlans']); } } \ No newline at end of file diff --git a/dmp-frontend/src/app/models/data-managemnt-plans/DataManagementPlanModel.ts b/dmp-frontend/src/app/models/data-managemnt-plans/DataManagementPlanModel.ts index fea9dd081..ba8ad860b 100644 --- a/dmp-frontend/src/app/models/data-managemnt-plans/DataManagementPlanModel.ts +++ b/dmp-frontend/src/app/models/data-managemnt-plans/DataManagementPlanModel.ts @@ -1,27 +1,57 @@ import { Serializable } from "../Serializable"; +import { ValidationContext } from "../../utilities/validators/ValidationContext"; +import { FormGroup, FormBuilder, FormControl, Validators } from "@angular/forms"; +import { BackendErrorValidator } from "../../utilities/validators/BackendErrorValidator"; +import { BaseErrorModel } from "../error/BaseErrorModel"; +import { AutoCompleteItem } from "../../shared/components/autocomplete/AutoCompleteItem"; export class DataManagementPlanModel implements Serializable { public id: String; public label: String; - public abbreviation: String; - public reference: String; - public uri: String; + public previous: String; + public version: number; public status: String; - public startDate: Date; - public endDate: Date; public description: String; + public selectedProject: AutoCompleteItem; + // public selectedProjectReference: AutoCompleteItem; + // public selectedProjectReference: AutoCompleteItem; + + + public errorModel: BaseErrorModel = new BaseErrorModel(); fromJSONObject(item: any): DataManagementPlanModel { 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.previous = item.previous; + this.version = item.version; + this.status = item.status; + this.description = item.description; + return this; } + + buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup { + if (context == null) { context = this.createValidationContext(); } + + const formGroup = new FormBuilder().group({ + label: [{ value: this.label, disabled: disabled }, context.getValidation('label').validators], + previous: [{ value: this.previous, disabled: disabled }, context.getValidation('previous').validators], + 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], + }); + + return formGroup; + } + + createValidationContext(): ValidationContext { + const baseContext: ValidationContext = new ValidationContext(); + baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'label')] }); + baseContext.validation.push({ key: 'previous', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'previous')] }); + 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')] }); + + return baseContext; + } } \ No newline at end of file diff --git a/dmp-frontend/src/app/models/data-table/DataTableRequest.ts b/dmp-frontend/src/app/models/data-table/DataTableRequest.ts index 1938c01e4..576c6b89b 100644 --- a/dmp-frontend/src/app/models/data-table/DataTableRequest.ts +++ b/dmp-frontend/src/app/models/data-table/DataTableRequest.ts @@ -1,11 +1,9 @@ -import { DataManagementPlanCriteria } from "../criteria/data-management-plan/DataManagementPlanCriteria"; -import { ProjectCriteria } from "../criteria/project/ProjectCriteria"; +import { BaseCriteria } from "../criteria/BaseCriteria"; export class DataTableRequest { offset = 0; length = 0; - projectCriteria: ProjectCriteria; - dmpCriteria: DataManagementPlanCriteria; + criteria: BaseCriteria; constructor(offset: number, length: number) { this.length = length; diff --git a/dmp-frontend/src/app/projects/editor/project-editor.component.css b/dmp-frontend/src/app/projects/editor/project-editor.component.css deleted file mode 100644 index 957c39499..000000000 --- a/dmp-frontend/src/app/projects/editor/project-editor.component.css +++ /dev/null @@ -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; -} diff --git a/dmp-frontend/src/app/projects/editor/project-editor.component.html b/dmp-frontend/src/app/projects/editor/project-editor.component.html index 903635a2a..e78eb51e2 100644 --- a/dmp-frontend/src/app/projects/editor/project-editor.component.html +++ b/dmp-frontend/src/app/projects/editor/project-editor.component.html @@ -1,5 +1,5 @@ -
-
+
+ {{'PROJECT-EDITOR.TITLE.NEW' | translate}} {{'PROJECT-EDITOR.TITLE.EDIT' | translate}} {{project.label}} @@ -49,17 +49,19 @@ - - - - + + + {{errorModel.description}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + +
- + + +
+
diff --git a/dmp-frontend/src/app/projects/editor/project-editor.component.scss b/dmp-frontend/src/app/projects/editor/project-editor.component.scss new file mode 100644 index 000000000..31e8a8de3 --- /dev/null +++ b/dmp-frontend/src/app/projects/editor/project-editor.component.scss @@ -0,0 +1,35 @@ +.full-width { + width: 100%; +} + +.input-table { + table-layout: fixed; +} + +.table-card .mat-grid-tile { + background: rgba(0, 0, 0, 0.32); +} + +.project-editor { + mat-form-field { + width: 100%; + padding: 3px; + } + + .mat-card { + margin: 16px 0; + } + + p { + margin: 16px; + } + + .left-button { + float: left; + } + + .description-area { + height: 100px; + } + +} diff --git a/dmp-frontend/src/app/projects/editor/project-editor.component.ts b/dmp-frontend/src/app/projects/editor/project-editor.component.ts index 5a26b076d..ae0c2db6e 100644 --- a/dmp-frontend/src/app/projects/editor/project-editor.component.ts +++ b/dmp-frontend/src/app/projects/editor/project-editor.component.ts @@ -1,4 +1,4 @@ -import { Component, ViewChild, OnInit, AfterViewInit } from "@angular/core"; +import { Component, ViewChild, OnInit, AfterViewInit, ViewEncapsulation } from "@angular/core"; import { MatPaginator, MatSort, MatSnackBar } from "@angular/material"; import { Router, ActivatedRoute, Params } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; @@ -9,14 +9,17 @@ import { ProjectModel } from "../../models/projects/ProjectModel"; import { ProjectService } from "../../services/project/project.service"; import { JsonSerializer } from "../../utilities/JsonSerializer"; import { FormGroup } from "@angular/forms"; +import { SnackBarNotificationComponent } from "../../shared/components/notificaiton/snack-bar-notification.component"; +import { BaseErrorModel } from "../../models/error/BaseErrorModel"; @Component({ selector: 'app-project-editor-component', templateUrl: 'project-editor.component.html', - styleUrls: ['./project-editor.component.css'], - providers: [ProjectService] + styleUrls: ['./project-editor.component.scss'], + providers: [ProjectService], + encapsulation: ViewEncapsulation.None }) export class ProjectEditorComponent implements AfterViewInit { @@ -27,6 +30,9 @@ export class ProjectEditorComponent implements AfterViewInit { constructor( private projectService: ProjectService, private route: ActivatedRoute, + public snackBar: MatSnackBar, + public router: Router, + public language: TranslateService ) { } @@ -44,8 +50,51 @@ export class ProjectEditorComponent implements AfterViewInit { }); } else { this.project = new ProjectModel(); - this.formGroup = this.project.buildForm(); + setTimeout(() => { + this.formGroup = this.project.buildForm(); + }); } }); } + + formSubmit(): void { + //this.touchAllFormFields(this.formGroup); + if (!this.isFormValid()) { return; } + this.onSubmit(); + } + + public isFormValid() { + return this.formGroup.valid; + } + + onSubmit(): void { + this.projectService.createProject(this.formGroup.value).subscribe( + complete => this.onCallbackSuccess(), + error => this.onCallbackError(error) + ); + } + + onCallbackSuccess(): void { + this.snackBar.openFromComponent(SnackBarNotificationComponent, { + data: { message: this.isNew ? 'GENERAL.SNACK-BAR.SUCCESSFUL-CREATION' : 'GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE', language: this.language }, + duration: 3000, + extraClasses: ['snackbar-success'] + }) + this.router.navigate(['/projects']); + } + + onCallbackError(error: any) { + this.setErrorModel(error.error); + //this.validateAllFormFields(this.formGroup); + } + + public setErrorModel(errorModel: BaseErrorModel) { + Object.keys(errorModel).forEach(item => { + (this.project.errorModel)[item] = (errorModel)[item]; + }) + } + + public cancel(): void { + this.router.navigate(['/projects']); + } } \ 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 deleted file mode 100644 index 957c39499..000000000 --- a/dmp-frontend/src/app/projects/project-listing.component.css +++ /dev/null @@ -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; -} diff --git a/dmp-frontend/src/app/projects/project-listing.component.scss b/dmp-frontend/src/app/projects/project-listing.component.scss new file mode 100644 index 000000000..d81a50420 --- /dev/null +++ b/dmp-frontend/src/app/projects/project-listing.component.scss @@ -0,0 +1,23 @@ +.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; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/projects/project-listing.component.ts b/dmp-frontend/src/app/projects/project-listing.component.ts index 8caa28a88..7c9479cea 100644 --- a/dmp-frontend/src/app/projects/project-listing.component.ts +++ b/dmp-frontend/src/app/projects/project-listing.component.ts @@ -1,4 +1,4 @@ -import { Component, ViewChild, OnInit, AfterViewInit } from "@angular/core"; +import { Component, ViewChild, OnInit, AfterViewInit, ViewEncapsulation } from "@angular/core"; import { MatPaginator, MatSort, MatSnackBar } from "@angular/material"; import { Router } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; @@ -16,8 +16,9 @@ import { SnackBarNotificationComponent } from "../shared/components/notificaiton @Component({ selector: 'app-project-listing-component', templateUrl: 'project-listing.component.html', - styleUrls: ['./project-listing.component.css'], - providers: [ProjectService] + styleUrls: ['./project-listing.component.scss'], + providers: [ProjectService], + encapsulation: ViewEncapsulation.None }) export class ProjectListingComponent implements OnInit, AfterViewInit { @@ -115,7 +116,7 @@ export class ProjectDataSource extends DataSource { }); const startIndex = this._paginator.pageIndex * this._paginator.pageSize; const request = new DataTableRequest(startIndex, this._paginator.pageSize); - request.projectCriteria = this._criteria.getFormData(); + request.criteria = this._criteria.getFormData(); return this._service.getPaged(request); }) .catch((error: any) => { @@ -136,7 +137,7 @@ export class ProjectDataSource extends DataSource { .map(result => { if (!result) { return []; } if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; } - return result.data; + return result.payload.data; }); } 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 index 13b5312c1..147715e75 100644 --- 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 @@ -18,7 +18,7 @@ export class DataManagementPlanService { constructor(private http: BaseHttpService) { - this.actionUrl = HostConfiguration.Server + 'api/dmps/'; + this.actionUrl = HostConfiguration.Server + 'dmps/'; this.headers = new HttpHeaders(); this.headers = this.headers.set('Content-Type', 'application/json'); @@ -32,4 +32,8 @@ export class DataManagementPlanService { getSingle(id: string): Observable { return this.http.get(this.actionUrl + id, { headers: this.headers }); } + + createDataManagementPlan(dataManagementPlanModel: DataManagementPlanModel): Observable { + return this.http.post(this.actionUrl + 'add', dataManagementPlanModel, { headers: this.headers }); + } } diff --git a/dmp-frontend/src/app/services/external-sources/external-sources.service.ts b/dmp-frontend/src/app/services/external-sources/external-sources.service.ts new file mode 100644 index 000000000..04f45e30b --- /dev/null +++ b/dmp-frontend/src/app/services/external-sources/external-sources.service.ts @@ -0,0 +1,43 @@ +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'; + + +@Injectable() +export class ExternalSourcesService { + + private actionUrl: string; + private headers: HttpHeaders; + + constructor(private http: BaseHttpService) { + + this.actionUrl = HostConfiguration.Server + 'external/'; + + this.headers = new HttpHeaders(); + this.headers = this.headers.set('Content-Type', 'application/json'); + this.headers = this.headers.set('Accept', 'application/json'); + } + + public searchDatasetRegistry(like: string) { + return this.http.get("registries" + "?query=" + like); + } + + public searchDatasetRepository(like: string) { + return this.http.get("datarepos" + "?query=" + like); + } + + public searchDatasetService(like: string) { + return this.http.get("services" + "?query=" + like); + } + + public searchDMPResearchers(like: string) { + return this.http.get("researchers" + "?query=" + like); + } + + public searchDMPOrganizations(like: string): Observable { + return this.http.get(this.actionUrl + "organisations" + "?query=" + like, { 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 index 426b18030..f22ee93ac 100644 --- a/dmp-frontend/src/app/services/project/project.service.ts +++ b/dmp-frontend/src/app/services/project/project.service.ts @@ -18,7 +18,7 @@ export class ProjectService { constructor(private http: BaseHttpService) { - this.actionUrl = HostConfiguration.Server + 'dmp-backend/rest/projects/'; + this.actionUrl = HostConfiguration.Server + 'projects/'; this.headers = new HttpHeaders(); this.headers = this.headers.set('Content-Type', 'application/json'); @@ -32,4 +32,9 @@ export class ProjectService { getSingle(id: string): Observable { return this.http.get(this.actionUrl + id, { headers: this.headers }); } + + createProject(projectModel: ProjectModel): Observable { + return this.http.post(this.actionUrl + 'add', projectModel, { headers: this.headers }); + } + } diff --git a/dmp-frontend/src/app/services/rest-base.ts b/dmp-frontend/src/app/services/rest-base.ts index 53ce4e7c1..e2ab6ab03 100644 --- a/dmp-frontend/src/app/services/rest-base.ts +++ b/dmp-frontend/src/app/services/rest-base.ts @@ -18,7 +18,7 @@ export class RestBase { protocol: string = "http"; - hostname: string ="192.168.32.103" + hostname: string ="192.168.32.171" port: number = 8080; /* diff --git a/dmp-frontend/src/app/shared/components/autocomplete/AutoCompleteConfiguration.ts b/dmp-frontend/src/app/shared/components/autocomplete/AutoCompleteConfiguration.ts new file mode 100644 index 000000000..bf4866ea5 --- /dev/null +++ b/dmp-frontend/src/app/shared/components/autocomplete/AutoCompleteConfiguration.ts @@ -0,0 +1,10 @@ +import { BaseCriteria } from "../../../models/criteria/BaseCriteria"; + +export class AutoCompleteConfiguration { + public callback: Function; + public criteria: BaseCriteria; + constructor(callback: Function, criteria: BaseCriteria) { + this.callback = callback; + this.criteria = criteria; + } +} diff --git a/dmp-frontend/src/app/shared/components/autocomplete/AutoCompleteItem.ts b/dmp-frontend/src/app/shared/components/autocomplete/AutoCompleteItem.ts new file mode 100644 index 000000000..919ddcdef --- /dev/null +++ b/dmp-frontend/src/app/shared/components/autocomplete/AutoCompleteItem.ts @@ -0,0 +1,23 @@ +import { FormGenerator } from "../../../utilities/forms/FormGenerator"; +import { ValidationContext } from "../../../utilities/validators/ValidationContext"; +import { FormBuilder, FormGroup } from "@angular/forms"; + +export class AutoCompleteItem implements FormGenerator { + + public value: string; + public text: string; + public description: string; + constructor(value: string, text: string, description: string) { + this.value = value; + this.text = text; + this.description = description; + } + + buildForm(context: ValidationContext, disabled: boolean = false): FormGroup { + return new FormBuilder().group({ + value: [{ value: this.value, disabled: disabled }, context.getValidation('value').validators], + text: [{ value: this.text, disabled: disabled }, context.getValidation('text').validators], + description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators] + }); + } +} diff --git a/dmp-frontend/src/app/shared/components/autocomplete/autocomplete.component.html b/dmp-frontend/src/app/shared/components/autocomplete/autocomplete.component.html new file mode 100644 index 000000000..eabd5c3dd --- /dev/null +++ b/dmp-frontend/src/app/shared/components/autocomplete/autocomplete.component.html @@ -0,0 +1,25 @@ +
+ + + + + + +
+ + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + {{errorString}} + + + + + +
+ + + {{ option.text }} {{option.description?'['+option.description+']':''}} + + +
\ No newline at end of file diff --git a/dmp-frontend/src/app/shared/components/autocomplete/autocomplete.component.scss b/dmp-frontend/src/app/shared/components/autocomplete/autocomplete.component.scss new file mode 100644 index 000000000..6e7ec5cf9 --- /dev/null +++ b/dmp-frontend/src/app/shared/components/autocomplete/autocomplete.component.scss @@ -0,0 +1,30 @@ +.autocomplete-input { + width: 100%; +} + +.autocomplete-progress { + overflow: initial !important; +} + +.autocomplete { + mat-form-field { + width: 100%; + padding: 3px; + } + + .mat-card { + margin: 16px 0; + } + + .left-button { + float: left; + } +} + +.input-table { + table-layout: fixed; +} + +.full-width { + width: 100%; +} diff --git a/dmp-frontend/src/app/shared/components/autocomplete/autocomplete.component.ts b/dmp-frontend/src/app/shared/components/autocomplete/autocomplete.component.ts new file mode 100644 index 000000000..0cebaeb85 --- /dev/null +++ b/dmp-frontend/src/app/shared/components/autocomplete/autocomplete.component.ts @@ -0,0 +1,120 @@ +import { FormControl, FormGroupDirective, NgForm, FormGroup } from '@angular/forms'; +import { Observable } from 'rxjs/Rx'; +import { setTimeout } from 'timers'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import 'rxjs/add/operator/debounceTime'; +import 'rxjs/add/operator/map'; +import { AutoCompleteConfiguration } from './AutoCompleteConfiguration'; +import { AutoCompleteItem } from './AutoCompleteItem'; +import { ErrorStateMatcher } from '@angular/material'; + +@Component({ + selector: 'auto-complete', + templateUrl: './autocomplete.component.html', + styleUrls: ['./autocomplete.component.scss'] +}) +export class AutocompleteComponent implements OnInit { + @Input() + configuration: AutoCompleteConfiguration; + + @Input() + mapper: Function; + + @Input() + typeaheadMS: number; + + @Input() + placeholder: String; + + @Input() + validationErrorString: String; + + public errorStateMatcher: AutoCompleteErrorStateMatcher = new AutoCompleteErrorStateMatcher(); + + @Input() + required: boolean; + + @Input() selectedDropdownItem: AutoCompleteItem; + @Output() selectedDropdownItemChange = new EventEmitter(); + + @Output() + output: EventEmitter = new EventEmitter(); + + @Input() form: FormGroup; + + @Input() createNew = false; + //term = new FormControl(); + @Input() + ClickFunctionCall: Function; + + loading = false; + + options: AutoCompleteItem[]; + constructor() { + } + + ngOnInit() { + const valueChanges = this.form.controls['text'].valueChanges.share(); + valueChanges.subscribe(searchTerm => { + this.loading = true; + if (this.form.controls['value'].value) { + this.resetFormGroupValue(); + } + }); + + valueChanges + .debounceTime(this.typeaheadMS) + .subscribe(searchTerm => { + if (typeof searchTerm === 'string') { + this.inputOnChange(searchTerm) + } + }); + } + + resetFormGroupValue() { + this.form.patchValue({ value: null }, { emitEvent: false }); + } + + // listingItemToDropDown(item: DropdownListingItem): AutoCompleteItem { + // return (item as DropdownListingItem).toDropdownList(); + // } + + optionSelected(event: any) { + this.form.patchValue(event.option.value, { emitEvent: false }); + this.selectedDropdownItemChange.emit(event.option.value); + //this.form.updateValueAndValidity(); + this.options = [event.option.value]; + this.loading = false; + } + + inputOnChange(term: string) { + //this.form.patchValue({ value: null, description: '', text: '' }); + //this.form.updateValueAndValidity(); + this.configuration.criteria.Like = term; + this.configuration.callback(this.configuration.criteria) + .map((res: any) => this.mapper(res)) + .subscribe( + (res: AutoCompleteItem[]) => { + this.options = res; + }, + null, + () => { this.loading = false }); + } + + displayFn(item: AutoCompleteItem): string { + return item.text ? item.text : ''; + } + + //fieldHasErrors(control: FormControl, form: FormGroupDirective | NgForm): boolean { + // return this.errorStateMatcher(control, form); + // } +} + +export class AutoCompleteErrorStateMatcher implements ErrorStateMatcher { + isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { + const isFormSubmitted = form && form.submitted; + const isControlInvalid = control && control.invalid && (control.dirty || control.touched || isFormSubmitted); + const isFormInvalid = form && form.enabled && form.invalid && (form.dirty || form.touched || isFormSubmitted) + return !!(isControlInvalid || isFormInvalid); + } +} \ No newline at end of file diff --git a/dmp-frontend/src/app/shared/material/material.module.ts b/dmp-frontend/src/app/shared/material/material.module.ts index 7d23975fb..4370b685f 100644 --- a/dmp-frontend/src/app/shared/material/material.module.ts +++ b/dmp-frontend/src/app/shared/material/material.module.ts @@ -27,6 +27,7 @@ import { } from '@angular/material'; import { CdkTableModule } from '@angular/cdk/table'; import { SnackBarNotificationComponent } from '../components/notificaiton/snack-bar-notification.component'; +import { CovalentLayoutModule, CovalentChipsModule } from '@covalent/core'; @NgModule({ imports: [ @@ -56,7 +57,9 @@ import { SnackBarNotificationComponent } from '../components/notificaiton/snack- MatProgressSpinnerModule, MatTooltipModule, MatCheckboxModule, - MatTabsModule + MatTabsModule, + CovalentLayoutModule, + CovalentChipsModule ], providers: [ diff --git a/dmp-frontend/src/assets/lang/en.json b/dmp-frontend/src/assets/lang/en.json index 184d150d0..291e96ff6 100644 --- a/dmp-frontend/src/assets/lang/en.json +++ b/dmp-frontend/src/assets/lang/en.json @@ -1,4 +1,9 @@ { + "GENERAL": { + "VALIDATION": { + "REQUIRED": "Required" + } + }, "NAV-BAR": { "TITLE": "DMPS" }, @@ -26,6 +31,19 @@ "TITLE": { "NEW": "New Project", "EDIT": "Edit" + }, + "FIELDS": { + "NAME": "New Project", + "ABBREVIATION": "Abbreviation", + "URI": "URI", + "START": "Start", + "END": "End", + "DESCRIPTION": "Description" + }, + "ACTIONS": { + "SAVE": "Save", + "CANCEL": "Cancel", + "DELETE": "Delete" } }, "CRITERIA": { diff --git a/dmp-frontend/src/styles.css b/dmp-frontend/src/styles.css deleted file mode 100644 index 67f8ba2b1..000000000 --- a/dmp-frontend/src/styles.css +++ /dev/null @@ -1,103 +0,0 @@ -@import "~@angular/material/prebuilt-themes/indigo-pink.css"; - -/* You can add global styles to this file, and also import other style files */ -/* -body { - padding-top: 40px; - padding-bottom: 40px; - background-color: #eee; - } - */ - .form-signin { - max-width: 330px; - padding: 15px; - margin: 0 auto; - box-shadow: 0px 0px 0px 1px #d8d4d4; - } - .form-signin .form-signin-heading, - .form-signin .checkbox { - margin-bottom: 10px; - } - .form-signin .checkbox { - font-weight: normal; - } - .form-signin .form-control { - position: relative; - height: auto; - -webkit-box-sizing: border-box; - box-sizing: border-box; - padding: 10px; - font-size: 16px; - } - .form-signin .form-control:focus { - z-index: 2; - } - .form-signin input[type="email"] { - margin-bottom: -1px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; - } - .form-signin input[type="password"] { - margin-bottom: 10px; - border-top-left-radius: 0; - border-top-right-radius: 0; - } - .errorMessage{ - color:red; - } - - .form-control.is-invalid{ - border-color: #dc3545 - } - - .invalid-feedbackCustom { - margin-top: .25rem; - font-size: 1.2rem; - color: #dc3545; - } - - .ng-valid[required], .ng-valid.required { - border-left: 5px solid #42A948; /* green */ - } - - .form-control.ng-invalid { - border-left: 5px solid #a94442; /* red */ - } - - .form-groupCustom { - border: 2px solid #A11515; - } - - .cursor-link{ - cursor: pointer; - } - - /* dashboard */ - - .card{ - box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.14); - border-radius: 6px; - color: rgba(0,0,0, 0.87); - background: #fff; - } - - .card-raised{ - box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.42), 0 4px 25px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2); - } - - @media screen and (max-width: 990px){ - #sidebar, #nav-right, #nav-left-button{ - display: none; - } - #menu{ - display: inline; - } - #main-panel{ - padding-left: 0; - -webkit-transition: all 400ms; - -moz-transition: all 400ms; - -ms-transition: all 400ms; - -o-transition: all 400ms; - transition: all 400ms; - } - } \ No newline at end of file diff --git a/dmp-frontend/src/styles.scss b/dmp-frontend/src/styles.scss new file mode 100644 index 000000000..d0630473b --- /dev/null +++ b/dmp-frontend/src/styles.scss @@ -0,0 +1,3 @@ +@import "~@angular/material/prebuilt-themes/indigo-pink.css"; +@import '~@angular/material/theming'; +@import '~@covalent/core/theming/all-theme'; diff --git a/dmp-frontend/yarn.lock b/dmp-frontend/yarn.lock index 449f4722c..f59d282e0 100644 --- a/dmp-frontend/yarn.lock +++ b/dmp-frontend/yarn.lock @@ -194,6 +194,12 @@ dependencies: tslib "^1.7.1" +"@covalent/core@^1.0.0-rc.1": + version "1.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@covalent/core/-/core-1.0.0-rc.1.tgz#99a8dfaf53e8328759955ec404ce0ac0c8e60d25" + dependencies: + tslib "^1.7.1" + "@ng-bootstrap/ng-bootstrap@1.0.0-beta.7": version "1.0.0-beta.7" resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-1.0.0-beta.7.tgz#58bc81f610028f40526529ce40483a95028163b0"