Skip to content

Commit

Permalink
[Unified search] Support fields custom label on filter editor (#130533)
Browse files Browse the repository at this point in the history
* [Unified search] Support fields custom label

* Use the custom label in filter badges and popover

* Unit tests

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
stratoula and kibanamachine committed May 3, 2022
1 parent 4d99fff commit 82f440b
Show file tree
Hide file tree
Showing 12 changed files with 100 additions and 12 deletions.
1 change: 1 addition & 0 deletions src/plugins/data/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export * from './deprecated';
export { getEsQueryConfig, FilterStateStore } from '../common';
export {
getDisplayValueFromFilter,
getFieldDisplayValueFromFilter,
generateFilters,
extractTimeRange,
getIndexPatternFromFilter,
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/data/public/query/filter_manager/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ export { FilterManager } from './filter_manager';

export { mapAndFlattenFilters } from './lib/map_and_flatten_filters';
export { generateFilters } from './lib/generate_filters';
export { getDisplayValueFromFilter } from './lib/get_display_value';
export { getDisplayValueFromFilter, getFieldDisplayValueFromFilter } from './lib/get_display_value';
export { getIndexPatternFromFilter } from './lib/get_index_pattern_from_filter';
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import type { DataView } from '@kbn/data-views-plugin/public';
import { FilterStateStore, PhraseFilter } from '@kbn/es-query';
import { stubIndexPattern, phraseFilter } from '../../../../common/stubs';
import { getDisplayValueFromFilter } from './get_display_value';
import { getDisplayValueFromFilter, getFieldDisplayValueFromFilter } from './get_display_value';
import { FieldFormat } from '@kbn/field-formats-plugin/common';

describe('getDisplayValueFromFilter', () => {
Expand Down Expand Up @@ -50,3 +51,43 @@ describe('getDisplayValueFromFilter', () => {
expect(displayValue).toBe('bananaabc');
});
});

describe('getFieldDisplayValueFromFilter', () => {
beforeEach(() => {
jest.resetAllMocks();
});

it('returns empty string if the index pattern is not found', () => {
const wrongIndexPattern = {
title: 'wrong index pattern',
id: 'wrong index pattern',
} as DataView;
const fieldLabel = getFieldDisplayValueFromFilter(phraseFilter, [wrongIndexPattern]);
expect(fieldLabel).toBe('');
});

it('returns empty string if custom label is not set', () => {
const filter: PhraseFilter = {
meta: {
negate: false,
index: 'logstash-*',
type: 'phrase',
key: 'bytes',
value: '1024',
disabled: false,
alias: null,
},
$state: {
store: FilterStateStore.APP_STATE,
},
query: {},
};
const fieldLabel = getFieldDisplayValueFromFilter(filter, [stubIndexPattern]);
expect(fieldLabel).toBe('');
});

it('returns the field custom label if it set', () => {
const fieldLabel = getFieldDisplayValueFromFilter(phraseFilter, [stubIndexPattern]);
expect(fieldLabel).toBe('OS');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ function getValueFormatter(indexPattern?: DataView, key?: string) {
return indexPattern.getFormatterForField(field);
}

export function getFieldDisplayValueFromFilter(filter: Filter, indexPatterns: DataView[]): string {
const { key } = filter.meta;
const indexPattern = getIndexPatternFromFilter(filter, indexPatterns);
if (!indexPattern) return '';
const field = indexPattern.fields.find((f: DataViewField) => f.name === key);
return field?.customLabel ?? '';
}

export function getDisplayValueFromFilter(filter: Filter, indexPatterns: DataView[]): string {
const { key, value } = filter.meta;
if (typeof value === 'function') {
Expand Down
1 change: 1 addition & 0 deletions src/plugins/data_views/common/field.stub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const createIndexPatternFieldStub = ({ spec }: { spec: FieldSpec }): Data
export const stubFieldSpecMap: Record<string, FieldSpec> = {
'machine.os': {
name: 'machine.os',
customLabel: 'OS',
esTypes: ['text'],
type: 'string',
aggregatable: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ import {
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import React, { Component } from 'react';
import { getDisplayValueFromFilter, mapAndFlattenFilters } from '@kbn/data-plugin/public';
import {
getDisplayValueFromFilter,
mapAndFlattenFilters,
getFieldDisplayValueFromFilter,
} from '@kbn/data-plugin/public';
import { Filter } from '@kbn/data-plugin/common';
import { DataView } from '@kbn/data-views-plugin/public';
import { FilterLabel } from '../filter_bar';
Expand All @@ -33,6 +37,7 @@ interface Props {

interface State {
isFilterSelected: boolean[];
fieldLabel?: string;
}

// Needed for React.lazy
Expand All @@ -46,12 +51,15 @@ export default class ApplyFiltersPopoverContent extends Component<Props, State>
super(props);
this.state = {
isFilterSelected: props.filters.map(() => true),
fieldLabel: undefined,
};
}
private getLabel(filter: Filter) {

private getLabel = (filter: Filter) => {
const valueLabel = getDisplayValueFromFilter(filter, this.props.indexPatterns);
return <FilterLabel filter={filter} valueLabel={valueLabel} />;
}
const fieldLabel = getFieldDisplayValueFromFilter(filter, this.props.indexPatterns);
return <FilterLabel filter={filter} valueLabel={valueLabel} fieldLabel={fieldLabel} />;
};

public render() {
if (this.props.filters.length === 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ class FilterEditorUI extends Component<Props, State> {
})}
options={fields}
selectedOptions={selectedField ? [selectedField] : []}
getLabel={(field) => field.name}
getLabel={(field) => field.customLabel || field.name}
onChange={this.onFieldChange}
singleSelection={{ asPlainText: true }}
isClearable={false}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ test('alias', () => {
expect(container).toMatchSnapshot();
});

test('field custom label', () => {
const filter = {
...phraseFilter,
meta: {
...phraseFilter.meta,
alias: 'geo.coordinates in US',
},
};
const { container } = render(<FilterLabel filter={filter} fieldLabel="test label" />);
expect(container).toMatchSnapshot();
});

test('alias with warning status', () => {
const filter = {
...phraseFilter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type { FilterLabelStatus } from '../../filter_item';
export interface FilterLabelProps {
filter: Filter;
valueLabel?: string;
fieldLabel?: string;
filterLabelStatus?: FilterLabelStatus;
hideAlias?: boolean;
}
Expand All @@ -25,6 +26,7 @@ export interface FilterLabelProps {
export default function FilterLabel({
filter,
valueLabel,
fieldLabel,
filterLabelStatus,
hideAlias,
}: FilterLabelProps) {
Expand Down Expand Up @@ -59,14 +61,14 @@ export default function FilterLabel({
return (
<Fragment>
{prefix}
{filter.meta.key}: {getValue(`${existsOperator.message}`)}
{fieldLabel || filter.meta.key}: {getValue(`${existsOperator.message}`)}
</Fragment>
);
case FILTERS.PHRASES:
return (
<Fragment>
{prefix}
{filter.meta.key}: {getValue(`${isOneOfOperator.message} ${valueLabel}`)}
{fieldLabel || filter.meta.key}: {getValue(`${isOneOfOperator.message} ${valueLabel}`)}
</Fragment>
);
case FILTERS.QUERY_STRING:
Expand All @@ -81,7 +83,7 @@ export default function FilterLabel({
return (
<Fragment>
{prefix}
{filter.meta.key}: {getValue(valueLabel)}
{fieldLabel || filter.meta.key}: {getValue(valueLabel)}
</Fragment>
);
default:
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/unified_search/public/filter_bar/filter_item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ import classNames from 'classnames';
import React, { MouseEvent, useState, useEffect, HTMLAttributes } from 'react';
import { IUiSettingsClient } from '@kbn/core/public';
import { DataView } from '@kbn/data-views-plugin/public';
import { getIndexPatternFromFilter, getDisplayValueFromFilter } from '@kbn/data-plugin/public';
import {
getIndexPatternFromFilter,
getDisplayValueFromFilter,
getFieldDisplayValueFromFilter,
} from '@kbn/data-plugin/public';
import { FilterEditor } from './filter_editor';
import { FilterView } from './filter_view';
import { getIndexPatterns } from '../services';
Expand Down Expand Up @@ -355,6 +359,7 @@ export function FilterItem(props: FilterItemProps) {
const filterViewProps = {
filter,
valueLabel: valueLabelConfig.title,
fieldLabel: getFieldDisplayValueFromFilter(filter, indexPatterns),
filterLabelStatus: valueLabelConfig.status,
errorMessage: valueLabelConfig.message,
className: getClasses(!!filter.meta.negate, valueLabelConfig),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type { FilterLabelStatus } from '../filter_item';
interface Props {
filter: Filter;
valueLabel: string;
fieldLabel?: string;
filterLabelStatus: FilterLabelStatus;
errorMessage?: string;
readonly?: boolean;
Expand All @@ -28,6 +29,7 @@ export const FilterView: FC<Props> = ({
iconOnClick,
onClick,
valueLabel,
fieldLabel,
errorMessage,
filterLabelStatus,
readonly,
Expand Down Expand Up @@ -100,6 +102,7 @@ export const FilterView: FC<Props> = ({
<FilterLabel
filter={filter}
valueLabel={valueLabel}
fieldLabel={fieldLabel}
filterLabelStatus={filterLabelStatus}
hideAlias={hideAlias}
/>
Expand Down

0 comments on commit 82f440b

Please sign in to comment.