From a2fb9b736cd8007a0ba04b9b1051d7988c690b5b Mon Sep 17 00:00:00 2001 From: Mykola Harmash Date: Wed, 4 Dec 2024 11:49:47 +0100 Subject: [PATCH] [Observability Onboarding] Prevent showing duplcated AWS services in Firehose flow (#201613) Closes #200931 Switched to using AWS service list as a base to showing the detected services in the UI instead of the list of populated indices as multiple indices can be related to a single service. ### How to test 1. Go to Firehose flow `/observabilityOnboarding/firehose` 2. Open Kibana dev tools in another tab 3. Ingest documents related into multiple data streams which related to a single AWS service: ``` POST logs-aws.apigateway_logs-default/_doc { "@timestamp": "2024-11-25T13:32:01.000Z", "some": 111, "aws.kinesis.name": "Elastic-CloudwatchLogs" } POST metrics-aws.apigateway_metrics-default/_doc { "@timestamp": "2024-11-25T13:31:01.000Z", "agent": { "type": "firehose" }, "aws": { "cloudwatch": { "namespace": "AWS/ApiGateway" }, "exporter": { "arn": "arn:aws:cloudwatch:us-west-2:975050175126:metric-stream/Elastic-CloudwatchLogsAndMetricsToFirehose-CloudWatchMetricStream-Nhb4NhzPdL4J" } }, "cloud": { "account": { "id": "975050175126" }, "provider": "aws", "region": "us-west-2" } } ``` 4. Make sure you see only one entry for the service appear in the Firehose flow --- .../use_aws_service_get_started_list.ts | 2 +- .../firehose/visualize_data.tsx | 129 +++++++++--------- 2 files changed, 68 insertions(+), 63 deletions(-) diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/use_aws_service_get_started_list.ts b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/use_aws_service_get_started_list.ts index 277c565986d3c..13273475c7697 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/use_aws_service_get_started_list.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/use_aws_service_get_started_list.ts @@ -14,7 +14,7 @@ import { DISCOVER_APP_LOCATOR } from '@kbn/discover-plugin/common'; import { AWSIndexName } from '../../../../common/aws_firehose'; import { ObservabilityOnboardingContextValue } from '../../../plugin'; -interface AWSServiceGetStartedConfig { +export interface AWSServiceGetStartedConfig { id: string; indexNameList: AWSIndexName[]; title: string; diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/visualize_data.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/visualize_data.tsx index 1b6b281495971..45a2089c2d1c4 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/visualize_data.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/quickstart_flows/firehose/visualize_data.tsx @@ -9,19 +9,21 @@ import { EuiIcon, EuiSpacer, EuiText, useGeneratedHtmlId } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useEffect, useState } from 'react'; import useInterval from 'react-use/lib/useInterval'; -import { union } from 'lodash'; +import { unionBy } from 'lodash'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { FormattedMessage } from '@kbn/i18n-react'; import { ObservabilityOnboardingAppServices } from '../../..'; import { FIREHOSE_CLOUDFORMATION_STACK_NAME, FIREHOSE_LOGS_STREAM_NAME, - type AWSIndexName, } from '../../../../common/aws_firehose'; import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; import { AccordionWithIcon } from '../shared/accordion_with_icon'; import { GetStartedPanel } from '../shared/get_started_panel'; -import { useAWSServiceGetStartedList } from './use_aws_service_get_started_list'; +import { + type AWSServiceGetStartedConfig, + useAWSServiceGetStartedList, +} from './use_aws_service_get_started_list'; import { AutoRefreshCallout } from './auto_refresh_callout'; import { ProgressCallout } from './progress_callout'; import { HAS_DATA_FETCH_INTERVAL } from './utils'; @@ -36,12 +38,12 @@ interface Props { export function VisualizeData({ onboardingId, selectedCreateStackOption }: Props) { const accordionId = useGeneratedHtmlId({ prefix: 'accordion' }); - const [orderedPopulatedAWSLogsIndexList, setOrderedPopulatedAWSLogsIndexList] = useState< - AWSIndexName[] + const [orderedVisibleAWSServiceList, setOrderedVisibleAWSServiceList] = useState< + AWSServiceGetStartedConfig[] >([]); const [shouldShowDataReceivedToast, setShouldShowDataReceivedToast] = useState(true); const { - data: populatedAWSLogsIndexList, + data: populatedAWSIndexList, status, refetch, } = useFetcher((callApi) => { @@ -60,12 +62,13 @@ export function VisualizeData({ onboardingId, selectedCreateStackOption }: Props context: { cloudServiceProvider }, }, } = useKibana(); + const awsServiceGetStartedConfigList = useAWSServiceGetStartedList(); useEffect(() => { if ( shouldShowDataReceivedToast && - Array.isArray(populatedAWSLogsIndexList) && - populatedAWSLogsIndexList.length > 0 + Array.isArray(populatedAWSIndexList) && + populatedAWSIndexList.length > 0 ) { notifications?.toasts.addSuccess( { @@ -90,17 +93,27 @@ export function VisualizeData({ onboardingId, selectedCreateStackOption }: Props setShouldShowDataReceivedToast(false); } - setOrderedPopulatedAWSLogsIndexList((currentList) => + setOrderedVisibleAWSServiceList((currentList) => /** - * Using union() to ensure items in the array are unique - * add stay in the insertion order to keep the order of - * the AWS services in the UI. + * unionBy() ensures uniqueness of the resulting list + * and preserves the order of the first list passed to it, + * which in turn keeps already visible services in the UI + * in place and new services are only appended to the end. */ - union(currentList, populatedAWSLogsIndexList) + unionBy( + currentList, + awsServiceGetStartedConfigList.filter(({ indexNameList }) => + indexNameList.some((indexName) => populatedAWSIndexList?.includes(indexName)) + ), + 'id' + ) ); - }, [notifications?.toasts, populatedAWSLogsIndexList, shouldShowDataReceivedToast]); - - const awsServiceGetStartedConfigList = useAWSServiceGetStartedList(); + }, [ + awsServiceGetStartedConfigList, + notifications?.toasts, + populatedAWSIndexList, + shouldShowDataReceivedToast, + ]); useInterval(() => { if (REQUEST_PENDING_STATUS_LIST.includes(status)) { @@ -110,7 +123,7 @@ export function VisualizeData({ onboardingId, selectedCreateStackOption }: Props refetch(); }, HAS_DATA_FETCH_INTERVAL); - if (populatedAWSLogsIndexList === undefined) { + if (populatedAWSIndexList === undefined) { return null; } @@ -127,56 +140,48 @@ export function VisualizeData({ onboardingId, selectedCreateStackOption }: Props - {orderedPopulatedAWSLogsIndexList.length === 0 && } - {orderedPopulatedAWSLogsIndexList.length > 0 && } + {orderedVisibleAWSServiceList.length === 0 && } + {orderedVisibleAWSServiceList.length > 0 && }
- {orderedPopulatedAWSLogsIndexList.map((indexName, index) => { - const getStartedConfig = awsServiceGetStartedConfigList.find(({ indexNameList }) => - indexNameList.includes(indexName) - ); - - if (!getStartedConfig) { - return null; + {orderedVisibleAWSServiceList.map( + ({ id, actionLinks, title, logoURL, previewImage }, index) => { + return ( + } + title={title} + initialIsOpen={true} + borders={ + index === 0 || index === orderedVisibleAWSServiceList.length - 1 + ? 'none' + : 'horizontal' + } + > + + + ); } - - const { id, actionLinks, title, logoURL, previewImage } = getStartedConfig; - - return ( - } - title={title} - initialIsOpen={true} - borders={ - index === 0 || index === orderedPopulatedAWSLogsIndexList.length - 1 - ? 'none' - : 'horizontal' - } - > - - - ); - })} + )}
);