#8845 - #8846: adding description template types, creation of description template type field in the dataset template editor, [wip] creation of admin page for creation/editing/deleting of description template types

This commit is contained in:
Bernaldo Mihasi 2023-07-25 15:27:15 +03:00
parent bc279b1610
commit 128b47d9c3
27 changed files with 816 additions and 5 deletions

View File

@ -0,0 +1,10 @@
package eu.eudat.data.dao.entities;
import eu.eudat.data.dao.DatabaseAccessLayer;
import eu.eudat.data.entities.DescriptionTemplateType;
import java.util.UUID;
public interface DescriptionTemplateTypeDao extends DatabaseAccessLayer<DescriptionTemplateType, UUID> {
DescriptionTemplateType findFromName(String name);
}

View File

@ -0,0 +1,61 @@
package eu.eudat.data.dao.entities;
import eu.eudat.data.dao.DatabaseAccess;
import eu.eudat.data.dao.databaselayer.service.DatabaseService;
import eu.eudat.data.entities.DescriptionTemplateType;
import eu.eudat.data.entities.EntityDoi;
import eu.eudat.queryable.QueryableList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.transaction.Transactional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@Component("descriptionTemplateTypeDao")
public class DescriptionTemplateTypeDaoImpl extends DatabaseAccess<DescriptionTemplateType> implements DescriptionTemplateTypeDao {
@Autowired
public DescriptionTemplateTypeDaoImpl(DatabaseService<DescriptionTemplateType> databaseService) {
super(databaseService);
}
@Override
public DescriptionTemplateType findFromName(String name){
return this.getDatabaseService().getQueryable(DescriptionTemplateType.class).where((builder, root) -> builder.equal(root.get("name"), name)).getSingle();
}
@Override
@Transactional
public DescriptionTemplateType createOrUpdate(DescriptionTemplateType item) {
return this.getDatabaseService().createOrUpdate(item, DescriptionTemplateType.class);
}
@Override
public DescriptionTemplateType find(UUID id) {
return getDatabaseService().getQueryable(DescriptionTemplateType.class).where((builder, root) -> builder.equal((root.get("id")), id)).getSingle();
}
@Override
public void delete(DescriptionTemplateType item) {
this.getDatabaseService().delete(item);
}
@Override
public QueryableList<DescriptionTemplateType> asQueryable() {
return this.getDatabaseService().getQueryable(DescriptionTemplateType.class);
}
@Async
@Override
public CompletableFuture<DescriptionTemplateType> createOrUpdateAsync(DescriptionTemplateType item) {
return CompletableFuture.supplyAsync(() -> this.createOrUpdate(item));
}
@Override
public DescriptionTemplateType find(UUID id, String hint) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,52 @@
package eu.eudat.data.entities;
import eu.eudat.queryable.queryableentity.DataEntity;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.util.List;
import java.util.UUID;
@Entity
@Table(name = "\"DescriptionTemplateType\"")
public class DescriptionTemplateType implements DataEntity<DescriptionTemplateType, UUID> {
@Id
@GeneratedValue
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Column(name = "\"ID\"", updatable = false, nullable = false, columnDefinition = "BINARY(16)")
private UUID id;
@Column(name = "\"Name\"", nullable = false)
private String name;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void update(DescriptionTemplateType entity) {
this.name = entity.name;
}
@Override
public UUID getKeys() {
return this.id;
}
@Override
public DescriptionTemplateType buildFromTuple(List<Tuple> tuple, List<String> fields, String base) {
this.id = UUID.fromString((String) tuple.get(0).get(!base.isEmpty() ? base + "." + "id" : "id"));
return this;
}
}

View File

@ -61,6 +61,7 @@ public class Admin extends BaseController {
//this.getLoggerService().info(principal, "Admin Added Dataset Profile"); //this.getLoggerService().info(principal, "Admin Added Dataset Profile");
DatasetProfile shortenProfile = profile.toShort(); DatasetProfile shortenProfile = profile.toShort();
DescriptionTemplate modelDefinition = AdminManager.generateViewStyleDefinition(shortenProfile, getApiContext()); DescriptionTemplate modelDefinition = AdminManager.generateViewStyleDefinition(shortenProfile, getApiContext());
modelDefinition.setType(getApiContext().getOperationsContext().getDatabaseRepository().getDescriptionTemplateTypeDao().findFromName(profile.getType()));
modelDefinition.setGroupId(UUID.randomUUID()); modelDefinition.setGroupId(UUID.randomUUID());
modelDefinition.setVersion((short) 0); modelDefinition.setVersion((short) 0);

View File

@ -0,0 +1,64 @@
package eu.eudat.controllers;
import eu.eudat.data.entities.DescriptionTemplateType;
import eu.eudat.exceptions.descriptiontemplate.DescriptionTemplatesWithTypeException;
import eu.eudat.logic.managers.DescriptionTemplateTypeManager;
import eu.eudat.logic.security.claims.ClaimedAuthorities;
import eu.eudat.logic.services.ApiContext;
import eu.eudat.models.data.helpers.common.DataTableData;
import eu.eudat.models.data.helpers.responses.ResponseItem;
import eu.eudat.models.data.security.Principal;
import eu.eudat.types.ApiMessageCode;
import eu.eudat.types.Authorities;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.transaction.Transactional;
import java.util.UUID;
import static eu.eudat.types.Authorities.ADMIN;
@RestController
@CrossOrigin
@RequestMapping(value = {"/api/descriptionTemplateType/"})
public class DescriptionTemplateTypeController extends BaseController {
private DescriptionTemplateTypeManager descriptionTemplateTypeManager;
@Autowired
public DescriptionTemplateTypeController(ApiContext apiContext, DescriptionTemplateTypeManager descriptionTemplateTypeManager){
super(apiContext);
this.descriptionTemplateTypeManager = descriptionTemplateTypeManager;
}
@Transactional
@RequestMapping(method = RequestMethod.POST, value = {"create"}, produces = "application/json")
public @ResponseBody
ResponseEntity<ResponseItem<DescriptionTemplateType>> createOrUpdate(@RequestBody String type, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) throws Exception {
this.descriptionTemplateTypeManager.create(type);
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<DescriptionTemplateType>().status(ApiMessageCode.SUCCESS_MESSAGE).message("Created"));
}
@RequestMapping(method = RequestMethod.GET, value = {"get"}, produces = "application/json")
public @ResponseBody
ResponseEntity<ResponseItem<DataTableData<DescriptionTemplateType>>> get(@ClaimedAuthorities(claims = {Authorities.ADMIN, Authorities.MANAGER, Authorities.USER, Authorities.ANONYMOUS}) Principal principal) throws Exception {
DataTableData<DescriptionTemplateType> dataTable = this.descriptionTemplateTypeManager.get();
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<DataTableData<DescriptionTemplateType>>().status(ApiMessageCode.NO_MESSAGE).payload(dataTable));
}
@Transactional
@RequestMapping(method = RequestMethod.DELETE, value = {"/delete/{id}"}, produces = "application/json")
public @ResponseBody
ResponseEntity<ResponseItem<DescriptionTemplateType>> delete(@PathVariable(value = "id") UUID id, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) throws Exception {
try{
this.descriptionTemplateTypeManager.delete(id);
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<DescriptionTemplateType>().status(ApiMessageCode.SUCCESS_MESSAGE).message("Deleted"));
}
catch(DescriptionTemplatesWithTypeException e){
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem<DescriptionTemplateType>().status(ApiMessageCode.UNSUCCESS_DELETE).message(e.getMessage()));
}
}
}

View File

@ -0,0 +1,9 @@
package eu.eudat.exceptions.descriptiontemplate;
public class DescriptionTemplatesWithTypeException extends RuntimeException {
public DescriptionTemplatesWithTypeException(String message) {
super(message);
}
}

View File

@ -0,0 +1,61 @@
package eu.eudat.logic.managers;
import eu.eudat.data.entities.DescriptionTemplateType;
import eu.eudat.exceptions.descriptiontemplate.DescriptionTemplatesWithTypeException;
import eu.eudat.logic.services.ApiContext;
import eu.eudat.logic.services.operations.DatabaseRepository;
import eu.eudat.models.data.helpers.common.DataTableData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.UUID;
@Component
public class DescriptionTemplateTypeManager {
private static final Logger logger = LoggerFactory.getLogger(DescriptionTemplateTypeManager.class);
private ApiContext apiContext;
private DatabaseRepository databaseRepository;
@Autowired
public DescriptionTemplateTypeManager(ApiContext apiContext, DatabaseRepository databaseRepository) {
this.apiContext = apiContext;
this.databaseRepository = databaseRepository;
}
public DataTableData<DescriptionTemplateType> get() {
List<DescriptionTemplateType> types = this.databaseRepository.getDescriptionTemplateTypeDao().asQueryable().toList();
DataTableData<DescriptionTemplateType> dataTableData = new DataTableData<>();
dataTableData.setData(types);
dataTableData.setTotalCount((long) types.size());
return dataTableData;
}
public DescriptionTemplateType create(String name) {
DescriptionTemplateType type = this.databaseRepository.getDescriptionTemplateTypeDao().findFromName(name);
if (type == null) {
type = new DescriptionTemplateType();
type.setId(UUID.randomUUID());
type.setName(name);
this.databaseRepository.getDescriptionTemplateTypeDao().createOrUpdate(type);
}
return type;
}
public void delete(UUID id) throws DescriptionTemplatesWithTypeException {
DescriptionTemplateType type = this.databaseRepository.getDescriptionTemplateTypeDao().find(id);
if (type != null) {
Long descriptionsWithType = this.databaseRepository.getDatasetProfileDao().countWithType(type.getId());
if(descriptionsWithType == 0) {
this.databaseRepository.getDescriptionTemplateTypeDao().delete(type);
}
else{
throw new DescriptionTemplatesWithTypeException("This type can not deleted, because Descriptions are associated with it");
}
}
}
}

