[8.16] [APM]Refactor ServiceTabEmptyState to use AddDataPanel (#197578) (#197665)

# Backport

This will backport the following commits from `main` to `8.16`:
- [[APM]Refactor ServiceTabEmptyState to use AddDataPanel
(#197578)](https://github.com/elastic/kibana/pull/197578)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Irene
Blanco","email":"irene.blanco@elastic.co"},"sourceCommit":{"committedDate":"2024-10-24T14:34:55Z","message":"[APM]Refactor
ServiceTabEmptyState to use AddDataPanel (#197578)\n\n##
Summary\r\n\r\nCloses
https://github.com/elastic/kibana/issues/195876\r\n\r\nThis PR refactors
the ServiceTabEmptyState component to use the newly\r\ncreated generic
AddDataPanel component, which was derived from it.\r\n\r\nThe
functionality remains the same.\r\n\r\n###
Tabs\r\n\r\n|Light|Dark|\r\n|-|-|\r\n\r\n|![callout_light](298386bf-eb76-4b23-9952-df6576032f86)|\r\n\r\n###
Actions\r\n\r\n![callout_actions](https://github.com/user-attachments/assets/08c4364c-c3cb-45af-b02e-5012cbf86536)\r\n\r\n###
Dismiss\r\n\r\n![callout_dismissable](https://github.com/user-attachments/assets/a0276001-98a9-47b3-83c9-aaa0685c7418)","sha":"42de8c858995b190f35858b2798f7ea4dfcb2439","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","apm","backport:prev-minor","ci:project-deploy-observability","Team:obs-ux-infra_services","v8.16.0","v8.17.0"],"title":"[APM]Refactor
ServiceTabEmptyState to use
AddDataPanel","number":197578,"url":"https://github.com/elastic/kibana/pull/197578","mergeCommit":{"message":"[APM]Refactor
ServiceTabEmptyState to use AddDataPanel (#197578)\n\n##
Summary\r\n\r\nCloses
https://github.com/elastic/kibana/issues/195876\r\n\r\nThis PR refactors
the ServiceTabEmptyState component to use the newly\r\ncreated generic
AddDataPanel component, which was derived from it.\r\n\r\nThe
functionality remains the same.\r\n\r\n###
Tabs\r\n\r\n|Light|Dark|\r\n|-|-|\r\n\r\n|![callout_light](298386bf-eb76-4b23-9952-df6576032f86)|\r\n\r\n###
Actions\r\n\r\n![callout_actions](https://github.com/user-attachments/assets/08c4364c-c3cb-45af-b02e-5012cbf86536)\r\n\r\n###
Dismiss\r\n\r\n![callout_dismissable](https://github.com/user-attachments/assets/a0276001-98a9-47b3-83c9-aaa0685c7418)","sha":"42de8c858995b190f35858b2798f7ea4dfcb2439"}},"sourceBranch":"main","suggestedTargetBranches":["8.16","8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/197578","number":197578,"mergeCommit":{"message":"[APM]Refactor
ServiceTabEmptyState to use AddDataPanel (#197578)\n\n##
Summary\r\n\r\nCloses
https://github.com/elastic/kibana/issues/195876\r\n\r\nThis PR refactors
the ServiceTabEmptyState component to use the newly\r\ncreated generic
AddDataPanel component, which was derived from it.\r\n\r\nThe
functionality remains the same.\r\n\r\n###
Tabs\r\n\r\n|Light|Dark|\r\n|-|-|\r\n\r\n|![callout_light](298386bf-eb76-4b23-9952-df6576032f86)|\r\n\r\n###
Actions\r\n\r\n![callout_actions](https://github.com/user-attachments/assets/08c4364c-c3cb-45af-b02e-5012cbf86536)\r\n\r\n###
Dismiss\r\n\r\n![callout_dismissable](https://github.com/user-attachments/assets/a0276001-98a9-47b3-83c9-aaa0685c7418)","sha":"42de8c858995b190f35858b2798f7ea4dfcb2439"}},{"branch":"8.16","label":"v8.16.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.x","label":"v8.17.0","branchLabelMappingKey":"^v8.17.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Irene Blanco <irene.blanco@elastic.co>
This commit is contained in:
Kibana Machine 2024-10-25 03:22:15 +11:00 committed by GitHub
parent 932e4b3182
commit 1957062894
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 197 additions and 220 deletions

View file

@ -97,7 +97,7 @@ export function ServiceOverview() {
<EuiFlexItem>
<ServiceTabEmptyState
id="serviceOverview"
onDissmiss={() => setDismissedLogsOnlyEmptyState(true)}
onDismiss={() => setDismissedLogsOnlyEmptyState(true)}
/>
</EuiFlexItem>
)}

View file

@ -5,9 +5,12 @@
* 2.0.
*/
import type { ObservabilityOnboardingLocatorParams } from '@kbn/deeplinks-observability';
import { i18n } from '@kbn/i18n';
import type { AddDataPanelProps } from '@kbn/observability-shared-plugin/public';
import type { LocatorPublic } from '@kbn/share-plugin/common';
export type EmptyStateKey =
export type AddAPMCalloutKeys =
| 'serviceOverview'
| 'serviceDependencies'
| 'infraOverview'
@ -16,80 +19,154 @@ export type EmptyStateKey =
| 'metrics'
| 'errorGroupOverview';
interface EmptyStateContent {
title: string;
content: string;
imgName?: string;
}
export const emptyStateDefinitions: Record<EmptyStateKey, EmptyStateContent> = {
serviceOverview: {
title: i18n.translate('xpack.apm.serviceTabEmptyState.overviewTitle', {
defaultMessage: 'Detect and resolve issues faster with deep visibility into your application',
}),
content: i18n.translate('xpack.apm.serviceTabEmptyState.overviewContent', {
defaultMessage:
'Understanding your application performance, relationships and dependencies by instrumenting with APM.',
}),
},
serviceDependencies: {
title: i18n.translate('xpack.apm.serviceTabEmptyState.dependenciesTitle', {
defaultMessage: 'Understand the dependencies for your service',
}),
content: i18n.translate('xpack.apm.serviceTabEmptyState.dependenciesContent', {
defaultMessage:
"See your service's dependencies on both internal and third-party services by instrumenting with APM.",
}),
imgName: 'service_tab_empty_state_dependencies.png',
},
infraOverview: {
title: i18n.translate('xpack.apm.serviceTabEmptyState.infrastructureTitle', {
defaultMessage: 'Understand what your service is running on',
}),
content: i18n.translate('xpack.apm.serviceTabEmptyState.infrastructureContent', {
defaultMessage:
'Troubleshoot service problems by seeing the infrastructure your service is running on.',
}),
imgName: 'service_tab_empty_state_infrastructure.png',
},
serviceMap: {
title: i18n.translate('xpack.apm.serviceTabEmptyState.serviceMapTitle', {
defaultMessage: 'Visualise the dependencies between your services',
}),
content: i18n.translate('xpack.apm.serviceTabEmptyState.serviceMapContent', {
defaultMessage:
'See your services dependencies at a glance to help identify dependencies that may be affecting your service.',
}),
imgName: 'service_tab_empty_state_service_map.png',
},
transactionOverview: {
title: i18n.translate('xpack.apm.serviceTabEmptyState.transactionsTitle', {
defaultMessage: 'Troubleshoot latency, throughput and errors',
}),
content: i18n.translate('xpack.apm.serviceTabEmptyState.transactionsContent', {
defaultMessage:
"Troubleshoot your service's performance by analysing latency, throughput and errors down to the specific transaction.",
}),
imgName: 'service_tab_empty_state_transactions.png',
},
metrics: {
title: i18n.translate('xpack.apm.serviceTabEmptyState.metricsTitle', {
defaultMessage: 'View core metrics for your application',
}),
content: i18n.translate('xpack.apm.serviceTabEmptyState.metricsContent', {
defaultMessage:
'View metric trends for the instances of your service to identify performance bottlenecks that could be affecting your users.',
}),
imgName: 'service_tab_empty_state_metrics.png',
},
errorGroupOverview: {
title: i18n.translate('xpack.apm.serviceTabEmptyState.errorGroupOverviewTitle', {
defaultMessage: 'Identify transaction errors with your applications',
}),
content: i18n.translate('xpack.apm.serviceTabEmptyState.errorGroupOverviewContent', {
defaultMessage:
'Analyse errors down to the specific transaction to pin-point specific errors within your service.',
}),
imgName: 'service_tab_empty_state_errors.png',
},
const defaultActions = (
locator: LocatorPublic<ObservabilityOnboardingLocatorParams> | undefined
) => {
return {
actions: {
primary: {
href: locator?.getRedirectUrl({ category: 'application' }),
label: i18n.translate('xpack.apm.serviceTabEmptyState.defaultPrimaryActionLabel', {
defaultMessage: 'Add APM',
}),
},
secondary: {
href: 'https://ela.st/demo-apm-try-it',
},
link: {
href: 'https://www.elastic.co/observability/application-performance-monitoring',
},
},
};
};
export const addAPMCalloutDefinitions = (
baseFolderPath: string,
locator: LocatorPublic<ObservabilityOnboardingLocatorParams> | undefined
): Record<
AddAPMCalloutKeys,
Omit<AddDataPanelProps, 'onDismiss' | 'onAddData' | 'onLearnMore' | 'onTryIt'>
> => {
return {
serviceOverview: {
content: {
title: i18n.translate('xpack.apm.serviceTabEmptyState.overviewTitle', {
defaultMessage:
'Detect and resolve issues faster with deep visibility into your application',
}),
content: i18n.translate('xpack.apm.serviceTabEmptyState.overviewContent', {
defaultMessage:
'Understanding your application performance, relationships and dependencies by instrumenting with APM.',
}),
img: {
name: 'service_tab_empty_state_overview.png',
baseFolderPath,
position: 'inside',
},
},
...defaultActions(locator),
},
serviceDependencies: {
content: {
title: i18n.translate('xpack.apm.serviceTabEmptyState.dependenciesTitle', {
defaultMessage: 'Understand the dependencies for your service',
}),
content: i18n.translate('xpack.apm.serviceTabEmptyState.dependenciesContent', {
defaultMessage:
"See your service's dependencies on both internal and third-party services by instrumenting with APM.",
}),
img: {
name: 'service_tab_empty_state_dependencies.png',
baseFolderPath,
position: 'below',
},
},
...defaultActions(locator),
},
infraOverview: {
content: {
title: i18n.translate('xpack.apm.serviceTabEmptyState.infrastructureTitle', {
defaultMessage: 'Understand what your service is running on',
}),
content: i18n.translate('xpack.apm.serviceTabEmptyState.infrastructureContent', {
defaultMessage:
'Troubleshoot service problems by seeing the infrastructure your service is running on.',
}),
img: {
name: 'service_tab_empty_state_infrastructure.png',
baseFolderPath,
position: 'below',
},
},
...defaultActions(locator),
},
serviceMap: {
content: {
title: i18n.translate('xpack.apm.serviceTabEmptyState.serviceMapTitle', {
defaultMessage: 'Visualise the dependencies between your services',
}),
content: i18n.translate('xpack.apm.serviceTabEmptyState.serviceMapContent', {
defaultMessage:
'See your services dependencies at a glance to help identify dependencies that may be affecting your service.',
}),
img: {
name: 'service_tab_empty_state_service_map.png',
baseFolderPath,
position: 'below',
},
},
...defaultActions(locator),
},
transactionOverview: {
content: {
title: i18n.translate('xpack.apm.serviceTabEmptyState.transactionsTitle', {
defaultMessage: 'Troubleshoot latency, throughput and errors',
}),
content: i18n.translate('xpack.apm.serviceTabEmptyState.transactionsContent', {
defaultMessage:
"Troubleshoot your service's performance by analysing latency, throughput and errors down to the specific transaction.",
}),
img: {
name: 'service_tab_empty_state_transactions.png',
baseFolderPath,
position: 'below',
},
},
...defaultActions(locator),
},
metrics: {
content: {
title: i18n.translate('xpack.apm.serviceTabEmptyState.metricsTitle', {
defaultMessage: 'View core metrics for your application',
}),
content: i18n.translate('xpack.apm.serviceTabEmptyState.metricsContent', {
defaultMessage:
'View metric trends for the instances of your service to identify performance bottlenecks that could be affecting your users.',
}),
img: {
name: 'service_tab_empty_state_metrics.png',
baseFolderPath,
position: 'below',
},
},
...defaultActions(locator),
},
errorGroupOverview: {
content: {
title: i18n.translate('xpack.apm.serviceTabEmptyState.errorGroupOverviewTitle', {
defaultMessage: 'Identify transaction errors with your applications',
}),
content: i18n.translate('xpack.apm.serviceTabEmptyState.errorGroupOverviewContent', {
defaultMessage:
'Analyse errors down to the specific transaction to pin-point specific errors within your service.',
}),
img: {
name: 'service_tab_empty_state_errors.png',
baseFolderPath,
position: 'below',
},
},
...defaultActions(locator),
},
};
};

View file

@ -5,50 +5,24 @@
* 2.0.
*/
/* eslint-disable @elastic/eui/href-or-on-click */
import {
EuiButton,
EuiButtonIcon,
EuiFlexGroup,
EuiFlexItem,
EuiImage,
EuiLink,
EuiPanel,
EuiSpacer,
EuiText,
EuiTitle,
useEuiTheme,
} from '@elastic/eui';
import React from 'react';
import { i18n } from '@kbn/i18n';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { AddDataPanel } from '@kbn/observability-shared-plugin/public';
import {
OBSERVABILITY_ONBOARDING_LOCATOR,
ObservabilityOnboardingLocatorParams,
} from '@kbn/deeplinks-observability';
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
import { EmptyStateClickParams, EntityInventoryAddDataParams } from '../../../services/telemetry';
import { ApmPluginStartDeps, ApmServices } from '../../../plugin';
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
import { useKibanaUrl } from '../../../hooks/use_kibana_url';
import { AddApmData } from '../../shared/add_data_buttons/buttons';
import { emptyStateDefinitions, EmptyStateKey } from './constants';
import { addAPMCalloutDefinitions, AddAPMCalloutKeys } from './constants';
export interface ServiceTabEmptyStateProps {
id: EmptyStateKey;
onDissmiss?: () => void;
id: AddAPMCalloutKeys;
onDismiss?: () => void;
}
const tryItNowButton = {
label: i18n.translate('xpack.apm.serviceTabEmptyState.tryItNowButtonLabel', {
defaultMessage: 'Try it now in our demo cluster',
}),
href: 'https://ela.st/demo-apm-try-it',
};
const learnMoreLink = {
label: i18n.translate('xpack.apm.serviceTabEmptyState.learnMoreLinkLabel', {
defaultMessage: 'Learn more',
}),
href: 'https://www.elastic.co/observability/application-performance-monitoring',
};
const baseImgFolder = '/plugins/apm/assets/service_tab_empty_state';
const defaultAddDataTelemetryParams: EntityInventoryAddDataParams = {
view: 'add_apm_cta',
@ -58,114 +32,40 @@ const defaultClickTelemetryParams: EmptyStateClickParams = {
view: 'add_apm_cta',
};
export function ServiceTabEmptyState({ id, onDissmiss }: ServiceTabEmptyStateProps) {
const { euiTheme } = useEuiTheme();
const { services } = useKibana<ApmPluginStartDeps & ApmServices>();
const { core } = useApmPluginContext();
export function ServiceTabEmptyState({ id, onDismiss }: ServiceTabEmptyStateProps) {
const {
services: { telemetry },
} = useKibana<ApmPluginStartDeps & ApmServices>();
const imgFolder = `${baseImgFolder}/${
core.uiSettings.get('theme:darkMode') === 'enabled' ? 'dark' : 'light'
}`;
const imgName = emptyStateDefinitions[id].imgName;
const imgSrc = useKibanaUrl(
`${imgFolder}/${imgName ? imgName : 'service_tab_empty_state_overview.png'}`
const { share } = useApmPluginContext();
const onboardingLocator = share.url.locators.get<ObservabilityOnboardingLocatorParams>(
OBSERVABILITY_ONBOARDING_LOCATOR
);
const imgBaseFolderPath = useKibanaUrl(baseImgFolder);
function handleAddAPMClick() {
services.telemetry.reportEntityInventoryAddData(defaultAddDataTelemetryParams);
telemetry.reportEntityInventoryAddData(defaultAddDataTelemetryParams);
}
function handleTryItClick() {
services.telemetry.reportTryItClick(defaultClickTelemetryParams);
telemetry.reportTryItClick(defaultClickTelemetryParams);
}
function handleLearnMoreClick() {
services.telemetry.reportLearnMoreClick(defaultClickTelemetryParams);
telemetry.reportLearnMoreClick(defaultClickTelemetryParams);
}
return (
<>
<EuiPanel color="subdued" paddingSize="xl" style={{ position: 'relative' }}>
<EuiFlexGroup alignItems="center">
<EuiFlexItem>
<EuiTitle size="s">
<h3>{emptyStateDefinitions[id].title}</h3>
</EuiTitle>
<EuiSpacer size="s" />
<EuiText size="s">{emptyStateDefinitions[id].content}</EuiText>
<EuiSpacer size="m" />
<EuiFlexGroup alignItems="center" gutterSize="m">
<EuiFlexItem grow={false}>
<AddApmData
data-test-subj="ServiceTabEmptyStateAddApmButton"
size="m"
fill
onClick={handleAddAPMClick}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
data-test-subj="ServiceTabEmptyStateTryItNowButton"
iconType="launch"
iconSide="right"
href={tryItNowButton.href}
onClick={handleTryItClick}
target="_blank"
>
{tryItNowButton.label}
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiLink
href={learnMoreLink.href}
onClick={handleLearnMoreClick}
target="_blank"
data-test-subj="ServiceTabEmptyStateLearnMoreButton"
external
>
{learnMoreLink.label}
</EuiLink>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
{!emptyStateDefinitions[id].imgName && (
<EuiFlexItem
style={{
maxHeight: `${euiTheme.base * 16}px`,
overflow: 'hidden',
borderRadius: `${euiTheme.border.radius.medium}`,
border: `${euiTheme.border.thin}`,
}}
>
<EuiImage src={imgSrc} alt={emptyStateDefinitions[id].content} />
</EuiFlexItem>
)}
{onDissmiss && (
<EuiButtonIcon
style={{
position: 'absolute',
top: `${euiTheme.size.s}`,
right: `${euiTheme.size.s}`,
}}
data-test-subj="ServiceTabEmptyStateDismissButton"
iconType="cross"
onClick={onDissmiss}
/>
)}
</EuiFlexGroup>
</EuiPanel>
{emptyStateDefinitions[id].imgName && (
<>
<EuiSpacer size="l" />
<EuiImage
src={imgSrc}
alt={emptyStateDefinitions[id].content}
size="fullWidth"
style={{ opacity: 0.4 }}
/>
</>
)}
</>
<AddDataPanel
data-test-subj="apmAddApmCallout"
content={addAPMCalloutDefinitions(imgBaseFolderPath, onboardingLocator)[id].content}
actions={addAPMCalloutDefinitions(imgBaseFolderPath, onboardingLocator)[id].actions}
onAddData={handleAddAPMClick}
onTryIt={handleTryItClick}
onLearnMore={handleLearnMoreClick}
onDismiss={onDismiss}
/>
);
}

View file

@ -13,10 +13,10 @@ import { useKibana } from '@kbn/kibana-react-plugin/public';
import { ApmPluginStartDeps } from '../../../../plugin';
interface EntitiesInventoryCalloutProps {
onDissmiss: () => void;
onDismiss: () => void;
}
export function EntitiesInventoryCallout({ onDissmiss }: EntitiesInventoryCalloutProps) {
export function EntitiesInventoryCallout({ onDismiss }: EntitiesInventoryCalloutProps) {
const { services } = useKibana<ApmPluginStartDeps>();
const { observabilityShared } = services;
@ -50,7 +50,7 @@ export function EntitiesInventoryCallout({ onDissmiss }: EntitiesInventoryCallou
<EuiButtonIcon
data-test-subj="apmEntitiesInventoryCalloutDismiss"
iconType="cross"
onClick={onDissmiss}
onClick={onDismiss}
/>
</EuiToolTip>
</EuiFlexItem>

View file

@ -176,7 +176,7 @@ export function ApmMainTemplate({
<EuiFlexGroup direction="column">
{showEntitiesInventoryCallout ? (
<EntitiesInventoryCallout
onDissmiss={() => {
onDismiss={() => {
setdismissedEntitiesInventoryCallout(true);
}}
/>

View file

@ -56,7 +56,7 @@ export function AddMetricsCallout({ id, onDismiss }: AddMetricsCalloutProps) {
onAddData={handleAddMetricsClick}
onTryIt={handleTryItClick}
onLearnMore={handleLearnMoreClick}
onDissmiss={onDismiss && handleDismiss}
onDismiss={onDismiss && handleDismiss}
/>
);
}

View file

@ -15,7 +15,7 @@ export default {
};
const defaultFunctions = {
onDissmiss: () => alert('Dismissed'),
onDismiss: () => alert('Dismissed'),
onAddData: () => alert('Add Data'),
onTryIt: () => alert('Try It'),
onLearnMore: () => alert('Learn More'),
@ -139,7 +139,7 @@ export function NotDismissable(props: ComponentProps<typeof AddDataPanel>) {
NotDismissable.args = {
...defaultContent(),
...defaultFunctions,
onDissmiss: undefined,
onDismiss: undefined,
actions: {
primary: defaultPrimaryAction,
secondary: {

View file

@ -43,7 +43,7 @@ type AddDataPanelButtonWithLabel = Required<AddDataPanelButton>;
export interface AddDataPanelProps {
content: AddDataPanelContent;
onDissmiss?: () => void;
onDismiss?: () => void;
onAddData: () => void;
onTryIt?: () => void;
onLearnMore: () => void;
@ -72,7 +72,7 @@ const learnMoreDefaultLabel = i18n.translate(
export function AddDataPanel({
content,
actions,
onDissmiss,
onDismiss,
onLearnMore,
onTryIt,
onAddData,
@ -155,7 +155,7 @@ export function AddDataPanel({
</EuiFlexItem>
)}
{onDissmiss && (
{onDismiss && (
<EuiButtonIcon
style={{
position: 'absolute',
@ -164,7 +164,7 @@ export function AddDataPanel({
}}
data-test-subj="AddDataPanelDismissButton"
iconType="cross"
onClick={onDissmiss}
onClick={onDismiss}
/>
)}
</EuiFlexGroup>