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] [Cases] Final case features for 7.7 #61161

Merged
merged 9 commits into from
Mar 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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

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}>
stephmilovic marked this conversation as resolved.
Show resolved Hide resolved
{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) {
stephmilovic marked this conversation as resolved.
Show resolved Hide resolved
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