Merge branch 'SI-2907-Initiale-Darstellung-des-Stoerungsortes' of ssh://git.eclipse.org:29418/openk-usermodules/org.eclipse.openk-usermodules.gridFailureInformation.frontend into DEVELOP
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list-column-definition.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list-column-definition.ts
index eb14ef8..14d3d99 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list-column-definition.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list-column-definition.ts
@@ -225,7 +225,7 @@
     sortable: true,
     comparator: stringInsensitiveComparator,
     suppressMovable: true,
-    filter: 'setFilterComponent',
+    filter: 'fuzzySetFilterComponent',
     valueSeparator: ', ',
   },
   {
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.ts
index 92c4216..ee54f11 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure-list/grid-failure-list.component.ts
@@ -29,6 +29,7 @@
 import * as store from '@grid-failure-information-app/shared/store';
 import { Store } from '@ngrx/store';
 import { GridFailure } from '@grid-failure-information-app/shared/models';
+import { FuzzySetFilterComponent } from '@grid-failure-information-app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component';
 
 @Component({
   selector: 'app-grid-failure-list',
@@ -62,7 +63,11 @@
 
   constructor(public sandbox: GridFailureSandbox, private appState$: Store<store.State>, private _router: Router, private _utilService: UtilService) {
     super();
-    this.frameworkComponents = { setFilterComponent: SetFilterComponent, headerCellRendererComponent: HeaderCellRendererComponent };
+    this.frameworkComponents = {
+      setFilterComponent: SetFilterComponent,
+      fuzzySetFilterComponent: FuzzySetFilterComponent,
+      headerCellRendererComponent: HeaderCellRendererComponent,
+    };
   }
 
   ngOnInit(): void {
diff --git a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.module.ts b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.module.ts
index 80d9064..b928a2a 100644
--- a/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.module.ts
+++ b/projects/grid-failure-information-app/src/app/pages/grid-failure/grid-failure.module.ts
@@ -42,6 +42,7 @@
 import { UtilityModule } from '@grid-failure-information-app/shared/utility';
 import { PipesModule } from '@grid-failure-information-app/shared/pipes/pipes.module';
 import { GridFailureInformationMapModule } from 'openk/grid-failure-information-map/src/public-api';
+import { FuzzySetFilterComponent } from '@grid-failure-information-app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component';
 @NgModule({
   imports: [
     CommonModule,
@@ -59,7 +60,7 @@
     UtilityModule,
     PipesModule,
     StoreModule.forFeature('grid-failure', gridFailureReducers),
-    AgGridModule.withComponents([SetFilterComponent]),
+    AgGridModule.withComponents([SetFilterComponent, FuzzySetFilterComponent]),
     EffectsModule.forFeature([GridFailuresEffects]),
     ContainersModule,
     PipesModule,
diff --git a/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component.css b/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component.css
new file mode 100644
index 0000000..d7e7381
--- /dev/null
+++ b/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component.css
@@ -0,0 +1,43 @@
+/********************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+label {
+  white-space: nowrap;
+}
+
+span {
+  margin: 3px;
+}
+
+.ag-grid-filter-container {
+  height: auto;
+  width: 250px;
+  margin: 4px;
+  border: 1px solid lightgrey;
+  z-index: 100;
+}
+
+.ag-grid-filter-text {
+  width: 99%;
+  margin: 1px;
+}
+
+.ag-grid-filter {
+  border-bottom: 1px solid lightgrey;
+  margin: 2px;
+}
+
+.ag-grid-filter-checkbox {
+  overflow-y: scroll;
+  overflow: hidden;
+  margin: 2px;
+}
diff --git a/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component.html b/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component.html
new file mode 100644
index 0000000..6d52e0f
--- /dev/null
+++ b/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component.html
@@ -0,0 +1,46 @@
+<!-- /********************************************************************************
+* Copyright (c) 2020 Contributors to the Eclipse Foundation
+*
+* See the NOTICE file(s) distributed with this work for additional
+* information regarding copyright ownership.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License v. 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0
+********************************************************************************/ -->
+<div class="ag-grid-filter-container">
+  <div class="ag-grid-filter">
+    <input mdInput class="ag-grid-filter-text" [(ngModel)]="filterText" name="'filterText'" (input)="filterCheckboxList($event.target.value)" />
+  </div>
+  <div class="ag-grid-filter">
+    <div class="checkbox">
+      <label
+        ><input type="checkbox" (change)="selectAll($event)" [checked]="selectAllChecked" /><span>{{ 'GridFailures.SelectAll' | translate }}</span></label
+      >
+    </div>
+  </div>
+  <div class="ag-grid-filter-checkbox">
+    <label *ngFor="let setItem of setItems | keyvalue" style="display: block;">
+      <input
+        type="checkbox"
+        [checked]="setItem.value.checked"
+        (change)="notifyFilter($event)"
+        [id]="setItem?.key"
+        *ngIf="setItem.key != 'null' && setItem.key != ''"
+      />
+      <span *ngIf="setItem.key != 'null' && setItem.key != ''">{{ setItem?.key }}</span>
+    </label>
+    <label *ngFor="let setItem of setItems | keyvalue" style="display: block;">
+      <input
+        type="checkbox"
+        [checked]="setItem.value.checked"
+        (change)="notifyFilter($event)"
+        [id]="setItem?.key"
+        *ngIf="setItem.key == 'null' && setItem.key != ''"
+      />
+      <span *ngIf="setItem.key == 'null' && setItem.key != ''">{{ 'GridFailures.NullValue' | translate }}</span>
+    </label>
+  </div>
+</div>
diff --git a/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component.spec.ts b/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component.spec.ts
new file mode 100644
index 0000000..ad0be59
--- /dev/null
+++ b/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component.spec.ts
@@ -0,0 +1,300 @@
+/********************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FuzzySetFilterComponent } from '@grid-failure-information-app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component';
+
+describe('FuzzySetFilterComponent', () => {
+  let component: FuzzySetFilterComponent;
+  let fixture: ComponentFixture<FuzzySetFilterComponent>;
+
+  beforeEach(() => {
+    const params: any = {
+      node: 'x',
+      colDef: {
+        colId: 'testColId',
+      },
+      rowModel: {
+        nodeManager: {
+          allNodesMap: {
+            0: { id: '0' },
+            1: { id: '1' },
+          },
+        },
+      },
+      doesRowPassOtherFilter() {},
+      filterChangedCallback() {},
+      api: {
+        getModel() {
+          return {
+            rowsToDisplay: {
+              map: () => {
+                return ['Störung'];
+              },
+            },
+          };
+        },
+        gridOptionsWrapper: { gridOptions: { onGridSizeChanged: () => {}, onRowDataChanged: () => {} } },
+      },
+    } as any;
+    component = new FuzzySetFilterComponent();
+    component['_params'] = params;
+    component.setItems = {
+      FilterText1: { checked: true },
+      FilterText2: { checkde: false },
+    };
+    component['_valueGetter'] = () => {
+      return { id: '0' };
+    };
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  it('should extend the setItems in _extendFilterItem when filterWord is test', () => {
+    const filterItems = { test: { checked: true } };
+    (component as any)._filteredItems = filterItems;
+    (component as any)._extendFilteredItem('test');
+    expect('test' in component.setItems).toBeTruthy();
+  });
+
+  it('should filterCheckboxList with setItems', () => {
+    component.setItems = [
+      { AAA: {}, checked: true },
+      { BBB: {}, checked: true },
+    ];
+    const compAnonym = component as any;
+    compAnonym._params = { filterChangedCallback() {} };
+    component.filterCheckboxList('X');
+    const filteredItem = compAnonym._filteredItems[0];
+    expect(filteredItem).toEqual({ AAA: {}, checked: true });
+  });
+
+  it('should set selectAllChecked false is an non-empty filter text is provided', () => {
+    component.setItems = [
+      { AAA: {}, checked: true },
+      { BBB: {}, checked: true },
+    ];
+    const compAnonym = component as any;
+    compAnonym._params = { filterChangedCallback() {} };
+    component.filterText = 'Test';
+    component.filterCheckboxList('X');
+    expect(component.selectAllChecked).toBeFalsy();
+  });
+
+  it('should add filtered filterItem to the filterModel in _addItemToFilterModel()', () => {
+    const compAnonym = component as any;
+    compAnonym.filterText = 'Filter';
+    compAnonym._addItemToFilterModel({}, 'FilterText');
+    expect(compAnonym.setItems).toBeDefined();
+    expect(compAnonym.setItems['FilterText']).toBeDefined();
+  });
+
+  it('should add a checked filtered filterItem to the filterModel in _addItemToFilterModel()', () => {
+    const oldFilterItems = {};
+    const compAnonym = component as any;
+    compAnonym.filterText = 'Filter';
+    compAnonym._addItemToFilterModel(oldFilterItems, 'FilterText');
+    expect(compAnonym.setItems).toBeDefined();
+    expect(compAnonym.setItems['FilterText']).toBeDefined();
+    expect(compAnonym.setItems['FilterText']['checked']).toBeTruthy();
+  });
+
+  it('should add a checked filterItem to the filterModel in _addItemToFilterModel()', () => {
+    const oldFilterItems = {
+      FilterText: {
+        checked: true,
+      },
+    };
+    const compAnonym = component as any;
+    compAnonym.filterText = '';
+    compAnonym._addItemToFilterModel(oldFilterItems, 'FilterText');
+    expect(compAnonym.setItems).toBeDefined();
+    expect(compAnonym.setItems['FilterText']).toBeDefined();
+    expect(compAnonym.setItems['FilterText']['checked']).toBeTruthy();
+  });
+
+  it('should setItems in response to filteredItems', () => {
+    component.setItems = [{ BBB: {}, checked: false }];
+    component['_filteredItem'] = [{ BBB: {}, checked: true }];
+    const compAnonym = component as any;
+    compAnonym._params = { filterChangedCallback() {} };
+    component.filterCheckboxList('B');
+    expect(component.setItems['BBB']).toEqual(component['_filteredItem']['BBB']);
+  });
+
+  it('should return isFilterActive', () => {
+    component.setItems = [{ checked: true }, { checked: true }];
+    expect(component.isFilterActive()).toBeFalsy();
+  });
+
+  it('should return model', () => {
+    component.setItems = 666;
+    expect(component.getModel().values).toBe(666);
+  });
+
+  it('should set model 1', () => {
+    component.setItems = 666;
+    component.setModel(null);
+    expect(component.setItems).toEqual([]);
+  });
+
+  it('should set model 2', () => {
+    component.setItems = 666;
+    component.setModel({ values: 333 });
+    expect(component.setItems).toEqual(333);
+  });
+
+  it('should set checked of setItems via notifyFilter (checked true)', () => {
+    component['_params'] = { filterChangedCallback() {} } as any;
+    component.setItems = { null: { checked: false } };
+    const event = { target: { id: 'null', checked: true } } as any;
+    component.notifyFilter(event);
+    expect(component.setItems.null.checked).toBeTruthy();
+  });
+
+  it('should set checked of setItems via notifyFilter (checked false)', () => {
+    component['_params'] = { filterChangedCallback() {} } as any;
+    component.setItems = { null: { checked: false } };
+    const event = { target: { id: 'null', checked: false } } as any;
+    component.notifyFilter(event);
+    expect(component.setItems.null.checked).toBeFalsy();
+  });
+
+  it('should set selectAllChecked false if filterText is empty', () => {
+    component['_params'] = { filterChangedCallback() {} } as any;
+    component.setItems = { null: { checked: false } };
+    component.filterText = '';
+    const event = { target: { id: 'null', checked: true } } as any;
+    component.notifyFilter(event);
+    expect(component.selectAllChecked).toBeFalsy();
+  });
+
+  it('should selectAll via selectAll with given event', () => {
+    component['_params'] = { filterChangedCallback() {} } as any;
+    component.setItems = { null: { checked: false } };
+    const event = { target: { id: 'null', checked: true } } as any;
+    component.selectAll(event);
+    expect(component.selectAllChecked).toBeTruthy();
+  });
+
+  it('should selectAll via selectAll without a given event', () => {
+    component['_params'] = { filterChangedCallback() {} } as any;
+    component.setItems = { null: { checked: false } };
+    component.selectAll();
+    expect(component.selectAllChecked).toBeTruthy();
+  });
+
+  it('should not pass filter for undefined setItems', () => {
+    const params = { node: 'x' } as any;
+    component['_valueGetter'] = () => {};
+    const returnValue = component.doesFilterPass(params);
+    expect(returnValue).toBeFalsy();
+  });
+
+  it('should not pass filter for itemKey null', () => {
+    const params = { node: '' } as any;
+    component['_valueGetter'] = () => params.node;
+    component.setItems = { null: { checked: false } };
+    const returnValue = component.doesFilterPass(params);
+    expect(returnValue).toBeFalsy();
+  });
+
+  it('should return true after calling doesFilterPass(..) with filter 50 and node value 50 ', () => {
+    component['_valueGetter'] = () => 50;
+    component.setItems = { 50: { checked: true } };
+    const returnValue = component.doesFilterPass({} as any);
+    expect(returnValue).toBeTruthy();
+  });
+
+  it('should return false after calling doesFilterPass(..) with filter 50 and node value 666 ', () => {
+    component['_valueGetter'] = () => 666;
+    component.setItems = { 50: { checked: true } };
+    const returnValue = component.doesFilterPass({} as any);
+    expect(returnValue).toBeFalsy();
+  });
+
+  it('should return false after calling doesFilterPass(..) with filter "oncle" and node value "tom" ', () => {
+    component['_valueGetter'] = () => 'tom';
+    component.setItems = { oncle: { checked: true } };
+    const returnValue = component.doesFilterPass({} as any);
+    expect(returnValue).toBeFalsy();
+  });
+
+  it('should return true after calling doesFilterPass(..) with filter "oncle" and node value "oncle" ', () => {
+    component['_valueGetter'] = () => 'oncle';
+    component.setItems = { oncle: { checked: true } };
+    const returnValue = component.doesFilterPass({} as any);
+    expect(returnValue).toBeTruthy();
+  });
+
+  it('should return true after calling doesFilterPass(..) with filter "oncle" and node value "oncle tom" ', () => {
+    component['_valueGetter'] = () => 'oncle tom';
+    component.setItems = { oncle: { checked: true } };
+    const returnValue = component.doesFilterPass({} as any);
+    expect(returnValue).toBeTruthy();
+  });
+
+  it('should set params via agInit()', () => {
+    const params: any = {
+      node: 'x',
+      colDef: {
+        colId: 'testColId',
+      },
+      rowModel: {
+        nodeManager: {
+          allNodesMap: {
+            0: { id: '0' },
+            1: { id: '1' },
+          },
+        },
+      },
+      doesRowPassOtherFilter() {},
+      filterChangedCallback() {},
+      api: {
+        getModel() {
+          return {
+            rowsToDisplay: {
+              map: () => {
+                return ['Störung'];
+              },
+            },
+          };
+        },
+        gridOptionsWrapper: {
+          gridOptions: {
+            onGridSizeChanged: () => {},
+            onRowDataChanged: () => {},
+          },
+        },
+      },
+    } as any;
+    component['_valueGetter'] = () => {
+      return { id: '0' };
+    };
+    component.agInit(params);
+    expect(component['_params']).toEqual(params as any);
+  });
+
+  it('should setFilterItems via afterGuiAttached', () => {
+    const spy = spyOn(component as any, '_setFilterItems');
+    component.afterGuiAttached('x');
+    expect(spy).toHaveBeenCalled();
+  });
+
+  it('should return false in _areAllFilterItemsSelected() when filter textbox is not empty', () => {
+    component.filterText = '0815';
+    const allFilterItemsSelected: boolean = (component as any)._areAllFilterItemsSelected();
+    expect(allFilterItemsSelected).toBe(false);
+  });
+});
diff --git a/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component.ts b/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component.ts
new file mode 100644
index 0000000..325a7bc
--- /dev/null
+++ b/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component.ts
@@ -0,0 +1,47 @@
+/********************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ********************************************************************************/
+import { Component, OnInit } from '@angular/core';
+import { IDoesFilterPassParams, IFilterParams, RowDataChangedEvent, RowNode } from 'ag-grid-community';
+import { SetFilterComponent } from '@grid-failure-information-app/shared/filters/ag-grid/set-filter/set-filter.component';
+
+@Component({
+  selector: 'fuzzy-filter-cell',
+  templateUrl: './fuzzy-set-filter.component.html',
+  styleUrls: ['./fuzzy-set-filter.component.css'],
+})
+export class FuzzySetFilterComponent extends SetFilterComponent {
+  doesFilterPass(params: IDoesFilterPassParams): boolean {
+    const nodeValue = this._valueGetter(params.node);
+    let passed: boolean = false;
+
+    for (let itemKey in this.setItems) {
+      if (isNaN(nodeValue)) {
+        if (itemKey === 'null') {
+          passed = !nodeValue || nodeValue === ''; // nodeValue is falsy or empty string
+        } else {
+          passed = !!nodeValue && nodeValue.includes(itemKey);
+        }
+      } else {
+        // is numeric or null
+        if (!nodeValue) {
+          passed = nodeValue === null && itemKey === 'null';
+        } else {
+          passed = nodeValue.toString() === itemKey;
+        }
+      }
+      passed = passed && this.setItems[itemKey].checked;
+      if (passed) return passed;
+    }
+    return passed;
+  }
+}
diff --git a/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/set-filter/set-filter.component.spec.ts b/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/set-filter/set-filter.component.spec.ts
index 1098295..b0489df 100644
--- a/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/set-filter/set-filter.component.spec.ts
+++ b/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/set-filter/set-filter.component.spec.ts
@@ -243,7 +243,7 @@
     component['_valueGetter'] = () => 'oncle tom';
     component.setItems = { oncle: { checked: true } };
     const returnValue = component.doesFilterPass({} as any);
-    expect(returnValue).toBeTruthy();
+    expect(returnValue).toBeFalsy();
   });
 
   it('should set params via agInit()', () => {
diff --git a/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/set-filter/set-filter.component.ts b/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/set-filter/set-filter.component.ts
index 6bdc12b..ea0f137 100644
--- a/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/set-filter/set-filter.component.ts
+++ b/projects/grid-failure-information-app/src/app/shared/filters/ag-grid/set-filter/set-filter.component.ts
@@ -32,7 +32,7 @@
 
   private _filteredItems: any = {};
   private _params: IFilterParams;
-  private _valueGetter: (rowNode: RowNode) => any;
+  protected _valueGetter: (rowNode: RowNode) => any;
   private _filterId: string = '';
 
   protected _endSubscriptions$: Subject<boolean> = new Subject();
@@ -43,22 +43,25 @@
       .toLowerCase()
       .split(' ')
       .forEach(filterWord => {
+        const trimmedFilterWord = filterWord.trim();
         if (Object.keys(this.setItems).length > 0) {
+          // setItems allready there ??
           for (var itemKey in this.setItems) {
-            if (!this._contains(itemKey, filterWord)) {
+            if (this._contains(itemKey, trimmedFilterWord)) {
+              // filtertext is in itemKey ??
+              this._extendFilteredItem(trimmedFilterWord);
+            } else {
               this._filteredItems[itemKey] = this.setItems[itemKey];
               delete this.setItems[itemKey];
-            } else {
-              this._extendFilteredItem(filterWord);
             }
           }
         } else {
-          this._extendFilteredItem(filterWord);
+          this._extendFilteredItem(trimmedFilterWord);
         }
-        if (this.filterText.length !== 0) {
-          this.selectAllChecked = false;
-        } else {
+        if (this.filterText.length === 0) {
           this.selectAll();
+        } else {
+          this.selectAllChecked = false;
         }
       });
     this._params.filterChangedCallback();
@@ -90,28 +93,8 @@
   }
 
   doesFilterPass(params: IDoesFilterPassParams): boolean {
-    const nodeValue = this._valueGetter(params.node);
-    let passed: boolean = false;
-
-    for (let itemKey in this.setItems) {
-      if (isNaN(nodeValue)) {
-        if (itemKey === 'null') {
-          passed = !nodeValue || nodeValue === ''; // nodeValue is falsy or empty string
-        } else {
-          passed = !!nodeValue && nodeValue.includes(itemKey);
-        }
-      } else {
-        // is numeric or null
-        if (!nodeValue) {
-          passed = nodeValue === null && itemKey === 'null';
-        } else {
-          passed = nodeValue.toString() === itemKey;
-        }
-      }
-      passed = passed && this.setItems[itemKey].checked;
-      if (passed) return passed;
-    }
-    return passed;
+    const itemKey = this._valueGetter(params.node);
+    return this.setItems[itemKey || null] !== undefined && this.setItems[itemKey || null].checked;
   }
 
   getModel(): any {
diff --git a/projects/grid-failure-information-app/src/app/shared/filters/filters.module.ts b/projects/grid-failure-information-app/src/app/shared/filters/filters.module.ts
index dd6cf57..6eaed20 100644
--- a/projects/grid-failure-information-app/src/app/shared/filters/filters.module.ts
+++ b/projects/grid-failure-information-app/src/app/shared/filters/filters.module.ts
@@ -15,9 +15,10 @@
 import { CommonModule } from '@angular/common';
 import { TranslateModule } from '@ngx-translate/core';
 import { FormsModule } from '@angular/forms';
+import { FuzzySetFilterComponent } from '@grid-failure-information-app/shared/filters/ag-grid/fuzzy-set-filter/fuzzy-set-filter.component';
 
 @NgModule({
-  declarations: [SetFilterComponent],
+  declarations: [SetFilterComponent, FuzzySetFilterComponent],
   exports: [SetFilterComponent],
   imports: [FormsModule, CommonModule, TranslateModule],
 })