Dataset profile editor. Preview step basic implementation.

This commit is contained in:
Kristian Ntavidi 2021-02-15 19:16:48 +02:00
parent 7445ec5042
commit 8579071cf7
10 changed files with 298 additions and 84 deletions

View File

@ -171,21 +171,23 @@
<div class="row" class="actions-list">
<mat-list role="list">
<!-- INPUT TOOLS -->
<h3 matSubheader>Input tools</h3>
<!-- Add new Input -->
<mat-list-item *ngIf="!viewOnly">
<mat-icon matListIcon>folder</mat-icon>
<span matLine (click)="addNewField()" style="cursor: pointer;" >Add Input</span>
</mat-list-item>
<!-- Visibility -->
<mat-list-item *ngIf="targetField && !viewOnly">
<mat-icon matListIcon [ngClass]="{'text-muted':!targetField.get('viewStyle').get('renderStyle').value}"
>visibility_off</mat-icon>
<button matLine class="mat-button" (click)="addVisibilityRule(targetField)" [disabled]="!targetField.get('viewStyle').get('renderStyle').value">
<span>Add Visibility Rule</span>
</button>
</mat-list-item>
<ng-container *ngIf="!viewOnly">
<h3 matSubheader>Input tools</h3>
<!-- Add new Input -->
<mat-list-item>
<mat-icon matListIcon>folder</mat-icon>
<span matLine (click)="addNewField()" style="cursor: pointer;" >Add Input</span>
</mat-list-item>
<!-- Visibility -->
<mat-list-item *ngIf="targetField">
<mat-icon matListIcon [ngClass]="{'text-muted':!targetField.get('viewStyle').get('renderStyle').value}"
>visibility_off</mat-icon>
<button matLine class="mat-button" (click)="addVisibilityRule(targetField)" [disabled]="!targetField.get('viewStyle').get('renderStyle').value">
<span>Add Visibility Rule</span>
</button>
</mat-list-item>
</ng-container>
<!-- INPUT SETTINGS -->
<h3 matSubheader>Input settings</h3>
@ -193,7 +195,7 @@
<!-- multiplicity -->
<mat-list-item>
<!-- <mat-icon matListIcon>folder</mat-icon> -->
<mat-checkbox matLine [(ngModel)]="isMultiplicityEnabled" (ngModelChange)="onIsMultiplicityEnabledChange(isMultiplicityEnabled)" [disabled]="viewOnly ||!targetField?.get('viewStyle').get('renderStyle').value">
<mat-checkbox matLine [checked]="isMultiplicityEnabled" (change)="onIsMultiplicityEnabledChange($event)" [disabled]="viewOnly ||!targetField?.get('viewStyle').get('renderStyle').value">
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-CHECKBOX' | translate}}
</mat-checkbox>
</mat-list-item>
@ -213,15 +215,17 @@
<!-- OTHER ACTIONS -->
<h3 matSubheader>Other actions</h3>
<!-- <mat-list-item> -->
<!-- <mat-icon matListIcon>folder</mat-icon> -->
<!-- <mat-checkbox [(ngModel)]="isComposite" (ngModelChange)="onIsCompositeChange(isComposite)" [disabled]="viewOnly">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.COMPOSITE-CHECKBOX' | translate}}</mat-checkbox>
</mat-list-item> -->
<mat-list-item *ngIf="targetField">
<mat-icon matListIcon>delete</mat-icon>
<span matLine (click)="deleteTargetField()" style="cursor: pointer;">Delete</span>
</mat-list-item>
<ng-container *ngIf="!viewOnly">
<h3 matSubheader>Other actions</h3>
<!-- <mat-list-item> -->
<!-- <mat-icon matListIcon>folder</mat-icon> -->
<!-- <mat-checkbox [(ngModel)]="isComposite" (ngModelChange)="onIsCompositeChange(isComposite)" [disabled]="viewOnly">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.COMPOSITE-CHECKBOX' | translate}}</mat-checkbox>
</mat-list-item> -->
<mat-list-item *ngIf="targetField && !viewOnly">
<mat-icon matListIcon>delete</mat-icon>
<span matLine (click)="deleteTargetField()" style="cursor: pointer;">Delete</span>
</mat-list-item>
</ng-container>
</mat-list>
</div>
</div>
@ -235,9 +239,12 @@
</app-form-composite-field> -->
Current FORM: {{this.form.value |json}}
<!-- Current FORM: {{this.form.value |json}}
<br>
Target: {{this.targetField?.value |json}}
Target: {{this.targetField?.value |json}} -->
<!--
<button (click)="generatePreview()">Generate preview</button>

