diff --git a/x-pack/plugins/aiops/public/application/utils/query_utils.ts b/x-pack/plugins/aiops/public/application/utils/query_utils.ts index 85ad3d236a98e..9bbe22ed2406b 100644 --- a/x-pack/plugins/aiops/public/application/utils/query_utils.ts +++ b/x-pack/plugins/aiops/public/application/utils/query_utils.ts @@ -16,6 +16,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Query } from '@kbn/es-query'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import type { ChangePoint } from '@kbn/ml-agg-utils'; +import type { GroupTableItem } from '../../components/spike_analysis_table/spike_analysis_table_groups'; /* * Contains utility functions for building and processing queries. @@ -29,7 +30,8 @@ export function buildBaseFilterCriteria( latestMs?: number, query?: Query['query'], selectedChangePoint?: ChangePoint, - includeSelectedChangePoint = true + includeSelectedChangePoint = true, + selectedGroup?: GroupTableItem | null ): estypes.QueryDslQueryContainer[] { const filterCriteria = []; if (timeFieldName && earliestMs && latestMs) { @@ -47,11 +49,24 @@ export function buildBaseFilterCriteria( if (query && typeof query === 'object') { filterCriteria.push(query); } + const groupFilter = []; - if (selectedChangePoint && includeSelectedChangePoint) { - filterCriteria.push({ - term: { [selectedChangePoint.fieldName]: selectedChangePoint.fieldValue }, - }); + if (selectedGroup) { + for (const fieldName in selectedGroup.group) { + if (selectedGroup.group.hasOwnProperty(fieldName)) { + groupFilter.push({ term: { [fieldName]: selectedGroup.group[fieldName] } }); + } + } + } + + if (includeSelectedChangePoint) { + if (selectedChangePoint) { + filterCriteria.push({ + term: { [selectedChangePoint.fieldName]: selectedChangePoint.fieldValue }, + }); + } else if (selectedGroup) { + filterCriteria.push(...groupFilter); + } } else if (selectedChangePoint && !includeSelectedChangePoint) { filterCriteria.push({ bool: { @@ -59,6 +74,7 @@ export function buildBaseFilterCriteria( { term: { [selectedChangePoint.fieldName]: selectedChangePoint.fieldValue }, }, + ...groupFilter, ], }, }); diff --git a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx index 98d6053a8b6f6..31dc521a39506 100644 --- a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx +++ b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx @@ -32,6 +32,7 @@ import type { ApiExplainLogRateSpikes } from '../../../common/api'; import { SpikeAnalysisGroupsTable } from '../spike_analysis_table'; import { SpikeAnalysisTable } from '../spike_analysis_table'; +import { GroupTableItem } from '../spike_analysis_table/spike_analysis_table_groups'; const groupResultsMessage = i18n.translate( 'xpack.aiops.spikeAnalysisTable.groupedSwitchLabel.groupResults', @@ -56,6 +57,7 @@ interface ExplainLogRateSpikesAnalysisProps { onPinnedChangePoint?: (changePoint: ChangePoint | null) => void; onSelectedChangePoint?: (changePoint: ChangePoint | null) => void; selectedChangePoint?: ChangePoint; + onSelectedGroup?: (group: GroupTableItem | null) => void; } export const ExplainLogRateSpikesAnalysis: FC = ({ @@ -67,6 +69,7 @@ export const ExplainLogRateSpikesAnalysis: FC onPinnedChangePoint, onSelectedChangePoint, selectedChangePoint, + onSelectedGroup, }) => { const { http } = useAiopsAppContext(); const basePath = http.basePath.get() ?? ''; @@ -244,6 +247,7 @@ export const ExplainLogRateSpikesAnalysis: FC onPinnedChangePoint={onPinnedChangePoint} onSelectedChangePoint={onSelectedChangePoint} selectedChangePoint={selectedChangePoint} + onSelectedGroup={onSelectedGroup} dataViewId={dataView.id} /> ) : null} diff --git a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_page.tsx b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_page.tsx index bdc91175c2913..370eed0b522c5 100644 --- a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_page.tsx +++ b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_page.tsx @@ -37,6 +37,7 @@ import { SearchPanel } from '../search_panel'; import { restorableDefaults } from './explain_log_rate_spikes_app_state'; import { ExplainLogRateSpikesAnalysis } from './explain_log_rate_spikes_analysis'; +import type { GroupTableItem } from '../spike_analysis_table/spike_analysis_table_groups'; // TODO port to `@emotion/react` once `useEuiBreakpoint` is available https://github.com/elastic/eui/pull/6057 import './explain_log_rate_spikes_page.scss'; @@ -94,6 +95,7 @@ export const ExplainLogRateSpikesPage: FC = ({ const [pinnedChangePoint, setPinnedChangePoint] = useState(null); const [selectedChangePoint, setSelectedChangePoint] = useState(null); + const [selectedGroup, setSelectedGroup] = useState(null); // If a row is pinned, still overrule with a potentially hovered row. const currentSelectedChangePoint = useMemo(() => { @@ -116,7 +118,8 @@ export const ExplainLogRateSpikesPage: FC = ({ { currentDataView: dataView, currentSavedSearch }, aiopsListState, setGlobalState, - currentSelectedChangePoint + currentSelectedChangePoint, + selectedGroup ); const { totalCount, documentCountStats, documentCountStatsCompare } = documentStats; @@ -167,6 +170,7 @@ export const ExplainLogRateSpikesPage: FC = ({ setWindowParameters(undefined); setPinnedChangePoint(null); setSelectedChangePoint(null); + setSelectedGroup(null); } return ( @@ -225,7 +229,9 @@ export const ExplainLogRateSpikesPage: FC = ({ clearSelectionHandler={clearSelection} documentCountStats={documentCountStats} documentCountStatsSplit={ - currentSelectedChangePoint ? documentCountStatsCompare : undefined + currentSelectedChangePoint || selectedGroup + ? documentCountStatsCompare + : undefined } totalCount={totalCount} changePoint={currentSelectedChangePoint} @@ -246,6 +252,7 @@ export const ExplainLogRateSpikesPage: FC = ({ onPinnedChangePoint={setPinnedChangePoint} onSelectedChangePoint={setSelectedChangePoint} selectedChangePoint={currentSelectedChangePoint} + onSelectedGroup={setSelectedGroup} /> )} {windowParameters === undefined && ( diff --git a/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table.tsx b/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table.tsx index 8a65a938d38c9..3515de2aeb721 100644 --- a/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table.tsx +++ b/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table.tsx @@ -32,6 +32,7 @@ import { getFailedTransactionsCorrelationImpactLabel } from './get_failed_transa const NARROW_COLUMN_WIDTH = '120px'; const ACTIONS_COLUMN_WIDTH = '60px'; +const NOT_AVAILABLE = '--'; const PAGINATION_SIZE_OPTIONS = [5, 10, 20, 50]; const DEFAULT_SORT_FIELD = 'pValue'; @@ -169,13 +170,16 @@ export const SpikeAnalysisTable: FC = ({ ), - render: (_, { histogram, fieldName, fieldValue }) => ( - - ), + render: (_, { histogram, fieldName, fieldValue }) => { + if (!histogram) return NOT_AVAILABLE; + return ( + + ); + }, sortable: false, }, { @@ -229,6 +233,7 @@ export const SpikeAnalysisTable: FC = ({ ), render: (_, { pValue }) => { + if (!pValue) return NOT_AVAILABLE; const label = getFailedTransactionsCorrelationImpactLabel(pValue); return label ? {label.impact} : null; }, diff --git a/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_expanded_row.tsx b/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_expanded_row.tsx deleted file mode 100644 index 367e5f32c695b..0000000000000 --- a/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_expanded_row.tsx +++ /dev/null @@ -1,357 +0,0 @@ -/* - * 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 React, { FC, useCallback, useMemo, useState } from 'react'; -import { sortBy } from 'lodash'; - -import { - EuiBadge, - EuiBasicTable, - EuiBasicTableColumn, - EuiIcon, - EuiTableSortingType, - EuiToolTip, -} from '@elastic/eui'; - -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { escapeKuery } from '@kbn/es-query'; -import type { ChangePoint } from '@kbn/ml-agg-utils'; - -import { SEARCH_QUERY_LANGUAGE } from '../../application/utils/search_utils'; -import { useEuiTheme } from '../../hooks/use_eui_theme'; -import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; - -import { MiniHistogram } from '../mini_histogram'; - -import { getFailedTransactionsCorrelationImpactLabel } from './get_failed_transactions_correlation_impact_label'; - -const NARROW_COLUMN_WIDTH = '120px'; -const ACTIONS_COLUMN_WIDTH = '60px'; -const NOT_AVAILABLE = '--'; - -const PAGINATION_SIZE_OPTIONS = [5, 10, 20, 50]; -const DEFAULT_SORT_FIELD = 'pValue'; -const DEFAULT_SORT_DIRECTION = 'asc'; -const viewInDiscoverMessage = i18n.translate( - 'xpack.aiops.spikeAnalysisTable.linksMenu.viewInDiscover', - { - defaultMessage: 'View in Discover', - } -); - -interface SpikeAnalysisTableExpandedRowProps { - changePoints: ChangePoint[]; - dataViewId?: string; - loading: boolean; - onPinnedChangePoint?: (changePoint: ChangePoint | null) => void; - onSelectedChangePoint?: (changePoint: ChangePoint | null) => void; - selectedChangePoint?: ChangePoint; -} - -export const SpikeAnalysisTableExpandedRow: FC = ({ - changePoints, - dataViewId, - loading, - onPinnedChangePoint, - onSelectedChangePoint, - selectedChangePoint, -}) => { - const euiTheme = useEuiTheme(); - - const [pageIndex, setPageIndex] = useState(0); - const [pageSize, setPageSize] = useState(10); - const [sortField, setSortField] = useState(DEFAULT_SORT_FIELD); - const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>(DEFAULT_SORT_DIRECTION); - - const { application, share, data } = useAiopsAppContext(); - - const discoverLocator = useMemo( - () => share.url.locators.get('DISCOVER_APP_LOCATOR'), - [share.url.locators] - ); - - const discoverUrlError = useMemo(() => { - if (!application.capabilities.discover?.show) { - const discoverNotEnabled = i18n.translate( - 'xpack.aiops.spikeAnalysisTable.discoverNotEnabledErrorMessage', - { - defaultMessage: 'Discover is not enabled', - } - ); - - return discoverNotEnabled; - } - if (!discoverLocator) { - const discoverLocatorMissing = i18n.translate( - 'xpack.aiops.spikeAnalysisTable.discoverLocatorMissingErrorMessage', - { - defaultMessage: 'No locator for Discover detected', - } - ); - - return discoverLocatorMissing; - } - if (!dataViewId) { - const autoGeneratedDiscoverLinkError = i18n.translate( - 'xpack.aiops.spikeAnalysisTable.autoGeneratedDiscoverLinkErrorMessage', - { - defaultMessage: 'Unable to link to Discover; no data view exists for this index', - } - ); - - return autoGeneratedDiscoverLinkError; - } - }, [application.capabilities.discover?.show, dataViewId, discoverLocator]); - - const generateDiscoverUrl = async (changePoint: ChangePoint) => { - if (discoverLocator !== undefined) { - const url = await discoverLocator.getRedirectUrl({ - indexPatternId: dataViewId, - timeRange: data.query.timefilter.timefilter.getTime(), - filters: data.query.filterManager.getFilters(), - query: { - language: SEARCH_QUERY_LANGUAGE.KUERY, - query: `${escapeKuery(changePoint.fieldName)}:${escapeKuery( - String(changePoint.fieldValue) - )}`, - }, - }); - - return url; - } - }; - - const columns: Array> = [ - { - 'data-test-subj': 'aiopsSpikeAnalysisTableColumnFieldName', - field: 'fieldName', - name: i18n.translate( - 'xpack.aiops.correlations.failedTransactions.correlationsTable.fieldNameLabel', - { defaultMessage: 'Field name' } - ), - sortable: true, - }, - { - 'data-test-subj': 'aiopsSpikeAnalysisTableColumnFieldValue', - field: 'fieldValue', - name: i18n.translate( - 'xpack.aiops.correlations.failedTransactions.correlationsTable.fieldValueLabel', - { defaultMessage: 'Field value' } - ), - render: (_, { fieldValue }) => String(fieldValue).slice(0, 50), - sortable: true, - }, - { - 'data-test-subj': 'aiopsSpikeAnalysisTableColumnLogRate', - width: NARROW_COLUMN_WIDTH, - field: 'pValue', - name: ( - - <> - - - - - ), - render: (_, { histogram, fieldName, fieldValue }) => { - if (!histogram) return NOT_AVAILABLE; - return ( - - ); - }, - sortable: false, - }, - { - 'data-test-subj': 'aiopsSpikeAnalysisTableColumnPValue', - width: NARROW_COLUMN_WIDTH, - field: 'pValue', - name: ( - - <> - - - - - ), - render: (pValue: number) => pValue?.toPrecision(3) ?? NOT_AVAILABLE, - sortable: true, - }, - { - 'data-test-subj': 'aiopsSpikeAnalysisTableColumnImpact', - width: NARROW_COLUMN_WIDTH, - field: 'pValue', - name: ( - - <> - - - - - ), - render: (_, { pValue }) => { - if (!pValue) return NOT_AVAILABLE; - const label = getFailedTransactionsCorrelationImpactLabel(pValue); - return label ? {label.impact} : null; - }, - sortable: true, - }, - { - 'data-test-subj': 'aiOpsSpikeAnalysisTableColumnAction', - name: i18n.translate('xpack.aiops.spikeAnalysisTable.actionsColumnName', { - defaultMessage: 'Actions', - }), - actions: [ - { - name: () => ( - - - - ), - description: viewInDiscoverMessage, - type: 'button', - onClick: async (changePoint) => { - const openInDiscoverUrl = await generateDiscoverUrl(changePoint); - if (typeof openInDiscoverUrl === 'string') { - await application.navigateToUrl(openInDiscoverUrl); - } - }, - enabled: () => discoverUrlError === undefined, - }, - ], - width: ACTIONS_COLUMN_WIDTH, - }, - ]; - - const onChange = useCallback((tableSettings) => { - const { index, size } = tableSettings.page; - const { field, direction } = tableSettings.sort; - - setPageIndex(index); - setPageSize(size); - setSortField(field); - setSortDirection(direction); - }, []); - - const { pagination, pageOfItems, sorting } = useMemo(() => { - const pageStart = pageIndex * pageSize; - const itemCount = changePoints?.length ?? 0; - - let items: ChangePoint[] = changePoints ?? []; - items = sortBy(changePoints, (item) => { - if (item && typeof item[sortField] === 'string') { - // @ts-ignore Object is possibly null or undefined - return item[sortField].toLowerCase(); - } - return item[sortField]; - }); - items = sortDirection === 'asc' ? items : items.reverse(); - - return { - pageOfItems: items.slice(pageStart, pageStart + pageSize), - pagination: { - pageIndex, - pageSize, - totalItemCount: itemCount, - pageSizeOptions: PAGINATION_SIZE_OPTIONS, - }, - sorting: { - sort: { - field: sortField, - direction: sortDirection, - }, - }, - }; - }, [pageIndex, pageSize, sortField, sortDirection, changePoints]); - - // Don't pass on the `loading` state to the table itself because - // it disables hovering events. Because the mini histograms take a while - // to load, hovering would not update the main chart. Instead, - // the loading state is shown by the progress bar on the outer component level. - // The outer component also will display a prompt when no data was returned - // running the analysis and will hide this table. - - return ( - } - rowProps={(changePoint) => { - return { - 'data-test-subj': `aiopsSpikeAnalysisTableRow row-${changePoint.fieldName}-${changePoint.fieldValue}`, - onClick: () => { - if (onPinnedChangePoint) { - onPinnedChangePoint(changePoint); - } - }, - onMouseEnter: () => { - if (onSelectedChangePoint) { - onSelectedChangePoint(changePoint); - } - }, - onMouseLeave: () => { - if (onSelectedChangePoint) { - onSelectedChangePoint(null); - } - }, - style: - selectedChangePoint && - selectedChangePoint.fieldValue === changePoint.fieldValue && - selectedChangePoint.fieldName === changePoint.fieldName - ? { - backgroundColor: euiTheme.euiColorLightestShade, - } - : null, - }; - }} - /> - ); -}; diff --git a/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_groups.tsx b/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_groups.tsx index 7b61911a96384..66ce76c25c1da 100644 --- a/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_groups.tsx +++ b/x-pack/plugins/aiops/public/components/spike_analysis_table/spike_analysis_table_groups.tsx @@ -22,12 +22,12 @@ import { import { i18n } from '@kbn/i18n'; import type { ChangePoint } from '@kbn/ml-agg-utils'; import { useEuiTheme } from '../../hooks/use_eui_theme'; -import { SpikeAnalysisTableExpandedRow } from './spike_analysis_table_expanded_row'; +import { SpikeAnalysisTable } from './spike_analysis_table'; const PAGINATION_SIZE_OPTIONS = [5, 10, 20, 50]; const DEFAULT_SORT_FIELD = 'docCount'; const DEFAULT_SORT_DIRECTION = 'desc'; -interface GroupTableItem { +export interface GroupTableItem { id: number; docCount: number; group: Record; @@ -42,6 +42,7 @@ interface SpikeAnalysisTableProps { onPinnedChangePoint?: (changePoint: ChangePoint | null) => void; onSelectedChangePoint?: (changePoint: ChangePoint | null) => void; selectedChangePoint?: ChangePoint; + onSelectedGroup?: (group: GroupTableItem | null) => void; } export const SpikeAnalysisGroupsTable: FC = ({ @@ -52,6 +53,7 @@ export const SpikeAnalysisGroupsTable: FC = ({ onPinnedChangePoint, onSelectedChangePoint, selectedChangePoint, + onSelectedGroup, }) => { const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); @@ -91,7 +93,7 @@ export const SpikeAnalysisGroupsTable: FC = ({ } itemIdToExpandedRowMapValues[item.id] = ( - = ({ toggleDetails(item)} - aria-label={itemIdToExpandedRowMap[item.id] ? 'Collapse' : 'Expand'} + aria-label={ + itemIdToExpandedRowMap[item.id] + ? i18n.translate('xpack.aiops.correlations.correlationsTable.collapseAriaLabel', { + defaultMessage: 'Collapse', + }) + : i18n.translate('xpack.aiops.correlations.correlationsTable.expandAriaLabel', { + defaultMessage: 'Expand', + }) + } iconType={itemIdToExpandedRowMap[item.id] ? 'arrowUp' : 'arrowDown'} /> ), @@ -236,8 +246,46 @@ export const SpikeAnalysisGroupsTable: FC = ({ rowProps={(group) => { return { 'data-test-subj': `aiopsSpikeAnalysisGroupsTableRow row-${group.id}`, + onMouseEnter: () => { + if (onSelectedGroup) { + onSelectedGroup(group); + } + }, + onMouseLeave: () => { + if (onSelectedGroup) { + onSelectedGroup(null); + } + }, }; }} + // rowProps={(changePoint) => { + // return { + // 'data-test-subj': `aiopsSpikeAnalysisTableRow row-${changePoint.fieldName}-${changePoint.fieldValue}`, + // onClick: () => { + // if (onPinnedChangePoint) { + // onPinnedChangePoint(changePoint); + // } + // }, + // onMouseEnter: () => { + // if (onSelectedChangePoint) { + // onSelectedChangePoint(changePoint); + // } + // }, + // onMouseLeave: () => { + // if (onSelectedChangePoint) { + // onSelectedChangePoint(null); + // } + // }, + // style: + // selectedChangePoint && + // selectedChangePoint.fieldValue === changePoint.fieldValue && + // selectedChangePoint.fieldName === changePoint.fieldName + // ? { + // backgroundColor: euiTheme.euiColorLightestShade, + // } + // : null, + // }; + // }} /> ); }; diff --git a/x-pack/plugins/aiops/public/get_document_stats.ts b/x-pack/plugins/aiops/public/get_document_stats.ts index 1df4e4bd57ae8..07324b5f10605 100644 --- a/x-pack/plugins/aiops/public/get_document_stats.ts +++ b/x-pack/plugins/aiops/public/get_document_stats.ts @@ -14,6 +14,7 @@ import type { ChangePoint } from '@kbn/ml-agg-utils'; import type { Query } from '@kbn/es-query'; import { buildBaseFilterCriteria } from './application/utils/query_utils'; +import { GroupTableItem } from './components/spike_analysis_table/spike_analysis_table_groups'; export interface DocumentCountStats { interval?: number; @@ -34,6 +35,7 @@ export interface DocumentStatsSearchStrategyParams { fieldsToFetch?: string[]; selectedChangePoint?: ChangePoint; includeSelectedChangePoint?: boolean; + selectedGroup?: GroupTableItem | null; } export const getDocumentCountStatsRequest = (params: DocumentStatsSearchStrategyParams) => { @@ -48,6 +50,7 @@ export const getDocumentCountStatsRequest = (params: DocumentStatsSearchStrategy fieldsToFetch, selectedChangePoint, includeSelectedChangePoint, + selectedGroup, } = params; const size = 0; @@ -57,7 +60,8 @@ export const getDocumentCountStatsRequest = (params: DocumentStatsSearchStrategy latestMs, searchQuery, selectedChangePoint, - includeSelectedChangePoint + includeSelectedChangePoint, + selectedGroup ); // Don't use the sampler aggregation as this can lead to some potentially diff --git a/x-pack/plugins/aiops/public/hooks/use_data.ts b/x-pack/plugins/aiops/public/hooks/use_data.ts index 9ea8f9bd2335b..c2e390d44ceb8 100644 --- a/x-pack/plugins/aiops/public/hooks/use_data.ts +++ b/x-pack/plugins/aiops/public/hooks/use_data.ts @@ -28,6 +28,7 @@ import { import { useTimefilter } from './use_time_filter'; import { useDocumentCountStats } from './use_document_count_stats'; import type { Dictionary } from './use_url_state'; +import type { GroupTableItem } from '../components/spike_analysis_table/spike_analysis_table_groups'; const DEFAULT_BAR_TARGET = 75; @@ -39,7 +40,8 @@ export const useData = ( aiopsListState: AiOpsIndexBasedAppState, onUpdate: (params: Dictionary) => void, selectedChangePoint?: ChangePoint, - barTarget: number = DEFAULT_BAR_TARGET + barTarget: number = DEFAULT_BAR_TARGET, + selectedGroup?: GroupTableItem | null ) => { const { uiSettings, @@ -114,10 +116,15 @@ export const useData = ( }, [fieldStatsRequest, selectedChangePoint]); const selectedChangePointStatsRequest = useMemo(() => { - return fieldStatsRequest && selectedChangePoint - ? { ...fieldStatsRequest, selectedChangePoint, includeSelectedChangePoint: true } + return fieldStatsRequest && (selectedChangePoint || selectedGroup) + ? { + ...fieldStatsRequest, + selectedChangePoint, + selectedGroup, + includeSelectedChangePoint: true, + } : undefined; - }, [fieldStatsRequest, selectedChangePoint]); + }, [fieldStatsRequest, selectedChangePoint, selectedGroup]); const documentStats = useDocumentCountStats( overallStatsRequest,