diff --git a/src/core/public/rendering/_base.scss b/src/core/public/rendering/_base.scss index 32a297a4066d9..c97afbf14a8f6 100644 --- a/src/core/public/rendering/_base.scss +++ b/src/core/public/rendering/_base.scss @@ -43,10 +43,12 @@ top: $headerHeight; } - .kbnStickyMenu { - position: sticky; - max-height: calc(100vh - #{$headerHeight + $euiSize}); - top: $headerHeight + $euiSize; + @include euiBreakpoint('xl', 'l') { + .kbnStickyMenu { + position: sticky; + max-height: calc(100vh - #{$headerHeight + $euiSize}); + top: $headerHeight + $euiSize; + } } } diff --git a/src/plugins/index_pattern_editor/public/components/empty_prompts/empty_index_list_prompt/empty_index_list_prompt.tsx b/src/plugins/index_pattern_editor/public/components/empty_prompts/empty_index_list_prompt/empty_index_list_prompt.tsx index a550209095898..3afd7ef1ded6b 100644 --- a/src/plugins/index_pattern_editor/public/components/empty_prompts/empty_index_list_prompt/empty_index_list_prompt.tsx +++ b/src/plugins/index_pattern_editor/public/components/empty_prompts/empty_index_list_prompt/empty_index_list_prompt.tsx @@ -91,7 +91,7 @@ export const EmptyIndexListPrompt = ({ { - navigateToApp('home', { path: '/app/integrations/browse' }); + navigateToApp('integrations', { path: '/browse' }); closeFlyout(); }} icon={} diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap index 8e1d0cb92e006..30703a4a5ebb7 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap @@ -15,11 +15,16 @@ exports[`ElasticAgentCard props button 1`] = ` Button - + + Button + + } href="/app/integrations/browse" image="/plugins/kibanaReact/assets/elastic_agent_card.svg" @@ -50,11 +55,15 @@ exports[`ElasticAgentCard props category 1`] = ` - Add Elastic Agent - + + Add Elastic Agent + + } href="/app/integrations/browse/custom" image="/plugins/kibanaReact/assets/elastic_agent_card.svg" @@ -85,11 +94,16 @@ exports[`ElasticAgentCard props href 1`] = ` Button - + + Button + + } href="#" image="/plugins/kibanaReact/assets/elastic_agent_card.svg" @@ -121,11 +135,15 @@ exports[`ElasticAgentCard props recommended 1`] = ` betaBadgeLabel="Recommended" description="Use Elastic Agent for a simple, unified way to collect data from your machines." footer={ - - Add Elastic Agent - + + Add Elastic Agent + + } href="/app/integrations/browse" image="/plugins/kibanaReact/assets/elastic_agent_card.svg" @@ -156,11 +174,15 @@ exports[`ElasticAgentCard renders 1`] = ` - Add Elastic Agent - + + Add Elastic Agent + + } href="/app/integrations/browse" image="/plugins/kibanaReact/assets/elastic_agent_card.svg" diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/no_data_card.test.tsx.snap b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/no_data_card.test.tsx.snap index fccbbe3a9e8ee..6959e2e29095a 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/no_data_card.test.tsx.snap +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/no_data_card.test.tsx.snap @@ -2,7 +2,7 @@ exports[`NoDataCard props button 1`] = `
- + +
`; exports[`NoDataCard props href 1`] = `
- + +
`; exports[`NoDataCard props recommended 1`] = `
+ `; exports[`NoDataCard renders 1`] = `
+ `; diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx index b9d412fe4df89..d429f9d712081 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx @@ -44,6 +44,7 @@ export const ElasticAgentCard: FunctionComponent = ({ {i18n.translate('kibana-react.noDataPage.elasticAgentCard.noPermission.title', { @@ -92,7 +93,12 @@ export const ElasticAgentCard: FunctionComponent = ({ defaultMessage: `Use Elastic Agent for a simple, unified way to collect data from your machines.`, })} betaBadgeLabel={recommended ? NO_DATA_RECOMMENDED : undefined} - footer={footer} + footer={ +
+ {button} + {footer} +
+ } layout={layout as 'vertical' | undefined} {...cardRest} /> diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/no_data_card.tsx b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/no_data_card.tsx index 9cc38cc5f6038..ad40a4f8f5499 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/no_data_card.tsx +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/no_data_card.tsx @@ -27,6 +27,7 @@ export const NoDataCard: FunctionComponent = ({ return ( = ({ defaultMessage: `Proceed without collecting data`, })} betaBadgeLabel={recommended ? NO_DATA_RECOMMENDED : undefined} - footer={footer} + footer={
{footer}
} layout={layout as 'vertical' | undefined} {...cardRest} /> diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/integration_preference.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/integration_preference.tsx index 4634996d6bc73..9c9027fb94ac5 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/integration_preference.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/integration_preference.tsx @@ -46,7 +46,7 @@ const link = ( const title = ( ); @@ -115,6 +115,7 @@ export const IntegrationPreference = ({ initialType, onChange }: Props) => { name="preference" /> + ); }; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx index d2d361cd212a6..91bd29d14d0b3 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid.tsx @@ -18,6 +18,7 @@ import { EuiText, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; + import { FormattedMessage } from '@kbn/i18n/react'; import { Loading } from '../../../components'; @@ -32,6 +33,7 @@ export interface Props { controls?: ReactNode | ReactNode[]; title?: string; list: IntegrationCardItem[]; + featuredList?: JSX.Element | null; initialSearch?: string; setSelectedCategory: (category: string) => void; onSearchChange: (search: string) => void; @@ -48,6 +50,7 @@ export const PackageListGrid: FunctionComponent = ({ onSearchChange, setSelectedCategory, showMissingIntegrationMessage = false, + featuredList = null, callout, }) => { const [searchTerm, setSearchTerm] = useState(initialSearch || ''); @@ -106,42 +109,45 @@ export const PackageListGrid: FunctionComponent = ({ } return ( -
- - - {controlsContent} - - - - {callout ? ( - <> - - {callout} - - ) : null} - - {gridContent} - {showMissingIntegrationMessage && ( - <> - - - - )} - - -
+ <> + {featuredList} +
+ + + {controlsContent} + + + + {callout ? ( + <> + + {callout} + + ) : null} + + {gridContent} + {showMissingIntegrationMessage && ( + <> + + + + )} + + +
+ ); }; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx index 73de0e51bea65..4f13a874532f1 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/home/available_packages.tsx @@ -8,7 +8,18 @@ import React, { memo, useMemo, useState } from 'react'; import { useLocation, useHistory, useParams } from 'react-router-dom'; import _ from 'lodash'; -import { EuiHorizontalRule, EuiFlexItem } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { + EuiHorizontalRule, + EuiFlexItem, + EuiFlexGrid, + EuiSpacer, + EuiCard, + EuiIcon, +} from '@elastic/eui'; + +import { useStartServices } from '../../../../hooks'; +import { TrackApplicationView } from '../../../../../../../../../../src/plugins/usage_collection/public'; import { pagePathGetters } from '../../../../constants'; import { @@ -98,6 +109,9 @@ export const AvailablePackages: React.FC = memo(() => { const [preference, setPreference] = useState('recommended'); useBreadcrumbs('integrations_all'); + const { http } = useStartServices(); + const addBasePath = http.basePath.prepend; + const { selectedCategory, searchParam } = getParams( useParams(), useLocation().search @@ -210,8 +224,62 @@ export const AvailablePackages: React.FC = memo(() => { return c.categories.includes(selectedCategory); }); + // TODO: Remove this hard coded list of integrations with a suggestion service + const featuredList = ( + <> + + + + } + href={addBasePath('/app/integrations/detail/endpoint/')} + title={i18n.translate('xpack.fleet.featuredSecurityTitle', { + defaultMessage: 'Endpoint Security', + })} + description={i18n.translate('xpack.fleet.featuredSecurityDesc', { + defaultMessage: + 'Protect your hosts with threat prevention, detection, and deep security data visibility.', + })} + /> + + + + + } + /> + + + + + } + href={addBasePath('/app/enterprise_search/app_search')} + title={i18n.translate('xpack.fleet.featuredSearchTitle', { + defaultMessage: 'Web site crawler', + })} + description={i18n.translate('xpack.fleet.featuredSearchDesc', { + defaultMessage: 'Add search to your website with the App Search web crawler.', + })} + /> + + + + + + ); + return ( { const { docLinks } = useStartServices(); @@ -56,10 +56,6 @@ const Callout = () => ( ); -const title = i18n.translate('xpack.fleet.epmList.installedTitle', { - defaultMessage: 'Installed integrations', -}); - // TODO: clintandrewhall - this component is hard to test due to the hooks, particularly those that use `http` // or `location` to load data. Ideally, we'll split this into "connected" and "pure" components. export const InstalledPackages: React.FC = memo(() => { @@ -115,7 +111,7 @@ export const InstalledPackages: React.FC = memo(() => { const categories: CategoryFacet[] = useMemo( () => [ { - ...ALL_CATEGORY, + ...INSTALLED_CATEGORY, count: allInstalledPackages.length, }, { @@ -153,7 +149,7 @@ export const InstalledPackages: React.FC = memo(() => { return (