View File

@ -62,5 +62,7 @@ public interface DatabaseRepository {
EntityDoiDao getEntityDoiDao(); EntityDoiDao getEntityDoiDao();
DescriptionTemplateTypeDao getDescriptionTemplateTypeDao();
<T> void detachEntity(T entity); <T> void detachEntity(T entity);
} }

View File

@ -40,6 +40,7 @@ public class DatabaseRepositoryImpl implements DatabaseRepository {
private NotificationDao notificationDao; private NotificationDao notificationDao;
private FileUploadDao fileUploadDao; private FileUploadDao fileUploadDao;
private EntityDoiDao entityDoiDao; private EntityDoiDao entityDoiDao;
private DescriptionTemplateTypeDao descriptionTemplateTypeDao;
private EntityManager entityManager; private EntityManager entityManager;
@ -328,6 +329,16 @@ public class DatabaseRepositoryImpl implements DatabaseRepository {
this.entityDoiDao = entityDoiDao; this.entityDoiDao = entityDoiDao;
} }
@Override
public DescriptionTemplateTypeDao getDescriptionTemplateTypeDao() {
return descriptionTemplateTypeDao;
}
@Autowired
public void setDescriptionTemplateTypeDao(DescriptionTemplateTypeDao descriptionTemplateTypeDao) {
this.descriptionTemplateTypeDao = descriptionTemplateTypeDao;
}
public <T> void detachEntity(T entity) { public <T> void detachEntity(T entity) {
this.entityManager.detach(entity); this.entityManager.detach(entity);
} }

View File

@ -13,6 +13,7 @@ import java.util.List;
public class DatasetProfile { public class DatasetProfile {
private String label; private String label;
private String description; private String description;
private String type;
private List<Page> pages; private List<Page> pages;
private List<Section> sections; private List<Section> sections;
private Short status; private Short status;
@ -35,6 +36,13 @@ public class DatasetProfile {
this.description = description; this.description = description;
} }
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<Page> getPages() { public List<Page> getPages() {
return pages; return pages;
} }
@ -80,6 +88,7 @@ public class DatasetProfile {
DatasetProfile shortProfile = new DatasetProfile(); DatasetProfile shortProfile = new DatasetProfile();
shortProfile.setLabel(this.label); shortProfile.setLabel(this.label);
shortProfile.setDescription(this.description); shortProfile.setDescription(this.description);
shortProfile.setType(this.type);
List<Section> shortSection = new LinkedList<>(); List<Section> shortSection = new LinkedList<>();
for (Section toshortSection : this.getSections()) { for (Section toshortSection : this.getSections()) {
shortSection.add(toshortSection.toShort()); shortSection.add(toshortSection.toShort());

View File

@ -99,6 +99,14 @@ const appRoutes: Routes = [
title: 'GENERAL.TITLES.DATASET-PROFILES' title: 'GENERAL.TITLES.DATASET-PROFILES'
} }
}, },
{
path: 'description-types',
loadChildren: () => import('./ui/admin/description-types/description-types.module').then(m => m.DescriptionTypesModule),
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.DESCRIPTION-TYPES'
}
},
{ {
path: 'contact-support', path: 'contact-support',
loadChildren: () => import('./ui/contact/contact.module').then(m => m.ContactModule), loadChildren: () => import('./ui/contact/contact.module').then(m => m.ContactModule),

View File

@ -52,6 +52,7 @@ import { FaqService } from './services/faq/faq.service';
import { GlossaryService } from './services/glossary/glossary.service'; import { GlossaryService } from './services/glossary/glossary.service';
import { TermsOfServiceService } from './services/terms-of-service/terms-of-service.service'; import { TermsOfServiceService } from './services/terms-of-service/terms-of-service.service';
import { UnlinkAccountEmailConfirmationService } from './services/unlink-account-email-confirmation/unlink-account-email-confirmation.service'; import { UnlinkAccountEmailConfirmationService } from './services/unlink-account-email-confirmation/unlink-account-email-confirmation.service';
import { DescriptionTemplateTypeService } from './services/description-template-type/description-template-type.service';
// //
// //
// This is shared module that provides all the services. Its imported only once on the AppModule. // This is shared module that provides all the services. Its imported only once on the AppModule.
@ -132,7 +133,8 @@ export class CoreServiceModule {
multi: true multi: true
}, },
LanguageInfoService, LanguageInfoService,
PrefillingService PrefillingService,
DescriptionTemplateTypeService
], ],
}; };
} }

View File

@ -3,6 +3,7 @@ import { UserInfoListingModel } from "../../user/user-info-listing";
export interface DatasetProfile { export interface DatasetProfile {
label: string; label: string;
type: string;
sections: Section[]; sections: Section[];
pages: Page[]; pages: Page[];
status: number; status: number;

View File

@ -0,0 +1,4 @@
export interface DescriptionTemplateType {
id: string;
name: string;
}

View File

@ -0,0 +1,30 @@
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ConfigurationService } from '../configuration/configuration.service';
import { BaseHttpService } from '../http/base-http.service';
import { Observable } from 'rxjs';
import { DataTableData } from '@app/core/model/data-table/data-table-data';
import { DescriptionTemplateType } from '@app/core/model/description-template-type/description-template-type';
@Injectable()
export class DescriptionTemplateTypeService {
private actionUrl: string;
private headers = new HttpHeaders();
constructor(private http: BaseHttpService, private httpClient: HttpClient, private configurationService: ConfigurationService) {
this.actionUrl = configurationService.server + 'descriptionTemplateType/';
}
getTypes(): Observable<DataTableData<DescriptionTemplateType>> {
return this.http.get<DataTableData<DescriptionTemplateType>>(this.actionUrl + 'get', { headers: this.headers });
}
createType(name: string): Observable<DescriptionTemplateType> {
return this.http.post<DescriptionTemplateType>(this.actionUrl + 'create', name, { headers: this.headers });
}
deleteType(id: string): Observable<DescriptionTemplateType> {
return this.http.delete<DescriptionTemplateType>(this.actionUrl + 'delete/' + id, { headers: this.headers });
}
}

View File

@ -15,6 +15,7 @@ export class DatasetProfileEditorModel extends BaseFormModel {
public status: number; public status: number;
public version: number; public version: number;
private description: string; private description: string;
private type: string;
private language: string; private language: string;
private users: UserInfoListingModel[] = []; private users: UserInfoListingModel[] = [];
@ -22,6 +23,7 @@ export class DatasetProfileEditorModel extends BaseFormModel {
if (item.sections) { this.sections = item.sections.map(x => new SectionEditorModel().fromModel(x)); } if (item.sections) { this.sections = item.sections.map(x => new SectionEditorModel().fromModel(x)); }
if (item.pages) { this.pages = item.pages.map(x => new PageEditorModel().fromModel(x)); } if (item.pages) { this.pages = item.pages.map(x => new PageEditorModel().fromModel(x)); }
this.label = item.label; this.label = item.label;
this.type = item.type;
this.status = item.status; this.status = item.status;
this.version = item.version; this.version = item.version;
this.description = item.description; this.description = item.description;
@ -34,6 +36,7 @@ export class DatasetProfileEditorModel extends BaseFormModel {
const formGroup: FormGroup = new FormBuilder().group({ const formGroup: FormGroup = new FormBuilder().group({
label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('DatasetProfileEditorModel.label')) }, [Validators.required]], label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('DatasetProfileEditorModel.label')) }, [Validators.required]],
description: [{ value: this.description, disabled: (disabled && !skipDisable.includes('DatasetProfileEditorModel.description')) }, [Validators.required]], description: [{ value: this.description, disabled: (disabled && !skipDisable.includes('DatasetProfileEditorModel.description')) }, [Validators.required]],
type: [{ value: this.type, disabled: (disabled && !skipDisable.includes('DatasetProfileEditorModel.type')) }, [Validators.required]],
language: [{ value: this.language, disabled: (disabled && !skipDisable.includes('DatasetProfileEditorModel.language')) }, [Validators.required]], language: [{ value: this.language, disabled: (disabled && !skipDisable.includes('DatasetProfileEditorModel.language')) }, [Validators.required]],
status: [{ value: this.status, disabled: (disabled && !skipDisable.includes('DatasetProfileEditorModel.status')) }], status: [{ value: this.status, disabled: (disabled && !skipDisable.includes('DatasetProfileEditorModel.status')) }],
version: [{ value: this.version, disabled: (disabled && !skipDisable.includes('DatasetProfileEditorModel.version')) }], version: [{ value: this.version, disabled: (disabled && !skipDisable.includes('DatasetProfileEditorModel.version')) }],

View File

@ -142,8 +142,21 @@
</div> </div>
<div class="col-12"> <div class="col-12">
<!-- <div class="heading">1.3 {{'DMP-EDITOR.FIELDS.LANGUAGE' | translate}}</div> --> <div class="heading">1.3 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DESCRIPTION-TEMPLATE-TYPE'| translate}} *</div>
<div class="heading">1.3 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-LANGUAGE'| translate}} *</div> <mat-form-field class="full-width basic-info-input">
<mat-select [formControl]="form.get('type')" placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DESCRIPTION-TEMPLATE-SELECT-TYPE'| translate}}">
<mat-option *ngFor="let type of descriptionTemplateTypes" [value]="type.name">
{{ type.name }}
</mat-option>
</mat-select>
<mat-error *ngIf="form.get('type').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' |
translate}}
</mat-error>
</mat-form-field>
</div>
<div class="col-12">
<!-- <div class="heading">1.4 {{'DMP-EDITOR.FIELDS.LANGUAGE' | translate}}</div> -->
<div class="heading">1.4 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-LANGUAGE'| translate}} *</div>
<mat-form-field class="full-width basic-info-input"> <mat-form-field class="full-width basic-info-input">
<!-- <input matInput formControlName="description" placeholder="{{'DATASET-PROFILE-EDITOR.FIELDS.DATASET-DESCRIPTION' | translate}}" required> --> <!-- <input matInput formControlName="description" placeholder="{{'DATASET-PROFILE-EDITOR.FIELDS.DATASET-DESCRIPTION' | translate}}" required> -->
<mat-select [formControl]="form.get('language')" placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-SELECT-LANGUAGE'| translate}}"> <mat-select [formControl]="form.get('language')" placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-SELECT-LANGUAGE'| translate}}">
@ -157,7 +170,7 @@
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-12"> <div class="col-12">
<div class="heading">1.4 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-USERS'| translate}}</div> <div class="heading">1.5 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-USERS'| translate}}</div>
<div class="hint">{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-USERS-HINT'| translate}}</div> <div class="hint">{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-USERS-HINT'| translate}}</div>
<div class="full-width basic-info-input"> <div class="full-width basic-info-input">
<table class="col-12 user-table"> <table class="col-12 user-table">

View File

@ -45,6 +45,8 @@ import { DatasetProfileComboBoxType } from '@app/core/common/enum/dataset-profil
import { UserService } from '@app/core/services/user/user.service'; import { UserService } from '@app/core/services/user/user.service';
import { MatInput } from '@angular/material/input'; import { MatInput } from '@angular/material/input';
import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component'; import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component';
import { DescriptionTemplateTypeService } from '@app/core/services/description-template-type/description-template-type.service';
import { DescriptionTemplateType } from '@app/core/model/description-template-type/description-template-type';
const skipDisable: any[] = require('../../../../../assets/resources/skipDisable.json'); const skipDisable: any[] = require('../../../../../assets/resources/skipDisable.json');
@ -80,6 +82,7 @@ export class DatasetProfileEditorComponent extends CheckDeactivateBaseComponent
tocEntryEnumValues = ToCEntryType; tocEntryEnumValues = ToCEntryType;
public userChipList:any[] = []; public userChipList:any[] = [];
displayedColumns: String[] = ['name', 'email', 'button']; displayedColumns: String[] = ['name', 'email', 'button'];
descriptionTemplateTypes: DescriptionTemplateType[] = [];
colorizeInvalid:boolean = false; colorizeInvalid:boolean = false;
inputUserState: 'untriggered'| 'triggered' = 'untriggered'; inputUserState: 'untriggered'| 'triggered' = 'untriggered';
@ -112,7 +115,8 @@ export class DatasetProfileEditorComponent extends CheckDeactivateBaseComponent
private visibilityRulesService: VisibilityRulesService, private visibilityRulesService: VisibilityRulesService,
private fb: FormBuilder, private fb: FormBuilder,
private sidenavService: SideNavService, private sidenavService: SideNavService,
private userService: UserService private userService: UserService,
private descriptionTemplateTypeService: DescriptionTemplateTypeService
) { ) {
super(); super();
// this.profileID = route.snapshot.params['id']; // this.profileID = route.snapshot.params['id'];
@ -227,6 +231,7 @@ export class DatasetProfileEditorComponent extends CheckDeactivateBaseComponent
} }
}); });
this.getDescriptionTemplateTypes();
combineLatest(this._inputUserButton$.asObservable(),this._inputUserField$.asObservable()) combineLatest(this._inputUserButton$.asObservable(),this._inputUserField$.asObservable())
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
@ -600,6 +605,14 @@ export class DatasetProfileEditorComponent extends CheckDeactivateBaseComponent
return filename; return filename;
} }
getDescriptionTemplateTypes(): DescriptionTemplateType[] {
this.descriptionTemplateTypeService.getTypes().pipe(takeUntil(this._destroyed))
.subscribe(types => {
this.descriptionTemplateTypes = types.data;
});
return this.descriptionTemplateTypes;
}
getLanguageInfos(): LanguageInfo[] { getLanguageInfos(): LanguageInfo[] {
return this.languageInfoService.getLanguageInfoValues(); return this.languageInfoService.getLanguageInfoValues();
} }

View File

@ -0,0 +1,19 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DescriptionTypesRoutingModule } from './description-types.routing';
import { DescriptionTypesComponent } from './listing/description-types.component';
import { CommonUiModule } from '@common/ui/common-ui.module';
import { DescriptionTypeEditorComponent } from './editor/description-type-editor.component';
@NgModule({
declarations: [
DescriptionTypesComponent,
DescriptionTypeEditorComponent
],
imports: [
CommonModule,
CommonUiModule,
DescriptionTypesRoutingModule
]
})
export class DescriptionTypesModule { }

View File

@ -0,0 +1,17 @@
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { AdminAuthGuard } from "@app/core/admin-auth-guard.service";
import { DescriptionTypeEditorComponent } from './editor/description-type-editor.component';
import { DescriptionTypesComponent } from "./listing/description-types.component";
const routes: Routes = [
{ path: '', component: DescriptionTypesComponent, canActivate: [AdminAuthGuard] },
{ path: 'new', component: DescriptionTypeEditorComponent, canActivate: [AdminAuthGuard], data: { title: 'GENERAL.TITLES.DESCRIPTION-TYPE-NEW' } },
{ path: ':id', component: DescriptionTypeEditorComponent, canActivate: [AdminAuthGuard], data: { title: 'GENERAL.TITLES.DESCRIPTION-TYPE-EDIT' } }
]
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class DescriptionTypesRoutingModule { }

View File

