src/app/core/basic-datatypes/entity/entity-import-config/entity-import-config.component.ts

Description

Inline import configuration component for entity reference fields. Lets users select which property of the referenced entity to match against import values, and optionally configure a value transformation for that property.

Example

Metadata

Relationships

Used by

No results matching.

Depends on

Index

Properties
Methods
Inputs

Inputs

additionalSettings
Type : ImportAdditionalSettings
col
Type : ColumnMapping
entityType
Type : EntityConstructor
onColumnMappingChange
Type : (col: ColumnMapping) => void
otherColumnMappings
Type : ColumnMapping[]
Default value : []
rawData
Type : any[]
Default value : []

Methods

onRefFieldChange
onRefFieldChange(newRefField: string)
Parameters :
Name Type Optional
newRefField string No
Returns : void

Properties

availableProperties
Type : unknown
Default value : computed(() => { const entity = this.referencedEntity(); if (!entity) return []; return [...entity.schema.entries()] .filter( ([prop, schema]) => (!!schema.label && !schema.isInternalField) || prop === "_id", ) .map(([prop, schema]) => ({ label: schema.label ?? prop, property: prop, })); })
hasMultiMapping
Type : unknown
Default value : computed(() => { const col = this.col(); const otherColumnMappings = this.otherColumnMappings(); return ( col?.propertyName !== undefined && otherColumnMappings?.some( (m) => m.propertyName === col.propertyName && m.column !== col.column, ) ); })
referencedEntity
Type : unknown
Default value : computed<EntityConstructor | null>(() => { const col = this.col(); const entityType = this.entityType(); if (!col?.propertyName || !entityType) return null; const fieldSchema = entityType.schema.get(col.propertyName); const entityName = fieldSchema?.additional; if (!entityName) return null; return this.entityRegistry.get(entityName) ?? null; })
selectedRefField
Type : unknown
Default value : computed(() => { const col = this.col(); const current = normalizeEntityAdditional(col?.additional); return current?.refField ?? ""; })
showInheritanceHint
Type : unknown
Default value : computed(() => { const col = this.col(); const entityType = this.entityType(); if (!col?.propertyName || !entityType) return false; return isInheritanceSourceReferenceField(entityType, col.propertyName); })
subFieldInlineConfig
Type : unknown
Default value : computed(() => { const refField = this.selectedRefField(); const refEntity = this.referencedEntity(); if (!refField || !refEntity) return null; const refFieldSchema = refEntity.schema.get(refField); if (!refFieldSchema) return null; const refDatatype = this.schemaService.getDatatypeOrDefault( refFieldSchema.dataType, ); if (!refDatatype?.importConfigComponent) return null; const col = this.col(); const additional = col?.additional as EntityAdditional; // Synthetic column mapping for the sub-field's inline component const syntheticCol: ColumnMapping = { column: col.column, propertyName: refField, additional: additional?.valueMapping, }; return { component: refDatatype.importConfigComponent, config: { col: syntheticCol, rawData: this.rawData(), entityType: refEntity, otherColumnMappings: [], additionalSettings: this.additionalSettings(), onColumnMappingChange: (updatedCol: ColumnMapping) => { const current = normalizeEntityAdditional(col.additional) ?? { refField: refField, }; const updatedParentCol: ColumnMapping = { ...col, additional: { ...current, refField: refField, valueMapping: updatedCol.additional, } as EntityAdditional, }; this.onColumnMappingChange()?.(updatedParentCol); }, }, }; })

Config for the sub-field's inline component (for value transformation config)

import {
  ChangeDetectionStrategy,
  Component,
  computed,
  inject,
  input,
} from "@angular/core";
import { ColumnMapping } from "../../../import/column-mapping";
import { EntityConstructor } from "../../../entity/model/entity";
import { ImportAdditionalSettings } from "../../../import/import-additional-settings";
import { EntityRegistry } from "../../../entity/database-entity.decorator";
import { MatSelectModule } from "@angular/material/select";
import { MatFormFieldModule } from "@angular/material/form-field";
import { FormsModule } from "@angular/forms";
import { FaIconComponent } from "@fortawesome/angular-fontawesome";
import { MatTooltip } from "@angular/material/tooltip";
import { HintBoxComponent } from "../../../common-components/hint-box/hint-box.component";
import { DynamicComponentDirective } from "../../../config/dynamic-components/dynamic-component.directive";
import { DynamicComponent } from "../../../config/dynamic-components/dynamic-component.decorator";
import {
  EntityAdditional,
  normalizeEntityAdditional,
} from "../entity.datatype";
import { isInheritanceSourceReferenceField } from "../../../import/import-inheritance-warning.util";
import { EntitySchemaService } from "../../../entity/schema/entity-schema.service";

/**
 * Inline import configuration component for entity reference fields.
 * Lets users select which property of the referenced entity to match against import values,
 * and optionally configure a value transformation for that property.
 */
@DynamicComponent("EntityImportConfig")
@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: "app-entity-import-config",
  templateUrl: "./entity-import-config.component.html",
  imports: [
    MatSelectModule,
    MatFormFieldModule,
    FormsModule,
    FaIconComponent,
    MatTooltip,
    HintBoxComponent,
    DynamicComponentDirective,
  ],
})
export class EntityImportConfigComponent {
  private readonly entityRegistry = inject(EntityRegistry);
  private readonly schemaService = inject(EntitySchemaService);

