import { EditEntityComponent } from "#src/app/core/basic-datatypes/entity/edit-entity/edit-entity.component";
import {
Component,
inject,
ChangeDetectionStrategy,
input,
model,
computed,
effect,
DestroyRef,
} from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import {
FormControl,
FormGroup,
ReactiveFormsModule,
Validators,
} from "@angular/forms";
import { MatButtonModule } from "@angular/material/button";
import { MatExpansionModule } from "@angular/material/expansion";
import { MatFormFieldModule } from "@angular/material/form-field";
import { MatListModule } from "@angular/material/list";
import { MatTooltipModule } from "@angular/material/tooltip";
import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";
import { EntityBlockComponent } from "../../../basic-datatypes/entity/entity-block/entity-block.component";
import { BasicAutocompleteComponent } from "../../../common-components/basic-autocomplete/basic-autocomplete.component";
import { EntityTypeLabelPipe } from "../../../common-components/entity-type-label/entity-type-label.pipe";
import { HelpButtonComponent } from "../../../common-components/help-button/help-button.component";
import { AdditionalImportAction } from "../additional-import-action";
import { ImportAdditionalService } from "../import-additional.service";
import { EntityAbility } from "../../../permissions/ability/entity-ability";
import { asArray } from "../../../../utils/asArray";
/**
* Import sub-step: Let user select additional import actions like adding entities to a group entity.
*/
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "app-import-additional-actions",
templateUrl: "./import-additional-actions.component.html",
styleUrls: ["./import-additional-actions.component.scss"],
imports: [
MatListModule,
FontAwesomeModule,
MatTooltipModule,
EntityTypeLabelPipe,
EntityBlockComponent,
ReactiveFormsModule,
MatFormFieldModule,
BasicAutocompleteComponent,
MatButtonModule,
EditEntityComponent,
HelpButtonComponent,
MatExpansionModule,
],
providers: [EntityTypeLabelPipe],
})
export class ImportAdditionalActionsComponent {
private importAdditionalService = inject(ImportAdditionalService);
private readonly ability = inject(EntityAbility);
entityType = input<string>();
importActions = model<AdditionalImportAction[]>([]);
availableImportActions = computed(() =>
this.importAdditionalService
.getActionsLinkingFor(this.entityType())
// an action links imported records into a related entity, which requires
// permission to update that related type (targetType may allow several types)
.filter(
(action) =>
!this.ability.initialized ||
asArray(action.targetType).some((type) =>
this.ability.can("update", type),
),
)
.sort(sortExportOnlyLast),
);
// TODO: may need more distinction --> like in ImportModule?
actionToString = (a: AdditionalImportAction) =>
this.importAdditionalService.createActionLabel(a);
linkEntityForm = new FormGroup({
action: new FormControl({ value: "", disabled: true }, Validators.required),
targetId: new FormControl(
{ value: "", disabled: true },
Validators.required,
),
});
constructor() {
this.linkEntityForm
.get("action")
.valueChanges.pipe(takeUntilDestroyed(inject(DestroyRef)))
.subscribe((val) =>
!!val
? this.linkEntityForm.get("targetId").enable()
: this.linkEntityForm.get("targetId").disable(),
);
effect(() => {
const entityType = this.entityType();
this.linkEntityForm.reset();
if (entityType) {
this.linkEntityForm.get("action").enable();
}
});
}
addAction() {
const newAction = this.linkEntityForm.get("action").getRawValue();
this.importActions.update((actions) => [
...(actions ?? []),
{
...newAction,
targetId: this.linkEntityForm.get("targetId").value,
},
]);
this.linkEntityForm.reset();
}
removeAction(actionToRemove: AdditionalImportAction) {
this.importActions.update((actions) =>
actions.filter((a) => a !== actionToRemove),
);
}
}
function sortExportOnlyLast(
a: AdditionalImportAction,
b: AdditionalImportAction,
) {
// show "non-expert" actions first
if (a.expertOnly === b.expertOnly) return 0;
else if (a.expertOnly) return 1;
else return -1;
}
<mat-expansion-panel
[expanded]="importActions()?.length > 0"
[disabled]="!entityType()"
>
<mat-expansion-panel-header>
<mat-panel-title>
<span i18n>Advanced Import Actions [optional]</span>
<app-help-button
style="float: right"
text="In addition to creating new records directly for the imported data you can also define additional actions
(e.g. to make all imported records members of an existing activity or group).
This is an advanced functionality you do not have to use.
First select an import type above to enable this section.
If uncertain, please refer to the user guides, videos or support contact."
i18n-text="import - additional actions - help text"
>
</app-help-button>
</mat-panel-title>
</mat-expansion-panel-header>
<!-- Existing additional actions -->
<div>
<mat-list>
@for (action of importActions(); track $index) {
<mat-list-item>
<fa-icon
icon="xmark"
matListItemIcon
(click)="removeAction(action)"
matTooltip="Remove"
i18n-matTooltip
class="existing-action-remove"
></fa-icon>
<div matListItemTitle i18n>
Link all imported records to
{{ action.targetType | entityTypeLabel }}
</div>
<div matListItemLine>
<app-entity-block
[entityId]="action.targetId"
[linkDisabled]="true"
></app-entity-block>
</div>
</mat-list-item>
}
</mat-list>
@if (!(importActions()?.length > 0)) {
<div
class="no-actions margin-bottom-large"
i18n="import additional actions"
>
no additional actions selected
</div>
}
</div>
<!-- Create new additional action -->
@if (availableImportActions()?.length > 0) {
<form [formGroup]="linkEntityForm">
<div>
@if (linkEntityForm.disabled) {
<mat-error i18n>
Select an Import Target Type before defining additional actions.
</mat-error>
}
</div>
<div class="flex-row flex-wrap align-start gap-regular">
<mat-form-field class="action-field">
<mat-label i18n="Label for linked entity type input"
>Link all imported records to:
</mat-label>
<app-basic-autocomplete
formControlName="action"
[multi]="false"
[options]="availableImportActions()"
[optionToString]="actionToString"
></app-basic-autocomplete>
</mat-form-field>
<mat-form-field class="record-field">
<mat-label i18n>for record</mat-label>
<app-edit-entity
formControlName="targetId"
[entityType]="
linkEntityForm.controls['action'].value?.['targetType']
"
[multi]="false"
label="for record"
i18n-label
>
</app-edit-entity>
</mat-form-field>
<button
(click)="addAction()"
[disabled]="!linkEntityForm.valid"
mat-stroked-button
color="accent"
class="action-add-button"
i18n
>
Add Action
</button>
</div>
</form>
} @else if (entityType()) {
<p i18n>
No special import actions are available for importing
{{ entityType() | entityTypeLabel: true }} records.
</p>
}
</mat-expansion-panel>