From 310a93b270a89584aa22ac66e2f574ba0a2d9d56 Mon Sep 17 00:00:00 2001 From: dej611 Date: Thu, 5 Dec 2024 18:12:32 +0100 Subject: [PATCH 01/12] :bug: filtr search context before updating --- .../fetch/publishes_unified_search.ts | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts b/packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts index aec8c33715c0f..3f99fa4783e2f 100644 --- a/packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts +++ b/packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts @@ -7,7 +7,15 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query'; +import { + AggregateQuery, + COMPARE_ALL_OPTIONS, + Filter, + Query, + TimeRange, + onlyDisabledFiltersChanged, +} from '@kbn/es-query'; +import fastIsEqual from 'fast-deep-equal'; import { useEffect, useMemo } from 'react'; import { BehaviorSubject } from 'rxjs'; import { PublishingSubject } from '../../publishing_subject'; @@ -113,15 +121,27 @@ export function useSearchApi({ }, []); useEffect(() => { - searchApi.filters$.next(filters); + if ( + !onlyDisabledFiltersChanged(searchApi.filters$.getValue(), filters, { + ...COMPARE_ALL_OPTIONS, + // do not compare $state to avoid refreshing when filter is pinned/unpinned (which does not impact results) + state: false, + }) + ) { + searchApi.filters$.next(filters); + } }, [filters, searchApi.filters$]); useEffect(() => { - searchApi.query$.next(query); + if (!fastIsEqual([searchApi.query$.getValue()], [query])) { + searchApi.query$.next(query); + } }, [query, searchApi.query$]); useEffect(() => { - searchApi.timeRange$.next(timeRange); + if (!fastIsEqual([searchApi.timeRange$.getValue()], [timeRange])) { + searchApi.timeRange$.next(timeRange); + } }, [timeRange, searchApi.timeRange$]); return searchApi; From 6eae7b25b25c2243c5b3083ad195af96d28475ce Mon Sep 17 00:00:00 2001 From: dej611 Date: Thu, 5 Dec 2024 18:12:41 +0100 Subject: [PATCH 02/12] :white_check_mark: Add FTR test --- .../apps/observability/index.ts | 1 + .../alerts/custom_threshold_preview_chart.ts | 89 +++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 x-pack/test/observability_functional/apps/observability/pages/alerts/custom_threshold_preview_chart.ts diff --git a/x-pack/test/observability_functional/apps/observability/index.ts b/x-pack/test/observability_functional/apps/observability/index.ts index f061fe68649d5..dce84cee32dfa 100644 --- a/x-pack/test/observability_functional/apps/observability/index.ts +++ b/x-pack/test/observability_functional/apps/observability/index.ts @@ -17,6 +17,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./pages/alerts/rule_stats')); loadTestFile(require.resolve('./pages/alerts/state_synchronization')); loadTestFile(require.resolve('./pages/alerts/table_storage')); + loadTestFile(require.resolve('./pages/alerts/custom_threshold_preview_chart')); loadTestFile(require.resolve('./pages/alerts/custom_threshold')); loadTestFile(require.resolve('./pages/cases/case_details')); loadTestFile(require.resolve('./pages/overview/alert_table')); diff --git a/x-pack/test/observability_functional/apps/observability/pages/alerts/custom_threshold_preview_chart.ts b/x-pack/test/observability_functional/apps/observability/pages/alerts/custom_threshold_preview_chart.ts new file mode 100644 index 0000000000000..6bc0564c711c1 --- /dev/null +++ b/x-pack/test/observability_functional/apps/observability/pages/alerts/custom_threshold_preview_chart.ts @@ -0,0 +1,89 @@ +/* + * 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 'expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default ({ getService, getPageObject }: FtrProviderContext) => { + const common = getPageObject('common'); + const esArchiver = getService('esArchiver'); + const testSubjects = getService('testSubjects'); + const kibanaServer = getService('kibanaServer'); + const supertest = getService('supertest'); + const find = getService('find'); + const logger = getService('log'); + const retry = getService('retry'); + + describe('Custom threshold preview chart', () => { + const observability = getService('observability'); + const DATA_VIEW_1 = 'metricbeat-*'; + const DATA_VIEW_1_ID = 'data-view-id_1'; + const DATA_VIEW_1_NAME = 'test-data-view-name_1'; + + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'); + await observability.alerts.common.createDataView({ + supertest, + name: DATA_VIEW_1_NAME, + id: DATA_VIEW_1_ID, + title: DATA_VIEW_1, + logger, + }); + await observability.alerts.common.navigateToRulesPage(); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'); + // This also deletes the created data views + await kibanaServer.savedObjects.cleanStandardList(); + }); + + it('does render the empty chart only once at bootstrap', async () => { + await observability.alerts.rulesPage.clickCreateRuleButton(); + await observability.alerts.rulesPage.clickOnObservabilityCategory(); + await observability.alerts.rulesPage.clickOnCustomThresholdRule(); + await common.sleep(1000); + expect(await find.existsByCssSelector('[data-rendering-count="2"]')).toBe(true); + }); + + it('does render the correct error message', async () => { + await testSubjects.setValue('ruleNameInput', 'test custom threshold rule'); + + await testSubjects.click('customEquation'); + const customEquationField = await find.byCssSelector( + '[data-test-subj="thresholdRuleCustomEquationEditorFieldText"]' + ); + await customEquationField.click(); + // set an invalid equation + await customEquationField.type('A + '); + + await testSubjects.click('o11yClosablePopoverTitleButton'); + + await testSubjects.existOrFail('embeddable-lens-failure'); + const el = await find.byCssSelector('[data-test-subj="embeddable-lens-failure"] p'); + const textContent = await el.getVisibleText(); + expect(textContent).toBe('An error occurred while rendering the chart'); + }); + + it('does render the chart after fixing the error', async () => { + await testSubjects.click('customEquation'); + const customEquationField = await find.byCssSelector( + '[data-test-subj="thresholdRuleCustomEquationEditorFieldText"]' + ); + await customEquationField.click(); + // fix the equation + await customEquationField.type('A'); + await testSubjects.click('o11yClosablePopoverTitleButton'); + + // check no error is visible + await testSubjects.missingOrFail('embeddable-lens-failure'); + await retry.waitFor('Chart rendered correctly', () => { + return find.existsByCssSelector('[data-render-complete="true"]'); + }); + }); + }); +}; From a67aa08950213089d090445508b89f5cc260b099 Mon Sep 17 00:00:00 2001 From: dej611 Date: Thu, 5 Dec 2024 21:12:02 +0100 Subject: [PATCH 03/12] :ok_hand: Integrate feedback --- .../interfaces/fetch/publishes_unified_search.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts b/packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts index 3f99fa4783e2f..08a21f16ca5e9 100644 --- a/packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts +++ b/packages/presentation/presentation_publishing/interfaces/fetch/publishes_unified_search.ts @@ -133,13 +133,13 @@ export function useSearchApi({ }, [filters, searchApi.filters$]); useEffect(() => { - if (!fastIsEqual([searchApi.query$.getValue()], [query])) { + if (!fastIsEqual(searchApi.query$.getValue(), query)) { searchApi.query$.next(query); } }, [query, searchApi.query$]); useEffect(() => { - if (!fastIsEqual([searchApi.timeRange$.getValue()], [timeRange])) { + if (!fastIsEqual(searchApi.timeRange$.getValue(), timeRange)) { searchApi.timeRange$.next(timeRange); } }, [timeRange, searchApi.timeRange$]); From 453066cc90868d55f2131923c2e80d5d645572a0 Mon Sep 17 00:00:00 2001 From: dej611 Date: Thu, 5 Dec 2024 21:12:16 +0100 Subject: [PATCH 04/12] :bug: Handle searchSession correctly --- x-pack/plugins/lens/public/react_embeddable/data_loader.ts | 3 +-- .../renderer/lens_custom_renderer_component.tsx | 3 +++ x-pack/plugins/lens/public/react_embeddable/types.ts | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/lens/public/react_embeddable/data_loader.ts b/x-pack/plugins/lens/public/react_embeddable/data_loader.ts index 64b7ca4501b08..44498b6c0a053 100644 --- a/x-pack/plugins/lens/public/react_embeddable/data_loader.ts +++ b/x-pack/plugins/lens/public/react_embeddable/data_loader.ts @@ -7,7 +7,6 @@ import type { DefaultInspectorAdapters } from '@kbn/expressions-plugin/common'; import { fetch$, type FetchContext } from '@kbn/presentation-publishing'; -import { apiPublishesSearchSession } from '@kbn/presentation-publishing/interfaces/fetch/publishes_search_session'; import { type KibanaExecutionContext } from '@kbn/core/public'; import { BehaviorSubject, @@ -262,7 +261,7 @@ export function loadEmbeddableData( // on data change from the parentApi, reload fetch$(api).pipe( tap((data) => { - const searchSessionId = apiPublishesSearchSession(parentApi) ? data.searchSessionId : ''; + const searchSessionId = data.searchSessionId || api.searchSessionId$.getValue(); unifiedSearch$.next({ query: data.query, filters: data.filters, diff --git a/x-pack/plugins/lens/public/react_embeddable/renderer/lens_custom_renderer_component.tsx b/x-pack/plugins/lens/public/react_embeddable/renderer/lens_custom_renderer_component.tsx index 5bc55d43c3212..ae9c06355823d 100644 --- a/x-pack/plugins/lens/public/react_embeddable/renderer/lens_custom_renderer_component.tsx +++ b/x-pack/plugins/lens/public/react_embeddable/renderer/lens_custom_renderer_component.tsx @@ -59,6 +59,7 @@ export function LensRenderer({ filters, timeRange, disabledActions, + searchSessionId, ...props }: LensRendererProps) { // Use the settings interface to store panel settings @@ -71,6 +72,7 @@ export function LensRenderer({ }, []); const disabledActionIds$ = useObservableVariable(disabledActions); const viewMode$ = useObservableVariable(viewMode); + const searchSessionId$ = useObservableVariable(searchSessionId); // Lens API will be set once, but when set trigger a reflow to adopt the latest attributes const [lensApi, setLensApi] = useState(undefined); @@ -135,6 +137,7 @@ export function LensRenderer({ ...props, // forward the unified search context ...searchApi, + searchSessionId$, disabledActionIds: disabledActionIds$, setDisabledActionIds: (ids: string[] | undefined) => disabledActionIds$.next(ids), viewMode: viewMode$, diff --git a/x-pack/plugins/lens/public/react_embeddable/types.ts b/x-pack/plugins/lens/public/react_embeddable/types.ts index c860c543570c1..1a4bf45b11f17 100644 --- a/x-pack/plugins/lens/public/react_embeddable/types.ts +++ b/x-pack/plugins/lens/public/react_embeddable/types.ts @@ -65,6 +65,7 @@ import type { AllowedPartitionOverrides } from '@kbn/expression-partition-vis-pl import type { AllowedXYOverrides } from '@kbn/expression-xy-plugin/common'; import type { Action } from '@kbn/ui-actions-plugin/public'; import { PresentationContainer } from '@kbn/presentation-containers'; +import { PublishesSearchSession } from '@kbn/presentation-publishing/interfaces/fetch/publishes_search_session'; import type { LegacyMetricState } from '../../common'; import type { LensDocument } from '../persistence'; import type { LensInspector } from '../lens_inspector_service'; @@ -364,6 +365,8 @@ export type LensApi = Simplify< PublishesBlockingError & // This is used by dashboard/container to show filters/queries on the panel PublishesUnifiedSearch & + // Forward the search session id + PublishesSearchSession & // Let the container know the loading state PublishesDataLoading & // Let the container know when the rendering has completed rendering From 9326cd9d8c4cf69fa07f5540303c0a189588e495 Mon Sep 17 00:00:00 2001 From: dej611 Date: Fri, 6 Dec 2024 08:21:19 +0100 Subject: [PATCH 05/12] :label: Fix type --- x-pack/plugins/lens/public/react_embeddable/mocks/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/lens/public/react_embeddable/mocks/index.tsx b/x-pack/plugins/lens/public/react_embeddable/mocks/index.tsx index ca8f489a711aa..30a0920f9557d 100644 --- a/x-pack/plugins/lens/public/react_embeddable/mocks/index.tsx +++ b/x-pack/plugins/lens/public/react_embeddable/mocks/index.tsx @@ -116,6 +116,7 @@ const LensApiMock: LensApi = { disabledActionIds: new BehaviorSubject(undefined), setDisabledActionIds: jest.fn(), rendered$: new BehaviorSubject(false), + searchSessionId$: new BehaviorSubject(undefined), }; const LensSerializedStateMock: LensSerializedState = createEmptyLensState( From ae67c6cb49bf34cf601cc181c97f936655aaa9cf Mon Sep 17 00:00:00 2001 From: dej611 Date: Fri, 6 Dec 2024 11:40:56 +0100 Subject: [PATCH 06/12] :bug: Final fix to have up to date search context --- .../public/react_embeddable/data_loader.ts | 53 +++++++++---------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/x-pack/plugins/lens/public/react_embeddable/data_loader.ts b/x-pack/plugins/lens/public/react_embeddable/data_loader.ts index 44498b6c0a053..ac69b79b42230 100644 --- a/x-pack/plugins/lens/public/react_embeddable/data_loader.ts +++ b/x-pack/plugins/lens/public/react_embeddable/data_loader.ts @@ -6,7 +6,7 @@ */ import type { DefaultInspectorAdapters } from '@kbn/expressions-plugin/common'; -import { fetch$, type FetchContext } from '@kbn/presentation-publishing'; +import { apiPublishesUnifiedSearch, fetch$ } from '@kbn/presentation-publishing'; import { type KibanaExecutionContext } from '@kbn/core/public'; import { BehaviorSubject, @@ -20,6 +20,7 @@ import { map, } from 'rxjs'; import fastIsEqual from 'fast-deep-equal'; +import { pick } from 'lodash'; import { getEditPath } from '../../common/constants'; import type { GetStateType, @@ -53,6 +54,24 @@ type ReloadReason = | 'viewMode' | 'searchContext'; +function getSearchContext(parentApi: unknown) { + const unifiedSearch$ = apiPublishesUnifiedSearch(parentApi) + ? pick(parentApi, 'filters$', 'query$', 'timeslice$', 'timeRange$') + : { + filters$: new BehaviorSubject(undefined), + query$: new BehaviorSubject(undefined), + timeslice$: new BehaviorSubject(undefined), + timeRange$: new BehaviorSubject(undefined), + }; + + return { + filters: unifiedSearch$.filters$.getValue(), + query: unifiedSearch$.query$.getValue(), + timeRange: unifiedSearch$.timeRange$.getValue(), + timeslice: unifiedSearch$.timeslice$?.getValue(), + }; +} + /** * The function computes the expression used to render the panel and produces the necessary props * for the ExpressionWrapper component, binding any outer context to them. @@ -111,16 +130,6 @@ export function loadEmbeddableData( } }; - const unifiedSearch$ = new BehaviorSubject< - Pick - >({ - query: undefined, - filters: undefined, - timeRange: undefined, - timeslice: undefined, - searchSessionId: undefined, - }); - async function reload( // make reload easier to debug sourceId: ReloadReason @@ -141,8 +150,6 @@ export function loadEmbeddableData( const currentState = getState(); - const { searchSessionId, ...unifiedSearch } = unifiedSearch$.getValue(); - const getExecutionContext = () => { const parentContext = getParentContext(parentApi); const lastState = getState(); @@ -197,7 +204,7 @@ export function loadEmbeddableData( const searchContext = getMergedSearchContext( currentState, - unifiedSearch, + getSearchContext(parentApi), api.timeRange$, parentApi, services @@ -215,7 +222,7 @@ export function loadEmbeddableData( }, renderMode: getRenderMode(parentApi), services, - searchSessionId, + searchSessionId: api.searchSessionId$.getValue(), abortController: internalApi.expressionAbortController$.getValue(), getExecutionContext, logError: getLogError(getExecutionContext), @@ -258,20 +265,8 @@ export function loadEmbeddableData( } const mergedSubscriptions = merge( - // on data change from the parentApi, reload - fetch$(api).pipe( - tap((data) => { - const searchSessionId = data.searchSessionId || api.searchSessionId$.getValue(); - unifiedSearch$.next({ - query: data.query, - filters: data.filters, - timeRange: data.timeRange, - timeslice: data.timeslice, - searchSessionId, - }); - }), - map(() => 'searchContext' as ReloadReason) - ), + // on search context change, reload + fetch$(api).pipe(map(() => 'searchContext' as ReloadReason)), // On state change, reload // this is used to refresh the chart on inline editing // just make sure to avoid to rerender if there's no substantial change From 183d0d2fc0e817d96dbf4f1ba5e82d598b7dbe1d Mon Sep 17 00:00:00 2001 From: dej611 Date: Fri, 6 Dec 2024 13:04:01 +0100 Subject: [PATCH 07/12] :bug: Fix issue with error message --- .../rule_condition_chart.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/rule_condition_chart.tsx b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/rule_condition_chart.tsx index 2a9fa2c295274..02dc7bc1f51d9 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/rule_condition_chart.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/rule_condition_chart.tsx @@ -138,19 +138,21 @@ export function RuleConditionChart({ const errorDiv = document.querySelector('.lnsEmbeddedError'); if (errorDiv) { const paragraphElements = errorDiv.querySelectorAll('p'); - if (!paragraphElements || paragraphElements.length < 2) return; + if (!paragraphElements) return; paragraphElements[0].innerText = i18n.translate( 'xpack.observability.ruleCondition.chart.error_equation.title', { defaultMessage: 'An error occurred while rendering the chart', } ); - paragraphElements[1].innerText = i18n.translate( - 'xpack.observability.ruleCondition.chart.error_equation.description', - { - defaultMessage: 'Check the rule equation.', - } - ); + if (paragraphElements.length > 1) { + paragraphElements[1].innerText = i18n.translate( + 'xpack.observability.ruleCondition.chart.error_equation.description', + { + defaultMessage: 'Check the rule equation.', + } + ); + } } }); }, [chartLoading, attributes]); From 219ccb3396ed99e44eb1b6b609d30ce5d59ad8be Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Mon, 9 Dec 2024 19:30:44 +0100 Subject: [PATCH 08/12] Update searchSessionId on setDateRange --- .../asset_details/hooks/use_date_picker.ts | 9 +++---- .../asset_details/hooks/use_loading_state.ts | 26 ++++--------------- 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_date_picker.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_date_picker.ts index e6b69c1ddca8f..4cb20bfc4f3d5 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_date_picker.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_date_picker.ts @@ -52,8 +52,9 @@ export function useDatePicker({ (newDateRange: TimeRange) => { setUrlState({ dateRange: newDateRange }); setParsedDateRange(parseDateRange(newDateRange)); + updateSearchSessionId(); }, - [setUrlState] + [setUrlState, updateSearchSessionId] ); const onRefresh = useCallback( @@ -62,12 +63,10 @@ export function useDatePicker({ if (autoRefreshEnabled) { autoRefreshTick$.next(null); } else { - updateSearchSessionId(); + setDateRange(newDateRange); } - - setDateRange(newDateRange); }, - [autoRefreshEnabled, autoRefreshTick$, setDateRange, updateSearchSessionId] + [autoRefreshEnabled, autoRefreshTick$, setDateRange] ); const setAutoRefresh = useCallback( diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_loading_state.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_loading_state.ts index f3098b6dca8f8..662723cccb420 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_loading_state.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_loading_state.ts @@ -26,7 +26,6 @@ import { useCallback, useEffect, useMemo } from 'react'; import { SearchSessionState, waitUntilNextSessionCompletes$ } from '@kbn/data-plugin/public'; import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useDatePickerContext } from './use_date_picker'; -import { useSearchSessionContext } from '../../../hooks/use_search_session'; export type RequestState = 'running' | 'done' | 'error'; const WAIT_MS = 1000; @@ -37,16 +36,11 @@ export const useLoadingState = () => { const { data: { search }, } = services; - const { updateSearchSessionId } = useSearchSessionContext(); const isAutoRefreshRequestPending$ = useMemo(() => new BehaviorSubject(false), []); const requestsCount$ = useMemo(() => new BehaviorSubject(0), []); const requestState$ = useMemo(() => new BehaviorSubject(null), []); - useEffect(() => { - updateSearchSessionId(); - }, [updateSearchSessionId]); - const waitUntilRequestsCompletes$ = useCallback( () => requestsCount$.pipe( @@ -132,27 +126,17 @@ export const useLoadingState = () => { autoRefreshTick$.pipe( skipUntil(isAutoRefreshEnabled$()), - withLatestFrom(search.session.state$, isAutoRefreshRequestPending$), - switchMap(([_, state, isAutoRefreshRequestPending]) => { + withLatestFrom(search.session.state$), + switchMap(([_, state]) => { // if the current state$ value is not Completed if (state === SearchSessionState.Loading) { // Wait until queries using data.search complete before processing the next tick // This will only be called when Lens is used in the Asset Details page - return waitUntilNextSessionCompletes$(search.session).pipe( - tap(() => { - updateSearchSessionId(); - }) - ); + return waitUntilNextSessionCompletes$(search.session); } // Else immediately emit true if session state is already completed - return of(null).pipe( - tap(() => { - if (!isAutoRefreshRequestPending) { - updateSearchSessionId(); - } - }) - ); + return of(null); }) ) ).subscribe(); @@ -169,7 +153,7 @@ export const useLoadingState = () => { requestState$, requestsCount$, search.session, - updateSearchSessionId, + // updateSearchSessionId, waitUntilRequestsCompletes$, ]); From 8852912717de99a08b62fb8984cbe84804f902be Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Tue, 10 Dec 2024 09:05:29 +0100 Subject: [PATCH 09/12] bring back updateSessionId usage on useLoadingState --- .../asset_details/hooks/use_loading_state.ts | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_loading_state.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_loading_state.ts index 662723cccb420..f3098b6dca8f8 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_loading_state.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_loading_state.ts @@ -26,6 +26,7 @@ import { useCallback, useEffect, useMemo } from 'react'; import { SearchSessionState, waitUntilNextSessionCompletes$ } from '@kbn/data-plugin/public'; import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { useDatePickerContext } from './use_date_picker'; +import { useSearchSessionContext } from '../../../hooks/use_search_session'; export type RequestState = 'running' | 'done' | 'error'; const WAIT_MS = 1000; @@ -36,11 +37,16 @@ export const useLoadingState = () => { const { data: { search }, } = services; + const { updateSearchSessionId } = useSearchSessionContext(); const isAutoRefreshRequestPending$ = useMemo(() => new BehaviorSubject(false), []); const requestsCount$ = useMemo(() => new BehaviorSubject(0), []); const requestState$ = useMemo(() => new BehaviorSubject(null), []); + useEffect(() => { + updateSearchSessionId(); + }, [updateSearchSessionId]); + const waitUntilRequestsCompletes$ = useCallback( () => requestsCount$.pipe( @@ -126,17 +132,27 @@ export const useLoadingState = () => { autoRefreshTick$.pipe( skipUntil(isAutoRefreshEnabled$()), - withLatestFrom(search.session.state$), - switchMap(([_, state]) => { + withLatestFrom(search.session.state$, isAutoRefreshRequestPending$), + switchMap(([_, state, isAutoRefreshRequestPending]) => { // if the current state$ value is not Completed if (state === SearchSessionState.Loading) { // Wait until queries using data.search complete before processing the next tick // This will only be called when Lens is used in the Asset Details page - return waitUntilNextSessionCompletes$(search.session); + return waitUntilNextSessionCompletes$(search.session).pipe( + tap(() => { + updateSearchSessionId(); + }) + ); } // Else immediately emit true if session state is already completed - return of(null); + return of(null).pipe( + tap(() => { + if (!isAutoRefreshRequestPending) { + updateSearchSessionId(); + } + }) + ); }) ) ).subscribe(); @@ -153,7 +169,7 @@ export const useLoadingState = () => { requestState$, requestsCount$, search.session, - // updateSearchSessionId, + updateSearchSessionId, waitUntilRequestsCompletes$, ]); From 9323641c50a1e2c42a8f2f01c649f5c8fd47e058 Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Tue, 10 Dec 2024 22:29:10 +0100 Subject: [PATCH 10/12] fix test --- .../metrics/hosts/hooks/use_unified_search.ts | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts index 8a7302da1a223..6239d3db0362d 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts @@ -59,7 +59,11 @@ export const useUnifiedSearch = () => { const { data: { - query: { filterManager: filterManagerService, queryString: queryStringService }, + query: { + filterManager: filterManagerService, + queryString: queryStringService, + timefilter: timeFilterService, + }, }, telemetry, } = services; @@ -95,8 +99,9 @@ export const useUnifiedSearch = () => { const onDateRangeChange = useCallback( (dateRange: StringDateRange) => { setSearch({ type: 'SET_DATE_RANGE', dateRange }); + updateSearchSessionId(); }, - [setSearch] + [setSearch, updateSearchSessionId] ); const onQueryChange = useCallback( @@ -115,9 +120,8 @@ export const useUnifiedSearch = () => { const onSubmit = useCallback( ({ dateRange }: { dateRange: TimeRange }) => { onDateRangeChange(dateRange); - updateSearchSessionId(); }, - [onDateRangeChange, updateSearchSessionId] + [onDateRangeChange] ); const parsedDateRange = useMemo(() => { @@ -182,6 +186,16 @@ export const useUnifiedSearch = () => { .subscribe() ); + subscription.add( + timeFilterService.timefilter + .getTimeUpdate$() + .pipe( + map(() => timeFilterService.timefilter.getTime()), + tap((dateRange) => onDateRangeChange(dateRange)) + ) + .subscribe() + ); + subscription.add( queryStringService .getUpdates$() @@ -195,7 +209,14 @@ export const useUnifiedSearch = () => { return () => { subscription.unsubscribe(); }; - }, [filterManagerService, queryStringService, onQueryChange, onFiltersChange]); + }, [ + filterManagerService, + queryStringService, + onQueryChange, + onFiltersChange, + timeFilterService.timefilter, + onDateRangeChange, + ]); // Track telemetry event on query/filter/date changes useEffect(() => { From 3e818e5f3196aad9ce5fb222013c9de33f93bd84 Mon Sep 17 00:00:00 2001 From: dej611 Date: Wed, 11 Dec 2024 10:40:12 +0100 Subject: [PATCH 11/12] :bug: Fix missing sessionid --- .../react_embeddable/renderer/lens_custom_renderer_component.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/lens/public/react_embeddable/renderer/lens_custom_renderer_component.tsx b/x-pack/plugins/lens/public/react_embeddable/renderer/lens_custom_renderer_component.tsx index 7f31664e5cdd0..70d59fc7486b2 100644 --- a/x-pack/plugins/lens/public/react_embeddable/renderer/lens_custom_renderer_component.tsx +++ b/x-pack/plugins/lens/public/react_embeddable/renderer/lens_custom_renderer_component.tsx @@ -59,6 +59,7 @@ export function LensRenderer({ filters, timeRange, disabledActions, + searchSessionId, hidePanelTitles, ...props }: LensRendererProps) { From 9e6540198507daa11a3d26b5b12f9430a5124905 Mon Sep 17 00:00:00 2001 From: Carlos Crespo Date: Wed, 11 Dec 2024 11:02:12 +0100 Subject: [PATCH 12/12] Add missing sessionid update (#24) --- .../pages/metrics/hosts/hooks/use_unified_search.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts index 2976a378d1292..291f95554e89c 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts @@ -72,22 +72,25 @@ export const useUnifiedSearch = () => { const onFiltersChange = useCallback( (filters: Filter[]) => { setSearch({ type: 'SET_FILTERS', filters }); + updateSearchSessionId(); }, - [setSearch] + [setSearch, updateSearchSessionId] ); const onPanelFiltersChange = useCallback( (panelFilters: Filter[]) => { setSearch({ type: 'SET_PANEL_FILTERS', panelFilters }); + updateSearchSessionId(); }, - [setSearch] + [setSearch, updateSearchSessionId] ); const onLimitChange = useCallback( (limit: number) => { setSearch({ type: 'SET_LIMIT', limit }); + updateSearchSessionId(); }, - [setSearch] + [setSearch, updateSearchSessionId] ); const onDateRangeChange = useCallback( @@ -104,11 +107,12 @@ export const useUnifiedSearch = () => { setError(null); validateQuery(query); setSearch({ type: 'SET_QUERY', query }); + updateSearchSessionId(); } catch (err) { setError(err); } }, - [validateQuery, setSearch] + [validateQuery, setSearch, updateSearchSessionId] ); const onSubmit = useCallback(