diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java index 371a61386..135cac60b 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java @@ -28,6 +28,7 @@ import eu.eudat.models.data.helpers.common.DataTableData; import eu.eudat.models.data.helpers.responses.ResponseItem; import eu.eudat.models.data.listingmodels.DataManagementPlanListingModel; import eu.eudat.models.data.listingmodels.DataManagementPlanOverviewModel; +import eu.eudat.models.data.listingmodels.UserInfoListingModel; import eu.eudat.models.data.security.Principal; import eu.eudat.query.DMPQuery; import eu.eudat.types.ApiMessageCode; @@ -277,6 +278,19 @@ public class DMPs extends BaseController { } } + + @Transactional + @RequestMapping(method = RequestMethod.POST, value = {"/updateusers/{id}"}) + public ResponseEntity> updateUsers(@PathVariable String id, @RequestBody List users, Principal principal) { + try { + this.dataManagementPlanManager.updateUsers(UUID.fromString(id), users, principal); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE).message("Successfully Updated Colaborators for Data Datamanagement Plan.")); + } catch (Exception e) { + logger.error(e.getMessage(), e); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.ERROR_MESSAGE).message("Failed to update the users of Data Management Plan.")); + } + } + /* * DOI Generation * */ diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java index 2796406fb..709b4265d 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DashBoardManager.java @@ -137,7 +137,7 @@ public class DashBoardManager { List roles = new LinkedList<>(); List finalDmps = dmps; - CompletableFuture dmpFuture = dataManagementPlanRepository.getAuthenticated(dmps != null ? dataManagementPlanRepository.asQueryable().where((builder, root) -> root.get("id").in(finalDmps.stream().map(Dmp::getId).collect(Collectors.toList()))) : dataManagementPlanRepository.getWithCriteria(dataManagementPlanCriteria), principal.getId(), roles).countAsync() + CompletableFuture dmpFuture = dataManagementPlanRepository.getAuthenticated(dmps != null ? dataManagementPlanRepository.asQueryable().where((builder, root) -> root.get("id").in(finalDmps.stream().map(Dmp::getId).collect(Collectors.toList()))) : dataManagementPlanRepository.getWithCriteria(dataManagementPlanCriteria), principal.getId(), roles).distinct().countAsync() .whenComplete((dmpsStats, throwable) -> statistics.setTotalDataManagementPlanCount(dmpsStats)); List finalDatasets = datasets; CompletableFuture datasetFuture = datasetRepository.getAuthenticated(datasets != null ? datasetRepository.asQueryable().where((builder, root) -> root.get("id").in(finalDatasets.stream().map(x -> UUID.fromString(x.getId())).collect(Collectors.toList()))) : datasetRepository.getWithCriteria(datasetCriteria), user, roles).countAsync() diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java index 8d272f67d..495811aaa 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java @@ -189,7 +189,7 @@ public class DataManagementPlanManager { .whenComplete((resultList, throwable) -> dataTable.setData(resultList)); } - CompletableFuture countFuture = authItems.countAsync().whenComplete((count, throwable) -> dataTable.setTotalCount(count)); + CompletableFuture countFuture = authItems.distinct().countAsync().whenComplete((count, throwable) -> dataTable.setTotalCount(count)); CompletableFuture.allOf(itemsFuture, countFuture).join(); return dataTable; } @@ -867,6 +867,18 @@ public class DataManagementPlanManager { this.updateIndex(dmp); } + public void updateUsers(UUID id, List users, Principal principal) throws Exception { + DMP dmp = this.apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().find(id); + if (!isUserOwnerOfDmp(dmp, principal)) + throw new Exception("User does not have the privilege to do this action."); + clearUsers(dmp); + for (UserInfoListingModel userListing : users) { + UserInfo tempUser = apiContext.getOperationsContext().getDatabaseRepository().getUserInfoDao().find(userListing.getId()); + assignUser(dmp, tempUser, UserDMP.UserDMPRoles.fromInteger(userListing.getRole())); + } + + } + /* * Export Data * */ diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/dataset/DatasetOverviewModel.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/dataset/DatasetOverviewModel.java index 1fe23c6a8..2ef2aeba1 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/dataset/DatasetOverviewModel.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/dataset/DatasetOverviewModel.java @@ -3,6 +3,8 @@ package eu.eudat.models.data.dataset; import eu.eudat.data.entities.Dataset; import eu.eudat.models.DataModel; import eu.eudat.models.data.datasetprofile.DatasetProfileOverviewModel; +import eu.eudat.models.data.grant.GrantOverviewModel; +import eu.eudat.models.data.listingmodels.DataManagementPlanOverviewModel; import eu.eudat.models.data.listingmodels.UserInfoListingModel; import java.util.Date; @@ -17,8 +19,8 @@ public class DatasetOverviewModel implements DataModel users; - private String dmp; - private String grant; + private DataManagementPlanOverviewModel dmp; + private GrantOverviewModel grant; private String description; private Boolean isPublic; private Date modified; @@ -59,19 +61,19 @@ public class DatasetOverviewModel implements DataModel new UserInfoListingModel().fromDataModel(x)).collect(Collectors.toList()); - this.dmp = entity.getDmp().getLabel(); - this.grant = entity.getDmp().getGrant().getLabel(); + this.dmp = new DataManagementPlanOverviewModel().fromDataModel(entity.getDmp()); + this.grant = new GrantOverviewModel().fromDataModel(entity.getDmp().getGrant()); this.description = entity.getDescription(); this.isPublic = entity.getDmp().isPublic(); this.modified = entity.getModified(); diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/rda/mapper/DmpRDAMapper.java b/dmp-backend/web/src/main/java/eu/eudat/models/rda/mapper/DmpRDAMapper.java index a64649c86..bda50f6ba 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/rda/mapper/DmpRDAMapper.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/rda/mapper/DmpRDAMapper.java @@ -3,6 +3,7 @@ package eu.eudat.models.rda.mapper; import eu.eudat.data.entities.*; import eu.eudat.logic.services.ApiContext; import eu.eudat.logic.utilities.helpers.StreamDistinctBy; +import eu.eudat.models.rda.Cost; import eu.eudat.models.rda.Dmp; import eu.eudat.models.rda.DmpId; import net.minidev.json.JSONObject; @@ -43,16 +44,34 @@ public class DmpRDAMapper { Map extraProperties = new org.json.JSONObject(dmp.getExtraProperties()).toMap(); if (!extraProperties.isEmpty()) { - rda.setLanguage(LanguageRDAMapper.mapLanguageIsoToRDAIso(extraProperties.get("language").toString())); + if (extraProperties.get("language") != null) { + rda.setLanguage(LanguageRDAMapper.mapLanguageIsoToRDAIso(extraProperties.get("language").toString())); + } + if (extraProperties.get("costs") != null) { + rda.setCost(new ArrayList<>()); + ((List) extraProperties.get("costs")).forEach(costl -> { + Cost cost = new Cost(); + Map code = new org.json.JSONObject((String) ((Map) costl).get("code")).toMap(); + cost.setCurrencyCode(Cost.CurrencyCode.fromValue((String) code.get("value"))); + cost.setDescription((String) ((Map) costl).get("description")); + cost.setTitle((String) ((Map) costl).get("title")); + cost.setValue(((Integer) ((Map) costl).get("value")).doubleValue()); + rda.getCost().add(cost); + }); + } + if (extraProperties.get("contact") != null) { + UserInfo contact = apiContext.getOperationsContext().getDatabaseRepository().getUserInfoDao().find(UUID.fromString((String)extraProperties.get("contact"))); + rda.setContact(ContactRDAMapper.toRDA(contact)); + } } - UserInfo creator; + /*UserInfo creator; if (dmp.getCreator() != null) { creator = dmp.getCreator(); } else { creator = dmp.getUsers().stream().filter(userDMP -> userDMP.getRole().equals(UserDMP.UserDMPRoles.OWNER.getValue())).map(UserDMP::getUser).findFirst().orElse(new UserInfo()); } - rda.setContact(ContactRDAMapper.toRDA(creator)); + rda.setContact(ContactRDAMapper.toRDA(creator));*/ rda.setContributor(new ArrayList<>()); if (dmp.getResearchers() != null && !dmp.getResearchers().isEmpty()) { rda.getContributor().addAll(dmp.getResearchers().stream().map(ContributorRDAMapper::toRDA).collect(Collectors.toList())); diff --git a/dmp-frontend/src/app/core/model/dataset/dataset-overview.ts b/dmp-frontend/src/app/core/model/dataset/dataset-overview.ts index 34bbe936c..3080a1548 100644 --- a/dmp-frontend/src/app/core/model/dataset/dataset-overview.ts +++ b/dmp-frontend/src/app/core/model/dataset/dataset-overview.ts @@ -1,5 +1,6 @@ import { DatasetProfileModel } from "./dataset-profile"; import { GrantOverviewModel } from '../grant/grant-overview'; +import { DmpOverviewModel } from '../dmp/dmp-overview'; export interface DatasetOverviewModel { id: string; @@ -8,7 +9,7 @@ export interface DatasetOverviewModel { datasetTemplate: DatasetProfileModel; users: any[]; - dmp: String; + dmp: DmpOverviewModel; grant: GrantOverviewModel; description: String; public: boolean; diff --git a/dmp-frontend/src/app/core/model/dmp/cost.ts b/dmp-frontend/src/app/core/model/dmp/cost.ts new file mode 100644 index 000000000..ab432f02b --- /dev/null +++ b/dmp-frontend/src/app/core/model/dmp/cost.ts @@ -0,0 +1,9 @@ +import { FormGroup, FormBuilder, Validators } from '@angular/forms'; +import { ValidationContext } from '@common/forms/validation/validation-context'; + +export interface CostModel { + code: string; + description: string; + title: string; + value: number; +} diff --git a/dmp-frontend/src/app/core/model/researcher/researcher.ts b/dmp-frontend/src/app/core/model/researcher/researcher.ts index 6c5bf6a98..9d23a8403 100644 --- a/dmp-frontend/src/app/core/model/researcher/researcher.ts +++ b/dmp-frontend/src/app/core/model/researcher/researcher.ts @@ -1,5 +1,5 @@ export interface ResearcherModel { - id: String; + id: string; name: String; reference: String; lastName: String; diff --git a/dmp-frontend/src/app/core/services/dataset/dataset.service.ts b/dmp-frontend/src/app/core/services/dataset/dataset.service.ts index d21df6676..e7306d139 100644 --- a/dmp-frontend/src/app/core/services/dataset/dataset.service.ts +++ b/dmp-frontend/src/app/core/services/dataset/dataset.service.ts @@ -11,7 +11,7 @@ import { BaseHttpService } from '../http/base-http.service'; import { DatasetProfileCriteria } from '../../query/dataset-profile/dataset-profile-criteria'; import { ConfigurationService } from '../configuration/configuration.service'; import { DatasetOverviewModel } from '@app/core/model/dataset/dataset-overview'; -import { HttpHeaders } from '@angular/common/http'; +import { HttpHeaders, HttpResponse, HttpClient } from '@angular/common/http'; import { DatasetModel } from '@app/core/model/dataset/dataset'; @Injectable() @@ -22,7 +22,8 @@ export class DatasetService { constructor( private http: BaseHttpService, - private configurationSevice: ConfigurationService) { + private configurationSevice: ConfigurationService, + private httpClient: HttpClient) { this.actionUrl = configurationSevice.server + 'datasets/'; } @@ -69,4 +70,27 @@ export class DatasetService { delete(id: String): Observable { return this.http.delete(this.actionUrl + 'delete/' + id, { headers: this.headers }); // + 'delete/' } + + publish(id: String): Observable { + return this.http.get(this.actionUrl + 'makepublic/' + id, { headers: this.headers }); + } + + public downloadXML(id: string): Observable> { + let headerXml: HttpHeaders = this.headers.set('Content-Type', 'application/xml') + return this.httpClient.get(this.actionUrl + id, { responseType: 'blob', observe: 'response', headers: headerXml }); //+ "/getXml/" + } + + public downloadDocx(id: string): Observable> { + let headerDoc: HttpHeaders = this.headers.set('Content-Type', 'application/msword') + return this.httpClient.get(this.actionUrl + id, { responseType: 'blob', observe: 'response', headers: headerDoc }); + } + + public downloadPDF(id: string): Observable> { + let headerPdf: HttpHeaders = this.headers.set('Content-Type', 'application/pdf') + return this.httpClient.get(this.actionUrl + 'getPDF/' + id, { responseType: 'blob', observe: 'response', headers: headerPdf }); + } + + public downloadJson(id: string): Observable> { + return this.httpClient.get(this.actionUrl + 'rda/' + id, { responseType: 'blob', observe: 'response' }); + } } diff --git a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts index 9819c90e3..e97f1ec25 100644 --- a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts +++ b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts @@ -19,6 +19,7 @@ import { ExploreDmpCriteriaModel } from '../../query/explore-dmp/explore-dmp-cri import { RequestItem } from '../../query/request-item'; import { BaseHttpService } from '../http/base-http.service'; import { ConfigurationService } from '../configuration/configuration.service'; +import { UserInfoListingModel } from '@app/core/model/user/user-info-listing'; @Injectable() export class DmpService { @@ -96,6 +97,10 @@ export class DmpService { return this.http.post(this.actionUrl + 'unfinalize/' + id, { headers: this.headers }); } + updateUsers(id: string, users: UserInfoListingModel[]): Observable { + return this.http.post(`${this.actionUrl}updateusers/${id}`, users, {headers: this.headers}); + } + getDoi(id: string): Observable { return this.http.post(this.actionUrl + 'createZenodoDoi/' + id, { headers: this.headers }); } diff --git a/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.html b/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.html index ea6fa3f22..a85436ba8 100644 --- a/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.html +++ b/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.html @@ -8,8 +8,8 @@
- -

{{ dataset.label }}

+ +

{{ dataset.label }}

@@ -27,56 +27,40 @@ {{'DMP-OVERVIEW.PRIVATE' | translate}}
- - -
{{'GENERAL.STATUSES.EDIT' | translate}} : +
+ lock_outline + {{'DMP-OVERVIEW.LOCKED' | translate}} +
+
{{'GENERAL.STATUSES.EDIT' | translate}} : {{dataset.modified | date:"longDate"}}
- +
- -
{{'DATASET-LISTING.TOOLTIP.PART-OF' | translate}}
-
{{'DMP-OVERVIEW.GRANT' | translate}}
-
Grant label
- +
{{ dataset.grant.label }}
{{'DMP-OVERVIEW.RESEARCHERS' | translate}}
- +
{{'DATASET-LISTING.COLUMNS.DESCRIPTION' | translate}}
@@ -104,31 +87,9 @@
-
- - - - - - +
diff --git a/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.scss b/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.scss index cc76c8022..6b918f358 100644 --- a/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.scss +++ b/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.scss @@ -20,7 +20,7 @@ font-size: 1.2em; } -.mat-mini-fab:hover { +.actions-btn:hover { background-color: #129D99; color: #FFFFFF; } @@ -139,6 +139,7 @@ .dataset-label { font-weight: bold; + width: auto; } .uppercase { @@ -149,14 +150,13 @@ font-size: 0.875em; color: #008887; padding-right: 0.5em; - align-self: center; - + align-self: center;; } .header { opacity: 0.6; margin-top: 1em; - margin-bottom: 0.25em; + margin-bottom: 0.5em; } .dataset-label, .header { @@ -262,7 +262,7 @@ // ********CENTER ELEMENTS******** -.mat-mini-fab, .mat-mini-fab-icon, +.mat-mini-fab, .mat-mini-fab-icon, .actions-btn, .status-icon, .dataset-logo, .frame-btn, .finalize-btn { display: flex; justify-content: center; diff --git a/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.ts b/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.ts index e7cbd4742..adb861816 100644 --- a/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.ts +++ b/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.ts @@ -19,6 +19,15 @@ import { Location } from '@angular/common'; import { UserInfoListingModel } from '@app/core/model/user/user-info-listing'; import { DatasetStatus } from '@app/core/common/enum/dataset-status'; import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import * as FileSaver from 'file-saver'; +import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation.component'; +import { DatasetWizardEditorModel } from '../dataset-wizard/dataset-wizard-editor.model'; +import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service'; +import { FormControl } from '@angular/forms'; +import { DatasetCopyDialogueComponent } from '../dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { ResearcherModel } from '@app/core/model/researcher/researcher'; +import { LockService } from '@app/core/services/lock/lock.service'; @Component({ @@ -29,6 +38,7 @@ import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog export class DatasetOverviewComponent extends BaseComponent implements OnInit { dataset: DatasetOverviewModel; + datasetWizardModel: DatasetWizardEditorModel; isNew = true; isFinalized = false; isPublicView = true; @@ -37,6 +47,8 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit { isUserOwner: boolean; expand = false; hasDOIToken = false; + researchers: ResearcherModel[]; + lockStatus: Boolean; constructor( private route: ActivatedRoute, @@ -50,7 +62,10 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit { private configurationService: ConfigurationService, private oauth2DialogService: Oauth2DialogService, private userService: UserService, - private location: Location + private dmpService: DmpService, + private location: Location, + private datasetWizardService: DatasetWizardService, + private lockService: LockService ) { super(); } @@ -69,7 +84,12 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit { .pipe(takeUntil(this._destroyed)) .subscribe(data => { this.dataset = data; - // this.checkLockStatus(this.dataset.id); + this.getDmpResearchers(); + this.datasetWizardService.getSingle(this.dataset.id).pipe(takeUntil(this._destroyed)) + .subscribe(data => { + this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data); + }); + this.checkLockStatus(this.dataset.id); this.setIsUserOwner(); const breadCrumbs = []; breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), url: "/datasets" }); @@ -92,7 +112,12 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit { .pipe(takeUntil(this._destroyed)) .subscribe(data => { this.dataset = data; - // this.checkLockStatus(this.dataset.id); + this.getDmpResearchers(); + this.datasetWizardService.getSingle(this.dataset.id).pipe(takeUntil(this._destroyed)) + .subscribe(data => { + this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data); + }); + this.checkLockStatus(this.dataset.id); this.setIsUserOwner(); const breadCrumbs = []; breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC DATASETS'), url: "/explore" }); @@ -110,112 +135,241 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit { }); } - onFetchingDeletedCallbackError(redirectRoot: string) { - this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-OVERVIEW.ERROR.DELETED-DATASET'), SnackBarNotificationLevel.Error); - this.router.navigate([redirectRoot]); + checkLockStatus(id: string){ + this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed)) + .subscribe(lockStatus => this.lockStatus = lockStatus); } - onFetchingForbiddenCallbackError(redirectRoot: string) { - this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-OVERVIEW.ERROR.FORBIDEN-DATASET'), SnackBarNotificationLevel.Error); - this.router.navigate([redirectRoot]); + onFetchingDeletedCallbackError(redirectRoot: string) { + this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-OVERVIEW.ERROR.DELETED-DATASET'), SnackBarNotificationLevel.Error); + this.router.navigate([redirectRoot]); } - + + onFetchingForbiddenCallbackError(redirectRoot: string) { + this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-OVERVIEW.ERROR.FORBIDEN-DATASET'), SnackBarNotificationLevel.Error); + this.router.navigate([redirectRoot]); + } + goBack(): void { - this.location.back(); - } + this.location.back(); + } + + getDmpResearchers() { + this.dmpService.getSingle(this.dataset.dmp.id).pipe(takeUntil(this._destroyed)) + .subscribe(data => { + this.researchers = data.researchers; + }); + } setIsUserOwner() { - if (this.dataset) { - const principal: Principal = this.authentication.current(); - if (principal) this.isUserOwner = principal.id === this.dataset.users.find(x => x.role === Role.Owner).id; - } + if (this.dataset) { + const principal: Principal = this.authentication.current(); + if (principal) this.isUserOwner = principal.id === this.dataset.users.find(x => x.role === Role.Owner).id; + } + } + + isUserAuthor(userId: string): boolean { + const principal: Principal = this.authentication.current(); + return userId === principal.id; } isUserDatasetRelated() { - const principal: Principal = this.authentication.current(); - let isRelated: boolean = false; - if (this.dataset && principal) { - this.dataset.users.forEach(element => { - if (element.id === principal.id) { - isRelated = true; - } - }) - } - return isRelated; + const principal: Principal = this.authentication.current(); + let isRelated: boolean = false; + if (this.dataset && principal) { + this.dataset.users.forEach(element => { + if (element.id === principal.id) { + isRelated = true; + } + }) + } + return isRelated; } - - roleDisplayFromList(value: UserInfoListingModel[]) { - const principal: Principal = this.authentication.current(); - let role: number; - if (principal) { - value.forEach(element => { - if (principal.id === element.id) { - role = element.role; - } - }); - } - if (role === Role.Owner) { - return this.translate.instant('DMP-LISTING.OWNER'); - } else if (role === Role.Member) { - return this.translate.instant('DMP-LISTING.MEMBER'); - } else { - return this.translate.instant('DMP-LISTING.OWNER'); - } - } - - public isAuthenticated(): boolean { - return !(!this.authentication.current()); - } - - cloneClicked(dataset: DatasetOverviewModel) { - this.router.navigate(['/datasets/clone/' + dataset.id]); - } - - isDraftDataset(dataset: DatasetOverviewModel) { - return dataset.status == DatasetStatus.Draft; - } - - editClicked(dataset: DatasetOverviewModel) { - this.router.navigate(['/datasets/edit/' + dataset.id]); - } - - deleteClicked() { - const dialogRef = this.dialog.open(ConfirmationDialogComponent, { - maxWidth: '300px', - data: { - message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'), - confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.DELETE'), - cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), - isDeleteConfirmation: true - } - }); - dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { - if (result) { - this.datasetService.delete(this.dataset.id) - .pipe(takeUntil(this._destroyed)) - .subscribe( - complete => { this.onCallbackSuccess() }, - error => this.onDeleteCallbackError(error) - ); - } - }); - } - - onCallbackSuccess(): void { - this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success); - this.router.navigate(['/datasets']); - } - onDeleteCallbackError(error) { - this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DELETE'), SnackBarNotificationLevel.Error); + roleDisplay(value: UserInfoListingModel) { + if (value.role === Role.Owner) { + return this.translate.instant('DMP-LISTING.OWNER'); + } else if (value.role === Role.Member) { + return this.translate.instant('DMP-LISTING.MEMBER'); + } else { + return this.translate.instant('DMP-LISTING.OWNER'); + } } - + + + roleDisplayFromList(value: UserInfoListingModel[]) { + const principal: Principal = this.authentication.current(); + let role: number; + if (principal) { + value.forEach(element => { + if (principal.id === element.id) { + role = element.role; + } + }); + } + if (role === Role.Owner) { + return this.translate.instant('DMP-LISTING.OWNER'); + } else if (role === Role.Member) { + return this.translate.instant('DMP-LISTING.MEMBER'); + } else { + return this.translate.instant('DMP-LISTING.OWNER'); + } + } + + openShareDialog(rowId: any, rowName: any) { + const dialogRef = this.dialog.open(DmpInvitationDialogComponent, { + restoreFocus: false, + data: { + dmpId: rowId, + dmpName: rowName + } + }); + } + + public isAuthenticated(): boolean { + return !(!this.authentication.current()); + } + + isDraftDataset(dataset: DatasetOverviewModel) { + return dataset.status == DatasetStatus.Draft; + } + + isFinalizedDataset(dataset: DatasetOverviewModel) { + return dataset.status == DatasetStatus.Finalized; + } + + editClicked(dataset: DatasetOverviewModel) { + if (dataset.public) { + this.router.navigate(['/datasets/publicEdit/' + dataset.id]); + } else { + this.router.navigate(['/datasets/edit/' + dataset.id]); + } + } + + deleteClicked() { + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + maxWidth: '300px', + data: { + message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'), + confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.DELETE'), + cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), + isDeleteConfirmation: true + } + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { + if (result) { + this.datasetService.delete(this.dataset.id) + .pipe(takeUntil(this._destroyed)) + .subscribe( + complete => { this.onCallbackSuccess() }, + error => this.onDeleteCallbackError(error) + ); + } + }); + } + + dmpClicked(dmpId: String) { + this.router.navigate(['/plans/overview/' + dmpId]); + } + + onCallbackSuccess(): void { + this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success); + this.router.navigate(['/datasets']); + } + + onDeleteCallbackError(error) { + this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DELETE'), SnackBarNotificationLevel.Error); + } + public getOrcidPath(): string { - return this.configurationService.orcidPath; + return this.configurationService.orcidPath; } - - // showPublishButton(dataset: DatasetOverviewModel) { - // return this.isFinalizedDmp(dmp) && !dmp.isPublic && this.hasPublishButton; - // } + + downloadPDF(id: string) { + this.datasetService.downloadPDF(id) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/pdf' }); + const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + + FileSaver.saveAs(blob, filename); + }); + } + + downloadDocx(id: string) { + this.datasetService.downloadDocx(id) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/msword' }); + const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + + FileSaver.saveAs(blob, filename); + }); + } + + downloadXml(id: string) { + this.datasetService.downloadXML(id) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/xml' }); + const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + + FileSaver.saveAs(blob, filename); + }); + } + + downloadJson(id: string) { + this.datasetService.downloadJson(id) + .pipe(takeUntil(this._destroyed)) + .subscribe(response => { + const blob = new Blob([response.body], { type: 'application/json' }); + const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + FileSaver.saveAs(blob, filename); + }) + } + + getFilenameFromContentDispositionHeader(header: string): string { + const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g); + + const matches = header.match(regex); + let filename: string; + for (let i = 0; i < matches.length; i++) { + const match = matches[i]; + if (match.includes('filename="')) { + filename = match.substring(10, match.length - 1); + break; + } else if (match.includes('filename=')) { + filename = match.substring(9); + break; + } + } + return filename; + } + + openDmpSearchDialogue() { + const formControl = new FormControl(); + const dialogRef = this.dialog.open(DatasetCopyDialogueComponent, { + width: '500px', + restoreFocus: false, + data: { + formControl: formControl, + datasetId: this.dataset.id, + datasetProfileId: this.datasetWizardModel.profile, + datasetProfileExist: false, + confirmButton: this.language.instant('DATASET-WIZARD.DIALOGUE.COPY'), + cancelButton: this.language.instant('DATASET-WIZARD.DIALOGUE.CANCEL') + } + }); + + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)) + .subscribe(result => { + if (result && result.datasetProfileExist) { + const newDmpId = result.formControl.value.id + this.router.navigate(['/datasets/copy/' + result.datasetId], { queryParams: { newDmpId: newDmpId } }); + } + }); + } + + } diff --git a/dmp-frontend/src/app/ui/dmp/dmp.module.ts b/dmp-frontend/src/app/ui/dmp/dmp.module.ts index 9db709001..dee306705 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp.module.ts +++ b/dmp-frontend/src/app/ui/dmp/dmp.module.ts @@ -32,6 +32,8 @@ import { FormValidationErrorsDialogModule } from '@common/forms/form-validation- import { CommonUiModule } from '@common/ui/common-ui.module'; import { MultipleChoiceDialogModule } from '@common/modules/multiple-choice-dialog/multiple-choice-dialog.module'; import { AddOrganizationComponent } from './editor/add-organization/add-organization.component'; +import { AddCostComponent } from './editor/cost-editor/add-cost/add-cost.component'; +import { CostListingComponent } from './editor/cost-editor/cost-listing/cost-listing.component'; import { DmpCriteriaDialogComponent } from './listing/criteria/dmp-criteria-dialog.component'; @NgModule({ @@ -71,7 +73,10 @@ import { DmpCriteriaDialogComponent } from './listing/criteria/dmp-criteria-dial DatasetsTabComponent, DmpCloneComponent, AddOrganizationComponent, - DmpCriteriaDialogComponent + DmpCriteriaDialogComponent, + AddOrganizationComponent, + AddCostComponent, + CostListingComponent ], entryComponents: [ DmpInvitationDialogComponent, @@ -80,7 +85,9 @@ import { DmpCriteriaDialogComponent } from './listing/criteria/dmp-criteria-dial DmpFinalizeDialogComponent, DmpUploadDialogue, AddOrganizationComponent, - DmpCriteriaDialogComponent + DmpCriteriaDialogComponent, + AddOrganizationComponent, + AddCostComponent ] }) export class DmpModule { } diff --git a/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.component.html b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.component.html new file mode 100644 index 000000000..fca4f3c07 --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.component.html @@ -0,0 +1,28 @@ +
+

{{'ADDEDITCOST-EDITOR.ADD-TITLE' | translate}}

+
+ + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + +
+
+
+
+
+
+
+
diff --git a/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.component.ts b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.component.ts new file mode 100644 index 000000000..7a4da0f75 --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.component.ts @@ -0,0 +1,60 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { FormGroup } from '@angular/forms'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { ExternalResearcherService } from '@app/core/services/external-sources/researcher/external-researcher.service'; +import { BaseComponent } from '@common/base/base.component'; +import { takeUntil } from 'rxjs/operators'; +import { CostEditorModel } from './add-cost.model'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { Observable } from 'rxjs'; +import { LocalFetchModel } from '@app/core/model/local-fetch/local-fetch.model'; +import { CurrencyService } from '@app/core/services/currency/currency.service'; + +@Component({ + selector: 'app-add-cost-component', + templateUrl: 'add-cost.component.html', +}) +export class AddCostComponent extends BaseComponent implements OnInit { + + public formGroup: FormGroup; + + currencyAutoCompleteConfiguration: SingleAutoCompleteConfiguration = { + filterFn: this.searchCurrency.bind(this), + initialItems: () => this.searchCurrency(''), + displayFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, + titleFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, + valueAssign: (item) => JSON.stringify(item) + }; + + constructor( + private externalResearcherService: ExternalResearcherService, + public dialogRef: MatDialogRef, + private currencyService: CurrencyService, + @Inject(MAT_DIALOG_DATA) public data: any + ) { super(); } + + ngOnInit(): void { + const cost = new CostEditorModel(); + this.formGroup = cost.buildForm(); + } + + send(value: any) { + this.externalResearcherService.createResearcher(this.formGroup.value) + .pipe(takeUntil(this._destroyed)) + .subscribe( + null, null, () => this.dialogRef.close() + ); + } + + addCost() { + this.dialogRef.close(this.formGroup.value); + } + + isFormValid() { + return this.formGroup.valid; + } + + searchCurrency(like: string): Observable { + return this.currencyService.get(like); + } +} diff --git a/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.model.ts b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.model.ts new file mode 100644 index 000000000..252e4950d --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.model.ts @@ -0,0 +1,44 @@ +import { FormBuilder, FormGroup } from '@angular/forms'; +import { ResearcherModel } from '@app/core/model/researcher/researcher'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; +import { OrganizationModel } from '@app/core/model/organisation/organization'; +import { CostModel } from '@app/core/model/dmp/cost'; + +export class CostEditorModel implements CostModel{ + public code: string; + public description: string; + public title: string; + public value: number; + public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); + + fromModel(item: CostModel): CostEditorModel { + this.code = item.code; + this.description = item.description; + this.title = item.title; + this.value = item.value; + return this; + } + + buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup { + if (context == null) { context = this.createValidationContext(); } + const formGroup = new FormBuilder().group({ + code: [{ value: this.code, disabled: disabled }, context.getValidation('code').validators], + description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators], + title: [{ value: this.title, disabled: disabled }, context.getValidation('title').validators], + value: [{ value: this.value, disabled: disabled }, context.getValidation('value').validators] + }); + + return formGroup; + } + + createValidationContext(): ValidationContext { + const baseContext: ValidationContext = new ValidationContext(); + baseContext.validation.push({ key: 'code', validators: [] }); + baseContext.validation.push({ key: 'description', validators: [] }); + baseContext.validation.push({ key: 'title', validators: [BackendErrorValidator(this.validationErrorModel, 'title')] }); + baseContext.validation.push({ key: 'value', validators: [] }); + return baseContext; + } +} diff --git a/dmp-frontend/src/app/ui/dmp/editor/cost-editor/cost-listing/cost-listing.component.html b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/cost-listing/cost-listing.component.html new file mode 100644 index 000000000..8ed92f09d --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/cost-listing/cost-listing.component.html @@ -0,0 +1,42 @@ + + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + +
diff --git a/dmp-frontend/src/app/ui/dmp/editor/cost-editor/cost-listing/cost-listing.component.scss b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/cost-listing/cost-listing.component.scss new file mode 100644 index 000000000..52f45cc20 --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/cost-listing/cost-listing.component.scss @@ -0,0 +1,10 @@ +.listing-container { + height: fit-content; + width: fit-content; + background-color: whitesmoke; +} + + +.cost-element { + margin-bottom: 1em; +} diff --git a/dmp-frontend/src/app/ui/dmp/editor/cost-editor/cost-listing/cost-listing.component.ts b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/cost-listing/cost-listing.component.ts new file mode 100644 index 000000000..16bbc9a89 --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/cost-listing/cost-listing.component.ts @@ -0,0 +1,63 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { BaseComponent } from '@common/base/base.component'; +import { FormArray, FormControl } from '@angular/forms'; +import { takeUntil } from 'rxjs/operators'; +import { CostModel } from '@app/core/model/dmp/cost'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { CurrencyService } from '@app/core/services/currency/currency.service'; +import { Observable } from 'rxjs'; +import { LocalFetchModel } from '@app/core/model/local-fetch/local-fetch.model'; +import { CostEditorModel } from '../add-cost/add-cost.model'; + +@Component({ + selector: 'app-cost-listing', + templateUrl: './cost-listing.component.html', + styleUrls: ['./cost-listing.component.scss'] +}) +export class CostListingComponent extends BaseComponent implements OnInit { + + @Input() form: FormArray; + + private cost: CostEditorModel[] = []; + + currencyAutoCompleteConfiguration: SingleAutoCompleteConfiguration = { + filterFn: this.searchCurrency.bind(this), + initialItems: () => this.searchCurrency(''), + displayFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, + titleFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, + valueAssign: (item) => JSON.stringify(item) + }; + + constructor( + private currencyService: CurrencyService, + ) { + super(); + } + + ngOnInit() { + } + + searchCurrency(like: string): Observable { + return this.currencyService.get(like); +} + +switchEditMode(event: number) { + const control = this.form.at(event); + if (control.disabled) { + this.cost[event] = control.value; + control.enable(); + } else { + control.disable(); + } +} + +removeCost(event: number) { + this.form.removeAt(event); +} + +revertEdits(event: number) { + this.form.at(event).setValue(this.cost[event]); + this.form.at(event).disable(); +} + +} diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/extra-properties-form.model.ts b/dmp-frontend/src/app/ui/dmp/editor/general-tab/extra-properties-form.model.ts index 89d32c5ce..c2dc45d91 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/extra-properties-form.model.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/extra-properties-form.model.ts @@ -1,30 +1,53 @@ import { ValidationContext } from '@common/forms/validation/validation-context'; import { FormGroup, FormBuilder, Validators } from '@angular/forms'; import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { CostModel } from '@app/core/model/dmp/cost'; +import { isNullOrUndefined } from 'util'; +import { CostEditorModel } from '../cost-editor/add-cost/add-cost.model'; export class ExtraPropertiesFormModel { public language: string; public license: string; public visible: boolean; public publicDate: Date; + public contact: string; + public costs: CostEditorModel[] = []; fromModel(item: any): ExtraPropertiesFormModel { this.language = item.language; this.license = item.license; this.visible = item.visible; this.publicDate = item.publicDate; + this.contact = item.contact; + if (!isNullOrUndefined(item.costs)) { + (item.costs).forEach(element => { + this.costs.push(new CostEditorModel().fromModel(element)); + }); + } return this; } buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup { if (context == null) { context = this.createValidationContext(); } - + const formBuilder = new FormBuilder(); const formGroup = new FormBuilder().group({ language: [{ value: this.language, disabled: disabled }, context.getValidation('language').validators], license: [{ value: this.license, disabled: disabled }, context.getValidation('license').validators], visible: [{ value: this.visible, disabled: disabled }, context.getValidation('visible').validators], - publicDate: [{ value: this.publicDate, disabled: disabled }, context.getValidation('publicDate').validators] + publicDate: [{ value: this.publicDate, disabled: disabled }, context.getValidation('publicDate').validators], + contact: [{ value: this.contact, disabled: disabled }, context.getValidation('contact').validators], + // costs: [{ value: this.costs, disabled: disabled }, context.getValidation('costs').validators] }); + + const costArray = new Array(); + //if (this.externalDatasets && this.externalDatasets.length > 0) { + this.costs.forEach(item => { + costArray.push(item.buildForm(context.getValidation('costs').descendantValidations, true)); + }); + // } else { + // //externalDatasetsFormArray.push(new ExternalDatasetModel().buildForm(context.getValidation('externalDatasets').descendantValidations, disabled)); + // } + formGroup.addControl('costs', formBuilder.array(costArray)); return formGroup; } @@ -34,6 +57,8 @@ export class ExtraPropertiesFormModel { baseContext.validation.push({ key: 'license', validators: [] }); baseContext.validation.push({ key: 'visible', validators: [] }); baseContext.validation.push({ key: 'publicDate', validators: [] }); + baseContext.validation.push({ key: 'contact', validators: [] }); + baseContext.validation.push({ key: 'costs', validators: [] }); return baseContext; } diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html index ce433d868..78852a3a6 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html @@ -88,7 +88,7 @@ - {{formGroup.get('extraProperties').get('language').getError('backendError').message}} + {{formGroup.get('extraProperties').get('license').getError('backendError').message}} {{'GENERAL.VALIDATION.REQUIRED' | translate}} @@ -117,13 +117,36 @@ - - {{formGroup.get('extraProperties').get('visible').getError('backendError').message}} - + + {{formGroup.get('extraProperties').get('publicDate').getError('backendError').message}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} +
+ + + + + {{vis.name | translate}} + + + + {{formGroup.get('extraProperties').get('contact').getError('backendError').message}} + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + +
+
+ Costs + + +
diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.scss b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.scss index 05d8ae793..322c63d34 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.scss +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.scss @@ -37,3 +37,11 @@ ::ng-deep .mat-form-field-appearance-legacy .mat-form-field-wrapper { padding-bottom: 1.25em; } + +.cost-placeholder { + text-decoration: underline; +} + +.cost-add { + margin-top: 1em; +} diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts index 0dee0573f..f699dad91 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnInit } from '@angular/core'; -import { FormGroup } from '@angular/forms'; +import { FormGroup, FormArray } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; @@ -26,6 +26,8 @@ import { ConfigurationService } from '@app/core/services/configuration/configura import { LanguageInfoService } from '@app/core/services/culture/language-info-service'; import { LanguageInfo } from '@app/core/model/language-info'; import { LicenseCriteria } from '@app/core/query/license/license-criteria'; +import { AddCostComponent } from '../cost-editor/add-cost/add-cost.component'; +import { CostEditorModel } from '../cost-editor/add-cost/add-cost.model'; interface Visible { value: boolean; @@ -253,4 +255,27 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { getLanguageInfos(): LanguageInfo[] { return this.languageInfoService.getLanguageInfoValues(); } + + getAssociates(): any[] { + let associates: any[] = []; + //associates = (this.formGroup.get('researchers').value as any[]); + associates = associates.concat(this.formGroup.get('associatedUsers').value); + return associates; + } + + addCost(event: MouseEvent) { + event.stopPropagation(); + const dialogRef = this.dialog.open(AddCostComponent, { + data: this.formGroup.get('extraProperties').get('costs') + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { + if (result) { + const costsArray = this.formGroup.get('extraProperties').get('costs').value || []; + costsArray.push(result); + let costeditModel: CostEditorModel = new CostEditorModel(); + costeditModel = costeditModel.fromModel(result); + (this.formGroup.get('extraProperties').get('costs')).push(costeditModel.buildForm(null, true)); + } + }); + } } diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html index cd5c4e1f2..e69f6c004 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html @@ -26,15 +26,9 @@ {{'DMP-OVERVIEW.PRIVATE' | translate}}
-
-
- lock_outline - {{'DMP-OVERVIEW.LOCKED' | translate}} -
-
- lock_open - {{'DMP-OVERVIEW.UNLOCKED' | translate}} -
+
+ lock_outline + {{'DMP-OVERVIEW.LOCKED' | translate}}
@@ -56,22 +50,16 @@ matTooltip="{{'DMP-LISTING.ACTIONS.CLONE' | translate}}" matTooltipPosition="above"> content_copy - - -
{{'DMP-OVERVIEW.GRANT' | translate}}
{{ dmp.grant.label }}
@@ -141,7 +129,7 @@
-
+
- + +
@@ -60,7 +62,7 @@
-
About
+
FAQs
FAQs
@@ -108,7 +110,7 @@
-

ARGOS is comprised of two main functionalities: DMP templates and Dataset Descriptions. +

ARGOS is comprised of two main functionalities: DMP templates and Dataset Descriptions. Additional entities are Projects that link to funders and grants information.
ARGOS can be used for:

A. viewing/ consulting publicly released DMPs and @@ -131,7 +133,7 @@ Examples may refer to embedding DMP and DMP tools in specific curricula or even utilization of the tool for researchers and students familiarization with the concept and process, as part of library instructions’ sessions. -

+
@@ -206,4 +208,4 @@ - \ No newline at end of file + diff --git a/dmp-frontend/src/assets/splash/about/how-it-works.html b/dmp-frontend/src/assets/splash/about/how-it-works.html index 9bfe06404..7446523a2 100644 --- a/dmp-frontend/src/assets/splash/about/how-it-works.html +++ b/dmp-frontend/src/assets/splash/about/how-it-works.html @@ -59,7 +59,7 @@
-
About
+
How it works
How it works