Skip to content

Commit

Permalink
[SIEM] [Cases] Final case features for 7.7 (#61161)
Browse files Browse the repository at this point in the history
  • Loading branch information
stephmilovic committed Mar 25, 2020
1 parent 7b4a3e7 commit 1dbe251
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 26 deletions.

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

13 changes: 12 additions & 1 deletion x-pack/legacy/plugins/siem/public/components/markdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,20 @@
import { EuiLink, EuiTableRow, EuiTableRowCell, EuiText, EuiToolTip } from '@elastic/eui';
import React from 'react';
import ReactMarkdown from 'react-markdown';
import styled from 'styled-components';
import styled, { css } from 'styled-components';

const TableHeader = styled.thead`
font-weight: bold;
`;

const MyBlockquote = styled.div`
${({ theme }) => css`
padding: 0 ${theme.eui.euiSize};
color: ${theme.eui.euiColorMediumShade};
border-left: ${theme.eui.euiSizeXS} solid ${theme.eui.euiColorLightShade};
`}
`;

TableHeader.displayName = 'TableHeader';

/** prevents links to the new pages from accessing `window.opener` */
Expand Down Expand Up @@ -63,6 +71,9 @@ export const Markdown = React.memo<{
</EuiLink>
</EuiToolTip>
),
blockquote: ({ children }: { children: React.ReactNode[] }) => (
<MyBlockquote>{children}</MyBlockquote>
),
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ const initialCommentValue: CommentRequest = {

interface AddCommentProps {
caseId: string;
insertQuote: string | null;
onCommentSaving?: () => void;
onCommentPosted: (commentResponse: Comment) => void;
showLoading?: boolean;
}

export const AddComment = React.memo<AddCommentProps>(
({ caseId, showLoading = true, onCommentPosted, onCommentSaving }) => {
({ caseId, insertQuote, showLoading = true, onCommentPosted, onCommentSaving }) => {
const { commentData, isLoading, postComment, resetCommentData } = usePostComment(caseId);
const { form } = useForm<CommentRequest>({
defaultValue: initialCommentValue,
Expand All @@ -48,6 +49,16 @@ export const AddComment = React.memo<AddCommentProps>(
'comment'
);

useEffect(() => {
if (insertQuote !== null) {
const { comment } = form.getFormData();
form.setFieldValue(
'comment',
`${comment}${comment.length > 0 ? '\n\n' : ''}${insertQuote}`
);
}
}, [insertQuote]);

useEffect(() => {
if (commentData !== null) {
onCommentPosted(commentData);
Expand All @@ -67,7 +78,7 @@ export const AddComment = React.memo<AddCommentProps>(
}, [form]);

return (
<>
<span id="add-comment-permLink">
{isLoading && showLoading && <MySpinner size="xl" />}
<Form form={form}>
<UseField
Expand Down Expand Up @@ -100,7 +111,7 @@ export const AddComment = React.memo<AddCommentProps>(
}}
/>
</Form>
</>
</span>
);
}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
* 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 React, { useCallback } from 'react';
import {
EuiBadge,
EuiTableFieldDataColumnType,
EuiTableComputedColumnType,
EuiTableActionsColumnType,
EuiAvatar,
EuiLink,
EuiLoadingSpinner,
} from '@elastic/eui';
import styled from 'styled-components';
import { DefaultItemIconButtonAction } from '@elastic/eui/src/components/basic_table/action_types';
Expand All @@ -19,6 +21,7 @@ import { FormattedRelativePreferenceDate } from '../../../../components/formatte
import { CaseDetailsLink } from '../../../../components/links';
import { TruncatableText } from '../../../../components/truncatable_text';
import * as i18n from './translations';
import { useGetCaseUserActions } from '../../../../containers/case/use_get_case_user_actions';

export type CasesColumns =
| EuiTableFieldDataColumnType<Case>
Expand Down Expand Up @@ -60,7 +63,6 @@ export const getCasesColumns = (
}
return getEmptyTagValue();
},
width: '25%',
},
{
field: 'createdBy',
Expand Down Expand Up @@ -105,7 +107,6 @@ export const getCasesColumns = (
return getEmptyTagValue();
},
truncateText: true,
width: '20%',
},
{
align: 'right',
Expand Down Expand Up @@ -148,8 +149,47 @@ export const getCasesColumns = (
return getEmptyTagValue();
},
},
{
name: 'ServiceNow Incident',
render: (theCase: Case) => {
if (theCase.id != null) {
return <ServiceNowColumn theCase={theCase} />;
}
return getEmptyTagValue();
},
},
{
name: 'Actions',
actions,
},
];

interface Props {
theCase: Case;
}

const ServiceNowColumn: React.FC<Props> = ({ theCase }) => {
const { hasDataToPush, isLoading } = useGetCaseUserActions(theCase.id);
const handleRenderDataToPush = useCallback(
() =>
isLoading ? (
<EuiLoadingSpinner />
) : (
<p>
<EuiLink
data-test-subj={`case-table-column-external`}
href={theCase.externalService?.externalUrl}
target="_blank"
>
{theCase.externalService?.externalTitle}
</EuiLink>
{hasDataToPush ? i18n.REQUIRES_UPDATE : i18n.UP_TO_DATE}
</p>
),
[hasDataToPush, isLoading, theCase.externalService]
);
if (theCase.externalService !== null) {
return handleRenderDataToPush();
}
return renderStringField(i18n.NOT_PUSHED, `case-table-column-external-notPushed`);
};
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,21 @@ export const AllCases = React.memo(() => {

const { dispatchResetIsUpdated, isUpdated, updateBulkStatus } = useUpdateCases();

const refreshCases = useCallback(() => {
refetchCases(filterOptions, queryParams);
fetchCasesStatus();
}, [filterOptions, queryParams]);

useEffect(() => {
if (isDeleted) {
refetchCases(filterOptions, queryParams);
fetchCasesStatus();
refreshCases();
dispatchResetIsDeleted();
}
if (isUpdated) {
refetchCases(filterOptions, queryParams);
fetchCasesStatus();
refreshCases();
dispatchResetIsUpdated();
}
}, [isDeleted, isUpdated, filterOptions, queryParams]);

}, [isDeleted, isUpdated]);
const [deleteThisCase, setDeleteThisCase] = useState({
title: '',
id: '',
Expand Down Expand Up @@ -327,6 +329,10 @@ export const AllCases = React.memo(() => {
>
{i18n.BULK_ACTIONS}
</UtilityBarAction>

<UtilityBarAction iconSide="left" iconType="refresh" onClick={refreshCases}>
{i18n.REFRESH}
</UtilityBarAction>
</UtilityBarGroup>
</UtilityBarSection>
</UtilityBar>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,17 @@ export const CLOSED = i18n.translate('xpack.siem.case.caseTable.closed', {
export const DELETE = i18n.translate('xpack.siem.case.caseTable.delete', {
defaultMessage: 'Delete',
});
export const REQUIRES_UPDATE = i18n.translate('xpack.siem.case.caseTable.requiresUpdate', {
defaultMessage: ' requires update',
});

export const UP_TO_DATE = i18n.translate('xpack.siem.case.caseTable.upToDate', {
defaultMessage: ' is up to date',
});
export const NOT_PUSHED = i18n.translate('xpack.siem.case.caseTable.notPushed', {
defaultMessage: 'Not pushed',
});

export const REFRESH = i18n.translate('xpack.siem.case.caseTable.refreshTitle', {
defaultMessage: 'Refresh',
});
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ export const EDIT_DESCRIPTION = i18n.translate('xpack.siem.case.caseView.edit.de
defaultMessage: 'Edit description',
});

export const QUOTE = i18n.translate('xpack.siem.case.caseView.edit.quote', {
defaultMessage: 'Quote',
});

export const EDIT_COMMENT = i18n.translate('xpack.siem.case.caseView.edit.comment', {
defaultMessage: 'Edit comment',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const PropertyActions = React.memo<PropertyActionsProps>(({ propertyActio

const onClosePopover = useCallback((cb?: () => void) => {
setShowActions(false);
if (cb) {
if (cb != null) {
cb();
}
}, []);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export const UserActionTree = React.memo(
);
const currentUser = useCurrentUser();
const [manageMarkdownEditIds, setManangeMardownEditIds] = useState<string[]>([]);
const [insertQuote, setInsertQuote] = useState<string | null>(null);

const handleManageMarkdownEditId = useCallback(
(id: string) => {
Expand Down Expand Up @@ -92,6 +93,9 @@ export const UserActionTree = React.memo(
top: y,
behavior: 'smooth',
});
if (id === 'add-comment') {
moveToTarget.getElementsByTagName('textarea')[0].focus();
}
}
window.clearTimeout(handlerTimeoutId.current);
setSelectedOutlineCommentId(id);
Expand All @@ -103,6 +107,15 @@ export const UserActionTree = React.memo(
[handlerTimeoutId.current]
);

const handleManageQuote = useCallback(
(quote: string) => {
const addCarrots = quote.replace(new RegExp('\r?\n', 'g'), ' \n> ');
setInsertQuote(`> ${addCarrots} \n`);
handleOutlineComment('add-comment');
},
[handleOutlineComment]
);

const handleUpdate = useCallback(
(comment: Comment) => {
addPostedComment(comment);
Expand Down Expand Up @@ -131,12 +144,13 @@ export const UserActionTree = React.memo(
() => (
<AddComment
caseId={caseData.id}
insertQuote={insertQuote}
onCommentPosted={handleUpdate}
onCommentSaving={handleManageMarkdownEditId.bind(null, NEW_ID)}
showLoading={false}
/>
),
[caseData.id, handleUpdate]
[caseData.id, handleUpdate, insertQuote]
);

useEffect(() => {
Expand All @@ -156,10 +170,12 @@ export const UserActionTree = React.memo(
isEditable={manageMarkdownEditIds.includes(DESCRIPTION_ID)}
isLoading={isLoadingDescription}
labelEditAction={i18n.EDIT_DESCRIPTION}
labelQuoteAction={i18n.QUOTE}
labelTitle={<>{i18n.ADDED_DESCRIPTION}</>}
fullName={caseData.createdBy.fullName ?? caseData.createdBy.username}
markdown={MarkdownDescription}
onEdit={handleManageMarkdownEditId.bind(null, DESCRIPTION_ID)}
onQuote={handleManageQuote.bind(null, caseData.description)}
userName={caseData.createdBy.username}
/>

Expand All @@ -176,6 +192,7 @@ export const UserActionTree = React.memo(
isEditable={manageMarkdownEditIds.includes(comment.id)}
isLoading={isLoadingIds.includes(comment.id)}
labelEditAction={i18n.EDIT_COMMENT}
labelQuoteAction={i18n.QUOTE}
labelTitle={<>{i18n.ADDED_COMMENT}</>}
fullName={comment.createdBy.fullName ?? comment.createdBy.username}
markdown={
Expand All @@ -188,6 +205,7 @@ export const UserActionTree = React.memo(
/>
}
onEdit={handleManageMarkdownEditId.bind(null, comment.id)}
onQuote={handleManageQuote.bind(null, comment.comment)}
outlineComment={handleOutlineComment}
userName={comment.createdBy.username}
updatedAt={comment.updatedAt}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ interface UserActionItemProps {
isEditable: boolean;
isLoading: boolean;
labelEditAction?: string;
labelQuoteAction?: string;
labelTitle?: JSX.Element;
linkId?: string | null;
fullName: string;
markdown?: React.ReactNode;
onEdit?: (id: string) => void;
onQuote?: (id: string) => void;
userName: string;
updatedAt?: string | null;
outlineComment?: (id: string) => void;
Expand Down Expand Up @@ -113,11 +115,13 @@ export const UserActionItem = ({
isEditable,
isLoading,
labelEditAction,
labelQuoteAction,
labelTitle,
linkId,
fullName,
markdown,
onEdit,
onQuote,
outlineComment,
showBottomFooter,
showTopFooter,
Expand Down Expand Up @@ -147,11 +151,13 @@ export const UserActionItem = ({
id={id}
isLoading={isLoading}
labelEditAction={labelEditAction}
labelQuoteAction={labelQuoteAction}
labelTitle={labelTitle ?? <></>}
linkId={linkId}
userName={userName}
updatedAt={updatedAt}
onEdit={onEdit}
onQuote={onQuote}
outlineComment={outlineComment}
/>
{markdown}
Expand Down
Loading

0 comments on commit 1dbe251

Please sign in to comment.