Skip to content

Commit

Permalink
[Security Solutions][Cases] Cases Redesign (#73247)
Browse files Browse the repository at this point in the history
Co-authored-by: Xavier Mouligneau <189600+XavierM@users.noreply.github.com>
Co-authored-by: Yara Tercero <yctercero@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
4 people committed Sep 17, 2020
1 parent e97a7ff commit 631aaad
Show file tree
Hide file tree
Showing 54 changed files with 1,888 additions and 1,123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,16 @@ import {
ALL_CASES_TAGS_COUNT,
} from '../screens/all_cases';
import {
ACTION,
CASE_DETAILS_DESCRIPTION,
CASE_DETAILS_PAGE_TITLE,
CASE_DETAILS_PUSH_TO_EXTERNAL_SERVICE_BTN,
CASE_DETAILS_STATUS,
CASE_DETAILS_TAGS,
CASE_DETAILS_USER_ACTION,
CASE_DETAILS_USER_ACTION_DESCRIPTION_USERNAME,
CASE_DETAILS_USER_ACTION_DESCRIPTION_EVENT,
CASE_DETAILS_USERNAMES,
PARTICIPANTS,
REPORTER,
USER,
} from '../screens/case_details';
import { TIMELINE_DESCRIPTION, TIMELINE_QUERY, TIMELINE_TITLE } from '../screens/timeline';

Expand Down Expand Up @@ -84,8 +83,8 @@ describe('Cases', () => {
const expectedTags = case1.tags.join('');
cy.get(CASE_DETAILS_PAGE_TITLE).should('have.text', case1.name);
cy.get(CASE_DETAILS_STATUS).should('have.text', 'open');
cy.get(CASE_DETAILS_USER_ACTION).eq(USER).should('have.text', case1.reporter);
cy.get(CASE_DETAILS_USER_ACTION).eq(ACTION).should('have.text', 'added description');
cy.get(CASE_DETAILS_USER_ACTION_DESCRIPTION_USERNAME).should('have.text', case1.reporter);
cy.get(CASE_DETAILS_USER_ACTION_DESCRIPTION_EVENT).should('have.text', 'added description');
cy.get(CASE_DETAILS_DESCRIPTION).should(
'have.text',
`${case1.description} ${case1.timeline.title}`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
addNewCase,
selectCase,
} from '../tasks/timeline';
import { DESCRIPTION_INPUT } from '../screens/create_new_case';
import { DESCRIPTION_INPUT, ADD_COMMENT_INPUT } from '../screens/create_new_case';
import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver';
import { caseTimeline, TIMELINE_CASE_ID } from '../objects/case';

Expand All @@ -34,7 +34,7 @@ describe('attach timeline to case', () => {
cy.location('origin').then((origin) => {
cy.get(DESCRIPTION_INPUT).should(
'have.text',
`[${caseTimeline.title}](${origin}/app/security/timelines?timeline=(id:'${caseTimeline.id}',isOpen:!t))`
`[${caseTimeline.title}](${origin}/app/security/timelines?timeline=(id:%27${caseTimeline.id}%27,isOpen:!t))`
);
});
});
Expand All @@ -46,7 +46,7 @@ describe('attach timeline to case', () => {
cy.location('origin').then((origin) => {
cy.get(DESCRIPTION_INPUT).should(
'have.text',
`[${caseTimeline.title}](${origin}/app/security/timelines?timeline=(id:'${caseTimeline.id}',isOpen:!t))`
`[${caseTimeline.title}](${origin}/app/security/timelines?timeline=(id:%27${caseTimeline.id}%27,isOpen:!t))`
);
});
});
Expand All @@ -66,9 +66,9 @@ describe('attach timeline to case', () => {
selectCase(TIMELINE_CASE_ID);

cy.location('origin').then((origin) => {
cy.get(DESCRIPTION_INPUT).should(
cy.get(ADD_COMMENT_INPUT).should(
'have.text',
`[${caseTimeline.title}](${origin}/app/security/timelines?timeline=(id:'${caseTimeline.id}',isOpen:!t))`
`[${caseTimeline.title}](${origin}/app/security/timelines?timeline=(id:%27${caseTimeline.id}%27,isOpen:!t))`
);
});
});
Expand Down
16 changes: 9 additions & 7 deletions x-pack/plugins/security_solution/cypress/screens/case_details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/

export const ACTION = 2;

export const CASE_DETAILS_DESCRIPTION = '[data-test-subj="markdown-root"]';
export const CASE_DETAILS_DESCRIPTION =
'[data-test-subj="description-action"] [data-test-subj="user-action-markdown"]';

export const CASE_DETAILS_PAGE_TITLE = '[data-test-subj="header-page-title"]';

Expand All @@ -17,14 +16,17 @@ export const CASE_DETAILS_STATUS = '[data-test-subj="case-view-status"]';

export const CASE_DETAILS_TAGS = '[data-test-subj="case-tags"]';

export const CASE_DETAILS_TIMELINE_LINK_MARKDOWN = '[data-test-subj="markdown-timeline-link"]';
export const CASE_DETAILS_TIMELINE_LINK_MARKDOWN =
'[data-test-subj="description-action"] [data-test-subj="user-action-markdown"] button';

export const CASE_DETAILS_USER_ACTION_DESCRIPTION_EVENT =
'[data-test-subj="description-action"] .euiCommentEvent__headerEvent';

export const CASE_DETAILS_USER_ACTION = '[data-test-subj="user-action-title"] .euiFlexItem';
export const CASE_DETAILS_USER_ACTION_DESCRIPTION_USERNAME =
'[data-test-subj="description-action"] .euiCommentEvent__headerUsername';

export const CASE_DETAILS_USERNAMES = '[data-test-subj="case-view-username"]';

export const PARTICIPANTS = 1;

export const REPORTER = 0;

export const USER = 1;
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/

export const ADD_COMMENT_INPUT = '[data-test-subj="add-comment"] textarea';

export const BACK_TO_CASES_BTN = '[data-test-subj="backToCases"]';

export const DESCRIPTION_INPUT = '[data-test-subj="textAreaInput"]';
export const DESCRIPTION_INPUT = '[data-test-subj="caseDescription"] textarea';

export const INSERT_TIMELINE_BTN = '[data-test-subj="insert-timeline-button"]';
export const INSERT_TIMELINE_BTN = '.euiMarkdownEditorToolbar [aria-label="Insert timeline link"]';

export const LOADING_SPINNER = '[data-test-subj="create-case-loading-spinner"]';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
INSERT_TIMELINE_BTN,
LOADING_SPINNER,
TAGS_INPUT,
TIMELINE,
TIMELINE_SEARCHBOX,
TITLE_INPUT,
} from '../screens/create_new_case';
Expand Down Expand Up @@ -43,9 +42,6 @@ export const createNewCaseWithTimeline = (newCase: TestCase) => {

cy.get(INSERT_TIMELINE_BTN).click({ force: true });
cy.get(TIMELINE_SEARCHBOX).type(`${newCase.timeline.title}{enter}`);
cy.get(TIMELINE).should('be.visible');
cy.wait(300);
cy.get(TIMELINE).eq(0).click({ force: true });

cy.get(SUBMIT_BTN).click({ force: true });
cy.get(LOADING_SPINNER).should('exist');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import styled from 'styled-components';
import { CommentRequest } from '../../../../../case/common/api';
import { usePostComment } from '../../containers/use_post_comment';
import { Case } from '../../containers/types';
import { MarkdownEditorForm } from '../../../common/components/markdown_editor/form';
import { MarkdownEditorForm } from '../../../common/components/markdown_editor/eui_form';
import { InsertTimelinePopover } from '../../../timelines/components/timeline/insert_timeline_popover';
import { useInsertTimeline } from '../../../timelines/components/timeline/insert_timeline_popover/use_insert_timeline';
import { Form, useForm, UseField, useFormData } from '../../../shared_imports';

import * as i18n from './translations';
import { schema } from './schema';
import { useTimelineClick } from '../utils/use_timeline_click';
import { useTimelineClick } from '../../../common/utils/timeline/use_timeline_click';

const MySpinner = styled(EuiLoadingSpinner)`
position: absolute;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,34 +114,41 @@ describe('CaseView ', () => {
expect(wrapper.find(`[data-test-subj="case-view-title"]`).first().prop('title')).toEqual(
data.title
);

expect(wrapper.find(`[data-test-subj="case-view-status"]`).first().text()).toEqual(
data.status
);

expect(
wrapper
.find(`[data-test-subj="case-view-tag-list"] [data-test-subj="case-tag-coke"]`)
.find(`[data-test-subj="case-view-tag-list"] [data-test-subj="tag-coke"]`)
.first()
.text()
).toEqual(data.tags[0]);

expect(
wrapper
.find(`[data-test-subj="case-view-tag-list"] [data-test-subj="case-tag-pepsi"]`)
.find(`[data-test-subj="case-view-tag-list"] [data-test-subj="tag-pepsi"]`)
.first()
.text()
).toEqual(data.tags[1]);

expect(wrapper.find(`[data-test-subj="case-view-username"]`).first().text()).toEqual(
data.createdBy.username
);

expect(wrapper.contains(`[data-test-subj="case-view-closedAt"]`)).toBe(false);

expect(wrapper.find(`[data-test-subj="case-view-createdAt"]`).first().prop('value')).toEqual(
data.createdAt
);

expect(
wrapper
.find(`[data-test-subj="description-action"] [data-test-subj="user-action-markdown"]`)
.first()
.prop('raw')
).toEqual(data.description);
.text()
).toBe(data.description);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ import { schema } from './schema';
import { InsertTimelinePopover } from '../../../timelines/components/timeline/insert_timeline_popover';
import { useInsertTimeline } from '../../../timelines/components/timeline/insert_timeline_popover/use_insert_timeline';
import * as i18n from '../../translations';
import { MarkdownEditorForm } from '../../../common/components//markdown_editor/form';
import { MarkdownEditorForm } from '../../../common/components/markdown_editor/eui_form';
import { useGetTags } from '../../containers/use_get_tags';
import { getCaseDetailsUrl } from '../../../common/components/link_to';
import { useTimelineClick } from '../utils/use_timeline_click';
import { useTimelineClick } from '../../../common/utils/timeline/use_timeline_click';

export const CommonUseField = getUseField({ component: Field });

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ describe('TagList ', () => {
fetchTags,
}));
});

it('Renders no tags, and then edit', () => {
const wrapper = mount(
<TestProviders>
Expand All @@ -69,6 +70,7 @@ describe('TagList ', () => {
expect(wrapper.find(`[data-test-subj="no-tags"]`).last().exists()).toBeFalsy();
expect(wrapper.find(`[data-test-subj="edit-tags"]`).last().exists()).toBeTruthy();
});

it('Edit tag on submit', async () => {
const wrapper = mount(
<TestProviders>
Expand All @@ -81,6 +83,7 @@ describe('TagList ', () => {
await waitFor(() => expect(onSubmit).toBeCalledWith(sampleTags));
});
});

it('Tag options render with new tags added', () => {
const wrapper = mount(
<TestProviders>
Expand All @@ -92,6 +95,7 @@ describe('TagList ', () => {
wrapper.find(`[data-test-subj="caseTags"] [data-test-subj="input"]`).first().prop('options')
).toEqual([{ label: 'coke' }, { label: 'pepsi' }, { label: 'rad' }, { label: 'dude' }]);
});

it('Cancels on cancel', async () => {
const props = {
...defaultProps,
Expand All @@ -102,17 +106,19 @@ describe('TagList ', () => {
<TagList {...props} />
</TestProviders>
);
expect(wrapper.find(`[data-test-subj="case-tag-pepsi"]`).last().exists()).toBeTruthy();

expect(wrapper.find(`[data-test-subj="tag-pepsi"]`).last().exists()).toBeTruthy();
wrapper.find(`[data-test-subj="tag-list-edit-button"]`).last().simulate('click');
await act(async () => {
expect(wrapper.find(`[data-test-subj="case-tag-pepsi"]`).last().exists()).toBeFalsy();
expect(wrapper.find(`[data-test-subj="tag-pepsi"]`).last().exists()).toBeFalsy();
wrapper.find(`[data-test-subj="edit-tags-cancel"]`).last().simulate('click');
await waitFor(() => {
wrapper.update();
expect(wrapper.find(`[data-test-subj="case-tag-pepsi"]`).last().exists()).toBeTruthy();
expect(wrapper.find(`[data-test-subj="tag-pepsi"]`).last().exists()).toBeTruthy();
});
});
});

it('Renders disabled button', () => {
const props = { ...defaultProps, disabled: true };
const wrapper = mount(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import {
EuiHorizontalRule,
EuiFlexGroup,
EuiFlexItem,
EuiBadgeGroup,
EuiBadge,
EuiButton,
EuiButtonEmpty,
EuiButtonIcon,
Expand All @@ -25,6 +23,8 @@ import { schema } from './schema';
import { CommonUseField } from '../create';
import { useGetTags } from '../../containers/use_get_tags';

import { Tags } from './tags';

interface TagListProps {
disabled?: boolean;
isLoading: boolean;
Expand Down Expand Up @@ -99,15 +99,7 @@ export const TagList = React.memo(
<EuiHorizontalRule margin="xs" />
<MyFlexGroup gutterSize="xs" data-test-subj="case-tags">
{tags.length === 0 && !isEditTags && <p data-test-subj="no-tags">{i18n.NO_TAGS}</p>}
<EuiBadgeGroup>
{tags.length > 0 &&
!isEditTags &&
tags.map((tag) => (
<EuiBadge data-test-subj={`case-tag-${tag}`} color="hollow" key={tag}>
{tag}
</EuiBadge>
))}
</EuiBadgeGroup>
{!isEditTags && <Tags tags={tags} color="hollow" />}
{isEditTags && (
<EuiFlexGroup data-test-subj="edit-tags" direction="column">
<EuiFlexItem>
Expand Down
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;
* you may not use this file except in compliance with the Elastic License.
*/

import React, { memo } from 'react';
import { EuiBadgeGroup, EuiBadge, EuiBadgeGroupProps } from '@elastic/eui';

interface TagsProps {
tags: string[];
color?: string;
gutterSize?: EuiBadgeGroupProps['gutterSize'];
}

const TagsComponent: React.FC<TagsProps> = ({ tags, color = 'default', gutterSize }) => {
return (
<>
{tags.length > 0 && (
<EuiBadgeGroup gutterSize={gutterSize}>
{tags.map((tag) => (
<EuiBadge data-test-subj={`tag-${tag}`} color={color} key={tag}>
{tag}
</EuiBadge>
))}
</EuiBadgeGroup>
)}
</>
);
};

export const Tags = memo(TagsComponent);
Loading

0 comments on commit 631aaad

Please sign in to comment.