Merge branch 'ui-redesign' of gitlab.eudat.eu:dmp/OpenAIRE-EUDAT-DMP-service-pilot into ui-redesign

# Conflicts:
#	dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts
This commit is contained in:
apapachristou 2020-07-07 13:19:38 +03:00
commit 6fa7b4a350
32 changed files with 779 additions and 278 deletions

View File

@ -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.helpers.responses.ResponseItem;
import eu.eudat.models.data.listingmodels.DataManagementPlanListingModel; import eu.eudat.models.data.listingmodels.DataManagementPlanListingModel;
import eu.eudat.models.data.listingmodels.DataManagementPlanOverviewModel; import eu.eudat.models.data.listingmodels.DataManagementPlanOverviewModel;
import eu.eudat.models.data.listingmodels.UserInfoListingModel;
import eu.eudat.models.data.security.Principal; import eu.eudat.models.data.security.Principal;
import eu.eudat.query.DMPQuery; import eu.eudat.query.DMPQuery;
import eu.eudat.types.ApiMessageCode; import eu.eudat.types.ApiMessageCode;
@ -277,6 +278,19 @@ public class DMPs extends BaseController {
} }
} }
@Transactional
@RequestMapping(method = RequestMethod.POST, value = {"/updateusers/{id}"})
public ResponseEntity<ResponseItem<DMP>> updateUsers(@PathVariable String id, @RequestBody List<UserInfoListingModel> users, Principal principal) {
try {
this.dataManagementPlanManager.updateUsers(UUID.fromString(id), users, principal);
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<DMP>().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<DMP>().status(ApiMessageCode.ERROR_MESSAGE).message("Failed to update the users of Data Management Plan."));
}
}
/* /*
* DOI Generation * DOI Generation
* */ * */

View File

@ -137,7 +137,7 @@ public class DashBoardManager {
List<Integer> roles = new LinkedList<>(); List<Integer> roles = new LinkedList<>();
List<Dmp> finalDmps = dmps; List<Dmp> 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)); .whenComplete((dmpsStats, throwable) -> statistics.setTotalDataManagementPlanCount(dmpsStats));
List<eu.eudat.elastic.entities.Dataset> finalDatasets = datasets; List<eu.eudat.elastic.entities.Dataset> 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() 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()

View File

@ -189,7 +189,7 @@ public class DataManagementPlanManager {
.whenComplete((resultList, throwable) -> dataTable.setData(resultList)); .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(); CompletableFuture.allOf(itemsFuture, countFuture).join();
return dataTable; return dataTable;
} }
@ -867,6 +867,18 @@ public class DataManagementPlanManager {
this.updateIndex(dmp); this.updateIndex(dmp);
} }
public void updateUsers(UUID id, List<UserInfoListingModel> 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 * Export Data
* */ * */

View File

@ -3,6 +3,8 @@ package eu.eudat.models.data.dataset;
import eu.eudat.data.entities.Dataset; import eu.eudat.data.entities.Dataset;
import eu.eudat.models.DataModel; import eu.eudat.models.DataModel;
import eu.eudat.models.data.datasetprofile.DatasetProfileOverviewModel; 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 eu.eudat.models.data.listingmodels.UserInfoListingModel;
import java.util.Date; import java.util.Date;
@ -17,8 +19,8 @@ public class DatasetOverviewModel implements DataModel<Dataset, DatasetOverviewM
private short status; private short status;
private DatasetProfileOverviewModel datasetTemplate; private DatasetProfileOverviewModel datasetTemplate;
private List<UserInfoListingModel> users; private List<UserInfoListingModel> users;
private String dmp; private DataManagementPlanOverviewModel dmp;
private String grant; private GrantOverviewModel grant;
private String description; private String description;
private Boolean isPublic; private Boolean isPublic;
private Date modified; private Date modified;
@ -59,19 +61,19 @@ public class DatasetOverviewModel implements DataModel<Dataset, DatasetOverviewM
this.users = users; this.users = users;
} }
public String getDmp() { public DataManagementPlanOverviewModel getDmp() {
return dmp; return dmp;
} }
public void setDmp(String dmp) { public void setDmp(DataManagementPlanOverviewModel dmp) {
this.dmp = dmp; this.dmp = dmp;
} }
public String getGrant() { public GrantOverviewModel getGrant() {
return grant; return grant;
} }
public void setGrant(String grant) { public void setGrant(GrantOverviewModel grant) {
this.grant = grant; this.grant = grant;
} }
@ -106,8 +108,8 @@ public class DatasetOverviewModel implements DataModel<Dataset, DatasetOverviewM
this.status = entity.getStatus(); this.status = entity.getStatus();
this.datasetTemplate = new DatasetProfileOverviewModel().fromDataModel(entity.getProfile()); this.datasetTemplate = new DatasetProfileOverviewModel().fromDataModel(entity.getProfile());
this.users = entity.getDmp().getUsers().stream().map(x -> new UserInfoListingModel().fromDataModel(x)).collect(Collectors.toList()); this.users = entity.getDmp().getUsers().stream().map(x -> new UserInfoListingModel().fromDataModel(x)).collect(Collectors.toList());
this.dmp = entity.getDmp().getLabel(); this.dmp = new DataManagementPlanOverviewModel().fromDataModel(entity.getDmp());
this.grant = entity.getDmp().getGrant().getLabel(); this.grant = new GrantOverviewModel().fromDataModel(entity.getDmp().getGrant());
this.description = entity.getDescription(); this.description = entity.getDescription();
this.isPublic = entity.getDmp().isPublic(); this.isPublic = entity.getDmp().isPublic();
this.modified = entity.getModified(); this.modified = entity.getModified();

View File

@ -3,6 +3,7 @@ package eu.eudat.models.rda.mapper;
import eu.eudat.data.entities.*; import eu.eudat.data.entities.*;
import eu.eudat.logic.services.ApiContext; import eu.eudat.logic.services.ApiContext;
import eu.eudat.logic.utilities.helpers.StreamDistinctBy; import eu.eudat.logic.utilities.helpers.StreamDistinctBy;
import eu.eudat.models.rda.Cost;
import eu.eudat.models.rda.Dmp; import eu.eudat.models.rda.Dmp;
import eu.eudat.models.rda.DmpId; import eu.eudat.models.rda.DmpId;
import net.minidev.json.JSONObject; import net.minidev.json.JSONObject;
@ -43,16 +44,34 @@ public class DmpRDAMapper {
Map<String, Object> extraProperties = new org.json.JSONObject(dmp.getExtraProperties()).toMap(); Map<String, Object> extraProperties = new org.json.JSONObject(dmp.getExtraProperties()).toMap();
if (!extraProperties.isEmpty()) { 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<String, Object> 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) { if (dmp.getCreator() != null) {
creator = dmp.getCreator(); creator = dmp.getCreator();
} else { } else {
creator = dmp.getUsers().stream().filter(userDMP -> userDMP.getRole().equals(UserDMP.UserDMPRoles.OWNER.getValue())).map(UserDMP::getUser).findFirst().orElse(new UserInfo()); 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<>()); rda.setContributor(new ArrayList<>());
if (dmp.getResearchers() != null && !dmp.getResearchers().isEmpty()) { if (dmp.getResearchers() != null && !dmp.getResearchers().isEmpty()) {
rda.getContributor().addAll(dmp.getResearchers().stream().map(ContributorRDAMapper::toRDA).collect(Collectors.toList())); rda.getContributor().addAll(dmp.getResearchers().stream().map(ContributorRDAMapper::toRDA).collect(Collectors.toList()));

View File

@ -1,5 +1,6 @@
import { DatasetProfileModel } from "./dataset-profile"; import { DatasetProfileModel } from "./dataset-profile";
import { GrantOverviewModel } from '../grant/grant-overview'; import { GrantOverviewModel } from '../grant/grant-overview';
import { DmpOverviewModel } from '../dmp/dmp-overview';
export interface DatasetOverviewModel { export interface DatasetOverviewModel {
id: string; id: string;
@ -8,7 +9,7 @@ export interface DatasetOverviewModel {
datasetTemplate: DatasetProfileModel; datasetTemplate: DatasetProfileModel;
users: any[]; users: any[];
dmp: String; dmp: DmpOverviewModel;
grant: GrantOverviewModel; grant: GrantOverviewModel;
description: String; description: String;
public: boolean; public: boolean;

View File

@ -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;
}

View File

@ -1,5 +1,5 @@
export interface ResearcherModel { export interface ResearcherModel {
id: String; id: string;
name: String; name: String;
reference: String; reference: String;
lastName: String; lastName: String;

View File

@ -11,7 +11,7 @@ import { BaseHttpService } from '../http/base-http.service';
import { DatasetProfileCriteria } from '../../query/dataset-profile/dataset-profile-criteria'; import { DatasetProfileCriteria } from '../../query/dataset-profile/dataset-profile-criteria';
import { ConfigurationService } from '../configuration/configuration.service'; import { ConfigurationService } from '../configuration/configuration.service';
import { DatasetOverviewModel } from '@app/core/model/dataset/dataset-overview'; 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'; import { DatasetModel } from '@app/core/model/dataset/dataset';
@Injectable() @Injectable()
@ -22,7 +22,8 @@ export class DatasetService {
constructor( constructor(
private http: BaseHttpService, private http: BaseHttpService,
private configurationSevice: ConfigurationService) { private configurationSevice: ConfigurationService,
private httpClient: HttpClient) {
this.actionUrl = configurationSevice.server + 'datasets/'; this.actionUrl = configurationSevice.server + 'datasets/';
} }
@ -69,4 +70,27 @@ export class DatasetService {
delete(id: String): Observable<DatasetModel> { delete(id: String): Observable<DatasetModel> {
return this.http.delete<DatasetModel>(this.actionUrl + 'delete/' + id, { headers: this.headers }); // + 'delete/' return this.http.delete<DatasetModel>(this.actionUrl + 'delete/' + id, { headers: this.headers }); // + 'delete/'
} }
publish(id: String): Observable<DatasetModel> {
return this.http.get<DatasetModel>(this.actionUrl + 'makepublic/' + id, { headers: this.headers });
}
public downloadXML(id: string): Observable<HttpResponse<Blob>> {
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<HttpResponse<Blob>> {
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<HttpResponse<Blob>> {
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<HttpResponse<Blob>> {
return this.httpClient.get(this.actionUrl + 'rda/' + id, { responseType: 'blob', observe: 'response' });
}
} }

View File

@ -19,6 +19,7 @@ import { ExploreDmpCriteriaModel } from '../../query/explore-dmp/explore-dmp-cri
import { RequestItem } from '../../query/request-item'; import { RequestItem } from '../../query/request-item';
import { BaseHttpService } from '../http/base-http.service'; import { BaseHttpService } from '../http/base-http.service';
import { ConfigurationService } from '../configuration/configuration.service'; import { ConfigurationService } from '../configuration/configuration.service';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
@Injectable() @Injectable()
export class DmpService { export class DmpService {
@ -96,6 +97,10 @@ export class DmpService {
return this.http.post<DmpModel>(this.actionUrl + 'unfinalize/' + id, { headers: this.headers }); return this.http.post<DmpModel>(this.actionUrl + 'unfinalize/' + id, { headers: this.headers });
} }
updateUsers(id: string, users: UserInfoListingModel[]): Observable<DmpModel> {
return this.http.post<DmpModel>(`${this.actionUrl}updateusers/${id}`, users, {headers: this.headers});
}
getDoi(id: string): Observable<string> { getDoi(id: string): Observable<string> {
return this.http.post<string>(this.actionUrl + 'createZenodoDoi/' + id, { headers: this.headers }); return this.http.post<string>(this.actionUrl + 'createZenodoDoi/' + id, { headers: this.headers });
} }

View File

@ -8,8 +8,8 @@
<div class="row"> <div class="row">
<div class="col-md-8 col-lg-8 pl-4"> <div class="col-md-8 col-lg-8 pl-4">
<div class="row"> <div class="row">
<span class="dataset-logo">{{ 'NAV-BAR.DATASET' | translate }}</span> <span class="col-auto dataset-logo">{{ 'NAV-BAR.DATASET' | translate }}</span>
<p class="dataset-label ml-2 mb-0">{{ dataset.label }}</p> <p class="col dataset-label p-0 ml-3 mb-0">{{ dataset.label }}</p>
</div> </div>
<div class="row d-flex align-items-center mt-3 mb-4 label-txt"> <div class="row d-flex align-items-center mt-3 mb-4 label-txt">
<div *ngIf="isUserDatasetRelated()" class="d-flex"> <div *ngIf="isUserDatasetRelated()" class="d-flex">
@ -27,56 +27,40 @@
{{'DMP-OVERVIEW.PRIVATE' | translate}} {{'DMP-OVERVIEW.PRIVATE' | translate}}
</div> </div>
</div> </div>
<!-- <div class="d-flex mr-4"> <div *ngIf="lockStatus" class="d-flex flex-row mr-4">
<div *ngIf="lockStatus" class="d-flex flex-row"> <mat-icon class="status-icon">lock_outline</mat-icon>
<mat-icon class="status-icon">lock_outline</mat-icon> {{'DMP-OVERVIEW.LOCKED' | translate}}
{{'DMP-OVERVIEW.LOCKED' | translate}} </div>
</div> <div class="d-flex mr-3">{{'GENERAL.STATUSES.EDIT' | translate}} :
<div *ngIf="!lockStatus" class="d-flex flex-row">
<mat-icon class="status-icon">lock_open</mat-icon>
{{'DMP-OVERVIEW.UNLOCKED' | translate}}
</div>
</div> -->
<!-- <button class="d-flex mr-4 version-btn label2-txt"
(click)="viewVersions(dmp.groupId, dmp.label)">
{{'DMP-LISTING.ACTIONS.VIEW-VERSION' | translate}}
</button> -->
<div class="d-flex mr-4">{{'GENERAL.STATUSES.EDIT' | translate}} :
{{dataset.modified | date:"longDate"}} {{dataset.modified | date:"longDate"}}
</div> </div>
<!-- <div class="d-flex mr-4"> <div class="d-flex mr-4">
<div *ngIf="dmp.status" class="d-flex flex-row uppercase"> <div *ngIf="dataset.status" class="d-flex flex-row uppercase">
<mat-icon class="status-icon">check</mat-icon> <mat-icon class="status-icon">check</mat-icon>
{{'DATASET-LISTING.COLUMNS.FINALIZED' | translate}} {{'TYPES.DATASET-STATUS.FINALISED' | translate}}
</div> </div>
</div> --> </div>
</div> </div>
<div class="row mb-4 pb-3"> <div class="row mb-4 pb-3">
<button *ngIf="isAuthenticated()" (click)="cloneClicked(dataset)" mat-mini-fab <button *ngIf="isAuthenticated()" (click)="openDmpSearchDialogue()" mat-mini-fab
class="mr-3 d-flex justify-content-center align-items-center" class="mr-3 actions-btn" matTooltip="{{'DMP-LISTING.ACTIONS.CLONE' | translate}}"
matTooltip="{{'DMP-LISTING.ACTIONS.CLONE' | translate}}" matTooltipPosition="above"> matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">content_copy</mat-icon> <mat-icon class="mat-mini-fab-icon">content_copy</mat-icon>
</button> </button>
<button *ngIf="isDraftDataset(dataset) && isUserOwner" (click)="editClicked(dataset)" <button *ngIf="isDraftDataset(dataset) && isUserOwner" (click)="editClicked(dataset)"
mat-mini-fab class="mr-3 d-flex justify-content-center align-items-center" mat-mini-fab class="mr-3 actions-btn"
matTooltip="{{'DMP-LISTING.ACTIONS.EDIT' | translate}}" matTooltipPosition="above"> matTooltip="{{'DMP-LISTING.ACTIONS.EDIT' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">create</mat-icon> <mat-icon class="mat-mini-fab-icon">create</mat-icon>
</button> </button>
<button *ngIf="isDraftDataset(dataset) && isUserOwner" (click)="deleteClicked()" mat-mini-fab <button *ngIf="isDraftDataset(dataset) && isUserOwner" (click)="deleteClicked()" mat-mini-fab
class="mr-3 d-flex justify-content-center align-items-center" class="mr-3 actions-btn" matTooltip="{{'DMP-LISTING.ACTIONS.DELETE' | translate}}"
matTooltip="{{'DMP-LISTING.ACTIONS.DELETE' | translate}}" matTooltipPosition="above"> matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">delete</mat-icon> <mat-icon class="mat-mini-fab-icon">delete</mat-icon>
</button> </button>
<!-- <button *ngIf="isDraftDmp(dmp) && isUserOwner && !lockStatus" mat-mini-fab (click)="createOrUpdate(dmp.id)"
class="mr-3 d-flex justify-content-center align-items-center">
<mat-icon class="mat-mini-fab-icon" matTooltip="{{'DMP-OVERVIEW.LOCK' | translate}}"
matTooltipPosition="above">lock_outline
</mat-icon>
</button> -->
</div> </div>
<div class="row header">{{'DATASET-LISTING.TOOLTIP.PART-OF' | translate}}</div> <div class="row header">{{'DATASET-LISTING.TOOLTIP.PART-OF' | translate}}</div>
<div class="row "> <div class="row ">
<button class="dmp-btn"> <button class="dmp-btn" (click)="dmpClicked(dataset.dmp.id)">
<div class="dmp-btn-label"> <div class="dmp-btn-label">
{{ 'DATASET-LISTING.TOOLTIP.DMP-FOR' | translate }}: {{ dataset.datasetTemplate.label }} {{ 'DATASET-LISTING.TOOLTIP.DMP-FOR' | translate }}: {{ dataset.datasetTemplate.label }}
</div> </div>
@ -85,17 +69,16 @@
</div> </div>
<div class="row header">{{'DMP-OVERVIEW.GRANT' | translate}}</div> <div class="row header">{{'DMP-OVERVIEW.GRANT' | translate}}</div>
<div class="row dmp-label">Grant label</div> <div class="row dataset-label">{{ dataset.grant.label }}</div>
<!-- <div class="row dmp-label">{{ dataset.grant.label }}</div> -->
<div class="row header">{{'DMP-OVERVIEW.RESEARCHERS' | translate}}</div> <div class="row header">{{'DMP-OVERVIEW.RESEARCHERS' | translate}}</div>
<div class="row"> <div class="row">
<!-- <div *ngFor="let researcher of dataset.dmp.researchers; let last = last"> <div *ngFor="let researcher of researchers; let last = last">
<a href="{{getOrcidPath() + researcher.id }}" target="blank" class="researcher"> <a href="{{ getOrcidPath() + researcher.id }}" target="blank" class="researcher">
<div class="id-btn">&nbsp;</div> <div class="id-btn">&nbsp;</div>
<div *ngIf="!last">{{ researcher.name }}, </div> <div *ngIf="!last">{{ researcher.name }}, </div>
<div *ngIf="last">{{ researcher.name }}</div> <div *ngIf="last">{{ researcher.name }}</div>
</a> </a>
</div> --> </div>
</div> </div>
<div class="row header">{{'DATASET-LISTING.COLUMNS.DESCRIPTION' | translate}}</div> <div class="row header">{{'DATASET-LISTING.COLUMNS.DESCRIPTION' | translate}}</div>
@ -104,31 +87,9 @@
</div> </div>
</div> </div>
<div class="col-md-4 col-lg-4 p-0"> <div class="col-md-4 col-lg-4 p-0">
<!-- <div *ngIf="!hasDoi(dmp)" class="row d-flex flex-column ml-0 mr-0 mb-3">
<p class="doi-label">{{'DMP-EDITOR.TITLE.SUBTITLE' | translate}}</p>
<div class="doi-panel">
<p *ngIf="!hasDoi(dmp)" class="mb-0 ml-3">
<textarea #doi class="doi-txt">{{ dmp.doi }}</textarea>
</p>
<div class="d-flex justify-content-end">
<button (click)="copyDoi(doi)" mat-mini-fab
class="mr-2 d-flex justify-content-center align-items-center"
matTooltip="{{'DMP-LISTING.ACTIONS.CLONE' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">content_copy</mat-icon>
</button>
<button mat-mini-fab class="mr-2 d-flex justify-content-center align-items-center"
matTooltip="{{'GRANT-EDITOR.ACTIONS.VISIT-WEBSITE' | translate}}"
matTooltipPosition="above">
<a [href]="createDoiLink(dmp.doi)" class="doi-link" target="_blank">
<mat-icon class="mat-mini-fab-icon">launch</mat-icon>
</a>
</button>
</div>
</div>
</div> -->
<div class="frame mb-3 pt-4 pl-3 pr-5 pb-1"> <div class="frame mb-3 pt-4 pl-3 pr-5 pb-1">
<!-- <div *ngIf="!dmp.status && isDraftDmp(dmp) && isUserOwner"> <!-- <div *ngIf="!dataset.status && isDraftDataset(dataset) && isUserOwner">
<div class="row ml-0 mr-0 pl-4 d-flex align-items-center" (click)="finalize(dmp)"> <div class="row ml-0 mr-0 pl-4 d-flex align-items-center" (click)="finalize(dataset)">
<button mat-mini-fab class="finalize-btn"> <button mat-mini-fab class="finalize-btn">
<mat-icon class="mat-mini-fab-icon">check</mat-icon> <mat-icon class="mat-mini-fab-icon">check</mat-icon>
</button> </button>
@ -138,60 +99,38 @@
<hr class="hr-line"> <hr class="hr-line">
</div> </div>
</div> --> </div> -->
<!-- <div *ngIf="hasDoi(dmp) && isFinalizedDmp(dmp) && !this.isPublicView && isUserOwner" <div class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center">
(click)="getDoi(dmp)" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center">
<button mat-mini-fab class="frame-btn">
<mat-icon class="mat-mini-fab-icon">archive</mat-icon>
</button>
<p class="mb-0 pl-2 frame-txt">{{ 'DMP-LISTING.ACTIONS.DEPOSIT' | translate }}</p>
</div> -->
<!-- <div class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center">
<button mat-mini-fab class="frame-btn" [matMenuTriggerFor]="exportMenu"> <button mat-mini-fab class="frame-btn" [matMenuTriggerFor]="exportMenu">
<mat-icon class="mat-mini-fab-icon">open_in_new</mat-icon> <mat-icon class="mat-mini-fab-icon">open_in_new</mat-icon>
</button> </button>
<p class="mb-0 mr-0 pl-2 frame-txt" [matMenuTriggerFor]="exportMenu"> <p class="mb-0 mr-0 pl-2 frame-txt" [matMenuTriggerFor]="exportMenu">
{{ 'DMP-LISTING.ACTIONS.EXPORT' | translate }}</p> {{ 'DMP-LISTING.ACTIONS.EXPORT' | translate }}</p>
</div> -->
<!-- <div class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center" *ngIf="isUserOwner"
(click)="newVersion(dmp.id, dmp.label)">
<button mat-mini-fab class="frame-btn">
<mat-icon class="mat-mini-fab-icon">add_to_photos</mat-icon>
</button>
<p class="mb-0 pl-2 frame-txt">{{ 'DMP-LISTING.ACTIONS.START-NEW-VERSION' | translate }}
</p>
</div> -->
<!-- <div *ngIf="!dataset.public && showPublishButton(dmp) && isUserOwner"
class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center" (click)="publish(dmp.id)">
<button mat-mini-fab class="frame-btn">
<mat-icon class="mat-mini-fab-icon">public</mat-icon>
</button>
<p class="mb-0 pl-2 frame-txt">{{ 'DMP-LISTING.ACTIONS.MAKE-PUBLIC' | translate }}</p>
</div> </div>
<mat-menu #exportMenu="matMenu" xPosition="before"> <mat-menu #exportMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="downloadPDF(dmp.id)"> <button mat-menu-item (click)="downloadPDF(dataset.id)">
<i class="fa fa-file-pdf-o pr-2"></i> <i class="fa fa-file-pdf-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span> <span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span>
</button> </button>
<button mat-menu-item (click)="downloadDocx(dmp.id)"> <button mat-menu-item (click)="downloadDocx(dataset.id)">
<i class="fa fa-file-word-o pr-2"></i> <i class="fa fa-file-word-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.DOC' | translate}}</span> <span>{{'GENERAL.FILE-TYPES.DOC' | translate}}</span>
</button> </button>
<button mat-menu-item (click)="downloadXml(dmp.id)"> <button mat-menu-item (click)="downloadXml(dataset.id)">
<i class="fa fa-file-code-o pr-2"></i> <i class="fa fa-file-code-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.XML' | translate}}</span> <span>{{'GENERAL.FILE-TYPES.XML' | translate}}</span>
</button> </button>
<button mat-menu-item (click)="downloadJson(dmp.id)"> <button mat-menu-item (click)="downloadJson(dataset.id)">
<i class="fa fa-file-o pr-2"></i> <i class="fa fa-file-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.JSON' | translate}}</span> <span>{{'GENERAL.FILE-TYPES.JSON' | translate}}</span>
</button> </button>
</mat-menu> </mat-menu>
</div> --> </div>
<!-- <div class="frame mb-3 pt-4 pl-3 pr-3 pb-1"> <div class="frame mb-3 pt-4 pl-3 pr-3 pb-1">
<div class="row ml-0 mr-0 pl-4 pb-3"> <div class="row ml-0 mr-0 pl-4 pb-3">
<p class="header">{{ 'DATASET-OVERVIEW.DATASET-AUTHORS' | translate }}</p> <p class="header">{{ 'DATASET-OVERVIEW.DATASET-AUTHORS' | translate }}</p>
</div> </div>
<div class="row ml-0 mr-0 pl-4 ml-2 pb-3 d-flex align-items-center"> <div class="row ml-0 mr-0 pl-4 ml-2 pb-3 d-flex align-items-center">
<div *ngFor="let user of dmp.users" class="row authors"> <div *ngFor="let user of dataset.users" class="row authors">
<div class="d-flex flex-row"> <div class="d-flex flex-row">
<button class="account_btn mr-3 pl-0"> <button class="account_btn mr-3 pl-0">
<mat-icon class="account-icon">account_circle</mat-icon> <mat-icon class="account-icon">account_circle</mat-icon>
@ -204,19 +143,18 @@
<p class="authors-role">{{ roleDisplay(user) }}</p> <p class="authors-role">{{ roleDisplay(user) }}</p>
</div> </div>
</div> </div>
<button *ngIf="isUserOwner && !dmp.status && user.role" <button *ngIf="isUserOwner && !dataset.status && user.role"
(click)="removeCollaborator(user.id)"
class="remove-btn">{{ 'GENERAL.CONFIRMATION-DIALOG.ACTIONS.REMOVE' | translate}}</button> class="remove-btn">{{ 'GENERAL.CONFIRMATION-DIALOG.ACTIONS.REMOVE' | translate}}</button>
</div> </div>
</div> </div>
<div *ngIf="isUserOwner" (click)="openShareDialog(dmp.id,dmp.label)" <div *ngIf="isUserOwner" (click)="openShareDialog(dataset.dmp.id, dataset.dmp.label)"
class="row mt-3 mb-3 d-flex align-items-center justify-content-center"> class="row mt-3 mb-3 d-flex align-items-center justify-content-center">
<button mat-raised-button class="invite-btn"> <button mat-raised-button class="invite-btn">
<mat-icon>group_add</mat-icon> <mat-icon>group_add</mat-icon>
{{'DMP-LISTING.ACTIONS.INVITE-SHORT' | translate}} {{'DMP-LISTING.ACTIONS.INVITE-SHORT' | translate}}
</button> </button>
</div> </div>
</div> --> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -20,7 +20,7 @@
font-size: 1.2em; font-size: 1.2em;
} }
.mat-mini-fab:hover { .actions-btn:hover {
background-color: #129D99; background-color: #129D99;
color: #FFFFFF; color: #FFFFFF;
} }
@ -139,6 +139,7 @@
.dataset-label { .dataset-label {
font-weight: bold; font-weight: bold;
width: auto;
} }
.uppercase { .uppercase {
@ -149,14 +150,13 @@
font-size: 0.875em; font-size: 0.875em;
color: #008887; color: #008887;
padding-right: 0.5em; padding-right: 0.5em;
align-self: center; align-self: center;;
} }
.header { .header {
opacity: 0.6; opacity: 0.6;
margin-top: 1em; margin-top: 1em;
margin-bottom: 0.25em; margin-bottom: 0.5em;
} }
.dataset-label, .header { .dataset-label, .header {
@ -262,7 +262,7 @@
// ********CENTER ELEMENTS******** // ********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 { .status-icon, .dataset-logo, .frame-btn, .finalize-btn {
display: flex; display: flex;
justify-content: center; justify-content: center;

View File

@ -19,6 +19,15 @@ import { Location } from '@angular/common';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing'; import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import { DatasetStatus } from '@app/core/common/enum/dataset-status'; import { DatasetStatus } from '@app/core/common/enum/dataset-status';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; 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({ @Component({
@ -29,6 +38,7 @@ import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog
export class DatasetOverviewComponent extends BaseComponent implements OnInit { export class DatasetOverviewComponent extends BaseComponent implements OnInit {
dataset: DatasetOverviewModel; dataset: DatasetOverviewModel;
datasetWizardModel: DatasetWizardEditorModel;
isNew = true; isNew = true;
isFinalized = false; isFinalized = false;
isPublicView = true; isPublicView = true;
@ -37,6 +47,8 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
isUserOwner: boolean; isUserOwner: boolean;
expand = false; expand = false;
hasDOIToken = false; hasDOIToken = false;
researchers: ResearcherModel[];
lockStatus: Boolean;
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
@ -50,7 +62,10 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
private configurationService: ConfigurationService, private configurationService: ConfigurationService,
private oauth2DialogService: Oauth2DialogService, private oauth2DialogService: Oauth2DialogService,
private userService: UserService, private userService: UserService,
private location: Location private dmpService: DmpService,
private location: Location,
private datasetWizardService: DatasetWizardService,
private lockService: LockService
) { ) {
super(); super();
} }
@ -69,7 +84,12 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(data => { .subscribe(data => {
this.dataset = 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(); this.setIsUserOwner();
const breadCrumbs = []; const breadCrumbs = [];
breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), url: "/datasets" }); 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)) .pipe(takeUntil(this._destroyed))
.subscribe(data => { .subscribe(data => {
this.dataset = 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(); this.setIsUserOwner();
const breadCrumbs = []; const breadCrumbs = [];
breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC DATASETS'), url: "/explore" }); 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) { checkLockStatus(id: string){
this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-OVERVIEW.ERROR.DELETED-DATASET'), SnackBarNotificationLevel.Error); this.lockService.checkLockStatus(id).pipe(takeUntil(this._destroyed))
this.router.navigate([redirectRoot]); .subscribe(lockStatus => this.lockStatus = lockStatus);
} }
onFetchingForbiddenCallbackError(redirectRoot: string) { onFetchingDeletedCallbackError(redirectRoot: string) {
this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-OVERVIEW.ERROR.FORBIDEN-DATASET'), SnackBarNotificationLevel.Error); this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-OVERVIEW.ERROR.DELETED-DATASET'), SnackBarNotificationLevel.Error);
this.router.navigate([redirectRoot]); 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 { 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() { setIsUserOwner() {
if (this.dataset) { if (this.dataset) {
const principal: Principal = this.authentication.current(); const principal: Principal = this.authentication.current();
if (principal) this.isUserOwner = principal.id === this.dataset.users.find(x => x.role === Role.Owner).id; 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() { isUserDatasetRelated() {
const principal: Principal = this.authentication.current(); const principal: Principal = this.authentication.current();
let isRelated: boolean = false; let isRelated: boolean = false;
if (this.dataset && principal) { if (this.dataset && principal) {
this.dataset.users.forEach(element => { this.dataset.users.forEach(element => {
if (element.id === principal.id) { if (element.id === principal.id) {
isRelated = true; isRelated = true;
} }
}) })
} }
return isRelated; 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) { roleDisplay(value: UserInfoListingModel) {
this.uiNotificationService.snackBarNotification(error.error.message ? error.error.message : this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DELETE'), SnackBarNotificationLevel.Error); 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 { public getOrcidPath(): string {
return this.configurationService.orcidPath; return this.configurationService.orcidPath;
} }
// showPublishButton(dataset: DatasetOverviewModel) { downloadPDF(id: string) {
// return this.isFinalizedDmp(dmp) && !dmp.isPublic && this.hasPublishButton; 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 } });
}
});
}
} }

View File

@ -32,6 +32,8 @@ import { FormValidationErrorsDialogModule } from '@common/forms/form-validation-
import { CommonUiModule } from '@common/ui/common-ui.module'; import { CommonUiModule } from '@common/ui/common-ui.module';
import { MultipleChoiceDialogModule } from '@common/modules/multiple-choice-dialog/multiple-choice-dialog.module'; import { MultipleChoiceDialogModule } from '@common/modules/multiple-choice-dialog/multiple-choice-dialog.module';
import { AddOrganizationComponent } from './editor/add-organization/add-organization.component'; 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'; import { DmpCriteriaDialogComponent } from './listing/criteria/dmp-criteria-dialog.component';
@NgModule({ @NgModule({
@ -71,7 +73,10 @@ import { DmpCriteriaDialogComponent } from './listing/criteria/dmp-criteria-dial
DatasetsTabComponent, DatasetsTabComponent,
DmpCloneComponent, DmpCloneComponent,
AddOrganizationComponent, AddOrganizationComponent,
DmpCriteriaDialogComponent DmpCriteriaDialogComponent,
AddOrganizationComponent,
AddCostComponent,
CostListingComponent
], ],
entryComponents: [ entryComponents: [
DmpInvitationDialogComponent, DmpInvitationDialogComponent,
@ -80,7 +85,9 @@ import { DmpCriteriaDialogComponent } from './listing/criteria/dmp-criteria-dial
DmpFinalizeDialogComponent, DmpFinalizeDialogComponent,
DmpUploadDialogue, DmpUploadDialogue,
AddOrganizationComponent, AddOrganizationComponent,
DmpCriteriaDialogComponent DmpCriteriaDialogComponent,
AddOrganizationComponent,
AddCostComponent
] ]
}) })
export class DmpModule { } export class DmpModule { }

View File

@ -0,0 +1,28 @@
<form *ngIf="formGroup" [formGroup]="formGroup">
<h1 mat-dialog-title>{{'ADDEDITCOST-EDITOR.ADD-TITLE' | translate}}</h1>
<div mat-dialog-content class="row">
<mat-form-field class="col-12">
<app-single-auto-complete [formControl]="formGroup.get('code')" placeholder="{{'ADDEDITCOST-EDITOR.CODE' | translate}}" [configuration]="currencyAutoCompleteConfiguration">
</app-single-auto-complete>
<mat-error *ngIf="formGroup.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-12">
<input matInput formControlName="description" placeholder="{{'ADDEDITCOST-EDITOR.DESCRIPTION' | translate}}">
<mat-error *ngIf="formGroup.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-12">
<input matInput formControlName="title" placeholder="{{'ADDEDITCOST-EDITOR.TITLE' | translate}}" required>
<mat-error *ngIf="formGroup.get('title').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-12">
<input matInput formControlName="value" placeholder="{{'ADDEDITCOST-EDITOR.VALUE' | translate}}" type="number">
<mat-error *ngIf="formGroup.get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<div class="col-12">
<div class="row">
<div class="ml-auto col-auto"><button mat-raised-button mat-dialog-close type="button">{{'ADDEDITCOST-EDITOR.ACTIONS.CANCEL' | translate}}</button></div>
<div class="col-auto"><button mat-raised-button [disabled]="!isFormValid()" color="primary" (click)="addCost()" type="button">{{'ADDEDITCOST-EDITOR.ACTIONS.SAVE' | translate}}</button></div>
</div>
</div>
</div>
</form>

View File

@ -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<AddCostComponent>,
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<LocalFetchModel[]> {
return this.currencyService.get(like);
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,42 @@
<mat-card class="row listing-container">
<ng-template #costTemplate let-cost let-i="index">
<div class="row">
<div class="col-auto">
<mat-form-field>
<app-single-auto-complete [formControl]="cost.get('code')" placeholder="{{'ADDEDITCOST-EDITOR.CODE' | translate}}" [configuration]="currencyAutoCompleteConfiguration"></app-single-auto-complete>
</mat-form-field>
</div>
<div class="col-auto">
<mat-form-field>
<input matInput placeholder="{{'ADDEDITCOST-EDITOR.DESCRIPTION' | translate}}" type="text" [formControl]="cost.get('description')">
</mat-form-field>
</div>
<div class="col-auto">
<mat-form-field>
<input matInput placeholder="{{'ADDEDITCOST-EDITOR.TITLE' | translate}}" type="text" [formControl]="cost.get('title')">
</mat-form-field>
</div>
<div class="col-auto">
<mat-form-field>
<input matInput placeholder="{{'ADDEDITCOST-EDITOR.VALUE' | translate}}" type="text" [formControl]="cost.get('value')">
</mat-form-field>
</div>
</div>
<div class="col-12">
<div class="row"*ngIf="cost.disabled">
<div class=" ml-auto col-auto"><button type="button" mat-raised-button color="primary" (click)="switchEditMode(i)">Edit</button></div>
<div class="col-auto"><button type="button" mat-raised-button color="red" (click)="removeCost(i)">Delete</button></div>
</div>
<div class="row"*ngIf="!cost.disabled">
<div class=" ml-auto col-auto" *ngIf="!cost.disabled"><button type="button" mat-raised-button color="primary" (click)="switchEditMode(i)">Save</button></div>
<div class="col-auto" *ngIf="!cost.disabled"><button type="button" mat-raised-button (click)="revertEdits(i)">Cancel</button></div>
</div>
</div>
</ng-template>
<mat-card class="col-12 cost-element" *ngFor="let cost of form['controls']; let i = index">
<ng-container *ngTemplateOutlet="costTemplate; context: { $implicit: cost, index: i }">
</ng-container>
</mat-card>
</mat-card>

View File

@ -0,0 +1,10 @@
.listing-container {
height: fit-content;
width: fit-content;
background-color: whitesmoke;
}
.cost-element {
margin-bottom: 1em;
}

View File

@ -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<LocalFetchModel[]> {
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();
}
}

View File

@ -1,30 +1,53 @@
import { ValidationContext } from '@common/forms/validation/validation-context'; import { ValidationContext } from '@common/forms/validation/validation-context';
import { FormGroup, FormBuilder, Validators } from '@angular/forms'; import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; 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 { export class ExtraPropertiesFormModel {
public language: string; public language: string;
public license: string; public license: string;
public visible: boolean; public visible: boolean;
public publicDate: Date; public publicDate: Date;
public contact: string;
public costs: CostEditorModel[] = [];
fromModel(item: any): ExtraPropertiesFormModel { fromModel(item: any): ExtraPropertiesFormModel {
this.language = item.language; this.language = item.language;
this.license = item.license; this.license = item.license;
this.visible = item.visible; this.visible = item.visible;
this.publicDate = item.publicDate; this.publicDate = item.publicDate;
this.contact = item.contact;
if (!isNullOrUndefined(item.costs)) {
(<any[]>item.costs).forEach(element => {
this.costs.push(new CostEditorModel().fromModel(element));
});
}
return this; return this;
} }
buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup { buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup {
if (context == null) { context = this.createValidationContext(); } if (context == null) { context = this.createValidationContext(); }
const formBuilder = new FormBuilder();
const formGroup = new FormBuilder().group({ const formGroup = new FormBuilder().group({
language: [{ value: this.language, disabled: disabled }, context.getValidation('language').validators], language: [{ value: this.language, disabled: disabled }, context.getValidation('language').validators],
license: [{ value: this.license, disabled: disabled }, context.getValidation('license').validators], license: [{ value: this.license, disabled: disabled }, context.getValidation('license').validators],
visible: [{ value: this.visible, disabled: disabled }, context.getValidation('visible').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<FormGroup>();
//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; return formGroup;
} }
@ -34,6 +57,8 @@ export class ExtraPropertiesFormModel {
baseContext.validation.push({ key: 'license', validators: [] }); baseContext.validation.push({ key: 'license', validators: [] });
baseContext.validation.push({ key: 'visible', validators: [] }); baseContext.validation.push({ key: 'visible', validators: [] });
baseContext.validation.push({ key: 'publicDate', validators: [] }); baseContext.validation.push({ key: 'publicDate', validators: [] });
baseContext.validation.push({ key: 'contact', validators: [] });
baseContext.validation.push({ key: 'costs', validators: [] });
return baseContext; return baseContext;
} }

View File

@ -88,7 +88,7 @@
<app-single-auto-complete [formControl]="formGroup.get('extraProperties').get('license')" placeholder="{{'DMP-EDITOR.FIELDS.LICENSE' | translate}}" [configuration]="licenseAutoCompleteConfiguration"> <app-single-auto-complete [formControl]="formGroup.get('extraProperties').get('license')" placeholder="{{'DMP-EDITOR.FIELDS.LICENSE' | translate}}" [configuration]="licenseAutoCompleteConfiguration">
</app-single-auto-complete> </app-single-auto-complete>
<mat-error *ngIf="formGroup.get('extraProperties').get('license').hasError('backendError')"> <mat-error *ngIf="formGroup.get('extraProperties').get('license').hasError('backendError')">
{{formGroup.get('extraProperties').get('language').getError('backendError').message}}</mat-error> {{formGroup.get('extraProperties').get('license').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('extraProperties').get('license').hasError('required')"> <mat-error *ngIf="formGroup.get('extraProperties').get('license').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> {{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
@ -117,13 +117,36 @@
<input matInput [matDatepicker]="picker" [formControl]="formGroup.get('extraProperties').get('publicDate')" placeholder="{{'DMP-EDITOR.FIELDS.PUBLICATION' | translate}}"> <input matInput [matDatepicker]="picker" [formControl]="formGroup.get('extraProperties').get('publicDate')" placeholder="{{'DMP-EDITOR.FIELDS.PUBLICATION' | translate}}">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle> <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker> <mat-datepicker #picker></mat-datepicker>
<mat-error *ngIf="formGroup.get('extraProperties').get('visible').hasError('backendError')"> <mat-error *ngIf="formGroup.get('extraProperties').get('publicDate').hasError('backendError')">
{{formGroup.get('extraProperties').get('visible').getError('backendError').message}}</mat-error> {{formGroup.get('extraProperties').get('publicDate').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('extraProperties').get('visible').hasError('required')"> <mat-error *ngIf="formGroup.get('extraProperties').get('publicDate').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> {{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
<!-- <h4 mat-subheader class="col-12">{{'DMP-EDITOR.FIELDS.PROFILE' | translate}}</h4> --> <!-- <h4 mat-subheader class="col-12">{{'DMP-EDITOR.FIELDS.PROFILE' | translate}}</h4> -->
</div> </div>
<div class="row pt-3">
<mat-form-field class="col-sm-12 col-md-8">
<!-- <app-multiple-auto-complete [formControl]="formGroup.get('extraProperties').get('language')" placeholder="{{'DMP-EDITOR.FIELDS.RESEARCHERS' | translate}}" [configuration]="researchersAutoCompleteConfiguration">
</app-multiple-auto-complete> -->
<mat-select [formControl]="formGroup.get('extraProperties').get('contact')" placeholder="{{'DMP-EDITOR.FIELDS.CONTACT' | translate}}">
<mat-option *ngFor="let vis of getAssociates()" [value]="vis.id">
{{vis.name | translate}}
</mat-option>
</mat-select>
<mat-error *ngIf="formGroup.get('extraProperties').get('contact').hasError('backendError')">
{{formGroup.get('extraProperties').get('contact').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('extraProperties').get('contact').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<!-- <h4 mat-subheader class="col-12">{{'DMP-EDITOR.FIELDS.PROFILE' | translate}}</h4> -->
</div>
<div class="row pt-3">
<mat-label class="col-12 cost-placeholder">Costs</mat-label>
<app-cost-listing class="col-12" [form] = "formGroup.get('extraProperties').get('costs')"></app-cost-listing>
<button class="col-12 cost-add" matSuffix class="input-btn" type="button" (click)="addCost($event)">
<mat-icon class="icon-btn">add_circle</mat-icon>
</button>
</div>
<div class="row pt-2"> <div class="row pt-2">
<mat-form-field class="col-sm-12 col-md-8"> <mat-form-field class="col-sm-12 col-md-8">
<app-single-auto-complete [required]="false" [formControl]="formGroup.get('profile')" placeholder="{{'DMP-EDITOR.FIELDS.TEMPLATE' | translate}}" [configuration]="dmpProfileAutoCompleteConfiguration"> <app-single-auto-complete [required]="false" [formControl]="formGroup.get('profile')" placeholder="{{'DMP-EDITOR.FIELDS.TEMPLATE' | translate}}" [configuration]="dmpProfileAutoCompleteConfiguration">

View File

@ -37,3 +37,11 @@
::ng-deep .mat-form-field-appearance-legacy .mat-form-field-wrapper { ::ng-deep .mat-form-field-appearance-legacy .mat-form-field-wrapper {
padding-bottom: 1.25em; padding-bottom: 1.25em;
} }
.cost-placeholder {
text-decoration: underline;
}
.cost-add {
margin-top: 1em;
}

View File

@ -1,6 +1,6 @@
import { Component, Input, OnInit } from '@angular/core'; 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 { MatDialog } from '@angular/material/dialog';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; 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 { LanguageInfoService } from '@app/core/services/culture/language-info-service';
import { LanguageInfo } from '@app/core/model/language-info'; import { LanguageInfo } from '@app/core/model/language-info';
import { LicenseCriteria } from '@app/core/query/license/license-criteria'; 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 { interface Visible {
value: boolean; value: boolean;
@ -253,4 +255,27 @@ export class GeneralTabComponent extends BaseComponent implements OnInit {
getLanguageInfos(): LanguageInfo[] { getLanguageInfos(): LanguageInfo[] {
return this.languageInfoService.getLanguageInfoValues(); 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);
(<FormArray>this.formGroup.get('extraProperties').get('costs')).push(costeditModel.buildForm(null, true));
}
});
}
} }

View File

@ -26,15 +26,9 @@
{{'DMP-OVERVIEW.PRIVATE' | translate}} {{'DMP-OVERVIEW.PRIVATE' | translate}}
</div> </div>
</div> </div>
<div class="d-flex mr-4"> <div *ngIf="lockStatus" class="d-flex flex-row mr-4">
<div *ngIf="lockStatus" class="d-flex flex-row"> <mat-icon class="status-icon">lock_outline</mat-icon>
<mat-icon class="status-icon">lock_outline</mat-icon> {{'DMP-OVERVIEW.LOCKED' | translate}}
{{'DMP-OVERVIEW.LOCKED' | translate}}
</div>
<div *ngIf="!lockStatus" class="d-flex flex-row">
<mat-icon class="status-icon">lock_open</mat-icon>
{{'DMP-OVERVIEW.UNLOCKED' | translate}}
</div>
</div> </div>
<button class="d-flex mr-4 version-btn label2-txt" <button class="d-flex mr-4 version-btn label2-txt"
(click)="viewVersions(dmp.groupId, dmp.label)"> (click)="viewVersions(dmp.groupId, dmp.label)">
@ -46,7 +40,7 @@
<div class="d-flex mr-4"> <div class="d-flex mr-4">
<div *ngIf="dmp.status" class="d-flex flex-row uppercase"> <div *ngIf="dmp.status" class="d-flex flex-row uppercase">
<mat-icon class="status-icon">check</mat-icon> <mat-icon class="status-icon">check</mat-icon>
{{'DATASET-LISTING.COLUMNS.FINALIZED' | translate}} {{'TYPES.DMP.FINALISED' | translate}}
</div> </div>
</div> </div>
</div> </div>
@ -56,22 +50,16 @@
matTooltip="{{'DMP-LISTING.ACTIONS.CLONE' | translate}}" matTooltipPosition="above"> matTooltip="{{'DMP-LISTING.ACTIONS.CLONE' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">content_copy</mat-icon> <mat-icon class="mat-mini-fab-icon">content_copy</mat-icon>
</button> </button>
<button *ngIf="isDraftDmp(dmp) && isUserOwner" (click)="editClicked(dmp)" mat-mini-fab <button *ngIf="isDraftDmp(dmp) && isUserOwner && !lockStatus" (click)="editClicked(dmp)" mat-mini-fab
class="mr-3 d-flex justify-content-center align-items-center" class="mr-3 d-flex justify-content-center align-items-center"
matTooltip="{{'DMP-LISTING.ACTIONS.EDIT' | translate}}" matTooltipPosition="above"> matTooltip="{{'DMP-LISTING.ACTIONS.EDIT' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">create</mat-icon> <mat-icon class="mat-mini-fab-icon">create</mat-icon>
</button> </button>
<button *ngIf="isDraftDmp(dmp) && isUserOwner" (click)="deleteClicked()" mat-mini-fab <button *ngIf="isDraftDmp(dmp) && isUserOwner && !lockStatus" (click)="deleteClicked()" mat-mini-fab
class="mr-3 d-flex justify-content-center align-items-center" class="mr-3 d-flex justify-content-center align-items-center"
matTooltip="{{'DMP-LISTING.ACTIONS.DELETE' | translate}}" matTooltipPosition="above"> matTooltip="{{'DMP-LISTING.ACTIONS.DELETE' | translate}}" matTooltipPosition="above">
<mat-icon class="mat-mini-fab-icon">delete</mat-icon> <mat-icon class="mat-mini-fab-icon">delete</mat-icon>
</button> </button>
<button *ngIf="isDraftDmp(dmp) && isUserOwner && !lockStatus" mat-mini-fab (click)="createOrUpdate(dmp.id)"
class="mr-3 d-flex justify-content-center align-items-center">
<mat-icon class="mat-mini-fab-icon" matTooltip="{{'DMP-OVERVIEW.LOCK' | translate}}"
matTooltipPosition="above">lock_outline
</mat-icon>
</button>
</div> </div>
<div class="row header">{{'DMP-OVERVIEW.GRANT' | translate}}</div> <div class="row header">{{'DMP-OVERVIEW.GRANT' | translate}}</div>
<div class="row dmp-label">{{ dmp.grant.label }}</div> <div class="row dmp-label">{{ dmp.grant.label }}</div>
@ -141,7 +129,7 @@
</div> </div>
</div> </div>
<div class="frame mb-3 pt-4 pl-3 pr-5 pb-1"> <div class="frame mb-3 pt-4 pl-3 pr-5 pb-1">
<div *ngIf="!dmp.status && isDraftDmp(dmp) && isUserOwner"> <div *ngIf="!dmp.status && isDraftDmp(dmp) && isUserOwner && !lockStatus">
<div class="row ml-0 mr-0 pl-4 d-flex align-items-center" (click)="finalize(dmp)"> <div class="row ml-0 mr-0 pl-4 d-flex align-items-center" (click)="finalize(dmp)">
<button mat-mini-fab class="finalize-btn"> <button mat-mini-fab class="finalize-btn">
<mat-icon class="mat-mini-fab-icon">check</mat-icon> <mat-icon class="mat-mini-fab-icon">check</mat-icon>

View File

@ -161,7 +161,7 @@
.header { .header {
opacity: 0.6; opacity: 0.6;
margin-top: 1em; margin-top: 1em;
margin-bottom: 0.25em; margin-bottom: 0.5em;
} }
.dmp-label, .header { .dmp-label, .header {

View File

@ -52,7 +52,6 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
isUserOwner: boolean; isUserOwner: boolean;
expand = false; expand = false;
hasDOIToken = false; hasDOIToken = false;
lock: LockModel;
lockStatus: Boolean; lockStatus: Boolean;
textMessage: any; textMessage: any;
@ -183,11 +182,12 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
} }
datasetClicked(datasetId: String) { datasetClicked(datasetId: String) {
if (this.isPublicView) { // if (this.isPublicView) {
this.router.navigate(['/datasets/publicEdit/' + datasetId]); // this.router.navigate(['/datasets/publicEdit/' + datasetId]);
} else { // } else {
this.router.navigate(['/datasets/edit/' + datasetId]); // this.router.navigate(['/datasets/edit/' + datasetId]);
} // }
this.router.navigate(['/datasets/overview/' + datasetId]);
} }
datasetsClicked(dmpId: String) { datasetsClicked(dmpId: String) {
@ -609,24 +609,6 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
} }
} }
createOrUpdate(id: string): void {
if (!this.lockStatus) {
this.lock = new LockModel(id, this.getUserFromDMP());
this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => {
this.lock.id = Guid.parse(result);
this.checkLockStatus(id);
// interval(this.configurationService.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock());
});
}
}
// private pumpLock() {
// this.lock.touchedAt = new Date();
// this.lockStatus = true;
// this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => this.lock.id = Guid.parse(result));
// }
// advancedClicked() { // advancedClicked() {
// const dialogRef = this.dialog.open(ExportMethodDialogComponent, { // const dialogRef = this.dialog.open(ExportMethodDialogComponent, {

View File

@ -106,6 +106,7 @@
"LOGIN": "Login", "LOGIN": "Login",
"DMP-OVERVIEW": "DMP Overview", "DMP-OVERVIEW": "DMP Overview",
"DMP-EDIT": "Edit DMP", "DMP-EDIT": "Edit DMP",
"DATASET-OVERVIEW": "Dataset Overview",
"DATASET-EDIT": "Dataset View/Edit", "DATASET-EDIT": "Dataset View/Edit",
"DMP-NEW-VERSION": "DMP New Version", "DMP-NEW-VERSION": "DMP New Version",
"DMP-CLONE": "Clone DMP", "DMP-CLONE": "Clone DMP",
@ -567,7 +568,7 @@
} }
}, },
"DATASET-OVERVIEW": { "DATASET-OVERVIEW": {
"DATASET-AUTHORS": "Dataset description Authors", "DATASET-AUTHORS": "Dataset description authors",
"ERROR": { "ERROR": {
"DELETED-DATASET": "The requested dataset is deleted", "DELETED-DATASET": "The requested dataset is deleted",
"FORBIDEN-DATASET": "You are not allowed to access this dataset" "FORBIDEN-DATASET": "You are not allowed to access this dataset"
@ -755,7 +756,8 @@
"LANGUAGE": "Language", "LANGUAGE": "Language",
"LICENSE": "License", "LICENSE": "License",
"VISIBILITY": "Visibility", "VISIBILITY": "Visibility",
"PUBLICATION": "Publication Date" "PUBLICATION": "Publication Date",
"CONTACT": "Contact"
}, },
"ACTIONS": { "ACTIONS": {
"GO-TO-GRANT": "Go To DMP Grant", "GO-TO-GRANT": "Go To DMP Grant",
@ -1030,6 +1032,18 @@
"CANCEL": "Cancel" "CANCEL": "Cancel"
} }
}, },
"ADDEDITCOST-EDITOR": {
"ADD-TITLE": "Add a Cost",
"EDIT-TITLE": "Edit the Cost",
"CODE": "Code",
"DESCRIPTION": "Description",
"TITLE": "Title",
"VALUE": "Value",
"ACTIONS": {
"SAVE": "Save",
"CANCEL": "Cancel"
}
},
"DMP-WIZARD": { "DMP-WIZARD": {
"FIRST-STEP": { "FIRST-STEP": {
"DMP": "DMP Editor", "DMP": "DMP Editor",

View File

@ -105,6 +105,7 @@
"LOGIN": "Iniciar sesión", "LOGIN": "Iniciar sesión",
"DMP-OVERVIEW": "Resumen del PGD", "DMP-OVERVIEW": "Resumen del PGD",
"DMP-EDIT": "Editar el PGD", "DMP-EDIT": "Editar el PGD",
"DATASET-OVERVIEW": "Resumen del Dataset",
"DATASET-EDIT": "Ver/Editar el Dataset", "DATASET-EDIT": "Ver/Editar el Dataset",
"DMP-NEW-VERSION": "Nueva versiónd del PGD", "DMP-NEW-VERSION": "Nueva versiónd del PGD",
"DMP-CLONE": "Clonar el PGD", "DMP-CLONE": "Clonar el PGD",
@ -565,7 +566,7 @@
} }
}, },
"DATASET-OVERVIEW": { "DATASET-OVERVIEW": {
"DATASET-AUTHORS": "Descripciones del Dataset Autores", "DATASET-AUTHORS": "Descripciones del dataset autores",
"ERROR": { "ERROR": {
"DELETED-DATASET": "El Dataset solicitado está borrado", "DELETED-DATASET": "El Dataset solicitado está borrado",
"FORBIDEN-DATASET": "No tiene permiso para acceder a esto Dataset" "FORBIDEN-DATASET": "No tiene permiso para acceder a esto Dataset"

View File

@ -105,6 +105,7 @@
"LOGIN": "Σύνδεση", "LOGIN": "Σύνδεση",
"DMP-OVERVIEW": "Επισκόπηση Σχεδίου Διαχείρισης Δεδομένων", "DMP-OVERVIEW": "Επισκόπηση Σχεδίου Διαχείρισης Δεδομένων",
"DMP-EDIT": "Επεξεργασία Σχεδίου Διαχείρισης Δεδομένων", "DMP-EDIT": "Επεξεργασία Σχεδίου Διαχείρισης Δεδομένων",
"DATASET-OVERVIEW": "Επισκόπηση Συνόλου Δεδομένων",
"DATASET-EDIT": "Προβολή / Επεξεργασία Συνόλου Δεδομένων", "DATASET-EDIT": "Προβολή / Επεξεργασία Συνόλου Δεδομένων",
"DMP-NEW-VERSION": "Νέα έκδοση Σχεδίου Διαχείρισης Δεδομένων", "DMP-NEW-VERSION": "Νέα έκδοση Σχεδίου Διαχείρισης Δεδομένων",
"DMP-CLONE": "Κλωνοποίηση Σχεδίου Διαχείρισης Δεδομένων", "DMP-CLONE": "Κλωνοποίηση Σχεδίου Διαχείρισης Δεδομένων",
@ -566,7 +567,7 @@
} }
}, },
"DATASET-OVERVIEW": { "DATASET-OVERVIEW": {
"DATASET-AUTHORS": "Συγγραφείς Περιγραφής Δεδομένων", "DATASET-AUTHORS": "Συγγραφείς περιγραφής δεδομένων",
"ERROR": { "ERROR": {
"DELETED-DATASET": "H επιλεγμένη Περιγραφή Δεδομένων θα διαγραφεί", "DELETED-DATASET": "H επιλεγμένη Περιγραφή Δεδομένων θα διαγραφεί",
"FORBIDEN-DATASET": "Δεν επιτρέπεται η πρόσβαση σε αυτή την Περιγραφή Δεδομένων" "FORBIDEN-DATASET": "Δεν επιτρέπεται η πρόσβαση σε αυτή την Περιγραφή Δεδομένων"

View File

@ -51,7 +51,9 @@
</div> </div>
</li> </li>
<li class="nav-item"><a class="nav-link" href="../contact.html">CONTACT</a></li> <li class="nav-item"><a class="nav-link" href="../contact.html">CONTACT</a></li>
<li class="nav-item"><li class="nav-item"><a class="nav-link" href="/login">SIGN IN</a></li></li> <li class="nav-item">
<li class="nav-item"><a class="nav-link" href="/login">SIGN IN</a></li>
</li>
</ul> </ul>
</div> </div>
</div> </div>
@ -60,7 +62,7 @@
<section class="page-section how-it-works" id="how-it-works"> <section class="page-section how-it-works" id="how-it-works">
<div class="container-small"> <div class="container-small">
<div class="col"> <div class="col">
<div class="page-title">About</div> <div class="page-title">FAQs</div>
</div> </div>
<div class="col pt-5 pb-3"> <div class="col pt-5 pb-3">
<div class="row title-1">FAQs</div> <div class="row title-1">FAQs</div>
@ -108,7 +110,7 @@
</div> </div>
<div class="collapse show" id="collapseFAQ-3"> <div class="collapse show" id="collapseFAQ-3">
<div class="faq-content"> <div class="faq-content">
<p>ARGOS is comprised of two main functionalities: DMP templates and Dataset Descriptions. <div>ARGOS is comprised of two main functionalities: DMP templates and Dataset Descriptions.
Additional entities are Projects that link to funders and grants information.<br />ARGOS can Additional entities are Projects that link to funders and grants information.<br />ARGOS can
be used for: be used for:
<br /><br /><u style="padding:20px;"> A. viewing/ consulting publicly released DMPs and <br /><br /><u style="padding:20px;"> 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 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 of the tool for researchers and students familiarization with the concept and process, as
part of library instructions sessions. part of library instructions sessions.
</p> </div>
</div> </div>
</div> </div>
</div> </div>
@ -206,4 +208,4 @@
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
</body> </body>
</html> </html>

View File

@ -59,7 +59,7 @@
<section class="page-section how-it-works" id="how-it-works"> <section class="page-section how-it-works" id="how-it-works">
<div class="container-small"> <div class="container-small">
<div class="col"> <div class="col">
<div class="page-title">About</div> <div class="page-title">How it works</div>
</div> </div>
<div class="col pt-5 pb-2"> <div class="col pt-5 pb-2">
<div class="row title-1">How it works</div> <div class="row title-1">How it works</div>