View File

@ -27,7 +27,7 @@ export class DatasetProfileEditorCompositeFieldComponent implements OnInit, OnCh
previewForm: FormGroup;
// isComposite = false;
isMultiplicityEnabled = false;
// isMultiplicityEnabled = false;
viewStyleEnum = DatasetProfileFieldViewStyle;
constructor(
@ -38,13 +38,27 @@ export class DatasetProfileEditorCompositeFieldComponent implements OnInit, OnCh
ngOnChanges(){
this.setTargetField(null);
}
get isMultiplicityEnabled(){
if(!this.form.get('multiplicity')){
return false;
}
if (this.form.get('multiplicity').value.min > 0 || this.form.get('multiplicity').value.max > 0) {
return true;
}
return false;
}
ngOnInit() {
//this.addNewField();
if (this.form.get('multiplicity')) {
if (this.form.get('multiplicity').value.min > 1 || this.form.get('multiplicity').value.max > 1) {
this.isMultiplicityEnabled = true;
}
}
// if (this.form.get('multiplicity')) {
// if (this.form.get('multiplicity').value.min > 1 || this.form.get('multiplicity').value.max > 1) {
// this.isMultiplicityEnabled = true;
// }
// }
// this.isComposite = (this.form.get('fields') as FormArray).length > 1;
if (this.viewOnly) {
@ -109,11 +123,24 @@ export class DatasetProfileEditorCompositeFieldComponent implements OnInit, OnCh
}
}
onIsMultiplicityEnabledChange(isMultiplicityEnabled: boolean) {
if (!isMultiplicityEnabled) {
(<FormControl>this.form.get('multiplicity').get('min')).setValue(0);
(<FormControl>this.form.get('multiplicity').get('max')).setValue(0);
onIsMultiplicityEnabledChange(isMultiplicityEnabled: MatCheckboxChange) {
const multiplicity = this.form.get('multiplicity') as FormGroup;
const minControl = multiplicity.get('min');
const maxControl = multiplicity.get('max');
if (isMultiplicityEnabled.checked) {
minControl.setValue(0);
maxControl.setValue(1);
}else{
minControl.setValue(0);
maxControl.setValue(0);
}
minControl.updateValueAndValidity();
maxControl.updateValueAndValidity();
}
addNewField() {

View File

@ -35,7 +35,7 @@ import { Subscription } from 'rxjs';
templateUrl: './dataset-profile-editor-field.component.html',
styleUrls: ['./dataset-profile-editor-field.component.scss']
})
export class DatasetProfileEditorFieldComponent extends BaseComponent implements OnInit,OnChanges {
export class DatasetProfileEditorFieldComponent extends BaseComponent implements OnInit {
@Input() viewOnly: boolean;
@Input() form: FormGroup;
@Input() showOrdinal = true;
@ -50,9 +50,6 @@ export class DatasetProfileEditorFieldComponent extends BaseComponent implements
public enumUtils: EnumUtils,
public datasetProfileService: DatasetProfileService
) { super(); }
ngOnChanges(changes: SimpleChanges): void {
this.generatePreviewForm();
}
ngOnInit() {
this.showPreview = true;
@ -200,6 +197,14 @@ export class DatasetProfileEditorFieldComponent extends BaseComponent implements
}
if(value == true){
//value is already true
if(this._showPreview){
if(this._formChangesSubscription){
this._formChangesSubscription.unsubscribe();
this._formChangesSubscription = null;
}
}
this._formChangesSubscription = this.form.valueChanges.subscribe(()=>{
this.generatePreviewForm();
});
@ -215,6 +220,13 @@ export class DatasetProfileEditorFieldComponent extends BaseComponent implements
previewForm: FormGroup;
generatePreviewForm(){
if(!this.form.get('data')){
return;
}
this.previewForm = null;
// this._showPreview = false;
const fieldEditorModel = new DatasetDescriptionFieldEditorModel();

View File

@ -1,4 +1,6 @@
<div class="main-content" style="max-width:1500px">
<!-- View Only : {{viewOnly}} -->
<div class="main-content" style="max-width:1500px">
<div class="container-fluid dataset-profile-editor" *ngIf="form" [formGroup]='form'>
<h3 *ngIf="isNew && !isClone && !isNewVersion">{{'DATASET-PROFILE-EDITOR.TITLE.NEW-PROFILE' | translate}}</h3>
<h3 *ngIf="isNew && isClone">
@ -22,10 +24,10 @@
<!-- Total steps: {{stepper.steps.length}} -->
<!-- Steps Navigation -->
<div class="row" style="padding: 2em;">
<div class="row" style="padding: 2em;" *ngIf="steps">
<div class="col-7 bg-white" style="overflow: hidden; padding: 0px" id="progress-container">
<div id="progress" [ngStyle]="{'transform': 'translateX('+barPercentage+'%) skewX(-25deg)'}"></div>
<div id="progress" [ngStyle]="progressStyle"></div>
<div class="row p-1">
<div class="col text-center" *ngFor="let step of steps; index as idx">
<span (click)="stepper.selectedIndex=idx" style="cursor: pointer">
@ -46,7 +48,7 @@
</div>
<mat-horizontal-stepper [linear]="true" #stepper class="stepper">
<mat-horizontal-stepper [linear]="true" #stepper class="stepper" (selectionChange)="onMatStepperSelectionChange($event)">
<mat-step [label]="'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.TITLE' | translate">
<!-- <ng-template matStepLabel>{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.TITLE' | translate}}
@ -124,7 +126,8 @@
(newEntry)="addNewEntry($event)"
(createEntry) = "addNewEntry($event)"
(removeEntry)="onRemoveEntry($event)"
[itemSelected]="selectedTocEntry">
[itemSelected]="selectedTocEntry"
[viewOnly]="viewOnly">
</dataset-profile-table-of-contents>
</div>
@ -244,13 +247,17 @@
</mat-step>
<mat-step label="Preview and Finalize">
Preview and finalize
<!-- <button (click)="generatePreviewForm()">foo</button> -->
<app-dataset-description [form]="previewForm">
</app-dataset-description>
</mat-step>
</mat-horizontal-stepper>
<ng-container *ngIf="true">
<ng-container *ngIf="false">
<div class="d-flex">
<!-- SAVE BUTTON -->
@ -295,5 +302,8 @@
console form
</button>
</div>
<!-- <div class="row">
<button (click)="foo()">foo</button>
</div> -->
</div>
</div>

View File

@ -36,6 +36,7 @@ import { Guid } from '@common/types/guid';
import { FieldEditorModel } from '../admin/field-editor-model';
import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service';
import { StepperSelectionEvent } from '@angular/cdk/stepper';
import { DatasetDescriptionCompositeFieldEditorModel, DatasetDescriptionFieldEditorModel, DatasetDescriptionFormEditorModel, DatasetDescriptionPageEditorModel, DatasetDescriptionSectionEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model';
const skipDisable: any[] = require('../../../../../assets/resources/skipDisable.json');
@ -612,6 +613,31 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
return result;
}
private _findTocEntryById(id: string, tocentries: ToCEntry[]): ToCEntry{
if(!tocentries){
return null;
}
let tocEntryFound = tocentries.find(entry=>entry.id === id);
if(tocEntryFound){
return tocEntryFound;
}
for(let entry of tocentries){
const result = this._findTocEntryById(id, entry.subEntries);
if(result){
tocEntryFound = result;
break;
}
}
if(tocEntryFound) return tocEntryFound;
return null;
}
addNewEntry(tce: Foo) {
const parent = tce.parent;
@ -633,15 +659,8 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
//make new entry selected
const pagesArray = (this.form.get('pages') as FormArray);
const addedEntry = pagesArray.at(pagesArray.length-1) as FormGroup;
this.selectedTocEntry = {
form: addedEntry,
label: addedEntry.get('title').value,
type: ToCEntryType.Page,
id: addedEntry.get('id').value,
numbering:pagesArray.value.length,
subEntries:null,
subEntriesType: ToCEntryType.Section
}
this.selectedTocEntry = this._findTocEntryById(addedEntry.get('id').value, this.getTocEntries());
break;
case ToCEntryType.Section: //adding a section
@ -676,15 +695,7 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
const sectionAdded = sectionsArray.at(sectionsArray.length -1) as FormGroup;
this.selectedTocEntry = {
id: sectionAdded.get('id').value,
label: sectionAdded.get('title').value,
form: sectionAdded,
numbering:'',
subEntries: null,
subEntriesType: undefined, //ADDNEW VALUE TO TOCENTRY TYPE FOR UNDFINED
type: ToCEntryType.Section
}
this.selectedTocEntry = this._findTocEntryById(sectionAdded.get('id').value, this.getTocEntries());
break;
case ToCEntryType.FieldSet:
@ -705,16 +716,7 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
const parentArray = parent.form.get('fieldSets') as FormArray;
const addedFieldSet = parentArray.at(parentArray.length - 1);
this.selectedTocEntry = {
id: addedFieldSet.get('id').value,
label: addedFieldSet.get('title').value,
form: addedFieldSet,
numbering: '',
subEntries: null, //TODO IT SHOULD HAVE CHILDS
subEntriesType: ToCEntryType.Field,
type: ToCEntryType.FieldSet
}
this.selectedTocEntry = this._findTocEntryById(addedFieldSet.get('id').value, this.getTocEntries());
break;
@ -722,6 +724,7 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
break;
}
}
@ -969,6 +972,11 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
return (selectedIndex / this.stepper.steps.length) * 110- 110;
}
get progressStyle(){
return {'transform': 'translateX('+this.barPercentage+'%) skewX(-25deg)'}
}
get steps(){
if(!this.stepper){
return [];
@ -976,4 +984,133 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
return this.stepper.steps;
}
generatePreviewForm(){
const model = new DatasetDescriptionFormEditorModel();
const toCentries = this.getTocEntries();
//first level is always pages
model.pages = toCentries.map(entry=>{
if( !(entry.type == ToCEntryType.Page)){
return null;
}
const pageModel = new DatasetDescriptionPageEditorModel();
pageModel.ordinal = entry.form.get('ordinal').value;
pageModel.title = entry.label;
if(entry.subEntries){
pageModel.sections = entry.subEntries.map(section=>{
const sectionModel = new DatasetDescriptionSectionEditorModel();
sectionModel.id = section.id;
sectionModel.ordinal = section.form.get('ordinal').value;
sectionModel.description = section.form.get('description').value;
sectionModel.page = entry.form.get('ordinal').value;
sectionModel.title = section.label;
sectionModel.numbering = section.numbering;
if(section.subEntriesType == ToCEntryType.Section){
sectionModel.sections = this._buildSectionsRecursively(section.subEntries);
}else{
sectionModel.compositeFields = this._buildFormFields(section.subEntries)
}
return sectionModel;
})
};
return pageModel;
});
this.previewForm = model.buildForm();
}
private _buildSectionsRecursively( tocentries: ToCEntry[]): DatasetDescriptionSectionEditorModel[]{
if(!tocentries) return null;
const result: Array<DatasetDescriptionSectionEditorModel> = [];
tocentries.forEach(tocentry=>{
const sectionModel = new DatasetDescriptionSectionEditorModel();
sectionModel.id = tocentry.id;
sectionModel.ordinal = tocentry.form.get('ordinal').value;
sectionModel.description = tocentry.form.get('description').value;
// sectionModel.page = entry.form.get('ordinal').value;
sectionModel.title = tocentry.label;
sectionModel.numbering = tocentry.numbering;
if(tocentry.subEntriesType == ToCEntryType.Section){
sectionModel.sections = this._buildSectionsRecursively(tocentry.subEntries);
}else{
sectionModel.compositeFields = this._buildFormFields(tocentry.subEntries);
}
result.push(sectionModel);
})
return result;
}
private _buildFormFields(tocentries: ToCEntry[]):DatasetDescriptionCompositeFieldEditorModel[]{
if(!tocentries) return null;
const fieldsets:DatasetDescriptionCompositeFieldEditorModel[] = [];
tocentries.forEach(fs=>{
const fieldset = new DatasetDescriptionCompositeFieldEditorModel();
fieldset.description = fs.form.get('description').value;
fieldset.extendedDescription = fs.form.get('extendedDescription').value;
fieldset.id = fs.form.get('id').value;
fieldset.multiplicity = fs.form.get('multiplicity').value;
fieldset.additionalInformation = fs.form.get('additionalInformation').value;
fieldset.ordinal = fs.form.get('ordinal').value;
fieldset.hasCommentField = fs.form.get('hasCommentField').value;
fieldset.title = fs.label;
// fieldset.fields = (fs.form.get('fields') as FormArray).getRawValue();
fieldset.fields = (fs.form.get('fields') as FormArray).controls.map(field=>{
const fieldModel = new DatasetDescriptionFieldEditorModel();
fieldModel.data = (field.get('data') as FormGroup).getRawValue();
fieldModel.id = field.get('id').value;
fieldModel.viewStyle = (field.get('viewStyle') as FormGroup).getRawValue();
fieldModel.defaultValue = field.get('defaultValue').value;
fieldModel.page = field.get('page').value;
fieldModel.validations = field.get('validations').value;
return fieldModel;
});
fieldsets.push(fieldset);
});
return fieldsets;
}
onMatStepperSelectionChange(event: StepperSelectionEvent){
if(event.selectedIndex === 2){//preview selected
this.generatePreviewForm();//TODO LAZY LOADING IN THE TEMPLATE
}
}
previewForm:FormGroup;
}

View File

@ -2,11 +2,14 @@
<div *ngFor="let link of links; let i = index; last as isLast " class="docs-link mt-0" style="border-left: 1px solid black; padding-left: 1em;">
<div class="link-name">
<div class="table-item">
<span style="display: inline-block; cursor: pointer;" [ngClass]="{'active': itemSelected?.id == link.id}" (click)="itemClicked(link)" >
{{link.numbering}} {{link.label? link.label : 'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.UNTITLED' | translate}}
</span>
<div class="table-item-actions">
<div class="table-item row">
<div class="col link-info">
<span style="cursor: pointer;" [ngClass]="{'active': itemSelected?.id == link.id}" (click)="itemClicked(link)" >
{{link.numbering}} {{link.label? link.label : 'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.UNTITLED' | translate}}
<!-- <span class="mat-button table-item-actions" (click)="deleteEntry(link)"><mat-icon>delete</mat-icon></span> -->
</span>
</div>
<div class="table-item-actions col-auto" *ngIf="!viewOnly">
<button class="mat-button" (click)="deleteEntry(link)"><mat-icon>delete</mat-icon></button>
</div>
</div>
@ -33,14 +36,15 @@
(removeEntry)="deleteEntry($event)"
[parentLink]="link"
[itemSelected] = "itemSelected"
(createFooEntry)="createNewEntry($event)">
(createFooEntry)="createNewEntry($event)"
[viewOnly]="viewOnly">
</app-dataset-profile-table-of-contents-internal-section>
</div>
</div>
<!-- BUILD SUBENTRIES IF THEY DONT EXIST -- CURRENT ITEM DOES HAVE CHILDREN -->
<div *ngIf="!links && parentLink.type!= tocEntryType.FieldSet" class="docs-link mt-0" style="border: 1px solid ;">
<div *ngIf="(!links && parentLink.type!= tocEntryType.FieldSet) && !viewOnly" class="docs-link mt-0" style="border: 1px solid ;">
NoEntries
<div class="ml-2">
@ -61,7 +65,7 @@
<!-- BUILD TYPE OF SAME LEVEL AS LINK OF LINKS -->
<div *ngIf="links">
<div *ngIf="links && !viewOnly" >
<button class="mat-button" style="padding-left: 0px;" (click)="createNewEntry({childType:parentLink.subEntriesType,parent:parentLink})">
<mat-icon>add</mat-icon>
<!-- Create => {{parentLink?.subEntriesType}} -->

View File

@ -86,4 +86,17 @@
// display: inline-block;
visibility: visible;
}
}
// .table-item col{
// text-overflow: ellipsis;
// overflow: hidden;
// white-space: nowrap;
// }
.link-info{
// display: inline-block; cursor: pointer;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}

View File

@ -20,6 +20,8 @@ export class DatasetProfileTableOfContentsInternalSection extends BaseComponent
@Input() parentLink: ToCEntry;
@Input() itemSelected: ToCEntry;
@Input() viewOnly: boolean;
constructor(
@Inject(DOCUMENT) private _document: Document) {
super();

View File

@ -10,7 +10,8 @@
(newEntry)="addNewEntry($event)" (removeEntry)="deleteEntry($event)"
(createFooEntry)="createNewEntry($event)"
[parentLink]="{ subEntriesType: tocEntryType.Page }"
[itemSelected]="itemSelected"></app-dataset-profile-table-of-contents-internal-section>
[itemSelected]="itemSelected"
[viewOnly]="viewOnly"></app-dataset-profile-table-of-contents-internal-section>
<!-- <span *ngFor="let link of links; let i = index" (click)="toggle(link); goToStep(link);" class="docs-link mt-0">
<span class="link-name" (click)="itemClicked(link)"><span>{{link.label}}</span></span>

View File

@ -46,6 +46,7 @@ export class DatasetProfileTableOfContents extends BaseComponent implements OnIn
@Input() itemSelected: ToCEntry;
@Input() viewOnly: boolean;
subscription: Subscription;
linksSubject: Subject<HTMLElement[]> = new Subject<HTMLElement[]>();