Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SIEM] [Case] Comments to case view #58315

Merged
merged 66 commits into from
Mar 2, 2020
Merged
Show file tree
Hide file tree
Changes from 59 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
0984382
init commit, enable case by default and snake to camel on the FE
stephmilovic Feb 18, 2020
36a8cbc
fix sorting
stephmilovic Feb 18, 2020
a2576ea
add a couple tests
stephmilovic Feb 18, 2020
3414641
mock timezone
stephmilovic Feb 19, 2020
7d2818a
full_name to fullName and tests for case view
stephmilovic Feb 19, 2020
9de2163
update case
stephmilovic Feb 19, 2020
9bf863a
trying to fix time test
stephmilovic Feb 19, 2020
87933b5
attempt to fix test once more
stephmilovic Feb 19, 2020
4247111
comment out bad test
stephmilovic Feb 20, 2020
6764017
comment out bad test
stephmilovic Feb 20, 2020
4d5b84d
remove snapshot tests
stephmilovic Feb 20, 2020
b938feb
fix
stephmilovic Feb 20, 2020
fb158d1
rm thing
stephmilovic Feb 20, 2020
a51c776
simplify
stephmilovic Feb 20, 2020
1147b7d
Merge branch 'master' into case-cleanups
elasticmachine Feb 20, 2020
932a210
comments to case view
stephmilovic Feb 20, 2020
c589dce
fix up
stephmilovic Feb 21, 2020
473322d
Merge branch 'master' into case-cleanups
stephmilovic Feb 21, 2020
3da9bda
Merge branch 'master' into comments-to-case-view
stephmilovic Feb 21, 2020
5f6fed5
add comment work
stephmilovic Feb 21, 2020
e28d322
remove window.alert
stephmilovic Feb 21, 2020
0d68fde
suggested changes
stephmilovic Feb 21, 2020
388d77d
more fixes
stephmilovic Feb 21, 2020
fb92e30
better types
stephmilovic Feb 21, 2020
9df35a6
something fishy
stephmilovic Feb 21, 2020
b76038e
couple quick cleanups, lodash arg order incorrect on set
stephmilovic Feb 21, 2020
c2f680a
get changes from case-cleanups
stephmilovic Feb 21, 2020
bba7d6d
merge master, convertArrayToCamelCase
stephmilovic Feb 21, 2020
d672967
fix merge conflict
stephmilovic Feb 22, 2020
80961e0
md editor looking better and posting
stephmilovic Feb 22, 2020
f6cc595
verbiage change
stephmilovic Feb 23, 2020
d56b80f
more work in user action tree
stephmilovic Feb 23, 2020
f1b005d
placeholder for Add comment field
stephmilovic Feb 24, 2020
7df41ea
Merge branch 'master' into comments-to-case-view
stephmilovic Feb 24, 2020
39259b7
clean up user action tree
stephmilovic Feb 24, 2020
855ada6
good progress on comments, need to indicate loading for updating of f…
stephmilovic Feb 24, 2020
b1ae625
loading for each field, create page updates
stephmilovic Feb 25, 2020
85f2f93
loading for each field, create page updates
stephmilovic Feb 25, 2020
1bc1665
update styling of buttons on tags
stephmilovic Feb 25, 2020
cdf3c44
fix up title buttons
stephmilovic Feb 25, 2020
0eab8ca
cleanup mock data
stephmilovic Feb 25, 2020
927d485
Merge branch 'master' into comments-to-case-view
stephmilovic Feb 26, 2020
ea40f9e
test fixups
stephmilovic Feb 26, 2020
fbc4172
more test fix
stephmilovic Feb 26, 2020
119c9db
fix bug that prevented tags from being cleared
stephmilovic Feb 26, 2020
d6161c8
move markdown_editor to top level components
stephmilovic Feb 26, 2020
5981d2c
update translations
stephmilovic Feb 26, 2020
3afeb64
Merge branch 'master' into comments-to-case-view
stephmilovic Feb 27, 2020
ff43776
pr changes
stephmilovic Feb 27, 2020
74553a4
fix loading timing and clean ups
stephmilovic Feb 27, 2020
d49cf1c
link to const
stephmilovic Feb 27, 2020
bb82ba5
fix type err
stephmilovic Feb 27, 2020
313f490
fix md
stephmilovic Feb 27, 2020
312d34b
more pr changes
stephmilovic Feb 27, 2020
6713216
fix validation for markdown by using UseField
XavierM Feb 27, 2020
71e13d4
Merge branch 'comments-to-case-view' of github.com:stephmilovic/kiban…
XavierM Feb 27, 2020
cf73141
cleanup loading state issues
stephmilovic Feb 27, 2020
f68808e
resolve merge conflicts
stephmilovic Feb 28, 2020
e287002
refactor UserAction
XavierM Feb 28, 2020
4c7edfa
Merge branch 'master' of github.com:elastic/kibana into comments-to-c…
XavierM Feb 28, 2020
b0635b3
fix type + test
XavierM Feb 28, 2020
7de953a
Merge branch 'master' into comments-to-case-view
stephmilovic Feb 28, 2020
82c023f
rn file that shouldve been deleted
stephmilovic Feb 28, 2020
9703c98
fix merge conflicts
stephmilovic Mar 2, 2020
f0d4bec
Merge branch 'master' into comments-to-case-view
elasticmachine Mar 2, 2020
326191f
Merge branch 'master' into comments-to-case-view
elasticmachine Mar 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const FIELD = i18n.translate('xpack.siem.editDataProvider.fieldLabel', {
defaultMessage: 'Field',
});

