Skip to content

Commit

Permalink
create new ml landing links package
Browse files Browse the repository at this point in the history
  • Loading branch information
mgiota committed Sep 24, 2024
1 parent 23b2595 commit ee4ff52
Show file tree
Hide file tree
Showing 39 changed files with 2,669 additions and 2 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,7 @@
"@kbn/ml-is-defined": "link:x-pack/packages/ml/is_defined",
"@kbn/ml-is-populated-object": "link:x-pack/packages/ml/is_populated_object",
"@kbn/ml-kibana-theme": "link:x-pack/packages/ml/kibana_theme",
"@kbn/ml-landing-links": "link:x-pack/packages/ml/landing_links",
"@kbn/ml-local-storage": "link:x-pack/packages/ml/local_storage",
"@kbn/ml-nested-property": "link:x-pack/packages/ml/nested_property",
"@kbn/ml-number-utils": "link:x-pack/packages/ml/number_utils",
Expand Down
2 changes: 2 additions & 0 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,8 @@
"@kbn/ml-is-populated-object/*": ["x-pack/packages/ml/is_populated_object/*"],
"@kbn/ml-kibana-theme": ["x-pack/packages/ml/kibana_theme"],
"@kbn/ml-kibana-theme/*": ["x-pack/packages/ml/kibana_theme/*"],
"@kbn/ml-landing-links": ["x-pack/packages/ml/landing_links"],
"@kbn/ml-landing-links/*": ["x-pack/packages/ml/landing_links/*"],
"@kbn/ml-local-storage": ["x-pack/packages/ml/local_storage"],
"@kbn/ml-local-storage/*": ["x-pack/packages/ml/local_storage/*"],
"@kbn/ml-nested-property": ["x-pack/packages/ml/nested_property"],
Expand Down
19 changes: 19 additions & 0 deletions x-pack/packages/ml/landing_links/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* 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.
*/
export type { LandingLinksIconsCategoriesGroupsProps } from './src/landing_links_icons_categories_groups';
export type { LandingLinksIconsProps } from './src/landing_links_icons';
export type { LandingLinksIconsCategoriesProps } from './src/landing_links_icons_categories';
export type { LandingLinksIconsGroupsProps } from './src/landing_links_icons_groups';
export type { LandingLinksImagesProps } from './src/landing_links_images';
export {
LandingLinksIconsCategoriesGroups,
LandingLinksIcons,
LandingLinksIconsCategories,
LandingLinksIconsGroups,
LandingLinksImages,
LandingLinksImageCards,
} from './src/lazy';
12 changes: 12 additions & 0 deletions x-pack/packages/ml/landing_links/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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.
*/

module.exports = {
preset: '@kbn/test',
rootDir: '../../../..',
roots: ['<rootDir>/x-pack/packages/ml/landing_links'],
};
5 changes: 5 additions & 0 deletions x-pack/packages/ml/landing_links/kibana.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/ml-landing-links",
"owner": "@elastic/security-threat-hunting-explore"
}
7 changes: 7 additions & 0 deletions x-pack/packages/ml/landing_links/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "@kbn/ml-landing-links",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0",
"sideEffects": false
}
32 changes: 32 additions & 0 deletions x-pack/packages/ml/landing_links/src/beta_badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { css } from '@emotion/react';
import { EuiBetaBadge, useEuiTheme } from '@elastic/eui';

export const BETA = i18n.translate('securitySolutionPackages.beta.label', {
defaultMessage: 'Beta',
});

export const BetaBadge = ({ text, className }: { text?: string; className?: string }) => {
const { euiTheme } = useEuiTheme();

return (
<EuiBetaBadge
label={text ?? BETA}
size="s"
css={css`
margin-left: ${euiTheme.size.s};
color: ${euiTheme.colors.text};
vertical-align: middle;
margin-bottom: ${euiTheme.size.xxs};
`}
className={className}
/>
);
};
84 changes: 84 additions & 0 deletions x-pack/packages/ml/landing_links/src/landing_links.test.tsx
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);
});
});
78 changes: 78 additions & 0 deletions x-pack/packages/ml/landing_links/src/landing_links.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* 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 {
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
}) {
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>
);
}
);
109 changes: 109 additions & 0 deletions x-pack/packages/ml/landing_links/src/landing_links_icons.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* 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 type { CoreStart } from '@kbn/core/public';
import type { NavigationLink } from '../types';
import type { LandingLinksIconsProps } from './landing_links_icons';
import { LandingLinksIcons as LandingLinksIconsComponent } from './landing_links_icons';
import { NavigationProvider } from '../context';

const items: NavigationLink[] = [
{
id: 'link1',
title: 'link #1',
description: 'This is the description of the link #1',
landingIcon: 'addDataApp',
},
{
id: 'link2',
title: 'link #2',
description: 'This is the description of the link #2',
isBeta: true,
landingIcon: 'securityAnalyticsApp',
},
{
id: 'link3',
title: 'link #3',
description: 'This is the description of the link #3',
landingIcon: 'spacesApp',
},
{
id: 'link4',
title: 'link #4',
description: 'This is the description of the link #4',
landingIcon: 'appSearchApp',
},
{
id: 'link5',
title: 'link #5',
description: 'This is the description of the link #5',
landingIcon: 'heartbeatApp',
},
{
id: 'link6',
title: 'link #6',
description: 'This is the description of the link #6',
landingIcon: 'lensApp',
},
{
id: 'link7',
title: 'link #7',
description: 'This is the description of the link #7',
landingIcon: 'timelionApp',
},
{
id: 'link8',
title: 'link #8',
description: 'This is the description of the link #8',
landingIcon: 'managementApp',
},
];

export default {
title: 'Landing Links/Landing Links Icons',
description: 'Renders the links with icons.',
decorators: [
(storyFn: Function) => (
<div
css={{
height: '100%',
width: '100%',
background: '#fff',
}}
>
{storyFn()}
</div>
),
],
};

const mockCore = {
application: {
navigateToApp: () => {},
getUrlForApp: () => '#',
},
} as unknown as CoreStart;

export const LandingLinksIcons = (params: LandingLinksIconsProps) => (
<div style={{ padding: '25px' }}>
<NavigationProvider core={mockCore}>
<LandingLinksIconsComponent {...params} />
</NavigationProvider>
</div>
);

LandingLinksIcons.argTypes = {
items: {
control: 'object',
defaultValue: items,
},
};

LandingLinksIcons.parameters = {
layout: 'fullscreen',
};
Loading

0 comments on commit ee4ff52

Please sign in to comment.