[Security Solution] [Cases] Various Cases cleanups (#102103)

This commit is contained in:
Steph Milovic 2021-06-17 10:52:04 -06:00 committed by GitHub
parent 0e14cef4cb
commit 06be699862
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
170 changed files with 1096 additions and 1642 deletions

View file

@ -875,6 +875,16 @@ module.exports = {
},
},
/**
* Cases overrides
*/
{
files: ['x-pack/plugins/cases/**/*.{js,mjs,ts,tsx}'],
rules: {
'no-duplicate-imports': 'error',
},
},
/**
* Security Solution overrides
*/

View file

@ -108,6 +108,6 @@ pageLoadAssetSize:
banners: 17946
mapsEms: 26072
timelines: 28613
cases: 162385
screenshotMode: 17856
visTypePie: 35583
cases: 144442

View file

@ -10,8 +10,7 @@ import * as rt from 'io-ts';
import { NumberFromString } from '../saved_object';
import { UserRT } from '../user';
import { CommentResponseRt } from './comment';
import { CasesStatusResponseRt } from './status';
import { CaseStatusRt } from './status';
import { CaseStatusRt, CasesStatusResponseRt } from './status';
const SubCaseBasicRt = rt.type({
/**

View file

@ -10,7 +10,7 @@ import moment from 'moment-timezone';
import { useCallback, useEffect, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { DEFAULT_DATE_FORMAT, DEFAULT_DATE_FORMAT_TZ } from '../../../../common/constants';
import { DEFAULT_DATE_FORMAT, DEFAULT_DATE_FORMAT_TZ } from '../../../../common';
import { AuthenticatedUser } from '../../../../../security/common/model';
import { convertToCamelCase } from '../../../containers/utils';
import { StartServices } from '../../../types';

View file

@ -5,12 +5,10 @@
* 2.0.
*/
window.matchMedia = jest.fn().mockImplementation((query) => {
return {
matches: false,
media: query,
onchange: null,
addListener: jest.fn(),
removeListener: jest.fn(),
};
});
window.matchMedia = jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(),
removeListener: jest.fn(),
}));

View file

@ -40,26 +40,24 @@ const TestProvidersComponent: React.FC<Props> = ({ children }) => (
export const TestProviders = React.memo(TestProvidersComponent);
export const useFormFieldMock = <T,>(options?: Partial<FieldHook<T>>): FieldHook<T> => {
return {
path: 'path',
type: 'type',
value: ('mockedValue' as unknown) as T,
isPristine: false,
isValidating: false,
isValidated: false,
isChangingValue: false,
errors: [],
isValid: true,
getErrorsMessages: jest.fn(),
onChange: jest.fn(),
setValue: jest.fn(),
setErrors: jest.fn(),
clearErrors: jest.fn(),
validate: jest.fn(),
reset: jest.fn(),
__isIncludedInOutput: true,
__serializeValue: jest.fn(),
...options,
};
};
export const useFormFieldMock = <T,>(options?: Partial<FieldHook<T>>): FieldHook<T> => ({
path: 'path',
type: 'type',
value: ('mockedValue' as unknown) as T,
isPristine: false,
isValidating: false,
isValidated: false,
isChangingValue: false,
errors: [],
isValid: true,
getErrorsMessages: jest.fn(),
onChange: jest.fn(),
setValue: jest.fn(),
setErrors: jest.fn(),
clearErrors: jest.fn(),
validate: jest.fn(),
reset: jest.fn(),
__isIncludedInOutput: true,
__serializeValue: jest.fn(),
...options,
});

View file

@ -7,21 +7,6 @@
import { i18n } from '@kbn/i18n';
export const CASES_FEATURE_NO_PERMISSIONS_TITLE = i18n.translate(
'xpack.cases.caseFeatureNoPermissionsTitle',
{
defaultMessage: 'Kibana feature privileges required',
}
);
export const CASES_FEATURE_NO_PERMISSIONS_MSG = i18n.translate(
'xpack.cases.caseFeatureNoPermissionsMessage',
{
defaultMessage:
'To view cases, you must have privileges for the Cases feature in the Kibana space. For more information, contact your Kibana administrator.',
}
);
export const BACK_TO_ALL = i18n.translate('xpack.cases.caseView.backLabel', {
defaultMessage: 'Back to cases',
});
@ -56,10 +41,6 @@ export const PARTICIPANTS = i18n.translate('xpack.cases.caseView.particpantsLabe
defaultMessage: 'Participants',
});
export const CREATE_BC_TITLE = i18n.translate('xpack.cases.caseView.breadcrumb', {
defaultMessage: 'Create',
});
export const CREATE_TITLE = i18n.translate('xpack.cases.caseView.create', {
defaultMessage: 'Create new case',
});
@ -179,18 +160,10 @@ export const SAVE = i18n.translate('xpack.cases.caseView.description.save', {
defaultMessage: 'Save',
});
export const GO_TO_DOCUMENTATION = i18n.translate('xpack.cases.caseView.goToDocumentationButton', {
defaultMessage: 'View documentation',
});
export const CONNECTORS = i18n.translate('xpack.cases.caseView.connectors', {
defaultMessage: 'External Incident Management System',
});
export const EDIT_CONNECTOR = i18n.translate('xpack.cases.caseView.editConnector', {
defaultMessage: 'Change external incident management system',
});
export const NO_CONNECTOR = i18n.translate('xpack.cases.common.noConnector', {
defaultMessage: 'No connector selected',
});

View file

