[Lens] fix displaying position options for ref lines (#128778)

* [Lens] fix displaying position options for ref lines

* fix types

* move annotation config panel

* annotations functional tests

* fix dark theme style

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Marta Bondyra 2022-03-30 16:46:02 +02:00 committed by GitHub
parent 09218a8fed
commit 47c861bbad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 198 additions and 82 deletions

View file

@ -76,7 +76,11 @@ export function MarkerBody({
}
if (isHorizontal) {
return (
<div className="eui-textTruncate" style={{ maxWidth: LINES_MARKER_SIZE * 3 }}>
<div
className="eui-textTruncate"
style={{ maxWidth: LINES_MARKER_SIZE * 3 }}
data-test-subj="xyVisAnnotationText"
>
{label}
</div>
);
@ -84,6 +88,7 @@ export function MarkerBody({
return (
<div
className="xyDecorationRotatedWrapper"
data-test-subj="xyVisAnnotationText"
style={{
width: LINES_MARKER_SIZE,
}}
@ -105,6 +110,7 @@ function NumberIcon({ number }: { number: number }) {
<EuiFlexGroup
justifyContent="spaceAround"
className="xyAnnotationNumberIcon"
data-test-subj="xyVisGroupedAnnotationIcon"
gutterSize="none"
alignItems="center"
>
@ -139,6 +145,7 @@ export const AnnotationIcon = ({
return (
<EuiIcon
{...rest}
data-test-subj="xyVisAnnotationIcon"
type={iconConfig.icon || type}
className={classnames(
{ [rotateClassName]: iconConfig.shouldRotate },

View file

@ -43,7 +43,7 @@
}
.lensAnnotationIconFill {
fill: $euiColorGhost;
fill: $euiColorEmptyShade;
}
// Less-than-ideal styles to add a vertical divider after this button. Consider restructuring markup for better semantics and styling options in the future.

View file

@ -21,4 +21,8 @@
left: -$euiSize;
border-top: 1px solid $euiColorLightShade;
}
}
}
.lnsDimensionEditorSection__heading {
padding-bottom: 16px;
}

View file

@ -19,7 +19,7 @@ export const DimensionEditorSection = ({
<div className="lnsDimensionEditorSection">
<div className="lnsDimensionEditorSection__border" />
{title && (
<EuiTitle size="xxs" className="lnsXyConfigHeading">
<EuiTitle size="xxs" className="lnsDimensionEditorSection__heading">
<h3>{title}</h3>
</EuiTitle>
)}

View file

@ -1,3 +0,0 @@
.lnsXyConfigHeading {
padding-bottom: 16px;
}

View file

@ -21,11 +21,14 @@ import {
import { LensIconChartBarAnnotations } from '../../assets/chart_bar_annotations';
import { generateId } from '../../id_generator';
import { defaultAnnotationColor } from '../../../../../../src/plugins/event_annotation/public';
import { defaultAnnotationLabel } from './config_panel';
const MAX_DATE = 8640000000000000;
const MIN_DATE = -8640000000000000;
export const defaultAnnotationLabel = i18n.translate('xpack.lens.xyChart.defaultAnnotationLabel', {
defaultMessage: 'Event',
});
export function getStaticDate(
dataLayers: XYDataLayerConfig[],
activeData: FramePublicAPI['activeData']

View file

@ -31,8 +31,7 @@ import {
getReferenceLayers,
getAnnotationsLayers,
} from './visualization_helpers';
import { defaultAnnotationLabel } from './annotations/config_panel';
import { getUniqueLabels } from './annotations/helpers';
import { getUniqueLabels, defaultAnnotationLabel } from './annotations/helpers';
import { layerTypes } from '../../common';
export const getSortedAccessors = (

View file

@ -67,8 +67,9 @@ import {
import { groupAxesByType } from './axes_configuration';
import { XYState } from './types';
import { ReferenceLinePanel } from './xy_config_panel/reference_line_panel';
import { AnnotationsPanel } from './xy_config_panel/annotations_config_panel';
import { DimensionTrigger } from '../shared_components/dimension_trigger';
import { AnnotationsPanel, defaultAnnotationLabel } from './annotations/config_panel';
import { defaultAnnotationLabel } from './annotations/helpers';
export const getXyVisualization = ({
paletteService,

View file

@ -6,7 +6,6 @@
*/
import React, { useCallback } from 'react';
import './index.scss';
import { i18n } from '@kbn/i18n';
import { EuiDatePicker, EuiFormRow, EuiSwitch, EuiSwitchEvent } from '@elastic/eui';
import type { PaletteRegistry } from 'src/plugins/charts/public';
@ -15,18 +14,15 @@ import { EventAnnotationConfig } from 'src/plugins/event_annotation/common/types
import type { VisualizationDimensionEditorProps } from '../../../types';
import { State, XYState, XYAnnotationLayerConfig } from '../../types';
import { FormatFactory } from '../../../../common';
import { ColorPicker } from '../../xy_config_panel/color_picker';
import { DimensionEditorSection, NameInput, useDebouncedValue } from '../../../shared_components';
import { isHorizontalChart } from '../../state_helpers';
import { MarkerDecorationSettings } from '../../xy_config_panel/shared/marker_decoration_settings';
import { LineStyleSettings } from '../../xy_config_panel/shared/line_style_settings';
import { updateLayer } from '../../xy_config_panel';
import { defaultAnnotationLabel } from '../../annotations/helpers';
import { ColorPicker } from '../color_picker';
import { IconSelectSetting, TextDecorationSetting } from '../shared/marker_decoration_settings';
import { LineStyleSettings } from '../shared/line_style_settings';
import { updateLayer } from '..';
import { annotationsIconSet } from './icon_set';
export const defaultAnnotationLabel = i18n.translate('xpack.lens.xyChart.defaultAnnotationLabel', {
defaultMessage: 'Event',
});
export const AnnotationsPanel = (
props: VisualizationDimensionEditorProps<State> & {
formatFactory: FormatFactory;
@ -101,8 +97,7 @@ export const AnnotationsPanel = (
setAnnotations({ label: value });
}}
/>
<MarkerDecorationSettings
isHorizontal={isHorizontal}
<IconSelectSetting
setConfig={setAnnotations}
currentConfig={{
axisMode: 'bottom',
@ -110,6 +105,13 @@ export const AnnotationsPanel = (
}}
customIconSet={annotationsIconSet}
/>
<TextDecorationSetting
setConfig={setAnnotations}
currentConfig={{
axisMode: 'bottom',
...currentAnnotations,
}}
/>
<LineStyleSettings
isHorizontal={isHorizontal}
setConfig={setAnnotations}

View file

@ -21,7 +21,7 @@ import { ColorPicker } from './color_picker';
import { PalettePicker, useDebouncedValue } from '../../shared_components';
import { isAnnotationsLayer, isReferenceLayer } from '../visualization_helpers';
import { ReferenceLinePanel } from './reference_line_panel';
import { AnnotationsPanel } from '../annotations/config_panel';
import { AnnotationsPanel } from './annotations_config_panel';
type UnwrapArray<T> = T extends Array<infer P> ? P : T;

View file

@ -22,7 +22,11 @@ import { updateLayer } from '.';
import { useDebouncedValue } from '../../shared_components';
import { idPrefix } from './dimension_editor';
import { isHorizontalChart } from '../state_helpers';
import { MarkerDecorationSettings } from './shared/marker_decoration_settings';
import {
IconSelectSetting,
MarkerDecorationPosition,
TextDecorationSetting,
} from './shared/marker_decoration_settings';
import { LineStyleSettings } from './shared/line_style_settings';
export const ReferenceLinePanel = (
@ -72,8 +76,9 @@ export const ReferenceLinePanel = (
return (
<>
{' '}
<MarkerDecorationSettings
<TextDecorationSetting setConfig={setConfig} currentConfig={localConfig} />
<IconSelectSetting setConfig={setConfig} currentConfig={localConfig} />
<MarkerDecorationPosition
isHorizontal={isHorizontal}
setConfig={setConfig}
currentConfig={localConfig}

View file

@ -81,73 +81,96 @@ interface MarkerDecorationConfig {
textVisibility?: boolean;
}
export const MarkerDecorationSettings = ({
export const TextDecorationSetting = ({
currentConfig,
setConfig,
isHorizontal,
customIconSet,
}: {
currentConfig?: MarkerDecorationConfig;
setConfig: (config: MarkerDecorationConfig) => void;
isHorizontal: boolean;
customIconSet?: IconSet;
}) => {
return (
<>
<EuiFormRow
label={i18n.translate('xpack.lens.lineMarker.textVisibility', {
<EuiFormRow
label={i18n.translate('xpack.lens.lineMarker.textVisibility', {
defaultMessage: 'Text decoration',
})}
display="columnCompressed"
fullWidth
>
<EuiButtonGroup
legend={i18n.translate('xpack.lens.lineMarker.textVisibility', {
defaultMessage: 'Text decoration',
})}
display="columnCompressed"
fullWidth
>
<EuiButtonGroup
legend={i18n.translate('xpack.lens.lineMarker.textVisibility', {
defaultMessage: 'Text decoration',
})}
data-test-subj="lns-lineMarker-text-visibility"
name="textVisibilityStyle"
buttonSize="compressed"
options={[
{
id: `${idPrefix}none`,
label: i18n.translate('xpack.lens.xyChart.lineMarker.textVisibility.none', {
defaultMessage: 'None',
}),
'data-test-subj': 'lnsXY_textVisibility_none',
},
{
id: `${idPrefix}name`,
label: i18n.translate('xpack.lens.xyChart.lineMarker.textVisibility.name', {
defaultMessage: 'Name',
}),
'data-test-subj': 'lnsXY_textVisibility_name',
},
]}
idSelected={`${idPrefix}${Boolean(currentConfig?.textVisibility) ? 'name' : 'none'}`}
onChange={(id) => {
setConfig({ textVisibility: id === `${idPrefix}name` });
}}
isFullWidth
/>
</EuiFormRow>
<EuiFormRow
display="columnCompressed"
fullWidth
label={i18n.translate('xpack.lens.xyChart.lineMarker.icon', {
defaultMessage: 'Icon decoration',
})}
>
<IconSelect
customIconSet={customIconSet}
value={currentConfig?.icon}
onChange={(newIcon) => {
setConfig({ icon: newIcon });
}}
/>
</EuiFormRow>
{currentConfig?.iconPosition &&
(hasIcon(currentConfig?.icon) || currentConfig?.textVisibility) ? (
data-test-subj="lns-lineMarker-text-visibility"
name="textVisibilityStyle"
buttonSize="compressed"
options={[
{
id: `${idPrefix}none`,
label: i18n.translate('xpack.lens.xyChart.lineMarker.textVisibility.none', {
defaultMessage: 'None',
}),
'data-test-subj': 'lnsXY_textVisibility_none',
},
{
id: `${idPrefix}name`,
label: i18n.translate('xpack.lens.xyChart.lineMarker.textVisibility.name', {
defaultMessage: 'Name',
}),
'data-test-subj': 'lnsXY_textVisibility_name',
},
]}
idSelected={`${idPrefix}${Boolean(currentConfig?.textVisibility) ? 'name' : 'none'}`}
onChange={(id) => {
setConfig({ textVisibility: id === `${idPrefix}name` });
}}
isFullWidth
/>
</EuiFormRow>
);
};
export const IconSelectSetting = ({
currentConfig,
setConfig,
customIconSet,
}: {
currentConfig?: MarkerDecorationConfig;
setConfig: (config: MarkerDecorationConfig) => void;
customIconSet?: IconSet;
}) => {
return (
<EuiFormRow
display="columnCompressed"
fullWidth
label={i18n.translate('xpack.lens.xyChart.lineMarker.icon', {
defaultMessage: 'Icon decoration',
})}
>
<IconSelect
customIconSet={customIconSet}
value={currentConfig?.icon}
onChange={(newIcon) => {
setConfig({ icon: newIcon });
}}
/>
</EuiFormRow>
);
};
export const MarkerDecorationPosition = ({
currentConfig,
setConfig,
isHorizontal,
}: {
currentConfig?: MarkerDecorationConfig;
setConfig: (config: MarkerDecorationConfig) => void;
isHorizontal: boolean;
}) => {
return (
<>
{hasIcon(currentConfig?.icon) || currentConfig?.textVisibility ? (
<EuiFormRow
display="columnCompressed"
fullWidth

View file

@ -0,0 +1,74 @@
/*
* 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 expect from '@kbn/expect';
import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects(['visualize', 'lens', 'common', 'header']);
const find = getService('find');
const retry = getService('retry');
const testSubjects = getService('testSubjects');
describe('lens annotations tests', () => {
it('should show a disabled annotation layer button if there is no date histogram in data layer', async () => {
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.clickVisType('lens');
await PageObjects.lens.dragFieldToWorkspace('geo.src', 'xyVisChart');
await testSubjects.click('lnsLayerAddButton');
await retry.waitFor('wait for layer popup to appear', async () =>
testSubjects.exists(`lnsLayerAddButton-annotations`)
);
expect(
await (await testSubjects.find(`lnsLayerAddButton-annotations`)).getAttribute('disabled')
).to.be('true');
});
it('should add manual annotation layer with static date and allow edition', async () => {
await PageObjects.lens.removeLayer();
await PageObjects.lens.goToTimeRange();
await PageObjects.lens.dragFieldToWorkspace('@timestamp', 'xyVisChart');
await PageObjects.lens.createLayer('annotations');
expect((await find.allByCssSelector(`[data-test-subj^="lns-layerPanel-"]`)).length).to.eql(2);
expect(
await (
await testSubjects.find('lnsXY_xAnnotationsPanel > lns-dimensionTrigger')
).getVisibleText()
).to.eql('Event');
await testSubjects.click('lnsXY_xAnnotationsPanel > lns-dimensionTrigger');
await testSubjects.click('lnsXY_textVisibility_name');
await PageObjects.lens.closeDimensionEditor();
await testSubjects.existOrFail('xyVisAnnotationIcon');
await testSubjects.existOrFail('xyVisAnnotationText');
});
it('should duplicate the style when duplicating an annotation and group them in the chart', async () => {
// drag and drop to the empty field to generate a duplicate
await PageObjects.lens.dragDimensionToDimension(
'lnsXY_xAnnotationsPanel > lns-dimensionTrigger',
'lnsXY_xAnnotationsPanel > lns-empty-dimension'
);
await (
await find.byCssSelector(
'[data-test-subj="lnsXY_xAnnotationsPanel"]:nth-child(2) [data-test-subj="lns-dimensionTrigger"]'
)
).click();
expect(
await find.existsByCssSelector(
'[data-test-subj="lnsXY_textVisibility_name"][class$="isSelected"]'
)
).to.be(true);
await PageObjects.lens.closeDimensionEditor();
await testSubjects.existOrFail('xyVisAnnotationText');
await testSubjects.existOrFail('xyVisGroupedAnnotationIcon');
});
});
}

View file

@ -75,6 +75,7 @@ export default function ({ getService, loadTestFile, getPageObjects }: FtrProvid
loadTestFile(require.resolve('./gauge'));
loadTestFile(require.resolve('./metrics'));
loadTestFile(require.resolve('./reference_lines'));
loadTestFile(require.resolve('./annotations'));
loadTestFile(require.resolve('./inspector'));
loadTestFile(require.resolve('./error_handling'));
loadTestFile(require.resolve('./lens_tagging'));