[Logs onboarding] Add select logs step (#156182)

Closes #154941

<img width="1434" alt="image"
src="https://user-images.githubusercontent.com/1313018/236182563-e3c037ec-9ffb-49bb-9c05-a42882e3e66d.png">

---------

Co-authored-by: Oliver Gupte <oliver.gupte@elastic.co>
This commit is contained in:
Yngrid Coello 2023-05-04 14:26:16 +02:00 committed by GitHub
parent 5207e52895
commit 52b2e38da4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 422 additions and 64 deletions

View file

@ -5,10 +5,11 @@
* 2.0.
*/
import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useBreadcrumbs } from '@kbn/observability-plugin/public';
import React, { ComponentType, useRef, useState } from 'react';
import { breadcrumbsApp } from '../../../application/app';
import {
FilmstripFrame,
FilmstripTransition,
@ -16,8 +17,6 @@ import {
} from '../../shared/filmstrip_transition';
import { Provider as WizardProvider, Step as WizardStep } from './wizard';
import { HorizontalSteps } from './wizard/horizontal_steps';
import { PageTitle } from './wizard/page_title';
import { breadcrumbsApp } from '../../../application/app';
export function CustomLogs() {
useBreadcrumbs(
@ -62,7 +61,16 @@ function AnimatedTransitionsWizard() {
<EuiFlexGroup direction="column" alignItems="center">
<EuiFlexItem grow={false}>
<EuiSpacer size="l" />
<PageTitle />
<EuiTitle size="l">
<h1>
{i18n.translate(
'xpack.observability_onboarding.title.collectCustomLogs',
{
defaultMessage: 'Collect custom logs',
}
)}
</h1>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false} style={{ width: '50%' }}>
<HorizontalSteps />

View file

@ -0,0 +1,105 @@
/*
* 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 {
EuiButton,
EuiButtonEmpty,
EuiCallOut,
EuiFlexGroup,
EuiFlexItem,
EuiHorizontalRule,
EuiLoadingSpinner,
EuiSpacer,
EuiSteps,
EuiText,
} from '@elastic/eui';
import React from 'react';
import { useWizard } from '.';
import { useFetcher } from '../../../../hooks/use_fetcher';
import {
StepPanel,
StepPanelContent,
StepPanelFooter,
} from '../../../shared/step_panel';
export function CollectLogs() {
const { goToStep, goBack } = useWizard();
const { data } = useFetcher((callApi) => {
return callApi('GET /internal/observability_onboarding/get_status');
}, []);
function onContinue() {
goToStep('inspect');
}
function onBack() {
goBack();
}
return (
<StepPanel title="">
<StepPanelContent>
<EuiText color="subdued">
<p>
It might take a few minutes for the data to get to Elasticsearch. If
you&apos;re not seeing any, try generating some to verify. If
you&apos;re having trouble connecting, check out the troubleshooting
guide.
</p>
</EuiText>
<EuiSpacer size="m" />
<EuiCallOut>
<EuiFlexGroup justifyContent="flexStart" alignItems="center">
<EuiFlexItem grow={false}>
<EuiLoadingSpinner size="m" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText color="subdued">
<p>Listening for incoming logs</p>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiCallOut>
<EuiSpacer size="m" />
<EuiSteps
titleSize="xs"
steps={[
{ title: 'Ping received', status: data?.status, children: null },
{ title: 'File found', status: 'complete', children: null },
{
title: 'Downloading Elastic Agent',
status: 'loading',
children: null,
},
{
title: 'Starting Elastic Agent',
status: 'incomplete',
children: null,
},
]}
/>
<EuiHorizontalRule margin="l" />
<EuiFlexGroup justifyContent="center" alignItems="center">
<EuiFlexItem grow={false}>
<EuiButtonEmpty iconType="help">Need some help?</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexGroup>
</StepPanelContent>
<StepPanelFooter
items={[
<EuiButton color="ghost" fill onClick={onBack}>
Back
</EuiButton>,
<EuiButton color="primary" fill onClick={onContinue}>
Continue
</EuiButton>,
]}
/>
</StepPanel>
);
}

View file

@ -5,12 +5,13 @@
* 2.0.
*/
import React from 'react';
import { EuiStepsHorizontal } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { useWizard } from '.';
export function HorizontalSteps() {
const { getPath } = useWizard();
const { getPath, goToStep } = useWizard();
const [currentStep, ...previousSteps] = getPath().reverse();
function getStatus(stepKey: ReturnType<typeof getPath>[0]) {
@ -23,28 +24,63 @@ export function HorizontalSteps() {
return 'incomplete';
}
function isDisabled(stepKey: ReturnType<typeof getPath>[0]) {
return getStatus(stepKey) === 'incomplete';
}
return (
<EuiStepsHorizontal
steps={[
{
title: 'Name logs',
status: getStatus('nameLogs'),
onClick: () => {},
title: i18n.translate(
'xpack.observability_onboarding.steps.selectLogs',
{
defaultMessage: 'Select logs',
}
),
status: getStatus('selectLogs'),
onClick: () => {
goToStep('selectLogs');
},
},
{
title: 'Configure logs',
title: i18n.translate(
'xpack.observability_onboarding.steps.configureLogs',
{
defaultMessage: 'Configure logs',
}
),
status: getStatus('configureLogs'),
onClick: () => {},
disabled: isDisabled('configureLogs'),
onClick: () => {
goToStep('configureLogs');
},
},
{
title: 'Install shipper',
title: i18n.translate(
'xpack.observability_onboarding.steps.installShipper',
{
defaultMessage: 'Install shipper',
}
),
status: getStatus('installElasticAgent'),
onClick: () => {},
disabled: isDisabled('installElasticAgent'),
onClick: () => {
goToStep('installElasticAgent');
},
},
{
title: 'Import data',
status: getStatus('importData'),
onClick: () => {},
title: i18n.translate(
'xpack.observability_onboarding.steps.collectLogs',
{
defaultMessage: 'Collect logs',
}
),
status: getStatus('collectLogs'),
disabled: isDisabled('collectLogs'),
onClick: () => {
goToStep('collectLogs');
},
},
]}
/>

View file

@ -26,7 +26,7 @@ import {
StepPanelFooter,
} from '../../../shared/step_panel';
export function ImportData() {
export function CollectLogs() {
const { goToStep, goBack } = useWizard();
const { data } = useFetcher((callApi) => {

View file

@ -5,11 +5,11 @@
* 2.0.
*/
import { NameLogs } from './name_logs';
import { ConfigureLogs } from './configure_logs';
import { SelectLogs } from './select_logs';
import { InstallElasticAgent } from './install_elastic_agent';
import { createWizardContext } from '../../../../context/create_wizard_context';
import { ImportData } from './import_data';
import { CollectLogs } from './collect_logs';
import { Inspect } from './inspect';
interface WizardState {
@ -45,12 +45,12 @@ const initialState: WizardState = {
const { Provider, Step, useWizard } = createWizardContext({
initialState,
initialStep: 'nameLogs',
initialStep: 'selectLogs',
steps: {
nameLogs: NameLogs,
selectLogs: SelectLogs,
configureLogs: ConfigureLogs,
installElasticAgent: InstallElasticAgent,
importData: ImportData,
collectLogs: CollectLogs,
inspect: Inspect,
},
});

View file

@ -39,7 +39,7 @@ export function InstallElasticAgent() {
function onContinue() {
setState({ ...getState(), elasticAgentPlatform, alternativeShippers });
goToStep('importData');
goToStep('collectLogs');
}
function createAlternativeShipperToggle(

View file

@ -1,37 +0,0 @@
/*
* 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 { EuiTitle } from '@elastic/eui';
import { useWizard } from '.';
export function PageTitle() {
const { getPath } = useWizard();
const [currentStep] = getPath().reverse();
if (currentStep === 'installElasticAgent') {
return (
<EuiTitle size="l">
<h1>Select your shipper</h1>
</EuiTitle>
);
}
if (currentStep === 'importData') {
return (
<EuiTitle size="l">
<h1>Incoming logs</h1>
</EuiTitle>
);
}
return (
<EuiTitle size="l">
<h1>Collect and analyze my logs</h1>
</EuiTitle>
);
}

View file

@ -0,0 +1,242 @@
/*
* 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.
*/
/* eslint-disable @elastic/eui/href-or-on-click */
import React, { PropsWithChildren, MouseEvent } from 'react';
import {
EuiTitle,
EuiLink,
EuiButton,
EuiFlexGroup,
EuiFlexItem,
EuiHorizontalRule,
EuiSpacer,
EuiCard,
EuiIcon,
EuiIconProps,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import {
StepPanel,
StepPanelContent,
StepPanelFooter,
} from '../../../shared/step_panel';
import { useWizard } from '.';
import { useKibanaNavigation } from '../../../../hooks/use_kibana_navigation';
export function SelectLogs() {
const { navigateToKibanaUrl, navigateToAppUrl } = useKibanaNavigation();
const { goToStep, getState, setState } = useWizard();
function onBack() {
navigateToKibanaUrl('/app/observabilityOnboarding');
}
return (
<StepPanel
title={i18n.translate(
'xpack.observability_onboarding.selectLogs.chooseType',
{
defaultMessage: 'What logs do you want to collect?',
}
)}
>
<StepPanelContent>
<EuiFlexGroup>
<EuiFlexItem grow={false} style={{ width: '50%' }}>
<OptionCard
title={i18n.translate(
'xpack.observability_onboarding.selectLogs.streamLogFiles',
{
defaultMessage: 'Stream log files',
}
)}
iconType="desktop"
onClick={() => {
setState({ ...getState(), logsType: 'log-file' });
goToStep('configureLogs');
}}
description={i18n.translate(
'xpack.observability_onboarding.selectLogs.streamLogFiles.description',
{
defaultMessage: 'Stream your log file or directory.',
}
)}
/>
</EuiFlexItem>
</EuiFlexGroup>
<EuiHorizontalRule margin="l" />
<LogsTypeSection
title={i18n.translate(
'xpack.observability_onboarding.selectLogs.networkStreamingLogs',
{
defaultMessage: 'Network streaming logs',
}
)}
>
<EuiFlexGroup>
<EuiFlexItem>
<OptionCard
title={i18n.translate(
'xpack.observability_onboarding.selectLogs.sysLog',
{
defaultMessage: 'TCP/UDP/Syslog',
}
)}
iconType="documents"
onClick={() => {}}
description={i18n.translate(
'xpack.observability_onboarding.selectLogs.sysLog.description',
{
defaultMessage:
'Stream logs over TCP or UDP ports or from your syslog server.',
}
)}
/>
</EuiFlexItem>
<EuiFlexItem>
<OptionCard
title={i18n.translate(
'xpack.observability_onboarding.selectLogs.httpEndpointLogs',
{
defaultMessage: 'HTTP Endpoint',
}
)}
iconType="documents"
onClick={() => {}}
description={i18n.translate(
'xpack.observability_onboarding.selectLogs.httpEndpointLogs.description',
{
defaultMessage:
'Collect JSON data from listening HTTP port.',
}
)}
/>
</EuiFlexItem>
</EuiFlexGroup>
</LogsTypeSection>
<EuiHorizontalRule margin="l" />
<LogsTypeSection
title={i18n.translate(
'xpack.observability_onboarding.selectLogs.other',
{
defaultMessage: 'Other',
}
)}
>
<EuiFlexGroup>
<EuiFlexItem>
<OptionCard
title={i18n.translate(
'xpack.observability_onboarding.selectLogs.uploadLogFiles',
{
defaultMessage: 'Upload log files',
}
)}
iconType="exportAction"
onClick={() => {}}
description={i18n.translate(
'xpack.observability_onboarding.selectLogs.uploadLogFiles.description',
{
defaultMessage:
'Upload data from a CSV, TSV, JSON or other log file type for analysis.',
}
)}
/>
</EuiFlexItem>
<EuiFlexItem>
<OptionCard
title={i18n.translate(
'xpack.observability_onboarding.selectLogs.useOwnShipper',
{
defaultMessage: 'Get an API key',
}
)}
iconType="package"
onClick={() => {}}
description={i18n.translate(
'xpack.observability_onboarding.selectLogs.useOwnShipper.description',
{
defaultMessage:
'Use your own shipper to collect logs data by generating an API key.',
}
)}
/>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="m" />
<EuiLink
href="#"
target="_blank"
onClick={(event: MouseEvent) => {
event.preventDefault();
navigateToAppUrl('/integrations/browse/observability');
}}
>
{i18n.translate(
'xpack.observability_onboarding.exploreOtherIntegrations',
{
defaultMessage: 'Explore other integrations',
}
)}
</EuiLink>
</LogsTypeSection>
</StepPanelContent>
<StepPanelFooter
items={[
<EuiButton color="ghost" fill onClick={onBack}>
{i18n.translate('xpack.observability_onboarding.steps.back', {
defaultMessage: 'Back',
})}
</EuiButton>,
<></>,
]}
/>
</StepPanel>
);
}
function LogsTypeSection({
title,
children,
}: PropsWithChildren<{ title: string }>) {
return (
<>
<EuiTitle size="s">
<h3>{title}</h3>
</EuiTitle>
<EuiSpacer size="m" />
{children}
</>
);
}
function OptionCard({
title,
iconType,
onClick,
description,
}: {
title: string;
iconType: EuiIconProps['type'];
onClick: () => void;
description: string;
}) {
return (
<EuiCard
layout="horizontal"
icon={<EuiIcon type={iconType} size="l" />}
title={title}
titleSize="xs"
paddingSize="m"
onClick={onClick}
hasBorder={true}
description={description}
/>
);
}

View file

@ -25,7 +25,7 @@ import { breadcrumbsApp } from '../../../application/app';
export function Home() {
useBreadcrumbs([], breadcrumbsApp);
const navigateToKibanaUrl = useKibanaNavigation();
const { navigateToKibanaUrl } = useKibanaNavigation();
const handleClickSystemLogs = () => {};
const handleClickCustomLogs = () => {

View file

@ -15,13 +15,17 @@ interface ObservabilityOnboardingAppServices {
export function useKibanaNavigation() {
const {
application: { navigateToUrl },
application: { navigateToUrl, navigateToApp },
http: { basePath },
} = useKibana<ObservabilityOnboardingAppServices>().services;
const navigateToKibanaUrl = (kibanaPath: string) => {
navigateToUrl(basePath.prepend(kibanaPath));
navigateToUrl(basePath.prepend(kibanaPath), {});
};
return navigateToKibanaUrl;
const navigateToAppUrl = (path: string) => {
navigateToApp('', { path, openInNewTab: true });
};
return { navigateToKibanaUrl, navigateToAppUrl };
}