Skip to content

Commit f4a83a0

Browse files
walterrakibanamachine
authored andcommitted
[ML] APM Latency Correlations: Fix empty state (#109813)
- Correctly renders the empty chart state when no data is available. - Hides the "Click drag to select" and trace samples message when the chart shows an empty state to avoid redundant info. - Adds jest unit tests that would fail with the previously visible loading indicators. - Fix a bug with cancelling search strategies.
1 parent 62f1770 commit f4a83a0

15 files changed

Lines changed: 621 additions & 300 deletions

File tree

x-pack/plugins/apm/common/search_strategies/correlations/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,12 @@ export interface AsyncSearchProviderProgress {
5252
loadedFieldValuePairs: number;
5353
loadedHistograms: number;
5454
}
55+
56+
export interface SearchServiceRawResponse {
57+
ccsWarning: boolean;
58+
log: string[];
59+
overallHistogram?: HistogramItem[];
60+
percentileThresholdValue?: number;
61+
took: number;
62+
values: SearchServiceValue[];
63+
}

x-pack/plugins/apm/public/components/app/correlations/empty_state_prompt.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ export function CorrelationsEmptyStatePrompt() {
3333
id="xpack.apm.correlations.noCorrelationsTextLine1"
3434
defaultMessage="Correlations will only be identified if they have significant impact."
3535
/>
36-
</p>
37-
<p>
36+
<br />
3837
<FormattedMessage
3938
id="xpack.apm.correlations.noCorrelationsTextLine2"
4039
defaultMessage="Try selecting another time range or remove any added filter."

x-pack/plugins/apm/public/components/app/correlations/failed_transactions_correlations.tsx

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ import { CorrelationsLog } from './correlations_log';
4141
import { CorrelationsEmptyStatePrompt } from './empty_state_prompt';
4242
import { CrossClusterSearchCompatibilityWarning } from './cross_cluster_search_warning';
4343
import { CorrelationsProgressControls } from './progress_controls';
44-
import type { SearchServiceParams } from '../../../../common/search_strategies/correlations/types';
4544
import type { FailedTransactionsCorrelationValue } from '../../../../common/search_strategies/failure_correlations/types';
4645
import { Summary } from '../../shared/Summary';
4746
import { asPercent } from '../../../../common/utils/formatters';
@@ -70,16 +69,6 @@ export function FailedTransactionsCorrelations({
7069

7170
const inspectEnabled = uiSettings.get<boolean>(enableInspectEsQueries);
7271

73-
const searchServicePrams: SearchServiceParams = {
74-
environment,
75-
kuery,
76-
serviceName,
77-
transactionName,
78-
transactionType,
79-
start,
80-
end,
81-
};
82-
8372
const result = useFailedTransactionsCorrelationsFetcher();
8473

8574
const {
@@ -93,26 +82,30 @@ export function FailedTransactionsCorrelations({
9382
} = result;
9483

9584
const startFetchHandler = useCallback(() => {
96-
startFetch(searchServicePrams);
97-
// eslint-disable-next-line react-hooks/exhaustive-deps
98-
}, [environment, serviceName, kuery, start, end]);
85+
startFetch({
86+
environment,
87+
kuery,
88+
serviceName,
89+
transactionName,
90+
transactionType,
91+
start,
92+
end,
93+
});
94+
}, [
95+
startFetch,
96+
environment,
97+
serviceName,
98+
transactionName,
99+
transactionType,
100+
kuery,
101+
start,
102+
end,
103+
]);
99104

100-
// start fetching on load
101-
// we want this effect to execute exactly once after the component mounts
102105
useEffect(() => {
103-
if (isRunning) {
104-
cancelFetch();
105-
}
106-
107106
startFetchHandler();
108-
109-
return () => {
110-
// cancel any running async partial request when unmounting the component
111-
// we want this effect to execute exactly once after the component mounts
112-
cancelFetch();
113-
};
114-
// eslint-disable-next-line react-hooks/exhaustive-deps
115-
}, [startFetchHandler]);
107+
return cancelFetch;
108+
}, [cancelFetch, startFetchHandler]);
116109

117110
const [
118111
selectedSignificantTerm,
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import { render, screen, waitFor } from '@testing-library/react';
9+
import { createMemoryHistory } from 'history';
10+
import React, { ReactNode } from 'react';
11+
import { of } from 'rxjs';
12+
13+
import { __IntlProvider as IntlProvider } from '@kbn/i18n/react';
14+
15+
import { CoreStart } from 'kibana/public';
16+
import { merge } from 'lodash';
17+
import { dataPluginMock } from 'src/plugins/data/public/mocks';
18+
import type { IKibanaSearchResponse } from 'src/plugins/data/public';
19+
import { EuiThemeProvider } from 'src/plugins/kibana_react/common';
20+
import { createKibanaReactContext } from 'src/plugins/kibana_react/public';
21+
import type { SearchServiceRawResponse } from '../../../../common/search_strategies/correlations/types';
22+
import { MockUrlParamsContextProvider } from '../../../context/url_params_context/mock_url_params_context_provider';
23+
import { ApmPluginContextValue } from '../../../context/apm_plugin/apm_plugin_context';
24+
import {
25+
mockApmPluginContextValue,
26+
MockApmPluginContextWrapper,
27+
} from '../../../context/apm_plugin/mock_apm_plugin_context';
28+
import { fromQuery } from '../../shared/Links/url_helpers';
29+
30+
import { LatencyCorrelations } from './latency_correlations';
31+
32+
function Wrapper({
33+
children,
34+
dataSearchResponse,
35+
}: {
36+
children?: ReactNode;
37+
dataSearchResponse: IKibanaSearchResponse<SearchServiceRawResponse>;
38+
}) {
39+
const mockDataSearch = jest.fn(() => of(dataSearchResponse));
40+
41+
const dataPluginMockStart = dataPluginMock.createStartContract();
42+
const KibanaReactContext = createKibanaReactContext({
43+
data: {
44+
...dataPluginMockStart,
45+
search: {
46+
...dataPluginMockStart.search,
47+
search: mockDataSearch,
48+
},
49+
},
50+
usageCollection: { reportUiCounter: () => {} },
51+
} as Partial<CoreStart>);
52+
53+
const httpGet = jest.fn();
54+
55+
const history = createMemoryHistory();
56+
jest.spyOn(history, 'push');
57+
jest.spyOn(history, 'replace');
58+
59+
history.replace({
60+
pathname: '/services/the-service-name/transactions/view',
61+
search: fromQuery({ transactionName: 'the-transaction-name' }),
62+
});
63+
64+
const mockPluginContext = (merge({}, mockApmPluginContextValue, {
65+
core: { http: { get: httpGet } },
66+
}) as unknown) as ApmPluginContextValue;
67+
68+
return (
69+
<IntlProvider locale="en">
70+
<EuiThemeProvider darkMode={false}>
71+
<KibanaReactContext.Provider>
72+
<MockApmPluginContextWrapper
73+
history={history}
74+
value={mockPluginContext}
75+
>
76+
<MockUrlParamsContextProvider
77+
params={{
78+
rangeFrom: 'now-15m',
79+
rangeTo: 'now',
80+
start: 'mystart',
81+
end: 'myend',
82+
}}
83+
>
84+
{children}
85+
</MockUrlParamsContextProvider>
86+
</MockApmPluginContextWrapper>
87+
</KibanaReactContext.Provider>
88+
</EuiThemeProvider>
89+
</IntlProvider>
90+
);
91+
}
92+
93+
describe('correlations', () => {
94+
describe('LatencyCorrelations', () => {
95+
it('shows loading indicator when the service is running and returned no results yet', async () => {
96+
render(
97+
<Wrapper
98+
dataSearchResponse={{
99+
isRunning: true,
100+
rawResponse: { ccsWarning: false, took: 1234, values: [], log: [] },
101+
}}
102+
>
103+
<LatencyCorrelations onFilter={jest.fn()} />
104+
</Wrapper>
105+
);
106+
107+
await waitFor(() => {
108+
expect(screen.getByTestId('apmCorrelationsChart')).toBeInTheDocument();
109+
expect(screen.getByTestId('loading')).toBeInTheDocument();
110+
});
111+
});
112+
113+
it("doesn't show loading indicator when the service isn't running", async () => {
114+
render(
115+
<Wrapper
116+
dataSearchResponse={{
117+
isRunning: false,
118+
rawResponse: { ccsWarning: false, took: 1234, values: [], log: [] },
119+
}}
120+
>
121+
<LatencyCorrelations onFilter={jest.fn()} />
122+
</Wrapper>
123+
);
124+
125+
await waitFor(() => {
126+
expect(screen.getByTestId('apmCorrelationsChart')).toBeInTheDocument();
127+
expect(screen.queryByTestId('loading')).toBeNull(); // it doesn't exist
128+
});
129+
});
130+
});
131+
});

x-pack/plugins/apm/public/components/app/correlations/latency_correlations.tsx

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export function LatencyCorrelations({ onFilter }: { onFilter: () => void }) {
6161

6262
const {
6363
query: { kuery, environment, rangeFrom, rangeTo },
64-
} = useApmParams('/services/:serviceName');
64+
} = useApmParams('/services/:serviceName/transactions/view');
6565

6666
const { urlParams } = useUrlParams();
6767

@@ -95,25 +95,21 @@ export function LatencyCorrelations({ onFilter }: { onFilter: () => void }) {
9595
end,
9696
percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD,
9797
});
98-
// eslint-disable-next-line react-hooks/exhaustive-deps
99-
}, [environment, serviceName, kuery, start, end]);
98+
}, [
99+
startFetch,
100+
environment,
101+
serviceName,
102+
transactionName,
103+
transactionType,
104+
kuery,
105+
start,
106+
end,
107+
]);
100108

101-
// start fetching on load
102-
// we want this effect to execute exactly once after the component mounts
103109
useEffect(() => {
104-
if (isRunning) {
105-
cancelFetch();
106-
}
107-
108110
startFetchHandler();
109-
110-
return () => {
111-
// cancel any running async partial request when unmounting the component
112-
// we want this effect to execute exactly once after the component mounts
113-
cancelFetch();
114-
};
115-
// eslint-disable-next-line react-hooks/exhaustive-deps
116-
}, [startFetchHandler]);
111+
return cancelFetch;
112+
}, [cancelFetch, startFetchHandler]);
117113

118114
useEffect(() => {
119115
if (isErrorMessage(error)) {

x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.test.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)