mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[ML] Explain Log Rate Spikes: Fix analysis table row pinning. (#141455)
- Fixes styling of hovered and pinned rows to use EUI provided variables. - The above was also done for the Log Pattern Analysis page to fix an issue with dark theme. - Fixes unpinning a row for field/value pairs. - Fixes pinning/unpinning for groups.
This commit is contained in:
parent
f576b1f467
commit
8937be2db4
11 changed files with 250 additions and 106 deletions
|
@ -120,7 +120,7 @@ export const DocumentCountChart: FC<DocumentCountChartProps> = ({
|
|||
const overallSeriesNameWithSplit = i18n.translate(
|
||||
'xpack.aiops.dataGrid.field.documentCountChartSplit.seriesLabel',
|
||||
{
|
||||
defaultMessage: 'other document count',
|
||||
defaultMessage: 'Other document count',
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -5,13 +5,12 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState, FC, useMemo } from 'react';
|
||||
import React, { useEffect, useState, FC } from 'react';
|
||||
|
||||
import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { WindowParameters } from '@kbn/aiops-utils';
|
||||
import type { ChangePoint } from '@kbn/ml-agg-utils';
|
||||
|
||||
import { DocumentCountChart, DocumentCountChartPoint } from '../document_count_chart';
|
||||
import { TotalCountHeader } from '../total_count_header';
|
||||
|
@ -27,9 +26,9 @@ const clearSelectionLabel = i18n.translate(
|
|||
export interface DocumentCountContentProps {
|
||||
brushSelectionUpdateHandler: (d: WindowParameters) => void;
|
||||
clearSelectionHandler: () => void;
|
||||
changePoint?: ChangePoint;
|
||||
documentCountStats?: DocumentCountStats;
|
||||
documentCountStatsSplit?: DocumentCountStats;
|
||||
documentCountStatsSplitLabel?: string;
|
||||
totalCount: number;
|
||||
windowParameters?: WindowParameters;
|
||||
}
|
||||
|
@ -37,9 +36,9 @@ export interface DocumentCountContentProps {
|
|||
export const DocumentCountContent: FC<DocumentCountContentProps> = ({
|
||||
brushSelectionUpdateHandler,
|
||||
clearSelectionHandler,
|
||||
changePoint,
|
||||
documentCountStats,
|
||||
documentCountStatsSplit,
|
||||
documentCountStatsSplitLabel = '',
|
||||
totalCount,
|
||||
windowParameters,
|
||||
}) => {
|
||||
|
@ -52,10 +51,6 @@ export const DocumentCountContent: FC<DocumentCountContentProps> = ({
|
|||
const bucketTimestamps = Object.keys(documentCountStats?.buckets ?? {}).map((time) => +time);
|
||||
const timeRangeEarliest = Math.min(...bucketTimestamps);
|
||||
const timeRangeLatest = Math.max(...bucketTimestamps);
|
||||
const chartPointsSplitLabel = useMemo(
|
||||
() => `${changePoint?.fieldName}:${changePoint?.fieldValue}`,
|
||||
[changePoint]
|
||||
);
|
||||
|
||||
if (
|
||||
documentCountStats === undefined ||
|
||||
|
@ -121,7 +116,7 @@ export const DocumentCountContent: FC<DocumentCountContentProps> = ({
|
|||
timeRangeEarliest={timeRangeEarliest}
|
||||
timeRangeLatest={timeRangeLatest}
|
||||
interval={documentCountStats.interval}
|
||||
chartPointsSplitLabel={chartPointsSplitLabel}
|
||||
chartPointsSplitLabel={documentCountStatsSplitLabel}
|
||||
isBrushCleared={isBrushCleared}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -23,7 +23,6 @@ import { useFetchStream } from '@kbn/aiops-utils';
|
|||
import type { WindowParameters } from '@kbn/aiops-utils';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import type { ChangePoint } from '@kbn/ml-agg-utils';
|
||||
import type { Query } from '@kbn/es-query';
|
||||
|
||||
import { useAiopsAppContext } from '../../hooks/use_aiops_app_context';
|
||||
|
@ -32,7 +31,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';
|
||||
import { useSpikeAnalysisTableRowContext } from '../spike_analysis_table/spike_analysis_table_row_provider';
|
||||
|
||||
const groupResultsMessage = i18n.translate(
|
||||
'xpack.aiops.spikeAnalysisTable.groupedSwitchLabel.groupResults',
|
||||
|
@ -54,10 +53,6 @@ interface ExplainLogRateSpikesAnalysisProps {
|
|||
/** Window parameters for the analysis */
|
||||
windowParameters: WindowParameters;
|
||||
searchQuery: Query['query'];
|
||||
onPinnedChangePoint?: (changePoint: ChangePoint | null) => void;
|
||||
onSelectedChangePoint?: (changePoint: ChangePoint | null) => void;
|
||||
selectedChangePoint?: ChangePoint;
|
||||
onSelectedGroup?: (group: GroupTableItem | null) => void;
|
||||
}
|
||||
|
||||
export const ExplainLogRateSpikesAnalysis: FC<ExplainLogRateSpikesAnalysisProps> = ({
|
||||
|
@ -66,14 +61,12 @@ export const ExplainLogRateSpikesAnalysis: FC<ExplainLogRateSpikesAnalysisProps>
|
|||
latest,
|
||||
windowParameters,
|
||||
searchQuery,
|
||||
onPinnedChangePoint,
|
||||
onSelectedChangePoint,
|
||||
selectedChangePoint,
|
||||
onSelectedGroup,
|
||||
}) => {
|
||||
const { http } = useAiopsAppContext();
|
||||
const basePath = http.basePath.get() ?? '';
|
||||
|
||||
const { clearAllRowState } = useSpikeAnalysisTableRowContext();
|
||||
|
||||
const [currentAnalysisWindowParameters, setCurrentAnalysisWindowParameters] = useState<
|
||||
WindowParameters | undefined
|
||||
>();
|
||||
|
@ -81,6 +74,9 @@ export const ExplainLogRateSpikesAnalysis: FC<ExplainLogRateSpikesAnalysisProps>
|
|||
|
||||
const onSwitchToggle = (e: { target: { checked: React.SetStateAction<boolean> } }) => {
|
||||
setGroupResults(e.target.checked);
|
||||
|
||||
// When toggling the group switch, clear all row selections
|
||||
clearAllRowState();
|
||||
};
|
||||
|
||||
const {
|
||||
|
@ -109,15 +105,9 @@ export const ExplainLogRateSpikesAnalysis: FC<ExplainLogRateSpikesAnalysisProps>
|
|||
// Start handler clears possibly hovered or pinned
|
||||
// change points on analysis refresh.
|
||||
function startHandler() {
|
||||
// Reset grouping to false when restarting the analysis.
|
||||
// Reset grouping to false and clear all row selections when restarting the analysis.
|
||||
setGroupResults(false);
|
||||
|
||||
if (onPinnedChangePoint) {
|
||||
onPinnedChangePoint(null);
|
||||
}
|
||||
if (onSelectedChangePoint) {
|
||||
onSelectedChangePoint(null);
|
||||
}
|
||||
clearAllRowState();
|
||||
|
||||
setCurrentAnalysisWindowParameters(windowParameters);
|
||||
start();
|
||||
|
@ -249,10 +239,6 @@ export const ExplainLogRateSpikesAnalysis: FC<ExplainLogRateSpikesAnalysisProps>
|
|||
changePoints={data.changePoints}
|
||||
groupTableItems={groupTableItems}
|
||||
loading={isRunning}
|
||||
onPinnedChangePoint={onPinnedChangePoint}
|
||||
onSelectedChangePoint={onSelectedChangePoint}
|
||||
selectedChangePoint={selectedChangePoint}
|
||||
onSelectedGroup={onSelectedGroup}
|
||||
dataViewId={dataView.id}
|
||||
/>
|
||||
) : null}
|
||||
|
@ -260,9 +246,6 @@ export const ExplainLogRateSpikesAnalysis: FC<ExplainLogRateSpikesAnalysisProps>
|
|||
<SpikeAnalysisTable
|
||||
changePoints={data.changePoints}
|
||||
loading={isRunning}
|
||||
onPinnedChangePoint={onPinnedChangePoint}
|
||||
onSelectedChangePoint={onSelectedChangePoint}
|
||||
selectedChangePoint={selectedChangePoint}
|
||||
dataViewId={dataView.id}
|
||||
/>
|
||||
) : null}
|
||||
|
|
|
@ -36,6 +36,8 @@ import {
|
|||
import type { AiopsAppDependencies } from '../../hooks/use_aiops_app_context';
|
||||
import { AiopsAppContext } from '../../hooks/use_aiops_app_context';
|
||||
|
||||
import { SpikeAnalysisTableRowStateProvider } from '../spike_analysis_table/spike_analysis_table_row_provider';
|
||||
|
||||
import { ExplainLogRateSpikesPage } from './explain_log_rate_spikes_page';
|
||||
|
||||
export interface ExplainLogRateSpikesAppStateProps {
|
||||
|
@ -164,7 +166,9 @@ export const ExplainLogRateSpikesAppState: FC<ExplainLogRateSpikesAppStateProps>
|
|||
return (
|
||||
<AiopsAppContext.Provider value={appDependencies}>
|
||||
<UrlStateContextProvider value={{ searchString: urlSearchString, setUrlState }}>
|
||||
<ExplainLogRateSpikesPage dataView={dataView} savedSearch={savedSearch} />
|
||||
<SpikeAnalysisTableRowStateProvider>
|
||||
<ExplainLogRateSpikesPage dataView={dataView} savedSearch={savedSearch} />
|
||||
</SpikeAnalysisTableRowStateProvider>
|
||||
</UrlStateContextProvider>
|
||||
</AiopsAppContext.Provider>
|
||||
);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect, useMemo, useState, FC } from 'react';
|
||||
import React, { useCallback, useEffect, useState, FC } from 'react';
|
||||
import {
|
||||
EuiEmptyPrompt,
|
||||
EuiFlexGroup,
|
||||
|
@ -19,6 +19,7 @@ import {
|
|||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import type { WindowParameters } from '@kbn/aiops-utils';
|
||||
import type { ChangePoint } from '@kbn/ml-agg-utils';
|
||||
|
@ -38,10 +39,21 @@ 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';
|
||||
import { useSpikeAnalysisTableRowContext } from '../spike_analysis_table/spike_analysis_table_row_provider';
|
||||
|
||||
// TODO port to `@emotion/react` once `useEuiBreakpoint` is available https://github.com/elastic/eui/pull/6057
|
||||
import './explain_log_rate_spikes_page.scss';
|
||||
|
||||
function getDocumentCountStatsSplitLabel(changePoint?: ChangePoint, group?: GroupTableItem) {
|
||||
if (changePoint) {
|
||||
return `${changePoint?.fieldName}:${changePoint?.fieldValue}`;
|
||||
} else if (group) {
|
||||
return i18n.translate('xpack.aiops.spikeAnalysisPage.documentCountStatsSplitGroupLabel', {
|
||||
defaultMessage: 'Selected group',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ExplainLogRateSpikes props require a data view.
|
||||
*/
|
||||
|
@ -58,6 +70,15 @@ export const ExplainLogRateSpikesPage: FC<ExplainLogRateSpikesPageProps> = ({
|
|||
}) => {
|
||||
const { data: dataService } = useAiopsAppContext();
|
||||
|
||||
const {
|
||||
currentSelectedChangePoint,
|
||||
currentSelectedGroup,
|
||||
setPinnedChangePoint,
|
||||
setPinnedGroup,
|
||||
setSelectedChangePoint,
|
||||
setSelectedGroup,
|
||||
} = useSpikeAnalysisTableRowContext();
|
||||
|
||||
const [aiopsListState, setAiopsListState] = usePageUrlState(AppStateKey, restorableDefaults);
|
||||
const [globalState, setGlobalState] = useUrlState('_g');
|
||||
|
||||
|
@ -93,19 +114,6 @@ export const ExplainLogRateSpikesPage: FC<ExplainLogRateSpikesPageProps> = ({
|
|||
[currentSavedSearch, aiopsListState, setAiopsListState]
|
||||
);
|
||||
|
||||
const [pinnedChangePoint, setPinnedChangePoint] = useState<ChangePoint | null>(null);
|
||||
const [selectedChangePoint, setSelectedChangePoint] = useState<ChangePoint | null>(null);
|
||||
const [selectedGroup, setSelectedGroup] = useState<GroupTableItem | null>(null);
|
||||
|
||||
// If a row is pinned, still overrule with a potentially hovered row.
|
||||
const currentSelectedChangePoint = useMemo(() => {
|
||||
if (selectedChangePoint) {
|
||||
return selectedChangePoint;
|
||||
} else if (pinnedChangePoint) {
|
||||
return pinnedChangePoint;
|
||||
}
|
||||
}, [pinnedChangePoint, selectedChangePoint]);
|
||||
|
||||
const {
|
||||
documentStats,
|
||||
timefilter,
|
||||
|
@ -119,8 +127,7 @@ export const ExplainLogRateSpikesPage: FC<ExplainLogRateSpikesPageProps> = ({
|
|||
aiopsListState,
|
||||
setGlobalState,
|
||||
currentSelectedChangePoint,
|
||||
undefined,
|
||||
selectedGroup
|
||||
currentSelectedGroup
|
||||
);
|
||||
|
||||
const { totalCount, documentCountStats, documentCountStatsCompare } = documentStats;
|
||||
|
@ -170,6 +177,7 @@ export const ExplainLogRateSpikesPage: FC<ExplainLogRateSpikesPageProps> = ({
|
|||
function clearSelection() {
|
||||
setWindowParameters(undefined);
|
||||
setPinnedChangePoint(null);
|
||||
setPinnedGroup(null);
|
||||
setSelectedChangePoint(null);
|
||||
setSelectedGroup(null);
|
||||
}
|
||||
|
@ -230,12 +238,15 @@ export const ExplainLogRateSpikesPage: FC<ExplainLogRateSpikesPageProps> = ({
|
|||
clearSelectionHandler={clearSelection}
|
||||
documentCountStats={documentCountStats}
|
||||
documentCountStatsSplit={
|
||||
currentSelectedChangePoint || selectedGroup
|
||||
currentSelectedChangePoint || currentSelectedGroup
|
||||
? documentCountStatsCompare
|
||||
: undefined
|
||||
}
|
||||
documentCountStatsSplitLabel={getDocumentCountStatsSplitLabel(
|
||||
currentSelectedChangePoint,
|
||||
currentSelectedGroup
|
||||
)}
|
||||
totalCount={totalCount}
|
||||
changePoint={currentSelectedChangePoint}
|
||||
windowParameters={windowParameters}
|
||||
/>
|
||||
</EuiPanel>
|
||||
|
@ -250,10 +261,6 @@ export const ExplainLogRateSpikesPage: FC<ExplainLogRateSpikesPageProps> = ({
|
|||
latest={latest}
|
||||
windowParameters={windowParameters}
|
||||
searchQuery={searchQuery}
|
||||
onPinnedChangePoint={setPinnedChangePoint}
|
||||
onSelectedChangePoint={setSelectedChangePoint}
|
||||
selectedChangePoint={currentSelectedChangePoint}
|
||||
onSelectedGroup={setSelectedGroup}
|
||||
/>
|
||||
)}
|
||||
{windowParameters === undefined && (
|
||||
|
|
|
@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import type { TimefilterContract } from '@kbn/data-plugin/public';
|
||||
import {
|
||||
useEuiBackgroundColor,
|
||||
EuiButton,
|
||||
EuiSpacer,
|
||||
EuiFlexGroup,
|
||||
|
@ -62,6 +63,7 @@ export const CategoryTable: FC<Props> = ({
|
|||
setSelectedCategory,
|
||||
}) => {
|
||||
const euiTheme = useEuiTheme();
|
||||
const primaryBackgroundColor = useEuiBackgroundColor('primary');
|
||||
const { openInDiscoverWithFilter } = useDiscoverLinks();
|
||||
const [selectedCategories, setSelectedCategories] = useState<Category[]>([]);
|
||||
const { onTableChange, pagination, sorting } = useTableState<Category>(categories ?? [], 'key');
|
||||
|
@ -193,22 +195,18 @@ export const CategoryTable: FC<Props> = ({
|
|||
pinnedCategory.key === category.key
|
||||
) {
|
||||
return {
|
||||
backgroundColor: 'rgb(227,240,249,0.37)',
|
||||
backgroundColor: primaryBackgroundColor,
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
selectedCategory &&
|
||||
selectedCategory.key === category.key &&
|
||||
selectedCategory.key === category.key
|
||||
) {
|
||||
if (selectedCategory && selectedCategory.key === category.key) {
|
||||
return {
|
||||
backgroundColor: euiTheme.euiColorLightestShade,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
backgroundColor: 'white',
|
||||
backgroundColor: euiTheme.euiColorEmptyShade,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -116,6 +116,7 @@ export const LogCategorizationPage: FC<LogCategorizationPageProps> = ({
|
|||
aiopsListState,
|
||||
setGlobalState,
|
||||
undefined,
|
||||
undefined,
|
||||
BAR_TARGET
|
||||
);
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import React, { FC, useCallback, useMemo, useState } from 'react';
|
|||
import { sortBy } from 'lodash';
|
||||
|
||||
import {
|
||||
useEuiBackgroundColor,
|
||||
EuiBadge,
|
||||
EuiBasicTable,
|
||||
EuiBasicTableColumn,
|
||||
|
@ -29,6 +30,7 @@ import { useAiopsAppContext } from '../../hooks/use_aiops_app_context';
|
|||
import { MiniHistogram } from '../mini_histogram';
|
||||
|
||||
import { getFailedTransactionsCorrelationImpactLabel } from './get_failed_transactions_correlation_impact_label';
|
||||
import { useSpikeAnalysisTableRowContext } from './spike_analysis_table_row_provider';
|
||||
|
||||
const NARROW_COLUMN_WIDTH = '120px';
|
||||
const ACTIONS_COLUMN_WIDTH = '60px';
|
||||
|
@ -48,20 +50,18 @@ interface SpikeAnalysisTableProps {
|
|||
changePoints: ChangePoint[];
|
||||
dataViewId?: string;
|
||||
loading: boolean;
|
||||
onPinnedChangePoint?: (changePoint: ChangePoint | null) => void;
|
||||
onSelectedChangePoint?: (changePoint: ChangePoint | null) => void;
|
||||
selectedChangePoint?: ChangePoint;
|
||||
}
|
||||
|
||||
export const SpikeAnalysisTable: FC<SpikeAnalysisTableProps> = ({
|
||||
changePoints,
|
||||
dataViewId,
|
||||
loading,
|
||||
onPinnedChangePoint,
|
||||
onSelectedChangePoint,
|
||||
selectedChangePoint,
|
||||
}) => {
|
||||
const euiTheme = useEuiTheme();
|
||||
const primaryBackgroundColor = useEuiBackgroundColor('primary');
|
||||
|
||||
const { pinnedChangePoint, selectedChangePoint, setPinnedChangePoint, setSelectedChangePoint } =
|
||||
useSpikeAnalysisTableRowContext();
|
||||
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
|
@ -318,6 +318,32 @@ export const SpikeAnalysisTable: FC<SpikeAnalysisTableProps> = ({
|
|||
};
|
||||
}, [pageIndex, pageSize, sortField, sortDirection, changePoints]);
|
||||
|
||||
const getRowStyle = (changePoint: ChangePoint) => {
|
||||
if (
|
||||
pinnedChangePoint &&
|
||||
pinnedChangePoint.fieldName === changePoint.fieldName &&
|
||||
pinnedChangePoint.fieldValue === changePoint.fieldValue
|
||||
) {
|
||||
return {
|
||||
backgroundColor: primaryBackgroundColor,
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
selectedChangePoint &&
|
||||
selectedChangePoint.fieldName === changePoint.fieldName &&
|
||||
selectedChangePoint.fieldValue === changePoint.fieldValue
|
||||
) {
|
||||
return {
|
||||
backgroundColor: euiTheme.euiColorLightestShade,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
backgroundColor: euiTheme.euiColorEmptyShade,
|
||||
};
|
||||
};
|
||||
|
||||
// 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,
|
||||
|
@ -339,28 +365,22 @@ export const SpikeAnalysisTable: FC<SpikeAnalysisTableProps> = ({
|
|||
return {
|
||||
'data-test-subj': `aiopsSpikeAnalysisTableRow row-${changePoint.fieldName}-${changePoint.fieldValue}`,
|
||||
onClick: () => {
|
||||
if (onPinnedChangePoint) {
|
||||
onPinnedChangePoint(changePoint);
|
||||
if (
|
||||
changePoint.fieldName === pinnedChangePoint?.fieldName &&
|
||||
changePoint.fieldValue === pinnedChangePoint?.fieldValue
|
||||
) {
|
||||
setPinnedChangePoint(null);
|
||||
} else {
|
||||
setPinnedChangePoint(changePoint);
|
||||
}
|
||||
},
|
||||
onMouseEnter: () => {
|
||||
if (onSelectedChangePoint) {
|
||||
onSelectedChangePoint(changePoint);
|
||||
}
|
||||
setSelectedChangePoint(changePoint);
|
||||
},
|
||||
onMouseLeave: () => {
|
||||
if (onSelectedChangePoint) {
|
||||
onSelectedChangePoint(null);
|
||||
}
|
||||
setSelectedChangePoint(null);
|
||||
},
|
||||
style:
|
||||
selectedChangePoint &&
|
||||
selectedChangePoint.fieldValue === changePoint.fieldValue &&
|
||||
selectedChangePoint.fieldName === changePoint.fieldName
|
||||
? {
|
||||
backgroundColor: euiTheme.euiColorLightestShade,
|
||||
}
|
||||
: null,
|
||||
style: getRowStyle(changePoint),
|
||||
};
|
||||
}}
|
||||
/>
|
||||
|
|
|
@ -9,6 +9,7 @@ import React, { FC, useCallback, useMemo, useState } from 'react';
|
|||
import { sortBy } from 'lodash';
|
||||
|
||||
import {
|
||||
useEuiBackgroundColor,
|
||||
EuiBadge,
|
||||
EuiBasicTable,
|
||||
EuiBasicTableColumn,
|
||||
|
@ -34,6 +35,7 @@ import { MiniHistogram } from '../mini_histogram';
|
|||
|
||||
import { getFailedTransactionsCorrelationImpactLabel } from './get_failed_transactions_correlation_impact_label';
|
||||
import { SpikeAnalysisTable } from './spike_analysis_table';
|
||||
import { useSpikeAnalysisTableRowContext } from './spike_analysis_table_row_provider';
|
||||
|
||||
const NARROW_COLUMN_WIDTH = '120px';
|
||||
const EXPAND_COLUMN_WIDTH = '40px';
|
||||
|
@ -64,10 +66,6 @@ interface SpikeAnalysisTableProps {
|
|||
groupTableItems: GroupTableItem[];
|
||||
dataViewId?: string;
|
||||
loading: boolean;
|
||||
onPinnedChangePoint?: (changePoint: ChangePoint | null) => void;
|
||||
onSelectedChangePoint?: (changePoint: ChangePoint | null) => void;
|
||||
selectedChangePoint?: ChangePoint;
|
||||
onSelectedGroup?: (group: GroupTableItem | null) => void;
|
||||
}
|
||||
|
||||
export const SpikeAnalysisGroupsTable: FC<SpikeAnalysisTableProps> = ({
|
||||
|
@ -75,10 +73,6 @@ export const SpikeAnalysisGroupsTable: FC<SpikeAnalysisTableProps> = ({
|
|||
groupTableItems,
|
||||
dataViewId,
|
||||
loading,
|
||||
onPinnedChangePoint,
|
||||
onSelectedChangePoint,
|
||||
selectedChangePoint,
|
||||
onSelectedGroup,
|
||||
}) => {
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
|
@ -89,6 +83,10 @@ export const SpikeAnalysisGroupsTable: FC<SpikeAnalysisTableProps> = ({
|
|||
);
|
||||
|
||||
const euiTheme = useEuiTheme();
|
||||
const primaryBackgroundColor = useEuiBackgroundColor('primary');
|
||||
|
||||
const { pinnedGroup, selectedGroup, setPinnedGroup, setSelectedGroup } =
|
||||
useSpikeAnalysisTableRowContext();
|
||||
|
||||
const toggleDetails = (item: GroupTableItem) => {
|
||||
const itemIdToExpandedRowMapValues = { ...itemIdToExpandedRowMap };
|
||||
|
@ -121,9 +119,6 @@ export const SpikeAnalysisGroupsTable: FC<SpikeAnalysisTableProps> = ({
|
|||
<SpikeAnalysisTable
|
||||
changePoints={expandedTableItems as ChangePoint[]}
|
||||
loading={loading}
|
||||
onPinnedChangePoint={onPinnedChangePoint}
|
||||
onSelectedChangePoint={onSelectedChangePoint}
|
||||
selectedChangePoint={selectedChangePoint}
|
||||
dataViewId={dataViewId}
|
||||
/>
|
||||
);
|
||||
|
@ -458,6 +453,24 @@ export const SpikeAnalysisGroupsTable: FC<SpikeAnalysisTableProps> = ({
|
|||
};
|
||||
}, [pageIndex, pageSize, sortField, sortDirection, groupTableItems]);
|
||||
|
||||
const getRowStyle = (group: GroupTableItem) => {
|
||||
if (pinnedGroup && pinnedGroup.id === group.id) {
|
||||
return {
|
||||
backgroundColor: primaryBackgroundColor,
|
||||
};
|
||||
}
|
||||
|
||||
if (selectedGroup && selectedGroup.id === group.id) {
|
||||
return {
|
||||
backgroundColor: euiTheme.euiColorLightestShade,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
backgroundColor: euiTheme.euiColorEmptyShade,
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<EuiBasicTable
|
||||
data-test-subj="aiopsSpikeAnalysisGroupsTable"
|
||||
|
@ -473,16 +486,20 @@ export const SpikeAnalysisGroupsTable: FC<SpikeAnalysisTableProps> = ({
|
|||
rowProps={(group) => {
|
||||
return {
|
||||
'data-test-subj': `aiopsSpikeAnalysisGroupsTableRow row-${group.id}`,
|
||||
onMouseEnter: () => {
|
||||
if (onSelectedGroup) {
|
||||
onSelectedGroup(group);
|
||||
onClick: () => {
|
||||
if (group.id === pinnedGroup?.id) {
|
||||
setPinnedGroup(null);
|
||||
} else {
|
||||
setPinnedGroup(group);
|
||||
}
|
||||
},
|
||||
onMouseEnter: () => {
|
||||
setSelectedGroup(group);
|
||||
},
|
||||
onMouseLeave: () => {
|
||||
if (onSelectedGroup) {
|
||||
onSelectedGroup(null);
|
||||
}
|
||||
setSelectedGroup(null);
|
||||
},
|
||||
style: getRowStyle(group),
|
||||
};
|
||||
}}
|
||||
/>
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* 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, {
|
||||
createContext,
|
||||
useContext,
|
||||
useMemo,
|
||||
useState,
|
||||
type FC,
|
||||
type Dispatch,
|
||||
type SetStateAction,
|
||||
} from 'react';
|
||||
|
||||
import type { ChangePoint } from '@kbn/ml-agg-utils';
|
||||
|
||||
import type { GroupTableItem } from './spike_analysis_table_groups';
|
||||
|
||||
type ChangePointOrNull = ChangePoint | null;
|
||||
type GroupOrNull = GroupTableItem | null;
|
||||
|
||||
interface SpikeAnalysisTableRow {
|
||||
pinnedChangePoint: ChangePointOrNull;
|
||||
setPinnedChangePoint: Dispatch<SetStateAction<ChangePointOrNull>>;
|
||||
pinnedGroup: GroupOrNull;
|
||||
setPinnedGroup: Dispatch<SetStateAction<GroupOrNull>>;
|
||||
selectedChangePoint: ChangePointOrNull;
|
||||
setSelectedChangePoint: Dispatch<SetStateAction<ChangePointOrNull>>;
|
||||
selectedGroup: GroupOrNull;
|
||||
setSelectedGroup: Dispatch<SetStateAction<GroupOrNull>>;
|
||||
currentSelectedChangePoint?: ChangePoint;
|
||||
currentSelectedGroup?: GroupTableItem;
|
||||
clearAllRowState: () => void;
|
||||
}
|
||||
|
||||
export const spikeAnalysisTableRowContext = createContext<SpikeAnalysisTableRow | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
export const SpikeAnalysisTableRowStateProvider: FC = ({ children }) => {
|
||||
// State that will be shared with all components
|
||||
const [pinnedChangePoint, setPinnedChangePoint] = useState<ChangePointOrNull>(null);
|
||||
const [pinnedGroup, setPinnedGroup] = useState<GroupOrNull>(null);
|
||||
const [selectedChangePoint, setSelectedChangePoint] = useState<ChangePointOrNull>(null);
|
||||
const [selectedGroup, setSelectedGroup] = useState<GroupOrNull>(null);
|
||||
|
||||
// If a row is pinned, still overrule with a potentially hovered row.
|
||||
const currentSelectedChangePoint = useMemo(() => {
|
||||
if (selectedChangePoint) {
|
||||
return selectedChangePoint;
|
||||
} else if (pinnedChangePoint) {
|
||||
return pinnedChangePoint;
|
||||
}
|
||||
}, [pinnedChangePoint, selectedChangePoint]);
|
||||
|
||||
// If a group is pinned, still overrule with a potentially hovered group.
|
||||
const currentSelectedGroup = useMemo(() => {
|
||||
if (selectedGroup) {
|
||||
return selectedGroup;
|
||||
} else if (pinnedGroup) {
|
||||
return pinnedGroup;
|
||||
}
|
||||
}, [selectedGroup, pinnedGroup]);
|
||||
|
||||
const contextValue: SpikeAnalysisTableRow = useMemo(
|
||||
() => ({
|
||||
pinnedChangePoint,
|
||||
setPinnedChangePoint,
|
||||
pinnedGroup,
|
||||
setPinnedGroup,
|
||||
selectedChangePoint,
|
||||
setSelectedChangePoint,
|
||||
selectedGroup,
|
||||
setSelectedGroup,
|
||||
currentSelectedChangePoint,
|
||||
currentSelectedGroup,
|
||||
clearAllRowState: () => {
|
||||
setPinnedChangePoint(null);
|
||||
setPinnedGroup(null);
|
||||
setSelectedChangePoint(null);
|
||||
setSelectedGroup(null);
|
||||
},
|
||||
}),
|
||||
[
|
||||
pinnedChangePoint,
|
||||
setPinnedChangePoint,
|
||||
pinnedGroup,
|
||||
setPinnedGroup,
|
||||
selectedChangePoint,
|
||||
setSelectedChangePoint,
|
||||
selectedGroup,
|
||||
setSelectedGroup,
|
||||
currentSelectedChangePoint,
|
||||
currentSelectedGroup,
|
||||
]
|
||||
);
|
||||
|
||||
return (
|
||||
// Provider managing the state
|
||||
<spikeAnalysisTableRowContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</spikeAnalysisTableRowContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useSpikeAnalysisTableRowContext = () => {
|
||||
const spikeAnalysisTableRow = useContext(spikeAnalysisTableRowContext);
|
||||
|
||||
// If `undefined`, throw an error.
|
||||
if (spikeAnalysisTableRow === undefined) {
|
||||
throw new Error('useSpikeAnalysisTableRowContext was used outside of its Provider');
|
||||
}
|
||||
|
||||
return spikeAnalysisTableRow;
|
||||
};
|
|
@ -40,8 +40,8 @@ export const useData = (
|
|||
aiopsListState: AiOpsIndexBasedAppState,
|
||||
onUpdate: (params: Dictionary<unknown>) => void,
|
||||
selectedChangePoint?: ChangePoint,
|
||||
barTarget: number = DEFAULT_BAR_TARGET,
|
||||
selectedGroup?: GroupTableItem | null
|
||||
selectedGroup?: GroupTableItem | null,
|
||||
barTarget: number = DEFAULT_BAR_TARGET
|
||||
) => {
|
||||
const {
|
||||
uiSettings,
|
||||
|
@ -49,6 +49,7 @@ export const useData = (
|
|||
query: { filterManager },
|
||||
},
|
||||
} = useAiopsAppContext();
|
||||
|
||||
const [lastRefresh, setLastRefresh] = useState(0);
|
||||
const [fieldStatsRequest, setFieldStatsRequest] = useState<
|
||||
DocumentStatsSearchStrategyParams | undefined
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue