From 6d7998e70ce3919c9f33cd0357b63661488e585c Mon Sep 17 00:00:00 2001
From: Marshall Main <55718608+marshallmain@users.noreply.github.com>
Date: Thu, 26 Aug 2021 18:29:21 -0700
Subject: [PATCH 01/12] [Security Solution] Fix another reference to
ALERT_STATUS (#110376)
---
.../detections/components/alerts_table/default_config.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx
index 6608a0dd1458c..7e755ad654685 100644
--- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx
+++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/default_config.tsx
@@ -235,7 +235,7 @@ export const buildAlertStatusesFilterRuleRegistry = (statuses: Status[]): Filter
bool: {
should: statuses.map((status) => ({
term: {
- [ALERT_STATUS]: status,
+ [ALERT_WORKFLOW_STATUS]: status,
},
})),
},
From 49e3edf032466ea1b70eaca85406321bc6db7417 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cau=C3=AA=20Marcondes?=
<55978943+cauemarcondes@users.noreply.github.com>
Date: Thu, 26 Aug 2021 23:56:14 -0400
Subject: [PATCH 02/12] [APM] Latency threshold alerts are not being triggered
(#110315)
---
...egister_transaction_duration_alert_type.ts | 32 +++++++++++--------
1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts
index f3893a9da24c2..fedc185d84f9f 100644
--- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts
+++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts
@@ -5,9 +5,8 @@
* 2.0.
*/
-import { schema } from '@kbn/config-schema';
-import { take } from 'rxjs/operators';
import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types';
+import { schema } from '@kbn/config-schema';
import type {
ALERT_EVALUATION_THRESHOLD as ALERT_EVALUATION_THRESHOLD_TYPED,
ALERT_EVALUATION_VALUE as ALERT_EVALUATION_VALUE_TYPED,
@@ -19,33 +18,36 @@ import {
ALERT_REASON as ALERT_REASON_NON_TYPED,
// @ts-expect-error
} from '@kbn/rule-data-utils/target_node/technical_field_names';
-import { SearchAggregatedTransactionSetting } from '../../../common/aggregated_transactions';
+import { take } from 'rxjs/operators';
import { asDuration } from '../../../../observability/common/utils/formatters';
import { createLifecycleRuleTypeFactory } from '../../../../rule_registry/server';
-import {
- getEnvironmentLabel,
- getEnvironmentEsField,
-} from '../../../common/environment_filter_values';
+import { SearchAggregatedTransactionSetting } from '../../../common/aggregated_transactions';
import {
AlertType,
- APM_SERVER_FEATURE_ID,
ALERT_TYPES_CONFIG,
+ APM_SERVER_FEATURE_ID,
formatTransactionDurationReason,
} from '../../../common/alert_types';
import {
PROCESSOR_EVENT,
SERVICE_NAME,
- TRANSACTION_DURATION,
TRANSACTION_TYPE,
} from '../../../common/elasticsearch_fieldnames';
+import {
+ getEnvironmentEsField,
+ getEnvironmentLabel,
+} from '../../../common/environment_filter_values';
import { ProcessorEvent } from '../../../common/processor_event';
-import { getDurationFormatter } from '../../../common/utils/formatters';
import { environmentQuery } from '../../../common/utils/environment_query';
+import { getDurationFormatter } from '../../../common/utils/formatters';
+import {
+ getDocumentTypeFilterForAggregatedTransactions,
+ getTransactionDurationFieldForAggregatedTransactions,
+} from '../helpers/aggregated_transactions';
import { getApmIndices } from '../settings/apm_indices/get_apm_indices';
import { apmActionVariables } from './action_variables';
import { alertingEsClient } from './alerting_es_client';
import { RegisterRuleDependencies } from './register_apm_alerts';
-import { getDocumentTypeFilterForAggregatedTransactions } from '../helpers/aggregated_transactions';
const ALERT_EVALUATION_THRESHOLD: typeof ALERT_EVALUATION_THRESHOLD_TYPED = ALERT_EVALUATION_THRESHOLD_NON_TYPED;
const ALERT_EVALUATION_VALUE: typeof ALERT_EVALUATION_VALUE_TYPED = ALERT_EVALUATION_VALUE_NON_TYPED;
@@ -118,6 +120,10 @@ export function registerTransactionDurationAlertType({
? indices['apm_oss.metricsIndices']
: indices['apm_oss.transactionIndices'];
+ const field = getTransactionDurationFieldForAggregatedTransactions(
+ searchAggregatedTransactions
+ );
+
const searchParams = {
index,
body: {
@@ -148,10 +154,10 @@ export function registerTransactionDurationAlertType({
aggs: {
latency:
alertParams.aggregationType === 'avg'
- ? { avg: { field: TRANSACTION_DURATION } }
+ ? { avg: { field } }
: {
percentiles: {
- field: TRANSACTION_DURATION,
+ field,
percents: [
alertParams.aggregationType === '95th' ? 95 : 99,
],
From 5208cfdbc71127ae665d7c66068673a7b00efd8c Mon Sep 17 00:00:00 2001
From: Yaroslav Kuznietsov
Date: Fri, 27 Aug 2021 09:04:55 +0300
Subject: [PATCH 03/12] [Canvas] Fixes Expression errors are not rendered as
markdown.
---
src/plugins/expression_error/kibana.json | 2 +-
.../expression_error/public/components/error/error.tsx | 8 ++++++--
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/src/plugins/expression_error/kibana.json b/src/plugins/expression_error/kibana.json
index aa3201694619c..bf4eb51524ec6 100755
--- a/src/plugins/expression_error/kibana.json
+++ b/src/plugins/expression_error/kibana.json
@@ -11,5 +11,5 @@
"ui": true,
"requiredPlugins": ["expressions", "presentationUtil"],
"optionalPlugins": [],
- "requiredBundles": []
+ "requiredBundles": ["kibanaReact"]
}
diff --git a/src/plugins/expression_error/public/components/error/error.tsx b/src/plugins/expression_error/public/components/error/error.tsx
index 637309448da23..808424f9f4f8b 100644
--- a/src/plugins/expression_error/public/components/error/error.tsx
+++ b/src/plugins/expression_error/public/components/error/error.tsx
@@ -11,6 +11,7 @@ import { EuiCallOut } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { get } from 'lodash';
import { ShowDebugging } from './show_debugging';
+import { Markdown } from '../../../../kibana_react/public';
export interface Props {
payload: {
@@ -40,8 +41,11 @@ export const Error: FC = ({ payload }) => {
title={strings.getTitle()}
>
{message ? strings.getDescription() : ''}
- {message && {message}
}
-
+ {message && (
+
+
+
+ )}
);
From dfa6aa8bdf197414d98cda444fcf5a15c5478901 Mon Sep 17 00:00:00 2001
From: Yaroslav Kuznietsov
Date: Fri, 27 Aug 2021 09:06:31 +0300
Subject: [PATCH 04/12] [Canvas] Fixes Expression Failed Exit Button not
Clickable . (#110191)
* Fixed not clickable cross at error popup.
---
.../public/components/error/error.tsx | 14 +++++++++-----
.../public/components/error_component.tsx | 3 ++-
2 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/src/plugins/expression_error/public/components/error/error.tsx b/src/plugins/expression_error/public/components/error/error.tsx
index 808424f9f4f8b..2b42aa0f7eccd 100644
--- a/src/plugins/expression_error/public/components/error/error.tsx
+++ b/src/plugins/expression_error/public/components/error/error.tsx
@@ -7,9 +7,8 @@
*/
import React, { FC } from 'react';
-import { EuiCallOut } from '@elastic/eui';
+import { EuiButtonIcon, EuiCallOut } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import { get } from 'lodash';
import { ShowDebugging } from './show_debugging';
import { Markdown } from '../../../../kibana_react/public';
@@ -17,6 +16,7 @@ export interface Props {
payload: {
error: Error;
};
+ onClose?: () => void;
}
const strings = {
@@ -30,14 +30,18 @@ const strings = {
}),
};
-export const Error: FC = ({ payload }) => {
- const message = get(payload, 'error.message');
+export const Error: FC = ({ payload, onClose }) => {
+ const message = payload.error?.message;
+
+ const CloseIconButton = () => (
+
+ );
return (
{message ? strings.getDescription() : ''}
diff --git a/src/plugins/expression_error/public/components/error_component.tsx b/src/plugins/expression_error/public/components/error_component.tsx
index 58161d8a068a2..2a019c9ce6945 100644
--- a/src/plugins/expression_error/public/components/error_component.tsx
+++ b/src/plugins/expression_error/public/components/error_component.tsx
@@ -28,6 +28,7 @@ function ErrorComponent({ onLoaded, parentNode, error }: ErrorComponentProps) {
const [isPopoverOpen, setPopoverOpen] = useState(false);
const handlePopoverClick = () => setPopoverOpen(!isPopoverOpen);
+
const closePopover = () => setPopoverOpen(false);
const updateErrorView = useCallback(() => {
@@ -56,7 +57,7 @@ function ErrorComponent({ onLoaded, parentNode, error }: ErrorComponentProps) {
}
isOpen={isPopoverOpen}
>
-
+
);
From dde701faaaef3ef6ff3160aa0d16d0696710c409 Mon Sep 17 00:00:00 2001
From: Yaroslav Kuznietsov
Date: Fri, 27 Aug 2021 09:26:55 +0300
Subject: [PATCH 05/12] [Canvas] ItemGrid refactor. (#110044)
---
x-pack/plugins/canvas/public/components/item_grid/index.ts | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/x-pack/plugins/canvas/public/components/item_grid/index.ts b/x-pack/plugins/canvas/public/components/item_grid/index.ts
index 5e17416c30321..5ad51718bc109 100644
--- a/x-pack/plugins/canvas/public/components/item_grid/index.ts
+++ b/x-pack/plugins/canvas/public/components/item_grid/index.ts
@@ -4,8 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
-
-import { pure } from 'recompose';
+import { memo } from 'react';
import { ItemGrid as Component, Props as ComponentProps } from './item_grid';
-export const ItemGrid = pure>(Component);
+export const ItemGrid = memo>(Component);
From 2e4e0fca4c4c4a1e168b9a62a3b151a3735436dc Mon Sep 17 00:00:00 2001
From: Catherine Liu
Date: Thu, 26 Aug 2021 23:46:11 -0700
Subject: [PATCH 06/12] Clears resolved arg on embeddable destroy (#109945)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
---
x-pack/plugins/canvas/public/lib/create_handlers.ts | 3 +++
1 file changed, 3 insertions(+)
diff --git a/x-pack/plugins/canvas/public/lib/create_handlers.ts b/x-pack/plugins/canvas/public/lib/create_handlers.ts
index aba29ccd542be..dfc4387bcbf92 100644
--- a/x-pack/plugins/canvas/public/lib/create_handlers.ts
+++ b/x-pack/plugins/canvas/public/lib/create_handlers.ts
@@ -14,6 +14,7 @@ import {
import { setFilter } from '../state/actions/elements';
import { updateEmbeddableExpression, fetchEmbeddableRenderable } from '../state/actions/embeddable';
import { RendererHandlers, CanvasElement } from '../../types';
+import { clearValue } from '../state/actions/resolved_args';
// This class creates stub handlers to ensure every element and renderer fulfills the contract.
// TODO: consider warning if these methods are invoked but not implemented by the renderer...?
@@ -123,6 +124,8 @@ export const createDispatchedHandlerFactory = (
},
onEmbeddableDestroyed() {
+ const argumentPath = [element.id, 'expressionRenderable'];
+ dispatch(clearValue({ path: argumentPath }));
dispatch(fetchEmbeddableRenderable(element.id));
},
From 73f8a92a333bd20d7784af9b373849374b5818b6 Mon Sep 17 00:00:00 2001
From: Tyler Smalley
Date: Fri, 27 Aug 2021 00:30:59 -0700
Subject: [PATCH 07/12] [bazel] Move keepalive to common (#110351)
Signed-off-by: Tyler Smalley
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
---
src/dev/ci_setup/.bazelrc-ci | 3 ---
src/dev/ci_setup/.bazelrc-ci.common | 3 +++
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/dev/ci_setup/.bazelrc-ci b/src/dev/ci_setup/.bazelrc-ci
index bb8710d69ed54..ef6fab3a30590 100644
--- a/src/dev/ci_setup/.bazelrc-ci
+++ b/src/dev/ci_setup/.bazelrc-ci
@@ -12,8 +12,5 @@ build --bes_backend=grpcs://cloud.buildbuddy.io
build --remote_cache=grpcs://cloud.buildbuddy.io
build --remote_timeout=3600
-## Avoid to keep connections to build event backend connections alive across builds
-build --keep_backend_build_event_connections_alive=false
-
## Metadata settings
build --build_metadata=ROLE=CI
diff --git a/src/dev/ci_setup/.bazelrc-ci.common b/src/dev/ci_setup/.bazelrc-ci.common
index 9d00ee5639741..56a5ee8d30cd6 100644
--- a/src/dev/ci_setup/.bazelrc-ci.common
+++ b/src/dev/ci_setup/.bazelrc-ci.common
@@ -6,3 +6,6 @@ build --noshow_progress
# More details on failures
build --verbose_failures=true
+
+## Avoid to keep connections to build event backend connections alive across builds
+build --keep_backend_build_event_connections_alive=false
From d43e9f586bee4bbf040c4c895a9a0783faf5020e Mon Sep 17 00:00:00 2001
From: Yaroslav Kuznietsov
Date: Fri, 27 Aug 2021 13:58:10 +0300
Subject: [PATCH 08/12] [Canvas] Fixes Storybook for DatasourceComponent is
crashing. (#110180)
* Added mock for `es_service`.
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
---
.../plugins/canvas/storybook/__mocks__/es_service.ts | 10 ++++++++++
x-pack/plugins/canvas/storybook/main.ts | 4 ++++
2 files changed, 14 insertions(+)
create mode 100644 x-pack/plugins/canvas/storybook/__mocks__/es_service.ts
diff --git a/x-pack/plugins/canvas/storybook/__mocks__/es_service.ts b/x-pack/plugins/canvas/storybook/__mocks__/es_service.ts
new file mode 100644
index 0000000000000..686fd7b4fa947
--- /dev/null
+++ b/x-pack/plugins/canvas/storybook/__mocks__/es_service.ts
@@ -0,0 +1,10 @@
+/*
+ * 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.
+ */
+
+export const getDefaultIndex = () => {
+ return Promise.resolve('Demonstration index');
+};
diff --git a/x-pack/plugins/canvas/storybook/main.ts b/x-pack/plugins/canvas/storybook/main.ts
index 69c05322cf3f0..a043efd7c87f5 100644
--- a/x-pack/plugins/canvas/storybook/main.ts
+++ b/x-pack/plugins/canvas/storybook/main.ts
@@ -56,6 +56,10 @@ const canvasWebpack = {
resolve: {
alias: {
'src/plugins': resolve(KIBANA_ROOT, 'src/plugins'),
+ '../../lib/es_service': resolve(
+ KIBANA_ROOT,
+ 'x-pack/plugins/canvas/storybook/__mocks__/es_service.ts'
+ ),
},
},
};
From 54a45bba6532eacc4b59befd2cb0d203ce9298ed Mon Sep 17 00:00:00 2001
From: Walter Rafelsberger
Date: Fri, 27 Aug 2021 13:08:50 +0200
Subject: [PATCH 09/12] [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.
---
.../search_strategies/correlations/types.ts | 9 ++
.../app/correlations/empty_state_prompt.tsx | 3 +-
.../failed_transactions_correlations.tsx | 49 +++---
.../latency_correlations.test.tsx | 131 +++++++++++++++
.../app/correlations/latency_correlations.tsx | 30 ++--
.../distribution/index.test.ts | 22 ---
.../distribution/index.test.tsx | 151 ++++++++++++++++++
.../distribution/index.tsx | 58 ++++---
.../transaction_details/trace_samples_tab.tsx | 28 ++--
.../shared/charts/chart_container.tsx | 4 +-
.../transaction_distribution_chart/index.tsx | 45 ++++--
...ailed_transactions_correlations_fetcher.ts | 93 +++++------
.../use_transaction_distribution_fetcher.ts | 136 ++++++++--------
...ransaction_latency_correlations_fetcher.ts | 143 +++++++++--------
.../correlations/search_strategy.ts | 19 ++-
15 files changed, 621 insertions(+), 300 deletions(-)
create mode 100644 x-pack/plugins/apm/public/components/app/correlations/latency_correlations.test.tsx
delete mode 100644 x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.test.ts
create mode 100644 x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.test.tsx
diff --git a/x-pack/plugins/apm/common/search_strategies/correlations/types.ts b/x-pack/plugins/apm/common/search_strategies/correlations/types.ts
index 703106628f561..886c5fd6161d8 100644
--- a/x-pack/plugins/apm/common/search_strategies/correlations/types.ts
+++ b/x-pack/plugins/apm/common/search_strategies/correlations/types.ts
@@ -52,3 +52,12 @@ export interface AsyncSearchProviderProgress {
loadedFieldValuePairs: number;
loadedHistograms: number;
}
+
+export interface SearchServiceRawResponse {
+ ccsWarning: boolean;
+ log: string[];
+ overallHistogram?: HistogramItem[];
+ percentileThresholdValue?: number;
+ took: number;
+ values: SearchServiceValue[];
+}
diff --git a/x-pack/plugins/apm/public/components/app/correlations/empty_state_prompt.tsx b/x-pack/plugins/apm/public/components/app/correlations/empty_state_prompt.tsx
index 57e57a526baff..9b161fc1b9fa9 100644
--- a/x-pack/plugins/apm/public/components/app/correlations/empty_state_prompt.tsx
+++ b/x-pack/plugins/apm/public/components/app/correlations/empty_state_prompt.tsx
@@ -33,8 +33,7 @@ export function CorrelationsEmptyStatePrompt() {
id="xpack.apm.correlations.noCorrelationsTextLine1"
defaultMessage="Correlations will only be identified if they have significant impact."
/>
-
-
+
(enableInspectEsQueries);
- const searchServicePrams: SearchServiceParams = {
- environment,
- kuery,
- serviceName,
- transactionName,
- transactionType,
- start,
- end,
- };
-
const result = useFailedTransactionsCorrelationsFetcher();
const {
@@ -93,26 +82,30 @@ export function FailedTransactionsCorrelations({
} = result;
const startFetchHandler = useCallback(() => {
- startFetch(searchServicePrams);
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [environment, serviceName, kuery, start, end]);
+ startFetch({
+ environment,
+ kuery,
+ serviceName,
+ transactionName,
+ transactionType,
+ start,
+ end,
+ });
+ }, [
+ startFetch,
+ environment,
+ serviceName,
+ transactionName,
+ transactionType,
+ kuery,
+ start,
+ end,
+ ]);
- // start fetching on load
- // we want this effect to execute exactly once after the component mounts
useEffect(() => {
- if (isRunning) {
- cancelFetch();
- }
-
startFetchHandler();
-
- return () => {
- // cancel any running async partial request when unmounting the component
- // we want this effect to execute exactly once after the component mounts
- cancelFetch();
- };
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [startFetchHandler]);
+ return cancelFetch;
+ }, [cancelFetch, startFetchHandler]);
const [
selectedSignificantTerm,
diff --git a/x-pack/plugins/apm/public/components/app/correlations/latency_correlations.test.tsx b/x-pack/plugins/apm/public/components/app/correlations/latency_correlations.test.tsx
new file mode 100644
index 0000000000000..b0da5b6d60d74
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/app/correlations/latency_correlations.test.tsx
@@ -0,0 +1,131 @@
+/*
+ * 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 { render, screen, waitFor } from '@testing-library/react';
+import { createMemoryHistory } from 'history';
+import React, { ReactNode } from 'react';
+import { of } from 'rxjs';
+
+import { __IntlProvider as IntlProvider } from '@kbn/i18n/react';
+
+import { CoreStart } from 'kibana/public';
+import { merge } from 'lodash';
+import { dataPluginMock } from 'src/plugins/data/public/mocks';
+import type { IKibanaSearchResponse } from 'src/plugins/data/public';
+import { EuiThemeProvider } from 'src/plugins/kibana_react/common';
+import { createKibanaReactContext } from 'src/plugins/kibana_react/public';
+import type { SearchServiceRawResponse } from '../../../../common/search_strategies/correlations/types';
+import { MockUrlParamsContextProvider } from '../../../context/url_params_context/mock_url_params_context_provider';
+import { ApmPluginContextValue } from '../../../context/apm_plugin/apm_plugin_context';
+import {
+ mockApmPluginContextValue,
+ MockApmPluginContextWrapper,
+} from '../../../context/apm_plugin/mock_apm_plugin_context';
+import { fromQuery } from '../../shared/Links/url_helpers';
+
+import { LatencyCorrelations } from './latency_correlations';
+
+function Wrapper({
+ children,
+ dataSearchResponse,
+}: {
+ children?: ReactNode;
+ dataSearchResponse: IKibanaSearchResponse;
+}) {
+ const mockDataSearch = jest.fn(() => of(dataSearchResponse));
+
+ const dataPluginMockStart = dataPluginMock.createStartContract();
+ const KibanaReactContext = createKibanaReactContext({
+ data: {
+ ...dataPluginMockStart,
+ search: {
+ ...dataPluginMockStart.search,
+ search: mockDataSearch,
+ },
+ },
+ usageCollection: { reportUiCounter: () => {} },
+ } as Partial);
+
+ const httpGet = jest.fn();
+
+ const history = createMemoryHistory();
+ jest.spyOn(history, 'push');
+ jest.spyOn(history, 'replace');
+
+ history.replace({
+ pathname: '/services/the-service-name/transactions/view',
+ search: fromQuery({ transactionName: 'the-transaction-name' }),
+ });
+
+ const mockPluginContext = (merge({}, mockApmPluginContextValue, {
+ core: { http: { get: httpGet } },
+ }) as unknown) as ApmPluginContextValue;
+
+ return (
+
+
+
+
+
+ {children}
+
+
+
+
+
+ );
+}
+
+describe('correlations', () => {
+ describe('LatencyCorrelations', () => {
+ it('shows loading indicator when the service is running and returned no results yet', async () => {
+ render(
+
+
+
+ );
+
+ await waitFor(() => {
+ expect(screen.getByTestId('apmCorrelationsChart')).toBeInTheDocument();
+ expect(screen.getByTestId('loading')).toBeInTheDocument();
+ });
+ });
+
+ it("doesn't show loading indicator when the service isn't running", async () => {
+ render(
+
+
+
+ );
+
+ await waitFor(() => {
+ expect(screen.getByTestId('apmCorrelationsChart')).toBeInTheDocument();
+ expect(screen.queryByTestId('loading')).toBeNull(); // it doesn't exist
+ });
+ });
+ });
+});
diff --git a/x-pack/plugins/apm/public/components/app/correlations/latency_correlations.tsx b/x-pack/plugins/apm/public/components/app/correlations/latency_correlations.tsx
index 74702e621a0ba..ad8a56a3ac6f9 100644
--- a/x-pack/plugins/apm/public/components/app/correlations/latency_correlations.tsx
+++ b/x-pack/plugins/apm/public/components/app/correlations/latency_correlations.tsx
@@ -61,7 +61,7 @@ export function LatencyCorrelations({ onFilter }: { onFilter: () => void }) {
const {
query: { kuery, environment, rangeFrom, rangeTo },
- } = useApmParams('/services/:serviceName');
+ } = useApmParams('/services/:serviceName/transactions/view');
const { urlParams } = useUrlParams();
@@ -95,25 +95,21 @@ export function LatencyCorrelations({ onFilter }: { onFilter: () => void }) {
end,
percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD,
});
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [environment, serviceName, kuery, start, end]);
+ }, [
+ startFetch,
+ environment,
+ serviceName,
+ transactionName,
+ transactionType,
+ kuery,
+ start,
+ end,
+ ]);
- // start fetching on load
- // we want this effect to execute exactly once after the component mounts
useEffect(() => {
- if (isRunning) {
- cancelFetch();
- }
-
startFetchHandler();
-
- return () => {
- // cancel any running async partial request when unmounting the component
- // we want this effect to execute exactly once after the component mounts
- cancelFetch();
- };
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [startFetchHandler]);
+ return cancelFetch;
+ }, [cancelFetch, startFetchHandler]);
useEffect(() => {
if (isErrorMessage(error)) {
diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.test.ts b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.test.ts
deleted file mode 100644
index f541c16e655ab..0000000000000
--- a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.test.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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 { getFormattedSelection } from './index';
-
-describe('transaction_details/distribution', () => {
- describe('getFormattedSelection', () => {
- it('displays only one unit if from and to share the same unit', () => {
- expect(getFormattedSelection([10000, 100000])).toEqual('10 - 100 ms');
- });
-
- it('displays two units when from and to have different units', () => {
- expect(getFormattedSelection([100000, 1000000000])).toEqual(
- '100 ms - 17 min'
- );
- });
- });
-});
diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.test.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.test.tsx
new file mode 100644
index 0000000000000..5a9977b373c33
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.test.tsx
@@ -0,0 +1,151 @@
+/*
+ * 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 { render, screen, waitFor } from '@testing-library/react';
+import { createMemoryHistory } from 'history';
+import React, { ReactNode } from 'react';
+import { of } from 'rxjs';
+
+import { CoreStart } from 'kibana/public';
+import { merge } from 'lodash';
+import { dataPluginMock } from 'src/plugins/data/public/mocks';
+import type { IKibanaSearchResponse } from 'src/plugins/data/public';
+import { EuiThemeProvider } from 'src/plugins/kibana_react/common';
+import { createKibanaReactContext } from 'src/plugins/kibana_react/public';
+import type { SearchServiceRawResponse } from '../../../../../common/search_strategies/correlations/types';
+import { MockUrlParamsContextProvider } from '../../../../context/url_params_context/mock_url_params_context_provider';
+import { ApmPluginContextValue } from '../../../../context/apm_plugin/apm_plugin_context';
+import {
+ mockApmPluginContextValue,
+ MockApmPluginContextWrapper,
+} from '../../../../context/apm_plugin/mock_apm_plugin_context';
+import { fromQuery } from '../../../shared/Links/url_helpers';
+
+import { getFormattedSelection, TransactionDistribution } from './index';
+
+function Wrapper({
+ children,
+ dataSearchResponse,
+}: {
+ children?: ReactNode;
+ dataSearchResponse: IKibanaSearchResponse;
+}) {
+ const mockDataSearch = jest.fn(() => of(dataSearchResponse));
+
+ const dataPluginMockStart = dataPluginMock.createStartContract();
+ const KibanaReactContext = createKibanaReactContext({
+ data: {
+ ...dataPluginMockStart,
+ search: {
+ ...dataPluginMockStart.search,
+ search: mockDataSearch,
+ },
+ },
+ usageCollection: { reportUiCounter: () => {} },
+ } as Partial);
+
+ const httpGet = jest.fn();
+
+ const history = createMemoryHistory();
+ jest.spyOn(history, 'push');
+ jest.spyOn(history, 'replace');
+
+ history.replace({
+ pathname: '/services/the-service-name/transactions/view',
+ search: fromQuery({ transactionName: 'the-transaction-name' }),
+ });
+
+ const mockPluginContext = (merge({}, mockApmPluginContextValue, {
+ core: { http: { get: httpGet } },
+ }) as unknown) as ApmPluginContextValue;
+
+ return (
+
+
+
+
+ {children}
+
+
+
+
+ );
+}
+
+describe('transaction_details/distribution', () => {
+ describe('getFormattedSelection', () => {
+ it('displays only one unit if from and to share the same unit', () => {
+ expect(getFormattedSelection([10000, 100000])).toEqual('10 - 100 ms');
+ });
+
+ it('displays two units when from and to have different units', () => {
+ expect(getFormattedSelection([100000, 1000000000])).toEqual(
+ '100 ms - 17 min'
+ );
+ });
+ });
+
+ describe('TransactionDistribution', () => {
+ it('shows loading indicator when the service is running and returned no results yet', async () => {
+ const onHasData = jest.fn();
+ render(
+
+
+
+ );
+
+ await waitFor(() => {
+ expect(screen.getByTestId('apmCorrelationsChart')).toBeInTheDocument();
+ expect(screen.getByTestId('loading')).toBeInTheDocument();
+ expect(onHasData).toHaveBeenLastCalledWith(false);
+ });
+ });
+
+ it("doesn't show loading indicator when the service isn't running", async () => {
+ const onHasData = jest.fn();
+ render(
+
+
+
+ );
+
+ await waitFor(() => {
+ expect(screen.getByTestId('apmCorrelationsChart')).toBeInTheDocument();
+ expect(screen.queryByTestId('loading')).toBeNull(); // it doesn't exist
+ expect(onHasData).toHaveBeenLastCalledWith(false);
+ });
+ });
+ });
+});
diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx
index 86ebc04944cd5..2da61bc0fc555 100644
--- a/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/transaction_details/distribution/index.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
-import React, { useEffect } from 'react';
+import React, { useCallback, useEffect, useState } from 'react';
import { BrushEndListener, XYBrushArea } from '@elastic/charts';
import {
EuiBadge,
@@ -21,7 +21,10 @@ import { getDurationFormatter } from '../../../../../common/utils/formatters';
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context';
import { useTransactionDistributionFetcher } from '../../../../hooks/use_transaction_distribution_fetcher';
-import { TransactionDistributionChart } from '../../../shared/charts/transaction_distribution_chart';
+import {
+ OnHasData,
+ TransactionDistributionChart,
+} from '../../../shared/charts/transaction_distribution_chart';
import { useUiTracker } from '../../../../../../observability/public';
import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context';
import { useApmParams } from '../../../../hooks/use_apm_params';
@@ -47,10 +50,11 @@ export function getFormattedSelection(selection: Selection): string {
}`;
}
-interface Props {
+interface TransactionDistributionProps {
markerCurrentTransaction?: number;
onChartSelection: BrushEndListener;
onClearSelection: () => void;
+ onHasData: OnHasData;
selection?: Selection;
}
@@ -58,8 +62,9 @@ export function TransactionDistribution({
markerCurrentTransaction,
onChartSelection,
onClearSelection,
+ onHasData,
selection,
-}: Props) {
+}: TransactionDistributionProps) {
const {
core: { notifications },
} = useApmPluginContext();
@@ -68,7 +73,7 @@ export function TransactionDistribution({
const {
query: { kuery, environment, rangeFrom, rangeTo },
- } = useApmParams('/services/:serviceName');
+ } = useApmParams('/services/:serviceName/transactions/view');
const { start, end } = useTimeRange({ rangeFrom, rangeTo });
@@ -76,6 +81,16 @@ export function TransactionDistribution({
const { transactionName } = urlParams;
+ const [showSelection, setShowSelection] = useState(false);
+
+ const onTransactionDistributionHasData: OnHasData = useCallback(
+ (hasData) => {
+ setShowSelection(hasData);
+ onHasData(hasData);
+ },
+ [onHasData]
+ );
+
const emptySelectionText = i18n.translate(
'xpack.apm.transactionDetails.emptySelectionText',
{
@@ -93,17 +108,12 @@ export function TransactionDistribution({
const {
error,
percentileThresholdValue,
- isRunning,
startFetch,
cancelFetch,
transactionDistribution,
} = useTransactionDistributionFetcher();
- useEffect(() => {
- if (isRunning) {
- cancelFetch();
- }
-
+ const startFetchHandler = useCallback(() => {
startFetch({
environment,
kuery,
@@ -114,14 +124,21 @@ export function TransactionDistribution({
end,
percentileThreshold: DEFAULT_PERCENTILE_THRESHOLD,
});
+ }, [
+ startFetch,
+ environment,
+ serviceName,
+ transactionName,
+ transactionType,
+ kuery,
+ start,
+ end,
+ ]);
- return () => {
- // cancel any running async partial request when unmounting the component
- // we want this effect to execute exactly once after the component mounts
- cancelFetch();
- };
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [environment, serviceName, kuery, start, end]);
+ useEffect(() => {
+ startFetchHandler();
+ return cancelFetch;
+ }, [cancelFetch, startFetchHandler]);
useEffect(() => {
if (isErrorMessage(error)) {
@@ -166,7 +183,7 @@ export function TransactionDistribution({
- {!selection && (
+ {showSelection && !selection && (
)}
- {selection && (
+ {showSelection && selection && (
diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/trace_samples_tab.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/trace_samples_tab.tsx
index 0421fcd055d6c..ea02cfea5a941 100644
--- a/x-pack/plugins/apm/public/components/app/transaction_details/trace_samples_tab.tsx
+++ b/x-pack/plugins/apm/public/components/app/transaction_details/trace_samples_tab.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
-import React from 'react';
+import React, { useState } from 'react';
import { EuiSpacer } from '@elastic/eui';
@@ -34,11 +34,17 @@ function TraceSamplesTab({
status: waterfallStatus,
} = useWaterfallFetcher();
+ const [
+ transactionDistributionHasData,
+ setTransactionDistributionHasData,
+ ] = useState(false);
+
return (
<>
-
+ {transactionDistributionHasData && (
+ <>
+
-
+
+ >
+ )}
>
);
}
diff --git a/x-pack/plugins/apm/public/components/shared/charts/chart_container.tsx b/x-pack/plugins/apm/public/components/shared/charts/chart_container.tsx
index 4098fc5e696db..695e62b3b7d78 100644
--- a/x-pack/plugins/apm/public/components/shared/charts/chart_container.tsx
+++ b/x-pack/plugins/apm/public/components/shared/charts/chart_container.tsx
@@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n';
import React from 'react';
import { FETCH_STATUS } from '../../../hooks/use_fetcher';
-interface Props {
+export interface ChartContainerProps {
hasData: boolean;
status: FETCH_STATUS;
height: number;
@@ -24,7 +24,7 @@ export function ChartContainer({
status,
hasData,
id,
-}: Props) {
+}: ChartContainerProps) {
if (!hasData && status === FETCH_STATUS.LOADING) {
return ;
}
diff --git a/x-pack/plugins/apm/public/components/shared/charts/transaction_distribution_chart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/transaction_distribution_chart/index.tsx
index c511a708058d3..a58a2887b1576 100644
--- a/x-pack/plugins/apm/public/components/shared/charts/transaction_distribution_chart/index.tsx
+++ b/x-pack/plugins/apm/public/components/shared/charts/transaction_distribution_chart/index.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
-import React, { useMemo } from 'react';
+import React, { useEffect, useMemo } from 'react';
import {
AnnotationDomainType,
AreaSeries,
@@ -35,7 +35,14 @@ import { HistogramItem } from '../../../../../common/search_strategies/correlati
import { FETCH_STATUS } from '../../../../hooks/use_fetcher';
import { useTheme } from '../../../../hooks/use_theme';
-import { ChartContainer } from '../chart_container';
+import { ChartContainer, ChartContainerProps } from '../chart_container';
+
+export type TransactionDistributionChartLoadingState = Pick<
+ ChartContainerProps,
+ 'hasData' | 'status'
+>;
+
+export type OnHasData = (hasData: boolean) => void;
interface TransactionDistributionChartProps {
field?: string;
@@ -46,6 +53,7 @@ interface TransactionDistributionChartProps {
markerPercentile: number;
overallHistogram?: HistogramItem[];
onChartSelection?: BrushEndListener;
+ onHasData?: OnHasData;
selection?: [number, number];
}
@@ -103,6 +111,7 @@ export function TransactionDistributionChart({
markerPercentile,
overallHistogram,
onChartSelection,
+ onHasData,
selection,
}: TransactionDistributionChartProps) {
const chartTheme = useChartTheme();
@@ -154,6 +163,24 @@ export function TransactionDistributionChart({
]
: undefined;
+ const chartLoadingState: TransactionDistributionChartLoadingState = useMemo(
+ () => ({
+ hasData:
+ Array.isArray(patchedOverallHistogram) &&
+ patchedOverallHistogram.length > 0,
+ status: Array.isArray(patchedOverallHistogram)
+ ? FETCH_STATUS.SUCCESS
+ : FETCH_STATUS.LOADING,
+ }),
+ [patchedOverallHistogram]
+ );
+
+ useEffect(() => {
+ if (onHasData) {
+ onHasData(chartLoadingState.hasData);
+ }
+ }, [chartLoadingState, onHasData]);
+
return (
0
- }
- status={
- Array.isArray(patchedOverallHistogram)
- ? FETCH_STATUS.SUCCESS
- : FETCH_STATUS.LOADING
- }
+ hasData={chartLoadingState.hasData}
+ status={chartLoadingState.status}
>
{
}));
}
- const startFetch = (params: SearchServiceParams) => {
- setFetchState((prevState) => ({
- ...prevState,
- error: undefined,
- isComplete: false,
- }));
- searchSubscription$.current?.unsubscribe();
- abortCtrl.current.abort();
- abortCtrl.current = new AbortController();
+ const startFetch = useCallback(
+ (params: SearchServiceParams) => {
+ setFetchState((prevState) => ({
+ ...prevState,
+ error: undefined,
+ isComplete: false,
+ }));
+ searchSubscription$.current?.unsubscribe();
+ abortCtrl.current.abort();
+ abortCtrl.current = new AbortController();
- const req = { params };
+ const req = { params };
- // Submit the search request using the `data.search` service.
- searchSubscription$.current = data.search
- .search>(req, {
- strategy: FAILED_TRANSACTIONS_CORRELATION_SEARCH_STRATEGY,
- abortSignal: abortCtrl.current.signal,
- })
- .subscribe({
- next: (res: IKibanaSearchResponse) => {
- setResponse(res);
- if (isCompleteResponse(res)) {
- searchSubscription$.current?.unsubscribe();
+ // Submit the search request using the `data.search` service.
+ searchSubscription$.current = data.search
+ .search>(req, {
+ strategy: FAILED_TRANSACTIONS_CORRELATION_SEARCH_STRATEGY,
+ abortSignal: abortCtrl.current.signal,
+ })
+ .subscribe({
+ next: (res: IKibanaSearchResponse) => {
+ setResponse(res);
+ if (isCompleteResponse(res)) {
+ searchSubscription$.current?.unsubscribe();
+ setFetchState((prevState) => ({
+ ...prevState,
+ isRunnning: false,
+ isComplete: true,
+ }));
+ } else if (isErrorResponse(res)) {
+ searchSubscription$.current?.unsubscribe();
+ setFetchState((prevState) => ({
+ ...prevState,
+ error: (res as unknown) as Error,
+ isRunning: false,
+ }));
+ }
+ },
+ error: (error: Error) => {
setFetchState((prevState) => ({
...prevState,
- isRunnning: false,
- isComplete: true,
+ error,
+ isRunning: false,
}));
- } else if (isErrorResponse(res)) {
- searchSubscription$.current?.unsubscribe();
- setFetchState((prevState) => ({
- ...prevState,
- error: (res as unknown) as Error,
- setIsRunning: false,
- }));
- }
- },
- error: (error: Error) => {
- setFetchState((prevState) => ({
- ...prevState,
- error,
- setIsRunning: false,
- }));
- },
- });
- };
+ },
+ });
+ },
+ [data.search, setFetchState]
+ );
- const cancelFetch = () => {
+ const cancelFetch = useCallback(() => {
searchSubscription$.current?.unsubscribe();
searchSubscription$.current = undefined;
abortCtrl.current.abort();
setFetchState((prevState) => ({
...prevState,
- setIsRunning: false,
+ isRunning: false,
}));
- };
+ }, [setFetchState]);
return {
...fetchState,
diff --git a/x-pack/plugins/apm/public/hooks/use_transaction_distribution_fetcher.ts b/x-pack/plugins/apm/public/hooks/use_transaction_distribution_fetcher.ts
index 870dc8030d70b..2ff1b83ef1782 100644
--- a/x-pack/plugins/apm/public/hooks/use_transaction_distribution_fetcher.ts
+++ b/x-pack/plugins/apm/public/hooks/use_transaction_distribution_fetcher.ts
@@ -5,7 +5,7 @@
* 2.0.
*/
-import { useRef, useState } from 'react';
+import { useCallback, useRef, useState } from 'react';
import type { Subscription } from 'rxjs';
import {
IKibanaSearchRequest,
@@ -14,31 +14,21 @@ import {
isErrorResponse,
} from '../../../../../src/plugins/data/public';
import type {
- HistogramItem,
SearchServiceParams,
- SearchServiceValue,
+ SearchServiceRawResponse,
} from '../../common/search_strategies/correlations/types';
import { useKibana } from '../../../../../src/plugins/kibana_react/public';
import { ApmPluginStartDeps } from '../plugin';
-interface RawResponse {
- percentileThresholdValue?: number;
- took: number;
- values: SearchServiceValue[];
- overallHistogram: HistogramItem[];
- log: string[];
- ccsWarning: boolean;
-}
-
interface TransactionDistributionFetcherState {
error?: Error;
isComplete: boolean;
isRunning: boolean;
loaded: number;
- ccsWarning: RawResponse['ccsWarning'];
- log: RawResponse['log'];
- transactionDistribution?: RawResponse['overallHistogram'];
- percentileThresholdValue?: RawResponse['percentileThresholdValue'];
+ ccsWarning: SearchServiceRawResponse['ccsWarning'];
+ log: SearchServiceRawResponse['log'];
+ transactionDistribution?: SearchServiceRawResponse['overallHistogram'];
+ percentileThresholdValue?: SearchServiceRawResponse['percentileThresholdValue'];
timeTook?: number;
total: number;
}
@@ -63,7 +53,9 @@ export function useTransactionDistributionFetcher() {
const abortCtrl = useRef(new AbortController());
const searchSubscription$ = useRef();
- function setResponse(response: IKibanaSearchResponse) {
+ function setResponse(
+ response: IKibanaSearchResponse
+ ) {
setFetchState((prevState) => ({
...prevState,
isRunning: response.isRunning || false,
@@ -83,71 +75,81 @@ export function useTransactionDistributionFetcher() {
response.rawResponse?.percentileThresholdValue,
}
: {}),
+ // if loading is done but didn't return any data for the overall histogram,
+ // set it to an empty array so the consuming chart component knows loading is done.
+ ...(!response.isRunning &&
+ response.rawResponse?.overallHistogram === undefined
+ ? { transactionDistribution: [] }
+ : {}),
}));
}
- const startFetch = (
- params: Omit
- ) => {
- setFetchState((prevState) => ({
- ...prevState,
- error: undefined,
- isComplete: false,
- }));
- searchSubscription$.current?.unsubscribe();
- abortCtrl.current.abort();
- abortCtrl.current = new AbortController();
+ const startFetch = useCallback(
+ (params: Omit) => {
+ setFetchState((prevState) => ({
+ ...prevState,
+ error: undefined,
+ isComplete: false,
+ }));
+ searchSubscription$.current?.unsubscribe();
+ abortCtrl.current.abort();
+ abortCtrl.current = new AbortController();
- const searchServiceParams: SearchServiceParams = {
- ...params,
- analyzeCorrelations: false,
- };
- const req = { params: searchServiceParams };
+ const searchServiceParams: SearchServiceParams = {
+ ...params,
+ analyzeCorrelations: false,
+ };
+ const req = { params: searchServiceParams };
- // Submit the search request using the `data.search` service.
- searchSubscription$.current = data.search
- .search>(req, {
- strategy: 'apmCorrelationsSearchStrategy',
- abortSignal: abortCtrl.current.signal,
- })
- .subscribe({
- next: (res: IKibanaSearchResponse) => {
- setResponse(res);
- if (isCompleteResponse(res)) {
- searchSubscription$.current?.unsubscribe();
- setFetchState((prevState) => ({
- ...prevState,
- isRunnning: false,
- isComplete: true,
- }));
- } else if (isErrorResponse(res)) {
- searchSubscription$.current?.unsubscribe();
+ // Submit the search request using the `data.search` service.
+ searchSubscription$.current = data.search
+ .search<
+ IKibanaSearchRequest,
+ IKibanaSearchResponse
+ >(req, {
+ strategy: 'apmCorrelationsSearchStrategy',
+ abortSignal: abortCtrl.current.signal,
+ })
+ .subscribe({
+ next: (res: IKibanaSearchResponse) => {
+ setResponse(res);
+ if (isCompleteResponse(res)) {
+ searchSubscription$.current?.unsubscribe();
+ setFetchState((prevState) => ({
+ ...prevState,
+ isRunnning: false,
+ isComplete: true,
+ }));
+ } else if (isErrorResponse(res)) {
+ searchSubscription$.current?.unsubscribe();
+ setFetchState((prevState) => ({
+ ...prevState,
+ error: (res as unknown) as Error,
+ isRunning: false,
+ }));
+ }
+ },
+ error: (error: Error) => {
setFetchState((prevState) => ({
...prevState,
- error: (res as unknown) as Error,
- setIsRunning: false,
+ error,
+ isRunning: false,
}));
- }
- },
- error: (error: Error) => {
- setFetchState((prevState) => ({
- ...prevState,
- error,
- setIsRunning: false,
- }));
- },
- });
- };
+ },
+ });
+ },
+ [data.search, setFetchState]
+ );
- const cancelFetch = () => {
+ const cancelFetch = useCallback(() => {
searchSubscription$.current?.unsubscribe();
searchSubscription$.current = undefined;
abortCtrl.current.abort();
setFetchState((prevState) => ({
...prevState,
- setIsRunning: false,
+ isRunning: false,
}));
- };
+ }, [setFetchState]);
return {
...fetchState,
diff --git a/x-pack/plugins/apm/public/hooks/use_transaction_latency_correlations_fetcher.ts b/x-pack/plugins/apm/public/hooks/use_transaction_latency_correlations_fetcher.ts
index 49f2a279f4931..0b035c6af2354 100644
--- a/x-pack/plugins/apm/public/hooks/use_transaction_latency_correlations_fetcher.ts
+++ b/x-pack/plugins/apm/public/hooks/use_transaction_latency_correlations_fetcher.ts
@@ -5,7 +5,7 @@
* 2.0.
*/
-import { useRef, useState } from 'react';
+import { useCallback, useRef, useState } from 'react';
import type { Subscription } from 'rxjs';
import {
IKibanaSearchRequest,
@@ -14,32 +14,22 @@ import {
isErrorResponse,
} from '../../../../../src/plugins/data/public';
import type {
- HistogramItem,
SearchServiceParams,
- SearchServiceValue,
+ SearchServiceRawResponse,
} from '../../common/search_strategies/correlations/types';
import { useKibana } from '../../../../../src/plugins/kibana_react/public';
import { ApmPluginStartDeps } from '../plugin';
-interface RawResponse {
- percentileThresholdValue?: number;
- took: number;
- values: SearchServiceValue[];
- overallHistogram: HistogramItem[];
- log: string[];
- ccsWarning: boolean;
-}
-
interface TransactionLatencyCorrelationsFetcherState {
error?: Error;
isComplete: boolean;
isRunning: boolean;
loaded: number;
- ccsWarning: RawResponse['ccsWarning'];
- histograms: RawResponse['values'];
- log: RawResponse['log'];
- overallHistogram?: RawResponse['overallHistogram'];
- percentileThresholdValue?: RawResponse['percentileThresholdValue'];
+ ccsWarning: SearchServiceRawResponse['ccsWarning'];
+ histograms: SearchServiceRawResponse['values'];
+ log: SearchServiceRawResponse['log'];
+ overallHistogram?: SearchServiceRawResponse['overallHistogram'];
+ percentileThresholdValue?: SearchServiceRawResponse['percentileThresholdValue'];
timeTook?: number;
total: number;
}
@@ -65,7 +55,9 @@ export const useTransactionLatencyCorrelationsFetcher = () => {
const abortCtrl = useRef(new AbortController());
const searchSubscription$ = useRef();
- function setResponse(response: IKibanaSearchResponse) {
+ function setResponse(
+ response: IKibanaSearchResponse
+ ) {
setFetchState((prevState) => ({
...prevState,
isRunning: response.isRunning || false,
@@ -85,71 +77,86 @@ export const useTransactionLatencyCorrelationsFetcher = () => {
response.rawResponse?.percentileThresholdValue,
}
: {}),
+ // if loading is done but didn't return any data for the overall histogram,
+ // set it to an empty array so the consuming chart component knows loading is done.
+ ...(!response.isRunning &&
+ response.rawResponse?.overallHistogram === undefined
+ ? { overallHistogram: [] }
+ : {}),
}));
}
- const startFetch = (
- params: Omit
- ) => {
- setFetchState((prevState) => ({
- ...prevState,
- error: undefined,
- isComplete: false,
- }));
- searchSubscription$.current?.unsubscribe();
- abortCtrl.current.abort();
- abortCtrl.current = new AbortController();
+ const startFetch = useCallback(
+ (params: Omit) => {
+ setFetchState((prevState) => ({
+ ...prevState,
+ error: undefined,
+ isComplete: false,
+ }));
+ searchSubscription$.current?.unsubscribe();
+ abortCtrl.current.abort();
+ abortCtrl.current = new AbortController();
- const searchServiceParams: SearchServiceParams = {
- ...params,
- analyzeCorrelations: true,
- };
- const req = { params: searchServiceParams };
+ const searchServiceParams: SearchServiceParams = {
+ ...params,
+ analyzeCorrelations: true,
+ };
+ const req = { params: searchServiceParams };
- // Submit the search request using the `data.search` service.
- searchSubscription$.current = data.search
- .search>(req, {
- strategy: 'apmCorrelationsSearchStrategy',
- abortSignal: abortCtrl.current.signal,
- })
- .subscribe({
- next: (res: IKibanaSearchResponse) => {
- setResponse(res);
- if (isCompleteResponse(res)) {
- searchSubscription$.current?.unsubscribe();
+ // Submit the search request using the `data.search` service.
+ searchSubscription$.current = data.search
+ .search<
+ IKibanaSearchRequest,
+ IKibanaSearchResponse
+ >(req, {
+ strategy: 'apmCorrelationsSearchStrategy',
+ abortSignal: abortCtrl.current.signal,
+ })
+ .subscribe({
+ next: (res: IKibanaSearchResponse) => {
+ setResponse(res);
+ if (isCompleteResponse(res)) {
+ searchSubscription$.current?.unsubscribe();
+ setFetchState((prevState) => ({
+ ...prevState,
+ isRunnning: false,
+ isComplete: true,
+ }));
+ } else if (isErrorResponse(res)) {
+ searchSubscription$.current?.unsubscribe();
+ setFetchState((prevState) => ({
+ ...prevState,
+ error: (res as unknown) as Error,
+ isRunning: false,
+ }));
+ }
+ },
+ error: (error: Error) => {
setFetchState((prevState) => ({
...prevState,
- isRunnning: false,
- isComplete: true,
+ error,
+ isRunning: false,
}));
- } else if (isErrorResponse(res)) {
- searchSubscription$.current?.unsubscribe();
- setFetchState((prevState) => ({
- ...prevState,
- error: (res as unknown) as Error,
- setIsRunning: false,
- }));
- }
- },
- error: (error: Error) => {
- setFetchState((prevState) => ({
- ...prevState,
- error,
- setIsRunning: false,
- }));
- },
- });
- };
+ },
+ });
+ },
+ [data.search, setFetchState]
+ );
- const cancelFetch = () => {
+ const cancelFetch = useCallback(() => {
searchSubscription$.current?.unsubscribe();
searchSubscription$.current = undefined;
abortCtrl.current.abort();
setFetchState((prevState) => ({
...prevState,
- setIsRunning: false,
+ // If we didn't receive data for the overall histogram yet
+ // set it to an empty array to indicate loading stopped.
+ ...(prevState.overallHistogram === undefined
+ ? { overallHistogram: [] }
+ : {}),
+ isRunning: false,
}));
- };
+ }, [setFetchState]);
return {
...fetchState,
diff --git a/x-pack/plugins/apm/server/lib/search_strategies/correlations/search_strategy.ts b/x-pack/plugins/apm/server/lib/search_strategies/correlations/search_strategy.ts
index 3601f19ad7051..7f67147a75580 100644
--- a/x-pack/plugins/apm/server/lib/search_strategies/correlations/search_strategy.ts
+++ b/x-pack/plugins/apm/server/lib/search_strategies/correlations/search_strategy.ts
@@ -16,6 +16,7 @@ import {
import type {
SearchServiceParams,
+ SearchServiceRawResponse,
SearchServiceValue,
} from '../../../../common/search_strategies/correlations/types';
@@ -100,20 +101,22 @@ export const apmCorrelationsSearchStrategyProvider = (
const took = Date.now() - started;
+ const rawResponse: SearchServiceRawResponse = {
+ ccsWarning,
+ log,
+ took,
+ values,
+ percentileThresholdValue,
+ overallHistogram,
+ };
+
return of({
id,
loaded,
total,
isRunning,
isPartial: isRunning,
- rawResponse: {
- ccsWarning,
- log,
- took,
- values,
- percentileThresholdValue,
- overallHistogram,
- },
+ rawResponse,
});
},
cancel: async (id, options, deps) => {
From 74f3b76592e843f76e4877e4263d3b5ae8be6b1c Mon Sep 17 00:00:00 2001
From: Kyle Pollich
Date: Fri, 27 Aug 2021 08:08:53 -0400
Subject: [PATCH 10/12] [Fleet] Fix upgrade link in Fleet policy table
(#110228)
* Fix upgrade link in Fleet policy table
* Ensure upgrade page displays as upgrade even without from prop
---
.../components/package_policies/package_policies_table.tsx | 2 +-
.../agent_policy/edit_package_policy_page/index.tsx | 6 ++----
.../agent_policy/upgrade_package_policy_page/index.tsx | 2 +-
3 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx
index c84df5790ecb5..eb5f8e6c6a9b8 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx
@@ -237,7 +237,7 @@ export const PackagePoliciesTable: React.FunctionComponent = ({
upgradePackagePolicyHref={`${getHref('upgrade_package_policy', {
policyId: agentPolicy.id,
packagePolicyId: packagePolicy.id,
- })}`}
+ })}?from=fleet-policy-list`}
/>
);
},
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx
index 8a1ffe21a90e0..67cff3e2d0304 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx
@@ -71,8 +71,9 @@ export const EditPackagePolicyPage = memo(() => {
export const EditPackagePolicyForm = memo<{
packagePolicyId: string;
+ isUpgrade?: boolean;
from?: EditPackagePolicyFrom;
-}>(({ packagePolicyId, from = 'edit' }) => {
+}>(({ packagePolicyId, isUpgrade = false, from = 'edit' }) => {
const { application, notifications } = useStartServices();
const {
agents: { enabled: isFleetEnabled },
@@ -99,9 +100,6 @@ export const EditPackagePolicyForm = memo<{
>();
const [dryRunData, setDryRunData] = useState();
- const isUpgrade =
- from === 'upgrade-from-fleet-policy-list' || from === 'upgrade-from-integrations-policy-list';
-
const policyId = agentPolicy?.id ?? '';
// Retrieve agent policy, package, and package policy info
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/upgrade_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/upgrade_package_policy_page/index.tsx
index e9442f84d228e..18cf7847cd29b 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/upgrade_package_policy_page/index.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/upgrade_package_policy_page/index.tsx
@@ -30,5 +30,5 @@ export const UpgradePackagePolicyPage = memo(() => {
from = 'upgrade-from-integrations-policy-list';
}
- return ;
+ return ;
});
From c92978b9e58c1a7900460a9ffbe788e96218ace0 Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Fri, 27 Aug 2021 15:55:59 +0100
Subject: [PATCH 11/12] chore(NA): moving @kbn/securitysolution-list-constants
to babel transpiler (#110269)
* chore(NA): moving @kbn/securitysolution-list-constants to babel transpiler
* chore(NA): add web targets
---
.../.babelrc | 4 +++
.../.babelrc.browser | 4 +++
.../BUILD.bazel | 29 +++++++++++++------
.../package.json | 5 ++--
.../tsconfig.json | 3 +-
5 files changed, 33 insertions(+), 12 deletions(-)
create mode 100644 packages/kbn-securitysolution-list-constants/.babelrc
create mode 100644 packages/kbn-securitysolution-list-constants/.babelrc.browser
diff --git a/packages/kbn-securitysolution-list-constants/.babelrc b/packages/kbn-securitysolution-list-constants/.babelrc
new file mode 100644
index 0000000000000..40a198521b903
--- /dev/null
+++ b/packages/kbn-securitysolution-list-constants/.babelrc
@@ -0,0 +1,4 @@
+{
+ "presets": ["@kbn/babel-preset/node_preset"],
+ "ignore": ["**/*.test.ts", "**/*.test.tsx"]
+}
diff --git a/packages/kbn-securitysolution-list-constants/.babelrc.browser b/packages/kbn-securitysolution-list-constants/.babelrc.browser
new file mode 100644
index 0000000000000..71bbfbcd6eb2f
--- /dev/null
+++ b/packages/kbn-securitysolution-list-constants/.babelrc.browser
@@ -0,0 +1,4 @@
+{
+ "presets": ["@kbn/babel-preset/webpack_preset"],
+ "ignore": ["**/*.test.ts", "**/*.test.tsx"]
+}
diff --git a/packages/kbn-securitysolution-list-constants/BUILD.bazel b/packages/kbn-securitysolution-list-constants/BUILD.bazel
index e56c96e0b5da9..9b3de9520f6a1 100644
--- a/packages/kbn-securitysolution-list-constants/BUILD.bazel
+++ b/packages/kbn-securitysolution-list-constants/BUILD.bazel
@@ -1,5 +1,6 @@
load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project")
load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm")
+load("//src/dev/bazel:index.bzl", "jsts_transpiler")
PKG_BASE_NAME = "kbn-securitysolution-list-constants"
@@ -27,16 +28,25 @@ NPM_MODULE_EXTRA_FILES = [
"README.md",
]
-SRC_DEPS = [
- "@npm//tslib",
-]
+RUNTIME_DEPS = []
TYPES_DEPS = [
"@npm//@types/jest",
"@npm//@types/node",
]
-DEPS = SRC_DEPS + TYPES_DEPS
+jsts_transpiler(
+ name = "target_node",
+ srcs = SRCS,
+ build_pkg_name = package_name(),
+)
+
+jsts_transpiler(
+ name = "target_web",
+ srcs = SRCS,
+ build_pkg_name = package_name(),
+ config_file = ".babelrc.browser"
+)
ts_config(
name = "tsconfig",
@@ -48,24 +58,25 @@ ts_config(
)
ts_project(
- name = "tsc",
+ name = "tsc_types",
srcs = SRCS,
+ deps = TYPES_DEPS,
args = ["--pretty"],
declaration = True,
declaration_map = True,
- out_dir = "target",
+ emit_declaration_only = True,
+ out_dir = "target_types",
root_dir = "src",
source_map = True,
tsconfig = ":tsconfig",
- deps = DEPS,
)
js_library(
name = PKG_BASE_NAME,
- package_name = PKG_REQUIRE_NAME,
srcs = NPM_MODULE_EXTRA_FILES,
+ deps = RUNTIME_DEPS + [":target_node", ":target_web", ":tsc_types"],
+ package_name = PKG_REQUIRE_NAME,
visibility = ["//visibility:public"],
- deps = DEPS + [":tsc"],
)
pkg_npm(
diff --git a/packages/kbn-securitysolution-list-constants/package.json b/packages/kbn-securitysolution-list-constants/package.json
index b9d65734aff56..37f15fd06b0bc 100644
--- a/packages/kbn-securitysolution-list-constants/package.json
+++ b/packages/kbn-securitysolution-list-constants/package.json
@@ -3,7 +3,8 @@
"version": "1.0.0",
"description": "security solution list constants to use across plugins such lists, security_solution, cases, etc...",
"license": "SSPL-1.0 OR Elastic License 2.0",
- "main": "./target/index.js",
- "types": "./target/index.d.ts",
+ "browser": "./target_web/index.js",
+ "main": "./target_node/index.js",
+ "types": "./target_types/index.d.ts",
"private": true
}
diff --git a/packages/kbn-securitysolution-list-constants/tsconfig.json b/packages/kbn-securitysolution-list-constants/tsconfig.json
index 769b5df990e6b..8697cbd61580a 100644
--- a/packages/kbn-securitysolution-list-constants/tsconfig.json
+++ b/packages/kbn-securitysolution-list-constants/tsconfig.json
@@ -3,7 +3,8 @@
"compilerOptions": {
"declaration": true,
"declarationMap": true,
- "outDir": "target",
+ "emitDeclarationOnly": true,
+ "outDir": "target_types",
"rootDir": "src",
"sourceMap": true,
"sourceRoot": "../../../../packages/kbn-securitysolution-list-constants/src",
From 127402415c04208aa3bf144be6652af5d0594e39 Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Fri, 27 Aug 2021 15:56:18 +0100
Subject: [PATCH 12/12] chore(NA): moving @kbn/securitysolution-list-api to
babel transpiler (#110265)
* chore(NA): moving @kbn/securitysolution-list-api to babel transpiler
* chore(NA): add web targets
---
.../kbn-securitysolution-list-api/.babelrc | 4 +++
.../.babelrc.browser | 4 +++
.../kbn-securitysolution-list-api/BUILD.bazel | 35 ++++++++++++++-----
.../package.json | 5 +--
.../tsconfig.json | 3 +-
5 files changed, 39 insertions(+), 12 deletions(-)
create mode 100644 packages/kbn-securitysolution-list-api/.babelrc
create mode 100644 packages/kbn-securitysolution-list-api/.babelrc.browser
diff --git a/packages/kbn-securitysolution-list-api/.babelrc b/packages/kbn-securitysolution-list-api/.babelrc
new file mode 100644
index 0000000000000..40a198521b903
--- /dev/null
+++ b/packages/kbn-securitysolution-list-api/.babelrc
@@ -0,0 +1,4 @@
+{
+ "presets": ["@kbn/babel-preset/node_preset"],
+ "ignore": ["**/*.test.ts", "**/*.test.tsx"]
+}
diff --git a/packages/kbn-securitysolution-list-api/.babelrc.browser b/packages/kbn-securitysolution-list-api/.babelrc.browser
new file mode 100644
index 0000000000000..71bbfbcd6eb2f
--- /dev/null
+++ b/packages/kbn-securitysolution-list-api/.babelrc.browser
@@ -0,0 +1,4 @@
+{
+ "presets": ["@kbn/babel-preset/webpack_preset"],
+ "ignore": ["**/*.test.ts", "**/*.test.tsx"]
+}
diff --git a/packages/kbn-securitysolution-list-api/BUILD.bazel b/packages/kbn-securitysolution-list-api/BUILD.bazel
index 726d75d8c86b8..6858a9389119f 100644
--- a/packages/kbn-securitysolution-list-api/BUILD.bazel
+++ b/packages/kbn-securitysolution-list-api/BUILD.bazel
@@ -1,5 +1,6 @@
load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project")
load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm")
+load("//src/dev/bazel:index.bzl", "jsts_transpiler")
PKG_BASE_NAME = "kbn-securitysolution-list-api"
@@ -27,21 +28,36 @@ NPM_MODULE_EXTRA_FILES = [
"README.md",
]
-SRC_DEPS = [
+RUNTIME_DEPS = [
+ "//packages/kbn-securitysolution-io-ts-list-types",
"//packages/kbn-securitysolution-io-ts-utils",
"//packages/kbn-securitysolution-list-constants",
- "//packages/kbn-securitysolution-io-ts-list-types",
"@npm//fp-ts",
"@npm//io-ts",
- "@npm//tslib",
]
TYPES_DEPS = [
+ "//packages/kbn-securitysolution-io-ts-list-types",
+ "//packages/kbn-securitysolution-io-ts-utils",
+ "//packages/kbn-securitysolution-list-constants",
+ "@npm//fp-ts",
+ "@npm//io-ts",
"@npm//@types/jest",
"@npm//@types/node",
]
-DEPS = SRC_DEPS + TYPES_DEPS
+jsts_transpiler(
+ name = "target_node",
+ srcs = SRCS,
+ build_pkg_name = package_name(),
+)
+
+jsts_transpiler(
+ name = "target_web",
+ srcs = SRCS,
+ build_pkg_name = package_name(),
+ config_file = ".babelrc.browser"
+)
ts_config(
name = "tsconfig",
@@ -53,24 +69,25 @@ ts_config(
)
ts_project(
- name = "tsc",
+ name = "tsc_types",
srcs = SRCS,
+ deps = TYPES_DEPS,
args = ["--pretty"],
declaration = True,
declaration_map = True,
- out_dir = "target",
+ emit_declaration_only = True,
+ out_dir = "target_types",
root_dir = "src",
source_map = True,
tsconfig = ":tsconfig",
- deps = DEPS,
)
js_library(
name = PKG_BASE_NAME,
- package_name = PKG_REQUIRE_NAME,
srcs = NPM_MODULE_EXTRA_FILES,
+ deps = RUNTIME_DEPS + [":target_node", ":target_web", ":tsc_types"],
+ package_name = PKG_REQUIRE_NAME,
visibility = ["//visibility:public"],
- deps = DEPS + [":tsc"],
)
pkg_npm(
diff --git a/packages/kbn-securitysolution-list-api/package.json b/packages/kbn-securitysolution-list-api/package.json
index 11108c61bfde1..8454f13d841b4 100644
--- a/packages/kbn-securitysolution-list-api/package.json
+++ b/packages/kbn-securitysolution-list-api/package.json
@@ -3,7 +3,8 @@
"version": "1.0.0",
"description": "security solution list REST API",
"license": "SSPL-1.0 OR Elastic License 2.0",
- "main": "./target/index.js",
- "types": "./target/index.d.ts",
+ "browser": "./target_web/index.js",
+ "main": "./target_node/index.js",
+ "types": "./target_types/index.d.ts",
"private": true
}
diff --git a/packages/kbn-securitysolution-list-api/tsconfig.json b/packages/kbn-securitysolution-list-api/tsconfig.json
index c2ac6d3d92286..d51cd3ac71d8d 100644
--- a/packages/kbn-securitysolution-list-api/tsconfig.json
+++ b/packages/kbn-securitysolution-list-api/tsconfig.json
@@ -3,7 +3,8 @@
"compilerOptions": {
"declaration": true,
"declarationMap": true,
- "outDir": "target",
+ "emitDeclarationOnly": true,
+ "outDir": "target_types",
"rootDir": "src",
"sourceMap": true,
"sourceRoot": "../../../../packages/kbn-securitysolution-list-api/src",