[Logs UI] move ML job setup UI to a flyout (#68366)
Co-authored-by: Felix Stürmer <weltenwort@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
81bd66dcfd
commit
b172b5b777
|
@ -35,7 +35,7 @@ export type SetupStatus =
|
|||
| {
|
||||
type: 'skipped';
|
||||
newlyCreated?: boolean;
|
||||
}; // setup is hidden
|
||||
}; // setup is not necessary
|
||||
|
||||
/**
|
||||
* Maps a job status to the possibility that results have already been produced
|
||||
|
|
|
@ -252,7 +252,7 @@ const getSetupStatus = <JobType extends string>(everyJobStatus: Record<JobType,
|
|||
Object.entries<JobStatus>(everyJobStatus).reduce<SetupStatus>((setupStatus, [, jobStatus]) => {
|
||||
if (jobStatus === 'missing') {
|
||||
return { type: 'required', reason: 'missing' };
|
||||
} else if (setupStatus.type === 'required') {
|
||||
} else if (setupStatus.type === 'required' || setupStatus.type === 'succeeded') {
|
||||
return setupStatus;
|
||||
} else if (setupStatus.type === 'skipped' || isJobStatusWithResults(jobStatus)) {
|
||||
return {
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { useEffect } from 'react';
|
||||
import { isSetupStatusWithResults } from '../../../../common/log_analysis';
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { isJobStatusWithResults } from '../../../../common/log_analysis';
|
||||
import { LoadingPage } from '../../../components/loading_page';
|
||||
import {
|
||||
LogAnalysisSetupStatusUnknownPrompt,
|
||||
|
@ -21,6 +21,7 @@ import { useLogSourceContext } from '../../../containers/logs/log_source';
|
|||
import { LogEntryCategoriesResultsContent } from './page_results_content';
|
||||
import { LogEntryCategoriesSetupContent } from './page_setup_content';
|
||||
import { useLogEntryCategoriesModuleContext } from './use_log_entry_categories_module';
|
||||
import { LogEntryCategoriesSetupFlyout } from './setup_flyout';
|
||||
|
||||
export const LogEntryCategoriesPageContent = () => {
|
||||
const {
|
||||
|
@ -37,7 +38,11 @@ export const LogEntryCategoriesPageContent = () => {
|
|||
hasLogAnalysisSetupCapabilities,
|
||||
} = useLogAnalysisCapabilitiesContext();
|
||||
|
||||
const { fetchJobStatus, setupStatus } = useLogEntryCategoriesModuleContext();
|
||||
const { fetchJobStatus, setupStatus, jobStatus } = useLogEntryCategoriesModuleContext();
|
||||
|
||||
const [isFlyoutOpen, setIsFlyoutOpen] = useState<boolean>(false);
|
||||
const openFlyout = useCallback(() => setIsFlyoutOpen(true), []);
|
||||
const closeFlyout = useCallback(() => setIsFlyoutOpen(false), []);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasLogAnalysisReadCapabilities) {
|
||||
|
@ -45,6 +50,13 @@ export const LogEntryCategoriesPageContent = () => {
|
|||
}
|
||||
}, [fetchJobStatus, hasLogAnalysisReadCapabilities]);
|
||||
|
||||
// Open flyout if there are no ML jobs
|
||||
useEffect(() => {
|
||||
if (setupStatus.type === 'required' && setupStatus.reason === 'missing') {
|
||||
openFlyout();
|
||||
}
|
||||
}, [setupStatus, openFlyout]);
|
||||
|
||||
if (isLoading || isUninitialized) {
|
||||
return <SourceLoadingPage />;
|
||||
} else if (hasFailedLoadingSource) {
|
||||
|
@ -63,11 +75,21 @@ export const LogEntryCategoriesPageContent = () => {
|
|||
);
|
||||
} else if (setupStatus.type === 'unknown') {
|
||||
return <LogAnalysisSetupStatusUnknownPrompt retry={fetchJobStatus} />;
|
||||
} else if (isSetupStatusWithResults(setupStatus)) {
|
||||
return <LogEntryCategoriesResultsContent />;
|
||||
} else if (isJobStatusWithResults(jobStatus['log-entry-categories-count'])) {
|
||||
return (
|
||||
<>
|
||||
<LogEntryCategoriesResultsContent onOpenSetup={openFlyout} />
|
||||
<LogEntryCategoriesSetupFlyout isOpen={isFlyoutOpen} onClose={closeFlyout} />
|
||||
</>
|
||||
);
|
||||
} else if (!hasLogAnalysisSetupCapabilities) {
|
||||
return <MissingSetupPrivilegesPrompt />;
|
||||
} else {
|
||||
return <LogEntryCategoriesSetupContent />;
|
||||
return (
|
||||
<>
|
||||
<LogEntryCategoriesSetupContent onOpenSetup={openFlyout} />
|
||||
<LogEntryCategoriesSetupFlyout isOpen={isFlyoutOpen} onClose={closeFlyout} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -24,7 +24,13 @@ import {
|
|||
|
||||
const JOB_STATUS_POLLING_INTERVAL = 30000;
|
||||
|
||||
export const LogEntryCategoriesResultsContent: React.FunctionComponent = () => {
|
||||
interface LogEntryCategoriesResultsContentProps {
|
||||
onOpenSetup: () => void;
|
||||
}
|
||||
|
||||
export const LogEntryCategoriesResultsContent: React.FunctionComponent<LogEntryCategoriesResultsContentProps> = ({
|
||||
onOpenSetup,
|
||||
}) => {
|
||||
useTrackPageview({ app: 'infra_logs', path: 'log_entry_categories_results' });
|
||||
useTrackPageview({ app: 'infra_logs', path: 'log_entry_categories_results', delay: 15000 });
|
||||
|
||||
|
@ -123,12 +129,25 @@ export const LogEntryCategoriesResultsContent: React.FunctionComponent = () => {
|
|||
[setAutoRefresh]
|
||||
);
|
||||
|
||||
const viewSetupFlyoutForReconfiguration = useCallback(() => {
|
||||
viewSetupForReconfiguration();
|
||||
onOpenSetup();
|
||||
}, [onOpenSetup, viewSetupForReconfiguration]);
|
||||
|
||||
const viewSetupFlyoutForUpdate = useCallback(() => {
|
||||
viewSetupForUpdate();
|
||||
onOpenSetup();
|
||||
}, [onOpenSetup, viewSetupForUpdate]);
|
||||
|
||||
const hasResults = useMemo(() => topLogEntryCategories.length > 0, [
|
||||
topLogEntryCategories.length,
|
||||
]);
|
||||
|
||||
const isFirstUse = useMemo(
|
||||
() => setupStatus.type === 'skipped' && !!setupStatus.newlyCreated && !hasResults,
|
||||
() =>
|
||||
((setupStatus.type === 'skipped' && !!setupStatus.newlyCreated) ||
|
||||
setupStatus.type === 'succeeded') &&
|
||||
!hasResults,
|
||||
[hasResults, setupStatus]
|
||||
);
|
||||
|
||||
|
@ -184,8 +203,8 @@ export const LogEntryCategoriesResultsContent: React.FunctionComponent = () => {
|
|||
hasOutdatedJobDefinitions={hasOutdatedJobDefinitions}
|
||||
hasStoppedJobs={hasStoppedJobs}
|
||||
isFirstUse={isFirstUse}
|
||||
onRecreateMlJobForReconfiguration={viewSetupForReconfiguration}
|
||||
onRecreateMlJobForUpdate={viewSetupForUpdate}
|
||||
onRecreateMlJobForReconfiguration={viewSetupFlyoutForReconfiguration}
|
||||
onRecreateMlJobForUpdate={viewSetupFlyoutForUpdate}
|
||||
qualityWarnings={categoryQualityWarnings}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
|
@ -197,7 +216,7 @@ export const LogEntryCategoriesResultsContent: React.FunctionComponent = () => {
|
|||
isLoadingTopCategories={isLoadingTopLogEntryCategories}
|
||||
jobId={jobIds['log-entry-categories-count']}
|
||||
onChangeDatasetSelection={setCategoryQueryDatasets}
|
||||
onRequestRecreateMlJob={viewSetupForReconfiguration}
|
||||
onRequestRecreateMlJob={viewSetupFlyoutForReconfiguration}
|
||||
selectedDatasets={categoryQueryDatasets}
|
||||
sourceId={sourceId}
|
||||
timeRange={categoryQueryTimeRange.timeRange}
|
||||
|
|
|
@ -4,98 +4,51 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { EuiSpacer, EuiSteps, EuiText } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { EuiText, EuiButton, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import { BetaBadge } from '../../../components/beta_badge';
|
||||
import {
|
||||
createInitialConfigurationStep,
|
||||
createProcessStep,
|
||||
LogAnalysisSetupPage,
|
||||
LogAnalysisSetupPageContent,
|
||||
LogAnalysisSetupPageHeader,
|
||||
} from '../../../components/logging/log_analysis_setup';
|
||||
import { useTrackPageview } from '../../../../../observability/public';
|
||||
import { useLogEntryCategoriesSetup } from './use_log_entry_categories_setup';
|
||||
|
||||
export const LogEntryCategoriesSetupContent: React.FunctionComponent = () => {
|
||||
interface LogEntryCategoriesSetupContentProps {
|
||||
onOpenSetup: () => void;
|
||||
}
|
||||
|
||||
export const LogEntryCategoriesSetupContent: React.FunctionComponent<LogEntryCategoriesSetupContentProps> = ({
|
||||
onOpenSetup,
|
||||
}) => {
|
||||
useTrackPageview({ app: 'infra_logs', path: 'log_entry_categories_setup' });
|
||||
useTrackPageview({ app: 'infra_logs', path: 'log_entry_categories_setup', delay: 15000 });
|
||||
|
||||
const {
|
||||
cleanUpAndSetUp,
|
||||
endTime,
|
||||
isValidating,
|
||||
lastSetupErrorMessages,
|
||||
setEndTime,
|
||||
setStartTime,
|
||||
setValidatedIndices,
|
||||
setUp,
|
||||
setupStatus,
|
||||
startTime,
|
||||
validatedIndices,
|
||||
validationErrors,
|
||||
viewResults,
|
||||
} = useLogEntryCategoriesSetup();
|
||||
|
||||
const steps = useMemo(
|
||||
() => [
|
||||
createInitialConfigurationStep({
|
||||
setStartTime,
|
||||
setEndTime,
|
||||
startTime,
|
||||
endTime,
|
||||
isValidating,
|
||||
validatedIndices,
|
||||
setupStatus,
|
||||
setValidatedIndices,
|
||||
validationErrors,
|
||||
}),
|
||||
createProcessStep({
|
||||
cleanUpAndSetUp,
|
||||
errorMessages: lastSetupErrorMessages,
|
||||
isConfigurationValid: validationErrors.length <= 0 && !isValidating,
|
||||
setUp,
|
||||
setupStatus,
|
||||
viewResults,
|
||||
}),
|
||||
],
|
||||
[
|
||||
cleanUpAndSetUp,
|
||||
endTime,
|
||||
isValidating,
|
||||
lastSetupErrorMessages,
|
||||
setEndTime,
|
||||
setStartTime,
|
||||
setUp,
|
||||
setValidatedIndices,
|
||||
setupStatus,
|
||||
startTime,
|
||||
validatedIndices,
|
||||
validationErrors,
|
||||
viewResults,
|
||||
]
|
||||
);
|
||||
|
||||
return (
|
||||
<LogAnalysisSetupPage data-test-subj="logEntryCategoriesSetupPage">
|
||||
<LogAnalysisSetupPageHeader>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.logs.logEntryCategories.setupTitle"
|
||||
defaultMessage="Enable Machine Learning analysis"
|
||||
/>{' '}
|
||||
<BetaBadge />
|
||||
defaultMessage="Set up log category analysis"
|
||||
/>
|
||||
</LogAnalysisSetupPageHeader>
|
||||
<LogAnalysisSetupPageContent>
|
||||
<EuiText size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.infra.logs.logEntryCategories.setupDescription"
|
||||
defaultMessage="Use Machine Learning to automatically categorize log messages."
|
||||
/>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.logs.logEntryCategories.setupDescription"
|
||||
defaultMessage="To enable log categories, set up a machine learning job."
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiSteps steps={steps} />
|
||||
<EuiButton fill onClick={onOpenSetup}>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.logs.logEntryCategories.showAnalysisSetupButtonLabel"
|
||||
defaultMessage="ML setup"
|
||||
/>
|
||||
</EuiButton>
|
||||
</LogAnalysisSetupPageContent>
|
||||
</LogAnalysisSetupPage>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { useMemo, useCallback } from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import {
|
||||
EuiFlyout,
|
||||
EuiFlyoutHeader,
|
||||
EuiFlyoutBody,
|
||||
EuiTitle,
|
||||
EuiText,
|
||||
EuiSpacer,
|
||||
EuiSteps,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import {
|
||||
createInitialConfigurationStep,
|
||||
createProcessStep,
|
||||
} from '../../../components/logging/log_analysis_setup';
|
||||
import { useLogEntryCategoriesSetup } from './use_log_entry_categories_setup';
|
||||
|
||||
interface LogEntryCategoriesSetupFlyoutProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const LogEntryCategoriesSetupFlyout: React.FC<LogEntryCategoriesSetupFlyoutProps> = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
}) => {
|
||||
const {
|
||||
cleanUpAndSetUp,
|
||||
endTime,
|
||||
isValidating,
|
||||
lastSetupErrorMessages,
|
||||
setEndTime,
|
||||
setStartTime,
|
||||
setValidatedIndices,
|
||||
setUp,
|
||||
setupStatus,
|
||||
startTime,
|
||||
validatedIndices,
|
||||
validationErrors,
|
||||
viewResults,
|
||||
} = useLogEntryCategoriesSetup();
|
||||
|
||||
const viewResultsAndClose = useCallback(() => {
|
||||
viewResults();
|
||||
onClose();
|
||||
}, [viewResults, onClose]);
|
||||
|
||||
const steps = useMemo(
|
||||
() => [
|
||||
createInitialConfigurationStep({
|
||||
setStartTime,
|
||||
setEndTime,
|
||||
startTime,
|
||||
endTime,
|
||||
isValidating,
|
||||
validatedIndices,
|
||||
setupStatus,
|
||||
setValidatedIndices,
|
||||
validationErrors,
|
||||
}),
|
||||
createProcessStep({
|
||||
cleanUpAndSetUp,
|
||||
errorMessages: lastSetupErrorMessages,
|
||||
isConfigurationValid: validationErrors.length <= 0 && !isValidating,
|
||||
setUp,
|
||||
setupStatus,
|
||||
viewResults: viewResultsAndClose,
|
||||
}),
|
||||
],
|
||||
[
|
||||
cleanUpAndSetUp,
|
||||
endTime,
|
||||
isValidating,
|
||||
lastSetupErrorMessages,
|
||||
setEndTime,
|
||||
setStartTime,
|
||||
setUp,
|
||||
setValidatedIndices,
|
||||
setupStatus,
|
||||
startTime,
|
||||
validatedIndices,
|
||||
validationErrors,
|
||||
viewResultsAndClose,
|
||||
]
|
||||
);
|
||||
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<EuiFlyout onClose={onClose}>
|
||||
<EuiFlyoutHeader hasBorder>
|
||||
<EuiTitle size="s">
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.logs.setupFlyout.setupFlyoutTitle"
|
||||
defaultMessage="Anomaly detection with Machine Learning"
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
</EuiFlyoutHeader>
|
||||
<EuiFlyoutBody>
|
||||
<EuiTitle size="s">
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.logs.setupFlyout.logCategoriesTitle"
|
||||
defaultMessage="Log categories"
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiText size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.infra.logs.setupFlyout.logCategoriesDescription"
|
||||
defaultMessage="Use Machine Learning to automatically categorize log messages."
|
||||
/>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiSteps steps={steps} />
|
||||
</EuiFlyoutBody>
|
||||
</EuiFlyout>
|
||||
);
|
||||
};
|
|
@ -5,8 +5,8 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { useEffect } from 'react';
|
||||
import { isSetupStatusWithResults } from '../../../../common/log_analysis';
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { isJobStatusWithResults } from '../../../../common/log_analysis';
|
||||
import { LoadingPage } from '../../../components/loading_page';
|
||||
import {
|
||||
LogAnalysisSetupStatusUnknownPrompt,
|
||||
|
@ -21,6 +21,7 @@ import { useLogSourceContext } from '../../../containers/logs/log_source';
|
|||
import { LogEntryRateResultsContent } from './page_results_content';
|
||||
import { LogEntryRateSetupContent } from './page_setup_content';
|
||||
import { useLogEntryRateModuleContext } from './use_log_entry_rate_module';
|
||||
import { LogEntryRateSetupFlyout } from './setup_flyout';
|
||||
|
||||
export const LogEntryRatePageContent = () => {
|
||||
const {
|
||||
|
@ -37,7 +38,11 @@ export const LogEntryRatePageContent = () => {
|
|||
hasLogAnalysisSetupCapabilities,
|
||||
} = useLogAnalysisCapabilitiesContext();
|
||||
|
||||
const { fetchJobStatus, setupStatus } = useLogEntryRateModuleContext();
|
||||
const { fetchJobStatus, setupStatus, jobStatus } = useLogEntryRateModuleContext();
|
||||
|
||||
const [isFlyoutOpen, setIsFlyoutOpen] = useState<boolean>(false);
|
||||
const openFlyout = useCallback(() => setIsFlyoutOpen(true), []);
|
||||
const closeFlyout = useCallback(() => setIsFlyoutOpen(false), []);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasLogAnalysisReadCapabilities) {
|
||||
|
@ -45,6 +50,13 @@ export const LogEntryRatePageContent = () => {
|
|||
}
|
||||
}, [fetchJobStatus, hasLogAnalysisReadCapabilities]);
|
||||
|
||||
// Open flyout if there are no ML jobs
|
||||
useEffect(() => {
|
||||
if (setupStatus.type === 'required' && setupStatus.reason === 'missing') {
|
||||
openFlyout();
|
||||
}
|
||||
}, [setupStatus, openFlyout]);
|
||||
|
||||
if (isLoading || isUninitialized) {
|
||||
return <SourceLoadingPage />;
|
||||
} else if (hasFailedLoadingSource) {
|
||||
|
@ -63,11 +75,21 @@ export const LogEntryRatePageContent = () => {
|
|||
);
|
||||
} else if (setupStatus.type === 'unknown') {
|
||||
return <LogAnalysisSetupStatusUnknownPrompt retry={fetchJobStatus} />;
|
||||
} else if (isSetupStatusWithResults(setupStatus)) {
|
||||
return <LogEntryRateResultsContent />;
|
||||
} else if (isJobStatusWithResults(jobStatus['log-entry-rate'])) {
|
||||
return (
|
||||
<>
|
||||
<LogEntryRateResultsContent onOpenSetup={openFlyout} />
|
||||
<LogEntryRateSetupFlyout isOpen={isFlyoutOpen} onClose={closeFlyout} />
|
||||
</>
|
||||
);
|
||||
} else if (!hasLogAnalysisSetupCapabilities) {
|
||||
return <MissingSetupPrivilegesPrompt />;
|
||||
} else {
|
||||
return <LogEntryRateSetupContent />;
|
||||
return (
|
||||
<>
|
||||
<LogEntryRateSetupContent onOpenSetup={openFlyout} />
|
||||
<LogEntryRateSetupFlyout isOpen={isFlyoutOpen} onClose={closeFlyout} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -36,7 +36,13 @@ import {
|
|||
|
||||
const JOB_STATUS_POLLING_INTERVAL = 30000;
|
||||
|
||||
export const LogEntryRateResultsContent: React.FunctionComponent = () => {
|
||||
interface LogEntryRateResultsContentProps {
|
||||
onOpenSetup: () => void;
|
||||
}
|
||||
|
||||
export const LogEntryRateResultsContent: React.FunctionComponent<LogEntryRateResultsContentProps> = ({
|
||||
onOpenSetup,
|
||||
}) => {
|
||||
useTrackPageview({ app: 'infra_logs', path: 'log_entry_rate_results' });
|
||||
useTrackPageview({ app: 'infra_logs', path: 'log_entry_rate_results', delay: 15000 });
|
||||
|
||||
|
@ -127,13 +133,26 @@ export const LogEntryRateResultsContent: React.FunctionComponent = () => {
|
|||
[setAutoRefresh]
|
||||
);
|
||||
|
||||
const viewSetupFlyoutForReconfiguration = useCallback(() => {
|
||||
viewSetupForReconfiguration();
|
||||
onOpenSetup();
|
||||
}, [viewSetupForReconfiguration, onOpenSetup]);
|
||||
|
||||
const viewSetupFlyoutForUpdate = useCallback(() => {
|
||||
viewSetupForUpdate();
|
||||
onOpenSetup();
|
||||
}, [viewSetupForUpdate, onOpenSetup]);
|
||||
|
||||
/* eslint-disable-next-line react-hooks/exhaustive-deps */
|
||||
const hasResults = useMemo(() => (logEntryRate?.histogramBuckets?.length ?? 0) > 0, [
|
||||
logEntryRate,
|
||||
]);
|
||||
|
||||
const isFirstUse = useMemo(
|
||||
() => setupStatus.type === 'skipped' && !!setupStatus.newlyCreated && !hasResults,
|
||||
() =>
|
||||
((setupStatus.type === 'skipped' && !!setupStatus.newlyCreated) ||
|
||||
setupStatus.type === 'succeeded') &&
|
||||
!hasResults,
|
||||
[hasResults, setupStatus]
|
||||
);
|
||||
|
||||
|
@ -209,8 +228,8 @@ export const LogEntryRateResultsContent: React.FunctionComponent = () => {
|
|||
hasOutdatedJobDefinitions={hasOutdatedJobDefinitions}
|
||||
hasStoppedJobs={hasStoppedJobs}
|
||||
isFirstUse={isFirstUse}
|
||||
onRecreateMlJobForReconfiguration={viewSetupForReconfiguration}
|
||||
onRecreateMlJobForUpdate={viewSetupForUpdate}
|
||||
onRecreateMlJobForReconfiguration={viewSetupFlyoutForReconfiguration}
|
||||
onRecreateMlJobForUpdate={viewSetupFlyoutForUpdate}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -227,7 +246,7 @@ export const LogEntryRateResultsContent: React.FunctionComponent = () => {
|
|||
<EuiPanel paddingSize="m">
|
||||
<AnomaliesResults
|
||||
isLoading={isLoading}
|
||||
viewSetupForReconfiguration={viewSetupForReconfiguration}
|
||||
viewSetupForReconfiguration={viewSetupFlyoutForReconfiguration}
|
||||
results={logEntryRate}
|
||||
setTimeRange={handleChartTimeRangeChange}
|
||||
timeRange={queryTimeRange.value}
|
||||
|
|
|
@ -4,98 +4,51 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { EuiSpacer, EuiSteps, EuiText } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { EuiText, EuiButton, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import { BetaBadge } from '../../../components/beta_badge';
|
||||
import {
|
||||
createInitialConfigurationStep,
|
||||
createProcessStep,
|
||||
LogAnalysisSetupPage,
|
||||
LogAnalysisSetupPageContent,
|
||||
LogAnalysisSetupPageHeader,
|
||||
} from '../../../components/logging/log_analysis_setup';
|
||||
import { useTrackPageview } from '../../../../../observability/public';
|
||||
import { useLogEntryRateSetup } from './use_log_entry_rate_setup';
|
||||
|
||||
export const LogEntryRateSetupContent: React.FunctionComponent = () => {
|
||||
interface LogEntryRateSetupContentProps {
|
||||
onOpenSetup: () => void;
|
||||
}
|
||||
|
||||
export const LogEntryRateSetupContent: React.FunctionComponent<LogEntryRateSetupContentProps> = ({
|
||||
onOpenSetup,
|
||||
}) => {
|
||||
useTrackPageview({ app: 'infra_logs', path: 'log_entry_rate_setup' });
|
||||
useTrackPageview({ app: 'infra_logs', path: 'log_entry_rate_setup', delay: 15000 });
|
||||
|
||||
const {
|
||||
cleanUpAndSetUp,
|
||||
endTime,
|
||||
isValidating,
|
||||
lastSetupErrorMessages,
|
||||
setEndTime,
|
||||
setStartTime,
|
||||
setValidatedIndices,
|
||||
setUp,
|
||||
setupStatus,
|
||||
startTime,
|
||||
validatedIndices,
|
||||
validationErrors,
|
||||
viewResults,
|
||||
} = useLogEntryRateSetup();
|
||||
|
||||
const steps = useMemo(
|
||||
() => [
|
||||
createInitialConfigurationStep({
|
||||
setStartTime,
|
||||
setEndTime,
|
||||
startTime,
|
||||
endTime,
|
||||
isValidating,
|
||||
validatedIndices,
|
||||
setupStatus,
|
||||
setValidatedIndices,
|
||||
validationErrors,
|
||||
}),
|
||||
createProcessStep({
|
||||
cleanUpAndSetUp,
|
||||
errorMessages: lastSetupErrorMessages,
|
||||
isConfigurationValid: validationErrors.length <= 0 && !isValidating,
|
||||
setUp,
|
||||
setupStatus,
|
||||
viewResults,
|
||||
}),
|
||||
],
|
||||
[
|
||||
cleanUpAndSetUp,
|
||||
endTime,
|
||||
isValidating,
|
||||
lastSetupErrorMessages,
|
||||
setEndTime,
|
||||
setStartTime,
|
||||
setUp,
|
||||
setValidatedIndices,
|
||||
setupStatus,
|
||||
startTime,
|
||||
validatedIndices,
|
||||
validationErrors,
|
||||
viewResults,
|
||||
]
|
||||
);
|
||||
|
||||
return (
|
||||
<LogAnalysisSetupPage data-test-subj="logEntryRateSetupPage">
|
||||
<LogAnalysisSetupPageHeader>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.analysisSetup.analysisSetupTitle"
|
||||
defaultMessage="Enable Machine Learning analysis"
|
||||
/>{' '}
|
||||
<BetaBadge />
|
||||
id="xpack.infra.logs.logEntryRate.setupTitle"
|
||||
defaultMessage="Set up log anomaly analysis"
|
||||
/>
|
||||
</LogAnalysisSetupPageHeader>
|
||||
<LogAnalysisSetupPageContent>
|
||||
<EuiText size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.infra.analysisSetup.analysisSetupDescription"
|
||||
defaultMessage="Use Machine Learning to automatically detect anomalous log rate counts."
|
||||
/>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.logs.logEntryRate.setupDescription"
|
||||
defaultMessage="To enable log anomalies, set up a machine learning job"
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiSteps steps={steps} />
|
||||
<EuiButton fill onClick={onOpenSetup}>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.logs.logEntryRate.showAnalysisSetupButtonLabel"
|
||||
defaultMessage="ML Setup"
|
||||
/>
|
||||
</EuiButton>
|
||||
</LogAnalysisSetupPageContent>
|
||||
</LogAnalysisSetupPage>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { useMemo, useCallback } from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import {
|
||||
EuiFlyout,
|
||||
EuiFlyoutHeader,
|
||||
EuiFlyoutBody,
|
||||
EuiTitle,
|
||||
EuiText,
|
||||
EuiSpacer,
|
||||
EuiSteps,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import {
|
||||
createInitialConfigurationStep,
|
||||
createProcessStep,
|
||||
} from '../../../components/logging/log_analysis_setup';
|
||||
import { useLogEntryRateSetup } from './use_log_entry_rate_setup';
|
||||
|
||||
interface LogEntryRateSetupFlyoutProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const LogEntryRateSetupFlyout: React.FC<LogEntryRateSetupFlyoutProps> = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
}) => {
|
||||
const {
|
||||
cleanUpAndSetUp,
|
||||
endTime,
|
||||
isValidating,
|
||||
lastSetupErrorMessages,
|
||||
setEndTime,
|
||||
setStartTime,
|
||||
setValidatedIndices,
|
||||
setUp,
|
||||
setupStatus,
|
||||
startTime,
|
||||
validatedIndices,
|
||||
validationErrors,
|
||||
viewResults,
|
||||
} = useLogEntryRateSetup();
|
||||
|
||||
const viewResultsAndClose = useCallback(() => {
|
||||
viewResults();
|
||||
onClose();
|
||||
}, [viewResults, onClose]);
|
||||
|
||||
const steps = useMemo(
|
||||
() => [
|
||||
createInitialConfigurationStep({
|
||||
setStartTime,
|
||||
setEndTime,
|
||||
startTime,
|
||||
endTime,
|
||||
isValidating,
|
||||
validatedIndices,
|
||||
setupStatus,
|
||||
setValidatedIndices,
|
||||
validationErrors,
|
||||
}),
|
||||
createProcessStep({
|
||||
cleanUpAndSetUp,
|
||||
errorMessages: lastSetupErrorMessages,
|
||||
isConfigurationValid: validationErrors.length <= 0 && !isValidating,
|
||||
setUp,
|
||||
setupStatus,
|
||||
viewResults: viewResultsAndClose,
|
||||
}),
|
||||
],
|
||||
[
|
||||
cleanUpAndSetUp,
|
||||
endTime,
|
||||
isValidating,
|
||||
lastSetupErrorMessages,
|
||||
setEndTime,
|
||||
setStartTime,
|
||||
setUp,
|
||||
setValidatedIndices,
|
||||
setupStatus,
|
||||
startTime,
|
||||
validatedIndices,
|
||||
validationErrors,
|
||||
viewResultsAndClose,
|
||||
]
|
||||
);
|
||||
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<EuiFlyout onClose={onClose}>
|
||||
<EuiFlyoutHeader hasBorder>
|
||||
<EuiTitle size="s">
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.logs.setupFlyout.setupFlyoutTitle"
|
||||
defaultMessage="Anomaly detection with Machine Learning"
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
</EuiFlyoutHeader>
|
||||
<EuiFlyoutBody>
|
||||
<EuiTitle size="s">
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.logs.setupFlyout.logRateTitle"
|
||||
defaultMessage="Log rate"
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiText size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.infra.logs.setupFlyout.logRateDescription"
|
||||
defaultMessage="Use Machine Learning to automatically detect anomalous log rate counts."
|
||||
/>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiSteps steps={steps} />
|
||||
</EuiFlyoutBody>
|
||||
</EuiFlyout>
|
||||
);
|
||||
};
|
|
@ -7316,8 +7316,6 @@
|
|||
"xpack.infra.alerting.logs.manageAlerts": "アラートを管理",
|
||||
"xpack.infra.alerting.manageAlerts": "アラートを管理",
|
||||
"xpack.infra.analysisSetup.actionStepTitle": "MLジョブを作成",
|
||||
"xpack.infra.analysisSetup.analysisSetupDescription": "機械学習を使用して自動的に異常ログレートカウントを検出します。",
|
||||
"xpack.infra.analysisSetup.analysisSetupTitle": "機械学習分析を有効にする",
|
||||
"xpack.infra.analysisSetup.configurationStepTitle": "構成",
|
||||
"xpack.infra.analysisSetup.createMlJobButton": "ML ジョブを作成",
|
||||
"xpack.infra.analysisSetup.deleteAnalysisResultsWarning": "これにより以前検出された異常が削除されます。",
|
||||
|
|
|
@ -7320,8 +7320,6 @@
|
|||
"xpack.infra.alerting.logs.manageAlerts": "管理告警",
|
||||
"xpack.infra.alerting.manageAlerts": "管理告警",
|
||||
"xpack.infra.analysisSetup.actionStepTitle": "创建 ML 作业",
|
||||
"xpack.infra.analysisSetup.analysisSetupDescription": "使用 Machine Learning 自动检测异常日志速率计数。",
|
||||
"xpack.infra.analysisSetup.analysisSetupTitle": "启用 Machine Learning 分析",
|
||||
"xpack.infra.analysisSetup.configurationStepTitle": "配置",
|
||||
"xpack.infra.analysisSetup.createMlJobButton": "创建 ML 作业",
|
||||
"xpack.infra.analysisSetup.deleteAnalysisResultsWarning": "这将移除以前检测到的异常。",
|
||||
|
|
Loading…
Reference in a new issue