Skip to content

Commit

Permalink
[Observability Onboarding] Update onboarding landing page (#194565)
Browse files Browse the repository at this point in the history
Resolves elastic/observability-dev#3775
Resolves #192949

## Summary

Updates the "add data" page according to new design

<img width="1448" alt="Screenshot 2024-10-01 at 12 36 15"
src="https://github.com/user-attachments/assets/1301a487-d3b9-4d6f-ad5d-f88d2cfc029d">

---------

Co-authored-by: kibanamachine <[email protected]>
  • Loading branch information
thomheymann and kibanamachine authored Oct 7, 2024
1 parent 84d9187 commit 28d6a22
Show file tree
Hide file tree
Showing 13 changed files with 308 additions and 290 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import type { FunctionComponent } from 'react';
import {
EuiAvatar,
EuiCheckableCard,
EuiFlexGroup,
EuiFlexItem,
Expand All @@ -21,12 +20,13 @@ import {
useGeneratedHtmlId,
useEuiTheme,
EuiBadge,
EuiFlexGrid,
} from '@elastic/eui';
import { css } from '@emotion/react';

import { useSearchParams } from 'react-router-dom-v5-compat';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { OnboardingFlowPackageList } from '../packages_list';
import { useCustomMargin } from '../shared/use_custom_margin';
import { Category } from './types';
import { useCustomCardsForCategory } from './use_custom_cards_for_category';
import { useVirtualSearchResults } from './use_virtual_search_results';
Expand All @@ -44,51 +44,63 @@ interface UseCaseOption {
export const OnboardingFlowForm: FunctionComponent = () => {
const options: UseCaseOption[] = [
{
id: 'logs',
id: 'host',
label: i18n.translate(
'xpack.observability_onboarding.experimentalOnboardingFlow.euiCheckableCard.collectAndAnalyzeMyLabel',
{ defaultMessage: 'Collect and analyze logs' }
'xpack.observability_onboarding.experimentalOnboardingFlow.euiCheckableCard.hostLabel',
{ defaultMessage: 'Host' }
),
description: i18n.translate(
'xpack.observability_onboarding.onboardingFlowForm.detectPatternsAndOutliersLabel',
'xpack.observability_onboarding.onboardingFlowForm.hostDescription',
{
defaultMessage:
'Detect patterns, gain insights from logs, get alerted when surpassing error thresholds',
'Monitor your host and the services running on it, set-up SLO, get alerted, remediate performance issues',
}
),
logos: ['azure', 'aws', 'nginx', 'gcp'],
showIntegrationsBadge: true,
logos: ['kubernetes', 'opentelemetry', 'apache', 'mysql'],
},
{
id: 'apm',
id: 'kubernetes',
label: i18n.translate(
'xpack.observability_onboarding.experimentalOnboardingFlow.euiCheckableCard.monitorMyApplicationPerformanceLabel',
{ defaultMessage: 'Monitor my application performance' }
'xpack.observability_onboarding.experimentalOnboardingFlow.euiCheckableCard.kubernetesLabel',
{ defaultMessage: 'Kubernetes' }
),
description: i18n.translate(
'xpack.observability_onboarding.onboardingFlowForm.captureAndAnalyzeDistributedLabel',
'xpack.observability_onboarding.onboardingFlowForm.kubernetesDescription',
{
defaultMessage:
'Catch application problems, get alerted on performance issues or SLO breaches, expedite root cause analysis and remediation',
'Observe your Kubernetes cluster, and your container workloads using logs, metrics, traces and profiling data',
}
),
logos: ['opentelemetry', 'java', 'javascript', 'dotnet'],
logos: ['kubernetes', 'opentelemetry'],
},
{
id: 'infra',
id: 'application',
label: i18n.translate(
'xpack.observability_onboarding.experimentalOnboardingFlow.euiCheckableCard.monitorMyInfrastructureLabel',
{ defaultMessage: 'Monitor infrastructure' }
'xpack.observability_onboarding.experimentalOnboardingFlow.euiCheckableCard.applicationLabel',
{ defaultMessage: 'Application' }
),
description: i18n.translate(
'xpack.observability_onboarding.onboardingFlowForm.builtOnPowerfulElasticsearchLabel',
'xpack.observability_onboarding.onboardingFlowForm.applicationDescription',
{
defaultMessage:
'Check my system’s health, get alerted on performance issues or SLO breaches, expedite root cause analysis and remediation',
'Monitor the frontend and backend application that you have developed, set-up synthetic monitors',
}
),
logos: ['kubernetes', 'prometheus', 'docker', 'opentelemetry'],
showIntegrationsBadge: true,
logos: ['opentelemetry', 'java', 'javascript', 'dotnet'],
},
{
id: 'cloud',
label: i18n.translate(
'xpack.observability_onboarding.experimentalOnboardingFlow.euiCheckableCard.cloudLabel',
{ defaultMessage: 'Cloud' }
),
description: i18n.translate(
'xpack.observability_onboarding.onboardingFlowForm.cloudDescription',
{
defaultMessage: 'Ingest telemetry data from the Cloud for your applications and services',
}
),
logos: ['azure', 'aws', 'gcp'],
},
];

Expand All @@ -97,7 +109,6 @@ export const OnboardingFlowForm: FunctionComponent = () => {
context: { isCloud },
},
} = useKibana<ObservabilityOnboardingAppServices>();
const customMargin = useCustomMargin();
const radioGroupId = useGeneratedHtmlId({ prefix: 'onboardingCategory' });
const categorySelectorTitleId = useGeneratedHtmlId();
const packageListTitleId = useGeneratedHtmlId();
Expand Down Expand Up @@ -152,33 +163,72 @@ export const OnboardingFlowForm: FunctionComponent = () => {

return (
<EuiPanel hasBorder paddingSize="xl">
<TitleWithIcon
id={categorySelectorTitleId}
iconType="createSingleMetricJob"
title={i18n.translate(
'xpack.observability_onboarding.experimentalOnboardingFlow.strong.startCollectingYourDataLabel',
{
defaultMessage: 'What do you want to monitor?',
}
)}
/>
<EuiSpacer size="m" />
<EuiFlexGroup
css={{ ...customMargin, maxWidth: '560px' }}
gutterSize="l"
direction="column"
role="group"
aria-labelledby={categorySelectorTitleId}
>
<EuiTitle size="s" id={categorySelectorTitleId}>
<strong>
{i18n.translate(
'xpack.observability_onboarding.experimentalOnboardingFlow.strong.startCollectingYourDataLabel',
{
defaultMessage: 'What do you want to monitor?',
}
)}
</strong>
</EuiTitle>
<EuiSpacer />
<EuiFlexGrid columns={2} role="group" aria-labelledby={categorySelectorTitleId}>
{options.map((option) => (
<EuiFlexItem
key={option.id}
data-test-subj={`observabilityOnboardingUseCaseCard-${option.id}`}
data-test-subj={`observabilityOnboardingUseCaseCard-${option.id}`} // EuiCheckableCard does not forward `data-test-subj` prop so using parent element instead
>
<EuiCheckableCard
id={`${radioGroupId}_${option.id}`}
name={radioGroupId}
label={<EuiText css={{ fontWeight: 'bold' }}>{option.label}</EuiText>}
label={
<>
<EuiText>
<strong>{option.label}</strong>
</EuiText>
{/* The description and logo icons are passed into `label` prop instead of `children` to ensure they are clickable */}
<EuiSpacer size="s" />
<EuiText
color="subdued"
size="s"
css={css`
flex-grow: 1; // Allow the description to grow to fill the space
`}
>
{option.description}
</EuiText>
{(option.logos || option.showIntegrationsBadge) && (
<>
<EuiSpacer size="m" />
<EuiFlexGroup
gutterSize="m"
responsive={false}
css={css`
flex-grow: 0; // Prevent the logos from growing to align to the bottom
`}
aria-hidden // Hide from screen readers as the logos are mainly decorative
>
{option.logos?.map((logo) => (
<EuiFlexItem key={logo} grow={false}>
<LogoIcon logo={logo} size="l" />
</EuiFlexItem>
))}
{option.showIntegrationsBadge && (
<EuiBadge color="hollow">
<FormattedMessage
defaultMessage="+ Integrations"
id="xpack.observability_onboarding.experimentalOnboardingFlow.form.addIntegrations"
description="A badge indicating that the user can add additional observability integrations to their deployment via this option"
/>
</EuiBadge>
)}
</EuiFlexGroup>
</>
)}
</>
}
checked={option.id === searchParams.get('category')}
/**
* onKeyDown and onKeyUp handlers disable
Expand All @@ -204,67 +254,79 @@ export const OnboardingFlowForm: FunctionComponent = () => {
);
}
}}
>
<EuiText color="subdued" size="s">
{option.description}
</EuiText>
{(option.logos || option.showIntegrationsBadge) && (
<>
<EuiSpacer size="m" />
<EuiFlexGroup gutterSize="s" responsive={false}>
{option.logos?.map((logo) => (
<EuiFlexItem key={logo} grow={false}>
<LogoIcon logo={logo} />
</EuiFlexItem>
))}
{option.showIntegrationsBadge && (
<EuiBadge color="hollow">
<FormattedMessage
defaultMessage="+ Integrations"
id="xpack.observability_onboarding.experimentalOnboardingFlow.form.addIntegrations"
description="A badge indicating that the user can add additional observability integrations to their deployment via this option"
/>
</EuiBadge>
)}
</EuiFlexGroup>
</>
)}
</EuiCheckableCard>
css={css`
flex-grow: 1;
& > .euiPanel {
display: flex;
& > .euiCheckableCard__label {
display: flex;
flex-direction: column;
}
}
`}
/>
</EuiFlexItem>
))}
</EuiFlexGroup>
</EuiFlexGrid>
{/* Hiding element instead of not rending these elements in order to preload available packages on page load */}
<div
hidden={!searchParams.get('category') || !customCards}
role="group"
aria-labelledby={packageListTitleId}
>
<EuiSpacer />
<EuiSpacer size="xxl" />
<div ref={suggestedPackagesRef}>
<TitleWithIcon
id={packageListTitleId}
iconType="savedObjectsApp"
title={i18n.translate(
'xpack.observability_onboarding.experimentalOnboardingFlow.whatTypeOfResourceLabel',
{
defaultMessage: 'What type of resource are you monitoring?',
}
)}
/>
<EuiSpacer size="s" />
<EuiTitle size="s" id={packageListTitleId}>
<strong>
{searchParams.get('category') === 'kubernetes'
? i18n.translate(
'xpack.observability_onboarding.experimentalOnboardingFlow.kubernetesPackagesTitle',
{
defaultMessage: 'Monitor your Kubernetes cluster using:',
}
)
: searchParams.get('category') === 'application'
? i18n.translate(
'xpack.observability_onboarding.experimentalOnboardingFlow.applicationPackagesTitle',
{
defaultMessage: 'Monitor your Application using:',
}
)
: searchParams.get('category') === 'cloud'
? i18n.translate(
'xpack.observability_onboarding.experimentalOnboardingFlow.cloudPackagesTitle',
{
defaultMessage: 'Select your Cloud provider:',
}
)
: i18n.translate(
'xpack.observability_onboarding.experimentalOnboardingFlow.hostPackagesTitle',
{
defaultMessage: 'Monitor your Host using:',
}
)}
</strong>
</EuiTitle>
<EuiSpacer size="m" />
<OnboardingFlowPackageList
customCards={customCards}
flowSearch={integrationSearch}
flowCategory={searchParams.get('category')}
/>
</div>
<div ref={searchResultsRef}>
<EuiText css={customMargin} size="s" color="subdued">
<FormattedMessage
id="xpack.observability_onboarding.experimentalOnboardingFlow.form.searchPromptText"
defaultMessage="Not seeing yours? Search through our 130 ways of ingesting data:"
/>
<EuiSpacer size="m" />
<EuiText size="s" color="subdued">
<strong>
<FormattedMessage
id="xpack.observability_onboarding.experimentalOnboardingFlow.form.searchPromptText"
defaultMessage="Search through other ways of ingesting data:"
/>
</strong>
</EuiText>
<EuiSpacer size="m" />
<OnboardingFlowPackageList
showSearchBar={true}
searchQuery={integrationSearch}
Expand All @@ -286,25 +348,6 @@ export const OnboardingFlowForm: FunctionComponent = () => {
);
};

interface TitleWithIconProps {
title: string;
iconType: string;
id?: string;
}

const TitleWithIcon: FunctionComponent<TitleWithIconProps> = ({ title, iconType, id }) => (
<EuiFlexGroup responsive={false} gutterSize="m" alignItems="center">
<EuiFlexItem grow={false}>
<EuiAvatar size="l" name={title} iconType={iconType} iconSize="l" color="subdued" />
</EuiFlexItem>
<EuiFlexItem>
<EuiTitle size="s" id={id}>
<strong>{title}</strong>
</EuiTitle>
</EuiFlexItem>
</EuiFlexGroup>
);

function scrollIntoViewWithOffset(element: HTMLElement, offset = 0) {
// Fixed header in Kibana is different height between serverless and stateful so need to calculate dynamically.
const fixedHeaders = document.querySelectorAll('#globalHeaderBars [data-fixed-header=true]');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
* 2.0.
*/

export type Category = 'apm' | 'infra' | 'logs';
export type Category = 'host' | 'kubernetes' | 'application' | 'cloud';
Loading

0 comments on commit 28d6a22

Please sign in to comment.