Skip to content

Commit

Permalink
[8.x] [ML] Adds action to add log rate analysis to a case (#201549) (#…
Browse files Browse the repository at this point in the history
…202431)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[ML] Adds action to add log rate analysis to a case
(#201549)](#201549)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Robert
Jaszczurek","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-12-02T10:59:54Z","message":"[ML]
Adds action to add log rate analysis to a case (#201549)\n\n##
Summary\r\n\r\nFollow up to
[#197247](https://github.com/elastic/kibana/issues/197247)\r\n\r\nAdds
action to add Log Rate Analysis Embeddable to a
case.\r\n\r\n\r\n\r\nhttps://github.com/user-attachments/assets/f45554e1-cef7-4c54-bea5-c509f236a956\r\n\r\n\r\n\r\n###
Checklist\r\n\r\nCheck the PR satisfies following conditions.
\r\n\r\nReviewers should verify this PR satisfies this list as
well.\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<[email protected]>","sha":"aa4c39c11955333176a612fd1b3601c34fcbc8ad","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:enhancement",":ml","v9.0.0","Team:ML","Feature:ML/AIOps","backport:version","v8.18.0"],"title":"[ML]
Adds action to add log rate analysis to a
case","number":201549,"url":"https://github.com/elastic/kibana/pull/201549","mergeCommit":{"message":"[ML]
Adds action to add log rate analysis to a case (#201549)\n\n##
Summary\r\n\r\nFollow up to
[#197247](https://github.com/elastic/kibana/issues/197247)\r\n\r\nAdds
action to add Log Rate Analysis Embeddable to a
case.\r\n\r\n\r\n\r\nhttps://github.com/user-attachments/assets/f45554e1-cef7-4c54-bea5-c509f236a956\r\n\r\n\r\n\r\n###
Checklist\r\n\r\nCheck the PR satisfies following conditions.
\r\n\r\nReviewers should verify this PR satisfies this list as
well.\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<[email protected]>","sha":"aa4c39c11955333176a612fd1b3601c34fcbc8ad"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/201549","number":201549,"mergeCommit":{"message":"[ML]
Adds action to add log rate analysis to a case (#201549)\n\n##
Summary\r\n\r\nFollow up to
[#197247](https://github.com/elastic/kibana/issues/197247)\r\n\r\nAdds
action to add Log Rate Analysis Embeddable to a
case.\r\n\r\n\r\n\r\nhttps://github.com/user-attachments/assets/f45554e1-cef7-4c54-bea5-c509f236a956\r\n\r\n\r\n\r\n###
Checklist\r\n\r\nCheck the PR satisfies following conditions.
\r\n\r\nReviewers should verify this PR satisfies this list as
well.\r\n\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common
scenarios\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine
<[email protected]>","sha":"aa4c39c11955333176a612fd1b3601c34fcbc8ad"}},{"branch":"8.x","label":"v8.18.0","branchLabelMappingKey":"^v8.18.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Robert Jaszczurek <[email protected]>
  • Loading branch information
kibanamachine and rbrtj authored Dec 2, 2024
1 parent 86c3d01 commit 2d09fbb
Show file tree
Hide file tree
Showing 27 changed files with 450 additions and 90 deletions.
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pageLoadAssetSize:
actions: 20000
advancedSettings: 27596
aiAssistantManagementSelection: 19146
aiops: 16670
aiops: 17680
alerting: 106936
apm: 64385
banners: 17946
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ export interface DocumentCountChartProps {
dataTestSubj?: string;
/** Optional change point metadata */
changePoint?: DocumentCountStatsChangePoint;
/** Whether the brush should be non-interactive */
nonInteractive?: boolean;
}

const SPEC_ID = 'document_count';
Expand Down Expand Up @@ -190,6 +192,7 @@ export const DocumentCountChart: FC<DocumentCountChartProps> = (props) => {
barHighlightColorOverride,
deviationBrush = {},
baselineBrush = {},
nonInteractive,
} = props;

const { data, uiSettings, fieldFormats, charts } = dependencies;
Expand Down Expand Up @@ -470,6 +473,7 @@ export const DocumentCountChart: FC<DocumentCountChartProps> = (props) => {
marginLeft={mlBrushMarginLeft}
snapTimestamps={snapTimestamps}
width={mlBrushWidth}
nonInteractive={nonInteractive}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ interface DualBrushProps {
* Width
*/
width: number;
/**
* Whether the brush should be non-interactive. When true, the brush is still visible
* but cannot be moved or resized by the user.
*/
nonInteractive?: boolean;
}

/**
Expand All @@ -98,7 +103,16 @@ interface DualBrushProps {
* @returns The DualBrush component.
*/
export const DualBrush: FC<DualBrushProps> = (props) => {
const { windowParameters, min, max, onChange, marginLeft, snapTimestamps, width } = props;
const {
windowParameters,
min,
max,
onChange,
marginLeft,
snapTimestamps,
width,
nonInteractive,
} = props;
const d3BrushContainer = useRef(null);
const brushes = useRef<DualBrush[]>([]);

Expand Down Expand Up @@ -301,6 +315,10 @@ export const DualBrush: FC<DualBrushProps> = (props) => {
.attr('rx', BRUSH_HANDLE_ROUNDED_CORNER)
.attr('ry', BRUSH_HANDLE_ROUNDED_CORNER);

if (nonInteractive) {
mlBrushSelection.merge(mlBrushSelection).attr('pointer-events', 'none');
}

mlBrushSelection.exit().remove();
}

Expand Down Expand Up @@ -355,6 +373,7 @@ export const DualBrush: FC<DualBrushProps> = (props) => {
deviationMax,
snapTimestamps,
onChange,
nonInteractive,
]);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ interface ProgressControlProps {
shouldRerunAnalysis: boolean;
runAnalysisDisabled?: boolean;
analysisInfo?: React.ReactNode;
isAnalysisControlsDisabled?: boolean;
}

/**
Expand All @@ -63,6 +64,7 @@ export const ProgressControls: FC<PropsWithChildren<ProgressControlProps>> = (pr
shouldRerunAnalysis,
runAnalysisDisabled = false,
analysisInfo = null,
isAnalysisControlsDisabled = false,
} = props;

const progressOutput = Math.round(progress * 100);
Expand All @@ -73,47 +75,55 @@ export const ProgressControls: FC<PropsWithChildren<ProgressControlProps>> = (pr

return (
<EuiFlexGroup alignItems="center" gutterSize="s">
<EuiFlexItem grow={false}>
{!isRunning && (
<EuiButton
disabled={runAnalysisDisabled}
data-test-subj={`aiopsRerunAnalysisButton${shouldRerunAnalysis ? ' shouldRerun' : ''}`}
size="s"
onClick={onRefresh}
color={shouldRerunAnalysis ? 'warning' : 'primary'}
>
<EuiFlexGroup>
<EuiFlexItem>
<FormattedMessage
id="xpack.aiops.rerunAnalysisButtonTitle"
defaultMessage="Run analysis"
/>
</EuiFlexItem>
{shouldRerunAnalysis && (
<>
<EuiFlexItem>
<EuiIconTip
aria-label="Warning"
type="warning"
color="warning"
content={i18n.translate('xpack.aiops.rerunAnalysisTooltipContent', {
defaultMessage:
'Analysis data may be out of date due to selection update. Rerun analysis.',
})}
/>
</EuiFlexItem>
</>
)}
</EuiFlexGroup>
</EuiButton>
)}
{isRunning && (
<EuiButton data-test-subj="aiopsCancelAnalysisButton" size="s" onClick={onCancel}>
<FormattedMessage id="xpack.aiops.cancelAnalysisButtonTitle" defaultMessage="Cancel" />
</EuiButton>
)}
</EuiFlexItem>
{(progress === 1 || isRunning === false) && !isBrushCleared ? (
{!isAnalysisControlsDisabled && (
<EuiFlexItem grow={false}>
{!isRunning && (
<EuiButton
disabled={runAnalysisDisabled}
data-test-subj={`aiopsRerunAnalysisButton${
shouldRerunAnalysis ? ' shouldRerun' : ''
}`}
size="s"
onClick={onRefresh}
color={shouldRerunAnalysis ? 'warning' : 'primary'}
>
<EuiFlexGroup>
<EuiFlexItem>
<FormattedMessage
id="xpack.aiops.rerunAnalysisButtonTitle"
defaultMessage="Run analysis"
/>
</EuiFlexItem>
{shouldRerunAnalysis && (
<>
<EuiFlexItem>
<EuiIconTip
aria-label="Warning"
type="warning"
color="warning"
content={i18n.translate('xpack.aiops.rerunAnalysisTooltipContent', {
defaultMessage:
'Analysis data may be out of date due to selection update. Rerun analysis.',
})}
/>
</EuiFlexItem>
</>
)}
</EuiFlexGroup>
</EuiButton>
)}
{isRunning && (
<EuiButton data-test-subj="aiopsCancelAnalysisButton" size="s" onClick={onCancel}>
<FormattedMessage
id="xpack.aiops.cancelAnalysisButtonTitle"
defaultMessage="Cancel"
/>
</EuiButton>
)}
</EuiFlexItem>
)}

{(progress === 1 || isRunning === false) && !isBrushCleared && !isAnalysisControlsDisabled ? (
<EuiFlexItem grow={false}>
<EuiButton
data-test-subj="aiopsClearSelectionBadge"
Expand Down
2 changes: 2 additions & 0 deletions x-pack/packages/ml/aiops_log_rate_analysis/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,5 @@ export const EMBEDDABLE_LOG_RATE_ANALYSIS_TYPE = 'aiopsLogRateAnalysisEmbeddable

/** */
export const LOG_RATE_ANALYSIS_DATA_VIEW_REF_NAME = 'aiopsLogRateAnalysisEmbeddableDataViewId';

export const CASES_ATTACHMENT_LOG_RATE_ANALYSIS = 'aiopsLogRateAnalysisEmbeddable';
52 changes: 52 additions & 0 deletions x-pack/plugins/aiops/public/cases/log_rate_analysis_attachment.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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 from 'react';
import { memoize } from 'lodash';
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
import type { PersistableStateAttachmentViewProps } from '@kbn/cases-plugin/public/client/attachment_framework/types';
import { FIELD_FORMAT_IDS } from '@kbn/field-formats-plugin/common';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiDescriptionList } from '@elastic/eui';
import type {
LogRateAnalysisEmbeddableWrapper,
LogRateAnalysisEmbeddableWrapperProps,
} from '../shared_components/log_rate_analysis_embeddable_wrapper';

export const initComponent = memoize(
(fieldFormats: FieldFormatsStart, LogRateAnalysisComponent: LogRateAnalysisEmbeddableWrapper) => {
return React.memo((props: PersistableStateAttachmentViewProps) => {
const { persistableStateAttachmentState } = props;
const dataFormatter = fieldFormats.deserialize({
id: FIELD_FORMAT_IDS.DATE,
});
const inputProps =
persistableStateAttachmentState as unknown as LogRateAnalysisEmbeddableWrapperProps;

const listItems = [
{
title: (
<FormattedMessage
id="xpack.aiops.logRateAnalysis.cases.timeRangeLabel"
defaultMessage="Time range"
/>
),
description: `${dataFormatter.convert(
inputProps.timeRange.from
)} - ${dataFormatter.convert(inputProps.timeRange.to)}`,
},
];

return (
<>
<EuiDescriptionList compressed type={'inline'} listItems={listItems} />
<LogRateAnalysisComponent {...inputProps} embeddingOrigin={'cases'} />
</>
);
});
}
);
58 changes: 58 additions & 0 deletions x-pack/plugins/aiops/public/cases/register_cases.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import type { CasesPublicSetup } from '@kbn/cases-plugin/public';
import type { CoreStart } from '@kbn/core/public';
import { CASES_ATTACHMENT_CHANGE_POINT_CHART } from '@kbn/aiops-change-point-detection/constants';
import { CASES_ATTACHMENT_LOG_PATTERN } from '@kbn/aiops-log-pattern-analysis/constants';
import { CASES_ATTACHMENT_LOG_RATE_ANALYSIS } from '@kbn/aiops-log-rate-analysis/constants';
import {
getChangePointDetectionComponent,
getLogRateAnalysisEmbeddableWrapperComponent,
getPatternAnalysisComponent,
} from '../shared_components';
import type { AiopsPluginStartDeps } from '../types';
Expand Down Expand Up @@ -47,6 +49,14 @@ export function registerCases(
};
}),
}),
getAttachmentRemovalObject: () => ({
event: (
<FormattedMessage
id="xpack.aiops.changePointDetection.cases.attachmentRemovalEvent"
defaultMessage="removed change point chart"
/>
),
}),
});

const LogPatternAttachmentComponent = getPatternAnalysisComponent(coreStart, pluginStart);
Expand All @@ -71,5 +81,53 @@ export function registerCases(
return { default: initComponent(pluginStart.fieldFormats, LogPatternAttachmentComponent) };
}),
}),
getAttachmentRemovalObject: () => ({
event: (
<FormattedMessage
id="xpack.aiops.logPatternAnalysis.cases.attachmentRemovalEvent"
defaultMessage="removed log pattern analysis"
/>
),
}),
});