@ -0,0 +1,36 @@
<div class="main-content">
<div class="container-fluid description-type-editor">
<div class="row align-items-center mb-4" *ngIf="formGroup">
<div class="col-auto">
<h3>{{'DESCRIPTION-TYPE-EDITOR.NEW' | translate}}</h3>
</div>
</div>
<form *ngIf="formGroup" (ngSubmit)="formSubmit()" [formGroup]="formGroup">
<mat-card style="padding: 2em;">
<mat-card-content>
<div class="row" style="gap:1em">
<mat-form-field class="col-lg-6" appearance="legacy">
<input matInput placeholder="{{'DESCRIPTION-TYPE-EDITOR.FIELDS.LABEL' | translate}}" type="text" name="name" formControlName="name"
required>
<mat-error *ngIf="formGroup.get('name').hasError('backendError')">
{{formGroup.get('name').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('name').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="row mt-4">
<div class="col-auto">
<button mat-button class="action-btn" (click)="cancel()" type="button">{{'DESCRIPTION-TYPE-EDITOR.ACTIONS.CANCEL' | translate}}</button>
</div>
<div class="col"></div>
<div class="col-auto">
<button mat-button class="action-btn" type="submit" [disabled]="!formGroup.valid">
{{'DESCRIPTION-TYPE-EDITOR.ACTIONS.SAVE' | translate}}
</button>
</div>
</div>
</mat-card-content>
</mat-card>
</form>
</div>
</div>

View File

@ -0,0 +1,24 @@
.description-type-editor {
margin-top: 1.3rem;
margin-left: 1em;
margin-right: 3em;
}
.action-btn {
border-radius: 30px;
background-color: var(--secondary-color);
border: 1px solid transparent;
padding-left: 2em;
padding-right: 2em;
box-shadow: 0px 3px 6px #1E202029;
transition-property: background-color, color;
transition-duration: 200ms;
transition-delay: 50ms;
transition-timing-function: ease-in-out;
&:disabled{
background-color: #CBCBCB;
color: #FFF;
border: 0px;
}
}

View File

@ -0,0 +1,85 @@
import { AfterViewInit, Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { DescriptionTemplateTypeService } from '@app/core/services/description-template-type/description-template-type.service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { BaseComponent } from '@common/base/base.component';
import { FormService } from '@common/forms/form-service';
import { TranslateService } from '@ngx-translate/core';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-description-type-editor',
templateUrl: './description-type-editor.component.html',
styleUrls: ['./description-type-editor.component.scss']
})
export class DescriptionTypeEditorComponent extends BaseComponent implements AfterViewInit {
formGroup: FormGroup = null;
descriptionTypeModel: DescriptionTypeEditorModel
constructor(
private descriptionTemplateTypeService: DescriptionTemplateTypeService,
private formService: FormService,
private uiNotificationService: UiNotificationService,
private language: TranslateService,
private router: Router
) {
super();
}
ngAfterViewInit(): void {
this.descriptionTypeModel = new DescriptionTypeEditorModel();
setTimeout(() => {
this.formGroup = this.descriptionTypeModel.buildForm();
});
}
formSubmit(): void {
this.formService.touchAllFormFields(this.formGroup);
if (!this.isFormValid()) { return; }
this.onSubmit();
}
public isFormValid() {
return this.formGroup.valid;
}
onSubmit(): void {
console.log(this.formGroup.value);
this.descriptionTemplateTypeService.createType(this.formGroup.value)
.pipe(takeUntil(this._destroyed))
.subscribe(
complete => this.onCallbackSuccess(),
error => this.onCallbackError(error)
);
}
onCallbackSuccess(): void {
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION'), SnackBarNotificationLevel.Success);
this.router.navigate(['/description-types']);
}
onCallbackError(errorResponse: any) {
// this.setErrorModel(errorResponse.error);
// this.formService.validateAllFormFields(this.formGroup);
}
public cancel(): void {
this.router.navigate(['/description-types']);
}
}
export class DescriptionTypeEditorModel {
public id: string;
public name: string;
buildForm(): FormGroup {
const formGroup = new FormBuilder().group({
id: [this.id],
name: [this.name, Validators.required],
});
return formGroup;
}
}

View File

@ -0,0 +1,51 @@
<div class="main-content">
<div class="container-fluid description-types-listing">
<div class="row align-items-center">
<div class="col-auto">
<h3>{{'DESCRIPTION-TYPES-LISTING.TITLE' | translate}}</h3>
</div>
<div class="col"></div>
<div class="col-auto">
<button mat-raised-button class="create-btn ml-md-3" [routerLink]="['/description-types/new']">
<span class="button-text">
{{'DESCRIPTION-TYPES-LISTING.CREATE-TYPE' | translate}}
</span>
</button>
</div>
</div>
<!-- <app-dmp-profile-criteria-component></app-dmp-profile-criteria-component> -->
<div class="mat-elevation-z6">
<mat-table [dataSource]="dataSource" matSort (matSortChange)="refresh()">
<!-- Column Definition: Name -->
<ng-container cdkColumnDef="label">
<mat-header-cell *matHeaderCellDef mat-sort-header="label">
{{'DESCRIPTION-TYPES-LISTING.COLUMNS.NAME' | translate}}</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.name}}</mat-cell>
</ng-container>
<ng-container cdkColumnDef="status">
<mat-header-cell *matHeaderCellDef mat-sort-header="status">{{'DESCRIPTION-TYPES-LISTING.COLUMNS.STATUS' |
translate}}</mat-header-cell>
<mat-cell *matCellDef="let row"> <div [ngClass]="['status-chip',getStatusClass(row.status)]">{{ 'DATASET-PROFILE-STATUS.FINALIZED' | translate}}</div></mat-cell>
</ng-container>
<ng-container cdkColumnDef="delete">
<mat-header-cell *matHeaderCellDef></mat-header-cell>
<mat-cell *matCellDef="let row" (click)="$event.stopPropagation()">
<button mat-icon-button (click)="deleteTemplate(row.id)">
<mat-icon [matTooltip]="('DESCRIPTION-TYPES-LISTING.ACTIONS.DELETE' | translate)" matTooltipPosition="right" class="dlt-btn">delete</mat-icon>
</button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
<mat-paginator #paginator [length]="1" [pageSizeOptions]="[10, 25, 100]">
</mat-paginator>
</div>
</div>
</div>

View File

@ -0,0 +1,71 @@
.mat-table {
margin-top: 47px;
border-radius: 4px;
}
.description-types-listing {
margin-top: 1.3rem;
margin-left: 1rem;
margin-right: 2rem;
.mat-header-row{
background: #f3f5f8;
}
.mat-card {
margin: 16px 0;
padding: 0px;
}
.mat-row {
cursor: pointer;
min-height: 4.5em;
}
mat-row:hover {
background-color: #eef5f6;
}
.mat-fab-bottom-right {
float: right;
z-index: 5;
}
}
// PAGINATOR
:host ::ng-deep .mat-paginator-container {
flex-direction: row-reverse !important;
justify-content: space-between !important;
background-color: #f6f6f6;
align-items: center;
}
.create-btn {
border-radius: 30px;
background-color: var(--secondary-color);
padding-left: 2em;
padding-right: 2em;
// color: #000;
.button-text{
display: inline-block;
}
}
.dlt-btn {
color: rgba(0, 0, 0, 0.54);
}
.status-chip{
border-radius: 20px;
padding-left: 1em;
padding-right: 1em;
padding-top: 0.2em;
font-size: .8em;
}
.status-chip-finalized{
color: #568b5a;
background: #9dd1a1 0% 0% no-repeat padding-box;
}
.status-chip-draft{
color: #00c4ff;
background: #d3f5ff 0% 0% no-repeat padding-box;
}

View File

@ -0,0 +1,153 @@
import { DataSource } from '@angular/cdk/table';
import { HttpErrorResponse } from '@angular/common/http';
import { Component, OnInit, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { DescriptionTemplateTypeService } from '@app/core/services/description-template-type/description-template-type.service';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
import { BaseComponent } from '@common/base/base.component';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { TranslateService } from '@ngx-translate/core';
import { merge as observableMerge, Observable, of } from 'rxjs';
import { map, startWith, switchMap, takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-description-types',
templateUrl: './description-types.component.html',
styleUrls: ['./description-types.component.scss']
})
export class DescriptionTypesComponent extends BaseComponent implements OnInit {
@ViewChild(MatPaginator, { static: true }) _paginator: MatPaginator;
@ViewChild(MatSort, { static: true }) sort: MatSort;
dataSource: DescriptionTypesDataSource | null;
displayedColumns: String[] = ['label', 'status', 'delete'];
constructor(
private descriptionTemplateTypeService: DescriptionTemplateTypeService,
private dialog: MatDialog,
private language: TranslateService,
private uiNotificationService: UiNotificationService
) {
super();
}
ngOnInit(): void {
this.refresh();
}
refresh() {
this.dataSource = new DescriptionTypesDataSource(this.descriptionTemplateTypeService, this._paginator, this.sort/*, this.criteria*/);
}
deleteTemplate(id: string){
if(id){
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
restoreFocus: false,
data: {
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'),
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
isDeleteConfirmation: true
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) {
// this.descriptionTemplateTypeService.deleteType(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(
// complete => {
// this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DATASET-PROFILE-DELETE'), SnackBarNotificationLevel.Success);
// this.refresh();
// },
// error => {
// this.onCallbackError(error);
// if (error.error.statusCode == 674) {
// this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DATASET-PROFILE-DELETE'), SnackBarNotificationLevel.Error);
// } else {
// this.uiNotificationService.snackBarNotification(this.language.instant(error.message), SnackBarNotificationLevel.Error);
// }
// }
// );
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DESCRIPTION-TEMPLATE-TYPE-DELETE'), SnackBarNotificationLevel.Error);
this.refresh();
}
});
}
}
onCallbackError(errorResponse: HttpErrorResponse) {
this.uiNotificationService.snackBarNotification(errorResponse.message, SnackBarNotificationLevel.Warning);
}
getStatusClass(status: number): string {
if(status == 1){
return 'status-chip-finalized'
}
return 'status-chip-draft';
}
}
export interface DescriptionTemplateTypeListingModel {
id: string;
name: string;
status: number;
}
export class DescriptionTypesDataSource extends DataSource<DescriptionTemplateTypeListingModel> {
totalCount = 0;
constructor(
private _service: DescriptionTemplateTypeService,
private _paginator: MatPaginator,
private _sort: MatSort//,
//private _criteria: DmpProfileCriteriaComponent
) {
super();
}
connect(): Observable<DescriptionTemplateTypeListingModel[]> {
const displayDataChanges = [
this._paginator.page
//this._sort.matSortChange
];
// return observableMerge(...displayDataChanges).pipe(
// 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<DmpProfileCriteria>(startIndex, this._paginator.pageSize, { fields: fields });
// // request.criteria = this._criteria.criteria;
// // return this._service.getPaged(request);
// return this._service.getTypes();
// }),
// map(result => {
// return result;
// }),
// map(result => {
// // if (!result) { return []; }
// // if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; }
// // return result.data;
// return result;
// }));
return of([{id: '1234', name: 'Dataset', status: 0}]);
}
disconnect() {
// No-op
}
}

View File

@ -1,5 +1,6 @@
[ [
"DatasetProfileEditorModel.description", "DatasetProfileEditorModel.description",
"DatasetProfileEditorModel.type",
"DatasetProfileEditorModel.label", "DatasetProfileEditorModel.label",
"SectionEditorModel.title", "SectionEditorModel.title",
"SectionEditorModel.description", "SectionEditorModel.description",