Skip to content

Commit

Permalink
[SIEM][CASE] Init Configure Case Page (elastic#58121)
Browse files Browse the repository at this point in the history
* [SIEM][CASE] Init configure cases

* [SIEM][CASE] Translate header title

* [SIEM][CASE] Add back link

* [SIEM][CASE] Add default options to header page

* [SIEM][CASE] Create configure cases page redirections and links

* [SIEM][CASE] Add configure cases button

* [SIEM][CASE] Change translation variable

* [SIEM][CASE] Create wrappers

* [SIEM][CASE]Create section wrapper

* [SIEM][CASE] Switch to new wrapper

* [SIEM][CASE] Add translations

* [SIEM][CASE] Add connectors dropdown component

* [SIEM][CASE] Add connectors component

* [SIEM][CASE] Show connectors

* [SIEM][CASE] Create add new connector button

* [SIEM][CASE] Change values

* [SIEM][CASE] Use state for connectors dropdown

* [SIEM][CASE] Remove unnecessary attribute

* [SIEM][CASE] Remove timeline in configuration page

* [SIEM][CASE] Remove text from gear button

* [SIEM][CASE] make show timeline more generic so we can re-use if need it

Co-authored-by: Xavier Mouligneau <[email protected]>
Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
3 people committed Feb 28, 2020
1 parent 7fd27c3 commit 8c065db
Show file tree
Hide file tree
Showing 17 changed files with 345 additions and 42 deletions.
2 changes: 2 additions & 0 deletions x-pack/legacy/plugins/siem/public/components/link_to/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export {
getCaseDetailsUrl,
getCaseUrl,
getCreateCaseUrl,
getConfigureCasesUrl,
RedirectToCasePage,
RedirectToCreatePage,
RedirectToConfigureCasesPage,
} from './redirect_to_case';
11 changes: 10 additions & 1 deletion x-pack/legacy/plugins/siem/public/components/link_to/link_to.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ import { RedirectToHostsPage, RedirectToHostDetailsPage } from './redirect_to_ho
import { RedirectToNetworkPage } from './redirect_to_network';
import { RedirectToOverviewPage } from './redirect_to_overview';
import { RedirectToTimelinesPage } from './redirect_to_timelines';
import { RedirectToCasePage, RedirectToCreatePage } from './redirect_to_case';
import {
RedirectToCasePage,
RedirectToCreatePage,
RedirectToConfigureCasesPage,
} from './redirect_to_case';
import { DetectionEngineTab } from '../../pages/detection_engine/types';

interface LinkToPageProps {
Expand All @@ -43,6 +47,11 @@ export const LinkToPage = React.memo<LinkToPageProps>(({ match }) => (
component={RedirectToCreatePage}
path={`${match.url}/:pageName(${SiemPageName.case})/create`}
/>
<Route
exact
component={RedirectToConfigureCasesPage}
path={`${match.url}/:pageName(${SiemPageName.case})/configure`}
/>
<Route
component={RedirectToCasePage}
path={`${match.url}/:pageName(${SiemPageName.case})/:detailName`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ export const RedirectToCasePage = ({
);

export const RedirectToCreatePage = () => <RedirectWrapper to={`/${SiemPageName.case}/create`} />;
export const RedirectToConfigureCasesPage = () => (
<RedirectWrapper to={`/${SiemPageName.case}/configure`} />
);

const baseCaseUrl = `#/link-to/${SiemPageName.case}`;

export const getCaseUrl = () => baseCaseUrl;
export const getCaseDetailsUrl = (detailName: string) => `${baseCaseUrl}/${detailName}`;
export const getCreateCaseUrl = () => `${baseCaseUrl}/create`;
export const getConfigureCasesUrl = () => `${baseCaseUrl}/configure`;
27 changes: 13 additions & 14 deletions x-pack/legacy/plugins/siem/public/pages/case/case.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,29 @@

import React from 'react';

import { EuiButton, EuiFlexGroup } from '@elastic/eui';
import { HeaderPage } from '../../components/header_page';
import { EuiButton, EuiButtonIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { CaseHeaderPage } from './components/case_header_page';
import { WrapperPage } from '../../components/wrapper_page';
import { AllCases } from './components/all_cases';
import { SpyRoute } from '../../utils/route/spy_routes';
import * as i18n from './translations';
import { getCreateCaseUrl } from '../../components/link_to';

const badgeOptions = {
beta: true,
text: i18n.PAGE_BADGE_LABEL,
tooltip: i18n.PAGE_BADGE_TOOLTIP,
};
import { getCreateCaseUrl, getConfigureCasesUrl } from '../../components/link_to';

export const CasesPage = React.memo(() => (
<>
<WrapperPage>
<HeaderPage badgeOptions={badgeOptions} subtitle={i18n.PAGE_SUBTITLE} title={i18n.PAGE_TITLE}>
<CaseHeaderPage subtitle={i18n.PAGE_SUBTITLE} title={i18n.PAGE_TITLE}>
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false} wrap={true}>
<EuiButton fill href={getCreateCaseUrl()} iconType="plusInCircle">
{i18n.CREATE_TITLE}
</EuiButton>
<EuiFlexItem grow={false}>
<EuiButton fill href={getCreateCaseUrl()} iconType="plusInCircle">
{i18n.CREATE_TITLE}
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonIcon href={getConfigureCasesUrl()} iconType="gear" />
</EuiFlexItem>
</EuiFlexGroup>
</HeaderPage>
</CaseHeaderPage>
<AllCases />
</WrapperPage>
<SpyRoute />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';

import { HeaderPage, HeaderPageProps } from '../../../../components/header_page';
import * as i18n from './translations';

const CaseHeaderPageComponent: React.FC<HeaderPageProps> = props => <HeaderPage {...props} />;

CaseHeaderPageComponent.defaultProps = {
badgeOptions: {
beta: true,
text: i18n.PAGE_BADGE_LABEL,
tooltip: i18n.PAGE_BADGE_TOOLTIP,
},
};

export const CaseHeaderPage = React.memo(CaseHeaderPageComponent);
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { i18n } from '@kbn/i18n';

export const PAGE_BADGE_LABEL = i18n.translate('xpack.siem.case.caseView.pageBadgeLabel', {
defaultMessage: 'Beta',
});

export const PAGE_BADGE_TOOLTIP = i18n.translate('xpack.siem.case.caseView.pageBadgeTooltip', {
defaultMessage:
'Case Workflow is still in beta. Please help us improve by reporting issues or bugs in the Kibana repo.',
});
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { UserActionTree } from '../user_action_tree';
import { UserList } from '../user_list';
import { useUpdateCase } from '../../../../containers/case/use_update_case';
import { WrapperPage } from '../../../../components/wrapper_page';
import { WhitePageWrapper } from '../wrappers';

interface Props {
caseId: string;
Expand All @@ -52,14 +53,6 @@ const MyWrapper = styled(WrapperPage)`
padding-bottom: 0;
`;

const BackgroundWrapper = styled.div`
${({ theme }) => css`
background-color: ${theme.eui.euiColorEmptyShade};
border-top: ${theme.eui.euiBorderThin};
height: 100%;
`}
`;

export interface CaseProps {
caseId: string;
initialData: Case;
Expand Down Expand Up @@ -279,7 +272,7 @@ export const CaseComponent = React.memo<CaseProps>(({ caseId, initialData, isLoa
</EuiFlexGroup>
</HeaderPage>
</MyWrapper>
<BackgroundWrapper>
<WhitePageWrapper>
<MyWrapper>
<EuiFlexGroup>
<EuiFlexItem grow={6}>
Expand All @@ -305,7 +298,7 @@ export const CaseComponent = React.memo<CaseProps>(({ caseId, initialData, isLoa
</EuiFlexItem>
</EuiFlexGroup>
</MyWrapper>
</BackgroundWrapper>
</WhitePageWrapper>
</>
);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import {
EuiDescribedFormGroup,
EuiFormRow,
EuiFlexGroup,
EuiFlexItem,
EuiLink,
} from '@elastic/eui';

import styled from 'styled-components';

import { ConnectorsDropdown } from './connectors_dropdown';
import * as i18n from './translations';

const EuiFormRowExtended = styled(EuiFormRow)`
.euiFormRow__labelWrapper {
.euiFormRow__label {
width: 100%;
}
}
`;

const ConnectorsComponent: React.FC = () => {
const dropDownLabel = (
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>{i18n.INCIDENT_MANAGEMENT_SYSTEM_LABEL}</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiLink>{i18n.ADD_NEW_CONNECTOR}</EuiLink>
</EuiFlexItem>
</EuiFlexGroup>
);

return (
<EuiDescribedFormGroup
fullWidth
title={<h3>{i18n.INCIDENT_MANAGEMENT_SYSTEM_TITLE}</h3>}
description={i18n.INCIDENT_MANAGEMENT_SYSTEM_DESC}
>
<EuiFormRowExtended fullWidth label={dropDownLabel}>
<ConnectorsDropdown />
</EuiFormRowExtended>
</EuiDescribedFormGroup>
);
};

export const Connectors = React.memo(ConnectorsComponent);
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useState, useCallback } from 'react';
import { EuiSuperSelect, EuiIcon, EuiSuperSelectOption } from '@elastic/eui';
import styled from 'styled-components';

import * as i18n from '../translations';

const ICON_SIZE = 'm';

const EuiIconExtended = styled(EuiIcon)`
margin-right: 13px;
`;

const connectors: Array<EuiSuperSelectOption<string>> = [
{
value: 'no-connector',
inputDisplay: (
<>
<EuiIconExtended type="minusInCircle" size={ICON_SIZE} />
<span>{i18n.NO_CONNECTOR}</span>
</>
),
'data-test-subj': 'no-connector',
},
{
value: 'servicenow-connector',
inputDisplay: (
<>
<EuiIconExtended type="logoWebhook" size={ICON_SIZE} />
<span>{'My ServiceNow connector'}</span>
</>
),
'data-test-subj': 'servicenow-connector',
},
];

const ConnectorsDropdownComponent: React.FC = () => {
const [selectedConnector, selectConnector] = useState(connectors[0].value);
const onChange = useCallback(connector => selectConnector(connector), [selectedConnector]);

return (
<EuiSuperSelect
options={connectors}
valueOfSelected={selectedConnector}
fullWidth
onChange={onChange}
/>
);
};

export const ConnectorsDropdown = React.memo(ConnectorsDropdownComponent);
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { i18n } from '@kbn/i18n';

export const INCIDENT_MANAGEMENT_SYSTEM_TITLE = i18n.translate(
'xpack.siem.case.configureCases.incidentManagementSystemTitle',
{
defaultMessage: 'Connect to third-party incident management system',
}
);

export const INCIDENT_MANAGEMENT_SYSTEM_DESC = i18n.translate(
'xpack.siem.case.configureCases.incidentManagementSystemDesc',
{
defaultMessage:
'You may optionally connect SIEM cases to a third-party incident management system of your choosing. This will allow you to push case data as an incident in your chosen third-party system.',
}
);

export const INCIDENT_MANAGEMENT_SYSTEM_LABEL = i18n.translate(
'xpack.siem.case.configureCases.incidentManagementSystemLabel',
{
defaultMessage: 'Incident management system',
}
);

export const NO_CONNECTOR = i18n.translate('xpack.siem.case.configureCases.noConnector', {
defaultMessage: 'No connector selected',
});

export const ADD_NEW_CONNECTOR = i18n.translate('xpack.siem.case.configureCases.addNewConnector', {
defaultMessage: 'Add new connector option',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import styled, { css } from 'styled-components';

export const WhitePageWrapper = styled.div`
${({ theme }) => css`
background-color: ${theme.eui.euiColorEmptyShade};
border-top: ${theme.eui.euiBorderThin};
height: 100%;
min-height: 100vh;
`}
`;

export const SectionWrapper = styled.div`
box-sizing: content-box;
margin: 0 auto;
max-width: 1175px;
`;
54 changes: 54 additions & 0 deletions x-pack/legacy/plugins/siem/public/pages/case/configure_cases.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import styled, { css } from 'styled-components';

import { WrapperPage } from '../../components/wrapper_page';
import { CaseHeaderPage } from './components/case_header_page';
import { SpyRoute } from '../../utils/route/spy_routes';
import { getCaseUrl } from '../../components/link_to';
import { WhitePageWrapper, SectionWrapper } from './components/wrappers';
import { Connectors } from './components/configure_cases/connectors';
import * as i18n from './translations';

const backOptions = {
href: getCaseUrl(),
text: i18n.BACK_TO_ALL,
};

const wrapperPageStyle: Record<string, string> = {
paddingLeft: '0',
paddingRight: '0',
paddingBottom: '0',
};

export const FormWrapper = styled.div`
${({ theme }) => css`
padding-top: ${theme.eui.paddingSizes.l};
padding-bottom: ${theme.eui.paddingSizes.l};
`}
`;

const ConfigureCasesPageComponent: React.FC = () => (
<>
<WrapperPage style={wrapperPageStyle}>
<SectionWrapper>
<CaseHeaderPage title={i18n.CONFIGURE_CASES_PAGE_TITLE} backOptions={backOptions} />
</SectionWrapper>
<WhitePageWrapper>
<FormWrapper>
<SectionWrapper>
<Connectors />
</SectionWrapper>
</FormWrapper>
</WhitePageWrapper>
</WrapperPage>
<SpyRoute />
</>
);

export const ConfigureCasesPage = React.memo(ConfigureCasesPageComponent);
Loading

0 comments on commit 8c065db

Please sign in to comment.