[Lens] Mute visualization modifier badge if layer has only manual annotations (#167483)

## Summary

Fixes #167408 

This PR reduces the amount of "visualization modifiers" in the specific
case where ALL annotations in a layer are manual.
The `Ignore global filters` will still be shown if at least one
query-based annotation is defined in the layer.


### Checklist

Delete any items that are not applicable to this PR.

- [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

---------

Co-authored-by: Stratoula Kalafateli <efstratia.kalafateli@elastic.co>
This commit is contained in:
Marco Liberati 2023-09-28 15:19:23 +02:00 committed by GitHub
parent 1f593f4c96
commit 911ed802b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 104 additions and 5 deletions

View file

@ -731,12 +731,14 @@ describe('xy_visualization', () => {
}, },
}; };
}); });
it('when there is no date histogram annotation layer is disabled', () => { it('when there is no date histogram annotation layer is disabled', () => {
const supportedAnnotationLayer = xyVisualization const supportedAnnotationLayer = xyVisualization
.getSupportedLayers(exampleState()) .getSupportedLayers(exampleState())
.find((a) => a.type === 'annotations'); .find((a) => a.type === 'annotations');
expect(supportedAnnotationLayer?.disabled).toBeTruthy(); expect(supportedAnnotationLayer?.disabled).toBeTruthy();
}); });
it('for data with date histogram annotation layer is enabled and calculates initial dimensions', () => { it('for data with date histogram annotation layer is enabled and calculates initial dimensions', () => {
const supportedAnnotationLayer = xyVisualization const supportedAnnotationLayer = xyVisualization
.getSupportedLayers(exampleState(), frame) .getSupportedLayers(exampleState(), frame)
@ -3216,6 +3218,34 @@ describe('xy_visualization', () => {
}); });
describe('info', () => { describe('info', () => {
function createStateWithAnnotationProps(annotation: Partial<EventAnnotationConfig>) {
return {
layers: [
{
layerId: 'first',
layerType: layerTypes.DATA,
seriesType: 'area',
splitAccessor: undefined,
xAccessor: DATE_HISTORGRAM_COLUMN_ID,
accessors: ['b'],
},
{
layerId: 'layerId',
layerType: 'annotations',
indexPatternId: 'first',
annotations: [
{
label: 'Event',
id: '1',
type: 'query',
timeField: 'start_date',
...annotation,
},
],
},
],
} as XYState;
}
function getFrameMock() { function getFrameMock() {
const datasourceMock = createMockDatasource('testDatasource'); const datasourceMock = createMockDatasource('testDatasource');
datasourceMock.publicAPIMock.getOperationForColumnId.mockImplementation((id) => datasourceMock.publicAPIMock.getOperationForColumnId.mockImplementation((id) =>
@ -3239,21 +3269,47 @@ describe('xy_visualization', () => {
}); });
} }
it('should return an info message if annotation layer is ignoring the global filters', () => { it('should not return an info message if annotation layer is ignoring the global filters but contains only manual annotations', () => {
const initialState = exampleState(); const initialState = createStateWithAnnotationProps({});
const state: State = { const state: State = {
...initialState, ...initialState,
layers: [ layers: [
...initialState.layers, // replace the existing annotation layers with a new one
...initialState.layers.filter(({ layerType }) => layerType !== layerTypes.ANNOTATIONS),
{ {
layerId: 'annotation', layerId: 'annotation',
layerType: layerTypes.ANNOTATIONS, layerType: layerTypes.ANNOTATIONS,
annotations: [exampleAnnotation2], annotations: [exampleAnnotation2, { ...exampleAnnotation2, id: 'an3' }],
ignoreGlobalFilters: true, ignoreGlobalFilters: true,
indexPatternId: 'myIndexPattern', indexPatternId: 'myIndexPattern',
}, },
], ],
}; };
expect(xyVisualization.getUserMessages!(state, { frame: getFrameMock() })).toHaveLength(0);
});
it("should return an info message if the annotation layer is ignoring filters and there's at least a query annotation", () => {
const state = createStateWithAnnotationProps({
filter: {
language: 'kuery',
query: 'agent.keyword: *',
type: 'kibana_query',
},
id: 'newColId',
key: {
type: 'point_in_time',
},
label: 'agent.keyword: *',
timeField: 'timestamp',
type: 'query',
});
const annotationLayer = state.layers.find(
({ layerType }) => layerType === layerTypes.ANNOTATIONS
)! as XYAnnotationLayerConfig;
annotationLayer.ignoreGlobalFilters = true;
annotationLayer.annotations.push(exampleAnnotation2);
expect(xyVisualization.getUserMessages!(state, { frame: getFrameMock() })).toContainEqual( expect(xyVisualization.getUserMessages!(state, { frame: getFrameMock() })).toContainEqual(
expect.objectContaining({ expect.objectContaining({
displayLocations: [{ id: 'embeddableBadge' }], displayLocations: [{ id: 'embeddableBadge' }],
@ -3264,6 +3320,30 @@ describe('xy_visualization', () => {
}) })
); );
}); });
it('should not return an info message if annotation layer is not ignoring the global filters', () => {
const state = createStateWithAnnotationProps({
filter: {
language: 'kuery',
query: 'agent.keyword: *',
type: 'kibana_query',
},
id: 'newColId',
key: {
type: 'point_in_time',
},
label: 'agent.keyword: *',
timeField: 'timestamp',
type: 'query',
});
const annotationLayer = state.layers.find(
({ layerType }) => layerType === layerTypes.ANNOTATIONS
)! as XYAnnotationLayerConfig;
annotationLayer.ignoreGlobalFilters = false;
annotationLayer.annotations.push(exampleAnnotation2);
expect(xyVisualization.getUserMessages!(state, { frame: getFrameMock() })).toHaveLength(0);
});
}); });
}); });

View file

@ -1149,7 +1149,10 @@ function getNotifiableFeatures(
fieldFormats: FieldFormatsStart fieldFormats: FieldFormatsStart
): UserMessage[] { ): UserMessage[] {
const annotationsWithIgnoreFlag = getAnnotationsLayers(state.layers).filter( const annotationsWithIgnoreFlag = getAnnotationsLayers(state.layers).filter(
(layer) => layer.ignoreGlobalFilters (layer) =>
layer.ignoreGlobalFilters &&
// If all annotations are manual, do not report it
layer.annotations.some((annotation) => annotation.type !== 'manual')
); );
if (!annotationsWithIgnoreFlag.length) { if (!annotationsWithIgnoreFlag.length) {
return []; return [];

View file

@ -12,6 +12,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects(['visualize', 'lens', 'common', 'header']); const PageObjects = getPageObjects(['visualize', 'lens', 'common', 'header']);
const find = getService('find'); const find = getService('find');
const testSubjects = getService('testSubjects'); const testSubjects = getService('testSubjects');
const retry = getService('retry');
describe('lens layer actions tests', () => { describe('lens layer actions tests', () => {
it('should allow creation of lens xy chart', async () => { it('should allow creation of lens xy chart', async () => {
@ -239,6 +240,21 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
// by default annotations ignore global filters // by default annotations ignore global filters
await PageObjects.lens.createLayer('annotations'); await PageObjects.lens.createLayer('annotations');
await testSubjects.click('lns-layerPanel-2 > lnsXY_xAnnotationsPanel > lns-dimensionTrigger');
await testSubjects.click('lnsXY_annotation_query');
await retry.try(async () => {
if (!(await testSubjects.exists('annotation-query-based-query-input'))) {
await testSubjects.setValue('annotation-query-based-query-input', '*', {
clearWithKeyboard: true,
typeCharByChar: true,
});
}
});
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.save('sampledVisualization', false, true, false, 'new'); await PageObjects.lens.save('sampledVisualization', false, true, false, 'new');
// now check for the bottom-left badge // now check for the bottom-left badge