[Fleet] Add installed integration callouts (#113893) (#114409)

Co-authored-by: Clint Andrew Hall <clint@clintandrewhall.com>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>

Co-authored-by: Thomas Neirynck <thomas@elastic.co>
Co-authored-by: Clint Andrew Hall <clint@clintandrewhall.com>
This commit is contained in:
Kibana Machine 2021-10-09 05:15:04 -04:00 committed by GitHub
parent 78879551b7
commit c854dfdbf8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 70 additions and 4 deletions

View file

@ -233,6 +233,7 @@ readonly links: {
datastreamsNamingScheme: string;
upgradeElasticAgent: string;
upgradeElasticAgent712lower: string;
learnMoreBlog: string;
}>;
readonly ecs: {
readonly guide: string;

View file

@ -476,6 +476,7 @@ export class DocLinksService {
datastreamsNamingScheme: `${FLEET_DOCS}data-streams.html#data-streams-naming-scheme`,
upgradeElasticAgent: `${FLEET_DOCS}upgrade-elastic-agent.html`,
upgradeElasticAgent712lower: `${FLEET_DOCS}upgrade-elastic-agent.html#upgrade-7.12-lower`,
learnMoreBlog: `${ELASTIC_WEBSITE_URL}blog/elastic-agent-and-fleet-make-it-easier-to-integrate-your-systems-with-elastic`,
},
ecs: {
guide: `${ELASTIC_WEBSITE_URL}guide/en/ecs/current/index.html`,
@ -728,6 +729,7 @@ export interface DocLinksStart {
datastreamsNamingScheme: string;
upgradeElasticAgent: string;
upgradeElasticAgent712lower: string;
learnMoreBlog: string;
}>;
readonly ecs: {
readonly guide: string;

View file

@ -703,6 +703,7 @@ export interface DocLinksStart {
datastreamsNamingScheme: string;
upgradeElasticAgent: string;
upgradeElasticAgent712lower: string;
learnMoreBlog: string;
}>;
readonly ecs: {
readonly guide: string;

View file

@ -38,6 +38,7 @@ export interface ListProps {
setSelectedCategory: (category: string) => void;
onSearchChange: (search: string) => void;
showMissingIntegrationMessage?: boolean;
callout?: JSX.Element | null;
}
export function PackageListGrid({
@ -49,6 +50,7 @@ export function PackageListGrid({
onSearchChange,
setSelectedCategory,
showMissingIntegrationMessage = false,
callout,
}: ListProps) {
const [searchTerm, setSearchTerm] = useState(initialSearch || '');
const localSearchRef = useLocalSearch(list);
@ -105,6 +107,7 @@ export function PackageListGrid({
}}
onChange={onQueryChange}
/>
{callout ? callout : null}
<EuiSpacer />
{gridContent}
{showMissingIntegrationMessage && (

View file

@ -5,10 +5,13 @@
* 2.0.
*/
import React, { memo, useMemo } from 'react';
import React, { memo, useMemo, Fragment } from 'react';
import { Switch, Route, useLocation, useHistory, useParams } from 'react-router-dom';
import semverLt from 'semver/functions/lt';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiCallOut, EuiLink, EuiSpacer } from '@elastic/eui';
import { installationStatuses } from '../../../../../../../common/constants';
import type { DynamicPage, DynamicPagePathValues, StaticPage } from '../../../../constants';
@ -24,6 +27,7 @@ import {
useGetAppendCustomIntegrations,
useGetReplacementCustomIntegrations,
useLink,
useStartServices,
} from '../../../../hooks';
import { doesPackageHaveIntegrations } from '../../../../services';
import { DefaultLayout } from '../../../../layouts';
@ -143,6 +147,7 @@ const InstalledPackages: React.FC = memo(() => {
experimental: true,
});
const { getHref, getAbsolutePath } = useLink();
const { docLinks } = useStartServices();
const { selectedCategory, searchParam } = getParams(
useParams<CategoryParams>(),
@ -225,6 +230,38 @@ const InstalledPackages: React.FC = memo(() => {
return mapToCard(getAbsolutePath, getHref, item);
});
const link = (
<EuiLink href={docLinks.links.fleet.learnMoreBlog} target="_blank">
{i18n.translate('xpack.fleet.epmList.availableCalloutBlogText', {
defaultMessage: 'announcement blog post',
})}
</EuiLink>
);
const calloutMessage = (
<FormattedMessage
id="xpack.fleet.epmList.availableCalloutIntroText"
defaultMessage="To learn more about integrations and the Elastic Agent, read our {link}"
values={{
link,
}}
/>
);
const callout =
selectedCategory === 'updates_available' ? null : (
<Fragment>
<EuiSpacer />
<EuiCallOut
title={i18n.translate('xpack.fleet.epmList.availableCalloutTitle', {
defaultMessage: 'Only installed Elastic Agent Integrations are displayed.',
})}
iconType="iInCircle"
>
<p>{calloutMessage}</p>
</EuiCallOut>
</Fragment>
);
return (
<PackageListGrid
isLoading={isLoadingPackages}
@ -234,6 +271,7 @@ const InstalledPackages: React.FC = memo(() => {
initialSearch={searchParam}
title={title}
list={cards}
callout={callout}
/>
);
});

View file

@ -0,0 +1,21 @@
/*
* 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 { DocLinksStart } from 'kibana/public';
export const getDocLinks = () => {
const docLinks: DocLinksStart = {
links: {
fleet: {
learnMoreBlog:
'https://www.elastic.co/blog/elastic-agent-and-fleet-make-it-easier-to-integrate-your-systems-with-elastic',
},
},
} as unknown as DocLinksStart;
return docLinks;
};

View file

@ -27,6 +27,7 @@ import { getHttp } from './http';
import { getUiSettings } from './ui_settings';
import { getNotifications } from './notifications';
import { stubbedStartServices } from './stubs';
import { getDocLinks } from './doc_links';
// TODO: clintandrewhall - this is not ideal, or complete. The root context of Fleet applications
// requires full start contracts of its dependencies. As a result, we have to mock all of those contracts
@ -42,8 +43,10 @@ export const StorybookContext: React.FC<{ storyContext?: StoryContext }> = ({
const history = new ScopedHistory(browserHistory, basepath);
const startServices: FleetStartServices = {
...stubbedStartServices,
application: getApplication(),
chrome: getChrome(),
docLinks: getDocLinks(),
http: getHttp(),
notifications: getNotifications(),
uiSettings: getUiSettings(),
@ -58,7 +61,6 @@ export const StorybookContext: React.FC<{ storyContext?: StoryContext }> = ({
customIntegrations: {
ContextProvider: getStorybookContextProvider(),
},
...stubbedStartServices,
};
setHttpClient(startServices.http);

View file

@ -9,7 +9,6 @@ import type { FleetStartServices } from '../../public/plugin';
type Stubs =
| 'storage'
| 'docLinks'
| 'data'
| 'deprecations'
| 'fatalErrors'
@ -22,7 +21,6 @@ type StubbedStartServices = Pick<FleetStartServices, Stubs>;
export const stubbedStartServices: StubbedStartServices = {
storage: {} as FleetStartServices['storage'],
docLinks: {} as FleetStartServices['docLinks'],
data: {} as FleetStartServices['data'],
deprecations: {} as FleetStartServices['deprecations'],
fatalErrors: {} as FleetStartServices['fatalErrors'],