no message
This commit is contained in:
parent
2b074f268d
commit
c08f05bc04
|
@ -35,7 +35,7 @@ public enum FieldType implements DatabaseEnum<String> {
|
|||
ORGANIZATIONS("organizations"),
|
||||
DATASET_IDENTIFIER("datasetIdentifier"),
|
||||
CURRENCY("currency"),
|
||||
VALIDATION("validation");;
|
||||
VALIDATION("validation");
|
||||
private final String value;
|
||||
|
||||
FieldType(String value) {
|
||||
|
|
|
@ -122,7 +122,7 @@ public class FieldEntity implements DatabaseViewStyleDefinition, XmlSerializable
|
|||
viewStyle.setAttribute("renderstyle", FieldType.INTERNAL_DMP_ENTRIES.getValue());
|
||||
break;
|
||||
}
|
||||
case BOOLEAN_DECISION: viewStyle.setAttribute("renderstyle", this.data.getFieldType().getValue());;
|
||||
case BOOLEAN_DECISION: viewStyle.setAttribute("renderstyle", this.data.getFieldType().getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@ import org.hibernate.annotations.GenericGenerator;
|
|||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "\"UserDatasetProfile\"")
|
||||
//@Entity
|
||||
//@Table(name = "\"UserDatasetProfile\"")
|
||||
public class UserDatasetProfile implements DataEntity<UserDatasetProfile, UUID> {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
|
|
|
@ -10,30 +10,30 @@ public class FieldSetPersist {
|
|||
|
||||
@NotNull(message = "{validation.empty}")
|
||||
@NotEmpty(message = "{validation.empty}")
|
||||
private String id = null;;
|
||||
private String id = null;
|
||||
|
||||
@NotNull(message = "{validation.empty}")
|
||||
private Integer ordinal = null;;
|
||||
private Integer ordinal = null;
|
||||
|
||||
@NotNull(message = "{validation.empty}")
|
||||
@NotEmpty(message = "{validation.empty}")
|
||||
private String numbering = null;;
|
||||
private String numbering = null;
|
||||
|
||||
@NotNull(message = "{validation.empty}")
|
||||
@NotEmpty(message = "{validation.empty}")
|
||||
private String title = null;;
|
||||
private String title = null;
|
||||
|
||||
@NotNull(message = "{validation.empty}")
|
||||
@NotEmpty(message = "{validation.empty}")
|
||||
private String description = null;;
|
||||
private String description = null;
|
||||
|
||||
@NotNull(message = "{validation.empty}")
|
||||
@NotEmpty(message = "{validation.empty}")
|
||||
private String extendedDescription = null;;
|
||||
private String extendedDescription = null;
|
||||
|
||||
@NotNull(message = "{validation.empty}")
|
||||
@NotEmpty(message = "{validation.empty}")
|
||||
private String additionalInformation = null;;
|
||||
private String additionalInformation = null;
|
||||
|
||||
@NotNull(message = "{validation.empty}")
|
||||
@Valid
|
||||
|
|
|
@ -256,7 +256,7 @@ public class DmpBlueprintServiceImpl implements DmpBlueprintService {
|
|||
}
|
||||
|
||||
private void reassignDefinition(Definition model){
|
||||
if (model == null) return;;
|
||||
if (model == null) return;
|
||||
|
||||
if (model.getSections() != null){
|
||||
for (Section section : model.getSections()) {
|
||||
|
@ -266,7 +266,7 @@ public class DmpBlueprintServiceImpl implements DmpBlueprintService {
|
|||
}
|
||||
|
||||
private void reassignSection(Section model){
|
||||
if (model == null) return;;
|
||||
if (model == null) return;
|
||||
model.setId(UUID.randomUUID());
|
||||
|
||||
if (model.getFields() != null){
|
||||
|
|
|
@ -3,8 +3,12 @@ package eu.eudat.service.fielddatahelper;
|
|||
import eu.eudat.commons.enums.FieldType;
|
||||
import gr.cite.tools.data.builder.Builder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class FieldDataHelperServiceProvider {
|
||||
|
||||
@Autowired
|
||||
|
|
|
@ -71,7 +71,7 @@ public class FileController {
|
|||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
String json = mapper.writeValueAsString(datasetprofile.getSections());;
|
||||
String json = mapper.writeValueAsString(datasetprofile.getSections());
|
||||
JsonNode propertiesJson = mapper.readTree(json);
|
||||
Set<JsonNode> fieldNodes = new HashSet<>();
|
||||
fieldNodes.addAll(JsonSearcher.findNodes(propertiesJson, "id", fieldId, false));
|
||||
|
|
|
@ -666,7 +666,7 @@ public class DatasetManager {
|
|||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
String json = mapper.writeValueAsString(datasetWizardModel.getDatasetProfileDefinition());;
|
||||
String json = mapper.writeValueAsString(datasetWizardModel.getDatasetProfileDefinition());
|
||||
JsonNode propertiesJson = mapper.readTree(json);
|
||||
|
||||
Set<JsonNode> uploadNodes = new HashSet<>();
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
export enum DescriptionTemplateFieldAutocompleteType {
|
||||
UNCACHED = 0,
|
||||
CACHED = 1
|
||||
}
|
|
@ -1,16 +1,17 @@
|
|||
import { DescriptionTemplateFieldAutocompleteType } from "@app/core/common/enum/description-template-field-autocomplete-type";
|
||||
import { DescriptionTemplateFieldDataExternalDatasetType } from "@app/core/common/enum/description-template-field-data-external-dataset-type";
|
||||
import { DescriptionTemplateFieldType } from "@app/core/common/enum/description-template-field-type";
|
||||
import { DescriptionTemplateFieldValidationType } from "@app/core/common/enum/description-template-field-validation-type";
|
||||
import { DescriptionTemplateStatus } from "@app/core/common/enum/description-template-status";
|
||||
import { BaseEntityPersist } from "@common/base/base-entity.model";
|
||||
import { Guid } from "@common/types/guid";
|
||||
import { DescriptionTemplateType } from "../description-template-type/description-template-type";
|
||||
|
||||
|
||||
export interface DescriptionTemplatePersist extends BaseEntityPersist {
|
||||
label: string;
|
||||
description: string;
|
||||
groupId: Guid;
|
||||
version: string;
|
||||
language: string;
|
||||
type: DescriptionTemplateType;
|
||||
type: Guid;
|
||||
status: DescriptionTemplateStatus;
|
||||
definition: DescriptionTemplateDefinitionPersist;
|
||||
}
|
||||
|
@ -32,11 +33,9 @@ export interface DescriptionTemplateSectionPersist {
|
|||
ordinal: number;
|
||||
defaultVisibility: boolean;
|
||||
multiplicity: boolean;
|
||||
numbering: string;
|
||||
page: string;
|
||||
title: string;
|
||||
description: string;
|
||||
extendedDescription: string;
|
||||
|
||||
sections?: DescriptionTemplateSectionPersist[];
|
||||
fieldSets: DescriptionTemplateFieldSetPersist[];
|
||||
|
@ -50,7 +49,7 @@ export interface DescriptionTemplateFieldSetPersist {
|
|||
description: string;
|
||||
extendedDescription: string;
|
||||
additionalInformation: string;
|
||||
multiplicity: DescriptionTemplateMultiplicityPersist
|
||||
multiplicity: DescriptionTemplateMultiplicityPersist;
|
||||
hasCommentField: boolean;
|
||||
fields: DescriptionTemplateFieldPersist[];
|
||||
}
|
||||
|
@ -58,12 +57,10 @@ export interface DescriptionTemplateFieldSetPersist {
|
|||
export interface DescriptionTemplateFieldPersist {
|
||||
id: Guid;
|
||||
ordinal: number;
|
||||
numbering: string;
|
||||
schematics: string[];
|
||||
defaultValue: string;
|
||||
visibilityRules: DescriptionTemplateRulePersist[];
|
||||
// validations: DescriptionTemplateFieldValidationType[];
|
||||
// fieldType: DescriptionTemplateFieldType;
|
||||
validations: DescriptionTemplateFieldValidationType[];
|
||||
includeInExport: boolean;
|
||||
data: DescriptionTemplateBaseFieldDataPersist;
|
||||
}
|
||||
|
@ -82,4 +79,151 @@ export interface DescriptionTemplateMultiplicityPersist {
|
|||
|
||||
export interface DescriptionTemplateBaseFieldDataPersist {
|
||||
label: string;
|
||||
fieldType: DescriptionTemplateFieldType;
|
||||
}
|
||||
|
||||
//
|
||||
// Field Types
|
||||
//
|
||||
export interface DescriptionTemplateAutoCompleteDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
multiAutoComplete: boolean;
|
||||
autoCompleteSingleDataList: DescriptionTemplateAutoCompleteSingleDataPersist[];
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateBooleanDecisionDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateDatasetAutoCompleteDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
multiAutoComplete: boolean;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateDmpAutoCompleteDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
multiAutoComplete: boolean;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateCheckBoxDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateDatePickerDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateExternalDatasetDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
multiAutoComplete: boolean;
|
||||
type: DescriptionTemplateFieldDataExternalDatasetType;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateFreeTextDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateLicenseDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
multiAutoComplete: boolean;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateOrganizationDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
multiAutoComplete: boolean;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplatePublicationDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
multiAutoComplete: boolean;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateRadioBoxDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
options: DescriptionTemplateRadioBoxOptionPersist;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateRegistryDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
multiAutoComplete: boolean;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateResearcherAutoCompleteDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
multiAutoComplete: boolean;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateResearcherDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
multiAutoComplete: boolean;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateRichTextAreaDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateServiceDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
multiAutoComplete: boolean;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateTagDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateTaxonomyDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
multiAutoComplete: boolean;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateTextAreaDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateUploadDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
types: DescriptionTemplateUploadOptionPersist[];
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateValidationDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateDatasetIdentifierDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateCurrencyDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateWordListDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
options: DescriptionTemplateComboBoxOptionPersist[];
|
||||
multiList: boolean;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateDataRepositoryDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
multiAutoComplete: boolean;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateJournalRepositoryDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
multiAutoComplete: boolean;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplatePublicationRepositoryDataPersist extends DescriptionTemplateBaseFieldDataPersist {
|
||||
multiAutoComplete: boolean;
|
||||
}
|
||||
|
||||
//
|
||||
// Others
|
||||
//
|
||||
export interface DescriptionTemplateAutoCompleteSingleDataPersist {
|
||||
autocompleteType: DescriptionTemplateFieldAutocompleteType;
|
||||
url: string;
|
||||
autoCompleteOptions: DescriptionTemplateComboBoxOptionPersist;
|
||||
optionsRoot: string;
|
||||
hasAuth: boolean;
|
||||
auth: DescriptionTemplateAuthAutoCompleteDataPersist
|
||||
method: string;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateAuthAutoCompleteDataPersist {
|
||||
url: string;
|
||||
method: string;
|
||||
body: string;
|
||||
path: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateComboBoxOptionPersist {
|
||||
label: string;
|
||||
value: string;
|
||||
source: string;
|
||||
uri: string;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateRadioBoxOptionPersist {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface DescriptionTemplateUploadOptionPersist {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
|
@ -68,7 +68,6 @@ export interface DescriptionTemplateField {
|
|||
defaultValue: string;
|
||||
visibilityRules: DescriptionTemplateRule[];
|
||||
validations: DescriptionTemplateFieldValidationType[];
|
||||
fieldType: DescriptionTemplateFieldType;
|
||||
includeInExport: boolean;
|
||||
data: DescriptionTemplateBaseFieldData;
|
||||
}
|
||||
|
|
|
@ -1,17 +1,27 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { IsActive } from '@app/core/common/enum/is-active.enum';
|
||||
import { DescriptionTemplateType, DescriptionTemplateTypePersist } from '@app/core/model/description-template-type/description-template-type';
|
||||
import { DescriptionTemplateTypeLookup } from '@app/core/query/description-template-type.lookup';
|
||||
import { DmpBlueprintLookup } from '@app/core/query/dmp-blueprint.lookup';
|
||||
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 { QueryResult } from '@common/model/query-result';
|
||||
import { FilterService } from '@common/modules/text-filter/filter-service';
|
||||
import { Guid } from '@common/types/guid';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
import { nameof } from 'ts-simple-nameof';
|
||||
import { ConfigurationService } from '../configuration/configuration.service';
|
||||
import { BaseHttpV2Service } from '../http/base-http-v2.service';
|
||||
|
||||
@Injectable()
|
||||
export class DescriptionTemplateTypeService {
|
||||
|
||||
constructor(private http: BaseHttpV2Service, private installationConfiguration: ConfigurationService) { }
|
||||
constructor(
|
||||
private http: BaseHttpV2Service,
|
||||
private installationConfiguration: ConfigurationService,
|
||||
private filterService: FilterService
|
||||
) { }
|
||||
|
||||
private get apiBase(): string { return `${this.installationConfiguration.server}description-template-type`; }
|
||||
|
||||
|
@ -46,4 +56,44 @@ export class DescriptionTemplateTypeService {
|
|||
.delete<DescriptionTemplateType>(url).pipe(
|
||||
catchError((error: any) => throwError(error)));
|
||||
}
|
||||
|
||||
//
|
||||
// Autocomplete Commons
|
||||
//
|
||||
// tslint:disable-next-line: member-ordering
|
||||
singleAutocompleteConfiguration: SingleAutoCompleteConfiguration = {
|
||||
initialItems: (data?: any) => this.query(this.buildAutocompleteLookup()).pipe(map(x => x.items)),
|
||||
filterFn: (searchQuery: string, data?: any) => this.query(this.buildAutocompleteLookup(searchQuery)).pipe(map(x => x.items)),
|
||||
getSelectedItem: (selectedItem: any) => this.query(this.buildAutocompleteLookup(null, null, [selectedItem])).pipe(map(x => x.items[0])),
|
||||
displayFn: (item: DescriptionTemplateType) => item.name,
|
||||
titleFn: (item: DescriptionTemplateType) => item.name,
|
||||
valueAssign: (item: DescriptionTemplateType) => item.id,
|
||||
};
|
||||
|
||||
// tslint:disable-next-line: member-ordering
|
||||
multipleAutocompleteConfiguration: MultipleAutoCompleteConfiguration = {
|
||||
initialItems: (excludedItems: any[], data?: any) => this.query(this.buildAutocompleteLookup(null, excludedItems ? excludedItems : null)).pipe(map(x => x.items)),
|
||||
filterFn: (searchQuery: string, excludedItems: any[]) => this.query(this.buildAutocompleteLookup(searchQuery, excludedItems)).pipe(map(x => x.items)),
|
||||
getSelectedItems: (selectedItems: any[]) => this.query(this.buildAutocompleteLookup(null, null, selectedItems)).pipe(map(x => x.items)),
|
||||
displayFn: (item: DescriptionTemplateType) => item.name,
|
||||
titleFn: (item: DescriptionTemplateType) => item.name,
|
||||
valueAssign: (item: DescriptionTemplateType) => item.id,
|
||||
};
|
||||
|
||||
private buildAutocompleteLookup(like?: string, excludedIds?: Guid[], ids?: Guid[]): DmpBlueprintLookup {
|
||||
const lookup: DmpBlueprintLookup = new DmpBlueprintLookup();
|
||||
lookup.page = { size: 100, offset: 0 };
|
||||
if (excludedIds && excludedIds.length > 0) { lookup.excludedIds = excludedIds; }
|
||||
if (ids && ids.length > 0) { lookup.ids = ids; }
|
||||
lookup.isActive = [IsActive.Active];
|
||||
lookup.project = {
|
||||
fields: [
|
||||
nameof<DescriptionTemplateType>(x => x.id),
|
||||
nameof<DescriptionTemplateType>(x => x.name)
|
||||
]
|
||||
};
|
||||
lookup.order = { items: [nameof<DescriptionTemplateType>(x => x.name)] };
|
||||
if (like) { lookup.like = this.filterService.transformLike(like); }
|
||||
return lookup;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,21 @@
|
|||
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { IsActive } from '@app/core/common/enum/is-active.enum';
|
||||
import { DataTableData } from '@app/core/model/data-table/data-table-data';
|
||||
import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing';
|
||||
import { DmpBlueprint, DmpBlueprintPersist } from '@app/core/model/dmp-blueprint/dmp-blueprint';
|
||||
import { DmpBlueprintLookup } from '@app/core/query/dmp-blueprint.lookup';
|
||||
import { DmpBlueprintExternalAutocompleteCriteria } from '@app/core/query/dmp/dmp-profile-external-autocomplete-criteria';
|
||||
import { RequestItem } from '@app/core/query/request-item';
|
||||
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 { BaseHttpParams } from '@common/http/base-http-params';
|
||||
import { InterceptorType } from '@common/http/interceptors/interceptor-type';
|
||||
import { QueryResult } from '@common/model/query-result';
|
||||
import { FilterService } from '@common/modules/text-filter/filter-service';
|
||||
import { Guid } from '@common/types/guid';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
import { nameof } from 'ts-simple-nameof';
|
||||
import { ConfigurationService } from '../configuration/configuration.service';
|
||||
import { BaseHttpV2Service } from '../http/base-http-v2.service';
|
||||
import { DmpBlueprintCriteria } from '@app/core/query/dmp/dmp-blueprint-criteria';
|
||||
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
|
||||
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
|
||||
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
|
||||
import { IsActive } from '@app/core/common/enum/is-active.enum';
|
||||
import { nameof } from 'ts-simple-nameof';
|
||||
import { FilterService } from '@common/modules/text-filter/filter-service';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class DmpBlueprintService {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
import { NgModule } from "@angular/core";
|
||||
import { AutoCompleteModule } from "@app/library/auto-complete/auto-complete.module";
|
||||
import { RichTextEditorModule } from '@app/library/rich-text-editor/rich-text-editor.module';
|
||||
import { UrlListingModule } from '@app/library/url-listing/url-listing.module';
|
||||
import { CommonFormattingModule } from '@common/formatting/common-formatting.module';
|
||||
import { CommonFormsModule } from '@common/forms/common-forms.module';
|
||||
|
@ -12,9 +13,11 @@ import { CommonUiModule } from '@common/ui/common-ui.module';
|
|||
import { NgxDropzoneModule } from "ngx-dropzone";
|
||||
import { DescriptionTemplateRoutingModule } from './description-template.routing';
|
||||
import { DescriptionTemplateEditorComponent } from './editor/description-template-editor.component';
|
||||
import { DescriptionTemplateTableOfContents } from './editor/table-of-contents/description-template-table-of-contents';
|
||||
import { DescriptionTemplateTableOfContentsInternalSection } from './editor/table-of-contents/table-of-contents-internal-section/description-template-table-of-contents-internal-section';
|
||||
import { DescriptionTemplateListingComponent } from './listing/description-template-listing.component';
|
||||
import { DescriptionTemplateListingFiltersComponent } from "./listing/filters/description-template-listing-filters.component";
|
||||
import { ImportDescriptionTemplateDialogComponent } from './listing/import-dmp-blueprint/import-description-template.dialog.component';
|
||||
import { ImportDescriptionTemplateDialogComponent } from './listing/import-description-template/import-description-template.dialog.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
|
@ -29,13 +32,23 @@ import { ImportDescriptionTemplateDialogComponent } from './listing/import-dmp-b
|
|||
HybridListingModule,
|
||||
TextFilterModule,
|
||||
UserSettingsModule,
|
||||
CommonFormattingModule
|
||||
CommonFormattingModule,
|
||||
RichTextEditorModule,
|
||||
|
||||
// FormattingModule,
|
||||
// FormProgressIndicationModule,
|
||||
// AngularStickyThingsModule,
|
||||
// MatBadgeModule,
|
||||
// DragulaModule,
|
||||
// TransitionGroupModule,
|
||||
],
|
||||
declarations: [
|
||||
// DescriptionTemplateEditorComponent,
|
||||
DescriptionTemplateEditorComponent,
|
||||
DescriptionTemplateListingComponent,
|
||||
DescriptionTemplateListingFiltersComponent,
|
||||
ImportDescriptionTemplateDialogComponent
|
||||
ImportDescriptionTemplateDialogComponent,
|
||||
DescriptionTemplateTableOfContents,
|
||||
DescriptionTemplateTableOfContentsInternalSection
|
||||
]
|
||||
})
|
||||
export class DescriptionTemplateModule { }
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
import { animate, keyframes, state, style, transition, trigger } from "@angular/animations";
|
||||
|
||||
export const STEPPER_ANIMATIONS = [
|
||||
trigger('previous_btn',[
|
||||
transition(':enter',[
|
||||
style({'transform': 'translateX(100%)', 'z-index':'9999', 'opacity':0.4}),
|
||||
animate('600ms ease-out', style({
|
||||
'transform': 'translateX(0)',
|
||||
'opacity':1
|
||||
}))
|
||||
]),
|
||||
transition(':leave',[
|
||||
style({
|
||||
'transform': 'translateX(0)',
|
||||
'opacity':'1',
|
||||
'z-index':'9999'
|
||||
}),
|
||||
animate('800ms ease-out', keyframes([
|
||||
style({'transform': 'translateX(120%)', offset:0.8}),
|
||||
style({'opacity': '0.2', offset:0.96})
|
||||
]))
|
||||
])
|
||||
]),
|
||||
trigger('next_btn', [
|
||||
transition(':leave',[
|
||||
style({opacity:1, position:'absolute', 'z-index':'9999'}),
|
||||
animate('700ms ease-out', keyframes( [
|
||||
style({ transform:'translateX(-100%)', offset:0.6}),
|
||||
style({ opacity:'0.2', offset:0.87})
|
||||
]))
|
||||
]),
|
||||
transition(':enter',[
|
||||
style({opacity:0.3, 'z-index':'9999', transform:'translateX(-100%)'}),
|
||||
animate('600ms ease-out', style({ opacity:'1', transform:'translateX(0)' }))
|
||||
])
|
||||
]),
|
||||
trigger('finalize_btn',[
|
||||
transition(':enter',[
|
||||
style({opacity:0.3}),
|
||||
animate('400ms ease-in', style({opacity:1}))
|
||||
]),
|
||||
transition(':leave',[
|
||||
style({opacity:1, position:'absolute'}),
|
||||
animate('600ms ease-in', style({opacity:0.3}))
|
||||
])
|
||||
])
|
||||
];
|
||||
export const GENERAL_ANIMATIONS = [
|
||||
trigger('enterIn',[
|
||||
transition(':enter',[
|
||||
style({
|
||||
transform:'scale(0)',
|
||||
'transform-origin':'50% 0',
|
||||
opacity:0
|
||||
}),
|
||||
animate('800ms ease', style({transform:'scale(1)', opacity:1}))
|
||||
])
|
||||
]),
|
||||
trigger('fadeElement',[
|
||||
state('updated',style({opacity:0})),
|
||||
transition("*=>updated",
|
||||
animate('2s 1s ease-out'))
|
||||
]),
|
||||
trigger('add-new-user-field', [
|
||||
state('untriggered', style({
|
||||
transform:'translateX(120%)'
|
||||
})),
|
||||
state('triggered', style({
|
||||
transform:'translateX(0)'
|
||||
})),
|
||||
transition('untriggered => triggered', animate('400ms ease')),
|
||||
transition('triggered => untriggered', animate('400ms 100ms ease'))
|
||||
]),
|
||||
trigger('scroll-on-top-btn',[
|
||||
transition(":enter", [style({opacity:0, transform:'scale(0)'}), animate('400ms ease', style({'opacity':1, transform:'scale(1)'}))]),
|
||||
transition(":leave", [style({opacity:1,transform:'scale(1)'}), animate('400ms ease', style({'opacity':0, transform:'scale(0)'}))])
|
||||
]),
|
||||
trigger('action-btn',[
|
||||
transition(":enter", [style({opacity:0, transform:'scale(0)'}), animate('400ms ease', style({'opacity':1, transform:'scale(1)'}))]),
|
||||
transition(":leave", [style({opacity:1,transform:'scale(1)'}), animate('400ms ease', style({'opacity':0, transform:'scale(0)'}))])
|
||||
]),
|
||||
trigger('fade-in',[
|
||||
transition(":enter", [style({opacity:0}), animate('1000ms 800ms ease', style({'opacity':1}))]),
|
||||
]),
|
||||
trigger('fade-in-fast',[
|
||||
transition(":enter", [style({opacity:0}), animate('800ms 100ms ease', style({'opacity':1}))]),
|
||||
]),
|
||||
|
||||
|
||||
]
|
|
@ -1,228 +1,318 @@
|
|||
<!-- <div class="container-fluid description-template-editor">
|
||||
<div class="row align-items-center mb-4" *ngIf="formGroup">
|
||||
<div class="col-auto">
|
||||
<h3 *ngIf="isNew && !isClone">{{'DESCRIPTION-TEMPLATE-EDITOR.TITLE.NEW' | translate}}</h3>
|
||||
<div class="container-fluid description-template-editor">
|
||||
<div id="header-outer-wrapper">
|
||||
<div class="row">
|
||||
<div class="col-12 d-flex" id="title-column">
|
||||
|
||||
<div style="padding-left: 2em;">
|
||||
<h3 *ngIf="isNew && !isClone && !isNewVersion">{{'DATASET-PROFILE-EDITOR.TITLE.NEW-PROFILE' | translate}}</h3>
|
||||
<h3 *ngIf="isNew && isClone">
|
||||
<span>{{'DESCRIPTION-TEMPLATE-EDITOR.TITLE.CLONE' | translate}}</span>
|
||||
<span *ngIf="isClone">{{'DATASET-PROFILE-EDITOR.TITLE.NEW-PROFILE-CLONE' | translate}}</span>
|
||||
{{formGroup.get('label').value}}
|
||||
</h3>
|
||||
<h3 *ngIf="isNew && isNewVersion">
|
||||
<span *ngIf="isNewVersion">{{'DATASET-PROFILE-EDITOR.TITLE.NEW-PROFILE-VERSION' | translate}}</span>
|
||||
{{formGroup.get('label').value}}
|
||||
</h3>
|
||||
|
||||
<h3 *ngIf="!isNew">{{formGroup.get('label').value}}</h3>
|
||||
</div>
|
||||
<div class="col"></div>
|
||||
<div class="col-auto" *ngIf="!isNew">
|
||||
<button mat-button class="action-btn" type="button" (click)="delete()">
|
||||
<mat-icon>delete</mat-icon>
|
||||
{{'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.DELETE' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-auto" *ngIf="formGroup.get('status').value==1">
|
||||
<button mat-button class="finalize-btn" (click)="downloadXML()" type="button">{{'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.DOWNLOAD-XML' | translate }}</button>
|
||||
</div>
|
||||
<div *ngIf="formGroup.get('status').value!=1" class="col-auto">
|
||||
<button mat-button class="finalize-btn" (click)="finalize()" [disabled]="!this.isFormValid()" type="button">{{'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.FINALIZE' | translate }}</button>
|
||||
<ng-container *ngTemplateOutlet="actions"></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<form *ngIf="formGroup" (ngSubmit)="formSubmit()">
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.NAME' | translate}}</mat-label>
|
||||
<input matInput type="text" name="label" [formControl]="formGroup.get('label')" required>
|
||||
<mat-error *ngIf="formGroup.get('label').hasError('required')">
|
||||
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<h4 class="col-12">{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.SECTIONS' | translate}}</h4>
|
||||
|
||||
<div class="col-12" cdkDropList (cdkDropListDropped)="dropSections($event)">
|
||||
<div *ngFor="let section of formGroup.get('definition').get('sections').controls; let sectionIndex=index;" class="row mb-3" cdkDrag [cdkDragDisabled]="formGroup.disabled">
|
||||
<div class="row stepper-navigation-outer-wrapper">
|
||||
|
||||
|
||||
<!-- Steps Navigation -->
|
||||
<div id="stepper-navigation-wrapper">
|
||||
<div class="col-12 d-flex" *ngIf="steps" id="stepper-navigation">
|
||||
|
||||
<div class="col-7 bg-white" style="overflow: hidden; padding: 0px" id="progress-container">
|
||||
<div id="progress" [ngStyle]="progressStyle"></div>
|
||||
<div class="row h-100 progress-min-height">
|
||||
<div class="col text-center align-self-center" *ngFor="let step of steps; index as idx">
|
||||
<span (click)="stepper.selectedIndex=idx" class="stepper-title-label" [ngClass]="{'stepper-title-label-locked': !isStepUnlocked(idx),'stepper-title-label-completed':idx < stepper.selectedIndex} ">
|
||||
<ng-container *ngIf="(step.completed &&(idx!=steps.length-1)) else numberLabel">
|
||||
<mat-icon style="font-size:0.7em; height: 0px;">done</mat-icon>
|
||||
</ng-container>
|
||||
<ng-template #numberLabel>
|
||||
{{idx+1}}
|
||||
</ng-template>
|
||||
{{step.label}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<mat-horizontal-stepper [linear]="true" #stepper class="stepper" (selectionChange)="onMatStepperSelectionChange($event)" style="padding-left: 8px; padding-right: 15px;">
|
||||
|
||||
<!-- IMPORTANT TO BE !INVALID (WHEN THE TEMPLATE IS FINALIZED THE CONTORLS ARE DISABLED) -->
|
||||
<mat-step [label]="'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.TITLE' | translate" [completed]="(!formGroup.get('label').invalid && !formGroup.get('description').invalid && !formGroup.get('language').invalid)">
|
||||
<!-- <ng-template matStepLabel>{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.TITLE' | translate}}
|
||||
</ng-template> -->
|
||||
<div class="col-9">
|
||||
<div class="col">
|
||||
<div class="col-12">
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<div class="row mb-3 d-flex align-items-center">
|
||||
<div class="col-auto d-flex">
|
||||
<mat-card-title>{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.SECTION-PREFIX' | translate}} {{sectionIndex + 1}}</mat-card-title>
|
||||
</div>
|
||||
<div class="col-auto d-flex"><mat-icon cdkDragHandle style="cursor: move; color: #129d99;">drag_indicator</mat-icon></div>
|
||||
|
||||
<div class="col-auto d-flex">
|
||||
<button mat-icon-button class="action-list-icon" matTooltip="{{'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.REMOVE-SECTION' | translate}}" (click)="removeSection(sectionIndex)" [disabled]="formGroup.disabled">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.SECTION-NAME' | translate}}</mat-label>
|
||||
<input matInput type="text" name="label" [formControl]="section.get('label')" required>
|
||||
<mat-error *ngIf="section.get('label').hasError('required')">
|
||||
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
<div class="heading">1.1 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-NAME'| translate}} *</div>
|
||||
<div class="hint">{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-NAME-HINT'| translate}}</div>
|
||||
<mat-form-field class="full-width basic-info-input">
|
||||
<input matInput [formControl]="formGroup.get('label')" placeholder="{{'DATASET-PROFILE-EDITOR.FIELDS.DATASET-TITLE' | translate}}">
|
||||
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' |
|
||||
translate}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.SECTION-DESCRIPTION' | translate}}</mat-label>
|
||||
<input matInput type="text" name="description" [formControl]="section.get('description')">
|
||||
<mat-error *ngIf="section.get('description').hasError('required')">
|
||||
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</mat-form-field>
|
||||
<div class="col-12">
|
||||
<div class="heading">1.2 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-DESCRIPTION'| translate}} *</div>
|
||||
<!-- <div class="hint">{{'DMP-EDITOR.MAIN-INFO.HINT' | translate}}</div> -->
|
||||
<div class="hint">{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-DESCRIPTION-HINT'| translate}}</div>
|
||||
<div class="full-width basic-info-input">
|
||||
<rich-text-editor-component [parentFormGroup]="formGroup" [controlName]="'description'" [placeholder]="'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-DESCRIPTION-PLACEHOLDER'" [wrapperClasses]="(formGroup.get('description').touched && formGroup.get('description').hasError('required')) ? 'required' : ''" [editable]="formGroup.controls['description'].status !== 'DISABLED'">
|
||||
</rich-text-editor-component>
|
||||
<div [class]="(formGroup.get('description').touched && formGroup.get('description').hasError('required')) ? 'visible' : 'invisible'" class="mat-form-field formGroup-field-subscript-wrapper">
|
||||
<mat-error>
|
||||
{{'GENERAL.VALIDATION.REQUIRED'| translate}}
|
||||
</mat-error>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.SYSTEM-FIELDS' | translate}}</mat-label>
|
||||
<mat-select multiple [(ngModel)]="selectedSystemFields" [ngModelOptions]="{standalone: true}">
|
||||
<mat-option *ngFor="let systemFieldType of descriptionTemplateSystemFieldTypeEnum" [disabled]="systemFieldDisabled(systemFieldType)" [value]="systemFieldType">{{enumUtils.toDescriptionTemplateSystemFieldTypeString(systemFieldType)}}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button mat-button class="action-btn" type="button" (click)="addExtraField(sectionIndex)" [disabled]="formGroup.disabled">{{'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.ADD-EXTRA-FIELD' | translate}}</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div cdkDropList class="col-12" (cdkDropListDropped)="dropFields($event, sectionIndex)">
|
||||
<div *ngFor="let field of section.get('fields').controls; let fieldIndex=index;" cdkDrag class="row align-items-center" [cdkDragDisabled]="formGroup.disabled">
|
||||
|
||||
<div class="col-auto">
|
||||
<span style="font-size: 15px;">{{fieldIndex + 1}}</span>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<mat-icon cdkDragHandle style="cursor: move; color: #129d99;">drag_indicator</mat-icon>
|
||||
</div>
|
||||
<div class="col-auto" *ngIf="field.get('category').value === descriptionTemplateSectionFieldCategory.SYSTEM">
|
||||
<div class="col-12">
|
||||
<div class="heading">1.3 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DESCRIPTION-TEMPLATE-TYPE'| translate}} *</div>
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.SYSTEM-FIELD' | translate}}</mat-label>
|
||||
<input matInput disabled value="{{enumUtils.toDescriptionTemplateSystemFieldTypeString(field.get('systemFieldType').value)}}" type="text" name="name">
|
||||
<mat-label>{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DESCRIPTION-TEMPLATE-SELECT-TYPE' | translate}}</mat-label>
|
||||
<app-single-auto-complete [required]="false" [formControl]="formGroup.get('type')" placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DESCRIPTION-TEMPLATE-SELECT-TYPE' | translate}}" [configuration]="descriptionTemplateTypeService.singleAutocompleteConfiguration">
|
||||
</app-single-auto-complete>
|
||||
<mat-error *ngIf="formGroup.get('type').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-auto" *ngIf="field.get('category').value === descriptionTemplateSectionFieldCategory.EXTRA">
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.FIELD-DATA-TYPE' | translate}}</mat-label>
|
||||
<mat-select [formControl]="field.get('dataType')" required>
|
||||
<mat-option *ngFor="let extraFieldDataType of descriptionTemplateExtraFieldDataTypeEnum" [value]="extraFieldDataType">
|
||||
{{enumUtils.toDescriptionTemplateExtraFieldDataTypeString(extraFieldDataType)}}
|
||||
<div class="col-12">
|
||||
<!-- <div class="heading">1.4 {{'DMP-EDITOR.FIELDS.LANGUAGE' | translate}}</div> -->
|
||||
<div class="heading">1.4 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-LANGUAGE'| translate}} *</div>
|
||||
<mat-form-field class="full-width basic-info-input">
|
||||
<!-- <input matInput formControlName="description" placeholder="{{'DATASET-PROFILE-EDITOR.FIELDS.DATASET-DESCRIPTION' | translate}}" required> -->
|
||||
<mat-select [formControl]="formGroup.get('language')" placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-SELECT-LANGUAGE'| translate}}">
|
||||
<mat-option *ngFor="let lang of availableLanguages" [value]="lang.code">
|
||||
{{ lang.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="field.get('dataType').hasError('required')">
|
||||
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
<mat-error *ngIf="formGroup.get('language').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' |
|
||||
translate}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col">
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.FIELD-LABEL' | translate}}</mat-label>
|
||||
<input matInput type="text" name="label" [formControl]="field.get('label')" required>
|
||||
<mat-error *ngIf="field.get('label').hasError('required')">
|
||||
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
<!-- <div class="col-12">
|
||||
<div class="heading">1.5 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-USERS'| translate}}</div>
|
||||
<div class="hint">{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-USERS-HINT'| translate}}</div>
|
||||
<div class="full-width basic-info-input">
|
||||
<table class="col-12 user-table">
|
||||
<thead class="user-table-header">
|
||||
<tr>
|
||||
<th>{{'USERS.LISTING.NAME' | translate}}</th>
|
||||
<th>{{'USERS.LISTING.EMAIL' | translate}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="user-table-body">
|
||||
<tr *ngFor="let user of userChipList" class="user-table-row">
|
||||
<td>{{user.name}}</td>
|
||||
<td >{{user.email}}</td>
|
||||
<td>
|
||||
<button mat-button class="delete-btn" (click)="verifyAndRemoveUser(user)" [matTooltip]="'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-REMOVE-USER'| translate"><mat-icon>person_remove</mat-icon></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngIf="!userChipList || !userChipList.length">
|
||||
<td style="text-align: end; line-height: 3em;" colspan="2" >
|
||||
{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-NO-USERS-YET' | translate}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- <div class="col-12">
|
||||
<div class="row justify-content-end">
|
||||
<div class="col d-flex justify-content-end" style="overflow: hidden;">
|
||||
<div style="min-width: 20em;max-width: 25em;" [@add-new-user-field]="inputUserState">
|
||||
<mat-form-field>
|
||||
<input matInput #email placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-USERS'| translate}}" (focus)="onUserFieldFocus()" (blur)="onUserFieldBlur()" (keyup.enter)="addUser(email)">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col">
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.FIELD-PLACEHOLDER' | translate}}</mat-label>
|
||||
<input matInput type="text" name="placeholder" [formControl]="field.get('placeholder')">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col">
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.FIELD-DESCRIPTION' | translate}}</mat-label>
|
||||
<input matInput type="text" name="description" [formControl]="field.get('description')">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-auto">
|
||||
<mat-checkbox [disabled]="field.get('systemFieldType')?.value === descriptionTemplateSystemFieldType.TEXT || field.get('systemFieldType')?.value === descriptionTemplateSystemFieldType.HTML_TEXT" [formControl]="field.get('required')"><span>{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.FIELD-REQUIRED' | translate}}</span></mat-checkbox>
|
||||
</div>
|
||||
<div *ngIf="field.get('category').value === descriptionTemplateSectionFieldCategory.SYSTEM" [hidden]="viewOnly" class="col-auto">
|
||||
<button mat-icon-button matTooltip="{{'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.REMOVE-SYSTEM-FIELD' | translate}}" (click)="removeSystemField(sectionIndex, fieldIndex)" [disabled]="formGroup.disabled">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="field.get('category').value === descriptionTemplateSectionFieldCategory.EXTRA" [hidden]="viewOnly" class="col-auto">
|
||||
<button mat-icon-button matTooltip="{{'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.REMOVE-EXTRA-FIELD' | translate}}" (click)="removeExtraField(sectionIndex, fieldIndex)" [disabled]="formGroup.disabled">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<button mat-mini-fab color="primary" (click)="addUser(email)" (focus)="onUserButtonFocus()" (blur)="onUserButtonBlur()" [matTooltip]="'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-VALIDATE-AND-ADD-USER'| translate" [disabled]="userFormDisabled">
|
||||
<ng-container *ngIf="inputUserState === 'untriggered' else triggericon">
|
||||
<mat-icon>add</mat-icon>
|
||||
</ng-container>
|
||||
<ng-template #triggericon>
|
||||
<mat-icon>person_add</mat-icon>
|
||||
</ng-template>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</div> -->
|
||||
|
||||
<div class="col-12">
|
||||
</div>
|
||||
|
||||
|
||||
<!-- <div class="col-12">
|
||||
<button mat-button class="full-width" (click)="addPage()"
|
||||
[disabled]="viewOnly">{{'DATASET-PROFILE-EDITOR.ACTIONS.NEXT' | translate}}</button>
|
||||
</div> -->
|
||||
</div>
|
||||
</mat-step>
|
||||
<mat-step [label]="'DATASET-PROFILE-EDITOR.STEPS.FORM.TITLE' | translate" [completed]="formGroup.valid">
|
||||
<div class="row">
|
||||
<div class="col-auto">
|
||||
<mat-checkbox [formControl]="section.get('hasTemplates')" (change)="checkForBlueprints($event, sectionIndex)">
|
||||
{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.DESCRIPTION-TEMPLATES' | translate}}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<!-- TABLE -->
|
||||
<div class="col-3">
|
||||
|
||||
|
||||
<div class="row sticky-top table-container" style="top : 7em;">
|
||||
<description-template-table-of-contents class="toc-pane-container col" style="margin-bottom: 2em;" [links]="toCEntries" (itemClick)="displayItem($event)" (createEntry)="addNewEntry($event)" (removeEntry)="onRemoveEntry($event)" [itemSelected]="selectedTocEntry" [viewOnly]="formGroup.disabled" (dataNeedsRefresh)="onDataNeedsRefresh($event)" [colorizeInvalid]="colorizeInvalid">
|
||||
</description-template-table-of-contents>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12" *ngIf="section.get('hasTemplates').value == true">
|
||||
|
||||
<!-- DISPLAYER -->
|
||||
<div class="col ml-3">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col">
|
||||
<!-- <div class="col-12" *ngIf="selectedTocEntry">
|
||||
|
||||
<div class="col-12 content-displayer" *ngIf="selectedTocEntry.type === tocEntryEnumValues.Page" [@fade-in-fast]>
|
||||
<formGroup [formGroup]="selectedTocEntry.formGroup" class="page-infos">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.DESCRIPTION-TEMPLATES' | translate}}</mat-label>
|
||||
<app-multiple-auto-complete [disabled]="formGroup.disabled" [hidePlaceholder]="true" required='false' [configuration]="blueprintsAutoCompleteConfiguration" (optionRemoved)="onRemoveDescritionTemplate($event, sectionIndex)" (optionSelected)="onSelectDescritionTemplate($event, sectionIndex)">
|
||||
</app-multiple-auto-complete>
|
||||
<div class="heading">{{'DATASET-PROFILE-EDITOR.STEPS.PAGE-INFO.PAGE-NAME' | translate}} *</div>
|
||||
<div class="hint">{{'DATASET-PROFILE-EDITOR.STEPS.PAGE-INFO.PAGE-NAME-HINT' | translate}}</div>
|
||||
<mat-form-field>
|
||||
<input type="text" matInput formControlName="title" [placeholder]="('DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.UNTITLED' | translate) +' '+ ('DATASET-PROFILE-EDITOR.STEPS.PAGE-INFO.PAGE' |translate)">
|
||||
<mat-error>{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-12" *ngIf="!viewOnly && (!selectedTocEntry?.subEntries?.length)">
|
||||
<button class="create-section-btn" (click)="addNewEntry({parent:selectedTocEntry, childType: tocEntryEnumValues.Section})">{{'DATASET-PROFILE-EDITOR.STEPS.PAGE-INFO.ACTIONS.CREATE-SECTION' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngFor="let descriptionTemplate of section.get('descriptionTemplates').controls; let j=index;" class="col-12">
|
||||
</formGroup>
|
||||
</div>
|
||||
|
||||
<div class="col-12" *ngIf="(selectedTocEntry.type === tocEntryEnumValues.Section) || (selectedTocEntry.type === tocEntryEnumValues.FieldSet)">
|
||||
<app-description-template-editor-section-fieldset-component [tocentry]="selectedTocEntry" [viewOnly]="viewOnly" [datasetProfileId]="datasetProfileId" (addNewFieldSet)="addNewEntry({childType: tocEntryEnumValues.FieldSet,parent: {formGroup: $event}})" (removeFieldSet)="onRemoveEntry(_findTocEntryById($event, toCEntries))" (cloneFieldSet)="cloneFieldSet($event)" (selectedEntryId)="displayItem(_findTocEntryById($event, toCEntries))" (dataNeedsRefresh)="onDataNeedsRefresh()">
|
||||
|
||||
</app-description-template-editor-section-fieldset-component>
|
||||
</div>
|
||||
|
||||
|
||||
</div> -->
|
||||
|
||||
<!-- <div class="content-displayer row justify-content-center" *ngIf="!numOfPages" style="min-height: 30em;">
|
||||
<div class="col-auto align-self-center">
|
||||
<div class="row w-100 justify-content-center">
|
||||
<div class="col-auto">
|
||||
{{'DATASET-PROFILE-EDITOR.STEPS.PAGE-INFO.ACTIONS.NOTHING-HERE-HINT'| translate}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-auto d-flex aling-contents-center">
|
||||
{{'DATASET-PROFILE-EDITOR.STEPS.PAGE-INFO.ACTIONS.START-CREATING-PAGE-START'| translate}}
|
||||
|
||||
<mat-icon color="accent" style="font-size: 1.5em; text-align: center; width: 1.5em;">add</mat-icon>
|
||||
<strong style="cursor: pointer;" (click)="addNewEntry({childType: tocEntryEnumValues.Page,parent: null})">
|
||||
{{'DATASET-PROFILE-EDITOR.STEPS.PAGE-INFO.ACTIONS.START-CREATING-PAGE-END'| translate}}
|
||||
</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-step>
|
||||
<mat-step [label]="'DATASET-PROFILE-EDITOR.ACTIONS.PREVIEW-AND-FINALIZE' | translate">
|
||||
<ng-container *ngIf="formGroup">
|
||||
<div class="col-9">
|
||||
<div class="col">
|
||||
<div class="col-12">
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-LABEL' | translate}}</mat-label>
|
||||
<input matInput type="text" value="descriptionTemplate.get('label')" name="label" [formControl]="descriptionTemplate.get('label')">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-MIN-MULTIPLICITY' | translate}}</mat-label>
|
||||
<input matInput type="number" min="0" name="minMultiplicity" [formControl]="descriptionTemplate.get('minMultiplicity')">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<mat-form-field class="w-100">
|
||||
<mat-label>{{'DESCRIPTION-TEMPLATE-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-MAX-MULTIPLICITY' | translate}}</mat-label>
|
||||
<input matInput type="number" min="1" name="maxMultiplicity" [formControl]="descriptionTemplate.get('maxMultiplicity')">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card>
|
||||
<app-final-preview-component [formGroup]="formGroup" [visibilityRules]="visibilityRules">
|
||||
|
||||
</app-final-preview-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</mat-step>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</mat-horizontal-stepper>
|
||||
|
||||
|
||||
<div class="col-12">
|
||||
<div class="row">
|
||||
<div class="col-auto">
|
||||
<button mat-button class="action-btn" type="button" (click)="addSection()" [disabled]="formGroup.disabled">{{'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.ADD-SECTION' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<div class="col-auto">
|
||||
<button mat-button class="action-btn" (click)="cancel()" type="button">{{'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.CANCEL' | translate}}</button>
|
||||
</div>
|
||||
<div class="col"></div>
|
||||
<div class="col-auto">
|
||||
<button mat-button class="action-btn" [disabled]="formGroup.disabled" type="submit">
|
||||
{{'DESCRIPTION-TEMPLATE-EDITOR.ACTIONS.SAVE' | translate}}
|
||||
<a class="scroll-on-top d-flex flex-column align-items-center" (click)="scrollOnTop()" [@scroll-on-top-btn] [matTooltip]="'DATASET-PROFILE-EDITOR.ACTIONS.BACK-TO-TOP'| translate">
|
||||
<mat-icon>
|
||||
arrow_upward
|
||||
</mat-icon>
|
||||
<div>SCROLL</div>
|
||||
</a>
|
||||
|
||||
<ng-container *ngIf="steps && stepper">
|
||||
<div class="floating-btn">
|
||||
<button *ngIf="stepper?.selectedIndex > 0" [@previous_btn] mat-button class="navigate-btn" (click)="stepper?.previous()">
|
||||
<mat-icon class="back-icon pointer">chevron_left</mat-icon>
|
||||
{{'DMP-EDITOR.STEPPER.PREVIOUS' | translate}}
|
||||
</button>
|
||||
<button *ngIf="stepper?.selectedIndex < (steps.length-1)" mat-button class="navigate-btn ml-3" [@next_btn] (click)="validateStep(stepper?.selectedIndex);stepper?.next();" [ngClass]="{'navigate-btn-disabled': !isStepCompleted(stepper?.selectedIndex)}">
|
||||
<span>{{'DMP-EDITOR.STEPPER.NEXT' | translate}}</span>
|
||||
<mat-icon class="back-icon pointer">chevron_right</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<ng-template #actions>
|
||||
<div>
|
||||
<button mat-raised-button class="template_action_btn mr-3" (click)="discardChanges()">{{'DATASET-WIZARD.ACTIONS.CLOSE' | translate}}</button>
|
||||
<button *ngIf="!formGroup.disabled && formGroup.get('status').value!=1" [disabled]="!formGroup.valid" mat-raised-button class="template_action_btn save-btn" type="button">
|
||||
<span class="d-flex flex-row row">
|
||||
<span (click)="onSubmit()" class="col">{{'DATASET-PROFILE-EDITOR.ACTIONS.SAVE' |translate}}</span>
|
||||
<mat-divider [vertical]="true"></mat-divider>
|
||||
<span class="align-items-center justify-content-center col-4 d-flex" (click)="$event.stopPropagation();" [matMenuTriggerFor]="menuSave">
|
||||
<mat-icon>expand_more</mat-icon>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<mat-menu #menuSave="matMenu">
|
||||
<button [disabled]="!formGroup.valid" mat-menu-item (click)="onSubmit(true)" type="button">{{ 'DATASET-PROFILE-EDITOR.ACTIONS.SAVE-AND-CLOSE' | translate }}</button>
|
||||
<button [disabled]="!formGroup.valid" mat-menu-item (click)="onSubmit()" type="button">{{ 'DATASET-PROFILE-EDITOR.ACTIONS.SAVE-AND-CONTINUE' | translate }}</button>
|
||||
</mat-menu>
|
||||
|
||||
<button *ngIf="formGroup.disabled || formGroup.get('status').value==1" [@finalize_btn] mat-raised-button class="template_action_btn save-btn" [disabled]="!formGroup.valid" (click)="updateAndFinalize()">
|
||||
{{'DATASET-PROFILE-EDITOR.ACTIONS.UPDATE' |translate}}
|
||||
<mat-icon (click)="$event.stopPropagation();" style="width: 14px;" [matMenuTriggerFor]="menuUpdate">expand_more</mat-icon>
|
||||
</button>
|
||||
<mat-menu #menuUpdate="matMenu">
|
||||
<button [disabled]="!formGroup.valid" mat-menu-item (click)="updateAndFinalize(true)" type="button">{{ 'DATASET-PROFILE-EDITOR.ACTIONS.UPDATE-AND-CLOSE' | translate }}</button>
|
||||
<button [disabled]="!formGroup.valid" mat-menu-item (click)="updateAndFinalize()" type="button">{{ 'DATASET-PROFILE-EDITOR.ACTIONS.UPDATE-AND-CONTINUE' | translate }}</button>
|
||||
</mat-menu>
|
||||
|
||||
<button *ngIf="!formGroup.disabled && formGroup.get('status').value!=1 && steps?.length-1 === stepper?.selectedIndex" [@finalize_btn] mat-button class="finalize-btn ml-3" [disabled]="!formGroup.valid" [class.invisible]="steps?.length-1 !== stepper?.selectedIndex" (click)="updateAndFinalize(true)">
|
||||
{{'DATASET-PROFILE-EDITOR.ACTIONS.FINALIZE' |translate}}
|
||||
</button>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</form>
|
||||
</div> -->
|
||||
</ng-template>
|
|
@ -1,57 +1,72 @@
|
|||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormArray, UntypedFormGroup } from '@angular/forms';
|
||||
import { Component, OnInit, QueryList, ViewChild } from '@angular/core';
|
||||
import { UntypedFormArray, UntypedFormGroup } from '@angular/forms';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
|
||||
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
|
||||
// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
|
||||
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||
import { CdkStep, StepperSelectionEvent } from '@angular/cdk/stepper';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { MatStepper } from '@angular/material/stepper';
|
||||
import { DatasetProfileComboBoxType } from '@app/core/common/enum/dataset-profile-combo-box-type';
|
||||
import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style';
|
||||
import { DescriptionTemplateStatus } from '@app/core/common/enum/description-template-status';
|
||||
import { IsActive } from '@app/core/common/enum/is-active.enum';
|
||||
import { AppPermission } from '@app/core/common/enum/permission.enum';
|
||||
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
|
||||
import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile';
|
||||
import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
|
||||
import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria';
|
||||
import { DescriptionTemplatePersist } from '@app/core/model/description-template/description-template-persist';
|
||||
import { LanguageInfo } from '@app/core/model/language-info';
|
||||
import { AuthService } from '@app/core/services/auth/auth.service';
|
||||
import { LanguageInfoService } from '@app/core/services/culture/language-info-service';
|
||||
import { DescriptionTemplateTypeService } from '@app/core/services/description-template-type/description-template-type.service';
|
||||
import { DescriptionTemplateService } from '@app/core/services/description-template/description-template.service';
|
||||
import { DmpService } from '@app/core/services/dmp/dmp.service';
|
||||
import { LoggingService } from '@app/core/services/logging/logging-service';
|
||||
import { MatomoService } from '@app/core/services/matomo/matomo-service';
|
||||
import { FileUtils } from '@app/core/services/utilities/file-utils.service';
|
||||
import { QueryParamsService } from '@app/core/services/utilities/query-params.service';
|
||||
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
|
||||
import { BaseEditor } from '@common/base/base-editor';
|
||||
import { FormService } from '@common/forms/form-service';
|
||||
import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component';
|
||||
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 * as FileSaver from 'file-saver';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, takeUntil } from 'rxjs/operators';
|
||||
import { GENERAL_ANIMATIONS, STEPPER_ANIMATIONS } from './animations/animations';
|
||||
import { DescriptionTemplateEditorModel, DescriptionTemplateFieldEditorModel, DescriptionTemplateFieldSetEditorModel, DescriptionTemplatePageEditorModel, DescriptionTemplateSectionEditorModel } from './description-template-editor.model';
|
||||
import { DescriptionTemplateEditorResolver } from './description-template-editor.resolver';
|
||||
import { DescriptionTemplateEditorService } from './description-template-editor.service';
|
||||
import { DescriptionTemplateEditorModel } from './description-template-editor.model';
|
||||
import { DescriptionTemplateService } from '@app/core/services/description-template/description-template.service';
|
||||
import { DescriptionTemplatePersist } from '@app/core/model/description-template/description-template-persist';
|
||||
import { NewEntryType, ToCEntry, ToCEntryType } from './table-of-contents/description-template-table-of-contents-entry';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-description-template-editor-component',
|
||||
templateUrl: 'description-template-editor.component.html',
|
||||
styleUrls: ['./description-template-editor.component.scss'],
|
||||
animations: [...STEPPER_ANIMATIONS, ...GENERAL_ANIMATIONS],
|
||||
providers: [DescriptionTemplateEditorService]
|
||||
})
|
||||
export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTemplateEditorModel, DescriptionTemplate> implements OnInit {
|
||||
|
||||
@ViewChild('stepper') stepper: MatStepper;
|
||||
|
||||
isNew = true;
|
||||
isDeleted = false;
|
||||
formGroup: UntypedFormGroup = null;
|
||||
showInactiveDetails = false;
|
||||
|
||||
availableLanguages: LanguageInfo[] = this.languageInfoService.getLanguageInfoValues();
|
||||
|
||||
isNewVersion = false;
|
||||
isClone = false;
|
||||
steps: QueryList<CdkStep>;
|
||||
toCEntries: ToCEntry[];
|
||||
selectedTocEntry: ToCEntry;
|
||||
colorizeInvalid: boolean = false;
|
||||
|
||||
|
||||
// selectedSystemFields: Array<DescriptionTemplateSystemFieldType> = [];
|
||||
// descriptionTemplateSectionFieldCategory = DescriptionTemplateSectionFieldCategory;
|
||||
// descriptionTemplateSystemFieldType = DescriptionTemplateSystemFieldType;
|
||||
|
@ -101,11 +116,13 @@ export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTe
|
|||
public authService: AuthService,
|
||||
public enumUtils: EnumUtils,
|
||||
private descriptionTemplateService: DescriptionTemplateService,
|
||||
public descriptionTemplateTypeService: DescriptionTemplateTypeService,
|
||||
private logger: LoggingService,
|
||||
private descriptionTemplateEditorService: DescriptionTemplateEditorService,
|
||||
private fileUtils: FileUtils,
|
||||
private matomoService: MatomoService,
|
||||
private dmpService: DmpService
|
||||
private dmpService: DmpService,
|
||||
private languageInfoService: LanguageInfoService
|
||||
) {
|
||||
super(dialog, language, formService, router, uiNotificationService, httpErrorHandlingService, filterService, datePipe, route, queryParamsService);
|
||||
}
|
||||
|
@ -129,6 +146,12 @@ export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTe
|
|||
this.editorModel = data ? new DescriptionTemplateEditorModel().fromModel(data) : new DescriptionTemplateEditorModel();
|
||||
this.isDeleted = data ? data.isActive === IsActive.Inactive : false;
|
||||
this.buildForm();
|
||||
|
||||
setTimeout(() => {
|
||||
this.steps = this.stepper.steps;
|
||||
});
|
||||
this._initializeToCEntries();
|
||||
|
||||
} catch (error) {
|
||||
this.logger.error('Could not parse descriptionTemplate item: ' + data + error);
|
||||
this.uiNotificationService.snackBarNotification(this.language.instant('COMMONS.ERRORS.DEFAULT'), SnackBarNotificationLevel.Error);
|
||||
|
@ -210,6 +233,769 @@ export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTe
|
|||
this.formService.validateAllFormFields(this.formGroup);
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Stepper
|
||||
//
|
||||
//
|
||||
onMatStepperSelectionChange(event: StepperSelectionEvent) {
|
||||
|
||||
if (event.selectedIndex === (this.steps.length - 1)) {//preview selected
|
||||
// this.generatePreviewForm();//TODO LAZY LOADING IN THE TEMPLATE
|
||||
// this.getPreview();
|
||||
} else {
|
||||
// this.previewForm = null;
|
||||
// this.formGroup = null;
|
||||
}
|
||||
this.formGroup.markAsUntouched();
|
||||
|
||||
}
|
||||
|
||||
isStepCompleted(stepIndex: number) {
|
||||
|
||||
let stepCompleted = false;
|
||||
this.steps.forEach((step, index) => {
|
||||
if (stepIndex === index) {
|
||||
stepCompleted = step.completed;
|
||||
}
|
||||
});
|
||||
|
||||
return stepCompleted;
|
||||
}
|
||||
|
||||
isStepUnlocked(stepIndex: number): boolean {
|
||||
if (stepIndex === 0) return true;
|
||||
if (stepIndex < 0) return false;
|
||||
//if previous step is valid then unlock
|
||||
let stepUnlocked: boolean = false;
|
||||
|
||||
if (!this.isStepUnlocked(stepIndex - 1)) return false;
|
||||
|
||||
this.steps.forEach((step, index) => {
|
||||
|
||||
if (index + 1 == stepIndex) {//previous step
|
||||
|
||||
if (step.completed) {
|
||||
stepUnlocked = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return stepUnlocked;
|
||||
}
|
||||
|
||||
validateStep(selectedIndex) {
|
||||
|
||||
if (selectedIndex === 1) {//form description
|
||||
if (this.formGroup.invalid) {
|
||||
this.checkFormValidation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Table of Contents
|
||||
//
|
||||
//
|
||||
private _initializeToCEntries() {
|
||||
const tocentries = this.refreshToCEntries();//tocentries are sorted based on their ordinal value
|
||||
|
||||
this._updateOrdinals(tocentries);
|
||||
|
||||
if (tocentries && tocentries.length) {
|
||||
this.selectedTocEntry = tocentries[0];
|
||||
}
|
||||
|
||||
//Checking invalid visibilty RULES
|
||||
const fieldsetEntries = this._getAllFieldSets(this.toCEntries);
|
||||
const fieldSetHavingInvalidVisibilityRules: ToCEntry[] = fieldsetEntries
|
||||
.filter(entry => {
|
||||
const fieldsFormGroup = entry.form.get('fields');
|
||||
const invalid = (fieldsFormGroup as UntypedFormArray).controls.filter(field => {
|
||||
return this.hasInvalidVisibilityRule(field as UntypedFormGroup);
|
||||
|
||||
});
|
||||
if (invalid && invalid.length) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
if (fieldSetHavingInvalidVisibilityRules.length) {
|
||||
const occurences = fieldSetHavingInvalidVisibilityRules.map(record => record.numbering).join(' , ');
|
||||
this.dialog.open(ConfirmationDialogComponent, {
|
||||
data: {
|
||||
message: this.language.instant('DATASET-PROFILE-EDITOR.ERRORS.INVALID-VISIBILITY-RULES.MESSAGE-START') + occurences + this.language.instant('DATASET-PROFILE-EDITOR.ERRORS.INVALID-VISIBILITY-RULES.MESSAGE-END'),
|
||||
confirmButton: this.language.instant('DATASET-PROFILE-EDITOR.ERRORS.INVALID-VISIBILITY-RULES.CONFIRM-YES'),
|
||||
cancelButton: this.language.instant('DATASET-PROFILE-EDITOR.ERRORS.INVALID-VISIBILITY-RULES.CONFIRM-NO')
|
||||
},
|
||||
maxWidth: '30em'
|
||||
})
|
||||
.afterClosed()
|
||||
.subscribe(confirm => {
|
||||
if (confirm) {
|
||||
this.removeFieldSetVisibilityRules(fieldSetHavingInvalidVisibilityRules);
|
||||
this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-PROFILE-EDITOR.ERRORS.INVALID-VISIBILITY-RULES.REMOVE-SUCCESS'), SnackBarNotificationLevel.Success);
|
||||
|
||||
} else {
|
||||
console.log('User not confirmed');
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private refreshToCEntries(): ToCEntry[] {
|
||||
this.toCEntries = this.getTocEntries();
|
||||
//update selected tocentry
|
||||
if (this.selectedTocEntry) {
|
||||
this.selectedTocEntry = this._findTocEntryById(this.selectedTocEntry.id, this.toCEntries);
|
||||
}
|
||||
// this.updateOrdinals(this.toCEntries);
|
||||
// this._updateNumbering(this.toCEntries);
|
||||
return this.toCEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates entries ordinal form value
|
||||
* based on the index they have on the tocentry array.
|
||||
* Tocentries that are on the same level have distinct ordinal value
|
||||
*
|
||||
* @param tocentries
|
||||
*
|
||||
*/
|
||||
private _updateOrdinals(tocentries: ToCEntry[]) {
|
||||
|
||||
if (!tocentries || !tocentries.length) return;
|
||||
tocentries.forEach((e, idx) => {
|
||||
const ordinalControl = e.form.get('ordinal');
|
||||
if (ordinalControl) {
|
||||
ordinalControl.setValue(idx);
|
||||
ordinalControl.updateValueAndValidity();
|
||||
}
|
||||
this._updateOrdinals(e.subEntries);
|
||||
});
|
||||
}
|
||||
|
||||
getTocEntries(): ToCEntry[] {
|
||||
if (this.formGroup == null) { return []; }
|
||||
const result: ToCEntry[] = [];
|
||||
|
||||
//build parent pages
|
||||
(this.formGroup.get('pages') as UntypedFormArray).controls.forEach((pageElement, i) => {
|
||||
result.push({
|
||||
id: pageElement.get('id').value,
|
||||
label: pageElement.get('title').value,
|
||||
type: ToCEntryType.Page,
|
||||
form: pageElement,
|
||||
numbering: (i + 1).toString(),
|
||||
subEntriesType: ToCEntryType.Section
|
||||
} as ToCEntry)
|
||||
});
|
||||
|
||||
// build first level sections
|
||||
(this.formGroup.get('sections') as UntypedFormArray).controls.forEach((sectionElement, i) => {
|
||||
const currentSectionPageId = sectionElement.get('page').value;
|
||||
const pageToAdd = result.filter(x => x.id == currentSectionPageId)[0];
|
||||
if (pageToAdd.subEntries == null) pageToAdd.subEntries = [];
|
||||
|
||||
const item = {
|
||||
id: sectionElement.get('id').value,
|
||||
label: sectionElement.get('title').value,
|
||||
type: ToCEntryType.Section,
|
||||
form: sectionElement,
|
||||
numbering: pageToAdd.numbering + '.' + (pageToAdd.subEntries.length + 1)
|
||||
} as ToCEntry;
|
||||
const sectionItems = this.populateSections(sectionElement.get('sections') as UntypedFormArray, item.numbering);
|
||||
const fieldSetItems = this.populateFieldSets(sectionElement.get('fieldSets') as UntypedFormArray, item.numbering);
|
||||
if (sectionItems != null) {
|
||||
item.subEntries = sectionItems;
|
||||
item.subEntriesType = ToCEntryType.Section;
|
||||
}
|
||||
if (fieldSetItems != null) {
|
||||
if (item.subEntries == null) {
|
||||
item.subEntries = fieldSetItems;
|
||||
} else {
|
||||
item.subEntries.push(...fieldSetItems);
|
||||
}
|
||||
item.subEntriesType = ToCEntryType.FieldSet;
|
||||
|
||||
}
|
||||
pageToAdd.subEntries.push(item);
|
||||
|
||||
});
|
||||
this._sortToCentries(result);//ordeby ordinal
|
||||
this._updateNumbering(result, '');//update nubering if needed
|
||||
return result;
|
||||
}
|
||||
|
||||
private populateSections(sections: UntypedFormArray, existingNumbering: string): ToCEntry[] {
|
||||
if (sections == null || sections.controls == null || sections.controls.length == 0) { return null; }
|
||||
|
||||
const result: ToCEntry[] = [];
|
||||
sections.controls.forEach((sectionElement, i) => {
|
||||
|
||||
const item = {
|
||||
id: sectionElement.get('id').value,
|
||||
label: sectionElement.get('title').value,
|
||||
type: ToCEntryType.Section,
|
||||
form: sectionElement,
|
||||
numbering: existingNumbering + '.' + (i + 1)
|
||||
} as ToCEntry;
|
||||
const sectionItems = this.populateSections(sectionElement.get('sections') as UntypedFormArray, item.numbering);
|
||||
const fieldSetItems = this.populateFieldSets(sectionElement.get('fieldSets') as UntypedFormArray, item.numbering);
|
||||
if (sectionItems != null) {
|
||||
item.subEntries = sectionItems;
|
||||
item.subEntriesType = ToCEntryType.Section;
|
||||
}
|
||||
if (fieldSetItems != null) {
|
||||
if (item.subEntries == null) {
|
||||
item.subEntries = fieldSetItems;
|
||||
} else {
|
||||
item.subEntries.push(...fieldSetItems);
|
||||
}
|
||||
item.subEntriesType = ToCEntryType.FieldSet;
|
||||
}
|
||||
result.push(item);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private populateFieldSets(fieldSets: UntypedFormArray, existingNumbering: string): ToCEntry[] {
|
||||
if (fieldSets == null || fieldSets.controls == null || fieldSets.controls.length == 0) { return null; }
|
||||
|
||||
const result: ToCEntry[] = [];
|
||||
fieldSets.controls.forEach((fieldSetElement, i) => {
|
||||
|
||||
result.push({
|
||||
id: fieldSetElement.get('id').value,
|
||||
label: fieldSetElement.get('title').value,
|
||||
type: ToCEntryType.FieldSet,
|
||||
//subEntries: this.populateSections((fieldSetElement.get('fieldSets') as FormArray), existingNumbering + '.' + i),
|
||||
form: fieldSetElement,
|
||||
numbering: existingNumbering + '.' + (i + 1)
|
||||
} as ToCEntry)
|
||||
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
addNewEntry(tce: NewEntryType) {
|
||||
|
||||
const parent = tce.parent;
|
||||
|
||||
//define entry type
|
||||
switch (tce.childType) {
|
||||
case ToCEntryType.Page:
|
||||
const pagesArray = (this.formGroup.get('pages') as UntypedFormArray);
|
||||
|
||||
const page: DescriptionTemplatePageEditorModel = new DescriptionTemplatePageEditorModel();
|
||||
if (isNaN(pagesArray.length)) { page.ordinal = 0; } else { page.ordinal = pagesArray.length; }
|
||||
const pageForm = page.buildForm();
|
||||
// this.dataModel.pages.push(page);
|
||||
|
||||
pagesArray.push(pageForm);
|
||||
// this.form.updateValueAndValidity();
|
||||
this.refreshToCEntries();
|
||||
this.selectedTocEntry = this._findTocEntryById(pageForm.get('id').value, this.toCEntries);
|
||||
|
||||
break;
|
||||
case ToCEntryType.Section:
|
||||
|
||||
const section: DescriptionTemplateSectionEditorModel = new DescriptionTemplateSectionEditorModel();
|
||||
section.id = Guid.create();
|
||||
let sectionsArray: UntypedFormArray;
|
||||
|
||||
if (parent.type === ToCEntryType.Page) {//FIRST LEVEL SECTION
|
||||
sectionsArray = this.formGroup.get('sections') as UntypedFormArray;
|
||||
|
||||
section.page = parent.id;
|
||||
|
||||
try {
|
||||
const max = sectionsArray.controls.filter(control => control.get('page').value === parent.id)
|
||||
.map(control => control.get('ordinal').value)
|
||||
.reduce((a, b) => Math.max(a, b));
|
||||
|
||||
section.ordinal = max + 1;
|
||||
} catch {
|
||||
section.ordinal = sectionsArray.length;
|
||||
|
||||
}
|
||||
sectionsArray.push(section.buildForm());
|
||||
// this.form.updateValueAndValidity();
|
||||
|
||||
} else if (parent.type == ToCEntryType.Section) { //SUBSECTION OF SECTION
|
||||
sectionsArray = parent.form.get('sections') as UntypedFormArray;
|
||||
|
||||
//adding page parent MAYBE NOT NEEDED
|
||||
section.page = parent.form.get('page').value;
|
||||
try {
|
||||
const maxOrdinal = sectionsArray.controls.map(control => control.get('ordinal').value).reduce((a, b) => Math.max(a, b));
|
||||
section.ordinal = maxOrdinal + 1;
|
||||
} catch {
|
||||
section.ordinal = sectionsArray.length;
|
||||
}
|
||||
|
||||
sectionsArray.push(section.buildForm());
|
||||
// (child.form.parent as FormArray).push(section.buildForm());
|
||||
|
||||
} else {
|
||||
console.error('Section can only be child of a page or another section');
|
||||
}
|
||||
|
||||
|
||||
const sectionAdded = sectionsArray.at(sectionsArray.length - 1) as UntypedFormGroup;
|
||||
// sectionAdded.setValidators(this.customEditorValidators.sectionHasAtLeastOneChildOf('fieldSets','sections'));
|
||||
// sectionAdded.updateValueAndValidity();
|
||||
|
||||
|
||||
this.refreshToCEntries();
|
||||
this.selectedTocEntry = this._findTocEntryById(sectionAdded.get('id').value, this.toCEntries);
|
||||
|
||||
break;
|
||||
case ToCEntryType.FieldSet:
|
||||
|
||||
//create one field form fieldset
|
||||
const field: DescriptionTemplateFieldEditorModel = new DescriptionTemplateFieldEditorModel();
|
||||
field.id = Guid.create();
|
||||
field.ordinal = 0;//first filed in the fields list
|
||||
const fieldForm = field.buildForm();
|
||||
// fieldForm.setValidators(this.customFieldValidator());
|
||||
// fieldForm.get('viewStyle').get('renderStyle').setValidators(Validators.required);
|
||||
|
||||
// fieldSet.fields.push(field);
|
||||
// field.ordinal = fieldSet.fields.length-1;
|
||||
|
||||
const fieldSetsArray = parent.form.get('fieldSets') as UntypedFormArray
|
||||
|
||||
//give fieldset id and ordinal
|
||||
const fieldSet: DescriptionTemplateFieldSetEditorModel = new DescriptionTemplateFieldSetEditorModel();
|
||||
const fieldSetId = Guid.create();
|
||||
fieldSet.id = fieldSetId;
|
||||
|
||||
try {
|
||||
const maxOrdinal = fieldSetsArray.controls.map(control => control.get('ordinal').value).reduce((a, b) => Math.max(a, b));
|
||||
fieldSet.ordinal = maxOrdinal + 1;
|
||||
} catch {
|
||||
fieldSet.ordinal = fieldSetsArray.length;
|
||||
}
|
||||
const fieldsetForm = fieldSet.buildForm();
|
||||
|
||||
|
||||
|
||||
(fieldsetForm.get('fields') as UntypedFormArray).push(fieldForm);
|
||||
fieldSetsArray.push(fieldsetForm);
|
||||
|
||||
this.refreshToCEntries();
|
||||
this.selectedTocEntry = this._findTocEntryById(fieldSetId.toString(), this.toCEntries);
|
||||
// fieldForm.updateValueAndValidity();
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
this.formGroup.updateValueAndValidity();
|
||||
}
|
||||
|
||||
|
||||
onRemoveEntry(tce: ToCEntry) {
|
||||
|
||||
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
|
||||
restoreFocus: false,
|
||||
data: {
|
||||
message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'),
|
||||
confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
|
||||
cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
|
||||
isDeleteConfirmation: true
|
||||
}
|
||||
});
|
||||
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
|
||||
if (result) {
|
||||
this._deleteEntry(tce);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _deleteEntry(tce: ToCEntry) {
|
||||
//define entry type
|
||||
switch (tce.type) {
|
||||
case ToCEntryType.Page:
|
||||
const pages = this.formGroup.get('pages') as UntypedFormArray;
|
||||
|
||||
let pageIndex = -1;
|
||||
//get the index
|
||||
for (let i = 0; i < pages.length; i++) {
|
||||
let page = pages.at(i) as UntypedFormGroup;
|
||||
|
||||
if (page.controls.id.value === tce.id) {
|
||||
pageIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pageIndex >= 0) {
|
||||
//remove page
|
||||
this._updateSelectedItem(tce);
|
||||
pages.removeAt(pageIndex);
|
||||
//clean up sections of removed page
|
||||
|
||||
const sections = (this.formGroup.get('sections') as UntypedFormArray);
|
||||
|
||||
const sectionsIndexToBeRemoved = [];
|
||||
|
||||
sections.controls.forEach((section, idx) => {
|
||||
if (section.get('page').value === tce.id) {
|
||||
sectionsIndexToBeRemoved.push(idx);
|
||||
}
|
||||
});
|
||||
|
||||
if (sectionsIndexToBeRemoved.length) {
|
||||
sectionsIndexToBeRemoved.reverse().forEach(index => {
|
||||
sections.removeAt(index);
|
||||
});
|
||||
}
|
||||
|
||||
//update page ordinals
|
||||
for (let i = 0; i < pages.length; i++) {
|
||||
pages.at(i).get('ordinal').patchValue(i);
|
||||
}
|
||||
|
||||
//update validity
|
||||
// this.form.controls.sections.updateValueAndValidity();
|
||||
}
|
||||
break;
|
||||
|
||||
case ToCEntryType.Section:
|
||||
|
||||
//FIRST LEVEL SECTION CASE
|
||||
let index = -1;
|
||||
|
||||
|
||||
const sections = (this.formGroup.get('sections') as UntypedFormArray);
|
||||
|
||||
for (let i = 0; i < sections.length; i++) {
|
||||
|
||||
let section = sections.at(i);
|
||||
|
||||
let sectionId = section.get('id').value;
|
||||
if (sectionId == tce.id) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (index >= 0) { //section found
|
||||
|
||||
const sections = (this.formGroup.get('sections') as UntypedFormArray);
|
||||
|
||||
//remove section
|
||||
this._updateSelectedItem(tce);
|
||||
sections.removeAt(index);
|
||||
|
||||
//update ordinal
|
||||
for (let i = 0; i < sections.length; i++) {
|
||||
sections.at(i).get('ordinal').patchValue(i);
|
||||
}
|
||||
} else {//NOT FOUND IN FIRST LEVEL CASE
|
||||
|
||||
//LOOK FOR SUBSECTION CASE
|
||||
let parentFormArray = tce.form.parent as UntypedFormArray;
|
||||
|
||||
for (let i = 0; i < parentFormArray.length; i++) {
|
||||
let section = parentFormArray.at(i);
|
||||
|
||||
if (section.get('id').value == tce.id) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index >= 0) {
|
||||
this._updateSelectedItem(tce);
|
||||
parentFormArray.removeAt(index);
|
||||
|
||||
//update odrinal
|
||||
|
||||
for (let i = 0; i < parentFormArray.length; i++) {
|
||||
parentFormArray.at(i).get('ordinal').patchValue(i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
case ToCEntryType.FieldSet:
|
||||
const parentFormArray = tce.form.parent as UntypedFormArray;
|
||||
|
||||
|
||||
let idx = -1;
|
||||
|
||||
for (let i = 0; i < parentFormArray.length; i++) {
|
||||
let inspectingField = parentFormArray.at(i);
|
||||
|
||||
if (inspectingField.get('id').value === tce.id) {
|
||||
//fieldset found
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (idx >= 0) {//fieldset found
|
||||
this._updateSelectedItem(tce);
|
||||
parentFormArray.removeAt(idx);
|
||||
|
||||
//patching order
|
||||
for (let i = 0; i < parentFormArray.length; i++) {
|
||||
parentFormArray.at(i).get('ordinal').patchValue(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//in case selectedtocentrhy is child of the removed element
|
||||
|
||||
// this.refreshToCEntries();
|
||||
this.onDataNeedsRefresh();
|
||||
this.formGroup.updateValueAndValidity();
|
||||
|
||||
}
|
||||
|
||||
private _updateSelectedItem(tce: ToCEntry) {
|
||||
|
||||
if (this.selectedTocEntry) {
|
||||
|
||||
if (this.tocEntryIsChildOf(this.selectedTocEntry, tce)) {
|
||||
if (this.selectedTocEntry.type == ToCEntryType.Page) {
|
||||
this.selectedTocEntry = null;
|
||||
} else {
|
||||
|
||||
//if first level section
|
||||
const firstLevelSections = (this.formGroup.get('sections') as UntypedFormArray);
|
||||
let isFirstLevel: boolean = false;
|
||||
firstLevelSections.controls.forEach(section => {
|
||||
if (section.get('id').value === tce.id) {
|
||||
isFirstLevel = true;
|
||||
}
|
||||
});
|
||||
|
||||
let parentId = null;
|
||||
if (isFirstLevel) {
|
||||
parentId = tce.form.get('page').value;
|
||||
} else {
|
||||
parentId = tce.form.parent.parent.get('id').value
|
||||
}
|
||||
|
||||
// const parentId = tce.form.parent.parent.get('id').value;
|
||||
if (parentId) {
|
||||
const tocentries = this.getTocEntries();
|
||||
const parent = this._findTocEntryById(parentId, tocentries);
|
||||
|
||||
if (parent) {
|
||||
this.selectedTocEntry = parent;
|
||||
} else {
|
||||
this.selectedTocEntry = null;
|
||||
}
|
||||
} else {
|
||||
this.selectedTocEntry = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tocEntryIsChildOf(testingChild: ToCEntry, parent: ToCEntry): boolean {
|
||||
|
||||
if (!testingChild || !parent) return false;
|
||||
|
||||
if (testingChild.id == parent.id) { return true; }
|
||||
|
||||
if (parent.subEntries) {
|
||||
let childFound: boolean = false;
|
||||
|
||||
parent.subEntries.forEach(subEntry => {
|
||||
if (this.tocEntryIsChildOf(testingChild, subEntry)) {
|
||||
childFound = true;
|
||||
return true;
|
||||
}
|
||||
})
|
||||
|
||||
return childFound;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
onDataNeedsRefresh(params?) {
|
||||
|
||||
const tocentries = this.refreshToCEntries();
|
||||
|
||||
if (params && params.draggedItemId) {
|
||||
if (params.draggedItemId) {
|
||||
this.displayItem(this._findTocEntryById(params.draggedItemId, tocentries));
|
||||
}
|
||||
}
|
||||
this.formGroup.markAsDirty();
|
||||
}
|
||||
|
||||
displayItem(entry: ToCEntry): void {
|
||||
this.selectedTocEntry = entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
private _sortToCentries(entries: ToCEntry[]) {
|
||||
if (!entries || !entries.length) return;
|
||||
entries.sort(this._compareOrdinals);
|
||||
entries.forEach(e => {
|
||||
this._sortToCentries(e.subEntries)
|
||||
});
|
||||
}
|
||||
private _compareOrdinals(a, b) {
|
||||
|
||||
const aValue = a.form.get('ordinal').value as number;
|
||||
const bValue = b.form.get('ordinal').value as number;
|
||||
|
||||
// if(!aValue || !bValue) return 0;
|
||||
return aValue - bValue;
|
||||
}
|
||||
private _updateNumbering(entries: ToCEntry[], parentNumbering: string) {
|
||||
if (!entries || !entries.length) return;
|
||||
let prefix = '';
|
||||
if (parentNumbering.length) {
|
||||
prefix = parentNumbering + '.';
|
||||
}
|
||||
entries.forEach((entry, index) => {
|
||||
const numbering = prefix + (index + 1);
|
||||
entry.numbering = numbering;
|
||||
this._updateNumbering(entry.subEntries, numbering);
|
||||
})
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Visibility Rules
|
||||
//
|
||||
//
|
||||
private hasInvalidVisibilityRule(field: UntypedFormGroup): boolean {
|
||||
const renderStyle = field.get('viewStyle').get('renderStyle').value;
|
||||
if (renderStyle && ![
|
||||
DatasetProfileFieldViewStyle.TextArea,
|
||||
DatasetProfileFieldViewStyle.RichTextArea,
|
||||
DatasetProfileFieldViewStyle.Upload,
|
||||
DatasetProfileFieldViewStyle.FreeText,
|
||||
DatasetProfileFieldViewStyle.BooleanDecision,
|
||||
DatasetProfileFieldViewStyle.RadioBox,
|
||||
DatasetProfileFieldViewStyle.CheckBox,
|
||||
DatasetProfileFieldViewStyle.DatePicker,
|
||||
DatasetProfileFieldViewStyle.ComboBox,
|
||||
].includes(renderStyle)) {
|
||||
if (((renderStyle === DatasetProfileFieldViewStyle) && (field.get('data').get('type').value === DatasetProfileComboBoxType.WordList))) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if (field.get('visible').get('rules').value.length) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private removeFieldSetVisibilityRules(fieldsets: ToCEntry[]) {
|
||||
|
||||
if (!fieldsets || !fieldsets.length) return;
|
||||
|
||||
fieldsets.forEach(fieldset => {
|
||||
if (fieldset.type != ToCEntryType.FieldSet) {
|
||||
return;
|
||||
}
|
||||
const fields = fieldset.form.get('fields') as UntypedFormArray;
|
||||
|
||||
fields.controls.forEach(fieldControl => {
|
||||
if (this.hasInvalidVisibilityRule(fieldControl as UntypedFormGroup)) {
|
||||
try {
|
||||
(fieldControl.get('visible').get('rules') as UntypedFormArray).clear();
|
||||
} catch { }
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Other
|
||||
//
|
||||
//
|
||||
scrollOnTop() {
|
||||
try {
|
||||
const topPage = document.getElementById('main-content');
|
||||
topPage.scrollIntoView({ behavior: 'smooth' });
|
||||
} catch {
|
||||
console.log('coulnd not scroll');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
checkFormValidation() {
|
||||
this.colorizeInvalid = true;
|
||||
// this.printMyErrors(this.form);
|
||||
}
|
||||
// //
|
||||
// //
|
||||
// // Sections
|
||||
|
@ -752,23 +1538,23 @@ export class DescriptionTemplateEditorComponent extends BaseEditor<DescriptionTe
|
|||
|
||||
// }
|
||||
|
||||
// finalize() {
|
||||
// if (this.checkValidity()) {
|
||||
// this.formGroup.get('status').setValue(DescriptionTemplateStatus.Finalized);
|
||||
// this.formSubmit();
|
||||
// }
|
||||
// }
|
||||
// finalize() {
|
||||
// if (this.checkValidity()) {
|
||||
// this.formGroup.get('status').setValue(DescriptionTemplateStatus.Finalized);
|
||||
// this.formSubmit();
|
||||
// }
|
||||
// }
|
||||
|
||||
// downloadXML(): void {
|
||||
// const blueprintId = this.formGroup.get('id').value;
|
||||
// if (blueprintId == null) return;
|
||||
// this.descriptionTemplateService.downloadXML(blueprintId)
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(response => {
|
||||
// const blob = new Blob([response.body], { type: 'application/xml' });
|
||||
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
|
||||
// downloadXML(): void {
|
||||
// const blueprintId = this.formGroup.get('id').value;
|
||||
// if (blueprintId == null) return;
|
||||
// this.descriptionTemplateService.downloadXML(blueprintId)
|
||||
// .pipe(takeUntil(this._destroyed))
|
||||
// .subscribe(response => {
|
||||
// const blob = new Blob([response.body], { type: 'application/xml' });
|
||||
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
|
||||
|
||||
// FileSaver.saveAs(blob, filename);
|
||||
// });
|
||||
// }
|
||||
// FileSaver.saveAs(blob, filename);
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
|
||||
import { DescriptionTemplateFieldValidationType } from "@app/core/common/enum/description-template-field-validation-type";
|
||||
import { DescriptionTemplateStatus } from "@app/core/common/enum/description-template-status";
|
||||
import { DescriptionTemplate, DescriptionTemplateDefinition } from "@app/core/model/description-template/description-template";
|
||||
import { DescriptionTemplateDefinitionPersist, DescriptionTemplatePersist } from "@app/core/model/description-template/description-template-persist";
|
||||
import { DescriptionTemplate, DescriptionTemplateDefinition, DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplateMultiplicity, DescriptionTemplatePage, DescriptionTemplateRule, DescriptionTemplateSection } from "@app/core/model/description-template/description-template";
|
||||
import { DescriptionTemplateBaseFieldDataPersist, DescriptionTemplateDefinitionPersist, DescriptionTemplateFieldPersist, DescriptionTemplateFieldSetPersist, DescriptionTemplateMultiplicityPersist, DescriptionTemplatePagePersist, DescriptionTemplatePersist, DescriptionTemplateRulePersist, DescriptionTemplateSectionPersist } from "@app/core/model/description-template/description-template-persist";
|
||||
import { BaseEditorModel } from "@common/base/base-form-editor-model";
|
||||
import { BackendErrorValidator } from "@common/forms/validation/custom-validator";
|
||||
import { ValidationErrorModel } from "@common/forms/validation/error-model/validation-error-model";
|
||||
import { Validation, ValidationContext } from "@common/forms/validation/validation-context";
|
||||
import { Guid } from "@common/types/guid";
|
||||
|
||||
export class DescriptionTemplateEditorModel extends BaseEditorModel { // implements DescriptionTemplatePersist {
|
||||
export class DescriptionTemplateEditorModel extends BaseEditorModel implements DescriptionTemplatePersist {
|
||||
label: string;
|
||||
// definition: DescriptionTemplateDefinitionEditorModel;
|
||||
status: DescriptionTemplateStatus = DescriptionTemplateStatus.Draft;
|
||||
description: string;
|
||||
language: string;
|
||||
type: Guid;
|
||||
status: DescriptionTemplateStatus = DescriptionTemplateStatus.Draft;
|
||||
definition: DescriptionTemplateDefinitionEditorModel;
|
||||
permissions: string[];
|
||||
|
||||
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
|
||||
|
@ -26,7 +29,7 @@ export class DescriptionTemplateEditorModel extends BaseEditorModel { // impleme
|
|||
this.label = item.label;
|
||||
this.status = item.status;
|
||||
this.description = item.description;
|
||||
//this.definition = new DescriptionTemplateDefinitionEditorModel().fromModel(item.definition);
|
||||
this.definition = new DescriptionTemplateDefinitionEditorModel().fromModel(item.definition);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -37,10 +40,13 @@ export class DescriptionTemplateEditorModel extends BaseEditorModel { // impleme
|
|||
return this.formBuilder.group({
|
||||
id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators],
|
||||
label: [{ value: this.label, disabled: disabled }, context.getValidation('label').validators],
|
||||
description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators],
|
||||
language: [{ value: this.language, disabled: disabled }, context.getValidation('language').validators],
|
||||
type: [{ value: this.type, disabled: disabled }, context.getValidation('type').validators],
|
||||
status: [{ value: this.status, disabled: disabled }, context.getValidation('status').validators],
|
||||
// definition: this.definition.buildForm({
|
||||
// rootPath: `definition.`
|
||||
// }),
|
||||
definition: this.definition.buildForm({
|
||||
rootPath: `definition.`
|
||||
}),
|
||||
hash: [{ value: this.hash, disabled: disabled }, context.getValidation('hash').validators]
|
||||
});
|
||||
}
|
||||
|
@ -50,6 +56,10 @@ export class DescriptionTemplateEditorModel extends BaseEditorModel { // impleme
|
|||
const baseValidationArray: Validation[] = new Array<Validation>();
|
||||
baseValidationArray.push({ key: 'id', validators: [BackendErrorValidator(this.validationErrorModel, 'id')] });
|
||||
baseValidationArray.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'label')] });
|
||||
baseValidationArray.push({ key: 'description', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'description')] });
|
||||
baseValidationArray.push({ key: 'language', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'language')] });
|
||||
baseValidationArray.push({ key: 'type', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'type')] });
|
||||
baseValidationArray.push({ key: 'type', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'type')] });
|
||||
baseValidationArray.push({ key: 'status', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'status')] });
|
||||
baseValidationArray.push({ key: 'hash', validators: [] });
|
||||
|
||||
|
@ -58,236 +68,527 @@ export class DescriptionTemplateEditorModel extends BaseEditorModel { // impleme
|
|||
}
|
||||
}
|
||||
|
||||
// export class DescriptionTemplateDefinitionEditorModel implements DescriptionTemplateDefinitionPersist {
|
||||
// sections: DescriptionTemplateDefinitionSectionEditorModel[] = [];
|
||||
export class DescriptionTemplateDefinitionEditorModel implements DescriptionTemplateDefinitionPersist {
|
||||
pages: DescriptionTemplatePageEditorModel[] = [];
|
||||
sections: DescriptionTemplateSectionEditorModel[] = [];
|
||||
|
||||
// protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
||||
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
||||
|
||||
// constructor(
|
||||
// public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
||||
// ) { }
|
||||
constructor(
|
||||
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
||||
) { }
|
||||
|
||||
// public fromModel(item: DescriptionTemplateDefinition): DescriptionTemplateDefinitionEditorModel {
|
||||
// if (item) {
|
||||
// if (item.sections) { item.sections.map(x => this.sections.push(new DescriptionTemplateDefinitionSectionEditorModel().fromModel(x))); }
|
||||
// }
|
||||
// return this;
|
||||
// }
|
||||
public fromModel(item: DescriptionTemplateDefinition): DescriptionTemplateDefinitionEditorModel {
|
||||
if (item) {
|
||||
if (item.pages) { item.pages.map(x => this.pages.push(new DescriptionTemplatePageEditorModel().fromModel(x))); }
|
||||
if (item.sections) { item.sections.map(x => this.sections.push(new DescriptionTemplateSectionEditorModel().fromModel(x))); }
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// buildForm(params?: {
|
||||
// context?: ValidationContext,
|
||||
// disabled?: boolean,
|
||||
// rootPath?: string
|
||||
// }): UntypedFormGroup {
|
||||
// let { context = null, disabled = false, rootPath } = params ?? {}
|
||||
// if (context == null) {
|
||||
// context = DescriptionTemplateDefinitionEditorModel.createValidationContext({
|
||||
// validationErrorModel: this.validationErrorModel,
|
||||
// rootPath
|
||||
// });
|
||||
// }
|
||||
buildForm(params?: {
|
||||
context?: ValidationContext,
|
||||
disabled?: boolean,
|
||||
rootPath?: string
|
||||
}): UntypedFormGroup {
|
||||
let { context = null, disabled = false, rootPath } = params ?? {}
|
||||
if (context == null) {
|
||||
context = DescriptionTemplateDefinitionEditorModel.createValidationContext({
|
||||
validationErrorModel: this.validationErrorModel,
|
||||
rootPath
|
||||
});
|
||||
}
|
||||
|
||||
// return this.formBuilder.group({
|
||||
// sections: this.formBuilder.array(
|
||||
// (this.sections ?? []).map(
|
||||
// (item, index) => new DescriptionTemplateDefinitionSectionEditorModel(
|
||||
// this.validationErrorModel
|
||||
// ).fromModel(item).buildForm({
|
||||
// rootPath: `sections[${index}].`
|
||||
// }), context.getValidation('sections')
|
||||
// )
|
||||
// ),
|
||||
// });
|
||||
// }
|
||||
return this.formBuilder.group({
|
||||
pages: this.formBuilder.array(
|
||||
(this.pages ?? []).map(
|
||||
(item, index) => new DescriptionTemplatePageEditorModel(
|
||||
this.validationErrorModel
|
||||
).fromModel(item).buildForm({
|
||||
rootPath: `pages[${index}].`
|
||||
}), context.getValidation('pages')
|
||||
)
|
||||
),
|
||||
sections: this.formBuilder.array(
|
||||
(this.sections ?? []).map(
|
||||
(item, index) => new DescriptionTemplateSectionEditorModel(
|
||||
this.validationErrorModel
|
||||
).fromModel(item).buildForm({
|
||||
rootPath: `sections[${index}].`
|
||||
}), context.getValidation('sections')
|
||||
)
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
// static createValidationContext(params: {
|
||||
// rootPath?: string,
|
||||
// validationErrorModel: ValidationErrorModel
|
||||
// }): ValidationContext {
|
||||
// const { rootPath = '', validationErrorModel } = params;
|
||||
static createValidationContext(params: {
|
||||
rootPath?: string,
|
||||
validationErrorModel: ValidationErrorModel
|
||||
}): ValidationContext {
|
||||
const { rootPath = '', validationErrorModel } = params;
|
||||
|
||||
// const baseContext: ValidationContext = new ValidationContext();
|
||||
// const baseValidationArray: Validation[] = new Array<Validation>();
|
||||
// baseValidationArray.push({ key: 'sections', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}sections`)] });
|
||||
const baseContext: ValidationContext = new ValidationContext();
|
||||
const baseValidationArray: Validation[] = new Array<Validation>();
|
||||
baseValidationArray.push({ key: 'pages', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}pages`)] });
|
||||
baseValidationArray.push({ key: 'sections', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}sections`)] });
|
||||
|
||||
// baseContext.validation = baseValidationArray;
|
||||
// return baseContext;
|
||||
// }
|
||||
baseContext.validation = baseValidationArray;
|
||||
return baseContext;
|
||||
}
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
// export class DescriptionTemplateDefinitionSectionEditorModel implements DescriptionTemplateDefinitionSectionPersist {
|
||||
// id: Guid;
|
||||
// label: string;
|
||||
// description: string;
|
||||
// ordinal: number;
|
||||
// fields: FieldInSectionEditorModel[] = [];
|
||||
// hasTemplates: boolean;
|
||||
// descriptionTemplates?: DescriptionTemplatesInSectionEditorModel[] = [];
|
||||
export class DescriptionTemplatePageEditorModel implements DescriptionTemplatePagePersist {
|
||||
id: Guid;
|
||||
ordinal: number;
|
||||
title: string;
|
||||
|
||||
// protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
||||
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
||||
|
||||
// constructor(
|
||||
// public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
||||
// ) { }
|
||||
constructor(
|
||||
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
||||
) { }
|
||||
|
||||
// public fromModel(item: DescriptionTemplateDefinitionSection): DescriptionTemplateDefinitionSectionEditorModel {
|
||||
// if (item) {
|
||||
// this.id = item.id;
|
||||
// this.label = item.label;
|
||||
// this.description = item.description;
|
||||
// this.ordinal = item.ordinal;
|
||||
// this.hasTemplates = item.hasTemplates;
|
||||
// if (item.fields) { item.fields.map(x => this.fields.push(new FieldInSectionEditorModel().fromModel(x))); }
|
||||
// if (item.descriptionTemplates) { item.descriptionTemplates.map(x => this.descriptionTemplates.push(new DescriptionTemplatesInSectionEditorModel().fromModel(x))); }
|
||||
// }
|
||||
// return this;
|
||||
// }
|
||||
public fromModel(item: DescriptionTemplatePage): DescriptionTemplatePageEditorModel {
|
||||
if (item) {
|
||||
this.id = item.id;
|
||||
this.ordinal = item.ordinal;
|
||||
this.title = item.title;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// buildForm(params?: {
|
||||
// context?: ValidationContext,
|
||||
// disabled?: boolean,
|
||||
// rootPath?: string
|
||||
// }): UntypedFormGroup {
|
||||
// let { context = null, disabled = false, rootPath } = params ?? {}
|
||||
// if (context == null) {
|
||||
// context = DescriptionTemplateDefinitionSectionEditorModel.createValidationContext({
|
||||
// validationErrorModel: this.validationErrorModel,
|
||||
// rootPath
|
||||
// });
|
||||
// }
|
||||
buildForm(params?: {
|
||||
context?: ValidationContext,
|
||||
disabled?: boolean,
|
||||
rootPath?: string
|
||||
}): UntypedFormGroup {
|
||||
let { context = null, disabled = false, rootPath } = params ?? {}
|
||||
if (context == null) {
|
||||
context = DescriptionTemplatePageEditorModel.createValidationContext({
|
||||
validationErrorModel: this.validationErrorModel,
|
||||
rootPath
|
||||
});
|
||||
}
|
||||
|
||||
// return this.formBuilder.group({
|
||||
// id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators],
|
||||
// label: [{ value: this.label, disabled: disabled }, context.getValidation('label').validators],
|
||||
// ordinal: [{ value: this.ordinal, disabled: disabled }, context.getValidation('ordinal').validators],
|
||||
// description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators],
|
||||
// hasTemplates: [{ value: this.hasTemplates, disabled: disabled }, context.getValidation('hasTemplates').validators],
|
||||
// fields: this.formBuilder.array(
|
||||
// (this.fields ?? []).map(
|
||||
// (item, index) => new FieldInSectionEditorModel(
|
||||
// this.validationErrorModel
|
||||
// ).fromModel(item).buildForm({
|
||||
// rootPath: `fields[${index}].`
|
||||
// }), context.getValidation('fields')
|
||||
// )
|
||||
// ),
|
||||
// descriptionTemplates: this.formBuilder.array(
|
||||
// (this.descriptionTemplates ?? []).map(
|
||||
// (item, index) => new DescriptionTemplatesInSectionEditorModel(
|
||||
// this.validationErrorModel
|
||||
// ).fromModel(item).buildForm({
|
||||
// rootPath: `fields[${index}].`
|
||||
// }), context.getValidation('descriptionTemplates')
|
||||
// )
|
||||
// )
|
||||
// });
|
||||
// }
|
||||
return this.formBuilder.group({
|
||||
id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators],
|
||||
ordinal: [{ value: this.ordinal, disabled: disabled }, context.getValidation('ordinal').validators],
|
||||
title: [{ value: this.title, disabled: disabled }, context.getValidation('title').validators]
|
||||
});
|
||||
}
|
||||
|
||||
// static createValidationContext(params: {
|
||||
// rootPath?: string,
|
||||
// validationErrorModel: ValidationErrorModel
|
||||
// }): ValidationContext {
|
||||
// const { rootPath = '', validationErrorModel } = params;
|
||||
static createValidationContext(params: {
|
||||
rootPath?: string,
|
||||
validationErrorModel: ValidationErrorModel
|
||||
}): ValidationContext {
|
||||
const { rootPath = '', validationErrorModel } = params;
|
||||
|
||||
// const baseContext: ValidationContext = new ValidationContext();
|
||||
// const baseValidationArray: Validation[] = new Array<Validation>();
|
||||
// baseValidationArray.push({ key: 'id', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}id`)] });
|
||||
// baseValidationArray.push({ key: 'label', validators: [Validators.required,BackendErrorValidator(validationErrorModel, `${rootPath}label`)] });
|
||||
// baseValidationArray.push({ key: 'ordinal', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}ordinal`)] });
|
||||
// baseValidationArray.push({ key: 'description', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}description`)] });
|
||||
// baseValidationArray.push({ key: 'hasTemplates', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}hasTemplates`)] });
|
||||
// baseValidationArray.push({ key: 'fields', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}fields`)] });
|
||||
// baseValidationArray.push({ key: 'descriptionTemplates', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}descriptionTemplates`)] });
|
||||
// baseValidationArray.push({ key: 'hash', validators: [] });
|
||||
const baseContext: ValidationContext = new ValidationContext();
|
||||
const baseValidationArray: Validation[] = new Array<Validation>();
|
||||
baseValidationArray.push({ key: 'id', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}id`)] });
|
||||
baseValidationArray.push({ key: 'ordinal', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}ordinal`)] });
|
||||
baseValidationArray.push({ key: 'title', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}title`)] });
|
||||
|
||||
// baseContext.validation = baseValidationArray;
|
||||
// return baseContext;
|
||||
// }
|
||||
baseContext.validation = baseValidationArray;
|
||||
return baseContext;
|
||||
}
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
// export class FieldInSectionEditorModel implements FieldInSectionPersist {
|
||||
// public id: Guid;
|
||||
// public category: DescriptionTemplateSectionFieldCategory;
|
||||
// public dataType: DescriptionTemplateExtraFieldDataType;
|
||||
// public systemFieldType: DescriptionTemplateSystemFieldType;
|
||||
// public label: string;
|
||||
// public placeholder: string;
|
||||
// public description: string;
|
||||
// public required: boolean = false;
|
||||
// public ordinal: number;
|
||||
export class DescriptionTemplateSectionEditorModel implements DescriptionTemplateSectionPersist {
|
||||
id: Guid;
|
||||
ordinal: number;
|
||||
defaultVisibility: boolean;
|
||||
multiplicity: boolean;
|
||||
page: string;
|
||||
title: string;
|
||||
description: string;
|
||||
sections?: DescriptionTemplateSectionEditorModel[] = [];
|
||||
fieldSets: DescriptionTemplateFieldSetEditorModel[] = [];
|
||||
|
||||
// protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
||||
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
||||
|
||||
// constructor(
|
||||
// public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
||||
// ) { }
|
||||
constructor(
|
||||
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
||||
) { }
|
||||
|
||||
// fromModel(item: FieldInSection): FieldInSectionEditorModel {
|
||||
// this.id = item.id;
|
||||
// this.category = item.category;
|
||||
// this.dataType = item.dataType;
|
||||
// this.systemFieldType = item.systemFieldType;
|
||||
// this.label = item.label;
|
||||
// this.placeholder = item.placeholder;
|
||||
// this.description = item.description;
|
||||
// this.required = item.required;
|
||||
// this.ordinal = item.ordinal;
|
||||
// return this;
|
||||
// }
|
||||
public fromModel(item: DescriptionTemplateSection | DescriptionTemplateSectionEditorModel): DescriptionTemplateSectionEditorModel {
|
||||
if (item) {
|
||||
this.id = item.id;
|
||||
this.ordinal = item.ordinal;
|
||||
this.defaultVisibility = item.defaultVisibility;
|
||||
this.multiplicity = item.multiplicity;
|
||||
this.page = item.page;
|
||||
this.title = item.title;
|
||||
this.description = item.description;
|
||||
if (item.sections) { item.sections.map(x => this.sections.push(new DescriptionTemplateSectionEditorModel().fromModel(x))); }
|
||||
if (item.fieldSets) { item.fieldSets.map(x => this.fieldSets.push(new DescriptionTemplateFieldSetEditorModel().fromModel(x))); }
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// buildForm(params?: {
|
||||
// context?: ValidationContext,
|
||||
// disabled?: boolean,
|
||||
// rootPath?: string
|
||||
// }): UntypedFormGroup {
|
||||
// let { context = null, disabled = false, rootPath } = params ?? {}
|
||||
// if (context == null) {
|
||||
// context = FieldInSectionEditorModel.createValidationContext({
|
||||
// validationErrorModel: this.validationErrorModel,
|
||||
// rootPath
|
||||
// });
|
||||
// }
|
||||
buildForm(params?: {
|
||||
context?: ValidationContext,
|
||||
disabled?: boolean,
|
||||
rootPath?: string
|
||||
}): UntypedFormGroup {
|
||||
let { context = null, disabled = false, rootPath } = params ?? {}
|
||||
if (context == null) {
|
||||
context = DescriptionTemplateSectionEditorModel.createValidationContext({
|
||||
validationErrorModel: this.validationErrorModel,
|
||||
rootPath
|
||||
});
|
||||
}
|
||||
|
||||
// return this.formBuilder.group({
|
||||
// id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators],
|
||||
return this.formBuilder.group({
|
||||
id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators],
|
||||
ordinal: [{ value: this.ordinal, disabled: disabled }, context.getValidation('ordinal').validators],
|
||||
defaultVisibility: [{ value: this.defaultVisibility, disabled: disabled }, context.getValidation('defaultVisibility').validators],
|
||||
multiplicity: [{ value: this.multiplicity, disabled: disabled }, context.getValidation('multiplicity').validators],
|
||||
page: [{ value: this.page, disabled: disabled }, context.getValidation('page').validators],
|
||||
title: [{ value: this.title, disabled: disabled }, context.getValidation('title').validators],
|
||||
description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators],
|
||||
sections: this.formBuilder.array(
|
||||
(this.sections ?? []).map(
|
||||
(item, index) => new DescriptionTemplateSectionEditorModel(
|
||||
this.validationErrorModel
|
||||
).fromModel(item).buildForm({
|
||||
rootPath: `sections[${index}].`
|
||||
}), context.getValidation('sections')
|
||||
)
|
||||
),
|
||||
fieldSets: this.formBuilder.array(
|
||||
(this.fieldSets ?? []).map(
|
||||
(item, index) => new DescriptionTemplateFieldSetEditorModel(
|
||||
this.validationErrorModel
|
||||
).fromModel(item).buildForm({
|
||||
rootPath: `fieldSets[${index}].`
|
||||
}), context.getValidation('fieldSets')
|
||||
)
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
// category: [{ value: this.category, disabled: disabled }, context.getValidation('category').validators],
|
||||
// dataType: [{ value: this.dataType, disabled: disabled }, context.getValidation('dataType').validators],
|
||||
// systemFieldType: [{ value: this.systemFieldType, disabled: disabled }, context.getValidation('systemFieldType').validators],
|
||||
// label: [{ value: this.label, disabled: disabled }, context.getValidation('label').validators],
|
||||
// placeholder: [{ value: this.placeholder, disabled: disabled }, context.getValidation('placeholder').validators],
|
||||
// description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators],
|
||||
// required: [{ value: this.required, disabled: disabled }, context.getValidation('required').validators],
|
||||
// ordinal: [{ value: this.ordinal, disabled: disabled }, context.getValidation('ordinal').validators],
|
||||
static createValidationContext(params: {
|
||||
rootPath?: string,
|
||||
validationErrorModel: ValidationErrorModel
|
||||
}): ValidationContext {
|
||||
const { rootPath = '', validationErrorModel } = params;
|
||||
|
||||
// });
|
||||
// }
|
||||
const baseContext: ValidationContext = new ValidationContext();
|
||||
const baseValidationArray: Validation[] = new Array<Validation>();
|
||||
baseValidationArray.push({ key: 'id', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}id`)] });
|
||||
baseValidationArray.push({ key: 'ordinal', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}ordinal`)] });
|
||||
baseValidationArray.push({ key: 'defaultVisibility', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}defaultVisibility`)] });
|
||||
baseValidationArray.push({ key: 'multiplicity', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}multiplicity`)] });
|
||||
baseValidationArray.push({ key: 'page', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}page`)] });
|
||||
baseValidationArray.push({ key: 'title', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}title`)] });
|
||||
baseValidationArray.push({ key: 'description', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}description`)] });
|
||||
baseValidationArray.push({ key: 'sections', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}sections`)] });
|
||||
baseValidationArray.push({ key: 'fieldSets', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}fieldSets`)] });
|
||||
|
||||
// static createValidationContext(params: {
|
||||
// rootPath?: string,
|
||||
// validationErrorModel: ValidationErrorModel
|
||||
// }): ValidationContext {
|
||||
// const { rootPath = '', validationErrorModel } = params;
|
||||
baseContext.validation = baseValidationArray;
|
||||
return baseContext;
|
||||
}
|
||||
|
||||
// const baseContext: ValidationContext = new ValidationContext();
|
||||
// const baseValidationArray: Validation[] = new Array<Validation>();
|
||||
// baseValidationArray.push({ key: 'id', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}id`)] });
|
||||
}
|
||||
|
||||
// baseValidationArray.push({ key: 'category', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}category`)] });
|
||||
// baseValidationArray.push({ key: 'dataType', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}dataType`)] });
|
||||
// baseValidationArray.push({ key: 'systemFieldType', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}systemFieldType`)] });
|
||||
// baseValidationArray.push({ key: 'label', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}label`)] });
|
||||
// baseValidationArray.push({ key: 'placeholder', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}placeholder`)] });
|
||||
// baseValidationArray.push({ key: 'description', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}description`)] });
|
||||
// baseValidationArray.push({ key: 'required', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}required`)] });
|
||||
// baseValidationArray.push({ key: 'ordinal', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}ordinal`)] });
|
||||
export class DescriptionTemplateFieldSetEditorModel implements DescriptionTemplateFieldSetPersist {
|
||||
id: Guid;
|
||||
ordinal: number;
|
||||
numbering: string;
|
||||
title: string;
|
||||
description: string;
|
||||
extendedDescription: string;
|
||||
additionalInformation: string;
|
||||
multiplicity: DescriptionTemplateMultiplicityEditorModel;
|
||||
hasCommentField: boolean;
|
||||
fields: DescriptionTemplateFieldEditorModel[] = [];
|
||||
|
||||
// baseContext.validation = baseValidationArray;
|
||||
// return baseContext;
|
||||
// }
|
||||
// }
|
||||
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
||||
|
||||
constructor(
|
||||
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
||||
) { }
|
||||
|
||||
fromModel(item: DescriptionTemplateFieldSet | DescriptionTemplateFieldSetEditorModel): DescriptionTemplateFieldSetEditorModel {
|
||||
if (item) {
|
||||
this.id = item.id;
|
||||
this.ordinal = item.ordinal;
|
||||
this.numbering = item.numbering;
|
||||
this.title = item.title;
|
||||
this.description = item.description;
|
||||
this.extendedDescription = item.extendedDescription;
|
||||
this.additionalInformation = item.additionalInformation;
|
||||
this.hasCommentField = item.hasCommentField;
|
||||
|
||||
this.multiplicity = new DescriptionTemplateMultiplicityEditorModel().fromModel(item.multiplicity);
|
||||
if (item.fields) { item.fields.map(x => this.fields.push(new DescriptionTemplateFieldEditorModel().fromModel(x))); }
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
buildForm(params?: {
|
||||
context?: ValidationContext,
|
||||
disabled?: boolean,
|
||||
rootPath?: string
|
||||
}): UntypedFormGroup {
|
||||
let { context = null, disabled = false, rootPath } = params ?? {}
|
||||
if (context == null) {
|
||||
context = DescriptionTemplateFieldSetEditorModel.createValidationContext({
|
||||
validationErrorModel: this.validationErrorModel,
|
||||
rootPath
|
||||
});
|
||||
}
|
||||
|
||||
return this.formBuilder.group({
|
||||
id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators],
|
||||
ordinal: [{ value: this.ordinal, disabled: disabled }, context.getValidation('ordinal').validators],
|
||||
numbering: [{ value: this.numbering, disabled: disabled }, context.getValidation('numbering').validators],
|
||||
title: [{ value: this.title, disabled: disabled }, context.getValidation('title').validators],
|
||||
description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators],
|
||||
extendedDescription: [{ value: this.extendedDescription, disabled: disabled }, context.getValidation('extendedDescription').validators],
|
||||
additionalInformation: [{ value: this.additionalInformation, disabled: disabled }, context.getValidation('additionalInformation').validators],
|
||||
hasCommentField: [{ value: this.hasCommentField, disabled: disabled }, context.getValidation('hasCommentField').validators],
|
||||
multiplicity: this.multiplicity.buildForm({
|
||||
rootPath: `multiplicity.`
|
||||
}),
|
||||
fields: this.formBuilder.array(
|
||||
(this.fields ?? []).map(
|
||||
(item, index) => new DescriptionTemplateFieldEditorModel(
|
||||
this.validationErrorModel
|
||||
).fromModel(item).buildForm({
|
||||
rootPath: `fields[${index}].`
|
||||
}), context.getValidation('fields')
|
||||
)
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
static createValidationContext(params: {
|
||||
rootPath?: string,
|
||||
validationErrorModel: ValidationErrorModel
|
||||
}): ValidationContext {
|
||||
const { rootPath = '', validationErrorModel } = params;
|
||||
|
||||
const baseContext: ValidationContext = new ValidationContext();
|
||||
const baseValidationArray: Validation[] = new Array<Validation>();
|
||||
baseValidationArray.push({ key: 'id', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}id`)] });
|
||||
baseValidationArray.push({ key: 'ordinal', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}ordinal`)] });
|
||||
baseValidationArray.push({ key: 'numbering', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}numbering`)] });
|
||||
baseValidationArray.push({ key: 'title', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}title`)] });
|
||||
baseValidationArray.push({ key: 'description', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}description`)] });
|
||||
baseValidationArray.push({ key: 'extendedDescription', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}extendedDescription`)] });
|
||||
baseValidationArray.push({ key: 'additionalInformation', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}additionalInformation`)] });
|
||||
baseValidationArray.push({ key: 'hasCommentField', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}hasCommentField`)] });
|
||||
baseValidationArray.push({ key: 'fields', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}fields`)] });
|
||||
|
||||
baseContext.validation = baseValidationArray;
|
||||
return baseContext;
|
||||
}
|
||||
}
|
||||
|
||||
export class DescriptionTemplateMultiplicityEditorModel implements DescriptionTemplateMultiplicityPersist {
|
||||
min: number;
|
||||
max: number;
|
||||
placeholder: string;
|
||||
tableView: boolean;
|
||||
|
||||
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
||||
|
||||
constructor(
|
||||
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
||||
) { }
|
||||
|
||||
fromModel(item: DescriptionTemplateMultiplicity): DescriptionTemplateMultiplicityEditorModel {
|
||||
if (item) {
|
||||
this.min = item.min;
|
||||
this.max = item.max;
|
||||
this.placeholder = item.placeholder;
|
||||
this.tableView = item.tableView;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
buildForm(params?: {
|
||||
context?: ValidationContext,
|
||||
disabled?: boolean,
|
||||
rootPath?: string
|
||||
}): UntypedFormGroup {
|
||||
let { context = null, disabled = false, rootPath } = params ?? {}
|
||||
if (context == null) {
|
||||
context = DescriptionTemplateMultiplicityEditorModel.createValidationContext({
|
||||
validationErrorModel: this.validationErrorModel,
|
||||
rootPath
|
||||
});
|
||||
}
|
||||
|
||||
return this.formBuilder.group({
|
||||
min: [{ value: this.min, disabled: disabled }, context.getValidation('min').validators],
|
||||
max: [{ value: this.max, disabled: disabled }, context.getValidation('max').validators],
|
||||
placeholder: [{ value: this.placeholder, disabled: disabled }, context.getValidation('placeholder').validators],
|
||||
tableView: [{ value: this.tableView, disabled: disabled }, context.getValidation('tableView').validators],
|
||||
});
|
||||
}
|
||||
|
||||
static createValidationContext(params: {
|
||||
rootPath?: string,
|
||||
validationErrorModel: ValidationErrorModel
|
||||
}): ValidationContext {
|
||||
const { rootPath = '', validationErrorModel } = params;
|
||||
|
||||
const baseContext: ValidationContext = new ValidationContext();
|
||||
const baseValidationArray: Validation[] = new Array<Validation>();
|
||||
baseValidationArray.push({ key: 'min', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}min`)] });
|
||||
baseValidationArray.push({ key: 'max', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}max`)] });
|
||||
baseValidationArray.push({ key: 'placeholder', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}placeholder`)] });
|
||||
baseValidationArray.push({ key: 'tableView', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}tableView`)] });
|
||||
|
||||
baseContext.validation = baseValidationArray;
|
||||
return baseContext;
|
||||
}
|
||||
}
|
||||
|
||||
export class DescriptionTemplateFieldEditorModel implements DescriptionTemplateFieldPersist {
|
||||
id: Guid;
|
||||
ordinal: number;
|
||||
schematics: string[];
|
||||
defaultValue: string;
|
||||
visibilityRules: DescriptionTemplateRuleEditorModel[] = [];
|
||||
validations: DescriptionTemplateFieldValidationType[];
|
||||
includeInExport: boolean;
|
||||
data: DescriptionTemplateBaseFieldDataPersist;
|
||||
|
||||
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
||||
|
||||
constructor(
|
||||
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
||||
) { }
|
||||
|
||||
fromModel(item: DescriptionTemplateField | DescriptionTemplateFieldEditorModel): DescriptionTemplateFieldEditorModel {
|
||||
if (item) {
|
||||
this.id = item.id;
|
||||
this.ordinal = item.ordinal;
|
||||
this.schematics = item.schematics;
|
||||
this.defaultValue = item.defaultValue;
|
||||
this.validations = item.validations;
|
||||
this.includeInExport = item.includeInExport;
|
||||
|
||||
//this.data = new DescriptionTemplateBaseFieldDataEditorModel().fromModel(item.data);
|
||||
if (item.visibilityRules) { item.visibilityRules.map(x => this.visibilityRules.push(new DescriptionTemplateRuleEditorModel().fromModel(x))); }
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
buildForm(params?: {
|
||||
context?: ValidationContext,
|
||||
disabled?: boolean,
|
||||
rootPath?: string
|
||||
}): UntypedFormGroup {
|
||||
let { context = null, disabled = false, rootPath } = params ?? {}
|
||||
if (context == null) {
|
||||
context = DescriptionTemplateFieldEditorModel.createValidationContext({
|
||||
validationErrorModel: this.validationErrorModel,
|
||||
rootPath
|
||||
});
|
||||
}
|
||||
|
||||
return this.formBuilder.group({
|
||||
id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators],
|
||||
ordinal: [{ value: this.ordinal, disabled: disabled }, context.getValidation('ordinal').validators],
|
||||
schematics: [{ value: this.schematics, disabled: disabled }, context.getValidation('schematics').validators],
|
||||
defaultValue: [{ value: this.defaultValue, disabled: disabled }, context.getValidation('defaultValue').validators],
|
||||
validations: [{ value: this.validations, disabled: disabled }, context.getValidation('validations').validators],
|
||||
includeInExport: [{ value: this.includeInExport, disabled: disabled }, context.getValidation('includeInExport').validators],
|
||||
// data: this.data.buildForm({
|
||||
// rootPath: `data.`
|
||||
// }),
|
||||
visibilityRules: this.formBuilder.array(
|
||||
(this.visibilityRules ?? []).map(
|
||||
(item, index) => new DescriptionTemplateRuleEditorModel(
|
||||
this.validationErrorModel
|
||||
).fromModel(item).buildForm({
|
||||
rootPath: `visibilityRules[${index}].`
|
||||
}), context.getValidation('visibilityRules')
|
||||
)
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
static createValidationContext(params: {
|
||||
rootPath?: string,
|
||||
validationErrorModel: ValidationErrorModel
|
||||
}): ValidationContext {
|
||||
const { rootPath = '', validationErrorModel } = params;
|
||||
|
||||
const baseContext: ValidationContext = new ValidationContext();
|
||||
const baseValidationArray: Validation[] = new Array<Validation>();
|
||||
baseValidationArray.push({ key: 'id', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}id`)] });
|
||||
baseValidationArray.push({ key: 'ordinal', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}ordinal`)] });
|
||||
baseValidationArray.push({ key: 'schematics', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}schematics`)] });
|
||||
baseValidationArray.push({ key: 'defaultValue', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}defaultValue`)] });
|
||||
baseValidationArray.push({ key: 'validations', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}validations`)] });
|
||||
baseValidationArray.push({ key: 'includeInExport', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}includeInExport`)] });
|
||||
baseValidationArray.push({ key: 'visibilityRules', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}visibilityRules`)] });
|
||||
|
||||
baseContext.validation = baseValidationArray;
|
||||
return baseContext;
|
||||
}
|
||||
}
|
||||
|
||||
export class DescriptionTemplateRuleEditorModel implements DescriptionTemplateRulePersist {
|
||||
target: string;
|
||||
value: string;
|
||||
|
||||
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
|
||||
|
||||
constructor(
|
||||
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel()
|
||||
) { }
|
||||
|
||||
fromModel(item: DescriptionTemplateRule): DescriptionTemplateRuleEditorModel {
|
||||
if (item) {
|
||||
this.target = item.target;
|
||||
this.value = item.value;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
buildForm(params?: {
|
||||
context?: ValidationContext,
|
||||
disabled?: boolean,
|
||||
rootPath?: string
|
||||
}): UntypedFormGroup {
|
||||
let { context = null, disabled = false, rootPath } = params ?? {}
|
||||
if (context == null) {
|
||||
context = DescriptionTemplateRuleEditorModel.createValidationContext({
|
||||
validationErrorModel: this.validationErrorModel,
|
||||
rootPath
|
||||
});
|
||||
}
|
||||
|
||||
return this.formBuilder.group({
|
||||
target: [{ value: this.target, disabled: disabled }, context.getValidation('target').validators],
|
||||
value: [{ value: this.value, disabled: disabled }, context.getValidation('value').validators]
|
||||
});
|
||||
}
|
||||
|
||||
static createValidationContext(params: {
|
||||
rootPath?: string,
|
||||
validationErrorModel: ValidationErrorModel
|
||||
}): ValidationContext {
|
||||
const { rootPath = '', validationErrorModel } = params;
|
||||
|
||||
const baseContext: ValidationContext = new ValidationContext();
|
||||
const baseValidationArray: Validation[] = new Array<Validation>();
|
||||
baseValidationArray.push({ key: 'target', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}target`)] });
|
||||
baseValidationArray.push({ key: 'value', validators: [Validators.required, BackendErrorValidator(validationErrorModel, `${rootPath}value`)] });
|
||||
|
||||
baseContext.validation = baseValidationArray;
|
||||
return baseContext;
|
||||
}
|
||||
}
|
||||
|
||||
// export class DescriptionTemplatesInSectionEditorModel implements DescriptionTemplatesInSectionPersist {
|
||||
// id: Guid;
|
||||
|
|
|
@ -58,7 +58,7 @@ export class DescriptionTemplateEditorResolver extends BaseEditorResolver {
|
|||
[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<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.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<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('.'),
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import { AbstractControl } from "@angular/forms";
|
||||
|
||||
export interface ToCEntry {
|
||||
id: string;
|
||||
label: string;
|
||||
subEntriesType: ToCEntryType;
|
||||
subEntries: ToCEntry[];
|
||||
type: ToCEntryType;
|
||||
form: AbstractControl;
|
||||
numbering: string;
|
||||
}
|
||||
|
||||
|
||||
export enum ToCEntryType {
|
||||
Page = 0,
|
||||
Section = 1,
|
||||
FieldSet = 2,
|
||||
Field = 3
|
||||
}
|
||||
|
||||
export interface NewEntryType {
|
||||
childType: ToCEntryType,
|
||||
parent: ToCEntry
|
||||
}
|
||||
|
||||
export interface TableUpdateInfo{
|
||||
draggedItemId?: string;
|
||||
data?:any;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<div class="table-container">
|
||||
<h3 id="guide-steps" [class.opacity-0]="isDragging">{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.GENERAL-INFO.TEMPLATE-OUTLINE' | translate}}</h3>
|
||||
<div class="scroll-container" id="tocentrytable">
|
||||
|
||||
<app-description-template-table-of-contents-internal-section [links]="links" (itemClick)="itemClicked($event)"
|
||||
(removeEntry)="deleteEntry($event)"
|
||||
(createFooEntry)="createNewEntry($event)"
|
||||
[parentLink]="{ subEntriesType: tocEntryType.Page, subEntries : links , id: ROOT_ID}"
|
||||
[itemSelected]="itemSelected"
|
||||
[viewOnly]="viewOnly"
|
||||
(dataNeedsRefresh)="onDataNeedsRefresh()"
|
||||
[DRAGULA_ITEM_ID_PREFIX]="DRAGULA_ITEM_ID_PREFIX"
|
||||
[overContainerId]="overcontainer"
|
||||
[isDragging]="isDragging"
|
||||
[draggingItemId]="draggingItemId"
|
||||
[parentRootId]="ROOT_ID"
|
||||
style="padding-right: 1em;"
|
||||
[colorizeInvalid]="colorizeInvalid"
|
||||
>
|
||||
</app-description-template-table-of-contents-internal-section>
|
||||
<div class="top-scroller table-scroller" [hidden]="!isDragging">
|
||||
<div class="col-auto">
|
||||
<mat-icon>keyboard_arrow_up</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-scroller table-scroller" [hidden]="!isDragging">
|
||||
<div class="col-auto">
|
||||
<mat-icon>keyboard_arrow_down</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,92 @@
|
|||
$scroller-height: 3em;
|
||||
.scroll-container {
|
||||
// overflow-y: auto;
|
||||
max-height: 60vh;
|
||||
overflow-y: scroll;
|
||||
padding-left: .2em;
|
||||
padding-right: 1em;
|
||||
// padding-top: $scroller-height;
|
||||
// padding-bottom: $scroller-height;
|
||||
}
|
||||
|
||||
// #style-6::-webkit-scrollbar-track
|
||||
// {
|
||||
// -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
|
||||
// background-color: #F5F5F5;
|
||||
// }
|
||||
|
||||
// #style-6::-webkit-scrollbar
|
||||
// {
|
||||
// width: 6px;
|
||||
// background-color: #F5F5F5;
|
||||
// }
|
||||
|
||||
// #style-6::-webkit-scrollbar-thumb
|
||||
// {
|
||||
// background-color: rgb(162, 163, 163);
|
||||
// background-image: -webkit-linear-gradient(45deg,
|
||||
// rgba(255, 255, 255, .2) 25%,
|
||||
// transparent 25%,
|
||||
// transparent 50%,
|
||||
// rgba(255, 255, 255, .2) 50%,
|
||||
// rgba(255, 255, 255, .2) 75%,
|
||||
// transparent 75%,
|
||||
// transparent)
|
||||
// }
|
||||
|
||||
|
||||
#tocentrytable::-webkit-scrollbar-track
|
||||
{
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
|
||||
border-radius: 10px;
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
|
||||
#tocentrytable::-webkit-scrollbar
|
||||
{
|
||||
width: 4px;
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
|
||||
#tocentrytable::-webkit-scrollbar-thumb
|
||||
{
|
||||
border-radius: 2px;
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
|
||||
background-color: rgb(158, 158, 158);// #FFF;//$blue-color-light;// rgb(162, 163, 163);// #D62929;
|
||||
}
|
||||
|
||||
|
||||
#guide-steps{
|
||||
color: #212121;
|
||||
opacity: 0.6;
|
||||
font-size: 1.6em;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.table-container{
|
||||
position: relative;
|
||||
}
|
||||
.table-scroller{
|
||||
// background-color: #5cf7f221;
|
||||
position: absolute;
|
||||
width: 95%;
|
||||
height: $scroller-height;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
// z-index: -9999;
|
||||
}
|
||||
.top-scroller{
|
||||
top: 1px;
|
||||
background: rgb(255,255,255);
|
||||
background: linear-gradient(0deg, rgba(255,255,255,0) 0%, rgba(92,247,242,0.4542191876750701) 100%);
|
||||
}
|
||||
.bottom-scroller{
|
||||
bottom: 1px;
|
||||
background: rgb(255,255,255);
|
||||
background: linear-gradient(180deg, rgba(255,255,255,0) 0%, rgba(92,247,242,0.4542191876750701) 100%);
|
||||
}
|
||||
|
||||
.opacity-0{
|
||||
opacity: 0 !important;
|
||||
}
|
|
@ -0,0 +1,605 @@
|
|||
import { DOCUMENT } from '@angular/common';
|
||||
import { AfterViewInit, Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core';
|
||||
import { UntypedFormArray } from '@angular/forms';
|
||||
import { MatSnackBar, MatSnackBarConfig } from '@angular/material/snack-bar';
|
||||
import { BaseComponent } from '@common/base/base.component';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DragulaService } from 'ng2-dragula';
|
||||
import { interval } from 'rxjs';
|
||||
import { filter, takeUntil } from 'rxjs/operators';
|
||||
import { NewEntryType, TableUpdateInfo, ToCEntry, ToCEntryType } from './description-template-table-of-contents-entry';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'description-template-table-of-contents',
|
||||
styleUrls: ['./description-template-table-of-contents.scss'],
|
||||
templateUrl: './description-template-table-of-contents.html'
|
||||
})
|
||||
export class DescriptionTemplateTableOfContents extends BaseComponent implements OnInit, AfterViewInit {
|
||||
|
||||
@Input() links: ToCEntry[];
|
||||
@Input() itemSelected: ToCEntry;
|
||||
@Input() colorizeInvalid: boolean = false;
|
||||
@Input() viewOnly: boolean;
|
||||
|
||||
|
||||
@Output() itemClick = new EventEmitter<ToCEntry>();
|
||||
// @Output() newEntry = new EventEmitter<ToCEntry>();
|
||||
@Output() removeEntry = new EventEmitter<ToCEntry>();
|
||||
@Output() createEntry = new EventEmitter<NewEntryType>();
|
||||
@Output() dataNeedsRefresh = new EventEmitter<TableUpdateInfo>();
|
||||
|
||||
isDragging: boolean = false;
|
||||
draggingItemId: string = null;
|
||||
tocEntryType = ToCEntryType;
|
||||
|
||||
DRAGULA_ITEM_ID_PREFIX = "table_item_id_";
|
||||
ROOT_ID: string = "ROOT_ID";//no special meaning
|
||||
private _dragStartedAt;
|
||||
private VALID_DROP_TIME = 500;//ms
|
||||
overcontainer: string = null;
|
||||
|
||||
$clock = interval(10);
|
||||
scrollTableTop = false;
|
||||
scrollTableBottom = false;
|
||||
pxToScroll = 15;
|
||||
|
||||
constructor(
|
||||
@Inject(DOCUMENT) private _document: Document,
|
||||
private dragulaService: DragulaService,
|
||||
private snackbar: MatSnackBar,
|
||||
private language: TranslateService
|
||||
) {
|
||||
super();
|
||||
|
||||
if (this.dragulaService.find('TABLEDRAG')) {
|
||||
this.dragulaService.destroy('TABLEDRAG');
|
||||
}
|
||||
|
||||
const dragula = this.dragulaService.createGroup('TABLEDRAG', {});
|
||||
|
||||
const drake = dragula.drake;
|
||||
|
||||
drake.on('drop', (el, target, source, sibling) => {
|
||||
|
||||
if (this._dragStartedAt) {
|
||||
const timeNow = new Date().getTime();
|
||||
|
||||
if (timeNow - this._dragStartedAt > this.VALID_DROP_TIME) {
|
||||
// console.log('timenow: ', timeNow);
|
||||
// console.log('timestarted', this._dragStartedAt);
|
||||
this._dragStartedAt = null;
|
||||
|
||||
} else {
|
||||
this.dataNeedsRefresh.emit();// even though the data is not changed the TABLE DRAG may has changed
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this.dataNeedsRefresh.emit();// even though the data is not changed the TABLE DRAG may has changed
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
const elementId = (el.id as string).replace(this.DRAGULA_ITEM_ID_PREFIX, '');
|
||||
const targetId = target.id as string;
|
||||
const sourceId = source.id as string;
|
||||
|
||||
|
||||
if (!(elementId && targetId && sourceId)) {
|
||||
console.info('Elements do not have an id');
|
||||
this.dataNeedsRefresh.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const element: ToCEntry = this._findTocEntryById(elementId, this.links);
|
||||
const targetContainer: ToCEntry = this._findTocEntryById(targetId, this.links);
|
||||
const sourceContainer: ToCEntry = this._findTocEntryById(sourceId, this.links);
|
||||
|
||||
if (!(element && (targetContainer || ((element.type === ToCEntryType.Page) && (targetId === this.ROOT_ID))) && (sourceContainer || ((element.type === ToCEntryType.Page) && (sourceId === this.ROOT_ID))))) {
|
||||
// console.info('Could not find elements');
|
||||
this.dataNeedsRefresh.emit();
|
||||
//TODO: angular update //drake.cancel(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch (element.type) {
|
||||
case ToCEntryType.FieldSet: {
|
||||
if (targetContainer.type != this.tocEntryType.Section) {
|
||||
// const message = 'Fieldset can only be child of Subsections';
|
||||
const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.FIELDSET-MUST-HAVE-PARENT-SECTION');
|
||||
// console.error(message);
|
||||
this.notifyUser(message)
|
||||
this.dataNeedsRefresh.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
//check if target container has no sections
|
||||
if ((targetContainer.form.get('sections') as UntypedFormArray).length) {
|
||||
// const message = 'Cannot have inputs and sections on the same level';
|
||||
const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.INPUT-SECTION-SAME-LEVEL');
|
||||
this.notifyUser(message);
|
||||
// console.error(message);
|
||||
this.dataNeedsRefresh.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
const fieldsetForm = element.form;
|
||||
const targetFieldsets = targetContainer.form.get('fieldSets') as UntypedFormArray;
|
||||
const sourceFieldsets = sourceContainer.form.get('fieldSets') as UntypedFormArray;
|
||||
|
||||
if (!targetFieldsets) {
|
||||
console.info('Not target fieldsets container found');
|
||||
this.dataNeedsRefresh.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
let sourceOrdinal = -1;
|
||||
let idx = -1;
|
||||
sourceFieldsets.controls.forEach((elem, index) => {
|
||||
if (elem.get('id').value === elementId) {
|
||||
sourceOrdinal = elem.get('ordinal').value;
|
||||
idx = index
|
||||
}
|
||||
});
|
||||
|
||||
if (sourceOrdinal >= 0 && idx >= 0) {
|
||||
sourceFieldsets.removeAt(idx);
|
||||
|
||||
sourceFieldsets.controls.forEach(control => {
|
||||
const ordinal = control.get('ordinal');
|
||||
if ((ordinal.value >= sourceOrdinal) && sourceOrdinal > 0) {
|
||||
const updatedOrdinalVal = ordinal.value - 1;
|
||||
ordinal.setValue(updatedOrdinalVal);
|
||||
}
|
||||
});
|
||||
sourceFieldsets.controls.sort(this._compareOrdinals);
|
||||
}
|
||||
|
||||
let position: number = targetFieldsets.length;
|
||||
|
||||
if (!sibling || !sibling.id) {
|
||||
console.info('No sibling Id found');
|
||||
} else {
|
||||
const siblingId = (sibling.id as string).replace(this.DRAGULA_ITEM_ID_PREFIX, '');
|
||||
let siblingIndex = -1;
|
||||
targetFieldsets.controls.forEach((e, idx) => {
|
||||
if (e.get('id').value === siblingId) {
|
||||
siblingIndex = idx;
|
||||
position = e.get('ordinal').value;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (siblingIndex >= 0) { //sibling found
|
||||
|
||||
targetFieldsets.controls.filter(control => control.get('ordinal').value >= position).forEach(control => {
|
||||
const ordinal = control.get('ordinal');
|
||||
const updatedOrdinalVal = ordinal.value + 1;
|
||||
ordinal.setValue(updatedOrdinalVal);
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
fieldsetForm.get('ordinal').setValue(position);
|
||||
targetFieldsets.insert(position, fieldsetForm);
|
||||
targetFieldsets.controls.sort(this._compareOrdinals);
|
||||
this.dataNeedsRefresh.emit({ draggedItemId: elementId });
|
||||
|
||||
break;
|
||||
}
|
||||
case ToCEntryType.Section: {
|
||||
|
||||
if (targetContainer.type == ToCEntryType.Section) {
|
||||
if ((targetContainer.form.get('fieldSets') as UntypedFormArray).length) {
|
||||
// const message = 'Cannot have inputs and sections on the same level';
|
||||
const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.INPUT-SECTION-SAME-LEVEL');;
|
||||
this.notifyUser(message);
|
||||
// console.info(message);
|
||||
this.dataNeedsRefresh.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
const targetSections = targetContainer.form.get('sections') as UntypedFormArray;
|
||||
const elementSectionForm = element.form;
|
||||
const sourceSections = elementSectionForm.parent as UntypedFormArray;
|
||||
|
||||
if (!(targetSections && sourceSections && elementSectionForm)) {
|
||||
console.info('Could not load sections');
|
||||
this.dataNeedsRefresh.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
let idx = -1;
|
||||
sourceSections.controls.forEach((section, i) => {
|
||||
if (section.get('id').value === elementId) {
|
||||
idx = i;
|
||||
}
|
||||
});
|
||||
|
||||
if (!(idx >= 0)) {
|
||||
console.info('Could not find element in Parent container');
|
||||
this.dataNeedsRefresh.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
sourceSections.controls.filter(control => control.get('ordinal').value >= elementSectionForm.get('ordinal').value).forEach(control => {
|
||||
const ordinal = control.get('ordinal');
|
||||
const updatedOrdinalVal = ordinal.value ? ordinal.value - 1 : 0;
|
||||
ordinal.setValue(updatedOrdinalVal);
|
||||
});
|
||||
|
||||
|
||||
sourceSections.removeAt(idx);
|
||||
|
||||
let targetOrdinal = targetSections.length;
|
||||
|
||||
if (sibling && sibling.id) {
|
||||
const siblingId = sibling.id.replace(this.DRAGULA_ITEM_ID_PREFIX, '');
|
||||
|
||||
targetSections.controls.forEach((section, i) => {
|
||||
if (section.get('id').value === siblingId) {
|
||||
targetOrdinal = section.get('ordinal').value;
|
||||
}
|
||||
})
|
||||
|
||||
// if(targetOrdinal!=targetSections.length){//mporei na einai idio
|
||||
// section.get('ordinal').setValue(i+1);
|
||||
targetSections.controls.filter(control => control.get('ordinal').value >= targetOrdinal).forEach(control => {
|
||||
const ordinal = control.get('ordinal');
|
||||
const updatedOrdinalVal = ordinal.value + 1;
|
||||
ordinal.setValue(updatedOrdinalVal);
|
||||
});
|
||||
// }
|
||||
|
||||
} else {
|
||||
console.info('no siblings found');
|
||||
}
|
||||
elementSectionForm.get('ordinal').setValue(targetOrdinal);
|
||||
targetSections.insert(targetOrdinal, elementSectionForm);
|
||||
|
||||
} else if (targetContainer.type === ToCEntryType.Page) {
|
||||
// const pageId = targetContainer.form.get('id').value;
|
||||
|
||||
const rootform = targetContainer.form.root;
|
||||
const sectionForm = element.form;
|
||||
const parentSections = sectionForm.parent as UntypedFormArray;
|
||||
|
||||
let parentIndex = -1;
|
||||
parentSections.controls.forEach((section, i) => {
|
||||
if (section.get('id').value === elementId) {
|
||||
parentIndex = i
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
if (parentIndex < 0) {
|
||||
console.info('could not locate section in parents array');
|
||||
this.dataNeedsRefresh.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
//update parent sections ordinal
|
||||
parentSections.controls.filter(section => section.get('ordinal').value >= sectionForm.get('ordinal').value).forEach(section => {
|
||||
const ordinal = section.get('ordinal');
|
||||
const updatedOrdinalVal = ordinal.value ? ordinal.value - 1 : 0;
|
||||
ordinal.setValue(updatedOrdinalVal);
|
||||
})
|
||||
|
||||
parentSections.removeAt(parentIndex);
|
||||
|
||||
|
||||
|
||||
let position = 0;
|
||||
if (targetContainer.subEntries) {
|
||||
position = targetContainer.subEntries.length;
|
||||
}
|
||||
//populate sections
|
||||
const targetSectionsArray = rootform.get('sections') as UntypedFormArray;
|
||||
|
||||
|
||||
if (sibling && sibling.id) {
|
||||
const siblingId = sibling.id.replace(this.DRAGULA_ITEM_ID_PREFIX, '');
|
||||
let indx = -1;
|
||||
|
||||
targetContainer.subEntries.forEach((e, i) => {
|
||||
if (e.form.get('id').value === siblingId) {
|
||||
indx = i;
|
||||
position = e.form.get('ordinal').value;
|
||||
}
|
||||
});
|
||||
if (indx >= 0) {
|
||||
|
||||
// e.form.get('ordinal').setValue(i+1);
|
||||
targetContainer.subEntries.filter(e => e.form.get('ordinal').value >= position).forEach(e => {
|
||||
const ordinal = e.form.get('ordinal');
|
||||
const updatedOrdinalVal = ordinal.value + 1;
|
||||
ordinal.setValue(updatedOrdinalVal);
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
console.info('No sibling found');
|
||||
}
|
||||
|
||||
sectionForm.get('ordinal').setValue(position);
|
||||
sectionForm.get('page').setValue(targetContainer.id);
|
||||
targetSectionsArray.push(sectionForm);
|
||||
|
||||
} else {
|
||||
// const message = 'Drag not support to specific container';
|
||||
const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.DRAG-NOT-SUPPORTED');
|
||||
this.notifyUser(message);
|
||||
// console.info(message);
|
||||
this.dataNeedsRefresh.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
this.dataNeedsRefresh.emit({ draggedItemId: elementId });
|
||||
break;
|
||||
}
|
||||
case ToCEntryType.Page: {
|
||||
if (targetId != this.ROOT_ID) {
|
||||
// const message = 'A page element can only be at top level';
|
||||
const message = this.language.instant('DESCRIPTION-TEMPLATE-EDITOR.STEPS.FORM.TABLE-OF-CONTENTS.ERROR-MESSAGES.PAGE-ELEMENT-ONLY-TOP-LEVEL');
|
||||
this.notifyUser(message);
|
||||
// console.info(message);
|
||||
this.dataNeedsRefresh.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
const rootForm = element.form.root;
|
||||
if (!rootForm) {
|
||||
console.info('Could not find root!')
|
||||
this.dataNeedsRefresh.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const pages = rootForm.get('pages') as UntypedFormArray;
|
||||
const pageForm = element.form;
|
||||
|
||||
let index = -1;
|
||||
|
||||
pages.controls.forEach((page, i) => {
|
||||
if (page.get('id').value === elementId) {
|
||||
index = i;
|
||||
}
|
||||
});
|
||||
|
||||
if (index < 0) {
|
||||
console.info('Could not locate page on pages');
|
||||
this.dataNeedsRefresh.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//ordinality
|
||||
pages.controls.filter(page => page.get('ordinal').value >= pageForm.get('ordinal').value).forEach(page => {
|
||||
const ordinal = page.get('ordinal');
|
||||
const ordinalVal = ordinal.value ? ordinal.value - 1 : 0;
|
||||
ordinal.setValue(ordinalVal);
|
||||
});
|
||||
|
||||
pages.removeAt(index);
|
||||
|
||||
let targetPosition = pages.length;
|
||||
|
||||
if (sibling) {
|
||||
const siblingId = sibling.id.replace(this.DRAGULA_ITEM_ID_PREFIX, '');
|
||||
|
||||
pages.controls.forEach((page, i) => {
|
||||
if (page.get('id').value === siblingId) {
|
||||
targetPosition = page.get('ordinal').value;
|
||||
}
|
||||
});
|
||||
}
|
||||
pageForm.get('ordinal').setValue(targetPosition);
|
||||
|
||||
//update ordinality
|
||||
pages.controls.filter(page => page.get('ordinal').value >= targetPosition).forEach(page => {
|
||||
const ordinal = page.get('ordinal');
|
||||
const ordinalVal = ordinal.value + 1;
|
||||
ordinal.setValue(ordinalVal);
|
||||
});
|
||||
|
||||
|
||||
pages.insert(targetPosition, pageForm);
|
||||
this.dataNeedsRefresh.emit({ draggedItemId: elementId });
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
console.info('Could not support moving objects for specific type of element');
|
||||
this.dataNeedsRefresh.emit();
|
||||
return;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
drake.on('drag', (el, source) => {
|
||||
this._dragStartedAt = new Date().getTime();
|
||||
// console.log('drag fired');
|
||||
this.isDragging = true;
|
||||
this.draggingItemId = (el.id as string).replace(this.DRAGULA_ITEM_ID_PREFIX, '');
|
||||
|
||||
// setTimeout(() => {
|
||||
// if(this.isDragging){
|
||||
// this._scrollIntoDragginItem(this.draggingItemId);
|
||||
// }
|
||||
// }, this.VALID_DROP_TIME);
|
||||
});
|
||||
drake.on('over', (el, container, source) => {
|
||||
try {
|
||||
this.overcontainer = container.id;
|
||||
} catch (error) {
|
||||
this.overcontainer = null;
|
||||
}
|
||||
});
|
||||
drake.on('dragend', (el) => {
|
||||
this.isDragging = false;
|
||||
this.draggingItemId = null;
|
||||
this.overcontainer = null;
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
ngAfterViewInit(): void {
|
||||
|
||||
const top = document.querySelector('.top-scroller');
|
||||
const bottom = document.querySelector('.bottom-scroller');
|
||||
const tableDiv = document.querySelector('#tocentrytable');
|
||||
|
||||
try {
|
||||
top.addEventListener('mouseover', (e) => { this.scrollTableTop = true; }, {
|
||||
passive: true
|
||||
});
|
||||
bottom.addEventListener('mouseover', (e) => { this.scrollTableBottom = true; }, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
top.addEventListener('mouseout', (e) => { this.scrollTableTop = false }, {
|
||||
passive: true
|
||||
});
|
||||
bottom.addEventListener('mouseout', (e) => { this.scrollTableBottom = false; }, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
|
||||
this.$clock
|
||||
.pipe(
|
||||
takeUntil(this._destroyed),
|
||||
filter(() => this.scrollTableTop)
|
||||
)
|
||||
.subscribe(() => {
|
||||
try {
|
||||
tableDiv.scrollBy(0, -this.pxToScroll);
|
||||
} catch { }
|
||||
});
|
||||
this.$clock
|
||||
.pipe(
|
||||
takeUntil(this._destroyed),
|
||||
filter(() => this.scrollTableBottom)
|
||||
)
|
||||
.subscribe(() => {
|
||||
try {
|
||||
tableDiv.scrollBy(0, this.pxToScroll);
|
||||
} catch { }
|
||||
});
|
||||
} catch {
|
||||
console.log('could not find scrolling elements');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private _scrollIntoDragginItem(id: string) {
|
||||
|
||||
// const table = document.getElementById('tocentrytable');
|
||||
// if(table){
|
||||
// // const element = document.getElementById('TABLE_ENTRY'+id);
|
||||
// console.log('Table found!');
|
||||
// const element = document.getElementById('TABLE_ENTRY' + id);
|
||||
// const elementFromTable = table.closest('#TABLE_ENTRY'+ id);
|
||||
|
||||
|
||||
// if(elementFromTable){
|
||||
// console.log('found from table:', elementFromTable);
|
||||
// }
|
||||
// if(element){
|
||||
// console.log('Element found!');
|
||||
// // element.classList.add('text-danger');
|
||||
// // console.log(element);
|
||||
|
||||
// const tableRect = table.getBoundingClientRect();
|
||||
// const elementRect = element.getBoundingClientRect();
|
||||
|
||||
|
||||
// console.log('tablerect :',tableRect);
|
||||
// console.log('elementRect :',elementRect);
|
||||
|
||||
// const dY = elementRect.top - tableRect.top;
|
||||
// console.log('Distance from table is ', dY);
|
||||
// // table.scroll({top:dY,behavior:'smooth'});
|
||||
// console.log('found from document ', element);
|
||||
|
||||
// // element.scrollIntoView();
|
||||
// }
|
||||
// // element.scrollIntoView();
|
||||
// }
|
||||
}
|
||||
|
||||
private _findTocEntryById(id: string, tocentries: ToCEntry[]): ToCEntry {
|
||||
if (!tocentries) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let tocEntryFound = tocentries.find(entry => entry.id === id);
|
||||
|
||||
if (tocEntryFound) {
|
||||
return tocEntryFound;
|
||||
}
|
||||
|
||||
for (let entry of tocentries) {
|
||||
const result = this._findTocEntryById(id, entry.subEntries);
|
||||
if (result) {
|
||||
tocEntryFound = result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return tocEntryFound ? tocEntryFound : null;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
itemClicked(item: ToCEntry) {
|
||||
//leaf node
|
||||
this.itemClick.emit(item);
|
||||
}
|
||||
|
||||
// addNewEntry(tce: ToCEntry){
|
||||
// this.newEntry.emit(tce);
|
||||
// }
|
||||
deleteEntry(currentLink: ToCEntry) {
|
||||
this.removeEntry.emit(currentLink);
|
||||
}
|
||||
|
||||
createNewEntry(newEntry: NewEntryType) {
|
||||
this.createEntry.emit(newEntry);
|
||||
}
|
||||
onDataNeedsRefresh() {
|
||||
this.dataNeedsRefresh.emit();
|
||||
}
|
||||
|
||||
notifyUser(message: string) {
|
||||
this.snackbar.open(message, null, this._snackBarConfig);
|
||||
}
|
||||
|
||||
private _snackBarConfig: MatSnackBarConfig = {
|
||||
duration: 2000
|
||||
}
|
||||
|
||||
private _compareOrdinals(a, b) {
|
||||
|
||||
const aValue = a.get('ordinal').value as number;
|
||||
const bValue = b.get('ordinal').value as number;
|
||||
|
||||
// if(!aValue || !bValue) return 0;
|
||||
return aValue - bValue;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
<!-- <span style="cursor: pointer;" [ngClass]="{'active': itemSelected?.id == parentLink?.id}" (click)="itemClicked(parentLink)" *ngIf="!(parentLink.type == undefined)" >
|
||||
{{parentLink?.numbering}} {{parentLink?.label? parentLink?.label : 'DESCRIPTION-TEMPLATE-EDITOR.STEPS.GENERAL-INFO.UNTITLED' | translate}}
|
||||
<span class="mat-button" (click)="deleteEntry(parentLink)" *ngIf="itemSelected?.id == parentLink?.id"><mat-icon>delete</mat-icon></span>
|
||||
</span> -->
|
||||
|
||||
<div class="table-item row align-items-center" *ngIf="!(parentLink.type == undefined)">
|
||||
<div class="col link-info"
|
||||
>
|
||||
<!-- [ngStyle]="{'padding-top': (!((parentLink?.subEntriesType == tocEntryType.FieldSet) && !selectedItemInLinks) || itemSelected?.id == parentLink.id)? '0em': '.6em'}" -->
|
||||
|
||||
<!-- <span style="cursor: pointer;" [ngClass]="{'active': itemSelected?.id == parentLink?.id}" (click)="itemClicked(parentLink)" >
|
||||
{{parentLink?.numbering}} {{parentLink?.label? parentLink?.label : 'DESCRIPTION-TEMPLATE-EDITOR.STEPS.GENERAL-INFO.UNTITLED' | translate}}
|
||||
</span> -->
|
||||
|
||||
<!-- <span style="cursor: pointer;" [ngClass]="{'active': itemSelected?.id == parentLink?.id}" (click)="itemClicked(parentLink)"
|
||||
[matBadge]="parentLink.subEntries?.length"
|
||||
matBadgeOverlap="false"
|
||||
[matBadgeHidden]="!((parentLink?.subEntriesType == tocEntryType.FieldSet) && !selectedItemInLinks) || itemSelected?.id == parentLink.id"
|
||||
matBadgePosition="before"
|
||||
matBadgeColor="accent"
|
||||
matBadgeSize="small"
|
||||
|
||||
[ngStyle]="{'font-size' : (parentLink.type == tocEntryType.FieldSet? '.9rem':'1rem')}"
|
||||
> -->
|
||||
<span class="table-label-element"
|
||||
[ngClass]="{'table-label-element-active': itemSelected?.id == parentLink?.id, 'text-danger': colorError() ||( (parentLink?.subEntriesType === tocEntryType.FieldSet )&& !colorError() && !selectedItemInLinks && parentLink?.form.invalid && colorizeInvalid && (itemSelected?.id != parentLink?.id) && !_findTocEntryById(itemSelected?.id, parentLink?.subEntries))}"
|
||||
(click)="itemClicked(parentLink)"
|
||||
[ngStyle]="{'font-size' : (parentLink.type == tocEntryType.FieldSet? '.9rem':'1rem')}"
|
||||
[id]="'TABLE_ENTRY'+parentLink.id"
|
||||
>
|
||||
<!-- {{parentLink?.numbering}} {{parentLink?.label? parentLink?.label : 'DESCRIPTION-TEMPLATE-EDITOR.STEPS.GENERAL-INFO.UNTITLED' | translate}} -->
|
||||
<!-- {{parentLink?.numbering}} {{parentLink?.form.get('title').value? parentLink?.form.get('title').value : ('DESCRIPTION-TEMPLATE-EDITOR.STEPS.GENERAL-INFO.UNTITLED' | translate) + ' '+ ( (parentLink.type ===tocEntryType.Page? ('DESCRIPTION-TEMPLATE-EDITOR.STEPS.PAGE-INFO.PAGE' | translate) : (parentLink.type === tocEntryType.Section? ('DESCRIPTION-TEMPLATE-EDITOR.STEPS.SECTION-INFO.SECTION' | translate) : '') ) | lowercase )}} -->
|
||||
{{parentLink?.numbering}} {{parentLink?.form.get('title').value? parentLink?.form.get('title').value : 'DESCRIPTION-TEMPLATE-EDITOR.STEPS.GENERAL-INFO.UNTITLED' | translate}}
|
||||
<ng-container *ngIf="!parentLink.form.get('title').value" [ngSwitch]="parentLink.type">
|
||||
<ng-container *ngSwitchCase="tocEntryType.FieldSet">
|
||||
{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.GENERAL-INFO.QUESTION' | translate |lowercase}}
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="tocEntryType.Section">
|
||||
{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.SECTION-INFO.SECTION' | translate |lowercase}}
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="tocEntryType.Page">
|
||||
{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.PAGE-INFO.PAGE' | translate | lowercase}}
|
||||
</ng-container>
|
||||
|
||||
</ng-container>
|
||||
<!-- {{parentLink?.numbering}} {{parentLink?.form.get('title').value? parentLink?.form.get('title').value : parentLink.id}} -->
|
||||
</span>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="col-auto d-flex align-items-center" >
|
||||
|
||||
<ng-container *ngIf="!(!((parentLink?.subEntriesType == tocEntryType.FieldSet) && !selectedItemInLinks) || itemSelected?.id == parentLink.id ||isDragging)">
|
||||
<!-- <mat-icon class="text-danger" style="font-size: 1.4em;" *ngIf="!colorError() && parentLink?.form.invalid && colorizeInvalid && allFieldsAreTouched(parentLink?.form)">priority_high</mat-icon> -->
|
||||
<span class="badge-ball"
|
||||
>
|
||||
{{parentLink.subEntries?.length}}
|
||||
</span>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<span style="cursor: pointer;" (click)="deleteEntry(parentLink)"
|
||||
[hidden]="!(!viewOnly && (itemSelected?.id == parentLink?.id) && (parentLink?.type != tocEntryType.FieldSet))"
|
||||
>
|
||||
<mat-icon style="font-size: 1.4em;">delete</mat-icon>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- When item is not selected then show only the pages (first level) -->
|
||||
<!-- <ng-container *ngIf="tocEntryIsChildOf(itemSelected,parentLink) || (!itemSelected && parentLink?.subEntriesType == tocEntryType.Page)"> -->
|
||||
<!-- [ngClass]="{'border-left-active':itemSelected?.id == parentLink?.id, 'pl-1':itemSelected?.id == parentLink?.id, 'pb-4': isDragging && (parentLink?.type!= tocEntryType.FieldSet) && (parentLink?.id != draggingItemId) }" -->
|
||||
<div dragula="TABLEDRAG" class="ml-2"
|
||||
[ngClass]="{'border-left-active':itemSelected?.id == parentLink?.id, 'ml-1':itemSelected?.id == parentLink?.id, 'pb-4': isDragging && (parentLink?.type!= tocEntryType.FieldSet) && (parentLink?.id != draggingItemId) }"
|
||||
[hidden]="!((parentLink?.subEntriesType!= tocEntryType.FieldSet) || selectedItemInLinks || parentLink?.id === itemSelected?.id ||isDragging)"
|
||||
class="cdk-link-list"
|
||||
[id]="parentLink.id"
|
||||
[ngStyle]="{'border': overContainerId === parentLink?.id? '1px solid #129D99': '', 'min-height': ((!links?.length||(links.length ==1) ) && (parentLink?.type != tocEntryType.FieldSet) && (isDragging) && (draggingItemId != parentLink?.id)) ? '3em':'inherit'}"
|
||||
>
|
||||
<ng-container *ngIf="draggingItemId != parentLink?.id">
|
||||
|
||||
<div *ngFor="let link of links; last as isLast"
|
||||
[ngClass]="{'mb-3': link.type === tocEntryType.Page}"
|
||||
[id]="DRAGULA_ITEM_ID_PREFIX + link.id"
|
||||
>
|
||||
<div class="docs-link mt-0">
|
||||
<!-- <div class="link-name"> -->
|
||||
|
||||
<!-- <div class="table-item row">
|
||||
<div class="col link-info">
|
||||
<span style="cursor: pointer;" [ngClass]="{'active': itemSelected?.id == link.id}" (click)="itemClicked(link)" >
|
||||
{{link.numbering}} {{link.label? link.label : 'DESCRIPTION-TEMPLATE-EDITOR.STEPS.GENERAL-INFO.UNTITLED' | translate}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="table-item-actions col-auto" *ngIf="!viewOnly">
|
||||
<button class="mat-button" (click)="deleteEntry(link)"><mat-icon>delete</mat-icon></button>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
|
||||
<!-- For dev purposes -->
|
||||
<!-- <ng-container [ngSwitch]="link.type">
|
||||
<div *ngSwitchCase="tocEntryType.FieldSet">
|
||||
<span style="background-color: yellow;"> Fieldset</span>
|
||||
</div>
|
||||
<div *ngSwitchCase="tocEntryType.Page">
|
||||
<span style="background-color: lightblue;"> Page</span>
|
||||
</div>
|
||||
<div *ngSwitchCase="tocEntryType.Section">
|
||||
<span style="background-color: lightgreen;"> Section</span>
|
||||
</div>
|
||||
</ng-container> -->
|
||||
<!-- </div> -->
|
||||
<!-- <button cdkDragHandle>drab</button> -->
|
||||
<div [ngClass]="{'ml-3': link.type != tocEntryType.Page }">
|
||||
<app-description-template-table-of-contents-internal-section
|
||||
[links]="link.subEntries"
|
||||
(itemClick)="itemClicked($event)"
|
||||
(removeEntry)="deleteEntry($event)"
|
||||
[parentLink]="link"
|
||||
[itemSelected] = "itemSelected"
|
||||
(createFooEntry)="createNewEntry($event)"
|
||||
[viewOnly]="viewOnly"
|
||||
(dataNeedsRefresh)="onDataNeedsRefresh()"
|
||||
[DRAGULA_ITEM_ID_PREFIX]="DRAGULA_ITEM_ID_PREFIX"
|
||||
[overContainerId]="overContainerId"
|
||||
[isDragging]="isDragging"
|
||||
[draggingItemId]="draggingItemId"
|
||||
[parentRootId]="parentRootId"
|
||||
[colorizeInvalid]="colorizeInvalid">
|
||||
</app-description-template-table-of-contents-internal-section>
|
||||
|
||||
|
||||
|
||||
<ng-container *ngIf="!isDragging">
|
||||
|
||||
<!-- <div *ngIf="links && !viewOnly && !(parentLink?.subEntriesType == tocEntryType.Page) " > -->
|
||||
<ng-container *ngIf="selectedItemInLinks && (link.type != tocEntryType.Page) && isLast && (!viewOnly)">
|
||||
<button class="mat-button add-new-entry" style="padding-left: 0px;" (click)="createNewEntry({childType:link.type,parent:parentLink})">
|
||||
<!-- <mat-icon>add</mat-icon> -->
|
||||
<ng-container [ngSwitch]="link.type">
|
||||
<ng-container *ngSwitchCase="tocEntryType.Section">
|
||||
<div class="d-flex" style="align-items: center;" >
|
||||
<mat-icon color="accent" style="font-size: 1.6em;margin-left: -0.3em;">add</mat-icon>
|
||||
<!-- Create new subsection -->
|
||||
{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.PAGE-INFO.ACTIONS.CREATE-NEW-SUBSECTION' |translate}}
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Subsection + -->
|
||||
</ng-container>
|
||||
<!-- <ng-container *ngSwitchCase="tocEntryType.Page">
|
||||
Section
|
||||
</ng-container> -->
|
||||
<ng-container *ngSwitchCase="tocEntryType.FieldSet">
|
||||
<img src="/assets/images/editor/icons/add_input_set.svg" alt="" style="margin-left: 0.1em;" class="add-input-icon">
|
||||
{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.TOOLKIT.NEW-INPUT-SET' | translate}}
|
||||
</ng-container>
|
||||
|
||||
</ng-container>
|
||||
</button>
|
||||
</ng-container>
|
||||
<!-- </div> -->
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div> <!-- END OF LOOP-->
|
||||
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<ng-container *ngIf="!isDragging">
|
||||
|
||||
|
||||
|
||||
<!-- BUILD SUBENTRIES IF THEY DONT EXIST -- CURRENT ITEM DOES HAVE CHILDREN -->
|
||||
<div *ngIf="(!links && parentLink.type!= tocEntryType.FieldSet) && !viewOnly &&parentLink?.id == itemSelected?.id" class="docs-link mt-0">
|
||||
<div class="ml-3">
|
||||
|
||||
<!-- Give option to generate fieldset (only if parent is section) -->
|
||||
<button *ngIf="parentLink.type == tocEntryType.Section" class="mat-button" style="padding-left: 0px;" (click)="createNewEntry({childType:tocEntryType.FieldSet,parent:parentLink})">
|
||||
<img src="/assets/images/editor/icons/add_input_set.svg" alt="" style="margin-left: -0.2em;" class="add-input-icon">
|
||||
{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.TOOLKIT.NEW-INPUT-SET' | translate}}
|
||||
</button>
|
||||
|
||||
<!-- Give option to generate section -->
|
||||
<button class="mat-button" style="padding-left: 0px; display: block;" (click)="createNewEntry({childType:tocEntryType.Section,parent:parentLink})">
|
||||
<!-- <mat-icon>add</mat-icon> -->
|
||||
<!-- Subsection + -->
|
||||
|
||||
<div class="d-flex" style="align-items: center;" >
|
||||
<mat-icon color="accent" style="font-size: 1.6em;margin-left: -0.3em;">add</mat-icon>
|
||||
<!-- Create new subsection -->
|
||||
{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.PAGE-INFO.ACTIONS.CREATE-NEW-SUBSECTION' |translate}}
|
||||
</div>
|
||||
|
||||
</button>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- BUILD TYPE OF SAME LEVEL AS LINK OF LINKS -->
|
||||
<!-- <div *ngIf="links && !viewOnly && !(parentLink?.subEntriesType == tocEntryType.Page) " >
|
||||
<ng-container >
|
||||
<button class="mat-button" style="padding-left: 0px;" (click)="createNewEntry({childType:parentLink.subEntriesType,parent:parentLink})">
|
||||
<mat-icon>add</mat-icon>
|
||||
<ng-container [ngSwitch]="parentLink?.subEntriesType">
|
||||
<ng-container *ngSwitchCase="tocEntryType.Section">
|
||||
Subsection
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="tocEntryType.Page">
|
||||
Section
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="tocEntryType.FieldSet">
|
||||
Fieldset
|
||||
</ng-container>
|
||||
|
||||
</ng-container>
|
||||
</button>
|
||||
</ng-container>
|
||||
</div> -->
|
||||
<!-- </ng-container> -->
|
||||
|
||||
<!-- Only for the page -->
|
||||
<!-- style="margin-left: -0.5em;" -->
|
||||
<div *ngIf="parentLink?.subEntriesType == tocEntryType.Page && !viewOnly" >
|
||||
<button class="mat-button mt-2" (click)="createNewEntry({childType:parentLink.subEntriesType,parent:parentLink})" style="padding-left:0px">
|
||||
<!-- <mat-icon>add</mat-icon> -->
|
||||
<div class="d-flex" style="align-items: center;" >
|
||||
<mat-icon color="accent" style="font-size: 1.6em;margin-left: -0.3em;">add</mat-icon>
|
||||
<ng-container *ngIf="!links?.length else createsection">
|
||||
{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.PAGE-INFO.ACTIONS.CREATE-FIRST-SECTION'| translate}}
|
||||
<!-- Create the first section -->
|
||||
</ng-container>
|
||||
<ng-template #createsection>
|
||||
{{'DESCRIPTION-TEMPLATE-EDITOR.STEPS.PAGE-INFO.ACTIONS.CREATE-NEW-SECTION'| translate}}
|
||||
<!-- Create new section -->
|
||||
</ng-template>
|
||||
</div>
|
||||
</button>
|
||||
<!-- <button (click)="showDroplists()">show droplist</button>
|
||||
<button (click)="showStructs()">structs</button> -->
|
||||
</div>
|
||||
|
||||
</ng-container>
|
|
@ -0,0 +1,116 @@
|
|||
// .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;
|
||||
// cursor: pointer;;
|
||||
// // 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;
|
||||
// }
|
||||
|
||||
// .table-item-actions{
|
||||
// // display: none;
|
||||
// display: inline-block;
|
||||
// visibility: hidden;
|
||||
// }
|
||||
|
||||
// .table-item:hover {
|
||||
// .table-item-actions{
|
||||
// // display: inline-block;
|
||||
// visibility: visible;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .table-item col{
|
||||
// text-overflow: ellipsis;
|
||||
// overflow: hidden;
|
||||
// white-space: nowrap;
|
||||
// }
|
||||
|
||||
.link-info{
|
||||
// display: inline-block; cursor: pointer;
|
||||
// padding-top: .6em;
|
||||
// padding-left: .6em;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
||||
.border-left-active{
|
||||
border-left: 1px solid #000;
|
||||
}
|
||||
|
||||
|
||||
.side-bolder{
|
||||
border-left: 1px solid red;
|
||||
}
|
||||
|
||||
|
||||
.cdk-link-list {
|
||||
|
||||
display: block;
|
||||
// background: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
|
||||
$blue-color : var(--primary-color);
|
||||
$blue-color-light: #5cf7f2;
|
||||
$yellow: var(--secondary-color);
|
||||
.badge-ball{
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
background-color: #FFF;
|
||||
font-size: small;
|
||||
font-weight: bold;
|
||||
min-width: 2em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.table-label-element{
|
||||
cursor: pointer;
|
||||
// font-weight: normal;
|
||||
|
||||
// transition-property: font-weight;
|
||||
// transition-duration: 160ms;
|
||||
// transition-delay: 50ms;
|
||||
// transition-timing-function: ease-in-out;
|
||||
}
|
||||
|
||||
|
||||
.table-label-element-active{
|
||||
font-weight: bold;
|
||||
// color: red;
|
||||
}
|
||||
.add-input-icon{
|
||||
width: 20px;
|
||||
}
|
|
@ -0,0 +1,280 @@
|
|||
import { DOCUMENT } from '@angular/common';
|
||||
import { Component, EventEmitter, Inject, Input, OnInit, Output, SimpleChanges } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormArray, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { BaseComponent } from '@common/base/base.component';
|
||||
import { NewEntryType, ToCEntry, ToCEntryType } from '../description-template-table-of-contents-entry';
|
||||
|
||||
@Component({
|
||||
selector: 'app-description-template-table-of-contents-internal-section',
|
||||
styleUrls: ['./description-template-table-of-contents-internal-section.scss'],
|
||||
templateUrl: './description-template-table-of-contents-internal-section.html'
|
||||
})
|
||||
export class DescriptionTemplateTableOfContentsInternalSection extends BaseComponent implements OnInit {
|
||||
|
||||
@Input() links: ToCEntry[];
|
||||
@Output() itemClick = new EventEmitter<ToCEntry>();
|
||||
@Output() removeEntry = new EventEmitter<ToCEntry>();
|
||||
|
||||
@Output() createFooEntry = new EventEmitter<NewEntryType>();
|
||||
|
||||
@Output() dataNeedsRefresh = new EventEmitter<void>();
|
||||
|
||||
|
||||
|
||||
@Input() parentLink: ToCEntry;
|
||||
@Input() itemSelected: ToCEntry;
|
||||
@Input() DRAGULA_ITEM_ID_PREFIX;
|
||||
@Input() overContainerId: string;
|
||||
@Input() isDragging;
|
||||
@Input() draggingItemId: string;
|
||||
@Input() parentRootId: string;
|
||||
|
||||
@Input() colorizeInvalid: boolean = false;
|
||||
|
||||
@Input() viewOnly: boolean;
|
||||
// @Input() dropListGroup: Set<string> = new Set<string>();
|
||||
// @Input() dropListGroup: string[];
|
||||
|
||||
// @Input() dragHoveringOver: boolean = false;
|
||||
// @Input() depth: number = 0;
|
||||
|
||||
// @Input() dropListStruct: { id: string, depth: number}[] = [];
|
||||
|
||||
constructor(
|
||||
@Inject(DOCUMENT) private _document: Document) {
|
||||
super();
|
||||
}
|
||||
|
||||
tocEntryType = ToCEntryType;
|
||||
|
||||
|
||||
// compareFn(a, b){
|
||||
// if(a.depth> b.depth) return -1;
|
||||
// if(a.depth< b.depth) return 1;
|
||||
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
// hoveroverEnter(){
|
||||
// // console.log('user hovering drag over', this.parentLink.id, this.parentLink.label);
|
||||
// this.dragHoveringOver = true;
|
||||
// }
|
||||
// hoveroverLeft(){
|
||||
// this.dragHoveringOver = false;
|
||||
// }
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
|
||||
}
|
||||
|
||||
// get grouListIds(){
|
||||
// return Array.from(this.dropListGroup);
|
||||
// }
|
||||
itemClicked(item: ToCEntry) {
|
||||
//leaf node
|
||||
this.itemClick.emit(item);
|
||||
}
|
||||
|
||||
deleteEntry(currentLink: ToCEntry) {
|
||||
this.removeEntry.emit(currentLink);
|
||||
}
|
||||
|
||||
createNewEntry(foo: NewEntryType) {
|
||||
this.createFooEntry.emit(foo);
|
||||
}
|
||||
|
||||
// tocEntryIsChildOf(testingChild: ToCEntry,parent: ToCEntry): boolean{
|
||||
|
||||
// if(!testingChild || !parent) return false;
|
||||
|
||||
// if(testingChild.id == parent.id){return true;}
|
||||
|
||||
// if(parent.subEntries){
|
||||
// let childFound:boolean = false;
|
||||
|
||||
// parent.subEntries.forEach(subEntry=>{
|
||||
// if(this.tocEntryIsChildOf(testingChild, subEntry)){
|
||||
// childFound = true;
|
||||
// return true;
|
||||
// }
|
||||
// })
|
||||
|
||||
// return childFound;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
get selectedItemInLinks() {
|
||||
if (!this.links || !this.itemSelected) return false;
|
||||
|
||||
const link = this.links.find(l => l.id === this.itemSelected.id);
|
||||
|
||||
if (link) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// appendAndGetDroplists(dropList: CdkDropList){
|
||||
// this.dropListGroup.push(dropList);
|
||||
// return this.dropListGroup;
|
||||
// }
|
||||
|
||||
// drop(event: CdkDragDrop<string[]>) {
|
||||
// // if(!this.links || !this.links.length) return;
|
||||
|
||||
// if(event.container === event.previousContainer){
|
||||
// moveItemInArray(this.links, event.previousIndex, event.currentIndex);
|
||||
|
||||
// let arrayToUpdate: FormArray = this.links[0].form.parent as FormArray;
|
||||
// // if(this.parentLink && this.parentLink.form){
|
||||
// // switch(this.parentLink.subEntriesType){
|
||||
// // case this.tocEntryType.Field:
|
||||
// // arrayToUpdate = (this.parentLink.form.get('fields') as FormArray);
|
||||
// // break;
|
||||
// // case this.tocEntryType.FieldSet:
|
||||
// // arrayToUpdate = (this.parentLink.form.get('fieldSets') as FormArray);
|
||||
// // break;
|
||||
// // case this.tocEntryType.Section:
|
||||
// // arrayToUpdate = (this.parentLink.form.get('sections') as FormArray);
|
||||
// // break
|
||||
// // }
|
||||
|
||||
// // }
|
||||
// if(arrayToUpdate.controls){
|
||||
// moveItemInArray(arrayToUpdate.controls, event.previousIndex, event.currentIndex);
|
||||
// //update ordinality
|
||||
// arrayToUpdate.controls.forEach((element,idx ) => {
|
||||
// element.get('ordinal').setValue(idx);
|
||||
// element.updateValueAndValidity();
|
||||
// });
|
||||
// }
|
||||
|
||||
// this.dataNeedsRefresh.emit();
|
||||
// }else{
|
||||
// console.log('not same container');
|
||||
// }
|
||||
|
||||
// console.log(event.container.id);
|
||||
|
||||
// }
|
||||
|
||||
onDataNeedsRefresh() {
|
||||
this.dataNeedsRefresh.emit();
|
||||
}
|
||||
|
||||
|
||||
// get hoveringOverParent(){
|
||||
// if(!this.overContainerId) return false;
|
||||
// const child = this._findTocEntryById(this.overContainerId, this.parentLink.subEntries);
|
||||
// if(!child) return false;
|
||||
// return true;
|
||||
// }
|
||||
|
||||
|
||||
public _findTocEntryById(id: string, tocentries: ToCEntry[]): ToCEntry {
|
||||
if (!tocentries) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let tocEntryFound = tocentries.find(entry => entry.id === id);
|
||||
|
||||
if (tocEntryFound) {
|
||||
return tocEntryFound;
|
||||
}
|
||||
|
||||
for (let entry of tocentries) {
|
||||
const result = this._findTocEntryById(id, entry.subEntries);
|
||||
if (result) {
|
||||
tocEntryFound = result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return tocEntryFound ? tocEntryFound : null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
colorError(): boolean {
|
||||
|
||||
if (!this.colorizeInvalid) return false;
|
||||
|
||||
const form = this.parentLink.form;
|
||||
if ((!form || form.valid || !form.touched) && this.parentLink.type !== this.tocEntryType.Page) return false;
|
||||
|
||||
const allFieldsAreTouched = this.allFieldsAreTouched(form);
|
||||
|
||||
//fieldset may have errros that are inside its controls and not in the fieldsetFormGroup
|
||||
if (this.parentLink.type === this.tocEntryType.FieldSet && allFieldsAreTouched) return true;
|
||||
|
||||
if (form.errors && allFieldsAreTouched) return true;
|
||||
|
||||
//check if page has sections
|
||||
if (this.parentLink.type === this.tocEntryType.Page && allFieldsAreTouched) {
|
||||
const rootForm = form.root;
|
||||
if (rootForm) {
|
||||
const sections = rootForm.get('sections') as UntypedFormArray;
|
||||
if (!sections.controls.find(section => section.get('page').value === this.parentLink.id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//checking first child form controls if have errors
|
||||
let hasErrors = false;
|
||||
if (allFieldsAreTouched) {
|
||||
if (form instanceof UntypedFormGroup) {
|
||||
const formGroup = form as UntypedFormGroup;
|
||||
|
||||
const controls = Object.keys(formGroup.controls);
|
||||
|
||||
controls.forEach(control => {
|
||||
if (formGroup.get(control).errors) {
|
||||
hasErrors = true;
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return hasErrors;
|
||||
}
|
||||
|
||||
|
||||
allFieldsAreTouched(aControl: AbstractControl) {//auto na testaroume
|
||||
|
||||
if (!aControl || aControl.untouched) return false;
|
||||
|
||||
if (aControl instanceof UntypedFormControl) {
|
||||
return aControl.touched;
|
||||
} else if (aControl instanceof UntypedFormGroup) {
|
||||
const controlKeys = Object.keys((aControl as UntypedFormGroup).controls);
|
||||
let areAllTouched = true;
|
||||
controlKeys.forEach(key => {
|
||||
if (!this.allFieldsAreTouched(aControl.get(key))) {
|
||||
areAllTouched = false;
|
||||
}
|
||||
})
|
||||
// const areAllTouched = controlKeys.reduce((acc, key)=>acc && this._allFieldsAreTouched(aControl.get(key)), true);
|
||||
return areAllTouched;
|
||||
|
||||
} else if (aControl instanceof UntypedFormArray) {
|
||||
const controls = (aControl as UntypedFormArray).controls;
|
||||
// const areAllTouched = controls.reduce((acc, control)=>acc && this._allFieldsAreTouched(control), true);
|
||||
let areAllTouched = true;
|
||||
// controls.reduce((acc, control)=>acc && this._allFieldsAreTouched(control), true);
|
||||
controls.forEach(control => {
|
||||
if (!this.allFieldsAreTouched(control)) {
|
||||
areAllTouched = false;
|
||||
}
|
||||
});
|
||||
return areAllTouched;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ import * as FileSaver from 'file-saver';
|
|||
import { Observable } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { nameof } from 'ts-simple-nameof';
|
||||
import { ImportDescriptionTemplateDialogComponent } from './import-dmp-blueprint/import-description-template.dialog.component';
|
||||
import { ImportDescriptionTemplateDialogComponent } from './import-description-template/import-description-template.dialog.component';
|
||||
import { DescriptionTemplateService } from '@app/core/services/description-template/description-template.service';
|
||||
import { DescriptionTemplateStatus } from '@app/core/common/enum/description-template-status';
|
||||
import { DescriptionTemplateLookup } from '@app/core/query/description-template.lookup';
|
||||
|
|
Loading…
Reference in New Issue