Merge branch 'dmp-refactoring' of code-repo.d4science.org:MaDgiK-CITE/argos into dmp-refactoring

# Conflicts:
#	dmp-backend/core/src/main/java/eu/eudat/model/persist/descriptionproperties/PropertyDefinitionFieldSetPersist.java
This commit is contained in:
Efstratios Giannopoulos 2024-04-25 10:27:06 +03:00
commit c27e98acd8
75 changed files with 559 additions and 749 deletions

View File

@ -228,7 +228,7 @@ public class DescriptionPersist {
.iff(() -> item.getStatus() == DescriptionStatus.Finalized)
.on(DescriptionPersist._properties)
.over(item.getProperties())
.using(() -> this.validatorFactory.validator(PropertyDefinitionPersist.PropertyDefinitionPersistValidator.class).setStatus(item.getStatus()).withDefinition(definition))
.using(() -> this.validatorFactory.validator(PropertyDefinitionPersist.PropertyDefinitionPersistValidator.class).setStatus(item.getStatus()).withDefinition(definition).withRules(definition))
// this.navSpec()
// .iff(() -> !this.isNull(item.getTags()))
// .on(DescriptionPersist._tags)

View File

@ -4,6 +4,7 @@ import eu.eudat.commons.enums.DescriptionStatus;
import eu.eudat.commons.enums.FieldType;
import eu.eudat.commons.enums.FieldValidationType;
import eu.eudat.commons.types.descriptiontemplate.FieldEntity;
import eu.eudat.commons.types.descriptiontemplate.RuleEntity;
import eu.eudat.commons.validation.BaseValidator;
import eu.eudat.model.persist.ReferencePersist;
import gr.cite.tools.validation.ValidatorFactory;
@ -95,6 +96,8 @@ public class FieldPersist {
private final MessageSource messageSource;
private FieldEntity fieldEntity;
private DescriptionStatus status;
private List<List<RuleEntity>> rules;
private Boolean fieldSetIsRuleTarget;
protected PersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, ValidatorFactory validatorFactory, MessageSource messageSource) {
super(conventionService, errors);
@ -111,33 +114,34 @@ public class FieldPersist {
protected List<Specification> specifications(FieldPersist item) {
FieldType fieldType = this.fieldEntity != null && this.fieldEntity.getData() != null ? this.fieldEntity.getData().getFieldType() : FieldType.FREE_TEXT;
boolean required = this.fieldEntity != null && this.fieldEntity.getValidations() != null ? this.fieldEntity.getValidations().contains(FieldValidationType.Required) : false;
boolean isRuleTarget = this.checkIfFieldIsRuleTarget();
return Arrays.asList(
this.spec()
.iff(()-> FieldType.isTextType(fieldType) && !fieldType.equals(FieldType.CHECK_BOX) && DescriptionStatus.Finalized.equals(this.status) && required)
.iff(()-> FieldType.isTextType(fieldType) && !fieldType.equals(FieldType.CHECK_BOX) && DescriptionStatus.Finalized.equals(this.status) && this.isListNullOrEmpty(fieldEntity.getVisibilityRules()) && !isRuleTarget && !fieldSetIsRuleTarget && required)
.must(() -> !this.isEmpty(item.getTextValue()))
.failOn(FieldPersist._textValue).failWith(messageSource.getMessage("Validation_Required", new Object[]{FieldPersist._textValue}, LocaleContextHolder.getLocale())),
this.spec()
.iff(()-> FieldType.isDateType(fieldType) && DescriptionStatus.Finalized.equals(this.status) && required)
.iff(()-> FieldType.isDateType(fieldType) && DescriptionStatus.Finalized.equals(this.status) && this.isListNullOrEmpty(fieldEntity.getVisibilityRules()) && !isRuleTarget && !fieldSetIsRuleTarget && required)
.must(() -> !this.isNull(item.getDateValue()))
.failOn(FieldPersist._dateValue).failWith(messageSource.getMessage("Validation_Required", new Object[]{FieldPersist._dateValue}, LocaleContextHolder.getLocale())),
this.spec()
.iff(()-> FieldType.isExternalIdentifierType(fieldType) && DescriptionStatus.Finalized.equals(this.status) && required)
.iff(()-> FieldType.isExternalIdentifierType(fieldType) && DescriptionStatus.Finalized.equals(this.status) && this.isListNullOrEmpty(fieldEntity.getVisibilityRules()) && !isRuleTarget && !fieldSetIsRuleTarget && required)
.must(() -> !this.isNull(item.getExternalIdentifier()))
.failOn(FieldPersist._externalIdentifier).failWith(messageSource.getMessage("Validation_Required", new Object[]{FieldPersist._externalIdentifier}, LocaleContextHolder.getLocale())),
this.spec()
.iff(()-> FieldType.isTextListType(fieldType) && DescriptionStatus.Finalized.equals(this.status) && required && !fieldType.equals(FieldType.TAGS))
.iff(()-> FieldType.isTextListType(fieldType) && DescriptionStatus.Finalized.equals(this.status) && this.isListNullOrEmpty(fieldEntity.getVisibilityRules()) && !isRuleTarget && !fieldSetIsRuleTarget && required && !fieldType.equals(FieldType.TAGS))
.must(() -> !this.isListNullOrEmpty(item.getTextListValue()) || !this.isEmpty(item.getTextValue()))
.failOn(FieldPersist._textListValue).failWith(messageSource.getMessage("Validation_Required", new Object[]{FieldPersist._textListValue}, LocaleContextHolder.getLocale())),
this.spec()
.iff(()-> fieldType.equals(FieldType.TAGS) && DescriptionStatus.Finalized.equals(this.status) && required)
.iff(()-> fieldType.equals(FieldType.TAGS) && DescriptionStatus.Finalized.equals(this.status) && this.isListNullOrEmpty(fieldEntity.getVisibilityRules()) && !isRuleTarget && !fieldSetIsRuleTarget && required)
.must(() -> !this.isListNullOrEmpty(item.getTextListValue()))
.failOn(FieldPersist._textListValue).failWith(messageSource.getMessage("Validation_Required", new Object[]{FieldPersist._textListValue}, LocaleContextHolder.getLocale())),
this.spec()
.iff(()-> FieldType.isReferenceType(fieldType) && DescriptionStatus.Finalized.equals(this.status) && required)
.iff(()-> FieldType.isReferenceType(fieldType) && DescriptionStatus.Finalized.equals(this.status) && this.isListNullOrEmpty(fieldEntity.getVisibilityRules()) && !isRuleTarget && !fieldSetIsRuleTarget && required)
.must(() -> !this.isListNullOrEmpty(item.getReferences()) || !this.isNull(item.getReference()))
.failOn(FieldPersist._textListValue).failWith(messageSource.getMessage("Validation_Required", new Object[]{FieldPersist._textListValue}, LocaleContextHolder.getLocale())),
this.spec()
.iff(()-> !this.isEmpty(item.getTextValue()) && (fieldType.equals(FieldType.CHECK_BOX) || fieldType.equals(FieldType.BOOLEAN_DECISION)) )
.iff(()-> !this.isEmpty(item.getTextValue()) && (fieldType.equals(FieldType.CHECK_BOX) || fieldType.equals(FieldType.BOOLEAN_DECISION)) && this.isListNullOrEmpty(fieldEntity.getVisibilityRules()) && !isRuleTarget && !fieldSetIsRuleTarget)
.must(() -> this.isBoolean(item.getTextValue()))
.failOn(FieldPersist._textValue).failWith(messageSource.getMessage("Validation_UnexpectedValue", new Object[]{FieldPersist._textValue}, LocaleContextHolder.getLocale())),
this.spec()
@ -167,10 +171,31 @@ public class FieldPersist {
return this;
}
public PersistValidator withRules(List<List<RuleEntity>> rules) {
this.rules = rules;
return this;
}
public PersistValidator setStatus(DescriptionStatus status) {
this.status = status;
return this;
}
public PersistValidator ifFieldSetIsRuleTarget(Boolean fieldSetIsRuleTarget){
this.fieldSetIsRuleTarget = fieldSetIsRuleTarget;
return this;
}
private boolean checkIfFieldIsRuleTarget(){
if (this.isListNullOrEmpty(rules)) return false;
for (List<RuleEntity> rulesBySection: rules) {
if (!this.isListNullOrEmpty(rulesBySection)){
for (RuleEntity rule :rulesBySection) {
if (rule.getTarget().equals(this.fieldEntity.getId())) return true;
}
}
}
return false;
}
}
}

View File

@ -3,6 +3,7 @@ package eu.eudat.model.persist.descriptionproperties;
import eu.eudat.commons.enums.DescriptionStatus;
import eu.eudat.commons.types.descriptiontemplate.FieldEntity;
import eu.eudat.commons.types.descriptiontemplate.FieldSetEntity;
import eu.eudat.commons.types.descriptiontemplate.RuleEntity;
import eu.eudat.commons.validation.BaseValidator;
import eu.eudat.convention.ConventionService;
import eu.eudat.errorcode.ErrorThesaurusProperties;
@ -60,6 +61,7 @@ public class PropertyDefinitionFieldSetItemPersist {
private final MessageSource messageSource;
private FieldSetEntity fieldSetEntity;
private List<List<RuleEntity>> rules;
private DescriptionStatus status;
protected PersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, ValidatorFactory validatorFactory, MessageSource messageSource) {
super(conventionService, errors);
@ -86,7 +88,7 @@ public class PropertyDefinitionFieldSetItemPersist {
.using((itm) ->
{
FieldEntity fieldEntity = fieldSetEntity != null ? fieldSetEntity.getFieldById((String)itm.getKey()).stream().findFirst().orElse(null) : null;
return this.validatorFactory.validator(FieldPersist.PersistValidator.class).withFieldEntity(fieldEntity).setStatus(this.status);
return this.validatorFactory.validator(FieldPersist.PersistValidator.class).withFieldEntity(fieldEntity).withRules(rules).ifFieldSetIsRuleTarget(this.checkIfFieldSetIsRuleTarget()).setStatus(this.status);
})
);
@ -97,10 +99,27 @@ public class PropertyDefinitionFieldSetItemPersist {
return this;
}
public PersistValidator withRules(List<List<RuleEntity>> rules) {
this.rules = rules;
return this;
}
public PersistValidator setStatus(DescriptionStatus status) {
this.status = status;
return this;
}
private Boolean checkIfFieldSetIsRuleTarget(){
if (this.isListNullOrEmpty(rules)) return false;
for (List<RuleEntity> rulesBySection: rules) {
if (!this.isListNullOrEmpty(rulesBySection)){
for (RuleEntity rule :rulesBySection) {
if (rule.getTarget().equals(this.fieldSetEntity.getId())) return true;
}
}
}
return false;
}
}
}

View File

@ -2,6 +2,7 @@ package eu.eudat.model.persist.descriptionproperties;
import eu.eudat.commons.enums.DescriptionStatus;
import eu.eudat.commons.types.descriptiontemplate.FieldSetEntity;
import eu.eudat.commons.types.descriptiontemplate.RuleEntity;
import eu.eudat.commons.validation.BaseValidator;
import eu.eudat.convention.ConventionService;
import eu.eudat.errorcode.ErrorThesaurusProperties;
@ -35,6 +36,7 @@ public class PropertyDefinitionFieldSetPersist {
private final MessageSource messageSource;
private FieldSetEntity fieldSetEntity;
private DescriptionStatus status;
private List<List<RuleEntity>> rules;
protected PersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, ValidatorFactory validatorFactory, MessageSource messageSource, MessageSource messageSource1) {
super(conventionService, errors);
this.validatorFactory = validatorFactory;
@ -56,7 +58,7 @@ public class PropertyDefinitionFieldSetPersist {
.iff(() -> !this.isNull(item.getItems()))
.on(PropertyDefinitionFieldSetPersist._items)
.over(item.getItems())
.using((itm) -> this.validatorFactory.validator(PropertyDefinitionFieldSetItemPersist.PersistValidator.class).withFieldSetEntity(this.fieldSetEntity).setStatus(this.status)),
.using((itm) -> this.validatorFactory.validator(PropertyDefinitionFieldSetItemPersist.PersistValidator.class).withFieldSetEntity(this.fieldSetEntity).withRules(this.rules).setStatus(this.status)),
this.spec()
.iff(() -> DescriptionStatus.Finalized.equals(this.status) && fieldSetEntity.getHasMultiplicity())
.must(() -> !this.isListNullOrEmpty(item.getItems()) && min <= item.getItems().size())
@ -73,6 +75,11 @@ public class PropertyDefinitionFieldSetPersist {
return this;
}
public PersistValidator withRules(List<List<RuleEntity>> rules) {
this.rules = rules;
return this;
}
public PropertyDefinitionFieldSetPersist.PersistValidator setStatus(DescriptionStatus status) {
this.status = status;
return this;

View File

@ -5,6 +5,7 @@ import eu.eudat.commons.enums.FieldValidationType;
import eu.eudat.commons.types.descriptiontemplate.DefinitionEntity;
import eu.eudat.commons.types.descriptiontemplate.FieldEntity;
import eu.eudat.commons.types.descriptiontemplate.FieldSetEntity;
import eu.eudat.commons.types.descriptiontemplate.RuleEntity;
import eu.eudat.commons.validation.BaseValidator;
import eu.eudat.convention.ConventionService;
import eu.eudat.errorcode.ErrorThesaurusProperties;
@ -47,6 +48,8 @@ public class PropertyDefinitionPersist {
private DescriptionStatus status;
private DefinitionEntity definition;
private List<List<RuleEntity>> rules;
protected PropertyDefinitionPersistValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource, ValidatorFactory validatorFactory) {
super(conventionService, errors);
this.messageSource = messageSource;
@ -78,7 +81,7 @@ public class PropertyDefinitionPersist {
.mapKey((k) -> ((String)k))
.using((itm) -> {
FieldSetEntity fieldSetEntity = definition != null ? definition.getFieldSetById((String)itm.getKey()).stream().findFirst().orElse(null) : null;
return this.validatorFactory.validator(PropertyDefinitionFieldSetPersist.PersistValidator.class).withFieldSetEntity(fieldSetEntity).setStatus(this.status);
return this.validatorFactory.validator(PropertyDefinitionFieldSetPersist.PersistValidator.class).withFieldSetEntity(fieldSetEntity).withRules(rules).setStatus(this.status);
})
);
}
@ -94,6 +97,12 @@ public class PropertyDefinitionPersist {
return this;
}
public PropertyDefinitionPersistValidator withRules(DefinitionEntity definition) {
List<FieldEntity> fields = definition.getAllField();
this.rules = fields.stream().filter(x -> x.getVisibilityRules() != null).map(FieldEntity::getVisibilityRules).collect(Collectors.toList());
return this;
}
private List<FieldSetEntity> getMissingFieldSetEntity(PropertyDefinitionPersist item){
List<FieldSetEntity> missingMultipleFieldSets = new ArrayList<>();

View File

@ -497,24 +497,20 @@ public class DescriptionServiceImpl implements DescriptionService {
if (FieldType.isTextType(fieldType)) {
if (FieldType.UPLOAD.equals(fieldType)){
UUID newFileId = this.conventionService.isValidUUID(persist.getTextValue()) ? UUID.fromString(persist.getTextValue()) : null;
UUID existingFileId = this.conventionService.isValidUUID(data.getTextValue()) ? UUID.fromString(data.getTextValue()) : null;
if (newFileId != null){
if (!newFileId.equals(existingFileId)) {
StorageFileEntity existingFile = this.queryFactory.query(StorageFileQuery.class).authorize(AuthorizationFlags.OwnerOrDmpAssociatedOrPermission).ids(newFileId).firstAs(new BaseFieldSet().ensure(StorageFile._id));
if (existingFile == null){
StorageFile storageFile = this.storageFileService.copyToStorage(newFileId, StorageType.Main, true, new BaseFieldSet().ensure(StorageFile._id));
this.storageFileService.updatePurgeAt(storageFile.getId(), null);
if (existingFileId != null){
data.setTextValue(storageFile.getId().toString());
} else {
if (existingFile.getId() != null){
//DO NOT Remove we can not be sure uf the description is copied
//this.storageFileService.updatePurgeAt(existingFileId, Instant.now().minusSeconds(60));
}
data.setTextValue(storageFile.getId().toString());
} else {
data.setTextValue(newFileId.toString());
}
} else {
if (existingFileId != null){
//DO NOT Remove we can not be sure uf the description is copied
//this.storageFileService.updatePurgeAt(existingFileId, Instant.now().minusSeconds(60));
}
data.setTextValue(null);
}
} else {

View File

@ -0,0 +1,9 @@
diff a/dmp-backend/web/pom.xml b/dmp-backend/web/pom.xml (rejected hunks)
@@ -13,6 +13,7 @@
<groupId>eu.eudat</groupId>
<artifactId>dmp-backend</artifactId>
<version>${revision}</version>
+ <relativePath>../pom.xml</relativePath>
</parent>
<properties>

File diff suppressed because one or more lines are too long

View File

@ -16,7 +16,8 @@ const appRoutes: Routes = [
path: 'home',
loadChildren: () => import('./ui/dashboard/dashboard.module').then(m => m.DashboardModule),
data: {
breadcrumb: true
breadcrumb: true,
title: 'GENERAL.TITLES.HOME'
}
},
{

View File

@ -4,14 +4,14 @@
<div class="col-12">
<mat-chip-grid #chipList ngDefaultControl class="chip-list">
<ng-container *ngIf="value as values;">
<mat-chip-row *ngFor="let value of values" [disabled]="disabled" [selectable]="selectable" [removable]="true" [ngClass]="computeClass(value)" class="chip-row">
<mat-chip-row *ngFor="let value of values" [disabled]="disabled" [selectable]="selectable" [removable]="true" [ngClass]="computeClass(value)" class="chip-row" [matTooltip]="_canRemoveItemMessage(getSelectedItem(value)) | translate" >
<ng-container *ngIf="getSelectedItem(value) as selectedItem;">
<ng-template #cellTemplate *ngIf="_selectedValueTemplate(selectedItem)" [ngTemplateOutlet]="_selectedValueTemplate(selectedItem)" [ngTemplateOutletContext]="{
item: selectedItem
}" />
<span *ngIf="!_selectedValueTemplate(selectedItem)" class="chip-text" [title]="_displayFn(selectedItem)">{{_displayFn(selectedItem)}}</span>
</ng-container>
<button matChipRemove *ngIf="!disabled" [disabled]="!_canRemoveItem(getSelectedItem(value))"[matTooltipDisabled]="_canRemoveItem(getSelectedItem(value))" [matTooltip]="_canRemoveItemMessage(getSelectedItem(value))" (click)="_removeSelectedItem(getSelectedItem(value), $event)">
<button matChipRemove *ngIf="!disabled && _canRemoveItem(getSelectedItem(value))" (click)="_removeSelectedItem(getSelectedItem(value), $event)">
<mat-icon>cancel</mat-icon>
</button>
</mat-chip-row>

View File

@ -333,6 +333,7 @@ export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase imp
writeValue(value: any): void {
this.value = Array.isArray(value) ? value : null;
// Update chips observable
this.autocompleteInput.nativeElement.value = '';
this._items = null;
this.getSelectedItems(this.value);
}
@ -434,16 +435,16 @@ export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase imp
}
_canRemoveItem(item: any): boolean {
if(this.configuration.canRemoveItem != null) {
return this.configuration.canRemoveItem(item).canRemove;
if(item != null && this.configuration.canRemoveItem != null) {
return this.configuration.canRemoveItem(item)?.canRemove;
}
return true;
}
_canRemoveItemMessage(item: any): string {
if(this.configuration.canRemoveItem != null) {
if(item != null && this.configuration.canRemoveItem != null) {
const canRemoveResuslt = this.configuration.canRemoveItem(item);
if (canRemoveResuslt.canRemove) return canRemoveResuslt.message;
if (!canRemoveResuslt?.canRemove) return canRemoveResuslt.message;
}
return null;
}
@ -491,3 +492,8 @@ export class MultipleAutoCompleteComponent extends _CustomComponentMixinBase imp
}
}
export interface MultipleAutoCompleteCanRemoveItem {
canRemove: boolean;
message: string;
}

View File

@ -205,7 +205,7 @@
<mat-divider></mat-divider>
<button mat-list-item (click)="$event.stopPropagation();" style="font-style: italic;">
<img src="/assets/images/editor/icons/argos_entities.svg" class="input_icon" alt="Argos Entities icon">
<img src="/assets/images/editor/icons/internal_entities.svg" class="input_icon" alt="Internal Entities icon">
Argos Entities
</button>
<mat-action-list class="ml-4">

View File

@ -3,20 +3,21 @@
<div class="col-12">
<div class="row">
<mat-form-field class="col-6">
<mat-form-field class="col-12 col-md-6">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.PRIMARY-COLOR' | translate}}</mat-label>
<input matInput [formControl]="formGroup.get('cssColors')?.get('primaryColorInput')" required />
<ngx-colors
class="suffix"
matSuffix
ngx-colors-trigger
[overlayClassName]="mr-1"
[formControl]="formGroup.get('cssColors')?.get('primaryColor')"
></ngx-colors>
<mat-error *ngIf="formGroup.get('cssColors')?.get('primaryColor')?.hasError('backendError')">{{formGroup.get('cssColors')?.get('primaryColor')?.getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('cssColors')?.get('primaryColor')?.hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<mat-error *ngIf="formGroup.get('cssColors')?.get('primaryColor')?.hasError('invalidColor')">{{'GENERAL.VALIDATION.INVALID-COLOR' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-6">
<mat-form-field class="col-12 col-md-6">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.PRIMARY-COLOR-2' | translate}}</mat-label>
<input matInput [formControl]="formGroup.get('cssColors')?.get('primaryColor2Input')" required />
<ngx-colors
@ -29,7 +30,7 @@
<mat-error *ngIf="formGroup.get('cssColors')?.get('primaryColor2')?.hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<mat-error *ngIf="formGroup.get('cssColors')?.get('primaryColor2')?.hasError('invalidColor')">{{'GENERAL.VALIDATION.INVALID-COLOR' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-6">
<mat-form-field class="col-12 col-md-6">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.PRIMARY-COLOR-3' | translate}}</mat-label>
<input matInput [formControl]="formGroup.get('cssColors')?.get('primaryColor3Input')" required />
<ngx-colors
@ -42,7 +43,7 @@
<mat-error *ngIf="formGroup.get('cssColors')?.get('primaryColor3')?.hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<mat-error *ngIf="formGroup.get('cssColors')?.get('primaryColor3')?.hasError('invalidColor')">{{'GENERAL.VALIDATION.INVALID-COLOR' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-6">
<mat-form-field class="col-12 col-md-6">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.SECONDARY-COLOR' | translate}}</mat-label>
<input matInput [formControl]="formGroup.get('cssColors')?.get('secondaryColorInput')" required />
<ngx-colors
@ -59,12 +60,11 @@
</div>
<div class="col-12">
<div class="row actions-row">
<div class="col"></div>
<div class="col-auto" *ngIf="editorModel.id"><button mat-raised-button color="primary" (click)="delete()">
<div class="ml-auto col-auto" *ngIf="editorModel.id"><button class="normal-btn-sm" (click)="delete()">
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.RESET-TO-DEFAULT' | translate}}
</button>
</div>
<div class="col-auto"><button mat-raised-button color="primary" (click)="formSubmit()">
<div class="ml-auto col-auto"><button class="normal-btn-sm" (click)="formSubmit()">
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.SAVE' | translate}}
</button>
</div>

View File

@ -1,3 +1,7 @@
.css-colors {
}
::ng-deep .mat-mdc-form-field-icon-suffix {
margin-right: 0.2em;
}

View File

@ -1,6 +1,6 @@
<div *ngIf="formGroup" class="container-fluid default-user-locale">
<div class="row">
<div class="col-12">
<div class="col-12 col-md-4">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.TIMEZONE' | translate}}</mat-label>
<mat-select [formControl]="this.formGroup.get('defaultUserLocale')?.get('timezone')" name="culture">
@ -11,6 +11,8 @@
<mat-error *ngIf="formGroup.get('defaultUserLocale')?.get('timezone').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<mat-error *ngIf="formGroup.get('defaultUserLocale')?.get('timezone')?.hasError('backendError')">{{formGroup.get('defaultUserLocale')?.get('timezone')?.getError('backendError').message}}</mat-error>
</mat-form-field>
</div>
<div class="col-12 col-md-4">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.CULTURE' | translate}}</mat-label>
<mat-select [formControl]="this.formGroup.get('defaultUserLocale')?.get('culture')" name="culture">
@ -21,6 +23,8 @@
<mat-error *ngIf="formGroup.get('defaultUserLocale')?.get('culture').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<mat-error *ngIf="formGroup.get('defaultUserLocale')?.get('culture')?.hasError('backendError')">{{formGroup.get('defaultUserLocale')?.get('culture')?.getError('backendError').message}}</mat-error>
</mat-form-field>
</div>
<div class="col-12 col-md-4">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.LANGUAGE' | translate}}</mat-label>
<mat-select [formControl]="this.formGroup.get('defaultUserLocale')?.get('language')" name="language">
@ -34,12 +38,11 @@
</div>
<div class="col-12">
<div class="row actions-row">
<div class="col"></div>
<div class="col-auto" *ngIf="editorModel.id"><button mat-raised-button color="primary" (click)="delete()">
<div class="ml-auto col-auto" *ngIf="editorModel.id"><button class="normal-btn-sm" (click)="delete()">
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.RESET-TO-DEFAULT' | translate}}
</button>
</div>
<div class="col-auto"><button mat-raised-button color="primary" (click)="formSubmit()">
<div class="ml-auto col-auto"><button class="normal-btn-sm" (click)="formSubmit()">
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.SAVE' | translate}}
</button>
</div>

View File

@ -24,7 +24,7 @@
</div>
</div>
<div class="row" >
<div class="col-6">
<div class="col-12 col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.REPOSITORY-ID' | translate}}</mat-label>
<input matInput type="text" name="repositoryId" [formControl]="source.get('repositoryId')" required>
@ -32,7 +32,7 @@
<mat-error *ngIf="source.get('repositoryId').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-6">
<div class="col-12 col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.URL' | translate}}</mat-label>
<input matInput type="text" name="url" [formControl]="source.get('url')" required>
@ -40,7 +40,7 @@
<mat-error *ngIf="source.get('url').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-6">
<div class="col-12 col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.ISSUER-URL' | translate}}</mat-label>
<input matInput type="text" name="issuerUrl" [formControl]="source.get('issuerUrl')" required>
@ -48,7 +48,7 @@
<mat-error *ngIf="source.get('issuerUrl').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-6">
<div class="col-12 col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.CLIENT-ID' | translate}}</mat-label>
<input matInput type="text" name="clientId" [formControl]="source.get('clientId')" required>
@ -56,7 +56,7 @@
<mat-error *ngIf="source.get('clientId').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-6">
<div class="col-12 col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.CLIENT-SECRET' | translate}}</mat-label>
<input matInput type="text" name="clientSecret" [formControl]="source.get('clientSecret')" required>
@ -64,7 +64,7 @@
<mat-error *ngIf="source.get('clientSecret').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-6">
<div class="col-12 col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.SCOPE' | translate}}</mat-label>
<input matInput type="text" name="scope" [formControl]="source.get('scope')" required>
@ -72,7 +72,7 @@
<mat-error *ngIf="source.get('scope').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-6">
<div class="col-12 col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.PDF-TRANSFORMER-ID' | translate}}</mat-label>
<input matInput type="text" name="pdfTransformerId" [formControl]="source.get('pdfTransformerId')" required>
@ -80,7 +80,7 @@
<mat-error *ngIf="source.get('pdfTransformerId').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-6">
<div class="col-12 col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.RDA-TRANSFORMER-ID' | translate}}</mat-label>
<input matInput type="text" name="rdaTransformerId" [formControl]="source.get('rdaTransformerId')" required>
@ -94,12 +94,11 @@
</div>
<div class="col-12">
<div class="row actions-row">
<div class="col"></div>
<div class="col-auto" *ngIf="editorModel.id"><button mat-raised-button color="primary" (click)="delete()">
<div class="ml-auto col-auto" *ngIf="editorModel.id"><button class="normal-btn-sm" (click)="delete()">
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.RESET-TO-DEFAULT' | translate}}
</button>
</div>
<div class="col-auto"><button mat-raised-button color="primary" (click)="formSubmit()">
<div class="ml-auto col-auto"><button class="normal-btn-sm" (click)="formSubmit()">
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.SAVE' | translate}}
</button>
</div>

View File

@ -18,3 +18,7 @@
}
}
}
::ng-deep label {
margin: 0;
}

View File

@ -23,7 +23,7 @@
</div>
</div>
<div class="row" >
<div class="col-6">
<div class="col-12 col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.TRANSFORMER-ID' | translate}}</mat-label>
<input matInput type="text" name="transformerId" [formControl]="source.get('transformerId')" required>
@ -31,7 +31,7 @@
<mat-error *ngIf="source.get('transformerId').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-6">
<div class="col-12 col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.URL' | translate}}</mat-label>
<input matInput type="text" name="url" [formControl]="source.get('url')" required>
@ -39,7 +39,7 @@
<mat-error *ngIf="source.get('url').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-6">
<div class="col-12 col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.ISSUER-URL' | translate}}</mat-label>
<input matInput type="text" name="issuerUrl" [formControl]="source.get('issuerUrl')" required>
@ -47,7 +47,7 @@
<mat-error *ngIf="source.get('issuerUrl').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-6">
<div class="col-12 col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.CLIENT-ID' | translate}}</mat-label>
<input matInput type="text" name="clientId" [formControl]="source.get('clientId')" required>
@ -55,7 +55,7 @@
<mat-error *ngIf="source.get('clientId').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-6">
<div class="col-12 col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.CLIENT-SECRET' | translate}}</mat-label>
<input matInput type="text" name="clientSecret" [formControl]="source.get('clientSecret')" required>
@ -63,7 +63,7 @@
<mat-error *ngIf="source.get('clientSecret').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-6">
<div class="col-12 col-md-6">
<mat-form-field class="w-100">
<mat-label>{{'TENANT-CONFIGURATION-EDITOR.FIELDS.SCOPE' | translate}}</mat-label>
<input matInput type="text" name="scope" [formControl]="source.get('scope')" required>
@ -78,11 +78,11 @@
<div class="col-12">
<div class="row actions-row">
<div class="col"></div>
<div class="col-auto" *ngIf="editorModel.id"><button mat-raised-button color="primary" (click)="delete()">
<div class="col-auto" *ngIf="editorModel.id"><button class="normal-btn-sm" (click)="delete()">
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.RESET-TO-DEFAULT' | translate}}
</button>
</div>
<div class="col-auto"><button mat-raised-button color="primary" (click)="formSubmit()">
<div class="col-auto"><button class="normal-btn-sm" (click)="formSubmit()">
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.SAVE' | translate}}
</button>
</div>

View File

@ -7,25 +7,25 @@
</ngx-dropzone-preview>
</ngx-dropzone>
<div class="col-12 d-flex justify-content-center attach-btn">
<button *ngIf="!formGroup.get('logo')?.get('storageFileId')?.value" mat-button (click)="drop.showFileSelector()" type="button" class="attach-file-btn" [disabled]="formGroup.get('logo')?.get('storageFileId')?.disabled">
<button *ngIf="!formGroup.get('logo')?.get('storageFileId')?.value" (click)="drop.showFileSelector()" mat-button type="button" class="attach-file" [disabled]="formGroup.get('logo')?.get('storageFileId')?.disabled">
<mat-icon class="mr-2">upload</mat-icon>
<mat-label>{{ "TENANT-CONFIGURATION-EDITOR.ACTIONS.UPLOAD" | translate }}</mat-label>
<span>{{ "TENANT-CONFIGURATION-EDITOR.ACTIONS.UPLOAD" | translate }}</span>
</button>
<button *ngIf="formGroup.get('logo')?.get('storageFileId')?.value" mat-button (click)="download(formGroup.get('logo')?.get('storageFileId')?.value)" type="button" class="attach-file-btn">
<button *ngIf="formGroup.get('logo')?.get('storageFileId')?.value" (click)="download(formGroup.get('logo')?.get('storageFileId')?.value)" mat-button type="button" class="attach-file">
<mat-icon class="mr-2">download</mat-icon>
<mat-label>{{ "TENANT-CONFIGURATION-EDITOR.ACTIONS.DOWNLOAD" | translate }}</mat-label>
<span>{{ "TENANT-CONFIGURATION-EDITOR.ACTIONS.DOWNLOAD" | translate }}</span>
</button>
</div>
</div>
<div class="col-12">
<div class="row actions-row">
<div class="col"></div>
<div class="col-auto" *ngIf="editorModel.id"><button mat-raised-button color="primary" (click)="delete()">
<div class="col-auto" *ngIf="editorModel.id"><button class="normal-btn-sm" (click)="delete()">
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.RESET-TO-DEFAULT' | translate}}
</button>
</div>
<div class="col-auto"><button mat-raised-button color="primary" (click)="formSubmit()">
<div class="col-auto"><button class="normal-btn-sm" (click)="formSubmit()">
{{'TENANT-CONFIGURATION-EDITOR.ACTIONS.SAVE' | translate}}
</button>
</div>

View File

@ -1,3 +1,19 @@
.logo {
.attach-btn {
top: -20px;
}
.attach-file {
width: 156px;
height: 44px;
color: #ffffff;
background: var(--primary-color) 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #1e202029;
border-radius: 30px;
}
.attach-file:hover {
background-color: #ffffff;
border: 1px solid var(--primary-color);
color: var(--primary-color);
}

View File

@ -8,20 +8,25 @@
</div>
</div>
<div class="row">
<div class="col-12">
<mat-card appearance="outlined">
<mat-card-header>
<mat-card-title>{{'TENANT-CONFIGURATION-EDITOR.TITLE' | translate}}</mat-card-title>
</mat-card-header>
<mat-card-content>
<div class="row">
<mat-accordion class="col-12 headers-align">
<div class="row mt-3">
<div class="col-12">
<mat-accordion class="headers-align">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>{{'TENANT-CONFIGURATION-EDITOR.DEFAULT-USER-LOCALE.TITLE' | translate}}</mat-panel-title>
<mat-panel-description>{{'TENANT-CONFIGURATION-EDITOR.DEFAULT-USER-LOCALE.HINT' | translate}}</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="mt-3">
<app-tenant-configuration-default-user-locale-editor></app-tenant-configuration-default-user-locale-editor>
</div>
</ng-template>
</mat-expansion-panel>
<mat-expansion-panel>
@ -63,8 +68,11 @@
</mat-accordion>
</div>
</div>
</mat-card-content>
</mat-card>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,81 +1,3 @@
<div class="login-bg d-flex flex-column align-items-center justify-content-center" [ngClass]="{'login-screen': !mergeUsers}">
<div>
</div>
<!-- <div class="login-screen login-bg d-flex flex-column align-items-center justify-content-center">
<div class="login-logo"></div>
<div class="card login-card">
<div class="container card-header">
<div *ngIf="hasGoogleOauth()" class="row social-btns">
<div class="col-auto">
<button mat-icon-button id="googleSignInButton" class="login-social-button">
<i class="fa fa-google"></i>
</button>
</div>
<div *ngIf="hasLinkedInOauth()" class="col-auto">
<button mat-icon-button class="login-social-button">
<i class="fa fa-linkedin" (click)="linkedInLogin()"></i>
</button>
</div>
<div *ngIf="hasFacebookOauth()" class="col-auto">
<button mat-icon-button (click)="facebookLogin()" class="login-social-button">
<i class="fa fa-facebook-square"></i>
</button>
</div>
<div *ngIf="hasTwitterOauth()" class="col-auto">
<button mat-icon-button (click)="twitterLogin()" class="login-social-button">
<i class="fa fa-twitter"></i>
</button>
</div>
</div>
<div class="w-100"></div>
<div class="row pt-2 mb-4 accesss-methods"> -->
<!-- <div class="col justify-content-center"> -->
<!-- <div *ngIf="hasB2AccessOauth()" class="col-auto logo">
<button class="b2access-button" mat-icon-button (click)="b2AccessLogin()" class="login-social-button">
<span class="iconmedium"></span> -->
<!-- <span></span> -->
<!-- </button>
</div>
<div *ngIf="hasOrcidOauth()" class="col-auto orcid-logo">
<button class="orcid-button" mat-icon-button (click)="orcidLogin()" class="login-social-button">
<span class="orcidIconMedium"></span> -->
<!-- <span></span> -->
<!-- </button>
</div>
<div *ngIf="hasOpenAireOauth()" class="col-auto openaire-logo">
<button class="openaire-button" mat-icon-button (click)="openaireLogin()" class="login-social-button">
<span class="openaireIcon"></span> -->
<!-- <span></span> -->
<!-- </button>
</div> -->
<!-- </div> -->
<!-- </div>
<div *ngIf="hasConfigurableProviders()" class="row pt-2 mb-4 accesss-methods">
<div *ngFor="let provider of this.configurableProviderService.providers" class="col-auto configurable-logo">
<button mat-icon-button class="configurable-button" (click)="configurableLogin(provider)" class="login-social-button">
<span class="configurableIcon">{{provider.name}}</span>
</button>
</div>
</div>
<div *ngIf="hasZenodoOauth()" class="col-auto zenodo-logo">
<button class="zenodo-button" mat-icon-button (click)="zenodoLogin()" class="login-social-button">
<span class="zenodoIcon"></span> -->
<!-- <span></span> -->
<!-- </button>
</div>
</div>
<div class="card-footer">
<h4 class="text-uppercase">
<strong>{{ 'HOME.LOGIN.TITLE' | translate }}</strong>
</h4>
<br />
<h5>{{ 'HOME.LOGIN.TEXT' | translate }}</h5>
</div>
</div>
</div> -->

View File

@ -1,401 +0,0 @@
.login-screen {
// margin-top: 70px;
min-height: calc(100vh - 10px);
}
.login-card {
// width: auto;
width: 510.92px;
height: 517.44px;
margin-top: 0;
}
.card {
// box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.14);
box-shadow: 0px 1px 3px #00000038;
border-radius: 6px;
color: rgba(0, 0, 0, 0.87);
background: #fff;
}
.card-raised {
box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.42), 0 4px 25px 0px rgba(0, 0, 0, 0.12),
0 8px 10px -5px rgba(0, 0, 0, 0.2);
}
.page-title {
margin-top: 40px;
}
.title {
text-align: center;
font: Bold 38px/82px Roboto;
height: 60px;
letter-spacing: -0.95px;
color: var(--primary-color-2);
margin-top: 11px;
margin-bottom: 21px;
}
.line {
border-top: 5px solid var(--primary-color-2);
width: 116px;
margin-bottom: 97px;
}
.container {
height: 100%;
position: relative;
z-index: 1;
padding: 15px 30px;
}
@-webkit-keyframes card {
from {
top: -40px;
}
to {
top: 0;
}
}
@keyframes card {
from {
top: -40px;
}
to {
top: 0;
}
}
.card {
position: relative;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 50px;
top: -50px;
-webkit-animation-name: card;
-moz-animation-name: card;
-o-animation-name: card;
animation-name: card;
-webkit-animation-duration: 600ms;
-moz-animation-duration: 600ms;
-o-animation-duration: 600ms;
animation-duration: 600ms;
-webkit-animation-fill-mode: forwards;
-moz-animation-fill-mode: forwards;
-o-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
.card-header {
position: relative;
overflow: hidden;
top: -50px;
width: 100%;
min-height: 200px;
padding: 25px;
border-radius: 3px;
background: #0c7489;
// background: rgb(0, 112, 192);
display: flex;
flex-direction: column;
align-items: center;
}
.card-header h4 {
font-weight: 400;
color: #fff;
margin-bottom: 25px;
margin-top: 5px;
}
// .social-btns {
// height: 6em;
// justify-content: center;
// }
// .social-btns i {
// font-size: 2.5em;
// padding: 0.8em;
// color: #fff;
// }
// .social-btns .col {
// flex-grow: 0;
// }
// .social-btns i:hover {
// background-color: #f5f5f51c;
// border-radius: 60%;
// }
.accesss-methods {
height: 5em;
justify-content: center;
}
.accesss-methods .col-auto:hover {
background-color: #f5f5f51c;
border-radius: 100%;
}
.accesss-methods .logo {
flex-grow: 0;
padding-top: 21px;
padding-bottom: 21px;
}
.accesss-methods .openaire-logo {
flex-grow: 0;
padding-top: 21px;
padding-bottom: 21px;
margin-top: 5px;
height: 90px;
}
.accesss-methods .orcid-logo {
height: 75px;
padding-top: 8px;
margin-top: 13px;
}
.accesss-methods .configurable-logo {
flex-grow: 0;
padding-top: 21px;
padding-bottom: 21px;
margin-top: 5px;
height: 90px;
}
.accesss-methods .zenodo-logo {
height: 75px;
padding-top: 8px;
margin-top: 13px;
}
.tip {
margin-top: -20px;
}
.form-row,
.card-form,
.mat-form-field {
width: 100%;
}
.card-form {
padding: 5px;
}
.form-row {
position: relative;
display: flex;
align-items: center;
margin-top: 13px;
}
.form-row i {
position: relative;
top: -5px;
margin-right: 15px;
color: #555;
}
.card-footer {
padding: 0;
border-radius: 0;
align-items: start;
flex-direction: column;
}
.card-footer button {
color: #e91e63;
}
.btn span.icon {
background: url(img/b2access_small.png) no-repeat;
float: left;
width: 45px;
height: 25px;
}
span.googleIcon {
background: url("../../../../assets/images/argos-login/NoPath\ -\ Copy\ \(2\).png") no-repeat;
}
span.facebookIcon {
background: url("../../../../assets/images/argos-login/NoPath\ -\ Copy\ \(4\).png") no-repeat;
}
span.twitterIcon {
background: url("../../../../assets/images/argos-login/NoPath\ -\ Copy\ \(5\).png") no-repeat;
}
span.googleIcon,
span.facebookIcon,
span.twitterIcon {
float: left;
transform: scale(0.8);
width: 45px;
height: 45px;
}
#googleSignInButton,
.facebookIconButton,
.twitterIconButton,
.openaireIconButton,
.orcidIconMediumButton,
.iconmediumButton {
width: 60px !important;
height: 60px !important;
}
#googleSignInButton:hover,
.facebookIconButton:hover,
.twitterIconButton:hover,
.openaireIconButton:hover,
.orcidIconMediumButton:hover,
.iconmediumButton:hover {
// background-color: var(--primary-color)3b;
background-color: #ececec;
border-radius: 60%;
}
span.openaireIcon {
background: url("../../../../assets/images/argos-login/NoPath\ -\ Copy\ \(6\).png") no-repeat;
background-position: center;
float: right;
transform: scale(0.8);
width: 50px;
height: 45px;
}
span.orcidIconMedium {
background: url("../../../../assets/images/argos-login/NoPath\ -\ Copy.png") no-repeat;
background-position: center;
float: left;
transform: scale(0.8);
width: 50px;
height: 45px;
}
span.iconmedium {
background: url("../../../../assets/images/argos-login/NoPath\ -\ Copy\ \(7\).png") no-repeat;
float: left;
transform: scale(0.85);
width: 67px;
height: 40px;
}
span.configurableIcon {
float: right;
transform: scale(0.85);
width: 50px;
height: 50px;
}
span.zenodoIcon {
background: url("../../../../assets/images/argos-login/zenodo-gradient-200.png") no-repeat;
background-position: center;
float: right;
transform: scale(0.7);
width: 200px;
height: 80px;
}
.b2access-button {
margin-top: 10px;
width: fit-content;
}
.orcid-button {
margin-top: 10px;
width: fit-content;
}
.openaire-button {
margin-top: 10px;
width: fit-content;
}
.configurable-button {
margin-top: 10px;
width: fit-content;
}
.zenodo-button {
margin-top: 10px;
width: fit-content;
}
// .login-logo {
// background: url(img/open-dmp.png) no-repeat;
// width: 273px;
// height: 300px;
// background-size: cover;
// }
.laptop-img {
background: url("../../../../assets/images/login-bottom-image.png") no-repeat;
width: 164px;
height: 200px;
position: relative;
top: -140px;
margin-bottom: -140px;
left: 243px;
border-top: none;
}
.login-bg {
// background: url(img/login_bg.png) no-repeat;
background-size: cover;
}
.login-social-button {
width: auto;
height: auto;
}
@media (min-width: 1200px) {
.container {
width: 100%;
}
}
@media (min-width: 992px) {
.container {
width: 100%;
}
}
@media (min-width: 768px) {
.container {
width: 100%;
}
}
@media (min-width: 401px) and (max-width: 560px) {
.social-btns i {
padding: 0.4em !important;
}
.accesss-methods {
padding-top: 1em;
}
}
@media (min-width: 0px) and (max-width: 400px) {
.social-btns i {
padding: 0.4em !important;
}
.card-header {
height: 350px !important;
}
.accesss-methods {
padding-top: 1em;
}
}

View File

@ -18,7 +18,6 @@ export class LoginComponent extends BaseComponent implements OnInit {
public auth2: any;
private returnUrl: string;
//public cofigurableProviders: ConfigurableProvider[];
constructor(
private zone: NgZone,

View File

@ -112,7 +112,7 @@
<span class="material-icons">chevron_right</span>
</div>
<button [disabled]="saving" (click)="saveAndClose()" *ngIf="(step === maxStep) && !isLocked && formGroup.get('descriptionTemplateId').value && !viewOnly" mat-raised-button type="button" class="col-auto stepper-btn add-description-btn ml-auto">
{{ 'DESCRIPTION-EDITOR.ACTIONS.SAVE' | translate }}
{{ 'DESCRIPTION-EDITOR.ACTIONS.SAVE-AND-CLOSE' | translate }}
</button>
</div>
<div class="col-auto pr-0">

View File

@ -49,6 +49,7 @@ import { DmpDescriptionTemplate } from '@app/core/model/dmp/dmp';
import { FileTransformerEntityType } from '@app/core/common/enum/file-transformer-entity-type';
import { nameof } from 'ts-simple-nameof';
import { AbstractControl, UntypedFormArray, UntypedFormGroup } from '@angular/forms';
import { TableOfContentsValidationService } from './table-of-contents/services/table-of-contents-validation-service';
@Component({
selector: 'app-description-editor-component',
@ -60,6 +61,7 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
isNew = true;
isDeleted = false;
isCopy = false;
item: Description;
fieldsetIdWithFocus: string;
fileTransformerEntityTypeEnum = FileTransformerEntityType;
@ -99,6 +101,7 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
private dmpService: DmpService,
public visibilityRulesService: VisibilityRulesService,
public fileTransformerService: FileTransformerService,
public tocValidationService: TableOfContentsValidationService
) {
super(dialog, language, formService, router, uiNotificationService, httpErrorHandlingService, filterService, datePipe, route, queryParamsService, lockService, authService, configurationService);
@ -124,10 +127,12 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
const itemId = params['id'];
const dmpId = params['dmpId'];
const copyDmpId = params['copyDmpId'];
const dmpSectionId = params['dmpSectionId'];
const isPublicDescription = params['public'];
const newDmpId = params['newDmpId'];
if(copyDmpId && !dmpId && dmpSectionId) this.isCopy = true;
@ -623,12 +628,13 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
refreshData(): void {
this.getItem(this.editorModel.id, (data: Description) => this.prepareForm(data));
this.tocValidationService.validateForm();
}
refreshOnNavigateToData(id?: Guid): void {
this.formGroup.markAsPristine();
if (this.isNew) {
if (this.isNew || this.isCopy) {
let route = [];
route.push('/descriptions/edit/' + id);
this.router.navigate(route, { queryParams: { 'lookup': this.queryParamsService.serializeLookup(this.lookupParams), 'lv': ++this.lv }, replaceUrl: true, relativeTo: this.route });
@ -841,7 +847,7 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
Object.keys(formControl.errors).forEach(key => {
if (key === 'required') {
// errors.push(this.language.instant(name + ": " + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.REQUIRED')));
if(name == 'label') errors.push(this.language.instant(this.language.instant('DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION') + ": " + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.REQUIRED')));
if(name == 'label') errors.push(this.language.instant(this.language.instant('DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TITLE') + ": " + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.REQUIRED')));
else if(name == 'descriptionTemplateId') errors.push(this.language.instant(this.language.instant('DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION-TEMPLATE') + ": " + this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.REQUIRED')));
}
else if (key === 'email') {
@ -1016,6 +1022,10 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
}
});
this.formGroup.get('properties').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(next => this.tocValidationService.validateForm());
// // const labelSubscription =
// this.formGroup.get('label').valueChanges
// .pipe(takeUntil(this._destroyed))
@ -1261,6 +1271,7 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
finalize() {
this.formService.removeAllBackEndErrors(this.formGroup);
this.formService.touchAllFormFields(this.formGroup);
this.tocValidationService.validateForm();
if (!this.isFormValid()) {
this.dialog.open(FormValidationErrorsDialogComponent, {
data: {

View File

@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { DescriptionStatus } from '@app/core/common/enum/description-status';
import { AppPermission } from '@app/core/common/enum/permission.enum';
import { DescriptionTemplate, DescriptionTemplateBaseFieldData, DescriptionTemplateDefinition, DescriptionTemplateExternalDatasetData, DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplateMultiplicity, DescriptionTemplatePage, DescriptionTemplateReferenceTypeData, DescriptionTemplateRule, DescriptionTemplateSection, DescriptionTemplateSelectData, DescriptionTemplateSelectOption, DescriptionTemplateUploadData, DescriptionTemplateUploadOption } from '@app/core/model/description-template/description-template';
import { Description, DescriptionExternalIdentifier, DescriptionField, DescriptionPropertyDefinition, DescriptionPropertyDefinitionFieldSet, DescriptionPropertyDefinitionFieldSetItem, DescriptionReference, DescriptionReferenceData, DescriptionTag } from '@app/core/model/description/description';
@ -204,8 +205,12 @@ export class DescriptionEditorResolver extends BaseEditorResolver {
return this.dmpService.getSingle(Guid.parse(copyDmpId), DescriptionEditorResolver.dmpLookupFields()).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed), concatMap(dmp => {
return this.descriptionService.getSingle(Guid.parse(id), DescriptionEditorResolver.cloneLookupFields()).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed), map(description => {
description.id = null;
description.hash = null;
description.status = DescriptionStatus.Draft;
description.dmp = dmp;
description.dmpDescriptionTemplate = {
id: dmp.dmpDescriptionTemplates.filter(x => x.sectionId == Guid.parse(dmpSectionId) && x.descriptionTemplateGroupId == description.descriptionTemplate.groupId)[0].id,
sectionId: Guid.parse(dmpSectionId)
}
return description;

View File

@ -21,7 +21,8 @@ const routes: Routes = [
data: {
...BreadcrumbService.generateRouteDataConfiguration({
title: 'BREADCRUMBS.EDIT-DESCRIPTION'
})
}),
title: 'DESCRIPTION-EDITOR.TITLE-EDIT-DESCRIPTION'
// ,
// authContext: {
// permissions: [AppPermission.EditDescription]
@ -39,7 +40,8 @@ const routes: Routes = [
data: {
...BreadcrumbService.generateRouteDataConfiguration({
title: 'BREADCRUMBS.EDIT-DESCRIPTION'
})
}),
title: 'DESCRIPTION-EDITOR.TITLE-EDIT-DESCRIPTION'
// ,
// authContext: {
// permissions: [AppPermission.EditDescription]
@ -57,7 +59,8 @@ const routes: Routes = [
data: {
...BreadcrumbService.generateRouteDataConfiguration({
title: 'BREADCRUMBS.EDIT-DESCRIPTION'
})
}),
title: 'DESCRIPTION-EDITOR.TITLE-NEW'
// ,
// authContext: {
// permissions: [AppPermission.EditDescription]
@ -75,7 +78,8 @@ const routes: Routes = [
data: {
...BreadcrumbService.generateRouteDataConfiguration({
title: 'BREADCRUMBS.EDIT-DESCRIPTION'
})
}),
title: 'DESCRIPTION-EDITOR.TITLE-NEW'
// ,
// authContext: {
// permissions: [AppPermission.EditDescription]

View File

@ -82,7 +82,7 @@
</div>
</div>
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.CHECK_BOX" class="col-12">
<mat-checkbox [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" [required]="isRequired">
<mat-checkbox [formControl]="propertiesFormGroup?.get(field.id).get('textValue')">
{{field.data.label}}</mat-checkbox>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('textValue').getError('backendError').message}}</mat-error>
</div>

View File

@ -164,7 +164,7 @@ export class DescriptionFormFieldComponent extends BaseComponent implements OnIn
// }
break;
case DescriptionTemplateFieldType.CHECK_BOX:
if (this.propertiesFormGroup?.get(this.field.id).get('textValue').value == "false") this.propertiesFormGroup?.get(this.field.id).get('textValue').setValue(undefined);
this.propertiesFormGroup?.get(this.field.id).get('textValue').setValue(this.propertiesFormGroup?.get(this.field.id).get('textValue').value === 'true');
break;
}

View File

@ -0,0 +1,13 @@
import { EventEmitter, Injectable } from "@angular/core";
@Injectable()
export class TableOfContentsValidationService {
private _validateFormEvent: EventEmitter<any> = new EventEmitter<any>();
get validateFormEvent(): EventEmitter<any> {
return this._validateFormEvent;
}
validateForm(): void {
this._validateFormEvent.emit();
}
}

View File

@ -6,6 +6,7 @@ import { ToCEntry } from '../models/toc-entry';
import { ToCEntryType } from '../models/toc-entry-type.enum';
import { DescriptionFieldIndicator } from '../../description-editor.model';
import { Observable, Subscription, map } from 'rxjs';
import { TableOfContentsValidationService } from '../services/table-of-contents-validation-service';
@Component({
selector: 'table-of-contents-internal',
@ -34,8 +35,7 @@ export class TableOfContentsInternal implements OnInit, OnDestroy {
tocEntriesStateSubscriptions: Subscription[] = [];
tocEntriesStateMap: Map<string, boolean> = new Map<string, boolean>();
constructor() {
}
constructor(private tocValidationService: TableOfContentsValidationService) { }
ngOnInit(): void {
// console.log('component created' + JSON.stringify(this.tocentries));
@ -90,10 +90,10 @@ export class TableOfContentsInternal implements OnInit, OnDestroy {
refreshErrorIndicators(): void {
this.updatedMap = this.updateMap(this.tocentries, this.parentMap);
for (let entry of this.tocentries) {
this.tocEntriesStateMap.set(entry.id, false);
this.tocEntriesStateMap.set(entry.id, this.hasErrors(entry.id));
this.tocEntriesStateSubscriptions.push(
this.propertiesFormGroup.statusChanges
this.tocValidationService.validateFormEvent
.pipe(map(() => this.hasErrors(entry.id)))
.subscribe(next => {
this.tocEntriesStateMap.set(entry.id, next);

View File

@ -5,11 +5,12 @@ import { TableOfContentsInternal } from './table-of-contents-internal/table-of-c
import { MatIconModule } from '@angular/material/icon';
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
import { TableOfContentsComponent } from './table-of-contents.component';
import { TableOfContentsValidationService } from './services/table-of-contents-validation-service';
@NgModule({
imports: [CommonModule, RouterModule, MatIconModule],
declarations: [TableOfContentsComponent, TableOfContentsInternal],
exports: [TableOfContentsComponent],
providers: [VisibilityRulesService]
providers: [VisibilityRulesService, TableOfContentsValidationService]
})
export class TableOfContentsModule { }

View File

@ -1,12 +1,3 @@
.header-image {
background: url("/assets/images/new-dashboard-bg.png") no-repeat;
background-size: cover;
margin-top: 70px;
min-height: 15em;
position: relative;
}
.header-title {
text-align: left;
font-size: 1.25rem;

View File

@ -52,7 +52,7 @@
}
.id-btn {
background: url("../../../../assets/images/NoPath.png") no-repeat center;
background: url("../../../../assets/images/orcid.png") no-repeat center;
width: 1em;
margin-right: 0.3em;
align-self: center;

View File

@ -78,19 +78,26 @@
</div>
<div class="row">
<div class="col-auto dmp-stepper" *ngIf="this.step != 0">
<div class="stepper-title">{{'DMP-EDITOR.TITLE' | translate}}</div>
<div class="stepper-options">
<!-- <div class="col-auto dmp-stepper" *ngIf="this.step != 0"> -->
<div class="col-12 col-md-3 pr-md-0" *ngIf="this.step != 0">
<div class="row stepper-title">
<div class="col-12 pl-0">
<span>{{'DMP-EDITOR.TITLE' | translate}}</span>
</div>
</div>
<div class="row stepper-options">
<!-- try col-12 too -->
<div class="col-auto">
<ol class="stepper-list" start="1">
<div *ngIf="selectedBlueprint?.definition && this.step !== 0">
<!-- <div *ngIf="selectedBlueprint?.definition"> -->
<div *ngFor="let section of selectedBlueprint?.definition?.sections; let i=index">
<!-- <div *ngFor="let section of selectedBlueprint?.definition?.sections; let i=index"> -->
<ng-container *ngFor="let section of selectedBlueprint?.definition?.sections; let i=index">
<li (click)="changeStep(i + 1)" [ngClass]="{'active': this.step === (i + 1), 'text-danger': hasErrors(section.id) }">{{section.label}}</li>
<ol class="descriptionsInSection">
<li *ngFor="let description of descriptionsInSection(section.id); let descriptionIndex = index" (click)="editDescription(description.id, false)" class="active-description">
<div class="d-flex flex-direction-row">
<div class="label" matTooltip="{{description.label}}">{{'DMP-EDITOR.DESCRIPTION' | translate}}: {{ description.label }}</div>
<mat-icon *ngIf="description.status !== descriptionStatusEnum.Finalized && canDeleteSection(section.id) && !formGroup.disabled" [ngClass]="{'drag-handle-disabled': formGroup.disabled}" class="ml-2 mr-2 remove-description size-16" matTooltip="{{'DMP-EDITOR.ACTIONS.DELETE' | translate}}" (click)="$event.stopPropagation(); removeDescription(description.id)">close</mat-icon>
<div (click)="$event.stopPropagation(); removeDescription(description.id)"><mat-icon *ngIf="description.status !== descriptionStatusEnum.Finalized && canDeleteSection(section.id) && !formGroup.disabled" [ngClass]="{'drag-handle-disabled': formGroup.disabled}" class="ml-2 mr-2 remove-description size-16" matTooltip="{{'DMP-EDITOR.ACTIONS.DELETE' | translate}}">close</mat-icon></div>
<mat-icon *ngIf="description.status === descriptionStatusEnum.Finalized" class="ml-2 mr-2 status-icon check-icon size-16" matTooltip="{{'TYPES.DESCRIPTION-STATUS.FINALIZED' | translate}}">check</mat-icon>
</div>
</li>
@ -102,26 +109,35 @@
</a>
</li>
</ul>
</div>
</ng-container>
</div>
</ol>
</div>
<div class="stepper-actions" *ngIf="this.step !== 0">
<div mat-raised-button type="button" class="col-auto previous stepper-btn mr-2 ml-auto" [ngClass]="{'previous-disabled': this.step === 1}" (click)="previousStep()">
</div>
<!-- TODO -->
<div class="row justify-content-around" *ngIf="this.step !== 0">
<div class="col-auto mb-1">
<div mat-raised-button type="button" class="previous stepper-btn mr-2" [ngClass]="{'previous-disabled': this.step === 1}" (click)="previousStep()">
<span class="material-icons">chevron_left</span>
<div>{{'DMP-EDITOR.ACTIONS.PREVIOUS-STEP' | translate}}</div>
</div>
</div>
<div class="col-auto mb-1">
<div *ngIf="this.step < this.maxSteps" mat-raised-button type="button" class="col-auto stepper-btn ml-auto" [ngClass]="{ 'next-disabled': this.step === this.maxSteps, 'next': this.step < selectedBlueprint?.definition?.sections?.length, 'description-next': this.step >= selectedBlueprint?.definition?.sections?.length }" (click)="nextStep()">
<div>{{'DMP-EDITOR.ACTIONS.NEXT-STEP' | translate}}</div>
<span class="material-icons">chevron_right</span>
</div>
</div>
<div class="col-auto pr-0" *ngIf="this.step !== 0">
</div>
<!-- TODO -->
<div class="row" *ngIf="this.step !== 0">
<div class="col-12">
<app-dmp-form-progress-indication class="col-12" *ngIf="formGroup && !formGroup.disabled && !lockStatus" [formGroup]="formGroup"></app-dmp-form-progress-indication>
</div>
</div>
</div>
<div class="col-auto form" id="editor-form" *ngIf="this.step !== 0">
<div class="col-12 col-md form" id="editor-form" *ngIf="this.step !== 0">
<div *ngIf="selectedBlueprint?.definition">
<div *ngFor="let section of selectedBlueprint?.definition?.sections; let i=index">
<div class="section-info" [hidden]="this.step !== (i + 1)">
@ -299,8 +315,7 @@
<div class="heading">{{'DMP-EDITOR.FIELDS.DESCRIPTION-TEMPLATES' | translate}}</div>
<mat-form-field class="w-100">
<mat-label>{{'DMP-EDITOR.FIELDS.DESCRIPTION-TEMPLATES-HINT' | translate}}</mat-label>
<!-- <app-multiple-auto-complete placeholder="{{'DMP-EDITOR.FIELDS.DESCRIPTION-TEMPLATES-HINT' | translate}}" [hidePlaceholder]="true" required='true' [formControl]="formGroup.get('descriptionTemplates').get(section.id)" [configuration]="getDescriptionTemplateMultipleAutoCompleteConfiguration(section.id)" (optionActionClicked)="onPreviewDescriptionTemplate($event, section.id)"> -->
<app-multiple-auto-complete placeholder="{{'DMP-EDITOR.FIELDS.DESCRIPTION-TEMPLATES-HINT' | translate}}" [hidePlaceholder]="true" required='true' [formControl]="formGroup.get('descriptionTemplates').get(section.id)" [configuration]="descriptionTemplateService.descriptionTempalteGroupMultipleAutocompleteConfiguration" (optionActionClicked)="onPreviewDescriptionTemplate($event, section.id)" (optionRemoved)="onRemoveDescriptionTemplate($event, section.id)">
<app-multiple-auto-complete placeholder="{{'DMP-EDITOR.FIELDS.DESCRIPTION-TEMPLATES-HINT' | translate}}" [hidePlaceholder]="true" required='true' [formControl]="formGroup.get('descriptionTemplates').get(section.id)" [configuration]="getDescriptionTemplateMultipleAutoCompleteConfiguration(section.id)" (optionActionClicked)="onPreviewDescriptionTemplate($event, section.id)" (optionRemoved)="onRemoveDescriptionTemplate($event, section.id)">
</app-multiple-auto-complete>
<mat-error *ngIf="formGroup.get('descriptionTemplates').get(section.id).hasError('backendError')">{{formGroup.get('descriptionTemplates').get(section.id).getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('descriptionTemplates').get(section.id).hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>

View File

@ -243,7 +243,7 @@ mat-icon.size-16 {
// width: calc(100% - 366px);
position: relative;
left: 362px;
// left: 362px;
width: calc(100% - 366px);
overflow-y: auto;
height: calc(100vh - 218px);

View File

@ -1,7 +1,7 @@
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { DatePipe } from '@angular/common';
import { Component, EventEmitter, OnInit } from '@angular/core';
import { FormArray, UntypedFormArray, UntypedFormGroup } from '@angular/forms';
import { Component, OnInit } from '@angular/core';
import { FormArray, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Router } from '@angular/router';
import { DescriptionStatus } from '@app/core/common/enum/description-status';
@ -17,6 +17,7 @@ import { DmpUserType } from '@app/core/common/enum/dmp-user-type';
import { IsActive } from '@app/core/common/enum/is-active.enum';
import { LockTargetType } from '@app/core/common/enum/lock-target-type';
import { AppPermission } from '@app/core/common/enum/permission.enum';
import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
import { DescriptionSectionPermissionResolver } from '@app/core/model/description/description';
import { DmpBlueprint, DmpBlueprintDefinitionSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
import { Dmp, DmpPersist } from '@app/core/model/dmp/dmp';
@ -35,9 +36,10 @@ import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/serv
import { UserService } from '@app/core/services/user/user.service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { QueryParamsService } from '@app/core/services/utilities/query-params.service';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { MultipleAutoCompleteCanRemoveItem } from '@app/library/auto-complete/multiple/multiple-auto-complete.component';
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { DescriptionTemplatePreviewDialogComponent } from '@app/ui/admin/description-template/description-template-preview/description-template-preview-dialog.component';
import { BaseEditor } from '@common/base/base-editor';
import { FormService } from '@common/forms/form-service';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
@ -45,14 +47,10 @@ import { HttpErrorHandlingService } from '@common/modules/errors/error-handling/
import { FilterService } from '@common/modules/text-filter/filter-service';
import { Guid } from '@common/types/guid';
import { TranslateService } from '@ngx-translate/core';
import { Observable, interval, of } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { DmpEditorModel, DmpFieldIndicator } from './dmp-editor.model';
import { DmpEditorResolver } from './dmp-editor.resolver';
import { DmpEditorService } from './dmp-editor.service';
import { DescriptionTemplatePreviewDialogComponent } from '@app/ui/admin/description-template/description-template-preview/description-template-preview-dialog.component';
import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
@Component({
selector: 'app-dmp-editor',
@ -260,7 +258,10 @@ export class DmpEditorComponent extends BaseEditor<DmpEditorModel, Dmp> implemen
}
refreshData(): void {
this.getItem(this.editorModel.id, (data: Dmp) => this.prepareForm(data));
this.getItem(this.editorModel.id, (data: Dmp) => {
this.prepareForm(data)
if (this.isNew === false) this.nextStep();
});
}
refreshOnNavigateToData(id?: Guid): void {
@ -636,7 +637,7 @@ export class DmpEditorComponent extends BaseEditor<DmpEditorModel, Dmp> implemen
}
}
canRemoveDescriptionTemplate(item: DescriptionTemplate, sectionId){
canRemoveDescriptionTemplate(item: DescriptionTemplate, sectionId): MultipleAutoCompleteCanRemoveItem {
if (item) {
const descriptionsInSection = this.descriptionsInSection(sectionId);
@ -644,13 +645,17 @@ export class DmpEditorComponent extends BaseEditor<DmpEditorModel, Dmp> implemen
for (let index = 0; index < descriptionsInSection.length; index++) {
const description = descriptionsInSection[index];
if (description.dmpDescriptionTemplate?.descriptionTemplateGroupId === item.groupId) {
return {canRemove: false,
return {
canRemove: false,
message: 'DMP-EDITOR.UNSUCCESSFUL-REMOVE-TEMPLATE'
} as CanRemoveDescriptionTemplate
} as MultipleAutoCompleteCanRemoveItem
}
}
}
}
return {
canRemove: true,
} as MultipleAutoCompleteCanRemoveItem;
}
//
@ -666,8 +671,3 @@ export class DmpEditorComponent extends BaseEditor<DmpEditorModel, Dmp> implemen
return this.languageInfoService.getLanguageInfoValues();
}
}
export interface CanRemoveDescriptionTemplate {
canRemove: boolean;
message: string;
}

View File

@ -13,14 +13,16 @@ const routes: Routes = [
path: 'new',
loadChildren: () => import('./dmp-editor-blueprint/dmp-editor.module').then(m => m.DmpEditorModule),
data: {
breadcrumb: true
breadcrumb: true,
title: 'DMP-EDITOR.TITLE-NEW'
}
},
{
path: 'edit',
loadChildren: () => import('./dmp-editor-blueprint/dmp-editor.module').then(m => m.DmpEditorModule),
data: {
breadcrumb: true
breadcrumb: true,
title: 'DMP-EDITOR.TITLE-EDIT'
}
},
{

View File

@ -60,14 +60,6 @@
color: var(--primary-color-3);
}
.header-image {
background: url("/assets/images/new-dashboard-bg.png") no-repeat;
background-size: cover;
margin-top: 70px;
min-height: 15em;
position: relative;
}
.header-title {
text-align: left;
font-size: 1.25rem;

View File

@ -36,7 +36,7 @@
// ********BUTTONS********
.id-btn {
background: url("../../../../assets/images/NoPath.png") no-repeat center;
background: url("../../../../assets/images/orcid.png") no-repeat center;
width: 1em;
margin-right: 0.3em;
align-self: center;

View File

@ -8,7 +8,7 @@ const routes: Routes = [
component: DmpOverviewComponent,
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.DATASET-OVERVIEW'
title: 'GENERAL.TITLES.PLAN-OVERVIEW'
},
},
{
@ -16,7 +16,7 @@ const routes: Routes = [
component: DmpOverviewComponent,
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.DATASET-OVERVIEW'
title: 'GENERAL.TITLES.PLAN-OVERVIEW'
},
}
];

View File

@ -3,7 +3,8 @@
<mat-list class="nav mat-list" *ngFor="let groupMenuItem of groupMenuItems; let firstGroup = first; let i = index" [class.nav-list-item]="showItem(groupMenuItem)" [class.nav-list-item-hidden]="!showItem(groupMenuItem)" [ngClass]="{'flex-grow-1': i == groupMenuItems.length - 2}">
<div *ngIf="showItem(groupMenuItem);">
<hr *ngIf="!firstGroup">
<mat-list-item routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}" *ngFor="let groupMenuRoute of groupMenuItem.routes; let first = first" class="nav-item" [ngClass]="{'mt-4': first && firstGroup}">
<mat-list-item routerLinkActive="active" [isActiveMatchOptions]="{ paths: 'exact', queryParams: 'ignored' }" *ngFor="let groupMenuRoute of groupMenuItem.routes; let first = first" class="nav-item" [ngClass]="{'mt-4': first && firstGroup}">
<!-- {{ groupMenuRoute |json }} -->
<a class="new-dmp nav-link nav-row" *ngIf="groupMenuRoute.path !== '/contact-support' && groupMenuRoute.path !== '/co-branding' && groupMenuRoute.path !== '/feedback' && groupMenuRoute.path !== '/descriptions'" [routerLink]="[groupMenuRoute.path]" [ngClass]="{'dmp-tour': groupMenuRoute.path == '/plans'}">
<i class="material-symbols-outlined icon">{{ groupMenuRoute.icon }}</i>
<i *ngIf="groupMenuRoute.path == '/plans'" class="material-symbols-outlined icon-mask">person</i>

View File

@ -263,16 +263,16 @@
}
span.googleIcon {
background: url("../../../assets/images/argos-login/NoPath\ -\ Copy\ \(2\).png") no-repeat;
background: url("../../../assets/images/login/google.png") no-repeat;
margin-left: .2rem;
}
span.facebookIcon {
background: url("../../../assets/images/argos-login/NoPath\ -\ Copy\ \(4\).png") no-repeat;
background: url("../../../assets/images/login/facebook.png") no-repeat;
}
span.twitterIcon {
background: url("../../../assets/images/argos-login/NoPath\ -\ Copy\ \(5\).png") no-repeat;
background: url("../../../assets/images/login/twitter.png") no-repeat;
}
span.linkedInIcon {
@ -290,7 +290,7 @@
}
span.orcidIconMedium {
background: url("../../../assets/images/argos-login/NoPath\ -\ Copy.png") no-repeat;
background: url("../../../assets/images/login/orcid.png") no-repeat;
background-position: center;
float: left;
transform: scale(0.45);
@ -299,7 +299,7 @@
}
span.openaireIcon {
background: url("../../../assets/images/argos-login/NoPath\ -\ Copy\ \(6\).png") no-repeat;
background: url("../../../assets/images/login/openaire.png") no-repeat;
background-position: center;
float: right;
transform: scale(0.4);
@ -308,7 +308,7 @@
}
span.zenodoIcon {
background: url("../../../assets/images/argos-login/zenodo-gradient-sm.png") no-repeat;
background: url("../../../assets/images/login/zenodo.png") no-repeat;
background-position: center;
float: right;
transform: scale(0.58);

View File

@ -1,6 +1,6 @@
{
"APP_NAME": "Argos",
"APP_NAME_CAPS": "ARGOS",
"APP_NAME": "OpenCDMP",
"APP_NAME_CAPS": "OpenCDMP",
"GENERAL": {
"VALIDATION": {
"REQUIRED": "Required",
@ -93,8 +93,10 @@
"USERS": "Users",
"PROFILE": "My Profile",
"LOGIN": "Login",
"PLAN-OVERVIEW": "Plan Overview",
"DATASET-OVERVIEW": "Description Overview",
"MAINTENANCE-TASKS": "Maintenance"
"MAINTENANCE-TASKS": "Maintenance",
"HOME": "Home"
},
"FILE-TRANSFORMER": {
"PDF": "PDF",
@ -754,6 +756,7 @@
"EMPTY-LIST": "Nothing here yet."
},
"DESCRIPTION-EDITOR": {
"TITLE-NEW": "New Description",
"TITLE-ADD-DESCRIPTION": "Adding Description",
"TITLE-EDIT-DESCRIPTION": "Editing Description",
"TITLE-PREVIEW-DESCRIPTION": "Previewing Description",
@ -1446,6 +1449,7 @@
}
},
"DMP-EDITOR": {
"TITLE-NEW": "New Plan",
"TITLE-EDIT": "Editing Plan",
"TITLE": "Plan Blueprint",
"UNSAVED-CHANGES": "unsaved changes",
@ -1453,7 +1457,7 @@
"DESCRIPTION": "Description",
"NO-TEMPLATE-MESSAGE": "If you can't find a template or if you want to create a personalized template for your institution, research community or training needs, please contact us.",
"DESCRIPTION-TEMPLATES-MAX-MULTIPLICITY": "Description Templates has reached the maximun multiplicity",
"UNSUCCESSFUL-REMOVE-TEMPLATE": "Failed to remove template, one or more Descriptions of this Plan use this template",
"UNSUCCESSFUL-REMOVE-TEMPLATE": "Cannot remove template, because it's already being used by one or more Descriptions.",
"FIELDS": {
"TITLE": "Title of Plan",
"DESCRIPTION": "Description",

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 411 B

After

Width:  |  Height:  |  Size: 411 B

View File

@ -1,10 +1,12 @@
<div class="form-content-editor-content">
<div mat-dialog-title class="d-flex justify-content-between m-0">
<span class="title">{{'GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.WARNING' | translate}}</span>
<div class="container-fluid">
<div class="row mt-3">
<div mat-dialog-title class="col-12 pr-1 d-flex justify-content-between">
<span class="mr-3 title">{{'GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.WARNING' | translate}}</span>
<mat-icon class="close-icon" (click)="onClose()">close</mat-icon>
</div>
<div class="content">
<div class="col p-0">
</div>
<div class="row mt-3 mr-3 mb-3">
<div class="col-12">
<ng-container *ngIf="errorMessages">
<ul class="error-list" *ngIf="errorMessages.length > 1 else singleError">
<li *ngFor="let error of errorMessages">{{error}}</li>
@ -15,8 +17,8 @@
</ng-template>
</div>
</div>
<div>
<div class="col actions">
<div class="row mt-3 mb-3">
<div class="col-12 actions">
<button mat-button type="button" class="ml-auto cancel-btn" (click)="onClose()">{{'GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.ACTIONS.CANCEL' | translate}}</button>
</div>
</div>

View File

@ -3,11 +3,18 @@
// Be sure that you only ever include this mixin once!
@include mat.core();
// :root {
// --primary-color: #129d99;
// --primary-color-2: #23bcba;
// --primary-color-3: #00b29f;
// --secondary-color: #f7dd72;
// }
:root {
--primary-color: #129d99;
--primary-color-2: #23bcba;
--primary-color-3: #00b29f;
--secondary-color: #f7dd72;
--primary-color: #18488F;
--primary-color-2: #1E59B1;
--primary-color-3: #246AD3;
--secondary-color: #36900B;
}
// Define your theme with color palettes, typography and density

View File

@ -48,7 +48,7 @@ You can also clear any filters already applied, by pressing the `clear all filte
## Edit form
When you try to add new notification templates or edit existing ones, the **notification template editing form** will appear containing the following controls:
When you try to add new notification templates or edit existing ones, the **notification template editing form** will appear containing the following sections.
### Main information section

View File

@ -1,5 +1,137 @@
---
sidebar_position: 5
description: Manage all reference types
---
# Reference Types
In this page, there is a listing where you can view details about all the available reference types.
:::info
A **reference type** is any type of information that is made available to the users when they fill [plan](/docs/category/plans) forms. This information is either static, or coming from an outside source (*an external API*). These sources are extremely configurable as we will see in this section.
:::
The information displayed by default is: the `name`, the `status`, the `identification code` and timestamps for the `creation` and `updates` of the records. At the top right corner of the listing you can also select which columns to display.
:::tip
For reference types, all the columns are visible by default.
:::
You can also create new or edit / remove reference types by clicking to the `+ Create Reference Type` button at the top right of the page or to the three dots at the last column, respectively.
## Authorization
Only users that have the **Admin** role can access this page.
## Pagination
Not all the records are being displayed at once. By default, there is a pagination of 10 records applied to them.
You can control how many records are being displayed at any time, by adjusting the `items per page` control at the bottom left corner of the table.
## Filtering
There is a filtering option available for reference types.
- **Is Active**: By toggling this control you can view only the active or only the disabled reference types.<br/>*By default, this option is set to true.*
In order for the filters to apply, you have to click the `Apply filters` button.
You can also clear any filters already applied, by pressing the `clear all filters` option, located at the top of the popup.
## Edit form
When you try to add new reference types or edit existing ones, the **reference type editing form** will appear containing the following sections.
### Main information section
- **Name**: The label of this reference type.
- **Code**: The identification code which is used internally for this type.
### Fields section
In this section we can add custom fields made available from the source. When the `Add Field` button is pressed, a form appears containing the following controls:
- **Label**: The label of the field.
- **Description**: A short description for the field. <br/>*This is optional*
- **Code**: An identification code for this field, used for the information mappings we will discuss about shortly.
- **Data Type**: The data type of a field information can either be `Text` or `Date`.
:::tip
There is no limit on the fields that can be configured. To remove a field configuration, press the `delete` icon on the right side of the field form.
:::
### Sources section
In this section we can add configuration for the sources of this reference type. The configured sources can be more than one. This is useful when there is a need to 'merge' information coming from multiple sources at the same time. The basic information we can provide for a source is the following:
- **Key**: An identification key for our source.<br/>*Used internally by the system.*
- **Label**: A display name for our source.
- **Ordinal**: This specifies the order in which the source will be called.
- **Dependencies**: A source can be dependent on other reference types. Here we can specify these dependencies.
- **Source Type**: It can either be `API` or `Static`.
:::info
All the options that follow are only applicable if the source type we select is `API`. In case we select `Static` the only thing we can add are the static fields of the source and their values.
:::
- **Url**: The url of our source.
- **Pagination Path**: The path inside the response in which the pagination information is located. This is only needed if the results are coming paginated from the source.
- **Content Type**: The content type of the responses of the source.<br/>*In most cases, this is `application/json`.*
- **First Page**: We can specify the first page to be different than the default 0.
- **HTTP Method**: The http method the source expects. This can either be `GET` or `POST`.
- **Filter Type**: How filtering is handled when this source is used. This can be set as `local` or `remote`.<br/>*In most cases, this is `remote`, meaning that the source handles the filtering. If set to `null`, the filtering (if any) is also handled remotely by the source.*
- **Results**: The path inside the source response where the results are located.
### Mappings section
In this section we can specify how we will be consuming the information coming from our sources by mapping all the source fields we are interested in.
For every field we have to specify the response path on which the information resides.
By default, there are three fields available for mapping from the start.
- **reference_id**: This can be used for identifier fields
- **label**
- **description**
If we have specified more fields for our source, these will also appear by their code in this form for configuring their paths.
### Authentication section
Some APIs require authentication. In this section we can specify the information about how our source API handles authentication. It is optional, and the form can be enabled by checking the `Authentication` checkbox. The options we have are the following:
- **Url**: The url where the API listens for authentication.
- **HTTP Method**: The HTTP method for the authentication request.
- **Token Path**: The path of the token, concatinated after the token type. <br/>*In most cases, it is `null`.*
- **Type**: The token type.<br/>*In most cases, it is `Bearer`.*
- **Request Body**: The body contents of the request, if required.
### Queries section
In this section we can specify query parameters we can apply to our requests.
- Name: The name of the query parameter. <br/>*For example, `like`.*
- Default Value: The default value of the parameter.<br/>*This is optional.*
## End notes
:::tip
The path fields on this form are using the [JsonPath](https://github.com/json-path/JsonPath) format.
:::
:::note
For every source we add, the form gets populated with new `field mapping`, `authentication` and `queries` sections we can configure as we saw above.
:::