  col = input<ColumnMapping>();
  rawData = input<any[]>([]);
  entityType = input<EntityConstructor>();
  otherColumnMappings = input<ColumnMapping[]>([]);
  additionalSettings = input<ImportAdditionalSettings>();
  onColumnMappingChange = input<(col: ColumnMapping) => void>();

  selectedRefField = computed(() => {
    const col = this.col();
    const current = normalizeEntityAdditional(col?.additional);
    return current?.refField ?? "";
  });

  referencedEntity = computed<EntityConstructor | null>(() => {
    const col = this.col();
    const entityType = this.entityType();
    if (!col?.propertyName || !entityType) return null;

    const fieldSchema = entityType.schema.get(col.propertyName);
    const entityName = fieldSchema?.additional;
    if (!entityName) return null;

    return this.entityRegistry.get(entityName) ?? null;
  });

  availableProperties = computed(() => {
    const entity = this.referencedEntity();
    if (!entity) return [];
    return [...entity.schema.entries()]
      .filter(
        ([prop, schema]) =>
          (!!schema.label && !schema.isInternalField) || prop === "_id",
      )
      .map(([prop, schema]) => ({
        label: schema.label ?? prop,
        property: prop,
      }));
  });

  showInheritanceHint = computed(() => {
    const col = this.col();
    const entityType = this.entityType();
    if (!col?.propertyName || !entityType) return false;
    return isInheritanceSourceReferenceField(entityType, col.propertyName);
  });

  hasMultiMapping = computed(() => {
    const col = this.col();
    const otherColumnMappings = this.otherColumnMappings();
    return (
      col?.propertyName !== undefined &&
      otherColumnMappings?.some(
        (m) => m.propertyName === col.propertyName && m.column !== col.column,
      )
    );
  });

  /** Config for the sub-field's inline component (for value transformation config) */
  subFieldInlineConfig = computed(() => {
    const refField = this.selectedRefField();
    const refEntity = this.referencedEntity();
    if (!refField || !refEntity) return null;

    const refFieldSchema = refEntity.schema.get(refField);
    if (!refFieldSchema) return null;

    const refDatatype = this.schemaService.getDatatypeOrDefault(
      refFieldSchema.dataType,
    );
    if (!refDatatype?.importConfigComponent) return null;

    const col = this.col();
    const additional = col?.additional as EntityAdditional;
    // Synthetic column mapping for the sub-field's inline component
    const syntheticCol: ColumnMapping = {
      column: col.column,
      propertyName: refField,
      additional: additional?.valueMapping,
    };

    return {
      component: refDatatype.importConfigComponent,
      config: {
        col: syntheticCol,
        rawData: this.rawData(),
        entityType: refEntity,
        otherColumnMappings: [],
        additionalSettings: this.additionalSettings(),
        onColumnMappingChange: (updatedCol: ColumnMapping) => {
          const current = normalizeEntityAdditional(col.additional) ?? {
            refField: refField,
          };
          const updatedParentCol: ColumnMapping = {
            ...col,
            additional: {
              ...current,
              refField: refField,
              valueMapping: updatedCol.additional,
            } as EntityAdditional,
          };
          this.onColumnMappingChange()?.(updatedParentCol);
        },
      },
    };
  });

  onRefFieldChange(newRefField: string) {
    const col = this.col();
    // Clear valueMapping when ref field changes
    this.onColumnMappingChange()?.({
      ...col,
      additional: { refField: newRefField } as EntityAdditional,
    });
  }
}
<div class="flex-row flex-wrap align-center gap-small">
  @if (showInheritanceHint()) {
    <app-hint-box type="warning" class="margin-bottom-regular">
      <strong i18n>⚠️ Manual update required</strong>
      <div i18n>
        Selected values will be imported as is. Inherited values need to be
        updated manually.
      </div>
    </app-hint-box>
  }

  <div class="flex-row gap-regular align-center">
    <mat-form-field class="margin-left-small">
      <mat-label i18n="import - entity - match by property label">
        Match by {{ referencedEntity()?.label }} property
      </mat-label>
      <mat-select
        [ngModel]="selectedRefField()"
        (ngModelChange)="onRefFieldChange($event)"
      >
        @for (prop of availableProperties(); track prop.property) {
          <mat-option [value]="prop.property">{{ prop.label }}</mat-option>
        }
      </mat-select>
    </mat-form-field>

    @if (hasMultiMapping()) {
      <fa-icon
        icon="object-group"
        matTooltip="This field is mapped from multiple imported columns."
        i18n-matTooltip
      ></fa-icon>
    }
  </div>

  @if (subFieldInlineConfig()) {
    <ng-container [appDynamicComponent]="subFieldInlineConfig()" />
  }
</div>
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""