no message

This commit is contained in:
Ioannis Kalyvas 2018-08-24 18:21:02 +03:00
parent 46db0d4184
commit 3ad1c1c8f2
72 changed files with 1092 additions and 274 deletions

View File

@ -1,6 +1,7 @@
package eu.eudat.data.dao.criteria;
import eu.eudat.data.entities.Project;
import eu.eudat.types.project.ProjectStateType;
import java.util.Date;
@ -8,6 +9,7 @@ public class ProjectCriteria extends Criteria<Project> {
private Date periodStart;
private Date periodEnd;
private String reference;
private Integer projectStateType;
public Date getPeriodStart() {
return periodStart;
@ -32,4 +34,12 @@ public class ProjectCriteria extends Criteria<Project> {
public void setReference(String reference) {
this.reference = reference;
}
public Integer getProjectStateType() {
return projectStateType;
}
public void setProjectStateType(Integer projectStateType) {
this.projectStateType = projectStateType;
}
}

View File

@ -6,10 +6,12 @@ import eu.eudat.data.dao.databaselayer.service.DatabaseService;
import eu.eudat.data.entities.Project;
import eu.eudat.data.entities.UserInfo;
import eu.eudat.queryable.QueryableList;
import eu.eudat.types.project.ProjectStateType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.persistence.criteria.JoinType;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@ -32,6 +34,14 @@ public class ProjectDaoImpl extends DatabaseAccess<Project> implements ProjectDa
query.where((builder, root) -> builder.greaterThan(root.get("startdate"), criteria.getPeriodStart()));
if (criteria.getReference() != null)
query.where((builder, root) -> builder.equal(root.get("reference"), criteria.getReference()));
if (criteria.getProjectStateType() != null) {
if (criteria.getProjectStateType().equals(ProjectStateType.FINISHED.getValue()))
query.where((builder, root) -> builder.lessThan(root.get("enddate"), new Date()));
if (criteria.getProjectStateType().equals(ProjectStateType.ONGOING.getValue()))
query.where((builder, root) ->
builder.or(builder.greaterThan(root.get("enddate"), new Date())
, builder.isNull(root.get("enddate"))));
}
query.where((builder, root) -> builder.notEqual(root.get("status"), Project.Status.DELETED.getValue()));
return query;
}

View File

@ -0,0 +1,29 @@
package eu.eudat.types.project;
/**
* Created by ikalyvas on 8/24/2018.
*/
public enum ProjectStateType {
ONGOING(0), FINISHED(1);
private Integer value;
private ProjectStateType(Integer value) {
this.value = value;
}
public Integer getValue() {
return value;
}
public static ProjectStateType fromInteger(Integer value) {
switch (value) {
case 0:
return ONGOING;
case 1:
return FINISHED;
default:
throw new RuntimeException("Unsupported Project State Type");
}
}
}

View File

@ -111,7 +111,7 @@ public class DMPs extends BaseController {
public @ResponseBody
ResponseEntity<ResponseItem<List<DataManagementPlan>>> getWithCriteria(@RequestBody DataManagementPlanCriteriaRequest dataManagementPlanCriteria, Principal principal) {
try {
List<DataManagementPlan> dataTable = new DataManagementPlanManager().getWithCriteria(this.getApiContext().getOperationsContext().getDatabaseRepository().getDmpDao(), dataManagementPlanCriteria);
List<DataManagementPlan> dataTable = new DataManagementPlanManager().getWithCriteria(this.getApiContext().getOperationsContext().getDatabaseRepository().getDmpDao(), dataManagementPlanCriteria, principal);
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<List<DataManagementPlan>>().status(ApiMessageCode.NO_MESSAGE).payload(dataTable));
} catch (Exception ex) {
ex.printStackTrace();

View File

@ -2,6 +2,7 @@ package eu.eudat.controllers;
import eu.eudat.logic.managers.DashBoardManager;
import eu.eudat.models.data.dashboard.recent.RecentActivity;
import eu.eudat.models.data.dashboard.searchbar.SearchBarItem;
import eu.eudat.models.data.dashboard.statistics.DashBoardStatistics;
import eu.eudat.models.data.helpers.responses.ResponseItem;
import eu.eudat.models.data.security.Principal;
@ -12,6 +13,8 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@CrossOrigin
@RequestMapping(value = {"/api"})
@ -57,4 +60,16 @@ public class DashBoardController extends BaseController {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem<RecentActivity>().status(ApiMessageCode.DEFAULT_ERROR_MESSAGE).message(ex.getMessage()));
}
}
@RequestMapping(method = RequestMethod.GET, value = {"/dashboard/search"}, produces = "application/json")
public ResponseEntity<ResponseItem<List<SearchBarItem>>> search(@RequestParam(name = "like") String like, Principal principal) {
try {
List<SearchBarItem> searchBarItemList = new DashBoardManager().searchUserData(like,this.getApiContext(), this.getApiContext().getOperationsContext().getDatabaseRepository().getDatasetDao(), this.getApiContext().getOperationsContext().getDatabaseRepository().getDmpDao()
, this.getApiContext().getOperationsContext().getDatabaseRepository().getProjectDao(), principal);
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<List<SearchBarItem>>().status(ApiMessageCode.NO_MESSAGE).payload(searchBarItemList));
} catch (Exception ex) {
ex.printStackTrace();
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem<List<SearchBarItem>>().status(ApiMessageCode.DEFAULT_ERROR_MESSAGE).message(ex.getMessage()));
}
}
}

View File

@ -8,6 +8,7 @@ import eu.eudat.data.query.items.table.userinfo.UserInfoTableRequestItem;
import eu.eudat.models.data.userinfo.UserListingModel;
import eu.eudat.logic.security.claims.ClaimedAuthorities;
import eu.eudat.logic.services.ApiContext;
import eu.eudat.models.data.userinfo.UserProfile;
import eu.eudat.types.ApiMessageCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
@ -17,6 +18,8 @@ import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.UUID;
import static eu.eudat.types.Authorities.ADMIN;
@ -54,6 +57,19 @@ public class Users extends BaseController {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem<UserListingModel>().status(ApiMessageCode.DEFAULT_ERROR_MESSAGE).message(ex.getMessage()));
}
}
@RequestMapping(method = RequestMethod.GET, value = {"/{id}"}, produces = "application/json")
public @ResponseBody
ResponseEntity<ResponseItem<UserProfile>> get(@PathVariable String id, Principal principal) {
try {
UUID userId = id.equals("me") ? principal.getId() : UUID.fromString(id);
UserProfile user = UserManager.getSingle(this.getApiContext(), userId);
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<UserProfile>().payload(user).status(ApiMessageCode.NO_MESSAGE));
} catch (Exception ex) {
ex.printStackTrace();
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem<UserProfile>().status(ApiMessageCode.DEFAULT_ERROR_MESSAGE).message(ex.getMessage()));
}
}
}

View File

@ -32,6 +32,7 @@ public final class PrincipalArgumentResolver implements HandlerMethodArgumentRes
String token = nativeWebRequest.getHeader("AuthToken");
Optional<Annotation> claimsAnnotation = Arrays.stream(methodParameter.getParameterAnnotations()).filter(annotation -> annotation.annotationType().equals(ClaimedAuthorities.class)).findAny();
List<Authorities> claimList = claimsAnnotation.map(annotation -> Arrays.asList(((ClaimedAuthorities) annotation).claims())).orElse(Authorities.all());
if(claimList.size() == 0 && claimList.get(0).equals(Authorities.ANONYMOUS)) return new Principal();
if (token == null) throw new UnauthorisedException("Authentication Information Is Missing");
UUID authToken;
try {

View File

@ -1,18 +1,21 @@
package eu.eudat.logic.managers;
import eu.eudat.logic.builders.model.models.RecentActivityDataBuilder;
import eu.eudat.data.dao.criteria.DataManagementPlanCriteria;
import eu.eudat.data.dao.criteria.DatasetCriteria;
import eu.eudat.data.dao.entities.DMPDao;
import eu.eudat.data.dao.entities.DatasetDao;
import eu.eudat.data.dao.entities.ProjectDao;
import eu.eudat.data.entities.UserInfo;
import eu.eudat.data.dao.criteria.DataManagementPlanCriteria;
import eu.eudat.data.dao.criteria.DatasetCriteria;
import eu.eudat.logic.builders.model.models.RecentActivityDataBuilder;
import eu.eudat.logic.services.ApiContext;
import eu.eudat.models.data.dashboard.recent.RecentActivity;
import eu.eudat.models.data.dashboard.recent.RecentActivityData;
import eu.eudat.models.data.dashboard.searchbar.SearchBarItem;
import eu.eudat.models.data.dashboard.statistics.DashBoardStatistics;
import eu.eudat.models.data.security.Principal;
import eu.eudat.logic.services.ApiContext;
import eu.eudat.types.searchbar.SearchBarItemType;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@ -87,4 +90,35 @@ public class DashBoardManager {
return activity;
}
public List<SearchBarItem> searchUserData(String like, ApiContext apiContext, DatasetDao datasetRepository, DMPDao dataManagementPlanRepository, ProjectDao projectRepository, Principal principal) {
RecentActivity activity = new RecentActivity();
UserInfo user = new UserInfo();
user.setId(principal.getId());
List<SearchBarItem> searchBarItems = new LinkedList<>();
CompletableFuture<List<SearchBarItem>> dmps = dataManagementPlanRepository.getAuthenticated(dataManagementPlanRepository.asQueryable(), user)
.withHint("dmpRecentActivity")
.where((builder, root) -> builder.like(root.get("label"), "%" + like + "%"))
.orderBy((builder, root) -> builder.desc(root.get("modified")))
.selectAsync(item -> new SearchBarItem(item.getId().toString(), item.getLabel(), SearchBarItemType.DMP.getValue()))
.whenComplete((dmpItems, throwable) -> searchBarItems.addAll(dmpItems));
CompletableFuture<List<SearchBarItem>> datasets = datasetRepository.getAuthenticated(datasetRepository.asQueryable(), user)
.withHint("datasetRecentActivity")
.where((builder, root) -> builder.like(root.get("label"), "%" + like + "%"))
.orderBy((builder, root) -> builder.desc(root.get("modified")))
.selectAsync(item -> new SearchBarItem(item.getId().toString(), item.getLabel(), SearchBarItemType.DATASET.getValue()))
.whenComplete((dataSetItems, throwable) -> searchBarItems.addAll(dataSetItems));
CompletableFuture<List<SearchBarItem>> projects = projectRepository.getAuthenticated(projectRepository.asQueryable(), user)
.withHint("projectRecentActivity")
.where((builder, root) -> builder.like(root.get("label"), "%" + like + "%"))
.orderBy((builder, root) -> builder.desc(root.get("modified")))
.selectAsync(item -> new SearchBarItem(item.getId().toString(), item.getLabel(), SearchBarItemType.PROJECT.getValue()))
.whenComplete((projectItems, throwable) -> searchBarItems.addAll(projectItems));
CompletableFuture.allOf(projects, dmps, datasets).join();
return searchBarItems;
}
}

View File

@ -88,9 +88,12 @@ public class DataManagementPlanManager {
return datamanagementPlan;
}
public List<DataManagementPlan> getWithCriteria(DMPDao dmpsRepository, DataManagementPlanCriteriaRequest dataManagementPlanCriteria) throws IllegalAccessException, InstantiationException {
QueryableList<DMP> items = dmpsRepository.getWithCriteria(dataManagementPlanCriteria.getCriteria());
List<eu.eudat.models.data.dmp.DataManagementPlan> datamanagementPlans = items.select(item -> new DataManagementPlan().fromDataModel(item));
public List<DataManagementPlan> getWithCriteria(DMPDao dmpsRepository, DataManagementPlanCriteriaRequest dataManagementPlanCriteria, Principal principal) throws IllegalAccessException, InstantiationException {
UserInfo userInfo = new UserInfo();
userInfo.setId(principal.getId());
QueryableList<DMP> items = dmpsRepository.getWithCriteria(dataManagementPlanCriteria.getCriteria()).withHint(HintedModelFactory.getHint(DataManagementPlan.class));
QueryableList<DMP> authenticatedItems = dmpsRepository.getAuthenticated(items, userInfo);
List<eu.eudat.models.data.dmp.DataManagementPlan> datamanagementPlans = authenticatedItems.select(item -> new DataManagementPlan().fromDataModel(item));
return datamanagementPlans;
}

View File

@ -4,11 +4,13 @@ import eu.eudat.logic.builders.entity.UserRoleBuilder;
import eu.eudat.logic.builders.model.models.DataTableDataBuilder;
import eu.eudat.data.entities.UserRole;
import eu.eudat.exceptions.security.UnauthorisedException;
import eu.eudat.models.data.dmp.DataManagementPlan;
import eu.eudat.models.data.helpers.common.DataTableData;
import eu.eudat.models.data.login.Credentials;
import eu.eudat.models.data.security.Principal;
import eu.eudat.data.query.items.table.userinfo.UserInfoTableRequestItem;
import eu.eudat.models.data.userinfo.UserListingModel;
import eu.eudat.models.data.userinfo.UserProfile;
import eu.eudat.queryable.QueryableList;
import eu.eudat.logic.services.ApiContext;
import eu.eudat.logic.services.operations.AuthenticationServiceImpl;
@ -17,6 +19,8 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
public class UserManager {
public static eu.eudat.models.data.user.composite.DatasetProfile generateDatasetProfileModel(eu.eudat.data.entities.DatasetProfile profile) {
@ -38,6 +42,13 @@ public class UserManager {
return apiContext.getOperationsContext().getBuilderFactory().getBuilder(DataTableDataBuilder.class).totalCount(users.count()).data(modelUsers).build();
}
public static UserProfile getSingle(ApiContext apiContext, UUID userId) throws Exception {
eu.eudat.data.entities.UserInfo user = apiContext.getOperationsContext().getDatabaseRepository().getUserInfoDao().find(userId);
UserProfile profile = new UserProfile().fromDataModel(user);
profile.setAssociatedDmps(user.getDmps().stream().map(x-> new DataManagementPlan().fromDataModel(x)).collect(Collectors.toList()));
return profile;
}
public static void editRoles(ApiContext apiContext, UserListingModel user) {
eu.eudat.data.entities.UserInfo userInfo = apiContext.getOperationsContext().getDatabaseRepository().getUserInfoDao().find(user.getId());
userInfo.getUserRoles().stream().forEach(item -> apiContext.getOperationsContext().getDatabaseRepository().getUserRoleDao().delete(item));

View File

@ -0,0 +1,40 @@
package eu.eudat.models.data.dashboard.searchbar;
/**
* Created by ikalyvas on 7/26/2018.
*/
public class SearchBarItem {
private String id;
private String label;
private int type;
public SearchBarItem(String id, String label, int type) {
this.id = id;
this.label = label;
this.type = type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
}

View File

@ -198,7 +198,9 @@ public class DatasetWizardModel implements DataModel<Dataset, DatasetWizardModel
entity.setReference(this.reference);
entity.setUri(this.uri);
entity.setStatus(this.status);
entity.setDmp(dmp.toDataModel());
DMP dmp = new DMP();
dmp.setId(this.dmp.getId());
entity.setDmp(dmp);
entity.setDescription(this.description);
entity.setCreated(this.created != null ? this.created : new Date());
entity.setModified(new Date());

View File

@ -2,13 +2,13 @@ package eu.eudat.models.data.dmp;
import eu.eudat.data.entities.DMP;
import eu.eudat.data.entities.DMPProfile;
import eu.eudat.logic.utilities.builders.XmlBuilder;
import eu.eudat.models.DataModel;
import eu.eudat.models.data.dynamicfields.DynamicFieldWithValue;
import eu.eudat.models.data.entities.xmlmodels.dmpprofiledefinition.DataManagementPlanProfile;
import eu.eudat.models.data.helpermodels.Tuple;
import eu.eudat.models.data.project.Project;
import eu.eudat.models.data.userinfo.UserInfo;
import eu.eudat.logic.utilities.builders.XmlBuilder;
import net.minidev.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@ -247,7 +247,7 @@ public class DataManagementPlan implements DataModel<DMP, DataManagementPlan> {
dataManagementPlanEntity.setProperties(this.properties != null ? JSONObject.toJSONString(this.properties) : null);
dataManagementPlanEntity.setGroupId(this.groupId != null ? this.groupId : UUID.randomUUID());
dataManagementPlanEntity.setCreated(this.created != null ? this.created : new Date());
dataManagementPlanEntity.setDmpProperties(JSONObject.toJSONString(this.dynamicFields.stream().filter(item -> item.getValue() != null).collect(Collectors.toMap(DynamicFieldWithValue::getId, DynamicFieldWithValue::getValue))));
if (this.dynamicFields != null)
dataManagementPlanEntity.setDmpProperties(JSONObject.toJSONString(this.dynamicFields.stream().filter(item -> item.getValue() != null).collect(Collectors.toMap(DynamicFieldWithValue::getId, DynamicFieldWithValue::getValue))));
dataManagementPlanEntity.setUsers(new HashSet<>(this.associatedUsers.stream().map(item -> item.toDataModel()).collect(Collectors.toList())));
return dataManagementPlanEntity;
@ -255,6 +255,6 @@ public class DataManagementPlan implements DataModel<DMP, DataManagementPlan> {
@Override
public String getHint() {
return null;
return "fullyDetailed";
}
}

View File

@ -0,0 +1,102 @@
package eu.eudat.models.data.userinfo;
import eu.eudat.data.entities.*;
import eu.eudat.data.entities.UserInfo;
import eu.eudat.models.DataModel;
import eu.eudat.models.data.dmp.DataManagementPlan;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* Created by ikalyvas on 8/24/2018.
*/
public class UserProfile implements DataModel<eu.eudat.data.entities.UserInfo, UserProfile> {
private UUID id;
private String email;
private Short usertype;
private String name;
private Date lastloggedin;
private String additionalinfo;
private List<DataManagementPlan> associatedDmps;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Short getUsertype() {
return usertype;
}
public void setUsertype(Short usertype) {
this.usertype = usertype;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getLastloggedin() {
return lastloggedin;
}
public void setLastloggedin(Date lastloggedin) {
this.lastloggedin = lastloggedin;
}
public String getAdditionalinfo() {
return additionalinfo;
}
public void setAdditionalinfo(String additionalinfo) {
this.additionalinfo = additionalinfo;
}
public List<DataManagementPlan> getAssociatedDmps() {
return associatedDmps;
}
public void setAssociatedDmps(List<DataManagementPlan> associatedDmps) {
this.associatedDmps = associatedDmps;
}
@Override
public UserProfile fromDataModel(UserInfo entity) {
this.id = entity.getId();
this.email = entity.getEmail();
this.usertype = entity.getUsertype();
this.name = entity.getName();
this.lastloggedin = entity.getLastloggedin();
this.additionalinfo = entity.getAdditionalinfo();
return this;
}
@Override
public UserInfo toDataModel() throws Exception {
return null;
}
@Override
public String getHint() {
return null;
}
}

View File

@ -5,7 +5,7 @@ import java.util.List;
public enum Authorities {
USER(0), MANAGER(1), ADMIN(2);
USER(0), MANAGER(1), ADMIN(2), ANONYMOUS(99);
private Integer value;
@ -25,6 +25,8 @@ public enum Authorities {
return MANAGER;
case 2:
return ADMIN;
case 99:
return ANONYMOUS;
default:
throw new RuntimeException("Unsupported Authority Type");
}

View File

@ -0,0 +1,32 @@
package eu.eudat.types.searchbar;
/**
* Created by ikalyvas on 7/26/2018.
*/
public enum SearchBarItemType {
DATASET(0), DMP(1), PROJECT(2);
private Integer value;
private SearchBarItemType(Integer value) {
this.value = value;
}
public Integer getValue() {
return value;
}
public static SearchBarItemType fromInteger(Integer value) {
switch (value) {
case 0:
return DATASET;
case 1:
return DMP;
case 2:
return PROJECT;
default:
throw new RuntimeException("Unsupported Search bar item Code");
}
}
}

View File

@ -71,5 +71,5 @@ http-logger.initial-delay = 0
http-logger.delay = 10
http-logger.server-address = http://logstash:31311
#############################Elastic Search######################################
elasticsearch.host = elasticsearch-dmp
elasticsearch.port = 9200
elasticsearch.host = localhost
elasticsearch.port = 9201

View File

@ -1,6 +1,6 @@
<app-navigation></app-navigation>
<app-navigation class="fixed"></app-navigation>
<div class="container-fluid">
<div class="container-fluid main-container">
<div class="row">
<help-content position="top"></help-content>
</div>

View File

@ -1,6 +1,6 @@
<div class="dataset-wizard">
<h3 *ngIf="isNew">New Dataset</h3>
<h3 *ngIf="!isNew">{{datasetWizardModel.label}} Dataset</h3>
<h3 *ngIf="!isNew">{{datasetWizardModel?.label}} Dataset</h3>
<div class="flex-container">
<button mat-raised-button color="primary" *ngIf="datasetWizardModel&&datasetWizardModel?.status != 1" style="margin-top: 15px;margin-bottom: 15px;margin-right: 15px;"
@ -22,6 +22,9 @@
<mat-horizontal-stepper [linear]="isLinear" #stepper>
<mat-step [stepControl]="formGroup">
<form *ngIf="formGroup" [formGroup]="formGroup">
<app-single-auto-complete [reactiveFormControl]="formGroup.get('dmp')" placeholder="{{'DATASET-EDITOR.FIELDS.DMP' | translate}}"
[configuration]="dmpAutoCompleteConfiguration">
</app-single-auto-complete>
<ng-template matStepLabel>{{'DATASET-WIZARD.FIRST-STEP.TITLE' | translate}}</ng-template>
<mat-form-field formGroupName="profile">
<mat-select placeholder=" {{'DATASET-WIZARD.FIRST-STEP.PROFILE'| translate}}" formControlName="id">

View File

@ -35,6 +35,8 @@ import { BreadcrumbItem } from '../../shared/components/breadcrumb/definition/br
import { TagsCriteria } from '../../models/criteria/tags/TagsCriteria';
import { TagModel } from '../../models/tags/TagModel';
import { AutoCompleteConfiguration } from '../../shared/components/auto-complete/AutoCompleteConfiguration';
import { SingleAutoCompleteConfiguration } from '../../shared/components/autocompletes/single/single-auto-complete-configuration';
import { DataManagementPlanListingModel } from '../../models/data-managemnt-plans/DataManagementPlanListingModel';
@Component({
selector: 'app-dataset-wizard-component',
@ -67,6 +69,8 @@ export class DatasetWizardComponent implements OnInit, IBreadCrumbComponent {
dataRepositoriesAutoCompleteConfiguration: AutoCompleteConfiguration;
servicesAutoCompleteConfiguration: AutoCompleteConfiguration;
tagsAutoCompleteConfiguration: AutoCompleteConfiguration;
dmpAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
externalSourcesConfiguration: ExternalSourcesConfiguration;
datasetWizardModel: DatasetWizardModel;
@ -127,7 +131,16 @@ export class DatasetWizardComponent implements OnInit, IBreadCrumbComponent {
this.externalSourcesConfiguration.services.push({ key: '', label: "All" })
this.externalSourcesConfiguration.tags.push({ key: '', label: "All" })
})
let dmpAutoCompleteConfiguration = {}
this.dmpAutoCompleteConfiguration = {
filterFn: this.searchDmp.bind(this),
items: this.searchDmp(''),
displayFn: (item) => item["label"],
titleFn: (item) => item["label"],
//mapFn: (item) => new JsonSerializer<ProjectReference>().fromJSONArray(item, ProjectReference).map(item => item.toDropdownList()),
loadDataOnStart: true
};
this.route.params.subscribe((params: Params) => {
this.itemId = params['id'];
const dmpId = params['dmpId'];
@ -187,11 +200,13 @@ export class DatasetWizardComponent implements OnInit, IBreadCrumbComponent {
});
});
} else {
this.datasetWizardModel = new DatasetWizardModel();
this.formGroup = this.datasetWizardModel.buildForm()
this.formGroup.get('dmp').valueChanges.subscribe(x => {
this.loadDatasetProfiles();
})
}
});
}
ngAfterViewInit() {
@ -201,12 +216,18 @@ export class DatasetWizardComponent implements OnInit, IBreadCrumbComponent {
})
}
searchDmp(query: string): Observable<DataManagementPlanListingModel[]> {
let dmpRequestItem: RequestItem<DataManagementPlanCriteria> = new RequestItem();
dmpRequestItem.criteria = new DataManagementPlanCriteria();
dmpRequestItem.criteria.like = query;
return this.dataManagementPlanService.get(dmpRequestItem);
}
loadDatasetProfiles() {
let datasetProfileRequestItem: RequestItem<DatasetProfileCriteria> = new RequestItem();
datasetProfileRequestItem.criteria = new DatasetProfileCriteria();
datasetProfileRequestItem.criteria.id = this.datasetWizardModel.dmp.id;
this.datasetWizardService.getAvailableProfiles(datasetProfileRequestItem).subscribe(items => {
datasetProfileRequestItem.criteria.id = this.formGroup.get("dmp").value.id;
if (datasetProfileRequestItem.criteria.id) this.datasetWizardService.getAvailableProfiles(datasetProfileRequestItem).subscribe(items => {
this.availableProfiles = JsonSerializer.fromJSONArray(items, DatasetProfileModel);
});
}
@ -251,7 +272,7 @@ export class DatasetWizardComponent implements OnInit, IBreadCrumbComponent {
submit() {
this.datasetWizardService.createDataset(this.formGroup.value).subscribe(data => {
this.router.navigateByUrl("/datasets/dmp/" + this.datasetWizardModel.dmp.id);
this.router.navigateByUrl("/datasets/dmp/" + this.formGroup.get("dmp").value.id);
});
}

View File

@ -27,23 +27,29 @@
<mat-cell *matCellDef="let row"> {{row.profile}} </mat-cell>
</ng-container>
<!-- Column Definition: Status -->
<ng-container cdkColumnDef="status">
<mat-header-cell *matHeaderCellDef >{{'DATASET-LISTING.COLUMNS.STATUS' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.status}} </mat-cell>
</ng-container>
<!-- Column Definition: DataRepositories -->
<ng-container cdkColumnDef="dataRepositories">
<!-- <ng-container cdkColumnDef="dataRepositories">
<mat-header-cell *matHeaderCellDef>{{'DATASET-LISTING.COLUMNS.DATAREPOSITORIES' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.dataRepositories}} </mat-cell>
</ng-container>
</ng-container> -->
<!-- Column Definition: DataRepositories -->
<ng-container cdkColumnDef="registries">
<!-- <ng-container cdkColumnDef="registries">
<mat-header-cell *matHeaderCellDef>{{'DATASET-LISTING.COLUMNS.REGISTRIES' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.registries}} </mat-cell>
</ng-container>
</ng-container> -->
<!-- Column Definition: DataRepositories -->
<ng-container cdkColumnDef="services">
<!-- <ng-container cdkColumnDef="services">
<mat-header-cell *matHeaderCellDef>{{'DATASET-LISTING.COLUMNS.SERVICES' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.services}} </mat-cell>
</ng-container>
</ng-container> -->
<!-- Column Definition: Status -->
<!-- <ng-container cdkColumnDef="status">
@ -93,4 +99,7 @@
<button *ngIf="dmpId" mat-fab class="mat-fab-bottom-right" color="primary" [routerLink]="['/datasets/new/'+dmpId] ">
<mat-icon class="mat-24">add</mat-icon>
</button>
<button *ngIf="!dmpId" mat-fab class="mat-fab-bottom-right" color="primary" [routerLink]="['/datasets/new'] ">
<mat-icon class="mat-24">add</mat-icon>
</button>
</div>

View File

@ -32,7 +32,7 @@ export class DatasetListingComponent implements OnInit, IBreadCrumbComponent {
breadCrumbs: Observable<BreadcrumbItem[]>;
dataSource: DatasetDataSource | null;
displayedColumns: String[] = ['label', 'dmp', 'profile', 'dataRepositories', 'registries', 'services', 'description', 'created', 'actions'];
displayedColumns: String[] = ['label', 'dmp', 'profile', 'status', 'description', 'created', 'actions'];
pageEvent: PageEvent;
titlePrefix: String;
dmpId: string;

View File

@ -45,14 +45,14 @@
</mat-form-field>
<div class="col-md-6">
<app-single-auto-complete [reactiveFormControl]="formGroup.get('project')" placeholder="{{this.languageResolverService.getBy('dmpEditor') | translate}}"
<app-single-auto-complete required='true' [reactiveFormControl]="formGroup.get('project')" placeholder="{{this.languageResolverService.getBy('dmpEditor') | translate}}"
[configuration]="projectAutoCompleteConfiguration">
</app-single-auto-complete>
</div>
<!-- <app-dynamic-fields-project [formGroup]="formGroup"></app-dynamic-fields-project> -->
<div class="col-md-6">
<div class="row">
<app-multiple-auto-complete class="col-md-10" [reactiveFormControl]="formGroup.get('profiles')" placeholder="{{'DMP-EDITOR.FIELDS.PROFILES' | translate}}"
<app-multiple-auto-complete required='true' class="col-md-10" [reactiveFormControl]="formGroup.get('profiles')" placeholder="{{'DMP-EDITOR.FIELDS.PROFILES' | translate}}"
[configuration]="profilesAutoCompleteConfiguration">
</app-multiple-auto-complete>
<div class="col-md-2">
@ -111,13 +111,15 @@
</mat-list>
</div>
<div class="col-md-12 float-right">
<div class="col-md-12">
<div class="right-button">
<button mat-raised-button color="primary" (click)="cancel()" type="button">{{'DMP-EDITOR.ACTIONS.CANCEL' | translate}}</button>
<!-- <button *ngIf="!isNew" mat-raised-button color="primary" (click)="invite()" type="button">{{'DMP-EDITOR.ACTIONS.INVITE' | translate}}</button> -->
<button mat-raised-button color="primary" type="submit">{{'DMP-EDITOR.ACTIONS.SAVE' | translate}}</button>
<button *ngIf="!isNew" mat-raised-button color="primary" type="button" (click)="openConfirm(formGroup.get('label').value, formGroup.get('id').value)">{{'DMP-EDITOR.ACTIONS.DELETE' | translate}}</button>
</div>
</div>
</div>
</mat-card-content>
</mat-card>
</form>

View File

@ -19,6 +19,9 @@
.left-button {
float: left;
}
.right-button {
float: right;
}
.description-area {
height: 100px;
}

View File

@ -158,7 +158,7 @@ export class DataManagementPlanDataSource extends DataSource<DataManagementPlanL
let fields: Array<string> = new Array()
if (this._sort.active) fields = this._sort.direction === "asc" ? ["+" + this._sort.active] : ["-" + this._sort.active];
const request = new DataTableRequest<DataManagementPlanCriteria>(startIndex, this._paginator.pageSize, { fields: fields });
request.criteria = this._criteria.criteria;
request.criteria = this._criteria.formGroup.value;
if (this.itemId) {
request.criteria.groupIds = [this.itemId];
request.criteria.allVersions = true;

View File

@ -30,7 +30,7 @@ import { MultipleAutoCompleteConfiguration } from '../../../shared/components/au
styleUrls: ['./dmp-wizard-editor.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class DataManagementPlanWizardEditorComponent implements AfterViewInit {
export class DataManagementPlanWizardEditorComponent implements OnInit {
isNew = true;

View File

@ -1,32 +1,88 @@
<div class="main-panel" id="main-panel">
<div class="container">
<div>
<div class="row" style="margin-top: 30px">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 col-md-offset-1">
<h3 *ngIf="!this.isAuthenticated()">{{ 'HOMEPAGE.OPEN-DMPS.STATS' | translate }}</h3>
<h3 *ngIf="this.isAuthenticated()">{{ 'HOMEPAGE.MY-DMPS.STATS' | translate }}</h3>
</div>
</div>
</div>
<div class="row" style="margin-top: 30px">
<div class="col-lg-3 col-md-3 col-sm-6 col-xs-12 col-md-offset-1">
<app-figurecard title={{dashboardStatisticsData.totalDataManagementPlanCount}} headerIcon="mode_edit" [category]="this.isAuthenticated() ? 'DASHBOARD.MY-DMPS' : 'DASHBOARD.DMPS' "
routelLink='/dmps' footerIcon="open_in_new" linearColor="linear-gradient(60deg, #ef5350, #e53935)" boxShadow="0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(244, 67, 54, 0.4)">
routelLink='/dmps' buttonRedirectLink="/dmps/new" buttonTitle="Create New DMP" footerIcon="open_in_new" linearColor="linear-gradient(60deg, #ef5350, #e53935)"
boxShadow="0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(244, 67, 54, 0.4)">
</app-figurecard>
<mat-card *ngIf="this.isAuthenticated()" class="example-card">
<mat-card-header>
<mat-card-title>
{{'RECENT-ACTIVITY.MY-TITLE-DMP' | translate}}
</mat-card-title>
</mat-card-header>
<mat-card-content>
<mat-nav-list *ngIf="dmpActivities!=null">
<mat-list-item (click)="redirect(activity.id,RecentActivityTypes.DMP)" *ngFor="let activity of dmpActivities">
<p mat-line>
{{activity.label}}
</p>
<p mat-line>
{{activity.timestamp | date:'shortDate'}}
</p>
</mat-list-item>
</mat-nav-list>
</mat-card-content>
</mat-card>
</div>
<div class="col-lg-3 col-md-3 col-sm-6 col-xs-12 ">
<app-figurecard title={{dashboardStatisticsData.totalProjectCount}} headerIcon="list" [category]="this.isAuthenticated() ? 'DASHBOARD.MY-PROJECTS' : 'DASHBOARD.PROJECTS' "
routelLink='/projects' footerIcon="open_in_new" linearColor="linear-gradient(60deg, #ffa726, #fb8c00)" boxShadow="0 4px 20px 0 rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 152, 0, 0.4)">
routelLink='/projects' buttonRedirectLink="/projects/new" buttonTitle="Create New Project" footerIcon="open_in_new"
linearColor="linear-gradient(60deg, #ffa726, #fb8c00)" boxShadow="0 4px 20px 0 rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 152, 0, 0.4)">
</app-figurecard>
<mat-card *ngIf="this.isAuthenticated()" class="example-card">
<mat-card-header>
<mat-card-title>
{{'RECENT-ACTIVITY.MY-TITLE-PROJECT' | translate}}
</mat-card-title>
</mat-card-header>
<mat-card-content>
<mat-nav-list *ngIf="projectActivities!=null">
<mat-list-item (click)="redirect(activity.id,RecentActivityTypes.PROJECT)" *ngFor="let activity of projectActivities">
<p mat-line>
{{activity.label}}
</p>
<p mat-line>
{{activity.timestamp | date:'shortDate'}}
</p>
</mat-list-item>
</mat-nav-list>
</mat-card-content>
</mat-card>
</div>
<div class="col-lg-3 col-md-3 col-sm-6 col-xs-12">
<app-figurecard title={{dashboardStatisticsData.totalDataSetCount}} headerIcon="subject" [category]="this.isAuthenticated() ? 'DASHBOARD.MY-DATASETS' : 'DASHBOARD.DATASETS'"
routelLink='/datasets' footerIcon="open_in_new" linearColor="linear-gradient(60deg, #26c6da, #00acc1)" boxShadow="0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(0, 188, 212, 0.4)">
routelLink='/datasets' buttonRedirectLink="/datasets/new" buttonTitle="Create New Dataset" footerIcon="open_in_new"
linearColor="linear-gradient(60deg, #26c6da, #00acc1)" boxShadow="0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(0, 188, 212, 0.4)">
</app-figurecard>
</div>
</div>
<div *ngIf="this.isAuthenticated()" class="row">
<div class="col-lg-9 col-md-12 col-sm-12 col-xs-12 col-md-offset-1">
<app-recent-activity></app-recent-activity>
</div>
<mat-card *ngIf="this.isAuthenticated()" class="example-card">
<mat-card-header>
<mat-card-title>
{{'RECENT-ACTIVITY.MY-TITLE-DATASET' | translate}}
</mat-card-title>
</mat-card-header>
<mat-card-content>
<mat-nav-list *ngIf="datasetActivities!=null">
<mat-list-item (click)="redirect(activity.id,RecentActivityTypes.DATASET)" *ngFor="let activity of datasetActivities">
<p mat-line>
{{activity.label}}
</p>
<p mat-line>
{{activity.timestamp | date:'shortDate'}}
</p>
</mat-list-item>
</mat-nav-list>
</mat-card-content>
</mat-card>
</div>
</div>
</div>

View File

@ -54,21 +54,6 @@
box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.42), 0 4px 25px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2);
}
@media screen and (max-width: 990px) {
#sidebar,
#nav-right,
#nav-left-button {
display: none;
}
#menu {
display: inline;
}
#main-panel {
padding-left: 0;
-webkit-transition: all 400ms;
-moz-transition: all 400ms;
-ms-transition: all 400ms;
-o-transition: all 400ms;
transition: all 400ms;
}
.full-width {
width: 100%;
}

View File

@ -4,22 +4,45 @@ import { DashboardService } from '../../app/services/dashboard/dashboard.service
import { DashboardStatisticsModel } from '../models/dashboard/DashboardStatisticsModel';
import { JsonSerializer } from '../utilities/JsonSerializer';
import { AuthService } from '../services/auth/auth.service';
import { FormControl } from '@angular/forms';
import { RequestItem } from '../models/criteria/RequestItem';
import { ProjectCriteria } from '../models/criteria/project/ProjectCriteria';
import { ProjectService } from '../services/project/project.service';
import { SingleAutoCompleteConfiguration } from '../shared/components/autocompletes/single/single-auto-complete-configuration';
import { UserReferenceService } from '../services/user-reference/user-reference-data.service';
import { RecentActivityTypes } from '../users/activity/RecentActivityTypes';
import { Observable } from 'rxjs/internal/Observable';
import { SearchBarItem } from '../models/dashboard/SearchBarItem';
import { SearchBarType } from '../shared/components/search-bar/types/search-bar-type';
@Component({
selector: 'homepage',
templateUrl: './homepage.component.html',
styleUrls: ['./homepage.component.css'],
styleUrls: ['./homepage.component.scss'],
providers: [ProjectService, UserReferenceService]
})
export class HomepageComponent implements OnInit {
public userInfo: any;
datasetActivities: any[];
projectActivities: any[];
dmpActivities: any[];
public dashboardStatisticsData: DashboardStatisticsModel = new DashboardStatisticsModel();
public formControl = new FormControl();
projectAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
public searchControl = new FormControl();
filteredOptions: Observable<SearchBarItem[]>;
RecentActivityTypes = RecentActivityTypes
public search = false;
constructor(
private route: ActivatedRoute,
private router: Router,
private projectService: ProjectService,
private dashBoardService: DashboardService,
private authentication: AuthService
private authentication: AuthService,
private userReferenceService: UserReferenceService
) {
this.dashboardStatisticsData.totalDataManagementPlanCount = 0;
this.dashboardStatisticsData.totalDataSetCount = 0;
@ -29,6 +52,21 @@ export class HomepageComponent implements OnInit {
ngOnInit() {
this.userReferenceService.getRecentActivity().subscribe(response => {
this.datasetActivities = response["recentDatasetActivities"];
this.dmpActivities = response["recentDmpActivities"];
this.projectActivities = response["recentProjectActivities"];
})
this.projectAutoCompleteConfiguration = {
filterFn: this.searchProject.bind(this),
items: this.searchProject(''),
displayFn: (item) => item["label"],
titleFn: (item) => item["label"],
//mapFn: (item) => new JsonSerializer<ProjectReference>().fromJSONArray(item, ProjectReference).map(item => item.toDropdownList()),
loadDataOnStart: true
};
if (!this.isAuthenticated()) {
this.dashBoardService.getStatistics().subscribe(results => {
//let data = results['payload'];
@ -40,6 +78,9 @@ export class HomepageComponent implements OnInit {
})
}
this.filteredOptions = this.searchControl.valueChanges.flatMap(x => {
return this.dashBoardService.searchUserItems(x);
})
}
@ -47,4 +88,36 @@ export class HomepageComponent implements OnInit {
return !(!this.authentication.current())
}
searchProject(query: string) {
let projectRequestItem: RequestItem<ProjectCriteria> = new RequestItem();
projectRequestItem.criteria = new ProjectCriteria();
projectRequestItem.criteria.like = query;
return this.projectService.getWithExternal(projectRequestItem);
}
redirect(id: string, type: RecentActivityTypes) {
switch (type) {
case RecentActivityTypes.PROJECT: {
this.router.navigate(["projects/edit/" + id]);
return;
}
case RecentActivityTypes.DATASET: {
this.router.navigate(["datasets/edit/" + id]);
return;
}
case RecentActivityTypes.DMP: {
this.router.navigate(["dmps/edit/" + id]);
return;
}
default: throw new Error("Unsupported Activity Type ")
}
}
onOptionSelected(event: any) {
let selectedSearchBarItem = event.option.value;
if (selectedSearchBarItem.type == SearchBarType.DATASET) this.router.navigate(["datasets/edit/" + selectedSearchBarItem.id])
if (selectedSearchBarItem.type == SearchBarType.PROJECT) this.router.navigate(["projects/edit/" + selectedSearchBarItem.id])
if (selectedSearchBarItem.type == SearchBarType.DATAMANAGEMENTPLAN) this.router.navigate(["dmps/edit/" + selectedSearchBarItem.id])
}
}

View File

@ -1,6 +1,8 @@
import { BaseCriteria } from "../BaseCriteria";
import { ProjectStateType } from "../../projects/ProjectStateType";
export class ProjectCriteria extends BaseCriteria {
public periodStart: Date;
public periodEnd: Date;
public projectStateType: ProjectStateType
}

View File

@ -0,0 +1,4 @@
export class SearchBarItem {
public id: string;
public label: string;
}

View File

@ -0,0 +1,4 @@
export enum ProjectStateType {
OnGoing = 0,
Finished = 1
}

View File

@ -4,6 +4,18 @@
<form *ngIf="formGroup" (ngSubmit)="formSubmit()" [formGroup]="formGroup">
<mat-card>
<mat-card-header>
<table class="logo-table col-md-12">
<tr>
<td>
<img mat-card-avatar (click)='imgFileInput.click()' *ngIf="!formGroup.get('files') || !formGroup.get('files').value" [src]="host+'files/any?type=jpg'">
<img mat-card-avatar (click)='imgFileInput.click()' *ngIf="formGroup.get('files') && formGroup.get('files').value" [src]="host+'files/'+formGroup.get('files').value[0].id+'?location='+formGroup.get('files').value[0].location+'&type='+formGroup.get('files').value[0].type">
</td>
<td>
<input class="hidden" type="file" #imgFileInput (change)="previewImage($event)" accept="image/*" />
<!-- <app-fileuploader-component [form]="formGroup.get('files')" [label]="'FILE-UPLOADER.PROJECT'" [fileUploader]="uploaderService"></app-fileuploader-component> -->
</td>
</tr>
</table>
<div class="fill-space"></div>
<div *ngIf="!isNew">
<button *ngIf="!editMode && !isExternalProject()" mat-icon-button (click)="enableForm()">
@ -20,6 +32,9 @@
</mat-card-header>
<mat-card-content>
<div class="row">
<mat-form-field class="col-md-12">
<input matInput placeholder="{{'PROJECT-EDITOR.FIELDS.LABEL' | translate}}" type="text" name="label" formControlName="label"
required>
@ -62,28 +77,16 @@
<mat-error *ngIf="formGroup.get('description').errors?.backendError">{{errorModel.description}}</mat-error>
<mat-error *ngIf="formGroup.get('description').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<p>{{this.languageResolverService.getBy('editorLogo') | translate}}</p>
<table class="logo-table col-md-12">
<tr>
<td>
<img mat-card-avatar *ngIf="!formGroup.get('files') || !formGroup.get('files').value" [src]="host+'files/any?type=jpg'">
<img mat-card-avatar *ngIf="formGroup.get('files') && formGroup.get('files').value" [src]="host+'files/'+formGroup.get('files').value[0].id+'?location='+formGroup.get('files').value[0].location+'&type='+formGroup.get('files').value[0].type">
</td>
<td>
<app-fileuploader-component [form]="formGroup.get('files')" [label]="'FILE-UPLOADER.PROJECT'" [fileUploader]="uploaderService"></app-fileuploader-component>
</td>
</tr>
</table>
<div class="col-md-12">
<div class="row">
<div class="col-auto">
<div class="col-auto right-button">
<button mat-raised-button color="primary" (click)="cancel()" type="button">{{'PROJECT-EDITOR.ACTIONS.CANCEL' | translate}}</button>
</div>
<div class="col-auto">
<div class="col-auto right-button">
<button *ngIf="isNew || editMode" mat-raised-button color="primary" type="submit">{{'PROJECT-EDITOR.ACTIONS.SAVE' | translate}}</button>
</div>
<div class="col-auto">
<div class="col-auto right-button">
<button *ngIf="!isNew && editMode" mat-raised-button color="primary" type="button" (click)="delete()">{{'PROJECT-EDITOR.ACTIONS.DELETE' | translate}}</button>
</div>
</div>

View File

@ -42,3 +42,8 @@
h3{
margin-top: 0px;
}
.hidden {
display: none !important;
}

View File

@ -185,4 +185,19 @@ export class ProjectEditorComponent implements OnInit, IBreadCrumbComponent {
public isExternalProject() {
return this.project.type === ProjectType.External;
}
public previewImage(event): void {
let fileList: FileList | File = event.target.files;
let formdata: FormData = new FormData();
if (fileList instanceof FileList) {
for (let i: number = 0; i < fileList.length; i++) {
formdata.append('file', fileList[i]);
}
} else {
formdata.append('file', fileList);
}
this.uploaderService.uploadFile(formdata).subscribe(files => this.formGroup.get('files').patchValue(files));
}
}

View File

@ -14,6 +14,7 @@ import { LanguageService } from '../../services/language/language.service';
import { LanguageResolverService } from '../../services/language-resolver/language-resolver.service';
import { BreadcrumbItem } from '../../shared/components/breadcrumb/definition/breadcrumb-item';
import { IBreadCrumbComponent } from '../../shared/components/breadcrumb/definition/IBreadCrumbComponent';
import { ProjectStateType } from '../../models/projects/ProjectStateType';
@Component({
selector: 'app-project-listing-component',
@ -61,6 +62,7 @@ export class ProjectListingComponent implements OnInit, IBreadCrumbComponent {
getDefaultCriteria(): ProjectCriteria {
const defaultCriteria = new ProjectCriteria();
defaultCriteria.projectStateType = ProjectStateType.OnGoing;
return defaultCriteria;
}
}

View File

@ -5,6 +5,7 @@ import { HostConfiguration } from './../../app.constants';
import { BaseHttpService } from '../../utilities/cite-http-service-module/base-http.service';
import { Observable } from 'rxjs/Observable';
import { DashboardStatisticsModel } from '../../models/dashboard/DashboardStatisticsModel';
import { SearchBarItem } from '../../models/dashboard/SearchBarItem';
@ -32,4 +33,8 @@ export class DashboardService {
return this.http.get<DashboardStatisticsModel>(this.actionUrl + 'me/getStatistics', { headers: this.headers });
}
searchUserItems(like: string): Observable<SearchBarItem[]> {
return this.http.get<SearchBarItem[]>(this.actionUrl + 'search?like=' + like, { headers: this.headers });
}
}

View File

@ -64,4 +64,8 @@ export class DataManagementPlanService {
getDynamicField(requestItem: RequestItem<DatasetProfileCriteria>): any {
return this.http.post<any>(this.actionUrl + "dynamic", requestItem, { headers: this.headers })
}
get(requestItem: RequestItem<DataManagementPlanCriteria>): Observable<DataManagementPlanListingModel[]> {
return this.http.post<DataManagementPlanListingModel[]>(this.actionUrl + 'get', requestItem, { headers: this.headers });
}
}

View File

@ -36,6 +36,10 @@ export class UserReferenceService {
return this.http.post<DataTableData<UserListingModel>>(this.actionUrl + 'getPaged', JSON.stringify(dataTableRequest), { headers: this.headers });
}
getUser(id: String): Observable<UserListingModel> {
return this.http.get<UserListingModel>(this.actionUrl + id, { headers: this.headers });
}
updateRoles(itemToUpdate: UserListingModel): Observable<UserListingModel> {
return this.http.post<UserListingModel>(this.actionUrl + 'updateRoles', JSON.stringify(itemToUpdate), { headers: this.headers });
}

View File

@ -1,5 +1,5 @@
<mat-form-field class="multiple-auto-complete">
<mat-chip-list #chipList ngDefaultControl [disabled]="reactiveFormControl.disabled" [formControl]="reactiveFormControl">
<mat-chip-list #chipList ngDefaultControl [required]='required' [disabled]="reactiveFormControl.disabled" [formControl]="reactiveFormControl">
<mat-chip *ngFor="let selectedItem of _chipItems()" [disabled]="reactiveFormControl.disabled" [selectable]="selectable" [removable]="removable" (removed)="_removeSelectedItem(selectedItem)">
{{this._displayFn(selectedItem)}}
<mat-icon matChipRemove *ngIf="!reactiveFormControl.disabled && removable">cancel</mat-icon>

View File

@ -22,7 +22,7 @@ export class MultipleAutoCompleteComponent implements OnInit {
@Input() placeholder: string;
@Input() validationErrorString: string;
@Input() configuration: MultipleAutoCompleteConfiguration;
@Input() required: boolean;
// Selected Option Event
@Output() optionSelected: EventEmitter<any> = new EventEmitter();
@ -135,9 +135,11 @@ export class MultipleAutoCompleteComponent implements OnInit {
}
_removeSelectedItem(item: any): void {
const index = this.reactiveFormControl.value.indexOf(item);
let autocompleteValue = this.reactiveFormControl.value;
const index = autocompleteValue.indexOf(item);
if (index >= 0) {
this.reactiveFormControl.value.splice(index, 1);
autocompleteValue.splice(index, 1);
this.reactiveFormControl.patchValue(autocompleteValue)
}
}

View File

@ -1,5 +1,5 @@
<mat-form-field class="auto-complete">
<input matInput [placeholder]="placeholder" [matAutocomplete]="auto" [formControl]="reactiveFormControl" (focus)="_onInputFocus()">
<input matInput [placeholder]="placeholder" [matAutocomplete]="auto" [required]='required' [formControl]="reactiveFormControl" (focus)="_onInputFocus()">
<mat-error *ngIf="validationErrorString">{{validationErrorString}}</mat-error>
<mat-error *ngIf="reactiveFormControl.hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<mat-error *ngIf="reactiveFormControl.hasError('invalidJson')">{{'GENERAL.VALIDATION.INVALID-JSON' | translate}}</mat-error>

View File

@ -16,7 +16,7 @@ export class SingleAutoCompleteComponent implements OnInit {
@Input() reactiveFormControl: FormControl;
@Input() placeholder: string;
@Input() validationErrorString: string;
@Input() required: boolean;
@Input() configuration: SingleAutoCompleteConfiguration;
// Selected Option Event

View File

@ -1,5 +1,5 @@
<mat-selection-list #datasetsprofiles>
<mat-list-option *ngFor="let profile of profiles" [value]="profile">
<mat-selection-list #datasetsprofiles [ngModel]="selectedOptions">
<mat-list-option *ngFor="let profile of profiles" [value]="profile" [selected]='isOptionSelected(profile)'>
{{profile.label}}
</mat-list-option>
</mat-selection-list>

View File

@ -18,7 +18,7 @@ export class AvailableProfilesComponent implements OnInit {
public formGroup: FormGroup;
public profiles: DatasetProfileModel[] = [];
public selectedProfiles: DatasetProfileModel[] = [];
public selectedOptions: any
constructor(
private datasetService: DatasetService,
private route: ActivatedRoute,
@ -28,19 +28,13 @@ export class AvailableProfilesComponent implements OnInit {
) { }
ngOnInit(): void {
this.formGroup = this.data["profiles"];
this.datasetService.getDatasetProfiles().subscribe(data => {
this.profiles = JsonSerializer.fromJSONArray(data, DatasetProfileModel)
}
)
})
}
addProfiles(profiles) {
// profiles.selectedOptions.forEach(element => {
// selectedProfiles.push(element.value)
// });
profiles.selectedOptions.selected.forEach(element => {
let selectedElement = new DatasetProfileModel();
selectedElement.id = element.value.id;
@ -50,4 +44,8 @@ export class AvailableProfilesComponent implements OnInit {
this.formGroup.setValue(this.selectedProfiles)
this.dialogRef.close();
}
isOptionSelected(profile: any){
return this.formGroup.value.map(x=> x.id).indexOf(profile.id) !== -1
}
}

View File

@ -8,24 +8,14 @@
<div class="row">
<div class="col-md-6">
<mat-form-field>
<input matInput placeholder="{{'CRITERIA.DMP.LIKE'| translate}}" name="projectCriteriaLike" [(ngModel)]="criteria.like" (ngModelChange)="controlModified()">
<input matInput placeholder="{{'CRITERIA.DMP.LIKE'| translate}}" name="projectCriteriaLike" [formControl]="formGroup.get('like')" (ngModelChange)="controlModified()">
<mat-error *ngIf="baseErrorModel?.like">{{baseErrorModel['Criteria.like']}}</mat-error>
</mat-form-field>
</div>
<div *ngIf="showProject" class="col-md-6">
<td-chips color="accent" [items]="filteredProjects" [(ngModel)]="criteria.projects" (ngModelChange)="controlModified()" placeholder="{{'CRITERIA.DMP.PROJECTS' | translate}}"
(inputChange)="filterProjects($event)" requireMatch>
<ng-template td-chip let-chip="chip">
<div class="tc-grey-100 bgc-teal-700" td-chip-avatar>{{chip.label.substring(0, 1).toUpperCase()}}</div>
{{chip.label}}
</ng-template>
<ng-template td-autocomplete-option let-option="option">
<div layout="row" layout-align="start center">
{{option.label}}
</div>
</ng-template>
<mat-progress-bar [style.height.px]="2" *ngIf="filteringProjectsAsync" mode="indeterminate"></mat-progress-bar>
</td-chips>
<app-multiple-auto-complete class="col-md-10" [reactiveFormControl]="formGroup.get('projects')" placeholder="{{'CRITERIA.DMP.PROJECTS' | translate}}"
[configuration]="projectAutoCompleteConfiguration">
</app-multiple-auto-complete>
</div>
</div>
</mat-card>

View File

@ -11,6 +11,7 @@ import { ProjectService } from '../../../../services/project/project.service';
import { ProjectCriteria } from '../../../../models/criteria/project/ProjectCriteria';
import { RequestItem } from '../../../../models/criteria/RequestItem';
import { create } from 'domain';
import { MultipleAutoCompleteConfiguration } from '../../autocompletes/multiple/multiple-auto-complete-configuration';
@Component({
selector: 'app-dmp-criteria-component',
@ -22,9 +23,13 @@ export class DataManagementPlanCriteriaComponent extends BaseCriteriaComponent i
@Input()
showProject: boolean;
public criteria: DataManagementPlanCriteria = new DataManagementPlanCriteria();
filteringProjectsAsync: boolean = false;
filteredProjects: ProjectModel[];
projectAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
public formGroup = new FormBuilder().group({
like: new FormControl(),
projects: new FormControl()
});
constructor(
public language: TranslateService,
@ -36,11 +41,24 @@ export class DataManagementPlanCriteriaComponent extends BaseCriteriaComponent i
ngOnInit() {
super.ngOnInit();
if (this.criteria == null) { this.criteria = new DataManagementPlanCriteria(); }
this.projectAutoCompleteConfiguration = {
filterFn: this.filterProject.bind(this),
initialItems: (excludedItems: any[]) => this.filterProject('').map(result => result.filter(x => excludedItems.map(x => x.id).indexOf(x.id) == -1)),
displayFn: (item) => item["label"],
titleFn: (item) => item["label"],
//mapFn: (item) => new JsonSerializer<ProjectReference>().fromJSONArray(item, ProjectReference).map(item => item.toDropdownList()),
loadDataOnStart: true
};
this.formGroup.get('projects').valueChanges.subscribe(x => this.controlModified())
this.formGroup.get('like').valueChanges.subscribe(x => this.controlModified())
//if (this.criteria == null) { this.criteria = new DataManagementPlanCriteria(); }
}
setCriteria(criteria: DataManagementPlanCriteria): void {
this.criteria = criteria;
this.formGroup.get('like').patchValue(criteria.like)
this.formGroup.get('projects').patchValue(criteria.projects)
}
onCallbackError(error: any) {
@ -50,26 +68,16 @@ export class DataManagementPlanCriteriaComponent extends BaseCriteriaComponent i
controlModified(): void {
this.clearErrorModel();
if (this.refreshCallback != null &&
(this.criteria.like == null || this.criteria.like.length == 0 || this.criteria.like.length > 2)
(this.formGroup.get('like').value == null || this.formGroup.get('like').value.length == 0 || this.formGroup.get('like').value.length > 2)
) {
this.refreshCallback();
}
}
filterProjects(value: string): void {
this.filteredProjects = undefined;
if (value) {
this.filteringProjectsAsync = true;
let requestItem: RequestItem<ProjectCriteria> = new RequestItem();
let criteria: ProjectCriteria = new ProjectCriteria();
criteria.like = value;
requestItem.criteria = criteria;
this.projectService.get(requestItem).subscribe(items => {
this.filteredProjects = items;
this.filteringProjectsAsync = false;
});
}
filterProject(query: string) {
let projectRequestItem: RequestItem<ProjectCriteria> = new RequestItem();
projectRequestItem.criteria = new ProjectCriteria();
projectRequestItem.criteria.like = query;
return this.projectService.getWithExternal(projectRequestItem);
}
}

View File

@ -1,11 +1,11 @@
<div class="row">
<!-- <h4 class="col-md-12">{{'CRITERIA.FILTERS'| translate}}</h4> -->
<mat-form-field class="col-md-4">
<mat-form-field class="col-md-3">
<input matInput placeholder=" {{'CRITERIA.PROJECTS.LIKE'| translate}}" name="projectCriteriaLike" [(ngModel)]="criteria.like"
(ngModelChange)="controlModified()">
<mat-error *ngIf="baseErrorModel?.like">{{baseErrorModel['criteria.like']}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-4">
<mat-form-field class="col-md-3">
<input matInput (focus)="periodStartPicker.open()" (click)="periodStartPicker.open()" placeholder=" {{this.languageResolver.getBy('criteriaStart')| translate}}"
[matDatepicker]="periodStartPicker" name="projectCriteriaPeriodStart" [(ngModel)]="criteria.periodStart" (ngModelChange)="controlModified()">
<mat-datepicker-toggle matSuffix [for]="periodStartPicker"></mat-datepicker-toggle>
@ -13,11 +13,22 @@
</mat-form-field>
<mat-error *ngIf="baseErrorModel['criteria.periodStart']">{{baseErrorModel['criteria.periodStart']}}</mat-error>
<mat-form-field class="col-md-4">
<mat-form-field class="col-md-3">
<input matInput (focus)="periodEndPicker.open()" (click)="periodEndPicker.open()" name="projectCriteriaPeriodEnd" placeholder=" {{this.languageResolver.getBy('criteriaEnd')| translate}}"
[matDatepicker]="periodEndPicker" [(ngModel)]="criteria.periodEnd" (ngModelChange)="controlModified()">
<mat-error *ngIf="baseErrorModel['criteria.periodEnd']">{{baseErrorModel['criteria.periodEnd']}}</mat-error>
<mat-datepicker-toggle matSuffix [for]="periodEndPicker"></mat-datepicker-toggle>
<mat-datepicker #periodEndPicker></mat-datepicker>
</mat-form-field>
<mat-form-field class="col-md-3">
<mat-select placeholder=" {{ 'CRITERIA.PROJECTS.PROJECT-STATE-TYPE' | translate}}" [(ngModel)]="criteria.projectStateType" (ngModelChange)="controlModified()" >
<mat-option [value]="ProjectStateType.OnGoing">
{{ 'CRITERIA.PROJECTS.TYPES.ON-GOING' | translate}}
</mat-option>
<mat-option [value]="ProjectStateType.Finished">
{{ 'CRITERIA.PROJECTS.TYPES.FINISHED' | translate}}
</mat-option>
</mat-select>
</mat-form-field>
</div>

View File

@ -7,6 +7,7 @@ import { BackendErrorValidator } from '../../../../utilities/validators/BackendE
import { ProjectCriteria } from '../../../../models/criteria/project/ProjectCriteria';
import { ProjectCriteriaErrorModel } from '../../../../models/criteria/project/ProjectCriteriaErrorModel';
import { LanguageResolverService } from '../../../../services/language-resolver/language-resolver.service';
import { ProjectStateType } from '../../../../models/projects/ProjectStateType';
@Component({
selector: 'app-projects-criteria-component',
@ -19,7 +20,7 @@ import { LanguageResolverService } from '../../../../services/language-resolver/
export class ProjectCriteriaComponent extends BaseCriteriaComponent implements OnInit {
// public form: ProjectType;
// public formStatus: ProjectStatus;
public ProjectStateType = ProjectStateType;
public criteria: ProjectCriteria = new ProjectCriteria();
constructor(

View File

@ -1,18 +1,22 @@
<div>
<div class="suggestions">
<div fxLayout="row">
<mat-form-field class="fxItems">
<div class="container">
<div class="row">
<div class="col-md-5">
<mat-form-field >
<mat-select placeholder="Sources" [(ngModel)]="choice" (selectionChange)="selectionChange($event)">
<mat-option *ngFor="let option of options" [value]="option.key">
{{ option.label }}
</mat-option>
</mat-select>
</mat-form-field>
<app-external-item class="fxItems" [autoCompleteConfiguration]="autoCompleteConfiguration" [formGroup]="formGroup" [displayFunction]="displayFunction"
</div>
<div>
<app-external-item class="col-md-7" [autoCompleteConfiguration]="autoCompleteConfiguration" [formGroup]="formGroup" [displayFunction]="displayFunction"
[placeholder]="placeholder" [subtitleFunction]="subtitleFunction" (onItemChange)="this.onItemChangeFunc($event)" [formCtrl]="formControl"
[disabled]="disabled">
</app-external-item>
</div>
</div>
<div fxLayout="row" *ngFor="let suggestion of formGroup['controls']; let i = index">
<ng-container *ngTemplateOutlet="parentTemplate; context: { $implicit: suggestion, index: i,function: this.deleteItem.bind(this) }">
</ng-container>

View File

@ -3,11 +3,10 @@
position: relative;
width: 100%;
margin: 25px 0;
cursor: pointer;
}
.card-content {
text-align: right;
text-align: center;
padding: 15px 20px 13px 20px;
}
@ -20,6 +19,7 @@
border-radius: 3px;
padding: 15px;
position: relative;
cursor: pointer;
}
.card-header i {

View File

@ -1,10 +1,11 @@
<div class="figure-card card" (click)="navigateToUrl()">
<div class="card-header" [ngStyle]="{ 'background': linearColor, 'box-shadow': boxShadow }">
<div class="figure-card card">
<div class="card-header" (click)="navigateToUrl()" [ngStyle]="{ 'background': linearColor, 'box-shadow': boxShadow }">
<i class="material-icons">{{ headerIcon }}</i>
</div>
<div class="card-content">
<p class="category">{{ category | translate }}</p>
<h3 class="title">{{ title }}</h3>
<button mat-raised-button color="primary" (click)="createNew()" >{{buttonTitle}}</button>
</div>
<div *ngIf="hasFootContent" class="card-footer">
</div>

View File

@ -16,6 +16,8 @@ export class FigurecardComponent implements OnInit {
@Input() boxShadow: string;
@Input() routelLink: string;
@Input() hasFootContent = true;
@Input() buttonTitle: string;
@Input() buttonRedirectLink: string;
constructor(private router: Router) { }
@ -24,7 +26,10 @@ export class FigurecardComponent implements OnInit {
navigateToUrl() {
this.router.navigate([this.routelLink]);
}
createNew(){
this.router.navigate([this.buttonRedirectLink]);
}
}

View File

@ -1,5 +1,5 @@
<mat-toolbar color="primary">
<a [fxLayoutAlign]="'center'" class="app-logo" routerLink="/">
<a class="app-logo" routerLink="/">
<img [src]="'/assets/images/openDmps.png'" alt="openDMPS">
</a>
<div *ngIf="isAuthenticated()">
@ -13,15 +13,33 @@
<!--<button mat-button class="navbar-button" routerLink="/about">{{'NAV-BAR.ABOUT' | translate}}</button>-->
<span class="navbar-spacer"></span>
<div *ngIf="isAuthenticated();else loginoption">
<img mat-card-avatar *ngIf="this.principalHasAvatar()" [src]="this.getPrincipalAvatar()">
<span class="user-label">{{this.getPrincipalName()}}</span>
<button mat-icon-button (click)="logout()">
<mat-icon>exit_to_app</mat-icon>
</button>
<div fxFlex *ngIf="search">
<mat-form-field class="full-width">
<input type="text" placeholder="{{'DASHBOARD.SEARCH' | translate}}" matInput [formControl]="searchControl" [matAutocomplete]="auto">
<mat-autocomplete autoActiveFirstOption #auto="matAutocomplete" (optionSelected)="onOptionSelected($event)">
<mat-option *ngFor="let option of filteredOptions | async" [value]="option">
{{option.label}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
<div fxLayout="row">
<div fxFlex *ngIf="!search">
<button mat-button (click)="this.search = true">
<mat-icon>search</mat-icon>
</button>
</div>
<div fxFlex *ngIf="search">
<button mat-button (click)="this.search = false">
<mat-icon>close</mat-icon>
</button>
</div>
<div fxFlex *ngIf="isAuthenticated();else loginoption">
<img mat-card-avatar *ngIf="this.principalHasAvatar()" [src]="this.getPrincipalAvatar()" (click)="openProfile()">
</div>
</div>
<ng-template #loginoption>
<button mat-button [routerLink]=" ['/login'] ">
<span class="login-label">Log in</span>

View File

@ -29,3 +29,11 @@
width: 38px;
height: 38px;
}
.user-profile{
width: 10%;
}
.full-width {
width: 100%;
}

View File

@ -3,19 +3,65 @@ import { Component, EventEmitter, Input, Output, ElementRef } from '@angular/cor
import { Principal } from '../../../models/login/Principal';
import { AuthService } from '../../../services/auth/auth.service';
import { LanguageResolverService } from '../../../services/language-resolver/language-resolver.service';
import { MatSidenav } from '@angular/material';
import { MatSidenav, MatDialog } from '@angular/material';
import { UserDialogComponent } from '../user-dialog/user-dialog.component';
import { SingleAutoCompleteConfiguration } from '../autocompletes/single/single-auto-complete-configuration';
import { ProjectCriteria } from '../../../models/criteria/project/ProjectCriteria';
import { RequestItem } from '../../../models/criteria/RequestItem';
import { ProjectService } from '../../../services/project/project.service';
import { FormControl } from '@angular/forms';
import { DashboardService } from '../../../services/dashboard/dashboard.service';
import { Observable } from 'rxjs/Observable';
import { SearchBarItem } from '../../../models/dashboard/SearchBarItem';
import { SearchBarType } from '../search-bar/types/search-bar-type';
import { Router } from '@angular/router';
@Component({
selector: 'app-navigation',
templateUrl: 'navigation.component.html',
styleUrls: ['./navigation.component.css'],
styleUrls: ['./navigation.component.scss'],
providers: [ProjectService]
})
export class NavigationComponent {
invert = false;
public search = false;
projectAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
public searchControl = new FormControl();
filteredOptions: Observable<SearchBarItem[]>;
constructor(private authentication: AuthService, private languageResolver: LanguageResolverService) {
constructor(
private authentication: AuthService,
private languageResolver: LanguageResolverService,
public dialog: MatDialog,
private projectService: ProjectService,
private dashBoardService: DashboardService,
private router: Router,
) {
}
ngOnInit() {
this.projectAutoCompleteConfiguration = {
filterFn: this.searchProject.bind(this),
items: this.searchProject(''),
displayFn: (item) => item["label"],
titleFn: (item) => item["label"],
//mapFn: (item) => new JsonSerializer<ProjectReference>().fromJSONArray(item, ProjectReference).map(item => item.toDropdownList()),
loadDataOnStart: true
};
this.filteredOptions = this.searchControl.valueChanges.flatMap(x => {
return this.dashBoardService.searchUserItems(x);
})
}
searchProject(query: string) {
let projectRequestItem: RequestItem<ProjectCriteria> = new RequestItem();
projectRequestItem.criteria = new ProjectCriteria();
projectRequestItem.criteria.like = query;
return this.projectService.getWithExternal(projectRequestItem);
}
public logout(): void {
@ -46,12 +92,6 @@ export class NavigationComponent {
return false;
}
public getPrincipalName(): string {
const principal: Principal = this.authentication.current();
if (principal) { return principal.name; }
return '';
}
public principalHasAvatar(): boolean {
return this.authentication.current().avatarUrl != null;
}
@ -63,4 +103,23 @@ export class NavigationComponent {
onSideNavClick() {
this.sideNav.toggle();
}
openProfile() {
let dialogRef = this.dialog.open(UserDialogComponent, {
hasBackdrop: true,
closeOnNavigation: true,
disableClose: false,
position: { top: "64px", left: "85%" }
});
}
onOptionSelected(event: any) {
this.search = false;
this.searchControl.patchValue(null);
let selectedSearchBarItem = event.option.value;
if (selectedSearchBarItem.type == SearchBarType.DATASET) this.router.navigate(["datasets/edit/" + selectedSearchBarItem.id])
if (selectedSearchBarItem.type == SearchBarType.PROJECT) this.router.navigate(["projects/edit/" + selectedSearchBarItem.id])
if (selectedSearchBarItem.type == SearchBarType.DATAMANAGEMENTPLAN) this.router.navigate(["dmps/edit/" + selectedSearchBarItem.id])
}
}

View File

@ -0,0 +1,17 @@
import { sample } from 'rxjs/operators';
import { Component, EventEmitter, Input, Output, ElementRef } from '@angular/core';
import { Principal } from '../../../models/login/Principal';
import { AuthService } from '../../../services/auth/auth.service';
import { LanguageResolverService } from '../../../services/language-resolver/language-resolver.service';
import { MatSidenav, MatDialog } from '@angular/material';
import { UserDialogComponent } from '../user-dialog/user-dialog.component';
@Component({
selector: 'app-search',
templateUrl: 'navigation.component.html',
styleUrls: ['./navigation.component.scss'],
})
export class SearchBarComponent {
}

View File

@ -0,0 +1,5 @@
export enum SearchBarType {
DATASET = 0,
DATAMANAGEMENTPLAN = 1,
PROJECT = 2
}

View File

@ -0,0 +1,24 @@
<form>
<div mat-dialog-title>
<img mat-card-avatar *ngIf="this.principalHasAvatar()" [src]="this.getPrincipalAvatar()">
<span class="user-label">{{this.getPrincipalName()}}</span>
</div>
<div mat-dialog-content>
<mat-divider></mat-divider>
{{'USER-DIALOG.USER-PROFILE' | translate}}
<button mat-icon-button (click)="navigateToProfile()">
<mat-icon>person</mat-icon>
</button>
<mat-divider></mat-divider>
</div>
<div mat-dialog-actions>
<div layout="row" class="full-width text-right" align="end">
{{'USER-DIALOG.EXIT' | translate}}
<button mat-icon-button (click)="logout()">
<mat-icon>exit_to_app</mat-icon>
</button>
</div>
</div>
</form>

View File

@ -0,0 +1,54 @@
import { JsonSerializer } from '../../../utilities/JsonSerializer';
import { RequestItem } from '../../../models/criteria/RequestItem';
import { Component, OnInit, Inject } from "@angular/core";
import { FormGroup } from '@angular/forms';
import { Params, ActivatedRoute, Router } from '@angular/router';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { ResearcherModel } from '../../../models/researcher/ResearcherModel';
import { ResearcherService } from '../../../services/researchers/researchers.service';
import { AuthService } from '../../../services/auth/auth.service';
import { Principal } from '../../../models/login/Principal';
@Component({
selector: 'user-dialog-component',
templateUrl: 'user-dialog.component.html',
})
export class UserDialogComponent implements OnInit {
public formGroup: FormGroup;
constructor(
private route: ActivatedRoute,
private authentication: AuthService,
public router: Router,
public dialogRef: MatDialogRef<UserDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any
) { }
ngOnInit(): void {
}
public logout(): void {
this.dialogRef.close();
this.authentication.logout();
}
public getPrincipalName(): string {
const principal: Principal = this.authentication.current();
if (principal) { return principal.name; }
return '';
}
public principalHasAvatar(): boolean {
return this.authentication.current().avatarUrl != null;
}
public getPrincipalAvatar(): string {
return this.authentication.current().avatarUrl;
}
public navigateToProfile() {
this.router.navigate(["/users/" + this.authentication.current().id]);
}
}

View File

@ -28,7 +28,8 @@ import {
MatRadioModule,
MatMenuModule,
MatListModule,
MatChipsModule
MatChipsModule,
MatBadgeModule
} from '@angular/material';
import { CdkTableModule } from '@angular/cdk/table';
import { SnackBarNotificationComponent } from '../components/notificaiton/snack-bar-notification.component';
@ -71,7 +72,8 @@ import { CovalentLayoutModule, CovalentChipsModule, CovalentDialogsModule, Coval
MatRadioModule,
MatMenuModule,
MatListModule,
MatChipsModule
MatChipsModule,
MatBadgeModule
],
providers: [

View File

@ -23,6 +23,7 @@ import { ExternalItemComponent } from './components/external-items/external-item
import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.component';
import { SingleAutoCompleteComponent } from './components/autocompletes/single/single-auto-complete.component';
import { MultipleAutoCompleteComponent } from './components/autocompletes/multiple/multiple-auto-complete.component';
import { UserDialogComponent } from './components/user-dialog/user-dialog.component';
@NgModule({
imports: [
@ -52,7 +53,8 @@ import { MultipleAutoCompleteComponent } from './components/autocompletes/multip
ExternalItemComponent,
BreadcrumbComponent,
SingleAutoCompleteComponent,
MultipleAutoCompleteComponent
MultipleAutoCompleteComponent,
UserDialogComponent
],
exports: [
@ -75,9 +77,11 @@ import { MultipleAutoCompleteComponent } from './components/autocompletes/multip
ExternalItemComponent,
BreadcrumbComponent,
SingleAutoCompleteComponent,
MultipleAutoCompleteComponent
MultipleAutoCompleteComponent,
UserDialogComponent
],
entryComponents: [
UserDialogComponent
]
})

View File

@ -1,27 +1,4 @@
<div class="container row">
<div class="col-md-3">
<mat-card class="example-card">
<mat-card-header>
<mat-card-title>
{{'RECENT-ACTIVITY.MY-TITLE-PROJECT' | translate}}
</mat-card-title>
</mat-card-header>
<mat-card-content>
<mat-nav-list *ngIf="projectActivities!=null">
<mat-list-item (click)="redirect(activity.id,RecentActivityTypes.PROJECT)" *ngFor="let activity of projectActivities">
<p mat-line>
{{activity.label}}
</p>
<p mat-line>
{{activity.timestamp | date:'shortDate'}}
</p>
</mat-list-item>
</mat-nav-list>
</mat-card-content>
</mat-card>
</div>
<div class="col-md-3">
<mat-card class="example-card">
<mat-card-header>
@ -43,6 +20,28 @@
</mat-card-content>
</mat-card>
</div>
<div class="col-md-3">
<mat-card class="example-card">
<mat-card-header>
<mat-card-title>
{{'RECENT-ACTIVITY.MY-TITLE-PROJECT' | translate}}
</mat-card-title>
</mat-card-header>
<mat-card-content>
<mat-nav-list *ngIf="projectActivities!=null">
<mat-list-item (click)="redirect(activity.id,RecentActivityTypes.PROJECT)" *ngFor="let activity of projectActivities">
<p mat-line>
{{activity.label}}
</p>
<p mat-line>
{{activity.timestamp | date:'shortDate'}}
</p>
</mat-list-item>
</mat-nav-list>
</mat-card-content>
</mat-card>
</div>
<div class="col-md-3">
<mat-card class="example-card">
<mat-card-header>

View File

@ -0,0 +1,37 @@
<div *ngIf="user | async as userProfile; else loading">
<mat-card class="example-card">
<mat-card-content>
<div fxLayout="column" fxLayoutAlign="center center">
<div fxFlex>
<img mat-card-avatar [src]="userProfile.additionalinfo.data.avatar.url">
</div>
<mat-card-title>{{userProfile.name}}</mat-card-title>
<mat-card-subtitle>{{userProfile.email}}</mat-card-subtitle>
</div>
</mat-card-content>
</mat-card>
<mat-card>
<mat-card-content>
<div fxLayout="column" fxLayoutAlign="center center">
<div fxFlex>
<h4>{{ 'USER-PROFILE.ASSOCIATED-DMPS' | translate}}</h4>
</div>
<div>
{{userProfile.associatedDmps}}
</div>
</div>
</mat-card-content>
</mat-card>
<mat-card>
<mat-card-content>
<div fxLayout="column" fxLayoutAlign="center center">
<div fxFlex>
<h4>{{ 'USER-PROFILE.SETTINGS' | translate}}</h4>
</div>
</div>
</mat-card-content>
</mat-card>
</div>
<ng-template #loading>
Loading stuff...
</ng-template>

View File

@ -0,0 +1,46 @@
import { DataTableRequest } from '../../models/data-table/DataTableRequest';
import { UserErrorModel } from '../../models/users/UserErrorModel';
import { UserReferenceService } from '../../services/user-reference/user-reference-data.service';
import { UserListingModel } from '../../models/users/UserListingModel';
import { SnackBarNotificationComponent } from '../../shared/components/notificaiton/snack-bar-notification.component';
import { UserCriteria } from '../../models/criteria/users/UserCriteria';
import { UserCriteriaErrorModel } from '../../models/criteria/users/UserCriteriaErrorModel';
import { Observable } from 'rxjs/Rx';
import { Component, OnInit, AfterViewInit, ViewChild } from '@angular/core';
import { UsersCriteriaComponent } from '../../shared/components/criteria/users/users-criteria.component';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { Principal } from '../../models/login/Principal';
import { MatPaginator, MatSort, MatSnackBar } from '@angular/material';
import { TranslateService } from '@ngx-translate/core';
import { DataSource } from '@angular/cdk/table';
import { RecentActivityTypes } from '../../users/activity/RecentActivityTypes';
import { AuthService } from '../../services/auth/auth.service';
@Component({
selector: 'app-user-profile',
templateUrl: './user-profile.component.html',
styleUrls: ['./user-profile.component.scss'],
providers: [
UserReferenceService
]
})
export class UserProfileComponent implements OnInit {
user: Observable<UserListingModel>;
constructor(
private userReferenceService: UserReferenceService,
private route: ActivatedRoute,
private authService: AuthService
) { }
ngOnInit() {
this.route.params.subscribe((params: Params) => {
let userId = params['id'] === this.authService.current().id ? 'me' : params['id']
this.user = this.userReferenceService.getUser(userId).map(result => { result["additionalinfo"] = JSON.parse(result["additionalinfo"]); return result })
})
}
}

View File

@ -16,6 +16,7 @@ import { RouterModule } from '@angular/router';
import { UsersRoutes } from './users.routes';
import { BaseHttpModule } from '../utilities/cite-http-service-module/cite-http.module';
import { BaseHttpService } from '../utilities/cite-http-service-module/base-http.service';
import { UserProfileComponent } from './profile/user-profile.component';
@NgModule({
imports: [
@ -39,6 +40,7 @@ import { BaseHttpService } from '../utilities/cite-http-service-module/base-http
UsersComponent,
UsersCriteriaComponent,
UserRoleEditorComponent,
UserProfileComponent
],
providers: [
BaseHttpService,

View File

@ -1,6 +1,8 @@
import { RouterModule, Routes } from '@angular/router';
import { UsersComponent } from './components/users.component';
import { UserProfileComponent } from './profile/user-profile.component';
export const UsersRoutes: Routes = [
{ path: '', component: UsersComponent }
{ path: '', component: UsersComponent },
{ path: ':id', component: UserProfileComponent }
];

View File

@ -40,7 +40,7 @@
"START": "Start",
"END": "End",
"ACTIONS": "Actions",
"DMPS": "Dmps"
"DMPS": "DMPs"
}
},
"DMP-LISTING": {
@ -160,7 +160,7 @@
"DESCRIPTION": "Description",
"ORGANISATIONS": "Organisations",
"RESEARCHERS": "Researchers",
"PROFILES": "Available Profiles",
"PROFILES": "Available Dataset Profiles",
"PROFILE": "DMP Profile",
"GRANT": "Grant",
"FUNDER": "Funder"
@ -178,7 +178,12 @@
"PROJECTS": {
"LIKE": "Search",
"PERIOD-FROM": "Project Start",
"PERIOD-TO": "Project End"
"PERIOD-TO": "Project End",
"PROJECT-STATE-TYPE": "Project Status",
"TYPES": {
"ON-GOING": "OnGoing",
"FINISHED": "Finished"
}
},
"DATA-SETS": {
"LIKE": "Search",
@ -281,7 +286,7 @@
},
"RECENT-ACTIVITY": {
"MY-TITLE-PROJECT": "My Recent Project Activity",
"MY-TITLE-DMP": "My Recent Dmp Activity",
"MY-TITLE-DMP": "My Recent DMP Activity",
"MY-TITLE-DATASET": "My Recent Dataset Activity"
},
"FILE-UPLOADER": {
@ -311,6 +316,15 @@
"MY-DMPS": "My DMPs",
"DMPS": "DMPs",
"MY-DATASETS": "My Datasets",
"DATASETS": "Datasets"
"DATASETS": "Datasets",
"SEARCH": "Search"
},
"USER-DIALOG": {
"USER-PROFILE": "My Profile",
"EXIT": "Exit "
},
"USER-PROFILE": {
"SETTINGS": "Settings",
"ASSOCIATED-DMPS": "Associated DMPs"
}
}