Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[APM] Service groups: Add EuiTour steps for assisting users in creating their first service group and provide guidance on the navigation changes #128068

Merged
merged 10 commits into from
Mar 23, 2022
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* 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 } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { ServiceGroupsTour } from '../service_groups_tour';
import { useServiceGroupsTour } from '../use_service_groups_tour';

interface Props {
onClick: () => void;
}

export function CreateButton({ onClick }: Props) {
const { tourEnabled, dismissTour } = useServiceGroupsTour('createGroup');
return (
<ServiceGroupsTour
tourEnabled={tourEnabled}
dismissTour={dismissTour}
title={i18n.translate('xpack.apm.serviceGroups.tour.createGroups.title', {
defaultMessage: 'Introducing service groups',
})}
content={i18n.translate(
'xpack.apm.serviceGroups.tour.createGroups.content',
{
defaultMessage:
'Group services together to build curated inventory views that remove noise and simplify investigations across services. Groups are Kibana space-specific and available for any users with appropriate access.',
}
)}
>
<EuiButton
iconType="plusInCircle"
onClick={() => {
dismissTour();
onClick();
}}
>
{i18n.translate('xpack.apm.serviceGroups.createGroupLabel', {
defaultMessage: 'Create group',
})}
</EuiButton>
</ServiceGroupsTour>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* 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 } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { ServiceGroupsTour } from '../service_groups_tour';
import { useServiceGroupsTour } from '../use_service_groups_tour';

interface Props {
onClick: () => void;
}

export function EditButton({ onClick }: Props) {
const { tourEnabled, dismissTour } = useServiceGroupsTour('editGroup');
return (
<ServiceGroupsTour
tourEnabled={tourEnabled}
dismissTour={dismissTour}
title={i18n.translate('xpack.apm.serviceGroups.tour.editGroups.title', {
defaultMessage: 'Edit this service group',
})}
content={i18n.translate(
'xpack.apm.serviceGroups.tour.editGroups.content',
{
defaultMessage:
'Use the edit option to change the name, query, or details of this service group.',
}
)}
>
<EuiButton
iconType="pencil"
onClick={() => {
dismissTour();
onClick();
}}
>
{i18n.translate('xpack.apm.serviceGroups.editGroupLabel', {
defaultMessage: 'Edit group',
})}
</EuiButton>
</ServiceGroupsTour>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { EuiButton } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { useState } from 'react';
import { useAnyOfApmParams } from '../../../../hooks/use_apm_params';
import { useFetcher } from '../../../../hooks/use_fetcher';
import { CreateButton } from './create_button';
import { EditButton } from './edit_button';
import { SaveGroupModal } from './save_modal';

export function ServiceGroupSaveButton() {
Expand All @@ -32,16 +32,18 @@ export function ServiceGroupSaveButton() {
);
const savedServiceGroup = data?.serviceGroup;

function onClick() {
setIsModalVisible((state) => !state);
}

return (
<>
<EuiButton
iconType={isGroupEditMode ? 'pencil' : 'plusInCircle'}
onClick={async () => {
setIsModalVisible((state) => !state);
}}
>
{isGroupEditMode ? EDIT_GROUP_LABEL : CREATE_GROUP_LABEL}
</EuiButton>
{isGroupEditMode ? (
<EditButton onClick={onClick} />
) : (
<CreateButton onClick={onClick} />
)}

cauemarcondes marked this conversation as resolved.
Show resolved Hide resolved
{isModalVisible && (
<SaveGroupModal
savedServiceGroup={savedServiceGroup}
Expand All @@ -53,12 +55,3 @@ export function ServiceGroupSaveButton() {
</>
);
}

const CREATE_GROUP_LABEL = i18n.translate(
'xpack.apm.serviceGroups.createGroupLabel',
{ defaultMessage: 'Create group' }
);
const EDIT_GROUP_LABEL = i18n.translate(
'xpack.apm.serviceGroups.editGroupLabel',
{ defaultMessage: 'Edit group' }
);
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,26 @@ import {
ServiceGroup,
SERVICE_GROUP_COLOR_DEFAULT,
} from '../../../../../common/service_groups';
import { ServiceGroupsTour } from '../service_groups_tour';
import { useServiceGroupsTour } from '../use_service_groups_tour';

interface Props {
serviceGroup: ServiceGroup;
hideServiceCount?: boolean;
onClick?: () => void;
href?: string;
withTour?: boolean;
}

export function ServiceGroupsCard({
serviceGroup,
hideServiceCount = false,
onClick,
href,
withTour,
}: Props) {
const { tourEnabled, dismissTour } = useServiceGroupsTour('serviceGroupCard');

const cardProps: EuiCardProps = {
style: { width: 286, height: 186 },
icon: (
Expand Down Expand Up @@ -69,10 +75,39 @@ export function ServiceGroupsCard({
)}
</EuiFlexGroup>
),
onClick,
onClick: () => {
dismissTour();
if (onClick) {
onClick();
}
},
href,
};

if (withTour) {
return (
<EuiFlexItem key={serviceGroup.groupName}>
<ServiceGroupsTour
tourEnabled={tourEnabled}
dismissTour={dismissTour}
title={i18n.translate(
'xpack.apm.serviceGroups.tour.serviceGroups.title',
{ defaultMessage: 'All services group' }
)}
content={i18n.translate(
'xpack.apm.serviceGroups.tour.serviceGroups.content',
{
defaultMessage:
"Now that you've created a service group, your All services inventory has moved here. This group cannot be edited or removed.",
}
)}
>
<EuiCard layout="vertical" {...cardProps} />
</ServiceGroupsTour>
</EuiFlexItem>
);
}

return (
<EuiFlexItem key={serviceGroup.groupName}>
<EuiCard layout="vertical" {...cardProps} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export function ServiceGroupsListItems({ items }: Props) {
/>
))}
<ServiceGroupsCard
withTour
serviceGroup={{
groupName: i18n.translate(
'xpack.apm.serviceGroups.list.allServices.name',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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 { EuiButtonEmpty, EuiSpacer, EuiText, EuiTourStep } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { ElasticDocsLink } from '../../shared/links/elastic_docs_link';

export type TourType = 'createGroup' | 'editGroup' | 'serviceGroupCard';

interface Props {
title: string;
content: string;
tourEnabled: boolean;
dismissTour: () => void;
children: React.ReactElement;
}

export function ServiceGroupsTour({
tourEnabled,
dismissTour,
title,
content,
children,
}: Props) {
return (
<EuiTourStep
content={
<>
<EuiText size="s">{content}</EuiText>
<EuiSpacer />
<div style={{ display: 'flex' }}>
cauemarcondes marked this conversation as resolved.
Show resolved Hide resolved
<EuiText size="s">
{i18n.translate('xpack.apm.serviceGroups.tour.content.link', {
cauemarcondes marked this conversation as resolved.
Show resolved Hide resolved
defaultMessage: 'Learn more in the',
})}{' '}
cauemarcondes marked this conversation as resolved.
Show resolved Hide resolved
<ElasticDocsLink
section="/kibana"
path="/services.html"
target="blank"
>
{i18n.translate(
'xpack.apm.serviceGroups.tour.content.link.docs',
{
defaultMessage: 'docs.',
}
)}
</ElasticDocsLink>
</EuiText>
</div>
</>
}
isStepOpen={tourEnabled}
onFinish={() => {}}
maxWidth={300}
minWidth={300}
step={1}
stepsTotal={1}
title={title}
anchorPosition="leftUp"
footerAction={
<EuiButtonEmpty color="text" size="xs" onClick={dismissTour}>
{i18n.translate('xpack.apm.serviceGroups.tour.dismiss', {
defaultMessage: 'Dismiss',
})}
</EuiButtonEmpty>
}
>
{children}
</EuiTourStep>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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 { useLocalStorage } from '../../../hooks/use_local_storage';
import { TourType } from './service_groups_tour';

const INITIAL_STATE: Record<TourType, boolean> = {
createGroup: true,
editGroup: true,
serviceGroupCard: true,
};

export function useServiceGroupsTour(type: TourType) {
const [tourEnabled, setTourEnabled] = useLocalStorage(
'apm.serviceGroupsTour',
INITIAL_STATE
);

return {
tourEnabled: tourEnabled[type],
dismissTour: () =>
setTourEnabled({
...tourEnabled,
[type]: false,
}),
};
}