description editor refactor - WIP
This commit is contained in:
parent
3e97d0fdd1
commit
c6508a0082
|
@ -71,16 +71,6 @@ const appRoutes: Routes = [
|
|||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
path: 'datasetcreatewizard',
|
||||
loadChildren: () => import('./ui/dataset-create-wizard/dataset-create-wizard.module').then(m => m.DatasetCreateWizardModule),
|
||||
data: {
|
||||
breadcrumb: true,
|
||||
title: 'GENERAL.TITLES.DATASETCREATEWIZARD'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
path: 'about',
|
||||
|
@ -100,14 +90,7 @@ const appRoutes: Routes = [
|
|||
// }
|
||||
// },
|
||||
|
||||
{
|
||||
path: 'quick-wizard',
|
||||
loadChildren: () => import('./ui/quick-wizard/quick-wizard.module').then(m => m.OuickWizardModule),
|
||||
data: {
|
||||
breadcrumb: true,
|
||||
title: "GENERAL.TITLES.QUICK-WIZARD"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
path: 'dataset-profiles',
|
||||
loadChildren: () => import('./ui/admin/dataset-profile/dataset-profile.module').then(m => m.DatasetProfileModule),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { OverlayModule } from '@angular/cdk/overlay';
|
||||
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { APP_INITIALIZER, LOCALE_ID, NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MAT_MOMENT_DATE_FORMATS, MatMomentDateModule } from '@angular/material-moment-adapter';
|
||||
|
@ -12,7 +12,6 @@ import { AppComponent } from '@app/app.component';
|
|||
import { CoreServiceModule } from '@app/core/core-service.module';
|
||||
import { NotificationModule } from '@app/library/notification/notification.module';
|
||||
import { LoginModule } from '@app/ui/auth/login/login.module';
|
||||
import { DatasetCreateWizardModule } from '@app/ui/dataset-create-wizard/dataset-create-wizard.module';
|
||||
// import { BreadcrumbModule } from '@app/ui/misc/breadcrumb/breadcrumb.module';
|
||||
import { HelpContentModule } from '@app/ui/misc/help-content/help-content.module';
|
||||
import { NavigationModule } from '@app/ui/misc/navigation/navigation.module';
|
||||
|
@ -143,7 +142,6 @@ export function InstallationConfigurationFactory(appConfig: ConfigurationService
|
|||
HelpContentModule,
|
||||
ReactiveFormsModule,
|
||||
FormsModule,
|
||||
DatasetCreateWizardModule,
|
||||
NavbarModule,
|
||||
SidebarModule,
|
||||
NgcCookieConsentModule.forRoot(cookieConfig),
|
||||
|
|
|
@ -39,7 +39,6 @@ import { UiNotificationService } from './services/notification/ui-notification-s
|
|||
import { OrganisationService } from './services/organisation/organisation.service';
|
||||
import { ProgressIndicationService } from './services/progress-indication/progress-indication-service';
|
||||
import { ProjectService } from './services/project/project.service';
|
||||
import { QuickWizardService } from './services/quick-wizard/quick-wizard.service';
|
||||
import { SearchBarService } from './services/search-bar/search-bar.service';
|
||||
import { TimezoneService } from './services/timezone/timezone-service';
|
||||
import { UnlinkAccountEmailConfirmationService } from './services/unlink-account-email-confirmation/unlink-account-email-confirmation.service';
|
||||
|
@ -119,7 +118,6 @@ export class CoreServiceModule {
|
|||
UserServiceOld,
|
||||
DmpInvitationService,
|
||||
DatasetExternalAutocompleteService,
|
||||
QuickWizardService,
|
||||
OrganisationService,
|
||||
EmailConfirmationService,
|
||||
ContactSupportService,
|
||||
|
|
|
@ -2,5 +2,4 @@ export class Rule {
|
|||
sourceField: string;
|
||||
targetField: string;
|
||||
requiredValue: any;
|
||||
type: string;
|
||||
}
|
|
@ -30,13 +30,13 @@ export interface DescriptionTemplateDefinitionPersist {
|
|||
|
||||
|
||||
export interface DescriptionTemplatePagePersist {
|
||||
id: Guid;
|
||||
id: string;
|
||||
ordinal: number;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateSectionPersist {
|
||||
id: Guid;
|
||||
id: string;
|
||||
ordinal: number;
|
||||
defaultVisibility: boolean;
|
||||
multiplicity: boolean;
|
||||
|
@ -49,7 +49,7 @@ export interface DescriptionTemplateSectionPersist {
|
|||
}
|
||||
|
||||
export interface DescriptionTemplateFieldSetPersist {
|
||||
id: Guid;
|
||||
id: string;
|
||||
ordinal: number;
|
||||
numbering: string;
|
||||
title: string;
|
||||
|
@ -62,7 +62,7 @@ export interface DescriptionTemplateFieldSetPersist {
|
|||
}
|
||||
|
||||
export interface DescriptionTemplateFieldPersist {
|
||||
id: Guid;
|
||||
id: string;
|
||||
ordinal: number;
|
||||
schematics: string[];
|
||||
defaultValue: string;
|
||||
|
|
|
@ -34,13 +34,13 @@ export interface DescriptionTemplateDefinition {
|
|||
|
||||
|
||||
export interface DescriptionTemplatePage {
|
||||
id: Guid;
|
||||
id: string;
|
||||
ordinal: number;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateSection {
|
||||
id: Guid;
|
||||
id: string;
|
||||
ordinal: number;
|
||||
defaultVisibility: boolean;
|
||||
multiplicity: boolean;
|
||||
|
@ -55,7 +55,7 @@ export interface DescriptionTemplateSection {
|
|||
}
|
||||
|
||||
export interface DescriptionTemplateFieldSet {
|
||||
id: Guid;
|
||||
id: string;
|
||||
ordinal: number;
|
||||
numbering: string;
|
||||
title: string;
|
||||
|
@ -68,7 +68,7 @@ export interface DescriptionTemplateFieldSet {
|
|||
}
|
||||
|
||||
export interface DescriptionTemplateField {
|
||||
id: Guid;
|
||||
id: string;
|
||||
ordinal: number;
|
||||
numbering?: string;
|
||||
schematics?: string[];
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
import { HttpHeaders } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
import { QuickWizardEditorWizardModel } from '../../../ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.model';
|
||||
import { BaseHttpService } from '../http/base-http.service';
|
||||
import { DatasetCreateWizardModel } from '../../../ui/dataset-create-wizard/dataset-create-wizard.model';
|
||||
import { ConfigurationService } from '../configuration/configuration.service';
|
||||
|
||||
@Injectable()
|
||||
export class QuickWizardService {
|
||||
private actionUrl: string;
|
||||
private headers: HttpHeaders;
|
||||
|
||||
constructor(private http: BaseHttpService, private configurationService: ConfigurationService) {
|
||||
this.actionUrl = configurationService.server + 'quick-wizard/';
|
||||
}
|
||||
|
||||
createQuickWizard(quickWizard: QuickWizardEditorWizardModel): Observable<QuickWizardEditorWizardModel> {
|
||||
return this.http.post<QuickWizardEditorWizardModel>(this.actionUrl, quickWizard, { headers: this.headers });
|
||||
}
|
||||
|
||||
createQuickDatasetWizard(datasetCreateWizardModel: DatasetCreateWizardModel): Observable<DatasetCreateWizardModel> {
|
||||
return this.http.post<DatasetCreateWizardModel>(this.actionUrl + 'datasetcreate', datasetCreateWizardModel, { headers: this.headers });
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import { Component, Input, OnInit} from '@angular/core';
|
||||
import { Rule } from '@app/core/model/dataset-profile-definition/rule';
|
||||
import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service';
|
||||
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
||||
|
||||
|
||||
@Component({
|
||||
|
|
|
@ -33,7 +33,7 @@ import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
|
|||
import { FieldSetEditorModel } from '../admin/field-set-editor-model';
|
||||
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 { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
||||
import { CdkStep, StepperSelectionEvent } from '@angular/cdk/stepper';
|
||||
import { DatasetDescriptionCompositeFieldEditorModel, DatasetDescriptionFieldEditorModel, DatasetDescriptionSectionEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model';
|
||||
import { Rule } from '@app/core/model/dataset-profile-definition/rule';
|
||||
|
|
|
@ -92,8 +92,9 @@
|
|||
</div>
|
||||
<div [id]="'preview_container'+ form.get('id').value" class="w-100" style="margin-right: -15px; margin-left: -15px;">
|
||||
<div *ngIf="previewForm && showPreview && firstField?.get('data')?.get('fieldType')?.value" [@fade-in-fast]>
|
||||
<app-form-section-inner [form]="previewForm" [tableView]="form.getRawValue().multiplicity?.tableView" [datasetProfileId]="datasetProfileId">
|
||||
</app-form-section-inner>
|
||||
<!-- Check what we need to do with this. -->
|
||||
<!-- <app-form-section-inner [form]="previewForm" [tableView]="form.getRawValue().multiplicity?.tableView" [datasetProfileId]="datasetProfileId">
|
||||
</app-form-section-inner> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -341,7 +341,7 @@ export class DescriptionTemplateEditorCompositeFieldComponent extends BaseCompon
|
|||
|
||||
addNewField() {
|
||||
const field: DescriptionTemplateFieldEditorModel = new DescriptionTemplateFieldEditorModel();
|
||||
field.id = Guid.create();
|
||||
field.id = Guid.create().toString();
|
||||
|
||||
field.ordinal = (this.form.get('fields') as UntypedFormArray).length;
|
||||
|
||||
|
@ -494,7 +494,7 @@ export class DescriptionTemplateEditorCompositeFieldComponent extends BaseCompon
|
|||
}
|
||||
|
||||
const field = {
|
||||
id: Guid.create(),
|
||||
id: Guid.create().toString(),
|
||||
ordinal: targetOrdinal,
|
||||
validations: [],
|
||||
includeInExport: true
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Component, Input, OnInit} from '@angular/core';
|
||||
import { Rule } from '@app/core/model/dataset-profile-definition/rule';
|
||||
import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service';
|
||||
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
||||
|
||||
|
||||
@Component({
|
||||
|
|
|
@ -22,7 +22,7 @@ export class DescriptionTemplateEditorSectionFieldSetComponent implements OnInit
|
|||
|
||||
@Input() datasetProfileId?: string;
|
||||
|
||||
@Output() selectedEntryId = new EventEmitter<Guid>();
|
||||
@Output() selectedEntryId = new EventEmitter<string>();
|
||||
@Output() dataNeedsRefresh = new EventEmitter<void>();
|
||||
@Output() removeFieldSet = new EventEmitter<string>();
|
||||
@Output() addNewFieldSet = new EventEmitter<UntypedFormGroup>();
|
||||
|
@ -101,11 +101,11 @@ export class DescriptionTemplateEditorSectionFieldSetComponent implements OnInit
|
|||
|
||||
|
||||
|
||||
private _selectedFieldSetId: Guid = null;
|
||||
private _selectedFieldSetId: string = null;
|
||||
get selectedFieldSetId() {
|
||||
return this._selectedFieldSetId;
|
||||
}
|
||||
set selectedFieldSetId(id: Guid) {
|
||||
set selectedFieldSetId(id: string) {
|
||||
|
||||
if (id === this._selectedFieldSetId) return;
|
||||
this._selectedFieldSetId = id;
|
||||
|
@ -140,7 +140,7 @@ export class DescriptionTemplateEditorSectionFieldSetComponent implements OnInit
|
|||
} else {
|
||||
// console.warn('!not found numbering');
|
||||
}
|
||||
this._selectedFieldSetId = Guid.parse(this.tocentry.id);
|
||||
this._selectedFieldSetId = this.tocentry.id;
|
||||
|
||||
// this._scrollToElement(this.selectedFieldSetId);
|
||||
this.scroller.next(this.tocentry.id);
|
||||
|
@ -194,13 +194,13 @@ export class DescriptionTemplateEditorSectionFieldSetComponent implements OnInit
|
|||
|
||||
addFieldSetAfter(afterOrdinal: number, afterIndex: number): void {
|
||||
const field: DescriptionTemplateFieldEditorModel = new DescriptionTemplateFieldEditorModel();
|
||||
field.id = Guid.create();
|
||||
field.id = Guid.create().toString();
|
||||
field.ordinal = 0;//first filed in the fields list
|
||||
const fieldForm = field.buildForm();
|
||||
|
||||
//give fieldset id and ordinal
|
||||
const fieldSet: DescriptionTemplateFieldSetEditorModel = new DescriptionTemplateFieldSetEditorModel();
|
||||
const fieldSetId = Guid.create();
|
||||
const fieldSetId = Guid.create().toString();
|
||||
fieldSet.id = fieldSetId;
|
||||
fieldSet.ordinal = afterOrdinal < 0 ? 0 : afterOrdinal;
|
||||
|
||||
|
|
|
@ -28,10 +28,10 @@ export class DescriptionTemplateEditorSectionComponent extends BaseComponent imp
|
|||
fieldSet.ordinal = (this.form.get('fieldSets') as UntypedFormArray).length;
|
||||
|
||||
const field: DescriptionTemplateFieldEditorModel = new DescriptionTemplateFieldEditorModel();
|
||||
field.id = Guid.create();
|
||||
field.id = Guid.create().toString();
|
||||
field.ordinal = 0;//first field in fields
|
||||
fieldSet.fields.push(field);
|
||||
fieldSet.id = Guid.create();
|
||||
fieldSet.id = Guid.create().toString();
|
||||
|
||||
const fieldsetsArray = this.form.get('fieldSets') as UntypedFormArray;
|
||||
fieldsetsArray.push(fieldSet.buildForm());
|
||||
|
|
|
@ -566,7 +566,7 @@ export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTe
|
|||
const pagesArray = (this.formGroup.get('definition').get('pages') as UntypedFormArray);
|
||||
|
||||
const page: DescriptionTemplatePageEditorModel = new DescriptionTemplatePageEditorModel();
|
||||
page.id = Guid.create();
|
||||
page.id = Guid.create().toString();
|
||||
if (isNaN(pagesArray.length)) { page.ordinal = 0; } else { page.ordinal = pagesArray.length; }
|
||||
const pageForm = page.buildForm();
|
||||
// this.dataModel.pages.push(page);
|
||||
|
@ -580,7 +580,7 @@ export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTe
|
|||
case ToCEntryType.Section:
|
||||
|
||||
const section: DescriptionTemplateSectionEditorModel = new DescriptionTemplateSectionEditorModel();
|
||||
section.id = Guid.create();
|
||||
section.id = Guid.create().toString();
|
||||
let sectionsArray: UntypedFormArray;
|
||||
|
||||
if (parent.type === ToCEntryType.Page) {//FIRST LEVEL SECTION
|
||||
|
@ -634,7 +634,7 @@ export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTe
|
|||
|
||||
//create one field form fieldset
|
||||
const field: DescriptionTemplateFieldEditorModel = new DescriptionTemplateFieldEditorModel();
|
||||
field.id = Guid.create();
|
||||
field.id = Guid.create().toString();
|
||||
field.ordinal = 0;//first filed in the fields list
|
||||
const fieldForm = field.buildForm();
|
||||
// fieldForm.setValidators(this.customFieldValidator());
|
||||
|
@ -647,7 +647,7 @@ export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTe
|
|||
|
||||
//give fieldset id and ordinal
|
||||
const fieldSet: DescriptionTemplateFieldSetEditorModel = new DescriptionTemplateFieldSetEditorModel();
|
||||
const fieldSetId = Guid.create();
|
||||
const fieldSetId = Guid.create().toString();
|
||||
fieldSet.id = fieldSetId;
|
||||
|
||||
try {
|
||||
|
|
|
@ -208,7 +208,7 @@ export class DescriptionTemplateDefinitionEditorModel implements DescriptionTemp
|
|||
}
|
||||
|
||||
export class DescriptionTemplatePageEditorModel implements DescriptionTemplatePagePersist {
|
||||
id: Guid;
|
||||
id: string;
|
||||
ordinal: number;
|
||||
title: string;
|
||||
|
||||
|
@ -266,7 +266,7 @@ export class DescriptionTemplatePageEditorModel implements DescriptionTemplatePa
|
|||
}
|
||||
|
||||
export class DescriptionTemplateSectionEditorModel implements DescriptionTemplateSectionPersist {
|
||||
id: Guid;
|
||||
id: string;
|
||||
ordinal: number;
|
||||
defaultVisibility: boolean = false; // TODO: check if used and remove
|
||||
multiplicity: boolean = false;
|
||||
|
@ -364,7 +364,7 @@ export class DescriptionTemplateSectionEditorModel implements DescriptionTemplat
|
|||
}
|
||||
|
||||
export class DescriptionTemplateFieldSetEditorModel implements DescriptionTemplateFieldSetPersist {
|
||||
id: Guid;
|
||||
id: string;
|
||||
ordinal: number;
|
||||
numbering: string = "0"; // Check if used and remove
|
||||
title: string;
|
||||
|
@ -525,7 +525,7 @@ export class DescriptionTemplateMultiplicityEditorModel implements DescriptionTe
|
|||
//
|
||||
//
|
||||
export class DescriptionTemplateFieldEditorModel implements DescriptionTemplateFieldPersist {
|
||||
id: Guid;
|
||||
id: string;
|
||||
ordinal: number;
|
||||
schematics: string[];
|
||||
defaultValue: string;
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
<div class="main-content">
|
||||
<div class="container-fluid">
|
||||
<div class="dataset-create-wizard">
|
||||
<h3 *ngIf="isNew">{{ 'QUICKWIZARD.CREATE-ADD.ADD.DATASET-WIZARD' | translate }}</h3>
|
||||
<p *ngIf="isNew">{{ 'QUICKWIZARD.CREATE-ADD.ADD.POST-SELECTION-INFO' | translate }}</p>
|
||||
<mat-horizontal-stepper linear #stepper>
|
||||
<mat-step class="step-container" [stepControl]="formGroup.get('dmpMeta')">
|
||||
<ng-template matStepLabel>{{'DATASET-CREATE-WIZARD.FIRST-STEP.TITLE'| translate}}</ng-template>
|
||||
<form [formGroup]="formGroup.get('dmpMeta')">
|
||||
<dataset-dmp-selector-component class="col-12" [formGroup]="formGroup.get('dmpMeta')" [datasetFormGroup]="formGroup.get('datasets')" [stepper]="stepper">
|
||||
</dataset-dmp-selector-component>
|
||||
</form>
|
||||
<div class="col-12">
|
||||
<div class="row">
|
||||
<div class="col"></div>
|
||||
<div><button matStepperNext mat-raised-button color="primary" [disabled]="!formGroup.get('dmpMeta').valid">{{'DATASET-CREATE-WIZARD.ACTIONS.NEXT'| translate}}</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-step>
|
||||
<mat-step [stepControl]="formGroup">
|
||||
<ng-template matStepLabel>
|
||||
{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.THIRD-STEP.TITLE' | translate}}
|
||||
</ng-template>
|
||||
<div *ngIf="formGroup.get('dmpMeta').valid && isActive('step2')">
|
||||
<app-dataset-editor-wizard-component class="col-12" [formGroup]="formGroup" [datasetProfile]="formGroup.get('dmpMeta').get('datasetProfile')" [datasetLabel]="formGroup.get('dmpMeta').get('dmp').value['label']">
|
||||
</app-dataset-editor-wizard-component>
|
||||
</div>
|
||||
<div class="navigation-buttons-container">
|
||||
<button matStepperPrevious mat-raised-button color="primary">{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.BACK' | translate}}</button>
|
||||
<button class="saveAndFinalizeButton" matStepperNext mat-raised-button (click)='saveFinalize()' [disabled]="!isFormValid() || !hasDatasets()" color="primary">{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.SAVE-AND-FINALIZE' | translate}}</button>
|
||||
<button class="saveButton" matStepperNext mat-raised-button (click)='save()' [disabled]="!hasDatasets()" color="primary">{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.SAVE' | translate}}</button>
|
||||
</div>
|
||||
</mat-step>
|
||||
</mat-horizontal-stepper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,11 +0,0 @@
|
|||
.saveAndFinalizeButton{
|
||||
float:right;
|
||||
}
|
||||
.finalizeButton{
|
||||
float: right;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.saveButton{
|
||||
float:right;
|
||||
margin-right: 15px;
|
||||
}
|
|
@ -1,163 +0,0 @@
|
|||
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatStepper } from '@angular/material/stepper';
|
||||
import { Router } from '@angular/router';
|
||||
import { DatasetStatus } from '@app/core/common/enum/dataset-status';
|
||||
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
|
||||
import { QuickWizardService } from '@app/core/services/quick-wizard/quick-wizard.service';
|
||||
import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component';
|
||||
import { DatasetCreateWizardModel } from '@app/ui/dataset-create-wizard/dataset-create-wizard.model';
|
||||
import { DatasetEditorWizardComponent } from '@app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component';
|
||||
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'dataset-create-wizard.component',
|
||||
templateUrl: 'dataset-create-wizard.component.html',
|
||||
styleUrls: ['./dataset-create-wizard.component.scss'],
|
||||
})
|
||||
export class DatasetCreateWizard extends CheckDeactivateBaseComponent implements OnInit { //IBreadCrumbComponent
|
||||
//breadCrumbs: Observable<BreadcrumbItem[]>;
|
||||
@ViewChild(DatasetEditorWizardComponent) datasetEditorWizardComponent: DatasetEditorWizardComponent;
|
||||
isLinear = false;
|
||||
isNew = true;
|
||||
isSubmitted = false;
|
||||
formGroup: UntypedFormGroup;
|
||||
|
||||
|
||||
datasetCreateWizardModel: DatasetCreateWizardModel;
|
||||
@ViewChild('stepper', { static: true }) stepper: MatStepper;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private formBuilder: UntypedFormBuilder,
|
||||
public quickWizardService: QuickWizardService,
|
||||
public language: TranslateService,
|
||||
private uiNotificationService: UiNotificationService,
|
||||
private dialog: MatDialog
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.datasetCreateWizardModel = new DatasetCreateWizardModel();
|
||||
this.formGroup = this.datasetCreateWizardModel.buildForm();
|
||||
this.language.get('NAV-BAR.DATASET-DESCRIPTION-WIZARD').pipe(takeUntil(this._destroyed)).subscribe(x => {
|
||||
// this.breadCrumbs = observableOf([
|
||||
// {
|
||||
// parentComponentName: 'Dashboard',
|
||||
// label: x,
|
||||
// url: '/datasetcreatewizard'
|
||||
// }]
|
||||
// );
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
save() {
|
||||
if (this.formGroup.get('datasets') && this.formGroup.get('datasets').get('datasetsList') && (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).length > 0) {
|
||||
for (let control of (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).controls) {
|
||||
control.get('status').setValue(DatasetStatus.Draft);
|
||||
}
|
||||
// this.onSubmitSave();
|
||||
const dmpId = this.formGroup.get('dmpMeta').get('dmp').value.id;
|
||||
this.quickWizardService.createQuickDatasetWizard(this.formGroup.value)
|
||||
.pipe(takeUntil(this._destroyed))
|
||||
.subscribe(
|
||||
complete => this.onCallbackSuccess(dmpId)
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
saveFinalize() {
|
||||
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
|
||||
maxWidth: '300px',
|
||||
restoreFocus: false,
|
||||
data: {
|
||||
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.FINALIZE-ITEM'),
|
||||
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
|
||||
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
|
||||
isDeleteConfirmation: false
|
||||
}
|
||||
});
|
||||
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
|
||||
if (result) {
|
||||
if (!this.isFormValid()) { return; }
|
||||
if (this.formGroup.get('datasets') && this.formGroup.get('datasets').get('datasetsList') && (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).length > 0) {
|
||||
for (let control of (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).controls) {
|
||||
control.get('status').setValue(DatasetStatus.Finalized);
|
||||
}
|
||||
this.onSubmitSaveAndFinalize();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// onSubmitSave() {
|
||||
// const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
|
||||
// data: {
|
||||
// message: this.language.instant('QUICKWIZARD.SAVE-DIALOG.TITLE'),
|
||||
// confirmButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.AFFIRMATIVE'),
|
||||
// cancelButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.NEGATIVE')
|
||||
// }
|
||||
// });
|
||||
// dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
|
||||
// if (result) {
|
||||
// this.datasetEditorWizardComponent.addDataset();
|
||||
// } else if (result === false) {
|
||||
// this.quickWizardService.createQuickDatasetWizard(this.formGroup.value)
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(
|
||||
// complete => this.onCallbackSuccess()
|
||||
// )
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
onSubmitSaveAndFinalize() {
|
||||
const dmpId = this.formGroup.get('dmpMeta').get('dmp').value.id;
|
||||
this.quickWizardService.createQuickDatasetWizard(this.formGroup.value)
|
||||
.pipe(takeUntil(this._destroyed))
|
||||
.subscribe(
|
||||
complete => this.onCallbackSuccess(dmpId)
|
||||
);
|
||||
}
|
||||
|
||||
hasDatasets() {
|
||||
if ((this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).length > 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public isFormValid() {
|
||||
return this.formGroup.valid;
|
||||
}
|
||||
|
||||
onCallbackSuccess(dmpId: string): void {
|
||||
this.isSubmitted = true;
|
||||
this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
|
||||
this.router.navigate(['/plans/overview/' + dmpId]);
|
||||
}
|
||||
|
||||
isActive(step: string): boolean {
|
||||
switch (step) {
|
||||
case 'step1':
|
||||
return this.stepper.selectedIndex == 0;
|
||||
case 'step2':
|
||||
return this.stepper.selectedIndex == 1;
|
||||
}
|
||||
}
|
||||
|
||||
canDeactivate(): boolean {
|
||||
return this.isSubmitted || !this.formGroup.dirty;
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
|
||||
import { DmpCreateWizardFormModel } from '@app/core/model/dmp/dmp-create-wizard/dmp-create-wizard-form.model';
|
||||
import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model';
|
||||
import { DatasetEditorWizardModel } from '@app/ui/quick-wizard/dataset-editor/dataset-editor-wizard-model';
|
||||
import { BackendErrorValidator } from '@common/forms/validation/custom-validator';
|
||||
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
|
||||
import { ValidationContext } from '@common/forms/validation/validation-context';
|
||||
|
||||
|
||||
export class DatasetCreateWizardModel {
|
||||
public dmpMeta: DmpCreateWizardFormModel;
|
||||
public datasets: DatasetEditorWizardModel;
|
||||
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
|
||||
|
||||
fromModelDmp(item: DmpCreateWizardFormModel): DatasetCreateWizardModel {
|
||||
this.dmpMeta.fromModel(item);
|
||||
return this;
|
||||
}
|
||||
|
||||
fromModelDataset(item: DatasetWizardEditorModel[]): DatasetCreateWizardModel {
|
||||
this.datasets.fromModel(item);
|
||||
return this;
|
||||
}
|
||||
|
||||
buildForm(context: ValidationContext = null): UntypedFormGroup {
|
||||
if (context == null) { context = this.createValidationContext(); }
|
||||
const formBuilder = new UntypedFormBuilder();
|
||||
const formGroup = formBuilder.group({
|
||||
dmpMeta: new DmpCreateWizardFormModel().buildForm(),
|
||||
datasets: new DatasetEditorWizardModel().buildForm()
|
||||
});
|
||||
|
||||
return formGroup;
|
||||
}
|
||||
|
||||
createValidationContext(): ValidationContext {
|
||||
const baseContext: ValidationContext = new ValidationContext();
|
||||
baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'label')] });
|
||||
baseContext.validation.push({ key: 'status', validators: [BackendErrorValidator(this.validationErrorModel, 'status')] });
|
||||
|
||||
return baseContext;
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { FormattingModule } from '@app/core/formatting.module';
|
||||
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module';
|
||||
import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module';
|
||||
import { CanDeactivateGuard } from '@app/library/deactivate/can-deactivate.guard';
|
||||
import { UrlListingModule } from '@app/library/url-listing/url-listing.module';
|
||||
import { DatasetCreateWizard } from '@app/ui/dataset-create-wizard/dataset-create-wizard.component';
|
||||
import { DatasetCreateWizardRoutingModule } from '@app/ui/dataset-create-wizard/dataset-create-wizard.routing';
|
||||
import { DatasetDmpSelector } from '@app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component';
|
||||
import { DatasetDescriptionFormModule } from '@app/ui/misc/dataset-description-form/dataset-description-form.module';
|
||||
import { OuickWizardModule } from '@app/ui/quick-wizard/quick-wizard.module';
|
||||
import { QuickWizardRoutingModule } from '@app/ui/quick-wizard/quick-wizard.routing';
|
||||
import { CommonFormsModule } from '@common/forms/common-forms.module';
|
||||
import { CommonUiModule } from '@common/ui/common-ui.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
DatasetCreateWizardRoutingModule,
|
||||
CommonUiModule,
|
||||
CommonFormsModule,
|
||||
AutoCompleteModule,
|
||||
FormattingModule,
|
||||
UrlListingModule,
|
||||
ConfirmationDialogModule,
|
||||
QuickWizardRoutingModule,
|
||||
DatasetDescriptionFormModule,
|
||||
OuickWizardModule,
|
||||
],
|
||||
declarations: [
|
||||
DatasetCreateWizard,
|
||||
DatasetDmpSelector,
|
||||
],
|
||||
providers: [
|
||||
CanDeactivateGuard
|
||||
]
|
||||
})
|
||||
export class DatasetCreateWizardModule { }
|
|
@ -1,32 +0,0 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { DatasetCreateWizard } from './dataset-create-wizard.component';
|
||||
import { DatasetDmpSelector } from './dmp-selector/dataset-dmp-selector.component';
|
||||
import { CanDeactivateGuard } from '../../library/deactivate/can-deactivate.guard';
|
||||
import { AuthGuard } from '@app/core/auth-guard.service';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: DatasetCreateWizard,
|
||||
canActivate: [AuthGuard],
|
||||
data: {
|
||||
breadcrumb: true
|
||||
},
|
||||
canDeactivate: [CanDeactivateGuard]
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: DatasetDmpSelector,
|
||||
canActivate: [AuthGuard],
|
||||
data: {
|
||||
breadcrumb: true
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class DatasetCreateWizardRoutingModule { }
|
|
@ -1,20 +0,0 @@
|
|||
<div class="dataset-dmp-selector" [formGroup]="formGroup" *ngIf="formGroup">
|
||||
<mat-card>
|
||||
<div>
|
||||
<mat-form-field class="col-md-12">
|
||||
<app-single-auto-complete [required]="true" [formControl]="formGroup.get('dmp')" placeholder="{{'DATASET-CREATE-WIZARD.FIRST-STEP.PLACEHOLDER' | translate}}"
|
||||
[configuration]="dmpAutoCompleteConfiguration">
|
||||
</app-single-auto-complete>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div>
|
||||
<mat-form-field class="col-md-12" *ngIf="availableProfiles.length > 1">
|
||||
<mat-select (selectionChange)="datasetChanged($event)" placeholder=" {{'DATASET-WIZARD.FIRST-STEP.PROFILE'| translate}}" [required]="true" formControlName="datasetProfile">
|
||||
<mat-option *ngFor="let datasetProfile of availableProfiles" [value]="datasetProfile">
|
||||
{{datasetProfile.label}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</mat-card>
|
||||
</div>
|
|
@ -1,104 +0,0 @@
|
|||
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { UntypedFormArray, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { MatStepper } from '@angular/material/stepper';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { DmpStatus } from '@app/core/common/enum/dmp-status';
|
||||
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
|
||||
import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile';
|
||||
import { DmpListingModel } from '@app/core/model/dmp/dmp-listing';
|
||||
import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria';
|
||||
import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria';
|
||||
import { RequestItem } from '@app/core/query/request-item';
|
||||
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
|
||||
import { DmpService } from '@app/core/services/dmp/dmp.service';
|
||||
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
|
||||
import { BaseComponent } from '@common/base/base.component';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, takeUntil } from 'rxjs/operators';
|
||||
import { DatePipe } from "@angular/common";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
|
||||
@Component({
|
||||
selector: 'dataset-dmp-selector-component',
|
||||
templateUrl: 'dataset-dmp-selector.component.html',
|
||||
styleUrls: ['./dataset-dmp-selector.component.scss'],
|
||||
})
|
||||
|
||||
export class DatasetDmpSelector extends BaseComponent implements OnInit {
|
||||
|
||||
dmpAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
||||
@Input() formGroup: UntypedFormGroup;
|
||||
@Input() datasetFormGroup: UntypedFormGroup;
|
||||
@Input() stepper: MatStepper;
|
||||
formControl: UntypedFormControl;
|
||||
availableProfiles: DatasetProfileModel[] = [];
|
||||
|
||||
constructor(
|
||||
public dmpService: DmpService,
|
||||
private datasetWizardService: DatasetWizardService,
|
||||
private language: TranslateService,
|
||||
private datepipe: DatePipe
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.dmpAutoCompleteConfiguration = {
|
||||
filterFn: this.searchDmp.bind(this),
|
||||
initialItems: (extraData) => this.searchDmp(''),
|
||||
displayFn: (item) => item['label'],
|
||||
titleFn: (item) => item['label'],
|
||||
subtitleFn: (item) => this.language.instant('QUICKWIZARD.CREATE-ADD.ADD.CREATED') + " " + this.datepipe.transform(item['creationTime'], 'yyyy-MM-dd')
|
||||
};
|
||||
|
||||
this.formGroup.get('dmp').valueChanges
|
||||
.pipe(takeUntil(this._destroyed))
|
||||
.subscribe(x => {
|
||||
if (x) { this.loadDatasetProfiles(); }
|
||||
else {
|
||||
this.availableProfiles = [];
|
||||
this.formGroup.get('datasetProfile').reset();
|
||||
}
|
||||
});
|
||||
|
||||
this.formGroup.get('datasetProfile').valueChanges
|
||||
.pipe(takeUntil(this._destroyed))
|
||||
.subscribe(x => {
|
||||
(this.datasetFormGroup.get('datasetsList') as UntypedFormArray).controls.length = 0;
|
||||
});
|
||||
}
|
||||
|
||||
searchDmp(query: string): Observable<DmpListingModel[]> {
|
||||
const fields: Array<string> = new Array<string>();
|
||||
fields.push('-created');
|
||||
const dmpDataTableRequest: DataTableRequest<DmpCriteria> = new DataTableRequest(0, null, { fields: fields });
|
||||
dmpDataTableRequest.criteria = new DmpCriteria();
|
||||
dmpDataTableRequest.criteria.status = DmpStatus.Draft;
|
||||
dmpDataTableRequest.criteria.like = query;
|
||||
|
||||
return this.dmpService.getPaged(dmpDataTableRequest, "autocomplete").pipe(
|
||||
map(y => y.data));
|
||||
}
|
||||
|
||||
loadDatasetProfiles() {
|
||||
const datasetProfileRequestItem: RequestItem<DatasetProfileCriteria> = new RequestItem();
|
||||
datasetProfileRequestItem.criteria = new DatasetProfileCriteria();
|
||||
datasetProfileRequestItem.criteria.id = this.formGroup.get('dmp').value.id;
|
||||
if (datasetProfileRequestItem.criteria.id) {
|
||||
this.datasetWizardService.getAvailableProfiles(datasetProfileRequestItem)
|
||||
.pipe(takeUntil(this._destroyed))
|
||||
.subscribe(items => {
|
||||
this.availableProfiles = items;
|
||||
if (this.availableProfiles.length === 1) {
|
||||
this.formGroup.get('datasetProfile').patchValue(this.availableProfiles[0]);
|
||||
this.stepper.next();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
datasetChanged($event) {
|
||||
this.stepper.next();
|
||||
}
|
||||
}
|
|
@ -50,7 +50,7 @@ import {
|
|||
LinkToScroll,
|
||||
TableOfContents
|
||||
} from '@app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents';
|
||||
import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service';
|
||||
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
||||
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
|
||||
import { FormService } from '@common/forms/form-service';
|
||||
import {
|
||||
|
|
|
@ -85,11 +85,11 @@ export class DatasetListingItemComponent extends BaseComponent implements OnInit
|
|||
|
||||
getItemLink(): string[] {
|
||||
// return this.isPublic ? [`/datasets/publicEdit/${this.dataset.id}`] : [`/datasets/edit/${this.dataset.id}`];
|
||||
return this.isPublic ? ['/datasets/publicOverview/' + this.dataset.id] : ['/datasets/overview/' + this.dataset.id];
|
||||
return this.isPublic ? ['/datasets/overview/public/' + this.dataset.id] : ['/datasets/overview/' + this.dataset.id];
|
||||
}
|
||||
|
||||
getDmpLink(): string[] {
|
||||
return this.isPublic ? [`/explore-plans/publicOverview/${this.dataset.dmpId}`] : [`/plans/edit/${this.dataset.dmpId}`];
|
||||
return this.isPublic ? [`/explore-plans/overview/public/${this.dataset.dmpId}`] : [`/plans/edit/${this.dataset.dmpId}`];
|
||||
}
|
||||
|
||||
downloadPDF(dataset: DatasetListingModel): void {
|
||||
|
|
|
@ -123,7 +123,7 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
|
|||
this.users = this.dataset.dmp.users;
|
||||
// const breadCrumbs = [];
|
||||
// breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC DATASETS'), url: "/explore" });
|
||||
// breadCrumbs.push({ parentComponentName: 'DatasetListingComponent', label: this.dataset.label, url: '/datasets/publicOverview/' + this.dataset.id });
|
||||
// breadCrumbs.push({ parentComponentName: 'DatasetListingComponent', label: this.dataset.label, url: '/datasets/overview/public/' + this.dataset.id });
|
||||
// this.breadCrumbs = observableOf(breadCrumbs);
|
||||
}, (error: any) => {
|
||||
if (error.status === 404) {
|
||||
|
@ -290,7 +290,7 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit {
|
|||
|
||||
dmpClicked(dmp: DmpOverviewModel) {
|
||||
if (this.isPublicView) {
|
||||
this.router.navigate(['/explore-plans/publicOverview/' + dmp.id]);
|
||||
this.router.navigate(['/explore-plans/overview/public/' + dmp.id]);
|
||||
} else {
|
||||
this.router.navigate(['/plans/overview/' + dmp.id]);
|
||||
}
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
<form class="dataset-editor" *ngIf="formGroup" [formGroup]="formGroup">
|
||||
<div class="col-12 intro">
|
||||
<p>{{'DATASET-EDITOR.TITLE.INTRO' | translate}}</p>
|
||||
<span>{{'DATASET-EDITOR.TITLE.INTRO-TIP' | translate}}</span>
|
||||
</div>
|
||||
<div class="col-12 card">
|
||||
<!-- Title Field -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="heading">1.1 {{'DATASET-EDITOR.FIELDS.TITLE' | translate}}*</div>
|
||||
<!-- <span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span> -->
|
||||
<!-- <a class="dmp-link dmp-tour-{{ formGroup.get('id').value + 1 }}" (click)="restartTour(formGroup.get('id').value + 1)">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a>
|
||||
<span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span> -->
|
||||
<div class="title-form">
|
||||
<mat-form-field>
|
||||
<input matInput placeholder="{{'DATASET-EDITOR.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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Description field -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="heading">1.2 {{'DATASET-EDITOR.FIELDS.DESCRIPTION' | translate}}</div>
|
||||
<span class="hint">{{'DATASET-EDITOR.HINT.DESCRIPTION' | translate}}</span>
|
||||
<!-- <span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span>
|
||||
<a class="dmp-link dmp-tour-{{ formGroup.get('id').value + 2 }}" (click)="restartTour(formGroup.get('id').value + 2)">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a>
|
||||
<span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span> -->
|
||||
<div class="description-form">
|
||||
<rich-text-editor-component [parentFormGroup]="formGroup" [controlName]="'description'"
|
||||
[placeholder]="'DMP-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>
|
||||
<mat-error *ngIf="formGroup.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Uri field -->
|
||||
<!-- <div class="row">
|
||||
<div class="col-12">
|
||||
<div class="heading">1.3 {{'DATASET-EDITOR.FIELDS.EXTERNAL-LINK' | translate}}</div>
|
||||
<span class="hint"></span>
|
||||
<div class="uri-form">
|
||||
<mat-form-field>
|
||||
<input matInput placeholder="{{'DATASET-EDITOR.PLACEHOLDER.EXTERNAL-LINK' | translate}}" type="text" name="uri" formControlName="uri">
|
||||
<mat-error *ngIf="formGroup.get('uri').hasError('backendError')">{{formGroup.get('uri').getError('backendError').message}}</mat-error>
|
||||
<mat-error *ngIf="formGroup.get('uri').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- External Fields -->
|
||||
<app-dataset-external-references-editor-component [formGroup]="formGroup" [viewOnly]="viewOnly"></app-dataset-external-references-editor-component>
|
||||
<!-- Template Field -->
|
||||
<div class="heading">1.4 {{'DATASET-EDITOR.FIELDS.PROFILE' | translate}}*</div>
|
||||
<div class="profile-form">
|
||||
<mat-form-field>
|
||||
<mat-select placeholder="{{'DATASET-WIZARD.FIRST-STEP.PROFILE'| translate}}" [required]="true" [compareWith]="compareWith" formControlName="profile">
|
||||
<mat-option *ngFor="let profile of availableProfiles" [value]="profile">
|
||||
<div (click)="checkMinMax($event, profile)">
|
||||
{{profile.label}}
|
||||
</div>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="formGroup.get('profile').hasError('backendError')">{{formGroup.get('profile').getError('backendError').message}}</mat-error>
|
||||
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
|
||||
<!-- <div class="container-fluid">
|
||||
<div class="row dataset-editor" [formGroup]="formGroup">
|
||||
<div class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-sm-12 col-md-6">
|
||||
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.NAME' | 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>
|
||||
</div>
|
||||
<div class="row" *ngIf="showUri">
|
||||
<mat-form-field class="col-sm-12 col-md-6">
|
||||
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.URI' | translate}}" type="text" name="uri" formControlName="uri">
|
||||
<mat-error *ngIf="formGroup.get('uri').hasError('backendError')">{{formGroup.get('uri').getError('backendError').message}}</mat-error>
|
||||
<mat-error *ngIf="formGroup.get('uri').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row">
|
||||
<mat-form-field class="col-sm-12 col-md-6">
|
||||
<textarea matInput class="description-area" placeholder="{{'DATASET-EDITOR.FIELDS.DESCRIPTION' | translate}}" formControlName="description"></textarea>
|
||||
<mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{formGroup.get('description').getError('backendError').message}}</mat-error>
|
||||
<mat-error *ngIf="formGroup.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
|
@ -1,145 +0,0 @@
|
|||
import { Component, Input } from '@angular/core';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { BaseComponent } from '@common/base/base.component';
|
||||
import { GuidedTourService } from '@app/library/guided-tour/guided-tour.service';
|
||||
import { GuidedTour, Orientation } from '@app/library/guided-tour/guided-tour.constants';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component';
|
||||
import { Guid } from '@common/types/guid';
|
||||
import { nameof } from 'ts-simple-nameof';
|
||||
import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dataset-editor-component',
|
||||
templateUrl: 'dataset-editor.component.html',
|
||||
styleUrls: ['./dataset-editor.component.scss']
|
||||
})
|
||||
export class DatasetEditorComponent extends BaseComponent {
|
||||
|
||||
@Input() formGroup: UntypedFormGroup;
|
||||
// @Input() formGroup: FormGroup = null;
|
||||
@Input() availableProfiles: DatasetProfileModel[];
|
||||
@Input() dmpId: string;
|
||||
showUri: boolean = false;
|
||||
dmpText: string = null;
|
||||
viewOnly = false;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private dmpBlueprintService: DmpBlueprintService,
|
||||
private dialog: MatDialog,
|
||||
private guidedTourService: GuidedTourService,
|
||||
private language: TranslateService
|
||||
) { super(); }
|
||||
|
||||
public dashboardTourDmp: GuidedTour = {
|
||||
tourId: 'only-dmp-tour',
|
||||
useOrb: true,
|
||||
steps: [
|
||||
{
|
||||
title: this.dmpText,
|
||||
content: 'Step 1',
|
||||
orientation: Orientation.Bottom,
|
||||
highlightPadding: 3,
|
||||
isStepUnique: true,
|
||||
customTopOffset: 8
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
checkMinMax(event, profile: DatasetProfileModel) {
|
||||
event.stopPropagation();
|
||||
const dmpSectionIndex = this.formGroup.get('dmpSectionIndex').value;
|
||||
const blueprintId = this.formGroup.get('dmp').value.profile.id;
|
||||
this.dmpBlueprintService.getSingle(blueprintId,
|
||||
[
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.id)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.label)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.description)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.ordinal)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.hasTemplates)].join('.'),
|
||||
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.id)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.category)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.dataType)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.systemFieldType)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.label)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.placeholder)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.description)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.required)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.ordinal)].join('.'),
|
||||
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.id)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.descriptionTemplateId)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.label)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.minMultiplicity)].join('.'),
|
||||
[nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.maxMultiplicity)].join('.'),
|
||||
]
|
||||
)
|
||||
.pipe(takeUntil(this._destroyed))
|
||||
.subscribe(result => {
|
||||
const section = result.definition.sections[dmpSectionIndex];
|
||||
if(section.hasTemplates){
|
||||
const foundTemplate = section.descriptionTemplates.find(template => template.descriptionTemplateId === Guid.parse(profile.id));
|
||||
if (foundTemplate !== undefined) {
|
||||
let count = 0;
|
||||
if(this.formGroup.get('dmp').value.datasets != null){
|
||||
for(let dataset of this.formGroup.get('dmp').value.datasets){
|
||||
if(dataset.dmpSectionIndex === dmpSectionIndex && dataset.profile.id === foundTemplate.descriptionTemplateId){
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if(count === foundTemplate.maxMultiplicity){
|
||||
this.dialog.open(PopupNotificationDialogComponent, {
|
||||
data: {
|
||||
title: this.language.instant('DATASET-EDITOR.MAX-DESCRIPTION-DIALOG.TITLE'),
|
||||
message: this.language.instant('DATASET-EDITOR.MAX-DESCRIPTION-DIALOG.MESSAGE')
|
||||
}, maxWidth: '30em'
|
||||
});
|
||||
}
|
||||
else{
|
||||
this.formGroup.get('profile').setValue(profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.formGroup.get('profile').setValue(profile);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.formGroup.get('profile').setValue(profile);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getDmpText(): string {
|
||||
return this.language.instant('DMP-LISTING.TEXT-INFO') + '\n\n' +
|
||||
this.language.instant('DMP-LISTING.TEXT-INFO-QUESTION') + ' ' +
|
||||
this.language.instant('DMP-LISTING.LINK-ZENODO') + ' ' +
|
||||
this.language.instant('DMP-LISTING.GET-IDEA');
|
||||
}
|
||||
|
||||
setDashboardTourDmp(label: string): void {
|
||||
this.dashboardTourDmp.steps[0].title = this.getDmpText();
|
||||
this.dashboardTourDmp.steps[0].selector = '.dmp-tour-' + label;
|
||||
}
|
||||
|
||||
public restartTour(label: string): void {
|
||||
this.setDashboardTourDmp(label);
|
||||
this.guidedTourService.startTour(this.dashboardTourDmp);
|
||||
|
||||
}
|
||||
|
||||
public cancel(): void {
|
||||
this.router.navigate(['/datasets']);
|
||||
}
|
||||
|
||||
public compareWith(object1: any, object2: any) {
|
||||
return object1 && object2 && object1.id === object2.id;
|
||||
}
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
<div class="main-content">
|
||||
<div class="container-fluid description-editor">
|
||||
<form *ngIf="formGroup" [formGroup]="formGroup">
|
||||
<!-- <form *ngIf="formGroup" [formGroup]="formGroup" (ngSubmit)="formSubmit()"> -->
|
||||
<!-- Description Header -->
|
||||
<div class="fixed-editor-header">
|
||||
<div class="card description-editor-header">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col info">
|
||||
<ng-container *ngIf="!viewOnly else viewOnlyTemplate">
|
||||
<div *ngIf="isNew" class="description-title">{{'DMP-EDITOR.TITLE.ADD-DATASET' | translate}}</div>
|
||||
<div *ngIf="!isNew" class="description-title">{{'DMP-EDITOR.TITLE.EDIT-DESCRIPTION' | translate}}</div>
|
||||
<div class="description-subtitle">{{ formGroup.get('label').value }} <span *ngIf="isDirty()" class="description-changes">({{'DMP-EDITOR.CHANGES' | translate}})</span></div>
|
||||
</ng-container>
|
||||
<ng-template #viewOnlyTemplate>
|
||||
<div class="description-title">{{'DMP-EDITOR.TITLE.PREVIEW-DATASET' | translate}}</div>
|
||||
</ng-template>
|
||||
<div class="d-flex flex-direction-row dmp-info">
|
||||
<div class="col-auto description-to-dmp">{{'DATASET-LISTING.TOOLTIP.TO-DMP' | translate}}</div>
|
||||
<div class="dmp-title p-0">: {{ formGroup.get('dmp').value.label }}</div>
|
||||
<div class="col-auto d-flex align-items-center">
|
||||
<a [routerLink]="['/overview/' + formGroup.get('dmp').value.id]" target="_blank" class="pointer open-in-new-icon">
|
||||
<mat-icon class="size-18">open_in_new</mat-icon>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-auto d-flex align-items-center">
|
||||
<button *ngIf="formGroup.get('id').value" [disabled]="isDirty()" [matTooltipDisabled]="!isDirty()"
|
||||
mat-raised-button class="description-export-btn" type="button"
|
||||
[matMenuTriggerFor]="exportMenu" (click)="$event.stopPropagation();"
|
||||
[matTooltip]="'DATASET-EDITOR.ACTIONS.DISABLED-EXPORT' | translate">
|
||||
{{ 'DMP-LISTING.ACTIONS.EXPORT' | translate }}
|
||||
<mat-icon [disabled]="isDirty()" style="width: 14px;">expand_more</mat-icon>
|
||||
</button>
|
||||
<mat-menu #exportMenu="matMenu" xPosition="before">
|
||||
<button mat-menu-item (click)="downloadPDF(formGroup.get('id').value)">
|
||||
<i class="fa fa-file-pdf-o pr-2"></i>
|
||||
<span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="downloadDOCX(formGroup.get('id').value)">
|
||||
<i class="fa fa-file-word-o pr-2"></i>
|
||||
<span>{{'GENERAL.FILE-TYPES.DOC' | translate}}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="downloadXML(formGroup.get('id').value)">
|
||||
<i class="fa fa-file-code-o pr-2"></i>
|
||||
<span>{{'GENERAL.FILE-TYPES.XML' | translate}}</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
|
||||
<mat-divider *ngIf="formGroup.get('id').value && (!viewOnly || (!lockStatus && !viewOnly) || lockStatus || (hasReversableStatus() && !lockStatus))"
|
||||
[vertical]="true" class="ml-2 mr-2"></mat-divider>
|
||||
|
||||
<div *ngIf="isDirty() && !viewOnly" class="col-auto d-flex align-items-center pr-0">
|
||||
<button [disabled]="saving" type="button" mat-raised-button class="description-discard-btn" (click)="discardChanges()">
|
||||
{{'DMP-EDITOR.ACTIONS.DISCARD' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-auto d-flex align-items-center">
|
||||
<button [disabled]="saving" *ngIf="!lockStatus && !viewOnly" mat-raised-button
|
||||
class="description-save-btn mr-2" type="button">
|
||||
<span class="d-flex flex-row row">
|
||||
<span (click)="!saving?save():null" class="col">{{ 'DATASET-WIZARD.ACTIONS.SAVE' | translate }}</span>
|
||||
<mat-divider [vertical]="true"></mat-divider>
|
||||
<span *ngIf="!saving" class="align-items-center justify-content-center col-4 d-flex"
|
||||
(click)="$event.stopPropagation();" [matMenuTriggerFor]="menu">
|
||||
<mat-icon >expand_more</mat-icon>
|
||||
</span>
|
||||
<span *ngIf="saving" class="align-items-center justify-content-center col-4 d-flex">
|
||||
<mat-icon >expand_more</mat-icon>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
<button [disabled]="saving" mat-menu-item (click)="save(saveAnd.close)" type="button">{{ 'DATASET-WIZARD.ACTIONS.SAVE-AND-CLOSE' | translate }}</button>
|
||||
<button [disabled]="saving" mat-menu-item (click)="save(saveAnd.addNew)" type="button">{{ 'DATASET-WIZARD.ACTIONS.SAVE-AND-ADD' | translate }}</button>
|
||||
<button [disabled]="saving" mat-menu-item (click)="save()" type="button">{{ 'DATASET-WIZARD.ACTIONS.SAVE-AND-CONTINUE' | translate }}</button>
|
||||
</mat-menu>
|
||||
|
||||
<button [disabled]="saving" *ngIf="!lockStatus && !viewOnly" mat-raised-button class="description-save-btn mr-2" type="button" (click)="saveFinalize()">{{ 'DATASET-WIZARD.ACTIONS.FINALIZE' | translate }}</button>
|
||||
<!-- <button *ngIf="!lockStatus && !viewOnly" mat-raised-button class="description-save-btn mr-2" (click)="save()" type="button">{{ 'DATASET-WIZARD.ACTIONS.SAVE' | translate }}</button>
|
||||
<button *ngIf="!lockStatus && !viewOnly" mat-raised-button class="description-save-btn mr-2" (click)="save(saveAnd.close)" type="button">{{ 'DATASET-WIZARD.ACTIONS.SAVE-AND-CLOSE' | translate }}</button>
|
||||
<button *ngIf="!lockStatus && !viewOnly" mat-raised-button class="description-save-btn mr-2" (click)="save(saveAnd.addNew)">{{ 'DATASET-WIZARD.ACTIONS.SAVE-AND-ADD' | translate }}</button> -->
|
||||
<button [disabled]="saving" *ngIf="lockStatus" mat-raised-button disabled class="description-save-btn cursor-default" type="button">{{ 'DMP-OVERVIEW.LOCKED' | translate}}</button>
|
||||
<button [disabled]="saving" *ngIf="hasReversableStatus() && !lockStatus" mat-raised-button class="description-save-btn mr-2" (click)="reverse()" type="button">{{ 'DATASET-WIZARD.ACTIONS.REVERSE' | translate }}</button>
|
||||
<!-- <button *ngIf="!lockStatus" mat-raised-button class="description-save-btn mr-2" (click)="touchForm()" type="button">{{ 'DATASET-WIZARD.ACTIONS.VALIDATE' | translate }}</button> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row editor-content">
|
||||
<div class="col-auto description-stepper">
|
||||
<div class="stepper-back d-flex flex-direction-row">
|
||||
<div class="d-flex align-items-center pr-2 back-to-dmp" (click)="backToDmp(formGroup.get('dmp').value.id)">
|
||||
<mat-icon class="back-icon pointer">chevron_left</mat-icon>
|
||||
<span class="pointer">{{'DATASET-WIZARD.ACTIONS.BACK-TO' | translate}}</span>
|
||||
</div>
|
||||
<div class="col-auto dmp-label ml-3">{{'DATASET-LISTING.TOOLTIP.DMP' | translate}}</div>
|
||||
</div>
|
||||
<div class="stepper-title">{{'DMP-EDITOR.STEPPER.USER-GUIDE' | translate}}</div>
|
||||
<div class="stepper-options" id="stepper-options">
|
||||
<div class="col stepper-list">
|
||||
<div (click)="table0fContents.onToCentrySelected()" *ngIf="!descriptionInfoValid()" class="main-info" [ngClass]="{'active': this.step === 0, 'text-danger':hintErrors}">0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (2)</div>
|
||||
<div (click)="table0fContents.onToCentrySelected()" *ngIf="descriptionInfoValid()" class="main-info" [ngClass]="{'active': this.step === 0}">0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (<mat-icon class="done-icon">done</mat-icon>)</div>
|
||||
<div class="row toc-pane-container" #boundary>
|
||||
<div #spacer></div>
|
||||
<table-of-contents [visibilityRulesService]="visRulesService" [selectedFieldsetId]="fieldsetIdWithFocus" #table0fContents
|
||||
[showErrors]="showtocentriesErrors" [TOCENTRY_ID_PREFIX]="TOCENTRY_ID_PREFIX" [hasFocus]="step > 0"
|
||||
[formGroup]="formGroup" *ngIf="formGroup && formGroup.get('descriptionProfileDefinition')" [links]="links"
|
||||
[boundary]="boundary" [spacer]="spacer" [isActive]="step !== 0" stickyThing (stepFound)="onStepFound($event)"
|
||||
(currentLinks)="getLinks($event)" (entrySelected)="changeStep($event.entry, $event.execute)"
|
||||
[visibilityRules]="formGroup.get('descriptionProfileDefinition').get('rules').value"></table-of-contents>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stepper-actions">
|
||||
<div mat-raised-button type="button" class="col-auto previous stepper-btn mr-2" [ngClass]="{'previous-disabled': this.step === 0}" (click)="previousStep()">
|
||||
<span class="material-icons">chevron_left</span>
|
||||
<div>{{'DMP-EDITOR.STEPPER.PREVIOUS' | translate}}</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="this.step < this.maxStep" mat-raised-button type="button" class="col-auto stepper-btn description-next ml-auto" (click)="nextStep()">
|
||||
<div>{{'DMP-EDITOR.STEPPER.NEXT' | translate}}</div>
|
||||
<span class="material-icons">chevron_right</span>
|
||||
</div>
|
||||
<div *ngIf="!formGroup.get('profile').value" mat-raised-button type="button" class="col-auto stepper-btn description-next next-disabled ml-auto">
|
||||
<div>{{'DMP-EDITOR.STEPPER.NEXT' | translate}}</div>
|
||||
<span class="material-icons">chevron_right</span>
|
||||
</div>
|
||||
<button [disabled]="saving" (click)="save(saveAnd.addNew)" *ngIf="(step === maxStep) && !lockStatus && formGroup.get('profile').value && !viewOnly" mat-raised-button type="button" class="col-auto stepper-btn add-description-btn ml-auto">
|
||||
{{ 'DATASET-WIZARD.ACTIONS.SAVE-AND-ADD' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-auto pr-0">
|
||||
<app-form-progress-indication class="col-12" *ngIf="formGroup && !viewOnly" [formGroup]="formGroup" [isDescriptionEditor]="true"></app-form-progress-indication>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto form" id="description-editor-form">
|
||||
<app-description-editor-component [hidden]="this.step !== 0" [formGroup]="formGroup" [dmpId]="formGroup.get('dmp').value.id" [availableProfiles]="availableDescriptionTemplates" (formChanged)="formChanged()"></app-description-editor-component>
|
||||
<app-description-description (visibilityRulesInstance)="visRulesService = $event" [TOCENTRY_ID_PREFIX]="TOCENTRY_ID_PREFIX" [hidden]="this.step === 0" *ngIf="formGroup && formGroup.get('descriptionProfileDefinition')" [form]="this.formGroup.get('descriptionProfileDefinition')" [visibilityRules]="formGroup.get('descriptionProfileDefinition').get('rules').value" [descriptionProfileId]="formGroup.get('profile').value" [linkToScroll]="linkToScroll" (fieldsetFocusChange)="fieldsetIdWithFocus = $event"></app-description-description>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
|
@ -1,67 +0,0 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||
import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
|
||||
import { Description, DescriptionField, DescriptionReference, DescriptionTag, PropertyDefinition } from '@app/core/model/description/description';
|
||||
import { Dmp, DmpDescriptionTemplate } from '@app/core/model/dmp/dmp';
|
||||
import { Reference } from '@app/core/model/reference/reference';
|
||||
import { Tag } from '@app/core/model/tag/tag';
|
||||
import { DescriptionService } from '@app/core/services/description/description.service';
|
||||
import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service';
|
||||
import { BaseEditorResolver } from '@common/base/base-editor.resolver';
|
||||
import { Guid } from '@common/types/guid';
|
||||
import { takeUntil, tap } from 'rxjs/operators';
|
||||
import { nameof } from 'ts-simple-nameof';
|
||||
|
||||
@Injectable()
|
||||
export class DescriptionEditorResolver extends BaseEditorResolver {
|
||||
|
||||
constructor(private descriptionService: DescriptionService, private breadcrumbService: BreadcrumbService) {
|
||||
super();
|
||||
}
|
||||
|
||||
public static lookupFields(): string[] {
|
||||
return [
|
||||
...BaseEditorResolver.lookupFields(),
|
||||
nameof<Description>(x => x.id),
|
||||
nameof<Description>(x => x.label),
|
||||
nameof<Description>(x => x.status),
|
||||
nameof<Description>(x => x.description),
|
||||
nameof<Description>(x => x.status),
|
||||
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.id)].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.dmpDescriptionTemplate), nameof<DmpDescriptionTemplate>(x => x.id)].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.properties), nameof<PropertyDefinition>(x => x.fields), nameof<DescriptionField>(x => x.key)].join('.'),
|
||||
[nameof<Description>(x => x.properties), nameof<PropertyDefinition>(x => x.fields), nameof<DescriptionField>(x => x.value)].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.descriptionTags), nameof<DescriptionTag>(x => x.id),].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTags), nameof<DescriptionTag>(x => x.tag), nameof<Tag>(x => x.label)].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.descriptionReferences), nameof<DescriptionReference>(x => x.reference), nameof<Reference>(x => x.id)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionReferences), nameof<DescriptionReference>(x => x.reference), nameof<Reference>(x => x.label)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionReferences), nameof<DescriptionReference>(x => x.reference), nameof<Reference>(x => x.type)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionReferences), nameof<DescriptionReference>(x => x.reference), nameof<Reference>(x => x.reference)].join('.'),
|
||||
nameof<Description>(x => x.createdAt),
|
||||
nameof<Description>(x => x.hash),
|
||||
nameof<Description>(x => x.isActive)
|
||||
]
|
||||
}
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
|
||||
const fields = [
|
||||
...DescriptionEditorResolver.lookupFields()
|
||||
];
|
||||
const id = route.paramMap.get('id');
|
||||
// const cloneid = route.paramMap.get('cloneid');
|
||||
if (id != null) {
|
||||
return this.descriptionService.getSingle(Guid.parse(id), fields).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed));
|
||||
}
|
||||
//TODO: check this
|
||||
// else if (cloneid != null) {
|
||||
// return this.descriptionService.clone(Guid.parse(cloneid), fields).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed));
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -1,84 +1,19 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { FormattingModule } from '@app/core/formatting.module';
|
||||
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module';
|
||||
import { ExportMethodDialogModule } from '@app/library/export-method-dialog/export-method-dialog.module';
|
||||
import { RichTextEditorModule } from "@app/library/rich-text-editor/rich-text-editor.module";
|
||||
import { UrlListingModule } from '@app/library/url-listing/url-listing.module';
|
||||
// import { DescriptionEditorComponent } from '@app/ui/description/description-wizard/description-editor/description-editor.component';
|
||||
// import { DescriptionWizardComponent } from '@app/ui/description/description-wizard/description-wizard.component';
|
||||
// import { DescriptionExternalReferencesEditorComponent } from '@app/ui/description/description-wizard/external-references/description-external-references-editor.component';
|
||||
// import { DescriptionExternalDataRepositoryDialogEditorComponent } from '@app/ui/description/description-wizard/external-references/editors/data-repository/description-external-data-repository-dialog-editor.component';
|
||||
// import { DescriptionExternalDescriptionDialogEditorComponent } from '@app/ui/description/description-wizard/external-references/editors/external-description/description-external-description-dialog-editor.component';
|
||||
// import { DescriptionExternalRegistryDialogEditorComponent } from '@app/ui/description/description-wizard/external-references/editors/registry/description-external-registry-dialog-editor.component';
|
||||
// import { DescriptionExternalServiceDialogEditorComponent } from '@app/ui/description/description-wizard/external-references/editors/service/description-external-service-dialog-editor.component';
|
||||
// import { PrefillDescriptionComponent } from "@app/ui/description/description-wizard/prefill-description/prefill-description.component";
|
||||
import { DescriptionRoutingModule } from '@app/ui/description/description.routing';
|
||||
// import { DescriptionCriteriaComponent } from '@app/ui/description/listing/criteria/description-criteria.component';
|
||||
// import { DescriptionUploadDialogue } from '@app/ui/description/listing/criteria/description-upload-dialogue/description-upload-dialogue.component';
|
||||
import { DescriptionListingComponent } from '@app/ui/description/listing/description-listing.component';
|
||||
import { DescriptionListingItemComponent } from '@app/ui/description/listing/listing-item/description-listing-item.component';
|
||||
// import { DescriptionDescriptionFormModule } from '@app/ui/misc/description-description-form/description-description-form.module';
|
||||
// import { TableOfContentsModule } from '@app/ui/misc/description-description-form/tableOfContentsMaterial/table-of-contents.module';
|
||||
import { ExternalSourcesModule } from '@app/ui/misc/external-sources/external-sources.module';
|
||||
import { CommonFormsModule } from '@common/forms/common-forms.module';
|
||||
import { FormValidationErrorsDialogModule } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.module';
|
||||
import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module';
|
||||
import { CommonUiModule } from '@common/ui/common-ui.module';
|
||||
import { AngularStickyThingsModule } from '@w11k/angular-sticky-things';
|
||||
import { DescriptionCopyDialogModule } from './description-copy-dialog/description-copy-dialog.module';
|
||||
import { DescriptionOverviewModule } from './overview/description-overview.module';
|
||||
import { DescriptionEditorComponent } from './dataset-wizard/description-editor.component';
|
||||
// import { FormProgressIndicationModule } from '../misc/description-description-form/components/form-progress-indication/form-progress-indication.module';
|
||||
// import { DescriptionCopyDialogModule } from './description-wizard/description-copy-dialogue/description-copy-dialogue.module';
|
||||
// import { DescriptionCriteriaDialogComponent } from './listing/criteria/description-criteria-dialogue/description-criteria-dialog.component';
|
||||
// import { DescriptionOverviewModule } from './overview/description-overview.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonUiModule,
|
||||
CommonFormsModule,
|
||||
UrlListingModule,
|
||||
FormattingModule,
|
||||
ConfirmationDialogModule,
|
||||
AutoCompleteModule,
|
||||
ExternalSourcesModule,
|
||||
ExportMethodDialogModule,
|
||||
// DescriptionDescriptionFormModule,
|
||||
// TableOfContentsModule,
|
||||
AngularStickyThingsModule,
|
||||
DescriptionRoutingModule,
|
||||
FormValidationErrorsDialogModule,
|
||||
// DescriptionCopyDialogModule,
|
||||
// DescriptionOverviewModule,
|
||||
// FormProgressIndicationModule,
|
||||
RichTextEditorModule,
|
||||
|
||||
DescriptionCopyDialogModule,
|
||||
DescriptionOverviewModule,
|
||||
],
|
||||
declarations: [
|
||||
DescriptionListingComponent,
|
||||
// DescriptionCriteriaComponent,
|
||||
// DescriptionWizardComponent,
|
||||
DescriptionEditorComponent,
|
||||
// DescriptionExternalReferencesEditorComponent,
|
||||
// DescriptionExternalDataRepositoryDialogEditorComponent,
|
||||
// DescriptionExternalDescriptionDialogEditorComponent,
|
||||
// DescriptionExternalRegistryDialogEditorComponent,
|
||||
// DescriptionExternalServiceDialogEditorComponent,
|
||||
// DescriptionUploadDialogue,
|
||||
DescriptionListingItemComponent,
|
||||
// DescriptionCriteriaDialogComponent,
|
||||
// PrefillDescriptionComponent
|
||||
],
|
||||
exports: [
|
||||
// DescriptionExternalReferencesEditorComponent,
|
||||
// DescriptionExternalDataRepositoryDialogEditorComponent,
|
||||
// DescriptionExternalDescriptionDialogEditorComponent,
|
||||
// DescriptionExternalRegistryDialogEditorComponent,
|
||||
// DescriptionExternalServiceDialogEditorComponent,
|
||||
// DescriptionEditorComponent,
|
||||
// DescriptionDescriptionFormModule
|
||||
]
|
||||
})
|
||||
export class DescriptionModule { }
|
||||
|
|
|
@ -1,136 +1,35 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { AuthGuard } from '../../core/auth-guard.service';
|
||||
// import { DescriptionWizardComponent } from './description-wizard/description-wizard.component';
|
||||
import { DescriptionListingComponent } from './listing/description-listing.component';
|
||||
import { DescriptionOverviewComponent } from './overview/description-overview.component';
|
||||
import { CanDeactivateGuard } from '@app/library/deactivate/can-deactivate.guard';
|
||||
import { DescriptionEditorComponent } from './dataset-wizard/description-editor.component';
|
||||
import { AppPermission } from '@app/core/common/enum/permission.enum';
|
||||
import { DescriptionEditorResolver } from './dataset-wizard/description-editor.resolver';
|
||||
import { PendingChangesGuard } from '@common/forms/pending-form-changes/pending-form-changes-guard.service';
|
||||
// import { DescriptionOverviewComponent } from './overview/description-overview.component';
|
||||
import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: DescriptionListingComponent,
|
||||
// canActivate: [AuthGuard],
|
||||
path: 'overview',
|
||||
loadChildren: () => import('./overview/description-overview.module').then(m => m.DescriptionOverviewModule),
|
||||
data: {
|
||||
breadcrumb: true
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'dmp/:dmpId',
|
||||
component: DescriptionListingComponent,
|
||||
canActivate: [AuthGuard],
|
||||
data: {
|
||||
breadcrumb: true
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'overview/:id',
|
||||
component: DescriptionOverviewComponent,
|
||||
data: {
|
||||
breadcrumb: true,
|
||||
title: 'GENERAL.TITLES.DATASET-OVERVIEW'
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'publicOverview/:publicId',
|
||||
component: DescriptionOverviewComponent,
|
||||
data: {
|
||||
breadcrumb: true,
|
||||
title: 'GENERAL.TITLES.DATASET-OVERVIEW'
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'edit/:id',
|
||||
canActivate: [AuthGuard],
|
||||
component: DescriptionEditorComponent,
|
||||
canDeactivate: [PendingChangesGuard],
|
||||
resolve: {
|
||||
'entity': DescriptionEditorResolver
|
||||
},
|
||||
data: {
|
||||
...BreadcrumbService.generateRouteDataConfiguration({
|
||||
title: 'BREADCRUMBS.EDIT-DESCRIPTION'
|
||||
}),
|
||||
authContext: {
|
||||
permissions: [AppPermission.EditDescription]
|
||||
}
|
||||
}
|
||||
},
|
||||
// {
|
||||
// path: 'new/:dmpId/:dmpSectionIndex',
|
||||
// component: DescriptionWizardComponent,
|
||||
// canActivate: [AuthGuard],
|
||||
// data: {
|
||||
// breadcrumb: true,
|
||||
// title: 'GENERAL.TITLES.DATASET-NEW'
|
||||
// },
|
||||
// canDeactivate:[CanDeactivateGuard]
|
||||
// },
|
||||
|
||||
// {
|
||||
// path: 'edit/:id/finalize',
|
||||
// component: DescriptionWizardComponent,
|
||||
// canActivate: [AuthGuard],
|
||||
// data: {
|
||||
// breadcrumb: true,
|
||||
// public: false,
|
||||
// title: 'GENERAL.TITLES.DATASET-EDIT',
|
||||
// finalize: true
|
||||
// },
|
||||
// canDeactivate:[CanDeactivateGuard]
|
||||
// },
|
||||
// {
|
||||
// path: 'publicEdit/:publicId',
|
||||
// component: DescriptionWizardComponent,
|
||||
// //canActivate: [AuthGuard],
|
||||
// data: {
|
||||
// public: true,
|
||||
// title: 'GENERAL.TITLES.DATASET-PUBLIC-EDIT'
|
||||
// },
|
||||
// canDeactivate:[CanDeactivateGuard]
|
||||
// },
|
||||
// {
|
||||
// path: 'new',
|
||||
// component: DescriptionWizardComponent,
|
||||
// canActivate: [AuthGuard],
|
||||
// data: {
|
||||
// breadcrumb: true,
|
||||
// title: 'GENERAL.TITLES.DATASET-NEW'
|
||||
// },
|
||||
// canDeactivate:[CanDeactivateGuard]
|
||||
// },
|
||||
// {
|
||||
// path: 'copy/:id',
|
||||
// component: DescriptionWizardComponent,
|
||||
// canActivate: [AuthGuard],
|
||||
// data: {
|
||||
// breadcrumb: true,
|
||||
// title: 'GENERAL.TITLES.DATASET-COPY'
|
||||
// },
|
||||
// canDeactivate:[CanDeactivateGuard]
|
||||
// },
|
||||
// {
|
||||
// path: 'profileupdate/:updateId',
|
||||
// component: DescriptionWizardComponent,
|
||||
// canActivate: [AuthGuard],
|
||||
// data: {
|
||||
// breadcrumb: true,
|
||||
// title: 'GENERAL.TITLES.DATASET-UPDATE'
|
||||
// },
|
||||
// canDeactivate:[CanDeactivateGuard]
|
||||
// },
|
||||
|
||||
{
|
||||
path: 'edit',
|
||||
loadChildren: () => import('./editor/description-editor.module').then(m => m.DescriptionEditorModule),
|
||||
data: {
|
||||
breadcrumb: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
loadChildren: () => import('./listing/description-listing.module').then(m => m.DescriptionListingModule),
|
||||
data: {
|
||||
breadcrumb: true
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
providers: [DescriptionEditorResolver]
|
||||
providers: []
|
||||
})
|
||||
export class DescriptionRoutingModule { }
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
<form class="description-base-fields-editor" *ngIf="formGroup" [formGroup]="formGroup">
|
||||
<div class="col-12 intro">
|
||||
<p>{{'DATASET-EDITOR.TITLE.INTRO' | translate}}</p>
|
||||
<span>{{'DATASET-EDITOR.TITLE.INTRO-TIP' | translate}}</span>
|
||||
</div>
|
||||
<div class="col-12 card">
|
||||
<!-- Title Field -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="heading">1.1 {{'DATASET-EDITOR.FIELDS.TITLE' | translate}}*</div>
|
||||
<div class="title-form">
|
||||
<mat-form-field>
|
||||
<input matInput placeholder="{{'DATASET-EDITOR.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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Description field -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="heading">1.2 {{'DATASET-EDITOR.FIELDS.DESCRIPTION' | translate}}</div>
|
||||
<span class="hint">{{'DATASET-EDITOR.HINT.DESCRIPTION' | translate}}</span>
|
||||
<div class="description-form">
|
||||
<rich-text-editor-component [parentFormGroup]="formGroup" [controlName]="'description'"
|
||||
[placeholder]="'DMP-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>
|
||||
<mat-error *ngIf="formGroup.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- External Fields -->
|
||||
<!-- TODO: add external references -->
|
||||
<!-- <app-dataset-external-references-editor-component [formGroup]="formGroup" [viewOnly]="viewOnly"></app-dataset-external-references-editor-component> -->
|
||||
<!-- Template Field -->
|
||||
<div class="heading">1.4 {{'DATASET-EDITOR.FIELDS.PROFILE' | translate}}*</div>
|
||||
<!-- <div class="profile-form">
|
||||
<mat-form-field>
|
||||
<mat-select placeholder="{{'DATASET-WIZARD.FIRST-STEP.PROFILE'| translate}}" [required]="true" [compareWith]="compareWith" formControlName="profile">
|
||||
<mat-option *ngFor="let descriptionTemplates of availableDescriptionTemplates" [value]="profile">
|
||||
<div (click)="checkMinMax($event, descriptionTemplates)">
|
||||
{{descriptionTemplates.label}}
|
||||
</div>
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="formGroup.get('profile').hasError('backendError')">{{formGroup.get('profile').getError('backendError').message}}</mat-error>
|
||||
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div> -->
|
||||
</div>
|
||||
</form>
|
|
@ -1,4 +1,4 @@
|
|||
.dataset-editor {
|
||||
.description-base-fields-editor {
|
||||
.intro {
|
||||
text-align: left;
|
||||
font-weight: 400;
|
|
@ -0,0 +1,90 @@
|
|||
import { Component, Input } from '@angular/core';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
|
||||
import { BaseComponent } from '@common/base/base.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-description-base-fields-editor-component',
|
||||
templateUrl: 'description-base-fields-editor.component.html',
|
||||
styleUrls: ['./description-base-fields-editor.component.scss']
|
||||
})
|
||||
export class DescriptionBaseFieldsEditorComponent extends BaseComponent {
|
||||
|
||||
@Input() formGroup: UntypedFormGroup;
|
||||
@Input() availableDescriptionTemplates: DescriptionTemplate[];
|
||||
@Input() dmpId: string;
|
||||
viewOnly = false; //TODO: not used.
|
||||
|
||||
constructor(
|
||||
) { super(); }
|
||||
|
||||
checkMinMax(event, profile: DescriptionTemplate) {
|
||||
//TODO: Add logic for validating description templates.
|
||||
// event.stopPropagation();
|
||||
// const dmpSectionIndex = this.formGroup.get('dmpSectionIndex').value;
|
||||
// const blueprintId = this.formGroup.get('dmp').value.profile.id;
|
||||
// this.dmpBlueprintService.getSingle(blueprintId,
|
||||
// [
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.id)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.label)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.description)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.ordinal)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.hasTemplates)].join('.'),
|
||||
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.id)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.category)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.dataType)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.systemFieldType)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.label)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.placeholder)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.description)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.required)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.fields), nameof<FieldInSection>(x => x.ordinal)].join('.'),
|
||||
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.id)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.descriptionTemplateId)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.label)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.minMultiplicity)].join('.'),
|
||||
// [nameof<DmpBlueprint>(x => x.definition), nameof<DmpBlueprintDefinition>(x => x.sections), nameof<DmpBlueprintDefinitionSection>(x => x.descriptionTemplates), nameof<DescriptionTemplatesInSection>(x => x.maxMultiplicity)].join('.'),
|
||||
// ]
|
||||
// )
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(result => {
|
||||
// const section = result.definition.sections[dmpSectionIndex];
|
||||
// if(section.hasTemplates){
|
||||
// const foundTemplate = section.descriptionTemplates.find(template => template.descriptionTemplateId === Guid.parse(profile.id));
|
||||
// if (foundTemplate !== undefined) {
|
||||
// let count = 0;
|
||||
// if(this.formGroup.get('dmp').value.datasets != null){
|
||||
// for(let dataset of this.formGroup.get('dmp').value.datasets){
|
||||
// if(dataset.dmpSectionIndex === dmpSectionIndex && dataset.profile.id === foundTemplate.descriptionTemplateId){
|
||||
// count++;
|
||||
// }
|
||||
// }
|
||||
// if(count === foundTemplate.maxMultiplicity){
|
||||
// this.dialog.open(PopupNotificationDialogComponent, {
|
||||
// data: {
|
||||
// title: this.language.instant('DATASET-EDITOR.MAX-DESCRIPTION-DIALOG.TITLE'),
|
||||
// message: this.language.instant('DATASET-EDITOR.MAX-DESCRIPTION-DIALOG.MESSAGE')
|
||||
// }, maxWidth: '30em'
|
||||
// });
|
||||
// }
|
||||
// else{
|
||||
// this.formGroup.get('profile').setValue(profile);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// this.formGroup.get('profile').setValue(profile);
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// this.formGroup.get('profile').setValue(profile);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
public compareWith(object1: any, object2: any) {
|
||||
return object1 && object2 && object1.id === object2.id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
<div class="main-content">
|
||||
<div class="container-fluid description-editor">
|
||||
<form *ngIf="formGroup" [formGroup]="formGroup">
|
||||
<!-- <form *ngIf="formGroup" [formGroup]="formGroup" (ngSubmit)="formSubmit()"> -->
|
||||
<!-- Description Header -->
|
||||
<div class="fixed-editor-header">
|
||||
<div class="card description-editor-header">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col info">
|
||||
<ng-container *ngIf="!viewOnly else viewOnlyTemplate">
|
||||
<div *ngIf="isNew" class="description-title">{{'DESCRIPTION-EDITOR.TITLE.ADD-DATASET' | translate}}</div>
|
||||
<div *ngIf="!isNew" class="description-title">{{'DESCRIPTION-EDITOR.TITLE.EDIT-DESCRIPTION' | translate}}</div>
|
||||
<div class="description-subtitle">{{ formGroup.get('label').value }} <span *ngIf="isDirty()" class="description-changes">({{'DESCRIPTION-EDITOR.CHANGES' | translate}})</span></div>
|
||||
</ng-container>
|
||||
<ng-template #viewOnlyTemplate>
|
||||
<div class="description-title">{{'DESCRIPTION-EDITOR.TITLE.PREVIEW-DATASET' | translate}}</div>
|
||||
</ng-template>
|
||||
<div class="d-flex flex-direction-row dmp-info">
|
||||
<div class="col-auto description-to-dmp">{{'DESCRIPTION-EDITOR.TOOLTIP.TO-DMP' | translate}}</div>
|
||||
<div class="dmp-title p-0">: {{ item.dmp.label }}</div>
|
||||
<div class="col-auto d-flex align-items-center">
|
||||
<a [routerLink]="['/overview/' + item.dmp.id]" target="_blank" class="pointer open-in-new-icon">
|
||||
<mat-icon class="size-18">open_in_new</mat-icon>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-auto d-flex align-items-center">
|
||||
<button *ngIf="formGroup.get('id').value" [disabled]="isDirty()" [matTooltipDisabled]="!isDirty()" mat-raised-button class="description-export-btn" type="button" [matMenuTriggerFor]="exportMenu" (click)="$event.stopPropagation();" [matTooltip]="'DATASET-EDITOR.ACTIONS.DISABLED-EXPORT' | translate">
|
||||
{{ 'DMP-LISTING.ACTIONS.EXPORT' | translate }}
|
||||
<mat-icon [disabled]="isDirty()" style="width: 14px;">expand_more</mat-icon>
|
||||
</button>
|
||||
<mat-menu #exportMenu="matMenu" xPosition="before">
|
||||
<button mat-menu-item (click)="downloadPDF(formGroup.get('id').value)">
|
||||
<i class="fa fa-file-pdf-o pr-2"></i>
|
||||
<span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="downloadDOCX(formGroup.get('id').value)">
|
||||
<i class="fa fa-file-word-o pr-2"></i>
|
||||
<span>{{'GENERAL.FILE-TYPES.DOC' | translate}}</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="downloadXML(formGroup.get('id').value)">
|
||||
<i class="fa fa-file-code-o pr-2"></i>
|
||||
<span>{{'GENERAL.FILE-TYPES.XML' | translate}}</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
|
||||
<mat-divider *ngIf="formGroup.get('id').value && (!viewOnly || (!lockStatus && !viewOnly) || lockStatus || (hasReversableStatus() && !lockStatus))" [vertical]="true" class="ml-2 mr-2"></mat-divider>
|
||||
|
||||
<div *ngIf="isDirty() && !viewOnly" class="col-auto d-flex align-items-center pr-0">
|
||||
<button [disabled]="saving" type="button" mat-raised-button class="description-discard-btn" (click)="discardChanges()">
|
||||
{{'DESCRIPTION-EDITOR.ACTIONS.DISCARD' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-auto d-flex align-items-center">
|
||||
<button [disabled]="saving" *ngIf="!lockStatus && !viewOnly" mat-raised-button class="description-save-btn mr-2" type="button">
|
||||
<span class="d-flex flex-row row">
|
||||
<span (click)="!saving?save():null" class="col">{{ 'DESCRIPTION-EDITOR.ACTIONS.SAVE' | translate }}</span>
|
||||
<mat-divider [vertical]="true"></mat-divider>
|
||||
<span *ngIf="!saving" class="align-items-center justify-content-center col-4 d-flex" (click)="$event.stopPropagation();" [matMenuTriggerFor]="menu">
|
||||
<mat-icon>expand_more</mat-icon>
|
||||
</span>
|
||||
<span *ngIf="saving" class="align-items-center justify-content-center col-4 d-flex">
|
||||
<mat-icon>expand_more</mat-icon>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
<button [disabled]="saving" mat-menu-item (click)="save(saveAnd.close)" type="button">{{ 'DESCRIPTION-EDITOR.ACTIONS.SAVE-AND-CLOSE' | translate }}</button>
|
||||
<button [disabled]="saving" mat-menu-item (click)="save(saveAnd.addNew)" type="button">{{ 'DESCRIPTION-EDITOR.ACTIONS.SAVE-AND-ADD' | translate }}</button>
|
||||
<button [disabled]="saving" mat-menu-item (click)="save()" type="button">{{ 'DESCRIPTION-EDITOR.ACTIONS.SAVE-AND-CONTINUE' | translate }}</button>
|
||||
</mat-menu>
|
||||
|
||||
<button [disabled]="saving" *ngIf="!lockStatus && !viewOnly" mat-raised-button class="description-save-btn mr-2" type="button" (click)="saveFinalize()">{{ 'DESCRIPTION-EDITOR.ACTIONS.FINALIZE' | translate }}</button>
|
||||
<button [disabled]="saving" *ngIf="lockStatus" mat-raised-button disabled class="description-save-btn cursor-default" type="button">{{ 'DMP-OVERVIEW.LOCKED' | translate}}</button>
|
||||
<button [disabled]="saving" *ngIf="hasReversableStatus() && !lockStatus" mat-raised-button class="description-save-btn mr-2" (click)="reverse()" type="button">{{ 'DESCRIPTION-EDITOR.ACTIONS.REVERSE' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row editor-content">
|
||||
<div class="col-auto description-stepper">
|
||||
<div class="stepper-back d-flex flex-direction-row">
|
||||
<div class="d-flex align-items-center pr-2 back-to-dmp" (click)="backToDmp()">
|
||||
<mat-icon class="back-icon pointer">chevron_left</mat-icon>
|
||||
<span class="pointer">{{'DESCRIPTION-EDITOR.ACTIONS.BACK-TO' | translate}}</span>
|
||||
</div>
|
||||
<div class="col-auto dmp-label ml-3">{{'DESCRIPTION-EDITOR.TOOLTIP.DMP' | translate}}</div>
|
||||
</div>
|
||||
<div class="stepper-title">{{'DESCRIPTION-EDITOR.STEPPER.USER-GUIDE' | translate}}</div>
|
||||
<div class="stepper-options" id="stepper-options">
|
||||
<div class="col stepper-list">
|
||||
<div (click)="table0fContents.onToCentrySelected()" *ngIf="!descriptionInfoValid()" class="main-info" [ngClass]="{'active': this.step === 0, 'text-danger':hintErrors}">0. {{'DESCRIPTION-EDITOR.STEPPER.MAIN-INFO' | translate}} (2)</div>
|
||||
<div (click)="table0fContents.onToCentrySelected()" *ngIf="descriptionInfoValid()" class="main-info" [ngClass]="{'active': this.step === 0}">0. {{'DESCRIPTION-EDITOR.STEPPER.MAIN-INFO' | translate}} (<mat-icon class="done-icon">done</mat-icon>)</div>
|
||||
<div class="row toc-pane-container" #boundary>
|
||||
<div #spacer></div>
|
||||
<app-table-of-contents [visibilityRulesService]="visibilityRulesService" [selectedFieldsetId]="fieldsetIdWithFocus" #table0fContents [showErrors]="showtocentriesErrors" [TOCENTRY_ID_PREFIX]="TOCENTRY_ID_PREFIX" [hasFocus]="step > 0" [propertiesFormGroup]="formGroup.get('properties')" [descriptionTemplate]="item.descriptionTemplate" *ngIf="formGroup" [links]="links" [boundary]="boundary" [spacer]="spacer" [isActive]="step !== 0" stickyThing (stepFound)="onStepFound($event)" (currentLinks)="getLinks($event)" (entrySelected)="changeStep($event.entry, $event.execute)"></app-table-of-contents>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stepper-actions">
|
||||
<div mat-raised-button type="button" class="col-auto previous stepper-btn mr-2" [ngClass]="{'previous-disabled': this.step === 0}" (click)="previousStep()">
|
||||
<span class="material-icons">chevron_left</span>
|
||||
<div>{{'DESCRIPTION-EDITOR.STEPPER.PREVIOUS' | translate}}</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="this.step < this.maxStep" mat-raised-button type="button" class="col-auto stepper-btn description-next ml-auto" (click)="nextStep()">
|
||||
<div>{{'DESCRIPTION-EDITOR.STEPPER.NEXT' | translate}}</div>
|
||||
<span class="material-icons">chevron_right</span>
|
||||
</div>
|
||||
<div *ngIf="!formGroup.get('descriptionTemplateId').value" mat-raised-button type="button" class="col-auto stepper-btn description-next next-disabled ml-auto">
|
||||
<div>{{'DESCRIPTION-EDITOR.STEPPER.NEXT' | translate}}</div>
|
||||
<span class="material-icons">chevron_right</span>
|
||||
</div>
|
||||
<button [disabled]="saving" (click)="save(saveAnd.addNew)" *ngIf="(step === maxStep) && !lockStatus && formGroup.get('descriptionTemplateId').value && !viewOnly" mat-raised-button type="button" class="col-auto stepper-btn add-description-btn ml-auto">
|
||||
{{ 'DESCRIPTION-EDITOR.ACTIONS.SAVE-AND-ADD' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-auto pr-0">
|
||||
<app-form-progress-indication class="col-12" *ngIf="formGroup && !viewOnly" [formGroup]="formGroup" [isDescriptionEditor]="true"></app-form-progress-indication>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto form" id="description-editor-form">
|
||||
<app-description-base-fields-editor-component [hidden]="this.step !== 0" [formGroup]="formGroup" [dmpId]="item.dmp.id" [availableDescriptionTemplates]="availableDescriptionTemplates" (formChanged)="formChanged()"></app-description-base-fields-editor-component>
|
||||
<app-description-form
|
||||
*ngIf="formGroup && formGroup.get('properties')"
|
||||
[propertiesFormGroup]="formGroup.get('properties')"
|
||||
[descriptionTemplate]="item.descriptionTemplate"
|
||||
[visibilityRulesService]="visibilityRulesService"
|
||||
[TOCENTRY_ID_PREFIX]="TOCENTRY_ID_PREFIX"
|
||||
[hidden]="this.step === 0"
|
||||
[linkToScroll]="linkToScroll"
|
||||
(fieldsetFocusChange)="fieldsetIdWithFocus = $event"></app-description-form>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
|
@ -1,27 +1,11 @@
|
|||
import { Location } from '@angular/common';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormArray, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import { DescriptionStatus } from '@app/core/common/enum/description-status';
|
||||
import { DmpStatus } from '@app/core/common/enum/dmp-status';
|
||||
import { SaveType } from '@app/core/common/enum/save-type';
|
||||
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
|
||||
import { DmpModel } from '@app/core/model/dmp/dmp';
|
||||
import { DmpListingModel } from '@app/core/model/dmp/dmp-listing';
|
||||
import { LockModel } from '@app/core/model/lock/lock.model';
|
||||
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
|
||||
import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria';
|
||||
import { RequestItem } from '@app/core/query/request-item';
|
||||
import { AuthService } from '@app/core/services/auth/auth.service';
|
||||
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
|
||||
import { DmpService } from '@app/core/services/dmp/dmp.service';
|
||||
import {
|
||||
ExternalSourcesConfigurationService
|
||||
} from '@app/core/services/external-sources/external-sources-configuration.service';
|
||||
import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service';
|
||||
import { LockService } from '@app/core/services/lock/lock.service';
|
||||
import { MatomoService } from '@app/core/services/matomo/matomo-service';
|
||||
import {
|
||||
|
@ -29,37 +13,34 @@ import {
|
|||
UiNotificationService
|
||||
} from '@app/core/services/notification/ui-notification-service';
|
||||
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
|
||||
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
|
||||
import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component';
|
||||
import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component';
|
||||
// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent';
|
||||
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
|
||||
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
|
||||
import { FormService } from '@common/forms/form-service';
|
||||
import {
|
||||
FormValidationErrorsDialogComponent
|
||||
} from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component';
|
||||
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
|
||||
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
|
||||
import { Guid } from '@common/types/guid';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import * as FileSaver from 'file-saver';
|
||||
import { Observable, interval, of as observableOf } from 'rxjs';
|
||||
import { catchError, debounceTime, filter, map, takeUntil } from 'rxjs/operators';
|
||||
import { DescriptionEditorService } from './description-editor.service';
|
||||
import { BaseEditor } from '@common/base/base-editor';
|
||||
import { DescriptionEditorModel } from './description-editor.model';
|
||||
import { Description, DescriptionPersist } from '@app/core/model/description/description';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { IsActive } from '@app/core/common/enum/is-active.enum';
|
||||
import { AppPermission } from '@app/core/common/enum/permission.enum';
|
||||
import { HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service';
|
||||
import { QueryParamsService } from '@app/core/services/utilities/query-params.service';
|
||||
import { FilterService } from '@common/modules/text-filter/filter-service';
|
||||
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
|
||||
import { Rule } from '@app/core/model/dataset-profile-definition/rule';
|
||||
import { Description, DescriptionPersist } from '@app/core/model/description/description';
|
||||
import { DescriptionService } from '@app/core/services/description/description.service';
|
||||
import { LoggingService } from '@app/core/services/logging/logging-service';
|
||||
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
|
||||
import { QueryParamsService } from '@app/core/services/utilities/query-params.service';
|
||||
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
||||
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
|
||||
import { BaseEditor } from '@common/base/base-editor';
|
||||
import { FormService } from '@common/forms/form-service';
|
||||
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
|
||||
import { HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service';
|
||||
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 } from './description-editor.model';
|
||||
import { DescriptionEditorResolver } from './description-editor.resolver';
|
||||
import { IsActive } from '@app/core/common/enum/is-active.enum';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { DescriptionEditorService } from './description-editor.service';
|
||||
import { ToCEntry } from './table-of-contents/models/toc-entry';
|
||||
import { TableOfContentsComponent } from './table-of-contents/table-of-contents.component';
|
||||
import { ToCEntryType } from './table-of-contents/models/toc-entry-type.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'app-description-editor-component',
|
||||
|
@ -72,6 +53,7 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
isNew = true;
|
||||
isDeleted = false;
|
||||
formGroup: UntypedFormGroup = null;
|
||||
item: Description;
|
||||
// showInactiveDetails = false;
|
||||
// selectedSystemFields: Array<DescriptionSystemFieldType> = [];
|
||||
// DescriptionSectionFieldCategory = DescriptionSectionFieldCategory;
|
||||
|
@ -89,6 +71,14 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
// popupItemActionIcon: 'visibility'
|
||||
// };
|
||||
|
||||
// hasChanges = false;
|
||||
viewOnly = false;
|
||||
lockStatus: Boolean;
|
||||
@ViewChild('table0fContents') table0fContents: TableOfContentsComponent;
|
||||
step: number = 0;
|
||||
|
||||
|
||||
|
||||
protected get canDelete(): boolean {
|
||||
return !this.isDeleted && !this.isNew && this.hasPermission(this.authService.permissionEnum.DeleteDescription);
|
||||
}
|
||||
|
@ -126,14 +116,428 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
private descriptionEditorService: DescriptionEditorService,
|
||||
private fileUtils: FileUtils,
|
||||
private matomoService: MatomoService,
|
||||
private dmpService: DmpService
|
||||
private dmpService: DmpService,
|
||||
private lockService: LockService,
|
||||
public visibilityRulesService: VisibilityRulesService
|
||||
|
||||
) {
|
||||
super(dialog, language, formService, router, uiNotificationService, httpErrorHandlingService, filterService, datePipe, route, queryParamsService);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.matomoService.trackPageView('Admin: DMP Blueprints');
|
||||
this.matomoService.trackPageView('Description Editor');
|
||||
super.ngOnInit();
|
||||
|
||||
|
||||
// const params = this.route.snapshot.params;
|
||||
// const queryParams = this.route.snapshot.queryParams;
|
||||
// const data: any = this.route.snapshot.data;
|
||||
|
||||
|
||||
// this.init();
|
||||
|
||||
|
||||
|
||||
this.route.params
|
||||
.pipe(takeUntil(this._destroyed))
|
||||
.subscribe((params: Params) => {
|
||||
const isPublicDescription = params['public'];
|
||||
const itemId = params['id'];
|
||||
const newDmpId = params['newDmpId'];
|
||||
// const publicId = params['publicId'];
|
||||
// this.dmpId = params['dmpId'];
|
||||
// this.dmpSectionIndex = parseInt(params['dmpSectionIndex']);
|
||||
// this.newDmpId = queryParams['newDmpId'];
|
||||
// this.publicId = params['publicId'];
|
||||
// this.profileUpdateId = params['updateId'];
|
||||
// this.finalize = data.finalize;
|
||||
// this.itemId ? this.downloadDocumentId = this.itemId : this.downloadDocumentId = this.publicId
|
||||
|
||||
this.viewOnly = isPublicDescription;
|
||||
// if (itemId != null) {
|
||||
// this.isNew = false;
|
||||
// this.isPublicView = false;
|
||||
// this.descriptionService.getSingle(itemId, this.lookupFields())
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(data => {
|
||||
// this.description = data;
|
||||
// this.researchers = this.referenceService.getReferencesForTypes(this.description?.dmp?.dmpReferences, [ReferenceType.Researcher]);
|
||||
// // this.users = this.description.dmp.users;
|
||||
// this.checkLockStatus(this.description.id);
|
||||
// this.setIsUserOwner();
|
||||
// }, (error: any) => {
|
||||
// if (error.status === 404) {
|
||||
// return this.onFetchingDeletedCallbackError('/descriptions/');
|
||||
// }
|
||||
// if (error.status === 403) {
|
||||
// return this.onFetchingForbiddenCallbackError('/descriptions/');
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// else if (publicId != null) {
|
||||
// this.isNew = false;
|
||||
// this.isFinalized = true;
|
||||
// this.isPublicView = true;
|
||||
// this.descriptionService.getPublicSingle(publicId, this.lookupFields())
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(data => {
|
||||
// this.description = data;
|
||||
// this.researchers = this.referenceService.getReferencesForTypes(this.description?.dmp?.dmpReferences, [ReferenceType.Researcher]);
|
||||
// // this.users = this.description.dmp.users;
|
||||
// // const breadCrumbs = [];
|
||||
// // breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC DESCRIPTIONS'), url: "/explore" });
|
||||
// // breadCrumbs.push({ parentComponentName: 'DescriptionListingComponent', label: this.description.label, url: '/descriptions/overview/public/' + this.description.id });
|
||||
// // this.breadCrumbs = observableOf(breadCrumbs);
|
||||
// }, (error: any) => {
|
||||
// if (error.status === 404) {
|
||||
// return this.onFetchingDeletedCallbackError('/explore-descriptions');
|
||||
// }
|
||||
// if (error.status === 403) {
|
||||
// return this.onFetchingForbiddenCallbackError('/explore-descriptions');
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
if (itemId != null && newDmpId == null) {
|
||||
this.isNew = false;
|
||||
this.lockService.checkLockStatus(itemId).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => {
|
||||
this.lockStatus = lockStatus;
|
||||
if (this.item.status === DescriptionStatus.Finalized || lockStatus) {
|
||||
this.formGroup.disable();
|
||||
this.viewOnly = true;
|
||||
}
|
||||
if (lockStatus) {
|
||||
this.dialog.open(PopupNotificationDialogComponent, {
|
||||
data: {
|
||||
title: this.language.instant('DATASET-WIZARD.LOCKED.TITLE'),
|
||||
message: this.language.instant('DATASET-WIZARD.LOCKED.MESSAGE')
|
||||
}, maxWidth: '30em'
|
||||
});
|
||||
}
|
||||
|
||||
if (!lockStatus && !isNullOrUndefined(this.authService.currentAccountIsAuthenticated())) {
|
||||
//TODO: lock it.
|
||||
// const lockedBy: UserInfoListingModel = {
|
||||
// email: this.authService.getUserProfileEmail(),
|
||||
// id: this.authService.userId()?.toString(),
|
||||
// name: this.authService.getPrincipalName(),
|
||||
// role: 0 //TODO
|
||||
// //role: this.authService.getRoles()?.at(0)
|
||||
// }
|
||||
// this.lock = new LockModel(data.id, lockedBy);
|
||||
|
||||
// this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => {
|
||||
// this.lock.id = Guid.parse(result);
|
||||
// interval(this.configurationService.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock());
|
||||
// });
|
||||
}
|
||||
// this.loadDescriptionProfiles();
|
||||
// this.registerFormListeners();
|
||||
});
|
||||
}
|
||||
|
||||
// if (this.itemId != null && this.newDmpId == null) {
|
||||
// this.isNew = false;
|
||||
// this.descriptionService.getSingle(this.itemId)
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(data => {
|
||||
// this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => {
|
||||
// this.lockStatus = lockStatus;
|
||||
// this.descriptionModel = new DescriptionEditorModel().fromModel(data);
|
||||
// this.dmpSectionIndex = this.descriptionModel.dmpSectionIndex;
|
||||
// this.needsUpdate();
|
||||
// // this.breadCrumbs = observableOf([
|
||||
// // {
|
||||
// // parentComponentName: null,
|
||||
// // label: this.descriptionModel.label,
|
||||
// // url: '/descriptions/edit/' + this.descriptionModel.id,
|
||||
// // notFoundResolver: [
|
||||
// // {
|
||||
// // parentComponentName: null,
|
||||
// // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS').toUpperCase(),
|
||||
// // url: '/descriptions'
|
||||
// // },
|
||||
// // ]
|
||||
// // }]);
|
||||
// this.formGroup = this.descriptionModel.buildForm();
|
||||
// let profiles = this.descriptionModel.dmp.profiles.filter(profile => profile.data.dmpSectionIndex.includes(this.descriptionModel.dmpSectionIndex));
|
||||
// for (var profile of profiles) {
|
||||
// this.availableDescriptionTemplates.push({ id: profile.descriptionTemplateId, label: profile.label, description: "" })
|
||||
// }
|
||||
// this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));
|
||||
// this.editMode = this.descriptionModel.status === DescriptionStatus.Draft;
|
||||
// if (this.descriptionModel.status === DescriptionStatus.Finalized || lockStatus) {
|
||||
// this.formGroup.disable();
|
||||
// this.viewOnly = true;
|
||||
// }
|
||||
// if (!lockStatus && !isNullOrUndefined(this.authService.currentAccountIsAuthenticated())) {
|
||||
// const lockedBy: UserInfoListingModel = {
|
||||
// email: this.authService.getUserProfileEmail(),
|
||||
// id: this.authService.userId()?.toString(),
|
||||
// name: this.authService.getPrincipalName(),
|
||||
// role: 0 //TODO
|
||||
// //role: this.authService.getRoles()?.at(0)
|
||||
// }
|
||||
// this.lock = new LockModel(data.id, lockedBy);
|
||||
|
||||
// this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => {
|
||||
// this.lock.id = Guid.parse(result);
|
||||
// interval(this.configurationService.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock());
|
||||
// });
|
||||
// }
|
||||
// // if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Description edit like DMP.
|
||||
// this.loadDescriptionProfiles();
|
||||
// this.registerFormListeners();
|
||||
|
||||
// if (lockStatus) {
|
||||
// this.dialog.open(PopupNotificationDialogComponent, {
|
||||
// data: {
|
||||
// title: this.language.instant('DATASET-WIZARD.LOCKED.TITLE'),
|
||||
// message: this.language.instant('DATASET-WIZARD.LOCKED.MESSAGE')
|
||||
// }, maxWidth: '30em'
|
||||
// });
|
||||
// }
|
||||
// if (this.finalize && !this.lockStatus && !this.viewOnly) {
|
||||
// setTimeout(() => {
|
||||
// this.saveFinalize();
|
||||
// }, 0);
|
||||
// }
|
||||
// // this.availableProfiles = this.descriptionModel.dmp.profiles;
|
||||
// });
|
||||
// },
|
||||
// error => {
|
||||
// switch (error.status) {
|
||||
// case 403:
|
||||
// this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-WIZARD.MESSAGES.DATASET-NOT-ALLOWED'), SnackBarNotificationLevel.Error);
|
||||
// break;
|
||||
// case 404:
|
||||
// this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-WIZARD.MESSAGES.DATASET-NOT-FOUND'), SnackBarNotificationLevel.Error);
|
||||
// break;
|
||||
// default:
|
||||
// this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.ERRORS.HTTP-REQUEST-ERROR'), SnackBarNotificationLevel.Error);
|
||||
// }
|
||||
// this.router.navigate(['/descriptions/']);
|
||||
// return observableOf(null);
|
||||
// });
|
||||
// } else if (this.dmpId != null) {
|
||||
// this.isNew = true;
|
||||
// this.dmpService.getSingle(this.dmpId).pipe(map(data => data as DmpModel))
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(data => {
|
||||
// this.descriptionModel = new DescriptionEditorModel();
|
||||
// setTimeout(() => {
|
||||
// this.descriptionModel.dmp = data;
|
||||
// this.descriptionModel.dmpSectionIndex = this.dmpSectionIndex;
|
||||
// this.formGroup = this.descriptionModel.buildForm();
|
||||
// let profiles = this.descriptionModel.dmp.profiles.filter(profile => profile.data.dmpSectionIndex.includes(this.dmpSectionIndex));
|
||||
// for (var profile of profiles) {
|
||||
// this.availableDescriptionTemplates.push({ id: profile.descriptionTemplateId, label: profile.label, description: "" })
|
||||
// }
|
||||
// this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));
|
||||
// this.editMode = this.descriptionModel.status === DescriptionStatus.Draft;
|
||||
// this.formGroup.get('dmp').disable();
|
||||
// const dialogRef = this.dialog.open(PrefillDescriptionComponent, {
|
||||
// width: '590px',
|
||||
// minHeight: '200px',
|
||||
// restoreFocus: false,
|
||||
// data: {
|
||||
// availableProfiles: this.availableDescriptionTemplates,
|
||||
// descriptionFormGroup: this.formGroup
|
||||
// },
|
||||
// panelClass: 'custom-modalbox'
|
||||
// });
|
||||
// dialogRef.afterClosed().subscribe(result => {
|
||||
// if (result) {
|
||||
// this.descriptionModel = this.descriptionModel.fromModel(result);
|
||||
// this.descriptionModel.dmp = data;
|
||||
// this.descriptionModel.dmpSectionIndex = this.dmpSectionIndex;
|
||||
// this.formGroup = this.descriptionModel.buildForm();
|
||||
// this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));
|
||||
// this.formGroup.get('dmp').disable();
|
||||
// this.loadDescriptionProfiles();
|
||||
// this.registerFormListeners();
|
||||
// }
|
||||
// })
|
||||
// this.loadDescriptionProfiles();
|
||||
// this.registerFormListeners();
|
||||
// // this.availableProfiles = data.profiles;
|
||||
|
||||
// // this.breadCrumbs = observableOf([
|
||||
// // {
|
||||
// // parentComponentName: null,
|
||||
// // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'),
|
||||
// // url: '/descriptions',
|
||||
// // notFoundResolver: [
|
||||
// // // {
|
||||
// // // parentComponentName: null,
|
||||
// // // label: this.descriptionModel.dmp.grant.label,
|
||||
// // // url: '/grants/edit/' + this.descriptionModel.dmp.grant.id
|
||||
// // // },
|
||||
// // {
|
||||
// // parentComponentName: null,
|
||||
// // label: this.descriptionModel.dmp.label,
|
||||
// // url: '/plans/edit/' + this.descriptionModel.dmp.id,
|
||||
// // }]
|
||||
// // }]);
|
||||
// });
|
||||
// });
|
||||
// } else if (this.newDmpId != null) {
|
||||
// this.isNew = false;
|
||||
// this.isCopy = true;
|
||||
// this.descriptionService.getSingle(this.itemId)
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(data => {
|
||||
// this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => {
|
||||
// this.lockStatus = lockStatus;
|
||||
// this.descriptionModel = new DescriptionEditorModel().fromModel(data);
|
||||
// this.dmpSectionIndex = this.descriptionModel.dmpSectionIndex;
|
||||
// this.descriptionModel.status = 0;
|
||||
// this.formGroup = this.descriptionModel.buildForm();
|
||||
// this.formGroup.get('id').setValue(null);
|
||||
// this.dmpService.getSingleNoDescriptions(this.newDmpId).pipe(map(data => data as DmpModel))
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(data => {
|
||||
// setTimeout(() => {
|
||||
// this.descriptionModel.dmp = data;
|
||||
// this.formGroup.get('dmp').setValue(this.descriptionModel.dmp);
|
||||
// this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));
|
||||
|
||||
// this.loadDescriptionProfiles();
|
||||
// // this.breadCrumbs = observableOf([
|
||||
// // {
|
||||
// // parentComponentName: null,
|
||||
// // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'),
|
||||
// // url: '/descriptions',
|
||||
// // notFoundResolver: [
|
||||
// // // {
|
||||
// // // parentComponentName: null,
|
||||
// // // label: this.descriptionModel.dmp.grant.label,
|
||||
// // // url: '/grants/edit/' + this.descriptionModel.dmp.grant.id
|
||||
// // // },
|
||||
// // {
|
||||
// // parentComponentName: null,
|
||||
// // label: this.descriptionModel.dmp.label,
|
||||
// // url: '/plans/edit/' + this.descriptionModel.dmp.id,
|
||||
// // }
|
||||
// // ]
|
||||
// // }]);
|
||||
// });
|
||||
// });
|
||||
// this.editMode = this.descriptionModel.status === DescriptionStatus.Draft;
|
||||
// if (this.descriptionModel.status === DescriptionStatus.Finalized || lockStatus) {
|
||||
// this.formGroup.disable();
|
||||
// this.viewOnly = true;
|
||||
// }
|
||||
// if (!lockStatus && !isNullOrUndefined(this.authService.currentAccountIsAuthenticated())) {
|
||||
// const lockedBy: UserInfoListingModel = {
|
||||
// email: this.authService.getUserProfileEmail(),
|
||||
// id: this.authService.userId()?.toString(),
|
||||
// name: this.authService.getPrincipalName(),
|
||||
// role: 0 //TODO
|
||||
// //role: this.authService.getRoles()?.at(0)
|
||||
// }
|
||||
// this.lock = new LockModel(data.id, lockedBy);
|
||||
|
||||
// this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => {
|
||||
// this.lock.id = Guid.parse(result);
|
||||
// interval(this.configurationService.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock());
|
||||
// });
|
||||
// }
|
||||
// // if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Description edit like DMP.
|
||||
// this.loadDescriptionProfiles();
|
||||
// // this.availableProfiles = data.dmp.profiles;
|
||||
// })
|
||||
// });
|
||||
// } else if (this.publicId != null) { // For Finalized -> Public Descriptions
|
||||
// this.isNew = false;
|
||||
// this.descriptionService.getSinglePublic(this.publicId)
|
||||
// .pipe(takeUntil(this._destroyed)).pipe(
|
||||
// catchError((error: any) => {
|
||||
// this.uiNotificationService.snackBarNotification(error.error.message, SnackBarNotificationLevel.Error);
|
||||
// this.router.navigate(['/descriptions/publicEdit/' + this.publicId]);
|
||||
// return observableOf(null);
|
||||
// }))
|
||||
// .subscribe(data => {
|
||||
// if (data) {
|
||||
// this.descriptionModel = new DescriptionEditorModel().fromModel(data);
|
||||
// this.formGroup = this.descriptionModel.buildForm();
|
||||
// this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));
|
||||
// this.formGroup.disable();
|
||||
// this.viewOnly = true;
|
||||
// this.editMode = this.descriptionModel.status === DescriptionStatus.Draft;
|
||||
// this.formGroup.get('dmp').setValue(this.descriptionModel.dmp);
|
||||
// const breadcrumbs = [];
|
||||
// breadcrumbs.push({
|
||||
// parentComponentName: null,
|
||||
// label: this.language.instant('NAV-BAR.PUBLIC DATASETS'),
|
||||
// url: '/explore-descriptions'
|
||||
// });
|
||||
// breadcrumbs.push({
|
||||
// parentComponentName: null,
|
||||
// label: this.descriptionModel.label,
|
||||
// url: '/descriptions/publicEdit/' + this.descriptionModel.id
|
||||
// });
|
||||
// // this.breadCrumbs = observableOf(breadcrumbs);
|
||||
// }
|
||||
// });
|
||||
// this.publicMode = true;
|
||||
// } else if (this.profileUpdateId != null) {
|
||||
// this.descriptionService.updateDescriptionProfile(this.profileUpdateId)
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(data => {
|
||||
// this.descriptionModel = new DescriptionEditorModel().fromModel(data);
|
||||
// this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));
|
||||
|
||||
// this.needsUpdate();
|
||||
// // this.breadCrumbs = observableOf([
|
||||
// // {
|
||||
// // parentComponentName: null,
|
||||
// // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'),
|
||||
// // url: '/descriptions',
|
||||
// // notFoundResolver: [
|
||||
// // // {
|
||||
// // // parentComponentName: null,
|
||||
// // // label: this.descriptionModel.dmp.grant.label,
|
||||
// // // url: '/grants/edit/' + this.descriptionModel.dmp.grant.id
|
||||
// // // },
|
||||
// // {
|
||||
// // parentComponentName: null,
|
||||
// // label: this.descriptionModel.dmp.label,
|
||||
// // url: '/plans/edit/' + this.descriptionModel.dmp.id,
|
||||
// // },
|
||||
// // ]
|
||||
// // }]);
|
||||
// this.formGroup = this.descriptionModel.buildForm();
|
||||
// this.editMode = this.descriptionModel.status === DescriptionStatus.Draft;
|
||||
// if (this.descriptionModel.status === DescriptionStatus.Finalized) {
|
||||
// this.formGroup.disable();
|
||||
// this.viewOnly = true;
|
||||
// }
|
||||
// // if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Description edit like DMP.
|
||||
// this.loadDescriptionProfiles();
|
||||
// });
|
||||
|
||||
// } else {
|
||||
// this.descriptionModel = new DescriptionEditorModel();
|
||||
// this.formGroup = this.descriptionModel.buildForm();
|
||||
// this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));
|
||||
|
||||
// this.editMode = this.descriptionModel.status === DescriptionStatus.Draft;
|
||||
// if (this.descriptionModel.status === DescriptionStatus.Finalized) {
|
||||
// this.formGroup.disable();
|
||||
// this.viewOnly = true;
|
||||
// }
|
||||
// //if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Description edit like DMP.
|
||||
// this.registerFormListeners();
|
||||
// this.dmpValueChanged(null);
|
||||
// // this.breadCrumbs = observableOf([
|
||||
// // {
|
||||
// // parentComponentName: null,
|
||||
// // label: this.language.instant('DATASET-LISTING.ACTIONS.CREATE-NEW').toUpperCase(),
|
||||
// // url: '/descriptions/new/'
|
||||
// // }]);
|
||||
// }
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
getItem(itemId: Guid, successFunction: (item: Description) => void) {
|
||||
|
@ -148,6 +552,7 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
prepareForm(data: Description) {
|
||||
try {
|
||||
this.editorModel = data ? new DescriptionEditorModel().fromModel(data) : new DescriptionEditorModel();
|
||||
this.item = data;
|
||||
this.isDeleted = data ? data.isActive === IsActive.Inactive : false;
|
||||
this.buildForm();
|
||||
} catch (error) {
|
||||
|
@ -158,6 +563,8 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
|
||||
buildForm() {
|
||||
this.formGroup = this.editorModel.buildForm(null, this.isDeleted || !this.authService.hasPermission(AppPermission.EditDescription));
|
||||
this.visibilityRulesService.buildVisibilityRules(this.visibilityRulesService.getVisibilityRulesFromDescriptionTempalte(this.item.descriptionTemplate), this.formGroup);
|
||||
|
||||
// this.selectedSystemFields = this.selectedSystemFieldDisabled();
|
||||
this.descriptionEditorService.setValidationErrorModel(this.editorModel.validationErrorModel);
|
||||
if (this.editorModel.status == DescriptionStatus.Finalized) {
|
||||
|
@ -231,6 +638,148 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
this.formService.validateAllFormFields(this.formGroup);
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Misc
|
||||
//
|
||||
//
|
||||
|
||||
isDirty() {
|
||||
return this.formGroup.dirty; //TODO: check if needed //&& this.hasChanges; // do we need this.formGroup.dirty
|
||||
}
|
||||
|
||||
hasReversableStatus(): boolean {
|
||||
if (this.item?.dmp) {
|
||||
return (this.item.dmp.status == DmpStatus.Draft && this.formGroup.get('status').value == DescriptionStatus.Finalized);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
descriptionInfoValid(): boolean {
|
||||
return this.formGroup.get('label') && this.formGroup.get('label').valid && this.formGroup.get('descriptionTemplateId') && this.formGroup.get('descriptionTemplateId').valid;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// Table of Contents
|
||||
//
|
||||
//
|
||||
public changeStep(selected: ToCEntry = null, execute: boolean = true) {
|
||||
if (execute) {
|
||||
if (selected) {
|
||||
let fieldSet = this.getFirstFieldSet(selected);
|
||||
let index = this.visibleFieldSets.findIndex(entry => entry.id === fieldSet.id);
|
||||
this.step = index + (selected.type === ToCEntryType.FieldSet ? 1 : 0.5);
|
||||
} else {
|
||||
this.step = 0;
|
||||
this.resetScroll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getFirstFieldSet(entry: ToCEntry): ToCEntry {
|
||||
if (entry.type === ToCEntryType.FieldSet && !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === entry.id.toString())) {
|
||||
return entry;
|
||||
} else {
|
||||
let subEntries = entry.subEntries.filter(subEntry => !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === subEntry.id.toString()));
|
||||
if (subEntries.length > 0) {
|
||||
return this.getFirstFieldSet(subEntries[0]);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private resetScroll() {
|
||||
document.getElementById('description-editor-form').scrollTop = 0;
|
||||
}
|
||||
|
||||
get visibleFieldSets(): ToCEntry[] {
|
||||
let fieldSets = [];
|
||||
let arrays = this.table0fContents ? this.table0fContents.tocentries.
|
||||
filter(entry => !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === entry.id.toString())).map(entry => {
|
||||
return this.getEntryVisibleFieldSets(entry);
|
||||
})
|
||||
: [];
|
||||
arrays.forEach(array => {
|
||||
fieldSets = fieldSets.concat(array);
|
||||
});
|
||||
return fieldSets;
|
||||
}
|
||||
|
||||
getEntryVisibleFieldSets(entry: ToCEntry): ToCEntry[] {
|
||||
let fieldSets = [];
|
||||
if (entry.type === ToCEntryType.FieldSet && !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === entry.id.toString())) {
|
||||
fieldSets.push(entry);
|
||||
} else if (entry.type !== ToCEntryType.FieldSet) {
|
||||
entry.subEntries.forEach(subEntry => {
|
||||
fieldSets = fieldSets.concat(this.getEntryVisibleFieldSets(subEntry));
|
||||
});
|
||||
}
|
||||
return fieldSets;
|
||||
}
|
||||
|
||||
// registerFormListeners() {
|
||||
// // const dmpSubscription =
|
||||
// this.formGroup.get('dmp').valueChanges
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(x => {
|
||||
// this.dmpValueChanged(x);
|
||||
// });
|
||||
// // const profileSubscription =
|
||||
// this.formGroup.get('profile').valueChanges
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(x => {
|
||||
// if (x) {
|
||||
// this.showtocentriesErrors = false;
|
||||
// this.descriptionProfileValueChanged(x.id);
|
||||
// this.formChanged();
|
||||
// }
|
||||
// });
|
||||
// // const labelSubscription =
|
||||
// this.formGroup.get('label').valueChanges
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(x => {
|
||||
// this.formChanged();
|
||||
// });
|
||||
// // const descriptionSubscription =
|
||||
// this.formGroup.get('description').valueChanges
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(x => {
|
||||
// this.formChanged();
|
||||
// });
|
||||
// // const uriSubscription =
|
||||
// this.formGroup.get('uri').valueChanges
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(x => {
|
||||
// this.formChanged();
|
||||
// });
|
||||
// // const tagsSubscription =
|
||||
// this.formGroup.get('tags').valueChanges
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(x => {
|
||||
// this.formChanged();
|
||||
// });
|
||||
// if (this.formGroup.get('descriptionProfileDefinition')) {
|
||||
// // const descriptionProfileDefinitionSubscription =
|
||||
// this.formGroup.get('descriptionProfileDefinition').valueChanges
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(x => {
|
||||
// this.formChanged();
|
||||
// });
|
||||
// // this._listenersSubscription.add(descriptionProfileDefinitionSubscription);
|
||||
// }
|
||||
|
||||
// // this._listenersSubscription.add(dmpSubscription);
|
||||
// // this._listenersSubscription.add(profileSubscription);
|
||||
// // this._listenersSubscription.add(labelSubscription);
|
||||
// // this._listenersSubscription.add(descriptionSubscription);
|
||||
// // this._listenersSubscription.add(uriSubscription);
|
||||
// // this._listenersSubscription.add(tagsSubscription);
|
||||
// }
|
||||
|
||||
// //
|
||||
// //
|
||||
// // Sections
|
||||
|
@ -1167,13 +1716,7 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
|
||||
// }
|
||||
|
||||
// hasReversableStatus(): boolean {
|
||||
// if (this.formGroup.get('dmp').value) {
|
||||
// return (this.formGroup.get('dmp').value.status == DmpStatus.Draft && this.formGroup.get('status').value == DescriptionStatus.Finalized);
|
||||
// } else {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// hasNotReversableStatus(): boolean {
|
||||
// if (this.formGroup.get('dmp').value && !this.publicMode) {
|
||||
|
@ -1664,9 +2207,7 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
|
|||
// this.router.navigate(['/plans', 'edit', id]);
|
||||
// }
|
||||
|
||||
// descriptionInfoValid(): boolean {
|
||||
// return this.formGroup.get('label') && this.formGroup.get('label').valid && this.formGroup.get('profile') && this.formGroup.get('profile').valid;
|
||||
// }
|
||||
|
||||
|
||||
// getLinks(currentLinks: Link[]) {
|
||||
// this.links = currentLinks;
|
|
@ -106,17 +106,27 @@ export class DescriptionPropertyDefinitionEditorModel implements PropertyDefinit
|
|||
});
|
||||
}
|
||||
|
||||
return this.formBuilder.group({
|
||||
fields: this.formBuilder.array(
|
||||
(this.fields ?? []).map(
|
||||
(item, index) => new DescriptionFieldEditorModel(
|
||||
this.validationErrorModel
|
||||
).fromModel(item).buildForm({
|
||||
rootPath: `${rootPath}fields[${index}].`
|
||||
}), context.getValidation('fields')
|
||||
)
|
||||
),
|
||||
});
|
||||
const formGroup = this.formBuilder.group({});
|
||||
(this.fields ?? []).map(
|
||||
(item, index) => formGroup.addControl(item.key, new DescriptionFieldEditorModel(
|
||||
this.validationErrorModel
|
||||
).fromModel(item).buildForm({
|
||||
rootPath: `${rootPath}fields[${index}].`
|
||||
})), context.getValidation('fields')
|
||||
)
|
||||
return formGroup;
|
||||
|
||||
// return this.formBuilder.group({
|
||||
// fields: this.formBuilder.array(
|
||||
// (this.fields ?? []).map(
|
||||
// (item, index) => new DescriptionFieldEditorModel(
|
||||
// this.validationErrorModel
|
||||
// ).fromModel(item).buildForm({
|
||||
// rootPath: `${rootPath}fields[${index}].`
|
||||
// }), context.getValidation('fields')
|
||||
// )
|
||||
// )
|
||||
// });
|
||||
}
|
||||
|
||||
static createValidationContext(params: {
|
|
@ -0,0 +1,37 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { FormattingModule } from '@app/core/formatting.module';
|
||||
import { UrlListingModule } from '@app/library/url-listing/url-listing.module';
|
||||
import { CommonFormsModule } from '@common/forms/common-forms.module';
|
||||
import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module';
|
||||
import { CommonUiModule } from '@common/ui/common-ui.module';
|
||||
import { DescriptionBaseFieldsEditorComponent } from './description-base-fields-editor/description-base-fields-editor.component';
|
||||
import { DescriptionEditorComponent } from './description-editor.component';
|
||||
import { DescriptionEditorRoutingModule } from './description-editor.routing';
|
||||
import { DescriptionFormModule } from './description-form/description-form.module';
|
||||
import { VisibilityRulesService } from './description-form/visibility-rules/visibility-rules.service';
|
||||
import { DescriptionFormProgressIndicationModule } from './form-progress-indication/form-progress-indication.module';
|
||||
import { TableOfContentsModule } from './table-of-contents/table-of-contents.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonUiModule,
|
||||
CommonFormsModule,
|
||||
UrlListingModule,
|
||||
FormattingModule,
|
||||
ConfirmationDialogModule,
|
||||
TableOfContentsModule,
|
||||
DescriptionFormProgressIndicationModule,
|
||||
DescriptionFormModule,
|
||||
DescriptionEditorRoutingModule
|
||||
],
|
||||
declarations: [
|
||||
DescriptionEditorComponent,
|
||||
DescriptionBaseFieldsEditorComponent
|
||||
],
|
||||
exports: [
|
||||
],
|
||||
providers: [
|
||||
VisibilityRulesService
|
||||
]
|
||||
})
|
||||
export class DescriptionEditorModule { }
|
|
@ -0,0 +1,112 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||
import { DescriptionTemplate, DescriptionTemplateBaseFieldData, DescriptionTemplateDefinition, DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplatePage, DescriptionTemplateRule, DescriptionTemplateSection } from '@app/core/model/description-template/description-template';
|
||||
import { Description, DescriptionField, DescriptionReference, DescriptionTag, PropertyDefinition } from '@app/core/model/description/description';
|
||||
import { Dmp, DmpDescriptionTemplate } from '@app/core/model/dmp/dmp';
|
||||
import { Reference } from '@app/core/model/reference/reference';
|
||||
import { Tag } from '@app/core/model/tag/tag';
|
||||
import { DescriptionService } from '@app/core/services/description/description.service';
|
||||
import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service';
|
||||
import { BaseEditorResolver } from '@common/base/base-editor.resolver';
|
||||
import { Guid } from '@common/types/guid';
|
||||
import { takeUntil, tap } from 'rxjs/operators';
|
||||
import { nameof } from 'ts-simple-nameof';
|
||||
|
||||
@Injectable()
|
||||
export class DescriptionEditorResolver extends BaseEditorResolver {
|
||||
|
||||
constructor(private descriptionService: DescriptionService, private breadcrumbService: BreadcrumbService) {
|
||||
super();
|
||||
}
|
||||
|
||||
public static lookupFields(): string[] {
|
||||
return [
|
||||
...BaseEditorResolver.lookupFields(),
|
||||
nameof<Description>(x => x.id),
|
||||
nameof<Description>(x => x.label),
|
||||
nameof<Description>(x => x.status),
|
||||
nameof<Description>(x => x.description),
|
||||
nameof<Description>(x => x.status),
|
||||
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.id)].join('.'),
|
||||
[nameof<Description>(x => x.dmp), nameof<Dmp>(x => x.label)].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.dmpDescriptionTemplate), nameof<DmpDescriptionTemplate>(x => x.id)].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.id)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.pages), nameof<DescriptionTemplatePage>(x => x.id)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.pages), nameof<DescriptionTemplatePage>(x => x.ordinal)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.pages), nameof<DescriptionTemplatePage>(x => x.title)].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.id)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.ordinal)].join('.'),
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.defaultVisibility)].join('.'),
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.multiplicity)].join('.'),
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.numbering)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.page)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.title)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.description)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.extendedDescription)].join('.'),
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.ordinal)].join('.'), // TODO: need to sort based on that
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.sections)].join('.'), // TODO: it is recursive here
|
||||
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.id)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.ordinal)].join('.'),
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.numbering)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.title)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.description)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.extendedDescription)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.additionalInformation)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.hasCommentField)].join('.'),
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.multiplicity), nameof<DescriptionTemplateMultiplicity>(x => x.min)].join('.'),
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.multiplicity), nameof<DescriptionTemplateMultiplicity>(x => x.max)].join('.'),
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.multiplicity), nameof<DescriptionTemplateMultiplicity>(x => x.placeholder)].join('.'),
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.multiplicity), nameof<DescriptionTemplateMultiplicity>(x => x.tableView)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.fields), nameof<DescriptionTemplateField>(x => x.id)].join('.'),
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.fields), nameof<DescriptionTemplateField>(x => x.ordinal)].join('.'),
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.fields), nameof<DescriptionTemplateField>(x => x.numbering)].join('.'),
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.fields), nameof<DescriptionTemplateField>(x => x.schematics)].join('.'),
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.fields), nameof<DescriptionTemplateField>(x => x.defaultValue)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.fields), nameof<DescriptionTemplateField>(x => x.defaultValue)].join('.'),
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.fields), nameof<DescriptionTemplateField>(x => x.fieldType)].join('.'),
|
||||
// [nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.fields), nameof<DescriptionTemplateField>(x => x.includeInExport)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.fields), nameof<DescriptionTemplateField>(x => x.validations)].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.fields), nameof<DescriptionTemplateField>(x => x.visibilityRules), nameof<DescriptionTemplateRule>(x => x.target)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.fields), nameof<DescriptionTemplateField>(x => x.visibilityRules), nameof<DescriptionTemplateRule>(x => x.value)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.fields), nameof<DescriptionTemplateField>(x => x.data), nameof<DescriptionTemplateBaseFieldData>(x => x.label)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTemplate), nameof<DescriptionTemplate>(x => x.definition), nameof<DescriptionTemplateDefinition>(x => x.sections), nameof<DescriptionTemplateSection>(x => x.fieldSets), nameof<DescriptionTemplateFieldSet>(x => x.fields), nameof<DescriptionTemplateField>(x => x.data), nameof<DescriptionTemplateBaseFieldData>(x => x.fieldType)].join('.'),
|
||||
|
||||
|
||||
[nameof<Description>(x => x.properties), nameof<PropertyDefinition>(x => x.fields), nameof<DescriptionField>(x => x.key)].join('.'),
|
||||
[nameof<Description>(x => x.properties), nameof<PropertyDefinition>(x => x.fields), nameof<DescriptionField>(x => x.value)].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.descriptionTags), nameof<DescriptionTag>(x => x.id),].join('.'),
|
||||
[nameof<Description>(x => x.descriptionTags), nameof<DescriptionTag>(x => x.tag), nameof<Tag>(x => x.label)].join('.'),
|
||||
|
||||
[nameof<Description>(x => x.descriptionReferences), nameof<DescriptionReference>(x => x.reference), nameof<Reference>(x => x.id)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionReferences), nameof<DescriptionReference>(x => x.reference), nameof<Reference>(x => x.label)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionReferences), nameof<DescriptionReference>(x => x.reference), nameof<Reference>(x => x.type)].join('.'),
|
||||
[nameof<Description>(x => x.descriptionReferences), nameof<DescriptionReference>(x => x.reference), nameof<Reference>(x => x.reference)].join('.'),
|
||||
nameof<Description>(x => x.createdAt),
|
||||
nameof<Description>(x => x.hash),
|
||||
nameof<Description>(x => x.isActive)
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
|
||||
const fields = [
|
||||
...DescriptionEditorResolver.lookupFields()
|
||||
];
|
||||
const id = route.paramMap.get('id');
|
||||
// const cloneid = route.paramMap.get('cloneid');
|
||||
if (id != null) {
|
||||
return this.descriptionService.getSingle(Guid.parse(id), fields).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed));
|
||||
}
|
||||
//TODO: check this
|
||||
// else if (cloneid != null) {
|
||||
// return this.descriptionService.clone(Guid.parse(cloneid), fields).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed));
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
// import { DescriptionWizardComponent } from './description-wizard/description-wizard.component';
|
||||
import { AppPermission } from '@app/core/common/enum/permission.enum';
|
||||
import { PendingChangesGuard } from '@common/forms/pending-form-changes/pending-form-changes-guard.service';
|
||||
// import { DescriptionOverviewComponent } from './overview/description-overview.component';
|
||||
import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service';
|
||||
import { DescriptionEditorComponent } from './description-editor.component';
|
||||
import { DescriptionEditorResolver } from './description-editor.resolver';
|
||||
import { AuthGuard } from '@app/core/auth-guard.service';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: ':id',
|
||||
canActivate: [AuthGuard],
|
||||
component: DescriptionEditorComponent,
|
||||
canDeactivate: [PendingChangesGuard],
|
||||
resolve: {
|
||||
'entity': DescriptionEditorResolver
|
||||
},
|
||||
data: {
|
||||
...BreadcrumbService.generateRouteDataConfiguration({
|
||||
title: 'BREADCRUMBS.EDIT-DESCRIPTION'
|
||||
}),
|
||||
authContext: {
|
||||
permissions: [AppPermission.EditDescription]
|
||||
}
|
||||
}
|
||||
},
|
||||
// {
|
||||
// path: 'new/:dmpId/:dmpSectionIndex',
|
||||
// component: DescriptionWizardComponent,
|
||||
// canActivate: [AuthGuard],
|
||||
// data: {
|
||||
// breadcrumb: true,
|
||||
// title: 'GENERAL.TITLES.DATASET-NEW'
|
||||
// },
|
||||
// canDeactivate:[CanDeactivateGuard]
|
||||
// },
|
||||
|
||||
// {
|
||||
// path: 'edit/:id/finalize',
|
||||
// component: DescriptionWizardComponent,
|
||||
// canActivate: [AuthGuard],
|
||||
// data: {
|
||||
// breadcrumb: true,
|
||||
// public: false,
|
||||
// title: 'GENERAL.TITLES.DATASET-EDIT',
|
||||
// finalize: true
|
||||
// },
|
||||
// canDeactivate:[CanDeactivateGuard]
|
||||
// },
|
||||
// {
|
||||
// path: 'publicEdit/:publicId',
|
||||
// component: DescriptionWizardComponent,
|
||||
// //canActivate: [AuthGuard],
|
||||
// data: {
|
||||
// public: true,
|
||||
// title: 'GENERAL.TITLES.DATASET-PUBLIC-EDIT'
|
||||
// },
|
||||
// canDeactivate:[CanDeactivateGuard]
|
||||
// },
|
||||
// {
|
||||
// path: 'new',
|
||||
// component: DescriptionWizardComponent,
|
||||
// canActivate: [AuthGuard],
|
||||
// data: {
|
||||
// breadcrumb: true,
|
||||
// title: 'GENERAL.TITLES.DATASET-NEW'
|
||||
// },
|
||||
// canDeactivate:[CanDeactivateGuard]
|
||||
// },
|
||||
// {
|
||||
// path: 'copy/:id',
|
||||
// component: DescriptionWizardComponent,
|
||||
// canActivate: [AuthGuard],
|
||||
// data: {
|
||||
// breadcrumb: true,
|
||||
// title: 'GENERAL.TITLES.DATASET-COPY'
|
||||
// },
|
||||
// canDeactivate:[CanDeactivateGuard]
|
||||
// },
|
||||
// {
|
||||
// path: 'profileupdate/:updateId',
|
||||
// component: DescriptionWizardComponent,
|
||||
// canActivate: [AuthGuard],
|
||||
// data: {
|
||||
// breadcrumb: true,
|
||||
// title: 'GENERAL.TITLES.DATASET-UPDATE'
|
||||
// },
|
||||
// canDeactivate:[CanDeactivateGuard]
|
||||
// },
|
||||
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
providers: [DescriptionEditorResolver]
|
||||
})
|
||||
export class DescriptionEditorRoutingModule { }
|
|
@ -0,0 +1,15 @@
|
|||
<div class="form">
|
||||
<div class="row d-flex flex-row">
|
||||
<div class="col-auto ml-auto close-btn" (click)="close()">
|
||||
<mat-icon>close</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="data.formGroup" mat-dialog-content class="row">
|
||||
<app-form-composite-field class="align-self-center col" [form]="data.formGroup" [datasetProfileId]="data.datasetProfileId" [altVisibilityRulesService]="visibilityRulesService"
|
||||
[isChild]="false" [showDelete]="false" [showTitle]="false" [placeholderTitle]="true"></app-form-composite-field>
|
||||
</div>
|
||||
<div mat-dialog-actions class="row">
|
||||
<div class="ml-auto col-auto"><button mat-raised-button type="button" mat-dialog-close (click)="cancel()">{{'DATASET-EDITOR.ACTIONS.CANCEL' | translate}}</button></div>
|
||||
<div class="col-auto"><button mat-raised-button color="primary" type="button" [disabled]="!data.formGroup.valid" (click)="save()">{{'DATASET-EDITOR.ACTIONS.SAVE' | translate}}</button></div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,31 @@
|
|||
import {Component, Inject} from "@angular/core";
|
||||
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||
import { VisibilityRulesService } from "../../visibility-rules/visibility-rules.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-form-composite-field-dialog',
|
||||
templateUrl: 'form-composite-field-dialog.component.html'
|
||||
})
|
||||
export class FormCompositeFieldDialogComponent {
|
||||
|
||||
public visibilityRulesService: VisibilityRulesService;
|
||||
|
||||
constructor(
|
||||
private dialogRef: MatDialogRef<FormCompositeFieldDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any
|
||||
) {
|
||||
this.visibilityRulesService = data.visibilityRulesService;
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
save() {
|
||||
this.dialogRef.close(this.data.formGroup);
|
||||
}
|
||||
|
||||
public close() {
|
||||
this.dialogRef.close(false);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<div class="col-12">
|
||||
<div class="row">
|
||||
<h5 *ngIf="fieldSet.title && !isChild" class="col-auto compositeField toc-compositeField-header" [id]="fieldSet.id">
|
||||
<!-- TODO: We need the numbering here. -->
|
||||
<!-- {{tocentry? tocentry.numbering : form.get('numbering').value}} -->
|
||||
{{fieldSet.title}}
|
||||
</h5>
|
||||
<mat-icon class="col-auto info-icon" *ngIf="fieldSet.additionalInformation && !isChild" matTooltip="{{fieldSet.additionalInformation}}">info</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h6 *ngIf="fieldSet.description && !isChild" class="col-12" [innerHTML]="fieldSet.description"></h6>
|
||||
|
||||
<div *ngIf="fieldSet.extendedDescription && !isChild" class="col-12 mt-3 mb-3">
|
||||
<div *ngIf="!showExtendedDescription" (click)="showExtendedDescription = !showExtendedDescription">
|
||||
<span class="more d-flex justify-content-center">{{'DATASET-EDITOR.QUESTION.EXTENDED-DESCRIPTION.VIEW-MORE' | translate}}</span>
|
||||
</div>
|
||||
<div *ngIf="showExtendedDescription">
|
||||
<h6 [innerHTML]="fieldSet.extendedDescription"></h6>
|
||||
<span class="more d-flex justify-content-center" (click)="showExtendedDescription = !showExtendedDescription">
|
||||
{{'DATASET-EDITOR.QUESTION.EXTENDED-DESCRIPTION.VIEW-LESS' | translate}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,31 @@
|
|||
.compositeField {
|
||||
// font-weight: bold;
|
||||
// color: #3a3737;
|
||||
// max-width: 100%;
|
||||
// padding-top: 1em;
|
||||
text-align: left;
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
letter-spacing: 0px;
|
||||
color: #212121;
|
||||
opacity: 0.81;
|
||||
margin-top: 1.625rem;
|
||||
margin-bottom: 0.625rem;
|
||||
}
|
||||
|
||||
.info-icon{
|
||||
margin-top: 1.625rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
text-transform: none;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.more {
|
||||
text-decoration: underline;
|
||||
color: var(--secondary-color);
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { DescriptionTemplateFieldSet } from '@app/core/model/description-template/description-template';
|
||||
|
||||
@Component({
|
||||
selector: 'app-form-composite-title',
|
||||
templateUrl: './form-composite-title.component.html',
|
||||
styleUrls: ['./form-composite-title.component.scss']
|
||||
})
|
||||
export class DescriptionFormCompositeTitleComponent implements OnInit {
|
||||
|
||||
@Input() fieldSet: DescriptionTemplateFieldSet;
|
||||
@Input() isChild: Boolean = false;
|
||||
|
||||
public showExtendedDescription: boolean = false;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
<div *ngIf="fieldSet && isVisibleByVisibilityService && !tableRow" class="dynamic-form-composite-field row">
|
||||
<div *ngIf="fieldSet.fields.length === 1 && this.visibilityRulesService.isVisibleMap[fieldSet.fields.id] ?? true" class="col-12">
|
||||
<div class="row">
|
||||
<div *ngIf="showTitle" class="col-12">
|
||||
<app-form-composite-title class="row" [fieldSet]="fieldSet" [isChild]="isChild"></app-form-composite-title>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="row">
|
||||
<app-form-field class="align-self-center col" [propertiesFormGroup]="propertiesFormGroup" [field]="fieldSet.fields[0]" [fieldSet]="fieldSet" [visibilityRulesService]="visibilityRulesService" [datasetProfileId]="datasetProfileId" [isChild]="isChild"></app-form-field>
|
||||
<div *ngIf="showDelete" class="col-auto align-self-center">
|
||||
<button mat-icon-button type="button" class="deleteBtn" (click)="deleteCompositeField();" [disabled]="propertiesFormGroup.get(fieldSet.fields[0].id).disabled">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="fieldSet.fields.length > 1" class="col-12">
|
||||
<div class="row">
|
||||
<div *ngIf="showTitle" class="col-12">
|
||||
<app-form-composite-title class="row" [fieldSet]="fieldSet" [isChild]="isChild"></app-form-composite-title>
|
||||
</div>
|
||||
<div class="col align-self-center">
|
||||
<div *ngFor="let field of fieldSet.fields; let i = index;" class="col-12 compositeField">
|
||||
<ng-container *ngIf="this.visibilityRulesService.isVisibleMap[field.id] ?? true">
|
||||
<div class="row">
|
||||
<h5 *ngIf="placeholderTitle" class="col-auto font-weight-bold">{{field.label}}</h5>
|
||||
</div>
|
||||
<app-form-field class="col-12 compositeField" [propertiesFormGroup]="propertiesFormGroup" [field]="field" [fieldSet]="fieldSet" [visibilityRulesService]="visibilityRulesService" [datasetProfileId]="datasetProfileId" [isChild]="true"></app-form-field>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="showDelete" class="col-auto align-self-center">
|
||||
<button mat-icon-button type="button" class="deleteBtn" (click)="deleteCompositeField();">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ng-container *ngIf="fieldSet && isVisibleByVisibilityService && tableRow">
|
||||
<ng-container *ngFor="let field of fieldSet.fields;">
|
||||
<td *ngIf="this.visibilityRulesService.isVisibleMap[field.id] ?? true" class="text-wrap">{{propertiesFormGroup.get(field.id).get('value').getRawValue() | fieldValue | translate}}</td>
|
||||
</ng-container>
|
||||
<td class="actions">
|
||||
<button mat-icon-button type="button" class="deleteBtn btn-sm" (click)="editCompositeFieldInDialog()" [disabled]="propertiesFormGroup.get(field.id).disabled">
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
<button *ngIf="showDelete" mat-icon-button type="button" class="deleteBtn" (click)="deleteCompositeField();" [disabled]="propertiesFormGroup.get(field.id).disabled">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
|
@ -0,0 +1,17 @@
|
|||
.compositeField {
|
||||
padding-left: 0em !important;
|
||||
// padding-top: 2em !important;
|
||||
}
|
||||
|
||||
// ::ng-deep .mat-form-field-appearance-outline .mat-form-field-outline {
|
||||
// background: #fafafa !important;
|
||||
// }
|
||||
|
||||
// ::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix {
|
||||
// font-size: 1rem;
|
||||
// padding: 0.6em 0 1em 0 !important;
|
||||
// }
|
||||
|
||||
.actions {
|
||||
width: 110px;
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from '@angular/core';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { DescriptionTemplateFieldSet } from '@app/core/model/description-template/description-template';
|
||||
import { BaseComponent } from '@common/base/base.component';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { ToCEntry } from '../../../table-of-contents/models/toc-entry';
|
||||
import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-form-field-set',
|
||||
templateUrl: './form-field-set.component.html',
|
||||
styleUrls: ['./form-field-set.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DescriptionFormFieldSetComponent extends BaseComponent {
|
||||
|
||||
@Input() fieldSet: DescriptionTemplateFieldSet;
|
||||
@Input() propertiesFormGroup: UntypedFormGroup;
|
||||
isVisibleByVisibilityService: boolean = true;
|
||||
@Input() visibilityRulesService: VisibilityRulesService;
|
||||
|
||||
|
||||
@Input() datasetProfileId: String;
|
||||
// @Input() form: UntypedFormGroup;
|
||||
@Input() isChild: Boolean = false;
|
||||
@Input() showDelete: Boolean = false;
|
||||
@Input() tocentry: ToCEntry;
|
||||
@Input() tableRow: boolean = false;
|
||||
@Input() showTitle: boolean = true;
|
||||
@Input() placeholderTitle: boolean = false;
|
||||
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private changeDetector: ChangeDetectorRef
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.visibilityRulesService.getElementVisibilityMapObservable().pipe(takeUntil(this._destroyed)).subscribe(x => {
|
||||
if (x.has(this.fieldSet.id)) {
|
||||
this.isVisibleByVisibilityService = x.get(this.fieldSet.id);
|
||||
// this.changeDetector.markForCheck();
|
||||
}
|
||||
});
|
||||
// if (this.tocentry) {
|
||||
// this.form = this.tocentry.form as UntypedFormGroup;
|
||||
// }
|
||||
}
|
||||
|
||||
// editCompositeFieldInDialog() {
|
||||
// const dialogRef = this.dialog.open(FormCompositeFieldDialogComponent, {
|
||||
// width: '750px',
|
||||
// disableClose: true,
|
||||
// data: {
|
||||
// formGroup: cloneAbstractControl(this.form),
|
||||
// datasetProfileId: this.datasetProfileId,
|
||||
// visibilityRulesService: this.visibilityRulesService
|
||||
// }
|
||||
// });
|
||||
// dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(data => {
|
||||
// if (data) {
|
||||
// this.form.patchValue(data.value);
|
||||
// this.changeDetector.detectChanges();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// deleteCompositeField() {
|
||||
// if (this.isChild) {
|
||||
// this.deleteMultipeFieldFromCompositeFormGroup();
|
||||
// } else {
|
||||
// this.deleteCompositeFieldFormGroup();
|
||||
// }
|
||||
// }
|
||||
|
||||
// deleteCompositeFieldFormGroup() {
|
||||
|
||||
// const compositeFieldId = ((this.form.get('multiplicityItems') as UntypedFormArray).get('' + 0) as UntypedFormGroup).getRawValue().id;
|
||||
// const fieldIds = (this.form.get('fields') as UntypedFormArray).controls.map(control => control.get('id').value) as string[];
|
||||
|
||||
// const numberOfItems = this.form.get('multiplicityItems').get('' + 0).get('fields').value.length;
|
||||
// for (let i = 0; i < numberOfItems; i++) {
|
||||
// const multiplicityItem = this.form.get('multiplicityItems').get('' + 0).get('fields').get('' + i).value;
|
||||
// this.form.get('fields').get('' + i).patchValue(multiplicityItem);
|
||||
// }
|
||||
// (<UntypedFormArray>(this.form.get('multiplicityItems'))).removeAt(0);
|
||||
|
||||
|
||||
// this.visibilityRulesService.removeAllIdReferences(compositeFieldId);
|
||||
// fieldIds.forEach(x => this.visibilityRulesService.removeAllIdReferences(x));
|
||||
// }
|
||||
|
||||
// deleteMultipeFieldFromCompositeFormGroup() {
|
||||
// const parent = this.form.parent;
|
||||
// const index = (parent as UntypedFormArray).controls.indexOf(this.form);
|
||||
|
||||
// const currentId = this.form.get('id').value;
|
||||
// const fieldIds = (this.form.get('fields') as UntypedFormArray).controls.map(control => control.get('id').value) as string[];
|
||||
|
||||
|
||||
// this.visibilityRulesService.removeAllIdReferences(currentId);
|
||||
// fieldIds.forEach(x => this.visibilityRulesService.removeAllIdReferences(x));
|
||||
|
||||
// (parent as UntypedFormArray).removeAt(index);
|
||||
// (parent as UntypedFormArray).controls.forEach((control, i) => {
|
||||
// try {
|
||||
// control.get('ordinal').setValue(i);
|
||||
// } catch {
|
||||
// throw 'Could not find ordinal';
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,473 @@
|
|||
<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>
|
||||
<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">
|
||||
<i>{{fieldSet.extendedDescription}}</i>
|
||||
</h5>
|
||||
<mat-form-field *ngSwitchCase="descriptionTemplateFieldTypeEnum.FREE_TEXT" class="col-12">
|
||||
<input matInput [formControl]="propertiesFormGroup.get(field.id).get('value')" placeholder="{{(field.data.label) + (isRequired? ' *': '')}}" [required]="isRequired">
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('pattern')">{{'GENERAL.VALIDATION.URL.MESSAGE' | translate}}</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.AUTO_COMPLETE" class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<ng-container *ngIf="field.data.multiAutoComplete">
|
||||
<app-multiple-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '')}}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="multipleAutoCompleteConfiguration">
|
||||
</app-multiple-auto-complete>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(field.data.multiAutoComplete)">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '')}}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="singleAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
</ng-container>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.WORD_LIST" class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<mat-select [formControl]="propertiesFormGroup.get(field.id).get('value')" placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [required]="isRequired" [multiple]="field.data.multiList">
|
||||
<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('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.INTERNAL_DMP_ENTRIES_RESEARCHERS" class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-12" >
|
||||
<ng-container *ngIf="field.data.multiAutoComplete">
|
||||
<app-multiple-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="multipleAutoCompleteConfiguration">
|
||||
</app-multiple-auto-complete>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(field.data.multiAutoComplete)">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="singleAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
</ng-container>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.INTERNAL_DMP_ENTRIES_DATASETS" class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<ng-container *ngIf="field.data.multiAutoComplete">
|
||||
<app-multiple-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="multipleAutoCompleteConfiguration">
|
||||
</app-multiple-auto-complete>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(field.data.multiAutoComplete)">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="singleAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
</ng-container>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.INTERNAL_DMP_ENTRIES_DMPS" class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<ng-container *ngIf="field.data.multiAutoComplete">
|
||||
<app-multiple-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="multipleAutoCompleteConfiguration">
|
||||
</app-multiple-auto-complete>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(field.data.multiAutoComplete)">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="singleAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
</ng-container>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.CHECK_BOX" class="col-12">
|
||||
<mat-checkbox [formControl]="propertiesFormGroup.get(field.id).get('value')" [required]="isRequired">
|
||||
{{field.data.label}}</mat-checkbox>
|
||||
</div>
|
||||
<mat-form-field *ngSwitchCase="descriptionTemplateFieldTypeEnum.TEXT_AREA" class="col-12">
|
||||
<textarea matInput class="text-area" [formControl]="propertiesFormGroup.get(field.id).get('value')" matTextareaAutosize matAutosizeMinRows="3" matAutosizeMaxRows="15" [required]="isRequired"
|
||||
placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}"></textarea>
|
||||
<button mat-icon-button type="button" *ngIf="!propertiesFormGroup.get(field.id).get('value').disabled && propertiesFormGroup.get(field.id).get('value').value" matSuffix aria-label="Clear" (click)="this.propertiesFormGroup.get(field.id).get('value').patchValue('')">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value')['errors'] && propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</mat-form-field>
|
||||
<ng-container *ngSwitchCase="descriptionTemplateFieldTypeEnum.RICH_TEXT_AREA">
|
||||
<rich-text-editor-component class="col-12"
|
||||
[parentFormGroup]="propertiesFormGroup.get(field.id)" [controlName]="'value'"
|
||||
[placeholder]="field.data.label"
|
||||
[required]="isRequired"
|
||||
[wrapperClasses]="'full-width editor ' +
|
||||
((isRequired && propertiesFormGroup.get(field.id).get('value').touched && propertiesFormGroup.get(field.id).get('value').hasError('required')) ? 'required' : '')"
|
||||
[editable]="!propertiesFormGroup.get(field.id).get('value').disabled">
|
||||
</rich-text-editor-component>
|
||||
<div [class]="(propertiesFormGroup.get(field.id).get('value')['errors'] && propertiesFormGroup.get(field.id).get('value').hasError('required') && propertiesFormGroup.get(field.id).get('value').touched) ? 'visible' : 'invisible'" class="col-12">
|
||||
<div class="mat-form-field form-field-subscript-wrapper">
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value')['errors'] && propertiesFormGroup.get(field.id).get('value').hasError('required') && propertiesFormGroup.get(field.id).get('value').touched">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</div>
|
||||
</div>
|
||||
</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('value').disabled">
|
||||
<ngx-dropzone-preview *ngIf="propertiesFormGroup.get(field.id).get('value').value && propertiesFormGroup.get(field.id).get('value').value.name" class="file-preview"
|
||||
[removable]="true" (removed)="onRemove()">
|
||||
<ngx-dropzone-label class="file-label">{{ propertiesFormGroup.get(field.id).get('value').value.name }}</ngx-dropzone-label>
|
||||
</ngx-dropzone-preview>
|
||||
</ngx-dropzone>
|
||||
</div>
|
||||
<div class="col-12 d-flex justify-content-center attach-btn">
|
||||
<button *ngIf="!propertiesFormGroup.get(field.id).get('value').value || filesToUpload" mat-button (click)="drop.showFileSelector()" type="button" class="attach-file-btn"
|
||||
[disabled]="!!propertiesFormGroup.get(field.id).get('value').value || propertiesFormGroup.get(field.id).get('value').disabled">
|
||||
<mat-icon class="mr-2">upload</mat-icon>
|
||||
<mat-label>{{ (field.data.label | translate)}}</mat-label>
|
||||
</button>
|
||||
|
||||
<button *ngIf="propertiesFormGroup.get(field.id).get('value').value && !filesToUpload" mat-button (click)="download()" type="button" class="attach-file-btn"
|
||||
[disabled]="propertiesFormGroup.get(field.id).get('value').disabled">
|
||||
<mat-icon class="mr-2">download</mat-icon>
|
||||
<mat-label>{{ "TYPES.DATASET-PROFILE-UPLOAD-TYPE.DOWNLOAD" | translate }}</mat-label>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.BOOLEAN_DECISION" class="col-12">
|
||||
<mat-radio-group [formControl]="propertiesFormGroup.get(field.id).get('value')" [required]="isRequired">
|
||||
<mat-radio-button class="radio-button-item" name="{{propertiesFormGroup.get(field.id).get('key').value}}" value="true">{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.ACTIONS.YES" | translate }}</mat-radio-button>
|
||||
<mat-radio-button class="radio-button-item" name="{{propertiesFormGroup.get(field.id).get('key').value}}" value="false">{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.ACTIONS.NO" | translate }}</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
<small class="text-danger d-block" *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required') && propertiesFormGroup.get(field.id).get('value').touched">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</small>
|
||||
<small class="text-muted d-inline-block" *ngIf="(isRequired) && !propertiesFormGroup.get(field.id).get('value').touched">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</small>
|
||||
</div>
|
||||
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.RADIO_BOX" class="col-12">
|
||||
<mat-radio-group [formControl]="propertiesFormGroup.get(field.id).get('value')" [required]="isRequired">
|
||||
<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-group>
|
||||
<small class="text-danger d-block" *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required') && propertiesFormGroup.get(field.id).get('value').touched">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</small>
|
||||
<small class="text-muted d-inline-block" *ngIf="(isRequired) && !propertiesFormGroup.get(field.id).get('value').touched">{{'GENERAL.VALIDATION.REQUIRED' | translate}} *</small>
|
||||
</div>
|
||||
|
||||
<mat-form-field *ngSwitchCase="descriptionTemplateFieldTypeEnum.DATE_PICKER" class="col-12">
|
||||
<input matInput placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" class="table-input" [matDatepicker]="date" [required]="isRequired"
|
||||
[formControl]="propertiesFormGroup.get(field.id).get('value')">
|
||||
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
|
||||
<mat-datepicker #date></mat-datepicker>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">
|
||||
{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.EXTERNAL_DATASETS" class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<ng-container *ngIf="field.data.multiAutoComplete">
|
||||
<app-multiple-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="externalDatasetAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-multiple-auto-complete>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(field.data.multiAutoComplete)">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="externalDatasetAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
</ng-container>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.DATA_REPOSITORIES" class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<ng-container *ngIf="field.data.multiAutoComplete">
|
||||
<app-multiple-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="dataRepositoriesAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-multiple-auto-complete>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(field.data.multiAutoComplete)">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="dataRepositoriesAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
</ng-container>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.PUB_REPOSITORIES" class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<ng-container *ngIf="field.data.multiAutoComplete">
|
||||
<app-multiple-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="pubRepositoriesAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-multiple-auto-complete>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(field.data.multiAutoComplete)">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="pubRepositoriesAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
</ng-container>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.JOURNAL_REPOSITORIES" class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<ng-container *ngIf="field.data.multiAutoComplete">
|
||||
<app-multiple-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="journalRepositoriesAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-multiple-auto-complete>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(field.data.multiAutoComplete)">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="journalRepositoriesAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
</ng-container>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.TAXONOMIES" class="col-12">
|
||||
<div *ngIf="field.data" class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<ng-container *ngIf="field.data.multiAutoComplete">
|
||||
<app-multiple-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="taxonomiesAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-multiple-auto-complete>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(field.data.multiAutoComplete)">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="taxonomiesAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
</ng-container>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.LICENSES" class="col-12">
|
||||
<div *ngIf="field.data" class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<ng-container *ngIf="field.data.multiAutoComplete">
|
||||
<app-multiple-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="licensesAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-multiple-auto-complete>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(field.data.multiAutoComplete)">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="licensesAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
</ng-container>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.PUBLICATIONS" class="col-12">
|
||||
<div *ngIf="field.data" class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<ng-container *ngIf="field.data.multiAutoComplete">
|
||||
<app-multiple-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="publicationsAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-multiple-auto-complete>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(field.data.multiAutoComplete)">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="publicationsAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
</ng-container>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.REGISTRIES" class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<ng-container *ngIf="field.data.multiAutoComplete">
|
||||
<app-multiple-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="registriesAutoCompleteConfiguration">
|
||||
</app-multiple-auto-complete>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(field.data.multiAutoComplete)">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="registriesAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
</ng-container>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.SERVICES" class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<ng-container *ngIf="field.data.multiAutoComplete">
|
||||
<app-multiple-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="servicesAutoCompleteConfiguration">
|
||||
</app-multiple-auto-complete>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(field.data.multiAutoComplete)">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="servicesAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
</ng-container>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.TAGS" class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<app-multiple-auto-complete [configuration]="tagsAutoCompleteConfiguration" [formControl]="propertiesFormGroup.get(field.id).get('value')" placeholder="{{('DATASET-EDITOR.FIELDS.TAGS' | translate) + (isRequired? ' *': '')}}"></app-multiple-auto-complete>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.RESEARCHERS" class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<ng-container *ngIf="field.data.multiAutoComplete">
|
||||
<app-multiple-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="researchersAutoCompleteConfiguration">
|
||||
</app-multiple-auto-complete>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(field.data.multiAutoComplete)">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="researchersAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
</ng-container>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.ORGANIZATIONS" class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<ng-container *ngIf="field.data.multiAutoComplete">
|
||||
<app-multiple-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="organisationsAutoCompleteConfiguration">
|
||||
</app-multiple-auto-complete>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!(field.data.multiAutoComplete)">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="organisationsAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
</ng-container>
|
||||
|
||||
<mat-hint>{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.DATASET_IDENTIFIER" class="col-12">
|
||||
<div class="row" *ngIf="datasetIdInitialized">
|
||||
<mat-form-field class="col-md-12">
|
||||
<input matInput class="col-md-12" [formControl]="getDatasetIdControl('identifier')" placeholder="{{(field.data.label) + (isRequired? ' *': '')}}"
|
||||
[required]="isRequired" [disabled]="propertiesFormGroup.get(field.id).get('value').disabled">
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="col-md-12">
|
||||
<mat-select class="col-md-12" [formControl]="getDatasetIdControl('type')" [placeholder]="('TYPES.DATASET-PROFILE-IDENTIFIER.IDENTIFIER-TYPE' | translate) + (isRequired? ' *': '')"
|
||||
[disabled]="propertiesFormGroup.get(field.id).get('value').disabled">
|
||||
<mat-option *ngFor="let type of datasetIdTypes" [value]="type.value">
|
||||
{{ type.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.CURRENCY" class="col-12">
|
||||
<div class="row">
|
||||
<mat-form-field class="col-md-12">
|
||||
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup.get(field.id).get('value')"
|
||||
[configuration]="currencyAutoCompleteConfiguration" [required]="isRequired">
|
||||
</app-single-auto-complete>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.VALIDATION" class="col-12">
|
||||
<div class="row align-items-baseline">
|
||||
<mat-form-field class="col-md-4">
|
||||
<input matInput class="col-md-12" [formControl]="getDatasetIdControl('identifier')" placeholder="{{(field.data.label) + (isRequired? ' *': '')}}" [required]="isRequired">
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="col-md-4">
|
||||
<mat-select class="col-md-12" [formControl]="getDatasetIdControl('type')" [placeholder]="('TYPES.DATASET-PROFILE-VALIDATOR.REPOSITORIES-PLACEHOLDER' | translate) + (isRequired? ' *': '')">
|
||||
<mat-option *ngFor="let type of validationTypes" [value]="type.value">
|
||||
{{ type.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<div class="col-md-2">
|
||||
<button type="button" mat-button class="lightblue-btn" (click)="validateId()" [disabled]="propertiesFormGroup.get(field.id).get('value').disabled">{{ "TYPES.DATASET-PROFILE-VALIDATOR.ACTION" | translate }}</button>
|
||||
<mat-error *ngIf="propertiesFormGroup.get(field.id).get('value').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}
|
||||
</mat-error>
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
<mat-progress-spinner *ngIf="validationIcon === 'loading'" mode="indeterminate" [diameter]="24"></mat-progress-spinner>
|
||||
<mat-icon *ngIf="validationIcon !== 'loading'" [ngClass]="{'success': validationIcon === 'done', 'fail': validationIcon === 'clear'}">{{validationIcon}}</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,105 @@
|
|||
.dynamic-form-field {
|
||||
.radio-button-item {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.text-area {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.success {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.fail {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .mat-form-field-appearance-outline .mat-form-field-outline {
|
||||
background: #fafafa !important;
|
||||
}
|
||||
|
||||
::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix {
|
||||
font-size: 1rem;
|
||||
padding: 0.6em 0 1em 0 !important;
|
||||
}
|
||||
|
||||
|
||||
.attach-btn {
|
||||
top: -20px;
|
||||
}
|
||||
|
||||
.attach-file-btn {
|
||||
min-width: 156px;
|
||||
height: 44px;
|
||||
color: #ffffff;
|
||||
background: var(--primary-color) 0% 0% no-repeat padding-box;
|
||||
box-shadow: 0px 3px 6px #1e202029;
|
||||
border-radius: 30px;
|
||||
}
|
||||
|
||||
.attach-file-btn:hover {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.attach-file-btn.mdc-button-disabled, .attach-file-btn.mdc-button-disabled:hover {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid darkgray;
|
||||
color: darkgrey !important;
|
||||
}
|
||||
//
|
||||
//.mdc-button-disabled .attach-file-btn > ::ng-deep mdc-button-wrapper:hover > * {
|
||||
// color: darkgrey !important;
|
||||
//}
|
||||
|
||||
.drop-file {
|
||||
background-color: #fafafa;
|
||||
border: 1px dashed #d1d1d1;
|
||||
border-radius: 4px;
|
||||
//max-width: 480px;
|
||||
height: 98px;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.file-preview {
|
||||
height: auto !important;
|
||||
width: auto !important;
|
||||
max-width: 500px !important;
|
||||
min-height: 1rem !important;
|
||||
|
||||
background-color: #e0e0e0 !important;
|
||||
background-image: none !important;
|
||||
color: rgba(0, 0, 0, 0.87) !important;
|
||||
font-weight: 500 !important;
|
||||
border-radius: 24px !important;
|
||||
line-height: 1.25 !important;
|
||||
}
|
||||
|
||||
.file-label {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
::ng-deep ngx-dropzone-remove-badge {
|
||||
opacity: 1 !important;
|
||||
margin-left: .5rem !important;
|
||||
position: initial !important;
|
||||
}
|
||||
|
||||
::ng-deep .upload-form .mat-form-field-appearance-outline .mat-form-field-outline {
|
||||
background: #fafafa !important;
|
||||
}
|
||||
|
||||
::ng-deep .upload-form .mat-form-field-appearance-outline .mat-form-field-infix {
|
||||
font-size: 1rem;
|
||||
padding: 0.6em 0 1em 0 !important;
|
||||
}
|
|
@ -0,0 +1,764 @@
|
|||
|
||||
import { COMMA, ENTER } from '@angular/cdk/keycodes';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, SimpleChanges } from '@angular/core';
|
||||
import { FormControl, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { DescriptionTemplateFieldType } from '@app/core/common/enum/description-template-field-type';
|
||||
import { ReferenceType } from '@app/core/common/enum/reference-type';
|
||||
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
|
||||
import { DescriptionTemplateAutoCompleteData, DescriptionTemplateAutoCompleteSingleData, DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplateUploadData, DescriptionTemplateWordListData } from '@app/core/model/description-template/description-template';
|
||||
import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item';
|
||||
import { LocalFetchModel } from '@app/core/model/local-fetch/local-fetch.model';
|
||||
import { FetcherReference, Reference } from '@app/core/model/reference/reference';
|
||||
import { DatasetExternalAutocompleteCriteria, DatasetExternalAutocompleteOptionsCriteria } from '@app/core/query/dataset/daatset-external-autocomplete-criteria';
|
||||
import { DatasetCriteria } from '@app/core/query/dataset/dataset-criteria';
|
||||
import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria';
|
||||
import { ReferenceSearchLookup } from '@app/core/query/reference-search.lookup';
|
||||
import { RegistryCriteria } from '@app/core/query/registry/registry-criteria';
|
||||
import { RequestItem } from '@app/core/query/request-item';
|
||||
import { ResearcherCriteria } from '@app/core/query/researcher/researcher-criteria';
|
||||
import { ServiceCriteria } from '@app/core/query/service/service-criteria';
|
||||
import { TagCriteria } from '@app/core/query/tag/tag-criteria';
|
||||
import { TaxonomyCriteria } from "@app/core/query/taxonomy/taxonomy-criteria";
|
||||
import { CurrencyService } from '@app/core/services/currency/currency.service';
|
||||
import { DatasetExternalAutocompleteService } from '@app/core/services/dataset/dataset-external-autocomplete.service';
|
||||
import { DatasetService } from '@app/core/services/dataset/dataset.service';
|
||||
import { DmpService } from '@app/core/services/dmp/dmp.service';
|
||||
import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service';
|
||||
import { FileService } from "@app/core/services/file/file.service";
|
||||
import {
|
||||
SnackBarNotificationLevel,
|
||||
UiNotificationService
|
||||
} from "@app/core/services/notification/ui-notification-service";
|
||||
import { ReferenceService } from '@app/core/services/reference/reference.service';
|
||||
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
|
||||
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
|
||||
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
|
||||
import { ExternalTagEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model';
|
||||
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
||||
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
|
||||
import { BaseComponent } from '@common/base/base.component';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators';
|
||||
import { DescriptionFieldEditorModel } from '../../../description-editor.model';
|
||||
import { DescriptionTemplateFieldValidationType } from '@app/core/common/enum/description-template-field-validation-type';
|
||||
|
||||
@Component({
|
||||
selector: 'app-form-field',
|
||||
templateUrl: './form-field.component.html',
|
||||
styleUrls: ['./form-field.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DescriptionFormFieldComponent extends BaseComponent implements OnInit {
|
||||
|
||||
@Input() field: DescriptionTemplateField;
|
||||
@Input() fieldSet: DescriptionTemplateFieldSet;
|
||||
@Input() propertiesFormGroup: UntypedFormGroup;
|
||||
@Input() visibilityRulesService: VisibilityRulesService;
|
||||
isRequired: boolean = false;
|
||||
|
||||
|
||||
// @Input() field: Field;
|
||||
// @Input() form: UntypedFormGroup;
|
||||
@Input() datasetProfileId: any;
|
||||
@Input() isChild: Boolean = false;
|
||||
autocompleteOptions: DescriptionTemplateAutoCompleteSingleData[];
|
||||
|
||||
visible: boolean = true;
|
||||
|
||||
// change: Subscription;
|
||||
// trackByFn = (index, item) => item ? item['id'] : null;
|
||||
|
||||
descriptionTemplateFieldTypeEnum = DescriptionTemplateFieldType;
|
||||
|
||||
|
||||
|
||||
public singleAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
||||
public multipleAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
|
||||
|
||||
externalDatasetAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
||||
dataRepositoriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
||||
pubRepositoriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
||||
journalRepositoriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
||||
taxonomiesAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
||||
licensesAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
||||
publicationsAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
||||
registriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
||||
servicesAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
||||
tagsAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
||||
researchersAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
|
||||
organisationsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
|
||||
currencyAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
||||
|
||||
readonly separatorKeysCodes: number[] = [ENTER, COMMA];
|
||||
|
||||
tags: ExternalTagEditorModel[] = [];
|
||||
|
||||
datasetIdInitialized: boolean = false;
|
||||
|
||||
validationIcon;
|
||||
|
||||
readonly datasetIdTypes: any[] = [
|
||||
{ name: 'Handle', value: 'handle' },
|
||||
{ name: 'DOI', value: 'doi' },
|
||||
{ name: 'Ark', value: 'ark' },
|
||||
{ name: 'Url', value: 'url' },
|
||||
{ name: 'Other', value: 'other' }
|
||||
];
|
||||
|
||||
|
||||
readonly validationTypes: any[] = [
|
||||
{ name: 'Zenodo', value: 'zenodo' }
|
||||
];
|
||||
|
||||
filesToUpload: FileList;
|
||||
|
||||
constructor(
|
||||
private datasetExternalAutocompleteService: DatasetExternalAutocompleteService,
|
||||
private externalSourcesService: ExternalSourcesService,
|
||||
private language: TranslateService,
|
||||
private datasetService: DatasetService,
|
||||
private dmpService: DmpService,
|
||||
private currencyService: CurrencyService,
|
||||
private fileService: FileService,
|
||||
private cdr: ChangeDetectorRef,
|
||||
private uiNotificationService: UiNotificationService,
|
||||
public dialog: MatDialog,
|
||||
private fileUtils: FileUtils,
|
||||
private referenceService: ReferenceService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['form']) {
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
this.visibilityRulesService.getElementVisibilityMapObservable().pipe(takeUntil(this._destroyed)).subscribe(x => {
|
||||
if (x.has(this.field.id)){
|
||||
this.visible = x.get(this.field.id);
|
||||
}
|
||||
});
|
||||
|
||||
//TODO: validate that this logic is correct. Validation contenxt path might need to be fixed.
|
||||
if (this.propertiesFormGroup.get(this.field.id).get('value') == null) {
|
||||
const item: DescriptionFieldEditorModel = new DescriptionFieldEditorModel();
|
||||
item.key = this.field.id;
|
||||
this.propertiesFormGroup.addControl(this.field.id, item.buildForm());
|
||||
}
|
||||
|
||||
if (this.propertiesFormGroup.get(this.field.id).get('value').value) {
|
||||
this.visibilityRulesService.updateValueAndVisibility(this.field?.id, this.propertiesFormGroup.get(this.field.id).get('value').value);
|
||||
}
|
||||
|
||||
this.isRequired = this.field.validations?.includes(DescriptionTemplateFieldValidationType.Required);
|
||||
|
||||
if (this.field?.data?.fieldType === DescriptionTemplateFieldType.WORD_LIST) {
|
||||
if ((this.field.data as DescriptionTemplateWordListData).multiList) {
|
||||
const originalValue = <string>this.propertiesFormGroup.get(this.field.id).get('value').value;
|
||||
if (originalValue !== null && typeof originalValue === 'string') {
|
||||
let values = (<string>this.propertiesFormGroup.get(this.field.id).get('value').value).slice(1, -1).split(', ').filter((value) => !value.includes('"'));
|
||||
let specialValue = (<string>this.propertiesFormGroup.get(this.field.id).get('value').value).split('"').filter((value) => !value.startsWith('[') && !value.endsWith(']') && !values.includes(value) && value !== ', ');
|
||||
specialValue.forEach(value => values.push(value));
|
||||
if (!originalValue.startsWith('[') && !originalValue.endsWith(']')) {
|
||||
values = undefined;
|
||||
values = [originalValue];
|
||||
}
|
||||
this.propertiesFormGroup.get(this.field.id).get('value').patchValue(values);
|
||||
values.forEach(element => {
|
||||
this.visibilityRulesService.updateValueAndVisibility(this.field?.id, element);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup autocomplete configuration if needed
|
||||
if (this.field?.data?.fieldType === DescriptionTemplateFieldType.AUTO_COMPLETE) {
|
||||
if (!((this.field.data as DescriptionTemplateAutoCompleteData).multiAutoComplete)) {
|
||||
this.singleAutoCompleteConfiguration = {
|
||||
filterFn: this.searchFromAutocomplete.bind(this),
|
||||
initialItems: () => this.searchFromAutocomplete(''),
|
||||
displayFn: (item) => { try { return (item != null && item.length > 1) ? JSON.parse(item).label : item['label'] } catch { return '' } },
|
||||
titleFn: (item) => { try { return item['label'] } catch { return '' } },
|
||||
valueAssign: (item) => { try { return JSON.stringify(item) } catch { return '' } },
|
||||
subtitleFn: (item) => { try { return item['source'] ? this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-SUBTITLE') + item['source'] : this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-NO-SOURCE') } catch { return '' } }
|
||||
};
|
||||
}
|
||||
else {
|
||||
this.multipleAutoCompleteConfiguration = {
|
||||
filterFn: this.searchFromAutocomplete.bind(this),
|
||||
initialItems: () => this.searchFromAutocomplete(''),
|
||||
displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label'] } catch { return '' } },
|
||||
titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label'] } catch { return '' } },
|
||||
valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } },
|
||||
subtitleFn: (item) => { try { return item['source'] ? this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-SUBTITLE') + item['source'] : this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-NO-SOURCE') } catch { return '' } }
|
||||
}
|
||||
}
|
||||
if (isNullOrUndefined(this.datasetProfileId)) {
|
||||
this.autocompleteOptions = (this.field.data as DescriptionTemplateAutoCompleteData).autoCompleteSingleDataList;
|
||||
}
|
||||
}
|
||||
|
||||
switch (this.field?.data?.fieldType) {
|
||||
case DescriptionTemplateFieldType.EXTERNAL_DATASETS:
|
||||
this.externalDatasetAutoCompleteConfiguration = {
|
||||
filterFn: this.searchDatasetExternalDatasets.bind(this),
|
||||
initialItems: () => this.searchDatasetExternalDatasets(''),//.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1),
|
||||
displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } },
|
||||
valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
|
||||
};
|
||||
break;
|
||||
case DescriptionTemplateFieldType.DATA_REPOSITORIES:
|
||||
this.dataRepositoriesAutoCompleteConfiguration = {
|
||||
filterFn: this.searchDatasetExternalDataRepositories.bind(this),
|
||||
initialItems: () => this.searchDatasetExternalDataRepositories(''),
|
||||
displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } },
|
||||
valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
|
||||
};
|
||||
break;
|
||||
case DescriptionTemplateFieldType.PUB_REPOSITORIES:
|
||||
this.pubRepositoriesAutoCompleteConfiguration = {
|
||||
filterFn: this.searchDatasetExternalPubRepositories.bind(this),
|
||||
initialItems: () => this.searchDatasetExternalPubRepositories(''),
|
||||
displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } },
|
||||
valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
|
||||
};
|
||||
break;
|
||||
case DescriptionTemplateFieldType.JOURNAL_REPOSITORIES:
|
||||
this.journalRepositoriesAutoCompleteConfiguration = {
|
||||
filterFn: this.searchDatasetExternalJournalRepositories.bind(this),
|
||||
initialItems: () => this.searchDatasetExternalJournalRepositories(''),
|
||||
displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } },
|
||||
valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
|
||||
};
|
||||
break;
|
||||
case DescriptionTemplateFieldType.TAXONOMIES:
|
||||
this.taxonomiesAutoCompleteConfiguration = {
|
||||
filterFn: this.searchDatasetExternalTaxonomies.bind(this),
|
||||
initialItems: () => this.searchDatasetExternalTaxonomies(''),
|
||||
displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } },
|
||||
valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
|
||||
};
|
||||
break;
|
||||
case DescriptionTemplateFieldType.LICENSES:
|
||||
this.licensesAutoCompleteConfiguration = {
|
||||
filterFn: this.searchDatasetExternalLicences.bind(this),
|
||||
initialItems: () => this.searchDatasetExternalLicences(''),
|
||||
displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } },
|
||||
valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
|
||||
};
|
||||
break;
|
||||
case DescriptionTemplateFieldType.PUBLICATIONS:
|
||||
this.publicationsAutoCompleteConfiguration = {
|
||||
filterFn: this.searchDatasetExternalPublications.bind(this),
|
||||
initialItems: () => this.searchDatasetExternalPublications(''),
|
||||
displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } },
|
||||
valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
|
||||
};
|
||||
break;
|
||||
case DescriptionTemplateFieldType.REGISTRIES:
|
||||
this.registriesAutoCompleteConfiguration = {
|
||||
filterFn: this.searchDatasetExternalRegistries.bind(this),
|
||||
initialItems: () => this.searchDatasetExternalRegistries(''),
|
||||
displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } },
|
||||
valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
|
||||
};
|
||||
break;
|
||||
case DescriptionTemplateFieldType.SERVICES:
|
||||
this.servicesAutoCompleteConfiguration = {
|
||||
filterFn: this.searchDatasetExternalServices.bind(this),
|
||||
initialItems: () => this.searchDatasetExternalServices(''),
|
||||
displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } },
|
||||
valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
|
||||
};
|
||||
break;
|
||||
case DescriptionTemplateFieldType.TAGS:
|
||||
this.tagsAutoCompleteConfiguration = {
|
||||
filterFn: this.filterTags.bind(this),
|
||||
initialItems: (excludedItems: any[]) => this.filterTags('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
|
||||
displayFn: (item) => { try { return this.showTag(item) } catch { return '' } },
|
||||
titleFn: (item) => { try { return item['name'] } catch { return '' } },
|
||||
valueAssign: (item) => { try { return this.addTag(item) } catch { return '' } }
|
||||
};
|
||||
this.parseTags();
|
||||
break;
|
||||
case DescriptionTemplateFieldType.RESEARCHERS:
|
||||
this.researchersAutoCompleteConfiguration = {
|
||||
filterFn: this.filterResearchers.bind(this),
|
||||
initialItems: (excludedItems: any[]) => this.filterResearchers('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
|
||||
displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
subtitleFn: (item) => { try { return item['tag'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')) } catch { return '' } },
|
||||
valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
|
||||
};
|
||||
break;
|
||||
case DescriptionTemplateFieldType.ORGANIZATIONS:
|
||||
this.organisationsAutoCompleteConfiguration = {
|
||||
filterFn: this.filterOrganisations.bind(this),
|
||||
initialItems: (excludedItems: any[]) => this.filterOrganisations('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
|
||||
displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
subtitleFn: (item) => { try { return item['tag'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')) } catch { return '' } },
|
||||
valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
|
||||
};
|
||||
break;
|
||||
case DescriptionTemplateFieldType.DATASET_IDENTIFIER:
|
||||
const value = this.propertiesFormGroup.get(this.field.id).get('value').value;
|
||||
const disabled = this.propertiesFormGroup.get(this.field.id).disabled;
|
||||
//TODO: Refactor this.
|
||||
// this.form.removeControl('value');
|
||||
// this.form.addControl('value', new DatasetIdModel(value).buildForm());
|
||||
// if (disabled) {
|
||||
// this.form.disable();
|
||||
// }
|
||||
this.datasetIdInitialized = true;
|
||||
break;
|
||||
case DescriptionTemplateFieldType.CURRENCY:
|
||||
this.currencyAutoCompleteConfiguration = {
|
||||
filterFn: this.searchCurrency.bind(this),
|
||||
initialItems: () => this.searchCurrency(''),
|
||||
displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
|
||||
valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
|
||||
};
|
||||
break;
|
||||
case DescriptionTemplateFieldType.VALIDATION:
|
||||
const value1 = this.propertiesFormGroup.get(this.field.id).get('value').value;
|
||||
const disabled1 = this.propertiesFormGroup.get(this.field.id).disabled;
|
||||
//TODO: Refactor this.
|
||||
// this.form.removeControl('value');
|
||||
// this.form.addControl('value', new DatasetIdModel(value1).buildForm());
|
||||
// if (disabled1) {
|
||||
// this.form.disable();
|
||||
// }
|
||||
break;
|
||||
case DescriptionTemplateFieldType.INTERNAL_DMP_ENTRIES_RESEARCHERS:
|
||||
this.makeAutocompleteConfiguration(this.searchResearchers.bind(this), "name", "tag");
|
||||
break;
|
||||
case DescriptionTemplateFieldType.INTERNAL_DMP_ENTRIES_DATASETS:
|
||||
this.makeAutocompleteConfiguration(this.searchDatasets.bind(this), "label");
|
||||
break;
|
||||
case DescriptionTemplateFieldType.INTERNAL_DMP_ENTRIES_DMPS:
|
||||
this.makeAutocompleteConfiguration(this.searchDmps.bind(this), "label");
|
||||
break;
|
||||
}
|
||||
|
||||
// this.form = this.visibilityRulesService.getFormGroup(this.field.id);
|
||||
this.propertiesFormGroup.get(this.field.id).get('value').valueChanges
|
||||
.pipe(
|
||||
takeUntil(this._destroyed),
|
||||
distinctUntilChanged()
|
||||
)
|
||||
.subscribe(item => {
|
||||
// if (this.field?.data?.fieldType === DescriptionTemplateFieldType.ComboBox && this.form.get('data').value.type === DatasetProfileComboBoxType.WordList && this.form.get('data').value.multiList) {
|
||||
// item.forEach(element => {
|
||||
// this.visibilityRulesService.updateValueAndVisibility(this.field?.id, element);
|
||||
// });
|
||||
|
||||
// } else {
|
||||
this.visibilityRulesService.updateValueAndVisibility(this.field?.id, item);
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
// _optionRemove(event) {
|
||||
// const array = JSON.parse(this.propertiesFormGroup.get(this.field.id).get('value').value);
|
||||
// if (array) {
|
||||
// const index = array.map(x => x.id).indexOf(event.id);
|
||||
// if (index >= 0) {
|
||||
// array.splice(index, 1);
|
||||
// }
|
||||
// this.propertiesFormGroup.get(this.field.id).get('value').patchValue(JSON.stringify(array));
|
||||
// }
|
||||
// }
|
||||
|
||||
searchFromAutocomplete(query: string) {
|
||||
|
||||
if (this.autocompleteOptions) {
|
||||
const autocompleteRequestItem: RequestItem<DatasetExternalAutocompleteOptionsCriteria> = new RequestItem();
|
||||
autocompleteRequestItem.criteria = new DatasetExternalAutocompleteOptionsCriteria();
|
||||
//TODO: refactor this
|
||||
//autocompleteRequestItem.criteria.autoCompleteSingleDataList = this.autocompleteOptions;
|
||||
autocompleteRequestItem.criteria.like = query;
|
||||
return this.datasetExternalAutocompleteService.queryApi(autocompleteRequestItem);
|
||||
}
|
||||
else {
|
||||
const autocompleteRequestItem: RequestItem<DatasetExternalAutocompleteCriteria> = new RequestItem();
|
||||
autocompleteRequestItem.criteria = new DatasetExternalAutocompleteCriteria();
|
||||
let parseIdArray: string[] = this.field?.id.split('_');
|
||||
if (parseIdArray.length > 1) {
|
||||
autocompleteRequestItem.criteria.fieldID = parseIdArray[parseIdArray.length - 1];
|
||||
} else {
|
||||
autocompleteRequestItem.criteria.fieldID = this.field?.id;
|
||||
}
|
||||
if (typeof this.datasetProfileId === 'string') {
|
||||
autocompleteRequestItem.criteria.profileID = this.datasetProfileId;
|
||||
}
|
||||
else if (this.datasetProfileId != null) {
|
||||
autocompleteRequestItem.criteria.profileID = this.datasetProfileId.id;
|
||||
}
|
||||
autocompleteRequestItem.criteria.like = query;
|
||||
return this.datasetExternalAutocompleteService.queryAutocomplete(autocompleteRequestItem);
|
||||
}
|
||||
}
|
||||
|
||||
searchResearchers(query: string) {
|
||||
const reasearcherAutocompleteRequestItem: RequestItem<ResearcherCriteria> = new RequestItem();
|
||||
reasearcherAutocompleteRequestItem.criteria = new ResearcherCriteria;
|
||||
reasearcherAutocompleteRequestItem.criteria.name = query;
|
||||
return this.externalSourcesService.searchDMPResearchers(reasearcherAutocompleteRequestItem);
|
||||
}
|
||||
|
||||
searchDatasets(query: string) {
|
||||
let fields: Array<string> = new Array();
|
||||
const datasetsAutocompleteRequestItem: DataTableRequest<DatasetCriteria> = new DataTableRequest(0, 25, { fields: fields });
|
||||
datasetsAutocompleteRequestItem.criteria = new DatasetCriteria();
|
||||
datasetsAutocompleteRequestItem.criteria.like = query;
|
||||
return this.datasetService.getPaged(datasetsAutocompleteRequestItem).pipe(map(item => item.data));
|
||||
}
|
||||
|
||||
searchDmps(query: string) {
|
||||
let fields: Array<string> = new Array();
|
||||
const dmpsAutocompleteRequestItem: DataTableRequest<DmpCriteria> = new DataTableRequest(0, 25, { fields: fields });
|
||||
dmpsAutocompleteRequestItem.criteria = new DmpCriteria();
|
||||
dmpsAutocompleteRequestItem.criteria.like = query;
|
||||
return this.dmpService.getPaged(dmpsAutocompleteRequestItem).pipe(map(item => item.data));
|
||||
}
|
||||
|
||||
makeAutocompleteConfiguration(myfunc: Function, title: string, subtitle?: string): void {
|
||||
if (!((this.field.data as DescriptionTemplateAutoCompleteData).multiAutoComplete)) {
|
||||
this.singleAutoCompleteConfiguration = {
|
||||
filterFn: myfunc.bind(this),
|
||||
initialItems: (extraData) => myfunc(''),
|
||||
displayFn: (item) => { try { return (item != null && item.length > 1) ? JSON.parse(item)[title] : item[title] } catch { return '' } },
|
||||
titleFn: (item) => { try { return item[title] } catch { return '' } },
|
||||
valueAssign: (item) => JSON.stringify(item),
|
||||
subtitleFn: (item) => { try { return item[subtitle] } catch { return '' } }
|
||||
};
|
||||
}
|
||||
else {
|
||||
this.multipleAutoCompleteConfiguration = {
|
||||
filterFn: myfunc.bind(this),
|
||||
initialItems: (extraData) => myfunc(''),
|
||||
displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)[title] : item[title] } catch { return '' } },
|
||||
titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)[title] : item[title] } catch { return '' } },
|
||||
valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } },
|
||||
subtitleFn: (item) => { try { return item[subtitle] } catch { return '' } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
searchDatasetExternalDatasets(query: string): Observable<Reference[]> {
|
||||
// const requestItem: RequestItem<ExternalDatasetCriteria> = new RequestItem();
|
||||
// requestItem.criteria = new ExternalDatasetCriteria();
|
||||
// requestItem.criteria.like = query;
|
||||
// requestItem.criteria.type = '';
|
||||
// //return this.externalSourcesService.searchDatasetSExternalDatasetservice(requestItem);
|
||||
// return this.externalSourcesService.listExternal(ReferenceType.Datasets, requestItem.criteria.like, requestItem.criteria.type);
|
||||
const lookup = new ReferenceSearchLookup();
|
||||
lookup.like = query;
|
||||
lookup.key = '';
|
||||
lookup.type = ReferenceType.Datasets;
|
||||
return this.referenceService.search(lookup);
|
||||
}
|
||||
|
||||
searchDatasetExternalDataRepositories(query: string): Observable<Reference[]> {
|
||||
// const requestItem: RequestItem<DataRepositoryCriteria> = new RequestItem();
|
||||
// requestItem.criteria = new DataRepositoryCriteria();
|
||||
// requestItem.criteria.like = query;
|
||||
// requestItem.criteria.type = '';
|
||||
// return this.externalSourcesService.listExternal(ReferenceType.DataRepositories, requestItem.criteria.like, requestItem.criteria.type);
|
||||
const lookup = new ReferenceSearchLookup();
|
||||
lookup.like = query;
|
||||
lookup.key = '';
|
||||
lookup.type = ReferenceType.DataRepositories;
|
||||
return this.referenceService.search(lookup);
|
||||
}
|
||||
searchDatasetExternalPubRepositories(query: string): Observable<Reference[]> {
|
||||
// const requestItem: RequestItem<DataRepositoryCriteria> = new RequestItem();
|
||||
// requestItem.criteria = new DataRepositoryCriteria();
|
||||
// requestItem.criteria.like = query;
|
||||
// requestItem.criteria.type = '';
|
||||
// return this.externalSourcesService.listExternal(ReferenceType.PubRepositories, requestItem.criteria.like, requestItem.criteria.type);
|
||||
const lookup = new ReferenceSearchLookup();
|
||||
lookup.like = query;
|
||||
lookup.key = '';
|
||||
lookup.type = ReferenceType.PubRepositories;
|
||||
return this.referenceService.search(lookup);
|
||||
}
|
||||
searchDatasetExternalJournalRepositories(query: string): Observable<Reference[]> {
|
||||
// const requestItem: RequestItem<DataRepositoryCriteria> = new RequestItem();
|
||||
// requestItem.criteria = new DataRepositoryCriteria();
|
||||
// requestItem.criteria.like = query;
|
||||
// requestItem.criteria.type = '';
|
||||
// return this.externalSourcesService.listExternal(ReferenceType.Journals, requestItem.criteria.like, requestItem.criteria.type);
|
||||
const lookup = new ReferenceSearchLookup();
|
||||
lookup.like = query;
|
||||
lookup.key = '';
|
||||
lookup.type = ReferenceType.Journals;
|
||||
return this.referenceService.search(lookup);
|
||||
}
|
||||
searchDatasetExternalTaxonomies(query: string): Observable<FetcherReference[]> {
|
||||
const requestItem: RequestItem<TaxonomyCriteria> = new RequestItem();
|
||||
requestItem.criteria = new TaxonomyCriteria();
|
||||
requestItem.criteria.like = query;
|
||||
requestItem.criteria.type = '';
|
||||
return this.externalSourcesService.listExternal(ReferenceType.Taxonomies, requestItem.criteria.like, requestItem.criteria.type);
|
||||
}
|
||||
searchDatasetExternalLicences(query: string): Observable<Reference[]> {
|
||||
// const requestItem: RequestItem<LicenseCriteria> = new RequestItem();
|
||||
// requestItem.criteria = new LicenseCriteria();
|
||||
// requestItem.criteria.like = query;
|
||||
// requestItem.criteria.type = '';
|
||||
// return this.externalSourcesService.listExternal(ReferenceType.Licenses, requestItem.criteria.like, requestItem.criteria.type);
|
||||
const lookup = new ReferenceSearchLookup();
|
||||
lookup.like = query;
|
||||
lookup.key = '';
|
||||
lookup.type = ReferenceType.Licenses;
|
||||
return this.referenceService.search(lookup);
|
||||
}
|
||||
searchDatasetExternalPublications(query: string): Observable<Reference[]> {
|
||||
// const requestItem: RequestItem<PublicationCriteria> = new RequestItem();
|
||||
// requestItem.criteria = new PublicationCriteria();
|
||||
// requestItem.criteria.like = query;
|
||||
// requestItem.criteria.type = '';
|
||||
//return this.externalSourcesService.listExternal(ReferenceType.Publications, requestItem.criteria.like, requestItem.criteria.type);
|
||||
|
||||
const lookup = new ReferenceSearchLookup();
|
||||
lookup.like = query;
|
||||
lookup.key = '';
|
||||
lookup.type = ReferenceType.Publications;
|
||||
return this.referenceService.search(lookup);
|
||||
}
|
||||
|
||||
searchDatasetExternalRegistries(query: string): Observable<FetcherReference[]> {
|
||||
const requestItem: RequestItem<RegistryCriteria> = new RequestItem();
|
||||
requestItem.criteria = new RegistryCriteria();
|
||||
requestItem.criteria.like = query;
|
||||
requestItem.criteria.type = '';
|
||||
return this.externalSourcesService.listExternal(ReferenceType.Registries, requestItem.criteria.like, requestItem.criteria.type);
|
||||
}
|
||||
|
||||
searchDatasetExternalServices(query: string): Observable<FetcherReference[]> {
|
||||
const requestItem: RequestItem<ServiceCriteria> = new RequestItem();
|
||||
requestItem.criteria = new ServiceCriteria();
|
||||
requestItem.criteria.like = query;
|
||||
requestItem.criteria.type = '';
|
||||
return this.externalSourcesService.listExternal(ReferenceType.Services, requestItem.criteria.like, requestItem.criteria.type);
|
||||
}
|
||||
|
||||
searchDatasetTags(query: string): Observable<ExternalSourceItemModel[]> {
|
||||
const requestItem: RequestItem<TagCriteria> = new RequestItem();
|
||||
requestItem.criteria = new TagCriteria();
|
||||
requestItem.criteria.like = query;
|
||||
requestItem.criteria.type = '';
|
||||
return this.externalSourcesService.searchDatasetTags(requestItem);
|
||||
}
|
||||
|
||||
parseTags() {
|
||||
try {
|
||||
|
||||
|
||||
let stringValue = this.propertiesFormGroup.get(this.field.id).get('value').value;
|
||||
if (typeof stringValue === 'string') {
|
||||
stringValue = (<string>stringValue).replace(new RegExp('{', 'g'), '{"').replace(new RegExp('=', 'g'), '":"').replace(new RegExp(',', 'g'), '",').replace(new RegExp(', ', 'g'), ', "').replace(new RegExp('}', 'g'), '"}');
|
||||
stringValue = stringValue.replace(new RegExp('}"', 'g'), '}').replace(new RegExp('"{', 'g'), '{');
|
||||
} else if (stringValue instanceof Array) {
|
||||
const tempArray = new Array();
|
||||
for (let stringTag of stringValue) {
|
||||
tempArray.push(JSON.parse(stringTag));
|
||||
}
|
||||
stringValue = JSON.stringify(tempArray);
|
||||
}
|
||||
const tagArray = JSON.parse(stringValue);
|
||||
this.propertiesFormGroup.get(this.field.id).get('value').patchValue(tagArray);
|
||||
} catch (e) {
|
||||
console.warn('Could not parse tags');
|
||||
}
|
||||
}
|
||||
|
||||
filterTags(value: string): Observable<ExternalSourceItemModel[]> {
|
||||
const requestItem: RequestItem<TagCriteria> = new RequestItem();
|
||||
const criteria: TagCriteria = new TagCriteria();
|
||||
criteria.like = value;
|
||||
requestItem.criteria = criteria;
|
||||
return this.externalSourcesService.searchDatasetTags(requestItem);
|
||||
}
|
||||
|
||||
showTag(ev: any) {
|
||||
if (typeof ev === 'string') {
|
||||
return ev;
|
||||
} else {
|
||||
return ev.name;
|
||||
}
|
||||
}
|
||||
|
||||
addTag(ev: any) {
|
||||
let item: ExternalTagEditorModel;
|
||||
//this.filteredTags = this.formGroup.get('tags').value;
|
||||
if (typeof ev === 'string') {
|
||||
item = new ExternalTagEditorModel('', ev);
|
||||
} else {
|
||||
item = ev;
|
||||
}
|
||||
if (item.name !== '') {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
filterOrganisations(value: string): Observable<Reference[]> {
|
||||
//return this.externalSourcesService.searchDMPOrganizations(value);
|
||||
//return this.externalSourcesService.listExternal(ReferenceType.Organizations, value, '');
|
||||
const lookup = new ReferenceSearchLookup();
|
||||
lookup.like = value;
|
||||
lookup.key = '';
|
||||
lookup.type = ReferenceType.Organizations;
|
||||
return this.referenceService.search(lookup);
|
||||
}
|
||||
|
||||
filterResearchers(value: string): Observable<Reference[]> {
|
||||
//return this.externalSourcesService.searchDMPResearchers({ criteria: { name: value, like: null } });
|
||||
//return this.externalSourcesService.listExternal(ReferenceType.Researcher, value, '');
|
||||
const lookup = new ReferenceSearchLookup();
|
||||
lookup.like = value;
|
||||
lookup.key = '';
|
||||
lookup.type = ReferenceType.Researcher;
|
||||
return this.referenceService.search(lookup);
|
||||
}
|
||||
|
||||
getDatasetIdControl(name: string): UntypedFormControl {
|
||||
return this.propertiesFormGroup.get(this.field.id).get(name) as UntypedFormControl;
|
||||
}
|
||||
|
||||
searchCurrency(query: string): Observable<LocalFetchModel[]> {
|
||||
return this.currencyService.get(query);
|
||||
}
|
||||
|
||||
validateId() {
|
||||
const identifier = this.getDatasetIdControl('identifier').value;
|
||||
const type = this.getDatasetIdControl('type').value;
|
||||
this.validationIcon = 'loading';
|
||||
this.externalSourcesService.validateIdentifier(identifier, type).pipe(takeUntil(this._destroyed)).subscribe(result => {
|
||||
this.validationIcon = result === true ? 'done' : 'clear';
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public upload() {
|
||||
//TODO: refactor this
|
||||
// this.fileService.upload(this.filesToUpload[0], this.datasetProfileId.id, this.form.value.id).subscribe((fileId: string) => {
|
||||
// this.form.get("value").patchValue(
|
||||
// { "name": this.filesToUpload[0].name, "id": fileId + "", "type": this.filesToUpload[0].type });
|
||||
// this.cdr.detectChanges();
|
||||
// }, error => {
|
||||
// this.onCallbackUploadFail(error.error);
|
||||
// })
|
||||
}
|
||||
|
||||
|
||||
private onCallbackUploadFail(error: any) {
|
||||
this.makeFilesNull();
|
||||
this.uiNotificationService.snackBarNotification(this.language.instant(error.message), SnackBarNotificationLevel.Error);
|
||||
}
|
||||
|
||||
fileChangeEvent(fileInput: any, dropped: boolean = false) {
|
||||
//TODO: refactor this
|
||||
// if (this.form.value.value) {
|
||||
// this.onRemove(false);
|
||||
// }
|
||||
|
||||
// if (dropped) {
|
||||
// this.filesToUpload = fileInput.addedFiles;
|
||||
// } else {
|
||||
// this.filesToUpload = fileInput.target.files;
|
||||
// }
|
||||
|
||||
|
||||
// let messages: string[] = [];
|
||||
// if (this.filesToUpload.length == 0) {
|
||||
// messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.NO-FILES-SELECTED'));
|
||||
// return;
|
||||
// } else {
|
||||
// let fileToUpload = this.filesToUpload[0];
|
||||
// if (this.form.get("data") && this.form.get("data").value.types
|
||||
// && this.form.get("data").value.types.map(type => type.value).includes(fileToUpload.type)
|
||||
// && this.form.get("data").value.maxFileSizeInMB
|
||||
// && this.form.get("data").value.maxFileSizeInMB * 1048576 >= fileToUpload.size) {
|
||||
// this.upload();
|
||||
// } else {
|
||||
// this.filesToUpload = null;
|
||||
// messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.LARGE-FILE-OR-UNACCEPTED-TYPE'));
|
||||
// messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.MAX-FILE-SIZE', { 'maxfilesize': this.form.get("data").value.maxFileSizeInMB }));
|
||||
// messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.ACCEPTED-FILE-TYPES') + this.form.get("data").value.types.map(type => type.value).join(", "));
|
||||
// }
|
||||
|
||||
// if (messages && messages.length > 0) {
|
||||
// this.dialog.open(FormValidationErrorsDialogComponent, {
|
||||
// data: {
|
||||
// errorMessages: messages
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
onRemove(makeFilesNull: boolean = true) {
|
||||
//TODO: refactor this
|
||||
// delete from tmp folder - subscribe call
|
||||
// this.fileService.deleteFromTempFolder(this.form.value.value.id).subscribe(res => {
|
||||
// if (makeFilesNull) {
|
||||
// this.makeFilesNull();
|
||||
// }
|
||||
// this.cdr.detectChanges();
|
||||
// }, error => {
|
||||
// if (makeFilesNull) {
|
||||
// this.makeFilesNull();
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
makeFilesNull() {
|
||||
//TODO: refactor this
|
||||
// this.filesToUpload = null;
|
||||
// this.form.value.value = null;
|
||||
// this.form.get("value").patchValue(null);
|
||||
}
|
||||
|
||||
typesToString() {
|
||||
return (this.field.data as DescriptionTemplateUploadData).types.map(type => type.value).toString();
|
||||
}
|
||||
|
||||
download(): void {
|
||||
//TODO: refactor this
|
||||
// this.fileService.download(this.form.value.value.id)
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(response => {
|
||||
// const blob = new Blob([response.body], { type: this.form.value.value.type });
|
||||
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
|
||||
|
||||
// FileSaver.saveAs(blob, filename);
|
||||
// });
|
||||
}
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
<div class="dynamic-form-section row" [id]="section.id">
|
||||
<mat-accordion class="col-12">
|
||||
<mat-expansion-panel class="row expansion-panel toc-section-header" [id]="pathName" [(expanded)]="panelExpanded">
|
||||
<!-- TODO: uncomment -->
|
||||
<!-- <mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
<h6 class='panel-title'>{{tocentry? tocentry.numbering :form.get('numbering').value}}. {{section.title}}</h6>
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>-->
|
||||
<mat-panel-description class="col-12">
|
||||
<h6 class='panel-desc' *ngIf="section.description" [innerHTML]="section.description"></h6>
|
||||
</mat-panel-description>
|
||||
<ng-container *ngIf="!tocentry else tocentryCase">
|
||||
<div *ngFor="let fieldSet of section.fieldSets; let i = index;" class="col-12">
|
||||
<!-- <div class="row" *ngIf="(this.visibilityRulesService.isVisibleMap[fieldSet.id] ?? true) && this.visibilityRulesService.scanIfChildsOfCompositeFieldHasVisibleItems(fieldSet.id)"> -->
|
||||
<div class="row" *ngIf="(this.visibilityRulesService.isVisibleMap[fieldSet.id] ?? true) && this.visibilityRulesService.scanIfChildsOfCompositeFieldHasVisibleItems(fieldSet.id)">
|
||||
|
||||
<div class="col-12">
|
||||
<div class="row">
|
||||
<app-form-field-set class="align-self-center col" [propertiesFormGroup]="propertiesFormGroup" [fieldSet]="fieldSet" [visibilityRulesService]="visibilityRulesService" [datasetProfileId]="datasetProfileId"
|
||||
[isChild]="false"
|
||||
></app-form-field-set>
|
||||
<!-- [showDelete]="(compositeFieldFormGroup.get('multiplicityItems').length) > 0" TODO: add this above -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="fieldSet" class="col-12">
|
||||
<div class="row">
|
||||
<!-- <div class="col-12" *ngFor="let multipleCompositeFieldFormGroup of compositeFieldFormGroup.get('multiplicityItems')['controls']; let j = index">
|
||||
<div class="row">
|
||||
<app-form-field-set class=" align-self-center col" [form]="multipleCompositeFieldFormGroup" [visibilityRulesService]="visibilityRulesService" [datasetProfileId]="datasetProfileId"
|
||||
[isChild]="true" [showDelete]="true"></app-form-field-set>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="(compositeFieldFormGroup.get('multiplicity').value.max - 1) > (compositeFieldFormGroup.get('multiplicityItems').length)"
|
||||
class="col-12 mt-1 ml-0 mr-0 addOneFieldButton">
|
||||
<span class="d-inline-flex align-items-center" [ngClass]="compositeFieldFormGroup.disabled ? '' : 'pointer'" (click)="addMultipleField(i)">
|
||||
<button mat-icon-button color="primary" [disabled]="compositeFieldFormGroup.disabled">
|
||||
<mat-icon>add_circle</mat-icon>
|
||||
</button>
|
||||
<span class="mt-1" *ngIf="compositeFieldFormGroup.get('multiplicity').value.placeholder">{{compositeFieldFormGroup.get('multiplicity').value.placeholder}}</span>
|
||||
<span class="mt-1" *ngIf="!compositeFieldFormGroup.get('multiplicity').value.placeholder">{{('DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-ADD-ONE-FIELD' + (compositeFieldFormGroup.get('multiplicity').value.tableView?'-TABLEVIEW':'')) | translate}}</span>
|
||||
</span>
|
||||
</div> -->
|
||||
<div *ngIf="fieldSet.hasCommentField" class="col-12">
|
||||
<rich-text-editor-component [parentFormGroup]="propertiesFormGroup.get('commentFieldValue' + fieldSet.id)" [controlName]="'value'"
|
||||
[id]="'editor1'" [placeholder]="'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.COMMENT-PLACEHOLDER' | translate"
|
||||
[wrapperClasses]="'mb-2'" [editable]="!propertiesFormGroup.get('commentFieldValue' + fieldSet.id).disabled">
|
||||
</rich-text-editor-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="section.sections" class="col-12">
|
||||
<div *ngFor="let section of section.sections; let j = index;" class="row">
|
||||
<app-form-section class="col-12" [section]="section" [propertiesFormGroup]="propertiesFormGroup" [path]="path+'.'+(j+1)" [pathName]="pathName+'.sections.'+j" [linkToScroll]="subsectionLinkToScroll"
|
||||
[visibilityRulesService]="visibilityRulesService" [datasetProfileId]="datasetProfileId"></app-form-section>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- WORKING WITH TOCENTRIES -->
|
||||
|
||||
<ng-template #tocentryCase>
|
||||
|
||||
<ng-container [ngSwitch]="tocentry.subEntriesType">
|
||||
<ng-container *ngSwitchCase="tocentriesType.FieldSet">
|
||||
|
||||
<!-- FIELDSET CASE -->
|
||||
<div *ngFor="let fieldsetEntry of tocentry.subEntries; let i = index;" class="col-12" [id]="TOCENTRY_ID_PREFIX+fieldsetEntry.id" (click)="onAskedToScroll(fieldsetEntry.id)">
|
||||
<div class="row" *ngIf="((this.visibilityRulesService.isVisibleMap[fieldsetEntry.form.get('id').value] ?? true) && this.visibilityRulesService.scanIfChildsOfCompositeFieldHasVisibleItems(fieldsetEntry.form)) && !hiddenEntriesIds.includes(fieldsetEntry.id)">
|
||||
|
||||
<div class="col-12">
|
||||
<div *ngIf="!fieldsetEntry.form.get('multiplicity').value.tableView" class="row">
|
||||
<app-form-field-set [tocentry]="fieldsetEntry" class="align-self-center col" [form]="fieldsetEntry.form" [visibilityRulesService]="visibilityRulesService" [datasetProfileId]="datasetProfileId"
|
||||
[isChild]="false" [showDelete]="(fieldsetEntry.form.get('multiplicityItems').length) > 0"></app-form-field-set>
|
||||
</div>
|
||||
<ng-container *ngIf="fieldsetEntry.form.get('multiplicity').value.tableView">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<app-form-composite-title class="row" [fieldSet]="fieldsetEntry"></app-form-composite-title>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-bordered" style="table-layout: fixed">
|
||||
<tr>
|
||||
<ng-container *ngFor="let fieldFormGroup of fieldsetEntry.form.get('fields')['controls']; let i = index;">
|
||||
<th *ngIf="this.visibilityRulesService.isVisibleMap[fieldFormGroup.get('id').value] ?? true"
|
||||
class="text-wrap">{{fieldFormGroup.get('data').value.label}}</th>
|
||||
</ng-container>
|
||||
<th class="actions"></th>
|
||||
</tr>
|
||||
<tr app-form-field-set [form]="fieldsetEntry.form" [datasetProfileId]="datasetProfileId" [visibilityRulesService]="visibilityRulesService"
|
||||
[isChild]="false" [showDelete]="(fieldsetEntry.form.get('multiplicityItems').length) > 0" [tableRow]="true"></tr>
|
||||
<ng-container *ngIf="fieldsetEntry.form && fieldsetEntry.form.get('multiplicity').value.tableView">
|
||||
<tr app-form-field-set *ngFor="let multipleCompositeFieldFormGroup of fieldsetEntry.form.get('multiplicityItems')['controls']; let j = index"
|
||||
[form]="multipleCompositeFieldFormGroup" [datasetProfileId]="datasetProfileId" [visibilityRulesService]="visibilityRulesService"
|
||||
[isChild]="true" [showDelete]="true" [tableRow]="true"></tr>
|
||||
</ng-container>
|
||||
<tr *ngIf="(fieldsetEntry.form.get('multiplicity').value.max - 1) > (fieldsetEntry.form.get('multiplicityItems').length)">
|
||||
<td [colSpan]="visibleControls(fieldsetEntry.form.get('fields')['controls']).length + 1" class="text-center">
|
||||
<span class="d-inline-flex align-items-center" [ngClass]="fieldsetEntry.form.disabled ? '' : 'pointer'" (click)="addMultipleField(i)">
|
||||
<button mat-icon-button color="primary" [disabled]="fieldsetEntry.form.disabled">
|
||||
<mat-icon>add_circle</mat-icon>
|
||||
</button>
|
||||
<span class="mt-1" *ngIf="fieldsetEntry.form.get('multiplicity').value.placeholder">{{fieldsetEntry.form.get('multiplicity').value.placeholder}}</span>
|
||||
<span class="mt-1" *ngIf="!fieldsetEntry.form.get('multiplicity').value.placeholder">{{('DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-ADD-ONE-FIELD' + (fieldsetEntry.form.get('multiplicity').value.tableView?'-TABLEVIEW':'')) | translate}}</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div *ngIf="fieldsetEntry.form && !fieldsetEntry.form.get('multiplicity').value.tableView" class="col-12">
|
||||
<div class="row">
|
||||
<div class="col-12" *ngFor="let multipleCompositeFieldFormGroup of fieldsetEntry.form.get('multiplicityItems')['controls']; let j = index">
|
||||
<div class="row">
|
||||
<app-form-field-set class=" align-self-center col" [form]="multipleCompositeFieldFormGroup" [visibilityRulesService]="visibilityRulesService" [datasetProfileId]="datasetProfileId"
|
||||
[isChild]="true" [showDelete]="true"></app-form-field-set>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="(fieldsetEntry.form.get('multiplicity').value.max - 1) > (fieldsetEntry.form.get('multiplicityItems').length)"
|
||||
class="col-12 mt-1 ml-0 mr-0 addOneFieldButton">
|
||||
<span class="d-inline-flex align-items-center" [ngClass]="fieldsetEntry.form.disabled ? '' : 'pointer'" (click)="addMultipleField(i)">
|
||||
<button mat-icon-button color="primary" [disabled]="fieldsetEntry.form.disabled">
|
||||
<mat-icon>add_circle</mat-icon>
|
||||
</button>
|
||||
<span class="mt-1" *ngIf="fieldsetEntry.form.get('multiplicity').value.placeholder">{{fieldsetEntry.form.get('multiplicity').value.placeholder}}</span>
|
||||
<span class="mt-1" *ngIf="!fieldsetEntry.form.get('multiplicity').value.placeholder">{{('DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-ADD-ONE-FIELD' + (fieldsetEntry.form.get('multiplicity').value.tableView?'-TABLEVIEW':'')) | translate}}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div *ngIf="fieldsetEntry.form.get('hasCommentField').value" class="col-12">
|
||||
<rich-text-editor-component [parentFormGroup]="fieldsetEntry.form" [controlName]="'commentFieldValue'"
|
||||
[id]="'editor1'" [placeholder]="'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.COMMENT-PLACEHOLDER' | translate"
|
||||
[wrapperClasses]="' mb-2'" [editable]="!fieldsetEntry.form.get('commentFieldValue').disabled">
|
||||
</rich-text-editor-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="tocentriesType.Section">
|
||||
<!-- SECTION CASE -->
|
||||
|
||||
<div *ngIf="form.get('sections')" class="col-12"><!-- MAYBEE NOT NEEDED-->
|
||||
<ng-container *ngFor="let sectionEntry of tocentry.subEntries; let j = index;">
|
||||
<div class="row" *ngIf="!hiddenEntriesIds.includes(sectionEntry.id)">
|
||||
<app-form-section [TOCENTRY_ID_PREFIX]="TOCENTRY_ID_PREFIX" class="col-12" [tocentry]="sectionEntry" [form]="sectionEntry.form" [path]="path+'.'+(j+1)" [pathName]="pathName+'.sections.'+j" [linkToScroll]="subsectionLinkToScroll"
|
||||
[visibilityRulesService]="visibilityRulesService" [datasetProfileId]="datasetProfileId"
|
||||
(askedToScroll)="onAskedToScroll($event)"
|
||||
[hiddenEntriesIds]="hiddenEntriesIds"
|
||||
></app-form-section>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
</ng-container>
|
||||
|
||||
</ng-template>
|
|
@ -0,0 +1,46 @@
|
|||
.dynamic-form-section {
|
||||
.expansion-panel {
|
||||
// background-color: #eeeeee54;
|
||||
background-color: white;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
// margin-bottom: 1em;
|
||||
}
|
||||
.addOneFieldButton {
|
||||
margin-top: -15px;
|
||||
margin-left: -11px;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.panel-title,
|
||||
.panel-desc {
|
||||
text-align: left;
|
||||
font-weight: 700;
|
||||
font-size: 1rem;
|
||||
letter-spacing: 0px;
|
||||
color: #212121;
|
||||
opacity: 0.81;
|
||||
margin-top: 1.625rem;
|
||||
margin-bottom: 0.625rem;
|
||||
}
|
||||
|
||||
.panel-desc {
|
||||
// text-transform: capitalize;
|
||||
text-transform: none;
|
||||
font-weight: 400;
|
||||
margin-top: .5rem;
|
||||
}
|
||||
}
|
||||
.styleBorder {
|
||||
border: 0.2em solid lightgray;
|
||||
border-radius: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
.mat-expansion-panel-header-description {
|
||||
padding-bottom: 18px;
|
||||
color: black;
|
||||
}
|
||||
|
||||
::ng-deep .mat-expansion-panel-header {
|
||||
height: auto !important;
|
||||
min-height: 48px;
|
||||
}
|
|
@ -0,0 +1,266 @@
|
|||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnInit,
|
||||
Output,
|
||||
SimpleChanges
|
||||
} from '@angular/core';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
import { DescriptionTemplateSection } from '@app/core/model/description-template/description-template';
|
||||
import { BaseComponent } from '@common/base/base.component';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { DescriptionFieldEditorModel } from '../../../description-editor.model';
|
||||
import { ToCEntry } from '../../../table-of-contents/models/toc-entry';
|
||||
import { ToCEntryType } from '../../../table-of-contents/models/toc-entry-type.enum';
|
||||
import { LinkToScroll } from '../../../table-of-contents/table-of-contents.component';
|
||||
import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.service';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-form-section',
|
||||
templateUrl: './form-section.component.html',
|
||||
styleUrls: ['./form-section.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DescriptionFormSectionComponent extends BaseComponent implements OnInit, OnChanges {
|
||||
|
||||
@Input() section: DescriptionTemplateSection;
|
||||
@Input() propertiesFormGroup: UntypedFormGroup;
|
||||
@Input() visibilityRulesService: VisibilityRulesService;
|
||||
|
||||
// @Input() datasetProfileId: String;
|
||||
// @Input() form: UntypedFormGroup;
|
||||
@Input() tocentry: ToCEntry;
|
||||
@Input() pathName: string;
|
||||
@Input() path: string;
|
||||
@Input() linkToScroll: LinkToScroll;
|
||||
@Input() hiddenEntriesIds: string[] = [];
|
||||
panelExpanded = true;
|
||||
subsectionLinkToScroll: LinkToScroll;
|
||||
@Output() askedToScroll = new EventEmitter<string>();
|
||||
tocentriesType = ToCEntryType;
|
||||
@Input() TOCENTRY_ID_PREFIX = "";
|
||||
|
||||
constructor(
|
||||
private changeDetector: ChangeDetectorRef
|
||||
) {
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
this.visibilityRulesService.getElementVisibilityMapObservable().pipe(takeUntil(this._destroyed)).subscribe(x => {
|
||||
this.changeDetector.markForCheck();
|
||||
});
|
||||
// Set comment fields to properties
|
||||
this.section.fieldSets.forEach(fieldSet => {
|
||||
if (fieldSet.hasCommentField && !this.propertiesFormGroup.contains('commentFieldValue' + fieldSet.id)) {
|
||||
const item: DescriptionFieldEditorModel = new DescriptionFieldEditorModel();
|
||||
item.key = 'commentFieldValue' + fieldSet.id;
|
||||
this.propertiesFormGroup.addControl('commentFieldValue' + fieldSet.id, item.buildForm());
|
||||
}
|
||||
});
|
||||
|
||||
//TODO uncomment
|
||||
// if (this.tocentry) {//maybe not needed as well
|
||||
// this.form = this.tocentry.form as UntypedFormGroup;
|
||||
// }
|
||||
// this.initMultipleFieldsVisibility();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
|
||||
if (changes['linkToScroll']) {
|
||||
if (changes['linkToScroll'].currentValue && changes['linkToScroll'].currentValue.section) {
|
||||
|
||||
if (this.pathName === changes['linkToScroll'].currentValue.section) {
|
||||
this.panelExpanded = true;
|
||||
} else if (changes['linkToScroll'].currentValue.section.includes(this.pathName)) {
|
||||
this.subsectionLinkToScroll = changes['linkToScroll'].currentValue;
|
||||
this.panelExpanded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setMultipleFieldVisibility(parentCompositeField, compositeField: DatasetDescriptionCompositeFieldEditorModel, idMappings: { old: string, new: string }[]) {
|
||||
// // ** COMPOSITE FIELD IS SHOWN OR HIDDEN FROM ANOTHER ELEMENT
|
||||
// const compositeFieldVisibilityDependencies = this.visibilityRulesService.getVisibilityDependency(parentCompositeField);
|
||||
// if (compositeFieldVisibilityDependencies && compositeFieldVisibilityDependencies.length) {
|
||||
|
||||
// compositeFieldVisibilityDependencies.forEach(x => {
|
||||
// const visRule: Rule = {
|
||||
// targetField: compositeField.id,
|
||||
// sourceField: x.sourceControlId,
|
||||
// requiredValue: x.sourceControlValue
|
||||
// }
|
||||
// this.visibilityRulesService.addNewRule(visRule);
|
||||
// });
|
||||
// }
|
||||
|
||||
// // console.log('idMappings ', idMappings);
|
||||
// parentCompositeField.fields.forEach(element => {
|
||||
// // console.log(this.visibilityRulesService.getVisibilityDependency(element.id));
|
||||
// const dependency = this.visibilityRulesService.getVisibilityDependency(element.id);
|
||||
// if (dependency && dependency.length) {
|
||||
// // * INNER VISIBILITY DEPENDENCIES
|
||||
// // * IF INNER INPUT HIDES ANOTHER INNER INPUT
|
||||
// const innerDependency = parentCompositeField.fields.reduce((innerD, currentElement) => {
|
||||
// const innerDependecies = dependency.filter(d => d.sourceControlId === currentElement.id);
|
||||
// return [...innerD, ...innerDependecies];
|
||||
// }, []) as VisibilityRuleSource[];
|
||||
// if (innerDependency.length) {
|
||||
// //Build visibility source
|
||||
// const updatedRules = innerDependency.map(x => {
|
||||
// const newId = idMappings.find(y => y.old === x.sourceControlId);
|
||||
// return { ...x, sourceControlId: newId.new };
|
||||
// });
|
||||
// // const visRule: VisibilityRule = {
|
||||
// // targetControlId: idMappings.find(x => x.old === element.id).new,
|
||||
// // sourceVisibilityRules: updatedRules
|
||||
// // }
|
||||
|
||||
|
||||
// const rules = updatedRules.map(x => {
|
||||
// return {
|
||||
// requiredValue: x.sourceControlValue,
|
||||
// sourceField: x.sourceControlId,
|
||||
// targetField: idMappings.find(l => l.old === element.id).new,
|
||||
// type: ''
|
||||
// } as Rule;
|
||||
// });
|
||||
|
||||
// rules.forEach(rule => {
|
||||
// this.visibilityRulesService.addNewRule(rule);
|
||||
// })
|
||||
|
||||
// // this.visibilityRulesService.appendVisibilityRule(visRule);
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
|
||||
// // * OUTER DEPENDENCIES
|
||||
|
||||
// // * IF INNER INPUT HIDES OUTER INPUTS
|
||||
// const innerIds = idMappings.map(x => x.old) as string[];
|
||||
|
||||
// const outerTargets = this.visibilityRulesService.getVisibilityTargets(element.id).filter(x => !innerIds.includes(x));
|
||||
|
||||
// outerTargets.forEach(target => {
|
||||
|
||||
// const outerRules = (this.visibilityRulesService.getVisibilityDependency(target) as VisibilityRuleSource[]).filter(x => x.sourceControlId === element.id);
|
||||
// const updatedRules = outerRules.map(x => {
|
||||
// return { ...x, sourceControlId: idMappings.find(y => y.old === element.id).new };
|
||||
// });
|
||||
|
||||
// // const visRule: VisibilityRule = {
|
||||
// // targetControlId: target,
|
||||
// // sourceVisibilityRules: updatedRules
|
||||
// // }
|
||||
|
||||
|
||||
// const rules = updatedRules.map(x => {
|
||||
// return {
|
||||
// requiredValue: x.sourceControlValue,
|
||||
// sourceField: x.sourceControlId,
|
||||
// targetField: target,
|
||||
// type: ''
|
||||
// } as Rule;
|
||||
// })
|
||||
// rules.forEach(rule => {
|
||||
// this.visibilityRulesService.addNewRule(rule);
|
||||
// })
|
||||
// // this.visibilityRulesService.appendVisibilityRule(visRule);
|
||||
// });
|
||||
// // * IF INNER INPUT IS HIDDEN BY OUTER INPUT
|
||||
// if (dependency && dependency.length) {
|
||||
// const fieldsThatHideInnerElement = dependency.filter(x => !innerIds.includes(x.sourceControlId));
|
||||
// if (fieldsThatHideInnerElement.length) {
|
||||
// fieldsThatHideInnerElement.forEach(x => {
|
||||
// const visRule: Rule = {
|
||||
// targetField: idMappings.find(l => l.old === element.id).new,
|
||||
// sourceField: x.sourceControlId,
|
||||
// requiredValue: x.sourceControlValue
|
||||
// }
|
||||
// const shouldBeVisibile = this.visibilityRulesService.checkTargetVisibilityProvidedBySource(x.sourceControlId, element.id);
|
||||
// this.visibilityRulesService.addNewRule(visRule, shouldBeVisibile);
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// // console.log(`for ${element.id} targets are`, outerTargets);
|
||||
// });
|
||||
// }
|
||||
|
||||
// initMultipleFieldsVisibility() {
|
||||
// (this.form.get('compositeFields') as UntypedFormArray).controls.forEach(control => {
|
||||
// let parentCompositeField = (control as UntypedFormGroup).getRawValue();
|
||||
// if (parentCompositeField.multiplicityItems && parentCompositeField.multiplicityItems.length > 0) {
|
||||
// parentCompositeField.multiplicityItems.forEach(compositeField => {
|
||||
// let idMappings: { old: string, new: string }[] = [{ old: parentCompositeField.id, new: compositeField.id }];
|
||||
// parentCompositeField.fields.forEach((field, index) => {
|
||||
// idMappings.push({ old: field.id, new: compositeField.fields[index].id });
|
||||
// });
|
||||
// this.setMultipleFieldVisibility(parentCompositeField, compositeField, idMappings);
|
||||
// })
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// addMultipleField(fieldsetIndex: number) {
|
||||
// if (this.form.get('compositeFields').get('' + fieldsetIndex).disabled) {
|
||||
// return;
|
||||
// }
|
||||
// const compositeFieldToBeCloned = (this.form.get('compositeFields').get('' + fieldsetIndex) as UntypedFormGroup).getRawValue();
|
||||
// const multiplicityItemsArray = (<UntypedFormArray>(this.form.get('compositeFields').get('' + fieldsetIndex).get('multiplicityItems')));
|
||||
|
||||
// const ordinal = multiplicityItemsArray.length ? multiplicityItemsArray.controls.reduce((ordinal, currentControl) => {
|
||||
// const currentOrdinal = currentControl.get('ordinal').value as number;
|
||||
|
||||
// if (currentOrdinal >= ordinal) {
|
||||
// return currentOrdinal + 1;
|
||||
// }
|
||||
// return ordinal as number;
|
||||
// }, 0) : 0;
|
||||
// const idMappings = [] as { old: string, new: string }[];
|
||||
// const compositeField: DatasetDescriptionCompositeFieldEditorModel = new DatasetDescriptionCompositeFieldEditorModel().cloneForMultiplicity(compositeFieldToBeCloned, ordinal, idMappings);
|
||||
|
||||
// this.setMultipleFieldVisibility(compositeFieldToBeCloned, compositeField, idMappings);
|
||||
// multiplicityItemsArray.push(compositeField.buildForm());
|
||||
// }
|
||||
|
||||
// deleteCompositeFieldFormGroup(compositeFildIndex: number) {
|
||||
// const numberOfItems = this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems').get('' + 0).get('fields').value.length;
|
||||
// for (let i = 0; i < numberOfItems; i++) {
|
||||
// const multiplicityItem = this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems').get('' + 0).get('fields').get('' + i).value;
|
||||
// this.form.get('compositeFields').get('' + compositeFildIndex).get('fields').get('' + i).patchValue(multiplicityItem);
|
||||
// }
|
||||
// (<UntypedFormArray>(this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems'))).removeAt(0);
|
||||
// }
|
||||
|
||||
// deleteMultipeFieldFromCompositeFormGroup(compositeFildIndex: number, fildIndex: number) {
|
||||
// const multiplicityItemsArray = (<UntypedFormArray>(this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems')));
|
||||
// multiplicityItemsArray.removeAt(fildIndex);
|
||||
// multiplicityItemsArray.controls.forEach((control, i) => {
|
||||
// try {
|
||||
// control.get('ordinal').setValue(i);
|
||||
// } catch {
|
||||
// throw 'Could not find ordinal';
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// onAskedToScroll(id: string) {
|
||||
// this.panelExpanded = true;
|
||||
// this.askedToScroll.emit(id);
|
||||
// }
|
||||
|
||||
// visibleControls(controls: any[]) {
|
||||
// return controls.filter(control => this.visibilityRulesService.isVisibleMap[control.get('id').value));
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
<div *ngIf="datasetDescription" class="col-12 intro" [innerHTML]="datasetDescription"></div>
|
||||
<form *ngIf="descriptionTemplate && propertiesFormGroup" novalidate class="col-12 card">
|
||||
<div class="row">
|
||||
<div class="dynamic-form-editor p-0 col-md-12">
|
||||
<div id="form-container">
|
||||
<ng-container *ngIf="!tocentries else toctemplate">
|
||||
<div *ngFor="let page of descriptionTemplate?.definition?.pages; let z = index;">
|
||||
<div *ngFor="let section of getSectionsOfPage(page.id); let i = index;">
|
||||
<div class="row">
|
||||
<app-form-section class="col-12" [section]="section" [path]="z+1"
|
||||
[pathName]="'pages.'+z+'.sections.'+i" [propertiesFormGroup]="propertiesFormGroup" [visibilityRulesService]="visibilityRulesService"
|
||||
[linkToScroll]="linkToScroll"></app-form-section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<!-- TOCENTRIES -->
|
||||
<ng-template #toctemplate>
|
||||
<!--FIRST LEVEL ALWAYS PAGE-->
|
||||
<mat-accordion [multi]="true">
|
||||
|
||||
<ng-container *ngFor="let pageEntry of tocentries; let z = index;">
|
||||
<mat-expansion-panel [expanded]="true" #expansionPanel *ngIf="!hiddenEntriesIds.includes(pageEntry.id)">
|
||||
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
<h4 class="panel-title toc-page-header">
|
||||
{{pageEntry.numbering}}. {{pageEntry.label |uppercase}}
|
||||
</h4>
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
<!--
|
||||
<h4 class="toc-page-header">
|
||||
</h4> -->
|
||||
<ng-container *ngFor="let sectionEntry of pageEntry.subEntries; let i = index;">
|
||||
<div class="row" *ngIf="!hiddenEntriesIds.includes(sectionEntry.id)">
|
||||
<app-form-section [TOCENTRY_ID_PREFIX]="TOCENTRY_ID_PREFIX" class="col-12" [tocentry]="sectionEntry" [path]="z+1"
|
||||
[pathName]="'pages.'+z+'.sections.'+i" [datasetProfileId]="datasetProfileId" [visibilityRulesService]="visibilityRulesService"
|
||||
[linkToScroll]="linkToScroll"
|
||||
(askedToScroll)="onAskedToScroll(expansionPanel, $event)"
|
||||
[hiddenEntriesIds]="hiddenEntriesIds"
|
||||
></app-form-section>
|
||||
</div>
|
||||
</ng-container>
|
||||
</mat-expansion-panel>
|
||||
</ng-container>
|
||||
</mat-accordion>
|
||||
</ng-template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
|
@ -0,0 +1,47 @@
|
|||
@media (max-width: 768px) {
|
||||
.dynamic-form-editor {
|
||||
.form-container {
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-container {
|
||||
}
|
||||
|
||||
.intro {
|
||||
text-align: left;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0px;
|
||||
color: #212121;
|
||||
opacity: 1;
|
||||
margin: 3rem 0rem 3rem 0rem;
|
||||
}
|
||||
|
||||
.dynamic-form-editor {
|
||||
mat-vertical-stepper {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
// ::ng-deep .mat-form-field-flex > .mat-form-field-infix {padding: 0.4em 0px !important;}
|
||||
// ::ng-deep .mat-form-field-label-wrapper {
|
||||
// top: -1.5em;
|
||||
// }
|
||||
|
||||
// ::ng-deep
|
||||
// .mat-form-field-appearance-outline.mat-form-field-can-float.mat-form-field-should-float
|
||||
// .mat-form-field-label {
|
||||
// transform: translateY(-1.1em) scale(0.75);
|
||||
// width: 133.33333%;
|
||||
// }
|
||||
|
||||
// ::ng-deep .mat-form-field-appearance-outline .mat-form-field-outline {
|
||||
// background: #fafafa !important;
|
||||
// }
|
||||
|
||||
// ::ng-deep .mat-step-header .mat-step-icon-selected,
|
||||
// .mat-step-header .mat-step-icon-state-done,
|
||||
// .mat-step-header .mat-step-icon-state-edit {
|
||||
// background-color: var(--primary-color) !important;
|
||||
// }
|
|
@ -0,0 +1,371 @@
|
|||
import { AfterViewInit, Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
import { MatExpansionPanel } from '@angular/material/expansion';
|
||||
import { Rule } from '@app/core/model/dataset-profile-definition/rule';
|
||||
import { BaseComponent } from '@common/base/base.component';
|
||||
import { LinkToScroll } from '../table-of-contents/table-of-contents.component';
|
||||
import { VisibilityRulesService } from './visibility-rules/visibility-rules.service';
|
||||
import { DescriptionTemplate, DescriptionTemplateSection } from '@app/core/model/description-template/description-template';
|
||||
import { Guid } from '@common/types/guid';
|
||||
|
||||
@Component({
|
||||
selector: 'app-description-form',
|
||||
templateUrl: './description-form.component.html',
|
||||
styleUrls: ['./description-form.component.scss']
|
||||
})
|
||||
export class DescriptionFormComponent extends BaseComponent implements OnInit, AfterViewInit, OnChanges {
|
||||
|
||||
@Input() propertiesFormGroup: UntypedFormGroup;
|
||||
@Input() descriptionTemplate: DescriptionTemplate;
|
||||
@Input() visibilityRulesService: VisibilityRulesService;
|
||||
|
||||
// @ViewChild('stepper', { static: false }) stepper: MatStepper;
|
||||
@Input() path: string;
|
||||
@Input() visibilityRules: Rule[] = [];
|
||||
@Input() datasetDescription: String;
|
||||
@Input() linkToScroll: LinkToScroll;
|
||||
@Output() formChanged: EventEmitter<any> = new EventEmitter();
|
||||
@Output() fieldsetFocusChange: EventEmitter<string> = new EventEmitter<string>();
|
||||
|
||||
// tocentries: ToCEntry[];
|
||||
|
||||
|
||||
@Input() TOCENTRY_ID_PREFIX = "";
|
||||
@Output() visibilityRulesInstance = new EventEmitter<VisibilityRulesService>();
|
||||
|
||||
// public hiddenEntriesIds: string[] = [];
|
||||
|
||||
constructor(
|
||||
) {
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
this.init();
|
||||
// When the form is changed set stepper index to 0.
|
||||
// if (this.stepper && changes['form'] && !changes['form'].isFirstChange()) {
|
||||
// this.stepper.selectedIndex = 0;
|
||||
// } else if (this.stepper && changes['linkToScroll'] && changes['linkToScroll'].currentValue) {
|
||||
// if (changes['linkToScroll'].currentValue.page >= 0) {
|
||||
// this.stepper.selectedIndex = changes['linkToScroll'].currentValue.page;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
|
||||
}
|
||||
|
||||
getSectionsOfPage(pageId: string) : DescriptionTemplateSection[]{ //TODO: change that to something more performant since its used at html page.
|
||||
return this.descriptionTemplate.definition.sections.filter(x => x.page == pageId);
|
||||
}
|
||||
init() {
|
||||
// this.tocentries = this.getTocEntries();
|
||||
// const rules_to_append = this._enrichWithMultiplicityRules(this.tocentries);
|
||||
|
||||
// this.visibilityRulesService.buildVisibilityRules([...this.visibilityRules, ...rules_to_append], this.form);
|
||||
|
||||
// if (this.form) {
|
||||
// this.form.valueChanges
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(val => {
|
||||
// this.formChanged.emit(val);
|
||||
// });
|
||||
// }
|
||||
// this.visibilityRulesInstance.emit(this.visibilityRulesService);
|
||||
|
||||
|
||||
|
||||
|
||||
// this.hiddenEntriesIds = this._findHiddenEntries(this.tocentries);
|
||||
|
||||
// this.visibilityRulesService.visibilityChange
|
||||
// .pipe(
|
||||
// takeUntil(this._destroyed),
|
||||
// debounceTime(100)
|
||||
// )
|
||||
// .subscribe(_ => {
|
||||
// this.hiddenEntriesIds = this._findHiddenEntries(this.tocentries);
|
||||
// })
|
||||
}
|
||||
|
||||
onAskedToScroll(panel: MatExpansionPanel, id?: string) {
|
||||
panel.open();
|
||||
this.fieldsetFocusChange.emit(id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// private _enrichWithMultiplicityRules(tocentries: ToCEntry[]): Rule[] {
|
||||
// if (tocentries) {
|
||||
// return tocentries.map(entry => {
|
||||
// if (entry.type === ToCEntryType.Field) return []; // * TODO Me to tora implementation den tha ftasei pote edo
|
||||
|
||||
|
||||
// if (entry.type === ToCEntryType.FieldSet) {
|
||||
// // if(multiplicity: )
|
||||
// try {
|
||||
// // TODO OTAN KANW HIDE MULTIPLE PEDIO TOTE STO ON SHOW HANO TA VALUES (AUTO MPOREI NA EINAI KAI LEGIT) ('NA DOUME AN ONTOS DIAGRAFONTAI I APLA DEN TA DEIXNOUME')
|
||||
// // * UPDATE KANEI DESTROY TO COMPONENT H NGIF . PITHANOTATA NA XREIASTEI NA TO KANOUME HIDDEN AN THELOUME KATI ALLO
|
||||
// const multiplicity = entry.form.get('multiplicity').value;
|
||||
// if ((multiplicity.max > 1) && (multiplicity.min > 0) && (multiplicity.max >= multiplicity.min)) { // has valid multiplicity
|
||||
// return this._createAndAppendVisibilityRule(entry);
|
||||
// }
|
||||
// } catch {
|
||||
|
||||
// }
|
||||
// return [];
|
||||
// }
|
||||
|
||||
// if (entry.subEntries) {
|
||||
// return this._enrichWithMultiplicityRules(entry.subEntries);
|
||||
// }
|
||||
// })
|
||||
// .reduce((r, c) => { return [...c, ...r] }, []);
|
||||
// }
|
||||
// return [];
|
||||
// }
|
||||
|
||||
// private _createAndAppendVisibilityRule(entry: ToCEntry): Rule[] {
|
||||
|
||||
|
||||
// const rules_to_append = [];
|
||||
|
||||
// if (entry && (entry.type === ToCEntryType.FieldSet)) {
|
||||
|
||||
// //childs that are either target or source
|
||||
// const childIdsWithVisRules = (entry.form.get('fields') as UntypedFormArray).controls.reduce((all, s) => {
|
||||
// const sval = s.value as Field;
|
||||
// return this.visibilityRules.find(x => (x.targetField === sval.id) || (x.sourceField === sval.id)) ? [...all, sval] : all;
|
||||
// }, []) as Field[];
|
||||
|
||||
|
||||
// const innerCompositeFieldOriginalIds = (entry.form.get('fields') as UntypedFormArray).controls.map(x => x.get('id').value) as string[];
|
||||
|
||||
// //multiplicity items
|
||||
// const multiplicityItemsValue = entry.form.get('multiplicityItems').value as CompositeField[];
|
||||
|
||||
|
||||
// // ********* FIELDS OF FIELDSET ARE EITHER TARGETS OR SOURCES *****
|
||||
|
||||
|
||||
// if (childIdsWithVisRules.length && multiplicityItemsValue && multiplicityItemsValue.length) {
|
||||
// //check each multiplicity item composite field
|
||||
// multiplicityItemsValue.forEach(mi => {
|
||||
|
||||
// const multiplicityCompositeFieldIds = mi.fields.map(x => x.id);
|
||||
// const idMappings = multiplicityCompositeFieldIds.map(x => {
|
||||
// return {
|
||||
// original: innerCompositeFieldOriginalIds.find(l => x.includes(l)),
|
||||
// multiplicityIdValue: x
|
||||
// }
|
||||
// }) as { original: string, multiplicityIdValue: string }[];
|
||||
|
||||
// //each field of mutliplicity item
|
||||
// mi.fields.forEach(field => {
|
||||
|
||||
|
||||
// //get original visibility rules (original field)
|
||||
|
||||
// //original id
|
||||
// const original_id = childIdsWithVisRules.find(x => field.id.includes(x.id)).id;
|
||||
|
||||
|
||||
// //get vis rules
|
||||
|
||||
// //as source
|
||||
// const original_as_source = this.visibilityRules.filter(x => x.sourceField === original_id);
|
||||
// const original_as_target = this.visibilityRules.filter(x => x.targetField === original_id);
|
||||
|
||||
|
||||
|
||||
// if (original_as_source.length) {
|
||||
|
||||
// //inner dependencies
|
||||
// const innerDep = original_as_source.filter(x => innerCompositeFieldOriginalIds.includes(x.targetField));
|
||||
// innerDep.forEach(x => {
|
||||
// const newRule = { ...x, sourceField: field.id, targetField: idMappings.find(l => l.original === x.targetField).multiplicityIdValue } as Rule;
|
||||
// rules_to_append.push(newRule);
|
||||
// })
|
||||
|
||||
|
||||
// //outer dependencies
|
||||
// const outerDep = original_as_source.filter(x => !innerCompositeFieldOriginalIds.includes(x.targetField));
|
||||
// outerDep.forEach(x => {
|
||||
// const newRule = { ...x, sourceField: field.id };
|
||||
// rules_to_append.push(newRule);
|
||||
// })
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// if (original_as_target.length) {
|
||||
|
||||
// //inner dependencies
|
||||
// const innerDep = original_as_target.filter(x => innerCompositeFieldOriginalIds.includes(x.sourceField));
|
||||
// innerDep.forEach(x => {
|
||||
// const newRule = { ...x, targetField: field.id, sourceField: idMappings.find(l => l.original === x.sourceField).multiplicityIdValue } as Rule;
|
||||
// rules_to_append.push(newRule);
|
||||
// })
|
||||
|
||||
// //outer dependencies
|
||||
// const outerDep = original_as_target.filter(x => !innerCompositeFieldOriginalIds.includes(x.sourceField));
|
||||
// outerDep.forEach(x => {
|
||||
// const newRule = { ...x, targetField: field.id } as Rule;
|
||||
// rules_to_append.push(newRule);
|
||||
// })
|
||||
// }
|
||||
|
||||
// })
|
||||
// });
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
// // ** FIELDSET ITSELF IS TARGET
|
||||
// // ** source it can never be
|
||||
|
||||
// const compositeFieldAsTargetRules = this.visibilityRules.filter(x => x.targetField === entry.id);
|
||||
// const idCompositeFieldMappings = multiplicityItemsValue.map(x => {
|
||||
// return {
|
||||
// originalValue: entry.id,
|
||||
// newValue: x.id
|
||||
// }
|
||||
// }) as { originalValue: string, newValue: string }[];
|
||||
|
||||
|
||||
// if (compositeFieldAsTargetRules.length) {
|
||||
|
||||
// compositeFieldAsTargetRules.forEach(x => {
|
||||
// idCompositeFieldMappings.forEach(l => {
|
||||
// const newRule = { ...x, targetField: l.newValue };
|
||||
// rules_to_append.push(newRule);
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
|
||||
// }
|
||||
|
||||
// return rules_to_append;
|
||||
// }
|
||||
|
||||
// private _buildRecursively(form: UntypedFormGroup, whatAmI: ToCEntryType): ToCEntry {
|
||||
// if (!form) return null;
|
||||
|
||||
// switch (whatAmI) {
|
||||
// case ToCEntryType.Section:
|
||||
// const sections = form.get('sections') as UntypedFormArray;
|
||||
// const fieldsets = form.get('compositeFields') as UntypedFormArray;
|
||||
|
||||
|
||||
// const tempResult: ToCEntry[] = [];
|
||||
|
||||
// if (sections && sections.length) {
|
||||
// sections.controls.forEach(section => {
|
||||
// tempResult.push(this._buildRecursively(section as UntypedFormGroup, ToCEntryType.Section));
|
||||
// });
|
||||
|
||||
// } else if (fieldsets && fieldsets.length) {
|
||||
// fieldsets.controls.forEach(fieldset => {
|
||||
// tempResult.push(this._buildRecursively(fieldset as UntypedFormGroup, ToCEntryType.FieldSet));
|
||||
// });
|
||||
// }
|
||||
// return {
|
||||
// // form: form,
|
||||
// id: form.get('id').value,
|
||||
// label: form.get('title').value,
|
||||
// numbering: '',
|
||||
// subEntries: tempResult,
|
||||
// subEntriesType: sections && sections.length ? ToCEntryType.Section : ToCEntryType.FieldSet,
|
||||
// type: ToCEntryType.Section,
|
||||
// ordinal: form.get('ordinal').value
|
||||
// }
|
||||
// case ToCEntryType.FieldSet:
|
||||
// return {
|
||||
// // form: form,
|
||||
// label: form.get('title').value,
|
||||
// id: form.get('id').value,
|
||||
// numbering: 's',
|
||||
// subEntries: [],
|
||||
// subEntriesType: ToCEntryType.Field,
|
||||
// type: ToCEntryType.FieldSet,
|
||||
// ordinal: form.get('ordinal').value
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// private _sortByOrdinal(tocentries: ToCEntry[]) {
|
||||
|
||||
// if (!tocentries || !tocentries.length) return;
|
||||
|
||||
// tocentries.sort(this._customCompare);
|
||||
// tocentries.forEach(entry => {
|
||||
// this._sortByOrdinal(entry.subEntries);
|
||||
// });
|
||||
// }
|
||||
|
||||
// private _customCompare(a, b) {
|
||||
// return a.ordinal - b.ordinal;
|
||||
// }
|
||||
|
||||
// private _calculateNumbering(tocentries: ToCEntry[], depth: number[] = []) {
|
||||
// if (!tocentries || !tocentries.length) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// let prefixNumbering = depth.length ? depth.join('.') : '';
|
||||
|
||||
// if (depth.length) prefixNumbering = prefixNumbering + ".";
|
||||
// tocentries.forEach((entry, i) => {
|
||||
// entry.numbering = prefixNumbering + (i + 1);
|
||||
// this._calculateNumbering(entry.subEntries, [...depth, i + 1])
|
||||
// });
|
||||
// }
|
||||
|
||||
// getTocEntries(): ToCEntry[] {
|
||||
// if (!this.form) { return []; }
|
||||
// const result: ToCEntry[] = [];
|
||||
|
||||
// //build parent pages
|
||||
// (this.form.get('pages') as UntypedFormArray).controls.forEach((pageElement, i) => {
|
||||
// result.push({
|
||||
// id: i + 'id',
|
||||
// label: pageElement.get('title').value,
|
||||
// type: ToCEntryType.Page,
|
||||
// // form: pageElement,
|
||||
// numbering: (i + 1).toString(),
|
||||
// subEntriesType: ToCEntryType.Section,
|
||||
// subEntries: [],
|
||||
// ordinal: pageElement.get('ordinal').value
|
||||
// } as ToCEntry)
|
||||
// });
|
||||
|
||||
|
||||
|
||||
// result.forEach((entry, i) => {
|
||||
|
||||
// const sections = entry.form.get('sections') as UntypedFormArray;
|
||||
|
||||
// sections.controls.forEach(section => {
|
||||
// const tempResults = this._buildRecursively(section as UntypedFormGroup, ToCEntryType.Section);
|
||||
// entry.subEntries.push(tempResults);
|
||||
// });
|
||||
|
||||
// });
|
||||
|
||||
// this._sortByOrdinal(result);
|
||||
// //calculate numbering
|
||||
// this._calculateNumbering(result);
|
||||
// return result;
|
||||
|
||||
// }
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { FormattingModule } from "@app/core/formatting.module";
|
||||
import { FileService } from "@app/core/services/file/file.service";
|
||||
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module';
|
||||
import { RichTextEditorModule } from "@app/library/rich-text-editor/rich-text-editor.module";
|
||||
import { CommonFormsModule } from '@common/forms/common-forms.module';
|
||||
import { CommonUiModule } from '@common/ui/common-ui.module';
|
||||
import { NgxDropzoneModule } from "ngx-dropzone";
|
||||
import { DescriptionFormCompositeTitleComponent } from './components/form-composite-title/form-composite-title.component';
|
||||
import { DescriptionFormFieldSetComponent } from './components/form-field-set/form-field-set.component';
|
||||
import { DescriptionFormFieldComponent } from './components/form-field/form-field.component';
|
||||
import { DescriptionFormSectionComponent } from './components/form-section/form-section.component';
|
||||
import { DescriptionFormComponent } from './description-form.component';
|
||||
import { VisibilityRulesService } from './visibility-rules/visibility-rules.service';
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonUiModule,
|
||||
CommonFormsModule,
|
||||
AutoCompleteModule,
|
||||
RichTextEditorModule,
|
||||
NgxDropzoneModule,
|
||||
FormattingModule
|
||||
],
|
||||
declarations: [
|
||||
DescriptionFormComponent,
|
||||
DescriptionFormSectionComponent,
|
||||
DescriptionFormFieldSetComponent,
|
||||
DescriptionFormFieldComponent,
|
||||
DescriptionFormCompositeTitleComponent
|
||||
],
|
||||
exports: [
|
||||
DescriptionFormComponent
|
||||
],
|
||||
providers: [
|
||||
FileService
|
||||
]
|
||||
})
|
||||
export class DescriptionFormModule { }
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export class VisibilityRuleSource {
|
||||
public sourceControlId: string;
|
||||
public sourceControlValue: string;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
import { VisibilityRuleSource } from "./visibility-rule-source";
|
||||
|
||||
export class VisibilityRule {
|
||||
public targetControlId: string;
|
||||
public sourceVisibilityRules: Array<VisibilityRuleSource>;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
import { Rule } from "@app/core/model/dataset-profile-definition/rule";
|
||||
import { VisibilityRule } from "./visibility-rule";
|
||||
|
||||
export class VisibilityRulesContext {
|
||||
|
||||
public rules: Array<VisibilityRule> = new Array();
|
||||
|
||||
constructor() { }
|
||||
|
||||
public getRulesFromKey(id: string): VisibilityRule {
|
||||
|
||||
for (let i = 0; i < this.rules.length; i++) {
|
||||
if (id === this.rules[i].targetControlId) { return this.rules[i]; }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public buildVisibilityRuleContext(items: Array<Rule>) {
|
||||
items.forEach(item => {
|
||||
this.addToVisibilityRulesContext(item);
|
||||
});
|
||||
}
|
||||
|
||||
public addToVisibilityRulesContext(item: Rule): void {
|
||||
for (let i = 0; i < this.rules.length; i++) {
|
||||
if (this.rules[i].targetControlId === item.targetField) {
|
||||
|
||||
const newRule = { sourceControlId: item.sourceField, sourceControlValue: item.requiredValue };
|
||||
const ruleExists = this.rules[i].sourceVisibilityRules.find(x => {
|
||||
return Object.keys(x).reduce((exact, key) => {
|
||||
if (!exact) return false;
|
||||
return x[key] === newRule[key];
|
||||
}, true);
|
||||
})
|
||||
|
||||
if (!ruleExists) {
|
||||
this.rules[i].sourceVisibilityRules.push(newRule);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
const newVisibilityRuleArray = [({ sourceControlId: item.sourceField, sourceControlValue: item.requiredValue })];
|
||||
this.rules.push({ targetControlId: item.targetField, sourceVisibilityRules: newVisibilityRuleArray });
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,453 @@
|
|||
import { ApplicationRef, Injectable, NgZone } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormArray, UntypedFormGroup } from '@angular/forms';
|
||||
import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style';
|
||||
import { isNumeric } from '@app/utilities/enhancers/utils';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { VisibilityRule } from './models/visibility-rule';
|
||||
import { VisibilityRuleSource } from './models/visibility-rule-source';
|
||||
import { VisibilityRulesContext } from './models/visibility-rules-context';
|
||||
import { Rule } from '@app/core/model/dataset-profile-definition/rule';
|
||||
import { DescriptionTemplate, DescriptionTemplateSection } from '@app/core/model/description-template/description-template';
|
||||
|
||||
@Injectable()
|
||||
export class VisibilityRulesService {
|
||||
|
||||
private readonly VISIBILITY_RULE_LOGIC: 'OR' | 'AND' = 'OR';
|
||||
private readonly DEFAULTVISIBILITY = false;
|
||||
|
||||
private visibilityRuleContext: VisibilityRulesContext;
|
||||
private form: AbstractControl;
|
||||
public elementVisibilityMap = new MapWithDefault();
|
||||
private elementVisibilityMapSubject = new Subject<Map<String, boolean>>();
|
||||
private elementComputationalMap = new Map<String, Map<String, boolean>>(); /// keep saved the values of each form control validity value
|
||||
private _changeMade$ = new Subject<void>();
|
||||
|
||||
|
||||
get isVisibleMap(): MapWithDefault {
|
||||
// console.log('isVisibleMap');
|
||||
return this.elementVisibilityMap;
|
||||
|
||||
}; /// keep saved the values of each form control validity value
|
||||
|
||||
constructor(
|
||||
public applicationReference: ApplicationRef,
|
||||
public ngZone: NgZone
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
getElementVisibilityMapObservable(): Observable<Map<String, boolean>> {
|
||||
this.isVisibleMap
|
||||
console.log('getElementVisibilityMapObservable: ');
|
||||
return this.elementVisibilityMapSubject.asObservable();
|
||||
}
|
||||
|
||||
public checkElementVisibility(id: string): boolean {
|
||||
console.log('checkElementVisibility: ' + id);
|
||||
return true;
|
||||
// if (this.visibilityRuleContext.rules.filter(item => item.targetControlId === id).length === 0) { return true; }
|
||||
// console.log(this.elementVisibilityMap.has(id) ? this.elementVisibilityMap.get(id) : false);
|
||||
// return this.elementVisibilityMap.has(id) ? this.elementVisibilityMap.get(id) : false;
|
||||
}
|
||||
|
||||
public buildVisibilityRules(item: Array<Rule>, form: AbstractControl) {
|
||||
this.visibilityRuleContext = new VisibilityRulesContext();
|
||||
this.visibilityRuleContext.buildVisibilityRuleContext(item || []);
|
||||
this.form = form;
|
||||
this.resetVisibilityRules();
|
||||
}
|
||||
|
||||
public updateValueAndVisibility(id: string, value: any) {
|
||||
console.log('updateValueAndVisibility: ' + id + ' value: ' + value);
|
||||
const visibilityRules = this.visibilityRuleContext.rules.filter(item => item.sourceVisibilityRules.filter(source => source.sourceControlId === id).length > 0);
|
||||
if (visibilityRules.length > 0) {
|
||||
visibilityRules.forEach(item => this.evaluateVisibility(item, value, id));
|
||||
this.elementVisibilityMapSubject.next(this.elementVisibilityMap);
|
||||
}
|
||||
}
|
||||
|
||||
private evaluateVisibility(visibilityRule: VisibilityRule, value: any, sourceId: string) {// source controlId is the same
|
||||
console.log('evaluateVisibility: ' + visibilityRule + ' value: ' + value + ' sourceId: ' + sourceId);
|
||||
|
||||
const targetId = visibilityRule.targetControlId;
|
||||
const visibilityMap = this.elementComputationalMap.get(targetId) ? this.elementComputationalMap.get(targetId) : new Map<String, boolean>();
|
||||
|
||||
|
||||
if (value instanceof Array) {
|
||||
|
||||
const parsedSourceControlValues = visibilityRule.sourceVisibilityRules.map(e => this.parseValue(e.sourceControlValue));
|
||||
const parsedValues = value.map(e => this.parseValue(e));
|
||||
|
||||
const isVisible = parsedValues.map(v => parsedSourceControlValues.includes(v)).reduce((acc, current) => acc || current, false);
|
||||
|
||||
|
||||
// if(isVisible){
|
||||
// this._emitChangesIfNeeded(visibilityRule.targetControlId, true);
|
||||
// this.elementVisibilityMap.set(visibilityRule.targetControlId, true);
|
||||
// return;
|
||||
// }
|
||||
visibilityMap.set(sourceId, isVisible);
|
||||
|
||||
} else {
|
||||
const visibilityDependencySource = visibilityRule.sourceVisibilityRules.filter(x => x.sourceControlId === sourceId);
|
||||
|
||||
const shouldBeVisible = visibilityDependencySource.reduce((isVisible, x) => {
|
||||
|
||||
const shouldBeHidden = value !== null && (this.parseValue(value) !== this.parseValue(x.sourceControlValue));
|
||||
return this.VISIBILITY_RULE_LOGIC === 'OR' ? (isVisible || !shouldBeHidden) : (isVisible && !shouldBeHidden);
|
||||
// if(value !== null && )
|
||||
}, this.VISIBILITY_RULE_LOGIC === 'AND');
|
||||
visibilityMap.set(sourceId, shouldBeVisible);
|
||||
}
|
||||
|
||||
|
||||
this.elementComputationalMap.set(targetId, visibilityMap);// unnessecary
|
||||
|
||||
|
||||
const isVisible = this._computeVisibility(targetId);
|
||||
this._emitChangesIfNeeded(targetId, isVisible);
|
||||
const previousVisibility = this.elementVisibilityMap.get(targetId);
|
||||
this.elementVisibilityMap.set(targetId, isVisible);
|
||||
|
||||
if (!isVisible && previousVisibility !== isVisible) {
|
||||
this.resetControlWithId(this.form, targetId);
|
||||
}
|
||||
|
||||
|
||||
// for (let i = 0; i < visibilityRule.sourceVisibilityRules.length; i++) {
|
||||
// if (value != null && (this.parseValue(value) !== this.parseValue(visibilityRule.sourceVisibilityRules[i].sourceControlValue))) {
|
||||
// this._emitChangesIfNeeded(visibilityRule.targetControlId, false);
|
||||
// this.elementVisibilityMap.set(visibilityRule.targetControlId, false);
|
||||
// this.resetControlWithId(this.form, visibilityRule.targetControlId);
|
||||
// //this.updateValueAndVisibility(visibilityRule.targetControlId, null);
|
||||
// // this.clearValues(targetPathKey);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// this._emitChangesIfNeeded(visibilityRule.targetControlId, true);
|
||||
// this.elementVisibilityMap.set(visibilityRule.targetControlId, true);
|
||||
|
||||
// this.updateValueAndVisibility(visibilityRule.targetControlId, null);
|
||||
}
|
||||
|
||||
|
||||
private _computeVisibility(targetId: string): boolean {
|
||||
console.log('_computeVisibility: ' + targetId);
|
||||
|
||||
const visibilityMap = this.elementComputationalMap.get(targetId);
|
||||
const values = visibilityMap.values();
|
||||
let currentVal = values.next();
|
||||
let visibilityValues: boolean[] = [];
|
||||
while (!currentVal.done) {
|
||||
visibilityValues.push(currentVal.value);
|
||||
currentVal = values.next();
|
||||
}
|
||||
|
||||
|
||||
if (visibilityValues.length) {
|
||||
return visibilityValues.reduce((r, c) => {
|
||||
if (this.VISIBILITY_RULE_LOGIC === 'OR') {
|
||||
return r || c;
|
||||
} else {
|
||||
return r && c;
|
||||
}
|
||||
}, visibilityValues[0]);
|
||||
}
|
||||
|
||||
return this.DEFAULTVISIBILITY;
|
||||
}
|
||||
|
||||
private resetVisibilityRules() {
|
||||
console.log('resetVisibilityRules: ');
|
||||
|
||||
this.elementVisibilityMap.clear();
|
||||
this.elementVisibilityMap = new MapWithDefault();
|
||||
this.elementComputationalMap.clear();
|
||||
this.elementComputationalMap = new Map<String, Map<String, boolean>>();
|
||||
this._populateComputationMap(); /// !IMPORTANT FOR THE AND LOGIC
|
||||
this._changeMade$.next();
|
||||
}
|
||||
|
||||
private _populateComputationMap(): void {
|
||||
console.log('_populateComputationMap: ');
|
||||
this.visibilityRuleContext.rules.forEach(rule => {
|
||||
const targetId = rule.targetControlId;
|
||||
const visibilityMap = this.elementComputationalMap.get(targetId) ? this.elementComputationalMap.get(targetId) : new Map<String, boolean>();
|
||||
rule.sourceVisibilityRules.forEach(vr => {
|
||||
visibilityMap.set(vr.sourceControlId, this.DEFAULTVISIBILITY);
|
||||
});
|
||||
this.elementComputationalMap.set(targetId, visibilityMap);
|
||||
});
|
||||
}
|
||||
|
||||
parseValue(value: any) {
|
||||
if (typeof value === 'string') {
|
||||
if (isNumeric(value)) { return value; }
|
||||
else if (value === 'true') {
|
||||
return true;
|
||||
}
|
||||
else if (value === 'false') {
|
||||
return false;
|
||||
}
|
||||
else { return this.translate(value); }
|
||||
} else { return value; }
|
||||
}
|
||||
|
||||
search(path, obj, target) {
|
||||
for (const k in obj) {
|
||||
if (obj.hasOwnProperty(k)) {
|
||||
if (obj[k] === target) {
|
||||
return path + '.' + k;
|
||||
} else if (typeof obj[k] === 'object') {
|
||||
const result = this.search(path + '.' + k, obj[k], target);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
scanIfChildsOfCompositeFieldHasVisibleItems(compositeFieldParent: UntypedFormGroup): boolean {
|
||||
// console.log('scanIfChildsOfCompositeFieldHasVisibleItems: ' + compositeFieldParent);
|
||||
|
||||
//TODO: implement this
|
||||
return true;
|
||||
// let isVisible = false;
|
||||
// (<UntypedFormArray>(compositeFieldParent.get('fields'))).controls.forEach(element => {
|
||||
// if (this.checkElementVisibility(element.get('id').value)) {
|
||||
// isVisible = true;
|
||||
// }
|
||||
// });
|
||||
// return isVisible;
|
||||
}
|
||||
|
||||
private translate(item: any) {
|
||||
try {
|
||||
return JSON.parse(item).value;
|
||||
} catch (error) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
private resetControlWithId(formControl: AbstractControl, id: string) {
|
||||
console.log('resetControlWithId: ' + id);
|
||||
//TODO: implement this
|
||||
// if (formControl instanceof UntypedFormGroup) {
|
||||
// if ((formControl as UntypedFormGroup).contains('id') && (formControl as UntypedFormGroup).contains('value') && (formControl as UntypedFormGroup).get('id').value === id) {
|
||||
// this.resetFieldFormGroup(formControl);
|
||||
// } if ((formControl as UntypedFormGroup).contains('id') && (formControl as UntypedFormGroup).contains('fields') && (formControl as UntypedFormGroup).get('id').value === id) {
|
||||
// this.resetCompositeFieldFormGroup(formControl);
|
||||
// } else {
|
||||
// Object.keys(formControl.controls).forEach(item => {
|
||||
// const control = formControl.get(item);
|
||||
// this.resetControlWithId(control, id);
|
||||
// });
|
||||
// }
|
||||
// } else if (formControl instanceof UntypedFormArray) {
|
||||
// formControl.controls.forEach(item => {
|
||||
// this.resetControlWithId(item, id);
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
private resetFieldFormGroup(formGroup: UntypedFormGroup) {
|
||||
console.log('resetFieldFormGroup: ' + formGroup);
|
||||
//TODO: implement this
|
||||
// const renderStyle = formGroup.getRawValue().viewStyle.renderStyle;
|
||||
// if (renderStyle === DatasetProfileFieldViewStyle.Validation || renderStyle === DatasetProfileFieldViewStyle.DatasetIdentifier) {
|
||||
// formGroup.get('value').setValue({ identifier: '', type: '' });
|
||||
// } else {
|
||||
// formGroup.get('value').setValue(formGroup.get('defaultValue').value ? this.parseValue(formGroup.get('defaultValue').value.value) : undefined);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
private resetCompositeFieldFormGroup(formGroup: UntypedFormGroup) {
|
||||
console.log('resetCompositeFieldFormGroup: ' + formGroup);
|
||||
//TODO: implement this
|
||||
// (formGroup.get('fields') as UntypedFormArray).controls.forEach((element: UntypedFormGroup) => {
|
||||
// this.resetFieldFormGroup(element);
|
||||
// });
|
||||
// (formGroup.get('multiplicityItems') as UntypedFormArray).controls.splice(0);
|
||||
}
|
||||
private _emitChangesIfNeeded(id: string, valueToBeSet: boolean) {
|
||||
if (this.elementVisibilityMap.has(id)) {
|
||||
if (this.elementVisibilityMap.get(id) != valueToBeSet) {
|
||||
this._changeMade$.next();
|
||||
}
|
||||
} else {
|
||||
this._changeMade$.next();
|
||||
}
|
||||
}
|
||||
public get visibilityChange() {
|
||||
return this._changeMade$.asObservable();
|
||||
}
|
||||
public getVisibilityDependency(targetId: string): VisibilityRuleSource[] | null {
|
||||
console.log('getVisibilityDependency: ' + targetId);
|
||||
return this.visibilityRuleContext.rules.reduce((hasDependency, rule) => {
|
||||
if (hasDependency) return hasDependency;
|
||||
|
||||
if (rule.targetControlId === targetId) {
|
||||
return rule.sourceVisibilityRules;
|
||||
}
|
||||
|
||||
return null;
|
||||
}, null) as VisibilityRuleSource[];
|
||||
}
|
||||
|
||||
public getVisibilityTargets(sourceId: string): string[] {
|
||||
console.log('getVisibilityTargets: ' + sourceId);
|
||||
return this.visibilityRuleContext.rules.filter(x => {
|
||||
const result = x.sourceVisibilityRules.filter(y => y.sourceControlId === sourceId);
|
||||
return result.length;
|
||||
}).map(x => x.targetControlId);
|
||||
}
|
||||
|
||||
// public appendVisibilityRule(rule: VisibilityRule): void{
|
||||
|
||||
// const existingTargetRule = this.visibilityRuleContext.rules.find( r => r.targetControlId === rule.targetControlId);
|
||||
|
||||
// if(existingTargetRule){
|
||||
// rule.sourceVisibilityRules.forEach(svr =>{
|
||||
// existingTargetRule.sourceVisibilityRules.push(svr);
|
||||
// });
|
||||
// }else{
|
||||
// this.visibilityRuleContext.rules.push(rule);
|
||||
// }
|
||||
|
||||
|
||||
// }
|
||||
|
||||
|
||||
//removes rule that has the specific id either as a source either as a target
|
||||
public removeAllIdReferences(id: string): void {
|
||||
console.log('removeAllIdReferences: ' + id);
|
||||
|
||||
// * Remove from visibility rues and visibility rules context
|
||||
|
||||
//remove as a target
|
||||
const temp = this.visibilityRuleContext.rules.map((x, i) => (x.targetControlId === id) ? i : null);
|
||||
const indexes = temp.filter(x => x !== null);
|
||||
indexes.reverse().forEach(index => this.visibilityRuleContext.rules.splice(index, 1));
|
||||
this.elementVisibilityMap.delete(id);
|
||||
|
||||
|
||||
|
||||
//remove as a source
|
||||
const tbd = this.visibilityRuleContext.rules.reduce((to_be_deleted, rule, ruleIdx) => {
|
||||
const idxs = rule.sourceVisibilityRules.map((x, i) => (x.sourceControlId === id) ? i : null).filter(x => x !== null);
|
||||
idxs.reverse().forEach(index => rule.sourceVisibilityRules.splice(index, 1));
|
||||
|
||||
if (!rule.sourceVisibilityRules.length) {
|
||||
to_be_deleted.push(ruleIdx);
|
||||
}
|
||||
return to_be_deleted
|
||||
}, []);
|
||||
|
||||
|
||||
//clean up empty
|
||||
tbd.reverse().forEach(index => {
|
||||
this.visibilityRuleContext.rules.splice(index, 1);
|
||||
});
|
||||
|
||||
|
||||
|
||||
// * Remove from computational map
|
||||
|
||||
// as a target
|
||||
if (this.elementComputationalMap.get(id)) {
|
||||
this.elementComputationalMap.delete(id);
|
||||
}
|
||||
|
||||
|
||||
// as a source
|
||||
const keyIterator = this.elementComputationalMap.keys();
|
||||
let currentKey = keyIterator.next();
|
||||
|
||||
|
||||
while (!currentKey.done) {
|
||||
const currentVals = this.elementComputationalMap.get(currentKey.value);
|
||||
currentVals.delete(id);
|
||||
currentKey = keyIterator.next();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public addNewRule(rule: Rule, currentVisibility = this.DEFAULTVISIBILITY): void {
|
||||
console.log('addNewRule: ' + rule + ' currentVisibility: ' + currentVisibility);
|
||||
|
||||
const targetId = rule.targetField;
|
||||
const sourceId = rule.sourceField;
|
||||
this.visibilityRuleContext.addToVisibilityRulesContext(rule);
|
||||
|
||||
|
||||
let visibilityMap = this.elementComputationalMap.get(targetId);
|
||||
|
||||
if (!visibilityMap) {
|
||||
visibilityMap = new Map<String, boolean>();
|
||||
this.elementComputationalMap.set(targetId, visibilityMap);
|
||||
}
|
||||
|
||||
visibilityMap.set(sourceId, currentVisibility);
|
||||
const isVisible = this._computeVisibility(targetId);
|
||||
|
||||
this._emitChangesIfNeeded(targetId, isVisible);
|
||||
this.elementVisibilityMap.set(targetId, isVisible);
|
||||
this.elementVisibilityMapSubject.next(this.elementVisibilityMap);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check what sourceId hides or shows the target field
|
||||
* return true if no rule found
|
||||
*/
|
||||
public checkTargetVisibilityProvidedBySource(sourceId: string, targetId: string): boolean {
|
||||
console.log('checkTargetVisibilityProvidedBySource: ' + sourceId + ' targetId: ' + targetId);
|
||||
|
||||
const computationalMap = this.elementComputationalMap.get(targetId);
|
||||
if (computationalMap) {
|
||||
return !!computationalMap.get(sourceId);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public getVisibilityRulesFromDescriptionTempalte(descriptionTemplate: DescriptionTemplate): Rule[] {
|
||||
console.log('getVisibilityRulesFromDescriptionTempalte: ' + descriptionTemplate);
|
||||
const result: Rule[] = this.getVisibilityRulesFromDescriptionTempalteSections(descriptionTemplate?.definition?.sections);
|
||||
return result;
|
||||
}
|
||||
|
||||
public getVisibilityRulesFromDescriptionTempalteSections(sections: DescriptionTemplateSection[]): Rule[] {
|
||||
console.log('getVisibilityRulesFromDescriptionTempalteSections: ' + sections);
|
||||
const result: Rule[] = [];
|
||||
|
||||
sections.forEach(section => {
|
||||
if (section.sections != null) { result.push(...this.getVisibilityRulesFromDescriptionTempalteSections(section.sections)); };
|
||||
section?.fieldSets?.forEach(fieldSet => {
|
||||
fieldSet?.fields?.forEach(field => {
|
||||
field.visibilityRules?.forEach(visibilityRule => {
|
||||
result.push({
|
||||
sourceField: field.id.toString(),
|
||||
targetField: visibilityRule.target,
|
||||
requiredValue: visibilityRule.value
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class MapWithDefault extends Map<string, boolean> {
|
||||
get(key) {
|
||||
console.log('MapWithDefault');
|
||||
if (!this.has(key)) {
|
||||
this.set(key, true);
|
||||
}
|
||||
return super.get(key);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<div class="demo-progress-bar-container">
|
||||
<div *ngIf="isEditor()" class="percentage d-flex justify-content-center">{{progressSoFar}} {{'GENERAL.PREPOSITIONS.OF' | translate}} {{total}}</div>
|
||||
<mat-progress-bar class="form-progress-bar" [ngClass]="{'progress-bar': isEditor()}" mode="determinate" [value]="value"></mat-progress-bar>
|
||||
<div *ngIf="isEditor()" class="percentage" [ngStyle]="{'padding-left': value ? value - 10 + '%' : 0 + '%' }">{{value}}%</div>
|
||||
</div>
|
|
@ -0,0 +1,16 @@
|
|||
.percentage {
|
||||
color: #212121;
|
||||
opacity: 0.7;
|
||||
font-weight: 400;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
border-radius: 20px;
|
||||
height: 11px;
|
||||
|
||||
}
|
||||
|
||||
::ng-deep .mat-progress-bar .mat-progress-bar-fill::after {
|
||||
border-radius: 20px !important;
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
import {ChangeDetectorRef, Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core';
|
||||
import { AbstractControl, UntypedFormArray, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
||||
import { BaseComponent } from '@common/base/base.component';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'app-form-progress-indication',
|
||||
templateUrl: './form-progress-indication.component.html',
|
||||
styleUrls: ['./form-progress-indication.component.scss']
|
||||
})
|
||||
export class FormProgressIndicationComponent extends BaseComponent implements OnInit, OnChanges {
|
||||
@Input() formGroup: UntypedFormGroup;
|
||||
@Input() isDmpEditor: boolean;
|
||||
@Input() isDatasetEditor: boolean;
|
||||
@Input() public progressValueAccuracy = 2;
|
||||
determinateProgressValue: number;
|
||||
progressSoFar: number;
|
||||
total: number;
|
||||
percent: number;
|
||||
|
||||
constructor(private visibilityRulesService: VisibilityRulesService) { super(); }
|
||||
|
||||
public value = 0;
|
||||
ngOnInit() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if(changes.formGroup) {
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
setTimeout(() => {this.calculateValueForProgressbar();});
|
||||
this.formGroup
|
||||
.valueChanges
|
||||
.pipe(takeUntil(this._destroyed))
|
||||
.subscribe(control => {
|
||||
setTimeout(() => {this.calculateValueForProgressbar();});
|
||||
});
|
||||
}
|
||||
|
||||
calculateValueForProgressbar() {
|
||||
if (this.isDmpEditor) {
|
||||
this.progressSoFar = this.countFormControlsValidForProgress(this.formGroup);
|
||||
this.total = this.countFormControlsRequiredFieldsForTotal(this.formGroup);
|
||||
} else if (this.isDatasetEditor) {
|
||||
this.progressSoFar = this.countFormControlsValidForProgress(this.formGroup) + this.countFormControlsWithValueForProgress(this.formGroup);
|
||||
this.total = this.countFormControlsRequiredFieldsForTotal(this.formGroup, true) + this.CountFormControlDepthLengthFotTotal(this.formGroup);
|
||||
} else {
|
||||
this.progressSoFar = this.countFormControlsWithValueForProgress(this.formGroup);
|
||||
this.total = this.CountFormControlDepthLengthFotTotal(this.formGroup);
|
||||
}
|
||||
this.percent = (this.progressSoFar / this.total) * 100;
|
||||
this.value = Number.parseFloat(this.percent.toPrecision(this.progressValueAccuracy));
|
||||
}
|
||||
|
||||
countFormControlsWithValueForProgress(formControl: AbstractControl): number {
|
||||
let valueCurent = 0;
|
||||
if (formControl instanceof UntypedFormGroup) {
|
||||
if (this.checkFormsIfIsFieldsAndVisible(formControl) && this.checkIfIsRequired((formControl as UntypedFormGroup))) {
|
||||
if (this.hasValue(formControl))
|
||||
valueCurent++;
|
||||
}
|
||||
if (this.chechFieldIfIsFieldSetAndVisible((formControl as UntypedFormGroup)) && this.checkIfIsRequired((formControl as UntypedFormGroup))) {
|
||||
valueCurent = valueCurent + this.compositeFieldsGetChildsForProgress(formControl);
|
||||
} else {
|
||||
Object.keys(formControl.controls).forEach(item => {
|
||||
const control = formControl.get(item);
|
||||
valueCurent = valueCurent + this.countFormControlsWithValueForProgress(control);
|
||||
});
|
||||
}
|
||||
} else if (formControl instanceof UntypedFormArray) {
|
||||
formControl.controls.forEach(item => {
|
||||
valueCurent = valueCurent + this.countFormControlsWithValueForProgress(item);
|
||||
});
|
||||
}
|
||||
return valueCurent;
|
||||
}
|
||||
private hasValue(formGroup: UntypedFormGroup): boolean {
|
||||
return formGroup.get('value').valid && formGroup.get('value').value != null && formGroup.get('value').value !== '' && (this.visibilityRulesService.isVisibleMap[formGroup.get('id').value] ?? true);
|
||||
}
|
||||
|
||||
private compositeFieldsGetChildsForProgress(formGroup: UntypedFormGroup): number {
|
||||
let valueCurent = 0;
|
||||
if (this.visibilityRulesService.isVisibleMap[formGroup.get('id').value] ?? true) {
|
||||
(formGroup.get('fields') as UntypedFormArray).controls.forEach((element: UntypedFormGroup) => {
|
||||
valueCurent = valueCurent + this.countFormControlsWithValueForProgress(element);
|
||||
});
|
||||
|
||||
(formGroup.get('multiplicityItems') as UntypedFormArray).controls.forEach((element: UntypedFormGroup) => {
|
||||
valueCurent = valueCurent + this.countFormControlsWithValueForProgress(element);
|
||||
});
|
||||
}
|
||||
return valueCurent;
|
||||
}
|
||||
|
||||
private checkIfIsRequired(formControl: UntypedFormGroup): boolean {
|
||||
return !!(formControl.get('validationRequired') && formControl.get('validationRequired').value);
|
||||
|
||||
}
|
||||
|
||||
private checkFormsIfIsFieldsAndVisible(formControl: UntypedFormGroup): boolean {
|
||||
if (formControl.contains('id') && formControl.contains('value')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private chechFieldIfIsFieldSetAndVisible(formControl: UntypedFormGroup): boolean {
|
||||
if (formControl.contains('id') && formControl.contains('fields')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CountFormControlDepthLengthFotTotal(formControl: AbstractControl): number {
|
||||
let valueCurent = 0;
|
||||
if (formControl instanceof UntypedFormArray) {
|
||||
formControl.controls.forEach(item => {
|
||||
valueCurent = valueCurent + this.CountFormControlDepthLengthFotTotal(item);
|
||||
});
|
||||
} else if (formControl instanceof UntypedFormGroup) {
|
||||
if ((formControl as UntypedFormGroup).contains('id') && (formControl as UntypedFormGroup).contains('value') && (this.visibilityRulesService.isVisibleMap[(formControl as UntypedFormGroup).get('id').value] ?? true) && this.checkIfIsRequired((formControl as UntypedFormGroup))) {
|
||||
valueCurent++;
|
||||
} else if ((formControl as UntypedFormGroup).contains('id') && (formControl as UntypedFormGroup).contains('fields')) {
|
||||
valueCurent = valueCurent + this.compositeFieldsGetChildsForTotal(formControl);
|
||||
} else {
|
||||
Object.keys(formControl.controls).forEach(item => {
|
||||
const control = formControl.get(item);
|
||||
valueCurent = valueCurent + this.CountFormControlDepthLengthFotTotal(control);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return valueCurent;
|
||||
}
|
||||
|
||||
private compositeFieldsGetChildsForTotal(formGroup: UntypedFormGroup): number {
|
||||
let valueCurent = 0;
|
||||
if (this.visibilityRulesService.isVisibleMap[formGroup.get('id').value] ?? true) {
|
||||
(formGroup.get('fields') as UntypedFormArray).controls.forEach((element: UntypedFormGroup) => {
|
||||
valueCurent = valueCurent + this.CountFormControlDepthLengthFotTotal(element);
|
||||
});
|
||||
(formGroup.get('multiplicityItems') as UntypedFormArray).controls.forEach((element: UntypedFormGroup) => {
|
||||
valueCurent = valueCurent + this.CountFormControlDepthLengthFotTotal(element);
|
||||
});
|
||||
}
|
||||
return valueCurent;
|
||||
}
|
||||
|
||||
countFormControlsValidForProgress(formControl: AbstractControl): number {
|
||||
let valueCurrent = 0;
|
||||
if (formControl instanceof UntypedFormControl) {
|
||||
if (this.controlRequired(formControl) && this.controlEnabled(formControl) && formControl.valid) {
|
||||
valueCurrent++;
|
||||
}
|
||||
} else if (formControl instanceof UntypedFormGroup) {
|
||||
Object.keys(formControl.controls).forEach(item => {
|
||||
const control = formControl.get(item);
|
||||
valueCurrent = valueCurrent + this.countFormControlsValidForProgress(control);
|
||||
});
|
||||
} else if (formControl instanceof UntypedFormArray) {
|
||||
formControl.controls.forEach(item => {
|
||||
valueCurrent = valueCurrent + this.countFormControlsValidForProgress(item);
|
||||
});
|
||||
}
|
||||
return valueCurrent;
|
||||
}
|
||||
|
||||
countFormControlsRequiredFieldsForTotal(formControl: AbstractControl, checkVisibility = false): number {
|
||||
let valueCurrent = 0;
|
||||
if (formControl instanceof UntypedFormControl) {
|
||||
if (this.controlRequired(formControl) && this.controlEnabled(formControl)) {
|
||||
valueCurrent++;
|
||||
}
|
||||
} else if (formControl instanceof UntypedFormGroup) {
|
||||
if(!checkVisibility || (!formControl.get('id')?.value || (this.visibilityRulesService.isVisibleMap[formControl.get('id').value] ?? true))) {
|
||||
Object.keys(formControl.controls).forEach(item => {
|
||||
const control = formControl.get(item);
|
||||
valueCurrent = valueCurrent + this.countFormControlsRequiredFieldsForTotal(control, checkVisibility);
|
||||
});
|
||||
}
|
||||
} else if (formControl instanceof UntypedFormArray) {
|
||||
formControl.controls.forEach(item => {
|
||||
valueCurrent = valueCurrent + this.countFormControlsRequiredFieldsForTotal(item, checkVisibility);
|
||||
});
|
||||
}
|
||||
return valueCurrent;
|
||||
}
|
||||
|
||||
controlRequired(formControl: AbstractControl) {
|
||||
if (formControl.validator) {
|
||||
const validator = formControl.validator({} as AbstractControl);
|
||||
if (validator && validator.required) {
|
||||
return true;
|
||||
}
|
||||
} else { return false }
|
||||
}
|
||||
|
||||
controlEnabled(formControl: AbstractControl) {
|
||||
if (formControl.enabled) {
|
||||
return true;
|
||||
} else { return false }
|
||||
}
|
||||
|
||||
isEditor(): boolean {
|
||||
return this.isDmpEditor || this.isDatasetEditor;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonFormsModule } from '@common/forms/common-forms.module';
|
||||
import { CommonUiModule } from '@common/ui/common-ui.module';
|
||||
import { FormProgressIndicationComponent } from './form-progress-indication.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonUiModule,
|
||||
CommonFormsModule
|
||||
],
|
||||
declarations: [
|
||||
FormProgressIndicationComponent
|
||||
],
|
||||
exports: [
|
||||
FormProgressIndicationComponent
|
||||
]
|
||||
})
|
||||
export class DescriptionFormProgressIndicationModule { }
|
|
@ -0,0 +1,6 @@
|
|||
export enum ToCEntryType {
|
||||
Page = 0,
|
||||
Section = 1,
|
||||
FieldSet = 2,
|
||||
Field = 3
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import { Guid } from "@common/types/guid";
|
||||
import { ToCEntryType } from "./toc-entry-type.enum";
|
||||
|
||||
export interface ToCEntry {
|
||||
id: string;
|
||||
label: string;
|
||||
subEntriesType: ToCEntryType;
|
||||
subEntries: ToCEntry[];
|
||||
type: ToCEntryType;
|
||||
// form: AbstractControl;
|
||||
numbering: string;
|
||||
ordinal: number;
|
||||
hidden?: boolean
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<div *ngFor="let entry of tocentries; index as idx">
|
||||
<!-- check if is visible -->
|
||||
<ng-container *ngIf="!hiddenEntries.includes(entry.id)">
|
||||
|
||||
<!-- Is fieldset and has no visible inputs -->
|
||||
<!-- <ng-container *ngIf="!(entry.type === tocEntryTypeEnum.FieldSet && !visibilityRulesService.scanIfChildsOfCompositeFieldHasVisibleItems(entry.form))"> TODO: add this bellow -->
|
||||
<ng-container *ngIf="!(entry.type === tocEntryTypeEnum.FieldSet)">
|
||||
|
||||
<span class="table-entry"
|
||||
(click)="toggleExpand(idx);navigateToFieldSet(entry, $event); onEntrySelected(entry)"
|
||||
[ngStyle]="calculateStyle(entry)"
|
||||
[ngClass]="calculateClass(entry)"
|
||||
>
|
||||
<span [class.text-danger]="showErrors && propertiesFormGroup.get('entry.id')?.invalid && ( entry.type === tocEntryTypeEnum.FieldSet || (entry.type !== tocEntryTypeEnum.FieldSet && !expandChildren[idx])) && invalidChildsVisible(entry) ">
|
||||
{{entry.numbering}}. {{entry.label}}
|
||||
</span>
|
||||
<!-- <mat-icon style="transform: translateY(3px);" class="text-danger"
|
||||
*ngIf="showErrors && entry.form.invalid && entry.type !== tocEntryTypeEnum.FieldSet && !expandChildren[idx]">
|
||||
priority_high
|
||||
</mat-icon> -->
|
||||
<!-- <ng-container *ngIf="entry.subEntries && entry.subEntries.length && !expandChildren[idx]">
|
||||
<small>
|
||||
({{entry.subEntries.length}})
|
||||
</small>
|
||||
|
||||
</ng-container> -->
|
||||
</span>
|
||||
<!-- <div class="table-entry-container">
|
||||
</div> -->
|
||||
<div class="internal-table">
|
||||
<table-of-contents-internal
|
||||
[tocentries]="entry.subEntries"
|
||||
*ngIf="entry.subEntries && entry.subEntries.length && expandChildren[idx]"
|
||||
(entrySelected)="onEntrySelected($event)"
|
||||
[selected]="selected"
|
||||
[TOCENTRY_ID_PREFIX]="TOCENTRY_ID_PREFIX"
|
||||
[showErrors]="showErrors"
|
||||
[hiddenEntries]="hiddenEntries"
|
||||
[visibilityRulesService]="visibilityRulesService"
|
||||
>
|
||||
|
||||
</table-of-contents-internal>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
|
||||
|
||||
</ng-container>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
.internal-table{
|
||||
margin-left: 1em;
|
||||
padding-left: 0.2rem;
|
||||
|
||||
}
|
||||
.table-entry{
|
||||
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
padding-left: 0.2rem;
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
transition: color 100ms;
|
||||
|
||||
display: block;
|
||||
span{
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.table-entry:hover{
|
||||
background-color: #ececec;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.selected {
|
||||
color: #212121 !important;
|
||||
font-weight: 700 !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.section{
|
||||
line-height: 1.7em;
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
import { Component, EventEmitter, Input, OnInit, Output, QueryList, SimpleChanges, ViewChildren } from '@angular/core';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
||||
import { Guid } from '@common/types/guid';
|
||||
import { ToCEntry } from '../models/toc-entry';
|
||||
import { ToCEntryType } from '../models/toc-entry-type.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'table-of-contents-internal',
|
||||
styleUrls: ['./table-of-contents-internal.scss'],
|
||||
templateUrl: './table-of-contents-internal.html'
|
||||
})
|
||||
export class TableOfContentsInternal implements OnInit {
|
||||
|
||||
@Input() tocentries: ToCEntry[] = null;
|
||||
@Input() selected: ToCEntry = null;
|
||||
// @Input() visibilityRules:Rule[] = [];
|
||||
@Output() entrySelected = new EventEmitter<ToCEntry>();
|
||||
@Input() propertiesFormGroup: UntypedFormGroup;
|
||||
|
||||
expandChildren: boolean[];
|
||||
tocEntryTypeEnum = ToCEntryType;
|
||||
@Input() TOCENTRY_ID_PREFIX = "";
|
||||
@Input() showErrors: boolean = false;
|
||||
@Input() hiddenEntries: string[] = [];
|
||||
@Input() visibilityRulesService: VisibilityRulesService;
|
||||
@ViewChildren(TableOfContentsInternal) internalTables: QueryList<TableOfContentsInternal>;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
ngOnInit(): void {
|
||||
// console.log('component created');
|
||||
if (this.tocentries) {
|
||||
this.expandChildren = this.tocentries.map(() => false);
|
||||
if (this.selected) {
|
||||
for (let i = 0; i < this.tocentries.length; i++) {
|
||||
if (this._findTocEntryById(this.selected.id, this.tocentries[i].subEntries)) {
|
||||
if (this.expandChildren) {
|
||||
this.expandChildren[i] = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes.selected && this.selected) {
|
||||
for (let i = 0; i < this.tocentries.length; i++) {
|
||||
if (this._findTocEntryById(this.selected.id, this.tocentries[i].subEntries)) {
|
||||
if (this.expandChildren) {
|
||||
this.expandChildren[i] = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (!this.isActive && this.links && this.links.length > 0) {
|
||||
// this.links.forEach(link => {
|
||||
// link.selected = false;
|
||||
// })
|
||||
// this.links[0].selected = true;
|
||||
// }
|
||||
}
|
||||
|
||||
toggleExpand(index) {
|
||||
this.expandChildren[index] = !this.expandChildren[index];
|
||||
// console.log(this.expandChildren);
|
||||
}
|
||||
|
||||
navigateToFieldSet(entry: ToCEntry, event) {
|
||||
if (entry.type === ToCEntryType.FieldSet) {
|
||||
|
||||
const fieldSetId = entry.id;
|
||||
const element = document.getElementById(this.TOCENTRY_ID_PREFIX + fieldSetId);
|
||||
if (element) {
|
||||
element.click();//open mat expansion panel
|
||||
|
||||
//scroll asyn in 200 ms so the expansion panel is expanded and the element coordinates are updated
|
||||
setTimeout(() => {
|
||||
const element = document.getElementById(this.TOCENTRY_ID_PREFIX + fieldSetId);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onEntrySelected(entry: ToCEntry) {
|
||||
this.entrySelected.emit(entry);
|
||||
}
|
||||
|
||||
|
||||
calculateStyle(entry: ToCEntry) {
|
||||
const style = {};
|
||||
style['font-size'] = entry.type === this.tocEntryTypeEnum.FieldSet ? '.9em' : '1em';
|
||||
return style;
|
||||
}
|
||||
|
||||
calculateClass(entry: ToCEntry) {
|
||||
const myClass = {};
|
||||
|
||||
if (this.selected && entry.id === this.selected.id) {
|
||||
myClass['selected'] = true;
|
||||
}
|
||||
|
||||
if (entry.type != this.tocEntryTypeEnum.FieldSet) {
|
||||
myClass['section'] = true;
|
||||
}
|
||||
|
||||
return myClass;
|
||||
}
|
||||
|
||||
private _findTocEntryById(id: string, tocentries: ToCEntry[]): ToCEntry {
|
||||
if (!tocentries || !tocentries.length) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return tocEntryFound ? tocEntryFound : null;
|
||||
}
|
||||
public invalidChildsVisible(entry: ToCEntry): boolean {
|
||||
if (!entry || !this.visibilityRulesService) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry.type != this.tocEntryTypeEnum.FieldSet) {
|
||||
return entry.subEntries.some(_ => this.invalidChildsVisible(_));
|
||||
}
|
||||
if (entry.type === this.tocEntryTypeEnum.FieldSet) {
|
||||
const id = entry.id;
|
||||
if (!(this.visibilityRulesService.isVisibleMap[id.toString()] ?? true)) {
|
||||
return false;
|
||||
}
|
||||
// const fieldsArray = entry.form.get('fields') as UntypedFormArray;
|
||||
const hasError = !entry.subEntries.every(field => {//every invalid field should be invisible
|
||||
//TODO: check this
|
||||
// if (field.invalid) {
|
||||
// const id = field.id;
|
||||
// const isVisible = this.visibilityRulesService.isVisibleMap[id);
|
||||
// if (isVisible) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
return true;
|
||||
});
|
||||
return hasError;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<div *ngIf="links?.length" class="docs-toc-container">
|
||||
<div class="scroll-container">
|
||||
<span *ngFor="let link of links; let i = index" (click)="toggle(link); goToStep(link)" class="docs-level-{{link.type}} docs-link mt-0" [class.docs-active]="link.active">
|
||||
<span *ngIf="link.show" class="link-name"><span [class.selected]="link.selected && isActive">{{link.name}}</span></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="tocentries" class="docs-toc-container">
|
||||
|
||||
<div class="scroll-container col-12 internal-table">
|
||||
<table-of-contents-internal #internalTable [TOCENTRY_ID_PREFIX]="TOCENTRY_ID_PREFIX" [tocentries]="tocentries"
|
||||
[showErrors]="showErrors"
|
||||
(entrySelected)="onToCentrySelected($event)"
|
||||
[selected]="tocentrySelected"
|
||||
[hiddenEntries]="hiddenEntries"
|
||||
[visibilityRulesService]="visibilityRulesService"
|
||||
[propertiesFormGroup]="propertiesFormGroup"
|
||||
>
|
||||
|
||||
</table-of-contents-internal>
|
||||
</div>
|
||||
</div>
|
||||
{{hiddenEntries | json}}
|
|
@ -0,0 +1,80 @@
|
|||
.docs-toc-container {
|
||||
width: 100%;
|
||||
padding: 5px 0 10px 0px;
|
||||
cursor: pointer;
|
||||
// border-left: solid 4px #0c7489;
|
||||
|
||||
.scroll-container {
|
||||
overflow-y: auto;
|
||||
// calc(100vh - 250px)
|
||||
// height: calc(100vh - 250px);
|
||||
}
|
||||
|
||||
.docs-link {
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
// color: mat-color($app-blue-theme-foreground, secondary-text);
|
||||
transition: color 100ms;
|
||||
|
||||
&:hover,
|
||||
&.docs-active {
|
||||
.link-name {
|
||||
background-color: #ececec;
|
||||
border-radius: 6px;
|
||||
// color: #0c7489;
|
||||
}
|
||||
// color: mat-color($primary, if($is-dark-theme, 200, default));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.docs-toc-heading {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span {
|
||||
line-height: 16px;
|
||||
margin: 6px 0 0;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
color: #21212194;
|
||||
font-weight: 400;
|
||||
max-width: 290px;
|
||||
min-width: 290px;
|
||||
padding: 0rem .4rem;
|
||||
span {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.selected {
|
||||
color: #212121 !important;
|
||||
font-weight: 700 !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
// .docs-level-mat-expansion-panel {
|
||||
// margin-left: 12px;
|
||||
// }
|
||||
|
||||
.docs-level-h5 {
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
// .internal-table-outer{
|
||||
// padding-left: 1.1em;
|
||||
// width: 100%;
|
||||
// }
|
||||
|
||||
.internal-table{
|
||||
max-width: 320px;
|
||||
min-width: 320px;
|
||||
}
|
|
@ -0,0 +1,514 @@
|
|||
import { DOCUMENT } from '@angular/common';
|
||||
import { Component, EventEmitter, Inject, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
import { DescriptionTemplate, DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplateSection } from '@app/core/model/description-template/description-template';
|
||||
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
||||
import { BaseComponent } from '@common/base/base.component';
|
||||
import { Subject, Subscription, interval } from 'rxjs';
|
||||
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';
|
||||
|
||||
export interface Link {
|
||||
/* id of the section*/
|
||||
id: string;
|
||||
/* header type h3/h4 */
|
||||
type: string;
|
||||
/* If the anchor is in view of the page */
|
||||
active: boolean;
|
||||
/* name of the anchor */
|
||||
name: string;
|
||||
/* top offset px of the anchor */
|
||||
top: number;
|
||||
page: number;
|
||||
section: number;
|
||||
show: boolean;
|
||||
selected: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-table-of-contents',
|
||||
styleUrls: ['./table-of-contents.component.scss'],
|
||||
templateUrl: './table-of-contents.component.html'
|
||||
})
|
||||
export class TableOfContentsComponent extends BaseComponent implements OnInit, OnChanges {
|
||||
|
||||
@ViewChild('internalTable') internalTable: TableOfContentsInternal;
|
||||
|
||||
|
||||
@Input() links: Link[];
|
||||
container: string;
|
||||
headerSelectors = '.toc-page-header, .toc-section-header, .toc-compositeField-header';
|
||||
@Output() stepFound = new EventEmitter<LinkToScroll>();
|
||||
@Output() currentLinks = new EventEmitter<Link[]>();
|
||||
@Output() entrySelected = new EventEmitter<any>();
|
||||
subscription: Subscription;
|
||||
linksSubject: Subject<HTMLElement[]> = new Subject<HTMLElement[]>();
|
||||
|
||||
@Input() isActive: boolean;
|
||||
|
||||
tocentries: ToCEntry[] = null;
|
||||
@Input() TOCENTRY_ID_PREFIX = '';
|
||||
@Input() showErrors: boolean = false;
|
||||
@Input() selectedFieldsetId: string;
|
||||
|
||||
private _tocentrySelected: ToCEntry = null;
|
||||
private isSelecting: boolean = false;
|
||||
private _intersectionObserver: IntersectionObserver;
|
||||
private _actOnObservation: boolean = true;
|
||||
public hiddenEntries: string[] = [];
|
||||
get tocentrySelected() {
|
||||
return this.hasFocus ? this._tocentrySelected : null;
|
||||
}
|
||||
set tocentrySelected(value) {
|
||||
this._tocentrySelected = value;
|
||||
}
|
||||
|
||||
@Input() propertiesFormGroup: UntypedFormGroup;
|
||||
@Input() descriptionTemplate: DescriptionTemplate;
|
||||
@Input() hasFocus: boolean = false;
|
||||
@Input() visibilityRulesService: VisibilityRulesService;
|
||||
show: boolean = false;
|
||||
|
||||
constructor(
|
||||
@Inject(DOCUMENT) private _document: Document,
|
||||
// public visibilityRulesService: VisibilityRulesService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
if (this.descriptionTemplate) {
|
||||
this.tocentries = this.getTocEntries(this.descriptionTemplate);
|
||||
if (this.visibilityRulesService) {
|
||||
this.hiddenEntries = this._findHiddenEntries(this.tocentries);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
//emit value every 500ms
|
||||
const source = interval(500);
|
||||
this.subscription = source.subscribe(val => {
|
||||
const headers = Array.from(this._document.querySelectorAll(this.headerSelectors)) as HTMLElement[];
|
||||
this.linksSubject.next(headers);
|
||||
});
|
||||
|
||||
if (!this.links || this.links.length === 0) {
|
||||
this.linksSubject.asObservable()
|
||||
.pipe(distinctUntilChanged((p: HTMLElement[], q: HTMLElement[]) => JSON.stringify(p) == JSON.stringify(q)))
|
||||
.subscribe(headers => {
|
||||
const links: Array<Link> = [];
|
||||
|
||||
if (headers.length) {
|
||||
let page;
|
||||
let section;
|
||||
let show
|
||||
for (const header of headers) {
|
||||
let name;
|
||||
let id;
|
||||
if (header.classList.contains('toc-page-header')) { // deprecated after removing stepper
|
||||
name = header.innerText.trim().replace(/^link/, '');
|
||||
id = header.id;
|
||||
page = header.id.split('_')[1];
|
||||
section = undefined;
|
||||
show = true;
|
||||
} else if (header.classList.contains('toc-section-header')) {
|
||||
name = header.childNodes[0].childNodes[0].childNodes[0].childNodes[0].childNodes[0].nodeValue.trim().replace(/^link/, '');
|
||||
id = header.id;
|
||||
page = header.id.split('.')[1];
|
||||
section = header.id;
|
||||
if (header.id.split('.')[4]) { show = false; }
|
||||
else { show = true; }
|
||||
} else if (header.classList.contains('toc-compositeField-header')) {
|
||||
name = (header.childNodes[0]).nodeValue.trim().replace(/^link/, '');
|
||||
id = header.id;
|
||||
// id = header.parentElement.parentElement.parentElement.id;
|
||||
show = false;
|
||||
}
|
||||
const { top } = header.getBoundingClientRect();
|
||||
links.push({
|
||||
name,
|
||||
id,
|
||||
type: header.tagName.toLowerCase(),
|
||||
top: top,
|
||||
active: false,
|
||||
page: page,
|
||||
section: section,
|
||||
show: show,
|
||||
selected: false
|
||||
});
|
||||
}
|
||||
}
|
||||
this.links = links;
|
||||
// Initialize selected for button next on dataset wizard component editor
|
||||
this.links.length > 0 ? this.links[0].selected = true : null;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private _findHiddenEntries(tocentries: ToCEntry[]): string[] {
|
||||
if (!tocentries) return [];
|
||||
|
||||
const invisibleEntries: string[] = []
|
||||
tocentries.forEach(entry => {
|
||||
if (entry.type === ToCEntryType.FieldSet) {
|
||||
const isVisible = this.visibilityRulesService.isVisibleMap[entry.id.toString()] ?? true;
|
||||
if (!isVisible) {
|
||||
invisibleEntries.push(entry.id.toString());
|
||||
} else {
|
||||
//check field inputs
|
||||
const oneFieldAtLeastIsVisible = entry.subEntries.some(field => this.visibilityRulesService.isVisibleMap[field.id.toString()] ?? true);
|
||||
if (!oneFieldAtLeastIsVisible) {
|
||||
invisibleEntries.push(entry.id.toString());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const hiddenEntries = this._findHiddenEntries(entry.subEntries);
|
||||
|
||||
if (entry.subEntries && (entry.subEntries.every(e => hiddenEntries.includes(e.id.toString())))) {
|
||||
//all children all hidden then hide parent node;
|
||||
invisibleEntries.push(entry.id.toString());
|
||||
} else {
|
||||
invisibleEntries.push(...hiddenEntries);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return invisibleEntries;
|
||||
}
|
||||
|
||||
private _visibilityRulesSubscription: Subscription;
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
|
||||
if (this.selectedFieldsetId) {
|
||||
this.onToCentrySelected(this._findTocEntryById(this.selectedFieldsetId, this.tocentries), false);
|
||||
this._actOnObservation = false;
|
||||
setTimeout(() => {
|
||||
this._actOnObservation = true;
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (changes['hasFocus'] && changes.hasFocus.currentValue) {
|
||||
this._resetObserver();
|
||||
|
||||
}
|
||||
|
||||
if ('visibilityRulesService') {
|
||||
if (this._visibilityRulesSubscription) {
|
||||
this._visibilityRulesSubscription.unsubscribe();
|
||||
this._visibilityRulesSubscription = null;
|
||||
}
|
||||
|
||||
if (!this.visibilityRulesService) return;
|
||||
|
||||
this._visibilityRulesSubscription = this.visibilityRulesService.visibilityChange
|
||||
.pipe(takeUntil(this._destroyed))
|
||||
.pipe(debounceTime(200))
|
||||
.subscribe(_ => {
|
||||
if (this.hasFocus) {
|
||||
this._resetObserver();
|
||||
this.hiddenEntries = this._findHiddenEntries(this.tocentries);
|
||||
}
|
||||
});
|
||||
this.hiddenEntries = this._findHiddenEntries(this.tocentries);
|
||||
}
|
||||
// if (!this.isActive && this.links && this.links.length > 0) {
|
||||
// this.links.forEach(link => {
|
||||
// link.selected = false;
|
||||
// })
|
||||
// this.links[0].selected = true;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
private _resetObserver() {
|
||||
if (this._intersectionObserver) {//clean up
|
||||
this._intersectionObserver.disconnect();
|
||||
this._intersectionObserver = null;
|
||||
}
|
||||
|
||||
const options = {
|
||||
root: null,
|
||||
rootMargin: '-38% 0px -60% 0px',
|
||||
threshold: 0
|
||||
}
|
||||
|
||||
this._intersectionObserver = new IntersectionObserver((entries, observer) => {
|
||||
if (!this._actOnObservation) {
|
||||
return;
|
||||
}
|
||||
|
||||
entries.forEach(ie => {
|
||||
if (ie.isIntersecting) {
|
||||
try {
|
||||
const target_id = ie.target.id.replace(this.TOCENTRY_ID_PREFIX, '');
|
||||
if (this.visibilityRulesService.isVisibleMap[target_id] ?? true) {
|
||||
this.onToCentrySelected(this._findTocEntryById(target_id, this.tocentries));
|
||||
}
|
||||
} catch {
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
}, options);
|
||||
|
||||
const fieldsetsEtries = this._getAllFieldSets(this.tocentries);
|
||||
|
||||
fieldsetsEtries.forEach(e => {
|
||||
if (e.type === ToCEntryType.FieldSet) {
|
||||
try {
|
||||
const targetElement = document.getElementById(this.TOCENTRY_ID_PREFIX + e.id);
|
||||
this._intersectionObserver.observe(targetElement);
|
||||
} catch {
|
||||
console.log('element not found');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
goToStep(link: Link) {
|
||||
this.stepFound.emit({
|
||||
page: link.page,
|
||||
section: link.section
|
||||
});
|
||||
this.currentLinks.emit(this.links);
|
||||
|
||||
setTimeout(() => {
|
||||
const target = document.getElementById(link.id);
|
||||
target.scrollIntoView(true);
|
||||
|
||||
var scrolledY = window.scrollY;
|
||||
if (scrolledY) {
|
||||
window.scroll(0, scrolledY - 70);
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
toggle(headerLink: Link) {
|
||||
const headerPage = +headerLink.name.split(" ", 1);
|
||||
let innerPage;
|
||||
for (const link of this.links) {
|
||||
link.selected = false;
|
||||
if (link.type === 'mat-expansion-panel') {
|
||||
innerPage = +link.name.split(".", 1)[0];
|
||||
if (isNaN(innerPage)) { innerPage = +link.name.split(" ", 1) }
|
||||
} else if (link.type === 'h5') {
|
||||
innerPage = +link.name.split(".", 1)[0];
|
||||
}
|
||||
if (headerPage === innerPage && (link.type !== 'mat-expansion-panel' || (link.type === 'mat-expansion-panel' && link.id.split(".")[4]))) {
|
||||
link.show = !link.show;
|
||||
}
|
||||
}
|
||||
headerLink.selected = true;
|
||||
}
|
||||
|
||||
// getIndex(link: Link): number {
|
||||
// return +link.id.split("_", 2)[1];
|
||||
// }
|
||||
|
||||
|
||||
private _buildRecursivelySection(item: DescriptionTemplateSection): ToCEntry {
|
||||
if (!item) return null;
|
||||
|
||||
const sections = item.sections;
|
||||
const fieldsets = item.fieldSets;
|
||||
|
||||
|
||||
const tempResult: ToCEntry[] = [];
|
||||
|
||||
if (sections && sections.length) {
|
||||
sections.forEach(section => {
|
||||
tempResult.push(this._buildRecursivelySection(section));
|
||||
});
|
||||
|
||||
} else if (fieldsets && fieldsets.length) {
|
||||
fieldsets.forEach(fieldset => {
|
||||
tempResult.push(this._buildRecursivelyFieldSet(fieldset));
|
||||
});
|
||||
}
|
||||
return {
|
||||
// form: form,
|
||||
id: item.id,
|
||||
label: item.title,
|
||||
numbering: '',
|
||||
subEntries: tempResult,
|
||||
subEntriesType: sections && sections.length ? ToCEntryType.Section : ToCEntryType.FieldSet,
|
||||
type: ToCEntryType.Section,
|
||||
ordinal: item.ordinal
|
||||
}
|
||||
}
|
||||
|
||||
private _buildRecursivelyFieldSet(item: DescriptionTemplateFieldSet): ToCEntry {
|
||||
if (!item) return null;
|
||||
const tempResult: ToCEntry[] = [];
|
||||
if (item && item.fields.length > 0) {
|
||||
item.fields.forEach(field => {
|
||||
tempResult.push(this._buildRecursivelyField(field));
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
// form: form,
|
||||
id: item.id,
|
||||
label: item.title,
|
||||
numbering: 's',
|
||||
subEntries: tempResult,
|
||||
subEntriesType: ToCEntryType.Field,
|
||||
type: ToCEntryType.FieldSet,
|
||||
ordinal: item.ordinal
|
||||
};
|
||||
}
|
||||
|
||||
private _buildRecursivelyField(item: DescriptionTemplateField): ToCEntry {
|
||||
if (!item) return null;
|
||||
return {
|
||||
// form: form,
|
||||
id: item.id,
|
||||
label: null,
|
||||
numbering: 's',
|
||||
subEntries: null,
|
||||
subEntriesType: null,
|
||||
type: ToCEntryType.Field,
|
||||
ordinal: item.ordinal,
|
||||
hidden: true
|
||||
};
|
||||
}
|
||||
|
||||
private _sortByOrdinal(tocentries: ToCEntry[]) {
|
||||
|
||||
if (!tocentries || !tocentries.length) return;
|
||||
|
||||
tocentries.sort(this._customCompare);
|
||||
tocentries.forEach(entry => {
|
||||
this._sortByOrdinal(entry.subEntries);
|
||||
});
|
||||
}
|
||||
|
||||
private _customCompare(a, b) {
|
||||
return a.ordinal - b.ordinal;
|
||||
}
|
||||
|
||||
private _calculateNumbering(tocentries: ToCEntry[], depth: number[] = []) {
|
||||
if (!tocentries || !tocentries.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let prefixNumbering = depth.length ? depth.join('.') : '';
|
||||
|
||||
if (depth.length) prefixNumbering = prefixNumbering + ".";
|
||||
tocentries.forEach((entry, i) => {
|
||||
entry.numbering = prefixNumbering + (i + 1);
|
||||
this._calculateNumbering(entry.subEntries, [...depth, i + 1])
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
getTocEntries(descriptionTemplate: DescriptionTemplate): ToCEntry[] {
|
||||
if (descriptionTemplate == null) { return []; }
|
||||
const result: ToCEntry[] = [];
|
||||
|
||||
//build parent pages
|
||||
descriptionTemplate.definition.pages.forEach((pageElement, i) => {
|
||||
const tocEntry: ToCEntry = {
|
||||
// id: i + 'id',
|
||||
id: pageElement.id,
|
||||
label: pageElement.title,
|
||||
type: ToCEntryType.Page,
|
||||
// form: pageElement,
|
||||
numbering: (i + 1).toString(),
|
||||
subEntriesType: ToCEntryType.Section,
|
||||
subEntries: [],
|
||||
ordinal: pageElement.ordinal
|
||||
};
|
||||
|
||||
const sections = descriptionTemplate.definition.sections.filter(x => x.page == pageElement.id);
|
||||
|
||||
sections.forEach(section => {
|
||||
const tempResults = this._buildRecursivelySection(section);
|
||||
tocEntry.subEntries.push(tempResults);
|
||||
});
|
||||
result.push(tocEntry)
|
||||
});
|
||||
|
||||
this._sortByOrdinal(result);
|
||||
//calculate numbering
|
||||
this._calculateNumbering(result);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
onToCentrySelected(entry: ToCEntry = null, execute: boolean = true) {
|
||||
if (!this.isSelecting) {
|
||||
this.isSelecting = true;
|
||||
this.tocentrySelected = entry;
|
||||
this.entrySelected.emit({ entry: entry, execute: execute });
|
||||
setTimeout(() => {
|
||||
this.isSelecting = false;
|
||||
}, 600);
|
||||
}
|
||||
}
|
||||
|
||||
private _findTocEntryById(id: string, tocentries: ToCEntry[]): ToCEntry {
|
||||
if (!tocentries || !tocentries.length) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return tocEntryFound ? tocEntryFound : null;
|
||||
}
|
||||
/**
|
||||
* Get all filedsets in a tocentry array;
|
||||
* @param entries Tocentries to search in
|
||||
* @returns The tocentries that are Fieldsets provided in the entries
|
||||
*/
|
||||
private _getAllFieldSets(entries: ToCEntry[]): ToCEntry[] {
|
||||
|
||||
const fieldsets: ToCEntry[] = [];
|
||||
if (!entries || !entries.length) return fieldsets;
|
||||
|
||||
|
||||
entries.forEach(e => {
|
||||
if (e.type === ToCEntryType.FieldSet) {
|
||||
fieldsets.push(e);
|
||||
} else {
|
||||
fieldsets.push(...this._getAllFieldSets(e.subEntries));
|
||||
}
|
||||
});
|
||||
return fieldsets;
|
||||
}
|
||||
|
||||
|
||||
public hasVisibleInvalidFields(): boolean {
|
||||
if (!this.internalTable || !this.tocentries) {
|
||||
return false;
|
||||
}
|
||||
return this.tocentries.some(e => this.internalTable.invalidChildsVisible(e));
|
||||
}
|
||||
|
||||
protected readonly console = console;
|
||||
}
|
||||
|
||||
export interface LinkToScroll {
|
||||
page: number;
|
||||
section: number;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import {CommonModule} from '@angular/common';
|
||||
import {NgModule} from '@angular/core';
|
||||
import {RouterModule} from '@angular/router';
|
||||
import { TableOfContentsInternal } from './table-of-contents-internal/table-of-contents-internal';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
|
||||
import { TableOfContentsComponent } from './table-of-contents.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, RouterModule, MatIconModule],
|
||||
declarations: [TableOfContentsComponent, TableOfContentsInternal],
|
||||
exports: [TableOfContentsComponent],
|
||||
providers: [VisibilityRulesService]
|
||||
})
|
||||
export class TableOfContentsModule { }
|
|
@ -0,0 +1,27 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { FormattingModule } from '@app/core/formatting.module';
|
||||
import { UrlListingModule } from '@app/library/url-listing/url-listing.module';
|
||||
import { DescriptionListingComponent } from '@app/ui/description/listing/description-listing.component';
|
||||
import { DescriptionListingItemComponent } from '@app/ui/description/listing/listing-item/description-listing-item.component';
|
||||
import { CommonFormsModule } from '@common/forms/common-forms.module';
|
||||
import { CommonUiModule } from '@common/ui/common-ui.module';
|
||||
import { DescriptionListingRoutingModule } from './description-listing.routing';
|
||||
import { DescriptionCopyDialogModule } from '../description-copy-dialog/description-copy-dialog.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonUiModule,
|
||||
CommonFormsModule,
|
||||
UrlListingModule,
|
||||
FormattingModule,
|
||||
DescriptionCopyDialogModule,
|
||||
DescriptionListingRoutingModule
|
||||
],
|
||||
declarations: [
|
||||
DescriptionListingComponent,
|
||||
DescriptionListingItemComponent,
|
||||
],
|
||||
exports: [
|
||||
]
|
||||
})
|
||||
export class DescriptionListingModule { }
|
|
@ -0,0 +1,30 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { AuthGuard } from '@app/core/auth-guard.service';
|
||||
import { DescriptionListingComponent } from './description-listing.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: DescriptionListingComponent,
|
||||
// canActivate: [AuthGuard],
|
||||
data: {
|
||||
breadcrumb: true
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'dmp/:dmpId',
|
||||
component: DescriptionListingComponent,
|
||||
canActivate: [AuthGuard],
|
||||
data: {
|
||||
breadcrumb: true
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
providers: []
|
||||
})
|
||||
export class DescriptionListingRoutingModule { }
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue