mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Observability Onboarding] Make custom cards always appear in search results (#208913)
Closes #207734 This PR: * Changes the behavior of the search form to always include quickstart flows in search results even when a category is not selected * Refactors and cleans up the code a bit https://github.com/user-attachments/assets/e5de7092-2d9f-41be-8d69-25954e5e4bff ## How to test Make sure that the search works as expected and when clicking on the cards it leads to the right places.
This commit is contained in:
parent
b1b28c3258
commit
015a4ac618
11 changed files with 573 additions and 751 deletions
|
@ -26,12 +26,13 @@ import { css } from '@emotion/react';
|
|||
|
||||
import { useSearchParams } from 'react-router-dom-v5-compat';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { OnboardingFlowPackageList } from '../packages_list';
|
||||
import { IntegrationCardItem } from '@kbn/fleet-plugin/public';
|
||||
import { PackageListSearchForm } from '../package_list_search_form/package_list_search_form';
|
||||
import { Category } from './types';
|
||||
import { useCustomCardsForCategory } from './use_custom_cards_for_category';
|
||||
import { useVirtualSearchResults } from './use_virtual_search_results';
|
||||
import { useCustomCards } from './use_custom_cards';
|
||||
import { LogoIcon, SupportedLogo } from '../shared/logo_icon';
|
||||
import { ObservabilityOnboardingAppServices } from '../..';
|
||||
import { PackageList } from '../package_list/package_list';
|
||||
|
||||
interface UseCaseOption {
|
||||
id: Category;
|
||||
|
@ -147,11 +148,25 @@ export const OnboardingFlowForm: FunctionComponent = () => {
|
|||
[] // eslint-disable-line react-hooks/exhaustive-deps
|
||||
);
|
||||
|
||||
const customCards = useCustomCardsForCategory(
|
||||
createCollectionCardHandler,
|
||||
searchParams.get('category') as Category | null
|
||||
);
|
||||
const virtualSearchResults = useVirtualSearchResults();
|
||||
const featuredCardsForCategoryMap: Record<Category, string[]> = {
|
||||
host: ['auto-detect-logs', 'otel-logs'],
|
||||
kubernetes: ['kubernetes-quick-start', 'otel-kubernetes'],
|
||||
application: ['apm-virtual', 'otel-virtual', 'synthetics-virtual'],
|
||||
cloud: ['azure-logs-virtual', 'aws-logs-virtual', 'gcp-logs-virtual'],
|
||||
};
|
||||
const customCards = useCustomCards(createCollectionCardHandler);
|
||||
const featuredCardsForCategory: IntegrationCardItem[] = customCards.filter((card) => {
|
||||
const category = searchParams.get('category') as Category;
|
||||
|
||||
if (category === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const cardList = featuredCardsForCategoryMap[category] ?? [];
|
||||
|
||||
return cardList.includes(card.id);
|
||||
});
|
||||
|
||||
/**
|
||||
* Cloud deployments have the new Firehose quick start
|
||||
* flow enabled, so the ond card 'epr:awsfirehose' should
|
||||
|
@ -272,7 +287,7 @@ export const OnboardingFlowForm: FunctionComponent = () => {
|
|||
</EuiFlexGrid>
|
||||
{/* Hiding element instead of not rending these elements in order to preload available packages on page load */}
|
||||
<div
|
||||
hidden={!searchParams.get('category') || !customCards}
|
||||
hidden={featuredCardsForCategory.length === 0}
|
||||
role="group"
|
||||
aria-labelledby={packageListTitleId}
|
||||
>
|
||||
|
@ -310,11 +325,7 @@ export const OnboardingFlowForm: FunctionComponent = () => {
|
|||
</strong>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m" />
|
||||
<OnboardingFlowPackageList
|
||||
customCards={customCards}
|
||||
flowSearch={integrationSearch}
|
||||
flowCategory={searchParams.get('category')}
|
||||
/>
|
||||
<PackageList list={featuredCardsForCategory} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -329,20 +340,12 @@ export const OnboardingFlowForm: FunctionComponent = () => {
|
|||
</strong>
|
||||
</EuiText>
|
||||
<EuiSpacer size="m" />
|
||||
<OnboardingFlowPackageList
|
||||
showSearchBar={true}
|
||||
<PackageListSearchForm
|
||||
searchQuery={integrationSearch}
|
||||
flowSearch={integrationSearch}
|
||||
setSearchQuery={setIntegrationSearch}
|
||||
flowCategory={searchParams.get('category')}
|
||||
customCards={(customCards || [])
|
||||
.filter(
|
||||
// Filter out collection cards and regular integrations that show up via search anyway
|
||||
(card) => card.type === 'virtual' && !card.isCollectionCard
|
||||
)
|
||||
.concat(virtualSearchResults)}
|
||||
customCards={customCards.filter((card) => !card.isCollectionCard)}
|
||||
excludePackageIdList={searchExcludePackageIdList}
|
||||
joinCardLists
|
||||
/>
|
||||
</div>
|
||||
</EuiPanel>
|
||||
|
|
|
@ -0,0 +1,411 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { EuiFlexItem } from '@elastic/eui';
|
||||
import { reactRouterNavigate, useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { IntegrationCardItem } from '@kbn/fleet-plugin/public';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useLocation } from 'react-router-dom-v5-compat';
|
||||
import { ObservabilityOnboardingAppServices } from '../..';
|
||||
import { LogoIcon } from '../shared/logo_icon';
|
||||
|
||||
export function useCustomCards(
|
||||
createCollectionCardHandler: (query: string) => () => void
|
||||
): IntegrationCardItem[] {
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
const {
|
||||
services: {
|
||||
application,
|
||||
http,
|
||||
context: { isServerless, isCloud },
|
||||
},
|
||||
} = useKibana<ObservabilityOnboardingAppServices>();
|
||||
|
||||
const getUrlForApp = application?.getUrlForApp;
|
||||
|
||||
const { href: autoDetectUrl } = reactRouterNavigate(history, `/auto-detect/${location.search}`);
|
||||
const { href: otelLogsUrl } = reactRouterNavigate(history, `/otel-logs/${location.search}`);
|
||||
const { href: kubernetesUrl } = reactRouterNavigate(history, `/kubernetes/${location.search}`);
|
||||
const { href: otelKubernetesUrl } = reactRouterNavigate(
|
||||
history,
|
||||
`/otel-kubernetes/${location.search}`
|
||||
);
|
||||
const { href: customLogsUrl } = reactRouterNavigate(history, `/customLogs/${location.search}`);
|
||||
const { href: firehoseUrl } = reactRouterNavigate(history, `/firehose/${location.search}`);
|
||||
|
||||
const apmUrl = `${getUrlForApp?.('apm')}/${isServerless ? 'onboarding' : 'tutorial'}`;
|
||||
const otelApmUrl = isServerless ? `${apmUrl}?agent=openTelemetry` : apmUrl;
|
||||
|
||||
const firehoseQuickstartCard: IntegrationCardItem = {
|
||||
id: 'firehose-quick-start',
|
||||
name: 'firehose-quick-start',
|
||||
type: 'virtual',
|
||||
title: i18n.translate('xpack.observability_onboarding.packageList.uploadFileTitle', {
|
||||
defaultMessage: 'AWS Firehose',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.packageList.uploadFileDescription',
|
||||
{
|
||||
defaultMessage: 'Collect logs and metrics from Amazon Web Services (AWS).',
|
||||
}
|
||||
),
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'svg',
|
||||
src: 'https://epr.elastic.co/package/awsfirehose/1.1.0/img/logo_firehose.svg',
|
||||
},
|
||||
],
|
||||
url: firehoseUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
isQuickstart: true,
|
||||
};
|
||||
|
||||
return [
|
||||
{
|
||||
id: 'auto-detect-logs',
|
||||
name: 'auto-detect-logs-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.autoDetectTitle',
|
||||
{
|
||||
defaultMessage: 'Elastic Agent: Logs & Metrics',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.autoDetectDescription',
|
||||
{
|
||||
defaultMessage: 'Scan your host for log files, metrics, auto-install integrations',
|
||||
}
|
||||
),
|
||||
extraLabelsBadges: [
|
||||
<ExtraLabelBadgeWrapper>
|
||||
<LogoIcon logo="apple" size="m" />
|
||||
</ExtraLabelBadgeWrapper>,
|
||||
<ExtraLabelBadgeWrapper>
|
||||
<LogoIcon logo="linux" size="m" />
|
||||
</ExtraLabelBadgeWrapper>,
|
||||
],
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'eui',
|
||||
src: 'agentApp',
|
||||
},
|
||||
],
|
||||
url: autoDetectUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
isQuickstart: true,
|
||||
},
|
||||
{
|
||||
id: 'otel-logs',
|
||||
name: 'custom-logs-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.logsOtelTitle',
|
||||
{
|
||||
defaultMessage: 'OpenTelemetry: Logs & Metrics',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.logsOtelDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Collect logs and host metrics with the Elastic Distro for OTel Collector',
|
||||
}
|
||||
),
|
||||
extraLabelsBadges: [
|
||||
<ExtraLabelBadgeWrapper>
|
||||
<LogoIcon logo="apple" size="m" />
|
||||
</ExtraLabelBadgeWrapper>,
|
||||
<ExtraLabelBadgeWrapper>
|
||||
<LogoIcon logo="linux" size="m" />
|
||||
</ExtraLabelBadgeWrapper>,
|
||||
],
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'svg',
|
||||
src: http?.staticAssets.getPluginAssetHref('opentelemetry.svg') ?? '',
|
||||
},
|
||||
],
|
||||
url: otelLogsUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
isQuickstart: true,
|
||||
},
|
||||
{
|
||||
id: 'kubernetes-quick-start',
|
||||
name: 'kubernetes-quick-start',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.kubernetesTitle',
|
||||
{
|
||||
defaultMessage: 'Elastic Agent: Logs & Metrics',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.kubernetesDescription',
|
||||
{
|
||||
defaultMessage: 'Collect logs and metrics from Kubernetes using Elastic Agent',
|
||||
}
|
||||
),
|
||||
extraLabelsBadges: [
|
||||
<ExtraLabelBadgeWrapper>
|
||||
<LogoIcon logo="kubernetes" size="m" />
|
||||
</ExtraLabelBadgeWrapper>,
|
||||
],
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'eui',
|
||||
src: 'agentApp',
|
||||
},
|
||||
],
|
||||
url: kubernetesUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
isQuickstart: true,
|
||||
},
|
||||
{
|
||||
id: 'otel-kubernetes',
|
||||
name: 'otel-kubernetes-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.kubernetesOtelTitle',
|
||||
{
|
||||
defaultMessage: 'OpenTelemetry: Full Observability',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.kubernetesOtelDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Collect logs, traces and metrics with the Elastic Distro for OTel Collector',
|
||||
}
|
||||
),
|
||||
extraLabelsBadges: [
|
||||
<ExtraLabelBadgeWrapper>
|
||||
<LogoIcon logo="kubernetes" size="m" />
|
||||
</ExtraLabelBadgeWrapper>,
|
||||
],
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'svg',
|
||||
src: http?.staticAssets.getPluginAssetHref('opentelemetry.svg') ?? '',
|
||||
},
|
||||
],
|
||||
url: otelKubernetesUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
isQuickstart: true,
|
||||
},
|
||||
{
|
||||
id: 'apm-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate('xpack.observability_onboarding.useCustomCardsForCategory.apmTitle', {
|
||||
defaultMessage: 'Elastic APM',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.apmDescription',
|
||||
{
|
||||
defaultMessage: 'Collect distributed traces from your applications with Elastic APM',
|
||||
}
|
||||
),
|
||||
name: 'apm',
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'eui',
|
||||
src: 'apmApp',
|
||||
},
|
||||
],
|
||||
url: apmUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
},
|
||||
{
|
||||
id: 'otel-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.apmOtelTitle',
|
||||
{
|
||||
defaultMessage: 'OpenTelemetry',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.apmOtelDescription',
|
||||
{
|
||||
defaultMessage: 'Collect distributed traces with OpenTelemetry',
|
||||
}
|
||||
),
|
||||
name: 'otel',
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'svg',
|
||||
src: http?.staticAssets.getPluginAssetHref('opentelemetry.svg') ?? '',
|
||||
},
|
||||
],
|
||||
url: otelApmUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
},
|
||||
{
|
||||
id: 'synthetics-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.syntheticsTitle',
|
||||
{
|
||||
defaultMessage: 'Synthetic monitor',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.syntheticsDescription',
|
||||
{
|
||||
defaultMessage: 'Monitor endpoints, pages, and user journeys',
|
||||
}
|
||||
),
|
||||
name: 'synthetics',
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'eui',
|
||||
src: 'logoUptime',
|
||||
},
|
||||
],
|
||||
url: getUrlForApp?.('synthetics') ?? '',
|
||||
version: '',
|
||||
integration: '',
|
||||
},
|
||||
{
|
||||
id: 'azure-logs-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate('xpack.observability_onboarding.useCustomCardsForCategory.azureTitle', {
|
||||
defaultMessage: 'Azure',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.azureDescription',
|
||||
{
|
||||
defaultMessage: 'Collect logs from Microsoft Azure',
|
||||
}
|
||||
),
|
||||
name: 'azure',
|
||||
categories: ['observability'],
|
||||
icons: [],
|
||||
url: 'https://azure.com',
|
||||
version: '',
|
||||
integration: '',
|
||||
isCollectionCard: true,
|
||||
onCardClick: createCollectionCardHandler('azure'),
|
||||
},
|
||||
{
|
||||
id: 'aws-logs-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate('xpack.observability_onboarding.useCustomCardsForCategory.awsTitle', {
|
||||
defaultMessage: 'AWS',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.awsDescription',
|
||||
{
|
||||
defaultMessage: 'Collect logs from Amazon Web Services (AWS)',
|
||||
}
|
||||
),
|
||||
name: 'aws',
|
||||
categories: ['observability'],
|
||||
icons: [],
|
||||
url: 'https://aws.com',
|
||||
version: '',
|
||||
integration: '',
|
||||
isCollectionCard: true,
|
||||
onCardClick: createCollectionCardHandler('aws'),
|
||||
},
|
||||
{
|
||||
id: 'gcp-logs-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate('xpack.observability_onboarding.useCustomCardsForCategory.gcpTitle', {
|
||||
defaultMessage: 'Google Cloud Platform',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.gcpDescription',
|
||||
{
|
||||
defaultMessage: 'Collect logs from Google Cloud Platform',
|
||||
}
|
||||
),
|
||||
name: 'gcp',
|
||||
categories: ['observability'],
|
||||
icons: [],
|
||||
url: '',
|
||||
version: '',
|
||||
integration: '',
|
||||
isCollectionCard: true,
|
||||
onCardClick: createCollectionCardHandler('gcp'),
|
||||
},
|
||||
{
|
||||
id: 'upload-file-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate('xpack.observability_onboarding.packageList.uploadFileTitle', {
|
||||
defaultMessage: 'Upload a file',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.packageList.uploadFileDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Upload data from a CSV, TSV, JSON or other log file to Elasticsearch for analysis.',
|
||||
}
|
||||
),
|
||||
name: 'upload-file',
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'eui',
|
||||
src: 'addDataApp',
|
||||
},
|
||||
],
|
||||
url: `${getUrlForApp?.('home')}#/tutorial_directory/fileDataViz`,
|
||||
version: '',
|
||||
integration: '',
|
||||
isCollectionCard: false,
|
||||
},
|
||||
{
|
||||
id: 'custom-logs',
|
||||
type: 'virtual',
|
||||
title: 'Stream log files',
|
||||
description: 'Stream any logs into Elastic in a simple way and explore their data',
|
||||
name: 'custom-logs-virtual',
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'eui',
|
||||
src: 'filebeatApp',
|
||||
},
|
||||
],
|
||||
url: customLogsUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
},
|
||||
/**
|
||||
* The new Firehose card should only be visible on Cloud
|
||||
* as Firehose integration requires additional proxy,
|
||||
* which is not available for on-prem customers.
|
||||
*/
|
||||
...(isCloud ? [firehoseQuickstartCard] : []),
|
||||
];
|
||||
}
|
||||
|
||||
function ExtraLabelBadgeWrapper({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<EuiFlexItem grow={false} css={{ alignSelf: 'center' }}>
|
||||
{children}
|
||||
</EuiFlexItem>
|
||||
);
|
||||
}
|
|
@ -1,365 +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 { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { EuiFlexItem } from '@elastic/eui';
|
||||
import { reactRouterNavigate, useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useLocation } from 'react-router-dom-v5-compat';
|
||||
import { ObservabilityOnboardingAppServices } from '../..';
|
||||
import { CustomCard } from '../packages_list/types';
|
||||
import { Category } from './types';
|
||||
import { LogoIcon } from '../shared/logo_icon';
|
||||
|
||||
export function useCustomCardsForCategory(
|
||||
createCollectionCardHandler: (query: string) => () => void,
|
||||
category: Category | null
|
||||
): CustomCard[] | undefined {
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
const {
|
||||
services: {
|
||||
application,
|
||||
http,
|
||||
context: { isServerless },
|
||||
},
|
||||
} = useKibana<ObservabilityOnboardingAppServices>();
|
||||
const getUrlForApp = application?.getUrlForApp;
|
||||
|
||||
const { href: autoDetectUrl } = reactRouterNavigate(history, `/auto-detect/${location.search}`);
|
||||
const { href: otelLogsUrl } = reactRouterNavigate(history, `/otel-logs/${location.search}`);
|
||||
const { href: kubernetesUrl } = reactRouterNavigate(history, `/kubernetes/${location.search}`);
|
||||
const { href: otelKubernetesUrl } = reactRouterNavigate(
|
||||
history,
|
||||
`/otel-kubernetes/${location.search}`
|
||||
);
|
||||
|
||||
const apmUrl = `${getUrlForApp?.('apm')}/${isServerless ? 'onboarding' : 'tutorial'}`;
|
||||
const otelApmUrl = isServerless ? `${apmUrl}?agent=openTelemetry` : apmUrl;
|
||||
|
||||
switch (category) {
|
||||
case 'host':
|
||||
return [
|
||||
{
|
||||
id: 'auto-detect-logs',
|
||||
name: 'auto-detect-logs-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.autoDetectTitle',
|
||||
{
|
||||
defaultMessage: 'Elastic Agent: Logs & Metrics',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.autoDetectDescription',
|
||||
{
|
||||
defaultMessage: 'Scan your host for log files, metrics, auto-install integrations',
|
||||
}
|
||||
),
|
||||
extraLabelsBadges: [
|
||||
<ExtraLabelBadgeWrapper>
|
||||
<LogoIcon logo="apple" size="m" />
|
||||
</ExtraLabelBadgeWrapper>,
|
||||
<ExtraLabelBadgeWrapper>
|
||||
<LogoIcon logo="linux" size="m" />
|
||||
</ExtraLabelBadgeWrapper>,
|
||||
],
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'eui',
|
||||
src: 'agentApp',
|
||||
},
|
||||
],
|
||||
url: autoDetectUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
isQuickstart: true,
|
||||
},
|
||||
{
|
||||
id: 'otel-logs',
|
||||
name: 'custom-logs-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.logsOtelTitle',
|
||||
{
|
||||
defaultMessage: 'OpenTelemetry: Logs & Metrics',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.logsOtelDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Collect logs and host metrics with the Elastic Distro for OTel Collector',
|
||||
}
|
||||
),
|
||||
extraLabelsBadges: [
|
||||
<ExtraLabelBadgeWrapper>
|
||||
<LogoIcon logo="apple" size="m" />
|
||||
</ExtraLabelBadgeWrapper>,
|
||||
<ExtraLabelBadgeWrapper>
|
||||
<LogoIcon logo="linux" size="m" />
|
||||
</ExtraLabelBadgeWrapper>,
|
||||
],
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'svg',
|
||||
src: http?.staticAssets.getPluginAssetHref('opentelemetry.svg') ?? '',
|
||||
},
|
||||
],
|
||||
url: otelLogsUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
isQuickstart: true,
|
||||
},
|
||||
];
|
||||
|
||||
case 'kubernetes':
|
||||
return [
|
||||
{
|
||||
id: 'kubernetes-quick-start',
|
||||
name: 'kubernetes-quick-start',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.kubernetesTitle',
|
||||
{
|
||||
defaultMessage: 'Elastic Agent: Logs & Metrics',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.kubernetesDescription',
|
||||
{
|
||||
defaultMessage: 'Collect logs and metrics from Kubernetes using Elastic Agent',
|
||||
}
|
||||
),
|
||||
extraLabelsBadges: [
|
||||
<ExtraLabelBadgeWrapper>
|
||||
<LogoIcon logo="kubernetes" size="m" />
|
||||
</ExtraLabelBadgeWrapper>,
|
||||
],
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'eui',
|
||||
src: 'agentApp',
|
||||
},
|
||||
],
|
||||
url: kubernetesUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
isQuickstart: true,
|
||||
},
|
||||
{
|
||||
id: 'otel-kubernetes',
|
||||
name: 'otel-kubernetes-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.kubernetesOtelTitle',
|
||||
{
|
||||
defaultMessage: 'OpenTelemetry: Full Observability',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.kubernetesOtelDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Collect logs, traces and metrics with the Elastic Distro for OTel Collector',
|
||||
}
|
||||
),
|
||||
extraLabelsBadges: [
|
||||
<ExtraLabelBadgeWrapper>
|
||||
<LogoIcon logo="kubernetes" size="m" />
|
||||
</ExtraLabelBadgeWrapper>,
|
||||
],
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'svg',
|
||||
src: http?.staticAssets.getPluginAssetHref('opentelemetry.svg') ?? '',
|
||||
},
|
||||
],
|
||||
url: otelKubernetesUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
isQuickstart: true,
|
||||
},
|
||||
];
|
||||
|
||||
case 'application':
|
||||
return [
|
||||
{
|
||||
id: 'apm-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.apmTitle',
|
||||
{
|
||||
defaultMessage: 'Elastic APM',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.apmDescription',
|
||||
{
|
||||
defaultMessage: 'Collect distributed traces from your applications with Elastic APM',
|
||||
}
|
||||
),
|
||||
name: 'apm',
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'eui',
|
||||
src: 'apmApp',
|
||||
},
|
||||
],
|
||||
url: apmUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
},
|
||||
{
|
||||
id: 'otel-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.apmOtelTitle',
|
||||
{
|
||||
defaultMessage: 'OpenTelemetry',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.apmOtelDescription',
|
||||
{
|
||||
defaultMessage: 'Collect distributed traces with OpenTelemetry',
|
||||
}
|
||||
),
|
||||
name: 'otel',
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'svg',
|
||||
src: http?.staticAssets.getPluginAssetHref('opentelemetry.svg') ?? '',
|
||||
},
|
||||
],
|
||||
url: otelApmUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
},
|
||||
{
|
||||
id: 'synthetics-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.syntheticsTitle',
|
||||
{
|
||||
defaultMessage: 'Synthetic monitor',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.syntheticsDescription',
|
||||
{
|
||||
defaultMessage: 'Monitor endpoints, pages, and user journeys',
|
||||
}
|
||||
),
|
||||
name: 'synthetics',
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'eui',
|
||||
src: 'logoUptime',
|
||||
},
|
||||
],
|
||||
url: getUrlForApp?.('synthetics') ?? '',
|
||||
version: '',
|
||||
integration: '',
|
||||
},
|
||||
];
|
||||
|
||||
case 'cloud':
|
||||
return [
|
||||
{
|
||||
id: 'azure-logs-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.azureTitle',
|
||||
{
|
||||
defaultMessage: 'Azure',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.azureDescription',
|
||||
{
|
||||
defaultMessage: 'Collect logs from Microsoft Azure',
|
||||
}
|
||||
),
|
||||
name: 'azure',
|
||||
categories: ['observability'],
|
||||
icons: [],
|
||||
url: 'https://azure.com',
|
||||
version: '',
|
||||
integration: '',
|
||||
isCollectionCard: true,
|
||||
onCardClick: createCollectionCardHandler('azure'),
|
||||
},
|
||||
{
|
||||
id: 'aws-logs-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.awsTitle',
|
||||
{
|
||||
defaultMessage: 'AWS',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.awsDescription',
|
||||
{
|
||||
defaultMessage: 'Collect logs from Amazon Web Services (AWS)',
|
||||
}
|
||||
),
|
||||
name: 'aws',
|
||||
categories: ['observability'],
|
||||
icons: [],
|
||||
url: 'https://aws.com',
|
||||
version: '',
|
||||
integration: '',
|
||||
isCollectionCard: true,
|
||||
onCardClick: createCollectionCardHandler('aws'),
|
||||
},
|
||||
{
|
||||
id: 'gcp-logs-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.gcpTitle',
|
||||
{
|
||||
defaultMessage: 'Google Cloud Platform',
|
||||
}
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.useCustomCardsForCategory.gcpDescription',
|
||||
{
|
||||
defaultMessage: 'Collect logs from Google Cloud Platform',
|
||||
}
|
||||
),
|
||||
name: 'gcp',
|
||||
categories: ['observability'],
|
||||
icons: [],
|
||||
url: '',
|
||||
version: '',
|
||||
integration: '',
|
||||
isCollectionCard: true,
|
||||
onCardClick: createCollectionCardHandler('gcp'),
|
||||
},
|
||||
];
|
||||
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function ExtraLabelBadgeWrapper({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<EuiFlexItem grow={false} css={{ alignSelf: 'center' }}>
|
||||
{children}
|
||||
</EuiFlexItem>
|
||||
);
|
||||
}
|
|
@ -1,103 +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 { i18n } from '@kbn/i18n';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { reactRouterNavigate, useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { CustomCard } from '../packages_list/types';
|
||||
import { ObservabilityOnboardingAppServices } from '../..';
|
||||
|
||||
export function useVirtualSearchResults(): CustomCard[] {
|
||||
const {
|
||||
services: {
|
||||
application,
|
||||
context: { isCloud },
|
||||
},
|
||||
} = useKibana<ObservabilityOnboardingAppServices>();
|
||||
|
||||
const history = useHistory();
|
||||
const { href: customLogsUrl } = reactRouterNavigate(history, `/customLogs/${location.search}`);
|
||||
const { href: firehoseUrl } = reactRouterNavigate(history, `/firehose/${location.search}`);
|
||||
const getUrlForApp = application?.getUrlForApp;
|
||||
const firehoseQuickstartCard: CustomCard = {
|
||||
id: 'firehose-quick-start',
|
||||
name: 'firehose-quick-start',
|
||||
type: 'virtual',
|
||||
title: i18n.translate('xpack.observability_onboarding.packageList.uploadFileTitle', {
|
||||
defaultMessage: 'AWS Firehose',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.packageList.uploadFileDescription',
|
||||
{
|
||||
defaultMessage: 'Collect logs and metrics from Amazon Web Services (AWS).',
|
||||
}
|
||||
),
|
||||
categories: [],
|
||||
icons: [
|
||||
{
|
||||
type: 'svg',
|
||||
src: 'https://epr.elastic.co/package/awsfirehose/1.1.0/img/logo_firehose.svg',
|
||||
},
|
||||
],
|
||||
url: firehoseUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
isQuickstart: true,
|
||||
};
|
||||
|
||||
return [
|
||||
{
|
||||
id: 'upload-file-virtual',
|
||||
type: 'virtual',
|
||||
title: i18n.translate('xpack.observability_onboarding.packageList.uploadFileTitle', {
|
||||
defaultMessage: 'Upload a file',
|
||||
}),
|
||||
description: i18n.translate(
|
||||
'xpack.observability_onboarding.packageList.uploadFileDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Upload data from a CSV, TSV, JSON or other log file to Elasticsearch for analysis.',
|
||||
}
|
||||
),
|
||||
name: 'upload-file',
|
||||
categories: [],
|
||||
icons: [
|
||||
{
|
||||
type: 'eui',
|
||||
src: 'addDataApp',
|
||||
},
|
||||
],
|
||||
url: `${getUrlForApp?.('home')}#/tutorial_directory/fileDataViz`,
|
||||
version: '',
|
||||
integration: '',
|
||||
isCollectionCard: false,
|
||||
},
|
||||
{
|
||||
id: 'custom-logs',
|
||||
type: 'virtual',
|
||||
title: 'Stream log files',
|
||||
description: 'Stream any logs into Elastic in a simple way and explore their data',
|
||||
name: 'custom-logs-virtual',
|
||||
categories: ['observability'],
|
||||
icons: [
|
||||
{
|
||||
type: 'eui',
|
||||
src: 'filebeatApp',
|
||||
},
|
||||
],
|
||||
url: customLogsUrl,
|
||||
version: '',
|
||||
integration: '',
|
||||
},
|
||||
/**
|
||||
* The new Firehose card should only be visible on Cloud
|
||||
* as Firehose integration requires additional proxy,
|
||||
* which is not available for on-prem customers.
|
||||
*/
|
||||
...(isCloud ? [firehoseQuickstartCard] : []),
|
||||
];
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 { IntegrationCardItem } from '@kbn/fleet-plugin/public';
|
||||
import React, { Suspense, lazy } from 'react';
|
||||
|
||||
export const LazyPackageList = lazy(async () => ({
|
||||
default: await import('@kbn/fleet-plugin/public')
|
||||
.then((module) => module.PackageList())
|
||||
.then((pkg) => pkg.PackageListGrid),
|
||||
}));
|
||||
|
||||
interface Props {
|
||||
list: IntegrationCardItem[];
|
||||
searchTerm?: string;
|
||||
}
|
||||
|
||||
export function PackageList({ list, searchTerm = '' }: Props) {
|
||||
return (
|
||||
/**
|
||||
* Suspense wrapper is required by PackageListGrid, but
|
||||
* Onboarding does not need it because it pre-loads all
|
||||
* packages beforehand with a custom loading state.
|
||||
*/
|
||||
<Suspense fallback={<></>}>
|
||||
<LazyPackageList
|
||||
list={list}
|
||||
searchTerm={searchTerm}
|
||||
showControls={false}
|
||||
showSearchTools={false}
|
||||
// we either don't need these properties (yet) or handle them upstream, but
|
||||
// they are marked as required in the original API.
|
||||
selectedCategory=""
|
||||
setSearchTerm={() => {}}
|
||||
setCategory={() => {}}
|
||||
categories={[]}
|
||||
setUrlandReplaceHistory={() => {}}
|
||||
setUrlandPushHistory={() => {}}
|
||||
showCardLabels={true}
|
||||
/>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
|
@ -9,120 +9,80 @@ import type { AvailablePackagesHookType, IntegrationCardItem } from '@kbn/fleet-
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { EuiButton, EuiCallOut, EuiSearchBar, EuiSkeletonText } from '@elastic/eui';
|
||||
import React, { useRef, Suspense, useEffect } from 'react';
|
||||
import React, { useRef, useMemo } from 'react';
|
||||
import useAsyncRetry from 'react-use/lib/useAsyncRetry';
|
||||
import { PackageList, fetchAvailablePackagesHook } from './lazy';
|
||||
import { useIntegrationCardList } from './use_integration_card_list';
|
||||
import { CustomCard } from './types';
|
||||
import { useCardUrlRewrite } from './use_card_url_rewrite';
|
||||
import { PackageList } from '../package_list/package_list';
|
||||
|
||||
interface Props {
|
||||
searchQuery: string;
|
||||
setSearchQuery: (searchQuery: string) => void;
|
||||
/**
|
||||
* A subset of either existing card names to feature, or virtual
|
||||
* cards to display. The inclusion of CustomCards will override the default
|
||||
* list functionality.
|
||||
*/
|
||||
customCards?: CustomCard[];
|
||||
/**
|
||||
* Override the default `observability` option.
|
||||
* A list of custom items to include into the package list
|
||||
*/
|
||||
customCards?: IntegrationCardItem[];
|
||||
selectedCategory?: string[];
|
||||
showSearchBar?: boolean;
|
||||
packageListRef?: React.Ref<HTMLDivElement>;
|
||||
searchQuery?: string;
|
||||
setSearchQuery?: React.Dispatch<React.SetStateAction<string>>;
|
||||
flowCategory?: string | null;
|
||||
flowSearch?: string;
|
||||
/**
|
||||
* When enabled, custom and integration cards are joined into a single list.
|
||||
*/
|
||||
joinCardLists?: boolean;
|
||||
excludePackageIdList?: string[];
|
||||
onLoaded?: () => void;
|
||||
}
|
||||
|
||||
type WrapperProps = Props & {
|
||||
useAvailablePackages: AvailablePackagesHookType;
|
||||
};
|
||||
|
||||
const Loading = () => <EuiSkeletonText isLoading={true} lines={10} />;
|
||||
const fetchAvailablePackagesHook = (): Promise<AvailablePackagesHookType> =>
|
||||
import('@kbn/fleet-plugin/public')
|
||||
.then((module) => module.AvailablePackagesHook())
|
||||
.then((hook) => hook.useAvailablePackages);
|
||||
|
||||
const Loading = () => <EuiSkeletonText isLoading={true} lines={5} />;
|
||||
|
||||
const PackageListGridWrapper = ({
|
||||
selectedCategory = ['observability', 'os_system'],
|
||||
useAvailablePackages,
|
||||
showSearchBar = false,
|
||||
packageListRef,
|
||||
searchQuery,
|
||||
setSearchQuery,
|
||||
customCards,
|
||||
flowCategory,
|
||||
flowSearch,
|
||||
joinCardLists = false,
|
||||
excludePackageIdList = [],
|
||||
onLoaded,
|
||||
}: WrapperProps) => {
|
||||
const { filteredCards, isLoading } = useAvailablePackages({
|
||||
const { filteredCards: integrationCards, isLoading } = useAvailablePackages({
|
||||
prereleaseIntegrationsEnabled: false,
|
||||
});
|
||||
const rewriteUrl = useCardUrlRewrite({ category: flowCategory, search: searchQuery });
|
||||
|
||||
const list: IntegrationCardItem[] = useIntegrationCardList(
|
||||
filteredCards,
|
||||
selectedCategory,
|
||||
excludePackageIdList,
|
||||
customCards,
|
||||
flowCategory,
|
||||
flowSearch,
|
||||
joinCardLists
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoading && onLoaded !== undefined) {
|
||||
onLoaded();
|
||||
}
|
||||
}, [isLoading, onLoaded]);
|
||||
const list: IntegrationCardItem[] = useMemo(() => {
|
||||
return (customCards ?? [])
|
||||
.concat(integrationCards)
|
||||
.filter((card) =>
|
||||
card.categories.some((category) => ['observability', 'os_system'].includes(category))
|
||||
)
|
||||
.filter((card) => !excludePackageIdList.includes(card.id))
|
||||
.map(rewriteUrl);
|
||||
}, [customCards, excludePackageIdList, integrationCards, rewriteUrl]);
|
||||
|
||||
if (isLoading) return <Loading />;
|
||||
|
||||
const showPackageList = (showSearchBar && !!searchQuery) || showSearchBar === false;
|
||||
|
||||
return (
|
||||
<Suspense fallback={<Loading />}>
|
||||
<div ref={packageListRef}>
|
||||
{showSearchBar && (
|
||||
<EuiSearchBar
|
||||
box={{
|
||||
incremental: true,
|
||||
}}
|
||||
onChange={({ queryText, error }) => {
|
||||
if (error) return;
|
||||
<div ref={packageListRef}>
|
||||
<EuiSearchBar
|
||||
box={{
|
||||
incremental: true,
|
||||
}}
|
||||
onChange={({ queryText, error }) => {
|
||||
if (error) return;
|
||||
|
||||
setSearchQuery?.(queryText);
|
||||
}}
|
||||
query={searchQuery ?? ''}
|
||||
/>
|
||||
)}
|
||||
{showPackageList && (
|
||||
<PackageList
|
||||
list={list}
|
||||
searchTerm={searchQuery ?? ''}
|
||||
showControls={false}
|
||||
showSearchTools={false}
|
||||
// we either don't need these properties (yet) or handle them upstream, but
|
||||
// they are marked as required in the original API.
|
||||
selectedCategory=""
|
||||
setSearchTerm={() => {}}
|
||||
setCategory={() => {}}
|
||||
categories={[]}
|
||||
setUrlandReplaceHistory={() => {}}
|
||||
setUrlandPushHistory={() => {}}
|
||||
showCardLabels={true}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Suspense>
|
||||
setSearchQuery(queryText);
|
||||
}}
|
||||
query={searchQuery}
|
||||
/>
|
||||
{searchQuery !== '' && <PackageList list={list} searchTerm={searchQuery} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const WithAvailablePackages = React.forwardRef(
|
||||
export const PackageListSearchForm = React.forwardRef(
|
||||
(props: Props, packageListRef?: React.Ref<HTMLDivElement>) => {
|
||||
const ref = useRef<AvailablePackagesHookType | null>(null);
|
||||
|
||||
|
@ -176,5 +136,3 @@ const WithAvailablePackages = React.forwardRef(
|
|||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { WithAvailablePackages as OnboardingFlowPackageList };
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { addPathParamToUrl, toOnboardingPath } from './use_integration_card_list';
|
||||
import { addPathParamToUrl, toOnboardingPath } from './use_card_url_rewrite';
|
||||
|
||||
describe('useIntegratrionCardList', () => {
|
||||
describe('toOnboardingPath', () => {
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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 { useMemo } from 'react';
|
||||
import { IntegrationCardItem } from '@kbn/fleet-plugin/public';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
|
||||
export function toOnboardingPath({
|
||||
basePath,
|
||||
category,
|
||||
search,
|
||||
}: {
|
||||
basePath?: string;
|
||||
category?: string | null;
|
||||
search?: string;
|
||||
}): string | null {
|
||||
if (typeof basePath !== 'string' && !basePath) return null;
|
||||
const path = `${basePath}/app/observabilityOnboarding`;
|
||||
if (!category && !search) return path;
|
||||
const params = new URLSearchParams();
|
||||
if (category) params.append('category', category);
|
||||
if (search) params.append('search', search);
|
||||
return `${path}?${params.toString()}`;
|
||||
}
|
||||
|
||||
export function addPathParamToUrl(url: string, onboardingLink: string) {
|
||||
const encoded = encodeURIComponent(onboardingLink);
|
||||
if (url.indexOf('?') >= 0) {
|
||||
return `${url}&observabilityOnboardingLink=${encoded}`;
|
||||
}
|
||||
return `${url}?observabilityOnboardingLink=${encoded}`;
|
||||
}
|
||||
|
||||
export function useCardUrlRewrite(props: { category?: string | null; search?: string }) {
|
||||
const kibana = useKibana();
|
||||
const basePath = kibana.services.http?.basePath.get();
|
||||
const onboardingLink = useMemo(() => toOnboardingPath({ basePath, ...props }), [basePath, props]);
|
||||
return (card: IntegrationCardItem) => ({
|
||||
...card,
|
||||
url:
|
||||
card.url.indexOf('/app/integrations') >= 0 && onboardingLink
|
||||
? addPathParamToUrl(card.url, onboardingLink)
|
||||
: card.url,
|
||||
});
|
||||
}
|
|
@ -1,20 +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 type { AvailablePackagesHookType } from '@kbn/fleet-plugin/public';
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const PackageList = lazy(async () => ({
|
||||
default: await import('@kbn/fleet-plugin/public')
|
||||
.then((module) => module.PackageList())
|
||||
.then((pkg) => pkg.PackageListGrid),
|
||||
}));
|
||||
|
||||
export const fetchAvailablePackagesHook = (): Promise<AvailablePackagesHookType> =>
|
||||
import('@kbn/fleet-plugin/public')
|
||||
.then((module) => module.AvailablePackagesHook())
|
||||
.then((hook) => hook.useAvailablePackages);
|
|
@ -1,19 +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 { IntegrationCardItem } from '@kbn/fleet-plugin/public';
|
||||
|
||||
export type VirtualCard = {
|
||||
type: 'virtual';
|
||||
} & IntegrationCardItem;
|
||||
|
||||
export interface FeaturedCard {
|
||||
type: 'featured';
|
||||
name: string;
|
||||
}
|
||||
|
||||
export type CustomCard = FeaturedCard | VirtualCard;
|
|
@ -1,139 +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 { useMemo } from 'react';
|
||||
import { IntegrationCardItem } from '@kbn/fleet-plugin/public';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { CustomCard } from './types';
|
||||
|
||||
export function toOnboardingPath({
|
||||
basePath,
|
||||
category,
|
||||
search,
|
||||
}: {
|
||||
basePath?: string;
|
||||
category?: string | null;
|
||||
search?: string;
|
||||
}): string | null {
|
||||
if (typeof basePath !== 'string' && !basePath) return null;
|
||||
const path = `${basePath}/app/observabilityOnboarding`;
|
||||
if (!category && !search) return path;
|
||||
const params = new URLSearchParams();
|
||||
if (category) params.append('category', category);
|
||||
if (search) params.append('search', search);
|
||||
return `${path}?${params.toString()}`;
|
||||
}
|
||||
|
||||
export function addPathParamToUrl(url: string, onboardingLink: string) {
|
||||
const encoded = encodeURIComponent(onboardingLink);
|
||||
if (url.indexOf('?') >= 0) {
|
||||
return `${url}&observabilityOnboardingLink=${encoded}`;
|
||||
}
|
||||
return `${url}?observabilityOnboardingLink=${encoded}`;
|
||||
}
|
||||
|
||||
function useCardUrlRewrite(props: { category?: string | null; search?: string }) {
|
||||
const kibana = useKibana();
|
||||
const basePath = kibana.services.http?.basePath.get();
|
||||
const onboardingLink = useMemo(() => toOnboardingPath({ basePath, ...props }), [basePath, props]);
|
||||
return (card: IntegrationCardItem) => ({
|
||||
...card,
|
||||
url:
|
||||
card.url.indexOf('/app/integrations') >= 0 && onboardingLink
|
||||
? addPathParamToUrl(card.url, onboardingLink)
|
||||
: card.url,
|
||||
});
|
||||
}
|
||||
|
||||
function extractFeaturedCards(filteredCards: IntegrationCardItem[], featuredCardNames?: string[]) {
|
||||
const featuredCards: Record<string, IntegrationCardItem | undefined> = {};
|
||||
filteredCards.forEach((card) => {
|
||||
if (featuredCardNames?.includes(card.name)) {
|
||||
featuredCards[card.name] = card;
|
||||
}
|
||||
});
|
||||
return featuredCards;
|
||||
}
|
||||
|
||||
function formatCustomCards(
|
||||
rewriteUrl: (card: IntegrationCardItem) => IntegrationCardItem,
|
||||
customCards: CustomCard[],
|
||||
featuredCards: Record<string, IntegrationCardItem | undefined>
|
||||
) {
|
||||
const cards: IntegrationCardItem[] = [];
|
||||
for (const card of customCards) {
|
||||
if (card.type === 'featured' && !!featuredCards[card.name]) {
|
||||
cards.push(rewriteUrl(featuredCards[card.name]!));
|
||||
} else if (card.type === 'virtual') {
|
||||
cards.push(rewriteUrl(card));
|
||||
}
|
||||
}
|
||||
return cards;
|
||||
}
|
||||
|
||||
function useFilteredCards(
|
||||
rewriteUrl: (card: IntegrationCardItem) => IntegrationCardItem,
|
||||
integrationsList: IntegrationCardItem[],
|
||||
selectedCategory: string[],
|
||||
excludePackageIdList: string[],
|
||||
customCards?: CustomCard[]
|
||||
) {
|
||||
return useMemo(() => {
|
||||
const integrationCards = integrationsList
|
||||
.filter((card) => !excludePackageIdList.includes(card.id))
|
||||
.filter((card) => card.categories.some((category) => selectedCategory.includes(category)))
|
||||
.map(rewriteUrl);
|
||||
|
||||
if (!customCards) {
|
||||
return { featuredCards: {}, integrationCards };
|
||||
}
|
||||
|
||||
return {
|
||||
featuredCards: extractFeaturedCards(
|
||||
integrationsList,
|
||||
customCards.filter((c) => c.type === 'featured').map((c) => c.name)
|
||||
),
|
||||
integrationCards,
|
||||
};
|
||||
}, [integrationsList, rewriteUrl, customCards, excludePackageIdList, selectedCategory]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the cards to display on the integration list.
|
||||
* @param integrationsList the list of cards from the integrations API.
|
||||
* @param selectedCategory the card category to filter by.
|
||||
* @param customCards any virtual or featured cards.
|
||||
* @param fullList when true all integration cards are included.
|
||||
* @returns the list of cards to display.
|
||||
*/
|
||||
export function useIntegrationCardList(
|
||||
integrationsList: IntegrationCardItem[],
|
||||
selectedCategory: string[],
|
||||
excludePackageIdList: string[],
|
||||
customCards?: CustomCard[],
|
||||
flowCategory?: string | null,
|
||||
flowSearch?: string,
|
||||
fullList = false
|
||||
): IntegrationCardItem[] {
|
||||
const rewriteUrl = useCardUrlRewrite({ category: flowCategory, search: flowSearch });
|
||||
const { featuredCards, integrationCards } = useFilteredCards(
|
||||
rewriteUrl,
|
||||
integrationsList,
|
||||
selectedCategory,
|
||||
excludePackageIdList,
|
||||
customCards
|
||||
);
|
||||
|
||||
if (customCards && customCards.length > 0) {
|
||||
const formattedCustomCards = formatCustomCards(rewriteUrl, customCards, featuredCards);
|
||||
if (fullList) {
|
||||
return [...formattedCustomCards, ...integrationCards] as IntegrationCardItem[];
|
||||
}
|
||||
return formattedCustomCards;
|
||||
}
|
||||
return integrationCards;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue