From 128b47d9c355f39a65b3e07b8adb43f985588153 Mon Sep 17 00:00:00 2001 From: Aldo Mihasi Date: Tue, 25 Jul 2023 15:27:15 +0300 Subject: [PATCH] #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 --- .../entities/DescriptionTemplateTypeDao.java | 10 ++ .../DescriptionTemplateTypeDaoImpl.java | 61 +++++++ .../entities/DescriptionTemplateType.java | 52 ++++++ .../main/java/eu/eudat/controllers/Admin.java | 1 + .../DescriptionTemplateTypeController.java | 64 ++++++++ ...DescriptionTemplatesWithTypeException.java | 9 ++ .../DescriptionTemplateTypeManager.java | 61 +++++++ .../operations/DatabaseRepository.java | 2 + .../operations/DatabaseRepositoryImpl.java | 11 ++ .../data/admin/composite/DatasetProfile.java | 9 ++ dmp-frontend/src/app/app-routing.module.ts | 8 + .../src/app/core/core-service.module.ts | 4 +- .../admin/dataset-profile/dataset-profile.ts | 1 + .../description-template-type.ts | 4 + .../description-template-type.service.ts | 30 ++++ .../editor/dataset-profile-editor-model.ts | 3 + .../dataset-profile-editor.component.html | 19 ++- .../dataset-profile-editor.component.ts | 15 +- .../description-types.module.ts | 19 +++ .../description-types.routing.ts | 17 ++ .../description-type-editor.component.html | 36 +++++ .../description-type-editor.component.scss | 24 +++ .../description-type-editor.component.ts | 85 ++++++++++ .../listing/description-types.component.html | 51 ++++++ .../listing/description-types.component.scss | 71 ++++++++ .../listing/description-types.component.ts | 153 ++++++++++++++++++ .../src/assets/resources/skipDisable.json | 1 + 27 files changed, 816 insertions(+), 5 deletions(-) create mode 100644 dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DescriptionTemplateTypeDao.java create mode 100644 dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DescriptionTemplateTypeDaoImpl.java create mode 100644 dmp-backend/data/src/main/java/eu/eudat/data/entities/DescriptionTemplateType.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/controllers/DescriptionTemplateTypeController.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/exceptions/descriptiontemplate/DescriptionTemplatesWithTypeException.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/logic/managers/DescriptionTemplateTypeManager.java create mode 100644 dmp-frontend/src/app/core/model/description-template-type/description-template-type.ts create mode 100644 dmp-frontend/src/app/core/services/description-template-type/description-template-type.service.ts create mode 100644 dmp-frontend/src/app/ui/admin/description-types/description-types.module.ts create mode 100644 dmp-frontend/src/app/ui/admin/description-types/description-types.routing.ts create mode 100644 dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.html create mode 100644 dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.scss create mode 100644 dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.ts create mode 100644 dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.html create mode 100644 dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.scss create mode 100644 dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.ts diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DescriptionTemplateTypeDao.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DescriptionTemplateTypeDao.java new file mode 100644 index 000000000..764bf32e0 --- /dev/null +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DescriptionTemplateTypeDao.java @@ -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 findFromName(String name); +} diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DescriptionTemplateTypeDaoImpl.java b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DescriptionTemplateTypeDaoImpl.java new file mode 100644 index 000000000..2f0cac2f2 --- /dev/null +++ b/dmp-backend/data/src/main/java/eu/eudat/data/dao/entities/DescriptionTemplateTypeDaoImpl.java @@ -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 implements DescriptionTemplateTypeDao { + + @Autowired + public DescriptionTemplateTypeDaoImpl(DatabaseService 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 asQueryable() { + return this.getDatabaseService().getQueryable(DescriptionTemplateType.class); + } + + @Async + @Override + public CompletableFuture createOrUpdateAsync(DescriptionTemplateType item) { + return CompletableFuture.supplyAsync(() -> this.createOrUpdate(item)); + } + + @Override + public DescriptionTemplateType find(UUID id, String hint) { + throw new UnsupportedOperationException(); + } + +} diff --git a/dmp-backend/data/src/main/java/eu/eudat/data/entities/DescriptionTemplateType.java b/dmp-backend/data/src/main/java/eu/eudat/data/entities/DescriptionTemplateType.java new file mode 100644 index 000000000..e4d8d6257 --- /dev/null +++ b/dmp-backend/data/src/main/java/eu/eudat/data/entities/DescriptionTemplateType.java @@ -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 { + + @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, List fields, String base) { + this.id = UUID.fromString((String) tuple.get(0).get(!base.isEmpty() ? base + "." + "id" : "id")); + return this; + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/Admin.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/Admin.java index f9a5cd03b..b8604c456 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/controllers/Admin.java +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/Admin.java @@ -61,6 +61,7 @@ public class Admin extends BaseController { //this.getLoggerService().info(principal, "Admin Added Dataset Profile"); DatasetProfile shortenProfile = profile.toShort(); DescriptionTemplate modelDefinition = AdminManager.generateViewStyleDefinition(shortenProfile, getApiContext()); + modelDefinition.setType(getApiContext().getOperationsContext().getDatabaseRepository().getDescriptionTemplateTypeDao().findFromName(profile.getType())); modelDefinition.setGroupId(UUID.randomUUID()); modelDefinition.setVersion((short) 0); diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/DescriptionTemplateTypeController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/DescriptionTemplateTypeController.java new file mode 100644 index 000000000..f48b98f10 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/DescriptionTemplateTypeController.java @@ -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> createOrUpdate(@RequestBody String type, @ClaimedAuthorities(claims = {ADMIN}) Principal principal) throws Exception { + this.descriptionTemplateTypeManager.create(type); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE).message("Created")); + } + + @RequestMapping(method = RequestMethod.GET, value = {"get"}, produces = "application/json") + public @ResponseBody + ResponseEntity>> get(@ClaimedAuthorities(claims = {Authorities.ADMIN, Authorities.MANAGER, Authorities.USER, Authorities.ANONYMOUS}) Principal principal) throws Exception { + DataTableData dataTable = this.descriptionTemplateTypeManager.get(); + return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem>().status(ApiMessageCode.NO_MESSAGE).payload(dataTable)); + } + + @Transactional + @RequestMapping(method = RequestMethod.DELETE, value = {"/delete/{id}"}, produces = "application/json") + public @ResponseBody + ResponseEntity> 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().status(ApiMessageCode.SUCCESS_MESSAGE).message("Deleted")); + } + catch(DescriptionTemplatesWithTypeException e){ + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.UNSUCCESS_DELETE).message(e.getMessage())); + } + } + +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/exceptions/descriptiontemplate/DescriptionTemplatesWithTypeException.java b/dmp-backend/web/src/main/java/eu/eudat/exceptions/descriptiontemplate/DescriptionTemplatesWithTypeException.java new file mode 100644 index 000000000..2c6484b05 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/exceptions/descriptiontemplate/DescriptionTemplatesWithTypeException.java @@ -0,0 +1,9 @@ +package eu.eudat.exceptions.descriptiontemplate; + +public class DescriptionTemplatesWithTypeException extends RuntimeException { + + public DescriptionTemplatesWithTypeException(String message) { + super(message); + } + +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DescriptionTemplateTypeManager.java b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DescriptionTemplateTypeManager.java new file mode 100644 index 000000000..046c7bebd --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/managers/DescriptionTemplateTypeManager.java @@ -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 get() { + List types = this.databaseRepository.getDescriptionTemplateTypeDao().asQueryable().toList(); + DataTableData 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"); + } + } + } +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepository.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepository.java index 99e088a1c..b10ecaa0e 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepository.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepository.java @@ -62,5 +62,7 @@ public interface DatabaseRepository { EntityDoiDao getEntityDoiDao(); + DescriptionTemplateTypeDao getDescriptionTemplateTypeDao(); + void detachEntity(T entity); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepositoryImpl.java b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepositoryImpl.java index 2e2dd4c63..c72baec18 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepositoryImpl.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/services/operations/DatabaseRepositoryImpl.java @@ -40,6 +40,7 @@ public class DatabaseRepositoryImpl implements DatabaseRepository { private NotificationDao notificationDao; private FileUploadDao fileUploadDao; private EntityDoiDao entityDoiDao; + private DescriptionTemplateTypeDao descriptionTemplateTypeDao; private EntityManager entityManager; @@ -328,6 +329,16 @@ public class DatabaseRepositoryImpl implements DatabaseRepository { this.entityDoiDao = entityDoiDao; } + @Override + public DescriptionTemplateTypeDao getDescriptionTemplateTypeDao() { + return descriptionTemplateTypeDao; + } + + @Autowired + public void setDescriptionTemplateTypeDao(DescriptionTemplateTypeDao descriptionTemplateTypeDao) { + this.descriptionTemplateTypeDao = descriptionTemplateTypeDao; + } + public void detachEntity(T entity) { this.entityManager.detach(entity); } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/admin/composite/DatasetProfile.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/admin/composite/DatasetProfile.java index cbc23c2f4..146a4acc5 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/admin/composite/DatasetProfile.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/admin/composite/DatasetProfile.java @@ -13,6 +13,7 @@ import java.util.List; public class DatasetProfile { private String label; private String description; + private String type; private List pages; private List
sections; private Short status; @@ -35,6 +36,13 @@ public class DatasetProfile { this.description = description; } + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + public List getPages() { return pages; } @@ -80,6 +88,7 @@ public class DatasetProfile { DatasetProfile shortProfile = new DatasetProfile(); shortProfile.setLabel(this.label); shortProfile.setDescription(this.description); + shortProfile.setType(this.type); List
shortSection = new LinkedList<>(); for (Section toshortSection : this.getSections()) { shortSection.add(toshortSection.toShort()); diff --git a/dmp-frontend/src/app/app-routing.module.ts b/dmp-frontend/src/app/app-routing.module.ts index 0d2ac80a2..e13c1e00b 100644 --- a/dmp-frontend/src/app/app-routing.module.ts +++ b/dmp-frontend/src/app/app-routing.module.ts @@ -99,6 +99,14 @@ const appRoutes: Routes = [ 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', loadChildren: () => import('./ui/contact/contact.module').then(m => m.ContactModule), diff --git a/dmp-frontend/src/app/core/core-service.module.ts b/dmp-frontend/src/app/core/core-service.module.ts index 5186586e6..bbe2356b9 100644 --- a/dmp-frontend/src/app/core/core-service.module.ts +++ b/dmp-frontend/src/app/core/core-service.module.ts @@ -52,6 +52,7 @@ import { FaqService } from './services/faq/faq.service'; import { GlossaryService } from './services/glossary/glossary.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 { 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. @@ -132,7 +133,8 @@ export class CoreServiceModule { multi: true }, LanguageInfoService, - PrefillingService + PrefillingService, + DescriptionTemplateTypeService ], }; } diff --git a/dmp-frontend/src/app/core/model/admin/dataset-profile/dataset-profile.ts b/dmp-frontend/src/app/core/model/admin/dataset-profile/dataset-profile.ts index 8f8ec30d7..68b0d64db 100644 --- a/dmp-frontend/src/app/core/model/admin/dataset-profile/dataset-profile.ts +++ b/dmp-frontend/src/app/core/model/admin/dataset-profile/dataset-profile.ts @@ -3,6 +3,7 @@ import { UserInfoListingModel } from "../../user/user-info-listing"; export interface DatasetProfile { label: string; + type: string; sections: Section[]; pages: Page[]; status: number; diff --git a/dmp-frontend/src/app/core/model/description-template-type/description-template-type.ts b/dmp-frontend/src/app/core/model/description-template-type/description-template-type.ts new file mode 100644 index 000000000..08f9df8a8 --- /dev/null +++ b/dmp-frontend/src/app/core/model/description-template-type/description-template-type.ts @@ -0,0 +1,4 @@ +export interface DescriptionTemplateType { + id: string; + name: string; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/core/services/description-template-type/description-template-type.service.ts b/dmp-frontend/src/app/core/services/description-template-type/description-template-type.service.ts new file mode 100644 index 000000000..dc6859f30 --- /dev/null +++ b/dmp-frontend/src/app/core/services/description-template-type/description-template-type.service.ts @@ -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> { + return this.http.get>(this.actionUrl + 'get', { headers: this.headers }); + } + + createType(name: string): Observable { + return this.http.post(this.actionUrl + 'create', name, { headers: this.headers }); + } + + deleteType(id: string): Observable { + return this.http.delete(this.actionUrl + 'delete/' + id, { headers: this.headers }); + } +} diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor-model.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor-model.ts index d3cf2775e..059a1feb0 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor-model.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor-model.ts @@ -15,6 +15,7 @@ export class DatasetProfileEditorModel extends BaseFormModel { public status: number; public version: number; private description: string; + private type: string; private language: string; 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.pages) { this.pages = item.pages.map(x => new PageEditorModel().fromModel(x)); } this.label = item.label; + this.type = item.type; this.status = item.status; this.version = item.version; this.description = item.description; @@ -34,6 +36,7 @@ export class DatasetProfileEditorModel extends BaseFormModel { const formGroup: FormGroup = new FormBuilder().group({ label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('DatasetProfileEditorModel.label')) }, [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]], status: [{ value: this.status, disabled: (disabled && !skipDisable.includes('DatasetProfileEditorModel.status')) }], version: [{ value: this.version, disabled: (disabled && !skipDisable.includes('DatasetProfileEditorModel.version')) }], diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.html index c0288f59d..31bfbd1ea 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.html @@ -142,8 +142,21 @@
- -
1.3 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-LANGUAGE'| translate}} *
+
1.3 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DESCRIPTION-TEMPLATE-TYPE'| translate}} *
+ + + + {{ type.name }} + + + {{'GENERAL.VALIDATION.REQUIRED' | + translate}} + + +
+
+ +
1.4 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-LANGUAGE'| translate}} *
@@ -157,7 +170,7 @@
-
1.4 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-USERS'| translate}}
+
1.5 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-USERS'| translate}}
{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-USERS-HINT'| translate}}
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts index be47cb207..7892340cc 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts @@ -45,6 +45,8 @@ import { DatasetProfileComboBoxType } from '@app/core/common/enum/dataset-profil import { UserService } from '@app/core/services/user/user.service'; import { MatInput } from '@angular/material/input'; 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'); @@ -80,6 +82,7 @@ export class DatasetProfileEditorComponent extends CheckDeactivateBaseComponent tocEntryEnumValues = ToCEntryType; public userChipList:any[] = []; displayedColumns: String[] = ['name', 'email', 'button']; + descriptionTemplateTypes: DescriptionTemplateType[] = []; colorizeInvalid:boolean = false; inputUserState: 'untriggered'| 'triggered' = 'untriggered'; @@ -112,7 +115,8 @@ export class DatasetProfileEditorComponent extends CheckDeactivateBaseComponent private visibilityRulesService: VisibilityRulesService, private fb: FormBuilder, private sidenavService: SideNavService, - private userService: UserService + private userService: UserService, + private descriptionTemplateTypeService: DescriptionTemplateTypeService ) { super(); // this.profileID = route.snapshot.params['id']; @@ -227,6 +231,7 @@ export class DatasetProfileEditorComponent extends CheckDeactivateBaseComponent } }); + this.getDescriptionTemplateTypes(); combineLatest(this._inputUserButton$.asObservable(),this._inputUserField$.asObservable()) .pipe(takeUntil(this._destroyed)) @@ -600,6 +605,14 @@ export class DatasetProfileEditorComponent extends CheckDeactivateBaseComponent return filename; } + getDescriptionTemplateTypes(): DescriptionTemplateType[] { + this.descriptionTemplateTypeService.getTypes().pipe(takeUntil(this._destroyed)) + .subscribe(types => { + this.descriptionTemplateTypes = types.data; + }); + return this.descriptionTemplateTypes; + } + getLanguageInfos(): LanguageInfo[] { return this.languageInfoService.getLanguageInfoValues(); } diff --git a/dmp-frontend/src/app/ui/admin/description-types/description-types.module.ts b/dmp-frontend/src/app/ui/admin/description-types/description-types.module.ts new file mode 100644 index 000000000..1a91c9cee --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/description-types.module.ts @@ -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 { } diff --git a/dmp-frontend/src/app/ui/admin/description-types/description-types.routing.ts b/dmp-frontend/src/app/ui/admin/description-types/description-types.routing.ts new file mode 100644 index 000000000..fea0e116d --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/description-types.routing.ts @@ -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 { } \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.html b/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.html new file mode 100644 index 000000000..d55b295fc --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.html @@ -0,0 +1,36 @@ +
+
+
+
+

{{'DESCRIPTION-TYPE-EDITOR.NEW' | translate}}

+
+
+
+ + +
+ + + + {{formGroup.get('name').getError('backendError').message}} + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + +
+
+
+ +
+
+
+ +
+
+
+
+ +
+
diff --git a/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.scss b/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.scss new file mode 100644 index 000000000..93d519a62 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.scss @@ -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; + } +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.ts b/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.ts new file mode 100644 index 000000000..118a226df --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.ts @@ -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; + } +} diff --git a/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.html b/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.html new file mode 100644 index 000000000..bebfd44bc --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.html @@ -0,0 +1,51 @@ +
+
+
+
+

{{'DESCRIPTION-TYPES-LISTING.TITLE' | translate}}

+
+
+
+ +
+
+ + +
+ + + + + + {{'DESCRIPTION-TYPES-LISTING.COLUMNS.NAME' | translate}} + {{row.name}} + + + + {{'DESCRIPTION-TYPES-LISTING.COLUMNS.STATUS' | + translate}} +
{{ 'DATASET-PROFILE-STATUS.FINALIZED' | translate}}
+
+ + + + + + + + + + + +
+ + +
+
+
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.scss b/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.scss new file mode 100644 index 000000000..245b6aa81 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.scss @@ -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; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.ts b/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.ts new file mode 100644 index 000000000..d86fbbac9 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.ts @@ -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 { + + totalCount = 0; + + constructor( + private _service: DescriptionTemplateTypeService, + private _paginator: MatPaginator, + private _sort: MatSort//, + //private _criteria: DmpProfileCriteriaComponent + ) { + super(); + + } + + connect(): Observable { + 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 = new Array(); + // // if (this._sort.active) { fields = this._sort.direction === 'asc' ? ['+' + this._sort.active] : ['-' + this._sort.active]; } + // // const request = new DataTableRequest(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 + } +} diff --git a/dmp-frontend/src/assets/resources/skipDisable.json b/dmp-frontend/src/assets/resources/skipDisable.json index b0d92f82e..c791c76b3 100644 --- a/dmp-frontend/src/assets/resources/skipDisable.json +++ b/dmp-frontend/src/assets/resources/skipDisable.json @@ -1,5 +1,6 @@ [ "DatasetProfileEditorModel.description", + "DatasetProfileEditorModel.type", "DatasetProfileEditorModel.label", "SectionEditorModel.title", "SectionEditorModel.description",