Skip to content

Commit

Permalink
Update navigation landing pages to use appLinks config
Browse files Browse the repository at this point in the history
  • Loading branch information
machadoum committed May 12, 2022
1 parent 4ef0f1e commit b684e3d
Show file tree
Hide file tree
Showing 26 changed files with 277 additions and 304 deletions.
6 changes: 3 additions & 3 deletions x-pack/plugins/security_solution/public/app/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const USERS = i18n.translate('xpack.securitySolution.navigation.users', {
});

export const RULES = i18n.translate('xpack.securitySolution.navigation.rules', {
defaultMessage: 'Rules',
defaultMessage: 'SIEM rules',
});

export const EXCEPTIONS = i18n.translate('xpack.securitySolution.navigation.exceptions', {
Expand Down Expand Up @@ -71,7 +71,7 @@ export const ENDPOINTS = i18n.translate('xpack.securitySolution.search.administr
export const POLICIES = i18n.translate(
'xpack.securitySolution.navigation.administration.policies',
{
defaultMessage: 'Policies',
defaultMessage: 'Endpoint policies',
}
);
export const TRUSTED_APPLICATIONS = i18n.translate(
Expand All @@ -90,7 +90,7 @@ export const EVENT_FILTERS = i18n.translate(
export const HOST_ISOLATION_EXCEPTIONS = i18n.translate(
'xpack.securitySolution.search.administration.hostIsolationExceptions',
{
defaultMessage: 'Host isolation exceptions',
defaultMessage: 'Host isolation IP exceptions',
}
);
export const DETECT = i18n.translate('xpack.securitySolution.navigation.detect', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ import {

const allowedExperimentalValues = getExperimentalAllowedValues();

export const useIsExperimentalFeatureEnabled = (feature: keyof ExperimentalFeatures): boolean =>
useSelector(({ app: { enableExperimental } }: State) => {
if (!enableExperimental || !(feature in enableExperimental)) {
throw new Error(
`Invalid enable value ${feature}. Allowed values are: ${allowedExperimentalValues.join(
', '
)}`
);
}
return enableExperimental[feature];
});
export const useIsExperimentalFeatureEnabled = (feature: keyof ExperimentalFeatures): boolean => {
const enableExperimental = useEnableExperimental();

if (!enableExperimental || !(feature in enableExperimental)) {
throw new Error(
`Invalid enable value ${feature}. Allowed values are: ${allowedExperimentalValues.join(', ')}`
);
}
return enableExperimental[feature];
};

export const useEnableExperimental = (): ExperimentalFeatures =>
useSelector(({ app: { enableExperimental } }: State) => enableExperimental);
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 13 additions & 4 deletions x-pack/plugins/security_solution/public/common/links/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import { AppDeepLink, AppNavLinkStatus, Capabilities } from '@kbn/core/public';
import { get } from 'lodash';
import { SecurityPageName } from '../../../common/constants';
import { useEnableExperimental } from '../hooks/use_experimental_features';
import { useLicense } from '../hooks/use_license';
import { useKibana } from '../lib/kibana';
import { appLinks, getAppLinks } from './app_links';
import {
Feature,
Expand All @@ -32,8 +35,6 @@ const createDeepLink = (link: LinkItem, linkProps?: UserPermissions): AppDeepLin
}),
}
: {}),
...(link.icon != null ? { euiIconType: link.icon } : {}),
...(link.image != null ? { icon: link.image } : {}),
...(link.globalSearchKeywords != null ? { keywords: link.globalSearchKeywords } : {}),
...(link.globalNavEnabled != null
? { navLinkStatus: link.globalNavEnabled ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden }
Expand All @@ -47,8 +48,8 @@ const createNavLinkItem = (link: LinkItem, linkProps?: UserPermissions): NavLink
path: link.path,
title: link.title,
...(link.description != null ? { description: link.description } : {}),
...(link.icon != null ? { icon: link.icon } : {}),
...(link.image != null ? { image: link.image } : {}),
...(link.landingIcon != null ? { icon: link.landingIcon } : {}),
...(link.landingImage != null ? { image: link.landingImage } : {}),
...(link.links && link.links.length
? {
links: reduceLinks<NavLinkItem>({
Expand Down Expand Up @@ -195,3 +196,11 @@ export const getAncestorLinksInfo = (id: SecurityPageName): LinkInfo[] => {
export const needsUrlState = (id: SecurityPageName): boolean => {
return !getNormalizedLink(id).skipUrlState;
};

export const useAppNavLinks = (): NavLinkItem[] => {
const license = useLicense();
const enableExperimental = useEnableExperimental();
const capabilities = useKibana().services.application.capabilities;

return getNavLinkItems({ enableExperimental, license, capabilities });
};
15 changes: 12 additions & 3 deletions x-pack/plugins/security_solution/public/common/links/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import { Capabilities } from '@kbn/core/types';
import { LicenseType } from '@kbn/licensing-plugin/common/types';
import { IconType } from '@elastic/eui';
import { LicenseService } from '../../../common/license';
import { ExperimentalFeatures } from '../../../common/experimental_features';
import { CASES_FEATURE_ID, SecurityPageName, SERVER_APP_ID } from '../../../common/constants';
Expand Down Expand Up @@ -41,9 +42,17 @@ export interface LinkItem {
globalSearchEnabled?: boolean;
globalSearchKeywords?: string[];
hideWhenExperimentalKey?: keyof ExperimentalFeatures;
icon?: string;
id: SecurityPageName;
image?: string;
/**
* Icon that is displayed on menu navigation landing page.
* Only required for pages that are displayed inside a landing page.
*/
landingIcon?: IconType;
/**
* Image that is displayed on menu navigation landing page.
* Only required for pages that are displayed inside a landing page.
*/
landingImage?: string;
isBeta?: boolean;
licenseType?: LicenseType;
links?: LinkItem[];
Expand All @@ -54,7 +63,7 @@ export interface LinkItem {

export interface NavLinkItem {
description?: string;
icon?: string;
icon?: IconType;
id: SecurityPageName;
links?: NavLinkItem[];
image?: string;
Expand Down
6 changes: 6 additions & 0 deletions x-pack/plugins/security_solution/public/hosts/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@ import { i18n } from '@kbn/i18n';
import { HOSTS_PATH, SecurityPageName } from '../../common/constants';
import { HOSTS } from '../app/translations';
import { LinkItem } from '../common/links/types';
import hostsPageImg from '../common/images/hosts_page.png';

export const links: LinkItem = {
id: SecurityPageName.hosts,
title: HOSTS,
landingImage: hostsPageImg,
description: i18n.translate('xpack.securitySolution.landing.threatHunting.hostsDescription', {
defaultMessage:
'A computer or other device that communicates with other hosts on a network. Hosts on a network include clients and servers -- that send or receive data, services or applications.',
}),
path: HOSTS_PATH,
globalNavEnabled: true,
globalSearchKeywords: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,18 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import {
EuiFlexGrid,
EuiFlexGroup,
EuiFlexItem,
EuiIcon,
EuiText,
EuiTitle,
IconType,
} from '@elastic/eui';
import { EuiFlexGrid, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText, EuiTitle } from '@elastic/eui';
import React from 'react';
import styled from 'styled-components';
import { SecurityPageName } from '../../app/types';

import {
SecuritySolutionLinkAnchor,
withSecuritySolutionLink,
} from '../../common/components/links';
import { NavLinkItem } from '../../common/links/types';

interface LandingLinksImagesProps {
items: NavItem[];
}

export interface NavItem {
id: SecurityPageName;
label: string;
icon: IconType;
description: string;
path?: string;
items: NavLinkItem[];
}

const Link = styled.a`
Expand All @@ -50,7 +35,7 @@ const StyledEuiTitle = styled(EuiTitle)`

export const LandingLinksIcons: React.FC<LandingLinksImagesProps> = ({ items }) => (
<EuiFlexGrid columns={3} gutterSize="xl">
{items.map(({ label, description, path, id, icon }) => (
{items.map(({ title, description, id, icon }) => (
<EuiFlexItem key={id} data-test-subj="LandingItem">
<EuiFlexGroup
direction="column"
Expand All @@ -59,14 +44,14 @@ export const LandingLinksIcons: React.FC<LandingLinksImagesProps> = ({ items })
responsive={false}
>
<EuiFlexItem grow={false}>
<SecuritySolutionLink tabIndex={-1} deepLinkId={id} path={path}>
<EuiIcon aria-hidden="true" size="xl" type={icon} role="presentation" />
<SecuritySolutionLink tabIndex={-1} deepLinkId={id}>
<EuiIcon aria-hidden="true" size="xl" type={icon ?? ''} role="presentation" />
</SecuritySolutionLink>
</EuiFlexItem>
<EuiFlexItem>
<StyledEuiTitle size="xxs">
<SecuritySolutionLinkAnchor deepLinkId={id} path={path}>
<h2>{label}</h2>
<SecuritySolutionLinkAnchor deepLinkId={id}>
<h2>{title}</h2>
</SecuritySolutionLinkAnchor>
</StyledEuiTitle>
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@
import { render } from '@testing-library/react';
import React from 'react';
import { SecurityPageName } from '../../app/types';
import { NavLinkItem } from '../../common/links/types';
import { TestProviders } from '../../common/mock';
import { LandingLinksImages, NavItem } from './landing_links_images';
import { LandingLinksImages } from './landing_links_images';

const DEFAULT_NAV_ITEM: NavItem = {
const DEFAULT_NAV_ITEM: NavLinkItem = {
id: SecurityPageName.overview,
label: 'TEST LABEL',
title: 'TEST LABEL',
description: 'TEST DESCRIPTION',
image: 'TEST_IMAGE.png',
path: '',
};

jest.mock('../../common/lib/kibana/kibana_react', () => {
Expand All @@ -32,27 +34,27 @@ jest.mock('../../common/lib/kibana/kibana_react', () => {

describe('LandingLinksImages', () => {
it('renders', () => {
const label = 'test label';
const title = 'test label';

const { queryByText } = render(
<TestProviders>
<LandingLinksImages items={[{ ...DEFAULT_NAV_ITEM, label }]} />
<LandingLinksImages items={[{ ...DEFAULT_NAV_ITEM, title }]} />
</TestProviders>
);

expect(queryByText(label)).toBeInTheDocument();
expect(queryByText(title)).toBeInTheDocument();
});

it('renders image', () => {
const image = 'test_image.jpeg';
const label = 'TEST_LABEL';
const landingImage = 'test_image.jpeg';
const title = 'TEST_LABEL';

const { getByTestId } = render(
<TestProviders>
<LandingLinksImages items={[{ ...DEFAULT_NAV_ITEM, image, label }]} />
<LandingLinksImages items={[{ ...DEFAULT_NAV_ITEM, landingImage, title }]} />
</TestProviders>
);

expect(getByTestId('LandingLinksImage')).toHaveAttribute('src', image);
expect(getByTestId('LandingLinksImage')).toHaveAttribute('src', landingImage);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,11 @@
import { EuiFlexGroup, EuiFlexItem, EuiImage, EuiPanel, EuiText, EuiTitle } from '@elastic/eui';
import React from 'react';
import styled from 'styled-components';
import { SecurityPageName } from '../../app/types';
import { withSecuritySolutionLink } from '../../common/components/links';
import { LinkInfo } from '../../common/links/types';

interface LandingLinksImagesProps {
items: NavItem[];
}

export interface NavItem {
id: SecurityPageName;
label: string;
image: string;
description: string;
path?: string;
items: LinkInfo[];
}

const PrimaryEuiTitle = styled(EuiTitle)`
Expand Down Expand Up @@ -47,24 +39,26 @@ const Content = styled(EuiFlexItem)`

export const LandingLinksImages: React.FC<LandingLinksImagesProps> = ({ items }) => (
<EuiFlexGroup direction="column">
{items.map(({ label, description, path, image, id }) => (
{items.map(({ title, description, image, id }) => (
<EuiFlexItem key={id} data-test-subj="LandingItem">
<SecuritySolutionLink deepLinkId={id} path={path} tabIndex={-1}>
<SecuritySolutionLink deepLinkId={id} tabIndex={-1}>
{/* Empty onClick is to force hover style on `EuiPanel` */}
<EuiPanel hasBorder hasShadow={false} paddingSize="m" onClick={() => {}}>
<EuiFlexGroup>
<StyledFlexItem grow={false}>
<EuiImage
data-test-subj="LandingLinksImage"
size="l"
role="presentation"
alt=""
src={image}
/>
{image && (
<EuiImage
data-test-subj="LandingLinksImage"
size="l"
role="presentation"
alt=""
src={image}
/>
)}
</StyledFlexItem>
<Content>
<PrimaryEuiTitle size="s">
<h2>{label}</h2>
<h2>{title}</h2>
</PrimaryEuiTitle>
<LandingLinksDescripton size="s" color="text">
{description}
Expand Down
36 changes: 36 additions & 0 deletions x-pack/plugins/security_solution/public/landing_pages/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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 { SecurityPageName } from '../app/types';

export interface LandingNavGroup {
label: string;
itemIds: SecurityPageName[];
}

export const MANAGE_NAVIGATION_CATEGORIES: LandingNavGroup[] = [
{
label: i18n.translate('xpack.securitySolution.landing.siemTitle', {
defaultMessage: 'SIEM',
}),
itemIds: [SecurityPageName.rules, SecurityPageName.exceptions],
},
{
label: i18n.translate('xpack.securitySolution.landing.endpointsTitle', {
defaultMessage: 'ENDPOINTS',
}),
itemIds: [
SecurityPageName.endpoints,
SecurityPageName.policies,
SecurityPageName.trustedApps,
SecurityPageName.eventFilters,
SecurityPageName.blocklist,
SecurityPageName.hostIsolationExceptions,
],
},
];
Loading

0 comments on commit b684e3d

Please sign in to comment.