Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion x-pack/plugins/apm/public/application/application.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 './';
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,6 @@ export function ServiceInventory() {
canCreateJob &&
!userHasDismissedCallout;

const isLoading = mainStatisticsStatus === FETCH_STATUS.LOADING;

return (
<>
<SearchBar showTimeComparison />
Expand All @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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} />}
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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 />],
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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 }) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 '../..';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
8 changes: 0 additions & 8 deletions x-pack/plugins/apm/server/lib/services/get_services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
};
});
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/apm/server/lib/services/queries.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -56,7 +57,8 @@ const getTypedGlobalApmServerRouteRepository = () => {
.merge(sourceMapsRouteRepository)
.merge(apmFleetRouteRepository)
.merge(backendsRouteRepository)
.merge(fallbackToTransactionsRouteRepository);
.merge(fallbackToTransactionsRouteRepository)
.merge(historicalDataRouteRepository);

return repository;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Loading