Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export const getLensVisMock = async ({
allSuggestions,
isTransformationalESQL,
table,
externalVisContext,
getModifiedVisAttributes,
}: {
filters: QueryParams['filters'];
query: QueryParams['query'];
Expand All @@ -46,6 +48,8 @@ export const getLensVisMock = async ({
allSuggestions?: Suggestion[];
isTransformationalESQL?: boolean;
table?: Datatable;
externalVisContext?: UnifiedHistogramVisContext;
getModifiedVisAttributes?: Parameters<LensVisService['update']>[0]['getModifiedVisAttributes'];
}): Promise<{
lensService: LensVisService;
visContext: UnifiedHistogramVisContext | undefined;
Expand Down Expand Up @@ -88,9 +92,10 @@ export const getLensVisMock = async ({
},
timeInterval,
breakdownField,
externalVisContext: undefined,
externalVisContext,
table,
onSuggestionContextChange: () => {},
getModifiedVisAttributes,
});

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@

import { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query';
import type { Datatable, DatatableColumn } from '@kbn/expressions-plugin/public';
import type { EmbeddableComponentProps, LensEmbeddableInput } from '@kbn/lens-plugin/public';
import type {
EmbeddableComponentProps,
LensEmbeddableInput,
TypedLensByValueInput,
} from '@kbn/lens-plugin/public';
import { useEffect, useMemo, useState } from 'react';
import { Observable, Subject, of } from 'rxjs';
import useMount from 'react-use/lib/useMount';
import { pick } from 'lodash';
import { cloneDeep, pick } from 'lodash';
import type { DataView } from '@kbn/data-views-plugin/common';
import useObservable from 'react-use/lib/useObservable';
import useLatest from 'react-use/lib/useLatest';
import { UnifiedHistogramChartProps } from '../components/chart/chart';
import {
UnifiedHistogramExternalVisContextStatus,
Expand Down Expand Up @@ -122,6 +127,12 @@ export type UseUnifiedHistogramProps = Omit<UnifiedHistogramStateOptions, 'servi
nextVisContext: UnifiedHistogramVisContext | undefined,
externalVisContextStatus: UnifiedHistogramExternalVisContextStatus
) => void;
/**
* Callback to modify the default Lens vis attributes used in the chart
*/
getModifiedVisAttributes?: (
attributes: TypedLensByValueInput['attributes']
) => TypedLensByValueInput['attributes'];
};

export type UnifiedHistogramApi = {
Expand Down Expand Up @@ -230,6 +241,7 @@ export const useUnifiedHistogram = (props: UseUnifiedHistogramProps): UseUnified
const lensVisServiceCurrentSuggestionContext = useObservable(
lensVisService?.currentSuggestionContext$ ?? EMPTY_SUGGESTION_CONTEXT
);
const latestGetModifiedVisAttributes = useLatest(props.getModifiedVisAttributes);

useEffect(() => {
if (isChartLoading || !lensVisService) {
Expand All @@ -252,13 +264,17 @@ export const useUnifiedHistogram = (props: UseUnifiedHistogramProps): UseUnified
table,
onSuggestionContextChange: stateProps.onSuggestionContextChange,
onVisContextChanged: stateProps.onVisContextChanged,
getModifiedVisAttributes: (attributes) => {
return latestGetModifiedVisAttributes.current?.(cloneDeep(attributes)) ?? attributes;
},
});
}, [
columns,
columnsMap,
dataView,
externalVisContext,
isChartLoading,
latestGetModifiedVisAttributes,
lensVisService,
requestParams.filters,
requestParams.query,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,62 @@ describe('LensVisService attributes', () => {
});
});

it('should allow modifying attributes with getModifiedVisAttributes', async () => {
const lensVis = await getLensVisMock({
filters,
query,
dataView,
timeInterval,
breakdownField: undefined,
columns: [],
isPlainRecord: false,
getModifiedVisAttributes: (attributes) => ({
...attributes,
title: 'Modified title',
visualizationType: 'lnsHeatmap',
}),
});
expect(lensVis.visContext?.attributes).toEqual(
expect.objectContaining({
title: 'Modified title',
visualizationType: 'lnsHeatmap',
})
);
});

it('should not allow modifying attributes with getModifiedVisAttributes if externalVisContext is applied', async () => {
const lensVis = await getLensVisMock({
filters,
query,
dataView,
timeInterval,
breakdownField: undefined,
columns: [],
isPlainRecord: false,
});
const lensVis2 = await getLensVisMock({
filters,
query,
dataView,
timeInterval,
breakdownField: undefined,
columns: [],
isPlainRecord: false,
externalVisContext: lensVis.visContext,
getModifiedVisAttributes: (attributes) => ({
...attributes,
title: 'Modified title',
visualizationType: 'lnsHeatmap',
}),
});
expect(lensVis2.visContext?.attributes).not.toEqual(
expect.objectContaining({
title: 'Modified title',
visualizationType: 'lnsHeatmap',
})
);
});

it('should return suggestion title', async () => {
const lensVis = await getLensVisMock({
filters,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ export class LensVisService {
table,
onSuggestionContextChange,
onVisContextChanged,
getModifiedVisAttributes,
}: {
externalVisContext: UnifiedHistogramVisContext | undefined;
queryParams: QueryParams;
Expand All @@ -148,6 +149,9 @@ export class LensVisService {
visContext: UnifiedHistogramVisContext | undefined,
externalVisContextStatus: UnifiedHistogramExternalVisContextStatus
) => void;
getModifiedVisAttributes?: (
attributes: TypedLensByValueInput['attributes']
) => TypedLensByValueInput['attributes'];
}) => {
const suggestionState = this.getCurrentSuggestionState({
externalVisContext,
Expand All @@ -163,6 +167,7 @@ export class LensVisService {
timeInterval,
breakdownField,
table,
getModifiedVisAttributes,
});

onSuggestionContextChange(suggestionState.currentSuggestionContext);
Expand Down Expand Up @@ -657,13 +662,17 @@ export class LensVisService {
timeInterval,
breakdownField,
table,
getModifiedVisAttributes,
}: {
currentSuggestionContext: UnifiedHistogramSuggestionContext;
externalVisContext: UnifiedHistogramVisContext | undefined;
queryParams: QueryParams;
timeInterval: string | undefined;
breakdownField: DataViewField | undefined;
table: Datatable | undefined;
getModifiedVisAttributes?: (
attributes: TypedLensByValueInput['attributes']
) => TypedLensByValueInput['attributes'];
}): {
externalVisContextStatus: UnifiedHistogramExternalVisContextStatus;
visContext: UnifiedHistogramVisContext | undefined;
Expand Down Expand Up @@ -769,6 +778,13 @@ export class LensVisService {
};
}

if (
externalVisContextStatus !== UnifiedHistogramExternalVisContextStatus.applied &&
getModifiedVisAttributes
) {
visContext.attributes = getModifiedVisAttributes(visContext.attributes);
}

return {
externalVisContextStatus,
visContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import type { DiscoverCustomizationId } from '../../../../customizations/customi
import { internalStateActions } from '../../state_management/redux';
import { dataViewMockWithTimeField } from '@kbn/discover-utils/src/__mocks__';
import { DiscoverTestProvider } from '../../../../__mocks__/test_provider';
import type { ScopedProfilesManager } from '../../../../context_awareness';
import { createContextAwarenessMocks } from '../../../../context_awareness/__mocks__';
import type { TypedLensByValueInput } from '@kbn/lens-plugin/public';

const mockData = dataPluginMock.createStartContract();
let mockQueryState = {
Expand Down Expand Up @@ -104,12 +107,17 @@ describe('useDiscoverHistogram', () => {
return stateContainer;
};

const renderUseDiscoverHistogram = async (
stateContainer: DiscoverStateContainer = getStateContainer()
) => {
const renderUseDiscoverHistogram = async ({
stateContainer = getStateContainer(),
scopedProfilesManager,
}: {
stateContainer?: DiscoverStateContainer;
scopedProfilesManager?: ScopedProfilesManager;
} = {}) => {
const Wrapper = ({ children }: React.PropsWithChildren<unknown>) => (
<DiscoverTestProvider
stateContainer={stateContainer}
scopedProfilesManager={scopedProfilesManager}
runtimeState={{ currentDataView: dataViewMockWithTimeField, adHocDataViews: [] }}
>
{children}
Expand Down Expand Up @@ -183,7 +191,7 @@ describe('useDiscoverHistogram', () => {
const stateContainer = getStateContainer();
const inspectorAdapters = { requests: new RequestAdapter(), lensRequests: undefined };
stateContainer.dataState.inspectorAdapters = inspectorAdapters;
const { hook } = await renderUseDiscoverHistogram(stateContainer);
const { hook } = await renderUseDiscoverHistogram({ stateContainer });
const lensRequestAdapter = new RequestAdapter();
const state = {
timeInterval: '1m',
Expand All @@ -205,7 +213,7 @@ describe('useDiscoverHistogram', () => {

it('should not sync Unified Histogram state with the state container if there are no changes', async () => {
const stateContainer = getStateContainer();
const { hook } = await renderUseDiscoverHistogram(stateContainer);
const { hook } = await renderUseDiscoverHistogram({ stateContainer });
const containerState = stateContainer.appState.getState();
const state = {
timeInterval: containerState.interval,
Expand All @@ -223,7 +231,7 @@ describe('useDiscoverHistogram', () => {

it('should sync the state container state with Unified Histogram', async () => {
const stateContainer = getStateContainer();
const { hook } = await renderUseDiscoverHistogram(stateContainer);
const { hook } = await renderUseDiscoverHistogram({ stateContainer });
const api = createMockUnifiedHistogramApi();
let params: Partial<UnifiedHistogramState> = {};
api.setTotalHits = jest.fn((p) => {
Expand All @@ -247,7 +255,7 @@ describe('useDiscoverHistogram', () => {

it('should exclude totalHitsStatus and totalHitsResult from Unified Histogram state updates', async () => {
const stateContainer = getStateContainer();
const { hook } = await renderUseDiscoverHistogram(stateContainer);
const { hook } = await renderUseDiscoverHistogram({ stateContainer });
const containerState = stateContainer.appState.getState();
const state = {
timeInterval: containerState.interval,
Expand Down Expand Up @@ -281,7 +289,7 @@ describe('useDiscoverHistogram', () => {

it('should update total hits when the total hits state changes', async () => {
const stateContainer = getStateContainer();
const { hook } = await renderUseDiscoverHistogram(stateContainer);
const { hook } = await renderUseDiscoverHistogram({ stateContainer });
const containerState = stateContainer.appState.getState();
const state = {
timeInterval: containerState.interval,
Expand Down Expand Up @@ -324,7 +332,7 @@ describe('useDiscoverHistogram', () => {

mockData.query.getState = () => mockQueryState;
const stateContainer = getStateContainer();
const { hook } = await renderUseDiscoverHistogram(stateContainer);
const { hook } = await renderUseDiscoverHistogram({ stateContainer });
const containerState = stateContainer.appState.getState();
const error = new Error('test');
const state = {
Expand Down Expand Up @@ -359,7 +367,7 @@ describe('useDiscoverHistogram', () => {
const stateContainer = getStateContainer();
stateContainer.appState.update({ query: { esql: 'from *' } });
stateContainer.dataState.fetchChart$ = fetch$;
const { hook } = await renderUseDiscoverHistogram(stateContainer);
const { hook } = await renderUseDiscoverHistogram({ stateContainer });
act(() => {
fetch$.next();
});
Expand All @@ -380,7 +388,7 @@ describe('useDiscoverHistogram', () => {
},
})
);
const { hook } = await renderUseDiscoverHistogram(stateContainer);
const { hook } = await renderUseDiscoverHistogram({ stateContainer });
act(() => {
fetch$.next();
});
Expand All @@ -394,7 +402,7 @@ describe('useDiscoverHistogram', () => {
const savedSearchFetch$ = new Subject<void>();
const stateContainer = getStateContainer();
stateContainer.dataState.fetchChart$ = savedSearchFetch$;
const { hook } = await renderUseDiscoverHistogram(stateContainer);
const { hook } = await renderUseDiscoverHistogram({ stateContainer });
const api = createMockUnifiedHistogramApi();
act(() => {
hook.result.current.setUnifiedHistogramApi(api);
Expand All @@ -411,7 +419,7 @@ describe('useDiscoverHistogram', () => {
test('should use custom values provided by customization fwk ', async () => {
mockUseCustomizations = true;
const stateContainer = getStateContainer();
const { hook } = await renderUseDiscoverHistogram(stateContainer);
const { hook } = await renderUseDiscoverHistogram({ stateContainer });

expect(hook.result.current.onFilter).toEqual(mockHistogramCustomization.onFilter);
expect(hook.result.current.onBrushEnd).toEqual(mockHistogramCustomization.onBrushEnd);
Expand All @@ -421,4 +429,19 @@ describe('useDiscoverHistogram', () => {
expect(hook.result.current.disabledActions).toBeUndefined();
});
});

describe('context awareness', () => {
it('should modify vis attributes based on profile', async () => {
const { profilesManagerMock, scopedEbtManagerMock } = createContextAwarenessMocks();
const scopedProfilesManager = profilesManagerMock.createScopedProfilesManager({
scopedEbtManager: scopedEbtManagerMock,
});
scopedProfilesManager.resolveDataSourceProfile({});
const { hook } = await renderUseDiscoverHistogram({ scopedProfilesManager });
const modifiedAttributes = hook.result.current.getModifiedVisAttributes?.(
{} as TypedLensByValueInput['attributes']
);
expect(modifiedAttributes).toEqual({ title: 'Modified title' });
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import type { SavedSearch } from '@kbn/saved-search-plugin/common';
import type { Filter } from '@kbn/es-query';
import { isOfAggregateQueryType } from '@kbn/es-query';
import { ESQL_TABLE_TYPE } from '@kbn/data-plugin/common';
import { useProfileAccessor } from '../../../../context_awareness';
import { useDiscoverCustomization } from '../../../../customizations';
import { useDiscoverServices } from '../../../../hooks/use_discover_services';
import { FetchStatus } from '../../../types';
Expand Down Expand Up @@ -353,6 +354,14 @@ export const useDiscoverHistogram = (
[dispatch, setOverriddenVisContextAfterInvalidation, stateContainer.savedSearchState]
);

const getModifiedVisAttributesAccessor = useProfileAccessor('getModifiedVisAttributes');
const getModifiedVisAttributes = useCallback<
NonNullable<UseUnifiedHistogramProps['getModifiedVisAttributes']>
>(
(attributes) => getModifiedVisAttributesAccessor((params) => params.attributes)({ attributes }),
[getModifiedVisAttributesAccessor]
);

const chartHidden = useAppStateSelector((state) => state.hideChart);
const timeInterval = useAppStateSelector((state) => state.interval);
const breakdownField = useAppStateSelector((state) => state.breakdownField);
Expand Down Expand Up @@ -401,6 +410,7 @@ export const useDiscoverHistogram = (
breakdownField,
onBreakdownFieldChange,
searchSessionId,
getModifiedVisAttributes,
};
};

Expand Down
Loading