[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 './ml_unavailable_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,
|
||||
MissingResultsPrivilegesPrompt,
|
||||
MissingSetupPrivilegesPrompt,
|
||||
MlUnavailablePrompt,
|
||||
SubscriptionSplashContent,
|
||||
} from '../../../components/logging/log_analysis_setup';
|
||||
import { SourceErrorPage } from '../../../components/source_error_page';
|
||||
import { SourceLoadingPage } from '../../../components/source_loading_page';
|
||||
|
@ -50,7 +50,7 @@ export const LogEntryCategoriesPageContent = () => {
|
|||
} else if (hasFailedLoadingSource) {
|
||||
return <SourceErrorPage errorMessage={loadSourceFailureMessage ?? ''} retry={loadSource} />;
|
||||
} else if (!hasLogAnalysisCapabilites) {
|
||||
return <MlUnavailablePrompt />;
|
||||
return <SubscriptionSplashContent />;
|
||||
} else if (!hasLogAnalysisReadCapabilities) {
|
||||
return <MissingResultsPrivilegesPrompt />;
|
||||
} else if (setupStatus.type === 'initializing') {
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
LogAnalysisSetupStatusUnknownPrompt,
|
||||
MissingResultsPrivilegesPrompt,
|
||||
MissingSetupPrivilegesPrompt,
|
||||
MlUnavailablePrompt,
|
||||
SubscriptionSplashContent,
|
||||
} from '../../../components/logging/log_analysis_setup';
|
||||
import { SourceErrorPage } from '../../../components/source_error_page';
|
||||
import { SourceLoadingPage } from '../../../components/source_loading_page';
|
||||
|
@ -50,7 +50,7 @@ export const LogEntryRatePageContent = () => {
|
|||
} else if (hasFailedLoadingSource) {
|
||||
return <SourceErrorPage errorMessage={loadSourceFailureMessage ?? ''} retry={loadSource} />;
|
||||
} else if (!hasLogAnalysisCapabilites) {
|
||||
return <MlUnavailablePrompt />;
|
||||
return <SubscriptionSplashContent />;
|
||||
} else if (!hasLogAnalysisReadCapabilities) {
|
||||
return <MissingResultsPrivilegesPrompt />;
|
||||
} else if (setupStatus.type === 'initializing') {
|
||||
|
|
|
@ -17,7 +17,6 @@ import { HelpCenterContent } from '../../components/help_center_content';
|
|||
import { AppNavigation } from '../../components/navigation/app_navigation';
|
||||
import { RoutedTabs } from '../../components/navigation/routed_tabs';
|
||||
import { ColumnarPage } from '../../components/page';
|
||||
import { useLogAnalysisCapabilitiesContext } from '../../containers/logs/log_analysis';
|
||||
import { useLogSourceContext } from '../../containers/logs/log_source';
|
||||
import { RedirectWithQueryParams } from '../../utils/redirect_with_query_params';
|
||||
import { LogEntryCategoriesPage } from './log_entry_categories';
|
||||
|
@ -28,7 +27,6 @@ import { AlertDropdown } from '../../components/alerting/logs/alert_dropdown';
|
|||
|
||||
export const LogsPageContent: React.FunctionComponent = () => {
|
||||
const uiCapabilities = useKibana().services.application?.capabilities;
|
||||
const logAnalysisCapabilities = useLogAnalysisCapabilitiesContext();
|
||||
|
||||
const { initialize } = useLogSourceContext();
|
||||
|
||||
|
@ -79,13 +77,7 @@ export const LogsPageContent: React.FunctionComponent = () => {
|
|||
<AppNavigation aria-label={pageTitle}>
|
||||
<EuiFlexGroup gutterSize={'none'} alignItems={'center'}>
|
||||
<EuiFlexItem>
|
||||
<RoutedTabs
|
||||
tabs={
|
||||
logAnalysisCapabilities.hasLogAnalysisCapabilites
|
||||
? [streamTab, logRateTab, logCategoriesTab, settingsTab]
|
||||
: [streamTab, settingsTab]
|
||||
}
|
||||
/>
|
||||
<RoutedTabs tabs={[streamTab, logRateTab, logCategoriesTab, settingsTab]} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<AlertDropdown />
|
||||
|
|
Loading…
Reference in a new issue