Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
feat(filter-field): Added options for user defined tag parser function
Browse files Browse the repository at this point in the history
  • Loading branch information
Mireia Martin authored and tomheller committed Aug 6, 2020
1 parent 445b1e8 commit e16948a
Show file tree
Hide file tree
Showing 15 changed files with 622 additions and 142 deletions.
14 changes: 13 additions & 1 deletion libs/barista-components/filter-field/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,14 +199,26 @@ tags get disabled and therefore cannot be modified by the user.
### Readonly, non-deletable & non-editable tags

The filter field creates a `DtFilterFieldTag` for each active filter. You can
get subscribe to the list of current tags with the `currentTags` observable. By
get subscribed to the list of current tags with the `currentTags` observable. By
using the utility method `getTagForFilter` you can find a `DtFilterFieldTag`
instance created for a given filter. After getting the tag instance for your
filter you can configure the filter to your needs by using the properties
`editable`, `deletable` and `disabled`.

<ba-live-example name="DtExampleFilterFieldReadOnlyTags"></ba-live-example>

### Changing the default parsing of filter values

The filter field exposes a `defaultTagDataForFilterValuesParser` function,
describing how the key:value pairs of each chosen filter should be parsed and
shown. However, this function can be extended and replaced through the
`DT_FILTER_VALUES_PARSER_CONFIG` token, which can be injected in the parent
component and assigned a function of your own. In addition, this token can also
be overriden with an input function specific to the component using that filter
instance.

<ba-live-example name="DtExampleFilterFieldCustomParser"></ba-live-example>

### Validators

Handling the user input with validators provides you with control over input
Expand Down
12 changes: 11 additions & 1 deletion libs/barista-components/filter-field/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ export * from './src/filter-field-range/filter-field-range-trigger';
export * from './src/filter-field-data-source';
export * from './src/filter-field-default-data-source';
export * from './src/filter-field-errors';
export { applyDtOptionIds, DELIMITER } from './src/filter-field-util';
export {
applyDtOptionIds,
DELIMITER,
defaultTagDataForFilterValuesParser,
} from './src/filter-field-util';
export {
DtNodeFlags,
DtNodeDef,
Expand All @@ -44,4 +48,10 @@ export {
dtGroupDef,
isDtGroupDef,
isDtRenderType,
DtFilterValue,
DtFilterFieldTagData,
isDtAutocompleteValue,
isDtFreeTextValue,
isDtRangeValue,
} from './src/types';
export { DT_FILTER_VALUES_PARSER_CONFIG } from './src/filter-field-config';
33 changes: 33 additions & 0 deletions libs/barista-components/filter-field/src/filter-field-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* @license
* Copyright 2020 Dynatrace LLC
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { InjectionToken } from '@angular/core';
import { defaultTagDataForFilterValuesParser } from './filter-field-util';
import { DtFilterValue, DtFilterFieldTagData } from './types';

/** User defined parser function for tag key:values, overrides default parser function */
export type TagParserFunction = (
filterValues: DtFilterValue[],
editable?: boolean,
deletable?: boolean,
) => DtFilterFieldTagData | null;

/** Injection token for the external configuration of the filter-field component */
export const DT_FILTER_VALUES_PARSER_CONFIG = new InjectionToken<
TagParserFunction
>('dt-filter-value-config');

export const DT_FILTER_VALUES_DEFAULT_PARSER_CONFIG: TagParserFunction = defaultTagDataForFilterValuesParser;
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import {

import { mockObjectProperty } from '@dynatrace/testing/node';

import { _DtFilterFieldTagData } from '../types';
import { DtFilterFieldTagData } from '../types';
import { DtOverlayTrigger } from '@dynatrace/barista-components/overlay';

describe('DtFilterFieldTag', () => {
Expand Down Expand Up @@ -237,7 +237,7 @@ describe('DtFilterFieldTag', () => {

// Set the larger field value dynamically without destroying the
// tag component.
fixture.componentInstance.dummy = new _DtFilterFieldTagData(
fixture.componentInstance.dummy = new DtFilterFieldTagData(
'AUT',
'A larger value, value does not matter because scrollWidth is mocked',
':',
Expand Down Expand Up @@ -296,5 +296,5 @@ describe('DtFilterFieldTag', () => {
})
export class TestApp {
// we need to add this dummy data because the tags editable and deletable flags depend on the data being set
dummy = new _DtFilterFieldTagData('AUT', 'Linz', ':', false, []);
dummy = new DtFilterFieldTagData('AUT', 'Linz', ':', false, []);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
OnDestroy,
} from '@angular/core';

import { _DtFilterFieldTagData } from '../types';
import { DtFilterFieldTagData } from '../types';
import { DtOverlayConfig } from '@dynatrace/barista-components/overlay';
import { Platform } from '@angular/cdk/platform';
import { take, takeUntil, switchMap } from 'rxjs/operators';
Expand Down Expand Up @@ -58,16 +58,16 @@ export class DtFilterFieldTag implements OnDestroy {

/** Tag data object that contains view values for displaying (like key, value and separator) and the original source. */
@Input()
get data(): _DtFilterFieldTagData {
get data(): DtFilterFieldTagData {
return this._data;
}
set data(value: _DtFilterFieldTagData) {
set data(value: DtFilterFieldTagData) {
if (value !== this._data) {
this._stateChanges$.next();
}
this._data = value;
}
private _data: _DtFilterFieldTagData;
private _data: DtFilterFieldTagData;

/** Emits when the filter should be removed (usually by clicking the remove button). */
@Output() readonly remove = new EventEmitter<DtFilterFieldTag>();
Expand Down
76 changes: 38 additions & 38 deletions libs/barista-components/filter-field/src/filter-field-util.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
// Import locally because utils are not exported for the public
import {
DELIMITER,
createTagDataForFilterValues,
defaultTagDataForFilterValuesParser,
defDistinctPredicate,
defUniquePredicate,
findDefForSource,
Expand All @@ -45,9 +45,9 @@ import {
filterAutocompleteDef,
} from './filter-field-util';
import {
_DtAutocompleteValue,
_DtFilterValue,
_DtRangeValue,
DtAutocompleteValue,
DtFilterValue,
DtRangeValue,
dtRangeDef,
isDtFreeTextDef,
DtNodeDef,
Expand Down Expand Up @@ -503,8 +503,8 @@ describe('DtFilterField Util', () => {
);
optionDef.option!.parentAutocomplete = autocompleteDef;

const values = [optionDef] as _DtFilterValue[];
const tagData = createTagDataForFilterValues(values);
const values = [optionDef] as DtFilterValue[];
const tagData = defaultTagDataForFilterValuesParser(values);

expect(tagData).not.toBeNull();
expect(tagData!.key).toBe(null);
Expand Down Expand Up @@ -546,8 +546,8 @@ describe('DtFilterField Util', () => {
optionDef.option!.parentGroup = groupDef;
groupDef.group!.parentAutocomplete = autocompleteDef;

const values = [optionDef] as _DtFilterValue[];
const tagData = createTagDataForFilterValues(values);
const values = [optionDef] as DtFilterValue[];
const tagData = defaultTagDataForFilterValuesParser(values);

expect(tagData).not.toBeNull();
expect(tagData!.key).toBe(null);
Expand Down Expand Up @@ -600,8 +600,8 @@ describe('DtFilterField Util', () => {
);
outerOptionAutocompleteDef.option!.parentAutocomplete = rootAutocompleteDef;

const values = [outerOptionDef, innerOptionDef] as _DtFilterValue[];
const tagData = createTagDataForFilterValues(values);
const values = [outerOptionDef, innerOptionDef] as DtFilterValue[];
const tagData = defaultTagDataForFilterValuesParser(values);

expect(tagData).not.toBeNull();
expect(tagData!.key).toBe('Outer Option');
Expand All @@ -613,7 +613,7 @@ describe('DtFilterField Util', () => {

it('should create a tag object out of a single free text', () => {
const values = ['Some Text'];
const tagData = createTagDataForFilterValues(values);
const tagData = defaultTagDataForFilterValuesParser(values);

expect(tagData).not.toBeNull();
expect(tagData!.key).toBe(null);
Expand Down Expand Up @@ -646,8 +646,8 @@ describe('DtFilterField Util', () => {
);
freeTextDef.option!.parentAutocomplete = autocompleteDef;

const values = [freeTextDef, 'Some Text'] as _DtFilterValue[];
const tagData = createTagDataForFilterValues(values);
const values = [freeTextDef, 'Some Text'] as DtFilterValue[];
const tagData = defaultTagDataForFilterValuesParser(values);

expect(tagData).not.toBeNull();
expect(tagData!.key).toBe('Option 1');
Expand Down Expand Up @@ -690,8 +690,8 @@ describe('DtFilterField Util', () => {
freeTextDef.option!.parentAutocomplete = autocompleteDef;
groupDef.group!.parentAutocomplete = autocompleteDef;

const values = [optionDef, 'Some Text'] as _DtFilterValue[];
const tagData = createTagDataForFilterValues(values);
const values = [optionDef, 'Some Text'] as DtFilterValue[];
const tagData = defaultTagDataForFilterValuesParser(values);

expect(tagData).not.toBeNull();
expect(tagData!.key).toBe('Option 1');
Expand Down Expand Up @@ -1165,42 +1165,42 @@ describe('DtFilterField Util', () => {

describe('isDtRangeValueEqual', () => {
it('should return true if range values are equal', () => {
const test: _DtRangeValue = { operator: '=', range: 1 };
const test: DtRangeValue = { operator: '=', range: 1 };
expect(isDtRangeValueEqual(test, test)).toBeTruthy();

const test1: _DtRangeValue = { operator: 'range', range: [1, 2] };
const test1: DtRangeValue = { operator: 'range', range: [1, 2] };
expect(isDtRangeValueEqual(test1, test1)).toBeTruthy();

const test2: _DtRangeValue = {
const test2: DtRangeValue = {
operator: 'range',
range: [1, 2],
unit: 's',
};
expect(isDtRangeValueEqual(test2, test2)).toBeTruthy();
});
it('should return true if range values have different array instances but the same values within', () => {
const a: _DtRangeValue = { operator: 'range', range: [1, 2] };
const b: _DtRangeValue = { operator: 'range', range: [1, 2] };
const a: DtRangeValue = { operator: 'range', range: [1, 2] };
const b: DtRangeValue = { operator: 'range', range: [1, 2] };
expect(isDtRangeValueEqual(a, b)).toBeTruthy();
});
it('should return false when a has unit set but b does not', () => {
const a: _DtRangeValue = { operator: 'range', range: [1, 2] };
const b: _DtRangeValue = { operator: 'range', range: [1, 2], unit: 's' };
const a: DtRangeValue = { operator: 'range', range: [1, 2] };
const b: DtRangeValue = { operator: 'range', range: [1, 2], unit: 's' };
expect(isDtRangeValueEqual(a, b)).toBeFalsy();
});
it('should return false when a has different numbers in the range array than b', () => {
const a: _DtRangeValue = { operator: 'range', range: [1, 2] };
const b: _DtRangeValue = { operator: 'range', range: [2, 3] };
const a: DtRangeValue = { operator: 'range', range: [1, 2] };
const b: DtRangeValue = { operator: 'range', range: [2, 3] };
expect(isDtRangeValueEqual(a, b)).toBeFalsy();
});
it('should return false when a has the range numbers ordered differently than than b', () => {
const a: _DtRangeValue = { operator: 'range', range: [1, 2] };
const b: _DtRangeValue = { operator: 'range', range: [2, 1] };
const a: DtRangeValue = { operator: 'range', range: [1, 2] };
const b: DtRangeValue = { operator: 'range', range: [2, 1] };
expect(isDtRangeValueEqual(a, b)).toBeFalsy();
});
it('should return false when a has the range array and b has a number', () => {
const a: _DtRangeValue = { operator: 'range', range: [1, 2] };
const b: _DtRangeValue = { operator: 'range', range: 1 };
const a: DtRangeValue = { operator: 'range', range: [1, 2] };
const b: DtRangeValue = { operator: 'range', range: 1 };
expect(isDtRangeValueEqual(a, b)).toBeFalsy();
});
});
Expand All @@ -1215,15 +1215,15 @@ describe('DtFilterField Util', () => {
null,
null,
null,
) as _DtAutocompleteValue<any>;
) as DtAutocompleteValue<any>;
const b = dtOptionDef(
optionSource,
null,
optionSource.name,
null,
null,
null,
) as _DtAutocompleteValue<any>;
) as DtAutocompleteValue<any>;
expect(isDtAutocompleteValueEqual(a, b)).toBeTruthy();
expect(isDtAutocompleteValueEqual(b, a)).toBeTruthy();
});
Expand All @@ -1236,15 +1236,15 @@ describe('DtFilterField Util', () => {
`${optionSource.name}${DELIMITER}`,
null,
null,
) as _DtAutocompleteValue<any>;
) as DtAutocompleteValue<any>;
const b = dtOptionDef(
optionSource,
null,
optionSource.name,
null,
null,
null,
) as _DtAutocompleteValue<any>;
) as DtAutocompleteValue<any>;
expect(isDtAutocompleteValueEqual(a, b)).toBeTruthy();
expect(isDtAutocompleteValueEqual(b, a)).toBeTruthy();
});
Expand All @@ -1259,15 +1259,15 @@ describe('DtFilterField Util', () => {
`${prefix}${optionSource.name}${DELIMITER}`,
null,
null,
) as _DtAutocompleteValue<any>;
) as DtAutocompleteValue<any>;
const b = dtOptionDef(
optionSource,
null,
optionSource.name,
null,
null,
null,
) as _DtAutocompleteValue<any>;
) as DtAutocompleteValue<any>;
expect(isDtAutocompleteValueEqual(a, b, prefix)).toBeTruthy();
expect(isDtAutocompleteValueEqual(b, a, prefix)).toBeTruthy();
});
Expand All @@ -1281,7 +1281,7 @@ describe('DtFilterField Util', () => {
null,
null,
null,
) as _DtAutocompleteValue<any>;
) as DtAutocompleteValue<any>;
const optionSourceB = { name: 'Option 2' };
const b = dtOptionDef(
optionSourceB,
Expand All @@ -1290,7 +1290,7 @@ describe('DtFilterField Util', () => {
null,
null,
null,
) as _DtAutocompleteValue<any>;
) as DtAutocompleteValue<any>;
expect(isDtAutocompleteValueEqual(a, b)).toBeFalsy();
expect(isDtAutocompleteValueEqual(b, a)).toBeFalsy();
});
Expand All @@ -1303,7 +1303,7 @@ describe('DtFilterField Util', () => {
null,
null,
null,
) as _DtAutocompleteValue<any>;
) as DtAutocompleteValue<any>;
const optionSourceB = { name: 'Option 2' };
const b = dtOptionDef(
optionSourceB,
Expand All @@ -1312,7 +1312,7 @@ describe('DtFilterField Util', () => {
`${optionSourceB.name}${DELIMITER}`,
null,
null,
) as _DtAutocompleteValue<any>;
) as DtAutocompleteValue<any>;
expect(isDtAutocompleteValueEqual(a, b)).toBeFalsy();
expect(isDtAutocompleteValueEqual(b, a)).toBeFalsy();
});
Expand Down
Loading

0 comments on commit e16948a

Please sign in to comment.