[Logs UI] ML log integration splash screen (#69288)
Co-authored-by: Brandon Morelli <bmorelli25@gmail.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
2b72de5231
commit
f6c9ca20ed
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 64 KiB |
|
@ -13,3 +13,4 @@ export * from './missing_results_privileges_prompt';
|
||||||
export * from './missing_setup_privileges_prompt';
|
export * from './missing_setup_privileges_prompt';
|
||||||
export * from './ml_unavailable_prompt';
|
export * from './ml_unavailable_prompt';
|
||||||
export * from './setup_status_unknown_prompt';
|
export * from './setup_status_unknown_prompt';
|
||||||
|
export * from './subscription_splash_content';
|
||||||
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
/*
|
||||||
|
* 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, { useEffect } from 'react';
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import {
|
||||||
|
EuiPage,
|
||||||
|
EuiPageBody,
|
||||||
|
EuiPageContent,
|
||||||
|
EuiFlexGroup,
|
||||||
|
EuiFlexItem,
|
||||||
|
EuiSpacer,
|
||||||
|
EuiTitle,
|
||||||
|
EuiText,
|
||||||
|
EuiButton,
|
||||||
|
EuiButtonEmpty,
|
||||||
|
EuiImage,
|
||||||
|
} from '@elastic/eui';
|
||||||
|
import { FormattedMessage } from '@kbn/i18n/react';
|
||||||
|
import { LoadingPage } from '../../loading_page';
|
||||||
|
|
||||||
|
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
|
||||||
|
import { euiStyled } from '../../../../../observability/public';
|
||||||
|
import { useTrialStatus } from '../../../hooks/use_trial_status';
|
||||||
|
|
||||||
|
export const SubscriptionSplashContent: React.FC = () => {
|
||||||
|
const { services } = useKibana();
|
||||||
|
const { loadState, isTrialAvailable, checkTrialAvailability } = useTrialStatus();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
checkTrialAvailability();
|
||||||
|
}, [checkTrialAvailability]);
|
||||||
|
|
||||||
|
if (loadState === 'pending') {
|
||||||
|
return (
|
||||||
|
<LoadingPage
|
||||||
|
message={i18n.translate('xpack.infra.logs.logAnalysis.splash.loadingMessage', {
|
||||||
|
defaultMessage: 'Checking license...',
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const canStartTrial = isTrialAvailable && loadState === 'resolved';
|
||||||
|
|
||||||
|
let title;
|
||||||
|
let description;
|
||||||
|
let cta;
|
||||||
|
|
||||||
|
if (canStartTrial) {
|
||||||
|
title = (
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.infra.logs.logAnalysis.splash.startTrialTitle"
|
||||||
|
defaultMessage="To access anomaly detection, start a free trial"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
description = (
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.infra.logs.logAnalysis.splash.startTrialDescription"
|
||||||
|
defaultMessage="Our free, 14-day trial includes machine learning features, which enable you to detect anomalies in your logs."
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
cta = (
|
||||||
|
<EuiButton
|
||||||
|
fullWidth={false}
|
||||||
|
fill
|
||||||
|
href={services.http.basePath.prepend('/app/management/stack/license_management')}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.infra.logs.logAnalysis.splash.startTrialCta"
|
||||||
|
defaultMessage="Start trial"
|
||||||
|
/>
|
||||||
|
</EuiButton>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
title = (
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.infra.logs.logAnalysis.splash.updateSubscriptionTitle"
|
||||||
|
defaultMessage="To access anomaly detection, upgrade to a Platinum Subscription"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
description = (
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.infra.logs.logAnalysis.splash.updateSubscriptionDescription"
|
||||||
|
defaultMessage="You must have a Platinum Subscription to use machine learning features."
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
cta = (
|
||||||
|
<EuiButton fullWidth={false} fill href="https://www.elastic.co/subscriptions">
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.infra.logs.logAnalysis.splash.updateSubscriptionCta"
|
||||||
|
defaultMessage="Upgrade subscription"
|
||||||
|
/>
|
||||||
|
</EuiButton>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SubscriptionPage>
|
||||||
|
<EuiPageBody>
|
||||||
|
<SubscriptionPageContent verticalPosition="center" horizontalPosition="center">
|
||||||
|
<EuiFlexGroup>
|
||||||
|
<EuiFlexItem>
|
||||||
|
<EuiTitle size="m">
|
||||||
|
<h2>{title}</h2>
|
||||||
|
</EuiTitle>
|
||||||
|
<EuiSpacer size="xl" />
|
||||||
|
<EuiText>
|
||||||
|
<p>{description}</p>
|
||||||
|
</EuiText>
|
||||||
|
<EuiSpacer />
|
||||||
|
<div>{cta}</div>
|
||||||
|
</EuiFlexItem>
|
||||||
|
<EuiFlexItem>
|
||||||
|
<EuiImage
|
||||||
|
alt={i18n.translate('xpack.infra.logs.logAnalysis.splash.splashImageAlt', {
|
||||||
|
defaultMessage: 'Placeholder image',
|
||||||
|
})}
|
||||||
|
url={services.http.basePath.prepend(
|
||||||
|
'/plugins/infra/assets/anomaly_chart_minified.svg'
|
||||||
|
)}
|
||||||
|
size="fullWidth"
|
||||||
|
/>
|
||||||
|
</EuiFlexItem>
|
||||||
|
</EuiFlexGroup>
|
||||||
|
<SubscriptionPageFooter>
|
||||||
|
<EuiTitle size="xs">
|
||||||
|
<h3>
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.infra.logs.logAnalysis.splash.learnMoreTitle"
|
||||||
|
defaultMessage="Want to learn more?"
|
||||||
|
/>
|
||||||
|
</h3>
|
||||||
|
</EuiTitle>
|
||||||
|
<EuiButtonEmpty
|
||||||
|
flush="left"
|
||||||
|
iconType="training"
|
||||||
|
target="_blank"
|
||||||
|
color="text"
|
||||||
|
href="https://www.elastic.co/guide/en/kibana/master/xpack-logs-analysis.html"
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id="xpack.infra.logs.logAnalysis.splash.learnMoreLink"
|
||||||
|
defaultMessage="Read documentation"
|
||||||
|
/>
|
||||||
|
</EuiButtonEmpty>
|
||||||
|
</SubscriptionPageFooter>
|
||||||
|
</SubscriptionPageContent>
|
||||||
|
</EuiPageBody>
|
||||||
|
</SubscriptionPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const SubscriptionPage = euiStyled(EuiPage)`
|
||||||
|
height: 100%
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SubscriptionPageContent = euiStyled(EuiPageContent)`
|
||||||
|
max-width: 768px !important;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SubscriptionPageFooter = euiStyled.div`
|
||||||
|
background: ${(props) => props.theme.eui.euiColorLightestShade};
|
||||||
|
margin: 0 -${(props) => props.theme.eui.paddingSizes.l} -${(props) =>
|
||||||
|
props.theme.eui.paddingSizes.l};
|
||||||
|
padding: ${(props) => props.theme.eui.paddingSizes.l};
|
||||||
|
`;
|
51
x-pack/plugins/infra/public/hooks/use_trial_status.tsx
Normal file
51
x-pack/plugins/infra/public/hooks/use_trial_status.tsx
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* 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 { boolean } from 'io-ts';
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useKibana } from '../../../../../src/plugins/kibana_react/public';
|
||||||
|
import { API_BASE_PATH as LICENSE_MANAGEMENT_API_BASE_PATH } from '../../../license_management/common/constants';
|
||||||
|
import { useTrackedPromise } from '../utils/use_tracked_promise';
|
||||||
|
import { decodeOrThrow } from '../../common/runtime_types';
|
||||||
|
|
||||||
|
interface UseTrialStatusState {
|
||||||
|
loadState: 'uninitialized' | 'pending' | 'resolved' | 'rejected';
|
||||||
|
isTrialAvailable: boolean;
|
||||||
|
checkTrialAvailability: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTrialStatus(): UseTrialStatusState {
|
||||||
|
const { services } = useKibana();
|
||||||
|
const [isTrialAvailable, setIsTrialAvailable] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const [loadState, checkTrialAvailability] = useTrackedPromise(
|
||||||
|
{
|
||||||
|
createPromise: async () => {
|
||||||
|
const response = await services.http.get(`${LICENSE_MANAGEMENT_API_BASE_PATH}/start_trial`);
|
||||||
|
return decodeOrThrow(boolean)(response);
|
||||||
|
},
|
||||||
|
onResolve: (response) => {
|
||||||
|
setIsTrialAvailable(response);
|
||||||
|
},
|
||||||
|
onReject: (error) => {
|
||||||
|
services.notifications.toasts.addDanger(
|
||||||
|
i18n.translate('xpack.infra.trialStatus.trialStatusNetworkErrorMessage', {
|
||||||
|
defaultMessage: 'We could not determine if the trial license is available',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[services]
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
loadState: loadState.state,
|
||||||
|
isTrialAvailable,
|
||||||
|
checkTrialAvailability,
|
||||||
|
};
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ import {
|
||||||
LogAnalysisSetupStatusUnknownPrompt,
|
LogAnalysisSetupStatusUnknownPrompt,
|
||||||
MissingResultsPrivilegesPrompt,
|
MissingResultsPrivilegesPrompt,
|
||||||
MissingSetupPrivilegesPrompt,
|
MissingSetupPrivilegesPrompt,
|
||||||
MlUnavailablePrompt,
|
SubscriptionSplashContent,
|
||||||
} from '../../../components/logging/log_analysis_setup';
|
} from '../../../components/logging/log_analysis_setup';
|
||||||
import { SourceErrorPage } from '../../../components/source_error_page';
|
import { SourceErrorPage } from '../../../components/source_error_page';
|
||||||
import { SourceLoadingPage } from '../../../components/source_loading_page';
|
import { SourceLoadingPage } from '../../../components/source_loading_page';
|
||||||
|
@ -50,7 +50,7 @@ export const LogEntryCategoriesPageContent = () => {
|
||||||
} else if (hasFailedLoadingSource) {
|
} else if (hasFailedLoadingSource) {
|
||||||
return <SourceErrorPage errorMessage={loadSourceFailureMessage ?? ''} retry={loadSource} />;
|
return <SourceErrorPage errorMessage={loadSourceFailureMessage ?? ''} retry={loadSource} />;
|
||||||
} else if (!hasLogAnalysisCapabilites) {
|
} else if (!hasLogAnalysisCapabilites) {
|
||||||
return <MlUnavailablePrompt />;
|
return <SubscriptionSplashContent />;
|
||||||
} else if (!hasLogAnalysisReadCapabilities) {
|
} else if (!hasLogAnalysisReadCapabilities) {
|
||||||
return <MissingResultsPrivilegesPrompt />;
|
return <MissingResultsPrivilegesPrompt />;
|
||||||
} else if (setupStatus.type === 'initializing') {
|
} else if (setupStatus.type === 'initializing') {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
LogAnalysisSetupStatusUnknownPrompt,
|
LogAnalysisSetupStatusUnknownPrompt,
|
||||||
MissingResultsPrivilegesPrompt,
|
MissingResultsPrivilegesPrompt,
|
||||||
MissingSetupPrivilegesPrompt,
|
MissingSetupPrivilegesPrompt,
|
||||||
MlUnavailablePrompt,
|
SubscriptionSplashContent,
|
||||||
} from '../../../components/logging/log_analysis_setup';
|
} from '../../../components/logging/log_analysis_setup';
|
||||||
import { SourceErrorPage } from '../../../components/source_error_page';
|
import { SourceErrorPage } from '../../../components/source_error_page';
|
||||||
import { SourceLoadingPage } from '../../../components/source_loading_page';
|
import { SourceLoadingPage } from '../../../components/source_loading_page';
|
||||||
|
@ -50,7 +50,7 @@ export const LogEntryRatePageContent = () => {
|
||||||
} else if (hasFailedLoadingSource) {
|
} else if (hasFailedLoadingSource) {
|
||||||
return <SourceErrorPage errorMessage={loadSourceFailureMessage ?? ''} retry={loadSource} />;
|
return <SourceErrorPage errorMessage={loadSourceFailureMessage ?? ''} retry={loadSource} />;
|
||||||
} else if (!hasLogAnalysisCapabilites) {
|
} else if (!hasLogAnalysisCapabilites) {
|
||||||
return <MlUnavailablePrompt />;
|
return <SubscriptionSplashContent />;
|
||||||
} else if (!hasLogAnalysisReadCapabilities) {
|
} else if (!hasLogAnalysisReadCapabilities) {
|
||||||
return <MissingResultsPrivilegesPrompt />;
|
return <MissingResultsPrivilegesPrompt />;
|
||||||
} else if (setupStatus.type === 'initializing') {
|
} else if (setupStatus.type === 'initializing') {
|
||||||
|
|
|
@ -17,7 +17,6 @@ import { HelpCenterContent } from '../../components/help_center_content';
|
||||||
import { AppNavigation } from '../../components/navigation/app_navigation';
|
import { AppNavigation } from '../../components/navigation/app_navigation';
|
||||||
import { RoutedTabs } from '../../components/navigation/routed_tabs';
|
import { RoutedTabs } from '../../components/navigation/routed_tabs';
|
||||||
import { ColumnarPage } from '../../components/page';
|
import { ColumnarPage } from '../../components/page';
|
||||||
import { useLogAnalysisCapabilitiesContext } from '../../containers/logs/log_analysis';
|
|
||||||
import { useLogSourceContext } from '../../containers/logs/log_source';
|
import { useLogSourceContext } from '../../containers/logs/log_source';
|
||||||
import { RedirectWithQueryParams } from '../../utils/redirect_with_query_params';
|
import { RedirectWithQueryParams } from '../../utils/redirect_with_query_params';
|
||||||
import { LogEntryCategoriesPage } from './log_entry_categories';
|
import { LogEntryCategoriesPage } from './log_entry_categories';
|
||||||
|
@ -28,7 +27,6 @@ import { AlertDropdown } from '../../components/alerting/logs/alert_dropdown';
|
||||||
|
|
||||||
export const LogsPageContent: React.FunctionComponent = () => {
|
export const LogsPageContent: React.FunctionComponent = () => {
|
||||||
const uiCapabilities = useKibana().services.application?.capabilities;
|
const uiCapabilities = useKibana().services.application?.capabilities;
|
||||||
const logAnalysisCapabilities = useLogAnalysisCapabilitiesContext();
|
|
||||||
|
|
||||||
const { initialize } = useLogSourceContext();
|
const { initialize } = useLogSourceContext();
|
||||||
|
|
||||||
|
@ -79,13 +77,7 @@ export const LogsPageContent: React.FunctionComponent = () => {
|
||||||
<AppNavigation aria-label={pageTitle}>
|
<AppNavigation aria-label={pageTitle}>
|
||||||
<EuiFlexGroup gutterSize={'none'} alignItems={'center'}>
|
<EuiFlexGroup gutterSize={'none'} alignItems={'center'}>
|
||||||
<EuiFlexItem>
|
<EuiFlexItem>
|
||||||
<RoutedTabs
|
<RoutedTabs tabs={[streamTab, logRateTab, logCategoriesTab, settingsTab]} />
|
||||||
tabs={
|
|
||||||
logAnalysisCapabilities.hasLogAnalysisCapabilites
|
|
||||||
? [streamTab, logRateTab, logCategoriesTab, settingsTab]
|
|
||||||
: [streamTab, settingsTab]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
<AlertDropdown />
|
<AlertDropdown />
|
||||||
|
|
Loading…
Reference in a new issue