const LogRateAnalysisEmbeddableWrapperComponent = getLogRateAnalysisEmbeddableWrapperComponent(
coreStart,
pluginStart
);

cases.attachmentFramework.registerPersistableState({
id: CASES_ATTACHMENT_LOG_RATE_ANALYSIS,
icon: 'machineLearningApp',
displayName: i18n.translate('xpack.aiops.logRateAnalysis.cases.attachmentName', {
defaultMessage: 'Log rate analysis',
}),
getAttachmentViewObject: () => ({
event: (
<FormattedMessage
id="xpack.aiops.logRateAnalysis.cases.attachmentEvent"
defaultMessage="added log rate analysis"
/>
),
timelineAvatar: 'machineLearningApp',
children: React.lazy(async () => {
const { initComponent } = await import('./log_rate_analysis_attachment');

return {
default: initComponent(
pluginStart.fieldFormats,
LogRateAnalysisEmbeddableWrapperComponent
),
};
}),
}),
getAttachmentRemovalObject: () => ({
event: (
<FormattedMessage
id="xpack.aiops.logRateAnalysis.cases.attachmentRemovalEvent"
defaultMessage="removed log rate analysis"
/>
),
}),
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,25 @@ export const DocumentCountContent: FC<DocumentCountContentProps> = ({
const { documentStats } = useAppSelector((s) => s.logRateAnalysis);
const { sampleProbability, totalCount, documentCountStats } = documentStats;

const isCasesEmbedding = embeddingOrigin === AIOPS_EMBEDDABLE_ORIGIN.CASES;

const isEmbeddedInDashboardOrCases =
embeddingOrigin === AIOPS_EMBEDDABLE_ORIGIN.DASHBOARD || isCasesEmbedding;

if (documentCountStats === undefined) {
return totalCount !== undefined && embeddingOrigin !== AIOPS_EMBEDDABLE_ORIGIN.DASHBOARD ? (
return totalCount !== undefined && !isEmbeddedInDashboardOrCases ? (
<TotalCountHeader totalCount={totalCount} sampleProbability={sampleProbability} />
) : null;
}

if (embeddingOrigin === AIOPS_EMBEDDABLE_ORIGIN.DASHBOARD) {
if (isEmbeddedInDashboardOrCases) {
return (
<DocumentCountChartRedux
dependencies={{ data, uiSettings, fieldFormats, charts }}
barColorOverride={barColorOverride}
barHighlightColorOverride={barHighlightColorOverride}
changePoint={documentCountStats.changePoint}
nonInteractive={isCasesEmbedding}
{...docCountChartProps}
/>
);
Expand Down
Loading

0 comments on commit 2d09fbb

Please sign in to comment.