REVERT+REDO plan editor with new form focus directive, refactor description editor, fix annotation dialog accessibility, add id/name input to tags field component

This commit is contained in:
mchouliara 2024-09-26 14:33:51 +03:00
parent f2ce857e33
commit 9653a0cb04
17 changed files with 268 additions and 288 deletions

View File

@ -7,7 +7,7 @@ import { Subscription } from "rxjs";
selector: 'rich-text-editor-component',
template: `
<div class="editor-wrapper" [class]="wrapperClasses">
<angular-editor class="full-width editor" [ngClass]="editable ? '': 'disabled'" [id]="id"
<angular-editor class="full-width editor" [ngClass]="editable ? '': 'disabled'" [id]="name"
[config]="editorConfig" [formControl]="form" [required]="required"
placeholder="{{(placeholder? (placeholder | translate) : '') + (required ? ' *': '')}}"
(paste)="pasteWithoutFormatting($event)"></angular-editor>
@ -19,11 +19,11 @@ import { Subscription } from "rxjs";
changeDetection: ChangeDetectionStrategy.OnPush
})
export class RichTextEditorComponent implements OnInit, OnChanges, OnDestroy {
static nextId = 0;
@ViewChild(AngularEditorComponent) editor: AngularEditorComponent
@Input() form: FormControl;
@Input() id: string = "editor1";
@Input() name: string = `rich-text-editor${RichTextEditorComponent.nextId++}`;
@Input() placeholder: string = "Enter text";
@Input() required: boolean = false;
@Input() wrapperClasses: string = "";

View File

@ -9,13 +9,13 @@
</button>
</div>
<div class="col-auto pr-0 ml-auto dense-4">
<button mat-icon-button matTooltip="{{ 'DESCRIPTION-EDITOR.QUESTION.EXTENDED-DESCRIPTION.COPY-LINK' | translate }}" (click)="copyLink()">
<mat-icon>link</mat-icon>
<button mat-icon-button matTooltip="{{ 'DESCRIPTION-EDITOR.QUESTION.EXTENDED-DESCRIPTION.COPY-LINK' | translate }}" (click)="copyLink()" [attr.aria-label]="'DESCRIPTION-EDITOR.QUESTION.EXTENDED-DESCRIPTION.COPY-LINK' | translate">
<mat-icon aria-hidden>link</mat-icon>
</button>
</div>
<div class="col-auto pl-0 dense-4" >
<button mat-icon-button (click)="close()">
<mat-icon>close</mat-icon>
<button mat-icon-button (click)="close()" [attr.aria-label]="'GENERAL.NOTIFICATION-DIALOG.POPUP.CLOSE' | translate">
<mat-icon aria-hidden>close</mat-icon>
</button>
</div>
</div>
@ -36,8 +36,8 @@
</div>
<div class="col-6">
<mat-button-toggle-group appearance="standard" name="fontStyle" hideSingleSelectionIndicator="true" [formControl]="threadFormGroup.get('protectionType')" aria-label="Font Style" required>
<mat-button-toggle [value]="annotationProtectionTypeEnum.Private" [matTooltip]="enumUtils.toAnnotationProtectionTypeString(annotationProtectionTypeEnum.Private)"><mat-icon>visibility_off</mat-icon></mat-button-toggle>
<mat-button-toggle [value]="annotationProtectionTypeEnum.EntityAccessors" [matTooltip]="enumUtils.toAnnotationProtectionTypeString(annotationProtectionTypeEnum.EntityAccessors)"><mat-icon>public</mat-icon></mat-button-toggle>
<mat-button-toggle [value]="annotationProtectionTypeEnum.Private" [matTooltip]="enumUtils.toAnnotationProtectionTypeString(annotationProtectionTypeEnum.Private)" [attr.aria-label]="enumUtils.toAnnotationProtectionTypeString(annotationProtectionTypeEnum.Private)"><mat-icon aria-hidden>visibility_off</mat-icon></mat-button-toggle>
<mat-button-toggle [value]="annotationProtectionTypeEnum.EntityAccessors" [matTooltip]="enumUtils.toAnnotationProtectionTypeString(annotationProtectionTypeEnum.EntityAccessors)" [attr.aria-label]="enumUtils.toAnnotationProtectionTypeString(annotationProtectionTypeEnum.EntityAccessors)"><mat-icon aria-hidden>public</mat-icon></mat-button-toggle>
</mat-button-toggle-group>
</div>
<div class="col-auto ml-auto pr-1">
@ -105,12 +105,12 @@
<div class="row">
<ng-container *ngIf="annotationsPerThread[thread].length === 1 && !this.showRepliesPerThread[thread]">
<button mat-button class="action-button mt-3" (click)="showReplies(thread)">
<img src="/assets/images/annotations/reply.png" alt="reply"> <span class="mt-1 reply-btn"> 1 {{ 'ANNOTATION-DIALOG.THREADS.REPLY' | translate}} </span>
<img src="/assets/images/annotations/reply.png" alt="{{ 'ANNOTATION-DIALOG.THREADS.REPLY' | translate}}"> <span class="mt-1 reply-btn"> 1 {{ 'ANNOTATION-DIALOG.THREADS.REPLY' | translate}} </span>
</button>
</ng-container>
<ng-container *ngIf="annotationsPerThread[thread].length > 1 && !this.showRepliesPerThread[thread]">
<button mat-button class="action-button mt-3" (click)="showReplies(thread)">
<img src="/assets/images/annotations/reply.png" alt="reply"> <span class="mt-1 reply-btn"> {{ annotationsPerThread[thread].length }} {{ 'ANNOTATION-DIALOG.THREADS.REPLIES' | translate}} </span>
<img src="/assets/images/annotations/reply.png" alt="{{ 'ANNOTATION-DIALOG.THREADS.REPLY' | translate}}"> <span class="mt-1 reply-btn"> {{ annotationsPerThread[thread].length }} {{ 'ANNOTATION-DIALOG.THREADS.REPLIES' | translate}} </span>
</button>
</ng-container>
</div>

View File

@ -7,12 +7,12 @@
<!-- Title Field -->
<div class="row">
<div class="col-12">
<div class="heading">{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TITLE' | translate}}
<label for="titleInput" class="heading">{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TITLE' | translate}}
&nbsp;*<small class="required-text">{{'GENERAL.VALIDATION.REQUIRED' | translate }}</small>
</div>
</label>
<div class="title-form">
<mat-form-field class="w-100">
<input matInput placeholder="{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TITLE' | translate}}" type="text" name="label" formControlName="label" required>
<input id="titleInput" matInput placeholder="{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TITLE' | translate}}" type="text" name="label" formControlName="label" required>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')"> {{formGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
@ -22,11 +22,13 @@
<!-- Description field -->
<div class="row">
<div class="col-12">
<div class="heading">{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION' | translate}}</div>
<span class="hint">{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION-HINT' | translate}}</span>
<label (click)="descriptionInput?.focus()" class="heading">{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION' | translate}}</label>
<div class="hint">{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION-HINT' | translate}}</div>
<div class="description-form">
<rich-text-editor-component [form]="formGroup.get('description')" [placeholder]="'PLAN-EDITOR.PLACEHOLDER.DESCRIPTION'" [wrapperClasses]="'full-width editor ' +
((formGroup.get('description').touched && (formGroup.get('description').hasError('required') || formGroup.get('description').hasError('backendError'))) ? 'required' : '')" [editable]="!formGroup.get('description').disabled">
<rich-text-editor-component #descriptionInput [form]="formGroup.get('description')" [placeholder]="'PLAN-EDITOR.PLACEHOLDER.DESCRIPTION'"
[wrapperClasses]="'full-width editor ' + ((formGroup.get('description').touched && (formGroup.get('description').hasError('required') || formGroup.get('description').hasError('backendError'))) ? 'required' : '')"
[editable]="!formGroup.get('description').disabled"
>
</rich-text-editor-component>
<div [class]="(formGroup.get('description').touched && (formGroup.get('description').hasError('required') || formGroup.get('description').hasError('backendError'))) ? 'visible' : 'invisible'" class="mat-form-field form-field-subscript-wrapper">
<mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{formGroup.get('description').getError('backendError').message}}</mat-error>
@ -38,21 +40,21 @@
<!-- Tags -->
<div class="row">
<div class="col-12">
<div class="heading">{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TAGS' | translate}}</div>
<label for="tagInput" class="heading">{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TAGS' | translate}}</label>
<div class="profile-form">
<app-tags-field-component label="{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TAGS' | translate}}" placeholder="{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TAGS-PLACEHOLDER' | translate}}" [form]="formGroup.get('tags')"></app-tags-field-component>
<app-tags-field-component [name]="'tagInput'" label="{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TAGS' | translate}}" placeholder="{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.TAGS-PLACEHOLDER' | translate}}" [form]="formGroup.get('tags')"></app-tags-field-component>
</div>
</div>
</div>
<!-- Template Field -->
<div class="row">
<div class="col-12">
<div class="heading">{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION-TEMPLATE' | translate}}&nbsp;*
<label for="templateFieldInput" (click)="templateFieldInput?.focus()" class="heading">{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION-TEMPLATE' | translate}}&nbsp;*
<small class="required-text">{{'GENERAL.VALIDATION.REQUIRED' | translate }}</small>
</div>
</label>
<div class="profile-form">
<mat-form-field class="w-100">
<mat-select placeholder="{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION-TEMPLATE-PLACEHOLDER'| translate}}" [required]="true" [compareWith]="compareWith" [formControl]="formGroup.get('descriptionTemplateId')">
<mat-select id="templateFieldInput" #templateFieldInput placeholder="{{'DESCRIPTION-EDITOR.BASE-INFO.FIELDS.DESCRIPTION-TEMPLATE-PLACEHOLDER'| translate}}" [required]="true" [compareWith]="compareWith" [formControl]="formGroup.get('descriptionTemplateId')">
<mat-option *ngFor="let descriptionTemplate of availableDescriptionTemplates" [value]="descriptionTemplate.id" class="multiline-mat-option">
<div>
<span>{{descriptionTemplate.label}}, </span>

View File

@ -15,6 +15,7 @@ import { TagsFieldModule } from '@app/ui/tag/tags-field/tags-field.module';
import { NewDescriptionDialogComponent } from './new-description/new-description.component';
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module';
import { DeprecatedDescriptionTemplateDialog } from './description-base-fields-editor/dialog-description-template/deprecated-description-template-dialog.component';
import { FormFocusDirective } from '@common/forms/form-focus.directive';
@NgModule({
imports: [
@ -28,7 +29,8 @@ import { DeprecatedDescriptionTemplateDialog } from './description-base-fields-e
DescriptionEditorRoutingModule,
RichTextEditorModule,
TagsFieldModule,
AutoCompleteModule
AutoCompleteModule,
FormFocusDirective,
],
declarations: [
DescriptionEditorComponent,

View File

@ -1,10 +1,10 @@
<div *ngIf="!hideTitle" class="row">
<div class="col-12">
<div class="row title">
<h5 *ngIf="fieldSet.title && !isChild" class="col-auto field-set toc-field-set-header" [id]="fieldSet.id" [ngClass]="{'focused': isAnchor}">
<label [appFormFocus]="path" *ngIf="fieldSet.title && !isChild" class="col-auto field-set toc-field-set-header" [id]="fieldSet.id" [ngClass]="{'focused': isAnchor}">
{{path}}
{{fieldSet.title}}
</h5>
</label>
<mat-icon class="col-auto info-icon" *ngIf="fieldSet.additionalInformation && !isChild" matTooltip="{{fieldSet.additionalInformation}}">info</mat-icon>
<button *ngIf="!hildeLink" mat-icon-button class="col-auto link-icon" type="button" matTooltip="{{ 'DESCRIPTION-EDITOR.QUESTION.EXTENDED-DESCRIPTION.COPY-LINK' | translate }}" (click)="copyLink()">
<mat-icon class="">link</mat-icon>
@ -14,8 +14,8 @@
</div>
<div class="row">
<div class="col-12">
<h6 *ngIf="fieldSet.description && !isChild" [innerHTML]="fieldSet.description"></h6>
<div class="col-12 pb-2">
<small *ngIf="fieldSet.description && !isChild" [innerHTML]="fieldSet.description"></small>
</div>
</div>
@ -24,8 +24,8 @@
<div *ngIf="!showExtendedDescription" (click)="showExtendedDescription = !showExtendedDescription">
<span class="more d-flex justify-content-center">{{'DESCRIPTION-EDITOR.ACTIONS.VIEW-MORE' | translate}}</span>
</div>
<div *ngIf="showExtendedDescription">
<h6 [innerHTML]="fieldSet.extendedDescription"></h6>
<div *ngIf="showExtendedDescription" class="pb-2">
<small [innerHTML]="fieldSet.extendedDescription"></small>
<span class="more d-flex justify-content-center" (click)="showExtendedDescription = !showExtendedDescription">
{{'DESCRIPTION-EDITOR.ACTIONS.VIEW-LESS' | translate}}
</span>

View File

@ -21,7 +21,7 @@ h6 {
font-weight: 400;
}
.more {
.more { //TODO mchouliara link
text-decoration: underline;
color: var(--secondary-color);
cursor: pointer;

View File

@ -19,9 +19,9 @@
<div *ngFor="let field of fieldSet.fields; let i = index;" class="col-12">
<ng-container *ngIf="visibilityRulesService && visibilityRulesService.isVisibleMap[field.id + '_' + fieldSetItemPropertiesControl.get('ordinal').value] ?? true">
<div class="row">
<h5 *ngIf="placeholderTitle" class="col-auto font-weight-bold">{{field.label}}</h5>
<label *ngIf="placeholderTitle" class="col-auto font-weight-bold">{{field.label}}</label>
</div>
<app-description-form-field [propertiesFormGroup]="fieldSetItemPropertiesControl.get('fields')" [field]="field" [fieldSet]="fieldSet" [visibilityRulesService]="visibilityRulesService" [descriptionTemplateId]="descriptionTemplateId" [isChild]="true"></app-description-form-field>
<app-description-form-field [propertiesFormGroup]="fieldSetItemPropertiesControl.get('fields')" [path]="path" [field]="field" [fieldSet]="fieldSet" [visibilityRulesService]="visibilityRulesService" [descriptionTemplateId]="descriptionTemplateId" [isChild]="true"></app-description-form-field>
</ng-container>
</div>
</div>
@ -96,7 +96,7 @@
<!-- comment only on top level fieldset -->
<div class="row">
<div *ngIf="fieldSet.hasCommentField && propertiesFormGroup?.get('items')?.at(0)?.get('comment')" class="col-12">
<rich-text-editor-component [form]="propertiesFormGroup?.get('items')?.at(0)?.get('comment')" [id]="'editor1'" [placeholder]="'DESCRIPTION-EDITOR.FIELDS.COMMENT-PLACEHOLDER' | translate" [wrapperClasses]="'mb-2'" [editable]="!propertiesFormGroup?.get('items')?.at(0)?.get('comment').disabled" [required]="isRequired"></rich-text-editor-component>
<rich-text-editor-component [form]="propertiesFormGroup?.get('items')?.at(0)?.get('comment')" [placeholder]="'DESCRIPTION-EDITOR.FIELDS.COMMENT-PLACEHOLDER' | translate" [wrapperClasses]="'mb-2'" [editable]="!propertiesFormGroup?.get('items')?.at(0)?.get('comment').disabled" [required]="isRequired"></rich-text-editor-component>
</div>
</div>
</div>

View File

@ -1,17 +1,17 @@
<div *ngIf="field && visible" [id]="field.id" [ngSwitch]="this.field?.data?.fieldType" class="dynamic-form-field row">
<h5 *ngIf="fieldSet.title && !isChild">{{fieldSet.title}}</h5>
<label *ngIf="fieldSet.title && !isChild">{{fieldSet.title}}</label>
<mat-icon *ngIf="fieldSet.additionalInformation && !isChild" matTooltip="{{fieldSet.additionalInformation}}">info</mat-icon>
<h5 *ngIf="fieldSet.description && !isChild" class="col-12">{{fieldSet.description}}
</h5>
<h5 *ngIf="fieldSet.extendedDescription && !isChild" class="col-12">
<small *ngIf="fieldSet.description && !isChild" class="col-12">{{fieldSet.description}}
</small>
<small *ngIf="fieldSet.extendedDescription && !isChild" class="col-12">
<i>{{fieldSet.extendedDescription}}</i>
</h5>
</small>
<ng-container *ngSwitchCase="descriptionTemplateFieldTypeEnum.FREE_TEXT">
<div class="col-12">
<mat-form-field class="w-100">
<mat-label>{{ field.data.label }}</mat-label>
<input matInput [formControl]="propertiesFormGroup?.get(field.id).get('textValue')">
<input [id]="path" matInput [formControl]="propertiesFormGroup?.get(field.id).get('textValue')">
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('textValue').getError('backendError').message}}</mat-error>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('pattern')">{{'GENERAL.VALIDATION.URL.MESSAGE' | translate}}</mat-error>
@ -21,10 +21,10 @@
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.REFERENCE_TYPES" class="col-12">
<ng-container *ngIf="field.data.multipleSelect">
<app-reference-field-component [form]="propertiesFormGroup?.get(field.id).get('references')" [label]="field.data.label" [placeholder]="field.data.label" [referenceType]="field.data.referenceType" [multiple]="true" hint="{{ 'TYPES.DESCRIPTION-TEMPLATE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT' | translate }}"></app-reference-field-component>
<app-reference-field-component [id]="path" [form]="propertiesFormGroup?.get(field.id).get('references')" [label]="field.data.label" [placeholder]="field.data.label" [referenceType]="field.data.referenceType" [multiple]="true" hint="{{ 'TYPES.DESCRIPTION-TEMPLATE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT' | translate }}"></app-reference-field-component>
</ng-container>
<ng-container *ngIf="!(field.data.multipleSelect)">
<app-reference-field-component [form]="propertiesFormGroup?.get(field.id).get('reference')" [label]="field.data.label" [placeholder]="field.data.label" [referenceType]="field.data.referenceType" [multiple]="false" hint="{{ 'TYPES.DESCRIPTION-TEMPLATE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT' | translate }}"></app-reference-field-component>
<app-reference-field-component [id]="path" [form]="propertiesFormGroup?.get(field.id).get('reference')" [label]="field.data.label" [placeholder]="field.data.label" [referenceType]="field.data.referenceType" [multiple]="false" hint="{{ 'TYPES.DESCRIPTION-TEMPLATE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT' | translate }}"></app-reference-field-component>
</ng-container>
</div>
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.SELECT" class="col-12">
@ -32,7 +32,7 @@
<ng-container *ngIf="field.data.multipleSelect">
<mat-form-field class="col-md-12">
<mat-label>{{ field.data.label }}</mat-label>
<mat-select [formControl]="propertiesFormGroup?.get(field.id).get('textListValue')" [multiple]="field.data.multipleSelect">
<mat-select [id]="path" [formControl]="propertiesFormGroup?.get(field.id).get('textListValue')" [multiple]="field.data.multipleSelect">
<mat-option *ngFor="let opt of field.data.options" [value]="opt.value">{{opt.label}}</mat-option>
</mat-select>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textListValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('textListValue').getError('backendError').message}}</mat-error>
@ -42,7 +42,7 @@
<ng-container *ngIf="!(field.data.multipleSelect)">
<mat-form-field class="col-md-12">
<mat-label>{{ field.data.label }}</mat-label>
<mat-select [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" [multiple]="field.data.multipleSelect">
<mat-select [id]="path" [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" [multiple]="field.data.multipleSelect">
<mat-option *ngFor="let opt of field.data.options" [value]="opt.value">{{opt.label}}
</mat-option>
</mat-select>
@ -57,7 +57,7 @@
<ng-container *ngIf="field.data.multipleSelect">
<mat-form-field class="col-md-12">
<mat-label>{{ field.data.label }}</mat-label>
<app-multiple-auto-complete [formControl]="propertiesFormGroup?.get(field.id).get('textListValue')" [configuration]="descriptionService.multipleAutocompleteConfiguration">
<app-multiple-auto-complete [id]="path" [formControl]="propertiesFormGroup?.get(field.id).get('textListValue')" [configuration]="descriptionService.multipleAutocompleteConfiguration">
</app-multiple-auto-complete>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textListValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('textListValue').getError('backendError').message}}</mat-error>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textListValue').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -67,7 +67,7 @@
<ng-container *ngIf="!(field.data.multipleSelect)">
<mat-form-field class="col-md-12">
<mat-label>{{ field.data.label }}</mat-label>
<app-single-auto-complete [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" [configuration]="descriptionService.singleAutocompleteConfiguration">
<app-single-auto-complete [id]="path" [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" [configuration]="descriptionService.singleAutocompleteConfiguration">
</app-single-auto-complete>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('textValue').getError('backendError').message}}</mat-error>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -81,7 +81,7 @@
<ng-container *ngIf="field.data.multipleSelect">
<mat-form-field class="col-md-12">
<mat-label>{{ field.data.label }}</mat-label>
<app-multiple-auto-complete [formControl]="propertiesFormGroup?.get(field.id).get('textListValue')" [configuration]="planService.multipleAutocompleteConfiguration">
<app-multiple-auto-complete [id]="path" [formControl]="propertiesFormGroup?.get(field.id).get('textListValue')" [configuration]="planService.multipleAutocompleteConfiguration">
</app-multiple-auto-complete>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textListValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('textListValue').getError('backendError').message}}</mat-error>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textListValue').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -91,7 +91,7 @@
<ng-container *ngIf="!(field.data.multipleSelect)">
<mat-form-field class="col-md-12">
<mat-label>{{ field.data.label }}</mat-label>
<app-single-auto-complete [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" [configuration]="planService.singleAutocompleteConfiguration">
<app-single-auto-complete [id]="path" [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" [configuration]="planService.singleAutocompleteConfiguration">
</app-single-auto-complete>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('textValue').getError('backendError').message}}</mat-error>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -101,7 +101,7 @@
</div>
</div>
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.CHECK_BOX" class="col-12">
<mat-checkbox [formControl]="propertiesFormGroup?.get(field.id).get('booleanValue')">
<mat-checkbox [id]="path" [formControl]="propertiesFormGroup?.get(field.id).get('booleanValue')">
{{field.data.label}}</mat-checkbox>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('booleanValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('booleanValue').getError('backendError').message}}</mat-error>
</div>
@ -109,7 +109,7 @@
<div class="col-12">
<mat-form-field *ngSwitchCase="descriptionTemplateFieldTypeEnum.TEXT_AREA" class="w-100">
<mat-label>{{ field.data.label }}{{ isRequired ? '*' : ''}}</mat-label>
<textarea matInput class="text-area" [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" matTextareaAutosize matAutosizeMinRows="3" matAutosizeMaxRows="15"></textarea>
<textarea [id]="path" matInput class="text-area" [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" matTextareaAutosize matAutosizeMinRows="3" matAutosizeMaxRows="15"></textarea>
<button mat-icon-button type="button" *ngIf="!propertiesFormGroup?.get(field.id).get('textValue').disabled && propertiesFormGroup?.get(field.id).get('textValue').value" matSuffix aria-label="Clear" (click)="this.propertiesFormGroup?.get(field.id).get('textValue').patchValue('')">
<mat-icon>close</mat-icon>
</button>
@ -120,8 +120,15 @@
<ng-container *ngSwitchCase="descriptionTemplateFieldTypeEnum.RICH_TEXT_AREA">
<div class="col-12">
<rich-text-editor-component [form]="propertiesFormGroup?.get(field.id).get('textValue')" [placeholder]="field.data.label" [required]="isRequired" [wrapperClasses]="'full-width editor ' +
((isRequired && propertiesFormGroup?.get(field.id).get('textValue').touched && propertiesFormGroup?.get(field.id).get('textValue').hasError('required')) ? 'required' : '')" [editable]="!propertiesFormGroup?.get(field.id).get('textValue').disabled">
<rich-text-editor-component
id="{{path}}"
[form]="propertiesFormGroup?.get(field.id).get('textValue')"
[placeholder]="field.data.label"
[required]="isRequired"
[wrapperClasses]="'full-width editor ' + ((isRequired && propertiesFormGroup?.get(field.id).get('textValue').touched && propertiesFormGroup?.get(field.id).get('textValue').hasError('required')) ?
'required' : '')"
[editable]="!propertiesFormGroup?.get(field.id).get('textValue').disabled"
>
</rich-text-editor-component>
</div>
<div [class]="(propertiesFormGroup?.get(field.id).get('textValue')['errors'] && propertiesFormGroup?.get(field.id).get('textValue').hasError('required') && propertiesFormGroup?.get(field.id).get('textValue').touched) ? 'visible' : 'invisible'" class="col-12">
@ -133,7 +140,7 @@
</ng-container>
<ng-container *ngSwitchCase="descriptionTemplateFieldTypeEnum.UPLOAD">
<div class="col-12 d-flex justify-content-center">
<ngx-dropzone #drop class="drop-file col-12" (change)="fileChangeEvent($event, true)" [multiple]="false" [accept]="typesToString()" [disabled]="propertiesFormGroup?.get(field.id).get('textValue').disabled" [class.drop-file-error]="propertiesFormGroup?.get(field.id).get('textValue').touched && propertiesFormGroup?.get(field.id).get('textValue').hasError('required')">
<ngx-dropzone [id]="path" #drop class="drop-file col-12" (change)="fileChangeEvent($event, true)" [multiple]="false" [accept]="typesToString()" [disabled]="propertiesFormGroup?.get(field.id).get('textValue').disabled" [class.drop-file-error]="propertiesFormGroup?.get(field.id).get('textValue').touched && propertiesFormGroup?.get(field.id).get('textValue').hasError('required')">
<ngx-dropzone-preview *ngIf="propertiesFormGroup?.get(field.id).get('textValue').value" class="file-preview" [removable]="true" (removed)="onRemove()">
<ngx-dropzone-label class="file-label">{{ fileNameDisplay }}</ngx-dropzone-label>
</ngx-dropzone-preview>
@ -153,8 +160,8 @@
</ng-container>
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.BOOLEAN_DECISION" class="col-12">
<mat-radio-group [formControl]="propertiesFormGroup?.get(field.id).get('booleanValue')">
<mat-radio-button class="radio-button-item" [value]="true">{{ "TYPES.DESCRIPTION-TEMPLATE-COMBO-BOX-TYPE.ACTIONS.YES" | translate }}</mat-radio-button>
<mat-radio-button class="radio-button-item" [value]="false">{{ "TYPES.DESCRIPTION-TEMPLATE-COMBO-BOX-TYPE.ACTIONS.NO" | translate }}</mat-radio-button>
<mat-radio-button [id]="path" class="radio-button-item" [value]="true" tabindex="0" aria-label="{{ 'TYPES.DESCRIPTION-TEMPLATE-COMBO-BOX-TYPE.ACTIONS.YES' | translate }}">{{ "TYPES.DESCRIPTION-TEMPLATE-COMBO-BOX-TYPE.ACTIONS.YES" | translate }}</mat-radio-button>
<mat-radio-button class="radio-button-item" [value]="false" tabindex="0" aria-label="{{ 'TYPES.DESCRIPTION-TEMPLATE-COMBO-BOX-TYPE.ACTIONS.NO' | translate }}">{{ "TYPES.DESCRIPTION-TEMPLATE-COMBO-BOX-TYPE.ACTIONS.NO" | translate }}</mat-radio-button>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('booleanValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('booleanValue').getError('backendError').message}}</mat-error>
</mat-radio-group>
<small class="text-danger d-block" *ngIf="propertiesFormGroup?.get(field.id).get('booleanValue').hasError('required') && propertiesFormGroup?.get(field.id).get('booleanValue').touched">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
@ -164,7 +171,7 @@
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.RADIO_BOX" class="col-12">
<mat-radio-group [formControl]="propertiesFormGroup?.get(field.id).get('textValue')">
<mat-radio-button *ngFor="let option of field.data.options let index = index" class="radio-button-item" [value]="option.value">{{option.label}}</mat-radio-button>
<mat-radio-button id="{{path}}{{index > 0 ? '.' + index : ''}}" *ngFor="let option of field.data.options let index = index" class="radio-button-item" [value]="option.value" tabindex="0" aria-label="{{option.label}}">{{option.label}}</mat-radio-button>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('textValue').getError('backendError').message}}</mat-error>
</mat-radio-group>
<small class="text-danger d-block" *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('required') && propertiesFormGroup?.get(field.id).get('textValue').touched">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
@ -174,7 +181,7 @@
<mat-form-field *ngSwitchCase="descriptionTemplateFieldTypeEnum.DATE_PICKER" class="col-12">
<mat-label>{{ field.data.label }}</mat-label>
<input matInput class="table-input" [matDatepicker]="date" [formControl]="propertiesFormGroup?.get(field.id).get('dateValue')">
<input [id]="path" matInput class="table-input" [matDatepicker]="date" [formControl]="propertiesFormGroup?.get(field.id).get('dateValue')">
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
<mat-datepicker #date></mat-datepicker>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('dateValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('dateValue').getError('backendError').message}}</mat-error>
@ -189,7 +196,7 @@
<div class="row">
<mat-form-field class="col-md-12">
<mat-label>{{ field.data.label }}</mat-label>
<input matInput class="col-md-12" [formControl]="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier')">
<input [id]="path" matInput class="col-md-12" [formControl]="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier')">
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier').getError('backendError').message}}</mat-error>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
@ -210,7 +217,7 @@
<div class="row align-items-baseline">
<mat-form-field class="col-md-4">
<mat-label>{{ field.data.label }}</mat-label>
<input matInput class="col-md-12" [formControl]="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier')">
<input [id]="path" matInput class="col-md-12" [formControl]="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier')">
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier').getError('backendError').message}}</mat-error>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>

View File

@ -45,7 +45,7 @@ export class DescriptionFormFieldComponent extends BaseComponent implements OnIn
@Input() isChild: Boolean = false;
@Input() detectChangesObservable: Observable<any>;
@Input() path: string;
visible: boolean = true;
descriptionTemplateFieldTypeEnum = DescriptionTemplateFieldType;

View File

@ -16,6 +16,7 @@ import { DescriptionFormComponent } from './description-form.component';
import { FormAnnotationService } from '../../../annotations/annotation-dialog-component/form-annotation.service';
import { TagsFieldModule } from '@app/ui/tag/tags-field/tags-field.module';
import { DescriptionFormService } from './components/services/description-form.service';
import { FormFocusDirective } from '@common/forms/form-focus.directive';
@NgModule({
@ -28,7 +29,8 @@ import { DescriptionFormService } from './components/services/description-form.s
FormattingModule,
ReferenceFieldModule,
AnnotationDialogModule,
TagsFieldModule
TagsFieldModule,
FormFocusDirective,
],
declarations: [
DescriptionFormComponent,

View File

@ -68,7 +68,7 @@ p {
color: #0d7489;
}
.more-horiz {
.more-horiz { //TODO mchouliara link
font-size: 28px;
color: var(--gray);
}

View File

@ -51,7 +51,7 @@
padding: 0px;
}
.more-horiz {
.more-horiz { //TODO mchouliara link
font-size: 28px;
color: var(--gray);
}

View File

@ -82,16 +82,16 @@
<div class="col-12">
<mat-form-field class="w-100">
<mat-label>{{'PLAN-EDITOR.FIELDS.TITLE' | translate}}</mat-label>
<input matInput id="titleInput" type="text" name="label" [formControl]="formGroup.get('label')" required>
<input id="titleInput" matInput type="text" name="label" [formControl]="formGroup.get('label')" required>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{formGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
<div class="row">
<label class="heading2 col-12" (click)="newDescriptionInput?.focus()">{{'PLAN-EDITOR.FIELDS.DESCRIPTION' | translate}}</label>
<label [appFormFocus]="'descriptionInput'" class="heading2 col-12">{{'PLAN-EDITOR.FIELDS.DESCRIPTION' | translate}}</label>
<div class="col-12">
<rich-text-editor-component #newDescriptionInput [form]="formGroup.get('description')" placeholder="{{'PLAN-EDITOR.PLACEHOLDER.DESCRIPTION' | translate}}" [required]="false">
<rich-text-editor-component id="descriptionInput" [form]="formGroup.get('description')" placeholder="{{'PLAN-EDITOR.PLACEHOLDER.DESCRIPTION' | translate}}" [required]="false">
</rich-text-editor-component>
</div>
</div>
@ -201,64 +201,37 @@
<div class="row">
<div class="col-12">
<div *ngFor="let field of section.fields; let j=index">
@if(field.category === planBlueprintSectionFieldCategoryEnum.System){
@switch(field.systemFieldType){
@case(planBlueprintSystemFieldTypeEnum.AccessRights){
<div class="heading-wrapper row align-items-start" [id]="field.id">
<div class="col-auto">
<label (click)="matSelect?.focus()" class="heading">{{i + 1}}.{{j + 1}} {{field.label ?? enumUtils.toPlanBlueprintSystemFieldTypeString(field.systemFieldType)}}
<label [appFormFocus]="(i + 1)+'.'+(j + 1)" class="heading" *ngIf="!field.label && field.category === planBlueprintSectionFieldCategoryEnum.System">{{i + 1}}.{{j + 1}} {{enumUtils.toPlanBlueprintSystemFieldTypeString(field.systemFieldType)}}
<span *ngIf="field.required">&nbsp;*<small class="required-text">{{'GENERAL.VALIDATION.REQUIRED' | translate }}</small></span>
</label>
<label [appFormFocus]="(i + 1)+'.'+(j + 1)" class="heading" *ngIf="!field.label && field.category === planBlueprintSectionFieldCategoryEnum.ReferenceType">{{i + 1}}.{{j + 1}} {{field.referenceType.name}}
<span *ngIf="field.required">&nbsp;*<small class="required-text">{{'GENERAL.VALIDATION.REQUIRED' | translate }}</small></span>
</label>
<label [appFormFocus]="(i + 1)+'.'+(j + 1)" class="heading" *ngIf="field.label">{{i + 1}}.{{j + 1}} {{field.label}}
<span *ngIf="field.required">&nbsp;*<small class="required-text">{{'GENERAL.VALIDATION.REQUIRED' | translate }}</small></span>
</label>
</div>
<ng-container *ngTemplateOutlet="linkAnnotationTemplate"/>
<div class="col-auto link-icon" style="margin-top: 1rem;">
<button *ngIf="!hildeLink" mat-icon-button type="button" matTooltip="{{ 'PLAN-EDITOR.ACTIONS.COPY-LINK' | translate }}" (click)="copyLink(field?.id)">
<mat-icon>link</mat-icon>
</button>
</div>
<div class="input-form">
<mat-form-field class="w-100">
<mat-select #matSelect [formControl]="formGroup.get('accessType')" placeholder="{{ field.placeholder && field.placeholder != '' ? field.placeholder : 'PLAN-EDITOR.FIELDS.ACCESS-TYPE' | translate}}">
<mat-option *ngFor="let planAccessType of planAccessTypeEnumValues" [value]="planAccessType">
{{enumUtils.toPlanAccessTypeString(planAccessType)}}
</mat-option>
</mat-select>
<mat-error *ngIf="formGroup.get('accessType').hasError('backendError')">{{formGroup.get('accessType').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('accessType').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
}@case(planBlueprintSystemFieldTypeEnum.Language){
<div class="heading-wrapper row align-items-start" [id]="field.id">
<div class="col-auto">
<label (click)="languageInput?.focus()" class="heading">{{i + 1}}.{{j + 1}} {{field.label ?? enumUtils.toPlanBlueprintSystemFieldTypeString(field.systemFieldType)}}
<span *ngIf="field.required">&nbsp;*<small class="required-text">{{'GENERAL.VALIDATION.REQUIRED' | translate }}</small></span>
</label>
</div>
<ng-container *ngTemplateOutlet="linkAnnotationTemplate"/>
</div>
<div class="input-form">
<mat-form-field class="w-100">
<mat-select #languageInput [formControl]="formGroup.get('language')" placeholder="{{field.placeholder && field.placeholder != '' ? field.placeholder : 'PLAN-EDITOR.FIELDS.LANGUAGE' | translate}}" required>
<mat-option *ngFor="let lang of getLanguageInfos()" [value]="lang.code">
{{ lang.name }}
</mat-option>
</mat-select>
<mat-error *ngIf="formGroup.get('language').hasError('backendError')">{{formGroup.get('language').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('language').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
}@case(planBlueprintSystemFieldTypeEnum.Description){
<div class="heading-wrapper row align-items-start" [id]="field.id">
<div class="col-auto">
<label (click)="descriptionInput?.focus()" class="heading">{{i + 1}}.{{j + 1}} {{field.label ?? enumUtils.toPlanBlueprintSystemFieldTypeString(field.systemFieldType)}}
<span *ngIf="field.required">&nbsp;*<small class="required-text">{{'GENERAL.VALIDATION.REQUIRED' | translate }}</small></span>
</label>
</div>
<ng-container *ngTemplateOutlet="linkAnnotationTemplate"/>
</div>
<div class="input-form">
<rich-text-editor-component #descriptionInput [form]="formGroup.get('description')" [editable]="formGroup.get('description').status !== 'DISABLED'" [placeholder]="field.placeholder && field.placeholder != '' ? field.placeholder : 'PLAN-EDITOR.PLACEHOLDER.DESCRIPTION'" [required]="field.required"></rich-text-editor-component>
@if(!isNew){
<div class="ml-auto col-auto" style="margin-top: 1rem;">
<button mat-icon-button class="col-auto annotation-icon" (click)="showAnnotations(field.id)" matTooltip="{{ 'PLAN-EDITOR.ACTIONS.ANNOTATIONS' | translate }}" [disabled]="!canAnnotate(section.id)">
<mat-icon [matBadge]="annotationsPerAnchor?.get(field.id)" [matBadgeHidden]="annotationsPerAnchor?.get(field.id) <= 0" matBadgeColor="warn">comment</mat-icon>
</button>
</div>
}
@case(planBlueprintSystemFieldTypeEnum.Title){
<ng-container *ngTemplateOutlet="headerCommonTemplate; context: {labelAlt: enumUtils.toPlanBlueprintSystemFieldTypeString(field.systemFieldType)}"/>
</div>
<div *ngIf="field.description != null && field.description.length > 0" class="hint">{{field.description}}</div>
<div class="input-form">
<div *ngIf="field.category === planBlueprintSectionFieldCategoryEnum.System">
<div *ngIf="field.systemFieldType == planBlueprintSystemFieldTypeEnum.Title">
<mat-form-field class="w-100">
<input id="{{i + 1}}.{{j + 1}}" matInput placeholder="{{field.placeholder && field.placeholder != '' ? field.placeholder : field.label && field.label != '' ? field.label : 'PLAN-EDITOR.FIELDS.TITLE' | translate}}" type="text" name="label" [formControl]="formGroup.get('label')" required>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">
@ -267,9 +240,22 @@
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
}@case(planBlueprintSystemFieldTypeEnum.Contact){
<ng-container *ngTemplateOutlet="headerCommonTemplate; context: {labelAlt: enumUtils.toPlanBlueprintSystemFieldTypeString(field.systemFieldType)}"/>
<div class="input-form row">
<div *ngIf="field.systemFieldType == planBlueprintSystemFieldTypeEnum.Description">
<rich-text-editor-component id="{{i + 1}}.{{j + 1}}" [form]="formGroup.get('description')" [editable]="formGroup.get('description').status !== 'DISABLED'" [placeholder]="field.placeholder && field.placeholder != '' ? field.placeholder : 'PLAN-EDITOR.PLACEHOLDER.DESCRIPTION'" [required]="field.required">
</rich-text-editor-component>
</div>
<div *ngIf="field.systemFieldType == planBlueprintSystemFieldTypeEnum.Language">
<mat-form-field class="w-100">
<mat-select id="{{i + 1}}.{{j + 1}}" [formControl]="formGroup.get('language')" placeholder="{{field.placeholder && field.placeholder != '' ? field.placeholder : 'PLAN-EDITOR.FIELDS.LANGUAGE' | translate}}" required>
<mat-option *ngFor="let lang of getLanguageInfos()" [value]="lang.code">
{{ lang.name }}
</mat-option>
</mat-select>
<mat-error *ngIf="formGroup.get('language').hasError('backendError')">{{formGroup.get('language').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('language').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div *ngIf="field.systemFieldType == planBlueprintSystemFieldTypeEnum.Contact" class="row">
<div cdkDropList class="col-12" (cdkDropListDropped)="dropContacts($event)">
<div *ngFor="let contact of formGroup.get('properties').get('contacts').controls; let contactIndex=index;" cdkDrag class="row align-items-center" [cdkDragDisabled]="formGroup.disabled || !canEdit" (mouseenter)="onContactHover(contactIndex)" (mouseleave)="clearHoveredContact()">
<div class="col-12 col-xl-auto pr-0">
@ -283,7 +269,7 @@
<div class="col">
<mat-form-field class="w-100">
<mat-label>{{'PLAN-EDITOR.FIELDS.FIRST-NAME' | translate}}</mat-label>
<input id="{{i + 1}}.{{j + 1}}" matInput type="text" name="firstName" [formControl]="contact.get('firstName')">
<input id="{{i + 1}}.{{j + 1}}{{contactIndex > 0 ? '.' + contactIndex : ''}}" matInput type="text" name="firstName" [formControl]="contact.get('firstName')">
<mat-error *ngIf="contact.get('firstName').hasError('backendError')">{{contact.get('firstName').getError('backendError').message}}</mat-error>
<mat-error *ngIf="contact.get('firstName').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
@ -291,7 +277,7 @@
<div class="col">
<mat-form-field class="w-100">
<mat-label>{{'PLAN-EDITOR.FIELDS.LAST-NAME' | translate}}</mat-label>
<input id="{{i + 1}}.{{j + 1}}" matInput type="text" name="lastName" [formControl]="contact.get('lastName')">
<input matInput type="text" name="lastName" [formControl]="contact.get('lastName')">
<mat-error *ngIf="contact.get('lastName').hasError('backendError')">{{contact.get('lastName').getError('backendError').message}}</mat-error>
<mat-error *ngIf="contact.get('lastName').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
@ -299,7 +285,7 @@
<div class="col">
<mat-form-field class="w-100">
<mat-label>{{'PLAN-EDITOR.FIELDS.EMAIL' | translate}}</mat-label>
<input id="{{i + 1}}.{{j + 1}}" matInput type="text" name="email" [formControl]="contact.get('email')">
<input matInput type="text" name="email" [formControl]="contact.get('email')">
<mat-error *ngIf="contact.get('email').hasError('backendError')">{{contact.get('email').getError('backendError').message}}</mat-error>
<mat-error *ngIf="contact.get('email').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
@ -326,17 +312,24 @@
</button>
</div>
</div>
}@case(planBlueprintSystemFieldTypeEnum.User){
<ng-container *ngTemplateOutlet="headerCommonTemplate; context: {labelAlt: enumUtils.toPlanBlueprintSystemFieldTypeString(field.systemFieldType)}"/>
<div class="input-form">
<div *ngIf="field.systemFieldType == planBlueprintSystemFieldTypeEnum.AccessRights">
<mat-form-field class="w-100">
<mat-select id="{{i + 1}}.{{j + 1}}" [formControl]="formGroup.get('accessType')" placeholder="{{ field.placeholder && field.placeholder != '' ? field.placeholder : 'PLAN-EDITOR.FIELDS.ACCESS-TYPE' | translate}}">
<mat-option *ngFor="let planAccessType of planAccessTypeEnumValues" [value]="planAccessType">
{{enumUtils.toPlanAccessTypeString(planAccessType)}}
</mat-option>
</mat-select>
<mat-error *ngIf="formGroup.get('accessType').hasError('backendError')">{{formGroup.get('accessType').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('accessType').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div *ngIf="field.systemFieldType == planBlueprintSystemFieldTypeEnum.User">
<div>
<app-plan-user-field-component [form]="formGroup" [validationErrorModel]="editorModel.validationErrorModel" [sections]="selectedBlueprint.definition.sections" [viewOnly]="formGroup.disabled || !canEdit"></app-plan-user-field-component>
</div>
}
}
}
@if(field.category === planBlueprintSectionFieldCategoryEnum.ReferenceType){
<ng-container *ngTemplateOutlet="headerCommonTemplate; context: {labelAlt: field.referenceType.name}"/>
<div class="input-form">
</div>
</div>
<div *ngIf="field.category === planBlueprintSectionFieldCategoryEnum.ReferenceType">
<ng-container *ngIf="field.multipleSelect">
<app-reference-field-component id="{{i + 1}}.{{j + 1}}" [form]="formGroup.get('properties').get('planBlueprintValues').get(field.id).get('references')" [dependencies]="formGroup.get('properties').get('planBlueprintValues')" [label]="field.label" [placeholder]="field.placeholder && field.placeholder != '' ? field.placeholder : field.label" [referenceType]="field.referenceType" [multiple]="true"></app-reference-field-component>
</ng-container>
@ -344,12 +337,8 @@
<app-reference-field-component id="{{i + 1}}.{{j + 1}}" [form]="formGroup.get('properties').get('planBlueprintValues').get(field.id).get('reference')" [dependencies]="formGroup.get('properties').get('planBlueprintValues')" [label]="field.label" [placeholder]="field.placeholder && field.placeholder != '' ? field.placeholder : field.label" [referenceType]="field.referenceType" [multiple]="false"></app-reference-field-component>
</ng-container>
</div>
}
@if(field.category === planBlueprintSectionFieldCategoryEnum.Extra){
@switch(field.dataType){
@case(planBlueprintExtraFieldDataTypeEnum.Text){
<ng-container *ngTemplateOutlet="headerCommonTemplate; context: {labelAlt: ''}"/>
<div class="input-form">
<div *ngIf="field.category === planBlueprintSectionFieldCategoryEnum.Extra">
<div *ngIf="field.dataType === planBlueprintExtraFieldDataTypeEnum.Text">
<mat-form-field class="w-100">
<mat-label>{{field.label}}</mat-label>
<input id="{{i + 1}}.{{j + 1}}" matInput placeholder="{{field.placeholder && field.placeholder != '' ? field.placeholder : field.label}}" type="text" name="value" [formControl]="formGroup.get('properties').get('planBlueprintValues').get(field.id).get('fieldValue')" [required]="field.required">
@ -357,22 +346,10 @@
<mat-error *ngIf="formGroup.get('properties').get('planBlueprintValues').get(field.id).get('fieldValue').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
}
@case(planBlueprintExtraFieldDataTypeEnum.RichText){
<div class="heading-wrapper row align-items-start" [id]="field.id">
<div class="col-auto">
<label (click)="richTextInput?.focus()" class="heading">{{i + 1}}.{{j + 1}} {{field.label}}
<span *ngIf="field.required">&nbsp;*<small class="required-text">{{'GENERAL.VALIDATION.REQUIRED' | translate }}</small></span>
</label>
<div *ngIf="field.dataType === planBlueprintExtraFieldDataTypeEnum.RichText">
<rich-text-editor-component [form]="formGroup.get('properties').get('planBlueprintValues').get(field.id).get('fieldValue')" placeholder="{{field.placeholder && field.placeholder != '' ? field.placeholder : field.label}}" [required]="field.required"></rich-text-editor-component>
</div>
<ng-container *ngTemplateOutlet="linkAnnotationTemplate"/>
</div>
<div class="input-form">
<rich-text-editor-component #richTextInput [form]="formGroup.get('properties').get('planBlueprintValues').get(field.id).get('fieldValue')" placeholder="{{field.placeholder && field.placeholder != '' ? field.placeholder : field.label}}" [required]="field.required"></rich-text-editor-component>
</div>
}@case(planBlueprintExtraFieldDataTypeEnum.Date) {
<ng-container *ngTemplateOutlet="headerCommonTemplate; context: {labelAlt: ''}"/>
<div class="input-form">
<div *ngIf="field.dataType === planBlueprintExtraFieldDataTypeEnum.Date">
<mat-form-field class="w-100">
<mat-label>{{field.label}}</mat-label>
<input id="{{i + 1}}.{{j + 1}}" matInput placeholder="{{field.placeholder && field.placeholder != '' ? field.placeholder : field.label}}" name="value" [formControl]="formGroup.get('properties').get('planBlueprintValues').get(field.id).get('dateValue')" [matDatepicker]="date" [required]="field.required">
@ -382,9 +359,7 @@
<mat-error *ngIf="formGroup.get('properties').get('planBlueprintValues').get(field.id).get('dateValue').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
}@case(planBlueprintExtraFieldDataTypeEnum.Number) {
<ng-container *ngTemplateOutlet="headerCommonTemplate; context: {labelAlt: ''}"/>
<div class="input-form">
<div *ngIf="field.dataType === planBlueprintExtraFieldDataTypeEnum.Number">
<mat-form-field class="w-100">
<mat-label>{{field.label}}</mat-label>
<input id="{{i + 1}}.{{j + 1}}" matInput placeholder="{{field.placeholder && field.placeholder != '' ? field.placeholder : field.label}}" type="number" name="value" [formControl]="formGroup.get('properties').get('planBlueprintValues').get(field.id).get('numberValue')" [required]="field.required">
@ -392,35 +367,8 @@
<mat-error *ngIf="formGroup.get('properties').get('planBlueprintValues').get(field.id).get('numberValue').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
}
}
}
<ng-template #headerCommonTemplate let labelAlt="labelAlt">
<div class="heading-wrapper row align-items-start" [id]="field.id">
<div class="col-auto">
<label for="{{i + 1}}.{{j + 1}}" class="heading">{{i + 1}}.{{j + 1}} {{field.label ?? labelAlt}}
<span *ngIf="field.required">&nbsp;*<small class="required-text">{{'GENERAL.VALIDATION.REQUIRED' | translate }}</small></span>
</label>
</div>
<ng-container *ngTemplateOutlet="linkAnnotationTemplate"/>
</div>
</ng-template>
<ng-template #linkAnnotationTemplate>
@if(!isNew){
<div class="col-auto link-icon" style="margin-top: 1rem;">
<button mat-icon-button type="button" matTooltip="{{ 'PLAN-EDITOR.ACTIONS.COPY-LINK' | translate }}" (click)="copyLink(field?.id)">
<mat-icon>link</mat-icon>
</button>
</div>
<div class="ml-auto col-auto" style="margin-top: 1rem;">
<button mat-icon-button class="col-auto annotation-icon" (click)="showAnnotations(field.id)" matTooltip="{{ 'PLAN-EDITOR.ACTIONS.ANNOTATIONS' | translate }}" [disabled]="!canAnnotate(section.id)" [attr.aria-label]="'PLAN-EDITOR.ACTIONS.ANNOTATIONS' | translate">
<mat-icon [matBadge]="annotationsPerAnchor?.get(field.id)" [matBadgeHidden]="annotationsPerAnchor?.get(field.id) <= 0" matBadgeColor="warn">comment</mat-icon>
</button>
</div>
}
<div *ngIf="field.description != null && field.description.length > 0" class="col-12 hint">{{field.description}}</div>
</ng-template>
</div>
</div>
</div>
@ -429,10 +377,10 @@
<div class="row">
<div class="col-12">
<div class="input-form">
<label for="{{i + 1}}.{{j + 1}}" class="heading">{{'PLAN-EDITOR.FIELDS.DESCRIPTION-TEMPLATES' | translate}}</label>
<label for="descriptionTemplateInput" class="heading">{{'PLAN-EDITOR.FIELDS.DESCRIPTION-TEMPLATES' | translate}}</label>
<mat-form-field class="w-100">
<mat-label>{{'PLAN-EDITOR.FIELDS.DESCRIPTION-TEMPLATES-HINT' | translate}}</mat-label>
<app-multiple-auto-complete id="{{i + 1}}.{{j + 1}}" placeholder="{{'PLAN-EDITOR.FIELDS.DESCRIPTION-TEMPLATES-HINT' | translate}}" 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 [id]="'descriptionTemplateInput'" placeholder="{{'PLAN-EDITOR.FIELDS.DESCRIPTION-TEMPLATES-HINT' | translate}}" 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

@ -14,6 +14,7 @@ import { PlanFormProgressIndicationModule } from './form-progress-indication/pla
import { PlanDeleteDialogModule } from '../plan-delete-dialog/plan-delete-dialog.module';
import { PlanContactPrefillDialogModule } from '../plan-contact-prefill-dialog/plan-contact-prefill-dialog.module';
import { AnnotationDialogModule } from '@app/ui/annotations/annotation-dialog-component/annotation-dialog.module';
import { FormFocusDirective } from '@common/forms/form-focus.directive';
@NgModule({
imports: [
@ -30,7 +31,8 @@ import { AnnotationDialogModule } from '@app/ui/annotations/annotation-dialog-co
PlanUserFieldModule,
PlanFormProgressIndicationModule,
PlanContactPrefillDialogModule,
AnnotationDialogModule
AnnotationDialogModule,
FormFocusDirective
],
declarations: [
PlanEditorComponent,

View File

@ -8,7 +8,7 @@
</button>
</mat-chip-row>
</mat-chip-grid>
<input placeholder="{{placeholder}}" #tagInput [formControl]="tagsCtrl" [matChipInputFor]="chipGrid" [matAutocomplete]="auto" [matChipInputSeparatorKeyCodes]="separatorKeysCodes" (matChipInputTokenEnd)="add($event)" [readOnly]="form.disabled"/>
<input [id]="name" placeholder="{{placeholder}}" #tagInput [formControl]="tagsCtrl" [matChipInputFor]="chipGrid" [matAutocomplete]="auto" [matChipInputSeparatorKeyCodes]="separatorKeysCodes" (matChipInputTokenEnd)="add($event)" [readOnly]="form.disabled"/>
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
<mat-option *ngFor="let tag of filteredTags | async" [value]="tag">
{{tag}}

View File

@ -16,11 +16,11 @@ import { map, mergeMap, startWith, takeUntil } from 'rxjs/operators';
styleUrls: ['./tags-field.component.scss']
})
export class TagsComponent extends BaseComponent implements OnInit, OnChanges {
static nextId: number = 0;
@Input() form: UntypedFormControl = null;
@Input() label: string;
@Input() placeholder: string;
@Input() name: string = `tag-field-${TagsComponent.nextId++}`;
separatorKeysCodes: number[] = [ENTER, COMMA];
filteredTags: Observable<string[]>;
tags: string[] = [];

View File

@ -0,0 +1,17 @@
import { Directive, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appFormFocus]',
standalone: true
})
export class FormFocusDirective { //todo it doesn't work on rich-text-editor inputs
@Input() appFormFocus: string;
constructor() { }
@HostListener('click') onLabelClick(){
if(this.appFormFocus) {
document.getElementById(this.appFormFocus)?.focus();
(document.getElementById(this.appFormFocus)?.querySelector(".angular-editor-textarea") as HTMLElement)?.focus(); //for rich-text-editor
document.getElementById(`${this.appFormFocus}-input`)?.focus(); //for any mat component that nests the <input>
}
}
}