export const FIELD_PLACEHOLDER = i18n.translate('xpack.siem.editDataProvider.fieldPlaceholder', {
export const FIELD_PLACEHOLDER = i18n.translate('xpack.siem.editDataProvider.placeholder', {
defaultMessage: 'Select a field',
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,32 @@ export const FormattedRelativePreferenceDate = ({ value }: { value?: string | nu
</LocalizedDateTooltip>
);
};

/**
* Renders a preceding label according to under/over one hour
*/

export const FormattedRelativePreferenceLabel = ({
value,
preferenceLabel,
relativeLabel,
}: {
value?: string | number | null;
preferenceLabel?: string | null;
relativeLabel?: string | null;
}) => {
if (value == null) {
return null;
}
const maybeDate = getMaybeDate(value);
if (!maybeDate.isValid()) {
return null;
}
return moment(maybeDate.toDate())
.add(1, 'hours')
.isBefore(new Date()) ? (
<>{preferenceLabel}</>
) : (
<>{relativeLabel}</>
);
};

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

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

import {
Expand All @@ -14,19 +14,24 @@ import {
EuiFlexItem,
EuiFieldText,
EuiButtonIcon,
EuiLoadingSpinner,
} from '@elastic/eui';

import * as i18n from './translations';

import { Title } from './title';

const StyledEuiButtonIcon = styled(EuiButtonIcon)`
const MyEuiButtonIcon = styled(EuiButtonIcon)`
${({ theme }) => css`
margin-left: ${theme.eui.euiSize};
`}
`;

StyledEuiButtonIcon.displayName = 'StyledEuiButtonIcon';
const MySpinner = styled(EuiLoadingSpinner)`
${({ theme }) => css`
margin-left: ${theme.eui.euiSize};
`}
`;

interface Props {
isLoading: boolean;
Expand All @@ -36,42 +41,54 @@ interface Props {

const EditableTitleComponent: React.FC<Props> = ({ onSubmit, isLoading, title }) => {
const [editMode, setEditMode] = useState(false);
const [changedTitle, onTitleChange] = useState(title);
const [changedTitle, onTitleChange] = useState<string>(typeof title === 'string' ? title : '');

const onCancel = useCallback(() => setEditMode(false), []);
const onClickEditIcon = useCallback(() => setEditMode(true), []);

const onClickSubmit = useCallback(
(newTitle: string): void => {
onSubmit(newTitle);
stephmilovic marked this conversation as resolved.
Show resolved Hide resolved
setEditMode(false);
const onClickSubmit = useCallback((): void => {
if (changedTitle !== title) {
onSubmit(changedTitle);
}
setEditMode(false);
}, [changedTitle, title]);

const handleOnChange = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
onTitleChange(e.target.value);
},
[changedTitle]
[onTitleChange]
);

return editMode ? (
<EuiFlexGroup alignItems="center" gutterSize="m" justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiFieldText
onChange={e => onTitleChange(e.target.value)}
onChange={handleOnChange}
value={`${changedTitle}`}
data-test-subj="editable-title-input-field"
/>
</EuiFlexItem>
<EuiFlexGroup gutterSize="none" responsive={false} wrap={true}>
<EuiFlexItem grow={false}>
<EuiButton
fill
isDisabled={isLoading}
isLoading={isLoading}
onClick={() => onClickSubmit(changedTitle as string)}
color="secondary"
data-test-subj="editable-title-submit-btn"
fill
iconType="save"
onClick={onClickSubmit}
size="s"
>
{i18n.SUBMIT}
{i18n.SAVE}
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty onClick={onCancel} data-test-subj="editable-title-cancel-btn">
<EuiButtonEmpty
data-test-subj="editable-title-cancel-btn"
iconType="cross"
onClick={onCancel}
size="s"
>
{i18n.CANCEL}
</EuiButtonEmpty>
</EuiFlexItem>
Expand All @@ -84,12 +101,15 @@ const EditableTitleComponent: React.FC<Props> = ({ onSubmit, isLoading, title })
<Title title={title} />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<StyledEuiButtonIcon
aria-label={i18n.EDIT_TITLE_ARIA(title as string)}
iconType="pencil"
onClick={onClickEditIcon}
data-test-subj="editable-title-edit-icon"
/>
{isLoading && <MySpinner />}
{!isLoading && (
<MyEuiButtonIcon
aria-label={i18n.EDIT_TITLE_ARIA(title as string)}
iconType="pencil"
onClick={onClickEditIcon}
data-test-subj="editable-title-edit-icon"
/>
)}
</EuiFlexItem>
</EuiFlexGroup>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

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

export const SUBMIT = i18n.translate('xpack.siem.header.editableTitle.submit', {
defaultMessage: 'Submit',
export const SAVE = i18n.translate('xpack.siem.header.editableTitle.save', {
defaultMessage: 'Save',
});

export const CANCEL = i18n.translate('xpack.siem.header.editableTitle.cancel', {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* 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.
*/

export const MARKDOWN_HELP_LINK = 'https://www.markdownguide.org/cheat-sheet/';
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* 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 { EuiFormRow } from '@elastic/eui';
import React, { useCallback } from 'react';

import { FieldHook, getFieldValidityAndErrorMessage } from '../../shared_imports';
import { MarkdownEditor } from '.';

interface IMarkdownEditorForm {
dataTestSubj: string;
field: FieldHook;
idAria: string;
isDisabled: boolean;
placeholder?: string;
footerContentRight?: React.ReactNode;
}
export const MarkdownEditorForm = ({
dataTestSubj,
field,
idAria,
isDisabled = false,
placeholder,
footerContentRight,
}: IMarkdownEditorForm) => {
const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field);

const handleContentChange = useCallback(
(newContent: string) => {
field.setValue(newContent);
},
[field]
);

return (
<EuiFormRow
label={field.label}
labelAppend={field.labelAppend}
helpText={field.helpText}
error={errorMessage}
isInvalid={isInvalid}
fullWidth
data-test-subj={dataTestSubj}
describedByIds={idAria ? [idAria] : undefined}
>
<MarkdownEditor
initialContent={field.value as string}
isDisabled={isDisabled}
footerContentRight={footerContentRight}
onChange={handleContentChange}
placeholder={placeholder}
/>
</EuiFormRow>
);
};
121 changes: 121 additions & 0 deletions x-pack/legacy/plugins/siem/public/components/markdown_editor/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* 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 {
EuiFlexGroup,
EuiFlexItem,
EuiLink,
EuiPanel,
EuiTabbedContent,
EuiTextArea,
} from '@elastic/eui';
import React, { useEffect, useMemo, useState } from 'react';
import styled, { css } from 'styled-components';

import { Markdown } from '../markdown';
import * as i18n from './translations';
import { MARKDOWN_HELP_LINK } from './constants';

const TextArea = styled(EuiTextArea)`
width: 100%;
`;

const Container = styled(EuiPanel)`
${({ theme }) => css`
padding: 0;
background: ${theme.eui.euiColorLightestShade};
position: relative;
.euiTab {
padding: 10px;
}
.euiFormRow__labelWrapper {
position: absolute;
top: -${theme.eui.euiSizeL};
}
.euiFormErrorText {
padding: 0 ${theme.eui.euiSizeM};
}
`}
`;

const Tabs = styled(EuiTabbedContent)`
width: 100%;
`;

const Footer = styled(EuiFlexGroup)`
${({ theme }) => css`
height: 41px;
padding: 0 ${theme.eui.euiSizeM};
.euiLink {
font-size: ${theme.eui.euiSizeM};
}
`}
`;

const MarkdownContainer = styled(EuiPanel)`
min-height: 150px;
overflow: auto;
`;

/** An input for entering a new case description */
export const MarkdownEditor = React.memo<{
placeholder?: string;
footerContentRight?: React.ReactNode;
initialContent: string;
isDisabled?: boolean;
onChange: (description: string) => void;
}>(({ placeholder, footerContentRight, initialContent, isDisabled = false, onChange }) => {
const [content, setContent] = useState(initialContent);
useEffect(() => {
onChange(content);
}, [content]);
const tabs = useMemo(
() => [
{
id: 'comment',
name: i18n.MARKDOWN,
content: (
<TextArea
onChange={e => {
setContent(e.target.value);
}}
aria-label={`markdown-editor-comment`}
fullWidth={true}
disabled={isDisabled}
placeholder={placeholder ?? ''}
spellCheck={false}
value={content}
/>
),
},
{
id: 'preview',
name: i18n.PREVIEW,
content: (
<MarkdownContainer data-test-subj="markdown-container" paddingSize="s">
<Markdown raw={content} />
</MarkdownContainer>
),
},
],
[content, isDisabled, placeholder]
);
return (
<Container>
<Tabs data-test-subj={`markdown-tabs`} size="s" tabs={tabs} initialSelectedTab={tabs[0]} />
<Footer alignItems="center" gutterSize="none" justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiLink href={MARKDOWN_HELP_LINK} external target="_blank">
{i18n.MARKDOWN_SYNTAX_HELP}
</EuiLink>
</EuiFlexItem>
{footerContentRight && <EuiFlexItem grow={false}>{footerContentRight}</EuiFlexItem>}
</Footer>
</Container>
);
});

MarkdownEditor.displayName = 'MarkdownEditor';
Loading