AAE-46392 Fix card view select item crash on numeric initial value (#11917)

Guard autocomplete-only paths and coerce filter text to string so
select properties with numeric values (e.g. priority) no longer throw.
This commit is contained in:
Michaela
2026-05-26 15:57:37 +00:00
committed by GitHub
parent e6ef0de7a8
commit 70f90c65a5
2 changed files with 81 additions and 8 deletions
@@ -276,7 +276,8 @@ describe('CardViewSelectItemComponent', () => {
});
it('should set initial value to autocompleteControl', () => {
component.ngOnChanges({});
fixture.componentRef.setInput('property', component.property);
fixture.componentRef.setInput('editable', true);
fixture.detectChanges();
expect(component.autocompleteControl.value).toBe('initial value');
@@ -393,6 +394,70 @@ describe('CardViewSelectItemComponent', () => {
});
});
describe('Numeric initial value', () => {
const priorityOptions = [
{ key: 0, label: 'PROCESS_EDITOR.PRIORITIES.NONE' },
{ key: 1, label: 'PROCESS_EDITOR.PRIORITIES.LOW' },
{ key: 2, label: 'PROCESS_EDITOR.PRIORITIES.MEDIUM' },
{ key: 3, label: 'PROCESS_EDITOR.PRIORITIES.HIGH' }
];
const createNumericProperty = (config: {
autocompleteBased: boolean;
value: number;
label?: string;
displayNoneOption?: boolean;
options?: { key: number; label: string }[];
}) =>
new CardViewSelectItemModel({
label: config.label ?? 'Priority',
value: config.value,
key: 'priority',
editable: true,
autocompleteBased: config.autocompleteBased,
displayNoneOption: config.displayNoneOption,
options$: of(config.options ?? priorityOptions)
});
const applyInputs = (property: CardViewSelectItemModel<number>) => {
fixture.componentRef.setInput('property', property);
fixture.componentRef.setInput('editable', true);
fixture.detectChanges();
};
it('should not throw when autocompleteBased and initial value is numeric', fakeAsync(() => {
const property = createNumericProperty({
autocompleteBased: true,
value: 1,
options: [
{ key: 1, label: 'Option 1' },
{ key: 2, label: 'Option 2' }
]
});
const filterOptionsSpy = spyOn<any>(component, 'filterOptions').and.callThrough();
applyInputs(property);
tick(50);
expect(filterOptionsSpy).toHaveBeenCalled();
}));
it('should not call filterOptions when autocompleteBased is false and initial value is numeric', () => {
const property = createNumericProperty({
autocompleteBased: false,
value: 0,
label: 'PROCESS_EDITOR.ELEMENT_PROPERTIES.PRIORITY',
displayNoneOption: false
});
const filterOptionsSpy = spyOn<any>(component, 'filterOptions');
applyInputs(property);
expect(component.property.value).toBe(0);
expect(filterOptionsSpy).not.toHaveBeenCalled();
});
});
describe('Multivalued select', () => {
const multivaluedMockData = [
{ key: 'one', label: 'One' },
@@ -91,7 +91,7 @@ export class CardViewSelectItemComponent extends BaseCardView<CardViewSelectItem
this.property.value = [];
}
if (changes.property?.firstChange) {
if (changes.property?.firstChange && this.property.autocompleteBased) {
this.autocompleteControl.valueChanges
.pipe(
filter((textInputValue) => textInputValue !== this.editedValue && textInputValue !== null && !Array.isArray(textInputValue)),
@@ -126,7 +126,10 @@ export class CardViewSelectItemComponent extends BaseCardView<CardViewSelectItem
});
this.list$ = this.getList();
this.autocompleteControl.setValue(this.property.value);
if (this.property.autocompleteBased) {
this.autocompleteControl.setValue(this.property.value);
}
}
onFilterInputChange(value: string) {
@@ -199,16 +202,21 @@ export class CardViewSelectItemComponent extends BaseCardView<CardViewSelectItem
}
private filterOptions() {
if (!this.property.autocompleteBased) {
return;
}
this.getOptions()
.pipe(
map((options) =>
options.filter((option) => {
map((options) => {
const filterValue = String(this.editedValue ?? '').toLowerCase();
return options.filter((option) => {
const isSelected = this.property.multivalued
? this.property.value.some((val) => val === option.key)
: this.property.value === option.key;
return !isSelected && option.label.toLowerCase().includes(this.editedValue.toLowerCase());
})
)
return !isSelected && option.label.toLowerCase().includes(filterValue);
});
})
)
.pipe(take(1))
.subscribe((options: CardViewSelectItemOption<string | number>[]) => {