Adds the published DMPs view.

This commit is contained in:
gkolokythas 2019-04-26 17:05:15 +03:00
parent f98cfc2969
commit e591e47736
23 changed files with 803 additions and 18 deletions

View File

@ -0,0 +1,42 @@
package eu.eudat.data.dao.criteria;
import eu.eudat.data.entities.DMP;
import eu.eudat.types.project.ProjectStateType;
import java.util.List;
import java.util.UUID;
public class DataManagementPlanPublicCriteria extends Criteria<DMP> {
private ProjectStateType projectStatus;
private List<UUID> projects;
public List<UUID> datasetProfile;
private List<String> dmpOrganisations;
public ProjectStateType getProjectStatus() {
return projectStatus;
}
public void setProjectStatus(ProjectStateType projectStatus) {
this.projectStatus = projectStatus;
}
public List<UUID> getProjects() {
return projects;
}
public void setProjects(List<UUID> projects) {
this.projects = projects;
}
public List<UUID> getDatasetProfile() {
return datasetProfile;
}
public void setDatasetProfile(List<UUID> datasetProfile) {
this.datasetProfile = datasetProfile;
}
public List<String> getDmpOrganisations() {
return dmpOrganisations;
}
public void setDmpOrganisations(List<String> dmpOrganisations) {
this.dmpOrganisations = dmpOrganisations;
}
}

View File

@ -0,0 +1,44 @@
package eu.eudat.data.query.items.table.dmp;
import eu.eudat.data.dao.criteria.DataManagementPlanCriteria;
import eu.eudat.data.dao.criteria.DataManagementPlanPublicCriteria;
import eu.eudat.data.entities.DMP;
import eu.eudat.data.query.PaginationService;
import eu.eudat.data.query.definition.TableQuery;
import eu.eudat.queryable.QueryableList;
import eu.eudat.types.project.ProjectStateType;
import java.util.Date;
import java.util.UUID;
public class DataManagmentPlanPublicTableRequest extends TableQuery<DataManagementPlanPublicCriteria, DMP, UUID> {
public QueryableList<DMP> applyCriteria() {
QueryableList<DMP> query = this.getQuery();
query.where((builder, root) -> builder.equal(root.get("status"), DMP.DMPStatus.FINALISED.getValue()));
if (this.getCriteria().getLike() != null && !this.getCriteria().getLike().isEmpty())
query.where((builder, root) -> builder.or(
builder.like(builder.upper(root.get("label")), "%" + this.getCriteria().getLike().toUpperCase() + "%"),
builder.like(builder.upper(root.get("description")), "%" + this.getCriteria().getLike().toUpperCase() + "%")));
if (this.getCriteria().getProjects() != null && !this.getCriteria().getProjects().isEmpty())
query.where(((builder, root) -> root.get("project").get("id").in(this.getCriteria().getProjects())));
if (this.getCriteria().getProjectStatus() != null) {
if (this.getCriteria().getProjectStatus().getValue().equals(ProjectStateType.FINISHED.getValue()))
query.where((builder, root) -> builder.lessThan(root.get("project").get("enddate"), new Date()));
if (this.getCriteria().getProjectStatus().getValue().equals(ProjectStateType.ONGOING.getValue()))
query.where((builder, root) ->
builder.or(builder.greaterThan(root.get("project").get("enddate"), new Date())
, builder.isNull(root.get("project").get("enddate"))));
}
if (this.getCriteria().datasetProfile != null && !this.getCriteria().datasetProfile.isEmpty()) query
.where(((builder, root) -> root.get("profile").get("id").in(this.getCriteria().datasetProfile)));
if (this.getCriteria().getDmpOrganisations() != null && !this.getCriteria().getDmpOrganisations().isEmpty()) query
.where(((builder, root) -> root.join("organisations").get("reference").in(this.getCriteria().getDmpOrganisations())));
return query;
}
@Override
public QueryableList<DMP> applyPaging(QueryableList<DMP> items) {
return PaginationService.applyPaging(items, this);
}
}

View File

@ -8,11 +8,13 @@ import eu.eudat.data.dao.entities.DMPDao;
import eu.eudat.data.entities.DMP;
import eu.eudat.data.query.items.item.dmp.DataManagementPlanCriteriaRequest;
import eu.eudat.data.query.items.table.dmp.DataManagementPlanTableRequest;
import eu.eudat.data.query.items.table.dmp.DataManagmentPlanPublicTableRequest;
import eu.eudat.exceptions.datamanagementplan.DMPNewVersionException;
import eu.eudat.exceptions.datamanagementplan.DMPWithDatasetsDeleteException;
import eu.eudat.logic.managers.DataManagementPlanManager;
import eu.eudat.logic.managers.DatasetManager;
import eu.eudat.logic.managers.FileManager;
import eu.eudat.logic.security.claims.ClaimedAuthorities;
import eu.eudat.logic.services.ApiContext;
import eu.eudat.logic.services.forms.VisibilityRuleService;
import eu.eudat.logic.utilities.documents.helpers.FileEnvelope;
@ -24,6 +26,7 @@ import eu.eudat.models.data.helpers.responses.ResponseItem;
import eu.eudat.models.data.listingmodels.DataManagementPlanListingModel;
import eu.eudat.models.data.security.Principal;
import eu.eudat.types.ApiMessageCode;
import eu.eudat.types.Authorities;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
@ -95,6 +98,18 @@ public class DMPs extends BaseController {
}
}
@RequestMapping(method = RequestMethod.GET, value = {"/public/{id}"})
public @ResponseBody
ResponseEntity getSinglePublic(@PathVariable String id) throws IllegalAccessException,InterruptedException, InstantiationException, IOException {
try {
eu.eudat.models.data.dmp.DataManagementPlan dataManagementPlan = this.dataManagementPlanManager.getSinglePublic(id, this.dynamicProjectConfiguration);
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<DataManagementPlan>().status(ApiMessageCode.NO_MESSAGE).payload(dataManagementPlan));
}
catch (Exception ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem<DataManagementPlan>().status(ApiMessageCode.NO_MESSAGE).message(ex.getMessage()));
}
}
@Transactional
@RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
public @ResponseBody
@ -168,5 +183,12 @@ public class DMPs extends BaseController {
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<List>()
.status(ApiMessageCode.SUCCESS_MESSAGE));
}
@RequestMapping(method = RequestMethod.POST, value = {"/public/paged"}, consumes = "application/json", produces = "application/json")
public @ResponseBody
ResponseEntity<ResponseItem<DataTableData<DataManagementPlanListingModel>>> getPublicPaged(@RequestBody DataManagmentPlanPublicTableRequest dmpTableRequest, @ClaimedAuthorities(claims = {Authorities.ANONYMOUS}) Principal principal) throws Exception {
DataTableData<DataManagementPlanListingModel> dmp = this.dataManagementPlanManager.getPaged(dmpTableRequest, "listing") ;
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<DataTableData<DataManagementPlanListingModel>>().status(ApiMessageCode.NO_MESSAGE).payload(dmp));
}
}

View File

@ -9,6 +9,7 @@ import eu.eudat.data.entities.Organisation;
import eu.eudat.data.entities.Researcher;
import eu.eudat.data.query.items.item.dmp.DataManagementPlanCriteriaRequest;
import eu.eudat.data.query.items.table.dmp.DataManagementPlanTableRequest;
import eu.eudat.data.query.items.table.dmp.DataManagmentPlanPublicTableRequest;
import eu.eudat.exceptions.datamanagementplan.DMPNewVersionException;
import eu.eudat.exceptions.datamanagementplan.DMPWithDatasetsDeleteException;
import eu.eudat.exceptions.security.UnauthorisedException;
@ -116,6 +117,39 @@ public class DataManagementPlanManager {
return dataTable;
}
public DataTableData<DataManagementPlanListingModel> getPaged(DataManagmentPlanPublicTableRequest dataManagementPlanPublicTableRequest, String fieldsGroup) throws Exception {
dataManagementPlanPublicTableRequest.setQuery(databaseRepository.getDmpDao().asQueryable().withHint(HintedModelFactory.getHint(DataManagementPlanListingModel.class)));
QueryableList<DMP> items = dataManagementPlanPublicTableRequest.applyCriteria();
QueryableList<DMP> pagedItems = PaginationManager.applyPaging(items, dataManagementPlanPublicTableRequest);
DataTableData<DataManagementPlanListingModel> dataTable = new DataTableData<>();
CompletableFuture itemsFuture;
if(fieldsGroup.equals("listing")){
itemsFuture = pagedItems.withHint(HintedModelFactory.getHint(DataManagementPlanListingModel.class))
.selectAsync(item -> {
item.setDataset(
item.getDataset().stream()
.filter(dataset -> dataset.isPublic()).collect(Collectors.toSet()));
return new DataManagementPlanListingModel().fromDataModelDatasets(item);
})
.whenComplete((resultList, throwable) -> dataTable.setData(resultList));
}
else{
itemsFuture = pagedItems
.selectAsync(item -> new DataManagementPlanListingModel().fromDataModel(item))
.whenComplete((resultList, throwable) -> dataTable.setData(resultList));
}
CompletableFuture countFuture = items.countAsync().whenComplete((count, throwable) -> {
dataTable.setTotalCount(count);
});
CompletableFuture.allOf(itemsFuture, countFuture).join();
return dataTable;
}
public void unlock(UUID uuid) throws Exception {
apiContext.getOperationsContext().getDatabaseRepository().getDmpDao()
.asQueryable().where((builder, root) -> builder.equal(root.get("id"), uuid))
@ -216,6 +250,36 @@ public class DataManagementPlanManager {
return datamanagementPlan;
}
public eu.eudat.models.data.dmp.DataManagementPlan getSinglePublic(String id, DynamicProjectConfiguration dynamicProjectConfiguration) throws Exception {
DMP dataManagementPlanEntity = databaseRepository.getDmpDao().find(UUID.fromString(id));
if (dataManagementPlanEntity != null && dataManagementPlanEntity.getStatus() == 1){
eu.eudat.models.data.dmp.DataManagementPlan datamanagementPlan = new eu.eudat.models.data.dmp.DataManagementPlan();
datamanagementPlan.fromDataModel(dataManagementPlanEntity);
Map dmpProperties = dataManagementPlanEntity.getDmpProperties() != null ? new org.json.JSONObject(dataManagementPlanEntity.getDmpProperties()).toMap() : null;
datamanagementPlan.setDynamicFields(dynamicProjectConfiguration.getFields().stream().map(item -> {
DynamicFieldWithValue fieldWithValue = new DynamicFieldWithValue();
fieldWithValue.setId(item.getId());
fieldWithValue.setDependencies(item.getDependencies());
fieldWithValue.setName(item.getName());
fieldWithValue.setQueryProperty(item.getQueryProperty());
fieldWithValue.setRequired(item.getRequired());
return fieldWithValue;
}).collect(Collectors.toList()));
if (dmpProperties != null && datamanagementPlan.getDynamicFields() != null)
datamanagementPlan.getDynamicFields().forEach(item -> {
Map<String, String> properties = (Map<String, String>) dmpProperties.get(item.getId());
if (properties != null)
item.setValue(new Tuple<>(properties.get("id"), properties.get("label")));
});
return datamanagementPlan;
}
else {
throw new Exception("Selected DMP is not public");
}
}
public List<DataManagementPlan> getWithCriteria(DMPDao dmpsRepository, DataManagementPlanCriteriaRequest dataManagementPlanCriteria, Principal principal) throws IllegalAccessException, InstantiationException {
UserInfo userInfo = new UserInfo();
userInfo.setId(principal.getId());

View File

@ -25,6 +25,13 @@ const appRoutes: Routes = [
breadcrumb: true
}
},
{
path: 'exploreplans',
loadChildren: './ui/explore-dmp/explore-dmp.module#ExploreDmpModule',
data: {
breadcrumb: true
}
},
{
path: 'datasets',
loadChildren: './ui/dataset/dataset.module#DatasetModule',

View File

@ -0,0 +1,9 @@
import { BaseCriteria } from "../base-criteria";
import { ProjectStateType } from "../../common/enum/project-state-type";
export class ExploreDmpCriteriaModel extends BaseCriteria {
public projectStatus: ProjectStateType;
public projects: string[] = [];
public datasetProfile: string[] = [];
public dmpOrganisations: string[] = [];
}

View File

@ -15,6 +15,7 @@ import { BaseHttpService } from '../http/base-http.service';
import { ContentType } from '@angular/http/src/enums';
import { BaseHttpParams } from '../../../common/http/base-http-params';
import { InterceptorType } from '../../../common/http/interceptors/interceptor-type';
import { ExploreDmpCriteriaModel } from '../../query/explore-dmp/explore-dmp-criteria';
@Injectable()
export class DmpService {
@ -40,6 +41,10 @@ export class DmpService {
return this.http.get<DmpModel>(this.actionUrl + id, { headers: this.headers }); //'getSingle/' +
}
getSinglePublic(id: String): Observable<DmpModel> {
return this.http.get<DmpModel>(this.actionUrl + 'public/' + id, { headers: this.headers });
}
unlock(id: String): Observable<DmpModel> {
return this.http.get<DmpModel>(this.actionUrl + id + '/unlock', { headers: this.headers });
}
@ -89,7 +94,6 @@ export class DmpService {
public uploadXml(fileList: FileList, dmpTitle: string): Observable<ContentType> {
const formData: FormData = new FormData();
//formData.append('file', fileList[0], dmpTitle);
if (fileList instanceof FileList) {
for (let i = 0; i < fileList.length; i++) {
formData.append('file', fileList[i], dmpTitle);
@ -103,4 +107,8 @@ export class DmpService {
};
return this.http.post(this.actionUrl + 'upload', formData, { params: params });
}
getPublicPaged(dataTableRequest: DataTableRequest<ExploreDmpCriteriaModel>): Observable<DataTableData<DmpListingModel>> {
return this.http.post<DataTableData<DmpListingModel>>(this.actionUrl + 'public/paged', dataTableRequest);
}
}

View File

@ -34,6 +34,13 @@ const routes: Routes = [
breadcrumb: true
},
},
{
path: 'publicEdit/:publicId',
component: DmpEditorComponent,
data: {
breadcrumb: true
},
},
{
path: 'new/project/:projectId',
component: DmpEditorComponent,
@ -77,4 +84,4 @@ const routes: Routes = [
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class DmpRoutingModule { }
export class DmpRoutingModule { }

View File

@ -25,19 +25,19 @@
</button>
</div>
<div class="col-auto">
<button mat-button type="button" (click)="redirectToDatasets()">
<button mat-button type="button" *ngIf="!isPublic" (click)="redirectToDatasets()">
<mat-icon>arrow_right_alt</mat-icon>
<span>{{'DMP-EDITOR.ACTIONS.GO-TO-DATASETS' | translate}}</span>
</button>
</div>
<mat-menu #actionsMenu="matMenu">
<button mat-menu-item (click)="newVersion(dmp.id, dmp.label)">
<button mat-menu-item *ngIf="!isPublic" (click)="newVersion(dmp.id, dmp.label)">
<mat-icon>queue</mat-icon>{{'DMP-LISTING.ACTIONS.NEW-VERSION' | translate}}
</button>
<button mat-menu-item (click)="clone(dmp.id)">
<button mat-menu-item *ngIf="!isPublic" (click)="clone(dmp.id)">
<mat-icon>filter_none</mat-icon>{{'DMP-LISTING.ACTIONS.CLONE' | translate}}
</button>
<button mat-menu-item (click)="viewVersions(dmp.groupId, dmp.label)">
<button mat-menu-item *ngIf="!isPublic" (click)="viewVersions(dmp.groupId, dmp.label)">
<mat-icon>library_books</mat-icon>{{'DMP-LISTING.ACTIONS.VIEW-VERSION' | translate}}
</button>
<button mat-menu-item (click)="downloadXml(dmp.id)">

View File

@ -39,6 +39,7 @@ import { AddResearcherComponent } from './add-researcher/add-researcher.componen
import { AvailableProfilesComponent } from './available-profiles/available-profiles.component';
import { DmpEditorModel } from './dmp-editor.model';
import { DmpFinalizeDialogComponent } from './dmp-finalize-dialog/dmp-finalize-dialog.component';
import { AuthService } from '../../../core/services/auth/auth.service';
@Component({
selector: 'app-dmp-editor-component',
@ -51,6 +52,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
breadCrumbs: Observable<BreadcrumbItem[]>;
isNew = true;
isPublic = false;
dmp: DmpEditorModel;
formGroup: FormGroup = null;
@ -86,7 +88,8 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
private dialog: MatDialog,
private _viewContainerRef: ViewContainerRef,
public languageResolverService: LanguageResolverService,
private uiNotificationService: UiNotificationService
private uiNotificationService: UiNotificationService,
private authService: AuthService,
) {
super();
}
@ -97,6 +100,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
.subscribe((params: Params) => {
const itemId = params['id'];
const projectId = params['projectId'];
const publicId = params['publicId'];
const projectRequestItem: RequestItem<ProjectCriteria> = new RequestItem();
projectRequestItem.criteria = new ProjectCriteria();
@ -147,14 +151,16 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
this.formGroup = this.dmp.buildForm();
this.registerFormEventsForDmpProfile(this.dmp.definition);
if (!this.editMode || this.dmp.status === Status.Inactive) { this.formGroup.disable(); }
this.breadCrumbs = Observable.of([
{
parentComponentName: 'DmpListingComponent',
label: 'DMPs',
url: 'plans',
notFoundResolver: [await this.projectService.getSingle(this.dmp.project.id).map(x => ({ label: x.label, url: '/projects/edit/' + x.id }) as BreadcrumbItem).toPromise()]
}]
);
if (!this.isAuthenticated) {
this.breadCrumbs = Observable.of([
{
parentComponentName: 'DmpListingComponent',
label: 'DMPs',
url: 'plans',
notFoundResolver: [await this.projectService.getSingle(this.dmp.project.id).map(x => ({ label: x.label, url: '/projects/edit/' + x.id }) as BreadcrumbItem).toPromise()]
}]
);
}
this.associatedUsers = data.associatedUsers;
});
} else if (projectId != null) {
@ -169,6 +175,29 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
this.formGroup.get('project').disable();
this.registerFormEventsForNewItem();
});
} else if (publicId != null) {
this.isNew = false;
this.isPublic = true;
this.dmpService.getSinglePublic(publicId).map(data => data as DmpModel)
.pipe(takeUntil(this._destroyed))
.subscribe(async data => {
this.dmp = new DmpEditorModel().fromModel(data);
this.formGroup = this.dmp.buildForm();
this.registerFormEventsForDmpProfile(this.dmp.definition);
if (!this.editMode || this.dmp.status === Status.Inactive) { this.formGroup.disable(); }
if (!this.isAuthenticated) {
this.breadCrumbs = Observable.of([
{
parentComponentName: 'DmpListingComponent',
label: 'DMPs',
url: 'plans',
notFoundResolver: [await this.projectService.getSingle(this.dmp.project.id).map(x => ({ label: x.label, url: '/projects/edit/' + x.id }) as BreadcrumbItem).toPromise()]
}]
);
this.associatedUsers = data.associatedUsers;
}
});
} else {
this.dmp = new DmpEditorModel();
this.formGroup = this.dmp.buildForm();
@ -203,6 +232,9 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
})
}
isAuthenticated() {
return this.authService.current() != null;
}
registerFormEventsForNewItem() {
this.breadCrumbs = Observable.of([

View File

@ -0,0 +1,20 @@
<div *ngIf="searchEnabled">
<mat-form-field>
<input type="text" placeholder="{{ 'FACET-SEARCH.FILTER' | translate }}" matInput [formControl]="optionSearchControl">
</mat-form-field>
</div>
<mat-chip-list *ngIf="searchEnabled">
<mat-chip [removable]="true" (removed)="removeOption(option)" *ngFor="let option of selectedOptions">{{
displayLabel(option) }}
<mat-icon matChipRemove>cancel</mat-icon>
</mat-chip>
</mat-chip-list>
<div class="data-expand-panel">
<mat-selection-list #optionsList (selectionChange)="selectionChanged($event)">
<mat-list-option class="facet-option-item" *ngFor="let option of (options | async)" [value]="option" [selected]="isOptionSelected(option)">
<p>{{ displayLabel(option) }}</p>
</mat-list-option>
</mat-selection-list>
</div>

View File

@ -0,0 +1,14 @@
.facet-option-item {
height: auto !important;
min-height: 48px;
padding: 0.5em;
.mat-list-item-content {
min-height: inherit;
}
}
.data-expand-panel{
max-height: 20em;
overflow-x: hidden;
overflow-y: auto;
}

View File

@ -0,0 +1,82 @@
import { SelectionModel } from '@angular/cdk/collections';
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { FormControl } from '@angular/forms';
import { MatListOption, MatSelectionList } from '@angular/material';
import { Observable } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { BaseComponent } from '../../../../core/common/base/base.component';
@Component({
selector: 'app-explore-dmp-filter-item-component',
templateUrl: './explore-dmp-filter-item.component.html',
styleUrls: ['./explore-dmp-filter-item.component.scss']
})
export class ExploreDmpFilterItemComponent extends BaseComponent implements OnInit {
@Input()
searchEnabled = false;
@Input()
requestDelay = 200;
@Input()
multipleSelect = true;
@Input()
filterOptions: (value) => Observable<any[]>;
@Input()
options: Observable<any[]> = Observable.of([]);
@Input()
displayTitleFunc: (value) => string;
@Input()
displayValueFunc: (value) => string;
@Output()
selectedChanged = new EventEmitter();
@Output()
optionRemoved = new EventEmitter();
optionSearchControl = new FormControl('');
private selectedOptions: any[] = [];
@ViewChild('optionsList') selectionList: MatSelectionList;
constructor() { super(); }
ngOnInit(): void {
if (!this.multipleSelect) { this.selectionList.selectedOptions = new SelectionModel<MatListOption>(this.multipleSelect); }
this.optionSearchControl.valueChanges.debounceTime(this.requestDelay)
.distinctUntilChanged()
.pipe(takeUntil(this._destroyed))
.subscribe(x => { if (this.filterOptions) { this.options = this.filterOptions(x); } });
}
public selectionChanged(event: any) {
const eventValue = event.option.value;
if (event.option.selected) { this.selectedOptions.push(eventValue); }
if (!event.option.selected) {
const index = this.selectedOptions.map(x => this.displayValue(x)).indexOf(this.displayValue(eventValue));
this.selectedOptions.splice(index, 1);
}
this.selectedChanged.emit(event);
}
public removeOption(project) {
const list = this.selectionList.selectedOptions.selected.map(x => x.value);
const indexOfProject = list.indexOf(project);
if (this.selectionList.selectedOptions.selected[indexOfProject]) {
this.selectionList.selectedOptions.selected[indexOfProject].selected = false;
this.selectionList.selectedOptions.selected.splice(indexOfProject, 1);
}
this.selectedOptions.splice(this.selectedOptions.map(x => this.displayValue(x)).indexOf(this.displayValue(project)), 1);
this.optionRemoved.emit(project);
}
public isOptionSelected(value) {
return this.selectedOptions.map(x => this.displayValue(x)).indexOf(this.displayValue(value)) !== -1;
}
displayLabel(value) {
return this.displayTitleFunc ? this.displayTitleFunc(value) : value;
}
displayValue(value) {
return this.displayValueFunc ? this.displayValueFunc(value) : value;
}
}

View File

@ -0,0 +1,56 @@
<mat-accordion #facetAccordion="matAccordion" [multi]="true" class="facet-search-component">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
{{ 'FACET-SEARCH.FILTER' | translate }}
</mat-panel-title>
</mat-expansion-panel-header>
<div>
<mat-form-field>
<input matInput placeholder="{{'CRITERIA.PROJECTS.LIKE'| translate}}" name="dmpCriteriaName" [(ngModel)]="facetCriteria.like"
(ngModelChange)="controlModified()">
</mat-form-field>
</div>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
{{ 'FACET-SEARCH.PROJECT-STATUS.TITLE' | translate }}
</mat-panel-title>
</mat-expansion-panel-header>
<app-explore-dmp-filter-item-component [multipleSelect]="false" [options]="this.projectStateOptions" (selectedChanged)="projectStatusChanged($event)"
[displayTitleFunc]="displayProjectStateLabel" [displayValueFunc]="displayProjectStateValue">
</app-explore-dmp-filter-item-component>
</mat-expansion-panel>
<mat-expansion-panel *ngIf="this.facetCriteria.projectStatus == ProjectStateType.OnGoing || this.facetCriteria.projectStatus == ProjectStateType.Finished">
<mat-expansion-panel-header>
<mat-panel-title>
{{ 'FACET-SEARCH.PROJECT.TITLE' | translate }}
</mat-panel-title>
</mat-expansion-panel-header>
<app-explore-dmp-filter-item-component [options]="this.projects" (selectedChanged)="projectChanged($event)" [filterOptions]="projectSearch.bind(this)"
[searchEnabled]="true" (optionRemoved)="removeProject($event)" [displayTitleFunc]="displayProjectLabel" [displayValueFunc]="displayProjectValue">
</app-explore-dmp-filter-item-component>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
{{ 'FACET-SEARCH.PROFILES.TITLE' | translate }}
</mat-panel-title>
</mat-expansion-panel-header>
<app-explore-dmp-filter-item-component [options]="this.profiles" (selectedChanged)="profileChanged($event)" [filterOptions]="profileSearch.bind(this)"
(optionRemoved)="removeProfile($event)" [displayTitleFunc]="displayProfileLabel" [displayValueFunc]="displayProfileValue">
</app-explore-dmp-filter-item-component>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
{{ 'FACET-SEARCH.DMP-ORGANISATIONS.TITLE' | translate }}
</mat-panel-title>
</mat-expansion-panel-header>
<app-explore-dmp-filter-item-component [options]="this.dmpOrganisations" (selectedChanged)="dmpOrganisationChanged($event)"
[filterOptions]="dmpOrganisationSearch.bind(this)" (optionRemoved)="removeOrganisation($event)" [searchEnabled]="true"
[displayTitleFunc]="displayDmpOrganisationsLabel" [displayValueFunc]="displayDmpOrganisationsValue">
</app-explore-dmp-filter-item-component>
</mat-expansion-panel>
</mat-accordion>

View File

@ -0,0 +1,9 @@
.facet-search-component {
.mat-form-field {
width: 100%;
}
.tags-chips {
padding: 0px;
}
}

View File

@ -0,0 +1,164 @@
import { BaseComponent } from "../../../core/common/base/base.component";
import { Component, AfterViewInit, OnInit, Input, EventEmitter, Output, ViewChild } from "@angular/core";
import { ExploreDmpCriteriaModel } from "../../../core/query/explore-dmp/explore-dmp-criteria";
import { MatAccordion } from "@angular/material";
import { ActivatedRoute } from "@angular/router";
import { TranslateService } from "@ngx-translate/core";
import { ExternalSourceItemModel } from "../../../core/model/external-sources/external-source-item";
import { Observable } from "rxjs";
import { ExternalSourcesService } from "../../../core/services/external-sources/external-sources.service";
import { ProjectListingModel } from "../../../core/model/project/project-listing";
import { ProjectService } from "../../../core/services/project/project.service";
import { ProjectCriteria } from "../../../core/query/project/project-criteria";
import { DataTableRequest } from "../../../core/model/data-table/data-table-request";
import { ProjectStateType } from '../../../core/common/enum/project-state-type';
import { DatasetService } from "../../../core/services/dataset/dataset.service";
import { DatasetProfileModel } from "../../../core/model/dataset/dataset-profile";
@Component({
selector: 'app-explore-dmp-filters-component',
templateUrl: './explore-dmp-filters.component.html',
styleUrls: ['./explore-dmp-filters.component.scss']
})
export class ExploreDmpFiltersComponent extends BaseComponent implements OnInit, AfterViewInit {
@Input() facetCriteria = new ExploreDmpCriteriaModel();
@Output() facetCriteriaChange = new EventEmitter();
ProjectStateType = ProjectStateType;
projects: Observable<ProjectListingModel[]>;
profiles: Observable<DatasetProfileModel[]>;
dmpOrganisations: Observable<ExternalSourceItemModel[]>;
projectOptions: Observable<ProjectListingModel[]>;
projectStateOptions: Observable<any[]>;
@ViewChild('facetAccordion') accordion: MatAccordion;
displayProjectStateValue = (option) => option['value'];
displayProjectStateLabel = (option) => option['label'];
displayProjectValue = (option) => option['id'];
displayProjectLabel = (option) => option['label'];
displayProfileValue = (option) => option['id'];
displayProfileLabel = (option) => option['label'];
displayDmpOrganisationsValue = (option) => option['id'];
displayDmpOrganisationsLabel = (option) => option['name'];
constructor(
public activatedRoute: ActivatedRoute,
public languageService: TranslateService,
public projectService: ProjectService,
public datasetProfileService: DatasetService,
public externalSourcesService: ExternalSourcesService,
) { super(); }
ngOnInit() {
setTimeout(x => {
this.projectStateOptions = Observable.of(
[
{ label: this.languageService.instant('FACET-SEARCH.PROJECT-STATUS.OPTIONS.INACTIVE'), value: ProjectStateType.Finished },
{ label: this.languageService.instant('FACET-SEARCH.PROJECT-STATUS.OPTIONS.ACTIVE'), value: ProjectStateType.OnGoing },
]);
});
this.profiles = this.datasetProfileService.getDatasetProfiles();
this.dmpOrganisations = this.externalSourcesService.searchDMPOrganizations('');
}
ngAfterViewInit(): void {
this.accordion.openAll();
}
controlModified() {
this.facetCriteriaChange.emit(this.facetCriteria);
}
projectSearch(value: string): Observable<ProjectListingModel[]> {
const projectCriteria = new ProjectCriteria();
projectCriteria.projectStateType = this.facetCriteria.projectStatus;
projectCriteria['length'] = 10;
projectCriteria.like = value;
const fields: Array<string> = new Array<string>();
fields.push('asc');
const dataTableRequest: DataTableRequest<ProjectCriteria> = new DataTableRequest(0, null, { fields: fields });
dataTableRequest.criteria = projectCriteria;
return this.projectService.getPublicPaged(dataTableRequest).map(x => x.data);
}
projectStatusChanged(event) {
this.facetCriteria.projectStatus = event.option.value.value;
if (!event.option.selected) {
this.facetCriteria.projectStatus = null;
this.projects = Observable.of([]);
this.facetCriteria.projects = [];
}
if (event.option.selected) {
const fields: Array<string> = new Array<string>();
fields.push('asc');
const dataTableRequest: DataTableRequest<ProjectCriteria> = new DataTableRequest(0, null, { fields: fields });
dataTableRequest.criteria = new ProjectCriteria();
dataTableRequest.criteria.projectStateType = this.facetCriteria.projectStatus;
dataTableRequest.criteria['length'] = 10;
this.projects = this.projectService.getPublicPaged(dataTableRequest).map(x => x.data);
this.facetCriteria.projects = [];
}
this.facetCriteriaChange.emit(this.facetCriteria);
}
projectChanged(event: any) {
const eventValue = event.option.value.id;
if (event.option.selected) { this.facetCriteria.projects.push(eventValue); }
if (!event.option.selected) {
const index = this.facetCriteria.projects.indexOf(eventValue);
this.facetCriteria.projects.splice(index, 1);
}
this.facetCriteriaChange.emit(this.facetCriteria);
}
removeProject(project) {
this.facetCriteria.projects.splice(this.facetCriteria.projects.indexOf(project), 1);
this.facetCriteriaChange.emit(this.facetCriteria);
}
profileChanged(event: any) {
const eventValue = event.option.value.id;
if (event.option.selected) {
this.facetCriteria.datasetProfile.push(eventValue);
}
if (!event.option.selected) {
const index = this.facetCriteria.datasetProfile.indexOf(eventValue);
this.facetCriteria.datasetProfile.splice(index, 1);
}
this.facetCriteriaChange.emit(this.facetCriteria);
}
removeProfile(profile) {
this.facetCriteria.datasetProfile.splice(this.facetCriteria.datasetProfile.indexOf(profile), 1);
this.facetCriteriaChange.emit(this.facetCriteria);
}
dmpOrganisationChanged(event: any) {
const eventValue = event.option.value.id;
if (event.option.selected) { this.facetCriteria.dmpOrganisations.push(eventValue); }
if (!event.option.selected) {
const index = this.facetCriteria.dmpOrganisations.indexOf(eventValue);
this.facetCriteria.dmpOrganisations.splice(index, 1);
}
this.facetCriteriaChange.emit(this.facetCriteria);
}
profileSearch(value: string) {
return this.datasetProfileService.getDatasetProfiles();
}
dmpOrganisationSearch(value: string): Observable<ExternalSourceItemModel[]> {
return this.externalSourcesService.searchDMPOrganizations(value);
}
removeOrganisation(organisation) {
this.facetCriteria.dmpOrganisations.splice(this.facetCriteria.dmpOrganisations.indexOf(organisation), 1);
this.facetCriteriaChange.emit(this.facetCriteria);
}
}

View File

@ -0,0 +1,48 @@
<div class="main-content">
<div class="container-fluid">
<div class="explore-dmp">
<h3 class="text-center">{{'DMP-PUBLIC-LISTING.TITLE' | translate}} {{titlePrefix}}</h3>
<div class="row">
<div class="col-md-3">
<app-explore-dmp-filters-component (facetCriteriaChange)="onCriteriaChange($event)"></app-explore-dmp-filters-component>
</div>
<div class="col-md-9">
<mat-card class="mat-card">
<mat-table [dataSource]="dataSource" matSort (matSortChange)="refresh()">
<!-- Column Definition: Name -->
<ng-container cdkColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header="label">{{'DMP-LISTING.COLUMNS.NAME' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.label}}</mat-cell>
</ng-container>
<!-- Column Definition: Dmp -->
<ng-container cdkColumnDef="project">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.PROJECT' | translate}}
</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.project}} </mat-cell>
</ng-container>
<!-- Column Definition: Organisations -->
<ng-container cdkColumnDef="organisations">
<mat-header-cell *matHeaderCellDef>{{'DMP-LISTING.COLUMNS.ORGANISATIONS' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.organisations}} </mat-cell>
</ng-container>
<!-- Column Definition: Created -->
<ng-container cdkColumnDef="created">
<mat-header-cell *matHeaderCellDef mat-sort-header="created">{{'DMP-LISTING.COLUMNS.CREATION-TIME' | translate}}
</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.creationTime | date:'shortDate'}}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns" (click)="rowClick(row.id)"></mat-row>
</mat-table>
<mat-paginator #paginator [length]="dataSource?.totalCount" [pageSizeOptions]="[10, 25, 100]">
</mat-paginator>
</mat-card>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,3 @@
text-center{
text-align: center
}

View File

@ -0,0 +1,106 @@
import { BaseComponent } from "../../core/common/base/base.component";
import { Component, OnInit, ViewChild } from "@angular/core";
import { Router, ActivatedRoute } from "@angular/router";
import { MatPaginator, MatSort, MatSnackBar, PageEvent } from "@angular/material";
import { DataSource } from "@angular/cdk/collections";
import { DmpListingModel } from "../../core/model/dmp/dmp-listing";
import { TranslateService } from "@ngx-translate/core";
import { Observable } from "rxjs";
import { DmpService } from "../../core/services/dmp/dmp.service";
import { ExploreDmpCriteriaModel } from "../../core/query/explore-dmp/explore-dmp-criteria";
import { DataTableRequest } from "../../core/model/data-table/data-table-request";
import { DmpCriteria } from "../../core/query/dmp/dmp-criteria";
@Component({
selector: 'app-explore-dmp-listing-component',
templateUrl: 'explore-dmp-listing.component.html',
styleUrls: ['./explore-dmp-listing.component.scss'],
})
export class ExploreDmpListingComponent extends BaseComponent implements OnInit {
@ViewChild(MatPaginator) _paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
criteria: ExploreDmpCriteriaModel = new ExploreDmpCriteriaModel();
dataSource: DmpDataSource | null;
displayedColumns: String[] = ['name', 'project', 'organisations', 'created'];
pageEvent: PageEvent;
titlePrefix: String;
dmpId: string;
constructor(
public dmpService: DmpService,
private router: Router,
private languageService: TranslateService,
public snackBar: MatSnackBar,
public route: ActivatedRoute
) {
super();
}
ngOnInit() {
this.refresh();
}
rowClick(rowId: String) {
this.router.navigate(['/plans/publicEdit/' + rowId]);
}
refresh() {
this.dataSource = new DmpDataSource(this.dmpService, this._paginator, this.sort, this.languageService, this.snackBar, this.criteria);
}
getDefaultCriteria(dmpId: String): DmpCriteria {
const defaultCriteria = new DmpCriteria();
return defaultCriteria;
}
onCriteriaChange(event: ExploreDmpCriteriaModel) {
//console.log(event)
this.criteria = event;
this.refresh();
}
}
export class DmpDataSource extends DataSource<DmpListingModel> {
totalCount = 0;
constructor(
private _service: DmpService,
private _paginator: MatPaginator,
private _sort: MatSort,
private _languageService: TranslateService,
private _snackBar: MatSnackBar,
private _criteria: ExploreDmpCriteriaModel,
) {
super();
}
connect(): Observable<DmpListingModel[]> {
const displayDataChanges = [
this._paginator.page
];
return Observable.merge(...displayDataChanges)
.startWith(null)
.switchMap(() => {
const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
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<ExploreDmpCriteriaModel>(startIndex, this._paginator.pageSize, { fields: fields });
request.criteria = this._criteria;
//if (this.dmpId) request.criteria.allVersions = true;
return this._service.getPublicPaged(request);
})
.map(result => {
if (!result) { return []; }
if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; }
return result.data;
});
}
disconnect(): void {
// No-op
}
}

View File

@ -0,0 +1,23 @@
import { NgModule } from "@angular/core";
import { CommonUiModule } from "../../common/ui/common-ui.module";
import { CommonFormsModule } from "../../common/forms/common-forms.module";
import { AutoCompleteModule } from "../../library/auto-complete/auto-complete.module";
import { ExploreDmpListingComponent } from "./explore-dmp-listing.component";
import { ExploreDmpRoutingModule } from "./explore-dmp.routing";
import { ExploreDmpFiltersComponent } from "./dmp-explore-filters/explore-dmp-filters.component";
import { ExploreDmpFilterItemComponent } from "./dmp-explore-filters/explore-dmp-filter-item/explore-dmp-filter-item.component";
@NgModule({
imports: [
CommonUiModule,
CommonFormsModule,
AutoCompleteModule,
ExploreDmpRoutingModule
],
declarations: [
ExploreDmpListingComponent,
ExploreDmpFiltersComponent,
ExploreDmpFilterItemComponent
]
})
export class ExploreDmpModule {}

View File

@ -0,0 +1,19 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ExploreDmpListingComponent } from './explore-dmp-listing.component';
const routes: Routes = [
{
path: '',
component: ExploreDmpListingComponent,
data: {
breadcrumb: true
},
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ExploreDmpRoutingModule { }

View File

@ -26,7 +26,8 @@ export const DMP_ROUTES: RouteInfo[] = [
// ];
export const PUBLIC_ROUTES: RouteInfo[] = [
// { path: '/maps', title: 'PUBLIC DMPs', icon: 'public'},
{ path: '/explore', title: 'PUBLIC DATASET DESCRIPTIONS', icon: 'public'}
{ path: '/explore', title: 'PUBLIC DATASET DESCRIPTIONS', icon: 'public'},
{ path: '/exploreplans', title: 'PUBLIC DATASET PLANS ', icon: 'public'}
];
@Component({
@ -51,6 +52,7 @@ export class SidebarComponent implements OnInit {
// this.translate.get('SIDE-BAR.HISTORY-VISITED').subscribe((res: string) => {HISTORY_ROUTES[0].title = res});
// this.translate.get('SIDE-BAR.HISTORY-EDITED').subscribe((res: string) => {HISTORY_ROUTES[1].title = res});
this.translate.get('SIDE-BAR.PUBLIC-DESC').subscribe((res: string) => {PUBLIC_ROUTES[0].title = res});
this.translate.get('SIDE-BAR.PUBLIC-DMPS').subscribe((res: string) => {PUBLIC_ROUTES[1].title = res});
this.generalItems = {
title: '',
routes: GENERAL_ROUTES.filter(menuItem => menuItem)

View File

@ -238,6 +238,9 @@
"DOWNLOAD-PDF": "Download PDF"
}
},
"DMP-PUBLIC-LISTING": {
"TITLE": "Published Dataset Managment Plans"
},
"DMP-UPLOAD": {
"TITLE": "Import Data Managment Plan",
"UPLOAD-BUTTON": "Upload",
@ -463,7 +466,7 @@
"CRITERIA": {
"FILTERS": "Filters",
"PROJECTS": {
"LIKE": "Search Projects",
"LIKE": "Search",
"PERIOD-FROM": "Project Start",
"PERIOD-TO": "Project End",
"PROJECT-STATE-TYPE": "Project Status",
@ -595,7 +598,8 @@
},
"DATASET-PROFILE-COMBO-BOX-TYPE": {
"WORD-LIST": "Word List",
"AUTOCOMPLETE": "Autocomplete"
"AUTOCOMPLETE": "Autocomplete",
"EXTERNAL-SOURCE-HINT": "External source"
}
},
"ADDRESEARCHERS-EDITOR": {