[Logs onboarding] UI changes in custom logs onboarding flow (#162148)

Relates to https://github.com/elastic/kibana/issues/159655.

### Changes

This PR include the following changes:

#### ConfigureLogs step

- [x]  Change page title into “Stream log files to Elastic”
- [x] Remove stepper
- [x] Remove ’Stream log files to Elastic’ title inside the white box
- [x] Add tooltip to Dataset name with the text “Provide a dataset name
to help identify the source of your logs in future uses. Defaults to the
name of the log file.”
- [x] Add Dataset name input placeholder with “Give your logs a name”
- [x] Change helper text on Dataset name input to “All lowercase, max
100 chars, special characters will be replaced with ‘_’.”
- [x] Add tooltip to Service name with the text “Provide a service name
to allow for distributed services running on multiple hosts to correlate
the related instances.”
- [x] Add Service name input placeholder with “Give your service a name”
- [x] Add tooltip to Namespace (under advanced settings) with the text
“Provide a namespace to customize the grouping of your logs. Defaults to
the default namespace."

##### Before
<img width="1691" alt="image"
src="1b047624-1160-40eb-85ee-199d0874c805">

##### After
<img width="1690" alt="image"
src="572d7615-1363-4892-9b78-994f393a3ebe">


#### InstallShipper step

- [x] Change page title into “Install shipper to collect logs”
- [x] Remove stepper
- [x] Remove ’Install shipper to collect data’ title inside the white
box
- [x] Change first paragraph with “To collect the data from your system
and stream it to Elastic, you first need to install a shipping tool on
the machine generating the logs. In this case, the shipper is an Agent
developed by Elastic.”
- [x] Change text in first step (Install the Elastic agent) with “Select
your platform, and run the install command in your terminal to enroll
and start the Elastic Agent. Do this for each host. Review host
requirements and other installation options before installing.”
- [x] “Host requirements…” should open a link in a new tab to:
[https://www.elastic.co/guide/en/fleet/8.7/elastic-agent-installation.html](https://www.elastic.co/guide/en/fleet/8.7/install-standalone-elastic-agent.html)
- [x] Move up automatic config download switch before the agent download
code block
- [x] Change switch text to “Automatically download the agent’s config”
and add tooltip: “Turn on to add a string to the following code block
that downloads the agent's standard configuration to your host during
installation. Turn off to manually configure the agent in the next
step.”
- [x] When the users turn on the switch, we need to show a callout with
the following text: “Automatically downloading the agent config will
overwrite any existing agent config on your host.”
- [x] During the completion of the first step ‘Install the Elastic
agent’ provide users with callouts that appear as things happen: first
Elastic agent download, then Elastic agent extracted… and so on
- [x] If the user has the switch on (to automatically download the
config), they should also receive the callout confirmation that the
config was written to the yml file
- [x] Change paragraph text of ‘Configure the Elastic agent’ step to
“Add the following configuration to the elastic-agent.yml on the host
where you installed the Elastic agent.”
- [x] Change step 3 titles to “Ship logs to Elastic Observability”
(default state), “Waiting for Logs to be shipped...” (Loading state) and
“Logs are being shipped!” (Success state)
- [x] Change the style of ‘back’ button to Empty + add arrowLeft icon
with primary color
- ~~[ ] Change ‘Inspect’ button with default style, primary color. The
button should become active only when the full installation flow is
finished~~
- ~~[ ] Open the inspect of the installation in a flyout to avoid
interrupting the user flow~~

##### Before
<img width="1674" alt="image"
src="9c0539a3-6cde-4029-a6d3-2978f91b40de">

##### After
<img width="1671" alt="image"
src="84775312-fb5b-4646-90de-6268dec69246">

### Video


e8ae7067-604f-48fd-9b3d-7e7c0791df38
This commit is contained in:
Yngrid Coello 2023-07-19 16:16:24 +02:00 committed by GitHub
parent 0fd8a1196e
commit 06cfd36787
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 234 additions and 165 deletions

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { EuiButton } from '@elastic/eui';
import { EuiButtonEmpty } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { useHistory } from 'react-router-dom';
@ -16,14 +16,15 @@ export function BackButton({ onBack }: { onBack: () => void }) {
const history = useHistory();
return (
<EuiButton
color="text"
<EuiButtonEmpty
iconType="arrowLeft"
color="primary"
onClick={onBack}
disabled={history.length === 1 || getPath().length === 1}
>
{i18n.translate('xpack.observability_onboarding.steps.back', {
defaultMessage: 'Back',
})}
</EuiButton>
</EuiButtonEmpty>
);
}

View file

@ -16,6 +16,7 @@ import {
EuiForm,
EuiFormRow,
EuiHorizontalRule,
EuiIconTip,
EuiLink,
EuiSpacer,
EuiText,
@ -97,12 +98,6 @@ export function ConfigureLogs() {
return (
<StepPanel
title={i18n.translate(
'xpack.observability_onboarding.configureLogs.title',
{
defaultMessage: 'Stream log files to Elastic',
}
)}
panelFooter={
<StepPanelFooter
items={[
@ -201,17 +196,39 @@ export function ConfigureLogs() {
</EuiFlexGroup>
<EuiSpacer size="s" />
<EuiFormRow
label={i18n.translate(
'xpack.observability_onboarding.configureLogs.dataset.name',
{
defaultMessage: 'Dataset name',
}
)}
label={
<EuiFlexGroup
alignItems="center"
gutterSize="xs"
responsive={false}
>
<EuiFlexItem grow={false}>
{i18n.translate(
'xpack.observability_onboarding.configureLogs.dataset.name',
{
defaultMessage: 'Dataset name',
}
)}
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiIconTip
content={i18n.translate(
'xpack.observability_onboarding.configureLogs.dataset.name.tooltip',
{
defaultMessage:
'Provide a dataset name to help identify the source of your logs in future uses. Defaults to the name of the log file.',
}
)}
position="right"
/>
</EuiFlexItem>
</EuiFlexGroup>
}
helpText={i18n.translate(
'xpack.observability_onboarding.configureLogs.dataset.helper',
{
defaultMessage:
"Pick a name for your logs. All lowercase, max 100 chars, special characters will be replaced with '_'.",
"All lowercase, max 100 chars, special characters will be replaced with '_'.",
}
)}
isInvalid={isDatasetNameInvalid}
@ -221,7 +238,7 @@ export function ConfigureLogs() {
placeholder={i18n.translate(
'xpack.observability_onboarding.configureLogs.dataset.placeholder',
{
defaultMessage: 'Dataset name',
defaultMessage: 'Give your logs a name',
}
)}
value={datasetName}
@ -234,12 +251,34 @@ export function ConfigureLogs() {
</EuiFormRow>
<EuiSpacer size="m" />
<OptionalFormRow
label={i18n.translate(
'xpack.observability_onboarding.configureLogs.serviceName',
{
defaultMessage: 'Service name',
}
)}
label={
<EuiFlexGroup
alignItems="center"
gutterSize="xs"
responsive={false}
>
<EuiFlexItem grow={false}>
{i18n.translate(
'xpack.observability_onboarding.configureLogs.serviceName',
{
defaultMessage: 'Service name',
}
)}
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiIconTip
content={i18n.translate(
'xpack.observability_onboarding.configureLogs.serviceName.tooltip',
{
defaultMessage:
'Provide a service name to allow for distributed services running on multiple hosts to correlate the related instances.',
}
)}
position="right"
/>
</EuiFlexItem>
</EuiFlexGroup>
}
helpText={
<FormattedMessage
id="xpack.observability_onboarding.configureLogs.serviceName.helper"
@ -251,7 +290,7 @@ export function ConfigureLogs() {
placeholder={i18n.translate(
'xpack.observability_onboarding.configureLogs.serviceName.placeholder',
{
defaultMessage: 'Give a name to your service',
defaultMessage: 'Give your service a name',
}
)}
value={serviceName}
@ -287,12 +326,34 @@ export function ConfigureLogs() {
>
<EuiSpacer size="l" />
<EuiFormRow
label={i18n.translate(
'xpack.observability_onboarding.configureLogs.namespace',
{
defaultMessage: 'Namespace',
}
)}
label={
<EuiFlexGroup
alignItems="center"
gutterSize="xs"
responsive={false}
>
<EuiFlexItem grow={false}>
{i18n.translate(
'xpack.observability_onboarding.configureLogs.namespace',
{
defaultMessage: 'Namespace',
}
)}
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiIconTip
content={i18n.translate(
'xpack.observability_onboarding.configureLogs.namespace.tooltip',
{
defaultMessage:
'Provide a namespace to customize the grouping of your logs. Defaults to the default namespace.',
}
)}
position="right"
/>
</EuiFlexItem>
</EuiFlexGroup>
}
helpText={
<FormattedMessage
id="xpack.observability_onboarding.configureLogs.namespace.helper"

View file

@ -1,75 +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 { EuiStepsHorizontal } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { useWizard } from '.';
export function HorizontalSteps() {
const { getPath, goToStep } = useWizard();
const [currentStep, ...previousSteps] = getPath().reverse();
function getStatus(stepKey: ReturnType<typeof getPath>[0]) {
if (currentStep === stepKey) {
return 'current';
}
if (previousSteps.includes(stepKey)) {
return 'complete';
}
return 'incomplete';
}
function isDisabled(stepKey: ReturnType<typeof getPath>[0]) {
return getStatus(stepKey) === 'incomplete';
}
return (
<EuiStepsHorizontal
steps={[
{
title: i18n.translate(
'xpack.observability_onboarding.steps.selectLogs',
{
defaultMessage: 'Select logs',
}
),
status: getStatus('selectLogs'),
onClick: () => {
goToStep('selectLogs');
},
},
{
title: i18n.translate(
'xpack.observability_onboarding.steps.configureLogs',
{
defaultMessage: 'Configure logs',
}
),
status: getStatus('configureLogs'),
disabled: isDisabled('configureLogs'),
onClick: () => {
goToStep('configureLogs');
},
},
{
title: i18n.translate(
'xpack.observability_onboarding.steps.installShipper',
{
defaultMessage: 'Install shipper',
}
),
status: getStatus('installElasticAgent'),
disabled: isDisabled('installElasticAgent'),
onClick: () => {
goToStep('installElasticAgent');
},
},
]}
/>
);
}

View file

@ -5,8 +5,11 @@
* 2.0.
*/
import { ComponentType } from 'react';
import { createWizardContext } from '../../../../context/create_wizard_context';
import { i18n } from '@kbn/i18n';
import {
createWizardContext,
Step,
} from '../../../../context/create_wizard_context';
import { ConfigureLogs } from './configure_logs';
import { Inspect } from './inspect';
import { InstallElasticAgent } from './install_elastic_agent';
@ -51,11 +54,19 @@ export type CustomLogsSteps =
| 'installElasticAgent'
| 'inspect';
const steps: Record<CustomLogsSteps, ComponentType<{}>> = {
selectLogs: SelectLogs,
configureLogs: ConfigureLogs,
installElasticAgent: InstallElasticAgent,
inspect: Inspect,
const steps: Record<CustomLogsSteps, Step> = {
selectLogs: { component: SelectLogs },
configureLogs: { component: ConfigureLogs },
installElasticAgent: {
component: InstallElasticAgent,
title: i18n.translate(
'xpack.observability_onboarding.customLogs.installShipper.title',
{
defaultMessage: 'Install shipper to collect logs',
}
),
},
inspect: { component: Inspect },
};
const {
@ -64,7 +75,7 @@ const {
routes: customLogsRoutes,
} = createWizardContext({
initialState,
initialStep: 'selectLogs',
initialStep: 'configureLogs',
steps,
basePath: '/customLogs',
});

View file

@ -9,9 +9,12 @@ import {
EuiButton,
EuiButtonEmpty,
EuiButtonGroup,
EuiCallOut,
EuiCodeBlock,
EuiFlexGroup,
EuiFlexItem,
EuiIconTip,
EuiLink,
EuiSkeletonRectangle,
EuiSpacer,
EuiSteps,
@ -20,6 +23,7 @@ import {
EuiText,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { Buffer } from 'buffer';
import { flatten, zip } from 'lodash';
import { default as React, useCallback, useEffect, useState } from 'react';
@ -245,10 +249,6 @@ export function InstallElasticAgent() {
return (
<StepPanel
title={i18n.translate(
'xpack.observability_onboarding.installElasticAgent.title',
{ defaultMessage: 'Install shipper to collect data' }
)}
panelFooter={
<StepPanelFooter
items={[
@ -287,7 +287,7 @@ export function InstallElasticAgent() {
'xpack.observability_onboarding.installElasticAgent.description',
{
defaultMessage:
'Add Elastic Agent to your hosts to begin sending data to your Elastic Cloud. Run standalone if you want to download and manage each agent configuration file on your own, or enroll in Fleet, for centralized management of all your agents through our Fleet managed interface.',
'To collect the data from your system and stream it to Elastic, you first need to install a shipping tool on the machine generating the logs. In this case, the shipper is an Agent developed by Elastic.',
}
)}
</p>
@ -328,16 +328,83 @@ export function InstallElasticAgent() {
<>
<EuiText color="subdued">
<p>
{i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.description',
{
defaultMessage:
'Select a platform and run the command to install in your Terminal, enroll, and start the Elastic Agent. Do this for each host. For other platforms, see our downloads page. Review host requirements and other installation options.',
}
)}
<FormattedMessage
id="xpack.observability_onboarding.installElasticAgent.installStep.description"
defaultMessage="Select your platform, and run the install command in your terminal to enroll and start the Elastic Agent. Do this for each host. Review {hostRequirementsLink} before installing."
values={{
hostRequirementsLink: (
<EuiLink
external
href="https://www.elastic.co/guide/en/fleet/8.7/elastic-agent-installation.html"
>
{i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.hostRequirements',
{
defaultMessage:
'host requirements and other installation options',
}
)}
</EuiLink>
),
}}
/>
</p>
</EuiText>
<EuiSpacer size="m" />
<EuiSpacer size="l" />
<EuiSwitch
label={
<EuiFlexGroup
alignItems="center"
gutterSize="xs"
responsive={false}
>
<EuiFlexItem grow={false}>
{i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.autoDownloadConfig',
{
defaultMessage:
"Automatically download the agent's config",
}
)}
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiIconTip
content={i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.autoDownloadConfig.tooltip',
{
defaultMessage:
"Turn on to add a string to the following code block that downloads the agent's standard configuration to your host during installation. Turn off to manually configure the agent in the next step.",
}
)}
position="right"
/>
</EuiFlexItem>
</EuiFlexGroup>
}
checked={wizardState.autoDownloadConfig}
onChange={onAutoDownloadConfig}
disabled={
isInstallStarted ||
(monitoringRole && !monitoringRole?.hasPrivileges)
}
/>
<EuiSpacer size="l" />
{wizardState.autoDownloadConfig && (
<>
<EuiCallOut
title={i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.autoDownloadConfig.overwriteWarning',
{
defaultMessage:
'Automatically downloading the agent config will overwrite any existing agent config on your host.',
}
)}
color="warning"
iconType="warning"
/>
<EuiSpacer size="l" />
</>
)}
<EuiButtonGroup
isFullWidth
legend={i18n.translate(
@ -388,18 +455,6 @@ export function InstallElasticAgent() {
})}
</EuiCodeBlock>
<EuiSpacer size="m" />
<EuiSwitch
label={i18n.translate(
'xpack.observability_onboarding.installElasticAgent.installStep.autoDownloadConfig',
{ defaultMessage: 'Auto download config' }
)}
checked={wizardState.autoDownloadConfig}
onChange={onAutoDownloadConfig}
disabled={
isInstallStarted ||
(monitoringRole && !monitoringRole?.hasPrivileges)
}
/>
{isInstallStarted && (
<>
<EuiSpacer size="m" />
@ -516,7 +571,7 @@ export function InstallElasticAgent() {
'xpack.observability_onboarding.installElasticAgent.configStep.manual.description',
{
defaultMessage:
'Copy the config below to the elastic agent.yml on the host where the Elastic Agent is installed ({configPath}).',
'Add the following configuration to {configPath} on the host where you installed the Elastic agent.',
values: {
configPath:
'/opt/Elastic/Agent/elastic-agent.yml',
@ -578,11 +633,11 @@ export function InstallElasticAgent() {
id: 'logs-ingest',
incompleteTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.logsIngest.incompleteTitle',
{ defaultMessage: 'Check for shipped logs' }
{ defaultMessage: 'Ship logs to Elastic Observability' }
),
loadingTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.logsIngest.loadingTitle',
{ defaultMessage: 'Waiting for logs to be shipped' }
{ defaultMessage: 'Waiting for Logs to be shipped...' }
),
completedTitle: i18n.translate(
'xpack.observability_onboarding.installElasticAgent.progress.logsIngest.completedTitle',

View file

@ -127,7 +127,7 @@ export function Home() {
}
style={{
borderColor: euiTheme.colors.accent,
borderWidth: '2px',
borderWidth: 2,
}}
paddingSize="l"
display="plain"

View file

@ -17,7 +17,7 @@ import {
} from '@elastic/eui';
interface StepPanelProps {
title: string;
title?: string;
panelProps?: EuiPanelProps;
panelFooter?: ReactNode;
children?: ReactNode;
@ -29,12 +29,19 @@ export function StepPanel(props: StepPanelProps) {
return (
<>
<EuiPanel {...panelProps}>
<EuiFlexGroup direction="column">
<EuiFlexItem>
<EuiTitle size="m">
<h2>{title}</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexGroup direction="column" gutterSize="none">
{title ? (
<>
<EuiFlexItem>
<EuiTitle size="m">
<h2>{title}</h2>
</EuiTitle>
</EuiFlexItem>
<EuiSpacer size="m" />
</>
) : (
<EuiSpacer size="s" />
)}
{children}
</EuiFlexGroup>
</EuiPanel>

View file

@ -38,6 +38,11 @@ export interface WizardContext<T, StepKey extends string> {
};
}
export interface Step {
component: ComponentType;
title?: string;
}
export function createWizardContext<
T,
StepKey extends string,
@ -50,7 +55,7 @@ export function createWizardContext<
}: {
initialState: T;
initialStep: InitialStepKey;
steps: Record<StepKey, ComponentType>;
steps: Record<StepKey, Step>;
basePath: string;
}) {
const context = createContext<WizardContext<T, StepKey>>({
@ -70,7 +75,7 @@ export function createWizardContext<
stepKey === initialStep ? basePath : `${basePath}/${stepKey}`;
const routes = Object.entries(steps).reduce((acc, pair) => {
const [key, value] = pair as Entry<Record<StepKey, ComponentType>>;
const [key, value] = pair as Entry<Record<StepKey, Step>>;
return {
...acc,
[stepRoute(key)]: {
@ -78,7 +83,7 @@ export function createWizardContext<
handler: () =>
Page({
step: key,
Component: value,
Component: value.component,
}),
},
};
@ -109,6 +114,7 @@ export function createWizardContext<
onChangeStep?: (stepChangeEvent: {
direction: 'back' | 'next';
stepKey: StepKey;
stepTitle?: string;
StepComponent: ComponentType;
}) => void;
transitionDuration?: number;
@ -148,7 +154,8 @@ export function createWizardContext<
onChangeStep({
direction: stepVisited ? 'back' : 'next',
stepKey,
StepComponent: steps[stepKey],
stepTitle: steps[stepKey].title,
StepComponent: steps[stepKey].component,
});
}
},

View file

@ -10,7 +10,6 @@ import { i18n } from '@kbn/i18n';
import { useBreadcrumbs } from '@kbn/observability-shared-plugin/public';
import React, { ComponentType, useRef, useState } from 'react';
import { breadcrumbsApp } from '../../application/app';
import { HorizontalSteps } from '../../components/app/custom_logs/wizard/horizontal_steps';
import { Provider as WizardProvider } from '../../components/app/custom_logs/wizard';
import {
FilmstripFrame,
@ -28,7 +27,7 @@ export function CustomLogs({ children }: Props) {
{
text: i18n.translate(
'xpack.observability_onboarding.breadcrumbs.customLogs',
{ defaultMessage: 'Custom Logs' }
{ defaultMessage: 'Stream log files' }
),
},
],
@ -41,16 +40,20 @@ const TRANSITION_DURATION = 180;
function AnimatedTransitionsWizard({ children }: Props) {
const [transition, setTransition] = useState<TransitionState>('ready');
const [title, setTitle] = useState<string>();
const TransitionComponent = useRef<ComponentType>(() => null);
function onChangeStep({
direction,
stepTitle,
StepComponent,
}: {
direction: 'back' | 'next';
stepTitle?: string;
StepComponent: ComponentType;
}) {
setTransition(direction);
setTitle(stepTitle);
TransitionComponent.current = StepComponent;
setTimeout(() => {
setTransition('ready');
@ -70,18 +73,17 @@ function AnimatedTransitionsWizard({ children }: Props) {
data-test-subj="obltOnboardingStreamLogFilePageHeader"
>
<h1>
{i18n.translate(
'xpack.observability_onboarding.title.collectCustomLogs',
{
defaultMessage: 'Collect custom logs',
}
)}
{title
? title
: i18n.translate(
'xpack.observability_onboarding.title.collectCustomLogs',
{
defaultMessage: 'Stream log files to Elastic',
}
)}
</h1>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false} style={{ width: '50%' }}>
<HorizontalSteps />
</EuiFlexItem>
<EuiFlexItem grow={1} style={{ width: '50%' }}>
<FilmstripTransition
duration={TRANSITION_DURATION}