diff --git a/dmp-frontend/src/app/ui/admin/prefilling-source/editor/prefilling-source-editor.component.scss b/dmp-frontend/src/app/ui/admin/prefilling-source/editor/prefilling-source-editor.component.scss index df9e3a45f..74d11d8d1 100644 --- a/dmp-frontend/src/app/ui/admin/prefilling-source/editor/prefilling-source-editor.component.scss +++ b/dmp-frontend/src/app/ui/admin/prefilling-source/editor/prefilling-source-editor.component.scss @@ -40,4 +40,10 @@ color: #FFF; border: 0px; } -} \ No newline at end of file +} + +::ng-deep .mdc-form-field { + label { + margin: 0; + } +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-editor.component.html b/dmp-frontend/src/app/ui/description/editor/description-editor.component.html index 726e57a89..c9cacc5c8 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-editor.component.html +++ b/dmp-frontend/src/app/ui/description/editor/description-editor.component.html @@ -93,7 +93,7 @@
0. {{'DESCRIPTION-EDITOR.TOC.MAIN-INFO' | translate}} (done)
- +
diff --git a/dmp-frontend/src/app/ui/description/editor/description-editor.component.ts b/dmp-frontend/src/app/ui/description/editor/description-editor.component.ts index d7adf6939..1ea2e62f0 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-editor.component.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-editor.component.ts @@ -6,7 +6,7 @@ import { DescriptionStatus } from '@app/core/common/enum/description-status'; import { DmpStatus } from '@app/core/common/enum/dmp-status'; import { IsActive } from '@app/core/common/enum/is-active.enum'; import { AppPermission } from '@app/core/common/enum/permission.enum'; -import { Description, DescriptionPersist, DescriptionSectionPermissionResolver, DescriptionStatusPersist } from '@app/core/model/description/description'; +import { Description, DescriptionPersist, DescriptionPropertyDefinitionFieldSet, DescriptionSectionPermissionResolver, DescriptionStatusPersist } from '@app/core/model/description/description'; import { AuthService } from '@app/core/services/auth/auth.service'; import { DescriptionTemplateService } from '@app/core/services/description-template/description-template.service'; import { DescriptionService } from '@app/core/services/description/description.service'; @@ -32,7 +32,7 @@ import { FilterService } from '@common/modules/text-filter/filter-service'; import { Guid } from '@common/types/guid'; import { TranslateService } from '@ngx-translate/core'; import { map, takeUntil } from 'rxjs/operators'; -import { DescriptionEditorModel, DescriptionPropertyDefinitionEditorModel } from './description-editor.model'; +import { DescriptionEditorModel, DescriptionFieldIndicator, DescriptionPropertyDefinitionEditorModel } from './description-editor.model'; import { DescriptionEditorResolver } from './description-editor.resolver'; import { DescriptionEditorService } from './description-editor.service'; import { PrefillDescriptionDialogComponent } from './prefill-description/prefill-description.component'; @@ -44,7 +44,7 @@ import { ConfigurationService } from '@app/core/services/configuration/configura import { LockTargetType } from '@app/core/common/enum/lock-target-type'; import { FileTransformerService } from '@app/core/services/file-transformer/file-transformer.service'; import { DmpBlueprintDefinitionSection } from '@app/core/model/dmp-blueprint/dmp-blueprint'; -import { DescriptionTemplate } from '@app/core/model/description-template/description-template'; +import { DescriptionTemplate, DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplatePage, DescriptionTemplateSection } from '@app/core/model/description-template/description-template'; import { DmpDescriptionTemplate } from '@app/core/model/dmp/dmp'; import { FileTransformerEntityType } from '@app/core/common/enum/file-transformer-entity-type'; @@ -69,6 +69,7 @@ export class DescriptionEditorComponent extends BaseEditor = new Map(); constructor( // BaseFormEditor injected dependencies @@ -207,8 +208,8 @@ export class DescriptionEditorComponent extends BaseEditor x.sectionId == sectionId && x.descriptionTemplateGroupId == result.descriptionTemplate.groupId); - this.prepareForm(result); + // this.descriptionModel = this.descriptionModel.fromModel(result); // this.descriptionModel.dmp = data; // this.descriptionModel.dmpSectionIndex = this.dmpSectionIndex; @@ -850,6 +851,10 @@ export class DescriptionEditorComponent extends BaseEditor { + const pageToFieldSetMap = new Map(); + + descriptionTemplate.definition.pages?.forEach((page: DescriptionTemplatePage) => { + page.sections?.forEach((section: DescriptionTemplateSection) => { + const fieldsets = this.getFieldsetsFromSection(section); + const value = fieldsets?.flatMap((fieldset: DescriptionTemplateFieldSet) => + fieldset.fields?.flatMap((field: DescriptionTemplateField) => + new DescriptionFieldIndicator(page.id, section.id, fieldset.id, field.id, field.data.fieldType, field.data.multipleSelect) + // 'properties.fieldSets.' + fieldset.id + '.items.0.fields.' + field.id// + '.textValue' + )); + pageToFieldSetMap.set(page.id, + value + ); + }); + }); + + return pageToFieldSetMap; + } + + getFieldsetsFromSection(section: DescriptionTemplateSection): DescriptionTemplateFieldSet[] { + if (section.sections) { + return section.sections.flatMap((subsection: DescriptionTemplateSection) => this.getFieldsetsFromSection(subsection)); + } + + else return section.fieldSets; + } + // // this._listenersSubscription.add(dmpSubscription); // // this._listenersSubscription.add(profileSubscription); // // this._listenersSubscription.add(labelSubscription); diff --git a/dmp-frontend/src/app/ui/description/editor/description-editor.model.ts b/dmp-frontend/src/app/ui/description/editor/description-editor.model.ts index c1699a4a6..68b60a73d 100644 --- a/dmp-frontend/src/app/ui/description/editor/description-editor.model.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-editor.model.ts @@ -1,5 +1,6 @@ import { FormControl, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms"; import { DescriptionStatus } from "@app/core/common/enum/description-status"; +import { DescriptionTemplateFieldType } from "@app/core/common/enum/description-template-field-type"; import { IsActive } from "@app/core/common/enum/is-active.enum"; import { DescriptionTemplate, DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplateSection } from "@app/core/model/description-template/description-template"; import { Description, DescriptionExternalIdentifier, DescriptionExternalIdentifierPersist, DescriptionField, DescriptionFieldPersist, DescriptionPersist, DescriptionPropertyDefinition, DescriptionPropertyDefinitionFieldSet, DescriptionPropertyDefinitionFieldSetItem, DescriptionPropertyDefinitionFieldSetItemPersist, DescriptionPropertyDefinitionFieldSetPersist, DescriptionPropertyDefinitionPersist, DescriptionReference, DescriptionReferencePersist } from "@app/core/model/description/description"; @@ -691,3 +692,59 @@ export class DescriptionReferenceEditorModel implements DescriptionReferencePers }); } } + +export class DescriptionFieldIndicator { + pageId: string; + sectionId: string; + fieldSetId: string; + fieldId: string; + type: string; + + constructor(pageId: string, sectionId: string, fieldSetId: string, fieldId: string, type: DescriptionTemplateFieldType, multipleSelect: boolean = false) { + this.pageId = pageId; + this.sectionId = sectionId; + this.fieldSetId = fieldSetId; + this.fieldId = fieldId; + + switch (type) { + case DescriptionTemplateFieldType.FREE_TEXT: + case DescriptionTemplateFieldType.BOOLEAN_DECISION: + case DescriptionTemplateFieldType.CHECK_BOX: + case DescriptionTemplateFieldType.RADIO_BOX: + case DescriptionTemplateFieldType.TEXT_AREA: + case DescriptionTemplateFieldType.UPLOAD: + case DescriptionTemplateFieldType.RICH_TEXT_AREA: + this.type = "textValue"; + break; + case DescriptionTemplateFieldType.DATASET_IDENTIFIER: + case DescriptionTemplateFieldType.VALIDATION: + this.type = "externalIdentifier"; + break; + case DescriptionTemplateFieldType.DATE_PICKER: + this.type = "dateValue"; + break; + case DescriptionTemplateFieldType.EXTERNAL_DATASETS: + this.type = ""; + break; + case DescriptionTemplateFieldType.INTERNAL_ENTRIES_DESCRIPTIONS: + if (multipleSelect) this.type = "textListValue"; + else this.type = "textValue" + break; + case DescriptionTemplateFieldType.INTERNAL_ENTRIES_DMPS: + if (multipleSelect) this.type = "textListValue"; + else this.type = "textValue"; + break; + case DescriptionTemplateFieldType.REFERENCE_TYPES: + if (multipleSelect) this.type = "references"; + else this.type = "reference"; + break; + case DescriptionTemplateFieldType.SELECT: + if (multipleSelect) this.type = "textListValue"; + else this.type = "textValue"; + break; + case DescriptionTemplateFieldType.TAGS: + this.type = "textListValue"; + break; + } + } +} diff --git a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.html b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.html index 8653b61f4..d5a3845c7 100644 --- a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.html +++ b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.html @@ -39,6 +39,9 @@ [showErrors]="showErrors" [hiddenEntries]="hiddenEntries" [visibilityRulesService]="visibilityRulesService" + [propertiesFormGroup]="propertiesFormGroup" + [parentId]="entry.id" + [parentMap]="updatedMap" > diff --git a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.scss b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.scss index 91152786d..c9978f6a4 100644 --- a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.scss +++ b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.scss @@ -22,8 +22,9 @@ background-color: #ececec; border-radius: 6px; } + .selected { - color: #212121 !important; + color: #212121; font-weight: 700 !important; opacity: 1 !important; } diff --git a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.ts b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.ts index 5547ecfa2..4bc9f3c62 100644 --- a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.ts +++ b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.ts @@ -4,6 +4,7 @@ import { VisibilityRulesService } from '@app/ui/description/editor/description-f import { Guid } from '@common/types/guid'; import { ToCEntry } from '../models/toc-entry'; import { ToCEntryType } from '../models/toc-entry-type.enum'; +import { DescriptionFieldIndicator } from '../../description-editor.model'; @Component({ selector: 'table-of-contents-internal', @@ -26,6 +27,10 @@ export class TableOfContentsInternal implements OnInit { @Input() visibilityRulesService: VisibilityRulesService; @ViewChildren(TableOfContentsInternal) internalTables: QueryList; + @Input() parentId: string; + @Input() parentMap: Map = new Map(); + @Input() updatedMap: Map = new Map(); + constructor() { } ngOnInit(): void { @@ -42,6 +47,11 @@ export class TableOfContentsInternal implements OnInit { } } } + + if (this.parentMap) { + this.updatedMap = this.updateMap(this.tocentries, this.parentMap); + console.log(this.updatedMap); + } } } @@ -64,6 +74,47 @@ export class TableOfContentsInternal implements OnInit { // } } + updateMap(entries: ToCEntry[], parentMap:Map): Map { + if (this.parentId == null) return parentMap; + + let updatedMap = new Map(); + + parentMap.forEach((fields: DescriptionFieldIndicator[], parentId: string) => { + if (this.parentId === parentId) { + for (let entry of entries) { + let entryFields = fields.filter((field: DescriptionFieldIndicator) => field.sectionId === entry.id || field.fieldSetId === entry.id || field.fieldId === entry.id ) + + updatedMap.set(entry.id, entryFields); + } + } + }); + + return updatedMap; + } + + hasErrors(entryId: string): boolean { + if (this.updatedMap.size == 0) return true; + + const fields: DescriptionFieldIndicator[] = this.updatedMap.get(entryId); + + for (let field of fields) { + let formFieldName: string = `fieldSets.${field.fieldSetId}.items.0.fields.${field.fieldId}.${field.type}`; + if (this.isFormFieldValid(formFieldName) === false) { + return true; + } + } + + return false; + } + + isFormFieldValid(formFildName: string):boolean { + if (this.propertiesFormGroup?.get(formFildName) == null) return true; + + if (this.propertiesFormGroup.get(formFildName).touched === false) return true; + + return this.propertiesFormGroup.get(formFildName).valid; + } + toggleExpand(index) { this.expandChildren[index] = !this.expandChildren[index]; // console.log(this.expandChildren); @@ -113,6 +164,9 @@ export class TableOfContentsInternal implements OnInit { myClass['section'] = true; } + if(this.hasErrors(entry.id)) { + myClass['text-danger'] = true; + } return myClass; } diff --git a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.html b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.html index 2fb7f2929..62de7a1cb 100644 --- a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.html +++ b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.html @@ -15,7 +15,8 @@ [selected]="tocentrySelected" [hiddenEntries]="hiddenEntries" [visibilityRulesService]="visibilityRulesService" - [propertiesFormGroup]="propertiesFormGroup" + [propertiesFormGroup]="formGroup" + [parentMap]="pageToFieldSetMap" > diff --git a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.ts b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.ts index adbcae0ae..a88095d80 100644 --- a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.ts +++ b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.ts @@ -9,6 +9,7 @@ import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; import { ToCEntry } from './models/toc-entry'; import { ToCEntryType } from './models/toc-entry-type.enum'; import { TableOfContentsInternal } from './table-of-contents-internal/table-of-contents-internal'; +import { DescriptionFieldIndicator } from '../description-editor.model'; export interface Link { /* id of the section*/ @@ -65,12 +66,14 @@ export class TableOfContentsComponent extends BaseComponent implements OnInit, O this._tocentrySelected = value; } - @Input() propertiesFormGroup: UntypedFormGroup; + @Input() formGroup: UntypedFormGroup; @Input() descriptionTemplate: DescriptionTemplate; @Input() hasFocus: boolean = false; @Input() visibilityRulesService: VisibilityRulesService; show: boolean = false; + @Input() pageToFieldSetMap: Map; + constructor( @Inject(DOCUMENT) private _document: Document, // public visibilityRulesService: VisibilityRulesService diff --git a/docs/docs/documentation/administration/_category_.json b/docs/docs/documentation/administration/_category_.json index b1887e41a..6119399ee 100644 --- a/docs/docs/documentation/administration/_category_.json +++ b/docs/docs/documentation/administration/_category_.json @@ -2,6 +2,7 @@ "label": "Administration", "position": 4, "link": { - "type": "generated-index" + "type": "doc", + "id": "index" } } \ No newline at end of file diff --git a/docs/docs/documentation/administration/blueprints/_category_.json b/docs/docs/documentation/administration/blueprints/_category_.json index 4a6345c91..710f064d8 100644 --- a/docs/docs/documentation/administration/blueprints/_category_.json +++ b/docs/docs/documentation/administration/blueprints/_category_.json @@ -2,6 +2,7 @@ "label": "Blueprints", "position": 2, "link": { - "type": "generated-index" + "type": "doc", + "id": "index" } } \ No newline at end of file diff --git a/docs/docs/documentation/administration/blueprints/index.md b/docs/docs/documentation/administration/blueprints/index.md new file mode 100644 index 000000000..70a86910e --- /dev/null +++ b/docs/docs/documentation/administration/blueprints/index.md @@ -0,0 +1,5 @@ +# Blueprints + +import DocCardList from '@theme/DocCardList'; + + \ No newline at end of file diff --git a/docs/docs/documentation/administration/index.md b/docs/docs/documentation/administration/index.md new file mode 100644 index 000000000..201b509b7 --- /dev/null +++ b/docs/docs/documentation/administration/index.md @@ -0,0 +1,9 @@ +# Administration + +There are a lot of tools developed that can help administrators better manage a lot of aspects of the application or get a better idea about the usage of the platform. + +These tools will be described in this section. + +import DocCardList from '@theme/DocCardList'; + + \ No newline at end of file diff --git a/docs/docs/documentation/administration/introduction.md b/docs/docs/documentation/administration/introduction.md index 4fd6418bb..fd12980e6 100644 --- a/docs/docs/documentation/administration/introduction.md +++ b/docs/docs/documentation/administration/introduction.md @@ -2,4 +2,11 @@ sidebar_position: 1 --- -# Introduction \ No newline at end of file +# Introduction + +There are a lot of views in the application available only for users that are given elevated privileges. In the pages that follow we will discover all the configuration options available in these views for an administrator, with the most important being the following: + +- **Users**: Being able to control the users of the platform. +- **Tenants**: Being able to control the tenants of the platform. Think of tenants as different organisations that can use the application independently at the same time without the need of different deployments. +- **Notification Templates**: Being able to modify the structure of notifications sent to users based on different events. +- **Languages**: Being able to add support for more languages or modify existing ones. \ No newline at end of file diff --git a/docs/docs/documentation/administration/templates/_category_.json b/docs/docs/documentation/administration/templates/_category_.json index 2d8ec47cb..a6d5a5caa 100644 --- a/docs/docs/documentation/administration/templates/_category_.json +++ b/docs/docs/documentation/administration/templates/_category_.json @@ -2,6 +2,7 @@ "label": "Templates", "position": 4, "link": { - "type": "generated-index" + "type": "doc", + "id": "index" } } \ No newline at end of file diff --git a/docs/docs/documentation/administration/templates/index.md b/docs/docs/documentation/administration/templates/index.md new file mode 100644 index 000000000..d69a60ead --- /dev/null +++ b/docs/docs/documentation/administration/templates/index.md @@ -0,0 +1,5 @@ +# Templates + +import DocCardList from '@theme/DocCardList'; + + \ No newline at end of file diff --git a/docs/docs/documentation/administration/tenants.md b/docs/docs/documentation/administration/tenants.md index 3fde922cb..52ad512bd 100644 --- a/docs/docs/documentation/administration/tenants.md +++ b/docs/docs/documentation/administration/tenants.md @@ -2,4 +2,36 @@ sidebar_position: 7 --- -# Tenants \ No newline at end of file +# Tenants + +In this page, there is a listing where you can view details about all the available tenants. + +The information displayed by default is: the `display name` of the tenants, 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 tenants, all the columns are visible by default. + +::: + +You can also create new or edit / remove tenants by clicking to the `Create Tenant` 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 tenants. + +- **Is Active**: By toggling this control you can view only the active or only the disabled tenants.
*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. \ No newline at end of file diff --git a/docs/docs/documentation/administration/users.md b/docs/docs/documentation/administration/users.md index a34c624e0..e2c1d82e8 100644 --- a/docs/docs/documentation/administration/users.md +++ b/docs/docs/documentation/administration/users.md @@ -2,4 +2,37 @@ sidebar_position: 6 --- -# Users \ No newline at end of file +# Users + +In this page, there is a listing where you can view details about all the registered users. + +The information displayed by default is: the `name` of the users, the `status` of their accounts 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 users, there is a column for `emails`, hidden by default. + +::: + +You can also assign new or remove assigned roles from users by clicking to the icon next to the roles column. When you click it, a multiselect dropdown is made available in the roles column. + +## 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 are some filtering options available for users. + +- **Is Active**: By toggling this control you can view only the active or only the disabled users.
*By default, this option is set to true.* +- **Roles**: You can filter users by their assigned roles. You can select one or more roles.
*By default, no role is selected.* + +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. \ No newline at end of file diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts index 4aabd740a..0a1e90f91 100644 --- a/docs/docusaurus.config.ts +++ b/docs/docusaurus.config.ts @@ -93,6 +93,22 @@ const config: Config = { label: 'Getting Started', to: '/docs/category/getting-started', }, + { + label: 'Application', + to: '/docs/category/application', + }, + { + label: 'Supplementary Services', + to: '/docs/category/supplementary-services', + }, + { + label: 'Administration', + to: '/docs/documentation/administration', + }, + { + label: 'For Developers', + to: '/docs/category/for-developers', + }, ], }, {