mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
## Summary This PR adds support for an is one of operator allowing users to filter multiple values for one field. [Some investigation ](https://discuss.elastic.co/t/passing-multiple-values-in-kibana-add-filter-is-one-of/232694/2)by @andrew-goldstein revealed that since the underlying engine uses Lucene, we can add support for multiple values by using an OR query: `kibana.alert.workflow_status: ("open" OR "closed" OR "acknowledged")` is equivalent to ``` "terms": { "kibana.alert.workflow_status": [ "open", "closed", "acknowledged"] } ``` Where the former is usable in our `DataProviders` used by timeline and other components that navigate a user to a pre-populated timeline. As an enhancement to the timeline view, users can also use this `is one of` operator by interacting with the `Add field` button and selecting the new operator. <img width="433" alt="image" src="https://user-images.githubusercontent.com/28942857/193487154-769005b6-3e5a-40bf-9476-8dd3f3bcb8ee.png"> ### Checklist Delete any items that are not applicable to this PR. - [X] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [X] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ## Known issues This operator does not support timeline templates at this time so usage there disables the ability for conversion to template field but a better approach should be implemented to notify users. https://github.com/elastic/kibana/issues/142437. For now I have added a template message and prevented users from creating templates with this operator: <img width="374" alt="image" src="https://user-images.githubusercontent.com/28942857/201157676-80017c6c-9f5b-4cd7-ba0b-ee2e43a884cb.png"> ## Testing Create a new timeline or visit an existing one. Click 'Add field' button on Timeline in OR query section add any field ( preferably one that can have many values- consider `kibana.alerts.workflow_status` but this requires alerts. Select the `is one of` or `is not one of operator` Add or remove values in the value section. Click save. Co-authored-by: Kristof-Pierre Cummings <kristofpierre.cummings@elastic.co> Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
114 lines
2.8 KiB
TypeScript
114 lines
2.8 KiB
TypeScript
/*
|
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
* or more contributor license agreements. Licensed under the Elastic License
|
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
|
* 2.0.
|
|
*/
|
|
|
|
import { EuiButtonIcon } from '@elastic/eui';
|
|
import { getOr } from 'lodash/fp';
|
|
import React, { useCallback, useState } from 'react';
|
|
import styled, { css } from 'styled-components';
|
|
|
|
import { ModalInspectQuery } from './modal';
|
|
import * as i18n from './translations';
|
|
import { InspectQuery } from '../../store/t_grid/inputs';
|
|
|
|
export const BUTTON_CLASS = 'inspectButtonComponent';
|
|
|
|
export const InspectButtonContainer = styled.div<{ show?: boolean }>`
|
|
width: 100%;
|
|
display: flex;
|
|
flex-grow: 1;
|
|
|
|
> * {
|
|
max-width: 100%;
|
|
}
|
|
|
|
.${BUTTON_CLASS} {
|
|
pointer-events: none;
|
|
opacity: 0;
|
|
transition: opacity ${(props) => getOr(250, 'theme.eui.euiAnimSpeedNormal', props)} ease;
|
|
}
|
|
|
|
${({ show }) =>
|
|
show &&
|
|
css`
|
|
&:hover .${BUTTON_CLASS} {
|
|
pointer-events: auto;
|
|
opacity: 1;
|
|
}
|
|
`}
|
|
`;
|
|
|
|
InspectButtonContainer.displayName = 'InspectButtonContainer';
|
|
|
|
InspectButtonContainer.defaultProps = {
|
|
show: true,
|
|
};
|
|
|
|
interface OwnProps {
|
|
inspect: InspectQuery | null;
|
|
isDisabled?: boolean;
|
|
loading: boolean;
|
|
onCloseInspect?: () => void;
|
|
title: string | React.ReactElement | React.ReactNode;
|
|
}
|
|
|
|
export type InspectButtonProps = OwnProps;
|
|
|
|
const InspectButtonComponent: React.FC<InspectButtonProps> = ({
|
|
inspect,
|
|
isDisabled,
|
|
loading,
|
|
onCloseInspect,
|
|
title = '',
|
|
}) => {
|
|
const [isInspected, setIsInspected] = useState(false);
|
|
const isShowingModal = !loading && isInspected;
|
|
const handleClick = useCallback(() => {
|
|
setIsInspected(true);
|
|
}, []);
|
|
|
|
const handleCloseModal = useCallback(() => {
|
|
if (onCloseInspect != null) {
|
|
onCloseInspect();
|
|
}
|
|
setIsInspected(false);
|
|
}, [onCloseInspect, setIsInspected]);
|
|
|
|
let request: string | null = null;
|
|
if (inspect != null && inspect.dsl.length > 0) {
|
|
request = inspect.dsl[0];
|
|
}
|
|
|
|
let response: string | null = null;
|
|
if (inspect != null && inspect.response.length > 0) {
|
|
response = inspect.response[0];
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<EuiButtonIcon
|
|
className={BUTTON_CLASS}
|
|
aria-label={i18n.INSPECT}
|
|
data-test-subj="inspect-icon-button"
|
|
iconSize="m"
|
|
iconType="inspect"
|
|
isDisabled={loading || isDisabled}
|
|
title={i18n.INSPECT}
|
|
onClick={handleClick}
|
|
/>
|
|
<ModalInspectQuery
|
|
closeModal={handleCloseModal}
|
|
isShowing={isShowingModal}
|
|
request={request}
|
|
response={response}
|
|
title={title}
|
|
data-test-subj="inspect-modal"
|
|
/>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export const InspectButton = React.memo(InspectButtonComponent);
|