Skip to content

Commit

Permalink
[Security Solution][Unified IA] New sections with landing page (#163102)
Browse files Browse the repository at this point in the history
## Summary

closes: #157847

The new links and pages in Security Solution for Serverless:

- `Investigations`
   - `Timelines`
   - `Osquery`

- `Assets`
   - `Fleet` (and all its sub-links)
   - `Endpoints` (and all its sub-links)
   - `Cloud defend` (and all its sub-links)
   - Callout with button linking `Integrations` in Project Setting

-  `Project settings`
   - `Users & roles` (Cloud UI)   
   - `Billing & consumption` (Cloud UI)
- `Integrations` (link to integrations with _/browse/security_ path
parameter)
- `Entity risk score` (link currently under the
`riskScoringRoutesEnabled` experimental flag)
- `Management` accordion with a set of (stack) management categories and
pages links

Sections updated:

(ESS & Serverless) `Rules` links have been updated according to new
specs.
(ESS) The `Settings` page was renamed back to `Manage`.
(Serverless) The `Dev tools` link was moved to the bottom of the side
navigation.

#### Cypress tests for serverless:

They will be implemented in a follow-up PR when the infrastructure is
ready #162698

## Screenshots

### Serverless

Investigations:


![investigations](https://github.com/elastic/kibana/assets/17747913/19b602ab-53bb-4280-b0c3-dc69255ea3ab)

![investigations_panel](https://github.com/elastic/kibana/assets/17747913/8be036fc-6095-4234-8b07-1a7149c8a92b)

Assets:


![assets](https://github.com/elastic/kibana/assets/17747913/963723d5-16da-45dd-955c-a7d7b61099e6)

![assets_panel](https://github.com/elastic/kibana/assets/17747913/977c0716-7cc3-4369-acdf-0787e264a912)

Rules:


![rules](https://github.com/elastic/kibana/assets/17747913/5bafbd08-508c-4b50-bd28-dc052371e76a)

![rules_panel](https://github.com/elastic/kibana/assets/17747913/ea47f8d9-4b68-44f3-8a42-6f795d05b982)

Project Settings:


![project_settings](https://github.com/elastic/kibana/assets/17747913/36dbb446-3354-4519-b59c-e8b5005fbb71)

![project_settings_panel](https://github.com/elastic/kibana/assets/17747913/1315b54b-4423-41a2-b0ed-997ee77c1f6d)

## ESS

Side Navigation:

![ess_side_nav](https://github.com/elastic/kibana/assets/17747913/a3687a47-3ccb-4ce8-aa53-9e962a6ef1cf)

---------

Co-authored-by: kibanamachine <[email protected]>
Co-authored-by: Tomasz Ciecierski <[email protected]>
Co-authored-by: Tomasz Ciecierski <[email protected]>
  • Loading branch information
4 people authored Aug 15, 2023
1 parent 3640633 commit 560c871
Show file tree
Hide file tree
Showing 92 changed files with 3,287 additions and 635 deletions.
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pageLoadAssetSize:
files: 22673
filesManagement: 18683
fileUpload: 25664
fleet: 142263
fleet: 158438
globalSearch: 29696
globalSearchBar: 50403
globalSearchProviders: 25554
Expand Down
10 changes: 1 addition & 9 deletions x-pack/packages/security-solution/navigation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,4 @@ export { useGetAppUrl, useNavigateTo, useNavigation } from './src/navigation';
export type { GetAppUrl, NavigateTo } from './src/navigation';
export { NavigationProvider } from './src/context';
export { SecurityPageName, LinkCategoryType } from './src/constants';
export type {
NavigationLink,
LinkCategories,
LinkCategory,
TitleLinkCategory,
SeparatorLinkCategory,
AccordionLinkCategory,
} from './src/types';
export { isAccordionLinkCategory, isSeparatorLinkCategory, isTitleLinkCategory } from './src/types';
export * from './src/types';
2 changes: 1 addition & 1 deletion x-pack/packages/security-solution/navigation/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ export {
withLink,
LinkButton,
LinkAnchor,
isExternalId,
isSecurityId,
} from './src/links';
export type { GetLinkUrl, GetLinkProps, LinkProps } from './src/links';
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const SECURITY_UI_APP_ID = 'securitySolutionUI' as const;
export enum SecurityPageName {
administration = 'administration',
alerts = 'alerts',
assets = 'assets',
blocklist = 'blocklist',
/*
* Warning: Computed values are not permitted in an enum with string valued members
Expand All @@ -30,6 +31,7 @@ export enum SecurityPageName {
* Warning: Computed values are not permitted in an enum with string valued members
* All cloud defend page names must match `CloudDefendPageId` in x-pack/plugins/cloud_defend/public/common/navigation/types.ts
*/
cloudDefend = 'cloud_defend',
cloudDefendPolicies = 'cloud_defend-policies',
dashboards = 'dashboards',
dataQuality = 'data_quality',
Expand All @@ -44,7 +46,7 @@ export enum SecurityPageName {
hostsAnomalies = 'hosts-anomalies',
hostsRisk = 'hosts-risk',
hostsEvents = 'hosts-events',
investigate = 'investigate',
investigations = 'investigations',
kubernetes = 'kubernetes',
landing = 'get_started',
mlLanding = 'machine_learning-landing', // serverless only
Expand All @@ -57,6 +59,7 @@ export enum SecurityPageName {
noPage = '',
overview = 'overview',
policies = 'policy',
projectSettings = 'project_settings',
responseActionsHistory = 'response_actions_history',
rules = 'rules',
rulesAdd = 'rules-add',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export type { LandingLinksIconsCategoriesGroupsProps } from './landing_links_icons_categories_groups';
export type { LandingLinksIconsProps } from './landing_links_icons';
export type { LandingLinksIconsCategoriesProps } from './landing_links_icons_categories';
export type { LandingLinksIconsGroupsProps } from './landing_links_icons_groups';
export type { LandingLinksImagesProps } from './landing_links_images';
export {
LandingLinksIconsCategoriesGroups,
LandingLinksIcons,
LandingLinksIconsCategories,
LandingLinksIconsGroups,
LandingLinksImages,
LandingLinksImageCards,
} from './lazy';
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* 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 React from 'react';
import { render } from '@testing-library/react';
import { SecurityPageName } from '../constants';
import { mockNavigateTo, mockGetAppUrl } from '../../mocks/navigation';
import { LandingColumnLinks } from './landing_links';
import type { NavigationLink } from '../types';

jest.mock('../navigation');

mockGetAppUrl.mockImplementation(({ deepLinkId }: { deepLinkId: string }) => `/${deepLinkId}`);
const mockOnLinkClick = jest.fn();

const NAV_ITEM: NavigationLink = {
id: SecurityPageName.dashboards,
title: 'TEST LABEL',
description: 'TEST DESCRIPTION',
landingIcon: 'myTestIcon',
};
const NAV_ITEM_2: NavigationLink = {
id: SecurityPageName.alerts,
title: 'TEST LABEL 2',
description: 'TEST DESCRIPTION 2',
landingIcon: 'myTestIcon',
};

describe('LandingColumnLinks', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('should render items', () => {
const { queryByText } = render(<LandingColumnLinks items={[NAV_ITEM, NAV_ITEM_2]} />);

expect(queryByText(NAV_ITEM.title)).toBeInTheDocument();
expect(queryByText(NAV_ITEM_2.title)).toBeInTheDocument();
});

it('should navigate link', () => {
const { getByText } = render(<LandingColumnLinks items={[NAV_ITEM]} />);

getByText(NAV_ITEM.title).click();

expect(mockGetAppUrl).toHaveBeenCalledWith({
deepLinkId: NAV_ITEM.id,
absolute: false,
path: '',
});
expect(mockNavigateTo).toHaveBeenCalled();
});

it('should add urlState to link', () => {
const testUrlState = '?some=parameter&and=another';
const { getByText } = render(<LandingColumnLinks items={[NAV_ITEM]} urlState={testUrlState} />);

getByText(NAV_ITEM.title).click();

expect(mockGetAppUrl).toHaveBeenCalledWith({
deepLinkId: NAV_ITEM.id,
absolute: false,
path: testUrlState,
});
expect(mockNavigateTo).toHaveBeenCalled();
});

it('should call onLinkClick', () => {
const id = SecurityPageName.administration;
const title = 'myTestLabel';

const { getByText } = render(
<LandingColumnLinks items={[{ ...NAV_ITEM, id, title }]} onLinkClick={mockOnLinkClick} />
);

getByText(title).click();

expect(mockOnLinkClick).toHaveBeenCalledWith(id);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* 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 React from 'react';
import {
EuiLink,
EuiFlexGroup,
EuiFlexItem,
useEuiTheme,
type EuiLinkButtonProps,
type EuiLinkAnchorProps,
} from '@elastic/eui';
import { css } from '@emotion/react';
import { LinkAnchor } from '../links';
import type { NavigationLink } from '../types';
import { getKibanaLinkProps } from './utils';

type LandingLinkProps = EuiLinkAnchorProps &
EuiLinkButtonProps & {
item: NavigationLink;
urlState?: string;
onLinkClick?: (id: string) => void;
};

// Renders a link to either an external URL or an internal Kibana URL
export const LandingLink: React.FC<LandingLinkProps> = React.memo(function LandingLink({
item,
urlState,
onLinkClick,
children,
...rest
}) {
if (item.externalUrl != null) {
// Link to outside Kibana
const linkProps: EuiLinkAnchorProps = {
target: '_blank',
external: true,
href: item.externalUrl,
...(onLinkClick && !item.disabled && { onClick: () => onLinkClick(item.id) }),
...rest,
};
return <EuiLink {...linkProps}>{children}</EuiLink>;
} else {
// Kibana link
const linkProps = {
...getKibanaLinkProps({ item, urlState, onLinkClick }),
...rest,
};
return <LinkAnchor {...linkProps}>{children}</LinkAnchor>;
}
});

interface LandingLinksProps {
items: NavigationLink[];
urlState?: string;
onLinkClick?: (id: string) => void;
}

const useSubLinkStyles = () => {
const { euiTheme } = useEuiTheme();
return {
container: css`
margin-top: ${euiTheme.size.base};
`,
};
};

// Renders a list of links in a column layout
export const LandingColumnLinks: React.FC<LandingLinksProps> = React.memo(
function LandingColumnLinks({ items, urlState, onLinkClick }) {
const subLinkStyles = useSubLinkStyles();
return (
<EuiFlexGroup gutterSize="none" direction="column" alignItems="flexStart">
{items.map((subItem) => (
<EuiFlexItem
key={subItem.id}
grow={false}
css={subLinkStyles.container}
data-test-subj="LandingSubItem"
>
<LandingLink item={subItem} urlState={urlState} onLinkClick={onLinkClick}>
{subItem.title}
</LandingLink>
</EuiFlexItem>
))}
</EuiFlexGroup>
);
}
);
Loading

0 comments on commit 560c871

Please sign in to comment.