mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[ML] AIOps Log Rate Analysis: Replace custom global state management with Redux Toolkit. (#180969)
This commit is contained in:
parent
4bc122703c
commit
211a11bb72
57 changed files with 1011 additions and 963 deletions
|
@ -9,15 +9,7 @@ export { DualBrush, DualBrushAnnotation } from './src/dual_brush';
|
|||
export { ProgressControls } from './src/progress_controls';
|
||||
export {
|
||||
DocumentCountChart,
|
||||
DocumentCountChartWithAutoAnalysisStart,
|
||||
DocumentCountChartRedux,
|
||||
type BrushSettings,
|
||||
type BrushSelectionUpdateHandler,
|
||||
} from './src/document_count_chart';
|
||||
export type { DocumentCountChartProps } from './src/document_count_chart';
|
||||
export {
|
||||
useLogRateAnalysisStateContext,
|
||||
LogRateAnalysisStateProvider,
|
||||
type GroupTableItem,
|
||||
type GroupTableItemGroup,
|
||||
type TableItemAction,
|
||||
} from './src/log_rate_analysis_state_provider';
|
||||
|
|
|
@ -29,10 +29,10 @@ import {
|
|||
getSnappedWindowParameters,
|
||||
getWindowParametersForTrigger,
|
||||
type DocumentCountStatsChangePoint,
|
||||
type LogRateAnalysisType,
|
||||
type LogRateHistogramItem,
|
||||
type WindowParameters,
|
||||
} from '@kbn/aiops-log-rate-analysis';
|
||||
import { type BrushSelectionUpdatePayload } from '@kbn/aiops-log-rate-analysis/state';
|
||||
import { MULTILAYER_TIME_AXIS_STYLE } from '@kbn/charts-plugin/common';
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { ChartsPluginStart } from '@kbn/charts-plugin/public';
|
||||
|
@ -40,8 +40,6 @@ import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
|
|||
|
||||
import { DualBrush, DualBrushAnnotation } from '../..';
|
||||
|
||||
import { useLogRateAnalysisStateContext } from '../log_rate_analysis_state_provider';
|
||||
|
||||
import { BrushBadge } from './brush_badge';
|
||||
|
||||
declare global {
|
||||
|
@ -76,24 +74,19 @@ export interface BrushSettings {
|
|||
badgeWidth?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function which gets called when the brush selection has changed
|
||||
*
|
||||
* @param windowParameters Baseline and deviation time ranges.
|
||||
* @param force Force update
|
||||
* @param logRateAnalysisType `spike` or `dip` based on median log rate bucket size
|
||||
*/
|
||||
export type BrushSelectionUpdateHandler = (
|
||||
windowParameters: WindowParameters,
|
||||
force: boolean,
|
||||
logRateAnalysisType: LogRateAnalysisType
|
||||
) => void;
|
||||
|
||||
/**
|
||||
* Callback to set the autoRunAnalysis flag
|
||||
*/
|
||||
type SetAutoRunAnalysisFn = (isAutoRun: boolean) => void;
|
||||
|
||||
/**
|
||||
* Brush selection update handler
|
||||
*/
|
||||
type BrushSelectionUpdateHandler = (
|
||||
/** Payload for the brush selection update */
|
||||
d: BrushSelectionUpdatePayload
|
||||
) => void;
|
||||
|
||||
/**
|
||||
* Props for document count chart
|
||||
*/
|
||||
|
@ -126,7 +119,7 @@ export interface DocumentCountChartProps {
|
|||
/** Whether or not brush has been reset */
|
||||
isBrushCleared: boolean;
|
||||
/** Callback to set the autoRunAnalysis flag */
|
||||
setAutoRunAnalysis?: SetAutoRunAnalysisFn;
|
||||
setAutoRunAnalysisFn?: SetAutoRunAnalysisFn;
|
||||
/** Timestamp for start of initial analysis */
|
||||
autoAnalysisStart?: number | WindowParameters;
|
||||
/** Optional style to override bar chart */
|
||||
|
@ -190,7 +183,7 @@ export const DocumentCountChart: FC<DocumentCountChartProps> = (props) => {
|
|||
interval,
|
||||
chartPointsSplitLabel,
|
||||
isBrushCleared,
|
||||
setAutoRunAnalysis,
|
||||
setAutoRunAnalysisFn,
|
||||
autoAnalysisStart,
|
||||
barColorOverride,
|
||||
barStyleAccessor,
|
||||
|
@ -315,7 +308,7 @@ export const DocumentCountChart: FC<DocumentCountChartProps> = (props) => {
|
|||
windowParameters === undefined &&
|
||||
adjustedChartPoints !== undefined
|
||||
) {
|
||||
if (setAutoRunAnalysis) {
|
||||
if (setAutoRunAnalysisFn) {
|
||||
const autoRun =
|
||||
typeof startRange !== 'number' ||
|
||||
(typeof startRange === 'number' &&
|
||||
|
@ -323,7 +316,7 @@ export const DocumentCountChart: FC<DocumentCountChartProps> = (props) => {
|
|||
startRange >= changePoint.startTs &&
|
||||
startRange <= changePoint.endTs);
|
||||
|
||||
setAutoRunAnalysis(autoRun);
|
||||
setAutoRunAnalysisFn(autoRun);
|
||||
}
|
||||
|
||||
const wp = getWindowParametersForTrigger(
|
||||
|
@ -338,11 +331,11 @@ export const DocumentCountChart: FC<DocumentCountChartProps> = (props) => {
|
|||
setWindowParameters(wpSnap);
|
||||
|
||||
if (brushSelectionUpdateHandler !== undefined) {
|
||||
brushSelectionUpdateHandler(
|
||||
wpSnap,
|
||||
true,
|
||||
getLogRateAnalysisType(adjustedChartPoints, wpSnap)
|
||||
);
|
||||
brushSelectionUpdateHandler({
|
||||
windowParameters: wpSnap,
|
||||
force: true,
|
||||
analysisType: getLogRateAnalysisType(adjustedChartPoints, wpSnap),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -354,7 +347,7 @@ export const DocumentCountChart: FC<DocumentCountChartProps> = (props) => {
|
|||
timeRangeLatest,
|
||||
snapTimestamps,
|
||||
originalWindowParameters,
|
||||
setAutoRunAnalysis,
|
||||
setAutoRunAnalysisFn,
|
||||
setWindowParameters,
|
||||
brushSelectionUpdateHandler,
|
||||
adjustedChartPoints,
|
||||
|
@ -395,7 +388,11 @@ export const DocumentCountChart: FC<DocumentCountChartProps> = (props) => {
|
|||
}
|
||||
setWindowParameters(wp);
|
||||
setWindowParametersAsPixels(wpPx);
|
||||
brushSelectionUpdateHandler(wp, false, getLogRateAnalysisType(adjustedChartPoints, wp));
|
||||
brushSelectionUpdateHandler({
|
||||
windowParameters: wp,
|
||||
force: false,
|
||||
analysisType: getLogRateAnalysisType(adjustedChartPoints, wp),
|
||||
});
|
||||
}
|
||||
|
||||
const [mlBrushWidth, setMlBrushWidth] = useState<number>();
|
||||
|
@ -556,24 +553,3 @@ export const DocumentCountChart: FC<DocumentCountChartProps> = (props) => {
|
|||
</>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Functional component that renders a `DocumentCountChart` with additional properties
|
||||
* managed by the log rate analysis state. It leverages the `useLogRateAnalysisStateContext`
|
||||
* to acquire state variables like `initialAnalysisStart` and functions such as
|
||||
* `setAutoRunAnalysis`. These values are then passed as props to the `DocumentCountChart`.
|
||||
*
|
||||
* @param props - The properties passed to the DocumentCountChart component.
|
||||
* @returns The DocumentCountChart component enhanced with automatic analysis start capabilities.
|
||||
*/
|
||||
export const DocumentCountChartWithAutoAnalysisStart: FC<DocumentCountChartProps> = (props) => {
|
||||
const { initialAnalysisStart, setAutoRunAnalysis } = useLogRateAnalysisStateContext();
|
||||
|
||||
return (
|
||||
<DocumentCountChart
|
||||
{...props}
|
||||
autoAnalysisStart={initialAnalysisStart}
|
||||
setAutoRunAnalysis={setAutoRunAnalysis}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* 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, { memo, type FC } from 'react';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { LogRateHistogramItem } from '@kbn/aiops-log-rate-analysis';
|
||||
import {
|
||||
brushSelectionUpdate,
|
||||
setAutoRunAnalysis,
|
||||
useAppSelector,
|
||||
useAppDispatch,
|
||||
useCurrentSelectedGroup,
|
||||
useCurrentSelectedSignificantItem,
|
||||
type GroupTableItem,
|
||||
} from '@kbn/aiops-log-rate-analysis/state';
|
||||
import type { SignificantItem } from '@kbn/ml-agg-utils';
|
||||
|
||||
import { DocumentCountChart, type DocumentCountChartProps } from './document_count_chart';
|
||||
|
||||
function getDocumentCountStatsSplitLabel(
|
||||
significantItem?: SignificantItem,
|
||||
group?: GroupTableItem
|
||||
): string {
|
||||
if (significantItem) {
|
||||
return `${significantItem?.fieldName}:${significantItem?.fieldValue}`;
|
||||
} else if (group) {
|
||||
return i18n.translate('xpack.aiops.logRateAnalysis.page.documentCountStatsSplitGroupLabel', {
|
||||
defaultMessage: 'Selected group',
|
||||
});
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
type DocumentCountChartReduxProps = Omit<
|
||||
DocumentCountChartProps,
|
||||
| 'chartPointsSplitLabel'
|
||||
| 'autoAnalysisStart'
|
||||
| 'chartPoints'
|
||||
| 'chartPointsSplit'
|
||||
| 'documentStats'
|
||||
| 'isBrushCleared'
|
||||
| 'brushSelectionUpdateHandler'
|
||||
| 'timeRangeEarliest'
|
||||
| 'timeRangeLatest'
|
||||
| 'interval'
|
||||
>;
|
||||
|
||||
/**
|
||||
* Functional component that renders a `DocumentCountChart` with additional properties
|
||||
* managed by the log rate analysis state. It leverages the `LogRateAnalysisReduxProvider`
|
||||
* to acquire state variables like `initialAnalysisStart` and functions such as
|
||||
* `setAutoRunAnalysis`. These values are then passed as props to the `DocumentCountChart`.
|
||||
* This wrapper component is necessary since the `DocumentCountChart` component is
|
||||
* also used for log pattern analysis which doesn't use redux.
|
||||
*
|
||||
* @param props - The properties passed to the DocumentCountChart component.
|
||||
* @returns The DocumentCountChart component enhanced with automatic analysis start capabilities.
|
||||
*/
|
||||
export const DocumentCountChartRedux: FC<DocumentCountChartReduxProps> = memo((props) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const currentSelectedGroup = useCurrentSelectedGroup();
|
||||
const currentSelectedSignificantItem = useCurrentSelectedSignificantItem();
|
||||
const { documentStats, initialAnalysisStart, isBrushCleared } = useAppSelector(
|
||||
(s) => s.logRateAnalysis
|
||||
);
|
||||
const { documentCountStats, documentCountStatsCompare } = documentStats;
|
||||
|
||||
const bucketTimestamps = Object.keys(documentCountStats?.buckets ?? {}).map((time) => +time);
|
||||
const splitBucketTimestamps = Object.keys(documentCountStatsCompare?.buckets ?? {}).map(
|
||||
(time) => +time
|
||||
);
|
||||
const timeRangeEarliest = Math.min(...[...bucketTimestamps, ...splitBucketTimestamps]);
|
||||
const timeRangeLatest = Math.max(...[...bucketTimestamps, ...splitBucketTimestamps]);
|
||||
|
||||
if (
|
||||
documentCountStats === undefined ||
|
||||
documentCountStats.buckets === undefined ||
|
||||
documentCountStats.interval === undefined ||
|
||||
timeRangeEarliest === undefined ||
|
||||
timeRangeLatest === undefined
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const documentCountStatsSplitLabel = getDocumentCountStatsSplitLabel(
|
||||
currentSelectedSignificantItem,
|
||||
currentSelectedGroup
|
||||
);
|
||||
|
||||
const chartPoints: LogRateHistogramItem[] = Object.entries(documentCountStats.buckets).map(
|
||||
([time, value]) => ({
|
||||
time: +time,
|
||||
value,
|
||||
})
|
||||
);
|
||||
|
||||
let chartPointsSplit: LogRateHistogramItem[] | undefined;
|
||||
if (documentCountStatsCompare?.buckets !== undefined) {
|
||||
chartPointsSplit = Object.entries(documentCountStatsCompare?.buckets).map(([time, value]) => ({
|
||||
time: +time,
|
||||
value,
|
||||
}));
|
||||
}
|
||||
|
||||
return (
|
||||
<DocumentCountChart
|
||||
{...props}
|
||||
chartPointsSplitLabel={documentCountStatsSplitLabel}
|
||||
timeRangeEarliest={timeRangeEarliest}
|
||||
timeRangeLatest={timeRangeLatest}
|
||||
interval={documentCountStats.interval}
|
||||
chartPoints={chartPoints}
|
||||
chartPointsSplit={chartPointsSplit}
|
||||
autoAnalysisStart={initialAnalysisStart}
|
||||
brushSelectionUpdateHandler={(d) => dispatch(brushSelectionUpdate(d))}
|
||||
isBrushCleared={isBrushCleared}
|
||||
setAutoRunAnalysisFn={(d: boolean) => dispatch(setAutoRunAnalysis(d))}
|
||||
/>
|
||||
);
|
||||
});
|
|
@ -5,12 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export {
|
||||
DocumentCountChart,
|
||||
DocumentCountChartWithAutoAnalysisStart,
|
||||
} from './document_count_chart';
|
||||
export type {
|
||||
BrushSelectionUpdateHandler,
|
||||
BrushSettings,
|
||||
DocumentCountChartProps,
|
||||
} from './document_count_chart';
|
||||
export { DocumentCountChart } from './document_count_chart';
|
||||
export { DocumentCountChartRedux } from './document_count_chart_redux';
|
||||
export type { BrushSettings, DocumentCountChartProps } from './document_count_chart';
|
||||
|
|
|
@ -1,12 +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.
|
||||
*/
|
||||
|
||||
export {
|
||||
useLogRateAnalysisStateContext,
|
||||
LogRateAnalysisStateProvider,
|
||||
} from './log_rate_analysis_state_provider';
|
||||
export type { GroupTableItem, GroupTableItemGroup, TableItemAction } from './types';
|
|
@ -1,169 +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, {
|
||||
createContext,
|
||||
useContext,
|
||||
useMemo,
|
||||
useState,
|
||||
type FC,
|
||||
type PropsWithChildren,
|
||||
type Dispatch,
|
||||
type SetStateAction,
|
||||
} from 'react';
|
||||
|
||||
import type { SignificantItem } from '@kbn/ml-agg-utils';
|
||||
import type { WindowParameters } from '@kbn/aiops-log-rate-analysis';
|
||||
|
||||
import type { GroupTableItem } from './types';
|
||||
|
||||
type InitialAnalysisStart = number | WindowParameters | undefined;
|
||||
type SignificantItemOrNull = SignificantItem | null;
|
||||
type GroupOrNull = GroupTableItem | null;
|
||||
|
||||
interface LogRateAnalysisState {
|
||||
autoRunAnalysis: boolean;
|
||||
setAutoRunAnalysis: Dispatch<SetStateAction<boolean>>;
|
||||
initialAnalysisStart: InitialAnalysisStart;
|
||||
setInitialAnalysisStart: Dispatch<SetStateAction<InitialAnalysisStart>>;
|
||||
pinnedSignificantItem: SignificantItemOrNull;
|
||||
setPinnedSignificantItem: Dispatch<SetStateAction<SignificantItemOrNull>>;
|
||||
pinnedGroup: GroupOrNull;
|
||||
setPinnedGroup: Dispatch<SetStateAction<GroupOrNull>>;
|
||||
selectedSignificantItem: SignificantItemOrNull;
|
||||
setSelectedSignificantItem: Dispatch<SetStateAction<SignificantItemOrNull>>;
|
||||
selectedGroup: GroupOrNull;
|
||||
setSelectedGroup: Dispatch<SetStateAction<GroupOrNull>>;
|
||||
currentSelectedSignificantItem?: SignificantItem;
|
||||
currentSelectedGroup?: GroupTableItem;
|
||||
clearAllRowState: () => void;
|
||||
}
|
||||
|
||||
const LogRateAnalysisStateContext = createContext<LogRateAnalysisState | undefined>(undefined);
|
||||
|
||||
/**
|
||||
* Props for LogRateAnalysisStateProvider.
|
||||
*/
|
||||
interface LogRateAnalysisStateProviderProps {
|
||||
/** The parameters to be used to trigger an analysis. */
|
||||
initialAnalysisStart?: InitialAnalysisStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Context provider component that manages and provides global state for Log Rate Analysis.
|
||||
* This provider handles several pieces of state important for controlling and displaying
|
||||
* log rate analysis data, such as the control of automatic analysis runs, and the management
|
||||
* of both pinned and selected significant items and groups.
|
||||
*
|
||||
* The state includes mechanisms for setting initial analysis parameters, toggling analysis,
|
||||
* and managing the current selection and pinned state of significant items and groups.
|
||||
*
|
||||
* @param props - Props object containing initial settings for the analysis,
|
||||
* including children components to be wrapped by the Provider.
|
||||
* @returns A context provider wrapping children with access to log rate analysis state.
|
||||
*/
|
||||
export const LogRateAnalysisStateProvider: FC<
|
||||
PropsWithChildren<LogRateAnalysisStateProviderProps>
|
||||
> = (props) => {
|
||||
const { children, initialAnalysisStart: incomingInitialAnalysisStart } = props;
|
||||
|
||||
const [autoRunAnalysis, setAutoRunAnalysis] = useState(true);
|
||||
const [initialAnalysisStart, setInitialAnalysisStart] = useState<
|
||||
number | WindowParameters | undefined
|
||||
>(incomingInitialAnalysisStart);
|
||||
|
||||
// Row state that will be shared with all components
|
||||
const [pinnedSignificantItem, setPinnedSignificantItem] = useState<SignificantItemOrNull>(null);
|
||||
const [pinnedGroup, setPinnedGroup] = useState<GroupOrNull>(null);
|
||||
const [selectedSignificantItem, setSelectedSignificantItem] =
|
||||
useState<SignificantItemOrNull>(null);
|
||||
const [selectedGroup, setSelectedGroup] = useState<GroupOrNull>(null);
|
||||
|
||||
// If a row is pinned, still overrule with a potentially hovered row.
|
||||
const currentSelectedSignificantItem = useMemo(() => {
|
||||
if (selectedSignificantItem) {
|
||||
return selectedSignificantItem;
|
||||
} else if (pinnedSignificantItem) {
|
||||
return pinnedSignificantItem;
|
||||
}
|
||||
}, [pinnedSignificantItem, selectedSignificantItem]);
|
||||
|
||||
// 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: LogRateAnalysisState = useMemo(
|
||||
() => ({
|
||||
autoRunAnalysis,
|
||||
setAutoRunAnalysis,
|
||||
initialAnalysisStart,
|
||||
setInitialAnalysisStart,
|
||||
pinnedSignificantItem,
|
||||
setPinnedSignificantItem,
|
||||
pinnedGroup,
|
||||
setPinnedGroup,
|
||||
selectedSignificantItem,
|
||||
setSelectedSignificantItem,
|
||||
selectedGroup,
|
||||
setSelectedGroup,
|
||||
currentSelectedSignificantItem,
|
||||
currentSelectedGroup,
|
||||
clearAllRowState: () => {
|
||||
setPinnedSignificantItem(null);
|
||||
setPinnedGroup(null);
|
||||
setSelectedSignificantItem(null);
|
||||
setSelectedGroup(null);
|
||||
},
|
||||
}),
|
||||
[
|
||||
autoRunAnalysis,
|
||||
setAutoRunAnalysis,
|
||||
initialAnalysisStart,
|
||||
setInitialAnalysisStart,
|
||||
pinnedSignificantItem,
|
||||
setPinnedSignificantItem,
|
||||
pinnedGroup,
|
||||
setPinnedGroup,
|
||||
selectedSignificantItem,
|
||||
setSelectedSignificantItem,
|
||||
selectedGroup,
|
||||
setSelectedGroup,
|
||||
currentSelectedSignificantItem,
|
||||
currentSelectedGroup,
|
||||
]
|
||||
);
|
||||
|
||||
return (
|
||||
// Provider managing the state
|
||||
<LogRateAnalysisStateContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</LogRateAnalysisStateContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom hook for accessing the state of log rate analysis from the LogRateAnalysisStateContext.
|
||||
* This hook must be used within a component that is a descendant of the LogRateAnalysisStateContext provider.
|
||||
*
|
||||
* @returns The current state of the log rate analysis.
|
||||
* @throws Throws an error if the hook is used outside of its Provider context.
|
||||
*/
|
||||
export const useLogRateAnalysisStateContext = () => {
|
||||
const logRateAnalysisState = useContext(LogRateAnalysisStateContext);
|
||||
|
||||
// If `undefined`, throw an error.
|
||||
if (logRateAnalysisState === undefined) {
|
||||
throw new Error('useLogRateAnalysisStateContext was used outside of its Provider');
|
||||
}
|
||||
|
||||
return logRateAnalysisState;
|
||||
};
|
|
@ -30,12 +30,12 @@ import { useAnimatedProgressBarBackground } from './use_animated_progress_bar_ba
|
|||
* Props for ProgressControlProps
|
||||
*/
|
||||
interface ProgressControlProps {
|
||||
isBrushCleared: boolean;
|
||||
progress: number;
|
||||
progressMessage: string;
|
||||
onRefresh: () => void;
|
||||
onCancel: () => void;
|
||||
onReset: () => void;
|
||||
isBrushCleared: boolean;
|
||||
isRunning: boolean;
|
||||
shouldRerunAnalysis: boolean;
|
||||
runAnalysisDisabled?: boolean;
|
||||
|
@ -43,7 +43,7 @@ interface ProgressControlProps {
|
|||
|
||||
/**
|
||||
* ProgressControls React Component
|
||||
* Component with ability to Run & cancel analysis
|
||||
* Component with ability to run & cancel analysis
|
||||
* by default uses `Baseline` and `Deviation` for the badge name
|
||||
*
|
||||
* @param props ProgressControls component props
|
||||
|
@ -52,12 +52,12 @@ interface ProgressControlProps {
|
|||
export const ProgressControls: FC<PropsWithChildren<ProgressControlProps>> = (props) => {
|
||||
const {
|
||||
children,
|
||||
isBrushCleared,
|
||||
progress,
|
||||
progressMessage,
|
||||
onRefresh,
|
||||
onCancel,
|
||||
onReset,
|
||||
isBrushCleared,
|
||||
isRunning,
|
||||
shouldRerunAnalysis,
|
||||
runAnalysisDisabled = false,
|
||||
|
@ -66,6 +66,7 @@ export const ProgressControls: FC<PropsWithChildren<ProgressControlProps>> = (pr
|
|||
const progressOutput = Math.round(progress * 100);
|
||||
|
||||
const { euiTheme } = useEuiTheme();
|
||||
|
||||
const runningProgressBarStyles = useAnimatedProgressBarBackground(euiTheme.colors.success);
|
||||
const analysisCompleteStyle = { display: 'none' };
|
||||
|
||||
|
|
|
@ -1,182 +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 type {
|
||||
SignificantItem,
|
||||
SignificantItemHistogram,
|
||||
SignificantItemGroup,
|
||||
SignificantItemGroupHistogram,
|
||||
} from '@kbn/ml-agg-utils';
|
||||
|
||||
export const API_ACTION_NAME = {
|
||||
/** @since API v2 */
|
||||
ADD_SIGNIFICANT_ITEMS: 'add_significant_items',
|
||||
/** @since API v2 */
|
||||
ADD_SIGNIFICANT_ITEMS_HISTOGRAM: 'add_significant_items_histogram',
|
||||
/** @since API v2 */
|
||||
ADD_SIGNIFICANT_ITEMS_GROUP: 'add_significant_items_group',
|
||||
/** @since API v2 */
|
||||
ADD_SIGNIFICANT_ITEMS_GROUP_HISTOGRAM: 'add_significant_items_group_histogram',
|
||||
ADD_SIGNIFICANT_TERMS_GROUP_HISTOGRAM: 'add_significant_terms_group_histogram',
|
||||
ADD_ERROR: 'add_error',
|
||||
PING: 'ping',
|
||||
RESET_ALL: 'reset_all',
|
||||
RESET_ERRORS: 'reset_errors',
|
||||
RESET_GROUPS: 'reset_groups',
|
||||
SET_ZERO_DOCS_FALLBACK: 'set_zero_docs_fallback',
|
||||
UPDATE_LOADING_STATE: 'update_loading_state',
|
||||
} as const;
|
||||
export type ApiActionName = typeof API_ACTION_NAME[keyof typeof API_ACTION_NAME];
|
||||
|
||||
interface ApiActionAddSignificantItems {
|
||||
type: typeof API_ACTION_NAME.ADD_SIGNIFICANT_ITEMS;
|
||||
payload: SignificantItem[];
|
||||
}
|
||||
|
||||
export function addSignificantItemsAction(
|
||||
payload: ApiActionAddSignificantItems['payload']
|
||||
): ApiActionAddSignificantItems {
|
||||
return {
|
||||
type: API_ACTION_NAME.ADD_SIGNIFICANT_ITEMS,
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
interface ApiActionAddSignificantItemsHistogram {
|
||||
type: typeof API_ACTION_NAME.ADD_SIGNIFICANT_ITEMS_HISTOGRAM;
|
||||
payload: SignificantItemHistogram[];
|
||||
}
|
||||
|
||||
export function addSignificantItemsHistogramAction(
|
||||
payload: ApiActionAddSignificantItemsHistogram['payload']
|
||||
): ApiActionAddSignificantItemsHistogram {
|
||||
return {
|
||||
type: API_ACTION_NAME.ADD_SIGNIFICANT_ITEMS_HISTOGRAM,
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
interface ApiActionAddSignificantItemsGroup {
|
||||
type: typeof API_ACTION_NAME.ADD_SIGNIFICANT_ITEMS_GROUP;
|
||||
payload: SignificantItemGroup[];
|
||||
}
|
||||
|
||||
export function addSignificantItemsGroupAction(
|
||||
payload: ApiActionAddSignificantItemsGroup['payload']
|
||||
): ApiActionAddSignificantItemsGroup {
|
||||
return {
|
||||
type: API_ACTION_NAME.ADD_SIGNIFICANT_ITEMS_GROUP,
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
interface ApiActionAddSignificantItemsGroupHistogram {
|
||||
type: typeof API_ACTION_NAME.ADD_SIGNIFICANT_ITEMS_GROUP_HISTOGRAM;
|
||||
payload: SignificantItemGroupHistogram[];
|
||||
}
|
||||
|
||||
export function addSignificantItemsGroupHistogramAction(
|
||||
payload: ApiActionAddSignificantItemsGroupHistogram['payload']
|
||||
): ApiActionAddSignificantItemsGroupHistogram {
|
||||
return {
|
||||
type: API_ACTION_NAME.ADD_SIGNIFICANT_ITEMS_GROUP_HISTOGRAM,
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
interface ApiActionAddError {
|
||||
type: typeof API_ACTION_NAME.ADD_ERROR;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
export function addErrorAction(payload: ApiActionAddError['payload']): ApiActionAddError {
|
||||
return {
|
||||
type: API_ACTION_NAME.ADD_ERROR,
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
interface ApiActionResetErrors {
|
||||
type: typeof API_ACTION_NAME.RESET_ERRORS;
|
||||
}
|
||||
|
||||
export function resetErrorsAction() {
|
||||
return {
|
||||
type: API_ACTION_NAME.RESET_ERRORS,
|
||||
};
|
||||
}
|
||||
|
||||
interface ApiActionPing {
|
||||
type: typeof API_ACTION_NAME.PING;
|
||||
}
|
||||
|
||||
export function pingAction(): ApiActionPing {
|
||||
return { type: API_ACTION_NAME.PING };
|
||||
}
|
||||
|
||||
interface ApiActionResetAll {
|
||||
type: typeof API_ACTION_NAME.RESET_ALL;
|
||||
}
|
||||
|
||||
export function resetAllAction(): ApiActionResetAll {
|
||||
return { type: API_ACTION_NAME.RESET_ALL };
|
||||
}
|
||||
|
||||
interface ApiActionResetGroups {
|
||||
type: typeof API_ACTION_NAME.RESET_GROUPS;
|
||||
}
|
||||
|
||||
export function resetGroupsAction(): ApiActionResetGroups {
|
||||
return { type: API_ACTION_NAME.RESET_GROUPS };
|
||||
}
|
||||
|
||||
interface ApiActionUpdateLoadingState {
|
||||
type: typeof API_ACTION_NAME.UPDATE_LOADING_STATE;
|
||||
payload: {
|
||||
ccsWarning: boolean;
|
||||
loaded: number;
|
||||
loadingState: string;
|
||||
remainingFieldCandidates?: string[];
|
||||
groupsMissing?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export function updateLoadingStateAction(
|
||||
payload: ApiActionUpdateLoadingState['payload']
|
||||
): ApiActionUpdateLoadingState {
|
||||
return {
|
||||
type: API_ACTION_NAME.UPDATE_LOADING_STATE,
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
interface ApiActionSetZeroDocsFallback {
|
||||
type: typeof API_ACTION_NAME.SET_ZERO_DOCS_FALLBACK;
|
||||
payload: boolean;
|
||||
}
|
||||
|
||||
export function setZeroDocsFallback(
|
||||
payload: ApiActionSetZeroDocsFallback['payload']
|
||||
): ApiActionSetZeroDocsFallback {
|
||||
return {
|
||||
type: API_ACTION_NAME.SET_ZERO_DOCS_FALLBACK,
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
export type AiopsLogRateAnalysisApiAction =
|
||||
| ApiActionAddSignificantItems
|
||||
| ApiActionAddSignificantItemsGroup
|
||||
| ApiActionAddSignificantItemsHistogram
|
||||
| ApiActionAddSignificantItemsGroupHistogram
|
||||
| ApiActionAddError
|
||||
| ApiActionPing
|
||||
| ApiActionResetAll
|
||||
| ApiActionResetErrors
|
||||
| ApiActionResetGroups
|
||||
| ApiActionUpdateLoadingState
|
||||
| ApiActionSetZeroDocsFallback;
|
|
@ -9,19 +9,20 @@ import { significantTerms } from '@kbn/aiops-test-utils/artificial_logs/signific
|
|||
import { finalSignificantItemGroups } from '@kbn/aiops-test-utils/artificial_logs/final_significant_item_groups';
|
||||
|
||||
import {
|
||||
addSignificantItemsAction,
|
||||
addSignificantItemsGroupAction,
|
||||
resetAllAction,
|
||||
resetGroupsAction,
|
||||
updateLoadingStateAction,
|
||||
} from './actions';
|
||||
import { initialState, streamReducer } from './stream_reducer';
|
||||
addSignificantItems,
|
||||
addSignificantItemsGroup,
|
||||
resetAll,
|
||||
resetGroups,
|
||||
updateLoadingState,
|
||||
getDefaultState,
|
||||
streamReducer,
|
||||
} from './stream_reducer';
|
||||
|
||||
describe('streamReducer', () => {
|
||||
it('updates loading state', () => {
|
||||
const state = streamReducer(
|
||||
initialState,
|
||||
updateLoadingStateAction({ ccsWarning: true, loaded: 50, loadingState: 'Loaded 50%' })
|
||||
getDefaultState(),
|
||||
updateLoadingState({ ccsWarning: true, loaded: 50, loadingState: 'Loaded 50%' })
|
||||
);
|
||||
|
||||
expect(state).toEqual({
|
||||
|
@ -37,8 +38,8 @@ describe('streamReducer', () => {
|
|||
|
||||
it('adds significant item, then resets all state again', () => {
|
||||
const state1 = streamReducer(
|
||||
initialState,
|
||||
addSignificantItemsAction([
|
||||
getDefaultState(),
|
||||
addSignificantItems([
|
||||
{
|
||||
key: 'the-field-name:the-field-value',
|
||||
type: 'keyword',
|
||||
|
@ -57,26 +58,23 @@ describe('streamReducer', () => {
|
|||
|
||||
expect(state1.significantItems).toHaveLength(1);
|
||||
|
||||
const state2 = streamReducer(state1, resetAllAction());
|
||||
const state2 = streamReducer(state1, resetAll());
|
||||
|
||||
expect(state2.significantItems).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('adds significant items and groups, then resets groups only', () => {
|
||||
const state1 = streamReducer(initialState, addSignificantItemsAction(significantTerms));
|
||||
const state1 = streamReducer(getDefaultState(), addSignificantItems(significantTerms));
|
||||
|
||||
expect(state1.significantItems).toHaveLength(4);
|
||||
expect(state1.significantItemsGroups).toHaveLength(0);
|
||||
|
||||
const state2 = streamReducer(
|
||||
state1,
|
||||
addSignificantItemsGroupAction(finalSignificantItemGroups)
|
||||
);
|
||||
const state2 = streamReducer(state1, addSignificantItemsGroup(finalSignificantItemGroups));
|
||||
|
||||
expect(state2.significantItems).toHaveLength(4);
|
||||
expect(state2.significantItemsGroups).toHaveLength(4);
|
||||
|
||||
const state3 = streamReducer(state2, resetGroupsAction());
|
||||
const state3 = streamReducer(state2, resetGroups());
|
||||
|
||||
expect(state3.significantItems).toHaveLength(4);
|
||||
expect(state3.significantItemsGroups).toHaveLength(0);
|
||||
|
|
|
@ -5,10 +5,15 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { SignificantItem, SignificantItemGroup } from '@kbn/ml-agg-utils';
|
||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
import type { AiopsLogRateAnalysisApiAction } from './actions';
|
||||
import { API_ACTION_NAME } from './actions';
|
||||
import type {
|
||||
SignificantItem,
|
||||
SignificantItemGroup,
|
||||
SignificantItemHistogram,
|
||||
SignificantItemGroupHistogram,
|
||||
} from '@kbn/ml-agg-utils';
|
||||
|
||||
export interface StreamState {
|
||||
ccsWarning: boolean;
|
||||
|
@ -22,7 +27,7 @@ export interface StreamState {
|
|||
zeroDocsFallback: boolean;
|
||||
}
|
||||
|
||||
export const initialState: StreamState = {
|
||||
export const getDefaultState = (): StreamState => ({
|
||||
ccsWarning: false,
|
||||
significantItems: [],
|
||||
significantItemsGroups: [],
|
||||
|
@ -30,50 +35,87 @@ export const initialState: StreamState = {
|
|||
loaded: 0,
|
||||
loadingState: '',
|
||||
zeroDocsFallback: false,
|
||||
};
|
||||
});
|
||||
|
||||
export function streamReducer(
|
||||
state: StreamState,
|
||||
action: AiopsLogRateAnalysisApiAction
|
||||
): StreamState {
|
||||
switch (action.type) {
|
||||
case API_ACTION_NAME.ADD_SIGNIFICANT_ITEMS:
|
||||
return { ...state, significantItems: [...state.significantItems, ...action.payload] };
|
||||
case API_ACTION_NAME.ADD_SIGNIFICANT_ITEMS_HISTOGRAM:
|
||||
const significantItems = state.significantItems.map((cp) => {
|
||||
export const logRateAnalysisResultsSlice = createSlice({
|
||||
name: 'logRateAnalysisResults',
|
||||
initialState: getDefaultState(),
|
||||
reducers: {
|
||||
addSignificantItems: (state, action: PayloadAction<SignificantItem[]>) => {
|
||||
state.significantItems.push(...action.payload);
|
||||
},
|
||||
addSignificantItemsHistogram: (state, action: PayloadAction<SignificantItemHistogram[]>) => {
|
||||
state.significantItems = state.significantItems.map((cp) => {
|
||||
const cpHistogram = action.payload.find(
|
||||
(h) => h.fieldName === cp.fieldName && h.fieldValue === cp.fieldValue
|
||||
);
|
||||
if (cpHistogram) {
|
||||
cp.histogram = cpHistogram.histogram;
|
||||
}
|
||||
return cp;
|
||||
return {
|
||||
...cp,
|
||||
...(cpHistogram ? { histogram: cpHistogram.histogram } : {}),
|
||||
};
|
||||
});
|
||||
return { ...state, significantItems };
|
||||
case API_ACTION_NAME.ADD_SIGNIFICANT_ITEMS_GROUP:
|
||||
return { ...state, significantItemsGroups: action.payload };
|
||||
case API_ACTION_NAME.ADD_SIGNIFICANT_ITEMS_GROUP_HISTOGRAM:
|
||||
const significantItemsGroups = state.significantItemsGroups.map((cpg) => {
|
||||
},
|
||||
addSignificantItemsGroup: (state, action: PayloadAction<SignificantItemGroup[]>) => {
|
||||
state.significantItemsGroups = action.payload;
|
||||
},
|
||||
addSignificantItemsGroupHistogram: (
|
||||
state,
|
||||
action: PayloadAction<SignificantItemGroupHistogram[]>
|
||||
) => {
|
||||
state.significantItemsGroups = state.significantItemsGroups.map((cpg) => {
|
||||
const cpHistogram = action.payload.find((h) => h.id === cpg.id);
|
||||
if (cpHistogram) {
|
||||
cpg.histogram = cpHistogram.histogram;
|
||||
}
|
||||
return cpg;
|
||||
});
|
||||
return { ...state, significantItemsGroups };
|
||||
case API_ACTION_NAME.ADD_ERROR:
|
||||
return { ...state, errors: [...state.errors, action.payload] };
|
||||
case API_ACTION_NAME.RESET_ERRORS:
|
||||
return { ...state, errors: [] };
|
||||
case API_ACTION_NAME.RESET_GROUPS:
|
||||
return { ...state, significantItemsGroups: [] };
|
||||
case API_ACTION_NAME.RESET_ALL:
|
||||
return initialState;
|
||||
case API_ACTION_NAME.UPDATE_LOADING_STATE:
|
||||
},
|
||||
addError: (state, action: PayloadAction<string>) => {
|
||||
state.errors.push(action.payload);
|
||||
},
|
||||
ping: () => {},
|
||||
resetErrors: (state) => {
|
||||
state.errors = [];
|
||||
},
|
||||
resetGroups: (state) => {
|
||||
state.significantItemsGroups = [];
|
||||
},
|
||||
resetAll: () => getDefaultState(),
|
||||
updateLoadingState: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
ccsWarning: boolean;
|
||||
loaded: number;
|
||||
loadingState: string;
|
||||
remainingFieldCandidates?: string[];
|
||||
groupsMissing?: boolean;
|
||||
}>
|
||||
) => {
|
||||
return { ...state, ...action.payload };
|
||||
case API_ACTION_NAME.SET_ZERO_DOCS_FALLBACK:
|
||||
return { ...state, zeroDocsFallback: action.payload };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
},
|
||||
setZeroDocsFallback: (state, action: PayloadAction<boolean>) => {
|
||||
state.zeroDocsFallback = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const streamReducer = logRateAnalysisResultsSlice.reducer;
|
||||
export const streamReducerActions = logRateAnalysisResultsSlice.actions;
|
||||
|
||||
type StreamReducerActions = typeof streamReducerActions;
|
||||
export type ApiActionName = keyof StreamReducerActions;
|
||||
export type AiopsLogRateAnalysisApiAction = ReturnType<StreamReducerActions[ApiActionName]>;
|
||||
|
||||
export const {
|
||||
addError,
|
||||
addSignificantItems,
|
||||
addSignificantItemsGroup,
|
||||
addSignificantItemsGroupHistogram,
|
||||
addSignificantItemsHistogram,
|
||||
ping,
|
||||
resetAll,
|
||||
resetErrors,
|
||||
resetGroups,
|
||||
setZeroDocsFallback,
|
||||
updateLoadingState,
|
||||
} = logRateAnalysisResultsSlice.actions;
|
||||
|
|
|
@ -9,7 +9,7 @@ export { LOG_RATE_ANALYSIS_HIGHLIGHT_COLOR } from './constants';
|
|||
export { getLogRateAnalysisType } from './get_log_rate_analysis_type';
|
||||
export { LOG_RATE_ANALYSIS_TYPE, type LogRateAnalysisType } from './log_rate_analysis_type';
|
||||
export type { LogRateHistogramItem } from './log_rate_histogram_item';
|
||||
export type { DocumentCountStatsChangePoint } from './types';
|
||||
export type { DocumentCountStats, DocumentStats, DocumentCountStatsChangePoint } from './types';
|
||||
export type { WindowParameters } from './window_parameters';
|
||||
export { getSnappedTimestamps } from './get_snapped_timestamps';
|
||||
export { getSnappedWindowParameters } from './get_snapped_window_parameters';
|
||||
|
|
15
x-pack/packages/ml/aiops_log_rate_analysis/state/hooks.ts
Normal file
15
x-pack/packages/ml/aiops_log_rate_analysis/state/hooks.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* 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 type { TypedUseSelectorHook } from 'react-redux';
|
||||
import { useDispatch, useSelector, useStore } from 'react-redux';
|
||||
import type { AppDispatch, AppStore, RootState } from './store';
|
||||
|
||||
// Improves TypeScript support compared to plain `useDispatch` and `useSelector`
|
||||
export const useAppDispatch: () => AppDispatch = useDispatch;
|
||||
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
||||
export const useAppStore: () => AppStore = useStore;
|
31
x-pack/packages/ml/aiops_log_rate_analysis/state/index.ts
Normal file
31
x-pack/packages/ml/aiops_log_rate_analysis/state/index.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export {
|
||||
brushSelectionUpdate,
|
||||
clearSelection,
|
||||
setAnalysisType,
|
||||
setAutoRunAnalysis,
|
||||
setDocumentCountChartData,
|
||||
setInitialAnalysisStart,
|
||||
setIsBrushCleared,
|
||||
setStickyHistogram,
|
||||
setWindowParameters,
|
||||
type BrushSelectionUpdatePayload,
|
||||
} from './log_rate_analysis_slice';
|
||||
export {
|
||||
clearAllRowState,
|
||||
setPinnedGroup,
|
||||
setPinnedSignificantItem,
|
||||
setSelectedGroup,
|
||||
setSelectedSignificantItem,
|
||||
} from './log_rate_analysis_table_row_slice';
|
||||
export { LogRateAnalysisReduxProvider } from './store';
|
||||
export { useAppDispatch, useAppSelector, useAppStore } from './hooks';
|
||||
export { useCurrentSelectedGroup } from './use_current_selected_group';
|
||||
export { useCurrentSelectedSignificantItem } from './use_current_selected_significant_item';
|
||||
export type { GroupTableItem, GroupTableItemGroup, TableItemAction } from './types';
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* 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 type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
import type { WindowParameters } from '../window_parameters';
|
||||
|
||||
import type { LogRateAnalysisType } from '../log_rate_analysis_type';
|
||||
import { LOG_RATE_ANALYSIS_TYPE } from '../log_rate_analysis_type';
|
||||
|
||||
import type { DocumentStats } from '../types';
|
||||
|
||||
export type InitialAnalysisStart = number | WindowParameters | undefined;
|
||||
|
||||
/**
|
||||
* Payload for brushSelectionUpdate action
|
||||
*/
|
||||
export interface BrushSelectionUpdatePayload {
|
||||
/** The window parameters to update the analysis with */
|
||||
windowParameters: WindowParameters;
|
||||
/** Flag to force the update */
|
||||
force: boolean;
|
||||
|
||||
analysisType: LogRateAnalysisType;
|
||||
}
|
||||
|
||||
export interface LogRateAnalysisState {
|
||||
analysisType: LogRateAnalysisType;
|
||||
autoRunAnalysis: boolean;
|
||||
initialAnalysisStart: InitialAnalysisStart;
|
||||
isBrushCleared: boolean;
|
||||
stickyHistogram: boolean;
|
||||
windowParameters?: WindowParameters;
|
||||
earliest?: number;
|
||||
latest?: number;
|
||||
intervalMs?: number;
|
||||
documentStats: DocumentStats;
|
||||
}
|
||||
|
||||
function getDefaultState(): LogRateAnalysisState {
|
||||
return {
|
||||
analysisType: LOG_RATE_ANALYSIS_TYPE.SPIKE,
|
||||
autoRunAnalysis: true,
|
||||
initialAnalysisStart: undefined,
|
||||
isBrushCleared: true,
|
||||
documentStats: {
|
||||
sampleProbability: 1,
|
||||
totalCount: 0,
|
||||
},
|
||||
// Default to false for now, until page restructure work to enable smooth sticky histogram is done
|
||||
stickyHistogram: false,
|
||||
};
|
||||
}
|
||||
|
||||
export const logRateAnalysisSlice = createSlice({
|
||||
name: 'logRateAnalysis',
|
||||
initialState: getDefaultState(),
|
||||
reducers: {
|
||||
brushSelectionUpdate: (
|
||||
state: LogRateAnalysisState,
|
||||
action: PayloadAction<BrushSelectionUpdatePayload>
|
||||
) => {
|
||||
if (!state.isBrushCleared || action.payload.force) {
|
||||
state.windowParameters = action.payload.windowParameters;
|
||||
}
|
||||
if (action.payload.force) {
|
||||
state.isBrushCleared = false;
|
||||
}
|
||||
state.analysisType = action.payload.analysisType;
|
||||
},
|
||||
clearSelection: (state: LogRateAnalysisState) => {
|
||||
state.windowParameters = undefined;
|
||||
state.isBrushCleared = true;
|
||||
state.initialAnalysisStart = undefined;
|
||||
},
|
||||
setAnalysisType: (state: LogRateAnalysisState, action: PayloadAction<LogRateAnalysisType>) => {
|
||||
state.analysisType = action.payload;
|
||||
},
|
||||
setAutoRunAnalysis: (state: LogRateAnalysisState, action: PayloadAction<boolean>) => {
|
||||
state.autoRunAnalysis = action.payload;
|
||||
},
|
||||
setDocumentCountChartData: (
|
||||
state: LogRateAnalysisState,
|
||||
action: PayloadAction<{
|
||||
earliest?: number;
|
||||
latest?: number;
|
||||
intervalMs?: number;
|
||||
documentStats: DocumentStats;
|
||||
}>
|
||||
) => {
|
||||
state.earliest = action.payload.earliest;
|
||||
state.latest = action.payload.latest;
|
||||
state.intervalMs = action.payload.intervalMs;
|
||||
state.documentStats = action.payload.documentStats;
|
||||
},
|
||||
setInitialAnalysisStart: (
|
||||
state: LogRateAnalysisState,
|
||||
action: PayloadAction<InitialAnalysisStart>
|
||||
) => {
|
||||
state.initialAnalysisStart = action.payload;
|
||||
},
|
||||
setIsBrushCleared: (state: LogRateAnalysisState, action: PayloadAction<boolean>) => {
|
||||
state.isBrushCleared = action.payload;
|
||||
},
|
||||
setStickyHistogram: (state: LogRateAnalysisState, action: PayloadAction<boolean>) => {
|
||||
state.stickyHistogram = action.payload;
|
||||
},
|
||||
setWindowParameters: (
|
||||
state: LogRateAnalysisState,
|
||||
action: PayloadAction<WindowParameters | undefined>
|
||||
) => {
|
||||
state.windowParameters = action.payload;
|
||||
state.isBrushCleared = action.payload === undefined;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Action creators are generated for each case reducer function
|
||||
export const {
|
||||
brushSelectionUpdate,
|
||||
clearSelection,
|
||||
setAnalysisType,
|
||||
setAutoRunAnalysis,
|
||||
setDocumentCountChartData,
|
||||
setInitialAnalysisStart,
|
||||
setIsBrushCleared,
|
||||
setStickyHistogram,
|
||||
setWindowParameters,
|
||||
} = logRateAnalysisSlice.actions;
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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 type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
import type { SignificantItem } from '@kbn/ml-agg-utils';
|
||||
|
||||
import type { GroupTableItem } from './types';
|
||||
|
||||
type SignificantItemOrNull = SignificantItem | null;
|
||||
type GroupOrNull = GroupTableItem | null;
|
||||
|
||||
export interface LogRateAnalysisTableRowState {
|
||||
pinnedGroup: GroupOrNull;
|
||||
pinnedSignificantItem: SignificantItemOrNull;
|
||||
selectedGroup: GroupOrNull;
|
||||
selectedSignificantItem: SignificantItemOrNull;
|
||||
}
|
||||
|
||||
function getDefaultState(): LogRateAnalysisTableRowState {
|
||||
return {
|
||||
pinnedGroup: null,
|
||||
pinnedSignificantItem: null,
|
||||
selectedGroup: null,
|
||||
selectedSignificantItem: null,
|
||||
};
|
||||
}
|
||||
|
||||
export const logRateAnalysisTableRowSlice = createSlice({
|
||||
name: 'logRateAnalysisTableRow',
|
||||
initialState: getDefaultState(),
|
||||
reducers: {
|
||||
clearAllRowState: (state: LogRateAnalysisTableRowState) => {
|
||||
state.pinnedGroup = null;
|
||||
state.pinnedSignificantItem = null;
|
||||
state.selectedGroup = null;
|
||||
state.selectedSignificantItem = null;
|
||||
},
|
||||
setPinnedGroup: (state: LogRateAnalysisTableRowState, action: PayloadAction<GroupOrNull>) => {
|
||||
state.pinnedGroup = action.payload;
|
||||
},
|
||||
setPinnedSignificantItem: (
|
||||
state: LogRateAnalysisTableRowState,
|
||||
action: PayloadAction<SignificantItemOrNull>
|
||||
) => {
|
||||
state.pinnedSignificantItem = action.payload;
|
||||
},
|
||||
setSelectedGroup: (state: LogRateAnalysisTableRowState, action: PayloadAction<GroupOrNull>) => {
|
||||
state.selectedGroup = action.payload;
|
||||
},
|
||||
setSelectedSignificantItem: (
|
||||
state: LogRateAnalysisTableRowState,
|
||||
action: PayloadAction<SignificantItemOrNull>
|
||||
) => {
|
||||
state.selectedSignificantItem = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Action creators are generated for each case reducer function
|
||||
export const {
|
||||
clearAllRowState,
|
||||
setPinnedGroup,
|
||||
setPinnedSignificantItem,
|
||||
setSelectedGroup,
|
||||
setSelectedSignificantItem,
|
||||
} = logRateAnalysisTableRowSlice.actions;
|
56
x-pack/packages/ml/aiops_log_rate_analysis/state/store.tsx
Normal file
56
x-pack/packages/ml/aiops_log_rate_analysis/state/store.tsx
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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, { useMemo, type FC, type PropsWithChildren } from 'react';
|
||||
import { configureStore } from '@reduxjs/toolkit';
|
||||
import { Provider } from 'react-redux';
|
||||
import useMount from 'react-use/lib/useMount';
|
||||
|
||||
import { streamSlice } from '@kbn/ml-response-stream/client';
|
||||
|
||||
import { logRateAnalysisResultsSlice } from '../api/stream_reducer';
|
||||
|
||||
import { logRateAnalysisSlice } from './log_rate_analysis_slice';
|
||||
import { logRateAnalysisTableRowSlice } from './log_rate_analysis_table_row_slice';
|
||||
import type { InitialAnalysisStart } from './log_rate_analysis_slice';
|
||||
|
||||
const getReduxStore = () =>
|
||||
configureStore({
|
||||
reducer: {
|
||||
// General page state
|
||||
logRateAnalysis: logRateAnalysisSlice.reducer,
|
||||
// Analysis results
|
||||
logRateAnalysisResults: logRateAnalysisResultsSlice.reducer,
|
||||
// Handles running the analysis
|
||||
logRateAnalysisStream: streamSlice.reducer,
|
||||
// Handles hovering and pinning table rows
|
||||
logRateAnalysisTableRow: logRateAnalysisTableRowSlice.reducer,
|
||||
},
|
||||
});
|
||||
|
||||
interface LogRateAnalysisReduxProviderProps {
|
||||
initialAnalysisStart?: InitialAnalysisStart;
|
||||
}
|
||||
|
||||
export const LogRateAnalysisReduxProvider: FC<
|
||||
PropsWithChildren<LogRateAnalysisReduxProviderProps>
|
||||
> = ({ children, initialAnalysisStart }) => {
|
||||
const store = useMemo(getReduxStore, []);
|
||||
|
||||
useMount(() => {
|
||||
if (initialAnalysisStart) {
|
||||
store.dispatch(logRateAnalysisSlice.actions.setInitialAnalysisStart(initialAnalysisStart));
|
||||
}
|
||||
});
|
||||
|
||||
return <Provider store={store}>{children}</Provider>;
|
||||
};
|
||||
|
||||
// Infer the `RootState` and `AppDispatch` types from the store itself
|
||||
export type AppStore = ReturnType<typeof getReduxStore>;
|
||||
export type RootState = ReturnType<AppStore['getState']>;
|
||||
export type AppDispatch = AppStore['dispatch'];
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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 { createSelector } from '@reduxjs/toolkit';
|
||||
|
||||
import type { RootState } from './store';
|
||||
import { useAppSelector } from './hooks';
|
||||
|
||||
const selectSelectedGroup = (s: RootState) => s.logRateAnalysisTableRow.selectedGroup;
|
||||
const selectPinnedGroup = (s: RootState) => s.logRateAnalysisTableRow.pinnedGroup;
|
||||
const selectCurrentSelectedGroup = createSelector(
|
||||
selectSelectedGroup,
|
||||
selectPinnedGroup,
|
||||
(selectedGroup, pinnedGroup) => {
|
||||
if (selectedGroup) {
|
||||
return selectedGroup;
|
||||
} else if (pinnedGroup) {
|
||||
return pinnedGroup;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const useCurrentSelectedGroup = () => useAppSelector(selectCurrentSelectedGroup);
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 { createSelector } from '@reduxjs/toolkit';
|
||||
|
||||
import type { RootState } from './store';
|
||||
import { useAppSelector } from './hooks';
|
||||
|
||||
const selectSelectedSignificantItem = (s: RootState) =>
|
||||
s.logRateAnalysisTableRow.selectedSignificantItem;
|
||||
const selectPinnedSignificantItem = (s: RootState) =>
|
||||
s.logRateAnalysisTableRow.pinnedSignificantItem;
|
||||
const selectCurrentSelectedSignificantItem = createSelector(
|
||||
selectSelectedSignificantItem,
|
||||
selectPinnedSignificantItem,
|
||||
(selectedSignificantItem, pinnedSignificantItem) => {
|
||||
if (selectedSignificantItem) {
|
||||
return selectedSignificantItem;
|
||||
} else if (pinnedSignificantItem) {
|
||||
return pinnedSignificantItem;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const useCurrentSelectedSignificantItem = () =>
|
||||
useAppSelector(selectCurrentSelectedSignificantItem);
|
|
@ -29,5 +29,6 @@
|
|||
"@kbn/field-types",
|
||||
"@kbn/ml-chi2test",
|
||||
"@kbn/ml-string-hash",
|
||||
"@kbn/ml-response-stream",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -55,3 +55,37 @@ export interface DocumentCountStatsChangePoint {
|
|||
/** The type of change point. */
|
||||
type: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the document count statistics for a given time range.
|
||||
*/
|
||||
export interface DocumentCountStats {
|
||||
/** The time interval in milliseconds. */
|
||||
interval?: number;
|
||||
/** The document count per time bucket. */
|
||||
buckets?: { [key: string]: number };
|
||||
/** The change point in the document count statistics. */
|
||||
changePoint?: DocumentCountStatsChangePoint;
|
||||
/** The earliest timestamp in the time range. */
|
||||
timeRangeEarliest?: number;
|
||||
/** The latest timestamp in the time range. */
|
||||
timeRangeLatest?: number;
|
||||
/** The total document count. */
|
||||
totalCount: number;
|
||||
/** The timestamp of the last document in the time range. */
|
||||
lastDocTimeStampMs?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the overall document stats.
|
||||
*/
|
||||
export interface DocumentStats {
|
||||
/** The probability of sampling. */
|
||||
sampleProbability: number;
|
||||
/** The total document count. */
|
||||
totalCount: number;
|
||||
/** The document count statistics. */
|
||||
documentCountStats?: DocumentCountStats;
|
||||
/** The document count statistics for comparison. */
|
||||
documentCountStatsCompare?: DocumentCountStats;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import type { SignificantItem } from '@kbn/ml-agg-utils';
|
||||
import type { GroupTableItem } from '@kbn/aiops-components';
|
||||
import type { GroupTableItem } from '@kbn/aiops-log-rate-analysis/state';
|
||||
|
||||
import { buildExtendedBaseFilterCriteria } from './build_extended_base_filter_criteria';
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import type { Query } from '@kbn/es-query';
|
|||
import { type SignificantItem, SIGNIFICANT_ITEM_TYPE } from '@kbn/ml-agg-utils';
|
||||
import { buildBaseFilterCriteria } from '@kbn/ml-query-utils';
|
||||
import { getCategoryQuery } from '@kbn/aiops-log-pattern-analysis/get_category_query';
|
||||
import type { GroupTableItem } from '@kbn/aiops-components';
|
||||
import type { GroupTableItem } from '@kbn/aiops-log-rate-analysis/state';
|
||||
|
||||
/*
|
||||
* Contains utility functions for building and processing queries.
|
||||
|
|
|
@ -13,30 +13,18 @@ import type {
|
|||
RectAnnotationSpec,
|
||||
} from '@elastic/charts/dist/chart_types/xy_chart/utils/specs';
|
||||
|
||||
import type { LogRateHistogramItem, WindowParameters } from '@kbn/aiops-log-rate-analysis';
|
||||
import {
|
||||
DocumentCountChartWithAutoAnalysisStart,
|
||||
type BrushSelectionUpdateHandler,
|
||||
} from '@kbn/aiops-components';
|
||||
import { useAppSelector } from '@kbn/aiops-log-rate-analysis/state';
|
||||
import { DocumentCountChartRedux } from '@kbn/aiops-components';
|
||||
|
||||
import { useAiopsAppContext } from '../../../hooks/use_aiops_app_context';
|
||||
import type { DocumentCountStats } from '../../../get_document_stats';
|
||||
|
||||
import { TotalCountHeader } from '../total_count_header';
|
||||
|
||||
export interface DocumentCountContentProps {
|
||||
brushSelectionUpdateHandler: BrushSelectionUpdateHandler;
|
||||
documentCountStats?: DocumentCountStats;
|
||||
documentCountStatsSplit?: DocumentCountStats;
|
||||
documentCountStatsSplitLabel?: string;
|
||||
isBrushCleared: boolean;
|
||||
totalCount: number;
|
||||
sampleProbability: number;
|
||||
/** Optional color override for the default bar color for charts */
|
||||
barColorOverride?: string;
|
||||
/** Optional color override for the highlighted bar color for charts */
|
||||
barHighlightColorOverride?: string;
|
||||
windowParameters?: WindowParameters;
|
||||
baselineLabel?: string;
|
||||
deviationLabel?: string;
|
||||
barStyleAccessor?: BarStyleAccessor;
|
||||
|
@ -45,77 +33,35 @@ export interface DocumentCountContentProps {
|
|||
}
|
||||
|
||||
export const DocumentCountContent: FC<DocumentCountContentProps> = ({
|
||||
brushSelectionUpdateHandler,
|
||||
documentCountStats,
|
||||
documentCountStatsSplit,
|
||||
documentCountStatsSplitLabel = '',
|
||||
isBrushCleared,
|
||||
totalCount,
|
||||
sampleProbability,
|
||||
barColorOverride,
|
||||
barHighlightColorOverride,
|
||||
windowParameters,
|
||||
...docCountChartProps
|
||||
}) => {
|
||||
const { data, uiSettings, fieldFormats, charts } = useAiopsAppContext();
|
||||
|
||||
const bucketTimestamps = Object.keys(documentCountStats?.buckets ?? {}).map((time) => +time);
|
||||
const splitBucketTimestamps = Object.keys(documentCountStatsSplit?.buckets ?? {}).map(
|
||||
(time) => +time
|
||||
);
|
||||
const timeRangeEarliest = Math.min(...[...bucketTimestamps, ...splitBucketTimestamps]);
|
||||
const timeRangeLatest = Math.max(...[...bucketTimestamps, ...splitBucketTimestamps]);
|
||||
const { documentStats } = useAppSelector((s) => s.logRateAnalysis);
|
||||
const { sampleProbability, totalCount, documentCountStats } = documentStats;
|
||||
|
||||
if (
|
||||
documentCountStats === undefined ||
|
||||
documentCountStats.buckets === undefined ||
|
||||
timeRangeEarliest === undefined ||
|
||||
timeRangeLatest === undefined
|
||||
) {
|
||||
if (documentCountStats === undefined) {
|
||||
return totalCount !== undefined ? (
|
||||
<TotalCountHeader totalCount={totalCount} sampleProbability={sampleProbability} />
|
||||
) : null;
|
||||
}
|
||||
|
||||
const chartPoints: LogRateHistogramItem[] = Object.entries(documentCountStats.buckets).map(
|
||||
([time, value]) => ({
|
||||
time: +time,
|
||||
value,
|
||||
})
|
||||
);
|
||||
|
||||
let chartPointsSplit: LogRateHistogramItem[] | undefined;
|
||||
if (documentCountStatsSplit?.buckets !== undefined) {
|
||||
chartPointsSplit = Object.entries(documentCountStatsSplit?.buckets).map(([time, value]) => ({
|
||||
time: +time,
|
||||
value,
|
||||
}));
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiFlexGroup gutterSize="m" direction="column">
|
||||
<EuiFlexItem>
|
||||
<TotalCountHeader totalCount={totalCount} sampleProbability={sampleProbability} />
|
||||
</EuiFlexItem>
|
||||
{documentCountStats.interval !== undefined && (
|
||||
<EuiFlexItem>
|
||||
<DocumentCountChartWithAutoAnalysisStart
|
||||
dependencies={{ data, uiSettings, fieldFormats, charts }}
|
||||
brushSelectionUpdateHandler={brushSelectionUpdateHandler}
|
||||
chartPoints={chartPoints}
|
||||
chartPointsSplit={chartPointsSplit}
|
||||
timeRangeEarliest={timeRangeEarliest}
|
||||
timeRangeLatest={timeRangeLatest}
|
||||
interval={documentCountStats.interval}
|
||||
chartPointsSplitLabel={documentCountStatsSplitLabel}
|
||||
isBrushCleared={isBrushCleared}
|
||||
barColorOverride={barColorOverride}
|
||||
barHighlightColorOverride={barHighlightColorOverride}
|
||||
changePoint={documentCountStats.changePoint}
|
||||
{...docCountChartProps}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
<EuiFlexItem>
|
||||
<DocumentCountChartRedux
|
||||
dependencies={{ data, uiSettings, fieldFormats, charts }}
|
||||
barColorOverride={barColorOverride}
|
||||
barHighlightColorOverride={barHighlightColorOverride}
|
||||
changePoint={documentCountStats.changePoint}
|
||||
{...docCountChartProps}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -11,9 +11,9 @@ import React, { useMemo } from 'react';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { DocumentCountChart as DocumentCountChartRoot } from '@kbn/aiops-components';
|
||||
import type { Category } from '@kbn/aiops-log-pattern-analysis/types';
|
||||
import type { DocumentCountStats } from '@kbn/aiops-log-rate-analysis/types';
|
||||
|
||||
import { useAiopsAppContext } from '../../hooks/use_aiops_app_context';
|
||||
import type { DocumentCountStats } from '../../get_document_stats';
|
||||
|
||||
import { TotalCountHeader } from '../document_count_content/total_count_header';
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ import { UrlStateProvider } from '@kbn/ml-url-state';
|
|||
import { Storage } from '@kbn/kibana-utils-plugin/public';
|
||||
import { DatePickerContextProvider, type DatePickerDependencies } from '@kbn/ml-date-picker';
|
||||
import { UI_SETTINGS } from '@kbn/data-plugin/common';
|
||||
import { LogRateAnalysisReduxProvider } from '@kbn/aiops-log-rate-analysis/state';
|
||||
|
||||
import { LogRateAnalysisStateProvider } from '@kbn/aiops-components';
|
||||
import type { AiopsAppDependencies } from '../../hooks/use_aiops_app_context';
|
||||
import { AiopsAppContext } from '../../hooks/use_aiops_app_context';
|
||||
import { DataSourceContext } from '../../hooks/use_data_source';
|
||||
|
@ -38,8 +38,6 @@ export interface LogRateAnalysisAppStateProps {
|
|||
savedSearch: SavedSearch | null;
|
||||
/** App dependencies */
|
||||
appDependencies: AiopsAppDependencies;
|
||||
/** Option to make main histogram sticky */
|
||||
stickyHistogram?: boolean;
|
||||
/** Optional flag to indicate whether kibana is running in serverless */
|
||||
showFrozenDataTierChoice?: boolean;
|
||||
}
|
||||
|
@ -48,7 +46,6 @@ export const LogRateAnalysisAppState: FC<LogRateAnalysisAppStateProps> = ({
|
|||
dataView,
|
||||
savedSearch,
|
||||
appDependencies,
|
||||
stickyHistogram,
|
||||
showFrozenDataTierChoice = true,
|
||||
}) => {
|
||||
if (!dataView) return null;
|
||||
|
@ -69,13 +66,13 @@ export const LogRateAnalysisAppState: FC<LogRateAnalysisAppStateProps> = ({
|
|||
<AiopsAppContext.Provider value={appDependencies}>
|
||||
<UrlStateProvider>
|
||||
<DataSourceContext.Provider value={{ dataView, savedSearch }}>
|
||||
<LogRateAnalysisStateProvider>
|
||||
<LogRateAnalysisReduxProvider>
|
||||
<StorageContextProvider storage={localStorage} storageKeys={AIOPS_STORAGE_KEYS}>
|
||||
<DatePickerContextProvider {...datePickerDeps}>
|
||||
<LogRateAnalysisPage stickyHistogram={stickyHistogram} />
|
||||
<LogRateAnalysisPage />
|
||||
</DatePickerContextProvider>
|
||||
</StorageContextProvider>
|
||||
</LogRateAnalysisStateProvider>
|
||||
</LogRateAnalysisReduxProvider>
|
||||
</DataSourceContext.Provider>
|
||||
</UrlStateProvider>
|
||||
</AiopsAppContext.Provider>
|
||||
|
|
|
@ -6,14 +6,13 @@
|
|||
*/
|
||||
|
||||
import { isEqual } from 'lodash';
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState, type FC } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useRef, type FC } from 'react';
|
||||
import { EuiButton, EuiEmptyPrompt, EuiHorizontalRule, EuiPanel } from '@elastic/eui';
|
||||
import type { Moment } from 'moment';
|
||||
|
||||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import type { BarStyleAccessor } from '@elastic/charts/dist/chart_types/xy_chart/utils/specs';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import {
|
||||
getWindowParametersForTrigger,
|
||||
|
@ -21,14 +20,16 @@ import {
|
|||
getSnappedWindowParameters,
|
||||
LOG_RATE_ANALYSIS_HIGHLIGHT_COLOR,
|
||||
LOG_RATE_ANALYSIS_TYPE,
|
||||
type LogRateAnalysisType,
|
||||
type WindowParameters,
|
||||
} from '@kbn/aiops-log-rate-analysis';
|
||||
import type { SignificantItem } from '@kbn/ml-agg-utils';
|
||||
import { useLogRateAnalysisStateContext, type GroupTableItem } from '@kbn/aiops-components';
|
||||
|
||||
import { useData } from '../../../hooks/use_data';
|
||||
import { useDataSource } from '../../../hooks/use_data_source';
|
||||
import {
|
||||
clearAllRowState,
|
||||
clearSelection,
|
||||
setAutoRunAnalysis,
|
||||
setInitialAnalysisStart,
|
||||
useAppDispatch,
|
||||
useAppSelector,
|
||||
} from '@kbn/aiops-log-rate-analysis/state';
|
||||
|
||||
import { DocumentCountContent } from '../../document_count_content/document_count_content';
|
||||
import {
|
||||
|
@ -49,26 +50,11 @@ const DEFAULT_SEARCH_BAR_QUERY: estypes.QueryDslQueryContainer = {
|
|||
},
|
||||
};
|
||||
|
||||
export function getDocumentCountStatsSplitLabel(
|
||||
significantItem?: SignificantItem,
|
||||
group?: GroupTableItem
|
||||
) {
|
||||
if (significantItem) {
|
||||
return `${significantItem?.fieldName}:${significantItem?.fieldValue}`;
|
||||
} else if (group) {
|
||||
return i18n.translate('xpack.aiops.logRateAnalysis.page.documentCountStatsSplitGroupLabel', {
|
||||
defaultMessage: 'Selected group',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface LogRateAnalysisContentProps {
|
||||
/** Optional time range override */
|
||||
timeRange?: { min: Moment; max: Moment };
|
||||
/** Elasticsearch query to pass to analysis endpoint */
|
||||
esSearchQuery?: estypes.QueryDslQueryContainer;
|
||||
/** Option to make the main histogram sticky */
|
||||
stickyHistogram?: boolean;
|
||||
/** Optional color override for the default bar color for charts */
|
||||
barColorOverride?: string;
|
||||
/** Optional color override for the highlighted bar color for charts */
|
||||
|
@ -84,24 +70,22 @@ export interface LogRateAnalysisContentProps {
|
|||
export const LogRateAnalysisContent: FC<LogRateAnalysisContentProps> = ({
|
||||
timeRange,
|
||||
esSearchQuery = DEFAULT_SEARCH_QUERY,
|
||||
stickyHistogram,
|
||||
barColorOverride,
|
||||
barHighlightColorOverride,
|
||||
onAnalysisCompleted,
|
||||
onWindowParametersChange,
|
||||
embeddingOrigin,
|
||||
}) => {
|
||||
const { dataView } = useDataSource();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [windowParameters, setWindowParameters] = useState<WindowParameters | undefined>();
|
||||
const [isBrushCleared, setIsBrushCleared] = useState(true);
|
||||
const [logRateAnalysisType, setLogRateAnalysisType] = useState<LogRateAnalysisType>(
|
||||
LOG_RATE_ANALYSIS_TYPE.SPIKE
|
||||
const isRunning = useAppSelector((s) => s.logRateAnalysisStream.isRunning);
|
||||
const significantItems = useAppSelector((s) => s.logRateAnalysisResults.significantItems);
|
||||
const significantItemsGroups = useAppSelector(
|
||||
(s) => s.logRateAnalysisResults.significantItemsGroups
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setIsBrushCleared(windowParameters === undefined);
|
||||
}, [windowParameters]);
|
||||
const loaded = useAppSelector((s) => s.logRateAnalysisResults.loaded);
|
||||
const analysisType = useAppSelector((s) => s.logRateAnalysis.analysisType);
|
||||
const windowParameters = useAppSelector((s) => s.logRateAnalysis.windowParameters);
|
||||
|
||||
// Window parameters stored in the url state use this components
|
||||
// `initialAnalysisStart` prop to set the initial params restore from url state.
|
||||
|
@ -132,55 +116,15 @@ export const LogRateAnalysisContent: FC<LogRateAnalysisContentProps> = ({
|
|||
[esSearchQuery]
|
||||
);
|
||||
|
||||
const {
|
||||
autoRunAnalysis,
|
||||
currentSelectedSignificantItem,
|
||||
currentSelectedGroup,
|
||||
setAutoRunAnalysis,
|
||||
setInitialAnalysisStart,
|
||||
setPinnedSignificantItem,
|
||||
setPinnedGroup,
|
||||
setSelectedSignificantItem,
|
||||
setSelectedGroup,
|
||||
} = useLogRateAnalysisStateContext();
|
||||
|
||||
const { documentStats, earliest, latest } = useData(
|
||||
dataView,
|
||||
'log_rate_analysis',
|
||||
searchQuery,
|
||||
undefined,
|
||||
currentSelectedSignificantItem,
|
||||
currentSelectedGroup,
|
||||
undefined,
|
||||
true,
|
||||
timeRange
|
||||
const { autoRunAnalysis, documentStats, earliest, latest, isBrushCleared } = useAppSelector(
|
||||
(s) => s.logRateAnalysis
|
||||
);
|
||||
|
||||
const { sampleProbability, totalCount, documentCountStats, documentCountStatsCompare } =
|
||||
documentStats;
|
||||
const { documentCountStats } = documentStats;
|
||||
|
||||
function brushSelectionUpdate(
|
||||
windowParametersUpdate: WindowParameters,
|
||||
force: boolean,
|
||||
logRateAnalysisTypeUpdate: LogRateAnalysisType
|
||||
) {
|
||||
if (!isBrushCleared || force) {
|
||||
setWindowParameters(windowParametersUpdate);
|
||||
}
|
||||
if (force) {
|
||||
setIsBrushCleared(false);
|
||||
}
|
||||
setLogRateAnalysisType(logRateAnalysisTypeUpdate);
|
||||
}
|
||||
|
||||
function clearSelection() {
|
||||
setWindowParameters(undefined);
|
||||
setPinnedSignificantItem(null);
|
||||
setPinnedGroup(null);
|
||||
setSelectedSignificantItem(null);
|
||||
setSelectedGroup(null);
|
||||
setIsBrushCleared(true);
|
||||
setInitialAnalysisStart(undefined);
|
||||
function clearSelectionHandler() {
|
||||
dispatch(clearSelection());
|
||||
dispatch(clearAllRowState());
|
||||
}
|
||||
|
||||
const barStyle = {
|
||||
|
@ -204,8 +148,8 @@ export const LogRateAnalysisContent: FC<LogRateAnalysisContentProps> = ({
|
|||
: undefined;
|
||||
|
||||
const triggerAnalysisForManualSelection = useCallback(() => {
|
||||
setAutoRunAnalysis(true);
|
||||
}, [setAutoRunAnalysis]);
|
||||
dispatch(setAutoRunAnalysis(true));
|
||||
}, [dispatch]);
|
||||
|
||||
const triggerAnalysisForChangePoint = useCallback(() => {
|
||||
if (documentCountStats) {
|
||||
|
@ -224,10 +168,21 @@ export const LogRateAnalysisContent: FC<LogRateAnalysisContentProps> = ({
|
|||
const wpSnap = getSnappedWindowParameters(wp, snapTimestamps);
|
||||
|
||||
triggerAnalysisForManualSelection();
|
||||
setInitialAnalysisStart(wpSnap);
|
||||
dispatch(setInitialAnalysisStart(wpSnap));
|
||||
}
|
||||
}
|
||||
}, [documentCountStats, setInitialAnalysisStart, triggerAnalysisForManualSelection]);
|
||||
}, [documentCountStats, dispatch, triggerAnalysisForManualSelection]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isRunning && loaded === 1 && onAnalysisCompleted) {
|
||||
onAnalysisCompleted({
|
||||
analysisType,
|
||||
significantItems,
|
||||
significantItemsGroups,
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isRunning, loaded]);
|
||||
|
||||
const showDocumentCountContent = documentCountStats !== undefined;
|
||||
|
||||
|
@ -255,16 +210,6 @@ export const LogRateAnalysisContent: FC<LogRateAnalysisContentProps> = ({
|
|||
<EuiPanel hasBorder={false} hasShadow={false}>
|
||||
{showDocumentCountContent && (
|
||||
<DocumentCountContent
|
||||
brushSelectionUpdateHandler={brushSelectionUpdate}
|
||||
documentCountStats={documentCountStats}
|
||||
documentCountStatsSplit={documentCountStatsCompare}
|
||||
documentCountStatsSplitLabel={getDocumentCountStatsSplitLabel(
|
||||
currentSelectedSignificantItem,
|
||||
currentSelectedGroup
|
||||
)}
|
||||
isBrushCleared={isBrushCleared}
|
||||
totalCount={totalCount}
|
||||
sampleProbability={sampleProbability}
|
||||
barColorOverride={barColorOverride}
|
||||
barHighlightColorOverride={barHighlightColorOverride}
|
||||
barStyleAccessor={barStyleAccessor}
|
||||
|
@ -273,18 +218,10 @@ export const LogRateAnalysisContent: FC<LogRateAnalysisContentProps> = ({
|
|||
<EuiHorizontalRule />
|
||||
{showLogRateAnalysisResults && (
|
||||
<LogRateAnalysisResults
|
||||
analysisType={logRateAnalysisType}
|
||||
earliest={earliest}
|
||||
isBrushCleared={isBrushCleared}
|
||||
latest={latest}
|
||||
stickyHistogram={stickyHistogram}
|
||||
onReset={clearSelection}
|
||||
sampleProbability={sampleProbability}
|
||||
onReset={clearSelectionHandler}
|
||||
searchQuery={searchQuery}
|
||||
windowParameters={windowParameters}
|
||||
barColorOverride={barColorOverride}
|
||||
barHighlightColorOverride={barHighlightColorOverride}
|
||||
onAnalysisCompleted={onAnalysisCompleted}
|
||||
embeddingOrigin={embeddingOrigin}
|
||||
/>
|
||||
)}
|
||||
|
@ -315,7 +252,7 @@ export const LogRateAnalysisContent: FC<LogRateAnalysisContentProps> = ({
|
|||
</EuiButton>{' '}
|
||||
<EuiButton
|
||||
data-test-subj="aiopsClearSelectionBadge"
|
||||
onClick={() => clearSelection()}
|
||||
onClick={() => clearSelectionHandler()}
|
||||
color="text"
|
||||
>
|
||||
<FormattedMessage
|
||||
|
@ -380,7 +317,7 @@ export const LogRateAnalysisContent: FC<LogRateAnalysisContentProps> = ({
|
|||
data-test-subj="aiopsChangePointDetectedPrompt"
|
||||
/>
|
||||
)}
|
||||
{showDefaultEmptyPrompt && (
|
||||
{showDocumentCountContent && showDefaultEmptyPrompt && (
|
||||
<EuiEmptyPrompt
|
||||
color="subdued"
|
||||
hasShadow={false}
|
||||
|
|
|
@ -18,16 +18,17 @@ import { UrlStateProvider } from '@kbn/ml-url-state';
|
|||
import { Storage } from '@kbn/kibana-utils-plugin/public';
|
||||
import { DatePickerContextProvider } from '@kbn/ml-date-picker';
|
||||
import { UI_SETTINGS } from '@kbn/data-plugin/common';
|
||||
import { LogRateAnalysisStateProvider } from '@kbn/aiops-components';
|
||||
import { LogRateAnalysisReduxProvider } from '@kbn/aiops-log-rate-analysis/state';
|
||||
|
||||
import { timeSeriesDataViewWarning } from '../../../application/utils/time_series_dataview_check';
|
||||
import { AiopsAppContext, type AiopsAppDependencies } from '../../../hooks/use_aiops_app_context';
|
||||
import { DataSourceContext } from '../../../hooks/use_data_source';
|
||||
import { AIOPS_STORAGE_KEYS } from '../../../types/storage';
|
||||
|
||||
import { LogRateAnalysisContent } from './log_rate_analysis_content';
|
||||
import type { LogRateAnalysisResultsData } from '../log_rate_analysis_results';
|
||||
|
||||
import { LogRateAnalysisContent } from './log_rate_analysis_content';
|
||||
|
||||
const localStorage = new Storage(window.localStorage);
|
||||
|
||||
/**
|
||||
|
@ -36,8 +37,6 @@ const localStorage = new Storage(window.localStorage);
|
|||
export interface LogRateAnalysisContentWrapperProps {
|
||||
/** The data view to analyze. */
|
||||
dataView: DataView;
|
||||
/** Option to make main histogram sticky */
|
||||
stickyHistogram?: boolean;
|
||||
/** App dependencies */
|
||||
appDependencies: AiopsAppDependencies;
|
||||
/** Timestamp for start of initial analysis */
|
||||
|
@ -67,7 +66,6 @@ export const LogRateAnalysisContentWrapper: FC<LogRateAnalysisContentWrapperProp
|
|||
initialAnalysisStart,
|
||||
timeRange,
|
||||
esSearchQuery,
|
||||
stickyHistogram,
|
||||
barColorOverride,
|
||||
barHighlightColorOverride,
|
||||
onAnalysisCompleted,
|
||||
|
@ -92,13 +90,12 @@ export const LogRateAnalysisContentWrapper: FC<LogRateAnalysisContentWrapperProp
|
|||
<AiopsAppContext.Provider value={appDependencies}>
|
||||
<UrlStateProvider>
|
||||
<DataSourceContext.Provider value={{ dataView, savedSearch: null }}>
|
||||
<LogRateAnalysisStateProvider initialAnalysisStart={initialAnalysisStart}>
|
||||
<LogRateAnalysisReduxProvider initialAnalysisStart={initialAnalysisStart}>
|
||||
<StorageContextProvider storage={localStorage} storageKeys={AIOPS_STORAGE_KEYS}>
|
||||
<DatePickerContextProvider {...datePickerDeps}>
|
||||
<LogRateAnalysisContent
|
||||
timeRange={timeRange}
|
||||
esSearchQuery={esSearchQuery}
|
||||
stickyHistogram={stickyHistogram}
|
||||
barColorOverride={barColorOverride}
|
||||
barHighlightColorOverride={barHighlightColorOverride}
|
||||
onAnalysisCompleted={onAnalysisCompleted}
|
||||
|
@ -106,7 +103,7 @@ export const LogRateAnalysisContentWrapper: FC<LogRateAnalysisContentWrapperProp
|
|||
/>
|
||||
</DatePickerContextProvider>
|
||||
</StorageContextProvider>
|
||||
</LogRateAnalysisStateProvider>
|
||||
</LogRateAnalysisReduxProvider>
|
||||
</DataSourceContext.Provider>
|
||||
</UrlStateProvider>
|
||||
</AiopsAppContext.Provider>
|
||||
|
|
|
@ -18,7 +18,13 @@ import { useUrlState, usePageUrlState } from '@kbn/ml-url-state';
|
|||
import type { SearchQueryLanguage } from '@kbn/ml-query-utils';
|
||||
import type { WindowParameters } from '@kbn/aiops-log-rate-analysis';
|
||||
import { AIOPS_TELEMETRY_ID } from '@kbn/aiops-common/constants';
|
||||
import { useLogRateAnalysisStateContext } from '@kbn/aiops-components';
|
||||
import {
|
||||
useAppDispatch,
|
||||
useCurrentSelectedSignificantItem,
|
||||
useCurrentSelectedGroup,
|
||||
setInitialAnalysisStart,
|
||||
setDocumentCountChartData,
|
||||
} from '@kbn/aiops-log-rate-analysis/state';
|
||||
|
||||
import { useDataSource } from '../../hooks/use_data_source';
|
||||
import { useAiopsAppContext } from '../../hooks/use_aiops_app_context';
|
||||
|
@ -35,16 +41,14 @@ import { SearchPanel } from '../search_panel';
|
|||
import { PageHeader } from '../page_header';
|
||||
|
||||
import { LogRateAnalysisContent } from './log_rate_analysis_content/log_rate_analysis_content';
|
||||
interface Props {
|
||||
stickyHistogram?: boolean;
|
||||
}
|
||||
|
||||
export const LogRateAnalysisPage: FC<Props> = ({ stickyHistogram }) => {
|
||||
export const LogRateAnalysisPage: FC = () => {
|
||||
const { data: dataService } = useAiopsAppContext();
|
||||
const { dataView, savedSearch } = useDataSource();
|
||||
|
||||
const { currentSelectedSignificantItem, currentSelectedGroup, setInitialAnalysisStart } =
|
||||
useLogRateAnalysisStateContext();
|
||||
const currentSelectedGroup = useCurrentSelectedGroup();
|
||||
const currentSelectedSignificantItem = useCurrentSelectedSignificantItem();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [stateFromUrl, setUrlState] = usePageUrlState<LogRateAnalysisPageUrlState>(
|
||||
'logRateAnalysis',
|
||||
|
@ -89,7 +93,7 @@ export const LogRateAnalysisPage: FC<Props> = ({ stickyHistogram }) => {
|
|||
stateFromUrl
|
||||
);
|
||||
|
||||
const { timefilter } = useData(
|
||||
const { documentStats, timefilter, earliest, latest, intervalMs } = useData(
|
||||
dataView,
|
||||
'log_rate_analysis',
|
||||
searchQuery,
|
||||
|
@ -98,6 +102,23 @@ export const LogRateAnalysisPage: FC<Props> = ({ stickyHistogram }) => {
|
|||
currentSelectedGroup
|
||||
);
|
||||
|
||||
// TODO Since `useData` isn't just used within Log Rate Analysis, this is a bit of
|
||||
// a workaround to pass the result on to the redux store. At least this ensures
|
||||
// we now use `useData` only once across Log Rate Analysis! Originally `useData`
|
||||
// was quite general, but over time it got quite some specific features used
|
||||
// across Log Rate Analysis and Pattern Analysis. We discussed that we should
|
||||
// split this up into more specific hooks.
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
setDocumentCountChartData({
|
||||
earliest,
|
||||
latest,
|
||||
intervalMs,
|
||||
documentStats,
|
||||
})
|
||||
);
|
||||
}, [documentStats, dispatch, earliest, intervalMs, latest]);
|
||||
|
||||
useEffect(
|
||||
// TODO: Consolidate this hook/function with the one in `x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/index_data_visualizer_view/index_data_visualizer_view.tsx`
|
||||
function clearFiltersOnLeave() {
|
||||
|
@ -144,7 +165,7 @@ export const LogRateAnalysisPage: FC<Props> = ({ stickyHistogram }) => {
|
|||
|
||||
useEffect(
|
||||
() => {
|
||||
setInitialAnalysisStart(appStateToWindowParameters(stateFromUrl.wp));
|
||||
dispatch(setInitialAnalysisStart(appStateToWindowParameters(stateFromUrl.wp)));
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[]
|
||||
|
@ -179,7 +200,6 @@ export const LogRateAnalysisPage: FC<Props> = ({ stickyHistogram }) => {
|
|||
embeddingOrigin={AIOPS_TELEMETRY_ID.AIOPS_DEFAULT_SOURCE}
|
||||
esSearchQuery={searchQuery}
|
||||
onWindowParametersChange={onWindowParametersHandler}
|
||||
stickyHistogram={stickyHistogram}
|
||||
/>
|
||||
</EuiFlexGroup>
|
||||
</EuiPageSection>
|
||||
|
|
|
@ -24,7 +24,12 @@ import {
|
|||
|
||||
import { reportPerformanceMetricEvent } from '@kbn/ebt-tools';
|
||||
import { ProgressControls } from '@kbn/aiops-components';
|
||||
import { useFetchStream } from '@kbn/ml-response-stream/client';
|
||||
import { cancelStream, startStream } from '@kbn/ml-response-stream/client';
|
||||
import {
|
||||
clearAllRowState,
|
||||
useAppDispatch,
|
||||
useAppSelector,
|
||||
} from '@kbn/aiops-log-rate-analysis/state';
|
||||
import {
|
||||
LOG_RATE_ANALYSIS_TYPE,
|
||||
type LogRateAnalysisType,
|
||||
|
@ -34,10 +39,8 @@ import { i18n } from '@kbn/i18n';
|
|||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import type { SignificantItem, SignificantItemGroup } from '@kbn/ml-agg-utils';
|
||||
import { AIOPS_TELEMETRY_ID } from '@kbn/aiops-common/constants';
|
||||
import { initialState, streamReducer } from '@kbn/aiops-log-rate-analysis/api/stream_reducer';
|
||||
import type { AiopsLogRateAnalysisSchema } from '@kbn/aiops-log-rate-analysis/api/schema';
|
||||
import type { AiopsLogRateAnalysisSchemaSignificantItem } from '@kbn/aiops-log-rate-analysis/api/schema_v2';
|
||||
import { useLogRateAnalysisStateContext } from '@kbn/aiops-components';
|
||||
|
||||
import { useAiopsAppContext } from '../../hooks/use_aiops_app_context';
|
||||
import { useDataSource } from '../../hooks/use_data_source';
|
||||
|
@ -131,56 +134,45 @@ export interface LogRateAnalysisResultsData {
|
|||
* LogRateAnalysis props require a data view.
|
||||
*/
|
||||
interface LogRateAnalysisResultsProps {
|
||||
/** The type of analysis, whether it's a spike or dip */
|
||||
analysisType?: LogRateAnalysisType;
|
||||
/** Start timestamp filter */
|
||||
earliest: number;
|
||||
/** End timestamp filter */
|
||||
latest: number;
|
||||
isBrushCleared: boolean;
|
||||
/** Option to make main histogram sticky */
|
||||
stickyHistogram?: boolean;
|
||||
/** Callback for resetting the analysis */
|
||||
onReset: () => void;
|
||||
/** Window parameters for the analysis */
|
||||
windowParameters: WindowParameters;
|
||||
/** The search query to be applied to the analysis as a filter */
|
||||
searchQuery: estypes.QueryDslQueryContainer;
|
||||
/** Sample probability to be applied to random sampler aggregations */
|
||||
sampleProbability: number;
|
||||
/** Optional color override for the default bar color for charts */
|
||||
barColorOverride?: string;
|
||||
/** Optional color override for the highlighted bar color for charts */
|
||||
barHighlightColorOverride?: string;
|
||||
/** Optional callback that exposes data of the completed analysis */
|
||||
onAnalysisCompleted?: (d: LogRateAnalysisResultsData) => void;
|
||||
/** Identifier to indicate the plugin utilizing the component */
|
||||
embeddingOrigin: string;
|
||||
}
|
||||
|
||||
export const LogRateAnalysisResults: FC<LogRateAnalysisResultsProps> = ({
|
||||
analysisType = LOG_RATE_ANALYSIS_TYPE.SPIKE,
|
||||
earliest,
|
||||
isBrushCleared,
|
||||
latest,
|
||||
stickyHistogram,
|
||||
onReset,
|
||||
windowParameters,
|
||||
searchQuery,
|
||||
sampleProbability,
|
||||
barColorOverride,
|
||||
barHighlightColorOverride,
|
||||
onAnalysisCompleted,
|
||||
embeddingOrigin,
|
||||
}) => {
|
||||
const { analytics, http } = useAiopsAppContext();
|
||||
const { dataView } = useDataSource();
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const {
|
||||
analysisType,
|
||||
earliest,
|
||||
latest,
|
||||
windowParameters,
|
||||
documentStats: { sampleProbability },
|
||||
stickyHistogram,
|
||||
isBrushCleared,
|
||||
} = useAppSelector((s) => s.logRateAnalysis);
|
||||
const { isRunning, errors: streamErrors } = useAppSelector((s) => s.logRateAnalysisStream);
|
||||
const data = useAppSelector((s) => s.logRateAnalysisResults);
|
||||
|
||||
// Store the performance metric's start time using a ref
|
||||
// to be able to track it across rerenders.
|
||||
const analysisStartTime = useRef<number | undefined>(window.performance.now());
|
||||
|
||||
const { clearAllRowState } = useLogRateAnalysisStateContext();
|
||||
const abortCtrl = useRef(new AbortController());
|
||||
|
||||
const [currentAnalysisType, setCurrentAnalysisType] = useState<LogRateAnalysisType | undefined>();
|
||||
const [currentAnalysisWindowParameters, setCurrentAnalysisWindowParameters] = useState<
|
||||
|
@ -201,7 +193,7 @@ export const LogRateAnalysisResults: FC<LogRateAnalysisResultsProps> = ({
|
|||
setGroupResults(optionId === resultsGroupedOnId);
|
||||
|
||||
// When toggling the group switch, clear all row selections
|
||||
clearAllRowState();
|
||||
dispatch(clearAllRowState());
|
||||
};
|
||||
|
||||
const onFieldsFilterChange = (skippedFields: string[]) => {
|
||||
|
@ -221,49 +213,18 @@ export const LogRateAnalysisResults: FC<LogRateAnalysisResultsProps> = ({
|
|||
setSkippedColumns(columns);
|
||||
};
|
||||
|
||||
const {
|
||||
cancel,
|
||||
start,
|
||||
data,
|
||||
isRunning,
|
||||
errors: streamErrors,
|
||||
} = useFetchStream<AiopsLogRateAnalysisSchema<'2'>, typeof streamReducer>(
|
||||
http,
|
||||
'/internal/aiops/log_rate_analysis',
|
||||
'2',
|
||||
{
|
||||
start: earliest,
|
||||
end: latest,
|
||||
searchQuery: JSON.stringify(searchQuery),
|
||||
// TODO Handle data view without time fields.
|
||||
timeFieldName: dataView.timeFieldName ?? '',
|
||||
index: dataView.getIndexPattern(),
|
||||
grouping: true,
|
||||
flushFix: true,
|
||||
// If analysis type is `spike`, pass on window parameters as is,
|
||||
// if it's `dip`, swap baseline and deviation.
|
||||
...(analysisType === LOG_RATE_ANALYSIS_TYPE.SPIKE
|
||||
? windowParameters
|
||||
: {
|
||||
baselineMin: windowParameters.deviationMin,
|
||||
baselineMax: windowParameters.deviationMax,
|
||||
deviationMin: windowParameters.baselineMin,
|
||||
deviationMax: windowParameters.baselineMax,
|
||||
}),
|
||||
overrides,
|
||||
sampleProbability,
|
||||
},
|
||||
{ reducer: streamReducer, initialState },
|
||||
{ [AIOPS_TELEMETRY_ID.AIOPS_ANALYSIS_RUN_ORIGIN]: embeddingOrigin }
|
||||
);
|
||||
|
||||
const { significantItems, zeroDocsFallback } = data;
|
||||
const { significantItems } = data;
|
||||
|
||||
useEffect(
|
||||
() => setUniqueFieldNames(uniq(significantItems.map((d) => d.fieldName)).sort()),
|
||||
[significantItems]
|
||||
);
|
||||
|
||||
function cancelHandler() {
|
||||
abortCtrl.current.abort();
|
||||
dispatch(cancelStream());
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!isRunning) {
|
||||
const { loaded, remainingFieldCandidates, groupsMissing } = data;
|
||||
|
@ -282,15 +243,6 @@ export const LogRateAnalysisResults: FC<LogRateAnalysisResultsProps> = ({
|
|||
// Reset all overrides.
|
||||
setOverrides(undefined);
|
||||
|
||||
// If provided call the `onAnalysisCompleted` callback with the analysis results.
|
||||
if (onAnalysisCompleted) {
|
||||
onAnalysisCompleted({
|
||||
analysisType,
|
||||
significantItems: data.significantItems,
|
||||
significantItemsGroups: data.significantItemsGroups,
|
||||
});
|
||||
}
|
||||
|
||||
// Track performance metric
|
||||
if (analysisStartTime.current !== undefined) {
|
||||
const analysisDuration = window.performance.now() - analysisStartTime.current;
|
||||
|
@ -322,7 +274,7 @@ export const LogRateAnalysisResults: FC<LogRateAnalysisResultsProps> = ({
|
|||
if (resetGroupButton) {
|
||||
setGroupResults(false);
|
||||
setToggleIdSelected(resultsGroupedOffId);
|
||||
clearAllRowState();
|
||||
dispatch(clearAllRowState());
|
||||
}
|
||||
|
||||
setCurrentAnalysisType(analysisType);
|
||||
|
@ -333,18 +285,67 @@ export const LogRateAnalysisResults: FC<LogRateAnalysisResultsProps> = ({
|
|||
setShouldStart(true);
|
||||
}
|
||||
|
||||
const startParams = useMemo(() => {
|
||||
if (!windowParameters) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
http,
|
||||
endpoint: '/internal/aiops/log_rate_analysis',
|
||||
apiVersion: '2',
|
||||
abortCtrl,
|
||||
body: {
|
||||
start: earliest,
|
||||
end: latest,
|
||||
searchQuery: JSON.stringify(searchQuery),
|
||||
// TODO Handle data view without time fields.
|
||||
timeFieldName: dataView.timeFieldName ?? '',
|
||||
index: dataView.getIndexPattern(),
|
||||
grouping: true,
|
||||
flushFix: true,
|
||||
// If analysis type is `spike`, pass on window parameters as is,
|
||||
// if it's `dip`, swap baseline and deviation.
|
||||
...(analysisType === LOG_RATE_ANALYSIS_TYPE.SPIKE
|
||||
? windowParameters
|
||||
: {
|
||||
baselineMin: windowParameters.deviationMin,
|
||||
baselineMax: windowParameters.deviationMax,
|
||||
deviationMin: windowParameters.baselineMin,
|
||||
deviationMax: windowParameters.baselineMax,
|
||||
}),
|
||||
overrides,
|
||||
sampleProbability,
|
||||
},
|
||||
headers: { [AIOPS_TELEMETRY_ID.AIOPS_ANALYSIS_RUN_ORIGIN]: embeddingOrigin },
|
||||
};
|
||||
}, [
|
||||
analysisType,
|
||||
earliest,
|
||||
latest,
|
||||
http,
|
||||
searchQuery,
|
||||
dataView,
|
||||
windowParameters,
|
||||
sampleProbability,
|
||||
overrides,
|
||||
embeddingOrigin,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldStart) {
|
||||
start();
|
||||
if (shouldStart && startParams) {
|
||||
dispatch(startStream(startParams));
|
||||
setShouldStart(false);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [shouldStart]);
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentAnalysisType(analysisType);
|
||||
setCurrentAnalysisWindowParameters(windowParameters);
|
||||
start();
|
||||
if (startParams) {
|
||||
setCurrentAnalysisType(analysisType);
|
||||
setCurrentAnalysisWindowParameters(windowParameters);
|
||||
dispatch(startStream(startParams));
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
|
@ -365,7 +366,6 @@ export const LogRateAnalysisResults: FC<LogRateAnalysisResultsProps> = ({
|
|||
return p + c.groupItemsSortedByUniqueness.length;
|
||||
}, 0);
|
||||
const foundGroups = groupTableItems.length > 0 && groupItemCount > 0;
|
||||
const timeRangeMs = { from: earliest, to: latest };
|
||||
|
||||
// Disable the grouping switch toggle only if no groups were found,
|
||||
// the toggle wasn't enabled already and no fields were selected to be skipped.
|
||||
|
@ -392,7 +392,7 @@ export const LogRateAnalysisResults: FC<LogRateAnalysisResultsProps> = ({
|
|||
progressMessage={data.loadingState ?? ''}
|
||||
isRunning={isRunning}
|
||||
onRefresh={() => startHandler(false)}
|
||||
onCancel={cancel}
|
||||
onCancel={cancelHandler}
|
||||
onReset={onReset}
|
||||
shouldRerunAnalysis={shouldRerunAnalysis}
|
||||
>
|
||||
|
@ -454,10 +454,7 @@ export const LogRateAnalysisResults: FC<LogRateAnalysisResultsProps> = ({
|
|||
{showLogRateAnalysisResultsTable && currentAnalysisType !== undefined && (
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<LogRateAnalysisTypeCallOut
|
||||
analysisType={currentAnalysisType}
|
||||
zeroDocsFallback={zeroDocsFallback}
|
||||
/>
|
||||
<LogRateAnalysisTypeCallOut analysisType={currentAnalysisType} />
|
||||
<EuiSpacer size="xs" />
|
||||
</>
|
||||
)}
|
||||
|
@ -550,24 +547,17 @@ export const LogRateAnalysisResults: FC<LogRateAnalysisResultsProps> = ({
|
|||
skippedColumns={skippedColumns}
|
||||
significantItems={data.significantItems}
|
||||
groupTableItems={groupTableItems}
|
||||
loading={isRunning}
|
||||
timeRangeMs={timeRangeMs}
|
||||
searchQuery={searchQuery}
|
||||
barColorOverride={barColorOverride}
|
||||
barHighlightColorOverride={barHighlightColorOverride}
|
||||
zeroDocsFallback={zeroDocsFallback}
|
||||
/>
|
||||
) : null}
|
||||
{showLogRateAnalysisResultsTable && !groupResults ? (
|
||||
<LogRateAnalysisResultsTable
|
||||
skippedColumns={skippedColumns}
|
||||
significantItems={data.significantItems}
|
||||
loading={isRunning}
|
||||
timeRangeMs={timeRangeMs}
|
||||
searchQuery={searchQuery}
|
||||
barColorOverride={barColorOverride}
|
||||
barHighlightColorOverride={barHighlightColorOverride}
|
||||
zeroDocsFallback={zeroDocsFallback}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
|
|
@ -10,17 +10,18 @@ import React, { type FC } from 'react';
|
|||
import { EuiCallOut, EuiText } from '@elastic/eui';
|
||||
|
||||
import { LOG_RATE_ANALYSIS_TYPE, type LogRateAnalysisType } from '@kbn/aiops-log-rate-analysis';
|
||||
import { useAppSelector } from '@kbn/aiops-log-rate-analysis/state';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
interface LogRateAnalysisTypeCallOutProps {
|
||||
analysisType: LogRateAnalysisType;
|
||||
zeroDocsFallback: boolean;
|
||||
}
|
||||
|
||||
export const LogRateAnalysisTypeCallOut: FC<LogRateAnalysisTypeCallOutProps> = ({
|
||||
analysisType,
|
||||
zeroDocsFallback,
|
||||
}) => {
|
||||
const zeroDocsFallback = useAppSelector((s) => s.logRateAnalysisResults.zeroDocsFallback);
|
||||
|
||||
let callOutTitle: string;
|
||||
let callOutText: string;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { sortBy } from 'lodash';
|
||||
|
||||
import type { SignificantItemGroup } from '@kbn/ml-agg-utils';
|
||||
import type { GroupTableItem, GroupTableItemGroup } from '@kbn/aiops-components';
|
||||
import type { GroupTableItem, GroupTableItemGroup } from '@kbn/aiops-log-rate-analysis/state';
|
||||
|
||||
export function getGroupTableItems(
|
||||
significantItemsGroups: SignificantItemGroup[]
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { escapeKuery, escapeQuotes } from '@kbn/es-query';
|
||||
import { isSignificantItem, type SignificantItem } from '@kbn/ml-agg-utils';
|
||||
import type { GroupTableItem } from '@kbn/aiops-components';
|
||||
import type { GroupTableItem } from '@kbn/aiops-log-rate-analysis/state';
|
||||
|
||||
export const getTableItemAsKQL = (tableItem: GroupTableItem | SignificantItem) => {
|
||||
if (isSignificantItem(tableItem)) {
|
||||
|
|
|
@ -12,12 +12,18 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
|||
|
||||
import type { EuiTableSortingType } from '@elastic/eui';
|
||||
import { useEuiBackgroundColor, EuiBasicTable } from '@elastic/eui';
|
||||
import { type SignificantItem } from '@kbn/ml-agg-utils';
|
||||
import type { TimeRange as TimeRangeMs } from '@kbn/ml-date-picker';
|
||||
|
||||
import { useLogRateAnalysisStateContext } from '@kbn/aiops-components';
|
||||
import type { SignificantItem } from '@kbn/ml-agg-utils';
|
||||
import {
|
||||
setPinnedSignificantItem,
|
||||
setSelectedSignificantItem,
|
||||
useAppDispatch,
|
||||
useAppSelector,
|
||||
} from '@kbn/aiops-log-rate-analysis/state';
|
||||
|
||||
import type { GroupTableItemGroup } from '@kbn/aiops-log-rate-analysis/state';
|
||||
import { useEuiTheme } from '../../hooks/use_eui_theme';
|
||||
import { useColumns, SIG_ITEMS_TABLE } from './use_columns';
|
||||
import { useColumns, LOG_RATE_ANALYSIS_RESULTS_TABLE_TYPE } from './use_columns';
|
||||
|
||||
const PAGINATION_SIZE_OPTIONS = [5, 10, 20, 50];
|
||||
const DEFAULT_SORT_FIELD = 'pValue';
|
||||
|
@ -26,41 +32,59 @@ const DEFAULT_SORT_DIRECTION = 'asc';
|
|||
const DEFAULT_SORT_DIRECTION_ZERO_DOCS_FALLBACK = 'desc';
|
||||
|
||||
interface LogRateAnalysisResultsTableProps {
|
||||
significantItems: SignificantItem[];
|
||||
loading: boolean;
|
||||
isExpandedRow?: boolean;
|
||||
groupFilter?: GroupTableItemGroup[];
|
||||
searchQuery: estypes.QueryDslQueryContainer;
|
||||
timeRangeMs: TimeRangeMs;
|
||||
/** Optional color override for the default bar color for charts */
|
||||
barColorOverride?: string;
|
||||
/** Optional color override for the highlighted bar color for charts */
|
||||
barHighlightColorOverride?: string;
|
||||
skippedColumns: string[];
|
||||
zeroDocsFallback?: boolean;
|
||||
}
|
||||
|
||||
export const LogRateAnalysisResultsTable: FC<LogRateAnalysisResultsTableProps> = ({
|
||||
significantItems,
|
||||
loading,
|
||||
isExpandedRow,
|
||||
groupFilter,
|
||||
searchQuery,
|
||||
timeRangeMs,
|
||||
barColorOverride,
|
||||
barHighlightColorOverride,
|
||||
skippedColumns,
|
||||
zeroDocsFallback = false,
|
||||
}) => {
|
||||
const euiTheme = useEuiTheme();
|
||||
const primaryBackgroundColor = useEuiBackgroundColor('primary');
|
||||
|
||||
const {
|
||||
pinnedGroup,
|
||||
pinnedSignificantItem,
|
||||
selectedGroup,
|
||||
selectedSignificantItem,
|
||||
setPinnedSignificantItem,
|
||||
setSelectedSignificantItem,
|
||||
} = useLogRateAnalysisStateContext();
|
||||
const allSignificantItems = useAppSelector((s) => s.logRateAnalysisResults.significantItems);
|
||||
|
||||
const significantItems = useMemo(() => {
|
||||
if (!groupFilter) {
|
||||
return allSignificantItems;
|
||||
}
|
||||
|
||||
return groupFilter.reduce<SignificantItem[]>((p, groupItem) => {
|
||||
const st = allSignificantItems.find(
|
||||
(d) => d.fieldName === groupItem.fieldName && d.fieldValue === groupItem.fieldValue
|
||||
);
|
||||
|
||||
if (st !== undefined) {
|
||||
p.push({
|
||||
...st,
|
||||
unique: (groupItem.duplicate ?? 0) <= 1,
|
||||
});
|
||||
}
|
||||
|
||||
return p;
|
||||
}, []);
|
||||
}, [allSignificantItems, groupFilter]);
|
||||
|
||||
const zeroDocsFallback = useAppSelector((s) => s.logRateAnalysisResults.zeroDocsFallback);
|
||||
const pinnedGroup = useAppSelector((s) => s.logRateAnalysisTableRow.pinnedGroup);
|
||||
const selectedGroup = useAppSelector((s) => s.logRateAnalysisTableRow.selectedGroup);
|
||||
const pinnedSignificantItem = useAppSelector(
|
||||
(s) => s.logRateAnalysisTableRow.pinnedSignificantItem
|
||||
);
|
||||
const selectedSignificantItem = useAppSelector(
|
||||
(s) => s.logRateAnalysisTableRow.selectedSignificantItem
|
||||
);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
|
@ -72,15 +96,12 @@ export const LogRateAnalysisResultsTable: FC<LogRateAnalysisResultsTableProps> =
|
|||
);
|
||||
|
||||
const columns = useColumns(
|
||||
SIG_ITEMS_TABLE,
|
||||
LOG_RATE_ANALYSIS_RESULTS_TABLE_TYPE.SIGNIFICANT_ITEMS,
|
||||
skippedColumns,
|
||||
searchQuery,
|
||||
timeRangeMs,
|
||||
loading,
|
||||
zeroDocsFallback,
|
||||
barColorOverride,
|
||||
barHighlightColorOverride,
|
||||
isExpandedRow
|
||||
groupFilter !== undefined
|
||||
);
|
||||
|
||||
const onChange = useCallback((tableSettings) => {
|
||||
|
@ -151,7 +172,7 @@ export const LogRateAnalysisResultsTable: FC<LogRateAnalysisResultsTableProps> =
|
|||
selectedGroup === null &&
|
||||
pinnedGroup === null
|
||||
) {
|
||||
setSelectedSignificantItem(pageOfItems[0]);
|
||||
dispatch(setSelectedSignificantItem(pageOfItems[0]));
|
||||
}
|
||||
|
||||
// If a user switched pages and a pinned row is no longer visible
|
||||
|
@ -162,13 +183,12 @@ export const LogRateAnalysisResultsTable: FC<LogRateAnalysisResultsTableProps> =
|
|||
selectedGroup === null &&
|
||||
pinnedGroup === null
|
||||
) {
|
||||
setPinnedSignificantItem(null);
|
||||
dispatch(setPinnedSignificantItem(null));
|
||||
}
|
||||
}, [
|
||||
dispatch,
|
||||
selectedGroup,
|
||||
selectedSignificantItem,
|
||||
setSelectedSignificantItem,
|
||||
setPinnedSignificantItem,
|
||||
pageOfItems,
|
||||
pinnedGroup,
|
||||
pinnedSignificantItem,
|
||||
|
@ -178,8 +198,8 @@ export const LogRateAnalysisResultsTable: FC<LogRateAnalysisResultsTableProps> =
|
|||
// make sure to reset any hovered or pinned rows.
|
||||
useEffect(
|
||||
() => () => {
|
||||
setSelectedSignificantItem(null);
|
||||
setPinnedSignificantItem(null);
|
||||
dispatch(setSelectedSignificantItem(null));
|
||||
dispatch(setPinnedSignificantItem(null));
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[]
|
||||
|
@ -236,18 +256,18 @@ export const LogRateAnalysisResultsTable: FC<LogRateAnalysisResultsTableProps> =
|
|||
significantItem.fieldName === pinnedSignificantItem?.fieldName &&
|
||||
significantItem.fieldValue === pinnedSignificantItem?.fieldValue
|
||||
) {
|
||||
setPinnedSignificantItem(null);
|
||||
dispatch(setPinnedSignificantItem(null));
|
||||
} else {
|
||||
setPinnedSignificantItem(significantItem);
|
||||
dispatch(setPinnedSignificantItem(significantItem));
|
||||
}
|
||||
},
|
||||
onMouseEnter: () => {
|
||||
if (pinnedSignificantItem === null) {
|
||||
setSelectedSignificantItem(significantItem);
|
||||
dispatch(setSelectedSignificantItem(significantItem));
|
||||
}
|
||||
},
|
||||
onMouseLeave: () => {
|
||||
setSelectedSignificantItem(null);
|
||||
dispatch(setSelectedSignificantItem(null));
|
||||
},
|
||||
style: getRowStyle(significantItem),
|
||||
};
|
||||
|
|
|
@ -27,16 +27,21 @@ import {
|
|||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import type { SignificantItem } from '@kbn/ml-agg-utils';
|
||||
import type { TimeRange as TimeRangeMs } from '@kbn/ml-date-picker';
|
||||
import { type SignificantItem } from '@kbn/ml-agg-utils';
|
||||
import {
|
||||
setPinnedGroup,
|
||||
setSelectedGroup,
|
||||
useAppDispatch,
|
||||
useAppSelector,
|
||||
type GroupTableItem,
|
||||
} from '@kbn/aiops-log-rate-analysis/state';
|
||||
import { stringHash } from '@kbn/ml-string-hash';
|
||||
import { useLogRateAnalysisStateContext, type GroupTableItem } from '@kbn/aiops-components';
|
||||
|
||||
import usePrevious from 'react-use/lib/usePrevious';
|
||||
import useMountedState from 'react-use/lib/useMountedState';
|
||||
|
||||
import { LogRateAnalysisResultsTable } from './log_rate_analysis_results_table';
|
||||
import { GROUPS_TABLE, useColumns } from './use_columns';
|
||||
import { LOG_RATE_ANALYSIS_RESULTS_TABLE_TYPE, useColumns } from './use_columns';
|
||||
|
||||
const EXPAND_COLUMN_WIDTH = '40px';
|
||||
const MAX_GROUP_BADGES = 5;
|
||||
|
@ -51,29 +56,25 @@ interface LogRateAnalysisResultsTableProps {
|
|||
skippedColumns: string[];
|
||||
significantItems: SignificantItem[];
|
||||
groupTableItems: GroupTableItem[];
|
||||
loading: boolean;
|
||||
searchQuery: estypes.QueryDslQueryContainer;
|
||||
timeRangeMs: TimeRangeMs;
|
||||
/** Optional color override for the default bar color for charts */
|
||||
barColorOverride?: string;
|
||||
/** Optional color override for the highlighted bar color for charts */
|
||||
barHighlightColorOverride?: string;
|
||||
zeroDocsFallback?: boolean;
|
||||
}
|
||||
|
||||
export const LogRateAnalysisResultsGroupsTable: FC<LogRateAnalysisResultsTableProps> = ({
|
||||
skippedColumns,
|
||||
significantItems,
|
||||
groupTableItems,
|
||||
loading,
|
||||
timeRangeMs,
|
||||
searchQuery,
|
||||
barColorOverride,
|
||||
barHighlightColorOverride,
|
||||
zeroDocsFallback = false,
|
||||
}) => {
|
||||
const prevSkippedColumns = usePrevious(skippedColumns);
|
||||
|
||||
const zeroDocsFallback = useAppSelector((s) => s.logRateAnalysisResults.zeroDocsFallback);
|
||||
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
const [sortField, setSortField] = useState<'docCount' | 'pValue'>(
|
||||
|
@ -90,8 +91,9 @@ export const LogRateAnalysisResultsGroupsTable: FC<LogRateAnalysisResultsTablePr
|
|||
const visColors = euiPaletteColorBlind();
|
||||
const primaryBackgroundColor = useEuiBackgroundColor('primary');
|
||||
|
||||
const { pinnedGroup, selectedGroup, setPinnedGroup, setSelectedGroup } =
|
||||
useLogRateAnalysisStateContext();
|
||||
const pinnedGroup = useAppSelector((s) => s.logRateAnalysisTableRow.pinnedGroup);
|
||||
const selectedGroup = useAppSelector((s) => s.logRateAnalysisTableRow.selectedGroup);
|
||||
const dispatch = useAppDispatch();
|
||||
const isMounted = useMountedState();
|
||||
|
||||
const toggleDetails = (item: GroupTableItem) => {
|
||||
|
@ -102,26 +104,7 @@ export const LogRateAnalysisResultsGroupsTable: FC<LogRateAnalysisResultsTablePr
|
|||
itemIdToExpandedRowMapValues[item.id] = (
|
||||
<LogRateAnalysisResultsTable
|
||||
skippedColumns={skippedColumns}
|
||||
significantItems={item.groupItemsSortedByUniqueness.reduce<SignificantItem[]>(
|
||||
(p, groupItem) => {
|
||||
const st = significantItems.find(
|
||||
(d) => d.fieldName === groupItem.fieldName && d.fieldValue === groupItem.fieldValue
|
||||
);
|
||||
|
||||
if (st !== undefined) {
|
||||
p.push({
|
||||
...st,
|
||||
unique: (groupItem.duplicate ?? 0) <= 1,
|
||||
});
|
||||
}
|
||||
|
||||
return p;
|
||||
},
|
||||
[]
|
||||
)}
|
||||
loading={loading}
|
||||
isExpandedRow
|
||||
timeRangeMs={timeRangeMs}
|
||||
groupFilter={item.groupItemsSortedByUniqueness}
|
||||
searchQuery={searchQuery}
|
||||
barColorOverride={barColorOverride}
|
||||
barHighlightColorOverride={barHighlightColorOverride}
|
||||
|
@ -254,12 +237,9 @@ export const LogRateAnalysisResultsGroupsTable: FC<LogRateAnalysisResultsTablePr
|
|||
];
|
||||
|
||||
const columns = useColumns(
|
||||
GROUPS_TABLE,
|
||||
LOG_RATE_ANALYSIS_RESULTS_TABLE_TYPE.GROUPS,
|
||||
skippedColumns,
|
||||
searchQuery,
|
||||
timeRangeMs,
|
||||
loading,
|
||||
zeroDocsFallback,
|
||||
barColorOverride,
|
||||
barHighlightColorOverride
|
||||
) as Array<EuiBasicTableColumn<GroupTableItem>>;
|
||||
|
@ -331,22 +311,22 @@ export const LogRateAnalysisResultsGroupsTable: FC<LogRateAnalysisResultsTablePr
|
|||
pinnedGroup === null &&
|
||||
pageOfItems.length > 0
|
||||
) {
|
||||
setSelectedGroup(pageOfItems[0]);
|
||||
dispatch(setSelectedGroup(pageOfItems[0]));
|
||||
}
|
||||
|
||||
// If a user switched pages and a pinned row is no longer visible
|
||||
// on the current page, set the status of pinned rows back to `null`.
|
||||
if (pinnedGroup !== null && !pageOfItems.some((item) => isEqual(item, pinnedGroup))) {
|
||||
setPinnedGroup(null);
|
||||
dispatch(setPinnedGroup(null));
|
||||
}
|
||||
}, [selectedGroup, setSelectedGroup, setPinnedGroup, pageOfItems, pinnedGroup]);
|
||||
}, [dispatch, selectedGroup, pageOfItems, pinnedGroup]);
|
||||
|
||||
// When the analysis results table unmounts,
|
||||
// make sure to reset any hovered or pinned rows.
|
||||
useEffect(
|
||||
() => () => {
|
||||
setSelectedGroup(null);
|
||||
setPinnedGroup(null);
|
||||
dispatch(setSelectedGroup(null));
|
||||
dispatch(setPinnedGroup(null));
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[]
|
||||
|
@ -413,18 +393,18 @@ export const LogRateAnalysisResultsGroupsTable: FC<LogRateAnalysisResultsTablePr
|
|||
'data-test-subj': `aiopsLogRateAnalysisResultsGroupsTableRow row-${group.id}`,
|
||||
onClick: () => {
|
||||
if (group.id === pinnedGroup?.id) {
|
||||
setPinnedGroup(null);
|
||||
dispatch(setPinnedGroup(null));
|
||||
} else {
|
||||
setPinnedGroup(group);
|
||||
dispatch(setPinnedGroup(group));
|
||||
}
|
||||
},
|
||||
onMouseEnter: () => {
|
||||
if (pinnedGroup === null) {
|
||||
setSelectedGroup(group);
|
||||
dispatch(setSelectedGroup(group));
|
||||
}
|
||||
},
|
||||
onMouseLeave: () => {
|
||||
setSelectedGroup(null);
|
||||
dispatch(setSelectedGroup(null));
|
||||
},
|
||||
style: getRowStyle(group),
|
||||
};
|
||||
|
|
|
@ -12,8 +12,8 @@ import { i18n } from '@kbn/i18n';
|
|||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { type SignificantItem, SIGNIFICANT_ITEM_TYPE } from '@kbn/ml-agg-utils';
|
||||
import { getCategoryQuery } from '@kbn/aiops-log-pattern-analysis/get_category_query';
|
||||
import type { TimeRange as TimeRangeMs } from '@kbn/ml-date-picker';
|
||||
import type { FieldStatsServices } from '@kbn/unified-field-list/src/components/field_stats';
|
||||
import { useAppSelector } from '@kbn/aiops-log-rate-analysis/state';
|
||||
import { getFailedTransactionsCorrelationImpactLabel } from './get_failed_transactions_correlation_impact_label';
|
||||
import { FieldStatsPopover } from '../field_stats_popover';
|
||||
import { useAiopsAppContext } from '../../hooks/use_aiops_app_context';
|
||||
|
@ -61,9 +61,13 @@ export const significantItemColumns = {
|
|||
...commonColumns,
|
||||
} as const;
|
||||
|
||||
export const GROUPS_TABLE = 'groups';
|
||||
export const SIG_ITEMS_TABLE = 'significantItems';
|
||||
type TableType = typeof GROUPS_TABLE | typeof SIG_ITEMS_TABLE;
|
||||
export const LOG_RATE_ANALYSIS_RESULTS_TABLE_TYPE = {
|
||||
GROUPS: 'groups',
|
||||
SIGNIFICANT_ITEMS: 'significantItems',
|
||||
} as const;
|
||||
export type LogRateAnalysisResultsTableType =
|
||||
typeof LOG_RATE_ANALYSIS_RESULTS_TABLE_TYPE[keyof typeof LOG_RATE_ANALYSIS_RESULTS_TABLE_TYPE];
|
||||
|
||||
export type ColumnNames = keyof typeof significantItemColumns | 'unique';
|
||||
|
||||
const logRateHelpMessage = i18n.translate(
|
||||
|
@ -94,12 +98,9 @@ const impactMessage = i18n.translate(
|
|||
);
|
||||
|
||||
export const useColumns = (
|
||||
tableType: TableType,
|
||||
tableType: LogRateAnalysisResultsTableType,
|
||||
skippedColumns: string[],
|
||||
searchQuery: estypes.QueryDslQueryContainer,
|
||||
timeRangeMs: TimeRangeMs,
|
||||
loading: boolean,
|
||||
zeroDocsFallback: boolean,
|
||||
barColorOverride?: string,
|
||||
barHighlightColorOverride?: string,
|
||||
isExpandedRow: boolean = false
|
||||
|
@ -111,7 +112,13 @@ export const useColumns = (
|
|||
const viewInLogPatternAnalysisAction = useViewInLogPatternAnalysisAction(dataView.id);
|
||||
const copyToClipBoardAction = useCopyToClipboardAction();
|
||||
|
||||
const isGroupsTable = tableType === GROUPS_TABLE;
|
||||
const { earliest, latest } = useAppSelector((s) => s.logRateAnalysis);
|
||||
const timeRangeMs = { from: earliest ?? 0, to: latest ?? 0 };
|
||||
|
||||
const loading = useAppSelector((s) => s.logRateAnalysisStream.isRunning);
|
||||
const zeroDocsFallback = useAppSelector((s) => s.logRateAnalysisResults.zeroDocsFallback);
|
||||
|
||||
const isGroupsTable = tableType === LOG_RATE_ANALYSIS_RESULTS_TABLE_TYPE.GROUPS;
|
||||
|
||||
const fieldStatsServices: FieldStatsServices = useMemo(() => {
|
||||
return {
|
||||
|
|
|
@ -14,7 +14,7 @@ import type { SignificantItem } from '@kbn/ml-agg-utils';
|
|||
|
||||
import { finalSignificantItemGroups } from '@kbn/aiops-test-utils/artificial_logs/final_significant_item_groups';
|
||||
import { significantTerms } from '@kbn/aiops-test-utils/artificial_logs/significant_terms';
|
||||
import type { GroupTableItem } from '@kbn/aiops-components';
|
||||
import type { GroupTableItem } from '@kbn/aiops-log-rate-analysis/state';
|
||||
|
||||
import { getGroupTableItems } from './get_group_table_items';
|
||||
import { useCopyToClipboardAction } from './use_copy_to_clipboard_action';
|
||||
|
|
|
@ -11,7 +11,7 @@ import { EuiCopy, EuiToolTip } from '@elastic/eui';
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { isSignificantItem, type SignificantItem } from '@kbn/ml-agg-utils';
|
||||
import type { GroupTableItem, TableItemAction } from '@kbn/aiops-components';
|
||||
import type { GroupTableItem, TableItemAction } from '@kbn/aiops-log-rate-analysis/state';
|
||||
|
||||
import { TableActionButton } from './table_action_button';
|
||||
import { getTableItemAsKQL } from './get_table_item_as_kql';
|
||||
|
|
|
@ -10,7 +10,7 @@ import React, { useMemo } from 'react';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import type { SignificantItem } from '@kbn/ml-agg-utils';
|
||||
import { SEARCH_QUERY_LANGUAGE } from '@kbn/ml-query-utils';
|
||||
import type { GroupTableItem, TableItemAction } from '@kbn/aiops-components';
|
||||
import type { GroupTableItem, TableItemAction } from '@kbn/aiops-log-rate-analysis/state';
|
||||
|
||||
import { useAiopsAppContext } from '../../hooks/use_aiops_app_context';
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import type { SerializableRecord } from '@kbn/utility-types';
|
|||
import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { isSignificantItem, type SignificantItem, SIGNIFICANT_ITEM_TYPE } from '@kbn/ml-agg-utils';
|
||||
import type { GroupTableItem, TableItemAction } from '@kbn/aiops-components';
|
||||
import type { GroupTableItem, TableItemAction } from '@kbn/aiops-log-rate-analysis/state';
|
||||
|
||||
import { SEARCH_QUERY_LANGUAGE } from '@kbn/ml-query-utils';
|
||||
import { useAiopsAppContext } from '../../hooks/use_aiops_app_context';
|
||||
|
|
|
@ -10,28 +10,15 @@ import { get } from 'lodash';
|
|||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
|
||||
import dateMath from '@kbn/datemath';
|
||||
import {
|
||||
getExtendedChangePoint,
|
||||
type DocumentCountStatsChangePoint,
|
||||
} from '@kbn/aiops-log-rate-analysis';
|
||||
import { getExtendedChangePoint, type DocumentCountStats } from '@kbn/aiops-log-rate-analysis';
|
||||
import { isPopulatedObject } from '@kbn/ml-is-populated-object';
|
||||
import type { SignificantItem } from '@kbn/ml-agg-utils';
|
||||
import type { Query } from '@kbn/es-query';
|
||||
import type { RandomSamplerWrapper } from '@kbn/ml-random-sampler-utils';
|
||||
import type { GroupTableItem } from '@kbn/aiops-components';
|
||||
import type { GroupTableItem } from '@kbn/aiops-log-rate-analysis/state';
|
||||
|
||||
import { buildExtendedBaseFilterCriteria } from './application/utils/build_extended_base_filter_criteria';
|
||||
|
||||
export interface DocumentCountStats {
|
||||
interval?: number;
|
||||
buckets?: { [key: string]: number };
|
||||
changePoint?: DocumentCountStatsChangePoint;
|
||||
timeRangeEarliest?: number;
|
||||
timeRangeLatest?: number;
|
||||
totalCount: number;
|
||||
lastDocTimeStampMs?: number;
|
||||
}
|
||||
|
||||
export interface DocumentStatsSearchStrategyParams {
|
||||
earliest?: number;
|
||||
latest?: number;
|
||||
|
|
|
@ -18,7 +18,7 @@ import type { Dictionary } from '@kbn/ml-url-state';
|
|||
import { mlTimefilterRefresh$, useTimefilter } from '@kbn/ml-date-picker';
|
||||
import { useTimeBuckets } from '@kbn/ml-time-buckets';
|
||||
import { AIOPS_PLUGIN_ID } from '@kbn/aiops-common/constants';
|
||||
import type { GroupTableItem } from '@kbn/aiops-components';
|
||||
import type { GroupTableItem } from '@kbn/aiops-log-rate-analysis/state';
|
||||
|
||||
import type { DocumentStatsSearchStrategyParams } from '../get_document_stats';
|
||||
|
||||
|
|
|
@ -14,8 +14,9 @@ import { stringHash } from '@kbn/ml-string-hash';
|
|||
import { createRandomSamplerWrapper } from '@kbn/ml-random-sampler-utils';
|
||||
import { extractErrorProperties } from '@kbn/ml-error-utils';
|
||||
import { RANDOM_SAMPLER_SEED } from '@kbn/aiops-log-rate-analysis/constants';
|
||||
import type { DocumentCountStats } from '@kbn/aiops-log-rate-analysis/types';
|
||||
|
||||
import type { DocumentCountStats, DocumentStatsSearchStrategyParams } from '../get_document_stats';
|
||||
import type { DocumentStatsSearchStrategyParams } from '../get_document_stats';
|
||||
import { getDocumentCountStatsRequest, processDocumentCountStats } from '../get_document_stats';
|
||||
|
||||
import { useAiopsAppContext } from './use_aiops_app_context';
|
||||
|
|
|
@ -21,10 +21,10 @@ import {
|
|||
import { RANDOM_SAMPLER_SEED } from '@kbn/aiops-log-rate-analysis/constants';
|
||||
|
||||
import {
|
||||
addSignificantItemsGroupAction,
|
||||
addSignificantItemsGroupHistogramAction,
|
||||
updateLoadingStateAction,
|
||||
} from '@kbn/aiops-log-rate-analysis/api/actions';
|
||||
addSignificantItemsGroup,
|
||||
addSignificantItemsGroupHistogram,
|
||||
updateLoadingState,
|
||||
} from '@kbn/aiops-log-rate-analysis/api/stream_reducer';
|
||||
import type { AiopsLogRateAnalysisApiVersion as ApiVersion } from '@kbn/aiops-log-rate-analysis/api/schema';
|
||||
import { isRequestAbortedError } from '@kbn/aiops-common/is_request_aborted_error';
|
||||
|
||||
|
@ -56,7 +56,7 @@ export const groupingHandlerFactory =
|
|||
|
||||
function pushHistogramDataLoadingState() {
|
||||
responseStream.push(
|
||||
updateLoadingStateAction({
|
||||
updateLoadingState({
|
||||
ccsWarning: false,
|
||||
loaded: stateHandler.loaded(),
|
||||
loadingState: i18n.translate(
|
||||
|
@ -70,7 +70,7 @@ export const groupingHandlerFactory =
|
|||
}
|
||||
|
||||
responseStream.push(
|
||||
updateLoadingStateAction({
|
||||
updateLoadingState({
|
||||
ccsWarning: false,
|
||||
loaded: stateHandler.loaded(),
|
||||
loadingState: i18n.translate('xpack.aiops.logRateAnalysis.loadingState.groupingResults', {
|
||||
|
@ -133,7 +133,7 @@ export const groupingHandlerFactory =
|
|||
const maxItems = Math.max(...significantItemGroups.map((g) => g.group.length));
|
||||
|
||||
if (maxItems > 1) {
|
||||
responseStream.push(addSignificantItemsGroupAction(significantItemGroups));
|
||||
responseStream.push(addSignificantItemsGroup(significantItemGroups));
|
||||
}
|
||||
|
||||
stateHandler.loaded(PROGRESS_STEP_GROUPING, false);
|
||||
|
@ -211,7 +211,7 @@ export const groupingHandlerFactory =
|
|||
}) ?? [];
|
||||
|
||||
responseStream.push(
|
||||
addSignificantItemsGroupHistogramAction([
|
||||
addSignificantItemsGroupHistogram([
|
||||
{
|
||||
id: cpg.id,
|
||||
histogram,
|
||||
|
|
|
@ -18,9 +18,9 @@ import { fetchHistogramsForFields } from '@kbn/ml-agg-utils';
|
|||
import { RANDOM_SAMPLER_SEED } from '@kbn/aiops-log-rate-analysis/constants';
|
||||
|
||||
import {
|
||||
addSignificantItemsHistogramAction,
|
||||
updateLoadingStateAction,
|
||||
} from '@kbn/aiops-log-rate-analysis/api/actions';
|
||||
addSignificantItemsHistogram,
|
||||
updateLoadingState,
|
||||
} from '@kbn/aiops-log-rate-analysis/api/stream_reducer';
|
||||
import type { AiopsLogRateAnalysisApiVersion as ApiVersion } from '@kbn/aiops-log-rate-analysis/api/schema';
|
||||
import { getCategoryQuery } from '@kbn/aiops-log-pattern-analysis/get_category_query';
|
||||
|
||||
|
@ -50,7 +50,7 @@ export const histogramHandlerFactory =
|
|||
) => {
|
||||
function pushHistogramDataLoadingState() {
|
||||
responseStream.push(
|
||||
updateLoadingStateAction({
|
||||
updateLoadingState({
|
||||
ccsWarning: false,
|
||||
loaded: stateHandler.loaded(),
|
||||
loadingState: i18n.translate(
|
||||
|
@ -145,7 +145,7 @@ export const histogramHandlerFactory =
|
|||
stateHandler.loaded((1 / fieldValuePairsCount) * PROGRESS_STEP_HISTOGRAMS, false);
|
||||
pushHistogramDataLoadingState();
|
||||
responseStream.push(
|
||||
addSignificantItemsHistogramAction([
|
||||
addSignificantItemsHistogram([
|
||||
{
|
||||
fieldName,
|
||||
fieldValue,
|
||||
|
@ -238,7 +238,7 @@ export const histogramHandlerFactory =
|
|||
stateHandler.loaded((1 / fieldValuePairsCount) * PROGRESS_STEP_HISTOGRAMS, false);
|
||||
pushHistogramDataLoadingState();
|
||||
responseStream.push(
|
||||
addSignificantItemsHistogramAction([
|
||||
addSignificantItemsHistogram([
|
||||
{
|
||||
fieldName,
|
||||
fieldValue,
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import {
|
||||
updateLoadingStateAction,
|
||||
updateLoadingState,
|
||||
setZeroDocsFallback,
|
||||
} from '@kbn/aiops-log-rate-analysis/api/actions';
|
||||
} from '@kbn/aiops-log-rate-analysis/api/stream_reducer';
|
||||
import type { AiopsLogRateAnalysisApiVersion as ApiVersion } from '@kbn/aiops-log-rate-analysis/api/schema';
|
||||
import { isRequestAbortedError } from '@kbn/aiops-common/is_request_aborted_error';
|
||||
|
||||
|
@ -43,7 +43,7 @@ export const indexInfoHandlerFactory =
|
|||
if (!requestBody.overrides?.remainingFieldCandidates) {
|
||||
logDebugMessage('Fetch index information.');
|
||||
responseStream.push(
|
||||
updateLoadingStateAction({
|
||||
updateLoadingState({
|
||||
ccsWarning: false,
|
||||
loaded: stateHandler.loaded(),
|
||||
loadingState: i18n.translate(
|
||||
|
@ -85,7 +85,7 @@ export const indexInfoHandlerFactory =
|
|||
responseStream.pushPingWithTimeout();
|
||||
|
||||
responseStream.push(
|
||||
updateLoadingStateAction({
|
||||
updateLoadingState({
|
||||
ccsWarning: false,
|
||||
loaded: stateHandler.loaded(),
|
||||
loadingState: i18n.translate(
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
*/
|
||||
|
||||
import {
|
||||
resetAllAction,
|
||||
resetErrorsAction,
|
||||
resetGroupsAction,
|
||||
} from '@kbn/aiops-log-rate-analysis/api/actions';
|
||||
resetAll,
|
||||
resetErrors,
|
||||
resetGroups,
|
||||
} from '@kbn/aiops-log-rate-analysis/api/stream_reducer';
|
||||
import type { AiopsLogRateAnalysisApiVersion as ApiVersion } from '@kbn/aiops-log-rate-analysis/api/schema';
|
||||
|
||||
import type { ResponseStreamFetchOptions } from '../response_stream_factory';
|
||||
|
@ -24,15 +24,15 @@ export const overridesHandlerFactory =
|
|||
() => {
|
||||
if (!requestBody.overrides) {
|
||||
logDebugMessage('Full Reset.');
|
||||
responseStream.push(resetAllAction());
|
||||
responseStream.push(resetAll());
|
||||
} else {
|
||||
logDebugMessage('Reset Errors.');
|
||||
responseStream.push(resetErrorsAction());
|
||||
responseStream.push(resetErrors());
|
||||
}
|
||||
|
||||
if (requestBody.overrides?.regroupOnly) {
|
||||
logDebugMessage('Reset Groups.');
|
||||
responseStream.push(resetGroupsAction());
|
||||
responseStream.push(resetGroups());
|
||||
}
|
||||
|
||||
if (requestBody.overrides?.loaded) {
|
||||
|
|
|
@ -10,9 +10,9 @@ import { queue } from 'async';
|
|||
import { SIGNIFICANT_ITEM_TYPE, type SignificantItem } from '@kbn/ml-agg-utils';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
addSignificantItemsAction,
|
||||
updateLoadingStateAction,
|
||||
} from '@kbn/aiops-log-rate-analysis/api/actions';
|
||||
addSignificantItems,
|
||||
updateLoadingState,
|
||||
} from '@kbn/aiops-log-rate-analysis/api/stream_reducer';
|
||||
import type {
|
||||
AiopsLogRateAnalysisSchema,
|
||||
AiopsLogRateAnalysisApiVersion as ApiVersion,
|
||||
|
@ -137,7 +137,7 @@ export const significantItemsHandlerFactory =
|
|||
});
|
||||
significantTerms.push(...pValues);
|
||||
|
||||
responseStream.push(addSignificantItemsAction(pValues));
|
||||
responseStream.push(addSignificantItems(pValues));
|
||||
|
||||
fieldValuePairsCount += pValues.length;
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ export const significantItemsHandlerFactory =
|
|||
|
||||
if (significantCategoriesForField.length > 0) {
|
||||
significantCategories.push(...significantCategoriesForField);
|
||||
responseStream.push(addSignificantItemsAction(significantCategoriesForField));
|
||||
responseStream.push(addSignificantItems(significantCategoriesForField));
|
||||
fieldValuePairsCount += significantCategoriesForField.length;
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ export const significantItemsHandlerFactory =
|
|||
stateHandler.loaded(loadingStep, false);
|
||||
|
||||
responseStream.push(
|
||||
updateLoadingStateAction({
|
||||
updateLoadingState({
|
||||
ccsWarning: false,
|
||||
loaded: stateHandler.loaded(),
|
||||
loadingState: i18n.translate(
|
||||
|
|
|
@ -11,9 +11,9 @@ import { SIGNIFICANT_ITEM_TYPE, type SignificantItem } from '@kbn/ml-agg-utils';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import {
|
||||
addSignificantItemsAction,
|
||||
updateLoadingStateAction,
|
||||
} from '@kbn/aiops-log-rate-analysis/api/actions';
|
||||
addSignificantItems,
|
||||
updateLoadingState,
|
||||
} from '@kbn/aiops-log-rate-analysis/api/stream_reducer';
|
||||
|
||||
import type {
|
||||
AiopsLogRateAnalysisSchema,
|
||||
|
@ -75,7 +75,7 @@ export const topItemsHandlerFactory =
|
|||
);
|
||||
|
||||
if (topCategories.length > 0) {
|
||||
responseStream.push(addSignificantItemsAction(topCategories));
|
||||
responseStream.push(addSignificantItems(topCategories));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,11 +137,11 @@ export const topItemsHandlerFactory =
|
|||
});
|
||||
topTerms.push(...fetchedTopTerms);
|
||||
|
||||
responseStream.push(addSignificantItemsAction(fetchedTopTerms));
|
||||
responseStream.push(addSignificantItems(fetchedTopTerms));
|
||||
}
|
||||
|
||||
responseStream.push(
|
||||
updateLoadingStateAction({
|
||||
updateLoadingState({
|
||||
ccsWarning: false,
|
||||
loaded: stateHandler.loaded(),
|
||||
loadingState: i18n.translate(
|
||||
|
|
|
@ -10,7 +10,7 @@ import type { ElasticsearchClient } from '@kbn/core/server';
|
|||
import type { Headers, KibanaRequestEvents } from '@kbn/core-http-server';
|
||||
import type { Logger } from '@kbn/logging';
|
||||
|
||||
import { type AiopsLogRateAnalysisApiAction } from '@kbn/aiops-log-rate-analysis/api/actions';
|
||||
import { type AiopsLogRateAnalysisApiAction } from '@kbn/aiops-log-rate-analysis/api/stream_reducer';
|
||||
|
||||
import type {
|
||||
AiopsLogRateAnalysisSchema,
|
||||
|
|
|
@ -10,9 +10,9 @@ import { i18n } from '@kbn/i18n';
|
|||
import type { StreamFactoryReturnType } from '@kbn/ml-response-stream/server';
|
||||
|
||||
import {
|
||||
updateLoadingStateAction,
|
||||
updateLoadingState,
|
||||
type AiopsLogRateAnalysisApiAction,
|
||||
} from '@kbn/aiops-log-rate-analysis/api/actions';
|
||||
} from '@kbn/aiops-log-rate-analysis/api/stream_reducer';
|
||||
|
||||
/**
|
||||
* Helper function that will push a message to the stream that it's done and
|
||||
|
@ -26,7 +26,7 @@ export const streamEndWithUpdatedLoadingStateFactory = (
|
|||
) => {
|
||||
return function endWithUpdatedLoadingState() {
|
||||
push(
|
||||
updateLoadingStateAction({
|
||||
updateLoadingState({
|
||||
ccsWarning: false,
|
||||
loaded: 1,
|
||||
loadingState: i18n.translate('xpack.aiops.logRateAnalysis.loadingState.doneMessage', {
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
import type { StreamFactoryReturnType } from '@kbn/ml-response-stream/server';
|
||||
|
||||
import {
|
||||
addErrorAction,
|
||||
addError,
|
||||
type AiopsLogRateAnalysisApiAction,
|
||||
} from '@kbn/aiops-log-rate-analysis/api/actions';
|
||||
} from '@kbn/aiops-log-rate-analysis/api/stream_reducer';
|
||||
|
||||
import type { LogDebugMessage } from './log_debug_message';
|
||||
|
||||
|
@ -25,6 +25,6 @@ export const streamPushErrorFactory = (
|
|||
) => {
|
||||
return function pushError(m: string) {
|
||||
logDebugMessage('Push error.');
|
||||
push(addErrorAction(m));
|
||||
push(addError(m));
|
||||
};
|
||||
};
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
import type { StreamFactoryReturnType } from '@kbn/ml-response-stream/server';
|
||||
|
||||
import {
|
||||
pingAction,
|
||||
ping,
|
||||
type AiopsLogRateAnalysisApiAction,
|
||||
} from '@kbn/aiops-log-rate-analysis/api/actions';
|
||||
} from '@kbn/aiops-log-rate-analysis/api/stream_reducer';
|
||||
|
||||
import type { LogDebugMessage } from './log_debug_message';
|
||||
import type { StateHandler } from './state_handler';
|
||||
|
@ -32,7 +32,7 @@ export const streamPushPingWithTimeoutFactory = (
|
|||
setTimeout(() => {
|
||||
if (stateHandler.isRunning()) {
|
||||
logDebugMessage('Ping message.');
|
||||
push(pingAction());
|
||||
push(ping());
|
||||
pushPingWithTimeout();
|
||||
}
|
||||
}, PING_FREQUENCY);
|
||||
|
|
|
@ -33,8 +33,6 @@ export const LogRateAnalysisPage: FC = () => {
|
|||
</MlPageHeader>
|
||||
{dataView && (
|
||||
<LogRateAnalysis
|
||||
// Default to false for now, until page restructure work to enable smooth sticky histogram is done
|
||||
stickyHistogram={false}
|
||||
dataView={dataView}
|
||||
savedSearch={savedSearch}
|
||||
showFrozenDataTierChoice={showNodeInfo}
|
||||
|
|
|
@ -6,15 +6,16 @@
|
|||
*/
|
||||
|
||||
export const getAddSignificationItemsActions = (data: any[]) =>
|
||||
data.filter((d) => d.type === 'add_significant_items');
|
||||
data.filter((d) => d.type === 'logRateAnalysisResults/addSignificantItems');
|
||||
|
||||
export const getHistogramActions = (data: any[]) =>
|
||||
data.filter((d) => d.type === 'add_significant_items_histogram');
|
||||
data.filter((d) => d.type === 'logRateAnalysisResults/addSignificantItemsHistogram');
|
||||
|
||||
export const getGroupActions = (data: any[]) =>
|
||||
data.filter((d) => d.type === 'add_significant_items_group');
|
||||
data.filter((d) => d.type === 'logRateAnalysisResults/addSignificantItemsGroup');
|
||||
|
||||
export const getGroupHistogramActions = (data: any[]) =>
|
||||
data.filter((d) => d.type === 'add_significant_items_group_histogram');
|
||||
data.filter((d) => d.type === 'logRateAnalysisResults/addSignificantItemsGroupHistogram');
|
||||
|
||||
export const getErrorActions = (data: any[]) => data.filter((d) => d.type === 'add_error');
|
||||
export const getErrorActions = (data: any[]) =>
|
||||
data.filter((d) => d.type === 'logRateAnalysisResults/addError');
|
||||
|
|
|
@ -10,35 +10,35 @@ export const analysisTableTextfieldZerodocsfallback = [
|
|||
fieldName: 'message',
|
||||
fieldValue: 'Paul [11/19/2022, 8:00:34 AM] "GET /home.php HTTP/1.1" 200',
|
||||
logRate: 'Chart type:bar chart',
|
||||
pValue: '1.00',
|
||||
pValue: '',
|
||||
impact: '',
|
||||
},
|
||||
{
|
||||
fieldName: 'response_code',
|
||||
fieldValue: '500',
|
||||
logRate: 'Chart type:bar chart',
|
||||
pValue: '1.00',
|
||||
pValue: '',
|
||||
impact: '',
|
||||
},
|
||||
{
|
||||
fieldName: 'url',
|
||||
fieldValue: 'home.php',
|
||||
logRate: 'Chart type:bar chart',
|
||||
pValue: '1.00',
|
||||
pValue: '',
|
||||
impact: '',
|
||||
},
|
||||
{
|
||||
fieldName: 'user',
|
||||
fieldValue: 'Paul',
|
||||
logRate: 'Chart type:bar chart',
|
||||
pValue: '1.00',
|
||||
pValue: '',
|
||||
impact: '',
|
||||
},
|
||||
{
|
||||
fieldName: 'version',
|
||||
fieldValue: 'v1.0.0',
|
||||
logRate: 'Chart type:bar chart',
|
||||
pValue: '1.00',
|
||||
pValue: '',
|
||||
impact: '',
|
||||
},
|
||||
];
|
||||
|
|
|
@ -10,28 +10,28 @@ export const analysisTableZerodocsfallback = [
|
|||
fieldName: 'response_code',
|
||||
fieldValue: '500',
|
||||
logRate: 'Chart type:bar chart',
|
||||
pValue: '1.00',
|
||||
pValue: '',
|
||||
impact: '',
|
||||
},
|
||||
{
|
||||
fieldName: 'url',
|
||||
fieldValue: 'home.php',
|
||||
logRate: 'Chart type:bar chart',
|
||||
pValue: '1.00',
|
||||
pValue: '',
|
||||
impact: '',
|
||||
},
|
||||
{
|
||||
fieldName: 'user',
|
||||
fieldValue: 'Paul',
|
||||
logRate: 'Chart type:bar chart',
|
||||
pValue: '1.00',
|
||||
pValue: '',
|
||||
impact: '',
|
||||
},
|
||||
{
|
||||
fieldName: 'version',
|
||||
fieldValue: 'v1.0.0',
|
||||
logRate: 'Chart type:bar chart',
|
||||
pValue: '1.00',
|
||||
pValue: '',
|
||||
impact: '',
|
||||
},
|
||||
];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue