diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field.scss b/src/plugins/discover/public/application/components/sidebar/discover_field.scss new file mode 100644 index 00000000000000..8e1dd41f66ab1d --- /dev/null +++ b/src/plugins/discover/public/application/components/sidebar/discover_field.scss @@ -0,0 +1,4 @@ +.dscSidebarItem__fieldPopoverPanel { + min-width: 260px; + max-width: 300px; +} diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx b/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx index e1abbfd7657d06..a0d9e3c541e47e 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx @@ -104,9 +104,4 @@ describe('discover sidebar field', function () { findTestSubject(comp, 'fieldToggle-bytes').simulate('click'); expect(props.onRemoveField).toHaveBeenCalledWith('bytes'); }); - it('should trigger onShowDetails', function () { - const { comp, props } = getComponent(); - findTestSubject(comp, 'field-bytes-showDetails').simulate('click'); - expect(props.onShowDetails).toHaveBeenCalledWith(true, props.field); - }); }); diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field.tsx b/src/plugins/discover/public/application/components/sidebar/discover_field.tsx index 724908281146d4..639dbfe09277cd 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_field.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_field.tsx @@ -16,15 +16,16 @@ * specific language governing permissions and limitations * under the License. */ -import React from 'react'; -import { EuiButton } from '@elastic/eui'; +import React, { useState } from 'react'; +import { EuiPopover, EuiPopoverTitle, EuiButtonIcon, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { DiscoverFieldDetails } from './discover_field_details'; -import { FieldIcon } from '../../../../../kibana_react/public'; +import { FieldIcon, FieldButton } from '../../../../../kibana_react/public'; import { FieldDetails } from './types'; import { IndexPatternField, IndexPattern } from '../../../../../data/public'; import { shortenDottedString } from '../../helpers'; import { getFieldTypeName } from './lib/get_field_type_name'; +import './discover_field.scss'; export interface DiscoverFieldProps { /** @@ -48,14 +49,6 @@ export interface DiscoverFieldProps { * @param fieldName */ onRemoveField: (fieldName: string) => void; - /** - * Callback to hide/show details, buckets of the field - */ - onShowDetails: (show: boolean, field: IndexPatternField) => void; - /** - * Determines, whether details of the field are displayed - */ - showDetails: boolean; /** * Retrieve details data for the field */ @@ -76,22 +69,14 @@ export function DiscoverField({ onAddField, onRemoveField, onAddFilter, - onShowDetails, - showDetails, getDetails, selected, useShortDots, }: DiscoverFieldProps) { - const addLabel = i18n.translate('discover.fieldChooser.discoverField.addButtonLabel', { - defaultMessage: 'Add', - }); const addLabelAria = i18n.translate('discover.fieldChooser.discoverField.addButtonAriaLabel', { defaultMessage: 'Add {field} to table', values: { field: field.name }, }); - const removeLabel = i18n.translate('discover.fieldChooser.discoverField.removeButtonLabel', { - defaultMessage: 'Remove', - }); const removeLabelAria = i18n.translate( 'discover.fieldChooser.discoverField.removeButtonAriaLabel', { @@ -100,6 +85,8 @@ export function DiscoverField({ } ); + const [infoIsOpen, setOpen] = useState(false); + const toggleDisplay = (f: IndexPatternField) => { if (selected) { onRemoveField(f.name); @@ -108,6 +95,10 @@ export function DiscoverField({ } }; + function togglePopover() { + setOpen(!infoIsOpen); + } + function wrapOnDot(str?: string) { // u200B is a non-width white-space character, which allows // the browser to efficiently word-wrap right after the dot @@ -115,64 +106,96 @@ export function DiscoverField({ return str ? str.replace(/\./g, '.\u200B') : ''; } - return ( - <> -
onShowDetails(!showDetails, field)} - onKeyPress={() => onShowDetails(!showDetails, field)} - data-test-subj={`field-${field.name}-showDetails`} + const dscFieldIcon = ( + + ); + + const fieldName = ( + + {useShortDots ? wrapOnDot(shortenDottedString(field.name)) : wrapOnDot(field.displayName)} + + ); + + let actionButton; + if (field.name !== '_source' && !selected) { + actionButton = ( + + ) => { + ev.preventDefault(); + ev.stopPropagation(); + toggleDisplay(field); + }} + data-test-subj={`fieldToggle-${field.name}`} + aria-label={addLabelAria} + /> + + ); + } else if (field.name !== '_source' && selected) { + actionButton = ( + - - - - - {useShortDots ? wrapOnDot(shortenDottedString(field.name)) : wrapOnDot(field.displayName)} - - - {field.name !== '_source' && !selected && ( - ) => { - ev.preventDefault(); - ev.stopPropagation(); - toggleDisplay(field); - }} - data-test-subj={`fieldToggle-${field.name}`} - arial-label={addLabelAria} - > - {addLabel} - - )} - {field.name !== '_source' && selected && ( - ) => { - ev.preventDefault(); - ev.stopPropagation(); - toggleDisplay(field); - }} - data-test-subj={`fieldToggle-${field.name}`} - arial-label={removeLabelAria} - > - {removeLabel} - - )} - -
- {showDetails && ( + ) => { + ev.preventDefault(); + ev.stopPropagation(); + toggleDisplay(field); + }} + data-test-subj={`fieldToggle-${field.name}`} + aria-label={removeLabelAria} + /> + + ); + } + + return ( + { + togglePopover(); + }} + buttonProps={{ 'data-test-subj': `field-${field.name}-showDetails` }} + fieldIcon={dscFieldIcon} + fieldAction={actionButton} + fieldName={fieldName} + /> + } + isOpen={infoIsOpen} + closePopover={() => setOpen(false)} + anchorPosition="rightUp" + panelClassName="dscSidebarItem__fieldPopoverPanel" + > + + {' '} + {i18n.translate('discover.fieldChooser.discoverField.fieldTopValuesLabel', { + defaultMessage: 'Top 5 values', + })} + + {infoIsOpen && ( )} - + ); } diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field_details.scss b/src/plugins/discover/public/application/components/sidebar/discover_field_details.scss new file mode 100644 index 00000000000000..f4b3eed741f9f0 --- /dev/null +++ b/src/plugins/discover/public/application/components/sidebar/discover_field_details.scss @@ -0,0 +1,5 @@ +.dscFieldDetails__visualizeBtn { + @include euiFontSizeXS; + height: $euiSizeL !important; + min-width: $euiSize * 4; +} diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field_details.tsx b/src/plugins/discover/public/application/components/sidebar/discover_field_details.tsx index dd95a45f71626f..875b5a0aa446f7 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_field_details.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_field_details.tsx @@ -17,13 +17,14 @@ * under the License. */ import React from 'react'; -import { EuiLink, EuiIconTip, EuiText } from '@elastic/eui'; +import { EuiLink, EuiIconTip, EuiText, EuiPopoverFooter, EuiButton, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { DiscoverFieldBucket } from './discover_field_bucket'; import { getWarnings } from './lib/get_warnings'; import { Bucket, FieldDetails } from './types'; import { getServices } from '../../../kibana_services'; import { IndexPatternField, IndexPattern } from '../../../../../data/public'; +import './discover_field_details.scss'; interface DiscoverFieldDetailsProps { field: IndexPatternField; @@ -41,62 +42,68 @@ export function DiscoverFieldDetails({ const warnings = getWarnings(field); return ( -
- {!details.error && ( - - {' '} - {!indexPattern.metaFields.includes(field.name) && !field.scripted ? ( - onAddFilter('_exists_', field.name, '+')}> - {details.exists} - - ) : ( - {details.exists} - )}{' '} - / {details.total}{' '} - - - )} - {details.error && {details.error}} - {!details.error && ( -
- {details.buckets.map((bucket: Bucket, idx: number) => ( - - ))} -
- )} + <> +
+ {details.error && {details.error}} + {!details.error && ( +
+ {details.buckets.map((bucket: Bucket, idx: number) => ( + + ))} +
+ )} - {details.visualizeUrl && ( - <> - { - getServices().core.application.navigateToApp(details.visualizeUrl.app, { - path: details.visualizeUrl.path, - }); - }} - className="kuiButton kuiButton--secondary kuiButton--small kuiVerticalRhythmSmall" - data-test-subj={`fieldVisualize-${field.name}`} - > - + {details.visualizeUrl && ( + <> + + { + getServices().core.application.navigateToApp(details.visualizeUrl.app, { + path: details.visualizeUrl.path, + }); + }} + size="s" + className="dscFieldDetails__visualizeBtn" + data-test-subj={`fieldVisualize-${field.name}`} + > + + {warnings.length > 0 && ( )} - - + + )} +
+ {!details.error && ( + + + {!indexPattern.metaFields.includes(field.name) && !field.scripted ? ( + onAddFilter('_exists_', field.name, '+')}> + {' '} + {details.exists} + + ) : ( + {details.exists} + )}{' '} + / {details.total}{' '} + + + )} -
+ ); } diff --git a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.scss b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.scss index 07efd64752c84c..f130b0399f467d 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.scss +++ b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.scss @@ -42,54 +42,15 @@ } .dscSidebarItem { - border-top: 1px solid transparent; - position: relative; - display: flex; - align-items: center; - justify-content: space-between; - cursor: pointer; - font-size: $euiFontSizeXS; - border-top: solid 1px transparent; - border-bottom: solid 1px transparent; - line-height: normal; - margin-bottom: $euiSizeXS * 0.5; - &:hover, - &:focus { + &:focus-within, + &[class*='-isActive'] { .dscSidebarItem__action { opacity: 1; } } } -.dscSidebarItem--active { - border-top: 1px solid $euiColorLightShade; - color: $euiColorFullShade; -} - -.dscSidebarField { - padding: $euiSizeXS; - display: flex; - align-items: center; - max-width: 100%; - width: 100%; - border: none; - border-radius: $euiBorderRadius - 1px; - text-align: left; -} - -.dscSidebarField__name { - margin-left: $euiSizeS; - flex-grow: 1; - word-break: break-word; - padding-right: 1px; -} - -.dscSidebarField__fieldIcon { - margin-top: $euiSizeXS / 2; - margin-right: $euiSizeXS / 2; -} - /** * 1. Only visually hide the action, so that it's still accessible to screen readers. * 2. When tabbed to, this element needs to be visible for keyboard accessibility. @@ -101,7 +62,7 @@ &:focus { opacity: 1; /* 2 */ } - font-size: 12px; + font-size: $euiFontSizeXS; padding: 2px 6px !important; height: 22px !important; min-width: auto !important; @@ -130,8 +91,6 @@ } .dscFieldDetails { - padding: $euiSizeS; - background-color: $euiColorLightestShade; color: $euiTextColor; margin-bottom: $euiSizeS; } diff --git a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx index 58b468762c5011..450bb93f60bf36 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx @@ -92,7 +92,6 @@ export function DiscoverSidebar({ setIndexPattern, state, }: DiscoverSidebarProps) { - const [openFieldMap, setOpenFieldMap] = useState(new Map()); const [showFields, setShowFields] = useState(false); const [fields, setFields] = useState(null); const [fieldFilterState, setFieldFilterState] = useState(getDefaultFieldFilter()); @@ -103,19 +102,6 @@ export function DiscoverSidebar({ setFields(newFields); }, [selectedIndexPattern, fieldCounts, hits, services]); - const onShowDetails = useCallback( - (show: boolean, field: IndexPatternField) => { - if (!show) { - setOpenFieldMap(new Map(openFieldMap.set(field.name, false))); - } else { - setOpenFieldMap(new Map(openFieldMap.set(field.name, true))); - if (services.capabilities.discover.save) { - selectedIndexPattern.popularizeField(field.name, 1); - } - } - }, - [openFieldMap, selectedIndexPattern, services.capabilities.discover.save] - ); const onChangeFieldSearch = useCallback( (field: string, value: string | boolean | undefined) => { const newState = setFieldFilterProp(fieldFilterState, field, value); @@ -213,9 +199,7 @@ export function DiscoverSidebar({ onAddField={onAddField} onRemoveField={onRemoveField} onAddFilter={onAddFilter} - onShowDetails={onShowDetails} getDetails={getDetailsByField} - showDetails={openFieldMap.get(field.name) || false} selected={true} useShortDots={useShortDots} /> @@ -290,9 +274,7 @@ export function DiscoverSidebar({ onAddField={onAddField} onRemoveField={onRemoveField} onAddFilter={onAddFilter} - onShowDetails={onShowDetails} getDetails={getDetailsByField} - showDetails={openFieldMap.get(field.name) || false} useShortDots={useShortDots} /> @@ -318,9 +300,7 @@ export function DiscoverSidebar({ onAddField={onAddField} onRemoveField={onRemoveField} onAddFilter={onAddFilter} - onShowDetails={onShowDetails} getDetails={getDetailsByField} - showDetails={openFieldMap.get(field.name) || false} useShortDots={useShortDots} /> diff --git a/src/plugins/kibana_react/public/field_button/__snapshots__/field_button.test.tsx.snap b/src/plugins/kibana_react/public/field_button/__snapshots__/field_button.test.tsx.snap new file mode 100644 index 00000000000000..e65b5fcb8fbbd9 --- /dev/null +++ b/src/plugins/kibana_react/public/field_button/__snapshots__/field_button.test.tsx.snap @@ -0,0 +1,134 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`fieldAction is rendered 1`] = ` +
+ +
+ + fieldAction + +
+
+`; + +exports[`fieldIcon is rendered 1`] = ` +
+ +
+`; + +exports[`isActive defaults to false 1`] = ` +
+ +
+`; + +exports[`isActive renders true 1`] = ` +
+ +
+`; + +exports[`isDraggable is rendered 1`] = ` +
+ +
+`; + +exports[`sizes m is applied 1`] = ` +
+ +
+`; + +exports[`sizes s is applied 1`] = ` +
+ +
+`; diff --git a/src/plugins/kibana_react/public/field_button/field_button.scss b/src/plugins/kibana_react/public/field_button/field_button.scss new file mode 100644 index 00000000000000..43f60e4503576c --- /dev/null +++ b/src/plugins/kibana_react/public/field_button/field_button.scss @@ -0,0 +1,75 @@ +.kbnFieldButton { + @include euiFontSizeS; + border-radius: $euiBorderRadius; + margin-bottom: $euiSizeXS; + display: flex; + align-items: center; + transition: box-shadow $euiAnimSpeedFast $euiAnimSlightResistance, + background-color $euiAnimSpeedFast $euiAnimSlightResistance; // sass-lint:disable-line indentation + + &:focus-within, + &-isActive { + @include euiFocusRing; + } +} + +.kbnFieldButton--isDraggable { + background: lightOrDarkTheme($euiColorEmptyShade, $euiColorLightestShade); + + &:hover, + &:focus, + &:focus-within { + @include euiBottomShadowMedium; + border-radius: $euiBorderRadius; + z-index: 2; + } + + .kbnFieldButton__button { + &:hover, + &:focus { + cursor: grab; + } + } +} + +.kbnFieldButton__button { + flex-grow: 1; + text-align: left; + padding: $euiSizeS; + display: flex; + align-items: flex-start; +} + +.kbnFieldButton__fieldIcon { + flex-shrink: 0; + line-height: 0; + margin-right: $euiSizeS; +} + +.kbnFieldButton__name { + flex-grow: 1; + word-break: break-word; +} + +.kbnFieldButton__infoIcon { + flex-shrink: 0; + margin-left: $euiSizeXS; +} + +.kbnFieldButton__fieldAction { + margin-right: $euiSizeS; +} + +// Reduce text size and spacing for the small size +.kbnFieldButton--small { + font-size: $euiFontSizeXS; + + .kbnFieldButton__button { + padding: $euiSizeXS; + } + + .kbnFieldButton__fieldIcon, + .kbnFieldButton__fieldAction { + margin-right: $euiSizeXS; + } +} diff --git a/src/plugins/kibana_react/public/field_button/field_button.test.tsx b/src/plugins/kibana_react/public/field_button/field_button.test.tsx new file mode 100644 index 00000000000000..32e1203b897184 --- /dev/null +++ b/src/plugins/kibana_react/public/field_button/field_button.test.tsx @@ -0,0 +1,68 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 React from 'react'; +import { shallow } from 'enzyme'; +import { FieldButton, SIZES } from './field_button'; + +const noop = () => {}; + +describe('sizes', () => { + SIZES.forEach((size) => { + test(`${size} is applied`, () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + }); + }); +}); + +describe('isDraggable', () => { + it('is rendered', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + }); +}); + +describe('fieldIcon', () => { + it('is rendered', () => { + const component = shallow( + fieldIcon} /> + ); + expect(component).toMatchSnapshot(); + }); +}); + +describe('fieldAction', () => { + it('is rendered', () => { + const component = shallow( + fieldAction} /> + ); + expect(component).toMatchSnapshot(); + }); +}); + +describe('isActive', () => { + it('defaults to false', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + }); + it('renders true', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/kibana_react/public/field_button/field_button.tsx b/src/plugins/kibana_react/public/field_button/field_button.tsx new file mode 100644 index 00000000000000..e5833b261946ae --- /dev/null +++ b/src/plugins/kibana_react/public/field_button/field_button.tsx @@ -0,0 +1,111 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 './field_button.scss'; +import classNames from 'classnames'; +import React, { ReactNode, HTMLAttributes, ButtonHTMLAttributes } from 'react'; +import { CommonProps } from '@elastic/eui'; + +export interface FieldButtonProps extends HTMLAttributes { + /** + * Label for the button + */ + fieldName: ReactNode; + /** + * Icon representing the field type. + * Recommend using FieldIcon + */ + fieldIcon?: ReactNode; + /** + * An optional node to place inside and at the end of the + {fieldAction &&
{fieldAction}
} + + ); +} diff --git a/src/plugins/kibana_react/public/field_button/index.ts b/src/plugins/kibana_react/public/field_button/index.ts new file mode 100644 index 00000000000000..4819a7623a163d --- /dev/null +++ b/src/plugins/kibana_react/public/field_button/index.ts @@ -0,0 +1,19 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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. + */ +export * from './field_button'; diff --git a/src/plugins/kibana_react/public/index.ts b/src/plugins/kibana_react/public/index.ts index 7f8bf6c04cecc2..34140703fd8aee 100644 --- a/src/plugins/kibana_react/public/index.ts +++ b/src/plugins/kibana_react/public/index.ts @@ -23,6 +23,7 @@ export * from './context'; export * from './overlays'; export * from './ui_settings'; export * from './field_icon'; +export * from './field_button'; export * from './table_list_view'; export * from './split_panel'; export * from './react_router_navigate'; diff --git a/test/functional/apps/context/_context_navigation.js b/test/functional/apps/context/_context_navigation.js index babefe488d7bcf..c5af2fcb792961 100644 --- a/test/functional/apps/context/_context_navigation.js +++ b/test/functional/apps/context/_context_navigation.js @@ -18,11 +18,11 @@ */ const TEST_FILTER_COLUMN_NAMES = [ - ['extension', 'jpg'], [ 'agent', 'Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24', ], + ['extension', 'jpg'], ]; export default function ({ getService, getPageObjects }) { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/_field_item.scss b/x-pack/plugins/lens/public/indexpattern_datasource/_field_item.scss index 6e51c45ad02c11..d194c694abdf8a 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/_field_item.scss +++ b/x-pack/plugins/lens/public/indexpattern_datasource/_field_item.scss @@ -1,47 +1,11 @@ -.lnsFieldItem { - @include euiFontSizeS; - background: lightOrDarkTheme($euiColorEmptyShade, $euiColorLightestShade); - border-radius: $euiBorderRadius; - margin-bottom: $euiSizeXS; -} - -.lnsFieldItem__popoverAnchor:hover, -.lnsFieldItem__popoverAnchor:focus, -.lnsFieldItem__popoverAnchor:focus-within { - @include euiBottomShadowMedium; - border-radius: $euiBorderRadius; - z-index: 2; -} - .lnsFieldItem--missing { - background: lightOrDarkTheme(transparentize($euiColorMediumShade, .9), $euiColorEmptyShade); - color: $euiColorDarkShade; + .lnsFieldItem__info { + background: lightOrDarkTheme(transparentize($euiColorMediumShade, .9), $euiColorEmptyShade); + color: $euiColorDarkShade; + } } .lnsFieldItem__info { - border-radius: $euiBorderRadius - 1px; - padding: $euiSizeS; - display: flex; - align-items: flex-start; - transition: box-shadow $euiAnimSpeedFast $euiAnimSlightResistance, - background-color $euiAnimSpeedFast $euiAnimSlightResistance; // sass-lint:disable-line indentation - - .lnsFieldItem__name { - margin-left: $euiSizeS; - flex-grow: 1; - word-break: break-word; - } - - .lnsFieldListPanel__fieldIcon, - .lnsFieldItem__infoIcon { - flex-shrink: 0; - } - - .lnsFieldListPanel__fieldIcon { - margin-top: $euiSizeXS / 2; - margin-right: $euiSizeXS / 2; - } - .lnsFieldItem__infoIcon { visibility: hidden; } @@ -56,10 +20,6 @@ } } -.lnsFieldItem__info-isOpen { - @include euiFocusRing; -} - .lnsFieldItem__topValue { margin-bottom: $euiSizeS; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx index 0a3af97f8ad754..08a2f85ec70538 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx @@ -5,6 +5,7 @@ */ import React from 'react'; +import { ReactWrapper } from 'enzyme'; import { act } from 'react-dom/test-utils'; import { EuiLoadingSpinner, EuiPopover } from '@elastic/eui'; import { InnerFieldItem, FieldItemProps } from './field_item'; @@ -17,6 +18,10 @@ import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks' const chartsThemeService = chartPluginMock.createSetupContract().theme; +function clickField(wrapper: ReactWrapper, field: string) { + wrapper.find(`[data-test-subj="lnsFieldListPanelField-${field}"] button`).simulate('click'); +} + describe('IndexPattern Field Item', () => { let defaultProps: FieldItemProps; let indexPattern: IndexPattern; @@ -101,7 +106,7 @@ describe('IndexPattern Field Item', () => { const wrapper = mountWithIntl(); await act(async () => { - wrapper.find('[data-test-subj="lnsFieldListPanelField-bytes"]').simulate('click'); + clickField(wrapper, 'bytes'); }); expect(core.http.post).toHaveBeenCalledWith( @@ -125,7 +130,7 @@ describe('IndexPattern Field Item', () => { const wrapper = mountWithIntl(); - wrapper.find('[data-test-subj="lnsFieldListPanelField-bytes"]').simulate('click'); + clickField(wrapper, 'bytes'); expect(core.http.post).toHaveBeenCalledWith( `/api/lens/index_stats/my-fake-index-pattern/field`, @@ -174,7 +179,7 @@ describe('IndexPattern Field Item', () => { expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(0); - wrapper.find('[data-test-subj="lnsFieldListPanelField-bytes"]').simulate('click'); + clickField(wrapper, 'bytes'); expect(core.http.post).toHaveBeenCalledTimes(1); act(() => { @@ -200,7 +205,7 @@ describe('IndexPattern Field Item', () => { }); }); - wrapper.find('[data-test-subj="lnsFieldListPanelField-bytes"]').simulate('click'); + clickField(wrapper, 'bytes'); expect(core.http.post).toHaveBeenCalledTimes(2); expect(core.http.post).toHaveBeenLastCalledWith( diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx index fabf9e9e9bfff2..5dc6673bc29ecd 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx @@ -11,7 +11,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiIconTip, - EuiKeyboardAccessible, EuiLoadingSpinner, EuiPopover, EuiPopoverFooter, @@ -40,6 +39,7 @@ import { esQuery, IIndexPattern, } from '../../../../../src/plugins/data/public'; +import { FieldButton } from '../../../../../src/plugins/kibana_react/public'; import { ChartsPluginSetup } from '../../../../../src/plugins/charts/public'; import { DraggedField } from './indexpattern'; import { DragDrop } from '../drag_drop'; @@ -177,8 +177,27 @@ export const InnerFieldItem = function InnerFieldItem(props: FieldItemProps) { field, indexPattern.id, ]); + const lensFieldIcon = ; + const lensInfoIcon = ( + + ); return ( - -
{ - if (exists) { - togglePopover(); - } - }} - onKeyPress={(event) => { - if (exists && event.key === 'ENTER') { - togglePopover(); - } - }} - aria-label={i18n.translate('xpack.lens.indexPattern.fieldStatsButtonLabel', { - defaultMessage: 'Click for a field preview, or drag and drop to visualize.', - })} - > - - - - {wrappableHighlightableFieldName} - - - -
-
+ { + if (exists) { + togglePopover(); + } + }} + aria-label={i18n.translate('xpack.lens.indexPattern.fieldStatsButtonAriaLabel', { + defaultMessage: '{fieldName}: {fieldType}. Hit enter for a field preview.', + values: { + fieldName: field.name, + fieldType: field.type, + }, + })} + fieldIcon={lensFieldIcon} + fieldName={wrappableHighlightableFieldName} + fieldInfoIcon={lensInfoIcon} + /> } isOpen={infoIsOpen} diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 8c92e7359b2f7d..d2e8fe7d743bfa 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -1407,12 +1407,9 @@ "discover.fieldChooser.detailViews.filterOutValueButtonAriaLabel": "{field}を除外:\"{value}\"", "discover.fieldChooser.detailViews.filterValueButtonAriaLabel": "{field}を除外:\"{value}\"", "discover.fieldChooser.detailViews.recordsText": "記録", - "discover.fieldChooser.detailViews.topValuesInRecordsDescription": "次の記録のトップ5の値", "discover.fieldChooser.detailViews.visualizeLinkText": "可視化", "discover.fieldChooser.discoverField.addButtonAriaLabel": "{field}を表に追加", - "discover.fieldChooser.discoverField.addButtonLabel": "追加", "discover.fieldChooser.discoverField.removeButtonAriaLabel": "{field}を表から削除", - "discover.fieldChooser.discoverField.removeButtonLabel": "削除", "discover.fieldChooser.discoverField.scriptedFieldsTakeLongExecuteDescription": "スクリプトフィールドは実行に時間がかかる場合があります。", "discover.fieldChooser.fieldCalculator.analysisIsNotAvailableForGeoFieldsErrorMessage": "ジオフィールドは分析できません。", "discover.fieldChooser.fieldCalculator.analysisIsNotAvailableForObjectFieldsErrorMessage": "オブジェクトフィールドは分析できません。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 5ab70ff7a9d04d..6a211884069d6a 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -1408,12 +1408,9 @@ "discover.fieldChooser.detailViews.filterOutValueButtonAriaLabel": "筛除 {field}:“{value}”", "discover.fieldChooser.detailViews.filterValueButtonAriaLabel": "筛留 {field}:“{value}”", "discover.fieldChooser.detailViews.recordsText": "个记录", - "discover.fieldChooser.detailViews.topValuesInRecordsDescription": "排名前 5 值 - 范围", "discover.fieldChooser.detailViews.visualizeLinkText": "可视化", "discover.fieldChooser.discoverField.addButtonAriaLabel": "将 {field} 添加到表中", - "discover.fieldChooser.discoverField.addButtonLabel": "添加", "discover.fieldChooser.discoverField.removeButtonAriaLabel": "从表中移除 {field}", - "discover.fieldChooser.discoverField.removeButtonLabel": "移除", "discover.fieldChooser.discoverField.scriptedFieldsTakeLongExecuteDescription": "脚本字段执行时间会很长。", "discover.fieldChooser.fieldCalculator.analysisIsNotAvailableForGeoFieldsErrorMessage": "分析不适用于地理字段。", "discover.fieldChooser.fieldCalculator.analysisIsNotAvailableForObjectFieldsErrorMessage": "分析不适用于对象字段。",