[APM] Consistent "no data" screen with other Observability solutions (#111630)
* logic to show no data screen * fixing i18n * fixing ts * addressing pr comments
This commit is contained in:
parent
b9e6f935c4
commit
6e9b1b57b8
|
@ -9,7 +9,7 @@ import React from 'react';
|
|||
import { act } from '@testing-library/react';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { Observable } from 'rxjs';
|
||||
import { CoreStart } from 'src/core/public';
|
||||
import { CoreStart, DocLinksStart, HttpStart } from 'src/core/public';
|
||||
import { mockApmPluginContextValue } from '../context/apm_plugin/mock_apm_plugin_context';
|
||||
import { createCallApmApi } from '../services/rest/createCallApmApi';
|
||||
import { renderApp } from './';
|
||||
|
@ -85,6 +85,20 @@ describe('renderApp', () => {
|
|||
getEditAlertFlyout: jest.fn(),
|
||||
},
|
||||
usageCollection: { reportUiCounter: () => {} },
|
||||
http: {
|
||||
basePath: {
|
||||
prepend: (path: string) => `/basepath${path}`,
|
||||
get: () => `/basepath`,
|
||||
},
|
||||
} as HttpStart,
|
||||
docLinks: ({
|
||||
DOC_LINK_VERSION: '0',
|
||||
ELASTIC_WEBSITE_URL: 'https://www.elastic.co/',
|
||||
links: {
|
||||
apm: {},
|
||||
observability: { guide: '' },
|
||||
},
|
||||
} as unknown) as DocLinksStart,
|
||||
} as unknown) as ApmPluginStartDeps;
|
||||
|
||||
jest.spyOn(window, 'scrollTo').mockReturnValueOnce(undefined);
|
||||
|
|
|
@ -179,8 +179,6 @@ export function ServiceInventory() {
|
|||
canCreateJob &&
|
||||
!userHasDismissedCallout;
|
||||
|
||||
const isLoading = mainStatisticsStatus === FETCH_STATUS.LOADING;
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchBar showTimeComparison />
|
||||
|
@ -192,17 +190,10 @@ export function ServiceInventory() {
|
|||
)}
|
||||
<EuiFlexItem>
|
||||
<ServiceList
|
||||
isLoading={isLoading}
|
||||
isLoading={mainStatisticsStatus === FETCH_STATUS.LOADING}
|
||||
items={mainStatisticsData.items}
|
||||
comparisonData={comparisonData}
|
||||
noItemsMessage={
|
||||
!isLoading && (
|
||||
<NoServicesMessage
|
||||
historicalDataFound={mainStatisticsData.hasHistoricalData}
|
||||
status={mainStatisticsStatus}
|
||||
/>
|
||||
)
|
||||
}
|
||||
noItemsMessage={<NoServicesMessage status={mainStatisticsStatus} />}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -22,13 +22,9 @@ describe('NoServicesMessage', () => {
|
|||
describe(`when historicalDataFound is ${historicalDataFound}`, () => {
|
||||
it('renders', () => {
|
||||
expect(() =>
|
||||
render(
|
||||
<NoServicesMessage
|
||||
status={status}
|
||||
historicalDataFound={historicalDataFound}
|
||||
/>,
|
||||
{ wrapper: Wrapper }
|
||||
)
|
||||
render(<NoServicesMessage status={status} />, {
|
||||
wrapper: Wrapper,
|
||||
})
|
||||
).not.toThrowError();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,76 +5,35 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiEmptyPrompt, EuiLink } from '@elastic/eui';
|
||||
import { EuiEmptyPrompt } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { FETCH_STATUS } from '../../../hooks/use_fetcher';
|
||||
import { ErrorStatePrompt } from '../../shared/ErrorStatePrompt';
|
||||
import { useUpgradeAssistantHref } from '../../shared/Links/kibana';
|
||||
import { SetupInstructionsLink } from '../../shared/Links/SetupInstructionsLink';
|
||||
|
||||
interface Props {
|
||||
// any data submitted from APM agents found (not just in the given time range)
|
||||
historicalDataFound: boolean;
|
||||
status: FETCH_STATUS | undefined;
|
||||
}
|
||||
|
||||
export function NoServicesMessage({ historicalDataFound, status }: Props) {
|
||||
const upgradeAssistantHref = useUpgradeAssistantHref();
|
||||
|
||||
if (status === 'failure') {
|
||||
return <ErrorStatePrompt />;
|
||||
export function NoServicesMessage({ status }: Props) {
|
||||
if (status === FETCH_STATUS.LOADING) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (historicalDataFound) {
|
||||
return (
|
||||
<EuiEmptyPrompt
|
||||
title={
|
||||
<div>
|
||||
{i18n.translate('xpack.apm.servicesTable.notFoundLabel', {
|
||||
defaultMessage: 'No services found',
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
titleSize="s"
|
||||
/>
|
||||
);
|
||||
if (status === FETCH_STATUS.FAILURE) {
|
||||
return <ErrorStatePrompt />;
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiEmptyPrompt
|
||||
title={
|
||||
<div>
|
||||
{i18n.translate('xpack.apm.servicesTable.noServicesLabel', {
|
||||
defaultMessage: `Looks like you don't have any APM services installed. Let's add some!`,
|
||||
{i18n.translate('xpack.apm.servicesTable.notFoundLabel', {
|
||||
defaultMessage: 'No services found',
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
titleSize="s"
|
||||
body={
|
||||
<React.Fragment>
|
||||
<p>
|
||||
{i18n.translate('xpack.apm.servicesTable.7xUpgradeServerMessage', {
|
||||
defaultMessage: `Upgrading from a pre-7.x version? Make sure you've also upgraded
|
||||
your APM Server instance(s) to at least 7.0.`,
|
||||
})}
|
||||
</p>
|
||||
<p>
|
||||
{i18n.translate('xpack.apm.servicesTable.7xOldDataMessage', {
|
||||
defaultMessage:
|
||||
'You may also have old data that needs to be migrated.',
|
||||
})}{' '}
|
||||
<EuiLink href={upgradeAssistantHref}>
|
||||
{i18n.translate('xpack.apm.servicesTable.UpgradeAssistantLink', {
|
||||
defaultMessage:
|
||||
'Learn more by visiting the Kibana Upgrade Assistant',
|
||||
})}
|
||||
</EuiLink>
|
||||
.
|
||||
</p>
|
||||
</React.Fragment>
|
||||
}
|
||||
actions={<SetupInstructionsLink buttonFill={true} />}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -134,28 +134,6 @@ describe('ServiceInventory', () => {
|
|||
expect(container.querySelectorAll('.euiTableRow')).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should render getting started message, when list is empty and no historical data is found', async () => {
|
||||
httpGet
|
||||
.mockResolvedValueOnce({ fallbackToTransactions: false })
|
||||
.mockResolvedValueOnce({
|
||||
hasLegacyData: false,
|
||||
hasHistoricalData: false,
|
||||
items: [],
|
||||
});
|
||||
|
||||
const { findByText } = render(<ServiceInventory />, { wrapper });
|
||||
|
||||
// wait for requests to be made
|
||||
await waitFor(() => expect(httpGet).toHaveBeenCalledTimes(2));
|
||||
|
||||
// wait for elements to be rendered
|
||||
const gettingStartedMessage = await findByText(
|
||||
"Looks like you don't have any APM services installed. Let's add some!"
|
||||
);
|
||||
|
||||
expect(gettingStartedMessage).not.toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
it('should render empty message, when list is empty and historical data is found', async () => {
|
||||
httpGet
|
||||
.mockResolvedValueOnce({ fallbackToTransactions: false })
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
import { EuiPageHeaderProps, EuiPageTemplateProps } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
|
||||
import { useFetcher } from '../../../hooks/use_fetcher';
|
||||
import { ApmPluginStartDeps } from '../../../plugin';
|
||||
import { ApmEnvironmentFilter } from '../../shared/EnvironmentFilter';
|
||||
import { getNoDataConfig } from './no_data_config';
|
||||
|
||||
/*
|
||||
* This template contains:
|
||||
|
@ -31,12 +33,25 @@ export function ApmMainTemplate({
|
|||
children: React.ReactNode;
|
||||
} & EuiPageTemplateProps) {
|
||||
const { services } = useKibana<ApmPluginStartDeps>();
|
||||
const { http, docLinks } = services;
|
||||
const basePath = http?.basePath.get();
|
||||
|
||||
const ObservabilityPageTemplate =
|
||||
services.observability.navigation.PageTemplate;
|
||||
|
||||
const { data } = useFetcher((callApmApi) => {
|
||||
return callApmApi({ endpoint: 'GET /api/apm/has_data' });
|
||||
}, []);
|
||||
|
||||
const noDataConfig = getNoDataConfig({
|
||||
basePath,
|
||||
docsLink: docLinks!.links.observability.guide,
|
||||
hasData: data?.hasData,
|
||||
});
|
||||
|
||||
return (
|
||||
<ObservabilityPageTemplate
|
||||
noDataConfig={noDataConfig}
|
||||
pageHeader={{
|
||||
pageTitle,
|
||||
rightSideItems: [<ApmEnvironmentFilter />],
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import { KibanaPageTemplateProps } from '../../../../../../../src/plugins/kibana_react/public';
|
||||
|
||||
export function getNoDataConfig({
|
||||
docsLink,
|
||||
basePath,
|
||||
hasData,
|
||||
}: {
|
||||
docsLink: string;
|
||||
basePath?: string;
|
||||
hasData?: boolean;
|
||||
}): KibanaPageTemplateProps['noDataConfig'] {
|
||||
// Returns no data config when there is no historical data
|
||||
if (hasData === false) {
|
||||
return {
|
||||
solution: i18n.translate('xpack.apm.noDataConfig.solutionName', {
|
||||
defaultMessage: 'Observability',
|
||||
}),
|
||||
actions: {
|
||||
beats: {
|
||||
title: i18n.translate('xpack.apm.noDataConfig.beatsCard.title', {
|
||||
defaultMessage: 'Add data with APM agents',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'xpack.apm.noDataConfig.beatsCard.description',
|
||||
{
|
||||
defaultMessage:
|
||||
'Use APM agents to collect APM data. We make it easy with agents for many popular languages.',
|
||||
}
|
||||
),
|
||||
href: basePath + `/app/home#/tutorial/apm`,
|
||||
},
|
||||
},
|
||||
docsLink,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ import React, { ReactNode } from 'react';
|
|||
import { SettingsTemplate } from './settings_template';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { MemoryRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import { CoreStart } from 'kibana/public';
|
||||
import { CoreStart, DocLinksStart, HttpStart } from 'kibana/public';
|
||||
import { createKibanaReactContext } from 'src/plugins/kibana_react/public';
|
||||
|
||||
const { location } = createMemoryHistory();
|
||||
|
@ -25,6 +25,20 @@ const KibanaReactContext = createKibanaReactContext({
|
|||
},
|
||||
},
|
||||
},
|
||||
http: {
|
||||
basePath: {
|
||||
prepend: (path: string) => `/basepath${path}`,
|
||||
get: () => `/basepath`,
|
||||
},
|
||||
} as HttpStart,
|
||||
docLinks: ({
|
||||
DOC_LINK_VERSION: '0',
|
||||
ELASTIC_WEBSITE_URL: 'https://www.elastic.co/',
|
||||
links: {
|
||||
apm: {},
|
||||
observability: { guide: '' },
|
||||
},
|
||||
} as unknown) as DocLinksStart,
|
||||
} as Partial<CoreStart>);
|
||||
|
||||
function Wrapper({ children }: { children?: ReactNode }) {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { createStaticIndexPattern } from './create_static_index_pattern';
|
||||
import { Setup } from '../helpers/setup_request';
|
||||
import * as HistoricalAgentData from '../services/get_services/has_historical_agent_data';
|
||||
import * as HistoricalAgentData from '../../routes/historical_data/has_historical_agent_data';
|
||||
import { InternalSavedObjectsClient } from '../helpers/get_internal_saved_objects_client';
|
||||
import { APMConfig } from '../..';
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { SavedObjectsErrorHelpers } from '../../../../../../src/core/server';
|
||||
import { APM_STATIC_INDEX_PATTERN_ID } from '../../../common/index_pattern_constants';
|
||||
import apmIndexPattern from '../../tutorial/index_pattern.json';
|
||||
import { hasHistoricalAgentData } from '../services/get_services/has_historical_agent_data';
|
||||
import { hasHistoricalAgentData } from '../../routes/historical_data/has_historical_agent_data';
|
||||
import { Setup } from '../helpers/setup_request';
|
||||
import { APMRouteHandlerResources } from '../../routes/typings';
|
||||
import { InternalSavedObjectsClient } from '../helpers/get_internal_saved_objects_client.js';
|
||||
|
|
|
@ -6,12 +6,10 @@
|
|||
*/
|
||||
|
||||
import { Logger } from '@kbn/logging';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { withApmSpan } from '../../../utils/with_apm_span';
|
||||
import { Setup, SetupTimeRange } from '../../helpers/setup_request';
|
||||
import { getLegacyDataStatus } from './get_legacy_data_status';
|
||||
import { getServicesItems } from './get_services_items';
|
||||
import { hasHistoricalAgentData } from './has_historical_agent_data';
|
||||
|
||||
export async function getServices({
|
||||
environment,
|
||||
|
@ -38,14 +36,8 @@ export async function getServices({
|
|||
getLegacyDataStatus(setup),
|
||||
]);
|
||||
|
||||
const noDataInCurrentTimeRange = isEmpty(items);
|
||||
const hasHistoricalData = noDataInCurrentTimeRange
|
||||
? await hasHistoricalAgentData(setup)
|
||||
: true;
|
||||
|
||||
return {
|
||||
items,
|
||||
hasHistoricalData,
|
||||
hasLegacyData,
|
||||
};
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ import { getServiceAgent } from './get_service_agent';
|
|||
import { getServiceTransactionTypes } from './get_service_transaction_types';
|
||||
import { getServicesItems } from './get_services/get_services_items';
|
||||
import { getLegacyDataStatus } from './get_services/get_legacy_data_status';
|
||||
import { hasHistoricalAgentData } from './get_services/has_historical_agent_data';
|
||||
import { hasHistoricalAgentData } from '../../routes/historical_data/has_historical_agent_data';
|
||||
import {
|
||||
SearchParamsMock,
|
||||
inspectSearchParams,
|
||||
|
|
|
@ -33,6 +33,7 @@ import { sourceMapsRouteRepository } from './source_maps';
|
|||
import { traceRouteRepository } from './traces';
|
||||
import { transactionRouteRepository } from './transactions';
|
||||
import { APMRouteHandlerResources } from './typings';
|
||||
import { historicalDataRouteRepository } from './historical_data';
|
||||
|
||||
const getTypedGlobalApmServerRouteRepository = () => {
|
||||
const repository = createApmServerRouteRepository()
|
||||
|
@ -56,7 +57,8 @@ const getTypedGlobalApmServerRouteRepository = () => {
|
|||
.merge(sourceMapsRouteRepository)
|
||||
.merge(apmFleetRouteRepository)
|
||||
.merge(backendsRouteRepository)
|
||||
.merge(fallbackToTransactionsRouteRepository);
|
||||
.merge(fallbackToTransactionsRouteRepository)
|
||||
.merge(historicalDataRouteRepository);
|
||||
|
||||
return repository;
|
||||
};
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ProcessorEvent } from '../../../../common/processor_event';
|
||||
import { Setup } from '../../helpers/setup_request';
|
||||
import { ProcessorEvent } from '../../../common/processor_event';
|
||||
import { Setup } from '../../lib/helpers/setup_request';
|
||||
|
||||
// Note: this logic is duplicated in tutorials/apm/envs/on_prem
|
||||
export async function hasHistoricalAgentData(setup: Setup) {
|
25
x-pack/plugins/apm/server/routes/historical_data/index.ts
Normal file
25
x-pack/plugins/apm/server/routes/historical_data/index.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 { setupRequest } from '../../lib/helpers/setup_request';
|
||||
import { createApmServerRoute } from '../create_apm_server_route';
|
||||
import { createApmServerRouteRepository } from '../create_apm_server_route_repository';
|
||||
import { hasHistoricalAgentData } from './has_historical_agent_data';
|
||||
|
||||
const hasDataRoute = createApmServerRoute({
|
||||
endpoint: 'GET /api/apm/has_data',
|
||||
options: { tags: ['access:apm'] },
|
||||
handler: async (resources) => {
|
||||
const setup = await setupRequest(resources);
|
||||
const hasData = await hasHistoricalAgentData(setup);
|
||||
return { hasData };
|
||||
},
|
||||
});
|
||||
|
||||
export const historicalDataRouteRepository = createApmServerRouteRepository().add(
|
||||
hasDataRoute
|
||||
);
|
|
@ -31,7 +31,10 @@ export type WrappedPageTemplateProps = Pick<
|
|||
| 'restrictWidth'
|
||||
| 'template'
|
||||
| 'isEmptyState'
|
||||
>;
|
||||
| 'noDataConfig'
|
||||
> & {
|
||||
showSolutionNav?: boolean;
|
||||
};
|
||||
|
||||
export interface ObservabilityPageTemplateDependencies {
|
||||
currentAppId$: Observable<string | undefined>;
|
||||
|
@ -49,6 +52,7 @@ export function ObservabilityPageTemplate({
|
|||
getUrlForApp,
|
||||
navigateToApp,
|
||||
navigationSections$,
|
||||
showSolutionNav = true,
|
||||
...pageTemplateProps
|
||||
}: ObservabilityPageTemplateProps): React.ReactElement | null {
|
||||
const sections = useObservable(navigationSections$, []);
|
||||
|
@ -118,11 +122,15 @@ export function ObservabilityPageTemplate({
|
|||
<KibanaPageTemplate
|
||||
restrictWidth={false}
|
||||
{...pageTemplateProps}
|
||||
solutionNav={{
|
||||
icon: 'logoObservability',
|
||||
items: sideNavItems,
|
||||
name: sideNavTitle,
|
||||
}}
|
||||
solutionNav={
|
||||
showSolutionNav
|
||||
? {
|
||||
icon: 'logoObservability',
|
||||
items: sideNavItems,
|
||||
name: sideNavTitle,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</KibanaPageTemplate>
|
||||
|
|
|
@ -6895,20 +6895,16 @@
|
|||
"xpack.apm.serviceProfiling.valueTypeLabel.samples": "サンプル",
|
||||
"xpack.apm.serviceProfiling.valueTypeLabel.unknown": "その他",
|
||||
"xpack.apm.serviceProfiling.valueTypeLabel.wallTime": "Wall",
|
||||
"xpack.apm.servicesTable.7xOldDataMessage": "また、移行が必要な古いデータがある可能性もあります。",
|
||||
"xpack.apm.servicesTable.7xUpgradeServerMessage": "バージョン7.xより前からのアップグレードですか?また、\n APM Server インスタンスを7.0以降にアップグレードしていることも確認してください。",
|
||||
"xpack.apm.servicesTable.environmentColumnLabel": "環境",
|
||||
"xpack.apm.servicesTable.healthColumnLabel": "ヘルス",
|
||||
"xpack.apm.servicesTable.latencyAvgColumnLabel": "レイテンシ(平均)",
|
||||
"xpack.apm.servicesTable.metricsExplanationLabel": "これらのメトリックは何か。",
|
||||
"xpack.apm.servicesTable.nameColumnLabel": "名前",
|
||||
"xpack.apm.servicesTable.noServicesLabel": "APM サービスがインストールされていないようです。追加しましょう!",
|
||||
"xpack.apm.servicesTable.notFoundLabel": "サービスが見つかりません",
|
||||
"xpack.apm.servicesTable.throughputColumnLabel": "スループット",
|
||||
"xpack.apm.servicesTable.tooltip.metricsExplanation": "サービスメトリックは、トランザクションタイプ「要求」、「ページ読み込み」、または上位の使用可能なトランザクションタイプのいずれかで集計されます。",
|
||||
"xpack.apm.servicesTable.transactionColumnLabel": "トランザクションタイプ",
|
||||
"xpack.apm.servicesTable.transactionErrorRate": "失敗したトランザクション率",
|
||||
"xpack.apm.servicesTable.UpgradeAssistantLink": "Kibana アップグレードアシスタントで詳細をご覧ください",
|
||||
"xpack.apm.settings.agentConfig": "エージェントの編集",
|
||||
"xpack.apm.settings.agentConfig.createConfigButton.tooltip": "エージェント構成を作成する権限がありません",
|
||||
"xpack.apm.settings.agentConfig.descriptionText": "APMアプリ内からエージェント構成を微調整してください。変更はAPMエージェントに自動的に伝達されるので、再デプロイする必要はありません。",
|
||||
|
|
|
@ -6949,21 +6949,17 @@
|
|||
"xpack.apm.serviceProfiling.valueTypeLabel.samples": "样例",
|
||||
"xpack.apm.serviceProfiling.valueTypeLabel.unknown": "其他",
|
||||
"xpack.apm.serviceProfiling.valueTypeLabel.wallTime": "现实时间",
|
||||
"xpack.apm.servicesTable.7xOldDataMessage": "可能还有需要迁移的旧数据。",
|
||||
"xpack.apm.servicesTable.7xUpgradeServerMessage": "从 7.x 之前的版本升级?另外,确保您已将\n APM Server 实例升级到至少 7.0。",
|
||||
"xpack.apm.servicesTable.environmentColumnLabel": "环境",
|
||||
"xpack.apm.servicesTable.environmentCount": "{environmentCount, plural, one {1 个环境} other {# 个环境}}",
|
||||
"xpack.apm.servicesTable.healthColumnLabel": "运行状况",
|
||||
"xpack.apm.servicesTable.latencyAvgColumnLabel": "延迟(平均值)",
|
||||
"xpack.apm.servicesTable.metricsExplanationLabel": "这些指标是什么?",
|
||||
"xpack.apm.servicesTable.nameColumnLabel": "名称",
|
||||
"xpack.apm.servicesTable.noServicesLabel": "似乎您没有安装任何 APM 服务。让我们添加一些!",
|
||||
"xpack.apm.servicesTable.notFoundLabel": "未找到任何服务",
|
||||
"xpack.apm.servicesTable.throughputColumnLabel": "吞吐量",
|
||||
"xpack.apm.servicesTable.tooltip.metricsExplanation": "服务指标将基于事务类型“request”、“page-load”或排名靠前的可用事务类型进行聚合。",
|
||||
"xpack.apm.servicesTable.transactionColumnLabel": "事务类型",
|
||||
"xpack.apm.servicesTable.transactionErrorRate": "失败事务率",
|
||||
"xpack.apm.servicesTable.UpgradeAssistantLink": "通过访问 Kibana 升级助手来了解详情",
|
||||
"xpack.apm.settings.agentConfig": "代理配置",
|
||||
"xpack.apm.settings.agentConfig.createConfigButton.tooltip": "您无权创建代理配置",
|
||||
"xpack.apm.settings.agentConfig.descriptionText": "从 APM 应用中微调您的代理配置。更改将自动传播到 APM 代理,因此无需重新部署。",
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../common/ftr_provider_context';
|
||||
import { registry } from '../../common/registry';
|
||||
|
||||
export default function ApiTest({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
const archiveName = 'apm_8.0.0';
|
||||
|
||||
registry.when(
|
||||
'Historical data when data is not loaded',
|
||||
{ config: 'basic', archives: [] },
|
||||
() => {
|
||||
it('handles the empty state', async () => {
|
||||
const response = await supertest.get(`/api/apm/has_data`);
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
expect(response.body.hasData).to.be(false);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
registry.when(
|
||||
'Historical data when data is loaded',
|
||||
{ config: 'basic', archives: [archiveName] },
|
||||
() => {
|
||||
it('returns hasData: true', async () => {
|
||||
const response = await supertest.get(`/api/apm/has_data`);
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
expect(response.body.hasData).to.be(true);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
|
@ -224,6 +224,10 @@ export default function apmApiIntegrationTests(providerContext: FtrProviderConte
|
|||
loadTestFile(require.resolve('./csm/web_core_vitals'));
|
||||
});
|
||||
|
||||
describe('historical_data/has_data', function () {
|
||||
loadTestFile(require.resolve('./historical_data/has_data'));
|
||||
});
|
||||
|
||||
registry.run(providerContext);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
);
|
||||
|
||||
expect(response.status).to.be(200);
|
||||
expect(response.body.hasHistoricalData).to.be(false);
|
||||
expect(response.body.hasLegacyData).to.be(false);
|
||||
expect(response.body.items.length).to.be(0);
|
||||
});
|
||||
|
@ -66,10 +65,6 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
expect(response.status).to.eql(200);
|
||||
});
|
||||
|
||||
it('returns hasHistoricalData: true', () => {
|
||||
expect(response.body.hasHistoricalData).to.be(true);
|
||||
});
|
||||
|
||||
it('returns hasLegacyData: false', () => {
|
||||
expect(response.body.hasLegacyData).to.be(false);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue