Description
Configuration dialog for parsing date value of data imported from a file.
Example
Methods
|
Async
checkDateValues
|
checkDateValues()
|
|
|
|
|
|
data
|
Type : unknown
|
Default value : inject<MappingDialogData>(MAT_DIALOG_DATA)
|
|
|
|
format
|
Type : unknown
|
Default value : new FormControl("")
|
|
|
|
hasLowercaseMM
|
Type : boolean
|
|
|
The date formatting interprets lowercase "mm" as minutes instead of months,
this may lead to misunderstandings, so we check for it and show a warning if detected.
|
|
valid
|
Type : unknown
|
Default value : false
|
|
|
|
values
|
Type : { value: string; parsed?: Date }[]
|
Default value : []
|
|
|
import { ChangeDetectionStrategy, Component, inject } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import {
MAT_DIALOG_DATA,
MatDialogModule,
MatDialogRef,
} from "@angular/material/dialog";
import { FormControl, ReactiveFormsModule } from "@angular/forms";
import { from } from "rxjs";
import { switchMap } from "rxjs/operators";
import { ConfirmationDialogService } from "../../../common-components/confirmation-dialog/confirmation-dialog.service";
import { MappingDialogData } from "app/core/import/import-column-mapping/mapping-dialog-data";
import { MatInputModule } from "@angular/material/input";
import { CustomDatePipe } from "../custom-date.pipe";
import { MatListModule } from "@angular/material/list";
import { MatButtonModule } from "@angular/material/button";
import { HelpButtonComponent } from "../../../common-components/help-button/help-button.component";
import { DynamicComponent } from "../../../config/dynamic-components/dynamic-component.decorator";
import { DateDatatype } from "../date.datatype";
/**
* Configuration dialog for parsing date value of data imported from a file.
*/
@DynamicComponent("DateImportDialog")
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "app-date-import-dialog",
templateUrl: "./date-import-dialog.component.html",
styleUrls: ["./date-import-dialog.component.scss"],
imports: [
MatDialogModule,
MatInputModule,
ReactiveFormsModule,
MatListModule,
CustomDatePipe,
MatButtonModule,
HelpButtonComponent,
],
})
export class DateImportDialogComponent {
data = inject<MappingDialogData>(MAT_DIALOG_DATA);
private readonly confirmation = inject(ConfirmationDialogService);
private readonly dialog = inject<MatDialogRef<any>>(MatDialogRef);
format = new FormControl("");
valid = false;
values: { value: string; parsed?: Date }[] = [];
/**
* The date formatting interprets lowercase "mm" as minutes instead of months,
* this may lead to misunderstandings, so we check for it and show a warning if detected.
*/
hasLowercaseMM: boolean;
constructor() {
this.values = this.data.values
.filter((val) => !!val)
.map((value) => ({ value }));
this.format.valueChanges
.pipe(
switchMap(() => from(this.checkDateValues())),
takeUntilDestroyed(),
)
.subscribe();
this.format.setValue(this.data.col.additional);
}
async checkDateValues() {
this.format.setErrors(undefined);
this.hasLowercaseMM = /mm/.test(this.format.value || "");
const dateType = new DateDatatype();
for (const val of this.values) {
// TODO: check and improve the date parsing. Tests fail with moment.js > 2.29
const date = await dateType.importMapFunction(
val.value,
undefined, // the schema is not needed here, we can skip loading it
this.format.value,
);
if (date instanceof Date && !isNaN(date.getTime())) {
val.parsed = date;
} else {
delete val.parsed;
this.format.setErrors({ parsingError: true });
}
}
// Sort unparsed dates to front
this.values.sort((v1, v2) =>
v1.parsed && !v2.parsed ? 1 : !v1.parsed && v2.parsed ? -1 : 0,
);
}
async save() {
const confirmed =
!this.format.errors ||
(await this.confirmation.getConfirmation(
$localize`Ignore values?`,
$localize`Some values don't have a mapping and will not be imported. Are you sure you want to keep it like this?`,
));
if (confirmed) {
// an empty format is a valid choice (dates the system reads on its own), but it has to be
// stored as a value so that the column does not count as unconfigured afterwards
this.data.col.additional = this.format.value ?? "";
this.dialog.close();
}
}
}
<mat-dialog-content>
<mat-form-field>
<mat-label i18n>Date format</mat-label>
<input [formControl]="format" matInput />
<mat-hint>
<div i18n>
e.g. DD.MM.YYYY
<a
href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format"
target="_blank"
rel="noopener"
>(help)</a
>
</div>
@if (hasLowercaseMM) {
<div i18n>
Warning: "mm" is used for minutes, for months use "MM" instead.
</div>
}
@if (format.errors) {
<div class="warning" i18n>This format cannot parse all dates.</div>
}
</mat-hint>
</mat-form-field>
<app-help-button
text="Define how date values in your imported data are formatted, so that the system correctly understands them. Values that do not match the given format will be ignored (remain empty) during import."
i18n-text="import - value mapping (date) - help text"
></app-help-button>
<mat-list>
@for (val of values; track val) {
<mat-list-item [class.invalid]="!val.parsed">
{{ val.value }} -> {{ val.parsed | customDate }}
</mat-list-item>
}
</mat-list>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-raised-button color="accent" (click)="save()" i18n>
Save & Close
</button>
<button mat-stroked-button matDialogClose i18n>Cancel</button>
</mat-dialog-actions>
.invalid {
background-color: rgba(256, 0, 0, 0.5);
}
mat-list-item {
margin: 5px 0;
border-radius: 5px;
}
.warning {
color: red;
}
Legend
Html element with directive