@ -11,7 +11,6 @@ import { waitFor, act } from '@testing-library/react';
import { noop } from 'lodash/fp';
import { TestProviders } from '../../common/mock';
import { Router, routeData, mockHistory, mockLocation } from '../__mock__/router';
import { CommentRequest, CommentType, SECURITY_SOLUTION_OWNER } from '../../../common';
import { usePostComment } from '../../containers/use_post_comment';
@ -51,15 +50,12 @@ describe('AddComment ', () => {
beforeEach(() => {
jest.clearAllMocks();
usePostCommentMock.mockImplementation(() => defaultPostComment);
jest.spyOn(routeData, 'useLocation').mockReturnValue(mockLocation);
});
it('should post comment on submit click', async () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<AddComment {...addCommentProps} />
</Router>
<AddComment {...addCommentProps} />
</TestProviders>
);
@ -88,9 +84,7 @@ describe('AddComment ', () => {
usePostCommentMock.mockImplementation(() => ({ ...defaultPostComment, isLoading: true }));
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<AddComment {...{ ...addCommentProps, showLoading: true }} />
</Router>
<AddComment {...{ ...addCommentProps, showLoading: true }} />
</TestProviders>
);
@ -104,9 +98,7 @@ describe('AddComment ', () => {
usePostCommentMock.mockImplementation(() => ({ ...defaultPostComment, isLoading: true }));
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<AddComment {...{ ...addCommentProps, disabled: true }} />
</Router>
<AddComment {...{ ...addCommentProps, disabled: true }} />
</TestProviders>
);
@ -120,9 +112,7 @@ describe('AddComment ', () => {
const ref = React.createRef<AddCommentRefObject>();
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<AddComment {...{ ...addCommentProps }} ref={ref} />
</Router>
<AddComment {...{ ...addCommentProps }} ref={ref} />
</TestProviders>
);
@ -153,9 +143,7 @@ describe('AddComment ', () => {
const wrapper = mount(
<TestProviders>
<CasesTimelineIntegrationProvider timelineIntegration={mockTimelineIntegration}>
<Router history={mockHistory}>
<AddComment {...{ ...addCommentProps }} />
</Router>
<AddComment {...{ ...addCommentProps }} />
</CasesTimelineIntegrationProvider>
</TestProviders>
);

View file

@ -26,22 +26,20 @@ export const isIndividual = (theCase: Case | SubCase | null | undefined) =>
export const getSubCasesStatusCountsBadges = (
subCases: SubCase[]
): Array<{ name: CaseStatuses; color: string; count: number }> => {
return [
{
name: CaseStatuses.open,
color: statuses[CaseStatuses.open].color,
count: filter({ status: CaseStatuses.open }, subCases).length,
},
{
name: CaseStatuses['in-progress'],
color: statuses[CaseStatuses['in-progress']].color,
count: filter({ status: CaseStatuses['in-progress'] }, subCases).length,
},
{
name: CaseStatuses.closed,
color: statuses[CaseStatuses.closed].color,
count: filter({ status: CaseStatuses.closed }, subCases).length,
},
];
};
): Array<{ name: CaseStatuses; color: string; count: number }> => [
{
color: statuses[CaseStatuses.open].color,
count: filter({ status: CaseStatuses.open }, subCases).length,
name: CaseStatuses.open,
},
{
color: statuses[CaseStatuses['in-progress']].color,
count: filter({ status: CaseStatuses['in-progress'] }, subCases).length,
name: CaseStatuses['in-progress'],
},
{
color: statuses[CaseStatuses.closed].color,
count: filter({ status: CaseStatuses.closed }, subCases).length,
name: CaseStatuses.closed,
},
];

View file

@ -19,13 +19,11 @@ export interface AllCasesProps extends Owner {
userCanCrud: boolean;
}
export const AllCases: React.FC<AllCasesProps> = (props) => {
return (
<OwnerProvider owner={props.owner}>
<AllCasesGeneric {...props} />
</OwnerProvider>
);
};
export const AllCases: React.FC<AllCasesProps> = (props) => (
<OwnerProvider owner={props.owner}>
<AllCasesGeneric {...props} />
</OwnerProvider>
);
// eslint-disable-next-line import/no-default-export
export { AllCases as default };

View file

@ -17,18 +17,18 @@ interface GetBulkItems {
caseStatus: CaseStatusWithAllStatus;
closePopover: () => void;
deleteCasesAction: (cases: Case[]) => void;
includeCollections: boolean;
selectedCases: Case[];
updateCaseStatus: (status: string) => void;
includeCollections: boolean;
}
export const getBulkItems = ({
caseStatus,
closePopover,
deleteCasesAction,
includeCollections,
selectedCases,
updateCaseStatus,
includeCollections,
}: GetBulkItems) => {
let statusMenuItems: JSX.Element[] = [];
@ -36,8 +36,8 @@ export const getBulkItems = ({
<EuiContextMenuItem
data-test-subj="cases-bulk-open-button"
disabled={selectedCases.length === 0 || includeCollections}
key="cases-bulk-open-button"
icon={statuses[CaseStatuses.open].icon}
key="cases-bulk-open-button"
onClick={() => {
closePopover();
updateCaseStatus(CaseStatuses.open);
@ -51,8 +51,8 @@ export const getBulkItems = ({
<EuiContextMenuItem
data-test-subj="cases-bulk-in-progress-button"
disabled={selectedCases.length === 0 || includeCollections}
key="cases-bulk-in-progress-button"
icon={statuses[CaseStatuses['in-progress']].icon}
key="cases-bulk-in-progress-button"
onClick={() => {
closePopover();
updateCaseStatus(CaseStatuses['in-progress']);
@ -66,8 +66,8 @@ export const getBulkItems = ({
<EuiContextMenuItem
data-test-subj="cases-bulk-close-button"
disabled={selectedCases.length === 0 || includeCollections}
key="cases-bulk-close-button"
icon={statuses[CaseStatuses.closed].icon}
key="cases-bulk-close-button"
onClick={() => {
closePopover();
updateCaseStatus(CaseStatuses.closed);

View file

@ -6,7 +6,6 @@
*/
import React, { memo, useCallback, useMemo, useState } from 'react';
import { memoize } from 'lodash/fp';
import { EuiPopover, EuiContextMenuPanel, EuiContextMenuItem } from '@elastic/eui';
import { caseStatuses, CaseStatuses } from '../../../common';
import { Status } from '../status';
@ -19,8 +18,8 @@ interface Props {
const StatusContextMenuComponent: React.FC<Props> = ({
currentStatus,
onStatusChanged,
disabled = false,
onStatusChanged,
}) => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const closePopover = useCallback(() => setIsPopoverOpen(false), []);
@ -30,35 +29,38 @@ const StatusContextMenuComponent: React.FC<Props> = ({
[disabled, currentStatus, openPopover]
);
const onContextMenuItemClick = useMemo(
() =>
memoize<(status: CaseStatuses) => () => void>((status) => () => {
closePopover();
onStatusChanged(status);
}),
const onContextMenuItemClick = useCallback(
(status: CaseStatuses) => {
closePopover();
onStatusChanged(status);
},
[closePopover, onStatusChanged]
);
const panelItems = caseStatuses.map((status: CaseStatuses) => (
<EuiContextMenuItem
key={status}
icon={status === currentStatus ? 'check' : 'empty'}
onClick={onContextMenuItemClick(status)}
data-test-subj={`case-view-status-dropdown-${status}`}
>
<Status type={status} />
</EuiContextMenuItem>
));
const panelItems = useMemo(
() =>
caseStatuses.map((status: CaseStatuses) => (
<EuiContextMenuItem
data-test-subj={`case-view-status-dropdown-${status}`}
icon={status === currentStatus ? 'check' : 'empty'}
key={status}
onClick={() => onContextMenuItemClick(status)}
>
<Status type={status} />
</EuiContextMenuItem>
)),
[currentStatus, onContextMenuItemClick]
);
return (
<>
<EuiPopover
id="caseStatusPopover"
button={popOverButton}
isOpen={isPopoverOpen}
closePopover={closePopover}
anchorPosition="downLeft"
button={popOverButton}
closePopover={closePopover}
data-test-subj="case-view-status-dropdown"
id="caseStatusPopover"
isOpen={isPopoverOpen}
>
<EuiContextMenuPanel items={panelItems} />
</EuiPopover>

View file

@ -9,7 +9,6 @@ import React from 'react';
import { mount } from 'enzyme';
import '../../common/mock/match_media';
import { Router, mockHistory } from '../__mock__/router';
import { CaseComponent, CaseComponentProps, CaseView } from '.';
import {
basicCase,
@ -30,6 +29,10 @@ import { usePostPushToService } from '../../containers/use_post_push_to_service'
import { CaseType, ConnectorTypes } from '../../../common';
import { useKibana } from '../../common/lib/kibana';
const mockId = basicCase.id;
jest.mock('react-router-dom', () => ({
useParams: () => ({ detailName: mockId }),
}));
jest.mock('../../containers/use_update_case');
jest.mock('../../containers/use_get_case_user_actions');
jest.mock('../../containers/use_get_case');
@ -172,9 +175,7 @@ describe('CaseView ', () => {
it('should render CaseComponent', async () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...caseProps} />
</Router>
<CaseComponent {...caseProps} />
</TestProviders>
);
@ -230,9 +231,7 @@ describe('CaseView ', () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...caseClosedProps} />
</Router>
<CaseComponent {...caseClosedProps} />
</TestProviders>
);
@ -249,9 +248,7 @@ describe('CaseView ', () => {
it('should update status', async () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...caseProps} />
</Router>
<CaseComponent {...caseProps} />
</TestProviders>
);
wrapper.find('[data-test-subj="case-view-status-dropdown"] button').first().simulate('click');
@ -276,9 +273,7 @@ describe('CaseView ', () => {
}));
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...caseProps} />
</Router>
<CaseComponent {...caseProps} />
</TestProviders>
);
await waitFor(() => {
@ -299,9 +294,7 @@ describe('CaseView ', () => {
}));
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...caseProps} />
</Router>
<CaseComponent {...caseProps} />
</TestProviders>
);
await waitFor(() => {
@ -330,9 +323,7 @@ describe('CaseView ', () => {
}));
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...caseProps} />
</Router>
<CaseComponent {...caseProps} />
</TestProviders>
);
await waitFor(() => {
@ -350,9 +341,7 @@ describe('CaseView ', () => {
it('should update title', async () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...caseProps} />
</Router>
<CaseComponent {...caseProps} />
</TestProviders>
);
const newTitle = 'The new title';
@ -379,9 +368,7 @@ describe('CaseView ', () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...{ ...caseProps, updateCase }} />
</Router>
<CaseComponent {...{ ...caseProps, updateCase }} />
</TestProviders>
);
@ -404,34 +391,32 @@ describe('CaseView ', () => {
}));
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseView
{...{
allCasesNavigation: {
href: 'all-cases-href',
onClick: jest.fn(),
},
caseDetailsNavigation: {
href: 'case-details-href',
onClick: jest.fn(),
},
caseId: '1234',
configureCasesNavigation: {
href: 'configure-cases-href',
onClick: jest.fn(),
},
getCaseDetailHrefWithCommentId: jest.fn(),
onComponentInitialized: jest.fn(),
ruleDetailsNavigation: {
href: jest.fn(),
onClick: jest.fn(),
},
showAlertDetails: jest.fn(),
useFetchAlertData: jest.fn().mockReturnValue([false, alertsHit[0]]),
userCanCrud: true,
}}
/>
</Router>
<CaseView
{...{
allCasesNavigation: {
href: 'all-cases-href',
onClick: jest.fn(),
},
caseDetailsNavigation: {
href: 'case-details-href',
onClick: jest.fn(),
},
caseId: '1234',
configureCasesNavigation: {
href: 'configure-cases-href',
onClick: jest.fn(),
},
getCaseDetailHrefWithCommentId: jest.fn(),
onComponentInitialized: jest.fn(),
ruleDetailsNavigation: {
href: jest.fn(),
onClick: jest.fn(),
},
showAlertDetails: jest.fn(),
useFetchAlertData: jest.fn().mockReturnValue([false, alertsHit[0]]),
userCanCrud: true,
}}
/>
</TestProviders>
);
await waitFor(() => {
@ -446,34 +431,32 @@ describe('CaseView ', () => {
}));
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseView
{...{
allCasesNavigation: {
href: 'all-cases-href',
onClick: jest.fn(),
},
caseDetailsNavigation: {
href: 'case-details-href',
onClick: jest.fn(),
},
caseId: '1234',
configureCasesNavigation: {
href: 'configure-cases-href',
onClick: jest.fn(),
},
getCaseDetailHrefWithCommentId: jest.fn(),
onComponentInitialized: jest.fn(),
ruleDetailsNavigation: {
href: jest.fn(),
onClick: jest.fn(),
},
showAlertDetails: jest.fn(),
useFetchAlertData: jest.fn().mockReturnValue([false, alertsHit[0]]),
userCanCrud: true,
}}
/>
</Router>
<CaseView
{...{
allCasesNavigation: {
href: 'all-cases-href',
onClick: jest.fn(),
},
caseDetailsNavigation: {
href: 'case-details-href',
onClick: jest.fn(),
},
caseId: '1234',
configureCasesNavigation: {
href: 'configure-cases-href',
onClick: jest.fn(),
},
getCaseDetailHrefWithCommentId: jest.fn(),
onComponentInitialized: jest.fn(),
ruleDetailsNavigation: {
href: jest.fn(),
onClick: jest.fn(),
},
showAlertDetails: jest.fn(),
useFetchAlertData: jest.fn().mockReturnValue([false, alertsHit[0]]),
userCanCrud: true,
}}
/>
</TestProviders>
);
await waitFor(() => {
@ -485,34 +468,32 @@ describe('CaseView ', () => {
(useGetCase as jest.Mock).mockImplementation(() => defaultGetCase);
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseView
{...{
allCasesNavigation: {
href: 'all-cases-href',
onClick: jest.fn(),
},
caseDetailsNavigation: {
href: 'case-details-href',
onClick: jest.fn(),
},
caseId: '1234',
configureCasesNavigation: {
href: 'configure-cases-href',
onClick: jest.fn(),
},
getCaseDetailHrefWithCommentId: jest.fn(),
onComponentInitialized: jest.fn(),
ruleDetailsNavigation: {
href: jest.fn(),
onClick: jest.fn(),
},
showAlertDetails: jest.fn(),
useFetchAlertData: jest.fn().mockReturnValue([false, alertsHit[0]]),
userCanCrud: true,
}}
/>
</Router>
<CaseView
{...{
allCasesNavigation: {
href: 'all-cases-href',
onClick: jest.fn(),
},
caseDetailsNavigation: {
href: 'case-details-href',
onClick: jest.fn(),
},
caseId: '1234',
configureCasesNavigation: {
href: 'configure-cases-href',
onClick: jest.fn(),
},
getCaseDetailHrefWithCommentId: jest.fn(),
onComponentInitialized: jest.fn(),
ruleDetailsNavigation: {
href: jest.fn(),
onClick: jest.fn(),
},
showAlertDetails: jest.fn(),
useFetchAlertData: jest.fn().mockReturnValue([false, alertsHit[0]]),
userCanCrud: true,
}}
/>
</TestProviders>
);
await waitFor(() => {
@ -524,34 +505,32 @@ describe('CaseView ', () => {
(useGetCase as jest.Mock).mockImplementation(() => defaultGetCase);
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseView
{...{
allCasesNavigation: {
href: 'all-cases-href',
onClick: jest.fn(),
},
caseDetailsNavigation: {
href: 'case-details-href',
onClick: jest.fn(),
},
caseId: '1234',
configureCasesNavigation: {
href: 'configure-cases-href',
onClick: jest.fn(),
},
getCaseDetailHrefWithCommentId: jest.fn(),
onComponentInitialized: jest.fn(),
ruleDetailsNavigation: {
href: jest.fn(),
onClick: jest.fn(),
},
showAlertDetails: jest.fn(),
useFetchAlertData: jest.fn().mockReturnValue([false, alertsHit[0]]),
userCanCrud: true,
}}
/>
</Router>
<CaseView
{...{
allCasesNavigation: {
href: 'all-cases-href',
onClick: jest.fn(),
},
caseDetailsNavigation: {
href: 'case-details-href',
onClick: jest.fn(),
},
caseId: '1234',
configureCasesNavigation: {
href: 'configure-cases-href',
onClick: jest.fn(),
},
getCaseDetailHrefWithCommentId: jest.fn(),
onComponentInitialized: jest.fn(),
ruleDetailsNavigation: {
href: jest.fn(),
onClick: jest.fn(),
},
showAlertDetails: jest.fn(),
useFetchAlertData: jest.fn().mockReturnValue([false, alertsHit[0]]),
userCanCrud: true,
}}
/>
</TestProviders>
);
wrapper.find('[data-test-subj="case-refresh"]').first().simulate('click');
@ -569,15 +548,13 @@ describe('CaseView ', () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent
{...{
...caseProps,
updateCase,
caseData: { ...caseProps.caseData, connectorId: 'not-exist' },
}}
/>
</Router>
<CaseComponent
{...{
...caseProps,
updateCase,
caseData: { ...caseProps.caseData, connectorId: 'not-exist' },
}}
/>
</TestProviders>
);
await waitFor(() => {
@ -595,20 +572,18 @@ describe('CaseView ', () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent
{...caseProps}
caseData={{
...caseProps.caseData,
connector: {
id: 'servicenow-1',
name: 'SN 1',
type: ConnectorTypes.serviceNowITSM,
fields: null,
},
}}
/>
</Router>
<CaseComponent
{...caseProps}
caseData={{
...caseProps.caseData,
connector: {
id: 'servicenow-1',
name: 'SN 1',
type: ConnectorTypes.serviceNowITSM,
fields: null,
},
}}
/>
</TestProviders>
);
const connectorName = wrapper
@ -636,20 +611,18 @@ describe('CaseView ', () => {
it('should update connector', async () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent
{...caseProps}
caseData={{
...caseProps.caseData,
connector: {
id: 'servicenow-1',
name: 'SN 1',
type: ConnectorTypes.serviceNowITSM,
fields: null,
},
}}
/>
</Router>
<CaseComponent
{...caseProps}
caseData={{
...caseProps.caseData,
connector: {
id: 'servicenow-1',
name: 'SN 1',
type: ConnectorTypes.serviceNowITSM,
fields: null,
},
}}
/>
</TestProviders>
);
@ -681,9 +654,7 @@ describe('CaseView ', () => {
const onComponentInitialized = jest.fn();
mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...caseProps} onComponentInitialized={onComponentInitialized} />
</Router>
<CaseComponent {...caseProps} onComponentInitialized={onComponentInitialized} />
</TestProviders>
);
@ -705,9 +676,7 @@ describe('CaseView ', () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...caseProps} useFetchAlertData={useFetchAlertData} />
</Router>
<CaseComponent {...caseProps} useFetchAlertData={useFetchAlertData} />
</TestProviders>
);
@ -723,9 +692,7 @@ describe('CaseView ', () => {
const showAlertDetails = jest.fn();
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...caseProps} showAlertDetails={showAlertDetails} />
</Router>
<CaseComponent {...caseProps} showAlertDetails={showAlertDetails} />
</TestProviders>
);
@ -741,9 +708,7 @@ describe('CaseView ', () => {
it('should show the rule name', async () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...caseProps} />
</Router>
<CaseComponent {...caseProps} />
</TestProviders>
);
@ -762,9 +727,7 @@ describe('CaseView ', () => {
it('should update settings', async () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...caseProps} />
</Router>
<CaseComponent {...caseProps} />
</TestProviders>
);
@ -786,9 +749,7 @@ describe('CaseView ', () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...{ ...caseProps, connector: { ...caseProps, name: 'old-name' } }} />
</Router>
<CaseComponent {...{ ...caseProps, connector: { ...caseProps, name: 'old-name' } }} />
</TestProviders>
);
@ -808,9 +769,7 @@ describe('CaseView ', () => {
useConnectorsMock.mockImplementation(() => ({ connectors: [], loading: false }));
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...caseProps} />
</Router>
<CaseComponent {...caseProps} />
</TestProviders>
);
@ -824,9 +783,7 @@ describe('CaseView ', () => {
useConnectorsMock.mockImplementation(() => ({ connectors: [], loading: true }));
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent {...caseProps} />
</Router>
<CaseComponent {...caseProps} />
</TestProviders>
);
@ -841,12 +798,10 @@ describe('CaseView ', () => {
it('it does not allow the user to update the status', async () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent
{...caseProps}
caseData={{ ...caseProps.caseData, type: CaseType.collection }}
/>
</Router>
<CaseComponent
{...caseProps}
caseData={{ ...caseProps.caseData, type: CaseType.collection }}
/>
</TestProviders>
);
@ -868,12 +823,10 @@ describe('CaseView ', () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent
{...caseProps}
caseData={{ ...caseProps.caseData, type: CaseType.collection }}
/>
</Router>
<CaseComponent
{...caseProps}
caseData={{ ...caseProps.caseData, type: CaseType.collection }}
/>
</TestProviders>
);
@ -890,12 +843,10 @@ describe('CaseView ', () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<CaseComponent
{...caseProps}
caseData={{ ...caseProps.caseData, type: CaseType.collection }}
/>
</Router>
<CaseComponent
{...caseProps}
caseData={{ ...caseProps.caseData, type: CaseType.collection }}
/>
</TestProviders>
);

View file

@ -9,16 +9,6 @@ import { i18n } from '@kbn/i18n';
export * from '../../common/translations';
export const SHOWING_CASES = (actionDate: string, actionName: string, userName: string) =>
i18n.translate('xpack.cases.caseView.actionHeadline', {
values: {
actionDate,
actionName,
userName,
},
defaultMessage: '{userName} {actionName} on {actionDate}',
});
export const ADDED_FIELD = i18n.translate('xpack.cases.caseView.actionLabel.addedField', {
defaultMessage: 'added',
});
@ -89,10 +79,6 @@ export const ON = i18n.translate('xpack.cases.caseView.actionLabel.on', {
defaultMessage: 'on',
});
export const ADDED_COMMENT = i18n.translate('xpack.cases.caseView.actionLabel.addComment', {
defaultMessage: 'added comment',
});
export const STATUS = i18n.translate('xpack.cases.caseView.statusLabel', {
defaultMessage: 'Status',
});

View file

@ -22,33 +22,31 @@ const ClosureOptionsComponent: React.FC<ClosureOptionsProps> = ({
closureTypeSelected,
disabled,
onChangeClosureType,
}) => {
return (
<EuiDescribedFormGroup
}) => (
<EuiDescribedFormGroup
fullWidth
title={<h3>{i18n.CASE_CLOSURE_OPTIONS_TITLE}</h3>}
description={
<>
<p>{i18n.CASE_CLOSURE_OPTIONS_DESC}</p>
<p>{i18n.CASE_CLOSURE_OPTIONS_SUB_CASES}</p>
</>
}
data-test-subj="case-closure-options-form-group"
>
<EuiFormRow
fullWidth
title={<h3>{i18n.CASE_CLOSURE_OPTIONS_TITLE}</h3>}
description={
<>
<p>{i18n.CASE_CLOSURE_OPTIONS_DESC}</p>
<p>{i18n.CASE_COLSURE_OPTIONS_SUB_CASES}</p>
</>
}
data-test-subj="case-closure-options-form-group"
label={i18n.CASE_CLOSURE_OPTIONS_LABEL}
data-test-subj="case-closure-options-form-row"
>
<EuiFormRow
fullWidth
label={i18n.CASE_CLOSURE_OPTIONS_LABEL}
data-test-subj="case-closure-options-form-row"
>
<ClosureOptionsRadio
closureTypeSelected={closureTypeSelected}
disabled={disabled}
onChangeClosureType={onChangeClosureType}
data-test-subj="case-closure-options-radio"
/>
</EuiFormRow>
</EuiDescribedFormGroup>
);
};
<ClosureOptionsRadio
closureTypeSelected={closureTypeSelected}
disabled={disabled}
onChangeClosureType={onChangeClosureType}
data-test-subj="case-closure-options-radio"
/>
</EuiFormRow>
</EuiDescribedFormGroup>
);
export const ClosureOptions = React.memo(ClosureOptionsComponent);

View file

@ -50,7 +50,7 @@ export const CASE_CLOSURE_OPTIONS_DESC = i18n.translate(
}
);
export const CASE_COLSURE_OPTIONS_SUB_CASES = i18n.translate(
export const CASE_CLOSURE_OPTIONS_SUB_CASES = i18n.translate(
'xpack.cases.configureCases.caseClosureOptionsSubCases',
{
defaultMessage: 'Automated closures of sub-cases is not currently supported.',
@ -78,39 +78,24 @@ export const CASE_CLOSURE_OPTIONS_NEW_INCIDENT = i18n.translate(
}
);
export const CASE_CLOSURE_OPTIONS_CLOSED_INCIDENT = i18n.translate(
'xpack.cases.configureCases.caseClosureOptionsClosedIncident',
{
defaultMessage: 'Automatically close cases when incident is closed in external system',
}
);
export const FIELD_MAPPING_TITLE = (thirdPartyName: string): string => {
return i18n.translate('xpack.cases.configureCases.fieldMappingTitle', {
export const FIELD_MAPPING_TITLE = (thirdPartyName: string): string =>
i18n.translate('xpack.cases.configureCases.fieldMappingTitle', {
values: { thirdPartyName },
defaultMessage: '{ thirdPartyName } field mappings',
});
};
export const FIELD_MAPPING_DESC = (thirdPartyName: string): string => {
return i18n.translate('xpack.cases.configureCases.fieldMappingDesc', {
export const FIELD_MAPPING_DESC = (thirdPartyName: string): string =>
i18n.translate('xpack.cases.configureCases.fieldMappingDesc', {
values: { thirdPartyName },
defaultMessage:
'Map Case fields to { thirdPartyName } fields when pushing data to { thirdPartyName }. Field mappings require an established connection to { thirdPartyName }.',
});
};
export const FIELD_MAPPING_DESC_ERR = (thirdPartyName: string): string => {
return i18n.translate('xpack.cases.configureCases.fieldMappingDescErr', {
export const FIELD_MAPPING_DESC_ERR = (thirdPartyName: string): string =>
i18n.translate('xpack.cases.configureCases.fieldMappingDescErr', {
values: { thirdPartyName },
defaultMessage: 'Failed to retrieve mappings for { thirdPartyName }.',
});
};
export const EDIT_FIELD_MAPPING_TITLE = (thirdPartyName: string): string => {
return i18n.translate('xpack.cases.configureCases.editFieldMappingTitle', {
values: { thirdPartyName },
defaultMessage: 'Edit { thirdPartyName } field mappings',
});
};
export const FIELD_MAPPING_FIRST_COL = i18n.translate(
'xpack.cases.configureCases.fieldMappingFirstCol',
@ -119,12 +104,11 @@ export const FIELD_MAPPING_FIRST_COL = i18n.translate(
}
);
export const FIELD_MAPPING_SECOND_COL = (thirdPartyName: string): string => {
return i18n.translate('xpack.cases.configureCases.fieldMappingSecondCol', {
export const FIELD_MAPPING_SECOND_COL = (thirdPartyName: string): string =>
i18n.translate('xpack.cases.configureCases.fieldMappingSecondCol', {
values: { thirdPartyName },
defaultMessage: '{ thirdPartyName } field',
});
};
export const FIELD_MAPPING_THIRD_COL = i18n.translate(
'xpack.cases.configureCases.fieldMappingThirdCol',
@ -133,20 +117,6 @@ export const FIELD_MAPPING_THIRD_COL = i18n.translate(
}
);
export const FIELD_MAPPING_EDIT_NOTHING = i18n.translate(
'xpack.cases.configureCases.fieldMappingEditNothing',
{
defaultMessage: 'Nothing',
}
);
export const FIELD_MAPPING_EDIT_OVERWRITE = i18n.translate(
'xpack.cases.configureCases.fieldMappingEditOverwrite',
{
defaultMessage: 'Overwrite',
}
);
export const FIELD_MAPPING_EDIT_APPEND = i18n.translate(
'xpack.cases.configureCases.fieldMappingEditAppend',
{
@ -181,46 +151,22 @@ export const WARNING_NO_CONNECTOR_MESSAGE = i18n.translate(
}
);
export const MAPPING_FIELD_NOT_MAPPED = i18n.translate(
'xpack.cases.configureCases.mappingFieldNotMapped',
{
defaultMessage: 'Not mapped',
}
);
export const COMMENT = i18n.translate('xpack.cases.configureCases.commentMapping', {
defaultMessage: 'Comments',
});
export const NO_FIELDS_ERROR = (connectorName: string): string => {
return i18n.translate('xpack.cases.configureCases.noFieldsError', {
values: { connectorName },
defaultMessage:
'No { connectorName } fields found. Please check your { connectorName } connector settings or your { connectorName } instance settings to resolve.',
});
};
export const BLANK_MAPPINGS = (connectorName: string): string => {
return i18n.translate('xpack.cases.configureCases.blankMappings', {
values: { connectorName },
defaultMessage: 'At least one field needs to be mapped to { connectorName }',
});
};
export const REQUIRED_MAPPINGS = (connectorName: string, fields: string): string => {
return i18n.translate('xpack.cases.configureCases.requiredMappings', {
export const REQUIRED_MAPPINGS = (connectorName: string, fields: string): string =>
i18n.translate('xpack.cases.configureCases.requiredMappings', {
values: { connectorName, fields },
defaultMessage:
'At least one Case field needs to be mapped to the following required { connectorName } fields: { fields }',
});
};
export const UPDATE_FIELD_MAPPINGS = i18n.translate('xpack.cases.configureCases.updateConnector', {
defaultMessage: 'Update field mappings',
});
export const UPDATE_SELECTED_CONNECTOR = (connectorName: string): string => {
return i18n.translate('xpack.cases.configureCases.updateSelectedConnector', {
export const UPDATE_SELECTED_CONNECTOR = (connectorName: string): string =>
i18n.translate('xpack.cases.configureCases.updateSelectedConnector', {
values: { connectorName },
defaultMessage: 'Update { connectorName }',
});
};

View file

@ -22,21 +22,6 @@ export const CASE_CONNECTOR_TITLE = i18n.translate(
defaultMessage: 'Cases',
}
);
export const CASE_CONNECTOR_COMMENT_LABEL = i18n.translate(
'xpack.cases.components.connectors.cases.commentLabel',
{
defaultMessage: 'Comment',
}
);
export const CASE_CONNECTOR_COMMENT_REQUIRED = i18n.translate(
'xpack.cases.components.connectors.cases.commentRequired',
{
defaultMessage: 'Comment is required.',
}
);
export const CASE_CONNECTOR_CASES_DROPDOWN_ROW_LABEL = i18n.translate(
'xpack.cases.components.connectors.cases.casesDropdownRowLabel',
{
@ -44,20 +29,6 @@ export const CASE_CONNECTOR_CASES_DROPDOWN_ROW_LABEL = i18n.translate(
}
);
export const CASE_CONNECTOR_CASES_DROPDOWN_PLACEHOLDER = i18n.translate(
'xpack.cases.components.connectors.cases.casesDropdownPlaceholder',
{
defaultMessage: 'Select case',
}
);
export const CASE_CONNECTOR_CASES_OPTION_NEW_CASE = i18n.translate(
'xpack.cases.components.connectors.cases.optionAddNewCase',
{
defaultMessage: 'Add to a new case',
}
);
export const CASE_CONNECTOR_CASES_OPTION_EXISTING_CASE = i18n.translate(
'xpack.cases.components.connectors.cases.optionAddToExistingCase',
{
@ -100,10 +71,3 @@ export const CREATE_CASE = i18n.translate(
defaultMessage: 'Create case',
}
);
export const CONNECTED_CASE = i18n.translate(
'xpack.cases.components.connectors.cases.connectedCaseLabel',
{
defaultMessage: 'Connected case',
}
);

View file

@ -49,8 +49,6 @@ class CaseConnectors {
const caseConnectors = new CaseConnectors();
export const getCaseConnectors = (): GetCaseConnectorsReturn => {
return {
caseConnectorsRegistry: caseConnectors.registry(),
};
};
export const getCaseConnectors = (): GetCaseConnectorsReturn => ({
caseConnectorsRegistry: caseConnectors.registry(),
});

View file

@ -13,13 +13,10 @@ import * as i18n from './translations';
export * from './types';
export const getCaseConnector = (): CaseConnector<JiraFieldsType> => {
return {
id: '.jira',
fieldsComponent: lazy(() => import('./case_fields')),
};
};
export const getCaseConnector = (): CaseConnector<JiraFieldsType> => ({
id: '.jira',
fieldsComponent: lazy(() => import('./case_fields')),
});
export const fieldLabels = {
issueType: i18n.ISSUE_TYPE,
priority: i18n.PRIORITY,

View file

@ -13,12 +13,10 @@ import * as i18n from './translations';
export * from './types';
export const getCaseConnector = (): CaseConnector<ResilientFieldsType> => {
return {
id: '.resilient',
fieldsComponent: lazy(() => import('./case_fields')),
};
};
export const getCaseConnector = (): CaseConnector<ResilientFieldsType> => ({
id: '.resilient',
fieldsComponent: lazy(() => import('./case_fields')),
});
export const fieldLabels = {
incidentTypes: i18n.INCIDENT_TYPES_LABEL,

View file

@ -11,19 +11,15 @@ import { CaseConnector } from '../types';
import { ServiceNowITSMFieldsType, ServiceNowSIRFieldsType } from '../../../../common';
import * as i18n from './translations';
export const getServiceNowITSMCaseConnector = (): CaseConnector<ServiceNowITSMFieldsType> => {
return {
id: '.servicenow',
fieldsComponent: lazy(() => import('./servicenow_itsm_case_fields')),
};
};
export const getServiceNowITSMCaseConnector = (): CaseConnector<ServiceNowITSMFieldsType> => ({
id: '.servicenow',
fieldsComponent: lazy(() => import('./servicenow_itsm_case_fields')),
});
export const getServiceNowSIRCaseConnector = (): CaseConnector<ServiceNowSIRFieldsType> => {
return {
id: '.servicenow-sir',
fieldsComponent: lazy(() => import('./servicenow_sir_case_fields')),
};
};
export const getServiceNowSIRCaseConnector = (): CaseConnector<ServiceNowSIRFieldsType> => ({
id: '.servicenow-sir',
fieldsComponent: lazy(() => import('./servicenow_sir_case_fields')),
});
export const serviceNowITSMFieldLabels = {
impact: i18n.IMPACT,

View file

@ -19,24 +19,22 @@ import { useGetChoices } from '../connectors/servicenow/use_get_choices';
import { incidentTypes, severity, choices } from '../connectors/mock';
import { schema, FormProps } from './schema';
jest.mock('../../common/lib/kibana', () => {
return {
useKibana: () => ({
services: {
notifications: {},
http: {},
triggersActionsUi: {
actionTypeRegistry: {
get: jest.fn().mockReturnValue({
actionTypeTitle: 'test',
iconClass: 'logoSecurity',
}),
},
jest.mock('../../common/lib/kibana', () => ({
useKibana: () => ({
services: {
notifications: {},
http: {},
triggersActionsUi: {
actionTypeRegistry: {
get: jest.fn().mockReturnValue({
actionTypeTitle: 'test',
iconClass: 'logoSecurity',
}),
},
},
}),
};
});
},
}),
}));
jest.mock('../connectors/resilient/use_get_incident_types');
jest.mock('../connectors/resilient/use_get_severity');

View file

@ -8,11 +8,10 @@
import React, { memo, useCallback } from 'react';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { ConnectorTypes } from '../../../common';
import { ActionConnector, ConnectorTypes } from '../../../common';
import { UseField, useFormData, FieldHook, useFormContext } from '../../common/shared_imports';
import { ConnectorSelector } from '../connector_selector/form';
import { ConnectorFieldsForm } from '../connectors/fields_form';
import { ActionConnector } from '../../../common';
import { getConnectorById } from '../configure_cases/utils';
import { FormProps } from './schema';

View file

@ -15,7 +15,7 @@ import { CreateCaseForm } from './form';
import { FormContext } from './form_context';
import { SubmitCaseButton } from './submit_button';
import { Case } from '../../containers/types';
import { CaseType } from '../../../common/api/cases';
import { CaseType } from '../../../common';
import { CasesTimelineIntegration, CasesTimelineIntegrationProvider } from '../timeline_context';
import { fieldName as descriptionFieldName } from './description';
import { InsertTimeline } from '../insert_timeline';
@ -91,12 +91,10 @@ const CreateCaseComponent = ({
</CasesTimelineIntegrationProvider>
);
export const CreateCase: React.FC<CreateCaseProps> = React.memo((props) => {
return (
<OwnerProvider owner={props.owner}>
<CreateCaseComponent {...props} />
</OwnerProvider>
);
});
export const CreateCase: React.FC<CreateCaseProps> = React.memo((props) => (
<OwnerProvider owner={props.owner}>
<CreateCaseComponent {...props} />
</OwnerProvider>
));
// eslint-disable-next-line import/no-default-export
export { CreateCase as default };

View file

@ -88,41 +88,39 @@ const HeaderPageComponent: React.FC<HeaderPageProps> = ({
title,
titleNode,
...rest
}) => {
return (
<Header border={border} {...rest}>
<EuiFlexGroup alignItems="center">
<FlexItem>
{backOptions && (
<LinkBack>
<LinkIcon
dataTestSubj={backOptions.dataTestSubj}
onClick={backOptions.onClick}
href={backOptions.href}
iconType="arrowLeft"
>
{backOptions.text}
</LinkIcon>
</LinkBack>
)}
{!backOptions && backComponent && <>{backComponent}</>}
{titleNode || <Title title={title} badgeOptions={badgeOptions} />}
{subtitle && <Subtitle data-test-subj="header-page-subtitle" items={subtitle} />}
{subtitle2 && <Subtitle data-test-subj="header-page-subtitle-2" items={subtitle2} />}
{border && isLoading && <EuiProgress size="xs" color="accent" />}
</FlexItem>
{children && (
<FlexItem data-test-subj="header-page-supplements" grow={false}>
{children}
</FlexItem>
}) => (
<Header border={border} {...rest}>
<EuiFlexGroup alignItems="center">
<FlexItem>
{backOptions && (
<LinkBack>
<LinkIcon
dataTestSubj={backOptions.dataTestSubj}
onClick={backOptions.onClick}
href={backOptions.href}
iconType="arrowLeft"
>
{backOptions.text}
</LinkIcon>
</LinkBack>
)}
</EuiFlexGroup>
</Header>
);
};
{!backOptions && backComponent && <>{backComponent}</>}
{titleNode || <Title title={title} badgeOptions={badgeOptions} />}
{subtitle && <Subtitle data-test-subj="header-page-subtitle" items={subtitle} />}
{subtitle2 && <Subtitle data-test-subj="header-page-subtitle-2" items={subtitle2} />}
{border && isLoading && <EuiProgress size="xs" color="accent" />}
</FlexItem>
{children && (
<FlexItem data-test-subj="header-page-supplements" grow={false}>
{children}
</FlexItem>
)}
</EuiFlexGroup>
</Header>
);
export const HeaderPage = React.memo(HeaderPageComponent);

View file

@ -18,7 +18,9 @@ import * as i18n from './translations';
export interface CasesNavigation<T = React.MouseEvent | MouseEvent | null, K = null> {
href: K extends 'configurable' ? (arg: T) => string : string;
onClick: (arg: T) => void;
onClick: K extends 'configurable'
? (arg: T, arg2: React.MouseEvent | MouseEvent) => Promise<void> | void
: (arg: T) => Promise<void> | void;
}
export const LinkButton: React.FC<
@ -47,7 +49,7 @@ const CaseDetailsLinkComponent: React.FC<{
(ev) => {
if (onClick) {
ev.preventDefault();
onClick({ detailName, subCaseId });
onClick({ detailName, subCaseId }, ev);
}
},
[detailName, onClick, subCaseId]

View file

@ -7,8 +7,7 @@
import React, { memo, useEffect, useState, useCallback } from 'react';
import { PluggableList } from 'unified';
import { EuiMarkdownEditor } from '@elastic/eui';
import { EuiMarkdownEditorUiPlugin } from '@elastic/eui';
import { EuiMarkdownEditor, EuiMarkdownEditorUiPlugin } from '@elastic/eui';
import { usePlugins } from './use_plugins';
interface MarkdownEditorProps {

View file

@ -7,10 +7,6 @@
import { i18n } from '@kbn/i18n';
export const MARKDOWN_SYNTAX_HELP = i18n.translate('xpack.cases.markdownEditor.markdownInputHelp', {
defaultMessage: 'Markdown syntax help',
});
export const MARKDOWN = i18n.translate('xpack.cases.markdownEditor.markdown', {
defaultMessage: 'Markdown',
});

View file

@ -61,15 +61,13 @@ export interface SubtitleProps {
items: string | React.ReactNode | Array<string | React.ReactNode>;
}
export const Subtitle = React.memo<SubtitleProps>(({ items }) => {
return (
<Wrapper className="casesSubtitle">
{Array.isArray(items) ? (
items.map((item, i) => <SubtitleItem key={i}>{item}</SubtitleItem>)
) : (
<SubtitleItem>{items}</SubtitleItem>
)}
</Wrapper>
);
});
export const Subtitle = React.memo<SubtitleProps>(({ items }) => (
<Wrapper className="casesSubtitle">
{Array.isArray(items) ? (
items.map((item, i) => <SubtitleItem key={i}>{item}</SubtitleItem>)
) : (
<SubtitleItem>{items}</SubtitleItem>
)}
</Wrapper>
));
Subtitle.displayName = 'Subtitle';

View file

@ -14,20 +14,18 @@ interface TagsProps {
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>
)}
</>
);
};
const TagsComponent: React.FC<TagsProps> = ({ tags, color = 'default', gutterSize }) => (
<>
{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);

View file

@ -8,6 +8,4 @@
import { useContext } from 'react';
import { CasesTimelineIntegrationContext } from '.';
export const useTimelineContext = () => {
return useContext(CasesTimelineIntegrationContext);
};
export const useTimelineContext = () => useContext(CasesTimelineIntegrationContext);

View file

@ -29,8 +29,8 @@ const CreateModalComponent: React.FC<CreateCaseModalProps> = ({
onCloseCaseModal,
onSuccess,
owner,
}) => {
return isModalOpen ? (
}) =>
isModalOpen ? (
<EuiModal onClose={onCloseCaseModal} data-test-subj="create-case-modal">
<EuiModalHeader>
<EuiModalHeaderTitle>{i18n.CREATE_TITLE}</EuiModalHeaderTitle>
@ -47,7 +47,6 @@ const CreateModalComponent: React.FC<CreateCaseModalProps> = ({
</EuiModalBody>
</EuiModal>
) : null;
};
export const CreateCaseModal = memo(CreateModalComponent);

View file

@ -143,8 +143,8 @@ export const usePushToService = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [actionLicense, caseStatus, connectors.length, connector, loadingLicense]);
const pushToServiceButton = useMemo(() => {
return (
const pushToServiceButton = useMemo(
() => (
<EuiButton
data-test-subj="push-to-external-service"
fill
@ -159,21 +159,22 @@ export const usePushToService = ({
? i18n.UPDATE_THIRD(connector.name)
: i18n.PUSH_THIRD(connector.name)}
</EuiButton>
);
),
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
connector,
connectors,
errorsMsg,
handlePushToService,
isLoading,
loadingLicense,
userCanCrud,
isValidConnector,
]);
[
connector,
connectors,
errorsMsg,
handlePushToService,
isLoading,
loadingLicense,
userCanCrud,
isValidConnector,
]
);
const objToReturn = useMemo(() => {
return {
const objToReturn = useMemo(
() => ({
pushButton:
errorsMsg.length > 0 ? (
<EuiToolTip
@ -190,8 +191,9 @@ export const usePushToService = ({
errorsMsg.length > 0 ? (
<CaseCallOut title={i18n.ERROR_PUSH_SERVICE_CALLOUT_TITLE} messages={errorsMsg} />
) : null,
};
}, [errorsMsg, pushToServiceButton]);
}),
[errorsMsg, pushToServiceButton]
);
return objToReturn;
};

View file

@ -26,26 +26,26 @@ import { Status, statuses } from '../status';
import { UserActionShowAlert } from './user_action_show_alert';
import * as i18n from './translations';
import { AlertCommentEvent } from './user_action_alert_comment_event';
import { CasesNavigation } from '../links';
interface LabelTitle {
action: CaseUserActions;
field: string;
}
export type RuleDetailsNavigation = CasesNavigation<string | null | undefined, 'configurable'>;
const getStatusTitle = (id: string, status: CaseStatuses) => {
return (
<EuiFlexGroup
gutterSize="s"
alignItems={'center'}
data-test-subj={`${id}-user-action-status-title`}
>
<EuiFlexItem grow={false}>{i18n.MARKED_CASE_AS}</EuiFlexItem>
<EuiFlexItem grow={false}>
<Status type={status} />
</EuiFlexItem>
</EuiFlexGroup>
);
};
const getStatusTitle = (id: string, status: CaseStatuses) => (
<EuiFlexGroup
gutterSize="s"
alignItems={'center'}
data-test-subj={`${id}-user-action-status-title`}
>
<EuiFlexItem grow={false}>{i18n.MARKED_CASE_AS}</EuiFlexItem>
<EuiFlexItem grow={false}>
<Status type={status} />
</EuiFlexItem>
</EuiFlexGroup>
);
const isStatusValid = (status: string): status is CaseStatuses =>
Object.prototype.hasOwnProperty.call(statuses, status);
@ -204,67 +204,65 @@ export const getAlertAttachment = ({
alertId,
getCaseDetailHrefWithCommentId,
getRuleDetailsHref,
onRuleDetailsClick,
index,
loadingAlertData,
onRuleDetailsClick,
onShowAlertDetails,
ruleId,
ruleName,
onShowAlertDetails,
}: {
action: CaseUserActions;
getCaseDetailHrefWithCommentId: (commentId: string) => string;
getRuleDetailsHref: (ruleId: string | null | undefined) => string;
onRuleDetailsClick?: (ruleId: string | null | undefined) => void;
onShowAlertDetails: (alertId: string, index: string) => void;
alertId: string;
getCaseDetailHrefWithCommentId: (commentId: string) => string;
getRuleDetailsHref: RuleDetailsNavigation['href'];
index: string;
loadingAlertData: boolean;
onRuleDetailsClick?: RuleDetailsNavigation['onClick'];
onShowAlertDetails: (alertId: string, index: string) => void;
ruleId?: string | null;
ruleName?: string | null;
}): EuiCommentProps => {
return {
username: (
<UserActionUsernameWithAvatar
username={action.actionBy.username}
fullName={action.actionBy.fullName}
/>
),
className: 'comment-alert',
type: 'update',
event: (
<AlertCommentEvent
alertId={alertId}
getRuleDetailsHref={getRuleDetailsHref}
loadingAlertData={loadingAlertData}
onRuleDetailsClick={onRuleDetailsClick}
ruleId={ruleId}
ruleName={ruleName}
commentType={CommentType.alert}
/>
),
'data-test-subj': `${action.actionField[0]}-${action.action}-action-${action.actionId}`,
timestamp: <UserActionTimestamp createdAt={action.actionAt} />,
timelineIcon: 'bell',
actions: (
<EuiFlexGroup>
<EuiFlexItem>
<UserActionCopyLink
id={action.actionId}
getCaseDetailHrefWithCommentId={getCaseDetailHrefWithCommentId}
/>
</EuiFlexItem>
<EuiFlexItem>
<UserActionShowAlert
id={action.actionId}
alertId={alertId}
index={index}
onShowAlertDetails={onShowAlertDetails}
/>
</EuiFlexItem>
</EuiFlexGroup>
),
};
};
}): EuiCommentProps => ({
username: (
<UserActionUsernameWithAvatar
username={action.actionBy.username}
fullName={action.actionBy.fullName}
/>
),
className: 'comment-alert',
type: 'update',
event: (
<AlertCommentEvent
alertId={alertId}
getRuleDetailsHref={getRuleDetailsHref}
loadingAlertData={loadingAlertData}
onRuleDetailsClick={onRuleDetailsClick}
ruleId={ruleId}
ruleName={ruleName}
commentType={CommentType.alert}
/>
),
'data-test-subj': `${action.actionField[0]}-${action.action}-action-${action.actionId}`,
timestamp: <UserActionTimestamp createdAt={action.actionAt} />,
timelineIcon: 'bell',
actions: (
<EuiFlexGroup>
<EuiFlexItem>
<UserActionCopyLink
id={action.actionId}
getCaseDetailHrefWithCommentId={getCaseDetailHrefWithCommentId}
/>
</EuiFlexItem>
<EuiFlexItem>
<UserActionShowAlert
id={action.actionId}
alertId={alertId}
index={index}
onShowAlertDetails={onShowAlertDetails}
/>
</EuiFlexItem>
</EuiFlexGroup>
),
});
export const toStringArray = (value: unknown): string[] => {
if (Array.isArray(value)) {
@ -314,45 +312,43 @@ export const getGeneratedAlertsAttachment = ({
action: CaseUserActions;
alertIds: string[];
getCaseDetailHrefWithCommentId: (commentId: string) => string;
getRuleDetailsHref: (ruleId: string | null | undefined) => string;
onRuleDetailsClick?: (ruleId: string | null | undefined) => void;
getRuleDetailsHref: RuleDetailsNavigation['href'];
onRuleDetailsClick?: RuleDetailsNavigation['onClick'];
renderInvestigateInTimelineActionComponent?: (alertIds: string[]) => JSX.Element;
ruleId: string;
ruleName: string;
}): EuiCommentProps => {
return {
username: <EuiIcon type="logoSecurity" size="m" />,
className: 'comment-alert',
type: 'update',
event: (
<AlertCommentEvent
alertId={alertIds[0]}
getRuleDetailsHref={getRuleDetailsHref}
onRuleDetailsClick={onRuleDetailsClick}
ruleId={ruleId}
ruleName={ruleName}
alertsCount={alertIds.length}
commentType={CommentType.generatedAlert}
/>
),
'data-test-subj': `${action.actionField[0]}-${action.action}-action-${action.actionId}`,
timestamp: <UserActionTimestamp createdAt={action.actionAt} />,
timelineIcon: 'bell',
actions: (
<EuiFlexGroup>
<EuiFlexItem>
<UserActionCopyLink
getCaseDetailHrefWithCommentId={getCaseDetailHrefWithCommentId}
id={action.actionId}
/>
</EuiFlexItem>
{renderInvestigateInTimelineActionComponent ? (
<EuiFlexItem>{renderInvestigateInTimelineActionComponent(alertIds)}</EuiFlexItem>
) : null}
</EuiFlexGroup>
),
};
};
}): EuiCommentProps => ({
username: <EuiIcon type="logoSecurity" size="m" />,
className: 'comment-alert',
type: 'update',
event: (
<AlertCommentEvent
alertId={alertIds[0]}
getRuleDetailsHref={getRuleDetailsHref}
onRuleDetailsClick={onRuleDetailsClick}
ruleId={ruleId}
ruleName={ruleName}
alertsCount={alertIds.length}
commentType={CommentType.generatedAlert}
/>
),
'data-test-subj': `${action.actionField[0]}-${action.action}-action-${action.actionId}`,
timestamp: <UserActionTimestamp createdAt={action.actionAt} />,
timelineIcon: 'bell',
actions: (
<EuiFlexGroup>
<EuiFlexItem>
<UserActionCopyLink
getCaseDetailHrefWithCommentId={getCaseDetailHrefWithCommentId}
id={action.actionId}
/>
</EuiFlexItem>
{renderInvestigateInTimelineActionComponent ? (
<EuiFlexItem>{renderInvestigateInTimelineActionComponent(alertIds)}</EuiFlexItem>
) : null}
</EuiFlexGroup>
),
});
interface Signal {
rule: {

View file

@ -8,8 +8,9 @@
import React from 'react';
import { mount } from 'enzyme';
import { waitFor } from '@testing-library/react';
// eslint-disable-next-line @kbn/eslint/module_migration
import routeData from 'react-router';
import { Router, routeData, mockHistory, mockLocation } from '../__mock__/router';
import { getFormMock, useFormMock, useFormDataMock } from '../__mock__/form';
import { useUpdateComment } from '../../containers/use_update_comment';
import { basicCase, basicPush, getUserAction } from '../../containers/mock';
@ -63,7 +64,7 @@ describe(`UserActionTree`, () => {
const formHookMock = getFormMock(sampleData);
useFormMock.mockImplementation(() => ({ form: formHookMock }));
useFormDataMock.mockImplementation(() => [{ content: sampleData.content, comment: '' }]);
jest.spyOn(routeData, 'useLocation').mockReturnValue(mockLocation);
jest
.spyOn(routeData, 'useParams')
.mockReturnValue({ detailName: 'case-id', subCaseId: 'sub-case-id' });
@ -72,9 +73,7 @@ describe(`UserActionTree`, () => {
it('Loading spinner when user actions loading and displays fullName/username', () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<UserActionTree {...{ ...defaultProps, isLoadingUserActions: true }} />
</Router>
<UserActionTree {...{ ...defaultProps, isLoadingUserActions: true }} />
</TestProviders>
);
expect(wrapper.find(`[data-test-subj="user-actions-loading"]`).exists()).toEqual(true);
@ -109,13 +108,13 @@ describe(`UserActionTree`, () => {
};
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<UserActionTree {...props} />
</Router>
<UserActionTree {...props} />
</TestProviders>
);
expect(wrapper.find(`[data-test-subj="top-footer"]`).exists()).toEqual(true);
expect(wrapper.find(`[data-test-subj="bottom-footer"]`).exists()).toEqual(true);
await waitFor(() => {
expect(wrapper.find(`[data-test-subj="top-footer"]`).exists()).toEqual(true);
expect(wrapper.find(`[data-test-subj="bottom-footer"]`).exists()).toEqual(true);
});
});
it('Renders service now update line with top only when push is up to date', async () => {
@ -136,13 +135,13 @@ describe(`UserActionTree`, () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<UserActionTree {...props} />
</Router>
<UserActionTree {...props} />
</TestProviders>
);
expect(wrapper.find(`[data-test-subj="top-footer"]`).exists()).toEqual(true);
expect(wrapper.find(`[data-test-subj="bottom-footer"]`).exists()).toEqual(false);
await waitFor(() => {
expect(wrapper.find(`[data-test-subj="top-footer"]`).exists()).toEqual(true);
expect(wrapper.find(`[data-test-subj="bottom-footer"]`).exists()).toEqual(false);
});
});
it('Outlines comment when update move to link is clicked', async () => {
const ourActions = [getUserAction(['comment'], 'create'), getUserAction(['comment'], 'update')];
@ -153,9 +152,7 @@ describe(`UserActionTree`, () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<UserActionTree {...props} />
</Router>
<UserActionTree {...props} />
</TestProviders>
);
expect(
@ -190,9 +187,7 @@ describe(`UserActionTree`, () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<UserActionTree {...props} />
</Router>
<UserActionTree {...props} />
</TestProviders>
);
@ -236,9 +231,7 @@ describe(`UserActionTree`, () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<UserActionTree {...props} />
</Router>
<UserActionTree {...props} />
</TestProviders>
);
@ -287,9 +280,7 @@ describe(`UserActionTree`, () => {
it('calls update description when description markdown is saved', async () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<UserActionTree {...defaultProps} />
</Router>
<UserActionTree {...defaultProps} />
</TestProviders>
);
@ -333,9 +324,7 @@ describe(`UserActionTree`, () => {
const props = defaultProps;
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<UserActionTree {...props} />
</Router>
<UserActionTree {...props} />
</TestProviders>
);
@ -365,17 +354,16 @@ describe(`UserActionTree`, () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<UserActionTree {...props} />
</Router>
<UserActionTree {...props} />
</TestProviders>
);
expect(
wrapper
.find(`[data-test-subj="comment-create-action-${commentId}"]`)
.first()
.hasClass('outlined')
).toEqual(true);
await waitFor(() => {
expect(
wrapper
.find(`[data-test-subj="comment-create-action-${commentId}"]`)
.first()
.hasClass('outlined')
).toEqual(true);
});
});
});

View file

@ -21,15 +21,17 @@ import { isRight } from 'fp-ts/Either';
import * as i18n from './translations';
import { Case, CaseUserActions } from '../../../common';
import { useUpdateComment } from '../../containers/use_update_comment';
import { useCurrentUser } from '../../common/lib/kibana';
import { AddComment, AddCommentRefObject } from '../add_comment';
import {
ActionConnector,
AlertCommentRequestRt,
Case,
CaseUserActions,
CommentType,
ContextTypeUserRt,
Ecs,
} from '../../../common';
import { CaseServices } from '../../containers/use_get_case_user_actions';
import { parseString } from '../../containers/utils';
@ -42,6 +44,7 @@ import {
getUpdateAction,
getAlertAttachment,
getGeneratedAlertsAttachment,
RuleDetailsNavigation,
} from './helpers';
import { UserActionAvatar } from './user_action_avatar';
import { UserActionMarkdown } from './user_action_markdown';
@ -49,24 +52,24 @@ import { UserActionTimestamp } from './user_action_timestamp';
import { UserActionUsername } from './user_action_username';
import { UserActionContentToolbar } from './user_action_content_toolbar';
import { getManualAlertIdsWithNoRuleId } from '../case_view/helpers';
import { Ecs } from '../../../common';
export interface UserActionTreeProps {
getCaseDetailHrefWithCommentId: (commentId: string) => string;
caseServices: CaseServices;
caseUserActions: CaseUserActions[];
connectors: ActionConnector[];
data: Case;
getRuleDetailsHref?: (ruleId: string | null | undefined) => string;
fetchUserActions: () => void;
getCaseDetailHrefWithCommentId: (commentId: string) => string;
getRuleDetailsHref?: RuleDetailsNavigation['href'];
isLoadingDescription: boolean;
isLoadingUserActions: boolean;
onRuleDetailsClick?: (ruleId: string | null | undefined) => void;
onRuleDetailsClick?: RuleDetailsNavigation['onClick'];
onShowAlertDetails: (alertId: string, index: string) => void;
onUpdateField: ({ key, value, onSuccess, onError }: OnUpdateFields) => void;
renderInvestigateInTimelineActionComponent?: (alertIds: string[]) => JSX.Element;
updateCase: (newCase: Case) => void;
useFetchAlertData: (alertIds: string[]) => [boolean, Record<string, Ecs>];
userCanCrud: boolean;
onShowAlertDetails: (alertId: string, index: string) => void;
}
const MyEuiFlexGroup = styled(EuiFlexGroup)`
@ -114,22 +117,22 @@ const NEW_ID = 'newComment';
export const UserActionTree = React.memo(
({
data: caseData,
getCaseDetailHrefWithCommentId,
caseServices,
caseUserActions,
connectors,
getRuleDetailsHref,
data: caseData,
fetchUserActions,
getCaseDetailHrefWithCommentId,
getRuleDetailsHref,
isLoadingDescription,
isLoadingUserActions,
onRuleDetailsClick,
onShowAlertDetails,
onUpdateField,
renderInvestigateInTimelineActionComponent,
updateCase,
useFetchAlertData,
userCanCrud,
onShowAlertDetails,
}: UserActionTreeProps) => {
const { detailName: caseId, commentId, subCaseId } = useParams<{
detailName: string;

View file

@ -49,24 +49,10 @@ export const GENERATED_ALERT_COUNT_COMMENT_LABEL_TITLE = (totalCount: number) =>
defaultMessage: `{totalCount} {totalCount, plural, =1 {alert} other {alerts}}`,
});
export const ALERT_RULE_DELETED_COMMENT_LABEL = i18n.translate(
'xpack.cases.caseView.alertRuleDeletedLabelTitle',
{
defaultMessage: 'added an alert',
}
);
export const SHOW_ALERT_TOOLTIP = i18n.translate('xpack.cases.caseView.showAlertTooltip', {
defaultMessage: 'Show alert details',
});
export const SEND_ALERT_TO_TIMELINE = i18n.translate(
'xpack.cases.caseView.sendAlertToTimelineTooltip',
{
defaultMessage: 'Investigate in timeline',
}
);
export const UNKNOWN_RULE = i18n.translate('xpack.cases.caseView.unknownRule.label', {
defaultMessage: 'Unknown rule',
});

View file

@ -12,12 +12,13 @@ import { EuiText, EuiLoadingSpinner } from '@elastic/eui';
import * as i18n from './translations';
import { CommentType } from '../../../common';
import { LinkAnchor } from '../links';
import { RuleDetailsNavigation } from './helpers';
interface Props {
alertId: string;
commentType: CommentType;
getRuleDetailsHref: (ruleId: string | null | undefined) => string;
onRuleDetailsClick?: (ruleId: string | null | undefined) => void;
getRuleDetailsHref: RuleDetailsNavigation['href'];
onRuleDetailsClick?: RuleDetailsNavigation['onClick'];
ruleId?: string | null;
ruleName?: string | null;
alertsCount?: number;
@ -35,9 +36,9 @@ const AlertCommentEventComponent: React.FC<Props> = ({
commentType,
}) => {
const onLinkClick = useCallback(
(ev: { preventDefault: () => void }) => {
(ev) => {
ev.preventDefault();
if (onRuleDetailsClick) onRuleDetailsClick(ruleId);
if (onRuleDetailsClick) onRuleDetailsClick(ruleId, ev);
},
[ruleId, onRuleDetailsClick]
);

View file

@ -18,17 +18,15 @@ jest.mock('react-router-dom', () => {
};
});
jest.mock('../../common/lib/kibana', () => {
return {
useKibana: () => ({
services: {
application: {
getUrlForApp: jest.fn(),
},
jest.mock('../../common/lib/kibana', () => ({
useKibana: () => ({
services: {
application: {
getUrlForApp: jest.fn(),
},
}),
};
});
},
}),
}));
const props = {
getCaseDetailHrefWithCommentId: jest.fn().mockReturnValue('case-detail-url-with-comment-id-1'),

View file

@ -31,28 +31,23 @@ const UserActionContentToolbarComponent = ({
isLoading,
onEdit,
onQuote,
}: UserActionContentToolbarProps) => {
return (
<EuiFlexGroup>
<EuiFlexItem>
<UserActionCopyLink
id={id}
getCaseDetailHrefWithCommentId={getCaseDetailHrefWithCommentId}
/>
</EuiFlexItem>
<EuiFlexItem>
<UserActionPropertyActions
id={id}
editLabel={editLabel}
quoteLabel={quoteLabel}
disabled={disabled}
isLoading={isLoading}
onEdit={onEdit}
onQuote={onQuote}
/>
</EuiFlexItem>
</EuiFlexGroup>
);
};
}: UserActionContentToolbarProps) => (
<EuiFlexGroup>
<EuiFlexItem>
<UserActionCopyLink id={id} getCaseDetailHrefWithCommentId={getCaseDetailHrefWithCommentId} />
</EuiFlexItem>
<EuiFlexItem>
<UserActionPropertyActions
id={id}
editLabel={editLabel}
quoteLabel={quoteLabel}
disabled={disabled}
isLoading={isLoading}
onEdit={onEdit}
onQuote={onQuote}
/>
</EuiFlexItem>
</EuiFlexGroup>
);
export const UserActionContentToolbar = memo(UserActionContentToolbarComponent);

View file

@ -24,26 +24,22 @@ jest.mock('react-router-dom', () => {
};
});
jest.mock('copy-to-clipboard', () => {
return jest.fn();
});
jest.mock('copy-to-clipboard', () => jest.fn());
const mockGetUrlForApp = jest.fn(
(appId: string, options?: { path?: string; absolute?: boolean }) =>
`${appId}${options?.path ?? ''}`
);
jest.mock('../../common/lib/kibana', () => {
return {
useKibana: () => ({
services: {
application: {
getUrlForApp: mockGetUrlForApp,
},
jest.mock('../../common/lib/kibana', () => ({
useKibana: () => ({
services: {
application: {
getUrlForApp: mockGetUrlForApp,
},
}),
};
});
},
}),
}));
const props = {
id: 'comment-id',

View file

@ -7,7 +7,6 @@
import React from 'react';
import { mount } from 'enzyme';
import { Router, mockHistory } from '../__mock__/router';
import { UserActionMarkdown } from './user_action_markdown';
import { TestProviders } from '../../common/mock';
import { waitFor } from '@testing-library/react';
@ -31,9 +30,7 @@ describe('UserActionMarkdown ', () => {
it('Renders markdown correctly when not in edit mode', async () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<UserActionMarkdown {...{ ...defaultProps, isEditable: false }} />
</Router>
<UserActionMarkdown {...{ ...defaultProps, isEditable: false }} />
</TestProviders>
);
@ -43,9 +40,7 @@ describe('UserActionMarkdown ', () => {
it('Save button click calls onSaveContent and onChangeEditable', async () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<UserActionMarkdown {...defaultProps} />
</Router>
<UserActionMarkdown {...defaultProps} />
</TestProviders>
);
wrapper.find(`[data-test-subj="user-action-save-markdown"]`).first().simulate('click');
@ -58,9 +53,7 @@ describe('UserActionMarkdown ', () => {
it('Cancel button click calls only onChangeEditable', async () => {
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<UserActionMarkdown {...defaultProps} />
</Router>
<UserActionMarkdown {...defaultProps} />
</TestProviders>
);
wrapper.find(`[data-test-subj="user-action-cancel-markdown"]`).first().simulate('click');

View file

@ -32,8 +32,8 @@ const UserActionPropertyActionsComponent = ({
const onEditClick = useCallback(() => onEdit(id), [id, onEdit]);
const onQuoteClick = useCallback(() => onQuote(id), [id, onQuote]);
const propertyActions = useMemo(() => {
return [
const propertyActions = useMemo(
() => [
{
disabled,
iconType: 'pencil',
@ -46,8 +46,9 @@ const UserActionPropertyActionsComponent = ({
label: quoteLabel,
onClick: onQuoteClick,
},
];
}, [disabled, editLabel, quoteLabel, onEditClick, onQuoteClick]);
],
[disabled, editLabel, quoteLabel, onEditClick, onQuoteClick]
);
return (
<>
{isLoading && <EuiLoadingSpinner data-test-subj="user-action-title-loading" />}

View file

@ -17,31 +17,29 @@ interface UserActionAvatarProps {
updatedAt?: string | null;
}
const UserActionTimestampComponent = ({ createdAt, updatedAt }: UserActionAvatarProps) => {
return (
<>
<LocalizedDateTooltip date={new Date(createdAt)}>
<FormattedRelative
data-test-subj="user-action-title-creation-relative-time"
value={createdAt}
/>
</LocalizedDateTooltip>
{updatedAt && (
<EuiTextColor color="subdued">
{/* be careful of the extra space at the beginning of the parenthesis */}
{' ('}
{i18n.EDITED_FIELD}{' '}
<LocalizedDateTooltip date={new Date(updatedAt)}>
<FormattedRelative
data-test-subj="user-action-title-edited-relative-time"
value={updatedAt}
/>
</LocalizedDateTooltip>
{')'}
</EuiTextColor>
)}
</>
);
};
const UserActionTimestampComponent = ({ createdAt, updatedAt }: UserActionAvatarProps) => (
<>
<LocalizedDateTooltip date={new Date(createdAt)}>
<FormattedRelative
data-test-subj="user-action-title-creation-relative-time"
value={createdAt}
/>
</LocalizedDateTooltip>
{updatedAt && (
<EuiTextColor color="subdued">
{/* be careful of the extra space at the beginning of the parenthesis */}
{' ('}
{i18n.EDITED_FIELD}{' '}
<LocalizedDateTooltip date={new Date(updatedAt)}>
<FormattedRelative
data-test-subj="user-action-title-edited-relative-time"
value={updatedAt}
/>
</LocalizedDateTooltip>
{')'}
</EuiTextColor>
)}
</>
);
export const UserActionTimestamp = memo(UserActionTimestampComponent);

View file

@ -20,26 +20,24 @@ interface UserActionUsernameWithAvatarProps {
const UserActionUsernameWithAvatarComponent = ({
username,
fullName,
}: UserActionUsernameWithAvatarProps) => {
return (
<EuiFlexGroup
responsive={false}
alignItems="center"
gutterSize="s"
data-test-subj="user-action-username-with-avatar"
>
<EuiFlexItem grow={false}>
<EuiAvatar
size="s"
name={(isEmpty(fullName) ? username : fullName) ?? i18n.UNKNOWN}
data-test-subj="user-action-username-avatar"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<UserActionUsername username={username} fullName={fullName} />
</EuiFlexItem>
</EuiFlexGroup>
);
};
}: UserActionUsernameWithAvatarProps) => (
<EuiFlexGroup
responsive={false}
alignItems="center"
gutterSize="s"
data-test-subj="user-action-username-with-avatar"
>
<EuiFlexItem grow={false}>
<EuiAvatar
size="s"
name={(isEmpty(fullName) ? username : fullName) ?? i18n.UNKNOWN}
data-test-subj="user-action-username-avatar"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<UserActionUsername username={username} fullName={fullName} />
</EuiFlexItem>
</EuiFlexGroup>
);
export const UserActionUsernameWithAvatar = memo(UserActionUsernameWithAvatarComponent);

View file

@ -39,9 +39,7 @@ export const getCase = async (
caseId: string,
includeComments: boolean = true,
signal: AbortSignal
): Promise<Case> => {
return Promise.resolve(basicCase);
};
): Promise<Case> => Promise.resolve(basicCase);
export const getCasesStatus = async (signal: AbortSignal): Promise<CasesStatus> =>
Promise.resolve(casesStatus);

View file

@ -7,8 +7,13 @@
import { KibanaServices } from '../common/lib/kibana';
import { ConnectorTypes, CommentType, CaseStatuses, SECURITY_SOLUTION_OWNER } from '../../common';
import { CASES_URL } from '../../common';
import {
CASES_URL,
ConnectorTypes,
CommentType,
CaseStatuses,
SECURITY_SOLUTION_OWNER,
} from '../../common';
import {
deleteCases,

View file

@ -8,9 +8,14 @@
import { assign, omit } from 'lodash';
import {
ACTION_TYPES_URL,
CASE_REPORTERS_URL,
CASE_STATUS_URL,
CASE_TAGS_URL,
CasePatchRequest,
CasePostRequest,
CaseResponse,
CASES_URL,
CasesFindResponse,
CasesResponse,
CasesStatusResponse,
@ -18,32 +23,21 @@ import {
CaseUserActionsResponse,
CommentRequest,
CommentType,
getCaseCommentsUrl,
getCaseDetailsUrl,
getCasePushUrl,
getCaseUserActionUrl,
getSubCaseDetailsUrl,
getSubCaseUserActionUrl,
StatusAll,
SUB_CASE_DETAILS_URL,
SUB_CASES_PATCH_DEL_URL,
SubCasePatchRequest,
SubCaseResponse,
SubCasesResponse,
User,
} from '../../common';
import {
ACTION_TYPES_URL,
CASE_REPORTERS_URL,
CASE_STATUS_URL,
CASE_TAGS_URL,
CASES_URL,
SUB_CASE_DETAILS_URL,
SUB_CASES_PATCH_DEL_URL,
} from '../../common';
import {
getCaseCommentsUrl,
getCasePushUrl,
getCaseDetailsUrl,
getCaseUserActionUrl,
getSubCaseDetailsUrl,
getSubCaseUserActionUrl,
} from '../../common';
import { KibanaServices } from '../common/lib/kibana';
import {

View file

@ -72,10 +72,6 @@ export const SUCCESS_SEND_TO_EXTERNAL_SERVICE = (serviceName: string) =>
defaultMessage: 'Successfully sent to { serviceName }',
});
export const ERROR_GET_FIELDS = i18n.translate('xpack.cases.configure.errorGetFields', {
defaultMessage: 'Error getting fields from service',
});
export const SYNC_CASE = (caseTitle: string) =>
i18n.translate('xpack.cases.containers.syncCase', {
values: { caseTitle },

View file

@ -141,12 +141,13 @@ export const useUpdateCases = (): UseUpdateCases => {
[]
);
useEffect(() => {
return () => {
useEffect(
() => () => {
isCancelledRef.current = true;
abortCtrlRef.current.abort();
};
}, []);
},
[]
);
return { ...state, updateBulkStatus, dispatchResetIsUpdated };
};

View file

@ -134,12 +134,13 @@ export const useDeleteCases = (): UseDeleteCase => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [state.isDisplayConfirmDeleteModal]);
useEffect(() => {
return () => {
useEffect(
() => () => {
isCancelledRef.current = true;
abortCtrlRef.current.abort();
};
}, []);
},
[]
);
return { ...state, dispatchResetIsDeleted, handleOnDeleteConfirm, handleToggleModal };
};

View file

@ -80,11 +80,12 @@ export const usePostCase = (): UsePostCase => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
return () => {
useEffect(
() => () => {
isCancelledRef.current = true;
abortCtrlRef.current.abort();
};
}, []);
},
[]
);
return { ...state, postCase: postMyCase };
};

View file

@ -91,12 +91,13 @@ export const usePostComment = (): UsePostComment => {
[toasts]
);
useEffect(() => {
return () => {
useEffect(
() => () => {
isCancelledRef.current = true;
abortCtrlRef.current.abort();
};
}, []);
},
[]
);
return { ...state, postComment: postMyComment };
};

View file

@ -97,12 +97,13 @@ export const usePostPushToService = (): UsePostPushToService => {
[]
);
useEffect(() => {
return () => {
useEffect(
() => () => {
abortCtrlRef.current.abort();
cancel.current = true;
};
}, []);
},
[]
);
return { ...state, pushCaseToExternalService };
};

View file

@ -138,12 +138,13 @@ export const useUpdateCase = ({
[caseId, subCaseId]
);
useEffect(() => {
return () => {
useEffect(
() => () => {
isCancelledRef.current = true;
abortCtrlRef.current.abort();
};
}, []);
},
[]
);
return { ...state, updateCaseProperty: dispatchUpdateCaseProperty };
};

View file

@ -119,12 +119,13 @@ export const useUpdateComment = (): UseUpdateComment => {
[]
);
useEffect(() => {
return () => {
useEffect(
() => () => {
isCancelledRef.current = true;
abortCtrlRef.current.abort();
};
}, []);
},
[]
);
return { ...state, patchComment: dispatchUpdateComment };
};

View file

@ -43,49 +43,37 @@ export class CasesUiPlugin implements Plugin<void, CasesUiStart, SetupPlugins, S
* @param props AllCasesProps
* @return {ReactElement<AllCasesProps>}
*/
getAllCases: (props) => {
return getAllCasesLazy(props);
},
getAllCases: getAllCasesLazy,
/**
* Get the case view component
* @param props CaseViewProps
* @return {ReactElement<CaseViewProps>}
*/
getCaseView: (props) => {
return getCaseViewLazy(props);
},
getCaseView: getCaseViewLazy,
/**
* Get the configure case component
* @param props ConfigureCasesProps
* @return {ReactElement<ConfigureCasesProps>}
*/
getConfigureCases: (props) => {
return getConfigureCasesLazy(props);
},
getConfigureCases: getConfigureCasesLazy,
/**
* Get the create case form
* @param props CreateCaseProps
* @return {ReactElement<CreateCaseProps>}
*/
getCreateCase: (props) => {
return getCreateCaseLazy(props);
},
getCreateCase: getCreateCaseLazy,
/**
* Get the recent cases component
* @param props RecentCasesProps
* @return {ReactElement<RecentCasesProps>}
*/
getRecentCases: (props) => {
return getRecentCasesLazy(props);
},
getRecentCases: getRecentCasesLazy,
/**
* use Modal hook for all cases selector
* @param props UseAllCasesSelectorModalProps
* @return UseAllCasesSelectorModalReturnedValues
*/
getAllCasesSelectorModal: (props) => {
return getAllCasesSelectorModalLazy(props);
},
getAllCasesSelectorModal: getAllCasesSelectorModalLazy,
};
}

View file

@ -9,11 +9,10 @@ import { KibanaRequest, Logger } from 'kibana/server';
import Boom from '@hapi/boom';
import { SecurityPluginStart } from '../../../security/server';
import { PluginStartContract as FeaturesPluginStart } from '../../../features/server';
import { AuthFilterHelpers, GetSpaceFn } from './types';
import { AuthFilterHelpers, GetSpaceFn, OwnerEntity } from './types';
import { getOwnersFilter } from './utils';
import { AuthorizationAuditLogger, OperationDetails } from '.';
import { createCaseError } from '../common';
import { OwnerEntity } from './types';
/**
* This class handles ensuring that the user making a request has the correct permissions

View file

@ -11,7 +11,7 @@ import {
CASE_CONFIGURE_SAVED_OBJECT,
CASE_SAVED_OBJECT,
CASE_USER_ACTION_SAVED_OBJECT,
} from '../../common/constants';
} from '../../common';
import { Verbs, ReadOperations, WriteOperations, OperationDetails } from './types';
export * from './authorization';

View file

@ -7,7 +7,7 @@
import { remove, uniq } from 'lodash';
import { nodeBuilder, KueryNode } from '../../../../../src/plugins/data/common';
import { OWNER_FIELD } from '../../common/api';
import { OWNER_FIELD } from '../../common';
export const getOwnersFilter = (
savedObjectType: string,

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { CaseStatuses } from '../../../common/api';
import { CaseStatuses } from '../../../common';
import { AlertInfo } from '../../common';
import { CasesClientGetAlertsResponse } from './types';
import { get } from './get';

View file

@ -19,16 +19,19 @@ import {
import { nodeBuilder } from '../../../../../../src/plugins/data/common';
import {
throwErrors,
CommentRequestRt,
CommentType,
AlertCommentRequestRt,
CASE_COMMENT_SAVED_OBJECT,
CaseResponse,
CaseStatuses,
CaseType,
SubCaseAttributes,
CaseResponse,
User,
AlertCommentRequestRt,
CommentRequest,
CommentRequestRt,
CommentType,
ENABLE_CASE_CONNECTOR,
MAX_GENERATED_ALERTS_PER_SUB_CASE,
SubCaseAttributes,
throwErrors,
User,
} from '../../../common';
import {
buildCaseUserActionItem,
@ -37,17 +40,12 @@ import {
import { AttachmentService, CasesService, CaseUserActionService } from '../../services';
import {
createCaseError,
CommentableCase,
createAlertUpdateRequest,
isCommentRequestTypeGenAlert,
} from '../../common';
import { CasesClientArgs, CasesClientInternal } from '..';
import { createCaseError } from '../../common/error';
import {
ENABLE_CASE_CONNECTOR,
MAX_GENERATED_ALERTS_PER_SUB_CASE,
CASE_COMMENT_SAVED_OBJECT,
} from '../../../common';
import { decodeCommentRequest } from '../utils';
import { Operations } from '../../authorization';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { CommentResponse } from '../../../common/api';
import { CommentResponse } from '../../../common';
import { CasesClientInternal } from '../client_internal';
import { IAllCommentsResponse, ICaseResponse, ICommentsResponse } from '../typedoc_interfaces';

View file

@ -10,15 +10,15 @@ import pMap from 'p-map';
import { SavedObject } from 'kibana/public';
import {
AssociationType,
CASE_SAVED_OBJECT,
CommentAttributes,
MAX_CONCURRENT_SEARCHES,
SUB_CASE_SAVED_OBJECT,
} from '../../../common/constants';
import { AssociationType, CommentAttributes } from '../../../common/api';
} from '../../../common';
import { CasesClientArgs } from '../types';
import { buildCommentUserActionItem } from '../../services/user_actions/helpers';
import { createCaseError } from '../../common/error';
import { checkEnabledCaseConnectorOrThrow } from '../../common';
import { createCaseError, checkEnabledCaseConnectorOrThrow } from '../../common';
import { Operations } from '../../authorization';
/**

View file

@ -6,7 +6,6 @@
*/
import Boom from '@hapi/boom';
import { SavedObjectsFindResponse } from 'kibana/server';
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
import {
AllCommentsResponse,
@ -17,16 +16,17 @@ import {
CommentResponseRt,
CommentsResponse,
CommentsResponseRt,
ENABLE_CASE_CONNECTOR,
FindQueryParams,
} from '../../../common/api';
} from '../../../common';
import {
createCaseError,
checkEnabledCaseConnectorOrThrow,
defaultSortField,
transformComments,
flattenCommentSavedObject,
flattenCommentSavedObjects,
} from '../../common';
import { createCaseError } from '../../common/error';
import { defaultPage, defaultPerPage } from '../../routes/api';
import { CasesClientArgs } from '../types';
import { combineFilters, stringToKueryNode } from '../utils';

View file

@ -9,14 +9,17 @@ import { pick } from 'lodash/fp';
import Boom from '@hapi/boom';
import { SavedObjectsClientContract, Logger } from 'kibana/server';
import { checkEnabledCaseConnectorOrThrow, CommentableCase } from '../../common';
import { checkEnabledCaseConnectorOrThrow, CommentableCase, createCaseError } from '../../common';
import { buildCommentUserActionItem } from '../../services/user_actions/helpers';
import { CASE_SAVED_OBJECT, SUB_CASE_SAVED_OBJECT } from '../../../common/constants';
import {
CASE_SAVED_OBJECT,
SUB_CASE_SAVED_OBJECT,
CaseResponse,
CommentPatchRequest,
} from '../../../common';
import { AttachmentService, CasesService } from '../../services';
import { CaseResponse, CommentPatchRequest } from '../../../common/api';
import { CasesClientArgs } from '..';
import { decodeCommentRequest } from '../utils';
import { createCaseError } from '../../common/error';
import { Operations } from '../../authorization';
/**

View file

@ -12,7 +12,7 @@ import {
User,
AllTagsFindRequest,
AllReportersFindRequest,
} from '../../../common/api';
} from '../../../common';
import { CasesClient } from '../client';
import { CasesClientInternal } from '../client_internal';
import {

View file

@ -21,14 +21,14 @@ import {
CasePostRequest,
CaseType,
OWNER_FIELD,
ENABLE_CASE_CONNECTOR,
} from '../../../common';
import { buildCaseUserActionItem } from '../../services/user_actions/helpers';
import { getConnectorFromConfiguration } from '../utils';
import { createCaseError } from '../../common/error';
import { Operations } from '../../authorization';
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
import {
createCaseError,
flattenCaseSavedObject,
transformCaseConnectorToEsConnector,
transformNewCase,

View file

@ -8,13 +8,18 @@
import pMap from 'p-map';
import { Boom } from '@hapi/boom';
import { SavedObject, SavedObjectsClientContract, SavedObjectsFindResponse } from 'kibana/server';
import { ENABLE_CASE_CONNECTOR, MAX_CONCURRENT_SEARCHES } from '../../../common/constants';
import {
CommentAttributes,
ENABLE_CASE_CONNECTOR,
MAX_CONCURRENT_SEARCHES,
OWNER_FIELD,
SubCaseAttributes,
} from '../../../common';
import { CasesClientArgs } from '..';
import { createCaseError } from '../../common/error';
import { createCaseError } from '../../common';
import { AttachmentService, CasesService } from '../../services';
import { buildCaseUserActionItem } from '../../services/user_actions/helpers';
import { Operations, OwnerEntity } from '../../authorization';
import { OWNER_FIELD, SubCaseAttributes, CommentAttributes } from '../../../common/api';
async function deleteSubCases({
attachmentService,

View file

@ -18,13 +18,12 @@ import {
caseStatuses,
CasesFindResponseRt,
excess,
} from '../../../common/api';
} from '../../../common';
import { createCaseError } from '../../common/error';
import { createCaseError, transformCases } from '../../common';
import { constructQueryOptions } from '../utils';
import { includeFieldsRequiredForAuthentication } from '../../authorization/utils';
import { Operations } from '../../authorization';
import { transformCases } from '../../common';
import { CasesClientArgs } from '..';
/**

View file

@ -24,10 +24,9 @@ import {
AllReportersFindRequest,
CasesByAlertIDRequest,
CasesByAlertIDRequestRt,
} from '../../../common/api';
import { countAlertsForID, flattenCaseSavedObject } from '../../common';
import { createCaseError } from '../../common/error';
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
ENABLE_CASE_CONNECTOR,
} from '../../../common';
import { countAlertsForID, createCaseError, flattenCaseSavedObject } from '../../common';
import { CasesClientArgs } from '..';
import { Operations } from '../../authorization';
import { combineAuthorizedAndOwnerFilter } from '../utils';

View file

@ -17,12 +17,12 @@ import {
ESCaseAttributes,
ESCasesConfigureAttributes,
CaseType,
ENABLE_CASE_CONNECTOR,
} from '../../../common';
import { buildCaseUserActionItem } from '../../services/user_actions/helpers';
import { createIncident, getCommentContextFromAttributes } from './utils';
import { createCaseError, flattenCaseSavedObject, getAlertInfoFromComments } from '../../common';
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
import { CasesClient, CasesClientArgs, CasesClientInternal } from '..';
import { Operations } from '../../authorization';
import { casesConnectors } from '../../connectors';

View file

@ -21,39 +21,37 @@ import {
import { nodeBuilder } from '../../../../../../src/plugins/data/common';
import {
throwErrors,
excess,
CasesResponseRt,
ESCasePatchRequest,
CasePatchRequest,
CasesResponse,
CaseStatuses,
CasesPatchRequestRt,
CommentType,
ESCaseAttributes,
CaseType,
CasesPatchRequest,
AssociationType,
CASE_COMMENT_SAVED_OBJECT,
CASE_SAVED_OBJECT,
CasePatchRequest,
CasesPatchRequest,
CasesPatchRequestRt,
CasesResponse,
CasesResponseRt,
CaseStatuses,
CaseType,
CommentAttributes,
} from '../../../common/api';
CommentType,
ENABLE_CASE_CONNECTOR,
ESCaseAttributes,
ESCasePatchRequest,
excess,
MAX_CONCURRENT_SEARCHES,
SUB_CASE_SAVED_OBJECT,
throwErrors,
} from '../../../common';
import { buildCaseUserActions } from '../../services/user_actions/helpers';
import { getCaseToUpdate } from '../utils';
import { CasesService } from '../../services';
import {
CASE_COMMENT_SAVED_OBJECT,
CASE_SAVED_OBJECT,
MAX_CONCURRENT_SEARCHES,
SUB_CASE_SAVED_OBJECT,
} from '../../../common/constants';
import {
createAlertUpdateRequest,
transformCaseConnectorToEsConnector,
createCaseError,
flattenCaseSavedObject,
isCommentRequestTypeAlertOrGenAlert,
transformCaseConnectorToEsConnector,
} from '../../common';
import { createCaseError } from '../../common/error';
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
import { UpdateAlertRequest } from '../alerts/client';
import { CasesClientInternal } from '../client_internal';
import { CasesClientArgs } from '..';

View file

@ -11,7 +11,7 @@ import { AttachmentsSubClient, createAttachmentsSubClient } from './attachments/
import { UserActionsSubClient, createUserActionsSubClient } from './user_actions/client';
import { CasesClientInternal, createCasesClientInternal } from './client_internal';
import { createSubCasesClient, SubCasesClient } from './sub_cases/client';
import { ENABLE_CASE_CONNECTOR } from '../../common/constants';
import { ENABLE_CASE_CONNECTOR } from '../../common';
import { ConfigureSubClient, createConfigurationSubClient } from './configure/client';
import { createStatsSubClient, StatsSubClient } from './stats/client';

View file

@ -16,25 +16,26 @@ import {
SavedObjectsFindResponse,
SavedObjectsUtils,
} from '../../../../../../src/core/server';
import { MAX_CONCURRENT_SEARCHES, SUPPORTED_CONNECTORS } from '../../../common/constants';
import {
CaseConfigurationsResponseRt,
CaseConfigureResponseRt,
CasesConfigurationsResponse,
CasesConfigurePatch,
CasesConfigurePatchRt,
CasesConfigureRequest,
CasesConfigureResponse,
ConnectorMappings,
ConnectorMappingsAttributes,
ESCasesConfigureAttributes,
excess,
GetConfigureFindRequest,
GetConfigureFindRequestRt,
MAX_CONCURRENT_SEARCHES,
SUPPORTED_CONNECTORS,
throwErrors,
CasesConfigurationsResponse,
CaseConfigurationsResponseRt,
CasesConfigurePatchRt,
ConnectorMappings,
ESCasesConfigureAttributes,
} from '../../../common/api';
import { createCaseError } from '../../common/error';
} from '../../../common';
import {
createCaseError,
transformCaseConnectorToEsConnector,
transformESConnectorToCaseConnector,
} from '../../common';

View file

@ -5,9 +5,9 @@
* 2.0.
*/
import { ConnectorMappingsAttributes } from '../../../common/api';
import { ConnectorMappingsAttributes } from '../../../common';
import { ACTION_SAVED_OBJECT_TYPE } from '../../../../actions/server';
import { createCaseError } from '../../common/error';
import { createCaseError } from '../../common';
import { CasesClientArgs } from '..';
import { CreateMappingsArgs } from './types';
import { casesConnectors } from '../../connectors';

View file

@ -6,9 +6,9 @@
*/
import { SavedObjectsFindResponse } from 'kibana/server';
import { ConnectorMappings } from '../../../common/api';
import { ConnectorMappings } from '../../../common';
import { ACTION_SAVED_OBJECT_TYPE } from '../../../../actions/server';
import { createCaseError } from '../../common/error';
import { createCaseError } from '../../common';
import { CasesClientArgs } from '..';
import { MappingsArgs } from './types';

View file

@ -5,9 +5,9 @@
* 2.0.
*/
import { ConnectorMappingsAttributes } from '../../../common/api';
import { ConnectorMappingsAttributes } from '../../../common';
import { ACTION_SAVED_OBJECT_TYPE } from '../../../../actions/server';
import { createCaseError } from '../../common/error';
import { createCaseError } from '../../common';
import { CasesClientArgs } from '..';
import { UpdateMappingsArgs } from './types';
import { casesConnectors } from '../../connectors';

View file

@ -12,7 +12,7 @@ import {
ElasticsearchClient,
} from 'kibana/server';
import { SecurityPluginSetup, SecurityPluginStart } from '../../../security/server';
import { SAVED_OBJECT_TYPES } from '../../common/constants';
import { SAVED_OBJECT_TYPES } from '../../common';
import { Authorization } from '../authorization/authorization';
import { GetSpaceFn } from '../authorization/types';
import {

View file

@ -19,9 +19,9 @@ import {
throwErrors,
excess,
CasesStatusRequestRt,
} from '../../../common/api';
} from '../../../common';
import { Operations } from '../../authorization';
import { createCaseError } from '../../common/error';
import { createCaseError } from '../../common';
import { constructQueryOptions } from '../utils';
/**

View file

@ -10,19 +10,24 @@ import Boom from '@hapi/boom';
import { SavedObject } from 'kibana/server';
import {
CASE_SAVED_OBJECT,
caseStatuses,
CommentAttributes,
MAX_CONCURRENT_SEARCHES,
SubCaseResponse,
SubCaseResponseRt,
SubCasesFindRequest,
SubCasesFindResponse,
SubCasesFindResponseRt,
SubCasesPatchRequest,
} from '../../../common/api';
} from '../../../common';
import { CasesClientArgs, CasesClientInternal } from '..';
import { countAlertsForID, flattenSubCaseSavedObject, transformSubCases } from '../../common';
import { createCaseError } from '../../common/error';
import { CASE_SAVED_OBJECT, MAX_CONCURRENT_SEARCHES } from '../../../common/constants';
import {
countAlertsForID,
createCaseError,
flattenSubCaseSavedObject,
transformSubCases,
} from '../../common';
import { buildCaseUserActionItem } from '../../services/user_actions/helpers';
import { constructQueryOptions } from '../utils';
import { defaultPage, defaultPerPage } from '../../routes/api';

View file

@ -19,30 +19,31 @@ import {
import { nodeBuilder } from '../../../../../../src/plugins/data/common';
import { CasesService } from '../../services';
import {
CASE_COMMENT_SAVED_OBJECT,
CaseStatuses,
CommentAttributes,
CommentType,
ESCaseAttributes,
excess,
SUB_CASE_SAVED_OBJECT,
SubCaseAttributes,
SubCasePatchRequest,
SubCaseResponse,
SubCasesPatchRequest,
SubCasesPatchRequestRt,
CommentType,
excess,
throwErrors,
SubCasesResponse,
SubCasePatchRequest,
SubCaseAttributes,
ESCaseAttributes,
SubCaseResponse,
SubCasesResponseRt,
throwErrors,
User,
CommentAttributes,
} from '../../../common/api';
import { CASE_COMMENT_SAVED_OBJECT, SUB_CASE_SAVED_OBJECT } from '../../../common/constants';
} from '../../../common';
import { getCaseToUpdate } from '../utils';
import { buildSubCaseUserActions } from '../../services/user_actions/helpers';
import {
createAlertUpdateRequest,
createCaseError,
isCommentRequestTypeAlertOrGenAlert,
flattenSubCaseSavedObject,
} from '../../common';
import { createCaseError } from '../../common/error';
import { UpdateAlertRequest } from '../../client/alerts/client';
import { CasesClientArgs } from '../types';
import { CasesClientInternal } from '../client_internal';

View file

@ -7,7 +7,7 @@
import type { PublicMethodsOf } from '@kbn/utility-types';
import { ElasticsearchClient, SavedObjectsClientContract, Logger } from 'kibana/server';
import { User } from '../../common/api';
import { User } from '../../common';
import { Authorization } from '../authorization/authorization';
import {
AlertServiceContract,

View file

@ -6,13 +6,13 @@
*/
import {
SUB_CASE_SAVED_OBJECT,
CASE_SAVED_OBJECT,
CASE_COMMENT_SAVED_OBJECT,
} from '../../../common/constants';
import { CaseUserActionsResponseRt, CaseUserActionsResponse } from '../../../common/api';
import { createCaseError } from '../../common/error';
import { checkEnabledCaseConnectorOrThrow } from '../../common';
CASE_SAVED_OBJECT,
CaseUserActionsResponse,
CaseUserActionsResponseRt,
SUB_CASE_SAVED_OBJECT,
} from '../../../common';
import { createCaseError, checkEnabledCaseConnectorOrThrow } from '../../common';
import { CasesClientArgs } from '..';
import { Operations } from '../../authorization';
import { UserActionGet } from './client';

View file

@ -16,19 +16,20 @@ import { SavedObjectsFindResponse } from 'kibana/server';
import { nodeBuilder, KueryNode } from '../../../../../src/plugins/data/common';
import { esKuery } from '../../../../../src/plugins/data/server';
import {
AlertCommentRequestRt,
CASE_SAVED_OBJECT,
CaseConnector,
ESCasesConfigureAttributes,
ConnectorTypes,
CaseStatuses,
CaseType,
CommentRequest,
throwErrors,
excess,
ConnectorTypes,
ContextTypeUserRt,
AlertCommentRequestRt,
ESCasesConfigureAttributes,
excess,
OWNER_FIELD,
} from '../../common/api';
import { CASE_SAVED_OBJECT, SUB_CASE_SAVED_OBJECT } from '../../common/constants';
SUB_CASE_SAVED_OBJECT,
throwErrors,
} from '../../common';
import { combineFilterWithAuthorizationFilter } from '../authorization/utils';
import {
getIDsAndIndicesAsArrays,

View file

@ -15,30 +15,28 @@ import {
} from 'src/core/server';
import {
AssociationType,
CASE_SAVED_OBJECT,
CaseResponse,
CaseResponseRt,
CaseSettings,
CaseStatuses,
CaseType,
CaseResponse,
CaseResponseRt,
CommentAttributes,
CommentPatchRequest,
CommentRequest,
CommentType,
ESCaseAttributes,
MAX_DOCS_PER_PAGE,
SUB_CASE_SAVED_OBJECT,
SubCaseAttributes,
User,
} from '../../../common/api';
} from '../../../common';
import {
transformESConnectorToCaseConnector,
flattenCommentSavedObjects,
flattenSubCaseSavedObject,
transformNewComment,
} from '..';
import {
CASE_SAVED_OBJECT,
MAX_DOCS_PER_PAGE,
SUB_CASE_SAVED_OBJECT,
} from '../../../common/constants';
import { AttachmentService, CasesService } from '../../services';
import { createCaseError } from '../error';
import { countAlertsForID } from '../index';

View file

@ -6,7 +6,7 @@
*/
import { KueryNode } from '../../../../../src/plugins/data/server';
import { SavedObjectFindOptions } from '../../common/api';
import { SavedObjectFindOptions } from '../../common';
/**
* This structure holds the alert ID and index from an alert comment

View file

@ -25,6 +25,7 @@ import {
CommentsResponse,
CommentType,
ConnectorTypeFields,
ENABLE_CASE_CONNECTOR,
ESCaseAttributes,
ESCaseConnector,
ESConnectorFields,
@ -32,8 +33,7 @@ import {
SubCaseResponse,
SubCasesFindResponse,
User,
} from '../../common/api';
import { ENABLE_CASE_CONNECTOR } from '../../common/constants';
} from '../../common';
import { UpdateAlertRequest } from '../client/alerts/client';
/**

View file

@ -13,7 +13,8 @@ import {
CasePostRequest,
CommentRequest,
CommentType,
} from '../../../common/api';
ENABLE_CASE_CONNECTOR,
} from '../../../common';
import { CaseExecutorParamsSchema, CaseConfigurationSchema, CommentSchemaType } from './schema';
import {
CaseExecutorResponse,
@ -24,8 +25,7 @@ import {
import * as i18n from './translations';
import { GetActionTypeParams, isCommentGeneratedAlert, separator } from '..';
import { createCaseError } from '../../common/error';
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
import { createCaseError } from '../../common';
import { CasesClient } from '../../client';
const supportedSubActions: string[] = ['create', 'update', 'addComment'];

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { ConnectorTypes } from '../../common/api';
import { ConnectorTypes } from '../../common';
import { getCaseConnector as getJiraCaseConnector } from './jira';
import { getCaseConnector as getResilientCaseConnector } from './resilient';
import { getServiceNowITSMCaseConnector, getServiceNowSIRCaseConnector } from './servicenow';

View file

@ -12,7 +12,7 @@ import {
ContextTypeAlertSchemaType,
} from './types';
import { getActionType as getCaseConnector } from './case';
import { CommentRequest, CommentType } from '../../common/api';
import { CommentRequest, CommentType } from '../../common';
export * from './types';
export { transformConnectorComment } from './case';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { ConnectorJiraTypeFields } from '../../../common/api';
import { ConnectorJiraTypeFields } from '../../../common';
import { Format } from './types';
export const format: Format = (theCase, alerts) => {

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { JiraFieldsType } from '../../../common/api';
import { JiraFieldsType } from '../../../common';
import { ICasesConnector } from '../types';
interface ExternalServiceFormatterParams extends JiraFieldsType {

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { ConnectorResillientTypeFields } from '../../../common/api';
import { ConnectorResillientTypeFields } from '../../../common';
import { Format } from './types';
export const format: Format = (theCase, alerts) => {

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { ResilientFieldsType } from '../../../common/api';
import { ResilientFieldsType } from '../../../common';
import { ICasesConnector } from '../types';
export type ResilientCaseConnector = ICasesConnector<ResilientFieldsType>;

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { ConnectorServiceNowITSMTypeFields } from '../../../common/api';
import { ConnectorServiceNowITSMTypeFields } from '../../../common';
import { ServiceNowITSMFormat } from './types';
export const format: ServiceNowITSMFormat = (theCase, alerts) => {

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { get } from 'lodash/fp';
import { ConnectorServiceNowSIRTypeFields } from '../../../common/api';
import { ConnectorServiceNowSIRTypeFields } from '../../../common';
import { ServiceNowSIRFormat, SirFieldKey, AlertFieldMappingAndValues } from './types';
export const format: ServiceNowSIRFormat = (theCase, alerts) => {

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { ServiceNowITSMFieldsType } from '../../../common/api';
import { ServiceNowITSMFieldsType } from '../../../common';
import { ICasesConnector } from '../types';
export interface ServiceNowSIRFieldsType {

View file

@ -6,7 +6,7 @@
*/
import { Logger } from 'kibana/server';
import { CaseResponse, ConnectorMappingsAttributes } from '../../common/api';
import { CaseResponse, ConnectorMappingsAttributes } from '../../common';
import { CasesClientGetAlertsResponse } from '../client/alerts/types';
import { CasesClientFactory } from '../client/factory';
import { RegisterActionType } from '../types';

View file

@ -13,7 +13,7 @@ import {
PluginSetupContract as ActionsPluginSetup,
PluginStartContract as ActionsPluginStart,
} from '../../actions/server';
import { APP_ID, ENABLE_CASE_CONNECTOR } from '../common/constants';
import { APP_ID, ENABLE_CASE_CONNECTOR } from '../common';
import { ConfigType } from './config';
import { initCaseApi } from './routes/api';

Some files were not shown because too many files have changed in this diff Show more